sysctl.c revision 77928
11553Srgrimes/*
21553Srgrimes * Copyright (c) 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes * 1. Redistributions of source code must retain the above copyright
91553Srgrimes *    notice, this list of conditions and the following disclaimer.
101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111553Srgrimes *    notice, this list of conditions and the following disclaimer in the
121553Srgrimes *    documentation and/or other materials provided with the distribution.
131553Srgrimes * 3. All advertising materials mentioning features or use of this software
141553Srgrimes *    must display the following acknowledgement:
151553Srgrimes *	This product includes software developed by the University of
161553Srgrimes *	California, Berkeley and its contributors.
171553Srgrimes * 4. Neither the name of the University nor the names of its contributors
181553Srgrimes *    may be used to endorse or promote products derived from this software
191553Srgrimes *    without specific prior written permission.
201553Srgrimes *
211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311553Srgrimes * SUCH DAMAGE.
321553Srgrimes */
331553Srgrimes
341553Srgrimes#ifndef lint
3530602Scharnierstatic const char copyright[] =
361553Srgrimes"@(#) Copyright (c) 1993\n\
371553Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381553Srgrimes#endif /* not lint */
391553Srgrimes
401553Srgrimes#ifndef lint
4130602Scharnier#if 0
4230602Scharnierstatic char sccsid[] = "@(#)from: sysctl.c	8.1 (Berkeley) 6/6/93";
4330602Scharnier#endif
446284Swollmanstatic const char rcsid[] =
4550476Speter  "$FreeBSD: head/sbin/sysctl/sysctl.c 77928 2001-06-09 03:56:16Z dd $";
461553Srgrimes#endif /* not lint */
471553Srgrimes
4812946Sphk#include <sys/types.h>
491553Srgrimes#include <sys/stat.h>
501553Srgrimes#include <sys/sysctl.h>
5112946Sphk#include <sys/resource.h>
521553Srgrimes
5330602Scharnier#include <ctype.h>
5430602Scharnier#include <err.h>
551553Srgrimes#include <errno.h>
561553Srgrimes#include <stdio.h>
571553Srgrimes#include <stdlib.h>
581553Srgrimes#include <string.h>
5930602Scharnier#include <unistd.h>
601553Srgrimes
6177330Sdesstatic int	aflag, bflag, Nflag, nflag, oflag, xflag;
621553Srgrimes
6312946Sphkstatic int	oidfmt(int *, int, char *, u_int *);
6412946Sphkstatic void	parse(char *);
6512946Sphkstatic int	show_var(int *, int);
6612946Sphkstatic int	sysctl_all (int *oid, int len);
6712946Sphkstatic int	name2oid(char *, int *);
681553Srgrimes
6912946Sphkstatic void
7012946Sphkusage(void)
7112946Sphk{
721553Srgrimes
7377330Sdes	(void)fprintf(stderr, "%s\n%s\n",
7477330Sdes	    "usage: sysctl [-bNnox] variable[=value] ...",
7577330Sdes	    "       sysctl [-bNnox] -a");
7612946Sphk	exit(1);
7712946Sphk}
781553Srgrimes
791553Srgrimesint
8012946Sphkmain(int argc, char **argv)
811553Srgrimes{
8212946Sphk	int ch;
8312946Sphk	setbuf(stdout,0);
8412946Sphk	setbuf(stderr,0);
851553Srgrimes
8677330Sdes	while ((ch = getopt(argc, argv, "AabNnowxX")) != -1) {
871553Srgrimes		switch (ch) {
8871034Sdes		case 'A':
8977330Sdes			/* compatibility */
9077330Sdes			aflag = oflag = 1;
9171034Sdes			break;
9271034Sdes		case 'a':
9371034Sdes			aflag = 1;
9471034Sdes			break;
9571034Sdes		case 'b':
9671034Sdes			bflag = 1;
9771034Sdes			break;
9871034Sdes		case 'N':
9971034Sdes			Nflag = 1;
10071034Sdes			break;
10171034Sdes		case 'n':
10271034Sdes			nflag = 1;
10371034Sdes			break;
10477330Sdes		case 'o':
10577330Sdes			oflag = 1;
10677330Sdes			break;
10771034Sdes		case 'w':
10877330Sdes			/* compatibility */
10977330Sdes			/* ignored */
11071034Sdes			break;
11171034Sdes		case 'X':
11277330Sdes			/* compatibility */
11377330Sdes			aflag = xflag = 1;
11471034Sdes			break;
11577330Sdes		case 'x':
11677330Sdes			xflag = 1;
11777330Sdes			break;
11871034Sdes		default:
11971034Sdes			usage();
1201553Srgrimes		}
1211553Srgrimes	}
1221553Srgrimes	argc -= optind;
1231553Srgrimes	argv += optind;
1241553Srgrimes
12577330Sdes	if (Nflag && nflag)
12642456Sdes		usage();
12777330Sdes	if (aflag && argc == 0)
12877330Sdes		exit(sysctl_all(0, 0));
1291553Srgrimes	if (argc == 0)
1301553Srgrimes		usage();
1311553Srgrimes	while (argc-- > 0)
13212946Sphk		parse(*argv++);
1331553Srgrimes	exit(0);
1341553Srgrimes}
1351553Srgrimes
1361553Srgrimes/*
1371553Srgrimes * Parse a name into a MIB entry.
1381553Srgrimes * Lookup and print out the MIB entry if it exists.
1391553Srgrimes * Set a new value if requested.
1401553Srgrimes */
14112946Sphkstatic void
14212946Sphkparse(char *string)
1431553Srgrimes{
14412946Sphk	int len, i, j;
1451553Srgrimes	void *newval = 0;
1461553Srgrimes	int intval, newsize = 0;
1471553Srgrimes	quad_t quadval;
1481553Srgrimes	int mib[CTL_MAXNAME];
14912946Sphk	char *cp, *bufp, buf[BUFSIZ];
15012946Sphk	u_int kind;
1511553Srgrimes
1521553Srgrimes	bufp = buf;
1531553Srgrimes	snprintf(buf, BUFSIZ, "%s", string);
1541553Srgrimes	if ((cp = strchr(string, '=')) != NULL) {
1551553Srgrimes		*strchr(buf, '=') = '\0';
1561553Srgrimes		*cp++ = '\0';
1571553Srgrimes		while (isspace(*cp))
1581553Srgrimes			cp++;
1591553Srgrimes		newval = cp;
1601553Srgrimes		newsize = strlen(cp);
1611553Srgrimes	}
16212946Sphk	len = name2oid(bufp, mib);
1631553Srgrimes
16412946Sphk	if (len < 0)
16530602Scharnier		errx(1, "unknown oid '%s'", bufp);
1661553Srgrimes
16712946Sphk	if (oidfmt(mib, len, 0, &kind))
16830602Scharnier		err(1, "couldn't find format of oid '%s'", bufp);
1691553Srgrimes
17077330Sdes	if (newval == NULL) {
17112946Sphk		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
17212946Sphk			sysctl_all(mib, len);
17312946Sphk		} else {
17412946Sphk			i = show_var(mib, len);
17512946Sphk			if (!i && !bflag)
17612946Sphk				putchar('\n');
1771553Srgrimes		}
17812946Sphk	} else {
17912946Sphk		if ((kind & CTLTYPE) == CTLTYPE_NODE)
18012946Sphk			errx(1, "oid '%s' isn't a leaf node", bufp);
1811553Srgrimes
18212946Sphk		if (!(kind&CTLFLAG_WR))
18312946Sphk			errx(1, "oid '%s' is read only", bufp);
18412946Sphk
18512946Sphk		switch (kind & CTLTYPE) {
18612946Sphk			case CTLTYPE_INT:
18753317Sgrog				intval = (int) strtol(newval, NULL, 0);
18812946Sphk				newval = &intval;
18977928Sdd				newsize = sizeof(intval);
1901553Srgrimes				break;
19112946Sphk				break;
19212946Sphk			case CTLTYPE_STRING:
19312946Sphk				break;
19412946Sphk			case CTLTYPE_QUAD:
19512946Sphk				break;
19612946Sphk				sscanf(newval, "%qd", &quadval);
19712946Sphk				newval = &quadval;
19877928Sdd				newsize = sizeof(quadval);
19912946Sphk				break;
20012946Sphk			default:
20112946Sphk				errx(1, "oid '%s' is type %d,"
20231214Sjdp					" cannot set that", bufp,
20331214Sjdp					kind & CTLTYPE);
2041553Srgrimes		}
2051553Srgrimes
20612946Sphk		i = show_var(mib, len);
20712946Sphk		if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
20812946Sphk			if (!i && !bflag)
20912946Sphk				putchar('\n');
21012946Sphk			switch (errno) {
21112946Sphk			case EOPNOTSUPP:
21230602Scharnier				errx(1, "%s: value is not available",
21312946Sphk					string);
21412946Sphk			case ENOTDIR:
21530602Scharnier				errx(1, "%s: specification is incomplete",
21612946Sphk					string);
21712946Sphk			case ENOMEM:
21830602Scharnier				errx(1, "%s: type is unknown to this program",
21912946Sphk					string);
22012946Sphk			default:
22130602Scharnier				warn("%s", string);
22212946Sphk				return;
22312946Sphk			}
22412946Sphk		}
22512946Sphk		if (!bflag)
22612946Sphk			printf(" -> ");
22712946Sphk		i = nflag;
22812946Sphk		nflag = 1;
22912946Sphk		j = show_var(mib, len);
23012946Sphk		if (!j && !bflag)
23112946Sphk			putchar('\n');
23212946Sphk		nflag = i;
23312946Sphk	}
23412946Sphk}
2351553Srgrimes
23612946Sphk/* These functions will dump out various interesting structures. */
2371553Srgrimes
23812946Sphkstatic int
23912946SphkS_clockinfo(int l2, void *p)
24012946Sphk{
24112946Sphk	struct clockinfo *ci = (struct clockinfo*)p;
24277928Sdd	if (l2 != sizeof(*ci))
24377928Sdd		err(1, "S_clockinfo %d != %d", l2, sizeof(*ci));
24426899Sjhay	printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
24526899Sjhay		ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz);
24612946Sphk	return (0);
24712946Sphk}
2481553Srgrimes
24912946Sphkstatic int
25012946SphkS_loadavg(int l2, void *p)
25112946Sphk{
25212946Sphk	struct loadavg *tv = (struct loadavg*)p;
2538857Srgrimes
25477928Sdd	if (l2 != sizeof(*tv))
25577928Sdd		err(1, "S_loadavg %d != %d", l2, sizeof(*tv));
2561553Srgrimes
25712946Sphk	printf("{ %.2f %.2f %.2f }",
25812946Sphk		(double)tv->ldavg[0]/(double)tv->fscale,
25912946Sphk		(double)tv->ldavg[1]/(double)tv->fscale,
26012946Sphk		(double)tv->ldavg[2]/(double)tv->fscale);
26112946Sphk	return (0);
26212946Sphk}
2631553Srgrimes
26412946Sphkstatic int
26512946SphkS_timeval(int l2, void *p)
26612946Sphk{
26712946Sphk	struct timeval *tv = (struct timeval*)p;
26837266Sbde	time_t tv_sec;
26912946Sphk	char *p1, *p2;
2701553Srgrimes
27177928Sdd	if (l2 != sizeof(*tv))
27277928Sdd		err(1, "S_timeval %d != %d", l2, sizeof(*tv));
27312946Sphk	printf("{ sec = %ld, usec = %ld } ",
27412946Sphk		tv->tv_sec, tv->tv_usec);
27537266Sbde	tv_sec = tv->tv_sec;
27637266Sbde	p1 = strdup(ctime(&tv_sec));
27712946Sphk	for (p2=p1; *p2 ; p2++)
27812946Sphk		if (*p2 == '\n')
27912946Sphk			*p2 = '\0';
28012946Sphk	fputs(p1, stdout);
28112946Sphk	return (0);
28212946Sphk}
2831553Srgrimes
28412946Sphkstatic int
28512946SphkT_dev_t(int l2, void *p)
28612946Sphk{
28712946Sphk	dev_t *d = (dev_t *)p;
28877928Sdd	if (l2 != sizeof(*d))
28977928Sdd		err(1, "T_dev_T %d != %d", l2, sizeof(*d));
29061514Sphk	if ((int)(*d) != -1) {
29161514Sphk		if (minor(*d) > 255 || minor(*d) < 0)
29261514Sphk			printf("{ major = %d, minor = 0x%x }",
29361514Sphk				major(*d), minor(*d));
29461514Sphk		else
29561514Sphk			printf("{ major = %d, minor = %d }",
29661514Sphk				major(*d), minor(*d));
29761514Sphk	}
29812946Sphk	return (0);
29912946Sphk}
3001553Srgrimes
30112946Sphk/*
30212946Sphk * These functions uses a presently undocumented interface to the kernel
30312946Sphk * to walk the tree and get the type so it can print the value.
30412946Sphk * This interface is under work and consideration, and should probably
30512946Sphk * be killed with a big axe by the first person who can find the time.
30612946Sphk * (be aware though, that the proper interface isn't as obvious as it
30712946Sphk * may seem, there are various conflicting requirements.
30812946Sphk */
3091553Srgrimes
31012946Sphkstatic int
31112946Sphkname2oid(char *name, int *oidp)
31212946Sphk{
31312946Sphk	int oid[2];
31438533Sdfr	int i;
31538533Sdfr	size_t j;
3161553Srgrimes
31712946Sphk	oid[0] = 0;
31812946Sphk	oid[1] = 3;
3191553Srgrimes
32077928Sdd	j = CTL_MAXNAME * sizeof(int);
32112946Sphk	i = sysctl(oid, 2, oidp, &j, name, strlen(name));
32212946Sphk	if (i < 0)
32312946Sphk		return i;
32477928Sdd	j /= sizeof(int);
32512946Sphk	return (j);
3261553Srgrimes}
3271553Srgrimes
32812946Sphkstatic int
32912946Sphkoidfmt(int *oid, int len, char *fmt, u_int *kind)
33012946Sphk{
33112946Sphk	int qoid[CTL_MAXNAME+2];
33212946Sphk	u_char buf[BUFSIZ];
33338533Sdfr	int i;
33438533Sdfr	size_t j;
3351553Srgrimes
33612946Sphk	qoid[0] = 0;
33712946Sphk	qoid[1] = 4;
33812946Sphk	memcpy(qoid + 2, oid, len * sizeof(int));
3391553Srgrimes
34077928Sdd	j = sizeof(buf);
34112946Sphk	i = sysctl(qoid, len + 2, buf, &j, 0, 0);
34212946Sphk	if (i)
34330602Scharnier		err(1, "sysctl fmt %d %d %d", i, j, errno);
3441553Srgrimes
34512946Sphk	if (kind)
34612946Sphk		*kind = *(u_int *)buf;
34712946Sphk
34812946Sphk	if (fmt)
34912946Sphk		strcpy(fmt, (char *)(buf + sizeof(u_int)));
35012946Sphk	return 0;
3511553Srgrimes}
3521553Srgrimes
3531553Srgrimes/*
35412946Sphk * This formats and outputs the value of one variable
35512946Sphk *
35612946Sphk * Returns zero if anything was actually output.
35712946Sphk * Returns one if didn't know what to do with this.
35812946Sphk * Return minus one if we had errors.
3591553Srgrimes */
36012946Sphk
36112946Sphkstatic int
36212946Sphkshow_var(int *oid, int nlen)
3631553Srgrimes{
36412946Sphk	u_char buf[BUFSIZ], *val, *p;
36577567Sdd	char name[BUFSIZ], *fmt;
36612946Sphk	int qoid[CTL_MAXNAME+2];
36738533Sdfr	int i;
36838533Sdfr	size_t j, len;
36912946Sphk	u_int kind;
37077332Sdes	int (*func)(int, void *);
3711553Srgrimes
37242456Sdes	qoid[0] = 0;
37342456Sdes	memcpy(qoid + 2, oid, nlen * sizeof(int));
37442456Sdes
37542456Sdes	qoid[1] = 1;
37677928Sdd	j = sizeof(name);
37742456Sdes	i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
37842456Sdes	if (i || !j)
37942456Sdes		err(1, "sysctl name %d %d %d", i, j, errno);
38042456Sdes
38171034Sdes	if (Nflag) {
38271034Sdes		printf("%s", name);
38371034Sdes		return (0);
38471034Sdes	}
38571034Sdes
38612946Sphk	/* find an estimate of how much we need for this var */
38712946Sphk	j = 0;
38812946Sphk	i = sysctl(oid, nlen, 0, &j, 0, 0);
38912946Sphk	j += j; /* we want to be sure :-) */
39012946Sphk
39112946Sphk	val = alloca(j);
39212946Sphk	len = j;
39312946Sphk	i = sysctl(oid, nlen, val, &len, 0, 0);
39412946Sphk	if (i || !len)
39512946Sphk		return (1);
39612946Sphk
39712946Sphk	if (bflag) {
39812946Sphk		fwrite(val, 1, len, stdout);
39912946Sphk		return (0);
4001553Srgrimes	}
40112946Sphk
40212946Sphk	qoid[1] = 4;
40377928Sdd	j = sizeof(buf);
40412946Sphk	i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
40512946Sphk	if (i || !j)
40630602Scharnier		err(1, "sysctl fmt %d %d %d", i, j, errno);
40712946Sphk
40812946Sphk	kind = *(u_int *)buf;
40912946Sphk
41012946Sphk	fmt = (char *)(buf + sizeof(u_int));
41112946Sphk
41212946Sphk	p = val;
41312946Sphk	switch (*fmt) {
41412946Sphk	case 'A':
41512946Sphk		if (!nflag)
41612946Sphk			printf("%s: ", name);
41712946Sphk		printf("%s", p);
41812946Sphk		return (0);
41912946Sphk
42012946Sphk	case 'I':
42112946Sphk		if (!nflag)
42212946Sphk			printf("%s: ", name);
42362622Sjhb		fmt++;
42441019Sphk		val = "";
42541019Sphk		while (len >= sizeof(int)) {
42662622Sjhb			if(*fmt == 'U')
42762622Sjhb				printf("%s%u", val, *(unsigned int *)p);
42862622Sjhb			else
42962622Sjhb				printf("%s%d", val, *(int *)p);
43041019Sphk			val = " ";
43177332Sdes			len -= sizeof(int);
43277332Sdes			p += sizeof(int);
43341019Sphk		}
43412946Sphk		return (0);
43512946Sphk
43638533Sdfr	case 'L':
43738533Sdfr		if (!nflag)
43838533Sdfr			printf("%s: ", name);
43962622Sjhb		fmt++;
44062975Sphk		val = "";
44162975Sphk		while (len >= sizeof(long)) {
44262975Sphk			if(*fmt == 'U')
44362975Sphk				printf("%s%lu", val, *(unsigned long *)p);
44462975Sphk			else
44562975Sphk				printf("%s%ld", val, *(long *)p);
44662975Sphk			val = " ";
44777332Sdes			len -= sizeof(long);
44877332Sdes			p += sizeof(long);
44962975Sphk		}
45038533Sdfr		return (0);
45138533Sdfr
45238533Sdfr	case 'P':
45338533Sdfr		if (!nflag)
45438533Sdfr			printf("%s: ", name);
45538533Sdfr		printf("%p", *(void **)p);
45638533Sdfr		return (0);
45738533Sdfr
45812946Sphk	case 'T':
45912946Sphk	case 'S':
46012946Sphk		i = 0;
46177332Sdes		if (strcmp(fmt, "S,clockinfo") == 0)
46277332Sdes			func = S_clockinfo;
46377332Sdes		else if (strcmp(fmt, "S,timeval") == 0)
46477332Sdes			func = S_timeval;
46577332Sdes		else if (strcmp(fmt, "S,loadavg") == 0)
46677332Sdes			func = S_loadavg;
46777332Sdes		else if (strcmp(fmt, "T,dev_t") == 0)
46877332Sdes			func = T_dev_t;
46977332Sdes		else
47077332Sdes			func = NULL;
47112946Sphk		if (func) {
47212946Sphk			if (!nflag)
47312946Sphk				printf("%s: ", name);
47412946Sphk			return ((*func)(len, p));
47512946Sphk		}
47612946Sphk		/* FALL THROUGH */
47712946Sphk	default:
47877330Sdes		if (!oflag && !xflag)
47912946Sphk			return (1);
48012946Sphk		if (!nflag)
48112946Sphk			printf("%s: ", name);
48212946Sphk		printf("Format:%s Length:%d Dump:0x", fmt, len);
48377332Sdes		while (len-- && (xflag || p < val + 16))
48412946Sphk			printf("%02x", *p++);
48577332Sdes		if (!xflag && len > 16)
48612946Sphk			printf("...");
48712946Sphk		return (0);
4881553Srgrimes	}
48912946Sphk	return (1);
4901553Srgrimes}
4911553Srgrimes
49212946Sphkstatic int
49312946Sphksysctl_all (int *oid, int len)
4941553Srgrimes{
49512946Sphk	int name1[22], name2[22];
49638533Sdfr	int i, j;
49738533Sdfr	size_t l1, l2;
4981553Srgrimes
49912946Sphk	name1[0] = 0;
50012946Sphk	name1[1] = 2;
50112946Sphk	l1 = 2;
50212946Sphk	if (len) {
50377928Sdd		memcpy(name1+2, oid, len * sizeof(int));
50412946Sphk		l1 += len;
50512946Sphk	} else {
50612946Sphk		name1[2] = 1;
50712946Sphk		l1++;
50812946Sphk	}
50977332Sdes	for (;;) {
51077928Sdd		l2 = sizeof(name2);
51112946Sphk		j = sysctl(name1, l1, name2, &l2, 0, 0);
51248956Sbillf		if (j < 0) {
51312946Sphk			if (errno == ENOENT)
51412946Sphk				return 0;
51512946Sphk			else
51630602Scharnier				err(1, "sysctl(getnext) %d %d", j, l2);
51748956Sbillf		}
51812946Sphk
51977928Sdd		l2 /= sizeof(int);
52012946Sphk
52112946Sphk		if (l2 < len)
52212946Sphk			return 0;
52312946Sphk
52412946Sphk		for (i = 0; i < len; i++)
52512946Sphk			if (name2[i] != oid[i])
52612946Sphk				return 0;
52712946Sphk
52812946Sphk		i = show_var(name2, l2);
52912946Sphk		if (!i && !bflag)
53012946Sphk			putchar('\n');
53112946Sphk
53277928Sdd		memcpy(name1+2, name2, l2 * sizeof(int));
53312946Sphk		l1 = 2 + l2;
53412946Sphk	}
5351553Srgrimes}
536