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