sysctl.c revision 272913
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: stable/10/sbin/sysctl/sysctl.c 272913 2014-10-10 20:47:23Z jhb $";
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#ifdef __amd64__
52#include <sys/efi.h>
53#include <machine/metadata.h>
54#endif
55
56#if defined(__amd64__) || defined(__i386__)
57#include <machine/pc/bios.h>
58#endif
59
60#include <ctype.h>
61#include <err.h>
62#include <errno.h>
63#include <inttypes.h>
64#include <locale.h>
65#include <stdio.h>
66#include <stdlib.h>
67#include <string.h>
68#include <sysexits.h>
69#include <unistd.h>
70
71static const char *conffile;
72
73static int	aflag, bflag, dflag, eflag, hflag, iflag;
74static int	Nflag, nflag, oflag, qflag, Tflag, Wflag, xflag;
75
76static int	oidfmt(int *, int, char *, u_int *);
77static int	parsefile(const char *);
78static int	parse(const char *, int);
79static int	show_var(int *, int);
80static int	sysctl_all(int *oid, int len);
81static int	name2oid(char *, int *);
82
83static int	set_IK(const char *, int *);
84
85static void
86usage(void)
87{
88
89	(void)fprintf(stderr, "%s\n%s\n",
90	    "usage: sysctl [-bdehiNnoqTWx] [-f filename] name[=value] ...",
91	    "       sysctl [-bdehNnoqTWx] -a");
92	exit(1);
93}
94
95int
96main(int argc, char **argv)
97{
98	int ch;
99	int warncount = 0;
100
101	setlocale(LC_NUMERIC, "");
102	setbuf(stdout,0);
103	setbuf(stderr,0);
104
105	while ((ch = getopt(argc, argv, "Aabdef:hiNnoqTwWxX")) != -1) {
106		switch (ch) {
107		case 'A':
108			/* compatibility */
109			aflag = oflag = 1;
110			break;
111		case 'a':
112			aflag = 1;
113			break;
114		case 'b':
115			bflag = 1;
116			break;
117		case 'd':
118			dflag = 1;
119			break;
120		case 'e':
121			eflag = 1;
122			break;
123		case 'f':
124			conffile = optarg;
125			break;
126		case 'h':
127			hflag = 1;
128			break;
129		case 'i':
130			iflag = 1;
131			break;
132		case 'N':
133			Nflag = 1;
134			break;
135		case 'n':
136			nflag = 1;
137			break;
138		case 'o':
139			oflag = 1;
140			break;
141		case 'q':
142			qflag = 1;
143			break;
144		case 'T':
145			Tflag = 1;
146			break;
147		case 'w':
148			/* compatibility */
149			/* ignored */
150			break;
151		case 'W':
152			Wflag = 1;
153			break;
154		case 'X':
155			/* compatibility */
156			aflag = xflag = 1;
157			break;
158		case 'x':
159			xflag = 1;
160			break;
161		default:
162			usage();
163		}
164	}
165	argc -= optind;
166	argv += optind;
167
168	if (Nflag && nflag)
169		usage();
170	if (aflag && argc == 0)
171		exit(sysctl_all(0, 0));
172	if (argc == 0 && conffile == NULL)
173		usage();
174
175	warncount = 0;
176	if (conffile != NULL)
177		warncount += parsefile(conffile);
178
179	while (argc-- > 0)
180		warncount += parse(*argv++, 0);
181
182	return (warncount);
183}
184
185/*
186 * Parse a name into a MIB entry.
187 * Lookup and print out the MIB entry if it exists.
188 * Set a new value if requested.
189 */
190static int
191parse(const char *string, int lineno)
192{
193	int len, i, j;
194	void *newval = 0;
195	int intval;
196	unsigned int uintval;
197	long longval;
198	unsigned long ulongval;
199	size_t newsize = 0;
200	int64_t i64val;
201	uint64_t u64val;
202	int mib[CTL_MAXNAME];
203	char *cp, *bufp, buf[BUFSIZ], *endptr, fmt[BUFSIZ], line[BUFSIZ];
204	u_int kind;
205
206	if (lineno)
207		snprintf(line, sizeof(line), " at line %d", lineno);
208	else
209		line[0] = '\0';
210
211	cp = buf;
212	if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) {
213		warnx("oid too long: '%s'%s", string, line);
214		return (1);
215	}
216	bufp = strsep(&cp, "=:");
217	if (cp != NULL) {
218		/* Tflag just lists tunables, do not allow assignment */
219		if (Tflag || Wflag) {
220			warnx("Can't set variables when using -T or -W");
221			usage();
222		}
223		while (isspace(*cp))
224			cp++;
225		/* Strip a pair of " or ' if any. */
226		switch (*cp) {
227		case '\"':
228		case '\'':
229			if (cp[strlen(cp) - 1] == *cp)
230				cp[strlen(cp) - 1] = '\0';
231			cp++;
232		}
233		newval = cp;
234		newsize = strlen(cp);
235	}
236	len = name2oid(bufp, mib);
237
238	if (len < 0) {
239		if (iflag)
240			return (0);
241		if (qflag)
242			return (1);
243		else {
244			warn("unknown oid '%s'%s", bufp, line);
245			return (1);
246		}
247	}
248
249	if (oidfmt(mib, len, fmt, &kind)) {
250		warn("couldn't find format of oid '%s'%s", bufp, line);
251		if (iflag)
252			return (1);
253		else
254			exit(1);
255	}
256
257	if (newval == NULL || dflag) {
258		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
259			if (dflag) {
260				i = show_var(mib, len);
261				if (!i && !bflag)
262					putchar('\n');
263			}
264			sysctl_all(mib, len);
265		} else {
266			i = show_var(mib, len);
267			if (!i && !bflag)
268				putchar('\n');
269		}
270	} else {
271		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
272			warnx("oid '%s' isn't a leaf node%s", bufp, line);
273			return (1);
274		}
275
276		if (!(kind & CTLFLAG_WR)) {
277			if (kind & CTLFLAG_TUN) {
278				warnx("oid '%s' is a read only tunable%s", bufp, line);
279				warnx("Tunable values are set in /boot/loader.conf");
280			} else
281				warnx("oid '%s' is read only%s", bufp, line);
282			return (1);
283		}
284
285		if ((kind & CTLTYPE) == CTLTYPE_INT ||
286		    (kind & CTLTYPE) == CTLTYPE_UINT ||
287		    (kind & CTLTYPE) == CTLTYPE_LONG ||
288		    (kind & CTLTYPE) == CTLTYPE_ULONG ||
289		    (kind & CTLTYPE) == CTLTYPE_S64 ||
290		    (kind & CTLTYPE) == CTLTYPE_U64) {
291			if (strlen(newval) == 0) {
292				warnx("empty numeric value");
293				return (1);
294			}
295		}
296
297		switch (kind & CTLTYPE) {
298			case CTLTYPE_INT:
299				if (strcmp(fmt, "IK") == 0) {
300					if (!set_IK(newval, &intval)) {
301						warnx("invalid value '%s'%s",
302						    (char *)newval, line);
303						return (1);
304					}
305 				} else {
306					intval = (int)strtol(newval, &endptr,
307					    0);
308					if (endptr == newval || *endptr != '\0') {
309						warnx("invalid integer '%s'%s",
310						    (char *)newval, line);
311						return (1);
312					}
313				}
314				newval = &intval;
315				newsize = sizeof(intval);
316				break;
317			case CTLTYPE_UINT:
318				uintval = (int) strtoul(newval, &endptr, 0);
319				if (endptr == newval || *endptr != '\0') {
320					warnx("invalid unsigned integer '%s'%s",
321					    (char *)newval, line);
322					return (1);
323				}
324				newval = &uintval;
325				newsize = sizeof(uintval);
326				break;
327			case CTLTYPE_LONG:
328				longval = strtol(newval, &endptr, 0);
329				if (endptr == newval || *endptr != '\0') {
330					warnx("invalid long integer '%s'%s",
331					    (char *)newval, line);
332					return (1);
333				}
334				newval = &longval;
335				newsize = sizeof(longval);
336				break;
337			case CTLTYPE_ULONG:
338				ulongval = strtoul(newval, &endptr, 0);
339				if (endptr == newval || *endptr != '\0') {
340					warnx("invalid unsigned long integer"
341					    " '%s'%s", (char *)newval, line);
342					return (1);
343				}
344				newval = &ulongval;
345				newsize = sizeof(ulongval);
346				break;
347			case CTLTYPE_STRING:
348				break;
349			case CTLTYPE_S64:
350				i64val = strtoimax(newval, &endptr, 0);
351				if (endptr == newval || *endptr != '\0') {
352					warnx("invalid int64_t '%s'%s",
353					    (char *)newval, line);
354					return (1);
355				}
356				newval = &i64val;
357				newsize = sizeof(i64val);
358				break;
359			case CTLTYPE_U64:
360				u64val = strtoumax(newval, &endptr, 0);
361				if (endptr == newval || *endptr != '\0') {
362					warnx("invalid uint64_t '%s'%s",
363					    (char *)newval, line);
364					return (1);
365				}
366				newval = &u64val;
367				newsize = sizeof(u64val);
368				break;
369			case CTLTYPE_OPAQUE:
370				/* FALLTHROUGH */
371			default:
372				warnx("oid '%s' is type %d,"
373					" cannot set that%s", bufp,
374					kind & CTLTYPE, line);
375				return (1);
376		}
377
378		i = show_var(mib, len);
379		if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
380			if (!i && !bflag)
381				putchar('\n');
382			switch (errno) {
383			case EOPNOTSUPP:
384				warnx("%s: value is not available%s",
385					string, line);
386				return (1);
387			case ENOTDIR:
388				warnx("%s: specification is incomplete%s",
389					string, line);
390				return (1);
391			case ENOMEM:
392				warnx("%s: type is unknown to this program%s",
393					string, line);
394				return (1);
395			default:
396				warn("%s%s", string, line);
397				return (1);
398			}
399		}
400		if (!bflag)
401			printf(" -> ");
402		i = nflag;
403		nflag = 1;
404		j = show_var(mib, len);
405		if (!j && !bflag)
406			putchar('\n');
407		nflag = i;
408	}
409
410	return (0);
411}
412
413static int
414parsefile(const char *filename)
415{
416	FILE *file;
417	char line[BUFSIZ], *p, *pq, *pdq;
418	int warncount = 0, lineno = 0;
419
420	file = fopen(filename, "r");
421	if (file == NULL)
422		err(EX_NOINPUT, "%s", filename);
423	while (fgets(line, sizeof(line), file) != NULL) {
424		lineno++;
425		p = line;
426		pq = strchr(line, '\'');
427		pdq = strchr(line, '\"');
428		/* Replace the first # with \0. */
429		while((p = strchr(p, '#')) != NULL) {
430			if (pq != NULL && p > pq) {
431				if ((p = strchr(pq+1, '\'')) != NULL)
432					*(++p) = '\0';
433				break;
434			} else if (pdq != NULL && p > pdq) {
435				if ((p = strchr(pdq+1, '\"')) != NULL)
436					*(++p) = '\0';
437				break;
438			} else if (p == line || *(p-1) != '\\') {
439				*p = '\0';
440				break;
441			}
442			p++;
443		}
444		/* Trim spaces */
445		p = line + strlen(line) - 1;
446		while (p >= line && isspace((int)*p)) {
447			*p = '\0';
448			p--;
449		}
450		p = line;
451		while (isspace((int)*p))
452			p++;
453		if (*p == '\0')
454			continue;
455		else
456			warncount += parse(p, lineno);
457	}
458	fclose(file);
459
460	return (warncount);
461}
462
463/* These functions will dump out various interesting structures. */
464
465static int
466S_clockinfo(size_t l2, void *p)
467{
468	struct clockinfo *ci = (struct clockinfo*)p;
469
470	if (l2 != sizeof(*ci)) {
471		warnx("S_clockinfo %zu != %zu", l2, sizeof(*ci));
472		return (1);
473	}
474	printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
475		"{ hz = %d, tick = %d, profhz = %d, stathz = %d }",
476		ci->hz, ci->tick, ci->profhz, ci->stathz);
477	return (0);
478}
479
480static int
481S_loadavg(size_t l2, void *p)
482{
483	struct loadavg *tv = (struct loadavg*)p;
484
485	if (l2 != sizeof(*tv)) {
486		warnx("S_loadavg %zu != %zu", l2, sizeof(*tv));
487		return (1);
488	}
489	printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
490		(double)tv->ldavg[0]/(double)tv->fscale,
491		(double)tv->ldavg[1]/(double)tv->fscale,
492		(double)tv->ldavg[2]/(double)tv->fscale);
493	return (0);
494}
495
496static int
497S_timeval(size_t l2, void *p)
498{
499	struct timeval *tv = (struct timeval*)p;
500	time_t tv_sec;
501	char *p1, *p2;
502
503	if (l2 != sizeof(*tv)) {
504		warnx("S_timeval %zu != %zu", l2, sizeof(*tv));
505		return (1);
506	}
507	printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
508		"{ sec = %jd, usec = %ld } ",
509		(intmax_t)tv->tv_sec, tv->tv_usec);
510	tv_sec = tv->tv_sec;
511	p1 = strdup(ctime(&tv_sec));
512	for (p2=p1; *p2 ; p2++)
513		if (*p2 == '\n')
514			*p2 = '\0';
515	fputs(p1, stdout);
516	free(p1);
517	return (0);
518}
519
520static int
521S_vmtotal(size_t l2, void *p)
522{
523	struct vmtotal *v = (struct vmtotal *)p;
524	int pageKilo = getpagesize() / 1024;
525
526	if (l2 != sizeof(*v)) {
527		warnx("S_vmtotal %zu != %zu", l2, sizeof(*v));
528		return (1);
529	}
530
531	printf(
532	    "\nSystem wide totals computed every five seconds:"
533	    " (values in kilobytes)\n");
534	printf("===============================================\n");
535	printf(
536	    "Processes:\t\t(RUNQ: %hd Disk Wait: %hd Page Wait: "
537	    "%hd Sleep: %hd)\n",
538	    v->t_rq, v->t_dw, v->t_pw, v->t_sl);
539	printf(
540	    "Virtual Memory:\t\t(Total: %dK Active: %dK)\n",
541	    v->t_vm * pageKilo, v->t_avm * pageKilo);
542	printf("Real Memory:\t\t(Total: %dK Active: %dK)\n",
543	    v->t_rm * pageKilo, v->t_arm * pageKilo);
544	printf("Shared Virtual Memory:\t(Total: %dK Active: %dK)\n",
545	    v->t_vmshr * pageKilo, v->t_avmshr * pageKilo);
546	printf("Shared Real Memory:\t(Total: %dK Active: %dK)\n",
547	    v->t_rmshr * pageKilo, v->t_armshr * pageKilo);
548	printf("Free Memory:\t%dK", v->t_free * pageKilo);
549
550	return (0);
551}
552
553#ifdef __amd64__
554#define efi_next_descriptor(ptr, size) \
555	((struct efi_md *)(((uint8_t *) ptr) + size))
556
557static int
558S_efi_map(size_t l2, void *p)
559{
560	struct efi_map_header *efihdr;
561	struct efi_md *map;
562	const char *type;
563	size_t efisz;
564	int ndesc, i;
565
566	static const char *types[] = {
567		"Reserved",
568		"LoaderCode",
569		"LoaderData",
570		"BootServicesCode",
571		"BootServicesData",
572		"RuntimeServicesCode",
573		"RuntimeServicesData",
574		"ConventionalMemory",
575		"UnusableMemory",
576		"ACPIReclaimMemory",
577		"ACPIMemoryNVS",
578		"MemoryMappedIO",
579		"MemoryMappedIOPortSpace",
580		"PalCode"
581	};
582
583	/*
584	 * Memory map data provided by UEFI via the GetMemoryMap
585	 * Boot Services API.
586	 */
587	if (l2 < sizeof(*efihdr)) {
588		warnx("S_efi_map length less than header");
589		return (1);
590	}
591	efihdr = p;
592	efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
593	map = (struct efi_md *)((uint8_t *)efihdr + efisz);
594
595	if (efihdr->descriptor_size == 0)
596		return (0);
597	if (l2 != efisz + efihdr->memory_size) {
598		warnx("S_efi_map length mismatch %zu vs %zu", l2, efisz +
599		    efihdr->memory_size);
600		return (1);
601	}
602	ndesc = efihdr->memory_size / efihdr->descriptor_size;
603
604	printf("\n%23s %12s %12s %8s %4s",
605	    "Type", "Physical", "Virtual", "#Pages", "Attr");
606
607	for (i = 0; i < ndesc; i++,
608	    map = efi_next_descriptor(map, efihdr->descriptor_size)) {
609		if (map->md_type <= EFI_MD_TYPE_PALCODE)
610			type = types[map->md_type];
611		else
612			type = "<INVALID>";
613		printf("\n%23s %012lx %12p %08lx ", type, map->md_phys,
614		    map->md_virt, map->md_pages);
615		if (map->md_attr & EFI_MD_ATTR_UC)
616			printf("UC ");
617		if (map->md_attr & EFI_MD_ATTR_WC)
618			printf("WC ");
619		if (map->md_attr & EFI_MD_ATTR_WT)
620			printf("WT ");
621		if (map->md_attr & EFI_MD_ATTR_WB)
622			printf("WB ");
623		if (map->md_attr & EFI_MD_ATTR_UCE)
624			printf("UCE ");
625		if (map->md_attr & EFI_MD_ATTR_WP)
626			printf("WP ");
627		if (map->md_attr & EFI_MD_ATTR_RP)
628			printf("RP ");
629		if (map->md_attr & EFI_MD_ATTR_XP)
630			printf("XP ");
631		if (map->md_attr & EFI_MD_ATTR_RT)
632			printf("RUNTIME");
633	}
634	return (0);
635}
636#endif
637
638#if defined(__amd64__) || defined(__i386__)
639static int
640S_bios_smap_xattr(size_t l2, void *p)
641{
642	struct bios_smap_xattr *smap, *end;
643
644	if (l2 % sizeof(*smap) != 0) {
645		warnx("S_bios_smap_xattr %zu is not a multiple of %zu", l2,
646		    sizeof(*smap));
647		return (1);
648	}
649
650	end = (struct bios_smap_xattr *)((char *)p + l2);
651	for (smap = p; smap < end; smap++)
652		printf("\nSMAP type=%02x, xattr=%02x, base=%016jx, len=%016jx",
653		    smap->type, smap->xattr, (uintmax_t)smap->base,
654		    (uintmax_t)smap->length);
655	return (0);
656}
657#endif
658
659static int
660set_IK(const char *str, int *val)
661{
662	float temp;
663	int len, kelv;
664	const char *p;
665	char *endptr;
666
667	if ((len = strlen(str)) == 0)
668		return (0);
669	p = &str[len - 1];
670	if (*p == 'C' || *p == 'F') {
671		temp = strtof(str, &endptr);
672		if (endptr == str || endptr != p)
673			return (0);
674		if (*p == 'F')
675			temp = (temp - 32) * 5 / 9;
676		kelv = temp * 10 + 2732;
677	} else {
678		kelv = (int)strtol(str, &endptr, 10);
679		if (endptr == str || *endptr != '\0')
680			return (0);
681	}
682	*val = kelv;
683	return (1);
684}
685
686/*
687 * These functions uses a presently undocumented interface to the kernel
688 * to walk the tree and get the type so it can print the value.
689 * This interface is under work and consideration, and should probably
690 * be killed with a big axe by the first person who can find the time.
691 * (be aware though, that the proper interface isn't as obvious as it
692 * may seem, there are various conflicting requirements.
693 */
694
695static int
696name2oid(char *name, int *oidp)
697{
698	int oid[2];
699	int i;
700	size_t j;
701
702	oid[0] = 0;
703	oid[1] = 3;
704
705	j = CTL_MAXNAME * sizeof(int);
706	i = sysctl(oid, 2, oidp, &j, name, strlen(name));
707	if (i < 0)
708		return (i);
709	j /= sizeof(int);
710	return (j);
711}
712
713static int
714oidfmt(int *oid, int len, char *fmt, u_int *kind)
715{
716	int qoid[CTL_MAXNAME+2];
717	u_char buf[BUFSIZ];
718	int i;
719	size_t j;
720
721	qoid[0] = 0;
722	qoid[1] = 4;
723	memcpy(qoid + 2, oid, len * sizeof(int));
724
725	j = sizeof(buf);
726	i = sysctl(qoid, len + 2, buf, &j, 0, 0);
727	if (i)
728		err(1, "sysctl fmt %d %zu %d", i, j, errno);
729
730	if (kind)
731		*kind = *(u_int *)buf;
732
733	if (fmt)
734		strcpy(fmt, (char *)(buf + sizeof(u_int)));
735	return (0);
736}
737
738static int ctl_sign[CTLTYPE+1] = {
739	[CTLTYPE_INT] = 1,
740	[CTLTYPE_LONG] = 1,
741	[CTLTYPE_S64] = 1,
742};
743
744static int ctl_size[CTLTYPE+1] = {
745	[CTLTYPE_INT] = sizeof(int),
746	[CTLTYPE_UINT] = sizeof(u_int),
747	[CTLTYPE_LONG] = sizeof(long),
748	[CTLTYPE_ULONG] = sizeof(u_long),
749	[CTLTYPE_S64] = sizeof(int64_t),
750	[CTLTYPE_U64] = sizeof(int64_t),
751};
752
753/*
754 * This formats and outputs the value of one variable
755 *
756 * Returns zero if anything was actually output.
757 * Returns one if didn't know what to do with this.
758 * Return minus one if we had errors.
759 */
760static int
761show_var(int *oid, int nlen)
762{
763	u_char buf[BUFSIZ], *val, *oval, *p;
764	char name[BUFSIZ], fmt[BUFSIZ];
765	const char *sep, *sep1;
766	int qoid[CTL_MAXNAME+2];
767	uintmax_t umv;
768	intmax_t mv;
769	int i, hexlen, sign, ctltype;
770	size_t intlen;
771	size_t j, len;
772	u_int kind;
773	int (*func)(size_t, void *);
774
775	/* Silence GCC. */
776	umv = mv = intlen = 0;
777
778	bzero(buf, BUFSIZ);
779	bzero(fmt, BUFSIZ);
780	bzero(name, BUFSIZ);
781	qoid[0] = 0;
782	memcpy(qoid + 2, oid, nlen * sizeof(int));
783
784	qoid[1] = 1;
785	j = sizeof(name);
786	i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
787	if (i || !j)
788		err(1, "sysctl name %d %zu %d", i, j, errno);
789
790	oidfmt(oid, nlen, fmt, &kind);
791	/* if Wflag then only list sysctls that are writeable and not stats. */
792	if (Wflag && ((kind & CTLFLAG_WR) == 0 || (kind & CTLFLAG_STATS) != 0))
793		return 1;
794
795	/* if Tflag then only list sysctls that are tuneables. */
796	if (Tflag && (kind & CTLFLAG_TUN) == 0)
797		return 1;
798
799	if (Nflag) {
800		printf("%s", name);
801		return (0);
802	}
803
804	if (eflag)
805		sep = "=";
806	else
807		sep = ": ";
808
809	if (dflag) {	/* just print description */
810		qoid[1] = 5;
811		j = sizeof(buf);
812		i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
813		if (!nflag)
814			printf("%s%s", name, sep);
815		printf("%s", buf);
816		return (0);
817	}
818	/* find an estimate of how much we need for this var */
819	j = 0;
820	i = sysctl(oid, nlen, 0, &j, 0, 0);
821	j += j; /* we want to be sure :-) */
822
823	val = oval = malloc(j + 1);
824	if (val == NULL) {
825		warnx("malloc failed");
826		return (1);
827	}
828	ctltype = (kind & CTLTYPE);
829	len = j;
830	i = sysctl(oid, nlen, val, &len, 0, 0);
831	if (i != 0 || (len == 0 && ctltype != CTLTYPE_STRING)) {
832		free(oval);
833		return (1);
834	}
835
836	if (bflag) {
837		fwrite(val, 1, len, stdout);
838		free(oval);
839		return (0);
840	}
841	val[len] = '\0';
842	p = val;
843	sign = ctl_sign[ctltype];
844	intlen = ctl_size[ctltype];
845
846	switch (ctltype) {
847	case CTLTYPE_STRING:
848		if (!nflag)
849			printf("%s%s", name, sep);
850		printf("%.*s", (int)len, p);
851		free(oval);
852		return (0);
853
854	case CTLTYPE_INT:
855	case CTLTYPE_UINT:
856	case CTLTYPE_LONG:
857	case CTLTYPE_ULONG:
858	case CTLTYPE_S64:
859	case CTLTYPE_U64:
860		if (!nflag)
861			printf("%s%s", name, sep);
862		hexlen = 2 + (intlen * CHAR_BIT + 3) / 4;
863		sep1 = "";
864		while (len >= intlen) {
865			switch (kind & CTLTYPE) {
866			case CTLTYPE_INT:
867			case CTLTYPE_UINT:
868				umv = *(u_int *)p;
869				mv = *(int *)p;
870				break;
871			case CTLTYPE_LONG:
872			case CTLTYPE_ULONG:
873				umv = *(u_long *)p;
874				mv = *(long *)p;
875				break;
876			case CTLTYPE_S64:
877			case CTLTYPE_U64:
878				umv = *(uint64_t *)p;
879				mv = *(int64_t *)p;
880				break;
881			}
882			fputs(sep1, stdout);
883			if (xflag)
884				printf("%#0*jx", hexlen, umv);
885			else if (!sign)
886				printf(hflag ? "%'ju" : "%ju", umv);
887			else if (fmt[1] == 'K') {
888				if (mv < 0)
889					printf("%jd", mv);
890				else
891					printf("%.1fC", (mv - 2732.0) / 10);
892			} else
893				printf(hflag ? "%'jd" : "%jd", mv);
894			sep1 = " ";
895			len -= intlen;
896			p += intlen;
897		}
898		free(oval);
899		return (0);
900
901	case CTLTYPE_OPAQUE:
902		i = 0;
903		if (strcmp(fmt, "S,clockinfo") == 0)
904			func = S_clockinfo;
905		else if (strcmp(fmt, "S,timeval") == 0)
906			func = S_timeval;
907		else if (strcmp(fmt, "S,loadavg") == 0)
908			func = S_loadavg;
909		else if (strcmp(fmt, "S,vmtotal") == 0)
910			func = S_vmtotal;
911#ifdef __amd64__
912		else if (strcmp(fmt, "S,efi_map_header") == 0)
913			func = S_efi_map;
914#endif
915#if defined(__amd64__) || defined(__i386__)
916		else if (strcmp(fmt, "S,bios_smap_xattr") == 0)
917			func = S_bios_smap_xattr;
918#endif
919		else
920			func = NULL;
921		if (func) {
922			if (!nflag)
923				printf("%s%s", name, sep);
924			i = (*func)(len, p);
925			free(oval);
926			return (i);
927		}
928		/* FALLTHROUGH */
929	default:
930		if (!oflag && !xflag) {
931			free(oval);
932			return (1);
933		}
934		if (!nflag)
935			printf("%s%s", name, sep);
936		printf("Format:%s Length:%zu Dump:0x", fmt, len);
937		while (len-- && (xflag || p < val + 16))
938			printf("%02x", *p++);
939		if (!xflag && len > 16)
940			printf("...");
941		free(oval);
942		return (0);
943	}
944	free(oval);
945	return (1);
946}
947
948static int
949sysctl_all(int *oid, int len)
950{
951	int name1[22], name2[22];
952	int i, j;
953	size_t l1, l2;
954
955	name1[0] = 0;
956	name1[1] = 2;
957	l1 = 2;
958	if (len) {
959		memcpy(name1+2, oid, len * sizeof(int));
960		l1 += len;
961	} else {
962		name1[2] = 1;
963		l1++;
964	}
965	for (;;) {
966		l2 = sizeof(name2);
967		j = sysctl(name1, l1, name2, &l2, 0, 0);
968		if (j < 0) {
969			if (errno == ENOENT)
970				return (0);
971			else
972				err(1, "sysctl(getnext) %d %zu", j, l2);
973		}
974
975		l2 /= sizeof(int);
976
977		if (len < 0 || l2 < (unsigned int)len)
978			return (0);
979
980		for (i = 0; i < len; i++)
981			if (name2[i] != oid[i])
982				return (0);
983
984		i = show_var(name2, l2);
985		if (!i && !bflag)
986			putchar('\n');
987
988		memcpy(name1+2, name2, l2 * sizeof(int));
989		l1 = 2 + l2;
990	}
991}
992