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