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