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