sysctl.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 4. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#ifndef lint
33static const char copyright[] =
34"@(#) Copyright (c) 1993\n\
35	The Regents of the University of California.  All rights reserved.\n";
36#endif /* not lint */
37
38#ifndef lint
39#if 0
40static char sccsid[] = "@(#)from: sysctl.c	8.1 (Berkeley) 6/6/93";
41#endif
42static const char rcsid[] =
43  "$FreeBSD: stable/11/sbin/sysctl/sysctl.c 330897 2018-03-14 03:19:51Z eadler $";
44#endif /* not lint */
45
46#include <sys/param.h>
47#include <sys/time.h>
48#include <sys/resource.h>
49#include <sys/stat.h>
50#include <sys/sysctl.h>
51#include <sys/vmmeter.h>
52
53#ifdef __amd64__
54#include <sys/efi.h>
55#include <machine/metadata.h>
56#endif
57
58#if defined(__amd64__) || defined(__i386__)
59#include <machine/pc/bios.h>
60#endif
61
62#include <assert.h>
63#include <ctype.h>
64#include <err.h>
65#include <errno.h>
66#include <inttypes.h>
67#include <locale.h>
68#include <stdio.h>
69#include <stdlib.h>
70#include <string.h>
71#include <sysexits.h>
72#include <unistd.h>
73
74static const char *conffile;
75
76static int	aflag, bflag, Bflag, dflag, eflag, hflag, iflag;
77static int	Nflag, nflag, oflag, qflag, tflag, Tflag, Wflag, xflag;
78
79static int	oidfmt(int *, int, char *, u_int *);
80static int	parsefile(const char *);
81static int	parse(const char *, int);
82static int	show_var(int *, int);
83static int	sysctl_all(int *oid, int len);
84static int	name2oid(const char *, int *);
85
86static int	strIKtoi(const char *, char **, const char *);
87
88static int ctl_sign[CTLTYPE+1] = {
89	[CTLTYPE_INT] = 1,
90	[CTLTYPE_LONG] = 1,
91	[CTLTYPE_S8] = 1,
92	[CTLTYPE_S16] = 1,
93	[CTLTYPE_S32] = 1,
94	[CTLTYPE_S64] = 1,
95};
96
97static int ctl_size[CTLTYPE+1] = {
98	[CTLTYPE_INT] = sizeof(int),
99	[CTLTYPE_UINT] = sizeof(u_int),
100	[CTLTYPE_LONG] = sizeof(long),
101	[CTLTYPE_ULONG] = sizeof(u_long),
102	[CTLTYPE_S8] = sizeof(int8_t),
103	[CTLTYPE_S16] = sizeof(int16_t),
104	[CTLTYPE_S32] = sizeof(int32_t),
105	[CTLTYPE_S64] = sizeof(int64_t),
106	[CTLTYPE_U8] = sizeof(uint8_t),
107	[CTLTYPE_U16] = sizeof(uint16_t),
108	[CTLTYPE_U32] = sizeof(uint32_t),
109	[CTLTYPE_U64] = sizeof(uint64_t),
110};
111
112static const char *ctl_typename[CTLTYPE+1] = {
113	[CTLTYPE_INT] = "integer",
114	[CTLTYPE_UINT] = "unsigned integer",
115	[CTLTYPE_LONG] = "long integer",
116	[CTLTYPE_ULONG] = "unsigned long",
117	[CTLTYPE_U8] = "uint8_t",
118	[CTLTYPE_U16] = "uint16_t",
119	[CTLTYPE_U32] = "uint32_t",
120	[CTLTYPE_U64] = "uint64_t",
121	[CTLTYPE_S8] = "int8_t",
122	[CTLTYPE_S16] = "int16_t",
123	[CTLTYPE_S32] = "int32_t",
124	[CTLTYPE_S64] = "int64_t",
125	[CTLTYPE_NODE] = "node",
126	[CTLTYPE_STRING] = "string",
127	[CTLTYPE_OPAQUE] = "opaque",
128};
129
130static void
131usage(void)
132{
133
134	(void)fprintf(stderr, "%s\n%s\n",
135	    "usage: sysctl [-bdehiNnoqTtWx] [ -B <bufsize> ] [-f filename] name[=value] ...",
136	    "       sysctl [-bdehNnoqTtWx] [ -B <bufsize> ] -a");
137	exit(1);
138}
139
140int
141main(int argc, char **argv)
142{
143	int ch;
144	int warncount = 0;
145
146	setlocale(LC_NUMERIC, "");
147	setbuf(stdout,0);
148	setbuf(stderr,0);
149
150	while ((ch = getopt(argc, argv, "AabB:def:hiNnoqtTwWxX")) != -1) {
151		switch (ch) {
152		case 'A':
153			/* compatibility */
154			aflag = oflag = 1;
155			break;
156		case 'a':
157			aflag = 1;
158			break;
159		case 'b':
160			bflag = 1;
161			break;
162		case 'B':
163			Bflag = strtol(optarg, NULL, 0);
164			break;
165		case 'd':
166			dflag = 1;
167			break;
168		case 'e':
169			eflag = 1;
170			break;
171		case 'f':
172			conffile = optarg;
173			break;
174		case 'h':
175			hflag = 1;
176			break;
177		case 'i':
178			iflag = 1;
179			break;
180		case 'N':
181			Nflag = 1;
182			break;
183		case 'n':
184			nflag = 1;
185			break;
186		case 'o':
187			oflag = 1;
188			break;
189		case 'q':
190			qflag = 1;
191			break;
192		case 't':
193			tflag = 1;
194			break;
195		case 'T':
196			Tflag = 1;
197			break;
198		case 'w':
199			/* compatibility */
200			/* ignored */
201			break;
202		case 'W':
203			Wflag = 1;
204			break;
205		case 'X':
206			/* compatibility */
207			aflag = xflag = 1;
208			break;
209		case 'x':
210			xflag = 1;
211			break;
212		default:
213			usage();
214		}
215	}
216	argc -= optind;
217	argv += optind;
218
219	if (Nflag && nflag)
220		usage();
221	if (aflag && argc == 0)
222		exit(sysctl_all(0, 0));
223	if (argc == 0 && conffile == NULL)
224		usage();
225
226	warncount = 0;
227	if (conffile != NULL)
228		warncount += parsefile(conffile);
229
230	while (argc-- > 0)
231		warncount += parse(*argv++, 0);
232
233	return (warncount);
234}
235
236/*
237 * Parse a name into a MIB entry.
238 * Lookup and print out the MIB entry if it exists.
239 * Set a new value if requested.
240 */
241static int
242parse(const char *string, int lineno)
243{
244	int len, i, j;
245	const void *newval;
246	const char *newvalstr = NULL;
247	int8_t i8val;
248	uint8_t u8val;
249	int16_t i16val;
250	uint16_t u16val;
251	int32_t i32val;
252	uint32_t u32val;
253	int intval;
254	unsigned int uintval;
255	long longval;
256	unsigned long ulongval;
257	size_t newsize = Bflag;
258	int64_t i64val;
259	uint64_t u64val;
260	int mib[CTL_MAXNAME];
261	char *cp, *bufp, buf[BUFSIZ], *endptr = NULL, fmt[BUFSIZ], line[BUFSIZ];
262	u_int kind;
263
264	if (lineno)
265		snprintf(line, sizeof(line), " at line %d", lineno);
266	else
267		line[0] = '\0';
268
269	cp = buf;
270	if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) {
271		warnx("oid too long: '%s'%s", string, line);
272		return (1);
273	}
274	bufp = strsep(&cp, "=:");
275	if (cp != NULL) {
276		/* Tflag just lists tunables, do not allow assignment */
277		if (Tflag || Wflag) {
278			warnx("Can't set variables when using -T or -W");
279			usage();
280		}
281		while (isspace(*cp))
282			cp++;
283		/* Strip a pair of " or ' if any. */
284		switch (*cp) {
285		case '\"':
286		case '\'':
287			if (cp[strlen(cp) - 1] == *cp)
288				cp[strlen(cp) - 1] = '\0';
289			cp++;
290		}
291		newvalstr = cp;
292		newsize = strlen(cp);
293	}
294	/* Trim spaces */
295	cp = bufp + strlen(bufp) - 1;
296	while (cp >= bufp && isspace((int)*cp)) {
297		*cp = '\0';
298		cp--;
299	}
300	len = name2oid(bufp, mib);
301
302	if (len < 0) {
303		if (iflag)
304			return (0);
305		if (qflag)
306			return (1);
307		else {
308			if (errno == ENOENT) {
309				warnx("unknown oid '%s'%s", bufp, line);
310			} else {
311				warn("unknown oid '%s'%s", bufp, line);
312			}
313			return (1);
314		}
315	}
316
317	if (oidfmt(mib, len, fmt, &kind)) {
318		warn("couldn't find format of oid '%s'%s", bufp, line);
319		if (iflag)
320			return (1);
321		else
322			exit(1);
323	}
324
325	if (newvalstr == NULL || dflag) {
326		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
327			if (dflag) {
328				i = show_var(mib, len);
329				if (!i && !bflag)
330					putchar('\n');
331			}
332			sysctl_all(mib, len);
333		} else {
334			i = show_var(mib, len);
335			if (!i && !bflag)
336				putchar('\n');
337		}
338	} else {
339		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
340			warnx("oid '%s' isn't a leaf node%s", bufp, line);
341			return (1);
342		}
343
344		if (!(kind & CTLFLAG_WR)) {
345			if (kind & CTLFLAG_TUN) {
346				warnx("oid '%s' is a read only tunable%s", bufp, line);
347				warnx("Tunable values are set in /boot/loader.conf");
348			} else
349				warnx("oid '%s' is read only%s", bufp, line);
350			return (1);
351		}
352
353		switch (kind & CTLTYPE) {
354		case CTLTYPE_INT:
355		case CTLTYPE_UINT:
356		case CTLTYPE_LONG:
357		case CTLTYPE_ULONG:
358		case CTLTYPE_S8:
359		case CTLTYPE_S16:
360		case CTLTYPE_S32:
361		case CTLTYPE_S64:
362		case CTLTYPE_U8:
363		case CTLTYPE_U16:
364		case CTLTYPE_U32:
365		case CTLTYPE_U64:
366			if (strlen(newvalstr) == 0) {
367				warnx("empty numeric value");
368				return (1);
369			}
370			/* FALLTHROUGH */
371		case CTLTYPE_STRING:
372			break;
373		default:
374			warnx("oid '%s' is type %d,"
375				" cannot set that%s", bufp,
376				kind & CTLTYPE, line);
377			return (1);
378		}
379
380		errno = 0;
381
382		switch (kind & CTLTYPE) {
383			case CTLTYPE_INT:
384				if (strncmp(fmt, "IK", 2) == 0)
385					intval = strIKtoi(newvalstr, &endptr, fmt);
386				else
387					intval = (int)strtol(newvalstr, &endptr,
388					    0);
389				newval = &intval;
390				newsize = sizeof(intval);
391				break;
392			case CTLTYPE_UINT:
393				uintval = (int) strtoul(newvalstr, &endptr, 0);
394				newval = &uintval;
395				newsize = sizeof(uintval);
396				break;
397			case CTLTYPE_LONG:
398				longval = strtol(newvalstr, &endptr, 0);
399				newval = &longval;
400				newsize = sizeof(longval);
401				break;
402			case CTLTYPE_ULONG:
403				ulongval = strtoul(newvalstr, &endptr, 0);
404				newval = &ulongval;
405				newsize = sizeof(ulongval);
406				break;
407			case CTLTYPE_STRING:
408				newval = newvalstr;
409				break;
410			case CTLTYPE_S8:
411				i8val = (int8_t)strtol(newvalstr, &endptr, 0);
412				newval = &i8val;
413				newsize = sizeof(i8val);
414				break;
415			case CTLTYPE_S16:
416				i16val = (int16_t)strtol(newvalstr, &endptr,
417				    0);
418				newval = &i16val;
419				newsize = sizeof(i16val);
420				break;
421			case CTLTYPE_S32:
422				i32val = (int32_t)strtol(newvalstr, &endptr,
423				    0);
424				newval = &i32val;
425				newsize = sizeof(i32val);
426				break;
427			case CTLTYPE_S64:
428				i64val = strtoimax(newvalstr, &endptr, 0);
429				newval = &i64val;
430				newsize = sizeof(i64val);
431				break;
432			case CTLTYPE_U8:
433				u8val = (uint8_t)strtoul(newvalstr, &endptr, 0);
434				newval = &u8val;
435				newsize = sizeof(u8val);
436				break;
437			case CTLTYPE_U16:
438				u16val = (uint16_t)strtoul(newvalstr, &endptr,
439				    0);
440				newval = &u16val;
441				newsize = sizeof(u16val);
442				break;
443			case CTLTYPE_U32:
444				u32val = (uint32_t)strtoul(newvalstr, &endptr,
445				    0);
446				newval = &u32val;
447				newsize = sizeof(u32val);
448				break;
449			case CTLTYPE_U64:
450				u64val = strtoumax(newvalstr, &endptr, 0);
451				newval = &u64val;
452				newsize = sizeof(u64val);
453				break;
454			default:
455				/* NOTREACHED */
456				abort();
457		}
458
459		if (errno != 0 || endptr == newvalstr ||
460		    (endptr != NULL && *endptr != '\0')) {
461			warnx("invalid %s '%s'%s", ctl_typename[kind & CTLTYPE],
462			    newvalstr, line);
463			return (1);
464		}
465
466		i = show_var(mib, len);
467		if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
468			if (!i && !bflag)
469				putchar('\n');
470			switch (errno) {
471			case EOPNOTSUPP:
472				warnx("%s: value is not available%s",
473					string, line);
474				return (1);
475			case ENOTDIR:
476				warnx("%s: specification is incomplete%s",
477					string, line);
478				return (1);
479			case ENOMEM:
480				warnx("%s: type is unknown to this program%s",
481					string, line);
482				return (1);
483			default:
484				warn("%s%s", string, line);
485				return (1);
486			}
487		}
488		if (!bflag)
489			printf(" -> ");
490		i = nflag;
491		nflag = 1;
492		j = show_var(mib, len);
493		if (!j && !bflag)
494			putchar('\n');
495		nflag = i;
496	}
497
498	return (0);
499}
500
501static int
502parsefile(const char *filename)
503{
504	FILE *file;
505	char line[BUFSIZ], *p, *pq, *pdq;
506	int warncount = 0, lineno = 0;
507
508	file = fopen(filename, "r");
509	if (file == NULL)
510		err(EX_NOINPUT, "%s", filename);
511	while (fgets(line, sizeof(line), file) != NULL) {
512		lineno++;
513		p = line;
514		pq = strchr(line, '\'');
515		pdq = strchr(line, '\"');
516		/* Replace the first # with \0. */
517		while((p = strchr(p, '#')) != NULL) {
518			if (pq != NULL && p > pq) {
519				if ((p = strchr(pq+1, '\'')) != NULL)
520					*(++p) = '\0';
521				break;
522			} else if (pdq != NULL && p > pdq) {
523				if ((p = strchr(pdq+1, '\"')) != NULL)
524					*(++p) = '\0';
525				break;
526			} else if (p == line || *(p-1) != '\\') {
527				*p = '\0';
528				break;
529			}
530			p++;
531		}
532		/* Trim spaces */
533		p = line + strlen(line) - 1;
534		while (p >= line && isspace((int)*p)) {
535			*p = '\0';
536			p--;
537		}
538		p = line;
539		while (isspace((int)*p))
540			p++;
541		if (*p == '\0')
542			continue;
543		else
544			warncount += parse(p, lineno);
545	}
546	fclose(file);
547
548	return (warncount);
549}
550
551/* These functions will dump out various interesting structures. */
552
553static int
554S_clockinfo(size_t l2, void *p)
555{
556	struct clockinfo *ci = (struct clockinfo*)p;
557
558	if (l2 != sizeof(*ci)) {
559		warnx("S_clockinfo %zu != %zu", l2, sizeof(*ci));
560		return (1);
561	}
562	printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
563		"{ hz = %d, tick = %d, profhz = %d, stathz = %d }",
564		ci->hz, ci->tick, ci->profhz, ci->stathz);
565	return (0);
566}
567
568static int
569S_loadavg(size_t l2, void *p)
570{
571	struct loadavg *tv = (struct loadavg*)p;
572
573	if (l2 != sizeof(*tv)) {
574		warnx("S_loadavg %zu != %zu", l2, sizeof(*tv));
575		return (1);
576	}
577	printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
578		(double)tv->ldavg[0]/(double)tv->fscale,
579		(double)tv->ldavg[1]/(double)tv->fscale,
580		(double)tv->ldavg[2]/(double)tv->fscale);
581	return (0);
582}
583
584static int
585S_timeval(size_t l2, void *p)
586{
587	struct timeval *tv = (struct timeval*)p;
588	time_t tv_sec;
589	char *p1, *p2;
590
591	if (l2 != sizeof(*tv)) {
592		warnx("S_timeval %zu != %zu", l2, sizeof(*tv));
593		return (1);
594	}
595	printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
596		"{ sec = %jd, usec = %ld } ",
597		(intmax_t)tv->tv_sec, tv->tv_usec);
598	tv_sec = tv->tv_sec;
599	p1 = strdup(ctime(&tv_sec));
600	for (p2=p1; *p2 ; p2++)
601		if (*p2 == '\n')
602			*p2 = '\0';
603	fputs(p1, stdout);
604	free(p1);
605	return (0);
606}
607
608static int
609S_vmtotal(size_t l2, void *p)
610{
611	struct vmtotal *v = (struct vmtotal *)p;
612	int pageKilo = getpagesize() / 1024;
613
614	if (l2 != sizeof(*v)) {
615		warnx("S_vmtotal %zu != %zu", l2, sizeof(*v));
616		return (1);
617	}
618
619	printf(
620	    "\nSystem wide totals computed every five seconds:"
621	    " (values in kilobytes)\n");
622	printf("===============================================\n");
623	printf(
624	    "Processes:\t\t(RUNQ: %hd Disk Wait: %hd Page Wait: "
625	    "%hd Sleep: %hd)\n",
626	    v->t_rq, v->t_dw, v->t_pw, v->t_sl);
627	printf(
628	    "Virtual Memory:\t\t(Total: %jdK Active: %jdK)\n",
629	    (intmax_t)v->t_vm * pageKilo, (intmax_t)v->t_avm * pageKilo);
630	printf("Real Memory:\t\t(Total: %jdK Active: %jdK)\n",
631	    (intmax_t)v->t_rm * pageKilo, (intmax_t)v->t_arm * pageKilo);
632	printf("Shared Virtual Memory:\t(Total: %jdK Active: %jdK)\n",
633	    (intmax_t)v->t_vmshr * pageKilo, (intmax_t)v->t_avmshr * pageKilo);
634	printf("Shared Real Memory:\t(Total: %jdK Active: %jdK)\n",
635	    (intmax_t)v->t_rmshr * pageKilo, (intmax_t)v->t_armshr * pageKilo);
636	printf("Free Memory:\t%jdK", (intmax_t)v->t_free * pageKilo);
637
638	return (0);
639}
640
641#ifdef __amd64__
642static int
643S_efi_map(size_t l2, void *p)
644{
645	struct efi_map_header *efihdr;
646	struct efi_md *map;
647	const char *type;
648	size_t efisz;
649	int ndesc, i;
650
651	static const char *types[] = {
652		"Reserved",
653		"LoaderCode",
654		"LoaderData",
655		"BootServicesCode",
656		"BootServicesData",
657		"RuntimeServicesCode",
658		"RuntimeServicesData",
659		"ConventionalMemory",
660		"UnusableMemory",
661		"ACPIReclaimMemory",
662		"ACPIMemoryNVS",
663		"MemoryMappedIO",
664		"MemoryMappedIOPortSpace",
665		"PalCode"
666	};
667
668	/*
669	 * Memory map data provided by UEFI via the GetMemoryMap
670	 * Boot Services API.
671	 */
672	if (l2 < sizeof(*efihdr)) {
673		warnx("S_efi_map length less than header");
674		return (1);
675	}
676	efihdr = p;
677	efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
678	map = (struct efi_md *)((uint8_t *)efihdr + efisz);
679
680	if (efihdr->descriptor_size == 0)
681		return (0);
682	if (l2 != efisz + efihdr->memory_size) {
683		warnx("S_efi_map length mismatch %zu vs %zu", l2, efisz +
684		    efihdr->memory_size);
685		return (1);
686	}
687	ndesc = efihdr->memory_size / efihdr->descriptor_size;
688
689	printf("\n%23s %12s %12s %8s %4s",
690	    "Type", "Physical", "Virtual", "#Pages", "Attr");
691
692	for (i = 0; i < ndesc; i++,
693	    map = efi_next_descriptor(map, efihdr->descriptor_size)) {
694		if (map->md_type <= EFI_MD_TYPE_PALCODE)
695			type = types[map->md_type];
696		else
697			type = "<INVALID>";
698		printf("\n%23s %012lx %12p %08lx ", type, map->md_phys,
699		    map->md_virt, map->md_pages);
700		if (map->md_attr & EFI_MD_ATTR_UC)
701			printf("UC ");
702		if (map->md_attr & EFI_MD_ATTR_WC)
703			printf("WC ");
704		if (map->md_attr & EFI_MD_ATTR_WT)
705			printf("WT ");
706		if (map->md_attr & EFI_MD_ATTR_WB)
707			printf("WB ");
708		if (map->md_attr & EFI_MD_ATTR_UCE)
709			printf("UCE ");
710		if (map->md_attr & EFI_MD_ATTR_WP)
711			printf("WP ");
712		if (map->md_attr & EFI_MD_ATTR_RP)
713			printf("RP ");
714		if (map->md_attr & EFI_MD_ATTR_XP)
715			printf("XP ");
716		if (map->md_attr & EFI_MD_ATTR_RT)
717			printf("RUNTIME");
718	}
719	return (0);
720}
721#endif
722
723#if defined(__amd64__) || defined(__i386__)
724static int
725S_bios_smap_xattr(size_t l2, void *p)
726{
727	struct bios_smap_xattr *smap, *end;
728
729	if (l2 % sizeof(*smap) != 0) {
730		warnx("S_bios_smap_xattr %zu is not a multiple of %zu", l2,
731		    sizeof(*smap));
732		return (1);
733	}
734
735	end = (struct bios_smap_xattr *)((char *)p + l2);
736	for (smap = p; smap < end; smap++)
737		printf("\nSMAP type=%02x, xattr=%02x, base=%016jx, len=%016jx",
738		    smap->type, smap->xattr, (uintmax_t)smap->base,
739		    (uintmax_t)smap->length);
740	return (0);
741}
742#endif
743
744static int
745strIKtoi(const char *str, char **endptrp, const char *fmt)
746{
747	int kelv;
748	float temp;
749	size_t len;
750	const char *p;
751	int prec, i;
752
753	assert(errno == 0);
754
755	len = strlen(str);
756	/* caller already checked this */
757	assert(len > 0);
758
759	/*
760	 * A format of "IK" is in deciKelvin. A format of "IK3" is in
761	 * milliKelvin. The single digit following IK is log10 of the
762	 * multiplying factor to convert Kelvin into the untis of this sysctl,
763	 * or the dividing factor to convert the sysctl value to Kelvin. Numbers
764	 * larger than 6 will run into precision issues with 32-bit integers.
765	 * Characters that aren't ASCII digits after the 'K' are ignored. No
766	 * localization is present because this is an interface from the kernel
767	 * to this program (eg not an end-user interface), so isdigit() isn't
768	 * used here.
769	 */
770	if (fmt[2] != '\0' && fmt[2] >= '0' && fmt[2] <= '9')
771		prec = fmt[2] - '0';
772	else
773		prec = 1;
774	p = &str[len - 1];
775	if (*p == 'C' || *p == 'F' || *p == 'K') {
776		temp = strtof(str, endptrp);
777		if (*endptrp != str && *endptrp == p && errno == 0) {
778			if (*p == 'F')
779				temp = (temp - 32) * 5 / 9;
780			*endptrp = NULL;
781			if (*p != 'K')
782				temp += 273.15;
783			for (i = 0; i < prec; i++)
784				temp *= 10.0;
785			return ((int)(temp + 0.5));
786		}
787	} else {
788		/* No unit specified -> treat it as a raw number */
789		kelv = (int)strtol(str, endptrp, 10);
790		if (*endptrp != str && *endptrp == p && errno == 0) {
791			*endptrp = NULL;
792			return (kelv);
793		}
794	}
795
796	errno = ERANGE;
797	return (0);
798}
799
800/*
801 * These functions uses a presently undocumented interface to the kernel
802 * to walk the tree and get the type so it can print the value.
803 * This interface is under work and consideration, and should probably
804 * be killed with a big axe by the first person who can find the time.
805 * (be aware though, that the proper interface isn't as obvious as it
806 * may seem, there are various conflicting requirements.
807 */
808
809static int
810name2oid(const char *name, int *oidp)
811{
812	int oid[2];
813	int i;
814	size_t j;
815
816	oid[0] = 0;
817	oid[1] = 3;
818
819	j = CTL_MAXNAME * sizeof(int);
820	i = sysctl(oid, 2, oidp, &j, name, strlen(name));
821	if (i < 0)
822		return (i);
823	j /= sizeof(int);
824	return (j);
825}
826
827static int
828oidfmt(int *oid, int len, char *fmt, u_int *kind)
829{
830	int qoid[CTL_MAXNAME+2];
831	u_char buf[BUFSIZ];
832	int i;
833	size_t j;
834
835	qoid[0] = 0;
836	qoid[1] = 4;
837	memcpy(qoid + 2, oid, len * sizeof(int));
838
839	j = sizeof(buf);
840	i = sysctl(qoid, len + 2, buf, &j, 0, 0);
841	if (i)
842		err(1, "sysctl fmt %d %zu %d", i, j, errno);
843
844	if (kind)
845		*kind = *(u_int *)buf;
846
847	if (fmt)
848		strcpy(fmt, (char *)(buf + sizeof(u_int)));
849	return (0);
850}
851
852/*
853 * This formats and outputs the value of one variable
854 *
855 * Returns zero if anything was actually output.
856 * Returns one if didn't know what to do with this.
857 * Return minus one if we had errors.
858 */
859static int
860show_var(int *oid, int nlen)
861{
862	u_char buf[BUFSIZ], *val, *oval, *p;
863	char name[BUFSIZ], fmt[BUFSIZ];
864	const char *sep, *sep1, *prntype;
865	int qoid[CTL_MAXNAME+2];
866	uintmax_t umv;
867	intmax_t mv;
868	int i, hexlen, sign, ctltype;
869	size_t intlen;
870	size_t j, len;
871	u_int kind;
872	float base;
873	int (*func)(size_t, void *);
874	int prec;
875
876	/* Silence GCC. */
877	umv = mv = intlen = 0;
878
879	bzero(buf, BUFSIZ);
880	bzero(fmt, BUFSIZ);
881	bzero(name, BUFSIZ);
882	qoid[0] = 0;
883	memcpy(qoid + 2, oid, nlen * sizeof(int));
884
885	qoid[1] = 1;
886	j = sizeof(name);
887	i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
888	if (i || !j)
889		err(1, "sysctl name %d %zu %d", i, j, errno);
890
891	oidfmt(oid, nlen, fmt, &kind);
892	/* if Wflag then only list sysctls that are writeable and not stats. */
893	if (Wflag && ((kind & CTLFLAG_WR) == 0 || (kind & CTLFLAG_STATS) != 0))
894		return 1;
895
896	/* if Tflag then only list sysctls that are tuneables. */
897	if (Tflag && (kind & CTLFLAG_TUN) == 0)
898		return 1;
899
900	if (Nflag) {
901		printf("%s", name);
902		return (0);
903	}
904
905	if (eflag)
906		sep = "=";
907	else
908		sep = ": ";
909
910	ctltype = (kind & CTLTYPE);
911	if (tflag || dflag) {
912		if (!nflag)
913			printf("%s%s", name, sep);
914        	if (ctl_typename[ctltype] != NULL)
915            		prntype = ctl_typename[ctltype];
916        	else
917            		prntype = "unknown";
918		if (tflag && dflag)
919			printf("%s%s", prntype, sep);
920		else if (tflag) {
921			printf("%s", prntype);
922			return (0);
923		}
924		qoid[1] = 5;
925		j = sizeof(buf);
926		i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
927		printf("%s", buf);
928		return (0);
929	}
930	/* find an estimate of how much we need for this var */
931	if (Bflag)
932		j = Bflag;
933	else {
934		j = 0;
935		i = sysctl(oid, nlen, 0, &j, 0, 0);
936		j += j; /* we want to be sure :-) */
937	}
938
939	val = oval = malloc(j + 1);
940	if (val == NULL) {
941		warnx("malloc failed");
942		return (1);
943	}
944	len = j;
945	i = sysctl(oid, nlen, val, &len, 0, 0);
946	if (i != 0 || (len == 0 && ctltype != CTLTYPE_STRING)) {
947		free(oval);
948		return (1);
949	}
950
951	if (bflag) {
952		fwrite(val, 1, len, stdout);
953		free(oval);
954		return (0);
955	}
956	val[len] = '\0';
957	p = val;
958	sign = ctl_sign[ctltype];
959	intlen = ctl_size[ctltype];
960
961	switch (ctltype) {
962	case CTLTYPE_STRING:
963		if (!nflag)
964			printf("%s%s", name, sep);
965		printf("%.*s", (int)len, p);
966		free(oval);
967		return (0);
968
969	case CTLTYPE_INT:
970	case CTLTYPE_UINT:
971	case CTLTYPE_LONG:
972	case CTLTYPE_ULONG:
973	case CTLTYPE_S8:
974	case CTLTYPE_S16:
975	case CTLTYPE_S32:
976	case CTLTYPE_S64:
977	case CTLTYPE_U8:
978	case CTLTYPE_U16:
979	case CTLTYPE_U32:
980	case CTLTYPE_U64:
981		if (!nflag)
982			printf("%s%s", name, sep);
983		hexlen = 2 + (intlen * CHAR_BIT + 3) / 4;
984		sep1 = "";
985		while (len >= intlen) {
986			switch (kind & CTLTYPE) {
987			case CTLTYPE_INT:
988			case CTLTYPE_UINT:
989				umv = *(u_int *)p;
990				mv = *(int *)p;
991				break;
992			case CTLTYPE_LONG:
993			case CTLTYPE_ULONG:
994				umv = *(u_long *)p;
995				mv = *(long *)p;
996				break;
997			case CTLTYPE_S8:
998			case CTLTYPE_U8:
999				umv = *(uint8_t *)p;
1000				mv = *(int8_t *)p;
1001				break;
1002			case CTLTYPE_S16:
1003			case CTLTYPE_U16:
1004				umv = *(uint16_t *)p;
1005				mv = *(int16_t *)p;
1006				break;
1007			case CTLTYPE_S32:
1008			case CTLTYPE_U32:
1009				umv = *(uint32_t *)p;
1010				mv = *(int32_t *)p;
1011				break;
1012			case CTLTYPE_S64:
1013			case CTLTYPE_U64:
1014				umv = *(uint64_t *)p;
1015				mv = *(int64_t *)p;
1016				break;
1017			}
1018			fputs(sep1, stdout);
1019			if (xflag)
1020				printf("%#0*jx", hexlen, umv);
1021			else if (!sign)
1022				printf(hflag ? "%'ju" : "%ju", umv);
1023			else if (fmt[1] == 'K') {
1024				if (mv < 0)
1025					printf("%jd", mv);
1026				else {
1027					/*
1028					 * See strIKtoi for details on fmt.
1029					 */
1030					prec = 1;
1031					if (fmt[2] != '\0')
1032						prec = fmt[2] - '0';
1033					base = 1.0;
1034					for (int i = 0; i < prec; i++)
1035						base *= 10.0;
1036					printf("%.*fC", prec,
1037					    (float)mv / base - 273.15);
1038				}
1039			} else
1040				printf(hflag ? "%'jd" : "%jd", mv);
1041			sep1 = " ";
1042			len -= intlen;
1043			p += intlen;
1044		}
1045		free(oval);
1046		return (0);
1047
1048	case CTLTYPE_OPAQUE:
1049		i = 0;
1050		if (strcmp(fmt, "S,clockinfo") == 0)
1051			func = S_clockinfo;
1052		else if (strcmp(fmt, "S,timeval") == 0)
1053			func = S_timeval;
1054		else if (strcmp(fmt, "S,loadavg") == 0)
1055			func = S_loadavg;
1056		else if (strcmp(fmt, "S,vmtotal") == 0)
1057			func = S_vmtotal;
1058#ifdef __amd64__
1059		else if (strcmp(fmt, "S,efi_map_header") == 0)
1060			func = S_efi_map;
1061#endif
1062#if defined(__amd64__) || defined(__i386__)
1063		else if (strcmp(fmt, "S,bios_smap_xattr") == 0)
1064			func = S_bios_smap_xattr;
1065#endif
1066		else
1067			func = NULL;
1068		if (func) {
1069			if (!nflag)
1070				printf("%s%s", name, sep);
1071			i = (*func)(len, p);
1072			free(oval);
1073			return (i);
1074		}
1075		/* FALLTHROUGH */
1076	default:
1077		if (!oflag && !xflag) {
1078			free(oval);
1079			return (1);
1080		}
1081		if (!nflag)
1082			printf("%s%s", name, sep);
1083		printf("Format:%s Length:%zu Dump:0x", fmt, len);
1084		while (len-- && (xflag || p < val + 16))
1085			printf("%02x", *p++);
1086		if (!xflag && len > 16)
1087			printf("...");
1088		free(oval);
1089		return (0);
1090	}
1091	free(oval);
1092	return (1);
1093}
1094
1095static int
1096sysctl_all(int *oid, int len)
1097{
1098	int name1[22], name2[22];
1099	int i, j;
1100	size_t l1, l2;
1101
1102	name1[0] = 0;
1103	name1[1] = 2;
1104	l1 = 2;
1105	if (len) {
1106		memcpy(name1+2, oid, len * sizeof(int));
1107		l1 += len;
1108	} else {
1109		name1[2] = 1;
1110		l1++;
1111	}
1112	for (;;) {
1113		l2 = sizeof(name2);
1114		j = sysctl(name1, l1, name2, &l2, 0, 0);
1115		if (j < 0) {
1116			if (errno == ENOENT)
1117				return (0);
1118			else
1119				err(1, "sysctl(getnext) %d %zu", j, l2);
1120		}
1121
1122		l2 /= sizeof(int);
1123
1124		if (len < 0 || l2 < (unsigned int)len)
1125			return (0);
1126
1127		for (i = 0; i < len; i++)
1128			if (name2[i] != oid[i])
1129				return (0);
1130
1131		i = show_var(name2, l2);
1132		if (!i && !bflag)
1133			putchar('\n');
1134
1135		memcpy(name1+2, name2, l2 * sizeof(int));
1136		l1 = 2 + l2;
1137	}
1138}
1139