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 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifndef lint
31static const char copyright[] =
32"@(#) Copyright (c) 1993\n\
33	The Regents of the University of California.  All rights reserved.\n";
34#endif /* not lint */
35
36#ifndef lint
37#if 0
38static char sccsid[] = "@(#)from: sysctl.c	8.1 (Berkeley) 6/6/93";
39#endif
40static const char rcsid[] =
41  "$FreeBSD$";
42#endif /* not lint */
43
44#include <sys/param.h>
45#include <sys/time.h>
46#include <sys/resource.h>
47#include <sys/stat.h>
48#include <sys/sysctl.h>
49#include <sys/vmmeter.h>
50
51#include <ctype.h>
52#include <err.h>
53#include <errno.h>
54#include <inttypes.h>
55#include <locale.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59#include <sysexits.h>
60#include <unistd.h>
61
62static const char *conffile;
63
64static int	aflag, bflag, dflag, eflag, hflag, iflag;
65static int	Nflag, nflag, oflag, qflag, Tflag, Wflag, xflag;
66
67static int	oidfmt(int *, int, char *, u_int *);
68static int	parsefile(const char *);
69static int	parse(const char *, int);
70static int	show_var(int *, int);
71static int	sysctl_all(int *oid, int len);
72static int	name2oid(char *, int *);
73
74static int	set_IK(const char *, int *);
75
76static void
77usage(void)
78{
79
80	(void)fprintf(stderr, "%s\n%s\n",
81	    "usage: sysctl [-bdehiNnoqTWx] [-f filename] name[=value] ...",
82	    "       sysctl [-bdehNnoqTWx] -a");
83	exit(1);
84}
85
86int
87main(int argc, char **argv)
88{
89	int ch;
90	int warncount = 0;
91
92	setlocale(LC_NUMERIC, "");
93	setbuf(stdout,0);
94	setbuf(stderr,0);
95
96	while ((ch = getopt(argc, argv, "Aabdef:hiNnoqTwWxX")) != -1) {
97		switch (ch) {
98		case 'A':
99			/* compatibility */
100			aflag = oflag = 1;
101			break;
102		case 'a':
103			aflag = 1;
104			break;
105		case 'b':
106			bflag = 1;
107			break;
108		case 'd':
109			dflag = 1;
110			break;
111		case 'e':
112			eflag = 1;
113			break;
114		case 'f':
115			conffile = optarg;
116			break;
117		case 'h':
118			hflag = 1;
119			break;
120		case 'i':
121			iflag = 1;
122			break;
123		case 'N':
124			Nflag = 1;
125			break;
126		case 'n':
127			nflag = 1;
128			break;
129		case 'o':
130			oflag = 1;
131			break;
132		case 'q':
133			qflag = 1;
134			break;
135		case 'T':
136			Tflag = 1;
137			break;
138		case 'w':
139			/* compatibility */
140			/* ignored */
141			break;
142		case 'W':
143			Wflag = 1;
144			break;
145		case 'X':
146			/* compatibility */
147			aflag = xflag = 1;
148			break;
149		case 'x':
150			xflag = 1;
151			break;
152		default:
153			usage();
154		}
155	}
156	argc -= optind;
157	argv += optind;
158
159	if (Nflag && nflag)
160		usage();
161	if (aflag && argc == 0)
162		exit(sysctl_all(0, 0));
163	if (argc == 0 && conffile == NULL)
164		usage();
165
166	warncount = 0;
167	if (conffile != NULL)
168		warncount += parsefile(conffile);
169
170	while (argc-- > 0)
171		warncount += parse(*argv++, 0);
172
173	return (warncount);
174}
175
176/*
177 * Parse a name into a MIB entry.
178 * Lookup and print out the MIB entry if it exists.
179 * Set a new value if requested.
180 */
181static int
182parse(const char *string, int lineno)
183{
184	int len, i, j;
185	void *newval = 0;
186	int intval;
187	unsigned int uintval;
188	long longval;
189	unsigned long ulongval;
190	size_t newsize = 0;
191	int64_t i64val;
192	uint64_t u64val;
193	int mib[CTL_MAXNAME];
194	char *cp, *bufp, buf[BUFSIZ], *endptr, fmt[BUFSIZ], line[BUFSIZ];
195	u_int kind;
196
197	if (lineno)
198		snprintf(line, sizeof(line), " at line %d", lineno);
199	else
200		line[0] = '\0';
201
202	cp = buf;
203	if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) {
204		warn("oid too long: '%s'%s", string, line);
205		return (1);
206	}
207	bufp = strsep(&cp, "=:");
208	if (cp != NULL) {
209		/* Tflag just lists tunables, do not allow assignment */
210		if (Tflag || Wflag) {
211			warnx("Can't set variables when using -T or -W");
212			usage();
213		}
214		while (isspace(*cp))
215			cp++;
216		/* Strip a pair of " or ' if any. */
217		switch (*cp) {
218		case '\"':
219		case '\'':
220			if (cp[strlen(cp) - 1] == *cp)
221				cp[strlen(cp) - 1] = '\0';
222			cp++;
223		}
224		newval = cp;
225		newsize = strlen(cp);
226	}
227	len = name2oid(bufp, mib);
228
229	if (len < 0) {
230		if (iflag)
231			return (0);
232		if (qflag)
233			return (1);
234		else {
235			warn("unknown oid '%s'%s", bufp, line);
236			return (1);
237		}
238	}
239
240	if (oidfmt(mib, len, fmt, &kind)) {
241		warn("couldn't find format of oid '%s'%s", bufp, line);
242		if (iflag)
243			return (1);
244		else
245			exit(1);
246	}
247
248	if (newval == NULL || dflag) {
249		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
250			if (dflag) {
251				i = show_var(mib, len);
252				if (!i && !bflag)
253					putchar('\n');
254			}
255			sysctl_all(mib, len);
256		} else {
257			i = show_var(mib, len);
258			if (!i && !bflag)
259				putchar('\n');
260		}
261	} else {
262		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
263			warn("oid '%s' isn't a leaf node%s", bufp, line);
264			return (1);
265		}
266
267		if (!(kind & CTLFLAG_WR)) {
268			if (kind & CTLFLAG_TUN) {
269				warnx("oid '%s' is a read only tunable%s", bufp, line);
270				warnx("Tunable values are set in /boot/loader.conf");
271			} else
272				warnx("oid '%s' is read only%s", bufp, line);
273			return (1);
274		}
275
276		if ((kind & CTLTYPE) == CTLTYPE_INT ||
277		    (kind & CTLTYPE) == CTLTYPE_UINT ||
278		    (kind & CTLTYPE) == CTLTYPE_LONG ||
279		    (kind & CTLTYPE) == CTLTYPE_ULONG ||
280		    (kind & CTLTYPE) == CTLTYPE_S64 ||
281		    (kind & CTLTYPE) == CTLTYPE_U64) {
282			if (strlen(newval) == 0) {
283				warnx("empty numeric value");
284				return (1);
285			}
286		}
287
288		switch (kind & CTLTYPE) {
289			case CTLTYPE_INT:
290				if (strcmp(fmt, "IK") == 0) {
291					if (!set_IK(newval, &intval)) {
292						warnx("invalid value '%s'%s",
293						    (char *)newval, line);
294						return (1);
295					}
296 				} else {
297					intval = (int)strtol(newval, &endptr,
298					    0);
299					if (endptr == newval || *endptr != '\0') {
300						warnx("invalid integer '%s'%s",
301						    (char *)newval, line);
302						return (1);
303					}
304				}
305				newval = &intval;
306				newsize = sizeof(intval);
307				break;
308			case CTLTYPE_UINT:
309				uintval = (int) strtoul(newval, &endptr, 0);
310				if (endptr == newval || *endptr != '\0') {
311					warnx("invalid unsigned integer '%s'%s",
312					    (char *)newval, line);
313					return (1);
314				}
315				newval = &uintval;
316				newsize = sizeof(uintval);
317				break;
318			case CTLTYPE_LONG:
319				longval = strtol(newval, &endptr, 0);
320				if (endptr == newval || *endptr != '\0') {
321					warnx("invalid long integer '%s'%s",
322					    (char *)newval, line);
323					return (1);
324				}
325				newval = &longval;
326				newsize = sizeof(longval);
327				break;
328			case CTLTYPE_ULONG:
329				ulongval = strtoul(newval, &endptr, 0);
330				if (endptr == newval || *endptr != '\0') {
331					warnx("invalid unsigned long integer"
332					    " '%s'%s", (char *)newval, line);
333					return (1);
334				}
335				newval = &ulongval;
336				newsize = sizeof(ulongval);
337				break;
338			case CTLTYPE_STRING:
339				break;
340			case CTLTYPE_S64:
341				i64val = strtoimax(newval, &endptr, 0);
342				if (endptr == newval || *endptr != '\0') {
343					warnx("invalid int64_t '%s'%s",
344					    (char *)newval, line);
345					return (1);
346				}
347				newval = &i64val;
348				newsize = sizeof(i64val);
349				break;
350			case CTLTYPE_U64:
351				u64val = strtoumax(newval, &endptr, 0);
352				if (endptr == newval || *endptr != '\0') {
353					warnx("invalid uint64_t '%s'%s",
354					    (char *)newval, line);
355					return (1);
356				}
357				newval = &u64val;
358				newsize = sizeof(u64val);
359				break;
360			case CTLTYPE_OPAQUE:
361				/* FALLTHROUGH */
362			default:
363				warnx("oid '%s' is type %d,"
364					" cannot set that%s", bufp,
365					kind & CTLTYPE, line);
366				return (1);
367		}
368
369		i = show_var(mib, len);
370		if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
371			if (!i && !bflag)
372				putchar('\n');
373			switch (errno) {
374			case EOPNOTSUPP:
375				warnx("%s: value is not available%s",
376					string, line);
377				return (1);
378			case ENOTDIR:
379				warnx("%s: specification is incomplete%s",
380					string, line);
381				return (1);
382			case ENOMEM:
383				warnx("%s: type is unknown to this program%s",
384					string, line);
385				return (1);
386			default:
387				warn("%s%s", string, line);
388				return (1);
389			}
390		}
391		if (!bflag)
392			printf(" -> ");
393		i = nflag;
394		nflag = 1;
395		j = show_var(mib, len);
396		if (!j && !bflag)
397			putchar('\n');
398		nflag = i;
399	}
400
401	return (0);
402}
403
404static int
405parsefile(const char *filename)
406{
407	FILE *file;
408	char line[BUFSIZ], *p, *pq, *pdq;
409	int warncount = 0, lineno = 0;
410
411	file = fopen(filename, "r");
412	if (file == NULL)
413		err(EX_NOINPUT, "%s", filename);
414	while (fgets(line, sizeof(line), file) != NULL) {
415		lineno++;
416		p = line;
417		pq = strchr(line, '\'');
418		pdq = strchr(line, '\"');
419		/* Replace the first # with \0. */
420		while((p = strchr(p, '#')) != NULL) {
421			if (pq != NULL && p > pq) {
422				if ((p = strchr(pq+1, '\'')) != NULL)
423					*(++p) = '\0';
424				break;
425			} else if (pdq != NULL && p > pdq) {
426				if ((p = strchr(pdq+1, '\"')) != NULL)
427					*(++p) = '\0';
428				break;
429			} else if (p == line || *(p-1) != '\\') {
430				*p = '\0';
431				break;
432			}
433			p++;
434		}
435		/* Trim spaces */
436		p = line + strlen(line) - 1;
437		while (p >= line && isspace((int)*p)) {
438			*p = '\0';
439			p--;
440		}
441		p = line;
442		while (isspace((int)*p))
443			p++;
444		if (*p == '\0')
445			continue;
446		else
447			warncount += parse(p, lineno);
448	}
449	fclose(file);
450
451	return (warncount);
452}
453
454/* These functions will dump out various interesting structures. */
455
456static int
457S_clockinfo(int l2, void *p)
458{
459	struct clockinfo *ci = (struct clockinfo*)p;
460
461	if (l2 != sizeof(*ci)) {
462		warnx("S_clockinfo %d != %zu", l2, sizeof(*ci));
463		return (1);
464	}
465	printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
466		"{ hz = %d, tick = %d, profhz = %d, stathz = %d }",
467		ci->hz, ci->tick, ci->profhz, ci->stathz);
468	return (0);
469}
470
471static int
472S_loadavg(int l2, void *p)
473{
474	struct loadavg *tv = (struct loadavg*)p;
475
476	if (l2 != sizeof(*tv)) {
477		warnx("S_loadavg %d != %zu", l2, sizeof(*tv));
478		return (1);
479	}
480	printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
481		(double)tv->ldavg[0]/(double)tv->fscale,
482		(double)tv->ldavg[1]/(double)tv->fscale,
483		(double)tv->ldavg[2]/(double)tv->fscale);
484	return (0);
485}
486
487static int
488S_timeval(int l2, void *p)
489{
490	struct timeval *tv = (struct timeval*)p;
491	time_t tv_sec;
492	char *p1, *p2;
493
494	if (l2 != sizeof(*tv)) {
495		warnx("S_timeval %d != %zu", l2, sizeof(*tv));
496		return (1);
497	}
498	printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
499		"{ sec = %jd, usec = %ld } ",
500		(intmax_t)tv->tv_sec, tv->tv_usec);
501	tv_sec = tv->tv_sec;
502	p1 = strdup(ctime(&tv_sec));
503	for (p2=p1; *p2 ; p2++)
504		if (*p2 == '\n')
505			*p2 = '\0';
506	fputs(p1, stdout);
507	free(p1);
508	return (0);
509}
510
511static int
512S_vmtotal(int l2, void *p)
513{
514	struct vmtotal *v = (struct vmtotal *)p;
515	int pageKilo = getpagesize() / 1024;
516
517	if (l2 != sizeof(*v)) {
518		warnx("S_vmtotal %d != %zu", l2, sizeof(*v));
519		return (1);
520	}
521
522	printf(
523	    "\nSystem wide totals computed every five seconds:"
524	    " (values in kilobytes)\n");
525	printf("===============================================\n");
526	printf(
527	    "Processes:\t\t(RUNQ: %hd Disk Wait: %hd Page Wait: "
528	    "%hd Sleep: %hd)\n",
529	    v->t_rq, v->t_dw, v->t_pw, v->t_sl);
530	printf(
531	    "Virtual Memory:\t\t(Total: %dK Active: %dK)\n",
532	    v->t_vm * pageKilo, v->t_avm * pageKilo);
533	printf("Real Memory:\t\t(Total: %dK Active: %dK)\n",
534	    v->t_rm * pageKilo, v->t_arm * pageKilo);
535	printf("Shared Virtual Memory:\t(Total: %dK Active: %dK)\n",
536	    v->t_vmshr * pageKilo, v->t_avmshr * pageKilo);
537	printf("Shared Real Memory:\t(Total: %dK Active: %dK)\n",
538	    v->t_rmshr * pageKilo, v->t_armshr * pageKilo);
539	printf("Free Memory:\t%dK\n", v->t_free * pageKilo);
540
541	return (0);
542}
543
544static int
545set_IK(const char *str, int *val)
546{
547	float temp;
548	int len, kelv;
549	const char *p;
550	char *endptr;
551
552	if ((len = strlen(str)) == 0)
553		return (0);
554	p = &str[len - 1];
555	if (*p == 'C' || *p == 'F') {
556		temp = strtof(str, &endptr);
557		if (endptr == str || endptr != p)
558			return (0);
559		if (*p == 'F')
560			temp = (temp - 32) * 5 / 9;
561		kelv = temp * 10 + 2732;
562	} else {
563		kelv = (int)strtol(str, &endptr, 10);
564		if (endptr == str || *endptr != '\0')
565			return (0);
566	}
567	*val = kelv;
568	return (1);
569}
570
571/*
572 * These functions uses a presently undocumented interface to the kernel
573 * to walk the tree and get the type so it can print the value.
574 * This interface is under work and consideration, and should probably
575 * be killed with a big axe by the first person who can find the time.
576 * (be aware though, that the proper interface isn't as obvious as it
577 * may seem, there are various conflicting requirements.
578 */
579
580static int
581name2oid(char *name, int *oidp)
582{
583	int oid[2];
584	int i;
585	size_t j;
586
587	oid[0] = 0;
588	oid[1] = 3;
589
590	j = CTL_MAXNAME * sizeof(int);
591	i = sysctl(oid, 2, oidp, &j, name, strlen(name));
592	if (i < 0)
593		return (i);
594	j /= sizeof(int);
595	return (j);
596}
597
598static int
599oidfmt(int *oid, int len, char *fmt, u_int *kind)
600{
601	int qoid[CTL_MAXNAME+2];
602	u_char buf[BUFSIZ];
603	int i;
604	size_t j;
605
606	qoid[0] = 0;
607	qoid[1] = 4;
608	memcpy(qoid + 2, oid, len * sizeof(int));
609
610	j = sizeof(buf);
611	i = sysctl(qoid, len + 2, buf, &j, 0, 0);
612	if (i)
613		err(1, "sysctl fmt %d %zu %d", i, j, errno);
614
615	if (kind)
616		*kind = *(u_int *)buf;
617
618	if (fmt)
619		strcpy(fmt, (char *)(buf + sizeof(u_int)));
620	return (0);
621}
622
623static int ctl_sign[CTLTYPE+1] = {
624	[CTLTYPE_INT] = 1,
625	[CTLTYPE_LONG] = 1,
626	[CTLTYPE_S64] = 1,
627};
628
629static int ctl_size[CTLTYPE+1] = {
630	[CTLTYPE_INT] = sizeof(int),
631	[CTLTYPE_UINT] = sizeof(u_int),
632	[CTLTYPE_LONG] = sizeof(long),
633	[CTLTYPE_ULONG] = sizeof(u_long),
634	[CTLTYPE_S64] = sizeof(int64_t),
635	[CTLTYPE_U64] = sizeof(int64_t),
636};
637
638/*
639 * This formats and outputs the value of one variable
640 *
641 * Returns zero if anything was actually output.
642 * Returns one if didn't know what to do with this.
643 * Return minus one if we had errors.
644 */
645static int
646show_var(int *oid, int nlen)
647{
648	u_char buf[BUFSIZ], *val, *oval, *p;
649	char name[BUFSIZ], fmt[BUFSIZ];
650	const char *sep, *sep1;
651	int qoid[CTL_MAXNAME+2];
652	uintmax_t umv;
653	intmax_t mv;
654	int i, hexlen, sign, ctltype;
655	size_t intlen;
656	size_t j, len;
657	u_int kind;
658	int (*func)(int, void *);
659
660	/* Silence GCC. */
661	umv = mv = intlen = 0;
662
663	bzero(buf, BUFSIZ);
664	bzero(fmt, BUFSIZ);
665	bzero(name, BUFSIZ);
666	qoid[0] = 0;
667	memcpy(qoid + 2, oid, nlen * sizeof(int));
668
669	qoid[1] = 1;
670	j = sizeof(name);
671	i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
672	if (i || !j)
673		err(1, "sysctl name %d %zu %d", i, j, errno);
674
675	oidfmt(oid, nlen, fmt, &kind);
676	/* if Wflag then only list sysctls that are writeable and not stats. */
677	if (Wflag && ((kind & CTLFLAG_WR) == 0 || (kind & CTLFLAG_STATS) != 0))
678		return 1;
679
680	/* if Tflag then only list sysctls that are tuneables. */
681	if (Tflag && (kind & CTLFLAG_TUN) == 0)
682		return 1;
683
684	if (Nflag) {
685		printf("%s", name);
686		return (0);
687	}
688
689	if (eflag)
690		sep = "=";
691	else
692		sep = ": ";
693
694	if (dflag) {	/* just print description */
695		qoid[1] = 5;
696		j = sizeof(buf);
697		i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
698		if (!nflag)
699			printf("%s%s", name, sep);
700		printf("%s", buf);
701		return (0);
702	}
703	/* find an estimate of how much we need for this var */
704	j = 0;
705	i = sysctl(oid, nlen, 0, &j, 0, 0);
706	j += j; /* we want to be sure :-) */
707
708	val = oval = malloc(j + 1);
709	if (val == NULL) {
710		warnx("malloc failed");
711		return (1);
712	}
713	len = j;
714	i = sysctl(oid, nlen, val, &len, 0, 0);
715	if (i || !len) {
716		free(oval);
717		return (1);
718	}
719
720	if (bflag) {
721		fwrite(val, 1, len, stdout);
722		free(oval);
723		return (0);
724	}
725	val[len] = '\0';
726	p = val;
727	ctltype = (kind & CTLTYPE);
728	sign = ctl_sign[ctltype];
729	intlen = ctl_size[ctltype];
730
731	switch (ctltype) {
732	case CTLTYPE_STRING:
733		if (!nflag)
734			printf("%s%s", name, sep);
735		printf("%.*s", (int)len, p);
736		free(oval);
737		return (0);
738
739	case CTLTYPE_INT:
740	case CTLTYPE_UINT:
741	case CTLTYPE_LONG:
742	case CTLTYPE_ULONG:
743	case CTLTYPE_S64:
744	case CTLTYPE_U64:
745		if (!nflag)
746			printf("%s%s", name, sep);
747		hexlen = 2 + (intlen * CHAR_BIT + 3) / 4;
748		sep1 = "";
749		while (len >= intlen) {
750			switch (kind & CTLTYPE) {
751			case CTLTYPE_INT:
752			case CTLTYPE_UINT:
753				umv = *(u_int *)p;
754				mv = *(int *)p;
755				break;
756			case CTLTYPE_LONG:
757			case CTLTYPE_ULONG:
758				umv = *(u_long *)p;
759				mv = *(long *)p;
760				break;
761			case CTLTYPE_S64:
762			case CTLTYPE_U64:
763				umv = *(uint64_t *)p;
764				mv = *(int64_t *)p;
765				break;
766			}
767			fputs(sep1, stdout);
768			if (xflag)
769				printf("%#0*jx", hexlen, umv);
770			else if (!sign)
771				printf(hflag ? "%'ju" : "%ju", umv);
772			else if (fmt[1] == 'K') {
773				if (mv < 0)
774					printf("%jd", mv);
775				else
776					printf("%.1fC", (mv - 2732.0) / 10);
777			} else
778				printf(hflag ? "%'jd" : "%jd", mv);
779			sep1 = " ";
780			len -= intlen;
781			p += intlen;
782		}
783		free(oval);
784		return (0);
785
786	case CTLTYPE_OPAQUE:
787		i = 0;
788		if (strcmp(fmt, "S,clockinfo") == 0)
789			func = S_clockinfo;
790		else if (strcmp(fmt, "S,timeval") == 0)
791			func = S_timeval;
792		else if (strcmp(fmt, "S,loadavg") == 0)
793			func = S_loadavg;
794		else if (strcmp(fmt, "S,vmtotal") == 0)
795			func = S_vmtotal;
796		else
797			func = NULL;
798		if (func) {
799			if (!nflag)
800				printf("%s%s", name, sep);
801			i = (*func)(len, p);
802			free(oval);
803			return (i);
804		}
805		/* FALLTHROUGH */
806	default:
807		if (!oflag && !xflag) {
808			free(oval);
809			return (1);
810		}
811		if (!nflag)
812			printf("%s%s", name, sep);
813		printf("Format:%s Length:%zu Dump:0x", fmt, len);
814		while (len-- && (xflag || p < val + 16))
815			printf("%02x", *p++);
816		if (!xflag && len > 16)
817			printf("...");
818		free(oval);
819		return (0);
820	}
821	free(oval);
822	return (1);
823}
824
825static int
826sysctl_all(int *oid, int len)
827{
828	int name1[22], name2[22];
829	int i, j;
830	size_t l1, l2;
831
832	name1[0] = 0;
833	name1[1] = 2;
834	l1 = 2;
835	if (len) {
836		memcpy(name1+2, oid, len * sizeof(int));
837		l1 += len;
838	} else {
839		name1[2] = 1;
840		l1++;
841	}
842	for (;;) {
843		l2 = sizeof(name2);
844		j = sysctl(name1, l1, name2, &l2, 0, 0);
845		if (j < 0) {
846			if (errno == ENOENT)
847				return (0);
848			else
849				err(1, "sysctl(getnext) %d %zu", j, l2);
850		}
851
852		l2 /= sizeof(int);
853
854		if (len < 0 || l2 < (unsigned int)len)
855			return (0);
856
857		for (i = 0; i < len; i++)
858			if (name2[i] != oid[i])
859				return (0);
860
861		i = show_var(name2, l2);
862		if (!i && !bflag)
863			putchar('\n');
864
865		memcpy(name1+2, name2, l2 * sizeof(int));
866		l1 = 2 + l2;
867	}
868}
869