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