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