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