/* $NetBSD: sysctl.c,v 1.16 1998/03/11 17:44:02 thorpej Exp $ */ /* * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #ifndef lint __COPYRIGHT( "@(#) Copyright (c) 1993\n\ The Regents of the University of California. All rights reserved.\n"); #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)sysctl.c 8.1 (Berkeley) 6/6/93"; #else __RCSID("$NetBSD: sysctl.c,v 1.16 1998/03/11 17:44:02 thorpej Exp $"); #endif #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct ctlname topname[] = CTL_NAMES; struct ctlname kernname[] = CTL_KERN_NAMES; struct ctlname vmname[] = CTL_VM_NAMES; struct ctlname netname[] = CTL_NET_NAMES; struct ctlname hwname[] = CTL_HW_NAMES; struct ctlname username[] = CTL_USER_NAMES; struct ctlname ddbname[] = CTL_DDB_NAMES; struct ctlname debugname[CTL_DEBUG_MAXID]; #ifdef CTL_MACHDEP_NAMES struct ctlname machdepname[] = CTL_MACHDEP_NAMES; #endif char names[BUFSIZ]; struct list { struct ctlname *list; int size; }; struct list toplist = { topname, CTL_MAXID }; struct list secondlevel[] = { { 0, 0 }, /* CTL_UNSPEC */ { kernname, KERN_MAXID }, /* CTL_KERN */ { vmname, VM_MAXID }, /* CTL_VM */ { 0, 0 }, /* CTL_VFS */ { netname, NET_MAXID }, /* CTL_NET */ { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */ { hwname, HW_MAXID }, /* CTL_HW */ #ifdef CTL_MACHDEP_NAMES { machdepname, CPU_MAXID }, /* CTL_MACHDEP */ #else { 0, 0 }, /* CTL_MACHDEP */ #endif { username, USER_MAXID }, /* CTL_USER_NAMES */ { ddbname, DDBCTL_MAXID }, /* CTL_DDB_NAMES */ }; int Aflag, aflag, nflag, wflag; /* * Variables requiring special processing. */ #define CLOCK 0x00000001 #define BOOTTIME 0x00000002 #define CONSDEV 0x00000004 int main __P((int, char *[])); static void listall __P((char *, struct list *)); static void parse __P((char *, int)); static void debuginit __P((void)); static int sysctl_inet __P((char *, char **, int[], int, int *)); static int findname __P((char *, char *, char **, struct list *)); static void usage __P((void)); int main(argc, argv) int argc; char *argv[]; { extern char *optarg; extern int optind; int ch, lvl1; while ((ch = getopt(argc, argv, "Aanw")) != -1) { switch (ch) { case 'A': Aflag = 1; break; case 'a': aflag = 1; break; case 'n': nflag = 1; break; case 'w': wflag = 1; break; default: usage(); } } argc -= optind; argv += optind; if (Aflag || aflag) { debuginit(); for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); return 0; } if (argc == 0) usage(); while (argc-- > 0) parse(*argv++, 1); return 0; } /* * List all variables known to the system. */ static void listall(prefix, lp) char *prefix; struct list *lp; { int lvl2; char *cp, name[BUFSIZ]; if (lp->list == 0) return; strcpy(name, prefix); cp = &name[strlen(name)]; *cp++ = '.'; for (lvl2 = 0; lvl2 < lp->size; lvl2++) { if (lp->list[lvl2].ctl_name == 0) continue; strcpy(cp, lp->list[lvl2].ctl_name); parse(name, Aflag); } } /* * Parse a name into a MIB entry. * Lookup and print out the MIB entry if it exists. * Set a new value if requested. */ static void parse(string, flags) char *string; int flags; { int indx, type, state, len; int special = 0; void *newval = 0; int intval, newsize = 0; quad_t quadval; size_t size; struct list *lp; int mib[CTL_MAXNAME]; char *cp, *bufp, buf[BUFSIZ]; bufp = buf; snprintf(buf, BUFSIZ, "%s", string); if ((cp = strchr(string, '=')) != NULL) { if (!wflag) errx(2, "Must specify -w to set variables"); *strchr(buf, '=') = '\0'; *cp++ = '\0'; while (isspace((unsigned char) *cp)) cp++; newval = cp; newsize = strlen(cp); } if ((indx = findname(string, "top", &bufp, &toplist)) == -1) return; mib[0] = indx; if (indx == CTL_DEBUG) debuginit(); lp = &secondlevel[indx]; if (lp->list == 0) { warnx("Class `%s' is not implemented", topname[indx].ctl_name); return; } if (bufp == NULL) { listall(topname[indx].ctl_name, lp); return; } if ((indx = findname(string, "second", &bufp, lp)) == -1) return; mib[1] = indx; type = lp->list[indx].ctl_type; len = 2; switch (mib[0]) { case CTL_KERN: switch (mib[1]) { case KERN_PROF: mib[2] = GPROF_STATE; size = sizeof state; if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) { if (flags == 0) return; if (!nflag) fprintf(stdout, "%s: ", string); warnx("Kernel is not compiled for profiling"); return; } if (!nflag) fprintf(stdout, "%s: %s\n", string, state == GMON_PROF_OFF ? "off" : "running"); return; case KERN_VNODE: case KERN_FILE: if (flags == 0) return; warnx("Use pstat to view %s information", string); return; case KERN_PROC: if (flags == 0) return; warnx("Use ps to view %s information", string); return; case KERN_CLOCKRATE: special |= CLOCK; break; case KERN_BOOTTIME: special |= BOOTTIME; break; case KERN_NTPTIME: if (flags == 0) return; warnx("Use xntpdc -c kerninfo to view %s information", string); return; } break; case CTL_HW: break; case CTL_VM: if (mib[1] == VM_LOADAVG) { double loads[3]; getloadavg(loads, 3); if (!nflag) fprintf(stdout, "%s: ", string); fprintf(stdout, "%.2f %.2f %.2f\n", loads[0], loads[1], loads[2]); return; } if (flags == 0) return; warnx("Use vmstat or systat to view %s information", string); return; case CTL_NET: if (mib[1] == PF_INET) { len = sysctl_inet(string, &bufp, mib, flags, &type); if (len >= 0) break; return; } if (flags == 0) return; warnx("Use netstat to view %s information", string); return; case CTL_DEBUG: mib[2] = CTL_DEBUG_VALUE; len = 3; break; case CTL_MACHDEP: #ifdef CPU_CONSDEV if (mib[1] == CPU_CONSDEV) special |= CONSDEV; #endif break; case CTL_VFS: case CTL_USER: case CTL_DDB: break; default: warnx("Illegal top level value: %d", mib[0]); return; } if (bufp) { warnx("Name %s in %s is unknown", bufp, string); return; } if (newsize > 0) { switch (type) { case CTLTYPE_INT: intval = atoi(newval); newval = &intval; newsize = sizeof intval; break; case CTLTYPE_QUAD: sscanf(newval, "%qd", (long long *)&quadval); newval = &quadval; newsize = sizeof quadval; break; } } size = BUFSIZ; if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) { if (flags == 0) return; switch (errno) { case EOPNOTSUPP: warnx("The value of %s is not available", string); return; case ENOTDIR: warnx("The specification of %s is incomplete", string); return; case ENOMEM: warnx("The type %s is unknown to this program", string); return; default: warn("sysctl() for %s failed", string); return; } } if (special & CLOCK) { struct clockinfo *clkp = (struct clockinfo *)buf; if (!nflag) fprintf(stdout, "%s: ", string); fprintf(stdout, "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n", clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz); return; } if (special & BOOTTIME) { struct timeval *btp = (struct timeval *)buf; time_t boottime; if (!nflag) { boottime = btp->tv_sec; fprintf(stdout, "%s = %s\n", string, ctime(&boottime)); } else fprintf(stdout, "%ld\n", (long) btp->tv_sec); return; } if (special & CONSDEV) { dev_t dev = *(dev_t *)buf; if (!nflag) fprintf(stdout, "%s = %s\n", string, devname(dev, S_IFCHR)); else fprintf(stdout, "0x%x\n", dev); return; } switch (type) { case CTLTYPE_INT: if (newsize == 0) { if (!nflag) fprintf(stdout, "%s = ", string); fprintf(stdout, "%d\n", *(int *)buf); } else { if (!nflag) fprintf(stdout, "%s: %d -> ", string, *(int *)buf); fprintf(stdout, "%d\n", *(int *)newval); } return; case CTLTYPE_STRING: if (newsize == 0) { if (!nflag) fprintf(stdout, "%s = ", string); fprintf(stdout, "%s\n", buf); } else { if (!nflag) fprintf(stdout, "%s: %s -> ", string, buf); fprintf(stdout, "%s\n", (char *) newval); } return; case CTLTYPE_QUAD: if (newsize == 0) { if (!nflag) fprintf(stdout, "%s = ", string); fprintf(stdout, "%qd\n", (long long)(*(quad_t *)buf)); } else { if (!nflag) fprintf(stdout, "%s: %qd -> ", string, (long long)(*(quad_t *)buf)); fprintf(stdout, "%qd\n", (long long)(*(quad_t *)newval)); } return; case CTLTYPE_STRUCT: warnx("%s: unknown structure returned", string); return; default: case CTLTYPE_NODE: warnx("%s: unknown type returned", string); return; } } /* * Initialize the set of debugging names */ static void debuginit() { int mib[3], loc, i; size_t size; if (secondlevel[CTL_DEBUG].list != 0) return; secondlevel[CTL_DEBUG].list = debugname; mib[0] = CTL_DEBUG; mib[2] = CTL_DEBUG_NAME; for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) { mib[1] = i; size = BUFSIZ - loc; if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1) continue; debugname[i].ctl_name = &names[loc]; debugname[i].ctl_type = CTLTYPE_INT; loc += size; } } struct ctlname inetname[] = CTL_IPPROTO_NAMES; struct ctlname ipname[] = IPCTL_NAMES; struct ctlname icmpname[] = ICMPCTL_NAMES; struct ctlname tcpname[] = TCPCTL_NAMES; struct ctlname udpname[] = UDPCTL_NAMES; struct list inetlist = { inetname, IPPROTO_MAXID }; struct list inetvars[] = { { ipname, IPCTL_MAXID }, /* ip */ { icmpname, ICMPCTL_MAXID }, /* icmp */ { 0, 0 }, /* igmp */ { 0, 0 }, /* ggmp */ { 0, 0 }, { 0, 0 }, { tcpname, TCPCTL_MAXID }, /* tcp */ { 0, 0 }, { 0, 0 }, /* egp */ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, /* pup */ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { udpname, UDPCTL_MAXID }, /* udp */ }; /* * handle internet requests */ static int sysctl_inet(string, bufpp, mib, flags, typep) char *string; char **bufpp; int mib[]; int flags; int *typep; { struct list *lp; int indx; if (*bufpp == NULL) { listall(string, &inetlist); return (-1); } if ((indx = findname(string, "third", bufpp, &inetlist)) == -1) return (-1); mib[2] = indx; if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL) lp = &inetvars[indx]; else if (!flags) return (-1); else { warnx("No variables defined for protocol %s", string); return (-1); } if (*bufpp == NULL) { listall(string, lp); return (-1); } if ((indx = findname(string, "fourth", bufpp, lp)) == -1) return (-1); mib[3] = indx; *typep = lp->list[indx].ctl_type; return (4); } /* * Scan a list of names searching for a particular name. */ static int findname(string, level, bufp, namelist) char *string; char *level; char **bufp; struct list *namelist; { char *name; int i; if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { warnx("%s: incomplete specification", string); return (-1); } for (i = 0; i < namelist->size; i++) if (namelist->list[i].ctl_name != NULL && strcmp(name, namelist->list[i].ctl_name) == 0) break; if (i == namelist->size) { warnx("%s level name %s in %s is invalid", level, name, string); return (-1); } return (i); } static void usage() { extern char *__progname; (void)fprintf(stderr, "Usage:\t%s %s\n\t%s %s\n\t%s %s\n\t%s %s\n", __progname, "[-n] variable ...", __progname, "[-n] -w variable=value ...", __progname, "[-n] -a", __progname, "[-n] -A"); exit(1); }