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