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