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