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