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