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