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