158888Smckusick /* 258888Smckusick * Copyright (c) 1993 The Regents of the University of California. 358888Smckusick * All rights reserved. 458888Smckusick * 558888Smckusick * %sccs.include.redist.c% 658888Smckusick */ 758888Smckusick 858888Smckusick #ifndef lint 958888Smckusick char copyright[] = 1058888Smckusick "@(#) Copyright (c) 1993 The Regents of the University of California.\n\ 1158888Smckusick All rights reserved.\n"; 1258888Smckusick #endif /* not lint */ 1358888Smckusick 1458888Smckusick #ifndef lint 15*60426Smckusick static char sccsid[] = "@(#)sysctl.c 5.12 (Berkeley) 05/26/93"; 1658888Smckusick #endif /* not lint */ 1758888Smckusick 1859379Sbostic #include <sys/param.h> 1959658Smckusick #include <sys/gmon.h> 2058888Smckusick #include <sys/stat.h> 2158888Smckusick #include <sys/sysctl.h> 2258888Smckusick #include <sys/socket.h> 2358888Smckusick #include <vm/vm_param.h> 24*60426Smckusick #include <machine/cpu.h> 2559379Sbostic 2659140Smckusick #include <netinet/in.h> 2759140Smckusick #include <netinet/in_systm.h> 2859140Smckusick #include <netinet/ip.h> 2959140Smckusick #include <netinet/ip_icmp.h> 3059140Smckusick #include <netinet/icmp_var.h> 3159311Smckusick #include <netinet/ip_var.h> 3259311Smckusick #include <netinet/udp.h> 3359311Smckusick #include <netinet/udp_var.h> 3459379Sbostic 3558888Smckusick #include <errno.h> 3659379Sbostic #include <stdio.h> 3758888Smckusick #include <stdlib.h> 3858888Smckusick #include <string.h> 3958888Smckusick 4059140Smckusick struct ctlname topname[] = CTL_NAMES; 4159140Smckusick struct ctlname kernname[] = CTL_KERN_NAMES; 4259140Smckusick struct ctlname vmname[] = CTL_VM_NAMES; 4359140Smckusick struct ctlname netname[] = CTL_NET_NAMES; 4459140Smckusick struct ctlname hwname[] = CTL_HW_NAMES; 4559719Sbostic struct ctlname username[] = CTL_USER_NAMES; 4659159Smckusick struct ctlname debugname[CTL_DEBUG_MAXID]; 47*60426Smckusick #ifdef CTL_MACHDEP_NAMES 48*60426Smckusick struct ctlname machdepname[] = CTL_MACHDEP_NAMES; 49*60426Smckusick #endif 5059159Smckusick char names[BUFSIZ]; 5158888Smckusick 5258888Smckusick struct list { 5359140Smckusick struct ctlname *list; 5458888Smckusick int size; 5559140Smckusick }; 5659140Smckusick struct list toplist = { topname, CTL_MAXID }; 5759140Smckusick struct list secondlevel[] = { 5858888Smckusick { 0, 0 }, /* CTL_UNSPEC */ 5958888Smckusick { kernname, KERN_MAXID }, /* CTL_KERN */ 6058888Smckusick { vmname, VM_MAXID }, /* CTL_VM */ 6158888Smckusick { 0, 0 }, /* CTL_FS */ 6258888Smckusick { netname, NET_MAXID }, /* CTL_NET */ 6359159Smckusick { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */ 6458888Smckusick { hwname, HW_MAXID }, /* CTL_HW */ 65*60426Smckusick #ifdef CTL_MACHDEP_NAMES 66*60426Smckusick { machdepname, CPU_MAXID }, /* CTL_MACHDEP */ 67*60426Smckusick #else 6858888Smckusick { 0, 0 }, /* CTL_MACHDEP */ 69*60426Smckusick #endif 7059719Sbostic { username, USER_MAXID }, /* CTL_USER_NAMES */ 7158888Smckusick }; 7258888Smckusick 7358910Smckusick int Aflag, aflag, nflag, wflag; 7458888Smckusick 75*60426Smckusick /* 76*60426Smckusick * Variables requiring special processing. 77*60426Smckusick */ 78*60426Smckusick #define CLOCK 0x00000001 79*60426Smckusick #define BOOTTIME 0x00000002 80*60426Smckusick #define CONSDEV 0x00000004 81*60426Smckusick 8258888Smckusick int 8358888Smckusick main(argc, argv) 8458888Smckusick int argc; 8558888Smckusick char *argv[]; 8658888Smckusick { 8758888Smckusick extern char *optarg; 8858888Smckusick extern int optind; 8958910Smckusick int ch, lvl1; 9058888Smckusick 9158910Smckusick while ((ch = getopt(argc, argv, "Aanw")) != EOF) { 9258888Smckusick switch (ch) { 9358888Smckusick 9458888Smckusick case 'A': 9558888Smckusick Aflag = 1; 9658888Smckusick break; 9758888Smckusick 9858888Smckusick case 'a': 9958888Smckusick aflag = 1; 10058888Smckusick break; 10158888Smckusick 10258910Smckusick case 'n': 10358910Smckusick nflag = 1; 10458910Smckusick break; 10558910Smckusick 10658888Smckusick case 'w': 10758888Smckusick wflag = 1; 10858888Smckusick break; 10958888Smckusick 11058888Smckusick default: 11158888Smckusick usage(); 11258888Smckusick } 11358888Smckusick } 11458888Smckusick argc -= optind; 11558888Smckusick argv += optind; 11658888Smckusick 11758888Smckusick if (Aflag || aflag) { 11859159Smckusick debuginit(); 11958910Smckusick for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) 12059140Smckusick listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); 12158888Smckusick exit(0); 12258888Smckusick } 12358888Smckusick if (argc == 0) 12458888Smckusick usage(); 12558888Smckusick while (argc-- > 0) 12658888Smckusick parse(*argv, 1); 12758888Smckusick exit(0); 12858888Smckusick } 12958888Smckusick 13058888Smckusick /* 13158888Smckusick * List all variables known to the system. 13258888Smckusick */ 13359140Smckusick listall(prefix, lp) 13459140Smckusick char *prefix; 13559140Smckusick struct list *lp; 13658888Smckusick { 13758910Smckusick int lvl2; 13858888Smckusick char *cp, name[BUFSIZ]; 13958888Smckusick 14058910Smckusick if (lp->list == 0) 14158910Smckusick return; 14259140Smckusick strcpy(name, prefix); 14358910Smckusick cp = &name[strlen(name)]; 14458910Smckusick *cp++ = '.'; 14559140Smckusick for (lvl2 = 0; lvl2 < lp->size; lvl2++) { 14659140Smckusick if (lp->list[lvl2].ctl_name == 0) 14759140Smckusick continue; 14859140Smckusick strcpy(cp, lp->list[lvl2].ctl_name); 14958910Smckusick parse(name, Aflag); 15058888Smckusick } 15158888Smckusick } 15258888Smckusick 15358888Smckusick /* 15458888Smckusick * Parse a name into a MIB entry. 15558888Smckusick * Lookup and print out the MIB entry if it exists. 15658888Smckusick * Set a new value if requested. 15758888Smckusick */ 15858888Smckusick parse(string, flags) 15958888Smckusick char *string; 16058888Smckusick int flags; 16158888Smckusick { 16259658Smckusick int indx, type, state, size, len; 163*60426Smckusick int special = 0; 16458888Smckusick void *newval = 0; 16558888Smckusick int intval, newsize = 0; 16659140Smckusick quad_t quadval; 16759140Smckusick struct list *lp; 16858888Smckusick int mib[CTL_MAXNAME]; 16958888Smckusick char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ]; 17058888Smckusick 17158888Smckusick bufp = buf; 17258888Smckusick snprintf(buf, BUFSIZ, "%s", string); 17358888Smckusick if ((cp = strchr(string, '=')) != NULL) { 17458888Smckusick if (!wflag) { 17558888Smckusick fprintf(stderr, "Must specify -w to set variables\n"); 17658888Smckusick exit(2); 17758888Smckusick } 17858888Smckusick *strchr(buf, '=') = '\0'; 17958888Smckusick *cp++ = '\0'; 18058888Smckusick while (isspace(*cp)) 18158888Smckusick cp++; 18259140Smckusick newval = cp; 18359140Smckusick newsize = strlen(cp); 18458888Smckusick } 18559140Smckusick if ((indx = findname(string, "top", &bufp, &toplist)) == -1) 18658888Smckusick return; 18758888Smckusick mib[0] = indx; 18859159Smckusick if (indx == CTL_DEBUG) 18959159Smckusick debuginit(); 19058888Smckusick lp = &secondlevel[indx]; 19158888Smckusick if (lp->list == 0) { 19258888Smckusick fprintf(stderr, "%s: class is not implemented\n", 19358888Smckusick topname[indx]); 19458888Smckusick return; 19558888Smckusick } 19658910Smckusick if (bufp == NULL) { 19759140Smckusick listall(topname[indx].ctl_name, lp); 19858910Smckusick return; 19958910Smckusick } 20058888Smckusick if ((indx = findname(string, "second", &bufp, lp)) == -1) 20158888Smckusick return; 20258888Smckusick mib[1] = indx; 20359140Smckusick type = lp->list[indx].ctl_type; 20459140Smckusick len = 2; 20558888Smckusick switch (mib[0]) { 20658888Smckusick 20758888Smckusick case CTL_KERN: 20858888Smckusick switch (mib[1]) { 20959658Smckusick case KERN_PROF: 21059658Smckusick mib[2] = GPROF_STATE; 21159658Smckusick size = sizeof state; 21259658Smckusick if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) { 21359658Smckusick if (flags == 0) 21459658Smckusick return; 21559658Smckusick if (!nflag) 21659658Smckusick fprintf(stdout, "%s: ", string); 21759658Smckusick fprintf(stderr, 21859658Smckusick "kernel is not compiled for profiling\n"); 21959658Smckusick return; 22059658Smckusick } 22159658Smckusick if (!nflag) 22259658Smckusick fprintf(stdout, "%s: %s\n", string, 22359658Smckusick state == GMON_PROF_OFF ? "off" : "running"); 22459658Smckusick return; 22558888Smckusick case KERN_VNODE: 22658888Smckusick case KERN_FILE: 22758888Smckusick if (flags == 0) 22858888Smckusick return; 22958888Smckusick fprintf(stderr, 23058888Smckusick "Use pstat to view %s information\n", string); 23158888Smckusick return; 23258888Smckusick case KERN_PROC: 23358888Smckusick if (flags == 0) 23458888Smckusick return; 23558888Smckusick fprintf(stderr, 23658888Smckusick "Use ps to view %s information\n", string); 23758888Smckusick return; 23858888Smckusick case KERN_CLOCKRATE: 239*60426Smckusick special |= CLOCK; 24058888Smckusick break; 24160154Smckusick case KERN_BOOTTIME: 242*60426Smckusick special |= BOOTTIME; 24360154Smckusick break; 24458888Smckusick } 24558888Smckusick break; 24658888Smckusick 24758888Smckusick case CTL_HW: 24858888Smckusick break; 24958888Smckusick 25058888Smckusick case CTL_VM: 25158888Smckusick if (mib[1] == VM_LOADAVG) { 25258888Smckusick double loads[3]; 25358888Smckusick 25458888Smckusick getloadavg(loads, 3); 25558910Smckusick if (!nflag) 25658910Smckusick fprintf(stdout, "%s: ", string); 25758910Smckusick fprintf(stdout, "%.2f %.2f %.2f\n", 25858888Smckusick loads[0], loads[1], loads[2]); 25958888Smckusick return; 26058888Smckusick } 26158888Smckusick if (flags == 0) 26258888Smckusick return; 26358888Smckusick fprintf(stderr, 26458888Smckusick "Use vmstat or systat to view %s information\n", string); 26558888Smckusick return; 26658888Smckusick 26758888Smckusick case CTL_NET: 26859140Smckusick if (mib[1] == PF_INET) { 26959140Smckusick len = sysctl_inet(string, &bufp, mib, flags, &type); 27059140Smckusick if (len >= 0) 27159140Smckusick break; 27259140Smckusick return; 27359140Smckusick } 27458888Smckusick if (flags == 0) 27558888Smckusick return; 27658888Smckusick fprintf(stderr, "Use netstat to view %s information\n", string); 27758888Smckusick return; 27858888Smckusick 27959159Smckusick case CTL_DEBUG: 28059159Smckusick mib[2] = CTL_DEBUG_VALUE; 28159159Smckusick len = 3; 28259159Smckusick break; 28359159Smckusick 284*60426Smckusick case CTL_MACHDEP: 285*60426Smckusick #ifdef CPU_CONSDEV 286*60426Smckusick if (mib[1] == CPU_CONSDEV) 287*60426Smckusick special |= CONSDEV; 288*60426Smckusick #endif 289*60426Smckusick break; 290*60426Smckusick 29158888Smckusick case CTL_FS: 29259719Sbostic case CTL_USER: 29358888Smckusick break; 29458888Smckusick 29558888Smckusick default: 29658888Smckusick fprintf(stderr, "Illegal top level value: %d\n", mib[0]); 29758888Smckusick return; 29858888Smckusick 29958888Smckusick } 30059140Smckusick if (bufp) { 30159140Smckusick fprintf(stderr, "name %s in %s is unknown\n", *bufp, string); 30259140Smckusick return; 30359140Smckusick } 30459140Smckusick if (newsize > 0) { 30559140Smckusick switch (type) { 30659140Smckusick case CTLTYPE_INT: 30759140Smckusick intval = atoi(newval); 30859140Smckusick newval = &intval; 30959140Smckusick newsize = sizeof intval; 31059140Smckusick break; 31158888Smckusick 31259140Smckusick case CTLTYPE_QUAD: 31359140Smckusick sscanf(newval, "%qd", &quadval); 31459140Smckusick newval = &quadval; 31559140Smckusick newsize = sizeof quadval; 31659140Smckusick break; 31759140Smckusick } 31859140Smckusick } 31958888Smckusick size = BUFSIZ; 32059140Smckusick if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) { 32158888Smckusick if (flags == 0) 32258888Smckusick return; 32358888Smckusick switch (errno) { 32458888Smckusick case EOPNOTSUPP: 32558888Smckusick fprintf(stderr, "%s: value is not available\n", string); 32658888Smckusick return; 32758888Smckusick case ENOTDIR: 32858888Smckusick fprintf(stderr, "%s: specification is incomplete\n", 32958888Smckusick string); 33058888Smckusick return; 33158888Smckusick case ENOMEM: 33258888Smckusick fprintf(stderr, "%s: type is unknown to this program\n", 33358888Smckusick string); 33458888Smckusick return; 33558888Smckusick default: 33658888Smckusick perror(string); 33758888Smckusick return; 33858888Smckusick } 33958888Smckusick } 340*60426Smckusick if (special & CLOCK) { 34158888Smckusick struct clockinfo *clkp = (struct clockinfo *)buf; 34258888Smckusick 34358910Smckusick if (!nflag) 34458910Smckusick fprintf(stdout, "%s: ", string); 34558888Smckusick fprintf(stdout, 34658910Smckusick "hz = %d, tick = %d, profhz = %d, stathz = %d\n", 34758910Smckusick clkp->hz, clkp->tick, clkp->profhz, clkp->stathz); 34858888Smckusick return; 34958888Smckusick } 350*60426Smckusick if (special & BOOTTIME) { 35160154Smckusick struct timeval *btp = (struct timeval *)buf; 35260154Smckusick 35360154Smckusick if (!nflag) 35460154Smckusick fprintf(stdout, "%s = %s\n", string, 35560154Smckusick ctime(&btp->tv_sec)); 35660154Smckusick else 35760154Smckusick fprintf(stdout, "%d\n", btp->tv_sec); 35860154Smckusick return; 35960154Smckusick } 360*60426Smckusick if (special & CONSDEV) { 361*60426Smckusick dev_t dev = *(dev_t *)buf; 362*60426Smckusick 363*60426Smckusick if (!nflag) 364*60426Smckusick fprintf(stdout, "%s = %s\n", string, 365*60426Smckusick devname(dev, S_IFCHR)); 366*60426Smckusick else 367*60426Smckusick fprintf(stdout, "0x%x\n", dev); 368*60426Smckusick return; 369*60426Smckusick } 37059140Smckusick switch (type) { 37159140Smckusick case CTLTYPE_INT: 37258910Smckusick if (newsize == 0) { 37358910Smckusick if (!nflag) 37458910Smckusick fprintf(stdout, "%s = ", string); 37558910Smckusick fprintf(stdout, "%d\n", *(int *)buf); 37658910Smckusick } else { 37758910Smckusick if (!nflag) 37858910Smckusick fprintf(stdout, "%s: %d -> ", string, 37958910Smckusick *(int *)buf); 38058910Smckusick fprintf(stdout, "%d\n", *(int *)newval); 38158910Smckusick } 38259140Smckusick return; 38359140Smckusick 38459140Smckusick case CTLTYPE_STRING: 38558910Smckusick if (newsize == 0) { 38658910Smckusick if (!nflag) 38758910Smckusick fprintf(stdout, "%s = ", string); 38858910Smckusick fprintf(stdout, "%s\n", buf); 38958910Smckusick } else { 39058910Smckusick if (!nflag) 39158910Smckusick fprintf(stdout, "%s: %s -> ", string, buf); 39258910Smckusick fprintf(stdout, "%s\n", newval); 39358910Smckusick } 39459140Smckusick return; 39559140Smckusick 39659140Smckusick case CTLTYPE_QUAD: 39759140Smckusick if (newsize == 0) { 39859140Smckusick if (!nflag) 39959140Smckusick fprintf(stdout, "%s = ", string); 40059140Smckusick fprintf(stdout, "%qd\n", *(quad_t *)buf); 40159140Smckusick } else { 40259140Smckusick if (!nflag) 40359140Smckusick fprintf(stdout, "%s: %qd -> ", string, 40459140Smckusick *(quad_t *)buf); 40559140Smckusick fprintf(stdout, "%qd\n", *(quad_t *)newval); 40659140Smckusick } 40759140Smckusick return; 40859140Smckusick 40959140Smckusick case CTLTYPE_STRUCT: 41059140Smckusick fprintf(stderr, "%s: unknown structure returned\n", 41159140Smckusick string); 41259140Smckusick return; 41359140Smckusick 41459140Smckusick default: 41559140Smckusick case CTLTYPE_NODE: 41659140Smckusick fprintf(stderr, "%s: unknown type returned\n", 41759140Smckusick string); 41859140Smckusick return; 41959140Smckusick } 42058888Smckusick } 42158888Smckusick 42259159Smckusick /* 42359159Smckusick * Initialize the set of debugging names 42459159Smckusick */ 42559159Smckusick debuginit() 42659159Smckusick { 42759159Smckusick int mib[3], size, loc, i; 42859159Smckusick 42959159Smckusick if (secondlevel[CTL_DEBUG].list != 0) 43059159Smckusick return; 43159159Smckusick secondlevel[CTL_DEBUG].list = debugname; 43259159Smckusick mib[0] = CTL_DEBUG; 43359159Smckusick mib[2] = CTL_DEBUG_NAME; 43459159Smckusick for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) { 43559159Smckusick mib[1] = i; 43659159Smckusick size = BUFSIZ - loc; 43759159Smckusick if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1) 43859159Smckusick continue; 43959159Smckusick debugname[i].ctl_name = &names[loc]; 44059159Smckusick debugname[i].ctl_type = CTLTYPE_INT; 44159159Smckusick loc += size; 44259159Smckusick } 44359159Smckusick } 44459159Smckusick 44559140Smckusick struct ctlname inetname[] = CTL_IPPROTO_NAMES; 44659140Smckusick struct ctlname ipname[] = IPCTL_NAMES; 44759140Smckusick struct ctlname icmpname[] = ICMPCTL_NAMES; 44859311Smckusick struct ctlname udpname[] = UDPCTL_NAMES; 44959140Smckusick struct list inetlist = { inetname, IPPROTO_MAXID }; 45059140Smckusick struct list inetvars[] = { 45159311Smckusick { ipname, IPCTL_MAXID }, /* ip */ 45259311Smckusick { icmpname, ICMPCTL_MAXID }, /* icmp */ 45359311Smckusick { 0, 0 }, /* igmp */ 45459311Smckusick { 0, 0 }, /* ggmp */ 45559311Smckusick { 0, 0 }, 45659311Smckusick { 0, 0 }, 45759311Smckusick { 0, 0 }, /* tcp */ 45859311Smckusick { 0, 0 }, 45959311Smckusick { 0, 0 }, /* egp */ 46059311Smckusick { 0, 0 }, 46159311Smckusick { 0, 0 }, 46259311Smckusick { 0, 0 }, 46359311Smckusick { 0, 0 }, /* pup */ 46459311Smckusick { 0, 0 }, 46559311Smckusick { 0, 0 }, 46659311Smckusick { 0, 0 }, 46759311Smckusick { 0, 0 }, 46859311Smckusick { udpname, UDPCTL_MAXID }, /* udp */ 46959140Smckusick }; 47059140Smckusick 47158888Smckusick /* 47259140Smckusick * handle internet requests 47359140Smckusick */ 47459140Smckusick sysctl_inet(string, bufpp, mib, flags, typep) 47559140Smckusick char *string; 47659140Smckusick char **bufpp; 47759140Smckusick int mib[]; 47859140Smckusick int flags; 47959140Smckusick int *typep; 48059140Smckusick { 48159140Smckusick struct list *lp; 48259140Smckusick int indx; 48359140Smckusick 48459140Smckusick if (*bufpp == NULL) { 48559140Smckusick listall(string, &inetlist); 48659140Smckusick return (-1); 48759140Smckusick } 48859140Smckusick if ((indx = findname(string, "third", bufpp, &inetlist)) == -1) 48959140Smckusick return (-1); 49059140Smckusick mib[2] = indx; 49159311Smckusick if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL) 49259140Smckusick lp = &inetvars[indx]; 49359140Smckusick else if (!flags) 49459140Smckusick return (-1); 49559140Smckusick else { 49659140Smckusick fprintf(stderr, "%s: no variables defined for this protocol\n", 49759140Smckusick string); 49859140Smckusick return (-1); 49959140Smckusick } 50059140Smckusick if (*bufpp == NULL) { 50159140Smckusick listall(string, lp); 50259140Smckusick return (-1); 50359140Smckusick } 50459140Smckusick if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 50559140Smckusick return (-1); 50659140Smckusick mib[3] = indx; 50759140Smckusick *typep = lp->list[indx].ctl_type; 50859140Smckusick return (4); 50959140Smckusick } 51059140Smckusick 51159140Smckusick /* 51258888Smckusick * Scan a list of names searching for a particular name. 51358888Smckusick */ 51458888Smckusick findname(string, level, bufp, namelist) 51558888Smckusick char *string; 51658888Smckusick char *level; 51758888Smckusick char **bufp; 51858888Smckusick struct list *namelist; 51958888Smckusick { 52058888Smckusick char *name; 52158888Smckusick int i; 52258888Smckusick 52358888Smckusick if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { 52458888Smckusick fprintf(stderr, "%s: incomplete specification\n", string); 52558888Smckusick return (-1); 52658888Smckusick } 52758888Smckusick for (i = 0; i < namelist->size; i++) 52859252Storek if (namelist->list[i].ctl_name != NULL && 52959252Storek strcmp(name, namelist->list[i].ctl_name) == 0) 53058888Smckusick break; 53158888Smckusick if (i == namelist->size) { 53258888Smckusick fprintf(stderr, "%s level name %s in %s is invalid\n", 53358888Smckusick level, name, string); 53458888Smckusick return (-1); 53558888Smckusick } 53658888Smckusick return (i); 53758888Smckusick } 53858888Smckusick 53958888Smckusick usage() 54058888Smckusick { 54158888Smckusick 54258911Smckusick (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n", 54358911Smckusick "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...", 54458911Smckusick "sysctl [-n] -a", "sysctl [-n] -A"); 54558888Smckusick exit(1); 54658888Smckusick } 547