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