1 /* $NetBSD: sysctl.c,v 1.71 2003/08/07 10:04:40 agc Exp $ */ 2 3 /* 4 * Copyright (c) 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT( 35 "@(#) Copyright (c) 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"); 37 #endif /* not lint */ 38 39 #ifndef lint 40 #if 0 41 static char sccsid[] = "@(#)sysctl.c 8.1 (Berkeley) 6/6/93"; 42 #else 43 __RCSID("$NetBSD: sysctl.c,v 1.71 2003/08/07 10:04:40 agc Exp $"); 44 #endif 45 #endif /* not lint */ 46 47 #include <sys/param.h> 48 #include <sys/gmon.h> 49 #include <sys/stat.h> 50 #include <sys/sysctl.h> 51 #include <sys/socket.h> 52 #include <sys/mount.h> 53 #include <sys/mbuf.h> 54 #include <sys/resource.h> 55 #include <uvm/uvm_param.h> 56 #include <machine/cpu.h> 57 58 #include <ufs/ufs/dinode.h> 59 #include <ufs/ufs/dir.h> 60 #include <ufs/ffs/fs.h> 61 #include <ufs/ffs/ffs_extern.h> 62 63 #include <nfs/rpcv2.h> 64 #include <nfs/nfsproto.h> 65 #include <nfs/nfs.h> 66 67 #include <netinet/in.h> 68 #include <netinet/in_systm.h> 69 #include <netinet/ip.h> 70 #include <netinet/ip_icmp.h> 71 #include <netinet/icmp_var.h> 72 #include <netinet/ip_var.h> 73 #include <netinet/udp.h> 74 #include <netinet/udp_var.h> 75 #include <netinet/tcp.h> 76 #include <netinet/tcp_timer.h> 77 #include <netinet/tcp_var.h> 78 79 #ifdef INET6 80 #include <netinet/ip6.h> 81 #include <netinet/icmp6.h> 82 #include <netinet6/ip6_var.h> 83 #include <netinet6/udp6.h> 84 #include <netinet6/udp6_var.h> 85 #ifdef TCP6 86 #include <netinet6/tcp6.h> 87 #include <netinet6/tcp6_timer.h> 88 #include <netinet6/tcp6_var.h> 89 #endif 90 #include <netinet6/pim6_var.h> 91 #endif /* INET6 */ 92 93 #include "../../sys/compat/linux/common/linux_exec.h" 94 #include "../../sys/compat/irix/irix_sysctl.h" 95 #include "../../sys/compat/darwin/darwin_sysctl.h" 96 97 #ifdef IPSEC 98 #include <net/route.h> 99 #include <netinet6/ipsec.h> 100 #include <netkey/key_var.h> 101 #endif /* IPSEC */ 102 103 #include <sys/pipe.h> 104 105 #include <err.h> 106 #include <ctype.h> 107 #include <errno.h> 108 #include <stdio.h> 109 #include <stdlib.h> 110 #include <string.h> 111 #include <unistd.h> 112 113 struct ctlname topname[] = CTL_NAMES; 114 struct ctlname kernname[] = CTL_KERN_NAMES; 115 struct ctlname vmname[] = CTL_VM_NAMES; 116 struct ctlname vfsname[] = CTL_VFS_NAMES; 117 struct ctlname netname[] = CTL_NET_NAMES; 118 struct ctlname hwname[] = CTL_HW_NAMES; 119 struct ctlname username[] = CTL_USER_NAMES; 120 struct ctlname ddbname[] = CTL_DDB_NAMES; 121 struct ctlname debugname[CTL_DEBUG_MAXID]; 122 #ifdef CTL_MACHDEP_NAMES 123 struct ctlname machdepname[] = CTL_MACHDEP_NAMES; 124 #endif 125 struct ctlname emulname[] = CTL_EMUL_NAMES; 126 struct ctlname vendorname[] = { { 0, 0 } }; 127 128 /* this one is dummy, it's used only for '-a' or '-A' */ 129 struct ctlname procname[] = { {0, 0}, {"curproc", CTLTYPE_NODE} }; 130 131 char names[BUFSIZ]; 132 133 struct list { 134 struct ctlname *list; 135 int size; 136 }; 137 struct list toplist = { topname, CTL_MAXID }; 138 struct list secondlevel[] = { 139 { 0, 0 }, /* CTL_UNSPEC */ 140 { kernname, KERN_MAXID }, /* CTL_KERN */ 141 { vmname, VM_MAXID }, /* CTL_VM */ 142 { vfsname, VFS_MAXID }, /* CTL_VFS */ 143 { netname, NET_MAXID }, /* CTL_NET */ 144 { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */ 145 { hwname, HW_MAXID }, /* CTL_HW */ 146 #ifdef CTL_MACHDEP_NAMES 147 { machdepname, CPU_MAXID }, /* CTL_MACHDEP */ 148 #else 149 { 0, 0 }, /* CTL_MACHDEP */ 150 #endif 151 { username, USER_MAXID }, /* CTL_USER_NAMES */ 152 { ddbname, DDBCTL_MAXID }, /* CTL_DDB_NAMES */ 153 { procname, 2 }, /* dummy name */ 154 { vendorname, 0 }, /* CTL_VENDOR_NAMES */ 155 { emulname, EMUL_MAXID }, /* CTL_EMUL_NAMES */ 156 157 { 0, 0}, 158 }; 159 160 int Aflag, aflag, nflag, qflag, wflag; 161 FILE *warnfp = stderr; 162 163 /* 164 * Variables requiring special processing. 165 */ 166 #define CLOCK 0x00000001 167 #define BOOTTIME 0x00000002 168 #define CONSDEV 0x00000003 169 #define DISKINFO 0x00000004 170 #define CPTIME 0x00000005 171 #define CNMAGIC 0x00000006 172 173 /* 174 * A dummy type for limits, which requires special parsing 175 */ 176 #define CTLTYPE_LIMIT ((~0x1) << 31) 177 178 int main(int, char *[]); 179 180 static void listall(const char *, struct list *); 181 static void parse(char *, int); 182 static void debuginit(void); 183 static int sysctl_inet(char *, char **, int[], int, int *); 184 #ifdef INET6 185 static int sysctl_inet6(char *, char **, int[], int, int *); 186 #endif 187 static int sysctl_vfs(char *, char **, int[], int, int *); 188 static int sysctl_proc(char *, char **, int[], int, int *); 189 static int sysctl_3rd(struct list *, char *, char **, int[], int, int *); 190 191 #ifdef IPSEC 192 struct ctlname keynames[] = KEYCTL_NAMES; 193 struct list keyvars = { keynames, KEYCTL_MAXID }; 194 #endif /*IPSEC*/ 195 struct ctlname vfsgenname[] = CTL_VFSGENCTL_NAMES; 196 struct list vfsgenvars = { vfsgenname, VFSGEN_MAXID }; 197 struct ctlname mbufnames[] = CTL_MBUF_NAMES; 198 struct list mbufvars = { mbufnames, MBUF_MAXID }; 199 struct ctlname pipenames[] = CTL_PIPE_NAMES; 200 struct list pipevars = { pipenames, KERN_PIPE_MAXID }; 201 struct ctlname tkstatnames[] = KERN_TKSTAT_NAMES; 202 struct list tkstatvars = { tkstatnames, KERN_TKSTAT_MAXID }; 203 204 static int sysctl_linux(char *, char **, int[], int, int *); 205 static int sysctl_irix(char *, char **, int[], int, int *); 206 static int sysctl_darwin(char *, char **, int[], int, int *); 207 static int findname(char *, char *, char **, struct list *); 208 static void usage(void); 209 210 #define USEAPP(s, a) \ 211 if (flags) fprintf(warnfp, "%s: use '%s' to view this information\n", s, a) 212 213 214 int 215 main(int argc, char *argv[]) 216 { 217 char *fn = NULL; 218 int ch, lvl1; 219 220 while ((ch = getopt(argc, argv, "Aaf:nqw")) != -1) { 221 switch (ch) { 222 223 case 'A': 224 Aflag = 1; 225 break; 226 227 case 'a': 228 aflag = 1; 229 break; 230 231 case 'f': 232 fn = optarg; 233 wflag = 1; 234 break; 235 236 case 'n': 237 nflag = 1; 238 break; 239 240 case 'q': 241 qflag = 1; 242 break; 243 244 case 'w': 245 wflag = 1; 246 break; 247 248 default: 249 usage(); 250 } 251 } 252 253 if (qflag && !wflag) 254 usage(); 255 256 argc -= optind; 257 argv += optind; 258 259 if (Aflag || aflag) { 260 warnfp = stdout; 261 debuginit(); 262 for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) 263 listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); 264 return 0; 265 } 266 267 if (fn) { 268 FILE *fp; 269 char *l; 270 271 fp = fopen(fn, "r"); 272 if (fp == NULL) { 273 err(1, "%s", fn); 274 } else { 275 for (; (l = fparseln(fp, NULL, NULL, NULL, 0)) != NULL; 276 free(l)) { 277 if (*l) 278 parse(l, 1); 279 } 280 fclose(fp); 281 } 282 } else { 283 if (argc == 0) 284 usage(); 285 while (argc-- > 0) 286 parse(*argv++, 1); 287 } 288 return 0; 289 } 290 291 /* 292 * List all variables known to the system. 293 */ 294 static void 295 listall(const char *prefix, struct list *lp) 296 { 297 int lvl2; 298 char name[BUFSIZ], *cp; 299 300 if (lp->list == 0) 301 return; 302 strlcpy(name, prefix, sizeof(name)); 303 strlcat(name, ".", sizeof(name)); 304 cp = &name[strlen(name)]; 305 for (lvl2 = 0; lvl2 < lp->size; lvl2++) { 306 if (lp->list[lvl2].ctl_name == 0) 307 continue; 308 strlcpy(cp, lp->list[lvl2].ctl_name, 309 sizeof(name) - (cp - name)); 310 parse(name, Aflag); 311 } 312 } 313 314 /* 315 * Parse a name into a MIB entry. 316 * Lookup and print out the MIB entry if it exists. 317 * Set a new value if requested. 318 */ 319 static void 320 parse(char *string, int flags) 321 { 322 int indx, type, state, len; 323 int special = 0; 324 void *newval = 0; 325 int intval, newsize = 0; 326 long long quadval; 327 size_t size; 328 struct list *lp; 329 int mib[CTL_MAXNAME]; 330 char *cp, *bufp, buf[BUFSIZ]; 331 double loads[3]; 332 333 bufp = buf; 334 snprintf(buf, BUFSIZ, "%s", string); 335 if ((cp = strchr(string, '=')) != NULL) { 336 if (!wflag) 337 errx(2, "Must specify -w to set variables"); 338 *strchr(buf, '=') = '\0'; 339 *cp++ = '\0'; 340 while (isspace((unsigned char) *cp)) 341 cp++; 342 newval = cp; 343 newsize = strlen(cp); 344 } 345 if ((indx = findname(string, "top", &bufp, &toplist)) == -1) 346 return; 347 mib[0] = indx; 348 if (indx == CTL_DEBUG) 349 debuginit(); 350 if (mib[0] == CTL_PROC) { 351 type = CTLTYPE_NODE; 352 len = 1; 353 } else { 354 lp = &secondlevel[indx]; 355 if (lp->list == 0) { 356 warnx("Class `%s' is not implemented", 357 topname[indx].ctl_name); 358 return; 359 } 360 if (bufp == NULL) { 361 listall(topname[indx].ctl_name, lp); 362 return; 363 } 364 if ((indx = findname(string, "second", &bufp, lp)) == -1) 365 return; 366 mib[1] = indx; 367 type = lp->list[indx].ctl_type; 368 len = 2; 369 } 370 switch (mib[0]) { 371 372 case CTL_KERN: 373 switch (mib[1]) { 374 case KERN_PROF: 375 mib[2] = GPROF_STATE; 376 size = sizeof state; 377 if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) { 378 if (flags == 0) 379 return; 380 if (!nflag) 381 fprintf(warnfp, "%s: ", string); 382 fprintf(warnfp, 383 "kernel is not compiled for profiling\n"); 384 return; 385 } 386 if (!nflag) 387 printf("%s: %s\n", string, 388 state == GMON_PROF_OFF ? "off" : "running"); 389 return; 390 case KERN_VNODE: 391 case KERN_FILE: 392 USEAPP(string, "pstat"); 393 return; 394 case KERN_PROC: 395 case KERN_PROC2: 396 case KERN_PROC_ARGS: 397 USEAPP(string, "ps"); 398 return; 399 case KERN_CLOCKRATE: 400 special = CLOCK; 401 break; 402 case KERN_BOOTTIME: 403 special = BOOTTIME; 404 break; 405 case KERN_NTPTIME: 406 USEAPP(string, "ntpdc -c kerninfo"); 407 return; 408 case KERN_MBUF: 409 len = sysctl_3rd(&mbufvars, string, &bufp, mib, flags, 410 &type); 411 if (len < 0) 412 return; 413 break; 414 case KERN_CP_TIME: 415 special = CPTIME; 416 break; 417 case KERN_MSGBUF: 418 USEAPP(string, "dmesg"); 419 return; 420 case KERN_CONSDEV: 421 special = CONSDEV; 422 break; 423 case KERN_PIPE: 424 len = sysctl_3rd(&pipevars, string, &bufp, mib, flags, 425 &type); 426 if (len < 0) 427 return; 428 break; 429 case KERN_TKSTAT: 430 len = sysctl_3rd(&tkstatvars, string, &bufp, mib, flags, 431 &type); 432 if (len < 0) 433 return; 434 break; 435 } 436 break; 437 438 case CTL_HW: 439 switch (mib[1]) { 440 case HW_DISKSTATS: 441 USEAPP(string, "iostat"); 442 return; 443 case HW_CNMAGIC: 444 if (!nflag) 445 special = CNMAGIC; 446 break; 447 } 448 break; 449 450 case CTL_VM: 451 switch (mib[1]) { 452 case VM_LOADAVG: 453 getloadavg(loads, 3); 454 if (!nflag) 455 printf("%s: ", string); 456 printf("%.2f %.2f %.2f\n", loads[0], loads[1], 457 loads[2]); 458 return; 459 460 case VM_METER: 461 case VM_UVMEXP: 462 case VM_UVMEXP2: 463 USEAPP(string, "vmstat' or 'systat"); 464 return; 465 } 466 break; 467 468 case CTL_NET: 469 if (mib[1] == PF_INET) { 470 len = sysctl_inet(string, &bufp, mib, flags, &type); 471 if (len >= 0) 472 break; 473 return; 474 } 475 #ifdef INET6 476 else if (mib[1] == PF_INET6) { 477 len = sysctl_inet6(string, &bufp, mib, flags, &type); 478 if (len >= 0) 479 break; 480 return; 481 } 482 #endif /* INET6 */ 483 #ifdef IPSEC 484 else if (mib[1] == PF_KEY) { 485 len = sysctl_3rd(&keyvars, string, &bufp, mib, flags, 486 &type); 487 if (len >= 0) 488 break; 489 return; 490 } 491 #endif /* IPSEC */ 492 if (flags == 0) 493 return; 494 USEAPP(string, "netstat"); 495 return; 496 497 case CTL_DEBUG: 498 mib[2] = CTL_DEBUG_VALUE; 499 len = 3; 500 break; 501 502 case CTL_MACHDEP: 503 #ifdef CPU_CONSDEV 504 if (mib[1] == CPU_CONSDEV) 505 special = CONSDEV; 506 #endif 507 #ifdef CPU_DISKINFO 508 if (mib[1] == CPU_DISKINFO) 509 special = DISKINFO; 510 #endif 511 break; 512 513 case CTL_VFS: 514 if (mib[1] == VFS_GENERIC) { 515 len = sysctl_3rd(&vfsgenvars, string, &bufp, mib, flags, 516 &type); 517 /* Don't bother with VFS_CONF. */ 518 if (mib[2] == VFS_CONF) 519 len = -1; 520 } else 521 len = sysctl_vfs(string, &bufp, mib, flags, &type); 522 if (len < 0) 523 return; 524 525 /* XXX Special-case for NFS stats. */ 526 if (mib[1] == 2 && mib[2] == NFS_NFSSTATS) { 527 USEAPP(string, "nfsstat"); 528 return; 529 } 530 break; 531 532 case CTL_VENDOR: 533 case CTL_USER: 534 case CTL_DDB: 535 break; 536 case CTL_PROC: 537 len = sysctl_proc(string, &bufp, mib, flags, &type); 538 if (len < 0) 539 return; 540 break; 541 case CTL_EMUL: 542 switch (mib[1]) { 543 case EMUL_IRIX: 544 len = sysctl_irix(string, &bufp, mib, flags, &type); 545 break; 546 547 case EMUL_LINUX: 548 len = sysctl_linux(string, &bufp, mib, flags, &type); 549 break; 550 551 case EMUL_DARWIN: 552 len = sysctl_darwin(string, &bufp, mib, flags, &type); 553 break; 554 555 default: 556 warnx("Illegal emul level value: %d", mib[0]); 557 break; 558 } 559 if (len < 0) 560 return; 561 break; 562 default: 563 warnx("Illegal top level value: %d", mib[0]); 564 return; 565 566 } 567 if (bufp) { 568 warnx("Name %s in %s is unknown", bufp, string); 569 return; 570 } 571 if (newsize > 0) { 572 switch (type) { 573 case CTLTYPE_INT: 574 intval = atoi(newval); 575 newval = &intval; 576 newsize = sizeof intval; 577 break; 578 579 case CTLTYPE_LIMIT: 580 if (strcmp(newval, "unlimited") == 0) { 581 quadval = RLIM_INFINITY; 582 newval = &quadval; 583 newsize = sizeof quadval; 584 break; 585 } 586 /* FALLTHROUGH */ 587 case CTLTYPE_QUAD: 588 sscanf(newval, "%lld", &quadval); 589 newval = &quadval; 590 newsize = sizeof quadval; 591 break; 592 } 593 } 594 size = BUFSIZ; 595 if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) { 596 if (flags == 0) 597 return; 598 switch (errno) { 599 case EOPNOTSUPP: 600 fprintf(warnfp, 601 "%s: the value is not available\n", string); 602 return; 603 case ENOTDIR: 604 fprintf(warnfp, 605 "%s: the specification is incomplete\n", string); 606 return; 607 case ENOMEM: 608 fprintf(warnfp, 609 "%s: this type is unknown to this program\n", 610 string); 611 return; 612 default: 613 fprintf(warnfp, "%s: sysctl() failed with %s\n", 614 string, strerror(errno)); 615 return; 616 } 617 } 618 if (qflag && (newsize > 0)) 619 return; 620 if (special == CLOCK) { 621 struct clockinfo *clkp = (struct clockinfo *)buf; 622 623 if (!nflag) 624 printf("%s: ", string); 625 printf( 626 "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n", 627 clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz); 628 return; 629 } 630 if (special == BOOTTIME) { 631 struct timeval *btp = (struct timeval *)buf; 632 time_t boottime; 633 634 if (!nflag) { 635 boottime = btp->tv_sec; 636 /* ctime() provides the trailing newline */ 637 printf("%s = %s", string, ctime(&boottime)); 638 } else 639 printf("%ld\n", (long) btp->tv_sec); 640 return; 641 } 642 if (special == CONSDEV) { 643 dev_t dev = *(dev_t *)buf; 644 645 if (!nflag) 646 printf("%s = %s\n", string, devname(dev, S_IFCHR)); 647 else 648 printf("0x%x\n", dev); 649 return; 650 } 651 if (special == DISKINFO) { 652 #ifdef CPU_DISKINFO 653 /* Don't know a good way to deal with this i386 specific one */ 654 /* OTOH this does pass the info out... */ 655 struct disklist *dl = (void *)buf; 656 struct biosdisk_info *bi; 657 struct nativedisk_info *ni; 658 uint i, b, lim; 659 if (!nflag) 660 printf("%s: ", string); 661 lim = dl->dl_nbiosdisks; 662 if (lim > MAX_BIOSDISKS) 663 lim = MAX_BIOSDISKS; 664 for (bi = dl->dl_biosdisks, i = 0; i < lim; bi++, i++) 665 printf("%x:%lld(%d/%d/%d),%x ", 666 bi->bi_dev, (long long)bi->bi_lbasecs, 667 bi->bi_cyl, bi->bi_head, bi->bi_sec, 668 bi->bi_flags); 669 lim = dl->dl_nnativedisks; 670 ni = dl->dl_nativedisks; 671 bi = dl->dl_biosdisks; 672 if ((char *)&ni[lim] != (char *)buf + size) { 673 fprintf(warnfp, "size mismatch\n"); 674 return; 675 } 676 for (i = 0; i < lim; ni++, i++) { 677 char sep = ':'; 678 printf(" %.*s", (int)sizeof ni->ni_devname, 679 ni->ni_devname); 680 for (b = 0; b < ni->ni_nmatches; sep = ',', b++) 681 printf("%c%x", sep, 682 bi[ni->ni_biosmatches[b]].bi_dev); 683 } 684 printf("\n"); 685 #endif 686 return; 687 } 688 if (special == CPTIME) { 689 u_int64_t *cp_time = (u_int64_t *)buf; 690 691 if (!nflag) 692 printf("%s: ", string); 693 printf("user = %llu, nice = %llu, sys = %llu, intr = %llu, " 694 "idle = %llu\n", (unsigned long long) cp_time[0], 695 (unsigned long long) cp_time[1], 696 (unsigned long long) cp_time[2], 697 (unsigned long long) cp_time[3], 698 (unsigned long long) cp_time[4]); 699 return; 700 } 701 if (special == CNMAGIC) { 702 int i; 703 704 if (!nflag) 705 printf("%s%s ", string, newsize ? ":" : " ="); 706 for (i = 0; i < size - 1; i++) 707 printf("\\x%2.2x", buf[i]); 708 if (newsize != 0) { 709 printf(" -> "); 710 for (i = 0; i < newsize - 1; i++) 711 printf("\\x%2.2x", ((unsigned char *)newval)[i]); 712 } 713 printf("\n"); 714 return; 715 } 716 717 switch (type) { 718 case CTLTYPE_INT: 719 if (newsize == 0) { 720 if (!nflag) 721 printf("%s = ", string); 722 printf("%d\n", *(int *)buf); 723 } else { 724 if (!nflag) 725 printf("%s: %d -> ", string, *(int *)buf); 726 printf("%d\n", *(int *)newval); 727 } 728 return; 729 730 case CTLTYPE_STRING: 731 /* If sysctl() didn't return any data, don't print a string. */ 732 if (size == 0) 733 buf[0] = '\0'; 734 if (newsize == 0) { 735 if (!nflag) 736 printf("%s = ", string); 737 printf("%s\n", buf); 738 } else { 739 if (!nflag) 740 printf("%s: %s -> ", string, buf); 741 printf("%s\n", (char *) newval); 742 } 743 return; 744 745 case CTLTYPE_LIMIT: 746 #define PRINTF_LIMIT(lim) { \ 747 if ((lim) == RLIM_INFINITY) \ 748 printf("unlimited");\ 749 else \ 750 printf("%lld", (long long)(lim)); \ 751 } 752 753 if (newsize == 0) { 754 if (!nflag) 755 printf("%s = ", string); 756 PRINTF_LIMIT((long long)(*(quad_t *)buf)); 757 } else { 758 if (!nflag) { 759 printf("%s: ", string); 760 PRINTF_LIMIT((long long)(*(quad_t *)buf)); 761 printf(" -> "); 762 } 763 PRINTF_LIMIT((long long)(*(quad_t *)newval)); 764 } 765 printf("\n"); 766 return; 767 #undef PRINTF_LIMIT 768 769 case CTLTYPE_QUAD: 770 if (newsize == 0) { 771 if (!nflag) 772 printf("%s = ", string); 773 printf("%lld\n", (long long)(*(quad_t *)buf)); 774 } else { 775 if (!nflag) 776 printf("%s: %lld -> ", string, 777 (long long)(*(quad_t *)buf)); 778 printf("%lld\n", (long long)(*(quad_t *)newval)); 779 } 780 return; 781 782 case CTLTYPE_STRUCT: 783 warnx("%s: unknown structure returned", string); 784 return; 785 786 default: 787 case CTLTYPE_NODE: 788 warnx("%s: unknown type returned", string); 789 return; 790 } 791 } 792 793 /* 794 * Initialize the set of debugging names 795 */ 796 static void 797 debuginit(void) 798 { 799 int mib[3], loc, i; 800 size_t size; 801 802 if (secondlevel[CTL_DEBUG].list != 0) 803 return; 804 secondlevel[CTL_DEBUG].list = debugname; 805 mib[0] = CTL_DEBUG; 806 mib[2] = CTL_DEBUG_NAME; 807 for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) { 808 mib[1] = i; 809 size = BUFSIZ - loc; 810 if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1) 811 continue; 812 debugname[i].ctl_name = &names[loc]; 813 debugname[i].ctl_type = CTLTYPE_INT; 814 loc += size; 815 } 816 } 817 818 struct ctlname inetname[] = CTL_IPPROTO_NAMES; 819 struct ctlname ipname[] = IPCTL_NAMES; 820 struct ctlname icmpname[] = ICMPCTL_NAMES; 821 struct ctlname tcpname[] = TCPCTL_NAMES; 822 struct ctlname udpname[] = UDPCTL_NAMES; 823 #ifdef IPSEC 824 struct ctlname ipsecname[] = IPSECCTL_NAMES; 825 #endif 826 struct list inetlist = { inetname, IPPROTO_MAXID }; 827 struct list inetvars[] = { 828 /*0*/ { ipname, IPCTL_MAXID }, /* ip */ 829 { icmpname, ICMPCTL_MAXID }, /* icmp */ 830 { 0, 0 }, /* igmp */ 831 { 0, 0 }, /* ggmp */ 832 { 0, 0 }, 833 { 0, 0 }, 834 { tcpname, TCPCTL_MAXID }, /* tcp */ 835 { 0, 0 }, 836 { 0, 0 }, /* egp */ 837 { 0, 0 }, 838 /*10*/ { 0, 0 }, 839 { 0, 0 }, 840 { 0, 0 }, /* pup */ 841 { 0, 0 }, 842 { 0, 0 }, 843 { 0, 0 }, 844 { 0, 0 }, 845 { udpname, UDPCTL_MAXID }, /* udp */ 846 { 0, 0 }, 847 { 0, 0 }, 848 /*20*/ { 0, 0 }, 849 { 0, 0 }, 850 { 0, 0 }, /* idp */ 851 { 0, 0 }, 852 { 0, 0 }, 853 { 0, 0 }, 854 { 0, 0 }, 855 { 0, 0 }, 856 { 0, 0 }, 857 { 0, 0 }, 858 /*30*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 859 { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 860 /*40*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 861 { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 862 #ifdef IPSEC 863 { ipsecname, IPSECCTL_MAXID }, /* esp - for backward compatibility */ 864 { ipsecname, IPSECCTL_MAXID }, /* ah */ 865 #else 866 { 0, 0 }, 867 { 0, 0 }, 868 #endif 869 }; 870 871 /* 872 * handle internet requests 873 */ 874 static int 875 sysctl_inet(char *string, char **bufpp, int mib[], int flags, int *typep) 876 { 877 struct list *lp; 878 int indx; 879 880 if (*bufpp == NULL) { 881 listall(string, &inetlist); 882 return (-1); 883 } 884 if ((indx = findname(string, "third", bufpp, &inetlist)) == -1) 885 return (-1); 886 mib[2] = indx; 887 if (indx <= IPPROTO_MAXID && inetvars[indx].list != NULL) 888 lp = &inetvars[indx]; 889 else if (!flags) 890 return (-1); 891 else { 892 fprintf(warnfp, 893 "%s: no variables defined for protocol\n", string); 894 return (-1); 895 } 896 if (*bufpp == NULL) { 897 listall(string, lp); 898 return (-1); 899 } 900 if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 901 return (-1); 902 mib[3] = indx; 903 *typep = lp->list[indx].ctl_type; 904 return (4); 905 } 906 907 #ifdef INET6 908 struct ctlname inet6name[] = CTL_IPV6PROTO_NAMES; 909 struct ctlname ip6name[] = IPV6CTL_NAMES; 910 struct ctlname icmp6name[] = ICMPV6CTL_NAMES; 911 struct ctlname udp6name[] = UDP6CTL_NAMES; 912 struct ctlname pim6name[] = PIM6CTL_NAMES; 913 struct ctlname ipsec6name[] = IPSEC6CTL_NAMES; 914 struct list inet6list = { inet6name, IPV6PROTO_MAXID }; 915 struct list inet6vars[] = { 916 /*0*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 917 { 0, 0 }, 918 { tcpname, TCPCTL_MAXID }, /* tcp6 */ 919 { 0, 0 }, 920 { 0, 0 }, 921 { 0, 0 }, 922 /*10*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 923 { 0, 0 }, 924 { 0, 0 }, 925 { udp6name, UDP6CTL_MAXID }, /* udp6 */ 926 { 0, 0 }, 927 { 0, 0 }, 928 /*20*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 929 { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 930 /*30*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 931 { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 932 /*40*/ { 0, 0 }, 933 { ip6name, IPV6CTL_MAXID }, /* ipv6 */ 934 { 0, 0 }, 935 { 0, 0 }, 936 { 0, 0 }, 937 { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 938 #ifdef IPSEC 939 /*50*/ { ipsec6name, IPSECCTL_MAXID }, /* esp6 - for backward compatibility */ 940 { ipsec6name, IPSECCTL_MAXID }, /* ah6 */ 941 #else 942 { 0, 0 }, 943 { 0, 0 }, 944 #endif 945 { 0, 0 }, 946 { 0, 0 }, 947 { 0, 0 }, 948 { 0, 0 }, 949 { 0, 0 }, 950 { 0, 0 }, 951 { icmp6name, ICMPV6CTL_MAXID }, /* icmp6 */ 952 { 0, 0 }, 953 /*60*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 954 { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 955 /*70*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 956 { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 957 /*80*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 958 { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 959 /*90*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 960 { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 961 /*100*/ { 0, 0 }, 962 { 0, 0 }, 963 { 0, 0 }, 964 { pim6name, PIM6CTL_MAXID }, /* pim6 */ 965 }; 966 967 /* 968 * handle internet6 requests 969 */ 970 static int 971 sysctl_inet6(char *string, char **bufpp, int mib[], int flags, int *typep) 972 { 973 struct list *lp; 974 int indx; 975 976 if (*bufpp == NULL) { 977 listall(string, &inet6list); 978 return (-1); 979 } 980 if ((indx = findname(string, "third", bufpp, &inet6list)) == -1) 981 return (-1); 982 mib[2] = indx; 983 if (indx <= sizeof(inet6vars)/sizeof(inet6vars[0]) 984 && inet6vars[indx].list != NULL) { 985 lp = &inet6vars[indx]; 986 } else if (!flags) { 987 return (-1); 988 } else { 989 fprintf(stderr, "%s: no variables defined for this protocol\n", 990 string); 991 return (-1); 992 } 993 if (*bufpp == NULL) { 994 listall(string, lp); 995 return (-1); 996 } 997 if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 998 return (-1); 999 mib[3] = indx; 1000 *typep = lp->list[indx].ctl_type; 1001 return (4); 1002 } 1003 #endif /* INET6 */ 1004 1005 struct ctlname ffsname[] = FFS_NAMES; 1006 struct ctlname nfsname[] = NFS_NAMES; 1007 struct list vfsvars[] = { 1008 { 0, 0 }, /* generic */ 1009 { ffsname, FFS_MAXID }, /* FFS */ 1010 { nfsname, NFS_MAXID }, /* NFS */ 1011 { 0, 0 }, /* MFS */ 1012 { 0, 0 }, /* MSDOS */ 1013 { 0, 0 }, /* LFS */ 1014 { 0, 0 }, /* old LOFS */ 1015 { 0, 0 }, /* FDESC */ 1016 { 0, 0 }, /* PORTAL */ 1017 { 0, 0 }, /* NULL */ 1018 { 0, 0 }, /* UMAP */ 1019 { 0, 0 }, /* KERNFS */ 1020 { 0, 0 }, /* PROCFS */ 1021 { 0, 0 }, /* AFS */ 1022 { 0, 0 }, /* CD9660 */ 1023 { 0, 0 }, /* UNION */ 1024 { 0, 0 }, /* ADOSFS */ 1025 { 0, 0 }, /* EXT2FS */ 1026 { 0, 0 }, /* CODA */ 1027 { 0, 0 }, /* FILECORE */ 1028 }; 1029 1030 /* 1031 * handle vfs requests 1032 */ 1033 static int 1034 sysctl_vfs(char *string, char **bufpp, int mib[], int flags, int *typep) 1035 { 1036 struct list *lp = &vfsvars[mib[1]]; 1037 int indx; 1038 1039 if (lp->list == NULL) { 1040 if (flags) 1041 fprintf(warnfp, 1042 "%s: no variables defined for file system\n", 1043 string); 1044 return (-1); 1045 } 1046 if (*bufpp == NULL) { 1047 listall(string, lp); 1048 return (-1); 1049 } 1050 if ((indx = findname(string, "third", bufpp, lp)) == -1) 1051 return (-1); 1052 mib[2] = indx; 1053 *typep = lp->list[indx].ctl_type; 1054 return (3); 1055 } 1056 1057 /* 1058 * handle 3rd level requests. 1059 */ 1060 static int 1061 sysctl_3rd(struct list *lp, char *string, char **bufpp, int mib[], int flags, 1062 int *typep) 1063 { 1064 int indx; 1065 1066 if (*bufpp == NULL) { 1067 listall(string, lp); 1068 return (-1); 1069 } 1070 if ((indx = findname(string, "third", bufpp, lp)) == -1) 1071 return (-1); 1072 mib[2] = indx; 1073 *typep = lp->list[indx].ctl_type; 1074 return (3); 1075 } 1076 1077 struct ctlname procnames[] = PROC_PID_NAMES; 1078 struct list procvars = {procnames, PROC_PID_MAXID}; 1079 struct ctlname proclimitnames[] = PROC_PID_LIMIT_NAMES; 1080 struct list proclimitvars = {proclimitnames, PROC_PID_LIMIT_MAXID}; 1081 struct ctlname proclimittypenames[] = PROC_PID_LIMIT_TYPE_NAMES; 1082 struct list proclimittypevars = {proclimittypenames, 1083 PROC_PID_LIMIT_TYPE_MAXID}; 1084 /* 1085 * handle kern.proc requests 1086 */ 1087 static int 1088 sysctl_proc(char *string, char **bufpp, int mib[], int flags, int *typep) 1089 { 1090 char *cp, name[BUFSIZ]; 1091 struct list *lp; 1092 int indx; 1093 1094 if (*bufpp == NULL) { 1095 strlcpy(name, string, sizeof(name)); 1096 strlcat(name, ".curproc", sizeof(name)); 1097 parse(name, Aflag); 1098 return (-1); 1099 } 1100 cp = strsep(bufpp, "."); 1101 if (cp == NULL) { 1102 warnx("%s: incomplete specification", string); 1103 return (-1); 1104 } 1105 if (strcmp(cp, "curproc") == 0) { 1106 mib[1] = PROC_CURPROC; 1107 } else { 1108 mib[1] = atoi(cp); 1109 if (mib[1] == 0) { 1110 warnx("second level name %s in %s is invalid", cp, 1111 string); 1112 return (-1); 1113 } 1114 } 1115 *typep = CTLTYPE_NODE; 1116 lp = &procvars; 1117 if (*bufpp == NULL) { 1118 listall(string, lp); 1119 return (-1); 1120 } 1121 if ((indx = findname(string, "third", bufpp, lp)) == -1) 1122 return (-1); 1123 mib[2] = indx; 1124 *typep = lp->list[indx].ctl_type; 1125 if (*typep != CTLTYPE_NODE) 1126 return(3); 1127 lp = &proclimitvars; 1128 if (*bufpp == NULL) { 1129 listall(string, lp); 1130 return (-1); 1131 } 1132 if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 1133 return (-1); 1134 mib[3] = indx; 1135 lp = &proclimittypevars; 1136 if (*bufpp == NULL) { 1137 listall(string, lp); 1138 return (-1); 1139 } 1140 if ((indx = findname(string, "fifth", bufpp, lp)) == -1) 1141 return (-1); 1142 mib[4] = indx; 1143 *typep = CTLTYPE_LIMIT; 1144 return(5); 1145 } 1146 1147 struct ctlname linuxnames[] = EMUL_LINUX_NAMES; 1148 struct list linuxvars = { linuxnames, EMUL_LINUX_MAXID }; 1149 struct ctlname linuxkernnames[] = EMUL_LINUX_KERN_NAMES; 1150 struct list linuxkernvars = { linuxkernnames, EMUL_LINUX_KERN_MAXID }; 1151 1152 static int 1153 sysctl_linux(char *string, char **bufpp, int mib[], int flags, int *typep) 1154 { 1155 struct list *lp = &linuxvars; 1156 int indx; 1157 char name[BUFSIZ]; 1158 1159 if (*bufpp == NULL) { 1160 strlcpy(name, string, sizeof(name)); 1161 strlcat(name, ".kern", sizeof(name)); 1162 listall(name, &linuxkernvars); 1163 return (-1); 1164 } 1165 if ((indx = findname(string, "third", bufpp, lp)) == -1) 1166 return (-1); 1167 mib[2] = indx; 1168 lp = &linuxkernvars; 1169 *typep = lp->list[indx].ctl_type; 1170 if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 1171 return (-1); 1172 mib[3] = indx; 1173 *typep = lp->list[indx].ctl_type; 1174 return (4); 1175 } 1176 1177 struct ctlname irixnames[] = EMUL_IRIX_NAMES; 1178 struct list irixvars = { irixnames, EMUL_IRIX_MAXID }; 1179 struct ctlname irixkernnames[] = EMUL_IRIX_KERN_NAMES; 1180 struct list irixkernvars = { irixkernnames, EMUL_IRIX_KERN_MAXID }; 1181 1182 static int 1183 sysctl_irix(char *string, char **bufpp, int mib[], int flags, int *typep) 1184 { 1185 struct list *lp = &irixvars; 1186 int indx; 1187 char name[BUFSIZ]; 1188 1189 if (*bufpp == NULL) { 1190 strlcpy(name, string, sizeof(name)); 1191 strlcat(name, ".kern", sizeof(name)); 1192 listall(name, &irixkernvars); 1193 return (-1); 1194 } 1195 if ((indx = findname(string, "third", bufpp, lp)) == -1) 1196 return (-1); 1197 mib[2] = indx; 1198 lp = &irixkernvars; 1199 *typep = lp->list[indx].ctl_type; 1200 if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 1201 return (-1); 1202 mib[3] = indx; 1203 *typep = lp->list[indx].ctl_type; 1204 return (4); 1205 } 1206 1207 struct ctlname darwinnames[] = EMUL_DARWIN_NAMES; 1208 struct list darwinvars = { darwinnames, EMUL_DARWIN_MAXID }; 1209 1210 static int 1211 sysctl_darwin(char *string, char **bufpp, int mib[], int flags, int *typep) 1212 { 1213 struct list *lp = &darwinvars; 1214 int indx; 1215 1216 if (*bufpp == NULL) { 1217 listall(string, &darwinvars); 1218 return (-1); 1219 } 1220 if ((indx = findname(string, "third", bufpp, lp)) == -1) 1221 return (-1); 1222 mib[2] = indx; 1223 lp = &darwinvars; 1224 *typep = lp->list[indx].ctl_type; 1225 return (3); 1226 } 1227 1228 /* 1229 * Scan a list of names searching for a particular name. 1230 */ 1231 static int 1232 findname(char *string, char *level, char **bufp, struct list *namelist) 1233 { 1234 char *name; 1235 int i; 1236 1237 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { 1238 warnx("%s: incomplete specification", string); 1239 return (-1); 1240 } 1241 for (i = 0; i < namelist->size; i++) 1242 if (namelist->list[i].ctl_name != NULL && 1243 strcmp(name, namelist->list[i].ctl_name) == 0) 1244 break; 1245 if (i == namelist->size) { 1246 warnx("%s level name %s in %s is invalid", 1247 level, name, string); 1248 return (-1); 1249 } 1250 return (i); 1251 } 1252 1253 static void 1254 usage(void) 1255 { 1256 const char *progname = getprogname(); 1257 1258 (void)fprintf(stderr, 1259 "Usage:\t%s %s\n\t%s %s\n\t%s %s\n\t%s %s\n\t%s %s\n", 1260 progname, "[-n] variable ...", 1261 progname, "[-n] [-q] -w variable=value ...", 1262 progname, "[-n] -a", 1263 progname, "[-n] -A", 1264 progname, "[-n] [-q] -f file"); 1265 exit(1); 1266 } 1267