1 /* $NetBSD: sysctl.c,v 1.77 2004/01/05 23:23:33 jmmv 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 * 3. Neither the name of The NetBSD Foundation nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * Copyright (c) 1993 37 * The Regents of the University of California. All rights reserved. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 */ 63 64 #include <sys/cdefs.h> 65 #ifndef lint 66 __COPYRIGHT( 67 "@(#) Copyright (c) 1993\n\ 68 The Regents of the University of California. All rights reserved.\n"); 69 #endif /* not lint */ 70 71 #ifndef lint 72 #if 0 73 static char sccsid[] = "@(#)sysctl.c 8.1 (Berkeley) 6/6/93"; 74 #else 75 __RCSID("$NetBSD: sysctl.c,v 1.77 2004/01/05 23:23:33 jmmv Exp $"); 76 #endif 77 #endif /* not lint */ 78 79 #include <sys/types.h> 80 #include <sys/param.h> 81 #include <sys/sysctl.h> 82 #include <sys/mount.h> 83 #include <sys/resource.h> 84 #include <sys/stat.h> 85 #include <sys/sched.h> 86 #include <sys/socket.h> 87 #include <netinet/in.h> 88 #include <netinet/ip_var.h> 89 #include <netinet/tcp.h> 90 #include <netinet/tcp_timer.h> 91 #include <netinet/tcp_var.h> 92 #include <netinet/icmp6.h> 93 #include <nfs/rpcv2.h> 94 #include <nfs/nfsproto.h> 95 #include <nfs/nfs.h> 96 #include <machine/cpu.h> 97 #include <netkey/key_var.h> 98 99 #include <assert.h> 100 #include <ctype.h> 101 #include <err.h> 102 #include <errno.h> 103 #include <inttypes.h> 104 #include <stdarg.h> 105 #include <stdio.h> 106 #include <stdlib.h> 107 #include <string.h> 108 #include <time.h> 109 #include <unistd.h> 110 111 /* 112 * this needs to be able to do the printing and the setting 113 */ 114 #define HANDLER_PROTO const char *, const char *, char *, \ 115 int *, u_int, const struct sysctlnode *, \ 116 u_int, void * 117 #define HANDLER_ARGS const char *sname, const char *dname, char *value, \ 118 int *name, u_int namelen, const struct sysctlnode *pnode, \ 119 u_int type, void *v 120 #define DISPLAY_VALUE 0 121 #define DISPLAY_OLD 1 122 #define DISPLAY_NEW 2 123 124 /* 125 * generic routines 126 */ 127 static struct handlespec *findprinter(const int *, u_int); 128 static struct handlespec *findwriter(const int *, u_int); 129 static void print_tree(int *, u_int, struct sysctlnode *, u_int, int); 130 static void write_number(int *, u_int, struct sysctlnode *, char *); 131 static void write_string(int *, u_int, struct sysctlnode *, char *); 132 static void display_number(const struct sysctlnode *, const char *, 133 const void *, size_t, int); 134 static void display_string(const struct sysctlnode *, const char *, 135 const void *, size_t, int); 136 static void display_struct(const struct sysctlnode *, const char *, 137 const void *, size_t, int); 138 static void hex_dump(const unsigned char *, size_t); 139 static void usage(void); 140 static void parse(char *); 141 static void cparse(char *); 142 static void dparse(char *); 143 static void sysctlerror(int); 144 145 /* 146 * unexported from some place else (XXX tbd) 147 */ 148 int learn_tree(int *, u_int, struct sysctlnode *); 149 int sysctlnametomib(const char *, int *, u_int *, 150 char *, size_t *, struct sysctlnode **); 151 152 /* 153 * "handlers" 154 */ 155 static void printother(HANDLER_PROTO); 156 static void kern_clockrate(HANDLER_PROTO); 157 static void kern_boottime(HANDLER_PROTO); 158 static void kern_consdev(HANDLER_PROTO); 159 static void kern_cp_time(HANDLER_PROTO); 160 static void vm_loadavg(HANDLER_PROTO); 161 static void proc_limit(HANDLER_PROTO); 162 #ifdef CPU_DISKINFO 163 static void machdep_diskinfo(HANDLER_PROTO); 164 #endif /* CPU_DISKINFO */ 165 166 struct handlespec { 167 int ps_name[CTL_MAXNAME]; 168 void (*ps_p)(HANDLER_PROTO); 169 void (*ps_w)(HANDLER_PROTO); 170 void *ps_d; 171 } handlers[] = { 172 { { CTL_KERN, KERN_CLOCKRATE }, kern_clockrate }, 173 { { CTL_KERN, KERN_VNODE }, printother, NULL, "pstat" }, 174 { { CTL_KERN, KERN_PROC }, printother, NULL, "ps" }, 175 { { CTL_KERN, KERN_PROC2 }, printother, NULL, "ps" }, 176 { { CTL_KERN, KERN_PROC_ARGS }, printother, NULL, "ps" }, 177 { { CTL_KERN, KERN_FILE }, printother, NULL, "pstat" }, 178 { { CTL_KERN, KERN_NTPTIME }, printother, NULL, 179 "ntpdc -c kerninfo" }, 180 { { CTL_KERN, KERN_MSGBUF }, printother, NULL, "dmesg" }, 181 { { CTL_KERN, KERN_BOOTTIME }, kern_boottime }, 182 { { CTL_KERN, KERN_CONSDEV }, kern_consdev }, 183 { { CTL_KERN, KERN_CP_TIME }, kern_cp_time }, 184 { { CTL_KERN, KERN_SYSVIPC_INFO }, printother, NULL, "ipcs" }, 185 { { CTL_VM, VM_METER }, printother, NULL, 186 "vmstat' or 'systat" }, 187 { { CTL_VM, VM_LOADAVG }, vm_loadavg }, 188 { { CTL_VM, VM_UVMEXP }, printother, NULL, 189 "vmstat' or 'systat" }, 190 { { CTL_VM, VM_UVMEXP2 }, printother, NULL, 191 "vmstat' or 'systat" }, 192 { { CTL_VFS, 2 /* NFS */, NFS_NFSSTATS }, 193 printother, NULL, "nfsstat" }, 194 { { CTL_NET }, printother, NULL, NULL }, 195 { { CTL_NET, PF_LOCAL }, printother, NULL, NULL }, 196 { { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_IDENT }, 197 printother, NULL, "identd" }, 198 { { CTL_NET, PF_INET6, IPPROTO_TCP, TCPCTL_IDENT }, 199 printother, NULL, "identd" }, 200 201 { { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST }, 202 printother, NULL, "something else" }, 203 { { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST }, 204 printother, NULL, "something else" }, 205 206 207 { { CTL_NET, PF_KEY, KEYCTL_DUMPSA }, 208 printother, NULL, "setkey" }, 209 { { CTL_NET, PF_KEY, KEYCTL_DUMPSP }, 210 printother, NULL, "setkey" }, 211 /* { { CTL_DEBUG }, printother, NULL, NULL }, */ 212 { { CTL_HW, HW_DISKSTATS }, printother, NULL, "iostat" }, 213 #ifdef CPU_CONSDEV 214 { { CTL_MACHDEP, CPU_CONSDEV }, kern_consdev }, 215 #endif /* CPU_CONSDEV */ 216 #ifdef CPU_DISKINFO 217 { { CTL_MACHDEP, CPU_DISKINFO },machdep_diskinfo }, 218 #endif /* CPU_CONSDEV */ 219 { { CTL_DDB }, printother, NULL, NULL }, 220 { { CTL_PROC, -1, PROC_PID_LIMIT, -1, -1 }, proc_limit, proc_limit }, 221 { { CTL_UNSPEC }, }, 222 }; 223 224 struct sysctlnode my_root = { 225 #if defined(lint) 226 0 227 #else /* defined(lint) */ 228 .sysctl_flags = SYSCTL_ROOT| 229 SYSCTL_TYPE(CTLTYPE_NODE), 230 .sysctl_size = sizeof(struct sysctlnode), 231 .sysctl_num = 0, 232 .sysctl_name = "(prog_root)", 233 #endif /* defined(lint) */ 234 }; 235 236 int Aflag, aflag, Mflag, nflag, qflag, rflag, wflag, xflag; 237 int req; 238 FILE *warnfp = stderr; 239 240 /* 241 * vah-riables n stuff 242 */ 243 char gsname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME], 244 gdname[10 * CTL_MAXNAME + CTL_MAXNAME]; 245 char sep[2] = ".", *eq = " = "; 246 const char *lname[] = { 247 "top", "second", "third", "fourth", "fifth", "sixth", 248 "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth" 249 }; 250 251 /* 252 * you've heard of main, haven't you? 253 */ 254 int 255 main(int argc, char *argv[]) 256 { 257 char *fn = NULL; 258 int name[CTL_MAXNAME]; 259 int ch; 260 261 while ((ch = getopt(argc, argv, "Aaef:Mnqrwx")) != -1) { 262 switch (ch) { 263 case 'A': 264 Aflag++; 265 break; 266 case 'a': 267 aflag++; 268 break; 269 case 'e': 270 eq = "="; 271 break; 272 case 'f': 273 fn = optarg; 274 wflag++; 275 break; 276 case 'M': 277 Mflag++; 278 break; 279 case 'n': 280 nflag++; 281 break; 282 case 'q': 283 qflag++; 284 break; 285 case 'r': 286 rflag++; 287 break; 288 case 'w': 289 wflag++; 290 break; 291 case 'x': 292 xflag++; 293 break; 294 default: 295 usage(); 296 } 297 } 298 299 argc -= optind; 300 argv += optind; 301 302 if (qflag && !wflag) 303 usage(); 304 if (xflag && rflag) 305 usage(); 306 /* if ((xflag || rflag) && wflag) 307 usage(); */ 308 /* if (aflag && Mflag) 309 usage(); */ 310 if ((Aflag || Mflag) && argc == 0) 311 aflag = 1; 312 313 if (Aflag) 314 warnfp = stdout; 315 req = 0; 316 317 if (aflag) { 318 print_tree(&name[0], 0, NULL, CTLTYPE_NODE, 1); 319 /* if (argc == 0) */ 320 return (0); 321 } 322 323 if (fn) { 324 FILE *fp; 325 char *l; 326 327 fp = fopen(fn, "r"); 328 if (fp == NULL) { 329 err(1, "%s", fn); 330 } else { 331 while ((l = fparseln(fp, NULL, NULL, NULL, 0)) != NULL) 332 { 333 if (*l) { 334 parse(l); 335 free(l); 336 } 337 } 338 fclose(fp); 339 } 340 return (0); 341 } 342 343 if (argc == 0) 344 usage(); 345 346 while (argc-- > 0) 347 parse(*argv++); 348 349 return (0); 350 } 351 352 /* 353 * ******************************************************************** 354 * how to find someone special to handle the reading (or maybe even 355 * writing) of a particular node 356 * ******************************************************************** 357 */ 358 static struct handlespec * 359 findprinter(const int *name, u_int namelen) 360 { 361 struct handlespec *p; 362 int i, j; 363 364 if (namelen < 1) 365 return (NULL); 366 367 p = &handlers[0]; 368 for (i = 0; p[i].ps_name[0] != CTL_UNSPEC; i++) { 369 for (j = 0; j < namelen; j++) 370 if (p[i].ps_name[j] != name[j] && 371 p[i].ps_name[j] != -1) 372 break; 373 if (j == namelen && p[i].ps_p != NULL) 374 return (&p[i]); 375 } 376 377 return (NULL); 378 } 379 380 static struct handlespec * 381 findwriter(const int *name, u_int namelen) 382 { 383 struct handlespec *p; 384 int i, j; 385 386 if (namelen < 1) 387 return (NULL); 388 389 p = &handlers[0]; 390 for (i = 0; p[i].ps_name[0] != CTL_UNSPEC; i++) { 391 for (j = 0; j < namelen; j++) 392 if (p[i].ps_name[j] != name[j] && 393 p[i].ps_name[j] != -1) 394 break; 395 if (j == namelen && p[i].ps_w != NULL) 396 return (&p[i]); 397 } 398 399 return (NULL); 400 } 401 402 /* 403 * ******************************************************************** 404 * convert this special number to a special string so we can print the 405 * mib 406 * ******************************************************************** 407 */ 408 static const char * 409 sf(u_int f) 410 { 411 static char s[256]; 412 char *c; 413 414 s[0] = '\0'; 415 c = ""; 416 417 #define print_flag(_f, _s, _c, _q, _x) \ 418 if ((/*CONSTCOND*/_x) ? \ 419 (((_f) & (_x)) == (__CONCAT(SYSCTL_,_q))) : \ 420 ((_f) & (__CONCAT(SYSCTL_,_q)))) { \ 421 strlcat((_s), (_c), sizeof(_s)); \ 422 strlcat((_s), __STRING(_q), sizeof(_s)); \ 423 (_c) = ","; \ 424 (_f) &= ~(__CONCAT(SYSCTL_,_q)|(_x)); \ 425 } 426 print_flag(f, s, c, READONLY, SYSCTL_READWRITE); 427 print_flag(f, s, c, READONLY1, SYSCTL_READWRITE); 428 print_flag(f, s, c, READONLY2, SYSCTL_READWRITE); 429 print_flag(f, s, c, READWRITE, SYSCTL_READWRITE); 430 print_flag(f, s, c, ANYWRITE, 0); 431 print_flag(f, s, c, PRIVATE, 0); 432 print_flag(f, s, c, PERMANENT, 0); 433 print_flag(f, s, c, OWNDATA, 0); 434 print_flag(f, s, c, IMMEDIATE, 0); 435 print_flag(f, s, c, HEX, 0); 436 print_flag(f, s, c, ROOT, 0); 437 print_flag(f, s, c, ANYNUMBER, 0); 438 print_flag(f, s, c, HIDDEN, 0); 439 print_flag(f, s, c, ALIAS, 0); 440 #undef print_flag 441 442 if (f) { 443 char foo[9]; 444 snprintf(foo, sizeof(foo), "%x", f); 445 strlcat(s, c, sizeof(s)); 446 strlcat(s, foo, sizeof(s)); 447 } 448 449 return (s); 450 } 451 452 static const char * 453 st(u_int t) 454 { 455 456 switch (t) { 457 case CTLTYPE_NODE: 458 return "NODE"; 459 case CTLTYPE_INT: 460 return "INT"; 461 case CTLTYPE_STRING: 462 return "STRING"; 463 case CTLTYPE_QUAD: 464 return "QUAD"; 465 case CTLTYPE_STRUCT: 466 return "STRUCT"; 467 } 468 469 return "???"; 470 } 471 472 /* 473 * ******************************************************************** 474 * print this node and any others underneath it 475 * ******************************************************************** 476 */ 477 static void 478 print_tree(int *name, u_int namelen, struct sysctlnode *pnode, u_int type, 479 int add) 480 { 481 struct sysctlnode *node; 482 int rc, ni; 483 size_t sz; 484 char *sp, *dp, n[20]; 485 struct handlespec *p; 486 487 sp = &gsname[strlen(gsname)]; 488 dp = &gdname[strlen(gdname)]; 489 490 if (sp != &gsname[0] && dp == &gdname[0]) { 491 /* 492 * aw...shucks. now we must play catch up 493 */ 494 for (ni = 0; ni < namelen; ni++) { 495 (void)snprintf(n, sizeof(n), "%d", name[ni]); 496 if (ni > 0) 497 strncat(gdname, ".", sizeof(gdname)); 498 strncat(gdname, n, sizeof(gdname)); 499 } 500 } 501 502 if (pnode == NULL) 503 pnode = &my_root; 504 else if (add) { 505 snprintf(n, sizeof(n), "%d", pnode->sysctl_num); 506 if (namelen > 1) { 507 strncat(gsname, sep, sizeof(gsname)); 508 strncat(gdname, ".", sizeof(gdname)); 509 } 510 strncat(gsname, pnode->sysctl_name, sizeof(gsname)); 511 strncat(gdname, n, sizeof(gdname)); 512 } 513 514 if (Mflag && pnode != &my_root) { 515 if (nflag) 516 printf("%s: ", gdname); 517 else 518 printf("%s (%s): ", gsname, gdname); 519 printf("CTLTYPE_%s", st(type)); 520 if (type == CTLTYPE_NODE) { 521 if (SYSCTL_FLAGS(pnode->sysctl_flags) & SYSCTL_ALIAS) 522 printf(", alias %d", 523 pnode->sysctl_alias); 524 else 525 printf(", children %d/%d", 526 pnode->sysctl_clen, 527 pnode->sysctl_csize); 528 } 529 printf(", size %zu", pnode->sysctl_size); 530 printf(", flags 0x%x<%s>", 531 SYSCTL_FLAGS(pnode->sysctl_flags), 532 sf(SYSCTL_FLAGS(pnode->sysctl_flags))); 533 if (pnode->sysctl_func) 534 printf(", func=%p", pnode->sysctl_func); 535 printf(", ver=%d", pnode->sysctl_ver); 536 printf("\n"); 537 if (type != CTLTYPE_NODE) { 538 *sp = *dp = '\0'; 539 return; 540 } 541 } 542 543 /* 544 * if this is an alias and we added our name, that means we 545 * got here by recursing down into the tree, so skip it. The 546 * only way to print an aliased node is with either -M or by 547 * name specifically. 548 */ 549 if (SYSCTL_FLAGS(pnode->sysctl_flags) & SYSCTL_ALIAS && add) { 550 *sp = *dp = '\0'; 551 return; 552 } 553 554 p = findprinter(name, namelen); 555 if (type != CTLTYPE_NODE && p != NULL) { 556 (*p->ps_p)(gsname, gdname, NULL, name, namelen, pnode, type, 557 p->ps_d); 558 *sp = *dp = '\0'; 559 return; 560 } 561 562 if (type != CTLTYPE_NODE && pnode->sysctl_size == 0) { 563 rc = sysctl(&name[0], namelen, NULL, &sz, NULL, 0); 564 if (rc == -1) { 565 sysctlerror(1); 566 *sp = *dp = '\0'; 567 return; 568 } 569 if (sz == 0) { 570 if ((Aflag || req) && !Mflag) 571 printf("%s: node contains no data\n", gsname); 572 *sp = *dp = '\0'; 573 return; 574 } 575 } 576 else 577 sz = pnode->sysctl_size; 578 579 switch (type) { 580 case CTLTYPE_NODE: { 581 learn_tree(name, namelen, pnode); 582 node = pnode->sysctl_child; 583 if (node == NULL) { 584 if (p != NULL) 585 (*p->ps_p)(gsname, gdname, NULL, name, namelen, 586 pnode, type, p->ps_d); 587 else if ((Aflag || req) && !Mflag) 588 printf("%s: no children\n", gsname); 589 } 590 else { 591 req = 0; 592 for (ni = 0; ni < pnode->sysctl_clen; ni++) { 593 name[namelen] = node[ni].sysctl_num; 594 if ((node[ni].sysctl_flags & SYSCTL_HIDDEN) && 595 !(Aflag || req)) 596 continue; 597 print_tree(name, namelen + 1, &node[ni], 598 SYSCTL_TYPE(node[ni].sysctl_flags), 599 1); 600 } 601 } 602 break; 603 } 604 case CTLTYPE_INT: { 605 int i; 606 rc = sysctl(name, namelen, &i, &sz, NULL, 0); 607 if (rc == -1) { 608 sysctlerror(1); 609 break; 610 } 611 display_number(pnode, gsname, &i, sizeof(i), DISPLAY_VALUE); 612 break; 613 } 614 case CTLTYPE_STRING: { 615 unsigned char buf[1024], *tbuf; 616 tbuf = buf; 617 sz = sizeof(buf); 618 rc = sysctl(&name[0], namelen, tbuf, &sz, NULL, 0); 619 if (rc == -1 && errno == ENOMEM) { 620 tbuf = malloc(sz); 621 if (tbuf == NULL) { 622 sysctlerror(1); 623 break; 624 } 625 rc = sysctl(&name[0], namelen, tbuf, &sz, NULL, 0); 626 } 627 if (rc == -1) 628 sysctlerror(1); 629 else 630 display_string(pnode, gsname, buf, sz, DISPLAY_VALUE); 631 if (tbuf != buf) 632 free(tbuf); 633 break; 634 } 635 case CTLTYPE_QUAD: { 636 u_quad_t q; 637 sz = sizeof(q); 638 rc = sysctl(&name[0], namelen, &q, &sz, NULL, 0); 639 if (rc == -1) { 640 sysctlerror(1); 641 break; 642 } 643 display_number(pnode, gsname, &q, sizeof(q), DISPLAY_VALUE); 644 break; 645 } 646 case CTLTYPE_STRUCT: { 647 /* 648 * we shouldn't actually get here, but if we 649 * do, would it be nice to have *something* to 650 * do other than completely ignore the 651 * request. 652 */ 653 unsigned char *d; 654 if ((d = malloc(sz)) == NULL) { 655 fprintf(warnfp, "%s: !malloc failed!\n", gsname); 656 break; 657 } 658 rc = sysctl(&name[0], namelen, d, &sz, NULL, 0); 659 if (rc == -1) { 660 sysctlerror(1); 661 break; 662 } 663 display_struct(pnode, gsname, d, sz, DISPLAY_VALUE); 664 free(d); 665 break; 666 } 667 default: 668 /* should i print an error here? */ 669 break; 670 } 671 672 *sp = *dp = '\0'; 673 } 674 675 /* 676 * ******************************************************************** 677 * parse a request, possibly determining that it's a create or destroy 678 * request 679 * ******************************************************************** 680 */ 681 static void 682 parse(char *l) 683 { 684 struct sysctlnode *node; 685 struct handlespec *w; 686 int name[CTL_MAXNAME]; 687 u_int namelen, type; 688 char *key, *value, *dot; 689 size_t sz; 690 691 req = 1; 692 key = l; 693 value = strchr(l, '='); 694 if (value != NULL) { 695 if (!wflag) { 696 fprintf(warnfp, 697 "%s: Must specify -w to set variables\n", 698 getprogname()); 699 exit(1); 700 } 701 *value++ = '\0'; 702 } 703 704 if ((dot = strpbrk(key, "./")) == NULL) 705 sep[0] = '.'; 706 else 707 sep[0] = dot[0]; 708 sep[1] = '\0'; 709 710 if (key[0] == sep[0] && key[1] == sep[0]) { 711 if (value != NULL) 712 value[-1] = '='; 713 if (strncmp(key + 2, "create=", 7) == 0) 714 cparse(key + 9); 715 else if (strncmp(key + 2, "destroy=", 8) == 0) 716 dparse(key + 10); 717 else 718 fprintf(warnfp, "%s: unable to parse '%s'\n", 719 getprogname(), key); 720 return; 721 } 722 723 node = &my_root; 724 namelen = CTL_MAXNAME; 725 sz = sizeof(gsname); 726 727 if (sysctlnametomib(key, &name[0], &namelen, gsname, &sz, &node) == -1) 728 { 729 fprintf(warnfp, "%s: %s level name '%s' in '%s' is invalid\n", 730 getprogname(), lname[namelen], gsname, l); 731 exit(1); 732 } 733 734 type = SYSCTL_TYPE(node->sysctl_flags); 735 736 if (value == NULL) { 737 print_tree(&name[0], namelen, node, type, 0); 738 gsname[0] = '\0'; 739 return; 740 } 741 742 if (type != CTLTYPE_NODE && (w = findwriter(name, namelen)) != NULL) { 743 (*w->ps_w)(gsname, gdname, value, name, namelen, node, type, 744 w->ps_d); 745 gsname[0] = '\0'; 746 return; 747 } 748 749 switch (type) { 750 case CTLTYPE_NODE: 751 /* 752 * XXX old behavior is to print. should we error instead? 753 */ 754 print_tree(&name[0], namelen, node, CTLTYPE_NODE, 1); 755 break; 756 case CTLTYPE_INT: 757 write_number(&name[0], namelen, node, value); 758 break; 759 case CTLTYPE_STRING: 760 write_string(&name[0], namelen, node, value); 761 break; 762 case CTLTYPE_QUAD: 763 write_number(&name[0], namelen, node, value); 764 break; 765 case CTLTYPE_STRUCT: 766 /* 767 * XXX old behavior is to print. should we error instead? 768 */ 769 /* fprintf(warnfp, "you can't write to %s\n", gsname); */ 770 print_tree(&name[0], namelen, node, type, 0); 771 break; 772 } 773 } 774 775 /* 776 777 //create=foo.bar.whatever..., 778 [type=(int|quad|string|struct|node),] 779 [size=###,] 780 [n=###,] 781 [flags=(tiohxparw12),] 782 [addr=0x####,|symbol=...|value=...] 783 784 size is optional for some types. type must be set before anything 785 else. nodes can have [r12whp], but nothing else applies. if no 786 size or type is given, node is asserted. writeable is the default, 787 with [r12w] being read-only, writeable below securelevel 1, 788 writeable below securelevel 2, and unconditionally writeable 789 respectively. if you specify addr, it is assumed to be the name of 790 a kernel symbol, if value, SYSCTL_OWNDATA will be asserted for 791 strings, SYSCTL_IMMEDIATE for ints and u_quad_ts. you cannot 792 specify both value and addr. 793 794 */ 795 796 static void 797 cparse(char *l) 798 { 799 struct sysctlnode node; 800 size_t sz; 801 char *nname, *key, *value, *data, *addr, *c, *t; 802 int name[CTL_MAXNAME], i, rc, method, flags, rw; 803 u_int namelen, type; 804 u_quad_t q; 805 long li, lo; 806 807 /* 808 * these are the pieces that make up the description of a new 809 * node 810 */ 811 memset(&node, 0, sizeof(node)); 812 node.sysctl_num = CTL_CREATE; /* any number is fine */ 813 flags = 0; 814 rw = -1; 815 type = 0; 816 sz = 0; 817 data = addr = NULL; 818 memset(name, 0, sizeof(name)); 819 namelen = 0; 820 method = 0; 821 822 /* 823 * misc stuff used when constructing 824 */ 825 i = 0; 826 q = 0; 827 key = NULL; 828 value = NULL; 829 830 /* 831 * the name of the thing we're trying to create is first, so 832 * pick it off. 833 */ 834 nname = l; 835 if ((c = strchr(nname, ',')) != NULL) 836 *c++ = '\0'; 837 838 while (c != NULL) { 839 840 /* 841 * pull off the next "key=value" pair 842 */ 843 key = c; 844 if ((t = strchr(key, '=')) != NULL) { 845 *t++ = '\0'; 846 value = t; 847 } 848 else 849 value = NULL; 850 851 /* 852 * if the "key" is "value", then that eats the rest of 853 * the string, so we're done, otherwise bite it off at 854 * the next comma. 855 */ 856 if (strcmp(key, "value") == 0) { 857 c = NULL; 858 data = value; 859 break; 860 } 861 else { 862 if ((c = strchr(value, ',')) != NULL) 863 *c++ = '\0'; 864 } 865 866 /* 867 * note that we (mostly) let the invoker of sysctl(8) 868 * play rampant here and depend on the kernel to tell 869 * them that they were wrong. well...within reason. 870 * we later check the various parameters against each 871 * other to make sure it makes some sort of sense. 872 */ 873 if (strcmp(key, "addr") == 0) { 874 /* 875 * we can't check these two. only the kernel 876 * can tell us when it fails to find the name 877 * (or if the address is invalid). 878 */ 879 if (method != 0) { 880 fprintf(warnfp, 881 "%s: %s: already have %s for new node\n", 882 getprogname(), nname, 883 method == CTL_CREATE ? "addr" : "symbol"); 884 exit(1); 885 } 886 errno = 0; 887 addr = (void*)strtoul(value, &t, 0); 888 if (*t != '\0' || errno != 0) { 889 fprintf(warnfp, 890 "%s: %s: '%s' is not a valid address\n", 891 getprogname(), nname, value); 892 exit(1); 893 } 894 method = CTL_CREATE; 895 } 896 else if (strcmp(key, "symbol") == 0) { 897 if (method != 0) { 898 fprintf(warnfp, 899 "%s: %s: already have %s for new node\n", 900 getprogname(), nname, 901 method == CTL_CREATE ? "addr" : "symbol"); 902 exit(1); 903 } 904 addr = value; 905 method = CTL_CREATESYM; 906 } 907 else if (strcmp(key, "type") == 0) { 908 if (strcmp(value, "node") == 0) 909 type = CTLTYPE_NODE; 910 else if (strcmp(value, "int") == 0) { 911 sz = sizeof(int); 912 type = CTLTYPE_INT; 913 } 914 else if (strcmp(value, "string") == 0) 915 type = CTLTYPE_STRING; 916 else if (strcmp(value, "quad") == 0) { 917 sz = sizeof(u_quad_t); 918 type = CTLTYPE_QUAD; 919 } 920 else if (strcmp(value, "struct") == 0) 921 type = CTLTYPE_STRUCT; 922 else { 923 fprintf(warnfp, 924 "%s: %s: '%s' is not a valid type\n", 925 getprogname(), nname, value); 926 exit(1); 927 } 928 } 929 else if (strcmp(key, "size") == 0) { 930 errno = 0; 931 /* 932 * yes, i know size_t is not an unsigned long, 933 * but we can all agree that it ought to be, 934 * right? 935 */ 936 sz = strtoul(value, &t, 0); 937 if (*t != '\0' || errno != 0) { 938 fprintf(warnfp, 939 "%s: %s: '%s' is not a valid size\n", 940 getprogname(), nname, value); 941 exit(1); 942 } 943 } 944 else if (strcmp(key, "n") == 0) { 945 errno = 0; 946 li = strtol(value, &t, 0); 947 node.sysctl_num = li; 948 lo = node.sysctl_num; 949 if (*t != '\0' || errno != 0 || li != lo || lo < 0) { 950 fprintf(warnfp, 951 "%s: %s: '%s' is not a valid mib number\n", 952 getprogname(), nname, value); 953 exit(1); 954 } 955 } 956 else if (strcmp(key, "flags") == 0) { 957 t = value; 958 while (*t != '\0') { 959 switch (*t) { 960 case 'a': 961 flags |= SYSCTL_ANYWRITE; 962 break; 963 case 'h': 964 flags |= SYSCTL_HIDDEN; 965 break; 966 case 'i': 967 flags |= SYSCTL_IMMEDIATE; 968 break; 969 case 'o': 970 flags |= SYSCTL_OWNDATA; 971 break; 972 case 'p': 973 flags |= SYSCTL_PRIVATE; 974 break; 975 case 'x': 976 flags |= SYSCTL_HEX; 977 break; 978 979 case 'r': 980 rw = SYSCTL_READONLY; 981 break; 982 case '1': 983 rw = SYSCTL_READONLY1; 984 break; 985 case '2': 986 rw = SYSCTL_READONLY2; 987 break; 988 case 'w': 989 rw = SYSCTL_READWRITE; 990 break; 991 default: 992 fprintf(warnfp, 993 "%s: %s: '%c' is not a valid flag\n", 994 getprogname(), nname, *t); 995 exit(1); 996 } 997 t++; 998 } 999 } 1000 else { 1001 fprintf(warnfp, "%s: %s: unrecognized keyword '%s'\n", 1002 getprogname(), nname, key); 1003 exit(1); 1004 } 1005 } 1006 1007 /* 1008 * now that we've finished parsing the given string, fill in 1009 * anything they didn't specify 1010 */ 1011 if (type == 0) 1012 type = CTLTYPE_NODE; 1013 1014 /* 1015 * the "data" can be interpreted various ways depending on the 1016 * type of node we're creating, as can the size 1017 */ 1018 if (data != NULL) { 1019 if (addr != NULL) { 1020 fprintf(warnfp, 1021 "%s: %s: cannot specify both value and " 1022 "address\n", getprogname(), nname); 1023 exit(1); 1024 } 1025 1026 switch (type) { 1027 case CTLTYPE_INT: 1028 errno = 0; 1029 li = strtol(data, &t, 0); 1030 i = li; 1031 lo = i; 1032 if (*t != '\0' || errno != 0 || li != lo || lo < 0) { 1033 fprintf(warnfp, 1034 "%s: %s: '%s' is not a valid integer\n", 1035 getprogname(), nname, value); 1036 exit(1); 1037 } 1038 if (!(flags & SYSCTL_OWNDATA)) { 1039 flags |= SYSCTL_IMMEDIATE; 1040 node.sysctl_idata = i; 1041 } 1042 else 1043 node.sysctl_data = &i; 1044 if (sz == 0) 1045 sz = sizeof(int); 1046 break; 1047 case CTLTYPE_STRING: 1048 flags |= SYSCTL_OWNDATA; 1049 node.sysctl_data = data; 1050 if (sz == 0) 1051 sz = strlen(data) + 1; 1052 else if (sz < strlen(data) + 1) { 1053 fprintf(warnfp, "%s: %s: ignoring size=%zu for " 1054 "string node, too small for given " 1055 "value\n", getprogname(), nname, sz); 1056 sz = strlen(data) + 1; 1057 } 1058 break; 1059 case CTLTYPE_QUAD: 1060 errno = 0; 1061 q = strtouq(data, &t, 0); 1062 if (*t != '\0' || errno != 0) { 1063 fprintf(warnfp, 1064 "%s: %s: '%s' is not a valid quad\n", 1065 getprogname(), nname, value); 1066 exit(1); 1067 } 1068 if (!(flags & SYSCTL_OWNDATA)) { 1069 flags |= SYSCTL_IMMEDIATE; 1070 node.sysctl_qdata = q; 1071 } 1072 else 1073 node.sysctl_data = &q; 1074 if (sz == 0) 1075 sz = sizeof(u_quad_t); 1076 break; 1077 case CTLTYPE_STRUCT: 1078 fprintf(warnfp, 1079 "%s: %s: struct not initializable\n", 1080 getprogname(), nname); 1081 exit(1); 1082 } 1083 1084 /* 1085 * these methods have all provided local starting 1086 * values that the kernel must copy in 1087 */ 1088 } 1089 1090 /* 1091 * hmm...no data, but we have an address of data. that's 1092 * fine. 1093 */ 1094 else if (addr != 0) 1095 node.sysctl_data = (void*)addr; 1096 1097 /* 1098 * no data and no address? well...okay. we might be able to 1099 * manage that. 1100 */ 1101 else if (type != CTLTYPE_NODE) { 1102 if (sz == 0) { 1103 fprintf(warnfp, 1104 "%s: %s: need a size or a starting value\n", 1105 getprogname(), nname); 1106 exit(1); 1107 } 1108 if (!(flags & SYSCTL_IMMEDIATE)) 1109 flags |= SYSCTL_OWNDATA; 1110 } 1111 1112 /* 1113 * now we do a few sanity checks on the description we've 1114 * assembled 1115 */ 1116 if ((flags & SYSCTL_IMMEDIATE) && 1117 (type == CTLTYPE_STRING || type == CTLTYPE_STRUCT)) { 1118 fprintf(warnfp, 1119 "%s: %s: cannot make an immediate %s\n", 1120 getprogname(), nname, 1121 (type == CTLTYPE_STRING) ? "string" : "struct"); 1122 exit(1); 1123 } 1124 if (type == CTLTYPE_NODE && node.sysctl_data != NULL) { 1125 fprintf(warnfp, "%s: %s: nodes do not have data\n", 1126 getprogname(), nname); 1127 exit(1); 1128 } 1129 1130 /* 1131 * some types must have a particular size 1132 */ 1133 if (sz != 0) { 1134 if ((type == CTLTYPE_INT && sz != sizeof(int)) || 1135 (type == CTLTYPE_QUAD && sz != sizeof(u_quad_t)) || 1136 (type == CTLTYPE_NODE && sz != 0)) { 1137 fprintf(warnfp, "%s: %s: wrong size for type\n", 1138 getprogname(), nname); 1139 exit(1); 1140 } 1141 } 1142 else if (type == CTLTYPE_STRUCT) { 1143 fprintf(warnfp, "%s: %s: struct must have size\n", 1144 getprogname(), nname); 1145 exit(1); 1146 } 1147 1148 /* 1149 * now...if no one said anything yet, we default nodes or 1150 * any type that owns data being writeable, and everything 1151 * else being readonly. 1152 */ 1153 if (rw == -1) { 1154 if (type == CTLTYPE_NODE || 1155 (flags & (SYSCTL_OWNDATA|SYSCTL_IMMEDIATE))) 1156 rw = SYSCTL_READWRITE; 1157 else 1158 rw = SYSCTL_READONLY; 1159 } 1160 1161 /* 1162 * if a kernel address was specified, that can't be made 1163 * writeable by us. 1164 if (rw != SYSCTL_READONLY && addr) { 1165 fprintf(warnfp, "%s: %s: kernel data can only be readable\n", 1166 getprogname(), nname); 1167 exit(1); 1168 } 1169 */ 1170 1171 /* 1172 * what separator were they using in the full name of the new 1173 * node? 1174 */ 1175 if ((t = strpbrk(nname, "./")) == NULL) 1176 sep[0] = '.'; 1177 else 1178 sep[0] = t[0]; 1179 sep[1] = '\0'; 1180 1181 /* 1182 * put it all together, now. t'ain't much, is it? 1183 */ 1184 node.sysctl_flags = flags|rw|type; 1185 node.sysctl_size = sz; 1186 t = strrchr(nname, sep[0]); 1187 if (t != NULL) 1188 strlcpy(node.sysctl_name, t + 1, sizeof(node.sysctl_name)); 1189 else 1190 strlcpy(node.sysctl_name, nname, sizeof(node.sysctl_name)); 1191 1192 /* 1193 * if this is a new top-level node, then we don't need to find 1194 * the mib for its parent 1195 */ 1196 if (t == NULL) { 1197 namelen = 0; 1198 gsname[0] = '\0'; 1199 } 1200 1201 /* 1202 * on the other hand, if it's not a top-level node... 1203 */ 1204 else { 1205 namelen = sizeof(name) / sizeof(name[0]); 1206 sz = sizeof(gsname); 1207 *t = '\0'; 1208 rc = sysctlnametomib(nname, &name[0], &namelen, 1209 gsname, &sz, NULL); 1210 *t = sep[0]; 1211 if (rc == -1) { 1212 fprintf(warnfp, 1213 "%s: %s level name '%s' in '%s' is invalid\n", 1214 getprogname(), lname[namelen], gsname, nname); 1215 exit(1); 1216 } 1217 } 1218 1219 /* 1220 * yes, a new node is being created 1221 */ 1222 if (method != 0) 1223 name[namelen++] = method; 1224 else 1225 name[namelen++] = CTL_CREATE; 1226 1227 sz = sizeof(node); 1228 rc = sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node)); 1229 1230 if (rc == -1) { 1231 fprintf(warnfp, 1232 "%s: %s: CTL_CREATE failed: %s\n", 1233 getprogname(), nname, strerror(errno)); 1234 exit(1); 1235 } 1236 else if (!qflag && !nflag) 1237 printf("%s(%s): (created)\n", nname, st(type)); 1238 } 1239 1240 static void 1241 dparse(char *l) 1242 { 1243 struct sysctlnode node; 1244 size_t sz; 1245 int name[CTL_MAXNAME], rc; 1246 u_int namelen; 1247 1248 memset(name, 0, sizeof(name)); 1249 namelen = sizeof(name) / sizeof(name[0]); 1250 sz = sizeof(gsname); 1251 rc = sysctlnametomib(l, &name[0], &namelen, gsname, &sz, NULL); 1252 if (rc == -1) { 1253 fprintf(warnfp, 1254 "%s: %s level name '%s' in '%s' is invalid\n", 1255 getprogname(), lname[namelen], gsname, l); 1256 exit(1); 1257 } 1258 1259 memset(&node, 0, sizeof(node)); 1260 node.sysctl_num = name[namelen - 1]; 1261 name[namelen - 1] = CTL_DESTROY; 1262 1263 sz = sizeof(node); 1264 rc = sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node)); 1265 1266 if (rc == -1) { 1267 fprintf(warnfp, 1268 "%s: %s: CTL_DESTROY failed: %s\n", 1269 getprogname(), l, strerror(errno)); 1270 exit(1); 1271 } 1272 else if (!qflag && !nflag) 1273 printf("%s(%s): (destroyed)\n", gsname, 1274 st(SYSCTL_TYPE(node.sysctl_flags))); 1275 } 1276 1277 /* 1278 * ******************************************************************** 1279 * when things go wrong... 1280 * ******************************************************************** 1281 */ 1282 static void 1283 usage(void) 1284 { 1285 const char *progname = getprogname(); 1286 1287 (void)fprintf(stderr, 1288 "usage:\t%s %s\n" 1289 "\t%s %s\n" 1290 "\t%s %s\n" 1291 "\t%s %s\n" 1292 "\t%s %s\n" 1293 "\t%s %s\n", 1294 progname, "[-ne] [-x[x]|-r] variable ...", 1295 progname, "[-ne] [-q] -w variable=value ...", 1296 progname, "[-ne] -a", 1297 progname, "[-ne] -A", 1298 progname, "[-ne] -M", 1299 progname, "[-ne] [-q] -f file"); 1300 exit(1); 1301 } 1302 1303 void 1304 sysctlerror(int soft) 1305 { 1306 if (soft) { 1307 switch (errno) { 1308 case ENOENT: 1309 case ENOPROTOOPT: 1310 case ENOTDIR: 1311 case EOPNOTSUPP: 1312 case EPROTONOSUPPORT: 1313 if (Aflag || req) 1314 fprintf(warnfp, 1315 "%s: the value is not available\n", 1316 gsname); 1317 return; 1318 } 1319 } 1320 1321 fprintf(warnfp, "%s: sysctl() failed with %s\n", 1322 gsname, strerror(errno)); 1323 if (!soft) 1324 exit(1); 1325 } 1326 1327 /* 1328 * ******************************************************************** 1329 * how to write to a "simple" node 1330 * ******************************************************************** 1331 */ 1332 static void 1333 write_number(int *name, u_int namelen, struct sysctlnode *node, char *value) 1334 { 1335 int ii, io; 1336 u_quad_t qi, qo; 1337 size_t si, so; 1338 int rc; 1339 void *i, *o; 1340 char *t; 1341 1342 si = so = 0; 1343 i = o = NULL; 1344 errno = 0; 1345 qi = strtouq(value, &t, 0); 1346 if (errno != 0) { 1347 fprintf(warnfp, "%s: value too large\n", value); 1348 exit(1); 1349 } 1350 if (*t != '\0') { 1351 fprintf(warnfp, "%s: not a number\n", value); 1352 exit(1); 1353 } 1354 1355 switch (SYSCTL_TYPE(node->sysctl_flags)) { 1356 case CTLTYPE_INT: 1357 ii = (int)qi; 1358 qo = ii; 1359 if (qo != qi) { 1360 fprintf(warnfp, "%s: value too large\n", value); 1361 exit(1); 1362 } 1363 o = &io; 1364 so = sizeof(io); 1365 i = ⅈ 1366 si = sizeof(ii); 1367 break; 1368 case CTLTYPE_QUAD: 1369 o = &qo; 1370 so = sizeof(qo); 1371 i = &qi; 1372 si = sizeof(qi); 1373 break; 1374 } 1375 1376 rc = sysctl(name, namelen, o, &so, i, si); 1377 if (rc == -1) 1378 sysctlerror(0); 1379 1380 switch (SYSCTL_TYPE(node->sysctl_flags)) { 1381 case CTLTYPE_INT: 1382 display_number(node, gsname, &io, sizeof(io), DISPLAY_OLD); 1383 display_number(node, gsname, &ii, sizeof(ii), DISPLAY_NEW); 1384 break; 1385 case CTLTYPE_QUAD: 1386 display_number(node, gsname, &qo, sizeof(qo), DISPLAY_OLD); 1387 display_number(node, gsname, &qi, sizeof(qi), DISPLAY_NEW); 1388 break; 1389 } 1390 } 1391 1392 static void 1393 write_string(int *name, u_int namelen, struct sysctlnode *node, char *value) 1394 { 1395 char *i, *o; 1396 size_t si, so; 1397 int rc; 1398 1399 i = value; 1400 si = strlen(i) + 1; 1401 so = node->sysctl_size; 1402 if (si > so && so != 0) { 1403 fprintf(warnfp, "%s: string too long\n", value); 1404 exit(1); 1405 } 1406 o = malloc(so); 1407 if (o == NULL) { 1408 fprintf(warnfp, "%s: !malloc failed!\n", gsname); 1409 exit(1); 1410 } 1411 1412 rc = sysctl(name, namelen, o, &so, i, si); 1413 if (rc == -1) 1414 sysctlerror(0); 1415 1416 display_string(node, gsname, o, so, DISPLAY_OLD); 1417 display_string(node, gsname, i, si, DISPLAY_NEW); 1418 free(o); 1419 } 1420 1421 /* 1422 * ******************************************************************** 1423 * simple ways to print stuff consistently 1424 * ******************************************************************** 1425 */ 1426 static void 1427 display_number(const struct sysctlnode *node, const char *name, 1428 const void *data, size_t sz, int n) 1429 { 1430 u_quad_t q; 1431 int i; 1432 1433 if (qflag) 1434 return; 1435 if ((nflag || rflag) && (n == DISPLAY_OLD)) 1436 return; 1437 1438 if (rflag && n != DISPLAY_OLD) { 1439 fwrite(data, sz, 1, stdout); 1440 return; 1441 } 1442 1443 if (!nflag) { 1444 if (n == DISPLAY_VALUE) 1445 printf("%s%s", name, eq); 1446 else if (n == DISPLAY_OLD) 1447 printf("%s: ", name); 1448 } 1449 1450 if (xflag > 1) { 1451 printf("\n"); 1452 hex_dump(data, sz); 1453 return; 1454 } 1455 1456 switch (SYSCTL_TYPE(node->sysctl_flags)) { 1457 case CTLTYPE_INT: 1458 memcpy(&i, data, sz); 1459 if (xflag) 1460 printf("0x%0*x", (int)sz * 2, i); 1461 else if (node->sysctl_flags & SYSCTL_HEX) 1462 printf("%#x", i); 1463 else 1464 printf("%d", i); 1465 break; 1466 case CTLTYPE_QUAD: 1467 memcpy(&q, data, sz); 1468 if (xflag) 1469 printf("0x%0*" PRIx64, (int)sz * 2, q); 1470 else if (node->sysctl_flags & SYSCTL_HEX) 1471 printf("%#" PRIx64, q); 1472 else 1473 printf("%" PRIu64, q); 1474 break; 1475 } 1476 1477 if (n == DISPLAY_OLD) 1478 printf(" -> "); 1479 else 1480 printf("\n"); 1481 } 1482 1483 static void 1484 display_string(const struct sysctlnode *node, const char *name, 1485 const void *data, size_t sz, int n) 1486 { 1487 const unsigned char *buf = data; 1488 int ni; 1489 1490 if (qflag) 1491 return; 1492 if ((nflag || rflag) && (n == DISPLAY_OLD)) 1493 return; 1494 1495 if (rflag && n != DISPLAY_OLD) { 1496 fwrite(data, sz, 1, stdout); 1497 return; 1498 } 1499 1500 if (!nflag) { 1501 if (n == DISPLAY_VALUE) 1502 printf("%s%s", name, eq); 1503 else if (n == DISPLAY_OLD) 1504 printf("%s: ", name); 1505 } 1506 1507 if (xflag > 1) { 1508 printf("\n"); 1509 hex_dump(data, sz); 1510 return; 1511 } 1512 1513 if (xflag || node->sysctl_flags & SYSCTL_HEX) { 1514 for (ni = 0; ni < (int)sz; ni++) { 1515 if (xflag) 1516 printf("%02x", buf[ni]); 1517 if (buf[ni] == '\0') 1518 break; 1519 if (!xflag) 1520 printf("\\x%2.2x", buf[ni]); 1521 } 1522 } 1523 else 1524 printf("%.*s", (int)sz, buf); 1525 1526 if (n == DISPLAY_OLD) 1527 printf(" -> "); 1528 else 1529 printf("\n"); 1530 } 1531 1532 /*ARGSUSED*/ 1533 static void 1534 display_struct(const struct sysctlnode *node, const char *name, 1535 const void *data, size_t sz, int n) 1536 { 1537 const unsigned char *buf = data; 1538 int ni; 1539 size_t more; 1540 1541 if (qflag) 1542 return; 1543 if (!(xflag || rflag)) { 1544 if (Aflag || req) 1545 fprintf(warnfp, 1546 "%s: this type is unknown to this program\n", 1547 gsname); 1548 return; 1549 } 1550 if ((nflag || rflag) && (n == DISPLAY_OLD)) 1551 return; 1552 1553 if (rflag && n != DISPLAY_OLD) { 1554 fwrite(data, sz, 1, stdout); 1555 return; 1556 } 1557 1558 if (!nflag) { 1559 if (n == DISPLAY_VALUE) 1560 printf("%s%s", name, eq); 1561 else if (n == DISPLAY_OLD) 1562 printf("%s: ", name); 1563 } 1564 1565 if (xflag > 1) { 1566 printf("\n"); 1567 hex_dump(data, sz); 1568 return; 1569 } 1570 1571 if (sz > 16) { 1572 more = sz - 16; 1573 sz = 16; 1574 } 1575 else 1576 more = 0; 1577 for (ni = 0; ni < (int)sz; ni++) 1578 printf("%02x", buf[ni]); 1579 if (more) 1580 printf("...(%zu more bytes)", more); 1581 printf("\n"); 1582 } 1583 1584 static void 1585 hex_dump(const unsigned char *buf, size_t len) 1586 { 1587 int i, j; 1588 char line[80], tmp[12]; 1589 1590 memset(line, ' ', sizeof(line)); 1591 for (i = 0, j = 15; i < len; i++) { 1592 j = i % 16; 1593 /* reset line */ 1594 if (j == 0) { 1595 line[58] = '|'; 1596 line[77] = '|'; 1597 line[78] = 0; 1598 snprintf(tmp, sizeof(tmp), "%07d", i); 1599 memcpy(&line[0], tmp, 7); 1600 } 1601 /* copy out hex version of byte */ 1602 snprintf(tmp, sizeof(tmp), "%02x", buf[i]); 1603 memcpy(&line[9 + j * 3], tmp, 2); 1604 /* copy out plain version of byte */ 1605 line[60 + j] = (isprint(buf[i])) ? buf[i] : '.'; 1606 /* print a full line and erase it */ 1607 if (j == 15) { 1608 printf("%s\n", line); 1609 memset(line, ' ', sizeof(line)); 1610 } 1611 } 1612 if (line[0] != ' ') 1613 printf("%s\n", line); 1614 printf("%07zu bytes\n", len); 1615 } 1616 1617 /* 1618 * ******************************************************************** 1619 * functions that handle particular nodes 1620 * ******************************************************************** 1621 */ 1622 /*ARGSUSED*/ 1623 static void 1624 printother(HANDLER_ARGS) 1625 { 1626 int rc; 1627 void *p; 1628 size_t sz1, sz2; 1629 1630 if (!(Aflag || req) || Mflag) 1631 return; 1632 1633 /* 1634 * okay...you asked for it, so let's give it a go 1635 */ 1636 while (type != CTLTYPE_NODE && (xflag || rflag)) { 1637 rc = sysctl(name, namelen, NULL, &sz1, NULL, 0); 1638 if (rc == -1 || sz1 == 0) 1639 break; 1640 p = malloc(sz1); 1641 if (p == NULL) 1642 break; 1643 sz2 = sz1; 1644 rc = sysctl(name, namelen, p, &sz2, NULL, 0); 1645 if (rc == -1 || sz1 != sz2) { 1646 free(p); 1647 break; 1648 } 1649 display_struct(pnode, gsname, p, sz1, DISPLAY_VALUE); 1650 free(p); 1651 return; 1652 } 1653 1654 /* 1655 * that didn't work...do we have a specific message for this 1656 * thing? 1657 */ 1658 if (v != NULL) { 1659 fprintf(warnfp, "%s: use '%s' to view this information\n", 1660 gsname, (const char *)v); 1661 return; 1662 } 1663 1664 /* 1665 * hmm...i wonder if we have any generic hints? 1666 */ 1667 switch (name[0]) { 1668 case CTL_NET: 1669 fprintf(warnfp, "%s: use 'netstat' to view this information\n", 1670 sname); 1671 break; 1672 case CTL_DEBUG: 1673 fprintf(warnfp, "%s: missing 'options DEBUG' from kernel?\n", 1674 sname); 1675 break; 1676 case CTL_DDB: 1677 fprintf(warnfp, "%s: missing 'options DDB' from kernel?\n", 1678 sname); 1679 break; 1680 } 1681 } 1682 1683 /*ARGSUSED*/ 1684 static void 1685 kern_clockrate(HANDLER_ARGS) 1686 { 1687 struct clockinfo clkinfo; 1688 size_t sz; 1689 int rc; 1690 1691 sz = sizeof(clkinfo); 1692 rc = sysctl(name, namelen, &clkinfo, &sz, NULL, 0); 1693 if (rc == -1) { 1694 sysctlerror(1); 1695 return; 1696 } 1697 if (sz != sizeof(clkinfo)) 1698 errx(1, "%s: !returned size wrong!", sname); 1699 1700 if (xflag || rflag) 1701 display_struct(pnode, sname, &clkinfo, sz, 1702 DISPLAY_VALUE); 1703 else if (!nflag) 1704 printf("%s: ", sname); 1705 printf("tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n", 1706 clkinfo.tick, clkinfo.tickadj, 1707 clkinfo.hz, clkinfo.profhz, clkinfo.stathz); 1708 } 1709 1710 /*ARGSUSED*/ 1711 static void 1712 kern_boottime(HANDLER_ARGS) 1713 { 1714 struct timeval timeval; 1715 time_t boottime; 1716 size_t sz; 1717 int rc; 1718 1719 sz = sizeof(timeval); 1720 rc = sysctl(name, namelen, &timeval, &sz, NULL, 0); 1721 if (rc == -1) { 1722 sysctlerror(1); 1723 return; 1724 } 1725 if (sz != sizeof(timeval)) 1726 errx(1, "%s: !returned size wrong!", sname); 1727 1728 boottime = timeval.tv_sec; 1729 if (xflag || rflag) 1730 display_struct(pnode, sname, &timeval, sz, 1731 DISPLAY_VALUE); 1732 else if (!nflag) 1733 /* ctime() provides the \n */ 1734 printf("%s%s%s", sname, eq, ctime(&boottime)); 1735 else if (nflag == 1) 1736 printf("%ld\n", (long)boottime); 1737 else 1738 printf("%ld.%06ld\n", (long)timeval.tv_sec, 1739 (long)timeval.tv_usec); 1740 } 1741 1742 /*ARGSUSED*/ 1743 static void 1744 kern_consdev(HANDLER_ARGS) 1745 { 1746 dev_t cons; 1747 size_t sz; 1748 int rc; 1749 1750 sz = sizeof(cons); 1751 rc = sysctl(name, namelen, &cons, &sz, NULL, 0); 1752 if (rc == -1) { 1753 sysctlerror(1); 1754 return; 1755 } 1756 if (sz != sizeof(cons)) 1757 errx(1, "%s: !returned size wrong!", sname); 1758 1759 if (xflag || rflag) 1760 display_struct(pnode, sname, &cons, sz, 1761 DISPLAY_VALUE); 1762 else if (!nflag) 1763 printf("%s%s%s\n", sname, eq, devname(cons, S_IFCHR)); 1764 else 1765 printf("0x%x\n", cons); 1766 } 1767 1768 /*ARGSUSED*/ 1769 static void 1770 kern_cp_time(HANDLER_ARGS) 1771 { 1772 u_int64_t cp_time[CPUSTATES]; 1773 size_t sz; 1774 int rc; 1775 1776 sz = sizeof(cp_time); 1777 rc = sysctl(name, namelen, &cp_time, &sz, NULL, 0); 1778 if (rc == -1) { 1779 sysctlerror(1); 1780 return; 1781 } 1782 if (sz != sizeof(cp_time)) 1783 errx(1, "%s: !returned size wrong!", sname); 1784 1785 if (xflag || rflag) 1786 display_struct(pnode, sname, &cp_time, sz, 1787 DISPLAY_VALUE); 1788 else if (!nflag) 1789 printf("%s: ", sname); 1790 printf("user = %" PRIu64 1791 ", nice = %" PRIu64 1792 ", sys = %" PRIu64 1793 ", intr = %" PRIu64 1794 ", idle = %" PRIu64 1795 "\n", 1796 cp_time[CP_USER], 1797 cp_time[CP_NICE], 1798 cp_time[CP_SYS], 1799 cp_time[CP_INTR], 1800 cp_time[CP_IDLE]); 1801 } 1802 1803 /*ARGSUSED*/ 1804 static void 1805 vm_loadavg(HANDLER_ARGS) 1806 { 1807 struct loadavg loadavg; 1808 size_t sz; 1809 int rc; 1810 1811 sz = sizeof(loadavg); 1812 rc = sysctl(name, namelen, &loadavg, &sz, NULL, 0); 1813 if (rc == -1) { 1814 sysctlerror(1); 1815 return; 1816 } 1817 if (sz != sizeof(loadavg)) 1818 errx(1, "%s: !returned size wrong!", sname); 1819 1820 if (xflag || rflag) 1821 display_struct(pnode, sname, &loadavg, sz, 1822 DISPLAY_VALUE); 1823 else if (!nflag) 1824 printf("%s: ", sname); 1825 printf("%.2f %.2f %.2f\n", 1826 (double) loadavg.ldavg[0] / loadavg.fscale, 1827 (double) loadavg.ldavg[1] / loadavg.fscale, 1828 (double) loadavg.ldavg[2] / loadavg.fscale); 1829 } 1830 1831 /*ARGSUSED*/ 1832 static void 1833 proc_limit(HANDLER_ARGS) 1834 { 1835 u_quad_t olim, *newp, nlim; 1836 size_t osz, nsz; 1837 char *t; 1838 int rc; 1839 1840 osz = sizeof(olim); 1841 if (value != NULL) { 1842 nsz = sizeof(nlim); 1843 newp = &nlim; 1844 if (strcmp(value, "unlimited") == 0) 1845 nlim = RLIM_INFINITY; 1846 else { 1847 errno = 0; 1848 nlim = strtouq(value, &t, 0); 1849 if (*t != '\0' || errno != 0) { 1850 fprintf(warnfp, 1851 "%s: %s: '%s' is not a valid limit\n", 1852 getprogname(), sname, value); 1853 exit(1); 1854 } 1855 } 1856 } 1857 else { 1858 nsz = 0; 1859 newp = NULL; 1860 } 1861 1862 rc = sysctl(name, namelen, &olim, &osz, newp, nsz); 1863 if (rc == -1) { 1864 sysctlerror(newp == NULL); 1865 return; 1866 } 1867 1868 if (newp && qflag) 1869 return; 1870 1871 if (rflag || xflag || olim != RLIM_INFINITY) 1872 display_number(pnode, sname, &olim, sizeof(olim), 1873 newp ? DISPLAY_OLD : DISPLAY_VALUE); 1874 else 1875 display_string(pnode, sname, "unlimited", 10, 1876 newp ? DISPLAY_OLD : DISPLAY_VALUE); 1877 1878 if (newp) { 1879 if (rflag || xflag || nlim != RLIM_INFINITY) 1880 display_number(pnode, sname, &nlim, sizeof(nlim), 1881 DISPLAY_NEW); 1882 else 1883 display_string(pnode, sname, "unlimited", 10, 1884 DISPLAY_NEW); 1885 } 1886 } 1887 1888 #ifdef CPU_DISKINFO 1889 /*ARGSUSED*/ 1890 static void 1891 machdep_diskinfo(HANDLER_ARGS) 1892 { 1893 struct disklist *dl; 1894 struct biosdisk_info *bi; 1895 struct nativedisk_info *ni; 1896 int rc; 1897 size_t sz; 1898 uint i, b, lim; 1899 1900 rc = sysctl(name, namelen, NULL, &sz, NULL, 0); 1901 if (rc == -1) { 1902 sysctlerror(1); 1903 return; 1904 } 1905 dl = malloc(sz); 1906 if (dl == NULL) { 1907 sysctlerror(1); 1908 return; 1909 } 1910 rc = sysctl(name, namelen, dl, &sz, NULL, 0); 1911 if (rc == -1) { 1912 sysctlerror(1); 1913 return; 1914 } 1915 1916 if (!nflag) 1917 printf("%s: ", sname); 1918 lim = dl->dl_nbiosdisks; 1919 if (lim > MAX_BIOSDISKS) 1920 lim = MAX_BIOSDISKS; 1921 for (bi = dl->dl_biosdisks, i = 0; i < lim; bi++, i++) 1922 printf("%x:%" PRIu64 "(%d/%d/%d),%x ", 1923 bi->bi_dev, bi->bi_lbasecs, 1924 bi->bi_cyl, bi->bi_head, bi->bi_sec, 1925 bi->bi_flags); 1926 lim = dl->dl_nnativedisks; 1927 ni = dl->dl_nativedisks; 1928 bi = dl->dl_biosdisks; 1929 /* LINTED -- pointer casts are tedious */ 1930 if ((char *)&ni[lim] != (char *)dl + sz) { 1931 fprintf(warnfp, "size mismatch\n"); 1932 return; 1933 } 1934 for (i = 0; i < lim; ni++, i++) { 1935 char t = ':'; 1936 printf(" %.*s", (int)sizeof ni->ni_devname, 1937 ni->ni_devname); 1938 for (b = 0; b < ni->ni_nmatches; t = ',', b++) 1939 printf("%c%x", t, 1940 bi[ni->ni_biosmatches[b]].bi_dev); 1941 } 1942 printf("\n"); 1943 } 1944 #endif /* CPU_DISKINFO */ 1945