xref: /csrg-svn/usr.sbin/sysctl/sysctl.c (revision 59159)
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*59159Smckusick static char sccsid[] = "@(#)sysctl.c	5.5 (Berkeley) 04/19/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>
2359140Smckusick #include <netinet/in.h>
2459140Smckusick #include <netinet/in_systm.h>
2559140Smckusick #include <netinet/ip.h>
2659140Smckusick #include <netinet/ip_icmp.h>
2759140Smckusick #include <netinet/icmp_var.h>
2858888Smckusick #include <errno.h>
2958888Smckusick #include <stdlib.h>
3058888Smckusick #include <string.h>
3158888Smckusick #include <stdio.h>
3258888Smckusick 
3359140Smckusick struct ctlname topname[] = CTL_NAMES;
3459140Smckusick struct ctlname kernname[] = CTL_KERN_NAMES;
3559140Smckusick struct ctlname vmname[] = CTL_VM_NAMES;
3659140Smckusick struct ctlname netname[] = CTL_NET_NAMES;
3759140Smckusick struct ctlname hwname[] = CTL_HW_NAMES;
38*59159Smckusick struct ctlname debugname[CTL_DEBUG_MAXID];
39*59159Smckusick char names[BUFSIZ];
4058888Smckusick 
4158888Smckusick struct list {
4259140Smckusick 	struct	ctlname *list;
4358888Smckusick 	int	size;
4459140Smckusick };
4559140Smckusick struct list toplist = { topname, CTL_MAXID };
4659140Smckusick struct list secondlevel[] = {
4758888Smckusick 	{ 0, 0 },			/* CTL_UNSPEC */
4858888Smckusick 	{ kernname, KERN_MAXID },	/* CTL_KERN */
4958888Smckusick 	{ vmname, VM_MAXID },		/* CTL_VM */
5058888Smckusick 	{ 0, 0 },			/* CTL_FS */
5158888Smckusick 	{ netname, NET_MAXID },		/* CTL_NET */
52*59159Smckusick 	{ 0, CTL_DEBUG_MAXID },		/* CTL_DEBUG */
5358888Smckusick 	{ hwname, HW_MAXID },		/* CTL_HW */
5458888Smckusick 	{ 0, 0 },			/* CTL_MACHDEP */
5558888Smckusick };
5658888Smckusick 
5758910Smckusick int	Aflag, aflag, nflag, wflag;
5858888Smckusick 
5958888Smckusick int
6058888Smckusick main(argc, argv)
6158888Smckusick 	int argc;
6258888Smckusick 	char *argv[];
6358888Smckusick {
6458888Smckusick 	extern char *optarg;
6558888Smckusick 	extern int optind;
6658910Smckusick 	int ch, lvl1;
6758888Smckusick 
6858910Smckusick 	while ((ch = getopt(argc, argv, "Aanw")) != EOF) {
6958888Smckusick 		switch (ch) {
7058888Smckusick 
7158888Smckusick 		case 'A':
7258888Smckusick 			Aflag = 1;
7358888Smckusick 			break;
7458888Smckusick 
7558888Smckusick 		case 'a':
7658888Smckusick 			aflag = 1;
7758888Smckusick 			break;
7858888Smckusick 
7958910Smckusick 		case 'n':
8058910Smckusick 			nflag = 1;
8158910Smckusick 			break;
8258910Smckusick 
8358888Smckusick 		case 'w':
8458888Smckusick 			wflag = 1;
8558888Smckusick 			break;
8658888Smckusick 
8758888Smckusick 		default:
8858888Smckusick 			usage();
8958888Smckusick 		}
9058888Smckusick 	}
9158888Smckusick 	argc -= optind;
9258888Smckusick 	argv += optind;
9358888Smckusick 
9458888Smckusick 	if (Aflag || aflag) {
95*59159Smckusick 		debuginit();
9658910Smckusick 		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
9759140Smckusick 			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
9858888Smckusick 		exit(0);
9958888Smckusick 	}
10058888Smckusick 	if (argc == 0)
10158888Smckusick 		usage();
10258888Smckusick 	while (argc-- > 0)
10358888Smckusick 		parse(*argv, 1);
10458888Smckusick 	exit(0);
10558888Smckusick }
10658888Smckusick 
10758888Smckusick /*
10858888Smckusick  * List all variables known to the system.
10958888Smckusick  */
11059140Smckusick listall(prefix, lp)
11159140Smckusick 	char *prefix;
11259140Smckusick 	struct list *lp;
11358888Smckusick {
11458910Smckusick 	int lvl2;
11558888Smckusick 	char *cp, name[BUFSIZ];
11658888Smckusick 
11758910Smckusick 	if (lp->list == 0)
11858910Smckusick 		return;
11959140Smckusick 	strcpy(name, prefix);
12058910Smckusick 	cp = &name[strlen(name)];
12158910Smckusick 	*cp++ = '.';
12259140Smckusick 	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
12359140Smckusick 		if (lp->list[lvl2].ctl_name == 0)
12459140Smckusick 			continue;
12559140Smckusick 		strcpy(cp, lp->list[lvl2].ctl_name);
12658910Smckusick 		parse(name, Aflag);
12758888Smckusick 	}
12858888Smckusick }
12958888Smckusick 
13058888Smckusick /*
13158888Smckusick  * Parse a name into a MIB entry.
13258888Smckusick  * Lookup and print out the MIB entry if it exists.
13358888Smckusick  * Set a new value if requested.
13458888Smckusick  */
13558888Smckusick parse(string, flags)
13658888Smckusick 	char *string;
13758888Smckusick 	int flags;
13858888Smckusick {
13959140Smckusick 	int indx, type, size, len;
14058888Smckusick 	int isclockrate = 0;
14158888Smckusick 	void *newval = 0;
14258888Smckusick 	int intval, newsize = 0;
14359140Smckusick 	quad_t quadval;
14459140Smckusick 	struct list *lp;
14558888Smckusick 	int mib[CTL_MAXNAME];
14658888Smckusick 	char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ];
14758888Smckusick 
14858888Smckusick 	bufp = buf;
14958888Smckusick 	snprintf(buf, BUFSIZ, "%s", string);
15058888Smckusick 	if ((cp = strchr(string, '=')) != NULL) {
15158888Smckusick 		if (!wflag) {
15258888Smckusick 			fprintf(stderr, "Must specify -w to set variables\n");
15358888Smckusick 			exit(2);
15458888Smckusick 		}
15558888Smckusick 		*strchr(buf, '=') = '\0';
15658888Smckusick 		*cp++ = '\0';
15758888Smckusick 		while (isspace(*cp))
15858888Smckusick 			cp++;
15959140Smckusick 		newval = cp;
16059140Smckusick 		newsize = strlen(cp);
16158888Smckusick 	}
16259140Smckusick 	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
16358888Smckusick 		return;
16458888Smckusick 	mib[0] = indx;
165*59159Smckusick 	if (indx == CTL_DEBUG)
166*59159Smckusick 		debuginit();
16758888Smckusick 	lp = &secondlevel[indx];
16858888Smckusick 	if (lp->list == 0) {
16958888Smckusick 		fprintf(stderr, "%s: class is not implemented\n",
17058888Smckusick 		    topname[indx]);
17158888Smckusick 		return;
17258888Smckusick 	}
17358910Smckusick 	if (bufp == NULL) {
17459140Smckusick 		listall(topname[indx].ctl_name, lp);
17558910Smckusick 		return;
17658910Smckusick 	}
17758888Smckusick 	if ((indx = findname(string, "second", &bufp, lp)) == -1)
17858888Smckusick 		return;
17958888Smckusick 	mib[1] = indx;
18059140Smckusick 	type = lp->list[indx].ctl_type;
18159140Smckusick 	len = 2;
18258888Smckusick 	switch (mib[0]) {
18358888Smckusick 
18458888Smckusick 	case CTL_KERN:
18558888Smckusick 		switch (mib[1]) {
18658888Smckusick 		case KERN_VNODE:
18758888Smckusick 		case KERN_FILE:
18858888Smckusick 			if (flags == 0)
18958888Smckusick 				return;
19058888Smckusick 			fprintf(stderr,
19158888Smckusick 			    "Use pstat to view %s information\n", string);
19258888Smckusick 			return;
19358888Smckusick 		case KERN_PROC:
19458888Smckusick 			if (flags == 0)
19558888Smckusick 				return;
19658888Smckusick 			fprintf(stderr,
19758888Smckusick 			    "Use ps to view %s information\n", string);
19858888Smckusick 			return;
19958888Smckusick 		case KERN_CLOCKRATE:
20058888Smckusick 			isclockrate = 1;
20158888Smckusick 			break;
20258888Smckusick 		}
20358888Smckusick 		break;
20458888Smckusick 
20558888Smckusick 	case CTL_HW:
20658888Smckusick 		break;
20758888Smckusick 
20858888Smckusick 	case CTL_VM:
20958888Smckusick 		if (mib[1] == VM_LOADAVG) {
21058888Smckusick 			double loads[3];
21158888Smckusick 
21258888Smckusick 			getloadavg(loads, 3);
21358910Smckusick 			if (!nflag)
21458910Smckusick 				fprintf(stdout, "%s: ", string);
21558910Smckusick 			fprintf(stdout, "%.2f %.2f %.2f\n",
21658888Smckusick 			    loads[0], loads[1], loads[2]);
21758888Smckusick 			return;
21858888Smckusick 		}
21958888Smckusick 		if (flags == 0)
22058888Smckusick 			return;
22158888Smckusick 		fprintf(stderr,
22258888Smckusick 		    "Use vmstat or systat to view %s information\n", string);
22358888Smckusick 		return;
22458888Smckusick 
22558888Smckusick 	case CTL_NET:
22659140Smckusick 		if (mib[1] == PF_INET) {
22759140Smckusick 			len = sysctl_inet(string, &bufp, mib, flags, &type);
22859140Smckusick 			if (len >= 0)
22959140Smckusick 				break;
23059140Smckusick 			return;
23159140Smckusick 		}
23258888Smckusick 		if (flags == 0)
23358888Smckusick 			return;
23458888Smckusick 		fprintf(stderr, "Use netstat to view %s information\n", string);
23558888Smckusick 		return;
23658888Smckusick 
237*59159Smckusick 	case CTL_DEBUG:
238*59159Smckusick 		mib[2] = CTL_DEBUG_VALUE;
239*59159Smckusick 		len = 3;
240*59159Smckusick 		break;
241*59159Smckusick 
24258888Smckusick 	case CTL_FS:
24358888Smckusick 	case CTL_MACHDEP:
24458888Smckusick 		break;
24558888Smckusick 
24658888Smckusick 	default:
24758888Smckusick 		fprintf(stderr, "Illegal top level value: %d\n", mib[0]);
24858888Smckusick 		return;
24958888Smckusick 
25058888Smckusick 	}
25159140Smckusick 	if (bufp) {
25259140Smckusick 		fprintf(stderr, "name %s in %s is unknown\n", *bufp, string);
25359140Smckusick 		return;
25459140Smckusick 	}
25559140Smckusick 	if (newsize > 0) {
25659140Smckusick 		switch (type) {
25759140Smckusick 		case CTLTYPE_INT:
25859140Smckusick 			intval = atoi(newval);
25959140Smckusick 			newval = &intval;
26059140Smckusick 			newsize = sizeof intval;
26159140Smckusick 			break;
26258888Smckusick 
26359140Smckusick 		case CTLTYPE_QUAD:
26459140Smckusick 			sscanf(newval, "%qd", &quadval);
26559140Smckusick 			newval = &quadval;
26659140Smckusick 			newsize = sizeof quadval;
26759140Smckusick 			break;
26859140Smckusick 		}
26959140Smckusick 	}
27058888Smckusick 	size = BUFSIZ;
27159140Smckusick 	if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
27258888Smckusick 		if (flags == 0)
27358888Smckusick 			return;
27458888Smckusick 		switch (errno) {
27558888Smckusick 		case EOPNOTSUPP:
27658888Smckusick 			fprintf(stderr, "%s: value is not available\n", string);
27758888Smckusick 			return;
27858888Smckusick 		case ENOTDIR:
27958888Smckusick 			fprintf(stderr, "%s: specification is incomplete\n",
28058888Smckusick 			    string);
28158888Smckusick 			return;
28258888Smckusick 		case ENOMEM:
28358888Smckusick 			fprintf(stderr, "%s: type is unknown to this program\n",
28458888Smckusick 			    string);
28558888Smckusick 			return;
28658888Smckusick 		default:
28758888Smckusick 			perror(string);
28858888Smckusick 			return;
28958888Smckusick 		}
29058888Smckusick 	}
29158888Smckusick 	if (isclockrate) {
29258888Smckusick 		struct clockinfo *clkp = (struct clockinfo *)buf;
29358888Smckusick 
29458910Smckusick 		if (!nflag)
29558910Smckusick 			fprintf(stdout, "%s: ", string);
29658888Smckusick 		fprintf(stdout,
29758910Smckusick 		    "hz = %d, tick = %d, profhz = %d, stathz = %d\n",
29858910Smckusick 		    clkp->hz, clkp->tick, clkp->profhz, clkp->stathz);
29958888Smckusick 		return;
30058888Smckusick 	}
30159140Smckusick 	switch (type) {
30259140Smckusick 	case CTLTYPE_INT:
30358910Smckusick 		if (newsize == 0) {
30458910Smckusick 			if (!nflag)
30558910Smckusick 				fprintf(stdout, "%s = ", string);
30658910Smckusick 			fprintf(stdout, "%d\n", *(int *)buf);
30758910Smckusick 		} else {
30858910Smckusick 			if (!nflag)
30958910Smckusick 				fprintf(stdout, "%s: %d -> ", string,
31058910Smckusick 				    *(int *)buf);
31158910Smckusick 			fprintf(stdout, "%d\n", *(int *)newval);
31258910Smckusick 		}
31359140Smckusick 		return;
31459140Smckusick 
31559140Smckusick 	case CTLTYPE_STRING:
31658910Smckusick 		if (newsize == 0) {
31758910Smckusick 			if (!nflag)
31858910Smckusick 				fprintf(stdout, "%s = ", string);
31958910Smckusick 			fprintf(stdout, "%s\n", buf);
32058910Smckusick 		} else {
32158910Smckusick 			if (!nflag)
32258910Smckusick 				fprintf(stdout, "%s: %s -> ", string, buf);
32358910Smckusick 			fprintf(stdout, "%s\n", newval);
32458910Smckusick 		}
32559140Smckusick 		return;
32659140Smckusick 
32759140Smckusick 	case CTLTYPE_QUAD:
32859140Smckusick 		if (newsize == 0) {
32959140Smckusick 			if (!nflag)
33059140Smckusick 				fprintf(stdout, "%s = ", string);
33159140Smckusick 			fprintf(stdout, "%qd\n", *(quad_t *)buf);
33259140Smckusick 		} else {
33359140Smckusick 			if (!nflag)
33459140Smckusick 				fprintf(stdout, "%s: %qd -> ", string,
33559140Smckusick 				    *(quad_t *)buf);
33659140Smckusick 			fprintf(stdout, "%qd\n", *(quad_t *)newval);
33759140Smckusick 		}
33859140Smckusick 		return;
33959140Smckusick 
34059140Smckusick 	case CTLTYPE_STRUCT:
34159140Smckusick 		fprintf(stderr, "%s: unknown structure returned\n",
34259140Smckusick 		    string);
34359140Smckusick 		return;
34459140Smckusick 
34559140Smckusick 	default:
34659140Smckusick 	case CTLTYPE_NODE:
34759140Smckusick 		fprintf(stderr, "%s: unknown type returned\n",
34859140Smckusick 		    string);
34959140Smckusick 		return;
35059140Smckusick 	}
35158888Smckusick }
35258888Smckusick 
353*59159Smckusick /*
354*59159Smckusick  * Initialize the set of debugging names
355*59159Smckusick  */
356*59159Smckusick debuginit()
357*59159Smckusick {
358*59159Smckusick 	int mib[3], size, loc, i;
359*59159Smckusick 
360*59159Smckusick 	if (secondlevel[CTL_DEBUG].list != 0)
361*59159Smckusick 		return;
362*59159Smckusick 	secondlevel[CTL_DEBUG].list = debugname;
363*59159Smckusick 	mib[0] = CTL_DEBUG;
364*59159Smckusick 	mib[2] = CTL_DEBUG_NAME;
365*59159Smckusick 	for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) {
366*59159Smckusick 		mib[1] = i;
367*59159Smckusick 		size = BUFSIZ - loc;
368*59159Smckusick 		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
369*59159Smckusick 			continue;
370*59159Smckusick 		debugname[i].ctl_name = &names[loc];
371*59159Smckusick 		debugname[i].ctl_type = CTLTYPE_INT;
372*59159Smckusick 		loc += size;
373*59159Smckusick 	}
374*59159Smckusick }
375*59159Smckusick 
37659140Smckusick struct ctlname inetname[] = CTL_IPPROTO_NAMES;
37759140Smckusick struct ctlname ipname[] = IPCTL_NAMES;
37859140Smckusick struct ctlname icmpname[] = ICMPCTL_NAMES;
37959140Smckusick struct list inetlist = { inetname, IPPROTO_MAXID };
38059140Smckusick struct list inetvars[] = {
38159140Smckusick 	{ ipname, IPCTL_MAXID },
38259140Smckusick 	{ icmpname, ICMPCTL_MAXID },
38359140Smckusick };
38459140Smckusick 
38558888Smckusick /*
38659140Smckusick  * handle internet requests
38759140Smckusick  */
38859140Smckusick sysctl_inet(string, bufpp, mib, flags, typep)
38959140Smckusick 	char *string;
39059140Smckusick 	char **bufpp;
39159140Smckusick 	int mib[];
39259140Smckusick 	int flags;
39359140Smckusick 	int *typep;
39459140Smckusick {
39559140Smckusick 	struct list *lp;
39659140Smckusick 	int indx;
39759140Smckusick 
39859140Smckusick 	if (*bufpp == NULL) {
39959140Smckusick 		listall(string, &inetlist);
40059140Smckusick 		return (-1);
40159140Smckusick 	}
40259140Smckusick 	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
40359140Smckusick 		return (-1);
40459140Smckusick 	mib[2] = indx;
40559140Smckusick 	if (indx < 2)
40659140Smckusick 		lp = &inetvars[indx];
40759140Smckusick 	else if (!flags)
40859140Smckusick 		return (-1);
40959140Smckusick 	else {
41059140Smckusick 		fprintf(stderr, "%s: no variables defined for this protocol\n",
41159140Smckusick 		    string);
41259140Smckusick 		return (-1);
41359140Smckusick 	}
41459140Smckusick 	if (*bufpp == NULL) {
41559140Smckusick 		listall(string, lp);
41659140Smckusick 		return (-1);
41759140Smckusick 	}
41859140Smckusick 	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
41959140Smckusick 		return (-1);
42059140Smckusick 	mib[3] = indx;
42159140Smckusick 	*typep = lp->list[indx].ctl_type;
42259140Smckusick 	return (4);
42359140Smckusick }
42459140Smckusick 
42559140Smckusick /*
42658888Smckusick  * Scan a list of names searching for a particular name.
42758888Smckusick  */
42858888Smckusick findname(string, level, bufp, namelist)
42958888Smckusick 	char *string;
43058888Smckusick 	char *level;
43158888Smckusick 	char **bufp;
43258888Smckusick 	struct list *namelist;
43358888Smckusick {
43458888Smckusick 	char *name;
43558888Smckusick 	int i;
43658888Smckusick 
43758888Smckusick 	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
43858888Smckusick 		fprintf(stderr, "%s: incomplete specification\n", string);
43958888Smckusick 		return (-1);
44058888Smckusick 	}
44158888Smckusick 	for (i = 0; i < namelist->size; i++)
44259140Smckusick 		if (!strcmp(name, namelist->list[i].ctl_name))
44358888Smckusick 			break;
44458888Smckusick 	if (i == namelist->size) {
44558888Smckusick 		fprintf(stderr, "%s level name %s in %s is invalid\n",
44658888Smckusick 		    level, name, string);
44758888Smckusick 		return (-1);
44858888Smckusick 	}
44958888Smckusick 	return (i);
45058888Smckusick }
45158888Smckusick 
45258888Smckusick usage()
45358888Smckusick {
45458888Smckusick 
45558911Smckusick 	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
45658911Smckusick 	    "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
45758911Smckusick 	    "sysctl [-n] -a", "sysctl [-n] -A");
45858888Smckusick 	exit(1);
45958888Smckusick }
460