1 /* $NetBSD: sysctl.c,v 1.142 2012/03/15 02:02:22 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.142 2012/03/15 02:02:22 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 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 'x': 1181 flags |= CTLFLAG_HEX; 1182 break; 1183 1184 case 'r': 1185 rw = CTLFLAG_READONLY; 1186 break; 1187 case 'w': 1188 rw = CTLFLAG_READWRITE; 1189 break; 1190 default: 1191 sysctlperror( 1192 "%s: '%c' is not a valid flag\n", 1193 nname, *t); 1194 EXIT(1); 1195 } 1196 t++; 1197 } 1198 } 1199 else { 1200 sysctlperror("%s: unrecognized keyword '%s'\n", 1201 nname, key); 1202 EXIT(1); 1203 } 1204 } 1205 1206 /* 1207 * now that we've finished parsing the given string, fill in 1208 * anything they didn't specify 1209 */ 1210 if (type == 0) 1211 type = CTLTYPE_NODE; 1212 1213 /* 1214 * the "data" can be interpreted various ways depending on the 1215 * type of node we're creating, as can the size 1216 */ 1217 if (data != NULL) { 1218 if (addr != NULL) { 1219 sysctlperror( 1220 "%s: cannot specify both value and " 1221 "address\n", nname); 1222 EXIT(1); 1223 } 1224 1225 switch (type) { 1226 case CTLTYPE_INT: 1227 errno = 0; 1228 q = strtoll(data, &t, 0); 1229 if (t == data || *t != '\0' || errno != 0 || 1230 q < INT_MIN || q > UINT_MAX) { 1231 sysctlperror( 1232 "%s: '%s' is not a valid integer\n", 1233 nname, value); 1234 EXIT(1); 1235 } 1236 i = (int)q; 1237 if (!(flags & CTLFLAG_OWNDATA)) { 1238 flags |= CTLFLAG_IMMEDIATE; 1239 node.sysctl_idata = i; 1240 } 1241 else 1242 node.sysctl_data = &i; 1243 if (sz == 0) 1244 sz = sizeof(int); 1245 break; 1246 case CTLTYPE_BOOL: 1247 errno = 0; 1248 q = strtoll(data, &t, 0); 1249 if (t == data || *t != '\0' || errno != 0 || 1250 (q != 0 && q != 1)) { 1251 sysctlperror( 1252 "%s: '%s' is not a valid bool\n", 1253 nname, value); 1254 EXIT(1); 1255 } 1256 b = q == 1; 1257 if (!(flags & CTLFLAG_OWNDATA)) { 1258 flags |= CTLFLAG_IMMEDIATE; 1259 node.sysctl_idata = b; 1260 } 1261 else 1262 node.sysctl_data = &b; 1263 if (sz == 0) 1264 sz = sizeof(bool); 1265 break; 1266 case CTLTYPE_STRING: 1267 flags |= CTLFLAG_OWNDATA; 1268 node.sysctl_data = data; 1269 if (sz == 0) 1270 sz = strlen(data) + 1; 1271 else if (sz < strlen(data) + 1) { 1272 sysctlperror("%s: ignoring size=%zu for " 1273 "string node, too small for given " 1274 "value\n", nname, sz); 1275 sz = strlen(data) + 1; 1276 } 1277 break; 1278 case CTLTYPE_QUAD: 1279 errno = 0; 1280 uq = strtouq(data, &t, 0); 1281 if (t == data || *t != '\0' || errno != 0) { 1282 sysctlperror( 1283 "%s: '%s' is not a valid quad\n", 1284 nname, value); 1285 EXIT(1); 1286 } 1287 if (!(flags & CTLFLAG_OWNDATA)) { 1288 flags |= CTLFLAG_IMMEDIATE; 1289 node.sysctl_qdata = uq; 1290 } 1291 else 1292 node.sysctl_data = &uq; 1293 if (sz == 0) 1294 sz = sizeof(u_quad_t); 1295 break; 1296 case CTLTYPE_STRUCT: 1297 sysctlperror("%s: struct not initializable\n", 1298 nname); 1299 EXIT(1); 1300 } 1301 1302 /* 1303 * these methods have all provided local starting 1304 * values that the kernel must copy in 1305 */ 1306 } 1307 1308 /* 1309 * hmm...no data, but we have an address of data. that's 1310 * fine. 1311 */ 1312 else if (addr != 0) 1313 node.sysctl_data = (void*)addr; 1314 1315 /* 1316 * no data and no address? well...okay. we might be able to 1317 * manage that. 1318 */ 1319 else if (type != CTLTYPE_NODE) { 1320 if (sz == 0) { 1321 sysctlperror( 1322 "%s: need a size or a starting value\n", 1323 nname); 1324 EXIT(1); 1325 } 1326 if (!(flags & CTLFLAG_IMMEDIATE)) 1327 flags |= CTLFLAG_OWNDATA; 1328 } 1329 1330 /* 1331 * now we do a few sanity checks on the description we've 1332 * assembled 1333 */ 1334 if ((flags & CTLFLAG_IMMEDIATE) && 1335 (type == CTLTYPE_STRING || type == CTLTYPE_STRUCT)) { 1336 sysctlperror("%s: cannot make an immediate %s\n", 1337 nname, 1338 (type == CTLTYPE_STRING) ? "string" : "struct"); 1339 EXIT(1); 1340 } 1341 if (type == CTLTYPE_NODE && node.sysctl_data != NULL) { 1342 sysctlperror("%s: nodes do not have data\n", nname); 1343 EXIT(1); 1344 } 1345 1346 /* 1347 * some types must have a particular size 1348 */ 1349 if (sz != 0) { 1350 if ((type == CTLTYPE_INT && sz != sizeof(int)) || 1351 (type == CTLTYPE_BOOL && sz != sizeof(bool)) || 1352 (type == CTLTYPE_QUAD && sz != sizeof(u_quad_t)) || 1353 (type == CTLTYPE_NODE && sz != 0)) { 1354 sysctlperror("%s: wrong size for type\n", nname); 1355 EXIT(1); 1356 } 1357 } 1358 else if (type == CTLTYPE_STRUCT) { 1359 sysctlperror("%s: struct must have size\n", nname); 1360 EXIT(1); 1361 } 1362 1363 /* 1364 * now...if no one said anything yet, we default nodes or 1365 * any type that owns data being writeable, and everything 1366 * else being readonly. 1367 */ 1368 if (rw == -1) { 1369 if (type == CTLTYPE_NODE || 1370 (flags & (CTLFLAG_OWNDATA|CTLFLAG_IMMEDIATE))) 1371 rw = CTLFLAG_READWRITE; 1372 else 1373 rw = CTLFLAG_READONLY; 1374 } 1375 1376 /* 1377 * if a kernel address was specified, that can't be made 1378 * writeable by us. 1379 if (rw != CTLFLAG_READONLY && addr) { 1380 sysctlperror("%s: kernel data can only be readable\n", nname); 1381 EXIT(1); 1382 } 1383 */ 1384 1385 /* 1386 * what separator were they using in the full name of the new 1387 * node? 1388 */ 1389 if ((t = strpbrk(nname, "./")) == NULL) 1390 sep[0] = '.'; 1391 else 1392 sep[0] = t[0]; 1393 sep[1] = '\0'; 1394 1395 /* 1396 * put it all together, now. t'ain't much, is it? 1397 */ 1398 node.sysctl_flags = SYSCTL_VERSION|flags|rw|type; 1399 node.sysctl_size = sz; 1400 t = strrchr(nname, sep[0]); 1401 if (t != NULL) 1402 strlcpy(node.sysctl_name, t + 1, sizeof(node.sysctl_name)); 1403 else 1404 strlcpy(node.sysctl_name, nname, sizeof(node.sysctl_name)); 1405 if (t == nname) 1406 t = NULL; 1407 1408 /* 1409 * if this is a new top-level node, then we don't need to find 1410 * the mib for its parent 1411 */ 1412 if (t == NULL) { 1413 namelen = 0; 1414 gsname[0] = '\0'; 1415 } 1416 1417 /* 1418 * on the other hand, if it's not a top-level node... 1419 */ 1420 else { 1421 namelen = sizeof(name) / sizeof(name[0]); 1422 sz = sizeof(gsname); 1423 *t = '\0'; 1424 rc = sysctlgetmibinfo(nname, &name[0], &namelen, 1425 gsname, &sz, NULL, SYSCTL_VERSION); 1426 *t = sep[0]; 1427 if (rc == -1) { 1428 sysctlparseerror(namelen, nname); 1429 EXIT(1); 1430 } 1431 } 1432 1433 /* 1434 * yes, a new node is being created 1435 */ 1436 if (method != 0) 1437 name[namelen++] = method; 1438 else 1439 name[namelen++] = CTL_CREATE; 1440 1441 sz = sizeof(node); 1442 rc = prog_sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node)); 1443 1444 if (rc == -1) { 1445 sysctlperror("%s: CTL_CREATE failed: %s\n", 1446 nname, strerror(errno)); 1447 EXIT(1); 1448 } 1449 else { 1450 if (!qflag && !nflag) 1451 printf("%s(%s): (created)\n", nname, st(type)); 1452 stale = 1; 1453 } 1454 } 1455 1456 static void 1457 parse_destroy(char *l) 1458 { 1459 struct sysctlnode node; 1460 size_t sz; 1461 int name[CTL_MAXNAME], rc; 1462 u_int namelen; 1463 1464 if (!wflag) { 1465 sysctlperror("Must specify -w to destroy nodes\n"); 1466 exit(1); 1467 } 1468 1469 memset(name, 0, sizeof(name)); 1470 namelen = sizeof(name) / sizeof(name[0]); 1471 sz = sizeof(gsname); 1472 rc = sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL, 1473 SYSCTL_VERSION); 1474 if (rc == -1) { 1475 sysctlparseerror(namelen, l); 1476 EXIT(1); 1477 } 1478 1479 memset(&node, 0, sizeof(node)); 1480 node.sysctl_flags = SYSCTL_VERSION; 1481 node.sysctl_num = name[namelen - 1]; 1482 name[namelen - 1] = CTL_DESTROY; 1483 1484 sz = sizeof(node); 1485 rc = prog_sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node)); 1486 1487 if (rc == -1) { 1488 sysctlperror("%s: CTL_DESTROY failed: %s\n", 1489 l, strerror(errno)); 1490 EXIT(1); 1491 } 1492 else { 1493 if (!qflag && !nflag) 1494 printf("%s(%s): (destroyed)\n", gsname, 1495 st(SYSCTL_TYPE(node.sysctl_flags))); 1496 stale = 1; 1497 } 1498 } 1499 1500 static void 1501 parse_describe(char *l) 1502 { 1503 struct sysctlnode newdesc; 1504 char buf[1024], *value; 1505 struct sysctldesc *d = (void*)&buf[0]; 1506 int name[CTL_MAXNAME], rc; 1507 u_int namelen; 1508 size_t sz; 1509 1510 if (!wflag) { 1511 sysctlperror("Must specify -w to set descriptions\n"); 1512 exit(1); 1513 } 1514 1515 value = strchr(l, '='); 1516 *value++ = '\0'; 1517 1518 memset(name, 0, sizeof(name)); 1519 namelen = sizeof(name) / sizeof(name[0]); 1520 sz = sizeof(gsname); 1521 rc = sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL, 1522 SYSCTL_VERSION); 1523 if (rc == -1) { 1524 sysctlparseerror(namelen, l); 1525 EXIT(1); 1526 } 1527 1528 sz = sizeof(buf); 1529 memset(&newdesc, 0, sizeof(newdesc)); 1530 newdesc.sysctl_flags = SYSCTL_VERSION|CTLFLAG_OWNDESC; 1531 newdesc.sysctl_num = name[namelen - 1]; 1532 newdesc.sysctl_desc = value; 1533 name[namelen - 1] = CTL_DESCRIBE; 1534 rc = prog_sysctl(name, namelen, d, &sz, &newdesc, sizeof(newdesc)); 1535 if (rc == -1) 1536 sysctlperror("%s: CTL_DESCRIBE failed: %s\n", 1537 gsname, strerror(errno)); 1538 else if (d->descr_len == 1) 1539 sysctlperror("%s: description not set\n", gsname); 1540 else if (!qflag && !nflag) 1541 printf("%s: %s\n", gsname, d->descr_str); 1542 } 1543 1544 /* 1545 * ******************************************************************** 1546 * when things go wrong... 1547 * ******************************************************************** 1548 */ 1549 static void 1550 usage(void) 1551 { 1552 const char *progname = getprogname(); 1553 1554 (void)fprintf(stderr, 1555 "usage:\t%s %s\n" 1556 "\t%s %s\n" 1557 "\t%s %s\n" 1558 "\t%s %s\n" 1559 "\t%s %s\n" 1560 "\t%s %s\n", 1561 progname, "[-dneq] [-x[x]|-r] variable ...", 1562 progname, "[-ne] [-q] -w variable=value ...", 1563 progname, "[-dne] -a", 1564 progname, "[-dne] -A", 1565 progname, "[-ne] -M", 1566 progname, "[-dne] [-q] -f file"); 1567 exit(1); 1568 } 1569 1570 static void 1571 getdesc1(int *name, u_int namelen, struct sysctlnode *pnode) 1572 { 1573 struct sysctlnode node; 1574 char buf[1024], *desc; 1575 struct sysctldesc *d = (void*)buf; 1576 size_t sz = sizeof(buf); 1577 int rc; 1578 1579 memset(&node, 0, sizeof(node)); 1580 node.sysctl_flags = SYSCTL_VERSION; 1581 node.sysctl_num = name[namelen - 1]; 1582 name[namelen - 1] = CTL_DESCRIBE; 1583 rc = prog_sysctl(name, namelen, d, &sz, &node, sizeof(node)); 1584 1585 if (rc == -1 || 1586 d->descr_len == 1 || 1587 d->descr_num != pnode->sysctl_num || 1588 d->descr_ver != pnode->sysctl_ver) 1589 desc = (char *)-1; 1590 else 1591 desc = malloc(d->descr_len); 1592 1593 if (desc == NULL) 1594 desc = (char *)-1; 1595 if (desc != (char *)-1) 1596 memcpy(desc, &d->descr_str[0], d->descr_len); 1597 name[namelen - 1] = node.sysctl_num; 1598 if (pnode->sysctl_desc != NULL && 1599 pnode->sysctl_desc != (const char *)-1) 1600 free(__UNCONST(pnode->sysctl_desc)); 1601 pnode->sysctl_desc = desc; 1602 } 1603 1604 static void 1605 getdesc(int *name, u_int namelen, struct sysctlnode *pnode) 1606 { 1607 struct sysctlnode *node = pnode->sysctl_child; 1608 struct sysctldesc *d, *p, *plim; 1609 char *desc; 1610 size_t i, sz; 1611 int rc; 1612 1613 sz = 128 * pnode->sysctl_clen; 1614 name[namelen] = CTL_DESCRIBE; 1615 1616 /* 1617 * attempt *twice* to get the description chunk. if two tries 1618 * doesn't work, give up. 1619 */ 1620 i = 0; 1621 do { 1622 d = malloc(sz); 1623 if (d == NULL) 1624 return; 1625 rc = prog_sysctl(name, namelen + 1, d, &sz, NULL, 0); 1626 if (rc == -1) { 1627 free(d); 1628 d = NULL; 1629 if (i == 0 && errno == ENOMEM) 1630 i = 1; 1631 else 1632 return; 1633 } 1634 } while (d == NULL); 1635 1636 /* 1637 * hokey nested loop here, giving O(n**2) behavior, but should 1638 * suffice for now 1639 */ 1640 plim = /*LINTED ptr cast*/(struct sysctldesc *)((char*)d + sz); 1641 for (i = 0; i < pnode->sysctl_clen; i++) { 1642 node = &pnode->sysctl_child[i]; 1643 for (p = d; p < plim; p = NEXT_DESCR(p)) 1644 if (node->sysctl_num == p->descr_num) 1645 break; 1646 if (p < plim && node->sysctl_ver == p->descr_ver) { 1647 /* 1648 * match found, attempt to attach description 1649 */ 1650 if (p->descr_len == 1) 1651 desc = NULL; 1652 else 1653 desc = malloc(p->descr_len); 1654 if (desc == NULL) 1655 desc = (char *)-1; 1656 else 1657 memcpy(desc, &p->descr_str[0], p->descr_len); 1658 node->sysctl_desc = desc; 1659 } 1660 } 1661 1662 free(d); 1663 } 1664 1665 static void 1666 trim_whitespace(char *s, int dir) 1667 { 1668 char *i, *o; 1669 1670 i = o = s; 1671 if (dir & 1) 1672 while (isspace((unsigned char)*i)) 1673 i++; 1674 while ((*o++ = *i++) != '\0'); 1675 o -= 2; /* already past nul, skip back to before it */ 1676 if (dir & 2) 1677 while (o > s && isspace((unsigned char)*o)) 1678 *o-- = '\0'; 1679 } 1680 1681 void 1682 sysctlerror(int soft) 1683 { 1684 if (soft) { 1685 switch (errno) { 1686 case ENOENT: 1687 case ENOPROTOOPT: 1688 case ENOTDIR: 1689 case EINVAL: 1690 case EOPNOTSUPP: 1691 case EPROTONOSUPPORT: 1692 if (Aflag || req) 1693 sysctlperror("%s: the value is not available\n", 1694 gsname); 1695 return; 1696 } 1697 } 1698 1699 if (Aflag || req) 1700 sysctlperror("%s: %s\n", gsname, strerror(errno)); 1701 if (!soft) 1702 EXIT(1); 1703 } 1704 1705 void 1706 sysctlparseerror(u_int namelen, const char *pname) 1707 { 1708 1709 if (qflag) { 1710 errs++; 1711 return; 1712 } 1713 sysctlperror("%s level name '%s' in '%s' is invalid\n", 1714 lname[namelen], gsname, pname); 1715 } 1716 1717 static void 1718 sysctlperror(const char *fmt, ...) 1719 { 1720 va_list ap; 1721 1722 (void)fprintf(warnfp, "%s: ", getprogname()); 1723 if (fn) 1724 (void)fprintf(warnfp, "%s#%zu: ", fn, nr); 1725 va_start(ap, fmt); 1726 (void)vfprintf(warnfp, fmt, ap); 1727 va_end(ap); 1728 errs++; 1729 } 1730 1731 1732 /* 1733 * ******************************************************************** 1734 * how to write to a "simple" node 1735 * ******************************************************************** 1736 */ 1737 static void 1738 write_number(int *name, u_int namelen, struct sysctlnode *node, char *value) 1739 { 1740 u_int ii, io; 1741 u_quad_t qi, qo; 1742 size_t si, so; 1743 bool bi, bo; 1744 int rc; 1745 void *i, *o; 1746 char *t; 1747 1748 if (fn) 1749 trim_whitespace(value, 3); 1750 1751 si = so = 0; 1752 i = o = NULL; 1753 bi = bo = false; 1754 errno = 0; 1755 qi = strtouq(value, &t, 0); 1756 if (qi == UQUAD_MAX && errno == ERANGE) { 1757 sysctlperror("%s: %s\n", value, strerror(errno)); 1758 EXIT(1); 1759 } 1760 if (t == value || *t != '\0') { 1761 sysctlperror("%s: not a number\n", value); 1762 EXIT(1); 1763 } 1764 1765 switch (SYSCTL_TYPE(node->sysctl_flags)) { 1766 case CTLTYPE_INT: 1767 ii = (u_int)qi; 1768 io = (u_int)(qi >> 32); 1769 if (io != (u_int)-1 && io != 0) { 1770 sysctlperror("%s: %s\n", value, strerror(ERANGE)); 1771 EXIT(1); 1772 } 1773 o = &io; 1774 so = sizeof(io); 1775 i = ⅈ 1776 si = sizeof(ii); 1777 break; 1778 case CTLTYPE_BOOL: 1779 bi = (bool)qi; 1780 o = &bo; 1781 so = sizeof(bo); 1782 i = &bi; 1783 si = sizeof(bi); 1784 break; 1785 case CTLTYPE_QUAD: 1786 o = &qo; 1787 so = sizeof(qo); 1788 i = &qi; 1789 si = sizeof(qi); 1790 break; 1791 } 1792 1793 rc = prog_sysctl(name, namelen, o, &so, i, si); 1794 if (rc == -1) { 1795 sysctlerror(0); 1796 return; 1797 } 1798 1799 switch (SYSCTL_TYPE(node->sysctl_flags)) { 1800 case CTLTYPE_INT: 1801 display_number(node, gsname, &io, sizeof(io), DISPLAY_OLD); 1802 display_number(node, gsname, &ii, sizeof(ii), DISPLAY_NEW); 1803 break; 1804 case CTLTYPE_BOOL: 1805 display_number(node, gsname, &bo, sizeof(bo), DISPLAY_OLD); 1806 display_number(node, gsname, &bi, sizeof(bi), DISPLAY_NEW); 1807 break; 1808 case CTLTYPE_QUAD: 1809 display_number(node, gsname, &qo, sizeof(qo), DISPLAY_OLD); 1810 display_number(node, gsname, &qi, sizeof(qi), DISPLAY_NEW); 1811 break; 1812 } 1813 } 1814 1815 static void 1816 write_string(int *name, u_int namelen, struct sysctlnode *node, char *value) 1817 { 1818 char *i, *o; 1819 size_t si, so; 1820 int rc; 1821 1822 i = value; 1823 si = strlen(i) + 1; 1824 so = node->sysctl_size; 1825 if (si > so && so != 0) { 1826 sysctlperror("%s: string too long\n", value); 1827 EXIT(1); 1828 } 1829 o = malloc(so); 1830 if (o == NULL) { 1831 sysctlperror("%s: !malloc failed!\n", gsname); 1832 exit(1); 1833 } 1834 1835 rc = prog_sysctl(name, namelen, o, &so, i, si); 1836 if (rc == -1) { 1837 sysctlerror(0); 1838 return; 1839 } 1840 1841 display_string(node, gsname, o, so, DISPLAY_OLD); 1842 display_string(node, gsname, i, si, DISPLAY_NEW); 1843 free(o); 1844 } 1845 1846 /* 1847 * ******************************************************************** 1848 * simple ways to print stuff consistently 1849 * ******************************************************************** 1850 */ 1851 static void 1852 display_number(const struct sysctlnode *node, const char *name, 1853 const void *data, size_t sz, int n) 1854 { 1855 u_quad_t q; 1856 bool b; 1857 int i; 1858 1859 if (qflag) 1860 return; 1861 if ((nflag || rflag) && (n == DISPLAY_OLD)) 1862 return; 1863 1864 if (rflag && n != DISPLAY_OLD) { 1865 fwrite(data, sz, 1, stdout); 1866 return; 1867 } 1868 1869 if (!nflag) { 1870 if (n == DISPLAY_VALUE) 1871 printf("%s%s", name, eq); 1872 else if (n == DISPLAY_OLD) 1873 printf("%s: ", name); 1874 } 1875 1876 if (xflag > 1) { 1877 if (n != DISPLAY_NEW) 1878 printf("\n"); 1879 hex_dump(data, sz); 1880 return; 1881 } 1882 1883 switch (SYSCTL_TYPE(node->sysctl_flags)) { 1884 case CTLTYPE_INT: 1885 memcpy(&i, data, sz); 1886 if (xflag) 1887 printf("0x%0*x", (int)sz * 2, i); 1888 else if (node->sysctl_flags & CTLFLAG_HEX) 1889 printf("%#x", i); 1890 else 1891 printf("%d", i); 1892 break; 1893 case CTLTYPE_BOOL: 1894 memcpy(&b, data, sz); 1895 if (xflag) 1896 printf("0x%0*x", (int)sz * 2, b); 1897 else if (node->sysctl_flags & CTLFLAG_HEX) 1898 printf("%#x", b); 1899 else 1900 printf("%d", b); 1901 break; 1902 case CTLTYPE_QUAD: 1903 memcpy(&q, data, sz); 1904 if (xflag) 1905 printf("0x%0*" PRIx64, (int)sz * 2, q); 1906 else if (node->sysctl_flags & CTLFLAG_HEX) 1907 printf("%#" PRIx64, q); 1908 else 1909 printf("%" PRIu64, q); 1910 break; 1911 } 1912 1913 if (n == DISPLAY_OLD) 1914 printf(" -> "); 1915 else 1916 printf("\n"); 1917 } 1918 1919 static void 1920 display_string(const struct sysctlnode *node, const char *name, 1921 const void *data, size_t sz, int n) 1922 { 1923 const unsigned char *buf = data; 1924 int ni; 1925 1926 if (qflag) 1927 return; 1928 if ((nflag || rflag) && (n == DISPLAY_OLD)) 1929 return; 1930 1931 if (rflag && n != DISPLAY_OLD) { 1932 fwrite(data, sz, 1, stdout); 1933 return; 1934 } 1935 1936 if (!nflag) { 1937 if (n == DISPLAY_VALUE) 1938 printf("%s%s", name, eq); 1939 else if (n == DISPLAY_OLD) 1940 printf("%s: ", name); 1941 } 1942 1943 if (xflag > 1) { 1944 if (n != DISPLAY_NEW) 1945 printf("\n"); 1946 hex_dump(data, sz); 1947 return; 1948 } 1949 1950 if (xflag || node->sysctl_flags & CTLFLAG_HEX) { 1951 for (ni = 0; ni < (int)sz; ni++) { 1952 if (xflag) 1953 printf("%02x", buf[ni]); 1954 if (buf[ni] == '\0') 1955 break; 1956 if (!xflag) 1957 printf("\\x%2.2x", buf[ni]); 1958 } 1959 } 1960 else 1961 printf("%.*s", (int)sz, buf); 1962 1963 if (n == DISPLAY_OLD) 1964 printf(" -> "); 1965 else 1966 printf("\n"); 1967 } 1968 1969 /*ARGSUSED*/ 1970 static void 1971 display_struct(const struct sysctlnode *node, const char *name, 1972 const void *data, size_t sz, int n) 1973 { 1974 const unsigned char *buf = data; 1975 int ni; 1976 size_t more; 1977 1978 if (qflag) 1979 return; 1980 if (!(xflag || rflag)) { 1981 if (Aflag || req) 1982 sysctlperror( 1983 "%s: this type is unknown to this program\n", 1984 gsname); 1985 return; 1986 } 1987 if ((nflag || rflag) && (n == DISPLAY_OLD)) 1988 return; 1989 1990 if (rflag && n != DISPLAY_OLD) { 1991 fwrite(data, sz, 1, stdout); 1992 return; 1993 } 1994 1995 if (!nflag) { 1996 if (n == DISPLAY_VALUE) 1997 printf("%s%s", name, eq); 1998 else if (n == DISPLAY_OLD) 1999 printf("%s: ", name); 2000 } 2001 2002 if (xflag > 1) { 2003 if (n != DISPLAY_NEW) 2004 printf("\n"); 2005 hex_dump(data, sz); 2006 return; 2007 } 2008 2009 if (sz > 16) { 2010 more = sz - 16; 2011 sz = 16; 2012 } 2013 else 2014 more = 0; 2015 for (ni = 0; ni < (int)sz; ni++) 2016 printf("%02x", buf[ni]); 2017 if (more) 2018 printf("...(%zu more bytes)", more); 2019 printf("\n"); 2020 } 2021 2022 static void 2023 hex_dump(const unsigned char *buf, size_t len) 2024 { 2025 unsigned int i; 2026 int j; 2027 char line[80], tmp[12]; 2028 2029 memset(line, ' ', sizeof(line)); 2030 for (i = 0, j = 15; i < len; i++) { 2031 j = i % 16; 2032 /* reset line */ 2033 if (j == 0) { 2034 line[58] = '|'; 2035 line[77] = '|'; 2036 line[78] = 0; 2037 snprintf(tmp, sizeof(tmp), "%07x", i); 2038 memcpy(&line[0], tmp, 7); 2039 } 2040 /* copy out hex version of byte */ 2041 snprintf(tmp, sizeof(tmp), "%02x", buf[i]); 2042 memcpy(&line[9 + j * 3], tmp, 2); 2043 /* copy out plain version of byte */ 2044 line[60 + j] = (isprint(buf[i])) ? buf[i] : '.'; 2045 /* print a full line and erase it */ 2046 if (j == 15) { 2047 printf("%s\n", line); 2048 memset(line, ' ', sizeof(line)); 2049 } 2050 } 2051 if (line[0] != ' ') 2052 printf("%s\n", line); 2053 printf("%07zu bytes\n", len); 2054 } 2055 2056 /* 2057 * ******************************************************************** 2058 * functions that handle particular nodes 2059 * ******************************************************************** 2060 */ 2061 /*ARGSUSED*/ 2062 static void 2063 printother(HANDLER_ARGS) 2064 { 2065 int rc; 2066 void *p; 2067 size_t sz1, sz2; 2068 2069 if (!(Aflag || req) || Mflag) 2070 return; 2071 2072 /* 2073 * okay...you asked for it, so let's give it a go 2074 */ 2075 while (type != CTLTYPE_NODE && (xflag || rflag)) { 2076 rc = prog_sysctl(name, namelen, NULL, &sz1, NULL, 0); 2077 if (rc == -1 || sz1 == 0) 2078 break; 2079 p = malloc(sz1); 2080 if (p == NULL) 2081 break; 2082 sz2 = sz1; 2083 rc = prog_sysctl(name, namelen, p, &sz2, NULL, 0); 2084 if (rc == -1 || sz1 != sz2) { 2085 free(p); 2086 break; 2087 } 2088 display_struct(pnode, gsname, p, sz1, DISPLAY_VALUE); 2089 free(p); 2090 return; 2091 } 2092 2093 /* 2094 * that didn't work...do we have a specific message for this 2095 * thing? 2096 */ 2097 if (v != NULL) { 2098 sysctlperror("%s: use '%s' to view this information\n", 2099 gsname, (const char *)v); 2100 return; 2101 } 2102 2103 /* 2104 * hmm...i wonder if we have any generic hints? 2105 */ 2106 switch (name[0]) { 2107 case CTL_NET: 2108 sysctlperror("%s: use 'netstat' to view this information\n", 2109 sname); 2110 break; 2111 case CTL_DEBUG: 2112 sysctlperror("%s: missing 'options DEBUG' from kernel?\n", 2113 sname); 2114 break; 2115 case CTL_DDB: 2116 sysctlperror("%s: missing 'options DDB' from kernel?\n", 2117 sname); 2118 break; 2119 case CTL_VENDOR: 2120 sysctlperror("%s: no vendor extensions installed\n", 2121 sname); 2122 break; 2123 } 2124 } 2125 2126 /*ARGSUSED*/ 2127 static void 2128 kern_clockrate(HANDLER_ARGS) 2129 { 2130 struct clockinfo clkinfo; 2131 size_t sz; 2132 int rc; 2133 2134 sz = sizeof(clkinfo); 2135 rc = prog_sysctl(name, namelen, &clkinfo, &sz, NULL, 0); 2136 if (rc == -1) { 2137 sysctlerror(1); 2138 return; 2139 } 2140 if (sz != sizeof(clkinfo)) 2141 errx(1, "%s: !returned size wrong!", sname); 2142 2143 if (xflag || rflag) { 2144 display_struct(pnode, sname, &clkinfo, sz, 2145 DISPLAY_VALUE); 2146 return; 2147 } 2148 else if (!nflag) 2149 printf("%s: ", sname); 2150 printf("tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n", 2151 clkinfo.tick, clkinfo.tickadj, 2152 clkinfo.hz, clkinfo.profhz, clkinfo.stathz); 2153 } 2154 2155 /*ARGSUSED*/ 2156 static void 2157 kern_boottime(HANDLER_ARGS) 2158 { 2159 struct timeval timeval; 2160 time_t boottime; 2161 size_t sz; 2162 int rc; 2163 2164 sz = sizeof(timeval); 2165 rc = prog_sysctl(name, namelen, &timeval, &sz, NULL, 0); 2166 if (rc == -1) { 2167 sysctlerror(1); 2168 return; 2169 } 2170 if (sz != sizeof(timeval)) 2171 errx(1, "%s: !returned size wrong!", sname); 2172 2173 boottime = timeval.tv_sec; 2174 if (xflag || rflag) 2175 display_struct(pnode, sname, &timeval, sz, 2176 DISPLAY_VALUE); 2177 else if (!nflag) 2178 /* ctime() provides the \n */ 2179 printf("%s%s%s", sname, eq, ctime(&boottime)); 2180 else if (nflag == 1) 2181 printf("%ld\n", (long)boottime); 2182 else 2183 printf("%ld.%06ld\n", (long)timeval.tv_sec, 2184 (long)timeval.tv_usec); 2185 } 2186 2187 /*ARGSUSED*/ 2188 static void 2189 kern_consdev(HANDLER_ARGS) 2190 { 2191 dev_t cons; 2192 size_t sz; 2193 int rc; 2194 2195 sz = sizeof(cons); 2196 rc = prog_sysctl(name, namelen, &cons, &sz, NULL, 0); 2197 if (rc == -1) { 2198 sysctlerror(1); 2199 return; 2200 } 2201 if (sz != sizeof(cons)) 2202 errx(1, "%s: !returned size wrong!", sname); 2203 2204 if (xflag || rflag) 2205 display_struct(pnode, sname, &cons, sz, 2206 DISPLAY_VALUE); 2207 else { 2208 if (!nflag) 2209 printf("%s%s", sname, eq); 2210 if (nflag < 2 && (sname = devname(cons, S_IFCHR)) != NULL) 2211 printf("%s\n", sname); 2212 else 2213 printf("0x%llx\n", (unsigned long long)cons); 2214 } 2215 } 2216 2217 /*ARGSUSED*/ 2218 static void 2219 kern_cp_time(HANDLER_ARGS) 2220 { 2221 u_int64_t *cp_time; 2222 size_t sz, osz; 2223 int rc, i, n; 2224 char s[sizeof("kern.cp_time.nnnnnn")]; 2225 const char *tname; 2226 2227 /* 2228 * three things to do here. 2229 * case 1: get sum (no Aflag and namelen == 2) 2230 * case 2: get specific processor (namelen == 3) 2231 * case 3: get all processors (Aflag and namelen == 2) 2232 */ 2233 2234 if (namelen == 2 && Aflag) { 2235 sz = sizeof(n); 2236 rc = sysctlbyname("hw.ncpu", &n, &sz, NULL, 0); 2237 if (rc != 0) 2238 return; /* XXX print an error, eh? */ 2239 n++; /* Add on space for the sum. */ 2240 sz = n * sizeof(u_int64_t) * CPUSTATES; 2241 } 2242 else { 2243 n = -1; /* Just print one data set. */ 2244 sz = sizeof(u_int64_t) * CPUSTATES; 2245 } 2246 2247 cp_time = malloc(sz); 2248 if (cp_time == NULL) { 2249 sysctlerror(1); 2250 return; 2251 } 2252 2253 osz = sz; 2254 rc = prog_sysctl(name, namelen, cp_time + (n != -1) * CPUSTATES, &osz, 2255 NULL, 0); 2256 2257 if (rc == -1) { 2258 sysctlerror(1); 2259 free(cp_time); 2260 return; 2261 } 2262 2263 /* 2264 * Check, but account for space we'll occupy with the sum. 2265 */ 2266 if (osz != sz - (n != -1) * CPUSTATES * sizeof(u_int64_t)) 2267 errx(1, "%s: !returned size wrong!", sname); 2268 2269 /* 2270 * Compute the actual sum. Two calls would be easier (we 2271 * could just call ourselves recursively above), but the 2272 * numbers wouldn't add up. 2273 */ 2274 if (n != -1) { 2275 memset(cp_time, 0, sizeof(u_int64_t) * CPUSTATES); 2276 for (i = 1; i < n; i++) { 2277 cp_time[CP_USER] += cp_time[i * CPUSTATES + CP_USER]; 2278 cp_time[CP_NICE] += cp_time[i * CPUSTATES + CP_NICE]; 2279 cp_time[CP_SYS] += cp_time[i * CPUSTATES + CP_SYS]; 2280 cp_time[CP_INTR] += cp_time[i * CPUSTATES + CP_INTR]; 2281 cp_time[CP_IDLE] += cp_time[i * CPUSTATES + CP_IDLE]; 2282 } 2283 } 2284 2285 tname = sname; 2286 for (i = 0; n == -1 || i < n; i++) { 2287 if (i > 0) { 2288 (void)snprintf(s, sizeof(s), "%s%s%d", sname, sep, 2289 i - 1); 2290 tname = s; 2291 } 2292 if (xflag || rflag) 2293 display_struct(pnode, tname, cp_time + (i * CPUSTATES), 2294 sizeof(u_int64_t) * CPUSTATES, 2295 DISPLAY_VALUE); 2296 else { 2297 if (!nflag) 2298 printf("%s: ", tname); 2299 printf("user = %" PRIu64 2300 ", nice = %" PRIu64 2301 ", sys = %" PRIu64 2302 ", intr = %" PRIu64 2303 ", idle = %" PRIu64 2304 "\n", 2305 cp_time[i * CPUSTATES + CP_USER], 2306 cp_time[i * CPUSTATES + CP_NICE], 2307 cp_time[i * CPUSTATES + CP_SYS], 2308 cp_time[i * CPUSTATES + CP_INTR], 2309 cp_time[i * CPUSTATES + CP_IDLE]); 2310 } 2311 /* 2312 * Just printing the one node. 2313 */ 2314 if (n == -1) 2315 break; 2316 } 2317 2318 free(cp_time); 2319 } 2320 2321 /*ARGSUSED*/ 2322 static void 2323 kern_drivers(HANDLER_ARGS) 2324 { 2325 struct kinfo_drivers *kd; 2326 size_t sz, i; 2327 int rc; 2328 const char *comma; 2329 2330 rc = prog_sysctl(name, namelen, NULL, &sz, NULL, 0); 2331 if (rc == -1) { 2332 sysctlerror(1); 2333 return; 2334 } 2335 2336 if (sz % sizeof(*kd)) 2337 err(1, "bad size %zu for kern.drivers", sz); 2338 2339 kd = malloc(sz); 2340 if (kd == NULL) { 2341 sysctlerror(1); 2342 return; 2343 } 2344 2345 rc = prog_sysctl(name, namelen, kd, &sz, NULL, 0); 2346 if (rc == -1) { 2347 sysctlerror(1); 2348 return; 2349 } 2350 2351 comma = ""; 2352 if (!nflag) 2353 printf("%s%s", sname, eq); 2354 for (i = 0, sz /= sizeof(*kd); i < sz; i++) { 2355 (void)printf("%s[%d %d %s]", comma, kd[i].d_cmajor, 2356 kd[i].d_bmajor, kd[i].d_name); 2357 comma = ", "; 2358 } 2359 (void)printf("\n"); 2360 free(kd); 2361 } 2362 2363 /*ARGSUSED*/ 2364 static void 2365 kern_cp_id(HANDLER_ARGS) 2366 { 2367 u_int64_t *cp_id; 2368 size_t sz, osz; 2369 int rc, i, n; 2370 char s[sizeof("kern.cp_id.nnnnnn")]; 2371 const char *tname; 2372 struct sysctlnode node = *pnode; 2373 2374 /* 2375 * three things to do here. 2376 * case 1: print a specific cpu id (namelen == 3) 2377 * case 2: print all cpu ids separately (Aflag set) 2378 * case 3: print all cpu ids on one line 2379 */ 2380 2381 if (namelen == 2) { 2382 sz = sizeof(n); 2383 rc = sysctlbyname("hw.ncpu", &n, &sz, NULL, 0); 2384 if (rc != 0) 2385 return; /* XXX print an error, eh? */ 2386 sz = n * sizeof(u_int64_t); 2387 } 2388 else { 2389 n = -1; /* Just print one cpu id. */ 2390 sz = sizeof(u_int64_t); 2391 } 2392 2393 cp_id = malloc(sz); 2394 if (cp_id == NULL) { 2395 sysctlerror(1); 2396 return; 2397 } 2398 2399 osz = sz; 2400 rc = prog_sysctl(name, namelen, cp_id, &osz, NULL, 0); 2401 if (rc == -1) { 2402 sysctlerror(1); 2403 free(cp_id); 2404 return; 2405 } 2406 2407 /* 2408 * Check that we got back what we asked for. 2409 */ 2410 if (osz != sz) 2411 errx(1, "%s: !returned size wrong!", sname); 2412 2413 /* pretend for output purposes */ 2414 node.sysctl_flags = SYSCTL_FLAGS(pnode->sysctl_flags) | 2415 SYSCTL_TYPE(CTLTYPE_QUAD); 2416 2417 tname = sname; 2418 if (namelen == 3) 2419 display_number(&node, tname, cp_id, 2420 sizeof(u_int64_t), 2421 DISPLAY_VALUE); 2422 else if (Aflag) { 2423 for (i = 0; i < n; i++) 2424 (void)snprintf(s, sizeof(s), "%s%s%d", sname, sep, i); 2425 tname = s; 2426 display_number(&node, tname, &cp_id[i], 2427 sizeof(u_int64_t), 2428 DISPLAY_VALUE); 2429 } 2430 else { 2431 if (xflag || rflag) 2432 display_struct(pnode, tname, cp_id, sz, DISPLAY_VALUE); 2433 else { 2434 if (!nflag) 2435 printf("%s: ", tname); 2436 for (i = 0; i < n; i++) { 2437 if (i) 2438 printf(", "); 2439 printf("%d = %" PRIu64, i, cp_id[i]); 2440 } 2441 printf("\n"); 2442 } 2443 } 2444 2445 free(cp_id); 2446 } 2447 2448 /*ARGSUSED*/ 2449 static void 2450 vm_loadavg(HANDLER_ARGS) 2451 { 2452 struct loadavg loadavg; 2453 size_t sz; 2454 int rc; 2455 2456 sz = sizeof(loadavg); 2457 rc = prog_sysctl(name, namelen, &loadavg, &sz, NULL, 0); 2458 if (rc == -1) { 2459 sysctlerror(1); 2460 return; 2461 } 2462 if (sz != sizeof(loadavg)) 2463 errx(1, "%s: !returned size wrong!", sname); 2464 2465 if (xflag || rflag) { 2466 display_struct(pnode, sname, &loadavg, sz, 2467 DISPLAY_VALUE); 2468 return; 2469 } 2470 if (!nflag) 2471 printf("%s: ", sname); 2472 printf("%.2f %.2f %.2f\n", 2473 (double) loadavg.ldavg[0] / loadavg.fscale, 2474 (double) loadavg.ldavg[1] / loadavg.fscale, 2475 (double) loadavg.ldavg[2] / loadavg.fscale); 2476 } 2477 2478 /*ARGSUSED*/ 2479 static void 2480 proc_limit(HANDLER_ARGS) 2481 { 2482 u_quad_t olim, *newp, nlim; 2483 size_t osz, nsz; 2484 char *t; 2485 int rc; 2486 2487 if (fn) 2488 trim_whitespace(value, 3); 2489 2490 osz = sizeof(olim); 2491 if (value != NULL) { 2492 nsz = sizeof(nlim); 2493 newp = &nlim; 2494 if (strcmp(value, "unlimited") == 0) 2495 nlim = RLIM_INFINITY; 2496 else { 2497 errno = 0; 2498 nlim = strtouq(value, &t, 0); 2499 if (t == value || *t != '\0' || errno != 0) { 2500 sysctlperror("%s: '%s' is not a valid limit\n", 2501 sname, value); 2502 EXIT(1); 2503 } 2504 } 2505 } 2506 else { 2507 nsz = 0; 2508 newp = NULL; 2509 } 2510 2511 rc = prog_sysctl(name, namelen, &olim, &osz, newp, nsz); 2512 if (rc == -1) { 2513 sysctlerror(newp == NULL); 2514 return; 2515 } 2516 2517 if (newp && qflag) 2518 return; 2519 2520 if (rflag || xflag || olim != RLIM_INFINITY) 2521 display_number(pnode, sname, &olim, sizeof(olim), 2522 newp ? DISPLAY_OLD : DISPLAY_VALUE); 2523 else 2524 display_string(pnode, sname, "unlimited", 10, 2525 newp ? DISPLAY_OLD : DISPLAY_VALUE); 2526 2527 if (newp) { 2528 if (rflag || xflag || nlim != RLIM_INFINITY) 2529 display_number(pnode, sname, &nlim, sizeof(nlim), 2530 DISPLAY_NEW); 2531 else 2532 display_string(pnode, sname, "unlimited", 10, 2533 DISPLAY_NEW); 2534 } 2535 } 2536 2537 #ifdef CPU_DISKINFO 2538 /*ARGSUSED*/ 2539 static void 2540 machdep_diskinfo(HANDLER_ARGS) 2541 { 2542 struct disklist *dl; 2543 struct biosdisk_info *bi; 2544 struct nativedisk_info *ni; 2545 int rc; 2546 size_t sz; 2547 uint i, b, lim; 2548 2549 rc = prog_sysctl(name, namelen, NULL, &sz, NULL, 0); 2550 if (rc == -1) { 2551 sysctlerror(1); 2552 return; 2553 } 2554 dl = malloc(sz); 2555 if (dl == NULL) { 2556 sysctlerror(1); 2557 return; 2558 } 2559 rc = prog_sysctl(name, namelen, dl, &sz, NULL, 0); 2560 if (rc == -1) { 2561 sysctlerror(1); 2562 return; 2563 } 2564 2565 if (!nflag) 2566 printf("%s: ", sname); 2567 lim = dl->dl_nbiosdisks; 2568 if (lim > MAX_BIOSDISKS) 2569 lim = MAX_BIOSDISKS; 2570 for (bi = dl->dl_biosdisks, i = 0; i < lim; bi++, i++) 2571 printf("%x:%" PRIu64 "(%d/%d/%d),%x ", 2572 bi->bi_dev, bi->bi_lbasecs, 2573 bi->bi_cyl, bi->bi_head, bi->bi_sec, 2574 bi->bi_flags); 2575 lim = dl->dl_nnativedisks; 2576 ni = dl->dl_nativedisks; 2577 bi = dl->dl_biosdisks; 2578 /* LINTED -- pointer casts are tedious */ 2579 if ((char *)&ni[lim] != (char *)dl + sz) { 2580 sysctlperror("%s: size mismatch\n", gsname); 2581 return; 2582 } 2583 for (i = 0; i < lim; ni++, i++) { 2584 char t = ':'; 2585 printf(" %.*s", (int)sizeof ni->ni_devname, 2586 ni->ni_devname); 2587 for (b = 0; b < (unsigned int)ni->ni_nmatches; t = ',', b++) 2588 printf("%c%x", t, 2589 bi[ni->ni_biosmatches[b]].bi_dev); 2590 } 2591 printf("\n"); 2592 free(dl); 2593 } 2594 #endif /* CPU_DISKINFO */ 2595 2596 /*ARGSUSED*/ 2597 static void 2598 mode_bits(HANDLER_ARGS) 2599 { 2600 char buf[12], outbuf[100]; 2601 int o, m, *newp, rc; 2602 size_t osz, nsz; 2603 mode_t om, mm; 2604 2605 if (fn) 2606 trim_whitespace(value, 3); 2607 2608 newp = NULL; 2609 osz = sizeof(o); 2610 if (value != NULL) { 2611 void *foo; 2612 int tt; 2613 size_t ttsz = sizeof(tt); 2614 mode_t old_umask; 2615 2616 nsz = sizeof(m); 2617 newp = &m; 2618 errno = 0; 2619 rc = prog_sysctl(name, namelen, &tt, &ttsz, NULL, 0); 2620 if (rc == -1) { 2621 sysctlperror("%s: failed query\n", sname); 2622 return; 2623 } 2624 2625 old_umask = umask(0); 2626 foo = setmode(value); 2627 umask(old_umask); 2628 if (foo == NULL) { 2629 sysctlperror("%s: '%s' is an invalid mode\n", sname, 2630 value); 2631 EXIT(1); 2632 } 2633 old_umask = umask(0); 2634 m = getmode(foo, (mode_t)tt); 2635 umask(old_umask); 2636 if (errno) { 2637 sysctlperror("%s: '%s' is an invalid mode\n", sname, 2638 value); 2639 EXIT(1); 2640 } 2641 } 2642 else { 2643 nsz = 0; 2644 newp = NULL; 2645 } 2646 2647 rc = prog_sysctl(name, namelen, &o, &osz, newp, nsz); 2648 if (rc == -1) { 2649 sysctlerror(newp == NULL); 2650 return; 2651 } 2652 2653 if (newp && qflag) 2654 return; 2655 2656 om = (mode_t)o; 2657 mm = (mode_t)m; 2658 2659 if (rflag || xflag) 2660 display_number(pnode, sname, &o, sizeof(o), 2661 newp ? DISPLAY_OLD : DISPLAY_VALUE); 2662 else { 2663 memset(buf, 0, sizeof(buf)); 2664 strmode(om, buf); 2665 rc = snprintf(outbuf, sizeof(outbuf), "%04o (%s)", om, buf + 1); 2666 display_string(pnode, sname, outbuf, rc, newp ? DISPLAY_OLD : DISPLAY_VALUE); 2667 } 2668 2669 if (newp) { 2670 if (rflag || xflag) 2671 display_number(pnode, sname, &m, sizeof(m), 2672 DISPLAY_NEW); 2673 else { 2674 memset(buf, 0, sizeof(buf)); 2675 strmode(mm, buf); 2676 rc = snprintf(outbuf, sizeof(outbuf), "%04o (%s)", mm, buf + 1); 2677 display_string(pnode, sname, outbuf, rc, DISPLAY_NEW); 2678 } 2679 } 2680 } 2681