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