sysctl.c revision 48956
195584Sanholt/*
2152909Sanholt * Copyright (c) 1993
3152909Sanholt *	The Regents of the University of California.  All rights reserved.
495584Sanholt *
595584Sanholt * Redistribution and use in source and binary forms, with or without
695584Sanholt * modification, are permitted provided that the following conditions
795584Sanholt * are met:
895584Sanholt * 1. Redistributions of source code must retain the above copyright
995584Sanholt *    notice, this list of conditions and the following disclaimer.
1095584Sanholt * 2. Redistributions in binary form must reproduce the above copyright
1195584Sanholt *    notice, this list of conditions and the following disclaimer in the
1295584Sanholt *    documentation and/or other materials provided with the distribution.
1395584Sanholt * 3. All advertising materials mentioning features or use of this software
1495584Sanholt *    must display the following acknowledgement:
1595584Sanholt *	This product includes software developed by the University of
1695584Sanholt *	California, Berkeley and its contributors.
1795584Sanholt * 4. Neither the name of the University nor the names of its contributors
1895584Sanholt *    may be used to endorse or promote products derived from this software
1995584Sanholt *    without specific prior written permission.
2095584Sanholt *
2195584Sanholt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2295584Sanholt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2395584Sanholt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2495584Sanholt * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2595584Sanholt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2695584Sanholt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2795584Sanholt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2895584Sanholt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29112015Sanholt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3095584Sanholt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3195584Sanholt * SUCH DAMAGE.
3295584Sanholt */
3395584Sanholt
3495584Sanholt#ifndef lint
35152909Sanholtstatic const char copyright[] =
36152909Sanholt"@(#) Copyright (c) 1993\n\
37152909Sanholt	The Regents of the University of California.  All rights reserved.\n";
3895584Sanholt#endif /* not lint */
3995584Sanholt
4095584Sanholt#ifndef lint
4195584Sanholt#if 0
4295584Sanholtstatic char sccsid[] = "@(#)from: sysctl.c	8.1 (Berkeley) 6/6/93";
4395584Sanholt#endif
44112015Sanholtstatic const char rcsid[] =
4595584Sanholt	"$Id: sysctl.c,v 1.20 1999/01/10 02:10:08 des Exp $";
4695584Sanholt#endif /* not lint */
4795584Sanholt
4895584Sanholt#include <sys/types.h>
4995584Sanholt#include <sys/stat.h>
50145132Sanholt#include <sys/sysctl.h>
51145132Sanholt#include <sys/resource.h>
52145132Sanholt
53145132Sanholt#include <ctype.h>
5495584Sanholt#include <err.h>
5595584Sanholt#include <errno.h>
5695584Sanholt#include <stdio.h>
5795584Sanholt#include <stdlib.h>
5895584Sanholt#include <string.h>
5995584Sanholt#include <unistd.h>
6095584Sanholt
6195584Sanholtstatic int	Aflag, aflag, bflag, dflag, nflag, wflag, Xflag;
6295584Sanholt
6395584Sanholtstatic int	oidfmt(int *, int, char *, u_int *);
6495584Sanholtstatic void	parse(char *);
6595584Sanholtstatic int	show_var(int *, int);
6695584Sanholtstatic int	sysctl_all (int *oid, int len);
6795584Sanholtstatic int	name2oid(char *, int *);
6895584Sanholt
6995584Sanholtstatic void
7095584Sanholtusage(void)
7195584Sanholt{
72145132Sanholt
7395584Sanholt	(void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
7495584Sanholt		"usage: sysctl [-bdn] variable ...",
75145132Sanholt		"       sysctl [-bn] -w variable=value ...",
7695584Sanholt		"       sysctl [-bdn] -a",
7795584Sanholt		"       sysctl [-bdn] -A",
7895584Sanholt		"       sysctl [-bdn] -X");
79152909Sanholt	exit(1);
80152909Sanholt}
8195584Sanholt
8295584Sanholtint
8395584Sanholtmain(int argc, char **argv)
8495584Sanholt{
8595584Sanholt	int ch;
8695584Sanholt	setbuf(stdout,0);
8795584Sanholt	setbuf(stderr,0);
8895584Sanholt
8995584Sanholt	while ((ch = getopt(argc, argv, "AabdnwX")) != -1) {
9095584Sanholt		switch (ch) {
9195584Sanholt		case 'A': Aflag = 1; break;
92145132Sanholt		case 'a': aflag = 1; break;
93145132Sanholt		case 'b': bflag = 1; break;
9495584Sanholt		case 'd': dflag = 1; break;
95145132Sanholt		case 'n': nflag = 1; break;
96145132Sanholt		case 'w': wflag = 1; break;
9795584Sanholt		case 'X': Xflag = Aflag = 1; break;
98145132Sanholt		default: usage();
99145132Sanholt		}
10095584Sanholt	}
10195584Sanholt	argc -= optind;
10295584Sanholt	argv += optind;
10395584Sanholt
10495584Sanholt	if (wflag && (Aflag || aflag || dflag))
10595584Sanholt		usage();
10695584Sanholt	if (Aflag || aflag)
10795584Sanholt		exit (sysctl_all(0, 0));
10895584Sanholt	if (argc == 0)
10995584Sanholt		usage();
11095584Sanholt	while (argc-- > 0)
111298955Spfg		parse(*argv++);
11295584Sanholt	exit(0);
11395584Sanholt}
11495584Sanholt
11595584Sanholt/*
11695584Sanholt * Parse a name into a MIB entry.
11795584Sanholt * Lookup and print out the MIB entry if it exists.
11895584Sanholt * Set a new value if requested.
11995584Sanholt */
12095584Sanholtstatic void
12195584Sanholtparse(char *string)
12295584Sanholt{
12395584Sanholt	int len, i, j;
124130331Sanholt	void *newval = 0;
125130331Sanholt	int intval, newsize = 0;
126145132Sanholt	quad_t quadval;
12795584Sanholt	int mib[CTL_MAXNAME];
12895584Sanholt	char *cp, *bufp, buf[BUFSIZ];
12995584Sanholt	u_int kind;
13095584Sanholt
13195584Sanholt	bufp = buf;
13295584Sanholt	snprintf(buf, BUFSIZ, "%s", string);
13395584Sanholt	if ((cp = strchr(string, '=')) != NULL) {
13495584Sanholt		if (!wflag)
13595584Sanholt			errx(2, "must specify -w to set variables");
13695584Sanholt		*strchr(buf, '=') = '\0';
13795584Sanholt		*cp++ = '\0';
13895584Sanholt		while (isspace(*cp))
13995584Sanholt			cp++;
14095584Sanholt		newval = cp;
14195584Sanholt		newsize = strlen(cp);
14295584Sanholt	} else {
14395584Sanholt		if (wflag)
14495584Sanholt			usage();
14595584Sanholt	}
14695584Sanholt	len = name2oid(bufp, mib);
14795584Sanholt
14895584Sanholt	if (len < 0)
14995584Sanholt		errx(1, "unknown oid '%s'", bufp);
15095584Sanholt
15195584Sanholt	if (oidfmt(mib, len, 0, &kind))
15295584Sanholt		err(1, "couldn't find format of oid '%s'", bufp);
15395584Sanholt
15495584Sanholt	if (!wflag) {
15595584Sanholt		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
15695584Sanholt			sysctl_all(mib, len);
15795584Sanholt		} else {
15895584Sanholt			i = show_var(mib, len);
15995584Sanholt			if (!i && !bflag)
16095584Sanholt				putchar('\n');
16195584Sanholt		}
16295584Sanholt	} else {
16395584Sanholt		if ((kind & CTLTYPE) == CTLTYPE_NODE)
16495584Sanholt			errx(1, "oid '%s' isn't a leaf node", bufp);
16595584Sanholt
16695584Sanholt		if (!(kind&CTLFLAG_WR))
16795584Sanholt			errx(1, "oid '%s' is read only", bufp);
16895584Sanholt
16995584Sanholt		switch (kind & CTLTYPE) {
170145132Sanholt			case CTLTYPE_INT:
171145132Sanholt				intval = atoi(newval);
17295584Sanholt				newval = &intval;
17395584Sanholt				newsize = sizeof intval;
17495584Sanholt				break;
17595584Sanholt				break;
17695584Sanholt			case CTLTYPE_STRING:
17795584Sanholt				break;
178145132Sanholt			case CTLTYPE_QUAD:
179145132Sanholt				break;
180145132Sanholt				sscanf(newval, "%qd", &quadval);
181145132Sanholt				newval = &quadval;
182145132Sanholt				newsize = sizeof quadval;
183145132Sanholt				break;
18495584Sanholt			default:
18595584Sanholt				errx(1, "oid '%s' is type %d,"
18695584Sanholt					" cannot set that", bufp,
187182080Srnoland					kind & CTLTYPE);
188145132Sanholt		}
18995584Sanholt
19095584Sanholt		i = show_var(mib, len);
19195584Sanholt		if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
19295584Sanholt			if (!i && !bflag)
19395584Sanholt				putchar('\n');
19495584Sanholt			switch (errno) {
19595584Sanholt			case EOPNOTSUPP:
19695584Sanholt				errx(1, "%s: value is not available",
197145132Sanholt					string);
198145132Sanholt			case ENOTDIR:
19995584Sanholt				errx(1, "%s: specification is incomplete",
200145132Sanholt					string);
20195584Sanholt			case ENOMEM:
202145132Sanholt				errx(1, "%s: type is unknown to this program",
203145132Sanholt					string);
204145132Sanholt			default:
205145132Sanholt				warn("%s", string);
20695584Sanholt				return;
20795584Sanholt			}
208182080Srnoland		}
20995584Sanholt		if (!bflag)
21095584Sanholt			printf(" -> ");
21195584Sanholt		i = nflag;
21295584Sanholt		nflag = 1;
21395584Sanholt		j = show_var(mib, len);
21495584Sanholt		if (!j && !bflag)
21595584Sanholt			putchar('\n');
216145132Sanholt		nflag = i;
21795584Sanholt	}
218145132Sanholt}
21995584Sanholt
22095584Sanholt/* These functions will dump out various interesting structures. */
22195584Sanholt
222182080Srnolandstatic int
22395584SanholtS_clockinfo(int l2, void *p)
22495584Sanholt{
22595584Sanholt	struct clockinfo *ci = (struct clockinfo*)p;
22695584Sanholt	if (l2 != sizeof *ci)
227145132Sanholt		err(1, "S_clockinfo %d != %d", l2, sizeof *ci);
22895584Sanholt	printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
22995584Sanholt		ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz);
230112015Sanholt	return (0);
231112015Sanholt}
232112015Sanholt
233112015Sanholtstatic int
234130331SanholtS_loadavg(int l2, void *p)
235130331Sanholt{
236130331Sanholt	struct loadavg *tv = (struct loadavg*)p;
237130331Sanholt
238130331Sanholt	if (l2 != sizeof *tv)
239130331Sanholt		err(1, "S_loadavg %d != %d", l2, sizeof *tv);
240130331Sanholt
241130331Sanholt	printf("{ %.2f %.2f %.2f }",
242130331Sanholt		(double)tv->ldavg[0]/(double)tv->fscale,
243130331Sanholt		(double)tv->ldavg[1]/(double)tv->fscale,
24495584Sanholt		(double)tv->ldavg[2]/(double)tv->fscale);
245152909Sanholt	return (0);
246152909Sanholt}
247152909Sanholt
248152909Sanholtstatic int
249152909SanholtS_timeval(int l2, void *p)
250152909Sanholt{
251152909Sanholt	struct timeval *tv = (struct timeval*)p;
252152909Sanholt	time_t tv_sec;
253130331Sanholt	char *p1, *p2;
254130331Sanholt
255130331Sanholt	if (l2 != sizeof *tv)
256130331Sanholt		err(1, "S_timeval %d != %d", l2, sizeof *tv);
257130331Sanholt	printf("{ sec = %ld, usec = %ld } ",
258130331Sanholt		tv->tv_sec, tv->tv_usec);
259130331Sanholt	tv_sec = tv->tv_sec;
260130331Sanholt	p1 = strdup(ctime(&tv_sec));
261130331Sanholt	for (p2=p1; *p2 ; p2++)
262130331Sanholt		if (*p2 == '\n')
263152909Sanholt			*p2 = '\0';
264152909Sanholt	fputs(p1, stdout);
265152909Sanholt	return (0);
266130331Sanholt}
26795584Sanholt
268145132Sanholtstatic int
269145132SanholtT_dev_t(int l2, void *p)
270145132Sanholt{
27195584Sanholt	dev_t *d = (dev_t *)p;
27295584Sanholt	if (l2 != sizeof *d)
27395584Sanholt		err(1, "T_dev_T %d != %d", l2, sizeof *d);
274145132Sanholt	printf("{ major = %d, minor = %d }",
275145132Sanholt		major(*d), minor(*d));
276145132Sanholt	return (0);
27795584Sanholt}
27895584Sanholt
279145132Sanholt/*
28095584Sanholt * These functions uses a presently undocumented interface to the kernel
28195584Sanholt * to walk the tree and get the type so it can print the value.
282145132Sanholt * This interface is under work and consideration, and should probably
28395584Sanholt * be killed with a big axe by the first person who can find the time.
28495584Sanholt * (be aware though, that the proper interface isn't as obvious as it
28595584Sanholt * may seem, there are various conflicting requirements.
286145132Sanholt */
28795584Sanholt
288145132Sanholtstatic int
28995584Sanholtname2oid(char *name, int *oidp)
290145132Sanholt{
291145132Sanholt	int oid[2];
29295584Sanholt	int i;
293145132Sanholt	size_t j;
294145132Sanholt
29595584Sanholt	oid[0] = 0;
29695584Sanholt	oid[1] = 3;
29795584Sanholt
29895584Sanholt	j = CTL_MAXNAME * sizeof (int);
29995584Sanholt	i = sysctl(oid, 2, oidp, &j, name, strlen(name));
30095584Sanholt	if (i < 0)
30195584Sanholt		return i;
30295584Sanholt	j /= sizeof (int);
30395584Sanholt	return (j);
30495584Sanholt}
305152909Sanholt
306152909Sanholtstatic int
307152909Sanholtoidfmt(int *oid, int len, char *fmt, u_int *kind)
308182080Srnoland{
309152909Sanholt	int qoid[CTL_MAXNAME+2];
310152909Sanholt	u_char buf[BUFSIZ];
311182080Srnoland	int i;
312152909Sanholt	size_t j;
313152909Sanholt
314152909Sanholt	qoid[0] = 0;
315152909Sanholt	qoid[1] = 4;
316152909Sanholt	memcpy(qoid + 2, oid, len * sizeof(int));
317152909Sanholt
318152909Sanholt	j = sizeof buf;
319152909Sanholt	i = sysctl(qoid, len + 2, buf, &j, 0, 0);
320152909Sanholt	if (i)
321152909Sanholt		err(1, "sysctl fmt %d %d %d", i, j, errno);
322152909Sanholt
323152909Sanholt	if (kind)
324152909Sanholt		*kind = *(u_int *)buf;
325182080Srnoland
326152909Sanholt	if (fmt)
327152909Sanholt		strcpy(fmt, (char *)(buf + sizeof(u_int)));
328152909Sanholt	return 0;
329152909Sanholt}
330152909Sanholt
331152909Sanholt/*
332152909Sanholt * This formats and outputs the value of one variable
333152909Sanholt *
334182080Srnoland * Returns zero if anything was actually output.
335152909Sanholt * Returns one if didn't know what to do with this.
336152909Sanholt * Return minus one if we had errors.
337152909Sanholt */
338152909Sanholt
339152909Sanholtstatic int
340152909Sanholtshow_var(int *oid, int nlen)
341182080Srnoland{
342182080Srnoland	u_char buf[BUFSIZ], *val, *p;
343152909Sanholt	char name[BUFSIZ], descr[BUFSIZ], *fmt;
344152909Sanholt	int qoid[CTL_MAXNAME+2];
345182080Srnoland	int i;
346152909Sanholt	size_t j, len;
347152909Sanholt	u_int kind;
348152909Sanholt	int (*func)(int, void *) = 0;
349152909Sanholt
350152909Sanholt	qoid[0] = 0;
351152909Sanholt	memcpy(qoid + 2, oid, nlen * sizeof(int));
352152909Sanholt
353152909Sanholt	qoid[1] = 1;
354152909Sanholt	j = sizeof name;
355152909Sanholt	i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
356152909Sanholt	if (i || !j)
357152909Sanholt		err(1, "sysctl name %d %d %d", i, j, errno);
358182080Srnoland
359152909Sanholt	if (dflag) {
360152909Sanholt		qoid[1] = 5;
361152909Sanholt		j = sizeof descr;
362152909Sanholt		i = sysctl(qoid, nlen + 2, descr, &j, 0, 0);
363152909Sanholt		if (i || !j)
364152909Sanholt			err(1, "sysctl name %d %d %d", i, j, errno);
365152909Sanholt		if (!nflag)
366152909Sanholt			printf("%s: ", name);
367152909Sanholt		printf("%s", descr[0] ? descr : "[no description]");
368152909Sanholt		return (0);
369152909Sanholt	}
370152909Sanholt
371152909Sanholt	/* find an estimate of how much we need for this var */
37295584Sanholt	j = 0;
37395584Sanholt	i = sysctl(oid, nlen, 0, &j, 0, 0);
37495584Sanholt	j += j; /* we want to be sure :-) */
37595584Sanholt
37695584Sanholt	val = alloca(j);
37795584Sanholt	len = j;
37895584Sanholt	i = sysctl(oid, nlen, val, &len, 0, 0);
37995584Sanholt	if (i || !len)
38095584Sanholt		return (1);
381145132Sanholt
382145132Sanholt	if (bflag) {
383145132Sanholt		fwrite(val, 1, len, stdout);
38495584Sanholt		return (0);
38595584Sanholt	}
38695584Sanholt
387145132Sanholt	qoid[1] = 4;
38895584Sanholt	j = sizeof buf;
38995584Sanholt	i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
390145132Sanholt	if (i || !j)
39195584Sanholt		err(1, "sysctl fmt %d %d %d", i, j, errno);
39295584Sanholt
39395584Sanholt	kind = *(u_int *)buf;
39495584Sanholt
39595584Sanholt	fmt = (char *)(buf + sizeof(u_int));
39695584Sanholt
39795584Sanholt	p = val;
39895584Sanholt	switch (*fmt) {
39995584Sanholt	case 'A':
40095584Sanholt		if (!nflag)
40195584Sanholt			printf("%s: ", name);
40295584Sanholt		printf("%s", p);
40395584Sanholt		return (0);
40495584Sanholt
40595584Sanholt	case 'I':
406145132Sanholt		if (!nflag)
40795584Sanholt			printf("%s: ", name);
40895584Sanholt		val = "";
40995584Sanholt		while (len >= sizeof(int)) {
410112015Sanholt			printf("%s%d", val, *(int *)p);
411145132Sanholt			val = " ";
412112015Sanholt			len -= sizeof (int);
413112015Sanholt			p += sizeof (int);
414112015Sanholt		}
415152909Sanholt		return (0);
416152909Sanholt
417152909Sanholt	case 'L':
418152909Sanholt		if (!nflag)
419152909Sanholt			printf("%s: ", name);
420152909Sanholt		printf("%ld", *(long *)p);
421152909Sanholt		return (0);
422152909Sanholt
423112015Sanholt	case 'P':
424112015Sanholt		if (!nflag)
425145132Sanholt			printf("%s: ", name);
426112015Sanholt		printf("%p", *(void **)p);
427112015Sanholt		return (0);
42895584Sanholt
429	case 'T':
430	case 'S':
431		i = 0;
432		if (!strcmp(fmt, "S,clockinfo"))	func = S_clockinfo;
433		else if (!strcmp(fmt, "S,timeval"))	func = S_timeval;
434		else if (!strcmp(fmt, "S,loadavg"))	func = S_loadavg;
435		else if (!strcmp(fmt, "T,dev_t"))	func = T_dev_t;
436		if (func) {
437			if (!nflag)
438				printf("%s: ", name);
439			return ((*func)(len, p));
440		}
441		/* FALL THROUGH */
442	default:
443		if (!Aflag)
444			return (1);
445		if (!nflag)
446			printf("%s: ", name);
447		printf("Format:%s Length:%d Dump:0x", fmt, len);
448		while (len--) {
449			printf("%02x", *p++);
450			if (Xflag || p < val+16)
451				continue;
452			printf("...");
453			break;
454		}
455		return (0);
456	}
457	return (1);
458}
459
460static int
461sysctl_all (int *oid, int len)
462{
463	int name1[22], name2[22];
464	int i, j;
465	size_t l1, l2;
466
467	name1[0] = 0;
468	name1[1] = 2;
469	l1 = 2;
470	if (len) {
471		memcpy(name1+2, oid, len*sizeof (int));
472		l1 += len;
473	} else {
474		name1[2] = 1;
475		l1++;
476	}
477	while (1) {
478		l2 = sizeof name2;
479		j = sysctl(name1, l1, name2, &l2, 0, 0);
480		if (j < 0) {
481			if (errno == ENOENT)
482				return 0;
483			else
484				err(1, "sysctl(getnext) %d %d", j, l2);
485		}
486
487		l2 /= sizeof (int);
488
489		if (l2 < len)
490			return 0;
491
492		for (i = 0; i < len; i++)
493			if (name2[i] != oid[i])
494				return 0;
495
496		i = show_var(name2, l2);
497		if (!i && !bflag)
498			putchar('\n');
499
500		memcpy(name1+2, name2, l2*sizeof (int));
501		l1 = 2 + l2;
502	}
503}
504