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