sysctl.c revision 77928
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  "$FreeBSD: head/sbin/sysctl/sysctl.c 77928 2001-06-09 03:56:16Z dd $";
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, bflag, Nflag, nflag, oflag, 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",
74	    "usage: sysctl [-bNnox] variable[=value] ...",
75	    "       sysctl [-bNnox] -a");
76	exit(1);
77}
78
79int
80main(int argc, char **argv)
81{
82	int ch;
83	setbuf(stdout,0);
84	setbuf(stderr,0);
85
86	while ((ch = getopt(argc, argv, "AabNnowxX")) != -1) {
87		switch (ch) {
88		case 'A':
89			/* compatibility */
90			aflag = oflag = 1;
91			break;
92		case 'a':
93			aflag = 1;
94			break;
95		case 'b':
96			bflag = 1;
97			break;
98		case 'N':
99			Nflag = 1;
100			break;
101		case 'n':
102			nflag = 1;
103			break;
104		case 'o':
105			oflag = 1;
106			break;
107		case 'w':
108			/* compatibility */
109			/* ignored */
110			break;
111		case 'X':
112			/* compatibility */
113			aflag = xflag = 1;
114			break;
115		case 'x':
116			xflag = 1;
117			break;
118		default:
119			usage();
120		}
121	}
122	argc -= optind;
123	argv += optind;
124
125	if (Nflag && nflag)
126		usage();
127	if (aflag && argc == 0)
128		exit(sysctl_all(0, 0));
129	if (argc == 0)
130		usage();
131	while (argc-- > 0)
132		parse(*argv++);
133	exit(0);
134}
135
136/*
137 * Parse a name into a MIB entry.
138 * Lookup and print out the MIB entry if it exists.
139 * Set a new value if requested.
140 */
141static void
142parse(char *string)
143{
144	int len, i, j;
145	void *newval = 0;
146	int intval, newsize = 0;
147	quad_t quadval;
148	int mib[CTL_MAXNAME];
149	char *cp, *bufp, buf[BUFSIZ];
150	u_int kind;
151
152	bufp = buf;
153	snprintf(buf, BUFSIZ, "%s", string);
154	if ((cp = strchr(string, '=')) != NULL) {
155		*strchr(buf, '=') = '\0';
156		*cp++ = '\0';
157		while (isspace(*cp))
158			cp++;
159		newval = cp;
160		newsize = strlen(cp);
161	}
162	len = name2oid(bufp, mib);
163
164	if (len < 0)
165		errx(1, "unknown oid '%s'", bufp);
166
167	if (oidfmt(mib, len, 0, &kind))
168		err(1, "couldn't find format of oid '%s'", bufp);
169
170	if (newval == NULL) {
171		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
172			sysctl_all(mib, len);
173		} else {
174			i = show_var(mib, len);
175			if (!i && !bflag)
176				putchar('\n');
177		}
178	} else {
179		if ((kind & CTLTYPE) == CTLTYPE_NODE)
180			errx(1, "oid '%s' isn't a leaf node", bufp);
181
182		if (!(kind&CTLFLAG_WR))
183			errx(1, "oid '%s' is read only", bufp);
184
185		switch (kind & CTLTYPE) {
186			case CTLTYPE_INT:
187				intval = (int) strtol(newval, NULL, 0);
188				newval = &intval;
189				newsize = sizeof(intval);
190				break;
191				break;
192			case CTLTYPE_STRING:
193				break;
194			case CTLTYPE_QUAD:
195				break;
196				sscanf(newval, "%qd", &quadval);
197				newval = &quadval;
198				newsize = sizeof(quadval);
199				break;
200			default:
201				errx(1, "oid '%s' is type %d,"
202					" cannot set that", bufp,
203					kind & CTLTYPE);
204		}
205
206		i = show_var(mib, len);
207		if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
208			if (!i && !bflag)
209				putchar('\n');
210			switch (errno) {
211			case EOPNOTSUPP:
212				errx(1, "%s: value is not available",
213					string);
214			case ENOTDIR:
215				errx(1, "%s: specification is incomplete",
216					string);
217			case ENOMEM:
218				errx(1, "%s: type is unknown to this program",
219					string);
220			default:
221				warn("%s", string);
222				return;
223			}
224		}
225		if (!bflag)
226			printf(" -> ");
227		i = nflag;
228		nflag = 1;
229		j = show_var(mib, len);
230		if (!j && !bflag)
231			putchar('\n');
232		nflag = i;
233	}
234}
235
236/* These functions will dump out various interesting structures. */
237
238static int
239S_clockinfo(int l2, void *p)
240{
241	struct clockinfo *ci = (struct clockinfo*)p;
242	if (l2 != sizeof(*ci))
243		err(1, "S_clockinfo %d != %d", l2, sizeof(*ci));
244	printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
245		ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz);
246	return (0);
247}
248
249static int
250S_loadavg(int l2, void *p)
251{
252	struct loadavg *tv = (struct loadavg*)p;
253
254	if (l2 != sizeof(*tv))
255		err(1, "S_loadavg %d != %d", l2, sizeof(*tv));
256
257	printf("{ %.2f %.2f %.2f }",
258		(double)tv->ldavg[0]/(double)tv->fscale,
259		(double)tv->ldavg[1]/(double)tv->fscale,
260		(double)tv->ldavg[2]/(double)tv->fscale);
261	return (0);
262}
263
264static int
265S_timeval(int l2, void *p)
266{
267	struct timeval *tv = (struct timeval*)p;
268	time_t tv_sec;
269	char *p1, *p2;
270
271	if (l2 != sizeof(*tv))
272		err(1, "S_timeval %d != %d", l2, sizeof(*tv));
273	printf("{ sec = %ld, usec = %ld } ",
274		tv->tv_sec, tv->tv_usec);
275	tv_sec = tv->tv_sec;
276	p1 = strdup(ctime(&tv_sec));
277	for (p2=p1; *p2 ; p2++)
278		if (*p2 == '\n')
279			*p2 = '\0';
280	fputs(p1, stdout);
281	return (0);
282}
283
284static int
285T_dev_t(int l2, void *p)
286{
287	dev_t *d = (dev_t *)p;
288	if (l2 != sizeof(*d))
289		err(1, "T_dev_T %d != %d", l2, sizeof(*d));
290	if ((int)(*d) != -1) {
291		if (minor(*d) > 255 || minor(*d) < 0)
292			printf("{ major = %d, minor = 0x%x }",
293				major(*d), minor(*d));
294		else
295			printf("{ major = %d, minor = %d }",
296				major(*d), minor(*d));
297	}
298	return (0);
299}
300
301/*
302 * These functions uses a presently undocumented interface to the kernel
303 * to walk the tree and get the type so it can print the value.
304 * This interface is under work and consideration, and should probably
305 * be killed with a big axe by the first person who can find the time.
306 * (be aware though, that the proper interface isn't as obvious as it
307 * may seem, there are various conflicting requirements.
308 */
309
310static int
311name2oid(char *name, int *oidp)
312{
313	int oid[2];
314	int i;
315	size_t j;
316
317	oid[0] = 0;
318	oid[1] = 3;
319
320	j = CTL_MAXNAME * sizeof(int);
321	i = sysctl(oid, 2, oidp, &j, name, strlen(name));
322	if (i < 0)
323		return i;
324	j /= sizeof(int);
325	return (j);
326}
327
328static int
329oidfmt(int *oid, int len, char *fmt, u_int *kind)
330{
331	int qoid[CTL_MAXNAME+2];
332	u_char buf[BUFSIZ];
333	int i;
334	size_t j;
335
336	qoid[0] = 0;
337	qoid[1] = 4;
338	memcpy(qoid + 2, oid, len * sizeof(int));
339
340	j = sizeof(buf);
341	i = sysctl(qoid, len + 2, buf, &j, 0, 0);
342	if (i)
343		err(1, "sysctl fmt %d %d %d", i, j, errno);
344
345	if (kind)
346		*kind = *(u_int *)buf;
347
348	if (fmt)
349		strcpy(fmt, (char *)(buf + sizeof(u_int)));
350	return 0;
351}
352
353/*
354 * This formats and outputs the value of one variable
355 *
356 * Returns zero if anything was actually output.
357 * Returns one if didn't know what to do with this.
358 * Return minus one if we had errors.
359 */
360
361static int
362show_var(int *oid, int nlen)
363{
364	u_char buf[BUFSIZ], *val, *p;
365	char name[BUFSIZ], *fmt;
366	int qoid[CTL_MAXNAME+2];
367	int i;
368	size_t j, len;
369	u_int kind;
370	int (*func)(int, void *);
371
372	qoid[0] = 0;
373	memcpy(qoid + 2, oid, nlen * sizeof(int));
374
375	qoid[1] = 1;
376	j = sizeof(name);
377	i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
378	if (i || !j)
379		err(1, "sysctl name %d %d %d", i, j, errno);
380
381	if (Nflag) {
382		printf("%s", name);
383		return (0);
384	}
385
386	/* find an estimate of how much we need for this var */
387	j = 0;
388	i = sysctl(oid, nlen, 0, &j, 0, 0);
389	j += j; /* we want to be sure :-) */
390
391	val = alloca(j);
392	len = j;
393	i = sysctl(oid, nlen, val, &len, 0, 0);
394	if (i || !len)
395		return (1);
396
397	if (bflag) {
398		fwrite(val, 1, len, stdout);
399		return (0);
400	}
401
402	qoid[1] = 4;
403	j = sizeof(buf);
404	i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
405	if (i || !j)
406		err(1, "sysctl fmt %d %d %d", i, j, errno);
407
408	kind = *(u_int *)buf;
409
410	fmt = (char *)(buf + sizeof(u_int));
411
412	p = val;
413	switch (*fmt) {
414	case 'A':
415		if (!nflag)
416			printf("%s: ", name);
417		printf("%s", p);
418		return (0);
419
420	case 'I':
421		if (!nflag)
422			printf("%s: ", name);
423		fmt++;
424		val = "";
425		while (len >= sizeof(int)) {
426			if(*fmt == 'U')
427				printf("%s%u", val, *(unsigned int *)p);
428			else
429				printf("%s%d", val, *(int *)p);
430			val = " ";
431			len -= sizeof(int);
432			p += sizeof(int);
433		}
434		return (0);
435
436	case 'L':
437		if (!nflag)
438			printf("%s: ", name);
439		fmt++;
440		val = "";
441		while (len >= sizeof(long)) {
442			if(*fmt == 'U')
443				printf("%s%lu", val, *(unsigned long *)p);
444			else
445				printf("%s%ld", val, *(long *)p);
446			val = " ";
447			len -= sizeof(long);
448			p += sizeof(long);
449		}
450		return (0);
451
452	case 'P':
453		if (!nflag)
454			printf("%s: ", name);
455		printf("%p", *(void **)p);
456		return (0);
457
458	case 'T':
459	case 'S':
460		i = 0;
461		if (strcmp(fmt, "S,clockinfo") == 0)
462			func = S_clockinfo;
463		else if (strcmp(fmt, "S,timeval") == 0)
464			func = S_timeval;
465		else if (strcmp(fmt, "S,loadavg") == 0)
466			func = S_loadavg;
467		else if (strcmp(fmt, "T,dev_t") == 0)
468			func = T_dev_t;
469		else
470			func = NULL;
471		if (func) {
472			if (!nflag)
473				printf("%s: ", name);
474			return ((*func)(len, p));
475		}
476		/* FALL THROUGH */
477	default:
478		if (!oflag && !xflag)
479			return (1);
480		if (!nflag)
481			printf("%s: ", name);
482		printf("Format:%s Length:%d Dump:0x", fmt, len);
483		while (len-- && (xflag || p < val + 16))
484			printf("%02x", *p++);
485		if (!xflag && len > 16)
486			printf("...");
487		return (0);
488	}
489	return (1);
490}
491
492static int
493sysctl_all (int *oid, int len)
494{
495	int name1[22], name2[22];
496	int i, j;
497	size_t l1, l2;
498
499	name1[0] = 0;
500	name1[1] = 2;
501	l1 = 2;
502	if (len) {
503		memcpy(name1+2, oid, len * sizeof(int));
504		l1 += len;
505	} else {
506		name1[2] = 1;
507		l1++;
508	}
509	for (;;) {
510		l2 = sizeof(name2);
511		j = sysctl(name1, l1, name2, &l2, 0, 0);
512		if (j < 0) {
513			if (errno == ENOENT)
514				return 0;
515			else
516				err(1, "sysctl(getnext) %d %d", j, l2);
517		}
518
519		l2 /= sizeof(int);
520
521		if (l2 < len)
522			return 0;
523
524		for (i = 0; i < len; i++)
525			if (name2[i] != oid[i])
526				return 0;
527
528		i = show_var(name2, l2);
529		if (!i && !bflag)
530			putchar('\n');
531
532		memcpy(name1+2, name2, l2 * sizeof(int));
533		l1 = 2 + l2;
534	}
535}
536