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