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