xref: /dragonfly/sbin/sysctl/sysctl.c (revision fbc9049b)
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. 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  * @(#) Copyright (c) 1993 The Regents of the University of California.  All rights reserved.
30  * @(#)from: sysctl.c	8.1 (Berkeley) 6/6/93
31  * $FreeBSD: src/sbin/sysctl/sysctl.c,v 1.25.2.11 2003/05/01 22:48:08 trhodes Exp $
32  */
33 
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/sysctl.h>
37 #include <sys/resource.h>
38 #include <sys/sensors.h>
39 #include <sys/param.h>
40 
41 #include <machine/inttypes.h>
42 
43 #include <ctype.h>
44 #include <err.h>
45 #include <errno.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 
51 static int	aflag, bflag, dflag, eflag, Nflag, nflag, oflag, xflag;
52 
53 static int	oidfmt(int *, size_t, char *, u_int *);
54 static void	parse(const char *);
55 static int	show_var(int *, size_t);
56 static int	sysctl_all(int *, size_t);
57 static void	set_T_dev_t(const char *, void **, size_t *);
58 static int	set_IK(const char *, int *);
59 
60 static void
61 usage(void)
62 {
63 
64 	fprintf(stderr, "%s\n%s\n",
65 	    "usage: sysctl [-bdeNnox] variable[=value] ...",
66 	    "       sysctl [-bdeNnox] -a");
67 	exit(1);
68 }
69 
70 int
71 main(int argc, char **argv)
72 {
73 	int ch;
74 	setbuf(stdout,0);
75 	setbuf(stderr,0);
76 
77 	while ((ch = getopt(argc, argv, "AabdeNnowxX")) != -1) {
78 		switch (ch) {
79 		case 'A':
80 			/* compatibility */
81 			aflag = oflag = 1;
82 			break;
83 		case 'a':
84 			aflag = 1;
85 			break;
86 		case 'b':
87 			bflag = 1;
88 			break;
89 		case 'd':
90 			dflag = 1;
91 			break;
92 		case 'e':
93 			eflag = 1;
94 			break;
95 		case 'N':
96 			Nflag = 1;
97 			break;
98 		case 'n':
99 			nflag = 1;
100 			break;
101 		case 'o':
102 			oflag = 1;
103 			break;
104 		case 'w':
105 			/* compatibility */
106 			/* ignored */
107 			break;
108 		case 'X':
109 			/* compatibility */
110 			aflag = xflag = 1;
111 			break;
112 		case 'x':
113 			xflag = 1;
114 			break;
115 		default:
116 			usage();
117 		}
118 	}
119 	argc -= optind;
120 	argv += optind;
121 
122 	if (Nflag && nflag)
123 		usage();
124 	if (aflag && argc == 0)
125 		exit(sysctl_all(0, 0));
126 	if (argc == 0)
127 		usage();
128 	while (argc-- > 0)
129 		parse(*argv++);
130 	exit(0);
131 }
132 
133 /*
134  * Parse a name into a MIB entry.
135  * Lookup and print out the MIB entry if it exists.
136  * Set a new value if requested.
137  */
138 static void
139 parse(const char *string)
140 {
141 	size_t len;
142 	int i, j;
143 	void *newval = NULL;
144 	int intval;
145 	unsigned int uintval;
146 	long longval;
147 	unsigned long ulongval;
148 	size_t newsize = 0;
149 	quad_t quadval;
150 	u_quad_t uquadval;
151 	int mib[CTL_MAXNAME];
152 	char *cp, fmt[BUFSIZ];
153 	const char *name;
154 	char *name_allocated = NULL;
155 	u_int kind;
156 
157 	if ((cp = strchr(string, '=')) != NULL) {
158 		if ((name_allocated = malloc(cp - string + 1)) == NULL)
159 			err(1, "malloc failed");
160 		strlcpy(name_allocated, string, cp - string + 1);
161 		name = name_allocated;
162 
163 		while (isspace(*++cp))
164 			;
165 
166 		newval = cp;
167 		newsize = strlen(cp);
168 	} else {
169 		name = string;
170 	}
171 
172 	len = CTL_MAXNAME;
173 	if (sysctlnametomib(name, mib, &len) < 0) {
174 		if (errno == ENOENT) {
175 			errx(1, "unknown oid '%s'", name);
176 		} else {
177 			err(1, "sysctlnametomib(\"%s\")", name);
178 		}
179 	}
180 
181 	if (oidfmt(mib, len, fmt, &kind))
182 		err(1, "couldn't find format of oid '%s'", name);
183 
184 	if (newval == NULL) {
185 		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
186 			sysctl_all(mib, len);
187 		} else {
188 			i = show_var(mib, len);
189 			if (!i && !bflag)
190 				putchar('\n');
191 		}
192 	} else {
193 		if ((kind & CTLTYPE) == CTLTYPE_NODE)
194 			errx(1, "oid '%s' isn't a leaf node", name);
195 
196 		if (!(kind&CTLFLAG_WR))
197 			errx(1, "oid '%s' is read only", name);
198 
199 		switch (kind & CTLTYPE) {
200 			case CTLTYPE_INT:
201 				if (!(strcmp(fmt, "IK") == 0)) {
202 					if (!set_IK(newval, &intval))
203 						errx(1, "invalid value '%s'",
204 						    (char *)newval);
205 				} else
206 					intval = (int) strtol(newval, NULL, 0);
207 				newval = &intval;
208 				newsize = sizeof(intval);
209 				break;
210 			case CTLTYPE_UINT:
211 				uintval = (int) strtoul(newval, NULL, 0);
212 				newval = &uintval;
213 				newsize = sizeof uintval;
214 				break;
215 			case CTLTYPE_LONG:
216 				longval = strtol(newval, NULL, 0);
217 				newval = &longval;
218 				newsize = sizeof longval;
219 				break;
220 			case CTLTYPE_ULONG:
221 				ulongval = strtoul(newval, NULL, 0);
222 				newval = &ulongval;
223 				newsize = sizeof ulongval;
224 				break;
225 			case CTLTYPE_STRING:
226 				break;
227 			case CTLTYPE_QUAD:
228 				quadval = strtoq(newval, NULL, 0);
229 				newval = &quadval;
230 				newsize = sizeof(quadval);
231 				break;
232 			case CTLTYPE_UQUAD:
233 				uquadval = strtouq(newval, NULL, 0);
234 				newval = &uquadval;
235 				newsize = sizeof(uquadval);
236 				break;
237 			case CTLTYPE_OPAQUE:
238 				if (strcmp(fmt, "T,dev_t") == 0 ||
239 				    strcmp(fmt, "T,udev_t") == 0
240 				) {
241 					set_T_dev_t((char*)newval, &newval,
242 						    &newsize);
243 					break;
244 				}
245 				/* FALLTHROUGH */
246 			default:
247 				errx(1, "oid '%s' is type %d,"
248 					" cannot set that", name,
249 					kind & CTLTYPE);
250 		}
251 
252 		i = show_var(mib, len);
253 		if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
254 			if (!i && !bflag)
255 				putchar('\n');
256 			switch (errno) {
257 			case EOPNOTSUPP:
258 				errx(1, "%s: value is not available",
259 					string);
260 			case ENOTDIR:
261 				errx(1, "%s: specification is incomplete",
262 					string);
263 			case ENOMEM:
264 				errx(1, "%s: type is unknown to this program",
265 					string);
266 			default:
267 				warn("%s", string);
268 				return;
269 			}
270 		}
271 		if (!bflag)
272 			printf(" -> ");
273 		i = nflag;
274 		nflag = 1;
275 		j = show_var(mib, len);
276 		if (!j && !bflag)
277 			putchar('\n');
278 		nflag = i;
279 	}
280 
281 	if (name_allocated != NULL)
282 		free(name_allocated);
283 }
284 
285 /* These functions will dump out various interesting structures. */
286 
287 static int
288 S_clockinfo(int l2, void *p)
289 {
290 	struct clockinfo *ci = (struct clockinfo*)p;
291 	if (l2 != sizeof(*ci))
292 		err(1, "S_clockinfo %d != %zu", l2, sizeof(*ci));
293 	printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
294 		ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz);
295 	return (0);
296 }
297 
298 static int
299 S_loadavg(int l2, void *p)
300 {
301 	struct loadavg *tv = (struct loadavg*)p;
302 
303 	if (l2 != sizeof(*tv))
304 		err(1, "S_loadavg %d != %zu", l2, sizeof(*tv));
305 
306 	printf("{ %.2f %.2f %.2f }",
307 		(double)tv->ldavg[0]/(double)tv->fscale,
308 		(double)tv->ldavg[1]/(double)tv->fscale,
309 		(double)tv->ldavg[2]/(double)tv->fscale);
310 	return (0);
311 }
312 
313 static int
314 S_timespec(int l2, void *p)
315 {
316 	struct timespec *ts = (struct timespec*)p;
317 	time_t tv_sec;
318 	char *p1, *p2;
319 
320 	if (l2 != sizeof(*ts))
321 		err(1, "S_timespec %d != %zu", l2, sizeof(*ts));
322 	printf("{ sec = %ld, nsec = %ld } ",
323 		ts->tv_sec, ts->tv_nsec);
324 	tv_sec = ts->tv_sec;
325 	p1 = strdup(ctime(&tv_sec));
326 	for (p2=p1; *p2 ; p2++)
327 		if (*p2 == '\n')
328 			*p2 = '\0';
329 	fputs(p1, stdout);
330 	return (0);
331 }
332 
333 static int
334 S_timeval(int l2, void *p)
335 {
336 	struct timeval *tv = (struct timeval*)p;
337 	time_t tv_sec;
338 	char *p1, *p2;
339 
340 	if (l2 != sizeof(*tv))
341 		err(1, "S_timeval %d != %zu", l2, sizeof(*tv));
342 	printf("{ sec = %ld, usec = %ld } ",
343 		tv->tv_sec, tv->tv_usec);
344 	tv_sec = tv->tv_sec;
345 	p1 = strdup(ctime(&tv_sec));
346 	for (p2=p1; *p2 ; p2++)
347 		if (*p2 == '\n')
348 			*p2 = '\0';
349 	fputs(p1, stdout);
350 	return (0);
351 }
352 
353 static int
354 S_sensor(int l2, void *p)
355 {
356 	struct sensor *s = (struct sensor *)p;
357 
358 	if (l2 != sizeof(*s)) {
359 		warnx("S_sensor %d != %zu", l2, sizeof(*s));
360 		return (1);
361 	}
362 
363 	if (s->flags & SENSOR_FINVALID) {
364 		/*
365 		 * XXX: with this flag, the node should be entirely ignored,
366 		 * but as the magic-based sysctl(8) is not too flexible, we
367 		 * simply have to print out that the sensor is invalid.
368 		 */
369 		printf("invalid");
370 		return (0);
371 	}
372 
373 	if (s->flags & SENSOR_FUNKNOWN)
374 		printf("unknown");
375 	else {
376 		switch (s->type) {
377 		case SENSOR_TEMP:
378 			printf("%.2f degC",
379 			    (s->value - 273150000) / 1000000.0);
380 			break;
381 		case SENSOR_FANRPM:
382 			printf("%jd RPM", (intmax_t)s->value);
383 			break;
384 		case SENSOR_VOLTS_DC:
385 			printf("%.2f VDC", s->value / 1000000.0);
386 			break;
387 		case SENSOR_WATTS:
388 			printf("%.2f W", s->value / 1000000.0);
389 			break;
390 		case SENSOR_AMPS:
391 			printf("%.2f A", s->value / 1000000.0);
392 			break;
393 		case SENSOR_WATTHOUR:
394 			printf("%.2f Wh", s->value / 1000000.0);
395 			break;
396 		case SENSOR_AMPHOUR:
397 			printf("%.2f Ah", s->value / 1000000.0);
398 			break;
399 		case SENSOR_INDICATOR:
400 			printf("%s", s->value ? "On" : "Off");
401 			break;
402 		case SENSOR_FREQ:
403 			printf("%jd Hz", (intmax_t)s->value);
404 			break;
405 		case SENSOR_ECC:
406 		case SENSOR_INTEGER:
407 			printf("%jd", (intmax_t)s->value);
408 			break;
409 		case SENSOR_PERCENT:
410 			printf("%.2f%%", s->value / 1000.0);
411 			break;
412 		case SENSOR_LUX:
413 			printf("%.2f lx", s->value / 1000000.0);
414 			break;
415 		case SENSOR_DRIVE:
416 		{
417 			const char *name;
418 
419 			switch (s->value) {
420 			case SENSOR_DRIVE_EMPTY:
421 				name = "empty";
422 				break;
423 			case SENSOR_DRIVE_READY:
424 				name = "ready";
425 				break;
426 			case SENSOR_DRIVE_POWERUP:
427 				name = "powering up";
428 				break;
429 			case SENSOR_DRIVE_ONLINE:
430 				name = "online";
431 				break;
432 			case SENSOR_DRIVE_IDLE:
433 				name = "idle";
434 				break;
435 			case SENSOR_DRIVE_ACTIVE:
436 				name = "active";
437 				break;
438 			case SENSOR_DRIVE_REBUILD:
439 				name = "rebuilding";
440 				break;
441 			case SENSOR_DRIVE_POWERDOWN:
442 				name = "powering down";
443 				break;
444 			case SENSOR_DRIVE_FAIL:
445 				name = "failed";
446 				break;
447 			case SENSOR_DRIVE_PFAIL:
448 				name = "degraded";
449 				break;
450 			default:
451 				name = "unknown";
452 				break;
453 			}
454 			printf("%s", name);
455 			break;
456 		}
457 		case SENSOR_TIMEDELTA:
458 			printf("%.6f secs", s->value / 1000000000.0);
459 			break;
460 		default:
461 			printf("unknown");
462 		}
463 	}
464 
465 	if (s->desc[0] != '\0')
466 		printf(" (%s)", s->desc);
467 
468 	switch (s->status) {
469 	case SENSOR_S_UNSPEC:
470 		break;
471 	case SENSOR_S_OK:
472 		printf(", OK");
473 		break;
474 	case SENSOR_S_WARN:
475 		printf(", WARNING");
476 		break;
477 	case SENSOR_S_CRIT:
478 		printf(", CRITICAL");
479 		break;
480 	case SENSOR_S_UNKNOWN:
481 		printf(", UNKNOWN");
482 		break;
483 	}
484 
485 	if (s->tv.tv_sec) {
486 		time_t t = s->tv.tv_sec;
487 		char ct[26];
488 
489 		ctime_r(&t, ct);
490 		ct[19] = '\0';
491 		printf(", %s.%03ld", ct, s->tv.tv_usec / 1000);
492 	}
493 
494 	return (0);
495 }
496 
497 static int
498 T_dev_t(int l2, void *p)
499 {
500 	dev_t *d = (dev_t *)p;
501 	if (l2 != sizeof(*d))
502 		err(1, "T_dev_T %d != %zu", l2, sizeof(*d));
503 	if ((int)(*d) != -1) {
504 		if (minor(*d) > 255 || minor(*d) < 0)
505 			printf("{ major = %d, minor = 0x%x }",
506 				major(*d), minor(*d));
507 		else
508 			printf("{ major = %d, minor = %d }",
509 				major(*d), minor(*d));
510 	}
511 	return (0);
512 }
513 
514 static void
515 set_T_dev_t(const char *path, void **val, size_t *size)
516 {
517 	static struct stat statb;
518 
519 	if (strcmp(path, "none") && strcmp(path, "off")) {
520 		int rc = stat (path, &statb);
521 		if (rc) {
522 			err(1, "cannot stat %s", path);
523 		}
524 
525 		if (!S_ISCHR(statb.st_mode)) {
526 			errx(1, "must specify a device special file.");
527 		}
528 	} else {
529 		statb.st_rdev = NODEV;
530 	}
531 	*val = (char*) &statb.st_rdev;
532 	*size = sizeof statb.st_rdev;
533 }
534 
535 static int
536 set_IK(const char *str, int *val)
537 {
538 	float temp;
539 	int len, kelv;
540 	const char *p;
541 	char *endptr;
542 
543 	if ((len = strlen(str)) == 0)
544 		return (0);
545 	p = &str[len - 1];
546 	if (*p == 'C' || *p == 'F') {
547 		temp = strtof(str, &endptr);
548 		if (endptr == str || endptr != p)
549 			return 0;
550 		if (*p == 'F')
551 			temp = (temp - 32) * 5 / 9;
552 		kelv = temp * 10 + 2732;
553 	} else {
554 		/*
555 		 * I would like to just use, 0 but it would make numbers
556 		 * like '023' which were interpreted as decimal before
557 		 * suddenly interpreted as octal.
558 		 */
559 		if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
560 			kelv = (int)strtol(str, &endptr, 0);
561 		else
562 			kelv = (int)strtol(str, &endptr, 10);
563 		if (endptr == str || *endptr != '\0')
564 			return 0;
565 	}
566 	*val = kelv;
567 	return 1;
568 }
569 
570 /*
571  * These functions uses a presently undocumented interface to the kernel
572  * to walk the tree and get the type so it can print the value.
573  * This interface is under work and consideration, and should probably
574  * be killed with a big axe by the first person who can find the time.
575  * (be aware though, that the proper interface isn't as obvious as it
576  * may seem, there are various conflicting requirements.
577  */
578 
579 static int
580 oidfmt(int *oid, size_t len, char *fmt, u_int *kind)
581 {
582 	int qoid[CTL_MAXNAME+2];
583 	u_char buf[BUFSIZ];
584 	int i;
585 	size_t j;
586 
587 	qoid[0] = 0;
588 	qoid[1] = 4;
589 	memcpy(qoid + 2, oid, len * sizeof(int));
590 
591 	j = sizeof(buf);
592 	i = sysctl(qoid, len + 2, buf, &j, 0, 0);
593 	if (i)
594 		err(1, "sysctl fmt %d %zu %d", i, j, errno);
595 
596 	if (kind)
597 		*kind = *(u_int *)buf;
598 
599 	if (fmt)
600 		strcpy(fmt, (char *)(buf + sizeof(u_int)));
601 	return 0;
602 }
603 
604 /*
605  * This formats and outputs the value of one variable
606  *
607  * Returns zero if anything was actually output.
608  * Returns one if didn't know what to do with this.
609  * Return minus one if we had errors.
610  */
611 
612 static int
613 show_var(int *oid, size_t nlen)
614 {
615 	u_char buf[BUFSIZ], *val = NULL, *p, *nul;
616 	char name[BUFSIZ], *fmt;
617 	const char *sep, *spacer;
618 	int qoid[CTL_MAXNAME+2];
619 	int i;
620 	size_t j, len;
621 	u_int kind;
622 	int (*func)(int, void *);
623 	int error = 0;
624 
625 	qoid[0] = 0;
626 	memcpy(qoid + 2, oid, nlen * sizeof(int));
627 
628 	qoid[1] = 1;
629 	j = sizeof(name);
630 	i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
631 	if (i || !j)
632 		err(1, "sysctl name %d %zu %d", i, j, errno);
633 
634 	if (Nflag) {
635 		printf("%s", name);
636 		return (0);
637 	}
638 
639 	if (eflag)
640 		sep = "=";
641 	else
642 		sep = ": ";
643 
644 	if (dflag) {	/* just print description */
645 		qoid[1] = 5;
646 		j = sizeof(buf);
647 		i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
648 		if (!nflag)
649 			printf("%s%s", name, sep);
650 		printf("%s", buf);
651 		return(0);
652 	}
653 	/* find an estimate of how much we need for this var */
654 	j = 0;
655 	i = sysctl(oid, nlen, 0, &j, 0, 0);
656 	j += j; /* we want to be sure :-) */
657 
658 	val = malloc(j + 1);
659 	if (val == NULL)
660 		return (1);
661 
662 	len = j;
663 	i = sysctl(oid, nlen, val, &len, 0, 0);
664 	if (i || !len) {
665 		error = 1;
666 		goto done;
667 	}
668 
669 	if (bflag) {
670 		fwrite(val, 1, len, stdout);
671 		goto done;
672 	}
673 
674 	val[len] = '\0';
675 	fmt = buf;
676 	oidfmt(oid, nlen, fmt, &kind);
677 	p = val;
678 	switch (*fmt) {
679 	case 'A':
680 		if (!nflag)
681 			printf("%s%s", name, sep);
682 		nul = memchr(p, '\0', len);
683 		fwrite(p, nul == NULL ? (int)len : nul - p, 1, stdout);
684 		return (0);
685 
686 	case 'I':
687 		if (!nflag)
688 			printf("%s%s", name, sep);
689 		fmt++;
690 		spacer = "";
691 		while (len >= sizeof(int)) {
692 			if(*fmt == 'U')
693 				printf("%s%u", spacer, *(unsigned int *)p);
694 			else if (*fmt == 'K' && *(int *)p >= 0)
695 				printf("%s%.1fC", spacer, (*(int *)p - 2732) / 10.0);
696 			else
697 				printf("%s%d", spacer, *(int *)p);
698 			spacer = " ";
699 			len -= sizeof(int);
700 			p += sizeof(int);
701 		}
702 		goto done;
703 
704 	case 'L':
705 		if (!nflag)
706 			printf("%s%s", name, sep);
707 		fmt++;
708 		spacer = "";
709 		while (len >= sizeof(long)) {
710 			if(*fmt == 'U')
711 				printf("%s%lu", spacer, *(unsigned long *)p);
712 			else
713 				printf("%s%ld", spacer, *(long *)p);
714 			spacer = " ";
715 			len -= sizeof(long);
716 			p += sizeof(long);
717 		}
718 		goto done;
719 
720 	case 'P':
721 		if (!nflag)
722 			printf("%s%s", name, sep);
723 		printf("%p", *(void **)p);
724 		goto done;
725 
726 	case 'Q':
727 		if (!nflag)
728 			printf("%s%s", name, sep);
729 		fmt++;
730 		spacer = "";
731 		while (len >= sizeof(quad_t)) {
732 			if(*fmt == 'U') {
733 				printf("%s%ju",
734 				       spacer, (uintmax_t)*(u_quad_t *)p);
735 			} else {
736 				printf("%s%jd",
737 				       spacer, (intmax_t)*(quad_t *)p);
738 			}
739 			spacer = " ";
740 			len -= sizeof(int64_t);
741 			p += sizeof(int64_t);
742 		}
743 		goto done;
744 
745 	case 'T':
746 	case 'S':
747 		if (!oflag && !xflag) {
748 			i = 0;
749 			if (strcmp(fmt, "S,clockinfo") == 0)
750 				func = S_clockinfo;
751 			else if (strcmp(fmt, "S,timespec") == 0)
752 				func = S_timespec;
753 			else if (strcmp(fmt, "S,timeval") == 0)
754 				func = S_timeval;
755 			else if (strcmp(fmt, "S,loadavg") == 0)
756 				func = S_loadavg;
757 			else if (strcmp(fmt, "S,sensor") == 0)
758 				func = S_sensor;
759 			else if (strcmp(fmt, "T,dev_t") == 0)
760 				func = T_dev_t;
761 			else if (strcmp(fmt, "T,udev_t") == 0)
762 				func = T_dev_t;
763 			else
764 				func = NULL;
765 			if (func) {
766 				if (!nflag)
767 					printf("%s%s", name, sep);
768 				error = (*func)(len, p);
769 				goto done;
770 			}
771 		}
772 		/* FALL THROUGH */
773 	default:
774 		if (!oflag && !xflag) {
775 			error = 1;
776 			goto done;
777 		}
778 		if (!nflag)
779 			printf("%s%s", name, sep);
780 		printf("Format:%s Length:%zu Dump:0x", fmt, len);
781 		while (len-- && (xflag || p < val + 16))
782 			printf("%02x", *p++);
783 		if (!xflag && len > 16)
784 			printf("...");
785 		goto done;
786 	}
787 
788 done:
789 	if (val != NULL)
790 		free(val);
791 	return (error);
792 }
793 
794 static int
795 sysctl_all(int *oid, size_t len)
796 {
797 	int name1[22], name2[22];
798 	int retval;
799 	size_t i, l1, l2;
800 
801 	name1[0] = 0;
802 	name1[1] = 2;
803 	l1 = 2;
804 	if (len) {
805 		memcpy(name1+2, oid, len * sizeof(int));
806 		l1 += len;
807 	} else {
808 		name1[2] = 1;
809 		l1++;
810 	}
811 	for (;;) {
812 		l2 = sizeof(name2);
813 		retval = sysctl(name1, l1, name2, &l2, 0, 0);
814 		if (retval < 0) {
815 			if (errno == ENOENT)
816 				return 0;
817 			else
818 				err(1, "sysctl(getnext) %d %zu", retval, l2);
819 		}
820 
821 		l2 /= sizeof(int);
822 
823 		if (l2 < len)
824 			return 0;
825 
826 		for (i = 0; i < len; i++)
827 			if (name2[i] != oid[i])
828 				return 0;
829 
830 		retval = show_var(name2, l2);
831 		if (retval == 0 && !bflag)
832 			putchar('\n');
833 
834 		memcpy(name1+2, name2, l2 * sizeof(int));
835 		l1 = 2 + l2;
836 	}
837 }
838