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 * 3. 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#include <sys/param.h>
33#include <sys/time.h>
34#include <sys/resource.h>
35#include <sys/stat.h>
36#include <sys/sysctl.h>
37#include <sys/vmmeter.h>
38#include <dev/evdev/input.h>
39
40#ifdef __amd64__
41#include <sys/efi.h>
42#include <machine/metadata.h>
43#endif
44
45#if defined(__amd64__) || defined(__i386__)
46#include <machine/pc/bios.h>
47#endif
48
49#include <assert.h>
50#include <ctype.h>
51#include <err.h>
52#include <errno.h>
53#include <inttypes.h>
54#include <locale.h>
55#include <stdbool.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59#include <sysexits.h>
60#include <unistd.h>
61
62static const char *conffile;
63
64static int	aflag, bflag, Bflag, dflag, eflag, hflag, iflag;
65static int	Nflag, nflag, oflag, qflag, tflag, Tflag, Wflag, xflag;
66static bool	Fflag, lflag;
67
68static int	oidfmt(int *, int, char *, u_int *);
69static int	parsefile(const char *);
70static int	parse(const char *, int);
71static int	show_var(int *, int, bool);
72static int	sysctl_all(int *, int);
73static int	name2oid(const char *, int *);
74
75static int	strIKtoi(const char *, char **, const char *);
76
77static int ctl_sign[CTLTYPE+1] = {
78	[CTLTYPE_INT] = 1,
79	[CTLTYPE_LONG] = 1,
80	[CTLTYPE_S8] = 1,
81	[CTLTYPE_S16] = 1,
82	[CTLTYPE_S32] = 1,
83	[CTLTYPE_S64] = 1,
84};
85
86static int ctl_size[CTLTYPE+1] = {
87	[CTLTYPE_INT] = sizeof(int),
88	[CTLTYPE_UINT] = sizeof(u_int),
89	[CTLTYPE_LONG] = sizeof(long),
90	[CTLTYPE_ULONG] = sizeof(u_long),
91	[CTLTYPE_S8] = sizeof(int8_t),
92	[CTLTYPE_S16] = sizeof(int16_t),
93	[CTLTYPE_S32] = sizeof(int32_t),
94	[CTLTYPE_S64] = sizeof(int64_t),
95	[CTLTYPE_U8] = sizeof(uint8_t),
96	[CTLTYPE_U16] = sizeof(uint16_t),
97	[CTLTYPE_U32] = sizeof(uint32_t),
98	[CTLTYPE_U64] = sizeof(uint64_t),
99};
100
101static const char *ctl_typename[CTLTYPE+1] = {
102	[CTLTYPE_INT] = "integer",
103	[CTLTYPE_UINT] = "unsigned integer",
104	[CTLTYPE_LONG] = "long integer",
105	[CTLTYPE_ULONG] = "unsigned long",
106	[CTLTYPE_U8] = "uint8_t",
107	[CTLTYPE_U16] = "uint16_t",
108	[CTLTYPE_U32] = "uint32_t",
109	[CTLTYPE_U64] = "uint64_t",
110	[CTLTYPE_S8] = "int8_t",
111	[CTLTYPE_S16] = "int16_t",
112	[CTLTYPE_S32] = "int32_t",
113	[CTLTYPE_S64] = "int64_t",
114	[CTLTYPE_NODE] = "node",
115	[CTLTYPE_STRING] = "string",
116	[CTLTYPE_OPAQUE] = "opaque",
117};
118
119static void
120usage(void)
121{
122
123	(void)fprintf(stderr, "%s\n%s\n",
124	    "usage: sysctl [-bdeFhilNnoqTtWx] [ -B <bufsize> ] [-f filename] name[=value] ...",
125	    "       sysctl [-bdeFhlNnoqTtWx] [ -B <bufsize> ] -a");
126	exit(1);
127}
128
129int
130main(int argc, char **argv)
131{
132	int ch;
133	int warncount = 0;
134
135	setlocale(LC_NUMERIC, "");
136	setbuf(stdout,0);
137	setbuf(stderr,0);
138
139	while ((ch = getopt(argc, argv, "AabB:def:FhilNnoqtTwWxX")) != -1) {
140		switch (ch) {
141		case 'A':
142			/* compatibility */
143			aflag = oflag = 1;
144			break;
145		case 'a':
146			aflag = 1;
147			break;
148		case 'b':
149			bflag = 1;
150			break;
151		case 'B':
152			Bflag = strtol(optarg, NULL, 0);
153			break;
154		case 'd':
155			dflag = 1;
156			break;
157		case 'e':
158			eflag = 1;
159			break;
160		case 'f':
161			conffile = optarg;
162			break;
163		case 'F':
164			Fflag = true;
165			break;
166		case 'h':
167			hflag = 1;
168			break;
169		case 'i':
170			iflag = 1;
171			break;
172		case 'l':
173			lflag = true;
174			break;
175		case 'N':
176			Nflag = 1;
177			break;
178		case 'n':
179			nflag = 1;
180			break;
181		case 'o':
182			oflag = 1;
183			break;
184		case 'q':
185			qflag = 1;
186			break;
187		case 't':
188			tflag = 1;
189			break;
190		case 'T':
191			Tflag = 1;
192			break;
193		case 'w':
194			/* compatibility */
195			/* ignored */
196			break;
197		case 'W':
198			Wflag = 1;
199			break;
200		case 'X':
201			/* compatibility */
202			aflag = xflag = 1;
203			break;
204		case 'x':
205			xflag = 1;
206			break;
207		default:
208			usage();
209		}
210	}
211	argc -= optind;
212	argv += optind;
213
214	/* Nflag is name only and doesn't make sense to combine with these */
215	/* TODO: few other combinations do not make sense but come back later */
216	if (Nflag && (lflag || nflag))
217		usage();
218	if (aflag && argc == 0)
219		exit(sysctl_all(NULL, 0));
220	if (argc == 0 && conffile == NULL)
221		usage();
222
223	if (conffile != NULL)
224		warncount += parsefile(conffile);
225
226	while (argc-- > 0)
227		warncount += parse(*argv++, 0);
228
229	return (warncount);
230}
231
232/*
233 * Parse a single numeric value, append it to 'newbuf', and update
234 * 'newsize'.  Returns true if the value was parsed and false if the
235 * value was invalid.  Non-numeric types (strings) are handled
236 * directly in parse().
237 */
238static bool
239parse_numeric(const char *newvalstr, const char *fmt, u_int kind,
240    void **newbufp, size_t *newsizep)
241{
242	void *newbuf;
243	const void *newval;
244	int8_t i8val;
245	uint8_t u8val;
246	int16_t i16val;
247	uint16_t u16val;
248	int32_t i32val;
249	uint32_t u32val;
250	int intval;
251	unsigned int uintval;
252	long longval;
253	unsigned long ulongval;
254	int64_t i64val;
255	uint64_t u64val;
256	size_t valsize;
257	char *endptr = NULL;
258
259	errno = 0;
260
261	switch (kind & CTLTYPE) {
262	case CTLTYPE_INT:
263		if (strncmp(fmt, "IK", 2) == 0)
264			intval = strIKtoi(newvalstr, &endptr, fmt);
265		else
266			intval = (int)strtol(newvalstr, &endptr, 0);
267		newval = &intval;
268		valsize = sizeof(intval);
269		break;
270	case CTLTYPE_UINT:
271		uintval = (int) strtoul(newvalstr, &endptr, 0);
272		newval = &uintval;
273		valsize = sizeof(uintval);
274		break;
275	case CTLTYPE_LONG:
276		longval = strtol(newvalstr, &endptr, 0);
277		newval = &longval;
278		valsize = sizeof(longval);
279		break;
280	case CTLTYPE_ULONG:
281		ulongval = strtoul(newvalstr, &endptr, 0);
282		newval = &ulongval;
283		valsize = sizeof(ulongval);
284		break;
285	case CTLTYPE_S8:
286		i8val = (int8_t)strtol(newvalstr, &endptr, 0);
287		newval = &i8val;
288		valsize = sizeof(i8val);
289		break;
290	case CTLTYPE_S16:
291		i16val = (int16_t)strtol(newvalstr, &endptr, 0);
292		newval = &i16val;
293		valsize = sizeof(i16val);
294		break;
295	case CTLTYPE_S32:
296		i32val = (int32_t)strtol(newvalstr, &endptr, 0);
297		newval = &i32val;
298		valsize = sizeof(i32val);
299		break;
300	case CTLTYPE_S64:
301		i64val = strtoimax(newvalstr, &endptr, 0);
302		newval = &i64val;
303		valsize = sizeof(i64val);
304		break;
305	case CTLTYPE_U8:
306		u8val = (uint8_t)strtoul(newvalstr, &endptr, 0);
307		newval = &u8val;
308		valsize = sizeof(u8val);
309		break;
310	case CTLTYPE_U16:
311		u16val = (uint16_t)strtoul(newvalstr, &endptr, 0);
312		newval = &u16val;
313		valsize = sizeof(u16val);
314		break;
315	case CTLTYPE_U32:
316		u32val = (uint32_t)strtoul(newvalstr, &endptr, 0);
317		newval = &u32val;
318		valsize = sizeof(u32val);
319		break;
320	case CTLTYPE_U64:
321		u64val = strtoumax(newvalstr, &endptr, 0);
322		newval = &u64val;
323		valsize = sizeof(u64val);
324		break;
325	default:
326		/* NOTREACHED */
327		abort();
328	}
329
330	if (errno != 0 || endptr == newvalstr ||
331	    (endptr != NULL && *endptr != '\0'))
332		return (false);
333
334	newbuf = realloc(*newbufp, *newsizep + valsize);
335	if (newbuf == NULL)
336		err(1, "out of memory");
337	memcpy((char *)newbuf + *newsizep, newval, valsize);
338	*newbufp = newbuf;
339	*newsizep += valsize;
340
341	return (true);
342}
343
344/*
345 * Parse a name into a MIB entry.
346 * Lookup and print out the MIB entry if it exists.
347 * Set a new value if requested.
348 */
349static int
350parse(const char *string, int lineno)
351{
352	int len, i, j, save_errno;
353	const void *newval;
354	char *newvalstr = NULL;
355	void *newbuf;
356	size_t newsize = Bflag;
357	int mib[CTL_MAXNAME];
358	char *cp, *bufp, *buf, fmt[BUFSIZ], line[BUFSIZ];
359	u_int kind;
360
361	if (lineno)
362		snprintf(line, sizeof(line), " at line %d", lineno);
363	else
364		line[0] = '\0';
365
366	/*
367	 * Split the string into name and value.
368	 *
369	 * Either = or : may be used as the delimiter.
370	 * Whitespace surrounding the delimiter is trimmed.
371	 * Quotes around the value are stripped.
372	 */
373	cp = buf = strdup(string);
374	bufp = strsep(&cp, "=:");
375	if (cp != NULL) {
376		/* Tflag just lists tunables, do not allow assignment */
377		if (Tflag || Wflag) {
378			warnx("Can't set variables when using -T or -W");
379			usage();
380		}
381		/* Trim whitespace before the value. */
382		while (isspace(*cp))
383			cp++;
384		/* Strip a pair of " or ' if any. */
385		switch (*cp) {
386		case '\"':
387		case '\'':
388			if (cp[strlen(cp) - 1] == *cp)
389				cp[strlen(cp) - 1] = '\0';
390			cp++;
391		}
392		newvalstr = cp;
393		newsize = strlen(cp);
394	}
395	/* Trim whitespace after the name. */
396	cp = bufp + strlen(bufp) - 1;
397	while (cp >= bufp && isspace((int)*cp)) {
398		*cp = '\0';
399		cp--;
400	}
401
402	/*
403	 * Check the name is a useable oid.
404	 */
405	len = name2oid(bufp, mib);
406	if (len < 0) {
407		if (iflag) {
408			free(buf);
409			return (0);
410		}
411		if (!qflag) {
412			if (errno == ENOENT) {
413				warnx("unknown oid '%s'%s", bufp, line);
414			} else {
415				warn("unknown oid '%s'%s", bufp, line);
416			}
417		}
418		free(buf);
419		return (1);
420	}
421
422	if (oidfmt(mib, len, fmt, &kind)) {
423		warn("couldn't find format of oid '%s'%s", bufp, line);
424		free(buf);
425		if (iflag)
426			return (1);
427		else
428			exit(1);
429	}
430
431	/*
432	 * We have a useable oid to work with.  If there is no value given,
433	 * show the node and its children.  Otherwise, set the new value.
434	 */
435	if (newvalstr == NULL || dflag) {
436		free(buf);
437		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
438			if (dflag) {
439				i = show_var(mib, len, false);
440				if (!i && !bflag)
441					putchar('\n');
442			}
443			sysctl_all(mib, len);
444		} else {
445			i = show_var(mib, len, false);
446			if (!i && !bflag)
447				putchar('\n');
448		}
449		return (0);
450	}
451
452	/*
453	 * We have a new value to set.  Check its validity and parse if numeric.
454	 */
455	if ((kind & CTLTYPE) == CTLTYPE_NODE) {
456		warnx("oid '%s' isn't a leaf node%s", bufp, line);
457		free(buf);
458		return (1);
459	}
460
461	if (!(kind & CTLFLAG_WR)) {
462		if (kind & CTLFLAG_TUN) {
463			warnx("oid '%s' is a read only tunable%s", bufp, line);
464			warnx("Tunable values are set in /boot/loader.conf");
465		} else
466			warnx("oid '%s' is read only%s", bufp, line);
467		free(buf);
468		return (1);
469	}
470
471	switch (kind & CTLTYPE) {
472	case CTLTYPE_INT:
473	case CTLTYPE_UINT:
474	case CTLTYPE_LONG:
475	case CTLTYPE_ULONG:
476	case CTLTYPE_S8:
477	case CTLTYPE_S16:
478	case CTLTYPE_S32:
479	case CTLTYPE_S64:
480	case CTLTYPE_U8:
481	case CTLTYPE_U16:
482	case CTLTYPE_U32:
483	case CTLTYPE_U64:
484		if (strlen(newvalstr) == 0) {
485			warnx("empty numeric value");
486			free(buf);
487			return (1);
488		}
489		/* FALLTHROUGH */
490	case CTLTYPE_STRING:
491		break;
492	default:
493		warnx("oid '%s' is type %d, cannot set that%s",
494		    bufp, kind & CTLTYPE, line);
495		free(buf);
496		return (1);
497	}
498
499	newbuf = NULL;
500
501	switch (kind & CTLTYPE) {
502	case CTLTYPE_STRING:
503		newval = newvalstr;
504		break;
505	default:
506		newsize = 0;
507		while ((cp = strsep(&newvalstr, " ,")) != NULL) {
508			if (*cp == '\0')
509				continue;
510			if (!parse_numeric(cp, fmt, kind, &newbuf, &newsize)) {
511				warnx("invalid %s '%s'%s",
512				    ctl_typename[kind & CTLTYPE], cp, line);
513				free(newbuf);
514				free(buf);
515				return (1);
516			}
517		}
518		newval = newbuf;
519		break;
520	}
521
522	/*
523	 * Show the current value, then set and show the new value.
524	 */
525	i = show_var(mib, len, false);
526	if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
527		save_errno = errno;
528		free(newbuf);
529		free(buf);
530		if (!i && !bflag)
531			putchar('\n');
532		switch (save_errno) {
533		case EOPNOTSUPP:
534			warnx("%s: value is not available%s",
535			    string, line);
536			return (1);
537		case ENOTDIR:
538			warnx("%s: specification is incomplete%s",
539			    string, line);
540			return (1);
541		case ENOMEM:
542			warnx("%s: type is unknown to this program%s",
543			    string, line);
544			return (1);
545		default:
546			warnc(save_errno, "%s%s", string, line);
547			return (1);
548		}
549	}
550	free(newbuf);
551	free(buf);
552	if (!bflag)
553		printf(" -> ");
554	i = nflag;
555	nflag = 1;
556	j = show_var(mib, len, false);
557	if (!j && !bflag)
558		putchar('\n');
559	nflag = i;
560
561	return (0);
562}
563
564static int
565parsefile(const char *filename)
566{
567	FILE *file;
568	char line[BUFSIZ], *p, *pq, *pdq;
569	int warncount = 0, lineno = 0;
570
571	file = fopen(filename, "r");
572	if (file == NULL)
573		err(EX_NOINPUT, "%s", filename);
574	while (fgets(line, sizeof(line), file) != NULL) {
575		lineno++;
576		p = line;
577		pq = strchr(line, '\'');
578		pdq = strchr(line, '\"');
579		/* Replace the first # with \0. */
580		while((p = strchr(p, '#')) != NULL) {
581			if (pq != NULL && p > pq) {
582				if ((p = strchr(pq+1, '\'')) != NULL)
583					*(++p) = '\0';
584				break;
585			} else if (pdq != NULL && p > pdq) {
586				if ((p = strchr(pdq+1, '\"')) != NULL)
587					*(++p) = '\0';
588				break;
589			} else if (p == line || *(p-1) != '\\') {
590				*p = '\0';
591				break;
592			}
593			p++;
594		}
595		/* Trim spaces */
596		p = line + strlen(line) - 1;
597		while (p >= line && isspace((int)*p)) {
598			*p = '\0';
599			p--;
600		}
601		p = line;
602		while (isspace((int)*p))
603			p++;
604		if (*p == '\0')
605			continue;
606		else
607			warncount += parse(p, lineno);
608	}
609	fclose(file);
610
611	return (warncount);
612}
613
614/* These functions will dump out various interesting structures. */
615
616static int
617S_clockinfo(size_t l2, void *p)
618{
619	struct clockinfo *ci = (struct clockinfo*)p;
620
621	if (l2 != sizeof(*ci)) {
622		warnx("S_clockinfo %zu != %zu", l2, sizeof(*ci));
623		return (1);
624	}
625	printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
626		"{ hz = %d, tick = %d, profhz = %d, stathz = %d }",
627		ci->hz, ci->tick, ci->profhz, ci->stathz);
628	return (0);
629}
630
631static int
632S_loadavg(size_t l2, void *p)
633{
634	struct loadavg *tv = (struct loadavg*)p;
635
636	if (l2 != sizeof(*tv)) {
637		warnx("S_loadavg %zu != %zu", l2, sizeof(*tv));
638		return (1);
639	}
640	printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
641		(double)tv->ldavg[0]/(double)tv->fscale,
642		(double)tv->ldavg[1]/(double)tv->fscale,
643		(double)tv->ldavg[2]/(double)tv->fscale);
644	return (0);
645}
646
647static int
648S_timeval(size_t l2, void *p)
649{
650	struct timeval *tv = (struct timeval*)p;
651	time_t tv_sec;
652	char *p1, *p2;
653
654	if (l2 != sizeof(*tv)) {
655		warnx("S_timeval %zu != %zu", l2, sizeof(*tv));
656		return (1);
657	}
658	printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
659		"{ sec = %jd, usec = %ld } ",
660		(intmax_t)tv->tv_sec, tv->tv_usec);
661	tv_sec = tv->tv_sec;
662	p1 = strdup(ctime(&tv_sec));
663	for (p2=p1; *p2 ; p2++)
664		if (*p2 == '\n')
665			*p2 = '\0';
666	fputs(p1, stdout);
667	free(p1);
668	return (0);
669}
670
671static int
672S_vmtotal(size_t l2, void *p)
673{
674	struct vmtotal *v;
675	int pageKilo;
676
677	if (l2 != sizeof(*v)) {
678		warnx("S_vmtotal %zu != %zu", l2, sizeof(*v));
679		return (1);
680	}
681
682	v = p;
683	pageKilo = getpagesize() / 1024;
684
685#define	pg2k(a)	((uintmax_t)(a) * pageKilo)
686	printf("\nSystem wide totals computed every five seconds:"
687	    " (values in kilobytes)\n");
688	printf("===============================================\n");
689	printf("Processes:\t\t(RUNQ: %d Disk Wait: %d Page Wait: "
690	    "%d Sleep: %d)\n",
691	    v->t_rq, v->t_dw, v->t_pw, v->t_sl);
692	printf("Virtual Memory:\t\t(Total: %juK Active: %juK)\n",
693	    pg2k(v->t_vm), pg2k(v->t_avm));
694	printf("Real Memory:\t\t(Total: %juK Active: %juK)\n",
695	    pg2k(v->t_rm), pg2k(v->t_arm));
696	printf("Shared Virtual Memory:\t(Total: %juK Active: %juK)\n",
697	    pg2k(v->t_vmshr), pg2k(v->t_avmshr));
698	printf("Shared Real Memory:\t(Total: %juK Active: %juK)\n",
699	    pg2k(v->t_rmshr), pg2k(v->t_armshr));
700	printf("Free Memory:\t%juK", pg2k(v->t_free));
701	return (0);
702}
703
704static int
705S_input_id(size_t l2, void *p)
706{
707	struct input_id *id = p;
708
709	if (l2 != sizeof(*id)) {
710		warnx("S_input_id %zu != %zu", l2, sizeof(*id));
711		return (1);
712	}
713
714	printf("{ bustype = 0x%04x, vendor = 0x%04x, "
715	    "product = 0x%04x, version = 0x%04x }",
716	    id->bustype, id->vendor, id->product, id->version);
717	return (0);
718}
719
720static int
721S_pagesizes(size_t l2, void *p)
722{
723	char buf[256];
724	u_long *ps;
725	size_t l;
726	int i;
727
728	l = snprintf(buf, sizeof(buf), "{ ");
729	ps = p;
730	for (i = 0; i * sizeof(*ps) < l2 && ps[i] != 0 && l < sizeof(buf);
731	    i++) {
732		l += snprintf(&buf[l], sizeof(buf) - l,
733		    "%s%lu", i == 0 ? "" : ", ", ps[i]);
734	}
735	if (l < sizeof(buf))
736		(void)snprintf(&buf[l], sizeof(buf) - l, " }");
737
738	printf("%s", buf);
739
740	return (0);
741}
742
743#ifdef __amd64__
744static int
745S_efi_map(size_t l2, void *p)
746{
747	struct efi_map_header *efihdr;
748	struct efi_md *map;
749	const char *type;
750	size_t efisz;
751	int ndesc, i;
752
753	static const char * const types[] = {
754		[EFI_MD_TYPE_NULL] =	"Reserved",
755		[EFI_MD_TYPE_CODE] =	"LoaderCode",
756		[EFI_MD_TYPE_DATA] =	"LoaderData",
757		[EFI_MD_TYPE_BS_CODE] =	"BootServicesCode",
758		[EFI_MD_TYPE_BS_DATA] =	"BootServicesData",
759		[EFI_MD_TYPE_RT_CODE] =	"RuntimeServicesCode",
760		[EFI_MD_TYPE_RT_DATA] =	"RuntimeServicesData",
761		[EFI_MD_TYPE_FREE] =	"ConventionalMemory",
762		[EFI_MD_TYPE_BAD] =	"UnusableMemory",
763		[EFI_MD_TYPE_RECLAIM] =	"ACPIReclaimMemory",
764		[EFI_MD_TYPE_FIRMWARE] = "ACPIMemoryNVS",
765		[EFI_MD_TYPE_IOMEM] =	"MemoryMappedIO",
766		[EFI_MD_TYPE_IOPORT] =	"MemoryMappedIOPortSpace",
767		[EFI_MD_TYPE_PALCODE] =	"PalCode",
768		[EFI_MD_TYPE_PERSISTENT] = "PersistentMemory",
769	};
770
771	/*
772	 * Memory map data provided by UEFI via the GetMemoryMap
773	 * Boot Services API.
774	 */
775	if (l2 < sizeof(*efihdr)) {
776		warnx("S_efi_map length less than header");
777		return (1);
778	}
779	efihdr = p;
780	efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
781	map = (struct efi_md *)((uint8_t *)efihdr + efisz);
782
783	if (efihdr->descriptor_size == 0)
784		return (0);
785	if (l2 != efisz + efihdr->memory_size) {
786		warnx("S_efi_map length mismatch %zu vs %zu", l2, efisz +
787		    efihdr->memory_size);
788		return (1);
789	}
790	ndesc = efihdr->memory_size / efihdr->descriptor_size;
791
792	printf("\n%23s %12s %12s %8s %4s",
793	    "Type", "Physical", "Virtual", "#Pages", "Attr");
794
795	for (i = 0; i < ndesc; i++,
796	    map = efi_next_descriptor(map, efihdr->descriptor_size)) {
797		type = NULL;
798		if (map->md_type < nitems(types))
799			type = types[map->md_type];
800		if (type == NULL)
801			type = "<INVALID>";
802		printf("\n%23s %012jx %012jx %08jx ", type,
803		    (uintmax_t)map->md_phys, (uintmax_t)map->md_virt,
804		    (uintmax_t)map->md_pages);
805		if (map->md_attr & EFI_MD_ATTR_UC)
806			printf("UC ");
807		if (map->md_attr & EFI_MD_ATTR_WC)
808			printf("WC ");
809		if (map->md_attr & EFI_MD_ATTR_WT)
810			printf("WT ");
811		if (map->md_attr & EFI_MD_ATTR_WB)
812			printf("WB ");
813		if (map->md_attr & EFI_MD_ATTR_UCE)
814			printf("UCE ");
815		if (map->md_attr & EFI_MD_ATTR_WP)
816			printf("WP ");
817		if (map->md_attr & EFI_MD_ATTR_RP)
818			printf("RP ");
819		if (map->md_attr & EFI_MD_ATTR_XP)
820			printf("XP ");
821		if (map->md_attr & EFI_MD_ATTR_RT)
822			printf("RUNTIME");
823	}
824	return (0);
825}
826#endif
827
828#if defined(__amd64__) || defined(__i386__)
829static int
830S_bios_smap_xattr(size_t l2, void *p)
831{
832	struct bios_smap_xattr *smap, *end;
833
834	if (l2 % sizeof(*smap) != 0) {
835		warnx("S_bios_smap_xattr %zu is not a multiple of %zu", l2,
836		    sizeof(*smap));
837		return (1);
838	}
839
840	end = (struct bios_smap_xattr *)((char *)p + l2);
841	for (smap = p; smap < end; smap++)
842		printf("\nSMAP type=%02x, xattr=%02x, base=%016jx, len=%016jx",
843		    smap->type, smap->xattr, (uintmax_t)smap->base,
844		    (uintmax_t)smap->length);
845	return (0);
846}
847#endif
848
849static int
850strIKtoi(const char *str, char **endptrp, const char *fmt)
851{
852	int kelv;
853	float temp;
854	size_t len;
855	const char *p;
856	int prec, i;
857
858	assert(errno == 0);
859
860	len = strlen(str);
861	/* caller already checked this */
862	assert(len > 0);
863
864	/*
865	 * A format of "IK" is in deciKelvin. A format of "IK3" is in
866	 * milliKelvin. The single digit following IK is log10 of the
867	 * multiplying factor to convert Kelvin into the untis of this sysctl,
868	 * or the dividing factor to convert the sysctl value to Kelvin. Numbers
869	 * larger than 6 will run into precision issues with 32-bit integers.
870	 * Characters that aren't ASCII digits after the 'K' are ignored. No
871	 * localization is present because this is an interface from the kernel
872	 * to this program (eg not an end-user interface), so isdigit() isn't
873	 * used here.
874	 */
875	if (fmt[2] != '\0' && fmt[2] >= '0' && fmt[2] <= '9')
876		prec = fmt[2] - '0';
877	else
878		prec = 1;
879	p = &str[len - 1];
880	if (*p == 'C' || *p == 'F' || *p == 'K') {
881		temp = strtof(str, endptrp);
882		if (*endptrp != str && *endptrp == p && errno == 0) {
883			if (*p == 'F')
884				temp = (temp - 32) * 5 / 9;
885			*endptrp = NULL;
886			if (*p != 'K')
887				temp += 273.15;
888			for (i = 0; i < prec; i++)
889				temp *= 10.0;
890			return ((int)(temp + 0.5));
891		}
892	} else {
893		/* No unit specified -> treat it as a raw number */
894		kelv = (int)strtol(str, endptrp, 10);
895		if (*endptrp != str && *endptrp == p && errno == 0) {
896			*endptrp = NULL;
897			return (kelv);
898		}
899	}
900
901	errno = ERANGE;
902	return (0);
903}
904
905/*
906 * These functions uses a presently undocumented interface to the kernel
907 * to walk the tree and get the type so it can print the value.
908 * This interface is under work and consideration, and should probably
909 * be killed with a big axe by the first person who can find the time.
910 * (be aware though, that the proper interface isn't as obvious as it
911 * may seem, there are various conflicting requirements.
912 */
913
914static int
915name2oid(const char *name, int *oidp)
916{
917	int oid[2];
918	int i;
919	size_t j;
920
921	oid[0] = CTL_SYSCTL;
922	oid[1] = CTL_SYSCTL_NAME2OID;
923
924	j = CTL_MAXNAME * sizeof(int);
925	i = sysctl(oid, 2, oidp, &j, name, strlen(name));
926	if (i < 0)
927		return (i);
928	j /= sizeof(int);
929	return (j);
930}
931
932static int
933oidfmt(int *oid, int len, char *fmt, u_int *kind)
934{
935	int qoid[CTL_MAXNAME+2];
936	u_char buf[BUFSIZ];
937	int i;
938	size_t j;
939
940	qoid[0] = CTL_SYSCTL;
941	qoid[1] = CTL_SYSCTL_OIDFMT;
942	memcpy(qoid + 2, oid, len * sizeof(int));
943
944	j = sizeof(buf);
945	i = sysctl(qoid, len + 2, buf, &j, 0, 0);
946	if (i)
947		err(1, "sysctl fmt %d %zu %d", i, j, errno);
948
949	if (kind)
950		*kind = *(u_int *)buf;
951
952	if (fmt)
953		strcpy(fmt, (char *)(buf + sizeof(u_int)));
954	return (0);
955}
956
957/*
958 * This displays a combination of name, type, format, and/or description.
959 *
960 * Returns zero if anything was actually output.
961 * Returns one if there is an error.
962 */
963static int
964show_info(char *name, const char *sep, int ctltype, char *fmt, int *qoid, int nlen)
965{
966	u_char buf[BUFSIZ];
967	const char *prntype;
968	int error = 0, i;
969	size_t j;
970
971	if (!nflag)
972		printf("%s%s", name, sep);
973	if (tflag) {
974		if (ctl_typename[ctltype] != NULL)
975			prntype = ctl_typename[ctltype];
976		else {
977			prntype = "unknown";
978			error++;
979		}
980		if (Fflag || dflag)
981			printf("%s%s", prntype, sep);
982		else
983			fputs(prntype, stdout);
984	}
985	if (Fflag) {
986		if (!isprint(fmt[0])) /* Few codes doesn't have formats */
987			fmt = "";
988		if (dflag)
989			printf("%s%s", fmt, sep);
990		else
991			fputs(fmt, stdout);
992	}
993	if (!dflag)
994		return (error);
995
996	qoid[1] = CTL_SYSCTL_OIDDESCR;
997	bzero(buf, BUFSIZ);
998	j = sizeof(buf);
999	i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
1000	if (i < 0) {
1001		putchar('\n');
1002		return (1);
1003	}
1004	fputs(buf, stdout);
1005	return (error);
1006}
1007
1008/*
1009 * This formats and outputs the value of one variable
1010 *
1011 * Returns zero if anything was actually output.
1012 * Returns one if didn't know what to do with this.
1013 * Return minus one if we had errors.
1014 */
1015static int
1016show_var(int *oid, int nlen, bool honor_skip)
1017{
1018	static int skip_len = 0, skip_oid[CTL_MAXNAME];
1019	u_char *val, *oval, *p;
1020	char name[BUFSIZ], fmt[BUFSIZ];
1021	const char *sep, *sep1;
1022	int qoid[CTL_MAXNAME+2];
1023	uintmax_t umv;
1024	intmax_t mv;
1025	int i, hexlen, sign, ctltype;
1026	size_t intlen;
1027	size_t j, len;
1028	u_int kind;
1029	float base;
1030	int (*func)(size_t, void *);
1031	int prec;
1032
1033	/* Silence GCC. */
1034	umv = mv = intlen = 0;
1035
1036	bzero(fmt, BUFSIZ);
1037	bzero(name, BUFSIZ);
1038	qoid[0] = CTL_SYSCTL;
1039	qoid[1] = CTL_SYSCTL_NAME;
1040	memcpy(qoid + 2, oid, nlen * sizeof(int));
1041	j = sizeof(name);
1042	i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
1043	if (i || !j)
1044		err(1, "sysctl name %d %zu %d", i, j, errno);
1045
1046	oidfmt(oid, nlen, fmt, &kind);
1047	/* if Wflag then only list sysctls that are writeable and not stats. */
1048	if (Wflag && ((kind & CTLFLAG_WR) == 0 || (kind & CTLFLAG_STATS) != 0))
1049		return (1);
1050
1051	/* if Tflag then only list sysctls that are tuneables. */
1052	if (Tflag && (kind & CTLFLAG_TUN) == 0)
1053		return (1);
1054
1055	if (Nflag) {
1056		printf("%s", name);
1057		return (0);
1058	}
1059
1060	if (eflag)
1061		sep = "=";
1062	else
1063		sep = ": ";
1064
1065	ctltype = (kind & CTLTYPE);
1066	if (tflag || Fflag || dflag)
1067		return show_info(name, sep, ctltype, fmt, qoid, nlen);
1068
1069	/* keep track of encountered skip nodes, ignoring descendants */
1070	if ((skip_len == 0 || skip_len >= nlen * (int)sizeof(int)) &&
1071	    (kind & CTLFLAG_SKIP) != 0) {
1072		/* Save this oid so we can skip descendants. */
1073		skip_len = nlen * sizeof(int);
1074		memcpy(skip_oid, oid, skip_len);
1075	}
1076
1077	/* bail before fetching the value if we're honoring skip */
1078	if (honor_skip) {
1079		if (0 < skip_len && skip_len <= nlen * (int)sizeof(int) &&
1080		    memcmp(skip_oid, oid, skip_len) == 0)
1081			return (1);
1082		/* Not a skip node or descendant of a skip node. */
1083		skip_len = 0;
1084	}
1085
1086	/* don't fetch opaques that we don't know how to print */
1087	if (ctltype == CTLTYPE_OPAQUE) {
1088		if (strcmp(fmt, "S,clockinfo") == 0)
1089			func = S_clockinfo;
1090		else if (strcmp(fmt, "S,timeval") == 0)
1091			func = S_timeval;
1092		else if (strcmp(fmt, "S,loadavg") == 0)
1093			func = S_loadavg;
1094		else if (strcmp(fmt, "S,vmtotal") == 0)
1095			func = S_vmtotal;
1096		else if (strcmp(fmt, "S,input_id") == 0)
1097			func = S_input_id;
1098		else if (strcmp(fmt, "S,pagesizes") == 0)
1099			func = S_pagesizes;
1100#ifdef __amd64__
1101		else if (strcmp(fmt, "S,efi_map_header") == 0)
1102			func = S_efi_map;
1103#endif
1104#if defined(__amd64__) || defined(__i386__)
1105		else if (strcmp(fmt, "S,bios_smap_xattr") == 0)
1106			func = S_bios_smap_xattr;
1107#endif
1108		else {
1109			func = NULL;
1110			if (!bflag && !oflag && !xflag)
1111				return (1);
1112		}
1113	}
1114
1115	/* find an estimate of how much we need for this var */
1116	if (Bflag)
1117		j = Bflag;
1118	else {
1119		j = 0;
1120		i = sysctl(oid, nlen, 0, &j, 0, 0);
1121		j += j; /* we want to be sure :-) */
1122	}
1123
1124	val = oval = malloc(j + 1);
1125	if (val == NULL) {
1126		warnx("malloc failed");
1127		return (1);
1128	}
1129	len = j;
1130	i = sysctl(oid, nlen, val, &len, 0, 0);
1131	if (i != 0 || (len == 0 && ctltype != CTLTYPE_STRING)) {
1132		free(oval);
1133		return (1);
1134	}
1135
1136	if (bflag) {
1137		fwrite(val, 1, len, stdout);
1138		free(oval);
1139		return (0);
1140	}
1141	val[len] = '\0';
1142	p = val;
1143	sign = ctl_sign[ctltype];
1144	intlen = ctl_size[ctltype];
1145
1146	switch (ctltype) {
1147	case CTLTYPE_STRING:
1148		if (!nflag)
1149			printf("%s%s", name, sep);
1150		if (lflag)
1151			printf("%zd%s", len, sep);
1152		printf("%.*s", (int)len, p);
1153		free(oval);
1154		return (0);
1155
1156	case CTLTYPE_INT:
1157	case CTLTYPE_UINT:
1158	case CTLTYPE_LONG:
1159	case CTLTYPE_ULONG:
1160	case CTLTYPE_S8:
1161	case CTLTYPE_S16:
1162	case CTLTYPE_S32:
1163	case CTLTYPE_S64:
1164	case CTLTYPE_U8:
1165	case CTLTYPE_U16:
1166	case CTLTYPE_U32:
1167	case CTLTYPE_U64:
1168		if (!nflag)
1169			printf("%s%s", name, sep);
1170		if (lflag)
1171			printf("%zd%s", len, sep);
1172		hexlen = 2 + (intlen * CHAR_BIT + 3) / 4;
1173		sep1 = "";
1174		while (len >= intlen) {
1175			switch (kind & CTLTYPE) {
1176			case CTLTYPE_INT:
1177			case CTLTYPE_UINT:
1178				umv = *(u_int *)p;
1179				mv = *(int *)p;
1180				break;
1181			case CTLTYPE_LONG:
1182			case CTLTYPE_ULONG:
1183				umv = *(u_long *)p;
1184				mv = *(long *)p;
1185				break;
1186			case CTLTYPE_S8:
1187			case CTLTYPE_U8:
1188				umv = *(uint8_t *)p;
1189				mv = *(int8_t *)p;
1190				break;
1191			case CTLTYPE_S16:
1192			case CTLTYPE_U16:
1193				umv = *(uint16_t *)p;
1194				mv = *(int16_t *)p;
1195				break;
1196			case CTLTYPE_S32:
1197			case CTLTYPE_U32:
1198				umv = *(uint32_t *)p;
1199				mv = *(int32_t *)p;
1200				break;
1201			case CTLTYPE_S64:
1202			case CTLTYPE_U64:
1203				umv = *(uint64_t *)p;
1204				mv = *(int64_t *)p;
1205				break;
1206			}
1207			fputs(sep1, stdout);
1208			if (xflag)
1209				printf("%#0*jx", hexlen, umv);
1210			else if (!sign)
1211				printf(hflag ? "%'ju" : "%ju", umv);
1212			else if (fmt[1] == 'K') {
1213				if (mv < 0)
1214					printf("%jd", mv);
1215				else {
1216					/*
1217					 * See strIKtoi for details on fmt.
1218					 */
1219					prec = 1;
1220					if (fmt[2] != '\0')
1221						prec = fmt[2] - '0';
1222					base = 1.0;
1223					for (int i = 0; i < prec; i++)
1224						base *= 10.0;
1225					printf("%.*fC", prec,
1226					    (float)mv / base - 273.15);
1227				}
1228			} else
1229				printf(hflag ? "%'jd" : "%jd", mv);
1230			sep1 = " ";
1231			len -= intlen;
1232			p += intlen;
1233		}
1234		free(oval);
1235		return (0);
1236
1237	case CTLTYPE_OPAQUE:
1238		i = 0;
1239		if (func) {
1240			if (!nflag)
1241				printf("%s%s", name, sep);
1242			if (lflag)
1243				printf("%zd%s", len, sep);
1244			i = (*func)(len, p);
1245			free(oval);
1246			return (i);
1247		}
1248		/* FALLTHROUGH */
1249	default:
1250		if (!oflag && !xflag) {
1251			free(oval);
1252			return (1);
1253		}
1254		if (!nflag)
1255			printf("%s%s", name, sep);
1256		if (lflag)
1257			printf("%zd%s", len, sep);
1258		printf("Format:%s Length:%zu Dump:0x", fmt, len);
1259		while (len-- && (xflag || p < val + 16))
1260			printf("%02x", *p++);
1261		if (!xflag && len > 16)
1262			printf("...");
1263		free(oval);
1264		return (0);
1265	}
1266	free(oval);
1267	return (1);
1268}
1269
1270static int
1271sysctl_all(int *oid, int len)
1272{
1273	int name1[22], name2[22];
1274	int i, j;
1275	size_t l1, l2;
1276
1277	name1[0] = CTL_SYSCTL;
1278	name1[1] = (oid != NULL || Nflag || dflag || tflag) ?
1279	    CTL_SYSCTL_NEXTNOSKIP : CTL_SYSCTL_NEXT;
1280	l1 = 2;
1281	if (len) {
1282		memcpy(name1 + 2, oid, len * sizeof(int));
1283		l1 += len;
1284	} else {
1285		name1[2] = CTL_KERN;
1286		l1++;
1287	}
1288	for (;;) {
1289		l2 = sizeof(name2);
1290		j = sysctl(name1, l1, name2, &l2, 0, 0);
1291		if (j < 0) {
1292			if (errno == ENOENT)
1293				return (0);
1294			else
1295				err(1, "sysctl(getnext) %d %zu", j, l2);
1296		}
1297
1298		l2 /= sizeof(int);
1299
1300		if (len < 0 || l2 < (unsigned int)len)
1301			return (0);
1302
1303		if (memcmp(name2, oid, len * sizeof(int)) != 0)
1304			return (0);
1305
1306		i = show_var(name2, l2, true);
1307		if (!i && !bflag)
1308			putchar('\n');
1309
1310		memcpy(name1 + 2, name2, l2 * sizeof(int));
1311		l1 = 2 + l2;
1312	}
1313}
1314