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