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