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