sysctl.c revision 48956
1/*
2 * Copyright (c) 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1993\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)from: sysctl.c	8.1 (Berkeley) 6/6/93";
43#endif
44static const char rcsid[] =
45	"$Id: sysctl.c,v 1.20 1999/01/10 02:10:08 des Exp $";
46#endif /* not lint */
47
48#include <sys/types.h>
49#include <sys/stat.h>
50#include <sys/sysctl.h>
51#include <sys/resource.h>
52
53#include <ctype.h>
54#include <err.h>
55#include <errno.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59#include <unistd.h>
60
61static int	Aflag, aflag, bflag, dflag, nflag, wflag, Xflag;
62
63static int	oidfmt(int *, int, char *, u_int *);
64static void	parse(char *);
65static int	show_var(int *, int);
66static int	sysctl_all (int *oid, int len);
67static int	name2oid(char *, int *);
68
69static void
70usage(void)
71{
72
73	(void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
74		"usage: sysctl [-bdn] variable ...",
75		"       sysctl [-bn] -w variable=value ...",
76		"       sysctl [-bdn] -a",
77		"       sysctl [-bdn] -A",
78		"       sysctl [-bdn] -X");
79	exit(1);
80}
81
82int
83main(int argc, char **argv)
84{
85	int ch;
86	setbuf(stdout,0);
87	setbuf(stderr,0);
88
89	while ((ch = getopt(argc, argv, "AabdnwX")) != -1) {
90		switch (ch) {
91		case 'A': Aflag = 1; break;
92		case 'a': aflag = 1; break;
93		case 'b': bflag = 1; break;
94		case 'd': dflag = 1; break;
95		case 'n': nflag = 1; break;
96		case 'w': wflag = 1; break;
97		case 'X': Xflag = Aflag = 1; break;
98		default: usage();
99		}
100	}
101	argc -= optind;
102	argv += optind;
103
104	if (wflag && (Aflag || aflag || dflag))
105		usage();
106	if (Aflag || aflag)
107		exit (sysctl_all(0, 0));
108	if (argc == 0)
109		usage();
110	while (argc-- > 0)
111		parse(*argv++);
112	exit(0);
113}
114
115/*
116 * Parse a name into a MIB entry.
117 * Lookup and print out the MIB entry if it exists.
118 * Set a new value if requested.
119 */
120static void
121parse(char *string)
122{
123	int len, i, j;
124	void *newval = 0;
125	int intval, newsize = 0;
126	quad_t quadval;
127	int mib[CTL_MAXNAME];
128	char *cp, *bufp, buf[BUFSIZ];
129	u_int kind;
130
131	bufp = buf;
132	snprintf(buf, BUFSIZ, "%s", string);
133	if ((cp = strchr(string, '=')) != NULL) {
134		if (!wflag)
135			errx(2, "must specify -w to set variables");
136		*strchr(buf, '=') = '\0';
137		*cp++ = '\0';
138		while (isspace(*cp))
139			cp++;
140		newval = cp;
141		newsize = strlen(cp);
142	} else {
143		if (wflag)
144			usage();
145	}
146	len = name2oid(bufp, mib);
147
148	if (len < 0)
149		errx(1, "unknown oid '%s'", bufp);
150
151	if (oidfmt(mib, len, 0, &kind))
152		err(1, "couldn't find format of oid '%s'", bufp);
153
154	if (!wflag) {
155		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
156			sysctl_all(mib, len);
157		} else {
158			i = show_var(mib, len);
159			if (!i && !bflag)
160				putchar('\n');
161		}
162	} else {
163		if ((kind & CTLTYPE) == CTLTYPE_NODE)
164			errx(1, "oid '%s' isn't a leaf node", bufp);
165
166		if (!(kind&CTLFLAG_WR))
167			errx(1, "oid '%s' is read only", bufp);
168
169		switch (kind & CTLTYPE) {
170			case CTLTYPE_INT:
171				intval = atoi(newval);
172				newval = &intval;
173				newsize = sizeof intval;
174				break;
175				break;
176			case CTLTYPE_STRING:
177				break;
178			case CTLTYPE_QUAD:
179				break;
180				sscanf(newval, "%qd", &quadval);
181				newval = &quadval;
182				newsize = sizeof quadval;
183				break;
184			default:
185				errx(1, "oid '%s' is type %d,"
186					" cannot set that", bufp,
187					kind & CTLTYPE);
188		}
189
190		i = show_var(mib, len);
191		if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
192			if (!i && !bflag)
193				putchar('\n');
194			switch (errno) {
195			case EOPNOTSUPP:
196				errx(1, "%s: value is not available",
197					string);
198			case ENOTDIR:
199				errx(1, "%s: specification is incomplete",
200					string);
201			case ENOMEM:
202				errx(1, "%s: type is unknown to this program",
203					string);
204			default:
205				warn("%s", string);
206				return;
207			}
208		}
209		if (!bflag)
210			printf(" -> ");
211		i = nflag;
212		nflag = 1;
213		j = show_var(mib, len);
214		if (!j && !bflag)
215			putchar('\n');
216		nflag = i;
217	}
218}
219
220/* These functions will dump out various interesting structures. */
221
222static int
223S_clockinfo(int l2, void *p)
224{
225	struct clockinfo *ci = (struct clockinfo*)p;
226	if (l2 != sizeof *ci)
227		err(1, "S_clockinfo %d != %d", l2, sizeof *ci);
228	printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
229		ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz);
230	return (0);
231}
232
233static int
234S_loadavg(int l2, void *p)
235{
236	struct loadavg *tv = (struct loadavg*)p;
237
238	if (l2 != sizeof *tv)
239		err(1, "S_loadavg %d != %d", l2, sizeof *tv);
240
241	printf("{ %.2f %.2f %.2f }",
242		(double)tv->ldavg[0]/(double)tv->fscale,
243		(double)tv->ldavg[1]/(double)tv->fscale,
244		(double)tv->ldavg[2]/(double)tv->fscale);
245	return (0);
246}
247
248static int
249S_timeval(int l2, void *p)
250{
251	struct timeval *tv = (struct timeval*)p;
252	time_t tv_sec;
253	char *p1, *p2;
254
255	if (l2 != sizeof *tv)
256		err(1, "S_timeval %d != %d", l2, sizeof *tv);
257	printf("{ sec = %ld, usec = %ld } ",
258		tv->tv_sec, tv->tv_usec);
259	tv_sec = tv->tv_sec;
260	p1 = strdup(ctime(&tv_sec));
261	for (p2=p1; *p2 ; p2++)
262		if (*p2 == '\n')
263			*p2 = '\0';
264	fputs(p1, stdout);
265	return (0);
266}
267
268static int
269T_dev_t(int l2, void *p)
270{
271	dev_t *d = (dev_t *)p;
272	if (l2 != sizeof *d)
273		err(1, "T_dev_T %d != %d", l2, sizeof *d);
274	printf("{ major = %d, minor = %d }",
275		major(*d), minor(*d));
276	return (0);
277}
278
279/*
280 * These functions uses a presently undocumented interface to the kernel
281 * to walk the tree and get the type so it can print the value.
282 * This interface is under work and consideration, and should probably
283 * be killed with a big axe by the first person who can find the time.
284 * (be aware though, that the proper interface isn't as obvious as it
285 * may seem, there are various conflicting requirements.
286 */
287
288static int
289name2oid(char *name, int *oidp)
290{
291	int oid[2];
292	int i;
293	size_t j;
294
295	oid[0] = 0;
296	oid[1] = 3;
297
298	j = CTL_MAXNAME * sizeof (int);
299	i = sysctl(oid, 2, oidp, &j, name, strlen(name));
300	if (i < 0)
301		return i;
302	j /= sizeof (int);
303	return (j);
304}
305
306static int
307oidfmt(int *oid, int len, char *fmt, u_int *kind)
308{
309	int qoid[CTL_MAXNAME+2];
310	u_char buf[BUFSIZ];
311	int i;
312	size_t j;
313
314	qoid[0] = 0;
315	qoid[1] = 4;
316	memcpy(qoid + 2, oid, len * sizeof(int));
317
318	j = sizeof buf;
319	i = sysctl(qoid, len + 2, buf, &j, 0, 0);
320	if (i)
321		err(1, "sysctl fmt %d %d %d", i, j, errno);
322
323	if (kind)
324		*kind = *(u_int *)buf;
325
326	if (fmt)
327		strcpy(fmt, (char *)(buf + sizeof(u_int)));
328	return 0;
329}
330
331/*
332 * This formats and outputs the value of one variable
333 *
334 * Returns zero if anything was actually output.
335 * Returns one if didn't know what to do with this.
336 * Return minus one if we had errors.
337 */
338
339static int
340show_var(int *oid, int nlen)
341{
342	u_char buf[BUFSIZ], *val, *p;
343	char name[BUFSIZ], descr[BUFSIZ], *fmt;
344	int qoid[CTL_MAXNAME+2];
345	int i;
346	size_t j, len;
347	u_int kind;
348	int (*func)(int, void *) = 0;
349
350	qoid[0] = 0;
351	memcpy(qoid + 2, oid, nlen * sizeof(int));
352
353	qoid[1] = 1;
354	j = sizeof name;
355	i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
356	if (i || !j)
357		err(1, "sysctl name %d %d %d", i, j, errno);
358
359	if (dflag) {
360		qoid[1] = 5;
361		j = sizeof descr;
362		i = sysctl(qoid, nlen + 2, descr, &j, 0, 0);
363		if (i || !j)
364			err(1, "sysctl name %d %d %d", i, j, errno);
365		if (!nflag)
366			printf("%s: ", name);
367		printf("%s", descr[0] ? descr : "[no description]");
368		return (0);
369	}
370
371	/* find an estimate of how much we need for this var */
372	j = 0;
373	i = sysctl(oid, nlen, 0, &j, 0, 0);
374	j += j; /* we want to be sure :-) */
375
376	val = alloca(j);
377	len = j;
378	i = sysctl(oid, nlen, val, &len, 0, 0);
379	if (i || !len)
380		return (1);
381
382	if (bflag) {
383		fwrite(val, 1, len, stdout);
384		return (0);
385	}
386
387	qoid[1] = 4;
388	j = sizeof buf;
389	i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
390	if (i || !j)
391		err(1, "sysctl fmt %d %d %d", i, j, errno);
392
393	kind = *(u_int *)buf;
394
395	fmt = (char *)(buf + sizeof(u_int));
396
397	p = val;
398	switch (*fmt) {
399	case 'A':
400		if (!nflag)
401			printf("%s: ", name);
402		printf("%s", p);
403		return (0);
404
405	case 'I':
406		if (!nflag)
407			printf("%s: ", name);
408		val = "";
409		while (len >= sizeof(int)) {
410			printf("%s%d", val, *(int *)p);
411			val = " ";
412			len -= sizeof (int);
413			p += sizeof (int);
414		}
415		return (0);
416
417	case 'L':
418		if (!nflag)
419			printf("%s: ", name);
420		printf("%ld", *(long *)p);
421		return (0);
422
423	case 'P':
424		if (!nflag)
425			printf("%s: ", name);
426		printf("%p", *(void **)p);
427		return (0);
428
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