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