1 /* $NetBSD: sysctl.c,v 1.155 2014/11/09 22:50:38 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Brown. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 */ 60 61 #include <sys/cdefs.h> 62 #ifndef lint 63 __COPYRIGHT("@(#) Copyright (c) 1993\ 64 The Regents of the University of California. All rights reserved."); 65 #endif /* not lint */ 66 67 #ifndef lint 68 #if 0 69 static char sccsid[] = "@(#)sysctl.c 8.1 (Berkeley) 6/6/93"; 70 #else 71 __RCSID("$NetBSD: sysctl.c,v 1.155 2014/11/09 22:50:38 christos Exp $"); 72 #endif 73 #endif /* not lint */ 74 75 #include <sys/types.h> 76 #include <sys/param.h> 77 #include <sys/sysctl.h> 78 #include <sys/mount.h> 79 #include <sys/resource.h> 80 #include <sys/stat.h> 81 #include <sys/sched.h> 82 #include <sys/socket.h> 83 #include <sys/bitops.h> 84 #include <netinet/in.h> 85 #include <netinet/ip_var.h> 86 #include <netinet/tcp.h> 87 #include <netinet/tcp_timer.h> 88 #include <netinet/tcp_var.h> 89 #include <netinet/icmp6.h> 90 #include <nfs/rpcv2.h> 91 #include <nfs/nfsproto.h> 92 #include <nfs/nfs.h> 93 #include <machine/cpu.h> 94 95 #include <assert.h> 96 #include <ctype.h> 97 #include <err.h> 98 #include <errno.h> 99 #include <inttypes.h> 100 #include <regex.h> 101 #include <stdarg.h> 102 #include <stdio.h> 103 #include <stdlib.h> 104 #include <string.h> 105 #include <time.h> 106 #include <unistd.h> 107 108 #include "prog_ops.h" 109 110 /* 111 * this needs to be able to do the printing and the setting 112 */ 113 #define HANDLER_PROTO const char *, const char *, char *, \ 114 int *, u_int, const struct sysctlnode *, \ 115 u_int, void * 116 #define HANDLER_ARGS const char *sname, const char *dname, char *value, \ 117 int *name, u_int namelen, const struct sysctlnode *pnode, \ 118 u_int type, void *v 119 #define DISPLAY_VALUE 0 120 #define DISPLAY_OLD 1 121 #define DISPLAY_NEW 2 122 123 /* 124 * generic routines 125 */ 126 static const struct handlespec *findhandler(const char *, regex_t *, size_t *); 127 static void canonicalize(const char *, char *); 128 static void purge_tree(struct sysctlnode *); 129 static void print_tree(int *, u_int, struct sysctlnode *, u_int, int, regex_t *, 130 size_t *); 131 static void write_number(int *, u_int, struct sysctlnode *, char *); 132 static void write_string(int *, u_int, struct sysctlnode *, char *); 133 static void display_number(const struct sysctlnode *, const char *, 134 const void *, size_t, int); 135 static void display_string(const struct sysctlnode *, const char *, 136 const void *, size_t, int); 137 static void display_struct(const struct sysctlnode *, const char *, 138 const void *, size_t, int); 139 static void hex_dump(const unsigned char *, size_t); 140 __dead static void usage(void); 141 static void parse(char *, regex_t *, size_t *); 142 static void parse_create(char *); 143 static void parse_destroy(char *); 144 static void parse_describe(char *); 145 static void getdesc1(int *, u_int, struct sysctlnode *); 146 static void getdesc(int *, u_int, struct sysctlnode *); 147 static void trim_whitespace(char *, int); 148 static void sysctlerror(int); 149 static void sysctlparseerror(u_int, const char *); 150 static void sysctlperror(const char *, ...) __printflike(1, 2); 151 #define EXIT(n) do { \ 152 if (fn == NULL) exit(n); else return; } while (/*CONSTCOND*/0) 153 154 /* 155 * "borrowed" from libc:sysctlgetmibinfo.c 156 */ 157 int __learn_tree(int *, u_int, struct sysctlnode *); 158 159 /* 160 * "handlers" 161 */ 162 static void printother(HANDLER_PROTO); 163 static void kern_clockrate(HANDLER_PROTO); 164 static void kern_boottime(HANDLER_PROTO); 165 static void kern_consdev(HANDLER_PROTO); 166 static void kern_cp_time(HANDLER_PROTO); 167 static void kern_cp_id(HANDLER_PROTO); 168 static void kern_drivers(HANDLER_PROTO); 169 static void vm_loadavg(HANDLER_PROTO); 170 static void proc_limit(HANDLER_PROTO); 171 #ifdef CPU_DISKINFO 172 static void machdep_diskinfo(HANDLER_PROTO); 173 #endif /* CPU_DISKINFO */ 174 static void mode_bits(HANDLER_PROTO); 175 static void reserve(HANDLER_PROTO); 176 177 static const struct handlespec { 178 const char *ps_re; 179 void (*ps_p)(HANDLER_PROTO); 180 void (*ps_w)(HANDLER_PROTO); 181 const void *ps_d; 182 } handlers[] = { 183 { "/kern/clockrate", kern_clockrate, NULL, NULL }, 184 { "/kern/evcnt", printother, NULL, "vmstat -e" }, 185 { "/kern/vnode", printother, NULL, "pstat" }, 186 { "/kern/proc(2|_args)?", printother, NULL, "ps" }, 187 { "/kern/file2?", printother, NULL, "pstat" }, 188 { "/kern/ntptime", printother, NULL, 189 "ntpdc -c kerninfo" }, 190 { "/kern/msgbuf", printother, NULL, "dmesg" }, 191 { "/kern/boottime", kern_boottime, NULL, NULL }, 192 { "/kern/consdev", kern_consdev, NULL, NULL }, 193 { "/kern/cp_time(/[0-9]+)?", kern_cp_time, NULL, NULL }, 194 { "/kern/sysvipc_info", printother, NULL, "ipcs" }, 195 { "/kern/cp_id(/[0-9]+)?", kern_cp_id, NULL, NULL }, 196 197 { "/kern/coredump/setid/mode", mode_bits, mode_bits, NULL }, 198 { "/kern/drivers", kern_drivers, NULL, NULL }, 199 200 { "/vm/vmmeter", printother, NULL, 201 "vmstat' or 'systat" }, 202 { "/vm/loadavg", vm_loadavg, NULL, NULL }, 203 { "/vm/uvmexp2?", printother, NULL, 204 "vmstat' or 'systat" }, 205 206 { "/vfs/nfs/nfsstats", printother, NULL, "nfsstat" }, 207 208 { "/net/inet6?/tcp6?/ident", printother, NULL, "identd" }, 209 { "/net/inet6/icmp6/nd6_[dp]rlist", printother, NULL, "ndp" }, 210 { "/net/key/dumps[ap]", printother, NULL, "setkey" }, 211 { "/net/[^/]+/[^/]+/pcblist", printother, NULL, 212 "netstat' or 'sockstat" }, 213 { "/net/(inet|inet6)/[^/]+/stats", printother, NULL, "netstat"}, 214 { "/net/bpf/(stats|peers)", printother, NULL, "netstat"}, 215 216 { "/net/inet.*/tcp.*/deb.*", printother, NULL, "trpt" }, 217 218 { "/net/inet.*/ip.*/anonportalgo/reserve", reserve, reserve, NULL }, 219 220 { "/net/ns/spp/deb.*", printother, NULL, "trsp" }, 221 222 { "/hw/diskstats", printother, NULL, "iostat" }, 223 224 #ifdef CPU_CONSDEV 225 { "/machdep/consdev", kern_consdev, NULL, NULL }, 226 #endif /* CPU_CONSDEV */ 227 #ifdef CPU_DISKINFO 228 { "/machdep/diskinfo", machdep_diskinfo, NULL, NULL }, 229 #endif /* CPU_CONSDEV */ 230 231 { "/proc/[^/]+/rlimit/[^/]+/[^/]+", proc_limit, proc_limit, NULL }, 232 233 /* 234 * these will only be called when the given node has no children 235 */ 236 { "/net/[^/]+", printother, NULL, NULL }, 237 { "/debug", printother, NULL, NULL }, 238 { "/ddb", printother, NULL, NULL }, 239 { "/vendor", printother, NULL, NULL }, 240 241 { NULL, NULL, NULL, NULL }, 242 }; 243 244 struct sysctlnode my_root = { 245 .sysctl_flags = SYSCTL_VERSION|CTLFLAG_ROOT|CTLTYPE_NODE, 246 .sysctl_size = sizeof(struct sysctlnode), 247 .sysctl_num = 0, 248 .sysctl_name = "(prog_root)", 249 }; 250 251 int Aflag, aflag, dflag, Mflag, nflag, qflag, rflag, wflag, xflag; 252 size_t nr; 253 char *fn; 254 int req, stale, errs; 255 FILE *warnfp = stderr; 256 257 #define MAXPORTS 0x10000 258 259 /* 260 * vah-riables n stuff 261 */ 262 char gsname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME], 263 canonname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME], 264 gdname[10 * CTL_MAXNAME + CTL_MAXNAME]; 265 char sep[] = "."; 266 const char *eq = " = "; 267 const char *lname[] = { 268 "top", "second", "third", "fourth", "fifth", "sixth", 269 "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth" 270 }; 271 272 /* 273 * you've heard of main, haven't you? 274 */ 275 int 276 main(int argc, char *argv[]) 277 { 278 int name[CTL_MAXNAME]; 279 int ch; 280 size_t lastcompiled = 0; 281 regex_t *re; 282 283 setprogname(argv[0]); 284 while ((ch = getopt(argc, argv, "Aabdef:Mnqrwx")) != -1) { 285 switch (ch) { 286 case 'A': 287 Aflag++; 288 break; 289 case 'a': 290 aflag++; 291 break; 292 case 'd': 293 dflag++; 294 break; 295 case 'e': 296 eq = "="; 297 break; 298 case 'f': 299 fn = optarg; 300 wflag++; 301 break; 302 case 'M': 303 Mflag++; 304 break; 305 case 'n': 306 nflag++; 307 break; 308 case 'q': 309 qflag++; 310 break; 311 case 'b': /* FreeBSD compat */ 312 case 'r': 313 rflag++; 314 break; 315 case 'w': 316 wflag++; 317 break; 318 case 'x': 319 xflag++; 320 break; 321 default: 322 usage(); 323 } 324 } 325 326 argc -= optind; 327 argv += optind; 328 329 if (xflag && rflag) 330 usage(); 331 /* if ((xflag || rflag) && wflag) 332 usage(); */ 333 /* if (aflag && (Mflag || qflag)) 334 usage(); */ 335 if ((aflag || Aflag) && qflag) 336 usage(); 337 if ((Aflag || Mflag || dflag) && argc == 0 && fn == NULL) 338 aflag = 1; 339 340 if (prog_init && prog_init() == -1) 341 err(EXIT_FAILURE, "prog init failed"); 342 343 if (Aflag) 344 warnfp = stdout; 345 stale = req = 0; 346 347 if ((re = malloc(sizeof(*re) * __arraycount(handlers))) == NULL) 348 err(EXIT_FAILURE, "malloc regex"); 349 350 if (aflag) { 351 print_tree(&name[0], 0, NULL, CTLTYPE_NODE, 1, 352 re, &lastcompiled); 353 /* if (argc == 0) */ 354 return (0); 355 } 356 357 if (fn) { 358 FILE *fp; 359 char *l; 360 361 fp = fopen(fn, "r"); 362 if (fp == NULL) { 363 err(EXIT_FAILURE, "%s", fn); 364 } else { 365 nr = 0; 366 while ((l = fparseln(fp, NULL, &nr, NULL, 0)) != NULL) 367 { 368 if (*l) { 369 parse(l, re, &lastcompiled); 370 free(l); 371 } 372 } 373 fclose(fp); 374 } 375 return errs ? 1 : 0; 376 } 377 378 if (argc == 0) 379 usage(); 380 381 while (argc-- > 0) 382 parse(*argv++, re, &lastcompiled); 383 384 return errs ? EXIT_FAILURE : EXIT_SUCCESS; 385 } 386 387 /* 388 * ******************************************************************** 389 * how to find someone special to handle the reading (or maybe even 390 * writing) of a particular node 391 * ******************************************************************** 392 */ 393 static const struct handlespec * 394 findhandler(const char *s, regex_t *re, size_t *lastcompiled) 395 { 396 const struct handlespec *p; 397 size_t i, l; 398 int j; 399 char eb[64]; 400 regmatch_t match; 401 402 p = &handlers[0]; 403 l = strlen(s); 404 for (i = 0; p[i].ps_re != NULL; i++) { 405 if (i >= *lastcompiled) { 406 j = regcomp(&re[i], p[i].ps_re, REG_EXTENDED); 407 if (j != 0) { 408 regerror(j, &re[i], eb, sizeof(eb)); 409 errx(EXIT_FAILURE, "regcomp: %s: %s", p[i].ps_re, eb); 410 } 411 *lastcompiled = i + 1; 412 } 413 j = regexec(&re[i], s, 1, &match, 0); 414 if (j == 0) { 415 if (match.rm_so == 0 && match.rm_eo == (int)l) 416 return &p[i]; 417 } 418 else if (j != REG_NOMATCH) { 419 regerror(j, &re[i], eb, sizeof(eb)); 420 errx(EXIT_FAILURE, "regexec: %s: %s", p[i].ps_re, eb); 421 } 422 } 423 424 return NULL; 425 } 426 427 /* 428 * after sysctlgetmibinfo is done with the name, we convert all 429 * separators to / and stuff one at the front if it was missing 430 */ 431 static void 432 canonicalize(const char *i, char *o) 433 { 434 const char *t; 435 char p[SYSCTL_NAMELEN + 1]; 436 int l; 437 438 if (i[0] != *sep) { 439 o[0] = '/'; 440 o[1] = '\0'; 441 } 442 else 443 o[0] = '\0'; 444 445 t = i; 446 do { 447 i = t; 448 t = strchr(i, sep[0]); 449 if (t == NULL) 450 strcat(o, i); 451 else { 452 l = t - i; 453 t++; 454 memcpy(p, i, l); 455 p[l] = '\0'; 456 strcat(o, p); 457 strcat(o, "/"); 458 } 459 } while (t != NULL); 460 } 461 462 /* 463 * ******************************************************************** 464 * convert this special number to a special string so we can print the 465 * mib 466 * ******************************************************************** 467 */ 468 static const char * 469 sf(u_int f) 470 { 471 static char s[256]; 472 const char *c; 473 474 s[0] = '\0'; 475 c = ""; 476 477 #define print_flag(_f, _s, _c, _q, _x) \ 478 if (((_f) & (__CONCAT(CTLFLAG_,_x))) == (__CONCAT(CTLFLAG_,_q))) { \ 479 strlcat((_s), (_c), sizeof(_s)); \ 480 strlcat((_s), __STRING(_q), sizeof(_s)); \ 481 (_c) = ","; \ 482 (_f) &= ~(__CONCAT(CTLFLAG_,_x)); \ 483 } 484 print_flag(f, s, c, READONLY, READWRITE); 485 print_flag(f, s, c, READWRITE, READWRITE); 486 print_flag(f, s, c, ANYWRITE, ANYWRITE); 487 print_flag(f, s, c, PRIVATE, PRIVATE); 488 print_flag(f, s, c, PERMANENT, PERMANENT); 489 print_flag(f, s, c, OWNDATA, OWNDATA); 490 print_flag(f, s, c, IMMEDIATE, IMMEDIATE); 491 print_flag(f, s, c, HEX, HEX); 492 print_flag(f, s, c, ROOT, ROOT); 493 print_flag(f, s, c, ANYNUMBER, ANYNUMBER); 494 print_flag(f, s, c, HIDDEN, HIDDEN); 495 print_flag(f, s, c, ALIAS, ALIAS); 496 #undef print_flag 497 498 if (f) { 499 char foo[9]; 500 snprintf(foo, sizeof(foo), "%x", f); 501 strlcat(s, c, sizeof(s)); 502 strlcat(s, foo, sizeof(s)); 503 } 504 505 return (s); 506 } 507 508 static const char * 509 st(u_int t) 510 { 511 512 switch (t) { 513 case CTLTYPE_NODE: 514 return "NODE"; 515 case CTLTYPE_INT: 516 return "INT"; 517 case CTLTYPE_STRING: 518 return "STRING"; 519 case CTLTYPE_QUAD: 520 return "QUAD"; 521 case CTLTYPE_STRUCT: 522 return "STRUCT"; 523 case CTLTYPE_BOOL: 524 return "BOOL"; 525 } 526 527 return "???"; 528 } 529 530 /* 531 * ******************************************************************** 532 * recursively eliminate all data belonging to the given node 533 * ******************************************************************** 534 */ 535 static void 536 purge_tree(struct sysctlnode *rnode) 537 { 538 struct sysctlnode *node; 539 540 if (rnode == NULL || 541 SYSCTL_TYPE(rnode->sysctl_flags) != CTLTYPE_NODE || 542 rnode->sysctl_child == NULL) 543 return; 544 545 for (node = rnode->sysctl_child; 546 node < &rnode->sysctl_child[rnode->sysctl_clen]; 547 node++) 548 purge_tree(node); 549 free(rnode->sysctl_child); 550 rnode->sysctl_csize = 0; 551 rnode->sysctl_clen = 0; 552 rnode->sysctl_child = NULL; 553 554 if (rnode->sysctl_desc == (const char*)-1) 555 rnode->sysctl_desc = NULL; 556 if (rnode->sysctl_desc != NULL) 557 free(__UNCONST(rnode->sysctl_desc)); 558 rnode->sysctl_desc = NULL; 559 } 560 561 static void __attribute__((__format__(__printf__, 3, 4))) 562 appendprintf(char **bp, size_t *lbp, const char *fmt, ...) 563 { 564 int r; 565 va_list ap; 566 567 va_start(ap, fmt); 568 r = vsnprintf(*bp, *lbp, fmt, ap); 569 va_end(ap); 570 if (r < 0 || (size_t)r > *lbp) 571 r = *lbp; 572 *bp += r; 573 *lbp -= r; 574 } 575 576 /* 577 * ******************************************************************** 578 * print this node and any others underneath it 579 * ******************************************************************** 580 */ 581 static void 582 print_tree(int *name, u_int namelen, struct sysctlnode *pnode, u_int type, 583 int add, regex_t *re, size_t *lastcompiled) 584 { 585 struct sysctlnode *node; 586 int rc; 587 size_t ni, sz, ldp, lsp; 588 char *sp, *dp, *tsp, *tdp; 589 const struct handlespec *p; 590 591 sp = tsp = &gsname[strlen(gsname)]; 592 dp = tdp = &gdname[strlen(gdname)]; 593 ldp = sizeof(gdname) - (dp - gdname); 594 lsp = sizeof(gsname) - (sp - gsname); 595 596 if (sp != &gsname[0] && dp == &gdname[0]) { 597 /* 598 * aw...shucks. now we must play catch up 599 */ 600 for (ni = 0; ni < namelen; ni++) 601 appendprintf(&tdp, &ldp, "%s%d", ni > 0 ? "." : "", 602 name[ni]); 603 } 604 605 if (pnode == NULL) 606 pnode = &my_root; 607 else if (add) { 608 appendprintf(&tsp, &lsp, "%s%s", namelen > 1 ? sep : "", 609 pnode->sysctl_name); 610 appendprintf(&tdp, &ldp, "%s%d", namelen > 1 ? "." : "", 611 pnode->sysctl_num); 612 } 613 614 if (Mflag && pnode != &my_root) { 615 if (nflag) 616 printf("%s: ", gdname); 617 else 618 printf("%s (%s): ", gsname, gdname); 619 printf("CTLTYPE_%s", st(type)); 620 if (type == CTLTYPE_NODE) { 621 if (SYSCTL_FLAGS(pnode->sysctl_flags) & CTLFLAG_ALIAS) 622 printf(", alias %d", 623 pnode->sysctl_alias); 624 else 625 printf(", children %d/%d", 626 pnode->sysctl_clen, 627 pnode->sysctl_csize); 628 } 629 printf(", size %zu", pnode->sysctl_size); 630 printf(", flags 0x%x<%s>", 631 SYSCTL_FLAGS(pnode->sysctl_flags), 632 sf(SYSCTL_FLAGS(pnode->sysctl_flags))); 633 if (pnode->sysctl_func) 634 printf(", func=%p", pnode->sysctl_func); 635 printf(", ver=%d", pnode->sysctl_ver); 636 printf("\n"); 637 if (type != CTLTYPE_NODE) { 638 *sp = *dp = '\0'; 639 return; 640 } 641 } 642 643 if (dflag && pnode != &my_root) { 644 if (Aflag || type != CTLTYPE_NODE) { 645 if (pnode->sysctl_desc == NULL) 646 getdesc1(name, namelen, pnode); 647 if (Aflag || !add || 648 (pnode->sysctl_desc != NULL && 649 pnode->sysctl_desc != (const char*)-1)) { 650 if (!nflag) 651 printf("%s: ", gsname); 652 if (pnode->sysctl_desc == NULL || 653 pnode->sysctl_desc == (const char*)-1) 654 printf("(no description)\n"); 655 else 656 printf("%s\n", pnode->sysctl_desc); 657 } 658 } 659 660 if (type != CTLTYPE_NODE) { 661 *sp = *dp = '\0'; 662 return; 663 } 664 } 665 666 /* 667 * if this is an alias and we added our name, that means we 668 * got here by recursing down into the tree, so skip it. The 669 * only way to print an aliased node is with either -M or by 670 * name specifically. 671 */ 672 if (SYSCTL_FLAGS(pnode->sysctl_flags) & CTLFLAG_ALIAS && add) { 673 *sp = *dp = '\0'; 674 return; 675 } 676 677 canonicalize(gsname, canonname); 678 p = findhandler(canonname, re, lastcompiled); 679 if (type != CTLTYPE_NODE && p != NULL) { 680 if (p->ps_p == NULL) { 681 sysctlperror("Cannot print `%s': %s\n", gsname, 682 strerror(EOPNOTSUPP)); 683 exit(EXIT_FAILURE); 684 } 685 (*p->ps_p)(gsname, gdname, NULL, name, namelen, pnode, type, 686 __UNCONST(p->ps_d)); 687 *sp = *dp = '\0'; 688 return; 689 } 690 691 if (type != CTLTYPE_NODE && pnode->sysctl_size == 0) { 692 rc = prog_sysctl(&name[0], namelen, NULL, &sz, NULL, 0); 693 if (rc == -1) { 694 sysctlerror(1); 695 *sp = *dp = '\0'; 696 return; 697 } 698 if (sz == 0) { 699 if ((Aflag || req) && !Mflag) 700 printf("%s: node contains no data\n", gsname); 701 *sp = *dp = '\0'; 702 return; 703 } 704 } 705 else 706 sz = pnode->sysctl_size; 707 708 switch (type) { 709 case CTLTYPE_NODE: { 710 __learn_tree(name, namelen, pnode); 711 node = pnode->sysctl_child; 712 if (node == NULL) { 713 if (dflag) 714 /* do nothing */; 715 else if (p != NULL) 716 (*p->ps_p)(gsname, gdname, NULL, name, namelen, 717 pnode, type, __UNCONST(p->ps_d)); 718 else if ((Aflag || req) && !Mflag) 719 printf("%s: no children\n", gsname); 720 } 721 else { 722 if (dflag) 723 /* 724 * get all descriptions for next level 725 * in one chunk 726 */ 727 getdesc(name, namelen, pnode); 728 req = 0; 729 for (ni = 0; ni < pnode->sysctl_clen; ni++) { 730 name[namelen] = node[ni].sysctl_num; 731 if ((node[ni].sysctl_flags & CTLFLAG_HIDDEN) && 732 !(Aflag || req)) 733 continue; 734 print_tree(name, namelen + 1, &node[ni], 735 SYSCTL_TYPE(node[ni].sysctl_flags), 736 1, re, lastcompiled); 737 } 738 } 739 break; 740 } 741 case CTLTYPE_INT: { 742 int i; 743 rc = prog_sysctl(name, namelen, &i, &sz, NULL, 0); 744 if (rc == -1) { 745 sysctlerror(1); 746 break; 747 } 748 display_number(pnode, gsname, &i, sizeof(i), DISPLAY_VALUE); 749 break; 750 } 751 case CTLTYPE_BOOL: { 752 bool b; 753 rc = prog_sysctl(name, namelen, &b, &sz, NULL, 0); 754 if (rc == -1) { 755 sysctlerror(1); 756 break; 757 } 758 display_number(pnode, gsname, &b, sizeof(b), DISPLAY_VALUE); 759 break; 760 } 761 case CTLTYPE_STRING: { 762 unsigned char buf[1024], *tbuf; 763 tbuf = buf; 764 sz = sizeof(buf); 765 rc = prog_sysctl(&name[0], namelen, tbuf, &sz, NULL, 0); 766 if (rc == -1 && errno == ENOMEM) { 767 tbuf = malloc(sz); 768 if (tbuf == NULL) { 769 sysctlerror(1); 770 break; 771 } 772 rc = prog_sysctl(&name[0], namelen, tbuf, &sz, NULL, 0); 773 } 774 if (rc == -1) 775 sysctlerror(1); 776 else 777 display_string(pnode, gsname, tbuf, sz, DISPLAY_VALUE); 778 if (tbuf != buf) 779 free(tbuf); 780 break; 781 } 782 case CTLTYPE_QUAD: { 783 u_quad_t q; 784 sz = sizeof(q); 785 rc = prog_sysctl(&name[0], namelen, &q, &sz, NULL, 0); 786 if (rc == -1) { 787 sysctlerror(1); 788 break; 789 } 790 display_number(pnode, gsname, &q, sizeof(q), DISPLAY_VALUE); 791 break; 792 } 793 case CTLTYPE_STRUCT: { 794 /* 795 * we shouldn't actually get here, but if we 796 * do, would it be nice to have *something* to 797 * do other than completely ignore the 798 * request. 799 */ 800 unsigned char *d; 801 if ((d = malloc(sz)) == NULL) { 802 fprintf(warnfp, "%s: !malloc failed!\n", gsname); 803 break; 804 } 805 rc = prog_sysctl(&name[0], namelen, d, &sz, NULL, 0); 806 if (rc == -1) { 807 sysctlerror(1); 808 break; 809 } 810 display_struct(pnode, gsname, d, sz, DISPLAY_VALUE); 811 free(d); 812 break; 813 } 814 default: 815 /* should i print an error here? */ 816 break; 817 } 818 819 *sp = *dp = '\0'; 820 } 821 822 /* 823 * ******************************************************************** 824 * parse a request, possibly determining that it's a create or destroy 825 * request 826 * ******************************************************************** 827 */ 828 static void 829 parse(char *l, regex_t *re, size_t *lastcompiled) 830 { 831 struct sysctlnode *node; 832 const struct handlespec *w; 833 int name[CTL_MAXNAME], dodesc = 0; 834 u_int namelen, type; 835 char *key, *value, *dot; 836 size_t sz; 837 bool optional = false; 838 839 req = 1; 840 key = l; 841 842 if ((value = strchr(l, '=')) != NULL) { 843 if (value > l && value[-1] == '?') { 844 value[-1] = '\0'; 845 optional = true; 846 } 847 *value++ = '\0'; 848 } 849 850 if ((dot = strpbrk(key, "./")) == NULL) 851 sep[0] = '.'; 852 else 853 sep[0] = dot[0]; 854 sep[1] = '\0'; 855 856 while (key[0] == sep[0] && key[1] == sep[0]) { 857 if (value != NULL) 858 value[-1] = '='; 859 if (strncmp(key + 2, "create", 6) == 0 && 860 (key[8] == '=' || key[8] == sep[0])) 861 parse_create(key + 8 + (key[8] == '=' ? 1 : 0)); 862 else if (strncmp(key + 2, "destroy", 7) == 0 && 863 (key[9] == '=' || key[9] == sep[0])) 864 parse_destroy(key + 9 + (key[9] == '=' ? 1 : 0)); 865 else if (strncmp(key + 2, "describe", 8) == 0 && 866 (key[10] == '=' || key[10] == sep[0])) { 867 key += 10 + (key[10] == '='); 868 if ((value = strchr(key, '=')) != NULL) 869 parse_describe(key); 870 else { 871 if (!dflag) 872 dodesc = 1; 873 break; 874 } 875 } 876 else 877 sysctlperror("unable to parse '%s'\n", key); 878 return; 879 } 880 881 if (stale) { 882 purge_tree(&my_root); 883 stale = 0; 884 } 885 node = &my_root; 886 namelen = CTL_MAXNAME; 887 sz = sizeof(gsname); 888 889 if (sysctlgetmibinfo(key, &name[0], &namelen, gsname, &sz, &node, 890 SYSCTL_VERSION) == -1) { 891 if (optional) 892 return; 893 sysctlparseerror(namelen, l); 894 EXIT(EXIT_FAILURE); 895 } 896 897 type = SYSCTL_TYPE(node->sysctl_flags); 898 899 if (value == NULL) { 900 if (dodesc) 901 dflag = 1; 902 print_tree(&name[0], namelen, node, type, 0, re, lastcompiled); 903 if (dodesc) 904 dflag = 0; 905 gsname[0] = '\0'; 906 return; 907 } 908 909 if (fn) 910 trim_whitespace(value, 1); 911 912 if (!wflag) { 913 sysctlperror("Must specify -w to set variables\n"); 914 exit(EXIT_FAILURE); 915 } 916 917 canonicalize(gsname, canonname); 918 if (type != CTLTYPE_NODE && (w = findhandler(canonname, re, 919 lastcompiled)) != NULL) { 920 if (w->ps_w == NULL) { 921 sysctlperror("Cannot write `%s': %s\n", gsname, 922 strerror(EOPNOTSUPP)); 923 exit(EXIT_FAILURE); 924 } 925 (*w->ps_w)(gsname, gdname, value, name, namelen, node, type, 926 __UNCONST(w->ps_d)); 927 gsname[0] = '\0'; 928 return; 929 } 930 931 switch (type) { 932 case CTLTYPE_NODE: 933 /* 934 * XXX old behavior is to print. should we error instead? 935 */ 936 print_tree(&name[0], namelen, node, CTLTYPE_NODE, 1, re, 937 lastcompiled); 938 break; 939 case CTLTYPE_INT: 940 case CTLTYPE_BOOL: 941 case CTLTYPE_QUAD: 942 write_number(&name[0], namelen, node, value); 943 break; 944 case CTLTYPE_STRING: 945 write_string(&name[0], namelen, node, value); 946 break; 947 case CTLTYPE_STRUCT: 948 /* 949 * XXX old behavior is to print. should we error instead? 950 */ 951 /* fprintf(warnfp, "you can't write to %s\n", gsname); */ 952 print_tree(&name[0], namelen, node, type, 0, re, lastcompiled); 953 break; 954 } 955 } 956 957 /* 958 959 //create=foo.bar.whatever..., 960 [type=(int|quad|string|struct|node),] 961 [size=###,] 962 [n=###,] 963 [flags=(iohxparw12),] 964 [addr=0x####,|symbol=...|value=...] 965 966 size is optional for some types. type must be set before anything 967 else. nodes can have [rwhp], but nothing else applies. if no 968 size or type is given, node is asserted. writeable is the default, 969 with [rw] being read-only and unconditionally writeable 970 respectively. if you specify addr, it is assumed to be the name of 971 a kernel symbol, if value, CTLFLAG_OWNDATA will be asserted for 972 strings, CTLFLAG_IMMEDIATE for ints and u_quad_ts. you cannot 973 specify both value and addr. 974 975 */ 976 977 static void 978 parse_create(char *l) 979 { 980 struct sysctlnode node; 981 size_t sz; 982 char *nname, *key, *value, *data, *addr, *c, *t; 983 int name[CTL_MAXNAME], i, rc, method, flags, rw; 984 u_int namelen, type; 985 u_quad_t uq; 986 quad_t q; 987 bool b; 988 989 if (!wflag) { 990 sysctlperror("Must specify -w to create nodes\n"); 991 exit(EXIT_FAILURE); 992 } 993 994 /* 995 * these are the pieces that make up the description of a new 996 * node 997 */ 998 memset(&node, 0, sizeof(node)); 999 node.sysctl_num = CTL_CREATE; /* any number is fine */ 1000 flags = 0; 1001 rw = -1; 1002 type = 0; 1003 sz = 0; 1004 data = addr = NULL; 1005 memset(name, 0, sizeof(name)); 1006 namelen = 0; 1007 method = 0; 1008 1009 /* 1010 * misc stuff used when constructing 1011 */ 1012 i = 0; 1013 b = false; 1014 uq = 0; 1015 key = NULL; 1016 value = NULL; 1017 1018 /* 1019 * the name of the thing we're trying to create is first, so 1020 * pick it off. 1021 */ 1022 nname = l; 1023 if ((c = strchr(nname, ',')) != NULL) 1024 *c++ = '\0'; 1025 1026 while (c != NULL) { 1027 1028 /* 1029 * pull off the next "key=value" pair 1030 */ 1031 key = c; 1032 if ((t = strchr(key, '=')) != NULL) { 1033 *t++ = '\0'; 1034 value = t; 1035 } 1036 else 1037 value = NULL; 1038 1039 /* 1040 * if the "key" is "value", then that eats the rest of 1041 * the string, so we're done, otherwise bite it off at 1042 * the next comma. 1043 */ 1044 if (strcmp(key, "value") == 0) { 1045 c = NULL; 1046 data = value; 1047 break; 1048 } 1049 else if (value) { 1050 if ((c = strchr(value, ',')) != NULL) 1051 *c++ = '\0'; 1052 } 1053 1054 /* 1055 * note that we (mostly) let the invoker of prog_sysctl(8) 1056 * play rampant here and depend on the kernel to tell 1057 * them that they were wrong. well...within reason. 1058 * we later check the various parameters against each 1059 * other to make sure it makes some sort of sense. 1060 */ 1061 if (strcmp(key, "addr") == 0) { 1062 /* 1063 * we can't check these two. only the kernel 1064 * can tell us when it fails to find the name 1065 * (or if the address is invalid). 1066 */ 1067 if (method != 0) { 1068 sysctlperror( 1069 "%s: already have %s for new node\n", 1070 nname, 1071 method == CTL_CREATE ? "addr" : "symbol"); 1072 EXIT(EXIT_FAILURE); 1073 } 1074 if (value == NULL) { 1075 sysctlperror("%s: missing value\n", nname); 1076 EXIT(EXIT_FAILURE); 1077 } 1078 errno = 0; 1079 addr = (void*)strtoul(value, &t, 0); 1080 if (t == value || *t != '\0' || errno != 0) { 1081 sysctlperror( 1082 "%s: '%s' is not a valid address\n", 1083 nname, value); 1084 EXIT(EXIT_FAILURE); 1085 } 1086 method = CTL_CREATE; 1087 } 1088 else if (strcmp(key, "symbol") == 0) { 1089 if (method != 0) { 1090 sysctlperror( 1091 "%s: already have %s for new node\n", 1092 nname, 1093 method == CTL_CREATE ? "addr" : "symbol"); 1094 EXIT(EXIT_FAILURE); 1095 } 1096 addr = value; 1097 method = CTL_CREATESYM; 1098 } 1099 else if (strcmp(key, "type") == 0) { 1100 if (value == NULL) { 1101 sysctlperror("%s: missing value\n", nname); 1102 EXIT(EXIT_FAILURE); 1103 } 1104 if (strcmp(value, "node") == 0) 1105 type = CTLTYPE_NODE; 1106 else if (strcmp(value, "int") == 0) { 1107 sz = sizeof(int); 1108 type = CTLTYPE_INT; 1109 } 1110 else if (strcmp(value, "bool") == 0) { 1111 sz = sizeof(bool); 1112 type = CTLTYPE_BOOL; 1113 } 1114 else if (strcmp(value, "string") == 0) 1115 type = CTLTYPE_STRING; 1116 else if (strcmp(value, "quad") == 0) { 1117 sz = sizeof(u_quad_t); 1118 type = CTLTYPE_QUAD; 1119 } 1120 else if (strcmp(value, "struct") == 0) 1121 type = CTLTYPE_STRUCT; 1122 else { 1123 sysctlperror( 1124 "%s: '%s' is not a valid type\n", 1125 nname, value); 1126 EXIT(EXIT_FAILURE); 1127 } 1128 } 1129 else if (strcmp(key, "size") == 0) { 1130 if (value == NULL) { 1131 sysctlperror("%s: missing value\n", nname); 1132 EXIT(EXIT_FAILURE); 1133 } 1134 errno = 0; 1135 /* 1136 * yes, i know size_t is not an unsigned long, 1137 * but we can all agree that it ought to be, 1138 * right? 1139 */ 1140 sz = strtoul(value, &t, 0); 1141 if (t == value || *t != '\0' || errno != 0) { 1142 sysctlperror( 1143 "%s: '%s' is not a valid size\n", 1144 nname, value); 1145 EXIT(EXIT_FAILURE); 1146 } 1147 } 1148 else if (strcmp(key, "n") == 0) { 1149 if (value == NULL) { 1150 sysctlperror("%s: missing value\n", nname); 1151 EXIT(EXIT_FAILURE); 1152 } 1153 errno = 0; 1154 q = strtoll(value, &t, 0); 1155 if (t == value || *t != '\0' || errno != 0 || 1156 q < INT_MIN || q > UINT_MAX) { 1157 sysctlperror( 1158 "%s: '%s' is not a valid mib number\n", 1159 nname, value); 1160 EXIT(EXIT_FAILURE); 1161 } 1162 node.sysctl_num = (int)q; 1163 } 1164 else if (strcmp(key, "flags") == 0) { 1165 if (value == NULL) { 1166 sysctlperror("%s: missing value\n", nname); 1167 EXIT(EXIT_FAILURE); 1168 } 1169 t = value; 1170 while (*t != '\0') { 1171 switch (*t) { 1172 case 'a': 1173 flags |= CTLFLAG_ANYWRITE; 1174 break; 1175 case 'h': 1176 flags |= CTLFLAG_HIDDEN; 1177 break; 1178 case 'i': 1179 flags |= CTLFLAG_IMMEDIATE; 1180 break; 1181 case 'o': 1182 flags |= CTLFLAG_OWNDATA; 1183 break; 1184 case 'p': 1185 flags |= CTLFLAG_PRIVATE; 1186 break; 1187 case 'u': 1188 flags |= CTLFLAG_UNSIGNED; 1189 break; 1190 case 'x': 1191 flags |= CTLFLAG_HEX; 1192 break; 1193 1194 case 'r': 1195 rw = CTLFLAG_READONLY; 1196 break; 1197 case 'w': 1198 rw = CTLFLAG_READWRITE; 1199 break; 1200 default: 1201 sysctlperror( 1202 "%s: '%c' is not a valid flag\n", 1203 nname, *t); 1204 EXIT(EXIT_FAILURE); 1205 } 1206 t++; 1207 } 1208 } 1209 else { 1210 sysctlperror("%s: unrecognized keyword '%s'\n", 1211 nname, key); 1212 EXIT(EXIT_FAILURE); 1213 } 1214 } 1215 1216 /* 1217 * now that we've finished parsing the given string, fill in 1218 * anything they didn't specify 1219 */ 1220 if (type == 0) 1221 type = CTLTYPE_NODE; 1222 1223 /* 1224 * the "data" can be interpreted various ways depending on the 1225 * type of node we're creating, as can the size 1226 */ 1227 if (data != NULL) { 1228 if (addr != NULL) { 1229 sysctlperror( 1230 "%s: cannot specify both value and " 1231 "address\n", nname); 1232 EXIT(EXIT_FAILURE); 1233 } 1234 1235 switch (type) { 1236 case CTLTYPE_INT: 1237 errno = 0; 1238 q = strtoll(data, &t, 0); 1239 if (t == data || *t != '\0' || errno != 0 || 1240 q < INT_MIN || q > UINT_MAX) { 1241 sysctlperror( 1242 "%s: '%s' is not a valid integer\n", 1243 nname, value); 1244 EXIT(EXIT_FAILURE); 1245 } 1246 i = (int)q; 1247 if (!(flags & CTLFLAG_OWNDATA)) { 1248 flags |= CTLFLAG_IMMEDIATE; 1249 node.sysctl_idata = i; 1250 } 1251 else 1252 node.sysctl_data = &i; 1253 if (sz == 0) 1254 sz = sizeof(int); 1255 break; 1256 case CTLTYPE_BOOL: 1257 errno = 0; 1258 q = strtoll(data, &t, 0); 1259 if (t == data || *t != '\0' || errno != 0 || 1260 (q != 0 && q != 1)) { 1261 sysctlperror( 1262 "%s: '%s' is not a valid bool\n", 1263 nname, value); 1264 EXIT(EXIT_FAILURE); 1265 } 1266 b = q == 1; 1267 if (!(flags & CTLFLAG_OWNDATA)) { 1268 flags |= CTLFLAG_IMMEDIATE; 1269 node.sysctl_idata = b; 1270 } 1271 else 1272 node.sysctl_data = &b; 1273 if (sz == 0) 1274 sz = sizeof(bool); 1275 break; 1276 case CTLTYPE_STRING: 1277 flags |= CTLFLAG_OWNDATA; 1278 node.sysctl_data = data; 1279 if (sz == 0) 1280 sz = strlen(data) + 1; 1281 else if (sz < strlen(data) + 1) { 1282 sysctlperror("%s: ignoring size=%zu for " 1283 "string node, too small for given " 1284 "value\n", nname, sz); 1285 sz = strlen(data) + 1; 1286 } 1287 break; 1288 case CTLTYPE_QUAD: 1289 errno = 0; 1290 uq = strtouq(data, &t, 0); 1291 if (t == data || *t != '\0' || errno != 0) { 1292 sysctlperror( 1293 "%s: '%s' is not a valid quad\n", 1294 nname, value); 1295 EXIT(EXIT_FAILURE); 1296 } 1297 if (!(flags & CTLFLAG_OWNDATA)) { 1298 flags |= CTLFLAG_IMMEDIATE; 1299 node.sysctl_qdata = uq; 1300 } 1301 else 1302 node.sysctl_data = &uq; 1303 if (sz == 0) 1304 sz = sizeof(u_quad_t); 1305 break; 1306 case CTLTYPE_STRUCT: 1307 sysctlperror("%s: struct not initializable\n", 1308 nname); 1309 EXIT(EXIT_FAILURE); 1310 } 1311 1312 /* 1313 * these methods have all provided local starting 1314 * values that the kernel must copy in 1315 */ 1316 } 1317 1318 /* 1319 * hmm...no data, but we have an address of data. that's 1320 * fine. 1321 */ 1322 else if (addr != 0) 1323 node.sysctl_data = (void*)addr; 1324 1325 /* 1326 * no data and no address? well...okay. we might be able to 1327 * manage that. 1328 */ 1329 else if (type != CTLTYPE_NODE) { 1330 if (sz == 0) { 1331 sysctlperror( 1332 "%s: need a size or a starting value\n", 1333 nname); 1334 EXIT(EXIT_FAILURE); 1335 } 1336 if (!(flags & CTLFLAG_IMMEDIATE)) 1337 flags |= CTLFLAG_OWNDATA; 1338 } 1339 1340 /* 1341 * now we do a few sanity checks on the description we've 1342 * assembled 1343 */ 1344 if ((flags & CTLFLAG_IMMEDIATE) && 1345 (type == CTLTYPE_STRING || type == CTLTYPE_STRUCT)) { 1346 sysctlperror("%s: cannot make an immediate %s\n", 1347 nname, 1348 (type == CTLTYPE_STRING) ? "string" : "struct"); 1349 EXIT(EXIT_FAILURE); 1350 } 1351 if (type == CTLTYPE_NODE && node.sysctl_data != NULL) { 1352 sysctlperror("%s: nodes do not have data\n", nname); 1353 EXIT(EXIT_FAILURE); 1354 } 1355 1356 /* 1357 * some types must have a particular size 1358 */ 1359 if (sz != 0) { 1360 if ((type == CTLTYPE_INT && sz != sizeof(int)) || 1361 (type == CTLTYPE_BOOL && sz != sizeof(bool)) || 1362 (type == CTLTYPE_QUAD && sz != sizeof(u_quad_t)) || 1363 (type == CTLTYPE_NODE && sz != 0)) { 1364 sysctlperror("%s: wrong size for type\n", nname); 1365 EXIT(EXIT_FAILURE); 1366 } 1367 } 1368 else if (type == CTLTYPE_STRUCT) { 1369 sysctlperror("%s: struct must have size\n", nname); 1370 EXIT(EXIT_FAILURE); 1371 } 1372 1373 /* 1374 * now...if no one said anything yet, we default nodes or 1375 * any type that owns data being writeable, and everything 1376 * else being readonly. 1377 */ 1378 if (rw == -1) { 1379 if (type == CTLTYPE_NODE || 1380 (flags & (CTLFLAG_OWNDATA|CTLFLAG_IMMEDIATE))) 1381 rw = CTLFLAG_READWRITE; 1382 else 1383 rw = CTLFLAG_READONLY; 1384 } 1385 1386 /* 1387 * if a kernel address was specified, that can't be made 1388 * writeable by us. 1389 if (rw != CTLFLAG_READONLY && addr) { 1390 sysctlperror("%s: kernel data can only be readable\n", nname); 1391 EXIT(EXIT_FAILURE); 1392 } 1393 */ 1394 1395 /* 1396 * what separator were they using in the full name of the new 1397 * node? 1398 */ 1399 if ((t = strpbrk(nname, "./")) == NULL) 1400 sep[0] = '.'; 1401 else 1402 sep[0] = t[0]; 1403 sep[1] = '\0'; 1404 1405 /* 1406 * put it all together, now. t'ain't much, is it? 1407 */ 1408 node.sysctl_flags = SYSCTL_VERSION|flags|rw|type; 1409 node.sysctl_size = sz; 1410 t = strrchr(nname, sep[0]); 1411 if (t != NULL) 1412 strlcpy(node.sysctl_name, t + 1, sizeof(node.sysctl_name)); 1413 else 1414 strlcpy(node.sysctl_name, nname, sizeof(node.sysctl_name)); 1415 if (t == nname) 1416 t = NULL; 1417 1418 /* 1419 * if this is a new top-level node, then we don't need to find 1420 * the mib for its parent 1421 */ 1422 if (t == NULL) { 1423 namelen = 0; 1424 gsname[0] = '\0'; 1425 } 1426 1427 /* 1428 * on the other hand, if it's not a top-level node... 1429 */ 1430 else { 1431 namelen = sizeof(name) / sizeof(name[0]); 1432 sz = sizeof(gsname); 1433 *t = '\0'; 1434 rc = sysctlgetmibinfo(nname, &name[0], &namelen, 1435 gsname, &sz, NULL, SYSCTL_VERSION); 1436 *t = sep[0]; 1437 if (rc == -1) { 1438 sysctlparseerror(namelen, nname); 1439 EXIT(EXIT_FAILURE); 1440 } 1441 } 1442 1443 /* 1444 * yes, a new node is being created 1445 */ 1446 if (method != 0) 1447 name[namelen++] = method; 1448 else 1449 name[namelen++] = CTL_CREATE; 1450 1451 sz = sizeof(node); 1452 rc = prog_sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node)); 1453 1454 if (rc == -1) { 1455 sysctlperror("%s: CTL_CREATE failed: %s\n", 1456 nname, strerror(errno)); 1457 EXIT(EXIT_FAILURE); 1458 } 1459 else { 1460 if (!qflag && !nflag) 1461 printf("%s(%s): (created)\n", nname, st(type)); 1462 stale = 1; 1463 } 1464 } 1465 1466 static void 1467 parse_destroy(char *l) 1468 { 1469 struct sysctlnode node; 1470 size_t sz; 1471 int name[CTL_MAXNAME], rc; 1472 u_int namelen; 1473 1474 if (!wflag) { 1475 sysctlperror("Must specify -w to destroy nodes\n"); 1476 exit(EXIT_FAILURE); 1477 } 1478 1479 memset(name, 0, sizeof(name)); 1480 namelen = sizeof(name) / sizeof(name[0]); 1481 sz = sizeof(gsname); 1482 rc = sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL, 1483 SYSCTL_VERSION); 1484 if (rc == -1) { 1485 sysctlparseerror(namelen, l); 1486 EXIT(EXIT_FAILURE); 1487 } 1488 1489 memset(&node, 0, sizeof(node)); 1490 node.sysctl_flags = SYSCTL_VERSION; 1491 node.sysctl_num = name[namelen - 1]; 1492 name[namelen - 1] = CTL_DESTROY; 1493 1494 sz = sizeof(node); 1495 rc = prog_sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node)); 1496 1497 if (rc == -1) { 1498 sysctlperror("%s: CTL_DESTROY failed: %s\n", 1499 l, strerror(errno)); 1500 EXIT(EXIT_FAILURE); 1501 } 1502 else { 1503 if (!qflag && !nflag) 1504 printf("%s(%s): (destroyed)\n", gsname, 1505 st(SYSCTL_TYPE(node.sysctl_flags))); 1506 stale = 1; 1507 } 1508 } 1509 1510 static void 1511 parse_describe(char *l) 1512 { 1513 struct sysctlnode newdesc; 1514 char buf[1024], *value; 1515 struct sysctldesc *d = (void*)&buf[0]; 1516 int name[CTL_MAXNAME], rc; 1517 u_int namelen; 1518 size_t sz; 1519 1520 if (!wflag) { 1521 sysctlperror("Must specify -w to set descriptions\n"); 1522 exit(EXIT_FAILURE); 1523 } 1524 1525 value = strchr(l, '='); 1526 *value++ = '\0'; 1527 1528 memset(name, 0, sizeof(name)); 1529 namelen = sizeof(name) / sizeof(name[0]); 1530 sz = sizeof(gsname); 1531 rc = sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL, 1532 SYSCTL_VERSION); 1533 if (rc == -1) { 1534 sysctlparseerror(namelen, l); 1535 EXIT(EXIT_FAILURE); 1536 } 1537 1538 sz = sizeof(buf); 1539 memset(&newdesc, 0, sizeof(newdesc)); 1540 newdesc.sysctl_flags = SYSCTL_VERSION|CTLFLAG_OWNDESC; 1541 newdesc.sysctl_num = name[namelen - 1]; 1542 newdesc.sysctl_desc = value; 1543 name[namelen - 1] = CTL_DESCRIBE; 1544 rc = prog_sysctl(name, namelen, d, &sz, &newdesc, sizeof(newdesc)); 1545 if (rc == -1) 1546 sysctlperror("%s: CTL_DESCRIBE failed: %s\n", 1547 gsname, strerror(errno)); 1548 else if (d->descr_len == 1) 1549 sysctlperror("%s: description not set\n", gsname); 1550 else if (!qflag && !nflag) 1551 printf("%s: %s\n", gsname, d->descr_str); 1552 } 1553 1554 /* 1555 * ******************************************************************** 1556 * when things go wrong... 1557 * ******************************************************************** 1558 */ 1559 static void 1560 usage(void) 1561 { 1562 const char *progname = getprogname(); 1563 1564 (void)fprintf(stderr, 1565 "usage:\t%s %s\n" 1566 "\t%s %s\n" 1567 "\t%s %s\n" 1568 "\t%s %s\n" 1569 "\t%s %s\n" 1570 "\t%s %s\n", 1571 progname, "[-dneq] [-x[x]|-r] variable ...", 1572 progname, "[-ne] [-q] -w variable=value ...", 1573 progname, "[-dne] -a", 1574 progname, "[-dne] -A", 1575 progname, "[-ne] -M", 1576 progname, "[-dne] [-q] -f file"); 1577 exit(EXIT_FAILURE); 1578 } 1579 1580 static void 1581 getdesc1(int *name, u_int namelen, struct sysctlnode *pnode) 1582 { 1583 struct sysctlnode node; 1584 char buf[1024], *desc; 1585 struct sysctldesc *d = (void*)buf; 1586 size_t sz = sizeof(buf); 1587 int rc; 1588 1589 memset(&node, 0, sizeof(node)); 1590 node.sysctl_flags = SYSCTL_VERSION; 1591 node.sysctl_num = name[namelen - 1]; 1592 name[namelen - 1] = CTL_DESCRIBE; 1593 rc = prog_sysctl(name, namelen, d, &sz, &node, sizeof(node)); 1594 1595 if (rc == -1 || 1596 d->descr_len == 1 || 1597 d->descr_num != pnode->sysctl_num || 1598 d->descr_ver != pnode->sysctl_ver) 1599 desc = (char *)-1; 1600 else 1601 desc = malloc(d->descr_len); 1602 1603 if (desc == NULL) 1604 desc = (char *)-1; 1605 if (desc != (char *)-1) 1606 memcpy(desc, &d->descr_str[0], d->descr_len); 1607 name[namelen - 1] = node.sysctl_num; 1608 if (pnode->sysctl_desc != NULL && 1609 pnode->sysctl_desc != (const char *)-1) 1610 free(__UNCONST(pnode->sysctl_desc)); 1611 pnode->sysctl_desc = desc; 1612 } 1613 1614 static void 1615 getdesc(int *name, u_int namelen, struct sysctlnode *pnode) 1616 { 1617 struct sysctlnode *node = pnode->sysctl_child; 1618 struct sysctldesc *d, *p, *plim; 1619 char *desc; 1620 size_t i, sz, child_cnt; 1621 int rc; 1622 1623 sz = 128 * pnode->sysctl_clen; 1624 name[namelen] = CTL_DESCRIBE; 1625 1626 /* 1627 * attempt *twice* to get the description chunk. if two tries 1628 * doesn't work, give up. 1629 */ 1630 i = 0; 1631 do { 1632 d = malloc(sz); 1633 if (d == NULL) 1634 return; 1635 rc = prog_sysctl(name, namelen + 1, d, &sz, NULL, 0); 1636 if (rc == -1) { 1637 free(d); 1638 d = NULL; 1639 if (i == 0 && errno == ENOMEM) 1640 i = 1; 1641 else 1642 return; 1643 } 1644 } while (d == NULL); 1645 1646 /* 1647 * hokey nested loop here, giving O(n**2) behavior, but should 1648 * suffice for now 1649 */ 1650 plim = /*LINTED ptr cast*/(struct sysctldesc *)((char*)d + sz); 1651 child_cnt = (pnode->sysctl_flags & CTLTYPE_NODE) ? pnode->sysctl_clen 1652 : 0; 1653 for (i = 0; i < child_cnt; i++) { 1654 node = &pnode->sysctl_child[i]; 1655 for (p = d; p < plim; p = NEXT_DESCR(p)) 1656 if (node->sysctl_num == p->descr_num) 1657 break; 1658 if (p < plim && node->sysctl_ver == p->descr_ver) { 1659 /* 1660 * match found, attempt to attach description 1661 */ 1662 if (p->descr_len == 1) 1663 desc = NULL; 1664 else 1665 desc = malloc(p->descr_len); 1666 if (desc == NULL) 1667 desc = (char *)-1; 1668 else 1669 memcpy(desc, &p->descr_str[0], p->descr_len); 1670 node->sysctl_desc = desc; 1671 } 1672 } 1673 1674 free(d); 1675 } 1676 1677 static void 1678 trim_whitespace(char *s, int dir) 1679 { 1680 char *i, *o; 1681 1682 i = o = s; 1683 if (dir & 1) 1684 while (isspace((unsigned char)*i)) 1685 i++; 1686 while ((*o++ = *i++) != '\0'); 1687 o -= 2; /* already past nul, skip back to before it */ 1688 if (dir & 2) 1689 while (o > s && isspace((unsigned char)*o)) 1690 *o-- = '\0'; 1691 } 1692 1693 void 1694 sysctlerror(int soft) 1695 { 1696 if (soft) { 1697 switch (errno) { 1698 case ENOENT: 1699 case ENOPROTOOPT: 1700 case ENOTDIR: 1701 case EINVAL: 1702 case EOPNOTSUPP: 1703 case EPROTONOSUPPORT: 1704 if (Aflag || req) 1705 sysctlperror("%s: the value is not available " 1706 "(%s)\n", gsname, strerror(errno)); 1707 return; 1708 } 1709 } 1710 1711 if (Aflag || req) 1712 sysctlperror("%s: %s\n", gsname, strerror(errno)); 1713 if (!soft) 1714 EXIT(EXIT_FAILURE); 1715 } 1716 1717 void 1718 sysctlparseerror(u_int namelen, const char *pname) 1719 { 1720 1721 if (qflag) { 1722 errs++; 1723 return; 1724 } 1725 sysctlperror("%s level name '%s' in '%s' is invalid\n", 1726 lname[namelen], gsname, pname); 1727 } 1728 1729 static void 1730 sysctlperror(const char *fmt, ...) 1731 { 1732 va_list ap; 1733 1734 (void)fprintf(warnfp, "%s: ", getprogname()); 1735 if (fn) 1736 (void)fprintf(warnfp, "%s#%zu: ", fn, nr); 1737 va_start(ap, fmt); 1738 (void)vfprintf(warnfp, fmt, ap); 1739 va_end(ap); 1740 errs++; 1741 } 1742 1743 1744 /* 1745 * ******************************************************************** 1746 * how to write to a "simple" node 1747 * ******************************************************************** 1748 */ 1749 static void 1750 write_number(int *name, u_int namelen, struct sysctlnode *node, char *value) 1751 { 1752 u_int ii, io; 1753 u_quad_t qi, qo; 1754 size_t si, so; 1755 bool bi, bo; 1756 int rc; 1757 void *i, *o; 1758 char *t; 1759 1760 if (fn) 1761 trim_whitespace(value, 3); 1762 1763 si = so = 0; 1764 i = o = NULL; 1765 bi = bo = false; 1766 errno = 0; 1767 qi = strtouq(value, &t, 0); 1768 if (qi == UQUAD_MAX && errno == ERANGE) { 1769 sysctlperror("%s: %s\n", value, strerror(errno)); 1770 EXIT(EXIT_FAILURE); 1771 } 1772 if (t == value || *t != '\0') { 1773 sysctlperror("%s: not a number\n", value); 1774 EXIT(EXIT_FAILURE); 1775 } 1776 1777 switch (SYSCTL_TYPE(node->sysctl_flags)) { 1778 case CTLTYPE_INT: 1779 ii = (u_int)qi; 1780 io = (u_int)(qi >> 32); 1781 if (io != (u_int)-1 && io != 0) { 1782 sysctlperror("%s: %s\n", value, strerror(ERANGE)); 1783 EXIT(EXIT_FAILURE); 1784 } 1785 o = &io; 1786 so = sizeof(io); 1787 i = ⅈ 1788 si = sizeof(ii); 1789 break; 1790 case CTLTYPE_BOOL: 1791 bi = (bool)qi; 1792 o = &bo; 1793 so = sizeof(bo); 1794 i = &bi; 1795 si = sizeof(bi); 1796 break; 1797 case CTLTYPE_QUAD: 1798 o = &qo; 1799 so = sizeof(qo); 1800 i = &qi; 1801 si = sizeof(qi); 1802 break; 1803 } 1804 1805 rc = prog_sysctl(name, namelen, o, &so, i, si); 1806 if (rc == -1) { 1807 sysctlerror(0); 1808 return; 1809 } 1810 1811 switch (SYSCTL_TYPE(node->sysctl_flags)) { 1812 case CTLTYPE_INT: 1813 display_number(node, gsname, &io, sizeof(io), DISPLAY_OLD); 1814 display_number(node, gsname, &ii, sizeof(ii), DISPLAY_NEW); 1815 break; 1816 case CTLTYPE_BOOL: 1817 display_number(node, gsname, &bo, sizeof(bo), DISPLAY_OLD); 1818 display_number(node, gsname, &bi, sizeof(bi), DISPLAY_NEW); 1819 break; 1820 case CTLTYPE_QUAD: 1821 display_number(node, gsname, &qo, sizeof(qo), DISPLAY_OLD); 1822 display_number(node, gsname, &qi, sizeof(qi), DISPLAY_NEW); 1823 break; 1824 } 1825 } 1826 1827 static void 1828 write_string(int *name, u_int namelen, struct sysctlnode *node, char *value) 1829 { 1830 char *i, *o; 1831 size_t si, so; 1832 int rc; 1833 1834 i = value; 1835 si = strlen(i) + 1; 1836 so = node->sysctl_size; 1837 if (si > so && so != 0) { 1838 sysctlperror("%s: string too long\n", value); 1839 EXIT(EXIT_FAILURE); 1840 } 1841 o = malloc(so); 1842 if (o == NULL) { 1843 sysctlperror("%s: !malloc failed!\n", gsname); 1844 exit(EXIT_FAILURE); 1845 } 1846 1847 rc = prog_sysctl(name, namelen, o, &so, i, si); 1848 if (rc == -1) { 1849 sysctlerror(0); 1850 return; 1851 } 1852 1853 display_string(node, gsname, o, so, DISPLAY_OLD); 1854 display_string(node, gsname, i, si, DISPLAY_NEW); 1855 free(o); 1856 } 1857 1858 /* 1859 * ******************************************************************** 1860 * simple ways to print stuff consistently 1861 * ******************************************************************** 1862 */ 1863 static void 1864 display_number(const struct sysctlnode *node, const char *name, 1865 const void *data, size_t sz, int n) 1866 { 1867 u_quad_t q; 1868 bool b; 1869 int i; 1870 1871 if (qflag) 1872 return; 1873 if ((nflag || rflag) && (n == DISPLAY_OLD)) 1874 return; 1875 1876 if (rflag && n != DISPLAY_OLD) { 1877 fwrite(data, sz, 1, stdout); 1878 return; 1879 } 1880 1881 if (!nflag) { 1882 if (n == DISPLAY_VALUE) 1883 printf("%s%s", name, eq); 1884 else if (n == DISPLAY_OLD) 1885 printf("%s: ", name); 1886 } 1887 1888 if (xflag > 1) { 1889 if (n != DISPLAY_NEW) 1890 printf("\n"); 1891 hex_dump(data, sz); 1892 return; 1893 } 1894 1895 switch (SYSCTL_TYPE(node->sysctl_flags)) { 1896 case CTLTYPE_INT: 1897 memcpy(&i, data, sz); 1898 if (xflag) 1899 printf("0x%0*x", (int)sz * 2, i); 1900 else if (node->sysctl_flags & CTLFLAG_HEX) 1901 printf("%#x", i); 1902 else if (node->sysctl_flags & CTLFLAG_UNSIGNED) 1903 printf("%u", i); 1904 else 1905 printf("%d", i); 1906 break; 1907 case CTLTYPE_BOOL: 1908 memcpy(&b, data, sz); 1909 if (xflag) 1910 printf("0x%0*x", (int)sz * 2, b); 1911 else if (node->sysctl_flags & CTLFLAG_HEX) 1912 printf("%#x", b); 1913 else 1914 printf("%d", b); 1915 break; 1916 case CTLTYPE_QUAD: 1917 memcpy(&q, data, sz); 1918 if (xflag) 1919 printf("0x%0*" PRIx64, (int)sz * 2, q); 1920 else if (node->sysctl_flags & CTLFLAG_HEX) 1921 printf("%#" PRIx64, q); 1922 else if (node->sysctl_flags & CTLFLAG_UNSIGNED) 1923 printf("%" PRIu64, q); 1924 else 1925 printf("%" PRIu64, q); 1926 break; 1927 } 1928 1929 if (n == DISPLAY_OLD) 1930 printf(" -> "); 1931 else 1932 printf("\n"); 1933 } 1934 1935 static void 1936 display_string(const struct sysctlnode *node, const char *name, 1937 const void *data, size_t sz, int n) 1938 { 1939 const unsigned char *buf = data; 1940 int ni; 1941 1942 if (qflag) 1943 return; 1944 if ((nflag || rflag) && (n == DISPLAY_OLD)) 1945 return; 1946 1947 if (rflag && n != DISPLAY_OLD) { 1948 fwrite(data, sz, 1, stdout); 1949 return; 1950 } 1951 1952 if (!nflag) { 1953 if (n == DISPLAY_VALUE) 1954 printf("%s%s", name, eq); 1955 else if (n == DISPLAY_OLD) 1956 printf("%s: ", name); 1957 } 1958 1959 if (xflag > 1) { 1960 if (n != DISPLAY_NEW) 1961 printf("\n"); 1962 hex_dump(data, sz); 1963 return; 1964 } 1965 1966 if (xflag || node->sysctl_flags & CTLFLAG_HEX) { 1967 for (ni = 0; ni < (int)sz; ni++) { 1968 if (xflag) 1969 printf("%02x", buf[ni]); 1970 if (buf[ni] == '\0') 1971 break; 1972 if (!xflag) 1973 printf("\\x%2.2x", buf[ni]); 1974 } 1975 } 1976 else 1977 printf("%.*s", (int)sz, buf); 1978 1979 if (n == DISPLAY_OLD) 1980 printf(" -> "); 1981 else 1982 printf("\n"); 1983 } 1984 1985 /*ARGSUSED*/ 1986 static void 1987 display_struct(const struct sysctlnode *node, const char *name, 1988 const void *data, size_t sz, int n) 1989 { 1990 const unsigned char *buf = data; 1991 int ni; 1992 size_t more; 1993 1994 if (qflag) 1995 return; 1996 if (!(xflag || rflag)) { 1997 if (Aflag || req) 1998 sysctlperror( 1999 "%s: this type is unknown to this program\n", 2000 gsname); 2001 return; 2002 } 2003 if ((nflag || rflag) && (n == DISPLAY_OLD)) 2004 return; 2005 2006 if (rflag && n != DISPLAY_OLD) { 2007 fwrite(data, sz, 1, stdout); 2008 return; 2009 } 2010 2011 if (!nflag) { 2012 if (n == DISPLAY_VALUE) 2013 printf("%s%s", name, eq); 2014 else if (n == DISPLAY_OLD) 2015 printf("%s: ", name); 2016 } 2017 2018 if (xflag > 1) { 2019 if (n != DISPLAY_NEW) 2020 printf("\n"); 2021 hex_dump(data, sz); 2022 return; 2023 } 2024 2025 if (sz > 16) { 2026 more = sz - 16; 2027 sz = 16; 2028 } 2029 else 2030 more = 0; 2031 for (ni = 0; ni < (int)sz; ni++) 2032 printf("%02x", buf[ni]); 2033 if (more) 2034 printf("...(%zu more bytes)", more); 2035 printf("\n"); 2036 } 2037 2038 static void 2039 hex_dump(const unsigned char *buf, size_t len) 2040 { 2041 unsigned int i; 2042 int j; 2043 char line[80], tmp[12]; 2044 2045 memset(line, ' ', sizeof(line)); 2046 for (i = 0, j = 15; i < len; i++) { 2047 j = i % 16; 2048 /* reset line */ 2049 if (j == 0) { 2050 line[58] = '|'; 2051 line[77] = '|'; 2052 line[78] = 0; 2053 snprintf(tmp, sizeof(tmp), "%07x", i); 2054 memcpy(&line[0], tmp, 7); 2055 } 2056 /* copy out hex version of byte */ 2057 snprintf(tmp, sizeof(tmp), "%02x", buf[i]); 2058 memcpy(&line[9 + j * 3], tmp, 2); 2059 /* copy out plain version of byte */ 2060 line[60 + j] = (isprint(buf[i])) ? buf[i] : '.'; 2061 /* print a full line and erase it */ 2062 if (j == 15) { 2063 printf("%s\n", line); 2064 memset(line, ' ', sizeof(line)); 2065 } 2066 } 2067 if (line[0] != ' ') 2068 printf("%s\n", line); 2069 printf("%07zu bytes\n", len); 2070 } 2071 2072 /* 2073 * ******************************************************************** 2074 * functions that handle particular nodes 2075 * ******************************************************************** 2076 */ 2077 /*ARGSUSED*/ 2078 static void 2079 printother(HANDLER_ARGS) 2080 { 2081 int rc; 2082 void *p; 2083 size_t sz1, sz2; 2084 2085 if (!(Aflag || req) || Mflag) 2086 return; 2087 2088 /* 2089 * okay...you asked for it, so let's give it a go 2090 */ 2091 while (type != CTLTYPE_NODE && (xflag || rflag)) { 2092 rc = prog_sysctl(name, namelen, NULL, &sz1, NULL, 0); 2093 if (rc == -1 || sz1 == 0) 2094 break; 2095 p = malloc(sz1); 2096 if (p == NULL) 2097 break; 2098 sz2 = sz1; 2099 rc = prog_sysctl(name, namelen, p, &sz2, NULL, 0); 2100 if (rc == -1 || sz1 != sz2) { 2101 free(p); 2102 break; 2103 } 2104 display_struct(pnode, gsname, p, sz1, DISPLAY_VALUE); 2105 free(p); 2106 return; 2107 } 2108 2109 /* 2110 * that didn't work...do we have a specific message for this 2111 * thing? 2112 */ 2113 if (v != NULL) { 2114 sysctlperror("%s: use '%s' to view this information\n", 2115 gsname, (const char *)v); 2116 return; 2117 } 2118 2119 /* 2120 * hmm...i wonder if we have any generic hints? 2121 */ 2122 switch (name[0]) { 2123 case CTL_NET: 2124 sysctlperror("%s: use 'netstat' to view this information\n", 2125 sname); 2126 break; 2127 case CTL_DEBUG: 2128 sysctlperror("%s: missing 'options DEBUG' from kernel?\n", 2129 sname); 2130 break; 2131 case CTL_DDB: 2132 sysctlperror("%s: missing 'options DDB' from kernel?\n", 2133 sname); 2134 break; 2135 case CTL_VENDOR: 2136 sysctlperror("%s: no vendor extensions installed\n", 2137 sname); 2138 break; 2139 } 2140 } 2141 2142 /*ARGSUSED*/ 2143 static void 2144 kern_clockrate(HANDLER_ARGS) 2145 { 2146 struct clockinfo clkinfo; 2147 size_t sz; 2148 int rc; 2149 2150 sz = sizeof(clkinfo); 2151 rc = prog_sysctl(name, namelen, &clkinfo, &sz, NULL, 0); 2152 if (rc == -1) { 2153 sysctlerror(1); 2154 return; 2155 } 2156 if (sz != sizeof(clkinfo)) 2157 errx(EXIT_FAILURE, "%s: !returned size wrong!", sname); 2158 2159 if (xflag || rflag) { 2160 display_struct(pnode, sname, &clkinfo, sz, 2161 DISPLAY_VALUE); 2162 return; 2163 } 2164 else if (!nflag) 2165 printf("%s: ", sname); 2166 printf("tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n", 2167 clkinfo.tick, clkinfo.tickadj, 2168 clkinfo.hz, clkinfo.profhz, clkinfo.stathz); 2169 } 2170 2171 /*ARGSUSED*/ 2172 static void 2173 kern_boottime(HANDLER_ARGS) 2174 { 2175 struct timeval timeval; 2176 time_t boottime; 2177 size_t sz; 2178 int rc; 2179 2180 sz = sizeof(timeval); 2181 rc = prog_sysctl(name, namelen, &timeval, &sz, NULL, 0); 2182 if (rc == -1) { 2183 sysctlerror(1); 2184 return; 2185 } 2186 if (sz != sizeof(timeval)) 2187 errx(EXIT_FAILURE, "%s: !returned size wrong!", sname); 2188 2189 boottime = timeval.tv_sec; 2190 if (xflag || rflag) 2191 display_struct(pnode, sname, &timeval, sz, 2192 DISPLAY_VALUE); 2193 else if (!nflag) 2194 /* ctime() provides the \n */ 2195 printf("%s%s%s", sname, eq, ctime(&boottime)); 2196 else if (nflag == 1) 2197 printf("%ld\n", (long)boottime); 2198 else 2199 printf("%ld.%06ld\n", (long)timeval.tv_sec, 2200 (long)timeval.tv_usec); 2201 } 2202 2203 /*ARGSUSED*/ 2204 static void 2205 kern_consdev(HANDLER_ARGS) 2206 { 2207 dev_t cons; 2208 size_t sz; 2209 int rc; 2210 2211 sz = sizeof(cons); 2212 rc = prog_sysctl(name, namelen, &cons, &sz, NULL, 0); 2213 if (rc == -1) { 2214 sysctlerror(1); 2215 return; 2216 } 2217 if (sz != sizeof(cons)) 2218 errx(EXIT_FAILURE, "%s: !returned size wrong!", sname); 2219 2220 if (xflag || rflag) 2221 display_struct(pnode, sname, &cons, sz, 2222 DISPLAY_VALUE); 2223 else { 2224 if (!nflag) 2225 printf("%s%s", sname, eq); 2226 if (nflag < 2 && (sname = devname(cons, S_IFCHR)) != NULL) 2227 printf("%s\n", sname); 2228 else 2229 printf("0x%llx\n", (unsigned long long)cons); 2230 } 2231 } 2232 2233 /*ARGSUSED*/ 2234 static void 2235 kern_cp_time(HANDLER_ARGS) 2236 { 2237 u_int64_t *cp_time; 2238 size_t sz, osz; 2239 int rc, i, n; 2240 char s[sizeof("kern.cp_time.nnnnnn")]; 2241 const char *tname; 2242 2243 /* 2244 * three things to do here. 2245 * case 1: get sum (no Aflag and namelen == 2) 2246 * case 2: get specific processor (namelen == 3) 2247 * case 3: get all processors (Aflag and namelen == 2) 2248 */ 2249 2250 if (namelen == 2 && Aflag) { 2251 sz = sizeof(n); 2252 rc = sysctlbyname("hw.ncpu", &n, &sz, NULL, 0); 2253 if (rc != 0) 2254 return; /* XXX print an error, eh? */ 2255 n++; /* Add on space for the sum. */ 2256 sz = n * sizeof(u_int64_t) * CPUSTATES; 2257 } 2258 else { 2259 n = -1; /* Just print one data set. */ 2260 sz = sizeof(u_int64_t) * CPUSTATES; 2261 } 2262 2263 cp_time = malloc(sz); 2264 if (cp_time == NULL) { 2265 sysctlerror(1); 2266 return; 2267 } 2268 2269 osz = sz; 2270 rc = prog_sysctl(name, namelen, cp_time + (n != -1) * CPUSTATES, &osz, 2271 NULL, 0); 2272 2273 if (rc == -1) { 2274 sysctlerror(1); 2275 free(cp_time); 2276 return; 2277 } 2278 2279 /* 2280 * Check, but account for space we'll occupy with the sum. 2281 */ 2282 if (osz != sz - (n != -1) * CPUSTATES * sizeof(u_int64_t)) 2283 errx(EXIT_FAILURE, "%s: !returned size wrong!", sname); 2284 2285 /* 2286 * Compute the actual sum. Two calls would be easier (we 2287 * could just call ourselves recursively above), but the 2288 * numbers wouldn't add up. 2289 */ 2290 if (n != -1) { 2291 memset(cp_time, 0, sizeof(u_int64_t) * CPUSTATES); 2292 for (i = 1; i < n; i++) { 2293 cp_time[CP_USER] += cp_time[i * CPUSTATES + CP_USER]; 2294 cp_time[CP_NICE] += cp_time[i * CPUSTATES + CP_NICE]; 2295 cp_time[CP_SYS] += cp_time[i * CPUSTATES + CP_SYS]; 2296 cp_time[CP_INTR] += cp_time[i * CPUSTATES + CP_INTR]; 2297 cp_time[CP_IDLE] += cp_time[i * CPUSTATES + CP_IDLE]; 2298 } 2299 } 2300 2301 tname = sname; 2302 for (i = 0; n == -1 || i < n; i++) { 2303 if (i > 0) { 2304 (void)snprintf(s, sizeof(s), "%s%s%d", sname, sep, 2305 i - 1); 2306 tname = s; 2307 } 2308 if (xflag || rflag) 2309 display_struct(pnode, tname, cp_time + (i * CPUSTATES), 2310 sizeof(u_int64_t) * CPUSTATES, 2311 DISPLAY_VALUE); 2312 else { 2313 if (!nflag) 2314 printf("%s: ", tname); 2315 printf("user = %" PRIu64 2316 ", nice = %" PRIu64 2317 ", sys = %" PRIu64 2318 ", intr = %" PRIu64 2319 ", idle = %" PRIu64 2320 "\n", 2321 cp_time[i * CPUSTATES + CP_USER], 2322 cp_time[i * CPUSTATES + CP_NICE], 2323 cp_time[i * CPUSTATES + CP_SYS], 2324 cp_time[i * CPUSTATES + CP_INTR], 2325 cp_time[i * CPUSTATES + CP_IDLE]); 2326 } 2327 /* 2328 * Just printing the one node. 2329 */ 2330 if (n == -1) 2331 break; 2332 } 2333 2334 free(cp_time); 2335 } 2336 2337 /*ARGSUSED*/ 2338 static void 2339 kern_drivers(HANDLER_ARGS) 2340 { 2341 struct kinfo_drivers *kd; 2342 size_t sz, i; 2343 int rc; 2344 const char *comma; 2345 2346 rc = prog_sysctl(name, namelen, NULL, &sz, NULL, 0); 2347 if (rc == -1) { 2348 sysctlerror(1); 2349 return; 2350 } 2351 2352 if (sz % sizeof(*kd)) 2353 err(EXIT_FAILURE, "bad size %zu for kern.drivers", sz); 2354 2355 kd = malloc(sz); 2356 if (kd == NULL) { 2357 sysctlerror(1); 2358 return; 2359 } 2360 2361 rc = prog_sysctl(name, namelen, kd, &sz, NULL, 0); 2362 if (rc == -1) { 2363 sysctlerror(1); 2364 free(kd); 2365 return; 2366 } 2367 2368 comma = ""; 2369 if (!nflag) 2370 printf("%s%s", sname, eq); 2371 for (i = 0, sz /= sizeof(*kd); i < sz; i++) { 2372 (void)printf("%s[%d %d %s]", comma, kd[i].d_cmajor, 2373 kd[i].d_bmajor, kd[i].d_name); 2374 comma = ", "; 2375 } 2376 (void)printf("\n"); 2377 free(kd); 2378 } 2379 2380 /*ARGSUSED*/ 2381 static void 2382 kern_cp_id(HANDLER_ARGS) 2383 { 2384 u_int64_t *cp_id; 2385 size_t sz, osz; 2386 int rc, i, n; 2387 char s[sizeof("kern.cp_id.nnnnnn")]; 2388 const char *tname; 2389 struct sysctlnode node = *pnode; 2390 2391 /* 2392 * three things to do here. 2393 * case 1: print a specific cpu id (namelen == 3) 2394 * case 2: print all cpu ids separately (Aflag set) 2395 * case 3: print all cpu ids on one line 2396 */ 2397 2398 if (namelen == 2) { 2399 sz = sizeof(n); 2400 rc = sysctlbyname("hw.ncpu", &n, &sz, NULL, 0); 2401 if (rc != 0) 2402 return; /* XXX print an error, eh? */ 2403 sz = n * sizeof(u_int64_t); 2404 } 2405 else { 2406 n = -1; /* Just print one cpu id. */ 2407 sz = sizeof(u_int64_t); 2408 } 2409 2410 cp_id = malloc(sz); 2411 if (cp_id == NULL) { 2412 sysctlerror(1); 2413 return; 2414 } 2415 2416 osz = sz; 2417 rc = prog_sysctl(name, namelen, cp_id, &osz, NULL, 0); 2418 if (rc == -1) { 2419 sysctlerror(1); 2420 free(cp_id); 2421 return; 2422 } 2423 2424 /* 2425 * Check that we got back what we asked for. 2426 */ 2427 if (osz != sz) 2428 errx(EXIT_FAILURE, "%s: !returned size wrong!", sname); 2429 2430 /* pretend for output purposes */ 2431 node.sysctl_flags = SYSCTL_FLAGS(pnode->sysctl_flags) | 2432 SYSCTL_TYPE(CTLTYPE_QUAD); 2433 2434 tname = sname; 2435 if (namelen == 3) 2436 display_number(&node, tname, cp_id, 2437 sizeof(u_int64_t), 2438 DISPLAY_VALUE); 2439 else if (Aflag) { 2440 for (i = 0; i < n; i++) 2441 (void)snprintf(s, sizeof(s), "%s%s%d", sname, sep, i); 2442 tname = s; 2443 display_number(&node, tname, &cp_id[i], 2444 sizeof(u_int64_t), 2445 DISPLAY_VALUE); 2446 } 2447 else { 2448 if (xflag || rflag) 2449 display_struct(pnode, tname, cp_id, sz, DISPLAY_VALUE); 2450 else { 2451 if (!nflag) 2452 printf("%s: ", tname); 2453 for (i = 0; i < n; i++) { 2454 if (i) 2455 printf(", "); 2456 printf("%d = %" PRIu64, i, cp_id[i]); 2457 } 2458 printf("\n"); 2459 } 2460 } 2461 2462 free(cp_id); 2463 } 2464 2465 /*ARGSUSED*/ 2466 static void 2467 vm_loadavg(HANDLER_ARGS) 2468 { 2469 struct loadavg loadavg; 2470 size_t sz; 2471 int rc; 2472 2473 sz = sizeof(loadavg); 2474 rc = prog_sysctl(name, namelen, &loadavg, &sz, NULL, 0); 2475 if (rc == -1) { 2476 sysctlerror(1); 2477 return; 2478 } 2479 if (sz != sizeof(loadavg)) 2480 errx(EXIT_FAILURE, "%s: !returned size wrong!", sname); 2481 2482 if (xflag || rflag) { 2483 display_struct(pnode, sname, &loadavg, sz, 2484 DISPLAY_VALUE); 2485 return; 2486 } 2487 if (!nflag) 2488 printf("%s: ", sname); 2489 printf("%.2f %.2f %.2f\n", 2490 (double) loadavg.ldavg[0] / loadavg.fscale, 2491 (double) loadavg.ldavg[1] / loadavg.fscale, 2492 (double) loadavg.ldavg[2] / loadavg.fscale); 2493 } 2494 2495 /*ARGSUSED*/ 2496 static void 2497 proc_limit(HANDLER_ARGS) 2498 { 2499 u_quad_t olim, *newp, nlim; 2500 size_t osz, nsz; 2501 char *t; 2502 int rc; 2503 2504 if (fn) 2505 trim_whitespace(value, 3); 2506 2507 osz = sizeof(olim); 2508 if (value != NULL) { 2509 nsz = sizeof(nlim); 2510 newp = &nlim; 2511 if (strcmp(value, "unlimited") == 0) 2512 nlim = RLIM_INFINITY; 2513 else { 2514 errno = 0; 2515 nlim = strtouq(value, &t, 0); 2516 if (t == value || *t != '\0' || errno != 0) { 2517 sysctlperror("%s: '%s' is not a valid limit\n", 2518 sname, value); 2519 EXIT(EXIT_FAILURE); 2520 } 2521 } 2522 } 2523 else { 2524 nsz = 0; 2525 newp = NULL; 2526 } 2527 2528 rc = prog_sysctl(name, namelen, &olim, &osz, newp, nsz); 2529 if (rc == -1) { 2530 sysctlerror(newp == NULL); 2531 return; 2532 } 2533 2534 if (newp && qflag) 2535 return; 2536 2537 if (rflag || xflag || olim != RLIM_INFINITY) 2538 display_number(pnode, sname, &olim, sizeof(olim), 2539 newp ? DISPLAY_OLD : DISPLAY_VALUE); 2540 else 2541 display_string(pnode, sname, "unlimited", 10, 2542 newp ? DISPLAY_OLD : DISPLAY_VALUE); 2543 2544 if (newp) { 2545 if (rflag || xflag || nlim != RLIM_INFINITY) 2546 display_number(pnode, sname, &nlim, sizeof(nlim), 2547 DISPLAY_NEW); 2548 else 2549 display_string(pnode, sname, "unlimited", 10, 2550 DISPLAY_NEW); 2551 } 2552 } 2553 2554 #ifdef CPU_DISKINFO 2555 /*ARGSUSED*/ 2556 static void 2557 machdep_diskinfo(HANDLER_ARGS) 2558 { 2559 struct disklist *dl; 2560 struct biosdisk_info *bi; 2561 struct nativedisk_info *ni; 2562 int rc; 2563 size_t sz; 2564 uint i, b, lim; 2565 2566 rc = prog_sysctl(name, namelen, NULL, &sz, NULL, 0); 2567 if (rc == -1) { 2568 sysctlerror(1); 2569 return; 2570 } 2571 dl = malloc(sz); 2572 if (dl == NULL) { 2573 sysctlerror(1); 2574 return; 2575 } 2576 rc = prog_sysctl(name, namelen, dl, &sz, NULL, 0); 2577 if (rc == -1) { 2578 sysctlerror(1); 2579 return; 2580 } 2581 2582 if (!nflag) 2583 printf("%s: ", sname); 2584 lim = dl->dl_nbiosdisks; 2585 if (lim > MAX_BIOSDISKS) 2586 lim = MAX_BIOSDISKS; 2587 for (bi = dl->dl_biosdisks, i = 0; i < lim; bi++, i++) 2588 printf("%x:%" PRIu64 "(%d/%d/%d),%x ", 2589 bi->bi_dev, bi->bi_lbasecs, 2590 bi->bi_cyl, bi->bi_head, bi->bi_sec, 2591 bi->bi_flags); 2592 lim = dl->dl_nnativedisks; 2593 ni = dl->dl_nativedisks; 2594 bi = dl->dl_biosdisks; 2595 /* LINTED -- pointer casts are tedious */ 2596 if ((char *)&ni[lim] != (char *)dl + sz) { 2597 sysctlperror("%s: size mismatch\n", gsname); 2598 return; 2599 } 2600 for (i = 0; i < lim; ni++, i++) { 2601 char t = ':'; 2602 printf(" %.*s", (int)sizeof ni->ni_devname, 2603 ni->ni_devname); 2604 for (b = 0; b < (unsigned int)ni->ni_nmatches; t = ',', b++) 2605 printf("%c%x", t, 2606 bi[ni->ni_biosmatches[b]].bi_dev); 2607 } 2608 printf("\n"); 2609 free(dl); 2610 } 2611 #endif /* CPU_DISKINFO */ 2612 2613 /*ARGSUSED*/ 2614 static void 2615 mode_bits(HANDLER_ARGS) 2616 { 2617 char buf[12], outbuf[100]; 2618 int o, m, *newp, rc; 2619 size_t osz, nsz; 2620 mode_t om, mm; 2621 2622 if (fn) 2623 trim_whitespace(value, 3); 2624 2625 newp = NULL; 2626 osz = sizeof(o); 2627 if (value != NULL) { 2628 void *foo; 2629 int tt; 2630 size_t ttsz = sizeof(tt); 2631 mode_t old_umask; 2632 2633 nsz = sizeof(m); 2634 newp = &m; 2635 errno = 0; 2636 rc = prog_sysctl(name, namelen, &tt, &ttsz, NULL, 0); 2637 if (rc == -1) { 2638 sysctlperror("%s: failed query\n", sname); 2639 return; 2640 } 2641 2642 old_umask = umask(0); 2643 foo = setmode(value); 2644 umask(old_umask); 2645 if (foo == NULL) { 2646 sysctlperror("%s: '%s' is an invalid mode\n", sname, 2647 value); 2648 EXIT(EXIT_FAILURE); 2649 } 2650 old_umask = umask(0); 2651 m = getmode(foo, (mode_t)tt); 2652 umask(old_umask); 2653 if (errno) { 2654 sysctlperror("%s: '%s' is an invalid mode\n", sname, 2655 value); 2656 EXIT(EXIT_FAILURE); 2657 } 2658 } 2659 else { 2660 nsz = 0; 2661 newp = NULL; 2662 } 2663 2664 rc = prog_sysctl(name, namelen, &o, &osz, newp, nsz); 2665 if (rc == -1) { 2666 sysctlerror(newp == NULL); 2667 return; 2668 } 2669 2670 if (newp && qflag) 2671 return; 2672 2673 om = (mode_t)o; 2674 mm = (mode_t)m; 2675 2676 if (rflag || xflag) 2677 display_number(pnode, sname, &o, sizeof(o), 2678 newp ? DISPLAY_OLD : DISPLAY_VALUE); 2679 else { 2680 memset(buf, 0, sizeof(buf)); 2681 strmode(om, buf); 2682 rc = snprintf(outbuf, sizeof(outbuf), "%04o (%s)", om, buf + 1); 2683 display_string(pnode, sname, outbuf, rc, newp ? DISPLAY_OLD : DISPLAY_VALUE); 2684 } 2685 2686 if (newp) { 2687 if (rflag || xflag) 2688 display_number(pnode, sname, &m, sizeof(m), 2689 DISPLAY_NEW); 2690 else { 2691 memset(buf, 0, sizeof(buf)); 2692 strmode(mm, buf); 2693 rc = snprintf(outbuf, sizeof(outbuf), "%04o (%s)", mm, buf + 1); 2694 display_string(pnode, sname, outbuf, rc, DISPLAY_NEW); 2695 } 2696 } 2697 } 2698 2699 typedef __BITMAP_TYPE(, uint32_t, 0x10000) bitmap; 2700 2701 static char * 2702 bitmask_print(const bitmap *o) 2703 { 2704 char *s, *os; 2705 2706 s = os = NULL; 2707 for (size_t i = 0; i < MAXPORTS; i++) 2708 if (__BITMAP_ISSET(i, o)) { 2709 int rv; 2710 2711 if (os) 2712 rv = asprintf(&s, "%s,%zu", os, i); 2713 else 2714 rv = asprintf(&s, "%zu", i); 2715 if (rv == -1) 2716 err(EXIT_FAILURE, "%s 1", __func__); 2717 free(os); 2718 os = s; 2719 } 2720 if (s == NULL && (s = strdup("")) == NULL) 2721 err(EXIT_FAILURE, "%s 2", __func__); 2722 return s; 2723 } 2724 2725 static void 2726 bitmask_scan(const void *v, bitmap *o) 2727 { 2728 char *s = strdup(v); 2729 if (s == NULL) 2730 err(EXIT_FAILURE, "%s", __func__); 2731 2732 __BITMAP_ZERO(o); 2733 for (s = strtok(s, ","); s; s = strtok(NULL, ",")) { 2734 char *e; 2735 errno = 0; 2736 unsigned long l = strtoul(s, &e, 0); 2737 if ((l == ULONG_MAX && errno == ERANGE) || s == e || *e) 2738 errx(EXIT_FAILURE, "Invalid port: %s", s); 2739 if (l >= MAXPORTS) 2740 errx(EXIT_FAILURE, "Port out of range: %s", s); 2741 __BITMAP_SET(l, o); 2742 } 2743 } 2744 2745 2746 static void 2747 reserve(HANDLER_ARGS) 2748 { 2749 int rc; 2750 size_t osz, nsz; 2751 bitmap o, n; 2752 2753 if (fn) 2754 trim_whitespace(value, 3); 2755 2756 osz = sizeof(o); 2757 if (value) { 2758 bitmask_scan(value, &n); 2759 value = (char *)&n; 2760 nsz = sizeof(n); 2761 } else 2762 nsz = 0; 2763 2764 rc = prog_sysctl(name, namelen, &o, &osz, value, nsz); 2765 if (rc == -1) { 2766 sysctlerror(value == NULL); 2767 return; 2768 } 2769 2770 if (value && qflag) 2771 return; 2772 2773 if (rflag || xflag) 2774 display_struct(pnode, sname, &o, sizeof(o), 2775 value ? DISPLAY_OLD : DISPLAY_VALUE); 2776 else { 2777 char *s = bitmask_print(&o); 2778 display_string(pnode, sname, s, strlen(s), 2779 value ? DISPLAY_OLD : DISPLAY_VALUE); 2780 free(s); 2781 } 2782 2783 if (value) { 2784 if (rflag || xflag) 2785 display_struct(pnode, sname, &n, sizeof(n), 2786 DISPLAY_NEW); 2787 else { 2788 char *s = bitmask_print(&n); 2789 display_string(pnode, sname, s, strlen(s), DISPLAY_NEW); 2790 free(s); 2791 } 2792 } 2793 } 2794