xref: /csrg-svn/usr.sbin/sysctl/sysctl.c (revision 59140)
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*59140Smckusick static char sccsid[] = "@(#)sysctl.c	5.4 (Berkeley) 04/18/93";
1658888Smckusick #endif /* not lint */
1758888Smckusick 
1858888Smckusick #include <sys/types.h>
1958888Smckusick #include <sys/stat.h>
2058888Smckusick #include <sys/sysctl.h>
2158888Smckusick #include <sys/socket.h>
2258888Smckusick #include <vm/vm_param.h>
23*59140Smckusick #include <netinet/in.h>
24*59140Smckusick #include <netinet/in_systm.h>
25*59140Smckusick #include <netinet/ip.h>
26*59140Smckusick #include <netinet/ip_icmp.h>
27*59140Smckusick #include <netinet/icmp_var.h>
2858888Smckusick #include <errno.h>
2958888Smckusick #include <stdlib.h>
3058888Smckusick #include <string.h>
3158888Smckusick #include <stdio.h>
3258888Smckusick 
33*59140Smckusick struct ctlname topname[] = CTL_NAMES;
34*59140Smckusick struct ctlname kernname[] = CTL_KERN_NAMES;
35*59140Smckusick struct ctlname vmname[] = CTL_VM_NAMES;
36*59140Smckusick struct ctlname netname[] = CTL_NET_NAMES;
37*59140Smckusick struct ctlname hwname[] = CTL_HW_NAMES;
3858888Smckusick 
3958888Smckusick struct list {
40*59140Smckusick 	struct	ctlname *list;
4158888Smckusick 	int	size;
42*59140Smckusick };
43*59140Smckusick struct list toplist = { topname, CTL_MAXID };
44*59140Smckusick struct list secondlevel[] = {
4558888Smckusick 	{ 0, 0 },			/* CTL_UNSPEC */
4658888Smckusick 	{ kernname, KERN_MAXID },	/* CTL_KERN */
4758888Smckusick 	{ vmname, VM_MAXID },		/* CTL_VM */
4858888Smckusick 	{ 0, 0 },			/* CTL_FS */
4958888Smckusick 	{ netname, NET_MAXID },		/* CTL_NET */
5058888Smckusick 	{ 0, 0 },			/* CTL_DEBUG */
5158888Smckusick 	{ hwname, HW_MAXID },		/* CTL_HW */
5258888Smckusick 	{ 0, 0 },			/* CTL_MACHDEP */
5358888Smckusick };
5458888Smckusick 
5558910Smckusick int	Aflag, aflag, nflag, wflag;
5658888Smckusick 
5758888Smckusick int
5858888Smckusick main(argc, argv)
5958888Smckusick 	int argc;
6058888Smckusick 	char *argv[];
6158888Smckusick {
6258888Smckusick 	extern char *optarg;
6358888Smckusick 	extern int optind;
6458910Smckusick 	int ch, lvl1;
6558888Smckusick 
6658910Smckusick 	while ((ch = getopt(argc, argv, "Aanw")) != EOF) {
6758888Smckusick 		switch (ch) {
6858888Smckusick 
6958888Smckusick 		case 'A':
7058888Smckusick 			Aflag = 1;
7158888Smckusick 			break;
7258888Smckusick 
7358888Smckusick 		case 'a':
7458888Smckusick 			aflag = 1;
7558888Smckusick 			break;
7658888Smckusick 
7758910Smckusick 		case 'n':
7858910Smckusick 			nflag = 1;
7958910Smckusick 			break;
8058910Smckusick 
8158888Smckusick 		case 'w':
8258888Smckusick 			wflag = 1;
8358888Smckusick 			break;
8458888Smckusick 
8558888Smckusick 		default:
8658888Smckusick 			usage();
8758888Smckusick 		}
8858888Smckusick 	}
8958888Smckusick 	argc -= optind;
9058888Smckusick 	argv += optind;
9158888Smckusick 
9258888Smckusick 	if (Aflag || aflag) {
9358910Smckusick 		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
94*59140Smckusick 			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
9558888Smckusick 		exit(0);
9658888Smckusick 	}
9758888Smckusick 	if (argc == 0)
9858888Smckusick 		usage();
9958888Smckusick 	while (argc-- > 0)
10058888Smckusick 		parse(*argv, 1);
10158888Smckusick 	exit(0);
10258888Smckusick }
10358888Smckusick 
10458888Smckusick /*
10558888Smckusick  * List all variables known to the system.
10658888Smckusick  */
107*59140Smckusick listall(prefix, lp)
108*59140Smckusick 	char *prefix;
109*59140Smckusick 	struct list *lp;
11058888Smckusick {
11158910Smckusick 	int lvl2;
11258888Smckusick 	char *cp, name[BUFSIZ];
11358888Smckusick 
11458910Smckusick 	if (lp->list == 0)
11558910Smckusick 		return;
116*59140Smckusick 	strcpy(name, prefix);
11758910Smckusick 	cp = &name[strlen(name)];
11858910Smckusick 	*cp++ = '.';
119*59140Smckusick 	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
120*59140Smckusick 		if (lp->list[lvl2].ctl_name == 0)
121*59140Smckusick 			continue;
122*59140Smckusick 		strcpy(cp, lp->list[lvl2].ctl_name);
12358910Smckusick 		parse(name, Aflag);
12458888Smckusick 	}
12558888Smckusick }
12658888Smckusick 
12758888Smckusick /*
12858888Smckusick  * Parse a name into a MIB entry.
12958888Smckusick  * Lookup and print out the MIB entry if it exists.
13058888Smckusick  * Set a new value if requested.
13158888Smckusick  */
13258888Smckusick parse(string, flags)
13358888Smckusick 	char *string;
13458888Smckusick 	int flags;
13558888Smckusick {
136*59140Smckusick 	int indx, type, size, len;
13758888Smckusick 	int isclockrate = 0;
13858888Smckusick 	void *newval = 0;
13958888Smckusick 	int intval, newsize = 0;
140*59140Smckusick 	quad_t quadval;
141*59140Smckusick 	struct list *lp;
14258888Smckusick 	int mib[CTL_MAXNAME];
14358888Smckusick 	char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ];
14458888Smckusick 
14558888Smckusick 	bufp = buf;
14658888Smckusick 	snprintf(buf, BUFSIZ, "%s", string);
14758888Smckusick 	if ((cp = strchr(string, '=')) != NULL) {
14858888Smckusick 		if (!wflag) {
14958888Smckusick 			fprintf(stderr, "Must specify -w to set variables\n");
15058888Smckusick 			exit(2);
15158888Smckusick 		}
15258888Smckusick 		*strchr(buf, '=') = '\0';
15358888Smckusick 		*cp++ = '\0';
15458888Smckusick 		while (isspace(*cp))
15558888Smckusick 			cp++;
156*59140Smckusick 		newval = cp;
157*59140Smckusick 		newsize = strlen(cp);
15858888Smckusick 	}
159*59140Smckusick 	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
16058888Smckusick 		return;
16158888Smckusick 	mib[0] = indx;
16258888Smckusick 	lp = &secondlevel[indx];
16358888Smckusick 	if (lp->list == 0) {
16458888Smckusick 		fprintf(stderr, "%s: class is not implemented\n",
16558888Smckusick 		    topname[indx]);
16658888Smckusick 		return;
16758888Smckusick 	}
16858910Smckusick 	if (bufp == NULL) {
169*59140Smckusick 		listall(topname[indx].ctl_name, lp);
17058910Smckusick 		return;
17158910Smckusick 	}
17258888Smckusick 	if ((indx = findname(string, "second", &bufp, lp)) == -1)
17358888Smckusick 		return;
17458888Smckusick 	mib[1] = indx;
175*59140Smckusick 	type = lp->list[indx].ctl_type;
176*59140Smckusick 	len = 2;
17758888Smckusick 	switch (mib[0]) {
17858888Smckusick 
17958888Smckusick 	case CTL_KERN:
18058888Smckusick 		switch (mib[1]) {
18158888Smckusick 		case KERN_VNODE:
18258888Smckusick 		case KERN_FILE:
18358888Smckusick 			if (flags == 0)
18458888Smckusick 				return;
18558888Smckusick 			fprintf(stderr,
18658888Smckusick 			    "Use pstat to view %s information\n", string);
18758888Smckusick 			return;
18858888Smckusick 		case KERN_PROC:
18958888Smckusick 			if (flags == 0)
19058888Smckusick 				return;
19158888Smckusick 			fprintf(stderr,
19258888Smckusick 			    "Use ps to view %s information\n", string);
19358888Smckusick 			return;
19458888Smckusick 		case KERN_CLOCKRATE:
19558888Smckusick 			isclockrate = 1;
19658888Smckusick 			break;
19758888Smckusick 		}
19858888Smckusick 		break;
19958888Smckusick 
20058888Smckusick 	case CTL_HW:
20158888Smckusick 		break;
20258888Smckusick 
20358888Smckusick 	case CTL_VM:
20458888Smckusick 		if (mib[1] == VM_LOADAVG) {
20558888Smckusick 			double loads[3];
20658888Smckusick 
20758888Smckusick 			getloadavg(loads, 3);
20858910Smckusick 			if (!nflag)
20958910Smckusick 				fprintf(stdout, "%s: ", string);
21058910Smckusick 			fprintf(stdout, "%.2f %.2f %.2f\n",
21158888Smckusick 			    loads[0], loads[1], loads[2]);
21258888Smckusick 			return;
21358888Smckusick 		}
21458888Smckusick 		if (flags == 0)
21558888Smckusick 			return;
21658888Smckusick 		fprintf(stderr,
21758888Smckusick 		    "Use vmstat or systat to view %s information\n", string);
21858888Smckusick 		return;
21958888Smckusick 
22058888Smckusick 	case CTL_NET:
221*59140Smckusick 		if (mib[1] == PF_INET) {
222*59140Smckusick 			len = sysctl_inet(string, &bufp, mib, flags, &type);
223*59140Smckusick 			if (len >= 0)
224*59140Smckusick 				break;
225*59140Smckusick 			return;
226*59140Smckusick 		}
22758888Smckusick 		if (flags == 0)
22858888Smckusick 			return;
22958888Smckusick 		fprintf(stderr, "Use netstat to view %s information\n", string);
23058888Smckusick 		return;
23158888Smckusick 
23258888Smckusick 	case CTL_FS:
23358888Smckusick 	case CTL_DEBUG:
23458888Smckusick 	case CTL_MACHDEP:
23558888Smckusick 		break;
23658888Smckusick 
23758888Smckusick 	default:
23858888Smckusick 		fprintf(stderr, "Illegal top level value: %d\n", mib[0]);
23958888Smckusick 		return;
24058888Smckusick 
24158888Smckusick 	}
242*59140Smckusick 	if (bufp) {
243*59140Smckusick 		fprintf(stderr, "name %s in %s is unknown\n", *bufp, string);
244*59140Smckusick 		return;
245*59140Smckusick 	}
246*59140Smckusick 	if (newsize > 0) {
247*59140Smckusick 		switch (type) {
248*59140Smckusick 		case CTLTYPE_INT:
249*59140Smckusick 			intval = atoi(newval);
250*59140Smckusick 			newval = &intval;
251*59140Smckusick 			newsize = sizeof intval;
252*59140Smckusick 			break;
25358888Smckusick 
254*59140Smckusick 		case CTLTYPE_QUAD:
255*59140Smckusick 			sscanf(newval, "%qd", &quadval);
256*59140Smckusick 			newval = &quadval;
257*59140Smckusick 			newsize = sizeof quadval;
258*59140Smckusick 			break;
259*59140Smckusick 		}
260*59140Smckusick 	}
26158888Smckusick 	size = BUFSIZ;
262*59140Smckusick 	if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
26358888Smckusick 		if (flags == 0)
26458888Smckusick 			return;
26558888Smckusick 		switch (errno) {
26658888Smckusick 		case EOPNOTSUPP:
26758888Smckusick 			fprintf(stderr, "%s: value is not available\n", string);
26858888Smckusick 			return;
26958888Smckusick 		case ENOTDIR:
27058888Smckusick 			fprintf(stderr, "%s: specification is incomplete\n",
27158888Smckusick 			    string);
27258888Smckusick 			return;
27358888Smckusick 		case ENOMEM:
27458888Smckusick 			fprintf(stderr, "%s: type is unknown to this program\n",
27558888Smckusick 			    string);
27658888Smckusick 			return;
27758888Smckusick 		default:
27858888Smckusick 			perror(string);
27958888Smckusick 			return;
28058888Smckusick 		}
28158888Smckusick 	}
28258888Smckusick 	if (isclockrate) {
28358888Smckusick 		struct clockinfo *clkp = (struct clockinfo *)buf;
28458888Smckusick 
28558910Smckusick 		if (!nflag)
28658910Smckusick 			fprintf(stdout, "%s: ", string);
28758888Smckusick 		fprintf(stdout,
28858910Smckusick 		    "hz = %d, tick = %d, profhz = %d, stathz = %d\n",
28958910Smckusick 		    clkp->hz, clkp->tick, clkp->profhz, clkp->stathz);
29058888Smckusick 		return;
29158888Smckusick 	}
292*59140Smckusick 	switch (type) {
293*59140Smckusick 	case CTLTYPE_INT:
29458910Smckusick 		if (newsize == 0) {
29558910Smckusick 			if (!nflag)
29658910Smckusick 				fprintf(stdout, "%s = ", string);
29758910Smckusick 			fprintf(stdout, "%d\n", *(int *)buf);
29858910Smckusick 		} else {
29958910Smckusick 			if (!nflag)
30058910Smckusick 				fprintf(stdout, "%s: %d -> ", string,
30158910Smckusick 				    *(int *)buf);
30258910Smckusick 			fprintf(stdout, "%d\n", *(int *)newval);
30358910Smckusick 		}
304*59140Smckusick 		return;
305*59140Smckusick 
306*59140Smckusick 	case CTLTYPE_STRING:
30758910Smckusick 		if (newsize == 0) {
30858910Smckusick 			if (!nflag)
30958910Smckusick 				fprintf(stdout, "%s = ", string);
31058910Smckusick 			fprintf(stdout, "%s\n", buf);
31158910Smckusick 		} else {
31258910Smckusick 			if (!nflag)
31358910Smckusick 				fprintf(stdout, "%s: %s -> ", string, buf);
31458910Smckusick 			fprintf(stdout, "%s\n", newval);
31558910Smckusick 		}
316*59140Smckusick 		return;
317*59140Smckusick 
318*59140Smckusick 	case CTLTYPE_QUAD:
319*59140Smckusick 		if (newsize == 0) {
320*59140Smckusick 			if (!nflag)
321*59140Smckusick 				fprintf(stdout, "%s = ", string);
322*59140Smckusick 			fprintf(stdout, "%qd\n", *(quad_t *)buf);
323*59140Smckusick 		} else {
324*59140Smckusick 			if (!nflag)
325*59140Smckusick 				fprintf(stdout, "%s: %qd -> ", string,
326*59140Smckusick 				    *(quad_t *)buf);
327*59140Smckusick 			fprintf(stdout, "%qd\n", *(quad_t *)newval);
328*59140Smckusick 		}
329*59140Smckusick 		return;
330*59140Smckusick 
331*59140Smckusick 	case CTLTYPE_STRUCT:
332*59140Smckusick 		fprintf(stderr, "%s: unknown structure returned\n",
333*59140Smckusick 		    string);
334*59140Smckusick 		return;
335*59140Smckusick 
336*59140Smckusick 	default:
337*59140Smckusick 	case CTLTYPE_NODE:
338*59140Smckusick 		fprintf(stderr, "%s: unknown type returned\n",
339*59140Smckusick 		    string);
340*59140Smckusick 		return;
341*59140Smckusick 	}
34258888Smckusick }
34358888Smckusick 
344*59140Smckusick struct ctlname inetname[] = CTL_IPPROTO_NAMES;
345*59140Smckusick struct ctlname ipname[] = IPCTL_NAMES;
346*59140Smckusick struct ctlname icmpname[] = ICMPCTL_NAMES;
347*59140Smckusick struct list inetlist = { inetname, IPPROTO_MAXID };
348*59140Smckusick struct list inetvars[] = {
349*59140Smckusick 	{ ipname, IPCTL_MAXID },
350*59140Smckusick 	{ icmpname, ICMPCTL_MAXID },
351*59140Smckusick };
352*59140Smckusick 
35358888Smckusick /*
354*59140Smckusick  * handle internet requests
355*59140Smckusick  */
356*59140Smckusick sysctl_inet(string, bufpp, mib, flags, typep)
357*59140Smckusick 	char *string;
358*59140Smckusick 	char **bufpp;
359*59140Smckusick 	int mib[];
360*59140Smckusick 	int flags;
361*59140Smckusick 	int *typep;
362*59140Smckusick {
363*59140Smckusick 	struct list *lp;
364*59140Smckusick 	int indx;
365*59140Smckusick 
366*59140Smckusick 	if (*bufpp == NULL) {
367*59140Smckusick 		listall(string, &inetlist);
368*59140Smckusick 		return (-1);
369*59140Smckusick 	}
370*59140Smckusick 	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
371*59140Smckusick 		return (-1);
372*59140Smckusick 	mib[2] = indx;
373*59140Smckusick 	if (indx < 2)
374*59140Smckusick 		lp = &inetvars[indx];
375*59140Smckusick 	else if (!flags)
376*59140Smckusick 		return (-1);
377*59140Smckusick 	else {
378*59140Smckusick 		fprintf(stderr, "%s: no variables defined for this protocol\n",
379*59140Smckusick 		    string);
380*59140Smckusick 		return (-1);
381*59140Smckusick 	}
382*59140Smckusick 	if (*bufpp == NULL) {
383*59140Smckusick 		listall(string, lp);
384*59140Smckusick 		return (-1);
385*59140Smckusick 	}
386*59140Smckusick 	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
387*59140Smckusick 		return (-1);
388*59140Smckusick 	mib[3] = indx;
389*59140Smckusick 	*typep = lp->list[indx].ctl_type;
390*59140Smckusick 	return (4);
391*59140Smckusick }
392*59140Smckusick 
393*59140Smckusick /*
39458888Smckusick  * Scan a list of names searching for a particular name.
39558888Smckusick  */
39658888Smckusick findname(string, level, bufp, namelist)
39758888Smckusick 	char *string;
39858888Smckusick 	char *level;
39958888Smckusick 	char **bufp;
40058888Smckusick 	struct list *namelist;
40158888Smckusick {
40258888Smckusick 	char *name;
40358888Smckusick 	int i;
40458888Smckusick 
40558888Smckusick 	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
40658888Smckusick 		fprintf(stderr, "%s: incomplete specification\n", string);
40758888Smckusick 		return (-1);
40858888Smckusick 	}
40958888Smckusick 	for (i = 0; i < namelist->size; i++)
410*59140Smckusick 		if (!strcmp(name, namelist->list[i].ctl_name))
41158888Smckusick 			break;
41258888Smckusick 	if (i == namelist->size) {
41358888Smckusick 		fprintf(stderr, "%s level name %s in %s is invalid\n",
41458888Smckusick 		    level, name, string);
41558888Smckusick 		return (-1);
41658888Smckusick 	}
41758888Smckusick 	return (i);
41858888Smckusick }
41958888Smckusick 
42058888Smckusick usage()
42158888Smckusick {
42258888Smckusick 
42358911Smckusick 	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
42458911Smckusick 	    "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
42558911Smckusick 	    "sysctl [-n] -a", "sysctl [-n] -A");
42658888Smckusick 	exit(1);
42758888Smckusick }
428