xref: /f-stack/tools/sysctl/sysctl.c (revision 830124b8)
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 	setlocale(LC_NUMERIC, "");
245 	setbuf(stdout,0);
246 	setbuf(stderr,0);
247 
248 #ifndef FSTACK
249 	while ((ch = getopt(argc, argv, "AabB:def:hiNnoqtTwWxX")) != -1) {
250 #else
251 	while ((ch = getopt(argc, argv, "AabB:def:hiNnoqtTwWxXp:")) != -1) {
252 #endif
253 		switch (ch) {
254 		case 'A':
255 			/* compatibility */
256 			aflag = oflag = 1;
257 			break;
258 		case 'a':
259 			aflag = 1;
260 			break;
261 		case 'b':
262 			bflag = 1;
263 			break;
264 		case 'B':
265 			Bflag = strtol(optarg, NULL, 0);
266 			break;
267 		case 'd':
268 			dflag = 1;
269 			break;
270 		case 'e':
271 			eflag = 1;
272 			break;
273 		case 'f':
274 			conffile = optarg;
275 			break;
276 		case 'h':
277 			hflag = 1;
278 			break;
279 		case 'i':
280 			iflag = 1;
281 			break;
282 		case 'N':
283 			Nflag = 1;
284 			break;
285 		case 'n':
286 			nflag = 1;
287 			break;
288 		case 'o':
289 			oflag = 1;
290 			break;
291 		case 'q':
292 			qflag = 1;
293 			break;
294 		case 't':
295 			tflag = 1;
296 			break;
297 		case 'T':
298 			Tflag = 1;
299 			break;
300 		case 'w':
301 			/* compatibility */
302 			/* ignored */
303 			break;
304 		case 'W':
305 			Wflag = 1;
306 			break;
307 		case 'X':
308 			/* compatibility */
309 			aflag = xflag = 1;
310 			break;
311 		case 'x':
312 			xflag = 1;
313 			break;
314 #ifdef FSTACK
315 		case 'p':
316 			ff_set_proc_id(atoi(optarg));
317 			break;
318 #endif
319 		default:
320 			usage();
321 		}
322 	}
323 	argc -= optind;
324 	argv += optind;
325 
326 	if (Nflag && nflag)
327 		usage();
328 	if (aflag && argc == 0)
329 		exit(sysctl_all(0, 0));
330 	if (argc == 0 && conffile == NULL)
331 		usage();
332 
333 	warncount = 0;
334 	if (conffile != NULL)
335 		warncount += parsefile(conffile);
336 
337 	while (argc-- > 0)
338 		warncount += parse(*argv++, 0);
339 
340 	return (warncount);
341 }
342 
343 /*
344  * Parse a name into a MIB entry.
345  * Lookup and print out the MIB entry if it exists.
346  * Set a new value if requested.
347  */
348 static int
349 parse(const char *string, int lineno)
350 {
351 	int len, i, j;
352 	const void *newval;
353 	const char *newvalstr = NULL;
354 	int8_t i8val;
355 	uint8_t u8val;
356 	int16_t i16val;
357 	uint16_t u16val;
358 	int32_t i32val;
359 	uint32_t u32val;
360 	int intval;
361 	unsigned int uintval;
362 	long longval;
363 	unsigned long ulongval;
364 	size_t newsize = Bflag;
365 	int64_t i64val;
366 	uint64_t u64val;
367 	int mib[CTL_MAXNAME];
368 	char *cp, *bufp, buf[BUFSIZ], *endptr = NULL, fmt[BUFSIZ], line[BUFSIZ];
369 	u_int kind;
370 
371 	if (lineno)
372 		snprintf(line, sizeof(line), " at line %d", lineno);
373 	else
374 		line[0] = '\0';
375 
376 	cp = buf;
377 	if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) {
378 		warnx("oid too long: '%s'%s", string, line);
379 		return (1);
380 	}
381 	bufp = strsep(&cp, "=:");
382 	if (cp != NULL) {
383 		/* Tflag just lists tunables, do not allow assignment */
384 		if (Tflag || Wflag) {
385 			warnx("Can't set variables when using -T or -W");
386 			usage();
387 		}
388 		while (isspace(*cp))
389 			cp++;
390 		/* Strip a pair of " or ' if any. */
391 		switch (*cp) {
392 		case '\"':
393 		case '\'':
394 			if (cp[strlen(cp) - 1] == *cp)
395 				cp[strlen(cp) - 1] = '\0';
396 			cp++;
397 		}
398 		newvalstr = cp;
399 		newsize = strlen(cp);
400 	}
401 	/* Trim spaces */
402 	cp = bufp + strlen(bufp) - 1;
403 	while (cp >= bufp && isspace((int)*cp)) {
404 		*cp = '\0';
405 		cp--;
406 	}
407 	len = name2oid(bufp, mib);
408 
409 	if (len < 0) {
410 		if (iflag)
411 			return (0);
412 		if (qflag)
413 			return (1);
414 		else {
415 			if (errno == ENOENT) {
416 				warnx("unknown oid '%s'%s", bufp, line);
417 			} else {
418 				warn("unknown oid '%s'%s", bufp, line);
419 			}
420 			return (1);
421 		}
422 	}
423 
424 	if (oidfmt(mib, len, fmt, &kind)) {
425 		warn("couldn't find format of oid '%s'%s", bufp, line);
426 		if (iflag)
427 			return (1);
428 		else
429 			exit(1);
430 	}
431 
432 	if (newvalstr == NULL || dflag) {
433 		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
434 			if (dflag) {
435 				i = show_var(mib, len);
436 				if (!i && !bflag)
437 					putchar('\n');
438 			}
439 			sysctl_all(mib, len);
440 		} else {
441 			i = show_var(mib, len);
442 			if (!i && !bflag)
443 				putchar('\n');
444 		}
445 	} else {
446 		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
447 			warnx("oid '%s' isn't a leaf node%s", bufp, line);
448 			return (1);
449 		}
450 
451 		if (!(kind & CTLFLAG_WR)) {
452 			if (kind & CTLFLAG_TUN) {
453 				warnx("oid '%s' is a read only tunable%s", bufp, line);
454 				warnx("Tunable values are set in /boot/loader.conf");
455 			} else
456 				warnx("oid '%s' is read only%s", bufp, line);
457 			return (1);
458 		}
459 
460 		switch (kind & CTLTYPE) {
461 		case CTLTYPE_INT:
462 		case CTLTYPE_UINT:
463 		case CTLTYPE_LONG:
464 		case CTLTYPE_ULONG:
465 		case CTLTYPE_S8:
466 		case CTLTYPE_S16:
467 		case CTLTYPE_S32:
468 		case CTLTYPE_S64:
469 		case CTLTYPE_U8:
470 		case CTLTYPE_U16:
471 		case CTLTYPE_U32:
472 		case CTLTYPE_U64:
473 			if (strlen(newvalstr) == 0) {
474 				warnx("empty numeric value");
475 				return (1);
476 			}
477 			/* FALLTHROUGH */
478 		case CTLTYPE_STRING:
479 			break;
480 		default:
481 			warnx("oid '%s' is type %d,"
482 				" cannot set that%s", bufp,
483 				kind & CTLTYPE, line);
484 			return (1);
485 		}
486 
487 		errno = 0;
488 
489 		switch (kind & CTLTYPE) {
490 			case CTLTYPE_INT:
491 				if (strncmp(fmt, "IK", 2) == 0)
492 					intval = strIKtoi(newvalstr, &endptr, fmt);
493 				else
494 					intval = (int)strtol(newvalstr, &endptr,
495 					    0);
496 				newval = &intval;
497 				newsize = sizeof(intval);
498 				break;
499 			case CTLTYPE_UINT:
500 				uintval = (int) strtoul(newvalstr, &endptr, 0);
501 				newval = &uintval;
502 				newsize = sizeof(uintval);
503 				break;
504 			case CTLTYPE_LONG:
505 				longval = strtol(newvalstr, &endptr, 0);
506 				newval = &longval;
507 				newsize = sizeof(longval);
508 				break;
509 			case CTLTYPE_ULONG:
510 				ulongval = strtoul(newvalstr, &endptr, 0);
511 				newval = &ulongval;
512 				newsize = sizeof(ulongval);
513 				break;
514 			case CTLTYPE_STRING:
515 				newval = newvalstr;
516 				break;
517 			case CTLTYPE_S8:
518 				i8val = (int8_t)strtol(newvalstr, &endptr, 0);
519 				newval = &i8val;
520 				newsize = sizeof(i8val);
521 				break;
522 			case CTLTYPE_S16:
523 				i16val = (int16_t)strtol(newvalstr, &endptr,
524 				    0);
525 				newval = &i16val;
526 				newsize = sizeof(i16val);
527 				break;
528 			case CTLTYPE_S32:
529 				i32val = (int32_t)strtol(newvalstr, &endptr,
530 				    0);
531 				newval = &i32val;
532 				newsize = sizeof(i32val);
533 				break;
534 			case CTLTYPE_S64:
535 				i64val = strtoimax(newvalstr, &endptr, 0);
536 				newval = &i64val;
537 				newsize = sizeof(i64val);
538 				break;
539 			case CTLTYPE_U8:
540 				u8val = (uint8_t)strtoul(newvalstr, &endptr, 0);
541 				newval = &u8val;
542 				newsize = sizeof(u8val);
543 				break;
544 			case CTLTYPE_U16:
545 				u16val = (uint16_t)strtoul(newvalstr, &endptr,
546 				    0);
547 				newval = &u16val;
548 				newsize = sizeof(u16val);
549 				break;
550 			case CTLTYPE_U32:
551 				u32val = (uint32_t)strtoul(newvalstr, &endptr,
552 				    0);
553 				newval = &u32val;
554 				newsize = sizeof(u32val);
555 				break;
556 			case CTLTYPE_U64:
557 				u64val = strtoumax(newvalstr, &endptr, 0);
558 				newval = &u64val;
559 				newsize = sizeof(u64val);
560 				break;
561 			default:
562 				/* NOTREACHED */
563 				abort();
564 		}
565 
566 		if (errno != 0 || endptr == newvalstr ||
567 		    (endptr != NULL && *endptr != '\0')) {
568 			warnx("invalid %s '%s'%s", ctl_typename[kind & CTLTYPE],
569 			    newvalstr, line);
570 			return (1);
571 		}
572 
573 		i = show_var(mib, len);
574 		if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
575 			if (!i && !bflag)
576 				putchar('\n');
577 			switch (errno) {
578 			case EOPNOTSUPP:
579 				warnx("%s: value is not available%s",
580 					string, line);
581 				return (1);
582 			case ENOTDIR:
583 				warnx("%s: specification is incomplete%s",
584 					string, line);
585 				return (1);
586 			case ENOMEM:
587 				warnx("%s: type is unknown to this program%s",
588 					string, line);
589 				return (1);
590 			default:
591 				warn("%s%s", string, line);
592 				return (1);
593 			}
594 		}
595 		if (!bflag)
596 			printf(" -> ");
597 		i = nflag;
598 		nflag = 1;
599 		j = show_var(mib, len);
600 		if (!j && !bflag)
601 			putchar('\n');
602 		nflag = i;
603 	}
604 
605 	return (0);
606 }
607 
608 static int
609 parsefile(const char *filename)
610 {
611 	FILE *file;
612 	char line[BUFSIZ], *p, *pq, *pdq;
613 	int warncount = 0, lineno = 0;
614 
615 	file = fopen(filename, "r");
616 	if (file == NULL)
617 		err(EX_NOINPUT, "%s", filename);
618 	while (fgets(line, sizeof(line), file) != NULL) {
619 		lineno++;
620 		p = line;
621 		pq = strchr(line, '\'');
622 		pdq = strchr(line, '\"');
623 		/* Replace the first # with \0. */
624 		while((p = strchr(p, '#')) != NULL) {
625 			if (pq != NULL && p > pq) {
626 				if ((p = strchr(pq+1, '\'')) != NULL)
627 					*(++p) = '\0';
628 				break;
629 			} else if (pdq != NULL && p > pdq) {
630 				if ((p = strchr(pdq+1, '\"')) != NULL)
631 					*(++p) = '\0';
632 				break;
633 			} else if (p == line || *(p-1) != '\\') {
634 				*p = '\0';
635 				break;
636 			}
637 			p++;
638 		}
639 		/* Trim spaces */
640 		p = line + strlen(line) - 1;
641 		while (p >= line && isspace((int)*p)) {
642 			*p = '\0';
643 			p--;
644 		}
645 		p = line;
646 		while (isspace((int)*p))
647 			p++;
648 		if (*p == '\0')
649 			continue;
650 		else
651 			warncount += parse(p, lineno);
652 	}
653 	fclose(file);
654 
655 	return (warncount);
656 }
657 
658 /* These functions will dump out various interesting structures. */
659 
660 static int
661 S_clockinfo(size_t l2, void *p)
662 {
663 	struct clockinfo *ci = (struct clockinfo*)p;
664 
665 	if (l2 != sizeof(*ci)) {
666 		warnx("S_clockinfo %zu != %zu", l2, sizeof(*ci));
667 		return (1);
668 	}
669 	printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
670 		"{ hz = %d, tick = %d, profhz = %d, stathz = %d }",
671 		ci->hz, ci->tick, ci->profhz, ci->stathz);
672 	return (0);
673 }
674 
675 static int
676 S_loadavg(size_t l2, void *p)
677 {
678 	struct loadavg *tv = (struct loadavg*)p;
679 
680 	if (l2 != sizeof(*tv)) {
681 		warnx("S_loadavg %zu != %zu", l2, sizeof(*tv));
682 		return (1);
683 	}
684 	printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
685 		(double)tv->ldavg[0]/(double)tv->fscale,
686 		(double)tv->ldavg[1]/(double)tv->fscale,
687 		(double)tv->ldavg[2]/(double)tv->fscale);
688 	return (0);
689 }
690 
691 static int
692 S_timeval(size_t l2, void *p)
693 {
694 	struct timeval *tv = (struct timeval*)p;
695 	time_t tv_sec;
696 	char *p1, *p2;
697 
698 	if (l2 != sizeof(*tv)) {
699 		warnx("S_timeval %zu != %zu", l2, sizeof(*tv));
700 		return (1);
701 	}
702 	printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
703 		"{ sec = %jd, usec = %ld } ",
704 		(intmax_t)tv->tv_sec, tv->tv_usec);
705 	tv_sec = tv->tv_sec;
706 	p1 = strdup(ctime(&tv_sec));
707 	for (p2=p1; *p2 ; p2++)
708 		if (*p2 == '\n')
709 			*p2 = '\0';
710 	fputs(p1, stdout);
711 	free(p1);
712 	return (0);
713 }
714 
715 static int
716 S_vmtotal(size_t l2, void *p)
717 {
718 	struct vmtotal *v = (struct vmtotal *)p;
719 	int pageKilo = getpagesize() / 1024;
720 
721 	if (l2 != sizeof(*v)) {
722 		warnx("S_vmtotal %zu != %zu", l2, sizeof(*v));
723 		return (1);
724 	}
725 
726 	printf(
727 	    "\nSystem wide totals computed every five seconds:"
728 	    " (values in kilobytes)\n");
729 	printf("===============================================\n");
730 	printf(
731 	    "Processes:\t\t(RUNQ: %hd Disk Wait: %hd Page Wait: "
732 	    "%hd Sleep: %hd)\n",
733 	    v->t_rq, v->t_dw, v->t_pw, v->t_sl);
734 	printf(
735 	    "Virtual Memory:\t\t(Total: %jdK Active: %jdK)\n",
736 	    (intmax_t)v->t_vm * pageKilo, (intmax_t)v->t_avm * pageKilo);
737 	printf("Real Memory:\t\t(Total: %jdK Active: %jdK)\n",
738 	    (intmax_t)v->t_rm * pageKilo, (intmax_t)v->t_arm * pageKilo);
739 	printf("Shared Virtual Memory:\t(Total: %jdK Active: %jdK)\n",
740 	    (intmax_t)v->t_vmshr * pageKilo, (intmax_t)v->t_avmshr * pageKilo);
741 	printf("Shared Real Memory:\t(Total: %jdK Active: %jdK)\n",
742 	    (intmax_t)v->t_rmshr * pageKilo, (intmax_t)v->t_armshr * pageKilo);
743 	printf("Free Memory:\t%jdK", (intmax_t)v->t_free * pageKilo);
744 
745 	return (0);
746 }
747 
748 #ifdef __amd64__
749 #define efi_next_descriptor(ptr, size) \
750 	((struct efi_md *)(((uint8_t *) ptr) + size))
751 
752 static int
753 S_efi_map(size_t l2, void *p)
754 {
755 	struct efi_map_header *efihdr;
756 	struct efi_md *map;
757 	const char *type;
758 	size_t efisz;
759 	int ndesc, i;
760 
761 	static const char *types[] = {
762 		"Reserved",
763 		"LoaderCode",
764 		"LoaderData",
765 		"BootServicesCode",
766 		"BootServicesData",
767 		"RuntimeServicesCode",
768 		"RuntimeServicesData",
769 		"ConventionalMemory",
770 		"UnusableMemory",
771 		"ACPIReclaimMemory",
772 		"ACPIMemoryNVS",
773 		"MemoryMappedIO",
774 		"MemoryMappedIOPortSpace",
775 		"PalCode"
776 	};
777 
778 	/*
779 	 * Memory map data provided by UEFI via the GetMemoryMap
780 	 * Boot Services API.
781 	 */
782 	if (l2 < sizeof(*efihdr)) {
783 		warnx("S_efi_map length less than header");
784 		return (1);
785 	}
786 	efihdr = p;
787 	efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
788 	map = (struct efi_md *)((uint8_t *)efihdr + efisz);
789 
790 	if (efihdr->descriptor_size == 0)
791 		return (0);
792 	if (l2 != efisz + efihdr->memory_size) {
793 		warnx("S_efi_map length mismatch %zu vs %zu", l2, efisz +
794 		    efihdr->memory_size);
795 		return (1);
796 	}
797 	ndesc = efihdr->memory_size / efihdr->descriptor_size;
798 
799 	printf("\n%23s %12s %12s %8s %4s",
800 	    "Type", "Physical", "Virtual", "#Pages", "Attr");
801 
802 	for (i = 0; i < ndesc; i++,
803 	    map = efi_next_descriptor(map, efihdr->descriptor_size)) {
804 		if (map->md_type <= EFI_MD_TYPE_PALCODE)
805 			type = types[map->md_type];
806 		else
807 			type = "<INVALID>";
808 		printf("\n%23s %012lx %12p %08lx ", type, map->md_phys,
809 		    map->md_virt, map->md_pages);
810 		if (map->md_attr & EFI_MD_ATTR_UC)
811 			printf("UC ");
812 		if (map->md_attr & EFI_MD_ATTR_WC)
813 			printf("WC ");
814 		if (map->md_attr & EFI_MD_ATTR_WT)
815 			printf("WT ");
816 		if (map->md_attr & EFI_MD_ATTR_WB)
817 			printf("WB ");
818 		if (map->md_attr & EFI_MD_ATTR_UCE)
819 			printf("UCE ");
820 		if (map->md_attr & EFI_MD_ATTR_WP)
821 			printf("WP ");
822 		if (map->md_attr & EFI_MD_ATTR_RP)
823 			printf("RP ");
824 		if (map->md_attr & EFI_MD_ATTR_XP)
825 			printf("XP ");
826 		if (map->md_attr & EFI_MD_ATTR_RT)
827 			printf("RUNTIME");
828 	}
829 	return (0);
830 }
831 #endif
832 
833 #if defined(__amd64__) || defined(__i386__)
834 static int
835 S_bios_smap_xattr(size_t l2, void *p)
836 {
837 	struct bios_smap_xattr *smap, *end;
838 
839 	if (l2 % sizeof(*smap) != 0) {
840 		warnx("S_bios_smap_xattr %zu is not a multiple of %zu", l2,
841 		    sizeof(*smap));
842 		return (1);
843 	}
844 
845 	end = (struct bios_smap_xattr *)((char *)p + l2);
846 	for (smap = p; smap < end; smap++)
847 		printf("\nSMAP type=%02x, xattr=%02x, base=%016jx, len=%016jx",
848 		    smap->type, smap->xattr, (uintmax_t)smap->base,
849 		    (uintmax_t)smap->length);
850 	return (0);
851 }
852 #endif
853 
854 static int
855 strIKtoi(const char *str, char **endptrp, const char *fmt)
856 {
857 	int kelv;
858 	float temp;
859 	size_t len;
860 	const char *p;
861 	int prec, i;
862 
863 	assert(errno == 0);
864 
865 	len = strlen(str);
866 	/* caller already checked this */
867 	assert(len > 0);
868 
869 	/*
870 	 * A format of "IK" is in deciKelvin. A format of "IK3" is in
871 	 * milliKelvin. The single digit following IK is log10 of the
872 	 * multiplying factor to convert Kelvin into the untis of this sysctl,
873 	 * or the dividing factor to convert the sysctl value to Kelvin. Numbers
874 	 * larger than 6 will run into precision issues with 32-bit integers.
875 	 * Characters that aren't ASCII digits after the 'K' are ignored. No
876 	 * localization is present because this is an interface from the kernel
877 	 * to this program (eg not an end-user interface), so isdigit() isn't
878 	 * used here.
879 	 */
880 	if (fmt[2] != '\0' && fmt[2] >= '0' && fmt[2] <= '9')
881 		prec = fmt[2] - '0';
882 	else
883 		prec = 1;
884 	p = &str[len - 1];
885 	if (*p == 'C' || *p == 'F' || *p == 'K') {
886 		temp = strtof(str, endptrp);
887 		if (*endptrp != str && *endptrp == p && errno == 0) {
888 			if (*p == 'F')
889 				temp = (temp - 32) * 5 / 9;
890 			*endptrp = NULL;
891 			if (*p != 'K')
892 				temp += 273.15;
893 			for (i = 0; i < prec; i++)
894 				temp *= 10.0;
895 			return ((int)(temp + 0.5));
896 		}
897 	} else {
898 		/* No unit specified -> treat it as a raw number */
899 		kelv = (int)strtol(str, endptrp, 10);
900 		if (*endptrp != str && *endptrp == p && errno == 0) {
901 			*endptrp = NULL;
902 			return (kelv);
903 		}
904 	}
905 
906 	errno = ERANGE;
907 	return (0);
908 }
909 
910 /*
911  * These functions uses a presently undocumented interface to the kernel
912  * to walk the tree and get the type so it can print the value.
913  * This interface is under work and consideration, and should probably
914  * be killed with a big axe by the first person who can find the time.
915  * (be aware though, that the proper interface isn't as obvious as it
916  * may seem, there are various conflicting requirements.
917  */
918 
919 static int
920 name2oid(const char *name, int *oidp)
921 {
922 	int oid[2];
923 	int i;
924 	size_t j;
925 
926 	oid[0] = 0;
927 	oid[1] = 3;
928 
929 	j = CTL_MAXNAME * sizeof(int);
930 	i = sysctl(oid, 2, oidp, &j, name, strlen(name));
931 	if (i < 0)
932 		return (i);
933 	j /= sizeof(int);
934 	return (j);
935 }
936 
937 static int
938 oidfmt(int *oid, int len, char *fmt, u_int *kind)
939 {
940 	int qoid[CTL_MAXNAME+2];
941 	u_char buf[BUFSIZ];
942 	int i;
943 	size_t j;
944 
945 	qoid[0] = 0;
946 	qoid[1] = 4;
947 	memcpy(qoid + 2, oid, len * sizeof(int));
948 
949 	j = sizeof(buf);
950 	i = sysctl(qoid, len + 2, buf, &j, 0, 0);
951 	if (i)
952 		err(1, "sysctl fmt %d %zu %d", i, j, errno);
953 
954 	if (kind)
955 		*kind = *(u_int *)buf;
956 
957 	if (fmt)
958 		strcpy(fmt, (char *)(buf + sizeof(u_int)));
959 	return (0);
960 }
961 
962 /*
963  * This formats and outputs the value of one variable
964  *
965  * Returns zero if anything was actually output.
966  * Returns one if didn't know what to do with this.
967  * Return minus one if we had errors.
968  */
969 static int
970 show_var(int *oid, int nlen)
971 {
972 	u_char buf[BUFSIZ], *val, *oval, *p;
973 	char name[BUFSIZ], fmt[BUFSIZ];
974 	const char *sep, *sep1, *prntype;
975 	int qoid[CTL_MAXNAME+2];
976 	uintmax_t umv;
977 	intmax_t mv;
978 	int i, hexlen, sign, ctltype;
979 	size_t intlen;
980 	size_t j, len;
981 	u_int kind;
982 	float base;
983 	int (*func)(size_t, void *);
984 	int prec;
985 
986 	/* Silence GCC. */
987 	umv = mv = intlen = 0;
988 
989 	bzero(buf, BUFSIZ);
990 	bzero(fmt, BUFSIZ);
991 	bzero(name, BUFSIZ);
992 	qoid[0] = 0;
993 	memcpy(qoid + 2, oid, nlen * sizeof(int));
994 
995 	qoid[1] = 1;
996 	j = sizeof(name);
997 	i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
998 	if (i || !j)
999 		err(1, "sysctl name %d %zu %d", i, j, errno);
1000 
1001 	oidfmt(oid, nlen, fmt, &kind);
1002 	/* if Wflag then only list sysctls that are writeable and not stats. */
1003 	if (Wflag && ((kind & CTLFLAG_WR) == 0 || (kind & CTLFLAG_STATS) != 0))
1004 		return 1;
1005 
1006 	/* if Tflag then only list sysctls that are tuneables. */
1007 	if (Tflag && (kind & CTLFLAG_TUN) == 0)
1008 		return 1;
1009 
1010 	if (Nflag) {
1011 		printf("%s", name);
1012 		return (0);
1013 	}
1014 
1015 	if (eflag)
1016 		sep = "=";
1017 	else
1018 		sep = ": ";
1019 
1020 	ctltype = (kind & CTLTYPE);
1021 	if (tflag || dflag) {
1022 		if (!nflag)
1023 			printf("%s%s", name, sep);
1024         	if (ctl_typename[ctltype] != NULL)
1025             		prntype = ctl_typename[ctltype];
1026         	else
1027             		prntype = "unknown";
1028 		if (tflag && dflag)
1029 			printf("%s%s", prntype, sep);
1030 		else if (tflag) {
1031 			printf("%s", prntype);
1032 			return (0);
1033 		}
1034 		qoid[1] = 5;
1035 		j = sizeof(buf);
1036 		i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
1037 		printf("%s", buf);
1038 		return (0);
1039 	}
1040 	/* find an estimate of how much we need for this var */
1041 	if (Bflag)
1042 		j = Bflag;
1043 	else {
1044 		j = 0;
1045 		i = sysctl(oid, nlen, 0, &j, 0, 0);
1046 		j += j; /* we want to be sure :-) */
1047 	}
1048 
1049 	val = oval = malloc(j + 1);
1050 	if (val == NULL) {
1051 		warnx("malloc failed");
1052 		return (1);
1053 	}
1054 	len = j;
1055 	i = sysctl(oid, nlen, val, &len, 0, 0);
1056 	if (i != 0 || (len == 0 && ctltype != CTLTYPE_STRING)) {
1057 		free(oval);
1058 		return (1);
1059 	}
1060 
1061 	if (bflag) {
1062 		fwrite(val, 1, len, stdout);
1063 		free(oval);
1064 		return (0);
1065 	}
1066 	val[len] = '\0';
1067 	p = val;
1068 	sign = ctl_sign[ctltype];
1069 	intlen = ctl_size[ctltype];
1070 
1071 	switch (ctltype) {
1072 	case CTLTYPE_STRING:
1073 		if (!nflag)
1074 			printf("%s%s", name, sep);
1075 		printf("%.*s", (int)len, p);
1076 		free(oval);
1077 		return (0);
1078 
1079 	case CTLTYPE_INT:
1080 	case CTLTYPE_UINT:
1081 	case CTLTYPE_LONG:
1082 	case CTLTYPE_ULONG:
1083 	case CTLTYPE_S8:
1084 	case CTLTYPE_S16:
1085 	case CTLTYPE_S32:
1086 	case CTLTYPE_S64:
1087 	case CTLTYPE_U8:
1088 	case CTLTYPE_U16:
1089 	case CTLTYPE_U32:
1090 	case CTLTYPE_U64:
1091 		if (!nflag)
1092 			printf("%s%s", name, sep);
1093 		hexlen = 2 + (intlen * CHAR_BIT + 3) / 4;
1094 		sep1 = "";
1095 		while (len >= intlen) {
1096 			switch (kind & CTLTYPE) {
1097 			case CTLTYPE_INT:
1098 			case CTLTYPE_UINT:
1099 				umv = *(u_int *)p;
1100 				mv = *(int *)p;
1101 				break;
1102 			case CTLTYPE_LONG:
1103 			case CTLTYPE_ULONG:
1104 				umv = *(u_long *)p;
1105 				mv = *(long *)p;
1106 				break;
1107 			case CTLTYPE_S8:
1108 			case CTLTYPE_U8:
1109 				umv = *(uint8_t *)p;
1110 				mv = *(int8_t *)p;
1111 				break;
1112 			case CTLTYPE_S16:
1113 			case CTLTYPE_U16:
1114 				umv = *(uint16_t *)p;
1115 				mv = *(int16_t *)p;
1116 				break;
1117 			case CTLTYPE_S32:
1118 			case CTLTYPE_U32:
1119 				umv = *(uint32_t *)p;
1120 				mv = *(int32_t *)p;
1121 				break;
1122 			case CTLTYPE_S64:
1123 			case CTLTYPE_U64:
1124 				umv = *(uint64_t *)p;
1125 				mv = *(int64_t *)p;
1126 				break;
1127 			}
1128 			fputs(sep1, stdout);
1129 			if (xflag)
1130 				printf("%#0*jx", hexlen, umv);
1131 			else if (!sign)
1132 				printf(hflag ? "%'ju" : "%ju", umv);
1133 			else if (fmt[1] == 'K') {
1134 				if (mv < 0)
1135 					printf("%jd", mv);
1136 				else {
1137 					/*
1138 					 * See strIKtoi for details on fmt.
1139 					 */
1140 					prec = 1;
1141 					if (fmt[2] != '\0')
1142 						prec = fmt[2] - '0';
1143 					base = 1.0;
1144 					for (int i = 0; i < prec; i++)
1145 						base *= 10.0;
1146 					printf("%.*fC", prec,
1147 					    (float)mv / base - 273.15);
1148 				}
1149 			} else
1150 				printf(hflag ? "%'jd" : "%jd", mv);
1151 			sep1 = " ";
1152 			len -= intlen;
1153 			p += intlen;
1154 		}
1155 		free(oval);
1156 		return (0);
1157 
1158 	case CTLTYPE_OPAQUE:
1159 		i = 0;
1160 		if (strcmp(fmt, "S,clockinfo") == 0)
1161 			func = S_clockinfo;
1162 		else if (strcmp(fmt, "S,timeval") == 0)
1163 			func = S_timeval;
1164 		else if (strcmp(fmt, "S,loadavg") == 0)
1165 			func = S_loadavg;
1166 		else if (strcmp(fmt, "S,vmtotal") == 0)
1167 			func = S_vmtotal;
1168 #ifdef __amd64__
1169 		else if (strcmp(fmt, "S,efi_map_header") == 0)
1170 			func = S_efi_map;
1171 #endif
1172 #if defined(__amd64__) || defined(__i386__)
1173 		else if (strcmp(fmt, "S,bios_smap_xattr") == 0)
1174 			func = S_bios_smap_xattr;
1175 #endif
1176 		else
1177 			func = NULL;
1178 		if (func) {
1179 			if (!nflag)
1180 				printf("%s%s", name, sep);
1181 			i = (*func)(len, p);
1182 			free(oval);
1183 			return (i);
1184 		}
1185 		/* FALLTHROUGH */
1186 	default:
1187 		if (!oflag && !xflag) {
1188 			free(oval);
1189 			return (1);
1190 		}
1191 		if (!nflag)
1192 			printf("%s%s", name, sep);
1193 		printf("Format:%s Length:%zu Dump:0x", fmt, len);
1194 		while (len-- && (xflag || p < val + 16))
1195 			printf("%02x", *p++);
1196 		if (!xflag && len > 16)
1197 			printf("...");
1198 		free(oval);
1199 		return (0);
1200 	}
1201 	free(oval);
1202 	return (1);
1203 }
1204 
1205 static int
1206 sysctl_all(int *oid, int len)
1207 {
1208 	int name1[22], name2[22];
1209 	int i, j;
1210 	size_t l1, l2;
1211 
1212 	name1[0] = 0;
1213 	name1[1] = 2;
1214 	l1 = 2;
1215 	if (len) {
1216 		memcpy(name1+2, oid, len * sizeof(int));
1217 		l1 += len;
1218 	} else {
1219 		name1[2] = 1;
1220 		l1++;
1221 	}
1222 	for (;;) {
1223 		l2 = sizeof(name2);
1224 		j = sysctl(name1, l1, name2, &l2, 0, 0);
1225 		if (j < 0) {
1226 			if (errno == ENOENT)
1227 				return (0);
1228 			else
1229 				err(1, "sysctl(getnext) %d %zu", j, l2);
1230 		}
1231 
1232 		l2 /= sizeof(int);
1233 
1234 		if (len < 0 || l2 < (unsigned int)len)
1235 			return (0);
1236 
1237 		for (i = 0; i < len; i++)
1238 			if (name2[i] != oid[i])
1239 				return (0);
1240 
1241 		i = show_var(name2, l2);
1242 		if (!i && !bflag)
1243 			putchar('\n');
1244 
1245 		memcpy(name1+2, name2, l2 * sizeof(int));
1246 		l1 = 2 + l2;
1247 	}
1248 }
1249