sysctl.c revision 212726
1163953Srrs/*
2169382Srrs * Copyright (c) 1993
3235828Stuexen *	The Regents of the University of California.  All rights reserved.
4235828Stuexen *
5163953Srrs * Redistribution and use in source and binary forms, with or without
6163953Srrs * modification, are permitted provided that the following conditions
7163953Srrs * are met:
8163953Srrs * 1. Redistributions of source code must retain the above copyright
9163953Srrs *    notice, this list of conditions and the following disclaimer.
10228653Stuexen * 2. Redistributions in binary form must reproduce the above copyright
11163953Srrs *    notice, this list of conditions and the following disclaimer in the
12163953Srrs *    documentation and/or other materials provided with the distribution.
13163953Srrs * 4. Neither the name of the University nor the names of its contributors
14228653Stuexen *    may be used to endorse or promote products derived from this software
15163953Srrs *    without specific prior written permission.
16163953Srrs *
17163953Srrs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18163953Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19163953Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20163953Srrs * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21163953Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22163953Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23163953Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24163953Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25163953Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26163953Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27163953Srrs * SUCH DAMAGE.
28163953Srrs */
29163953Srrs
30163953Srrs#ifndef lint
31163953Srrsstatic const char copyright[] =
32163953Srrs"@(#) Copyright (c) 1993\n\
33163953Srrs	The Regents of the University of California.  All rights reserved.\n";
34163957Srrs#endif /* not lint */
35235828Stuexen
36163953Srrs#ifndef lint
37163953Srrs#if 0
38167598Srrsstatic char sccsid[] = "@(#)from: sysctl.c	8.1 (Berkeley) 6/6/93";
39163953Srrs#endif
40163953Srrsstatic const char rcsid[] =
41163953Srrs  "$FreeBSD: head/sbin/sysctl/sysctl.c 212726 2010-09-16 10:53:01Z zec $";
42163953Srrs#endif /* not lint */
43163953Srrs
44172091Srrs#include <sys/param.h>
45163953Srrs#include <sys/time.h>
46163953Srrs#include <sys/resource.h>
47163953Srrs#include <sys/stat.h>
48163953Srrs#include <sys/sysctl.h>
49163953Srrs#include <sys/vmmeter.h>
50163953Srrs
51163953Srrs#include <ctype.h>
52163953Srrs#include <err.h>
53163953Srrs#include <errno.h>
54237715Stuexen#include <inttypes.h>
55163953Srrs#include <locale.h>
56163953Srrs#include <stdio.h>
57163953Srrs#include <stdlib.h>
58163953Srrs#include <string.h>
59171477Srrs#include <unistd.h>
60171477Srrs
61171477Srrsstatic int	aflag, bflag, dflag, eflag, hflag, iflag;
62171477Srrsstatic int	Nflag, nflag, oflag, qflag, xflag, warncount;
63171477Srrs
64171477Srrsstatic int	oidfmt(int *, int, char *, u_int *);
65163953Srrsstatic void	parse(char *);
66163953Srrsstatic int	show_var(int *, int);
67163953Srrsstatic int	sysctl_all(int *oid, int len);
68163953Srrsstatic int	name2oid(char *, int *);
69163953Srrs
70163953Srrsstatic void	set_T_dev_t(char *, void **, size_t *);
71171477Srrsstatic int	set_IK(const char *, int *);
72171477Srrs
73171477Srrsstatic void
74171477Srrsusage(void)
75163953Srrs{
76163953Srrs
77163953Srrs	(void)fprintf(stderr, "%s\n%s\n",
78163953Srrs	    "usage: sysctl [-bdehiNnoqx] name[=value] ...",
79163953Srrs	    "       sysctl [-bdehNnoqx] -a");
80163953Srrs	exit(1);
81163953Srrs}
82163953Srrs
83243882Sglebiusint
84163953Srrsmain(int argc, char **argv)
85169420Srrs{
86169420Srrs	int ch;
87228907Stuexen
88163953Srrs	setlocale(LC_NUMERIC, "");
89163953Srrs	setbuf(stdout,0);
90163953Srrs	setbuf(stderr,0);
91163953Srrs
92163953Srrs	while ((ch = getopt(argc, argv, "AabdehiNnoqwxX")) != -1) {
93165647Srrs		switch (ch) {
94163953Srrs		case 'A':
95163953Srrs			/* compatibility */
96228907Stuexen			aflag = oflag = 1;
97163953Srrs			break;
98163953Srrs		case 'a':
99163953Srrs			aflag = 1;
100163953Srrs			break;
101163953Srrs		case 'b':
102163953Srrs			bflag = 1;
103163953Srrs			break;
104163953Srrs		case 'd':
105163953Srrs			dflag = 1;
106163953Srrs			break;
107163953Srrs		case 'e':
108163953Srrs			eflag = 1;
109163953Srrs			break;
110163953Srrs		case 'h':
111243882Sglebius			hflag = 1;
112163953Srrs			break;
113169420Srrs		case 'i':
114169420Srrs			iflag = 1;
115228907Stuexen			break;
116163953Srrs		case 'N':
117163953Srrs			Nflag = 1;
118163953Srrs			break;
119163953Srrs		case 'n':
120163953Srrs			nflag = 1;
121163953Srrs			break;
122163953Srrs		case 'o':
123163953Srrs			oflag = 1;
124163953Srrs			break;
125163953Srrs		case 'q':
126163953Srrs			qflag = 1;
127163953Srrs			break;
128169420Srrs		case 'w':
129169420Srrs			/* compatibility */
130169420Srrs			/* ignored */
131163953Srrs			break;
132228907Stuexen		case 'X':
133163953Srrs			/* compatibility */
134163953Srrs			aflag = xflag = 1;
135163953Srrs			break;
136163953Srrs		case 'x':
137163953Srrs			xflag = 1;
138165647Srrs			break;
139163953Srrs		default:
140163953Srrs			usage();
141163953Srrs		}
142228907Stuexen	}
143163953Srrs	argc -= optind;
144163953Srrs	argv += optind;
145163953Srrs
146237715Stuexen	if (Nflag && nflag)
147224641Stuexen		usage();
148163953Srrs	if (aflag && argc == 0)
149224641Stuexen		exit(sysctl_all(0, 0));
150163953Srrs	if (argc == 0)
151237715Stuexen		usage();
152221249Stuexen
153258454Stuexen	warncount = 0;
154258454Stuexen	while (argc-- > 0)
155258454Stuexen		parse(*argv++);
156258454Stuexen	exit(warncount);
157258454Stuexen}
158258454Stuexen
159163953Srrs/*
160163953Srrs * Parse a name into a MIB entry.
161225571Stuexen * Lookup and print out the MIB entry if it exists.
162163953Srrs * Set a new value if requested.
163221249Stuexen */
164221249Stuexenstatic void
165221249Stuexenparse(char *string)
166221249Stuexen{
167221249Stuexen	int len, i, j;
168163953Srrs	void *newval = 0;
169163953Srrs	int intval;
170163953Srrs	unsigned int uintval;
171163953Srrs	long longval;
172221249Stuexen	unsigned long ulongval;
173163953Srrs	size_t newsize = 0;
174163953Srrs	quad_t quadval;
175221249Stuexen	int mib[CTL_MAXNAME];
176221249Stuexen	char *cp, *bufp, buf[BUFSIZ], *endptr, fmt[BUFSIZ];
177258454Stuexen	u_int kind;
178221249Stuexen
179258454Stuexen	bufp = buf;
180163953Srrs	if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ)
181163953Srrs		errx(1, "oid too long: '%s'", string);
182221249Stuexen	if ((cp = strchr(string, '=')) != NULL) {
183163953Srrs		*strchr(buf, '=') = '\0';
184163953Srrs		*cp++ = '\0';
185163953Srrs		while (isspace(*cp))
186228907Stuexen			cp++;
187163953Srrs		newval = cp;
188221249Stuexen		newsize = strlen(cp);
189163953Srrs	}
190163953Srrs	len = name2oid(bufp, mib);
191163953Srrs
192163953Srrs	if (len < 0) {
193163953Srrs		if (iflag)
194163953Srrs			return;
195225571Stuexen		if (qflag)
196225571Stuexen			exit(1);
197225584Stuexen		else
198225571Stuexen			errx(1, "unknown oid '%s'", bufp);
199163953Srrs	}
200163953Srrs
201169420Srrs	if (oidfmt(mib, len, fmt, &kind))
202169420Srrs		err(1, "couldn't find format of oid '%s'", bufp);
203163953Srrs
204221249Stuexen	if (newval == NULL) {
205221249Stuexen		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
206163953Srrs			if (dflag) {
207163953Srrs				i = show_var(mib, len);
208163953Srrs				if (!i && !bflag)
209228907Stuexen					putchar('\n');
210163953Srrs			}
211221249Stuexen			sysctl_all(mib, len);
212163953Srrs		} else {
213163953Srrs			i = show_var(mib, len);
214163953Srrs			if (!i && !bflag)
215163953Srrs				putchar('\n');
216163953Srrs		}
217163953Srrs	} else {
218163953Srrs		if ((kind & CTLTYPE) == CTLTYPE_NODE)
219225571Stuexen			errx(1, "oid '%s' isn't a leaf node", bufp);
220225571Stuexen
221225571Stuexen		if (!(kind & CTLFLAG_WR)) {
222163953Srrs			if (kind & CTLFLAG_TUN) {
223163953Srrs				warnx("oid '%s' is a read only tunable", bufp);
224169420Srrs				errx(1, "Tunable values are set in /boot/loader.conf");
225169420Srrs			} else {
226221249Stuexen				errx(1, "oid '%s' is read only", bufp);
227169420Srrs			}
228163953Srrs		}
229163953Srrs
230225571Stuexen		if ((kind & CTLTYPE) == CTLTYPE_INT ||
231163953Srrs		    (kind & CTLTYPE) == CTLTYPE_UINT ||
232228907Stuexen		    (kind & CTLTYPE) == CTLTYPE_LONG ||
233163953Srrs		    (kind & CTLTYPE) == CTLTYPE_ULONG ||
234163953Srrs		    (kind & CTLTYPE) == CTLTYPE_QUAD) {
235163953Srrs			if (strlen(newval) == 0)
236179783Srrs				errx(1, "empty numeric value");
237237715Stuexen		}
238169420Srrs
239169420Srrs		switch (kind & CTLTYPE) {
240237715Stuexen			case CTLTYPE_INT:
241163953Srrs				if (strcmp(fmt, "IK") == 0) {
242163953Srrs					if (!set_IK(newval, &intval))
243225571Stuexen						errx(1, "invalid value '%s'",
244225571Stuexen						    (char *)newval);
245225571Stuexen 				} else {
246225571Stuexen					intval = (int)strtol(newval, &endptr,
247225571Stuexen					    0);
248165220Srrs					if (endptr == newval || *endptr != '\0')
249169420Srrs						errx(1, "invalid integer '%s'",
250169420Srrs						    (char *)newval);
251163953Srrs				}
252163953Srrs				newval = &intval;
253163953Srrs				newsize = sizeof(intval);
254163953Srrs				break;
255163953Srrs			case CTLTYPE_UINT:
256172090Srrs				uintval = (int) strtoul(newval, &endptr, 0);
257163953Srrs				if (endptr == newval || *endptr != '\0')
258163953Srrs					errx(1, "invalid unsigned integer '%s'",
259163953Srrs					    (char *)newval);
260163953Srrs				newval = &uintval;
261224641Stuexen				newsize = sizeof(uintval);
262169655Srrs				break;
263224641Stuexen			case CTLTYPE_LONG:
264224641Stuexen				longval = strtol(newval, &endptr, 0);
265224641Stuexen				if (endptr == newval || *endptr != '\0')
266224641Stuexen					errx(1, "invalid long integer '%s'",
267163953Srrs					    (char *)newval);
268228907Stuexen				newval = &longval;
269163953Srrs				newsize = sizeof(longval);
270163953Srrs				break;
271163953Srrs			case CTLTYPE_ULONG:
272171572Srrs				ulongval = strtoul(newval, &endptr, 0);
273163953Srrs				if (endptr == newval || *endptr != '\0')
274163953Srrs					errx(1, "invalid unsigned long integer"
275163953Srrs					    " '%s'", (char *)newval);
276163953Srrs				newval = &ulongval;
277163953Srrs				newsize = sizeof(ulongval);
278163953Srrs				break;
279163953Srrs			case CTLTYPE_STRING:
280228907Stuexen				break;
281163953Srrs			case CTLTYPE_QUAD:
282163953Srrs				quadval = strtoq(newval, &endptr, 0);
283163953Srrs				if (endptr == newval || *endptr != '\0')
284163953Srrs					errx(1, "invalid quad integer"
285163953Srrs					    " '%s'", (char *)newval);
286163953Srrs				newval = &quadval;
287169420Srrs				newsize = sizeof(quadval);
288169420Srrs				break;
289169420Srrs			case CTLTYPE_OPAQUE:
290169420Srrs				if (strcmp(fmt, "T,dev_t") == 0) {
291163953Srrs					set_T_dev_t (newval, &newval, &newsize);
292163953Srrs					break;
293172090Srrs				}
294163953Srrs				/* FALLTHROUGH */
295163953Srrs			default:
296228907Stuexen				errx(1, "oid '%s' is type %d,"
297163953Srrs					" cannot set that", bufp,
298163953Srrs					kind & CTLTYPE);
299163953Srrs		}
300237715Stuexen
301237715Stuexen		i = show_var(mib, len);
302163953Srrs		if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
303163953Srrs			if (!i && !bflag)
304163953Srrs				putchar('\n');
305237715Stuexen			switch (errno) {
306221249Stuexen			case EOPNOTSUPP:
307258454Stuexen				errx(1, "%s: value is not available",
308258454Stuexen					string);
309258454Stuexen			case ENOTDIR:
310258454Stuexen				errx(1, "%s: specification is incomplete",
311258454Stuexen					string);
312258454Stuexen			case ENOMEM:
313163953Srrs				errx(1, "%s: type is unknown to this program",
314163953Srrs					string);
315163953Srrs			default:
316163953Srrs				warn("%s", string);
317221249Stuexen				warncount++;
318221249Stuexen				return;
319221249Stuexen			}
320221249Stuexen		}
321221249Stuexen		if (!bflag)
322163953Srrs			printf(" -> ");
323163953Srrs		i = nflag;
324163953Srrs		nflag = 1;
325163953Srrs		j = show_var(mib, len);
326221249Stuexen		if (!j && !bflag)
327163953Srrs			putchar('\n');
328163953Srrs		nflag = i;
329221249Stuexen	}
330221249Stuexen}
331258454Stuexen
332221249Stuexen/* These functions will dump out various interesting structures. */
333258454Stuexen
334163953Srrsstatic int
335163953SrrsS_clockinfo(int l2, void *p)
336221249Stuexen{
337163953Srrs	struct clockinfo *ci = (struct clockinfo*)p;
338163953Srrs
339163953Srrs	if (l2 != sizeof(*ci)) {
340228907Stuexen		warnx("S_clockinfo %d != %zu", l2, sizeof(*ci));
341163953Srrs		return (1);
342221249Stuexen	}
343163953Srrs	printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
344163953Srrs		"{ hz = %d, tick = %d, profhz = %d, stathz = %d }",
345163953Srrs		ci->hz, ci->tick, ci->profhz, ci->stathz);
346163953Srrs	return (0);
347163953Srrs}
348163953Srrs
349163953Srrsstatic int
350163953SrrsS_loadavg(int l2, void *p)
351169420Srrs{
352169420Srrs	struct loadavg *tv = (struct loadavg*)p;
353169420Srrs
354163953Srrs	if (l2 != sizeof(*tv)) {
355221249Stuexen		warnx("S_loadavg %d != %zu", l2, sizeof(*tv));
356221249Stuexen		return (1);
357163953Srrs	}
358163953Srrs	printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
359163953Srrs		(double)tv->ldavg[0]/(double)tv->fscale,
360228907Stuexen		(double)tv->ldavg[1]/(double)tv->fscale,
361163953Srrs		(double)tv->ldavg[2]/(double)tv->fscale);
362221249Stuexen	return (0);
363163953Srrs}
364163953Srrs
365163953Srrsstatic int
366163953SrrsS_timeval(int l2, void *p)
367163953Srrs{
368163953Srrs	struct timeval *tv = (struct timeval*)p;
369163953Srrs	time_t tv_sec;
370163953Srrs	char *p1, *p2;
371163953Srrs
372169420Srrs	if (l2 != sizeof(*tv)) {
373169420Srrs		warnx("S_timeval %d != %zu", l2, sizeof(*tv));
374169420Srrs		return (1);
375221249Stuexen	}
376169420Srrs	printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
377163953Srrs		"{ sec = %jd, usec = %ld } ",
378163953Srrs		(intmax_t)tv->tv_sec, tv->tv_usec);
379163953Srrs	tv_sec = tv->tv_sec;
380163953Srrs	p1 = strdup(ctime(&tv_sec));
381228907Stuexen	for (p2=p1; *p2 ; p2++)
382163953Srrs		if (*p2 == '\n')
383163953Srrs			*p2 = '\0';
384163953Srrs	fputs(p1, stdout);
385237715Stuexen	free(p1);
386163953Srrs	return (0);
387169420Srrs}
388163953Srrs
389163953Srrsstatic int
390163953SrrsS_vmtotal(int l2, void *p)
391228907Stuexen{
392163953Srrs	struct vmtotal *v = (struct vmtotal *)p;
393163953Srrs	int pageKilo = getpagesize() / 1024;
394179783Srrs
395237715Stuexen	if (l2 != sizeof(*v)) {
396163953Srrs		warnx("S_vmtotal %d != %zu", l2, sizeof(*v));
397163953Srrs		return (1);
398163953Srrs	}
399169420Srrs
400163953Srrs	printf(
401163953Srrs	    "\nSystem wide totals computed every five seconds:"
402163953Srrs	    " (values in kilobytes)\n");
403163953Srrs	printf("===============================================\n");
404163953Srrs	printf(
405163953Srrs	    "Processes:\t\t(RUNQ: %hd Disk Wait: %hd Page Wait: "
406163953Srrs	    "%hd Sleep: %hd)\n",
407163953Srrs	    v->t_rq, v->t_dw, v->t_pw, v->t_sl);
408163953Srrs	printf(
409228907Stuexen	    "Virtual Memory:\t\t(Total: %dK Active: %dK)\n",
410163953Srrs	    v->t_vm * pageKilo, v->t_avm * pageKilo);
411163953Srrs	printf("Real Memory:\t\t(Total: %dK Active: %dK)\n",
412163953Srrs	    v->t_rm * pageKilo, v->t_arm * pageKilo);
413163953Srrs	printf("Shared Virtual Memory:\t(Total: %dK Active: %dK)\n",
414163953Srrs	    v->t_vmshr * pageKilo, v->t_avmshr * pageKilo);
415163953Srrs	printf("Shared Real Memory:\t(Total: %dK Active: %dK)\n",
416163953Srrs	    v->t_rmshr * pageKilo, v->t_armshr * pageKilo);
417163953Srrs	printf("Free Memory Pages:\t%dK\n", v->t_free * pageKilo);
418163953Srrs
419163953Srrs	return (0);
420169420Srrs}
421163953Srrs
422163953Srrsstatic int
423163953SrrsT_dev_t(int l2, void *p)
424163953Srrs{
425163953Srrs	dev_t *d = (dev_t *)p;
426163953Srrs
427163953Srrs	if (l2 != sizeof(*d)) {
428163953Srrs		warnx("T_dev_T %d != %zu", l2, sizeof(*d));
429172090Srrs		return (1);
430163953Srrs	}
431228907Stuexen	printf("%s", devname(*d, S_IFCHR));
432163953Srrs	return (0);
433163953Srrs}
434163953Srrs
435237715Stuexenstatic void
436171572Srrsset_T_dev_t(char *path, void **val, size_t *size)
437171572Srrs{
438163953Srrs	static struct stat statb;
439163953Srrs
440237715Stuexen	if (strcmp(path, "none") && strcmp(path, "off")) {
441221249Stuexen		int rc = stat (path, &statb);
442258454Stuexen		if (rc) {
443258454Stuexen			err(1, "cannot stat %s", path);
444258454Stuexen		}
445258454Stuexen
446258454Stuexen		if (!S_ISCHR(statb.st_mode)) {
447258454Stuexen			errx(1, "must specify a device special file.");
448163953Srrs		}
449163953Srrs	} else {
450163953Srrs		statb.st_rdev = NODEV;
451221249Stuexen	}
452221249Stuexen	*val = (void *) &statb.st_rdev;
453221249Stuexen	*size = sizeof(statb.st_rdev);
454221249Stuexen}
455221249Stuexen
456163953Srrsstatic int
457163953Srrsset_IK(const char *str, int *val)
458163953Srrs{
459163953Srrs	float temp;
460221249Stuexen	int len, kelv;
461163953Srrs	const char *p;
462163953Srrs	char *endptr;
463221249Stuexen
464221249Stuexen	if ((len = strlen(str)) == 0)
465258454Stuexen		return (0);
466221249Stuexen	p = &str[len - 1];
467258454Stuexen	if (*p == 'C' || *p == 'F') {
468163953Srrs		temp = strtof(str, &endptr);
469163953Srrs		if (endptr == str || endptr != p)
470221249Stuexen			return (0);
471163953Srrs		if (*p == 'F')
472163953Srrs			temp = (temp - 32) * 5 / 9;
473163953Srrs		kelv = temp * 10 + 2732;
474228907Stuexen	} else {
475163953Srrs		kelv = (int)strtol(str, &endptr, 10);
476221249Stuexen		if (endptr == str || *endptr != '\0')
477163953Srrs			return (0);
478163953Srrs	}
479163953Srrs	*val = kelv;
480163953Srrs	return (1);
481163953Srrs}
482163953Srrs
483163953Srrs/*
484169420Srrs * These functions uses a presently undocumented interface to the kernel
485169420Srrs * to walk the tree and get the type so it can print the value.
486163953Srrs * This interface is under work and consideration, and should probably
487221249Stuexen * be killed with a big axe by the first person who can find the time.
488221249Stuexen * (be aware though, that the proper interface isn't as obvious as it
489163953Srrs * may seem, there are various conflicting requirements.
490163953Srrs */
491163953Srrs
492228907Stuexenstatic int
493163953Srrsname2oid(char *name, int *oidp)
494221249Stuexen{
495163953Srrs	int oid[2];
496163953Srrs	int i;
497163953Srrs	size_t j;
498163953Srrs
499163953Srrs	oid[0] = 0;
500163953Srrs	oid[1] = 3;
501163953Srrs
502163953Srrs	j = CTL_MAXNAME * sizeof(int);
503169420Srrs	i = sysctl(oid, 2, oidp, &j, name, strlen(name));
504169420Srrs	if (i < 0)
505221249Stuexen		return (i);
506169420Srrs	j /= sizeof(int);
507163953Srrs	return (j);
508163953Srrs}
509163953Srrs
510163953Srrsstatic int
511228907Stuexenoidfmt(int *oid, int len, char *fmt, u_int *kind)
512163953Srrs{
513163953Srrs	int qoid[CTL_MAXNAME+2];
514163953Srrs	u_char buf[BUFSIZ];
515179783Srrs	int i;
516237715Stuexen	size_t j;
517169420Srrs
518169420Srrs	qoid[0] = 0;
519237715Stuexen	qoid[1] = 4;
520163953Srrs	memcpy(qoid + 2, oid, len * sizeof(int));
521163953Srrs
522163953Srrs	j = sizeof(buf);
523169420Srrs	i = sysctl(qoid, len + 2, buf, &j, 0, 0);
524169420Srrs	if (i)
525163953Srrs		err(1, "sysctl fmt %d %zu %d", i, j, errno);
526172090Srrs
527224641Stuexen	if (kind)
528224641Stuexen		*kind = *(u_int *)buf;
529224641Stuexen
530224641Stuexen	if (fmt)
531224641Stuexen		strcpy(fmt, (char *)(buf + sizeof(u_int)));
532224641Stuexen	return (0);
533163953Srrs}
534163953Srrs
535163953Srrs/*
536172091Srrs * This formats and outputs the value of one variable
537172091Srrs *
538172091Srrs * Returns zero if anything was actually output.
539172091Srrs * Returns one if didn't know what to do with this.
540172091Srrs * Return minus one if we had errors.
541206137Stuexen */
542206137Stuexen
543206137Stuexenstatic int
544172091Srrsshow_var(int *oid, int nlen)
545172091Srrs{
546172091Srrs	u_char buf[BUFSIZ], *val, *oval, *p;
547172091Srrs	char name[BUFSIZ], *fmt;
548172091Srrs	const char *sep, *sep1;
549172091Srrs	int qoid[CTL_MAXNAME+2];
550172091Srrs	uintmax_t umv;
551172091Srrs	intmax_t mv;
552172091Srrs	int i, hexlen;
553172091Srrs	size_t intlen;
554172091Srrs	size_t j, len;
555172091Srrs	u_int kind;
556172091Srrs	int (*func)(int, void *);
557172091Srrs
558172091Srrs	/* Silence GCC. */
559172091Srrs	umv = mv = intlen = 0;
560172091Srrs
561172091Srrs	bzero(buf, BUFSIZ);
562172091Srrs	bzero(name, BUFSIZ);
563172091Srrs	qoid[0] = 0;
564172091Srrs	memcpy(qoid + 2, oid, nlen * sizeof(int));
565172091Srrs
566212712Stuexen	qoid[1] = 1;
567212712Stuexen	j = sizeof(name);
568172091Srrs	i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
569172091Srrs	if (i || !j)
570172091Srrs		err(1, "sysctl name %d %zu %d", i, j, errno);
571172091Srrs
572163953Srrs	if (Nflag) {
573163953Srrs		printf("%s", name);
574169420Srrs		return (0);
575169420Srrs	}
576163953Srrs
577163953Srrs	if (eflag)
578163953Srrs		sep = "=";
579163953Srrs	else
580163953Srrs		sep = ": ";
581163953Srrs
582228907Stuexen	if (dflag) {	/* just print description */
583163953Srrs		qoid[1] = 5;
584163953Srrs		j = sizeof(buf);
585163953Srrs		i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
586163953Srrs		if (!nflag)
587163953Srrs			printf("%s%s", name, sep);
588163953Srrs		printf("%s", buf);
589163953Srrs		return (0);
590163953Srrs	}
591237715Stuexen	/* find an estimate of how much we need for this var */
592171990Srrs	j = 0;
593171990Srrs	i = sysctl(oid, nlen, 0, &j, 0, 0);
594163953Srrs	j += j; /* we want to be sure :-) */
595163953Srrs
596163953Srrs	val = oval = malloc(j + 1);
597171990Srrs	if (val == NULL) {
598163953Srrs		warnx("malloc failed");
599163953Srrs		return (1);
600163953Srrs	}
601224641Stuexen	len = j;
602163953Srrs	i = sysctl(oid, nlen, val, &len, 0, 0);
603163953Srrs	if (i || !len) {
604163953Srrs		free(oval);
605166675Srrs		return (1);
606171990Srrs	}
607163953Srrs
608163953Srrs	if (bflag) {
609163953Srrs		fwrite(val, 1, len, stdout);
610169420Srrs		free(oval);
611169420Srrs		return (0);
612169420Srrs	}
613163953Srrs	val[len] = '\0';
614163953Srrs	fmt = buf;
615163953Srrs	oidfmt(oid, nlen, fmt, &kind);
616163953Srrs	p = val;
617163953Srrs	switch (*fmt) {
618216825Stuexen	case 'A':
619163953Srrs		if (!nflag)
620169420Srrs			printf("%s%s", name, sep);
621169420Srrs		printf("%.*s", (int)len, p);
622169420Srrs		free(oval);
623163953Srrs		return (0);
624163953Srrs
625169420Srrs	case 'I':
626169420Srrs	case 'L':
627163953Srrs	case 'Q':
628163953Srrs		if (!nflag)
629163953Srrs			printf("%s%s", name, sep);
630163953Srrs		switch (*fmt) {
631163953Srrs		case 'I': intlen = sizeof(int); break;
632163953Srrs		case 'L': intlen = sizeof(long); break;
633169420Srrs		case 'Q': intlen = sizeof(quad_t); break;
634169420Srrs		}
635169420Srrs		hexlen = 2 + (intlen * CHAR_BIT + 3) / 4;
636171990Srrs		sep1 = "";
637171990Srrs		while (len >= intlen) {
638171990Srrs			switch (*fmt) {
639221249Stuexen			case 'I':
640171990Srrs				umv = *(u_int *)p;
641216822Stuexen				mv = *(int *)p;
642171990Srrs				break;
643171990Srrs			case 'L':
644171990Srrs				umv = *(u_long *)p;
645171990Srrs				mv = *(long *)p;
646216822Stuexen				break;
647171990Srrs			case 'Q':
648171990Srrs				umv = *(u_quad_t *)p;
649171990Srrs				mv = *(quad_t *)p;
650179783Srrs				break;
651171990Srrs			}
652163953Srrs			fputs(sep1, stdout);
653165647Srrs			if (fmt[1] == 'U')
654243882Sglebius				printf(hflag ? "%'ju" : "%ju", umv);
655163953Srrs			else if (fmt[1] == 'X')
656169420Srrs				printf("%#0*jx", hexlen, umv);
657169420Srrs			else if (fmt[1] == 'K') {
658163953Srrs				if (mv < 0)
659163953Srrs					printf("%jd", mv);
660163953Srrs				else
661163953Srrs					printf("%.1fC", (mv - 2732.0) / 10);
662163953Srrs			} else
663163953Srrs				printf(hflag ? "%'jd" : "%jd", mv);
664163953Srrs			sep1 = " ";
665163953Srrs			len -= intlen;
666163953Srrs			p += intlen;
667163953Srrs		}
668165647Srrs		free(oval);
669163953Srrs		return (0);
670163953Srrs
671163953Srrs	case 'P':
672163953Srrs		if (!nflag)
673163953Srrs			printf("%s%s", name, sep);
674163953Srrs		printf("%p", *(void **)p);
675169420Srrs		free(oval);
676169420Srrs		return (0);
677163953Srrs
678163953Srrs	case 'T':
679163953Srrs	case 'S':
680163953Srrs		i = 0;
681163953Srrs		if (strcmp(fmt, "S,clockinfo") == 0)
682163953Srrs			func = S_clockinfo;
683163953Srrs		else if (strcmp(fmt, "S,timeval") == 0)
684163953Srrs			func = S_timeval;
685163953Srrs		else if (strcmp(fmt, "S,loadavg") == 0)
686169420Srrs			func = S_loadavg;
687163953Srrs		else if (strcmp(fmt, "S,vmtotal") == 0)
688163953Srrs			func = S_vmtotal;
689163953Srrs		else if (strcmp(fmt, "T,dev_t") == 0)
690163953Srrs			func = T_dev_t;
691163953Srrs		else
692169420Srrs			func = NULL;
693163953Srrs		if (func) {
694163953Srrs			if (!nflag)
695163953Srrs				printf("%s%s", name, sep);
696224641Stuexen			i = (*func)(len, p);
697163953Srrs			free(oval);
698163953Srrs			return (i);
699163953Srrs		}
700163953Srrs		/* FALLTHROUGH */
701163953Srrs	default:
702163953Srrs		if (!oflag && !xflag) {
703163953Srrs			free(oval);
704163953Srrs			return (1);
705163953Srrs		}
706163953Srrs		if (!nflag)
707163953Srrs			printf("%s%s", name, sep);
708163953Srrs		printf("Format:%s Length:%zu Dump:0x", fmt, len);
709163953Srrs		while (len-- && (xflag || p < val + 16))
710169420Srrs			printf("%02x", *p++);
711163953Srrs		if (!xflag && len > 16)
712163953Srrs			printf("...");
713163953Srrs		free(oval);
714163953Srrs		return (0);
715169420Srrs	}
716163953Srrs	free(oval);
717163953Srrs	return (1);
718163953Srrs}
719163953Srrs
720163953Srrsstatic int
721169420Srrssysctl_all(int *oid, int len)
722163953Srrs{
723163953Srrs	int name1[22], name2[22];
724163953Srrs	int i, j;
725163953Srrs	size_t l1, l2;
726163953Srrs
727163953Srrs	name1[0] = 0;
728237715Stuexen	name1[1] = 2;
729224641Stuexen	l1 = 2;
730224641Stuexen	if (len) {
731163953Srrs		memcpy(name1+2, oid, len * sizeof(int));
732163953Srrs		l1 += len;
733163953Srrs	} else {
734237715Stuexen		name1[2] = 1;
735163953Srrs		l1++;
736163953Srrs	}
737163953Srrs	for (;;) {
738163953Srrs		l2 = sizeof(name2);
739163953Srrs		j = sysctl(name1, l1, name2, &l2, 0, 0);
740163953Srrs		if (j < 0) {
741163953Srrs			if (errno == ENOENT)
742237715Stuexen				return (0);
743163953Srrs			else
744163953Srrs				err(1, "sysctl(getnext) %d %zu", j, l2);
745185694Srrs		}
746185694Srrs
747185694Srrs		l2 /= sizeof(int);
748163953Srrs
749163953Srrs		if (len < 0 || l2 < (unsigned int)len)
750163953Srrs			return (0);
751163953Srrs
752163953Srrs		for (i = 0; i < len; i++)
753163953Srrs			if (name2[i] != oid[i])
754163953Srrs				return (0);
755163953Srrs
756163953Srrs		i = show_var(name2, l2);
757163953Srrs		if (!i && !bflag)
758163953Srrs			putchar('\n');
759163953Srrs
760163953Srrs		memcpy(name1+2, name2, l2 * sizeof(int));
761163953Srrs		l1 = 2 + l2;
762163953Srrs	}
763163953Srrs}
764163953Srrs