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