1/*	$NetBSD: sysctl.c,v 1.140 2012/02/12 20:54:07 christos Exp $ */
2
3/*-
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
5 *	All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Brown.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * Copyright (c) 1993
34 *	The Regents of the University of California.  All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 *    notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 *    notice, this list of conditions and the following disclaimer in the
43 *    documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the University nor the names of its contributors
45 *    may be used to endorse or promote products derived from this software
46 *    without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
61#include <sys/cdefs.h>
62#ifndef lint
63__COPYRIGHT("@(#) Copyright (c) 1993\
64 The Regents of the University of California.  All rights reserved.");
65#endif /* not lint */
66
67#ifndef lint
68#if 0
69static char sccsid[] = "@(#)sysctl.c	8.1 (Berkeley) 6/6/93";
70#else
71__RCSID("$NetBSD: sysctl.c,v 1.140 2012/02/12 20:54:07 christos Exp $");
72#endif
73#endif /* not lint */
74
75#include <sys/types.h>
76#include <sys/param.h>
77#include <sys/sysctl.h>
78#include <sys/mount.h>
79#include <sys/resource.h>
80#include <sys/stat.h>
81#include <sys/sched.h>
82#include <sys/socket.h>
83#include <netinet/in.h>
84#include <netinet/ip_var.h>
85#include <netinet/tcp.h>
86#include <netinet/tcp_timer.h>
87#include <netinet/tcp_var.h>
88#include <netinet/icmp6.h>
89#include <nfs/rpcv2.h>
90#include <nfs/nfsproto.h>
91#include <nfs/nfs.h>
92#include <machine/cpu.h>
93
94#include <assert.h>
95#include <ctype.h>
96#include <err.h>
97#include <errno.h>
98#include <inttypes.h>
99#include <regex.h>
100#include <stdarg.h>
101#include <stdio.h>
102#include <stdlib.h>
103#include <string.h>
104#include <time.h>
105#include <unistd.h>
106
107#include "prog_ops.h"
108
109/*
110 * this needs to be able to do the printing and the setting
111 */
112#define HANDLER_PROTO const char *, const char *, char *, \
113	int *, u_int, const struct sysctlnode *, \
114	u_int, void *
115#define HANDLER_ARGS const char *sname, const char *dname, char *value, \
116	int *name, u_int namelen, const struct sysctlnode *pnode, \
117	u_int type, void *v
118#define DISPLAY_VALUE	0
119#define DISPLAY_OLD	1
120#define DISPLAY_NEW	2
121
122/*
123 * generic routines
124 */
125static const struct handlespec *findhandler(const char *, int, regex_t *,
126    size_t *);
127static void canonicalize(const char *, char *);
128static void purge_tree(struct sysctlnode *);
129static void print_tree(int *, u_int, struct sysctlnode *, u_int, int, regex_t *,
130    size_t *);
131static void write_number(int *, u_int, struct sysctlnode *, char *);
132static void write_string(int *, u_int, struct sysctlnode *, char *);
133static void display_number(const struct sysctlnode *, const char *,
134			   const void *, size_t, int);
135static void display_string(const struct sysctlnode *, const char *,
136			   const void *, size_t, int);
137static void display_struct(const struct sysctlnode *, const char *,
138			   const void *, size_t, int);
139static void hex_dump(const unsigned char *, size_t);
140__dead static void usage(void);
141static void parse(char *, regex_t *, size_t *);
142static void parse_create(char *);
143static void parse_destroy(char *);
144static void parse_describe(char *);
145static void getdesc1(int *, u_int, struct sysctlnode *);
146static void getdesc(int *, u_int, struct sysctlnode *);
147static void trim_whitespace(char *, int);
148static void sysctlerror(int);
149static void sysctlparseerror(u_int, const char *);
150static void sysctlperror(const char *, ...);
151#define EXIT(n) do { \
152	if (fn == NULL) exit(n); else return; } while (/*CONSTCOND*/0)
153
154/*
155 * "borrowed" from libc:sysctlgetmibinfo.c
156 */
157int __learn_tree(int *, u_int, struct sysctlnode *);
158
159/*
160 * "handlers"
161 */
162static void printother(HANDLER_PROTO);
163static void kern_clockrate(HANDLER_PROTO);
164static void kern_boottime(HANDLER_PROTO);
165static void kern_consdev(HANDLER_PROTO);
166static void kern_cp_time(HANDLER_PROTO);
167static void kern_cp_id(HANDLER_PROTO);
168static void kern_drivers(HANDLER_PROTO);
169static void vm_loadavg(HANDLER_PROTO);
170static void proc_limit(HANDLER_PROTO);
171#ifdef CPU_DISKINFO
172static void machdep_diskinfo(HANDLER_PROTO);
173#endif /* CPU_DISKINFO */
174static void mode_bits(HANDLER_PROTO);
175
176static const struct handlespec {
177	const char *ps_re;
178	void (*ps_p)(HANDLER_PROTO);
179	void (*ps_w)(HANDLER_PROTO);
180	const void *ps_d;
181} handlers[] = {
182	{ "/kern/clockrate",			kern_clockrate, NULL, NULL },
183	{ "/kern/vnode",			printother, NULL, "pstat" },
184	{ "/kern/proc(2|_args)?",		printother, NULL, "ps" },
185	{ "/kern/file2?",			printother, NULL, "pstat" },
186	{ "/kern/ntptime",			printother, NULL,
187						"ntpdc -c kerninfo" },
188	{ "/kern/msgbuf",			printother, NULL, "dmesg" },
189	{ "/kern/boottime",			kern_boottime, NULL, NULL },
190	{ "/kern/consdev",			kern_consdev, NULL, NULL },
191	{ "/kern/cp_time(/[0-9]+)?",		kern_cp_time, NULL, NULL },
192	{ "/kern/sysvipc_info",			printother, NULL, "ipcs" },
193	{ "/kern/cp_id(/[0-9]+)?",		kern_cp_id, NULL, NULL },
194
195	{ "/kern/coredump/setid/mode",		mode_bits, mode_bits, NULL },
196	{ "/kern/drivers",			kern_drivers, NULL, NULL },
197
198	{ "/vm/vmmeter",			printother, NULL,
199						"vmstat' or 'systat" },
200	{ "/vm/loadavg",			vm_loadavg, NULL, NULL },
201	{ "/vm/uvmexp2?",			printother, NULL,
202						"vmstat' or 'systat" },
203
204	{ "/vfs/nfs/nfsstats",			printother, NULL, "nfsstat" },
205
206	{ "/net/inet6?/tcp6?/ident",		printother, NULL, "identd" },
207	{ "/net/inet6/icmp6/nd6_[dp]rlist",	printother, NULL, "ndp" },
208	{ "/net/key/dumps[ap]",			printother, NULL, "setkey" },
209	{ "/net/[^/]+/[^/]+/pcblist",		printother, NULL,
210						"netstat' or 'sockstat" },
211	{ "/net/(inet|inet6)/[^/]+/stats",	printother, NULL, "netstat"},
212	{ "/net/bpf/(stats|peers)",		printother, NULL, "netstat"},
213
214	{ "/net/inet.*/tcp.*/deb.*",		printother, NULL, "trpt" },
215
216	{ "/net/ns/spp/deb.*",			printother, NULL, "trsp" },
217
218	{ "/hw/diskstats",			printother, NULL, "iostat" },
219
220#ifdef CPU_CONSDEV
221	{ "/machdep/consdev",			kern_consdev, NULL, NULL },
222#endif /* CPU_CONSDEV */
223#ifdef CPU_DISKINFO
224	{ "/machdep/diskinfo",			machdep_diskinfo, NULL, NULL },
225#endif /* CPU_CONSDEV */
226
227	{ "/proc/[^/]+/rlimit/[^/]+/[^/]+",	proc_limit, proc_limit, NULL },
228
229	/*
230	 * these will only be called when the given node has no children
231	 */
232	{ "/net/[^/]+",				printother, NULL, NULL },
233	{ "/debug",				printother, NULL, NULL },
234	{ "/ddb",				printother, NULL, NULL },
235	{ "/vendor",				printother, NULL, NULL },
236
237	{ NULL,					NULL, NULL, NULL },
238};
239
240struct sysctlnode my_root = {
241	.sysctl_flags = SYSCTL_VERSION|CTLFLAG_ROOT|CTLTYPE_NODE,
242	sysc_init_field(_sysctl_size, sizeof(struct sysctlnode)),
243	.sysctl_num = 0,
244	.sysctl_name = "(prog_root)",
245};
246
247int	Aflag, aflag, dflag, Mflag, nflag, qflag, rflag, wflag, xflag;
248size_t	nr;
249char	*fn;
250int	req, stale, errs;
251FILE	*warnfp = stderr;
252
253/*
254 * vah-riables n stuff
255 */
256char gsname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME],
257	canonname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME],
258	gdname[10 * CTL_MAXNAME + CTL_MAXNAME];
259char sep[] = ".";
260const char *eq = " = ";
261const char *lname[] = {
262	"top", "second", "third", "fourth", "fifth", "sixth",
263	"seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth"
264};
265
266/*
267 * you've heard of main, haven't you?
268 */
269int
270main(int argc, char *argv[])
271{
272	int name[CTL_MAXNAME];
273	int ch;
274	size_t lastcompiled = 0;
275	regex_t *re;
276
277	setprogname(argv[0]);
278	while ((ch = getopt(argc, argv, "Aabdef:Mnqrwx")) != -1) {
279		switch (ch) {
280		case 'A':
281			Aflag++;
282			break;
283		case 'a':
284			aflag++;
285			break;
286		case 'd':
287			dflag++;
288			break;
289		case 'e':
290			eq = "=";
291			break;
292		case 'f':
293			fn = optarg;
294			wflag++;
295			break;
296		case 'M':
297			Mflag++;
298			break;
299		case 'n':
300			nflag++;
301			break;
302		case 'q':
303			qflag++;
304			break;
305		case 'b':	/* FreeBSD compat */
306		case 'r':
307			rflag++;
308			break;
309		case 'w':
310			wflag++;
311			break;
312		case 'x':
313			xflag++;
314			break;
315		default:
316			usage();
317		}
318	}
319
320	argc -= optind;
321	argv += optind;
322
323	if (xflag && rflag)
324		usage();
325	/* if ((xflag || rflag) && wflag)
326		usage(); */
327	/* if (aflag && (Mflag || qflag))
328		usage(); */
329	if ((aflag || Aflag) && qflag)
330		usage();
331	if ((Aflag || Mflag || dflag) && argc == 0 && fn == NULL)
332		aflag = 1;
333
334	if (prog_init && prog_init() == -1)
335		err(1, "prog init failed");
336
337	if (Aflag)
338		warnfp = stdout;
339	stale = req = 0;
340
341	if ((re = malloc(sizeof(*re) * __arraycount(handlers))) == NULL)
342		err(1, "malloc regex");
343
344	if (aflag) {
345		print_tree(&name[0], 0, NULL, CTLTYPE_NODE, 1,
346		    re, &lastcompiled);
347		/* if (argc == 0) */
348		return (0);
349	}
350
351	if (fn) {
352		FILE *fp;
353		char *l;
354
355		fp = fopen(fn, "r");
356		if (fp == NULL) {
357			err(1, "%s", fn);
358		} else {
359			nr = 0;
360			while ((l = fparseln(fp, NULL, &nr, NULL, 0)) != NULL)
361			{
362				if (*l) {
363					parse(l, re, &lastcompiled);
364					free(l);
365				}
366			}
367			fclose(fp);
368		}
369		return errs ? 1 : 0;
370	}
371
372	if (argc == 0)
373		usage();
374
375	while (argc-- > 0)
376		parse(*argv++, re, &lastcompiled);
377
378	return errs ? 1 : 0;
379}
380
381/*
382 * ********************************************************************
383 * how to find someone special to handle the reading (or maybe even
384 * writing) of a particular node
385 * ********************************************************************
386 */
387static const struct handlespec *
388findhandler(const char *s, int w, regex_t *re, size_t *lastcompiled)
389{
390	const struct handlespec *p;
391	size_t i, l;
392	int j;
393	char eb[64];
394	regmatch_t match;
395
396	p = &handlers[0];
397	l = strlen(s);
398	for (i = 0; p[i].ps_re != NULL; i++) {
399		if (i >= *lastcompiled) {
400			j = regcomp(&re[i], p[i].ps_re, REG_EXTENDED);
401			if (j != 0) {
402				regerror(j, &re[i], eb, sizeof(eb));
403				errx(1, "regcomp: %s: %s", p[i].ps_re, eb);
404			}
405			*lastcompiled = i + 1;
406		}
407		j = regexec(&re[i], s, 1, &match, 0);
408		if (j == 0) {
409			if (match.rm_so == 0 && match.rm_eo == (int)l &&
410			    (w ? p[i].ps_w : p[i].ps_p) != NULL)
411				return &p[i];
412		}
413		else if (j != REG_NOMATCH) {
414			regerror(j, &re[i], eb, sizeof(eb));
415			errx(1, "regexec: %s: %s", p[i].ps_re, eb);
416		}
417	}
418
419	return NULL;
420}
421
422/*
423 * after sysctlgetmibinfo is done with the name, we convert all
424 * separators to / and stuff one at the front if it was missing
425 */
426static void
427canonicalize(const char *i, char *o)
428{
429	const char *t;
430	char p[SYSCTL_NAMELEN + 1];
431	int l;
432
433	if (i[0] != *sep) {
434		o[0] = '/';
435		o[1] = '\0';
436	}
437	else
438		o[0] = '\0';
439
440	t = i;
441	do {
442		i = t;
443		t = strchr(i, sep[0]);
444		if (t == NULL)
445			strcat(o, i);
446		else {
447			l = t - i;
448			t++;
449			memcpy(p, i, l);
450			p[l] = '\0';
451			strcat(o, p);
452			strcat(o, "/");
453		}
454	} while (t != NULL);
455}
456
457/*
458 * ********************************************************************
459 * convert this special number to a special string so we can print the
460 * mib
461 * ********************************************************************
462 */
463static const char *
464sf(u_int f)
465{
466	static char s[256];
467	const char *c;
468
469	s[0] = '\0';
470	c = "";
471
472#define print_flag(_f, _s, _c, _q, _x) \
473	if (((_f) & (__CONCAT(CTLFLAG_,_x))) == (__CONCAT(CTLFLAG_,_q))) { \
474		strlcat((_s), (_c), sizeof(_s)); \
475		strlcat((_s), __STRING(_q), sizeof(_s)); \
476		(_c) = ","; \
477		(_f) &= ~(__CONCAT(CTLFLAG_,_x)); \
478	}
479	print_flag(f, s, c, READONLY,  READWRITE);
480	print_flag(f, s, c, READWRITE, READWRITE);
481	print_flag(f, s, c, ANYWRITE,  ANYWRITE);
482	print_flag(f, s, c, PRIVATE,   PRIVATE);
483	print_flag(f, s, c, PERMANENT, PERMANENT);
484	print_flag(f, s, c, OWNDATA,   OWNDATA);
485	print_flag(f, s, c, IMMEDIATE, IMMEDIATE);
486	print_flag(f, s, c, HEX,       HEX);
487	print_flag(f, s, c, ROOT,      ROOT);
488	print_flag(f, s, c, ANYNUMBER, ANYNUMBER);
489	print_flag(f, s, c, HIDDEN,    HIDDEN);
490	print_flag(f, s, c, ALIAS,     ALIAS);
491#undef print_flag
492
493	if (f) {
494		char foo[9];
495		snprintf(foo, sizeof(foo), "%x", f);
496		strlcat(s, c, sizeof(s));
497		strlcat(s, foo, sizeof(s));
498	}
499
500	return (s);
501}
502
503static const char *
504st(u_int t)
505{
506
507	switch (t) {
508	case CTLTYPE_NODE:
509		return "NODE";
510	case CTLTYPE_INT:
511		return "INT";
512	case CTLTYPE_STRING:
513		return "STRING";
514	case CTLTYPE_QUAD:
515                return "QUAD";
516	case CTLTYPE_STRUCT:
517		return "STRUCT";
518	case CTLTYPE_BOOL:
519		return "BOOL";
520	}
521
522	return "???";
523}
524
525/*
526 * ********************************************************************
527 * recursively eliminate all data belonging to the given node
528 * ********************************************************************
529 */
530static void
531purge_tree(struct sysctlnode *rnode)
532{
533	struct sysctlnode *node;
534
535	if (rnode == NULL ||
536	    SYSCTL_TYPE(rnode->sysctl_flags) != CTLTYPE_NODE ||
537	    rnode->sysctl_child == NULL)
538		return;
539
540	for (node = rnode->sysctl_child;
541	     node < &rnode->sysctl_child[rnode->sysctl_clen];
542	     node++)
543		purge_tree(node);
544	free(rnode->sysctl_child);
545	rnode->sysctl_csize = 0;
546	rnode->sysctl_clen = 0;
547	rnode->sysctl_child = NULL;
548
549	if (rnode->sysctl_desc == (const char*)-1)
550		rnode->sysctl_desc = NULL;
551	if (rnode->sysctl_desc != NULL)
552		free(__UNCONST(rnode->sysctl_desc));
553	rnode->sysctl_desc = NULL;
554}
555
556static void __attribute__((__format__(__printf__, 3, 4)))
557appendprintf(char **bp, size_t *lbp, const char *fmt, ...)
558{
559	int r;
560	va_list ap;
561
562	va_start(ap, fmt);
563	r = vsnprintf(*bp, *lbp, fmt, ap);
564	va_end(ap);
565	if (r < 0 || (size_t)r > *lbp)
566		r = *lbp;
567	*bp += r;
568	*lbp -= r;
569}
570
571/*
572 * ********************************************************************
573 * print this node and any others underneath it
574 * ********************************************************************
575 */
576static void
577print_tree(int *name, u_int namelen, struct sysctlnode *pnode, u_int type,
578   int add, regex_t *re, size_t *lastcompiled)
579{
580	struct sysctlnode *node;
581	int rc;
582	size_t ni, sz, ldp, lsp;
583	char *sp, *dp, *tsp, *tdp;
584	const struct handlespec *p;
585
586	sp = tsp = &gsname[strlen(gsname)];
587	dp = tdp = &gdname[strlen(gdname)];
588	ldp = sizeof(gdname) - (dp - gdname);
589	lsp = sizeof(gsname) - (sp - gsname);
590
591	if (sp != &gsname[0] && dp == &gdname[0]) {
592		/*
593		 * aw...shucks.  now we must play catch up
594		 */
595		for (ni = 0; ni < namelen; ni++)
596			appendprintf(&tdp, &ldp, "%s%d", ni > 0 ? "." : "",
597			    name[ni]);
598	}
599
600	if (pnode == NULL)
601		pnode = &my_root;
602	else if (add) {
603		appendprintf(&tsp, &lsp, "%s%s", namelen > 1 ? sep : "",
604			pnode->sysctl_name);
605		appendprintf(&tdp, &ldp, "%s%d", namelen > 1 ? "." : "",
606			pnode->sysctl_num);
607	}
608
609	if (Mflag && pnode != &my_root) {
610		if (nflag)
611			printf("%s: ", gdname);
612		else
613			printf("%s (%s): ", gsname, gdname);
614		printf("CTLTYPE_%s", st(type));
615		if (type == CTLTYPE_NODE) {
616			if (SYSCTL_FLAGS(pnode->sysctl_flags) & CTLFLAG_ALIAS)
617				printf(", alias %d",
618				       pnode->sysctl_alias);
619			else
620				printf(", children %d/%d",
621				       pnode->sysctl_clen,
622				       pnode->sysctl_csize);
623		}
624		printf(", size %zu", pnode->sysctl_size);
625		printf(", flags 0x%x<%s>",
626		       SYSCTL_FLAGS(pnode->sysctl_flags),
627		       sf(SYSCTL_FLAGS(pnode->sysctl_flags)));
628		if (pnode->sysctl_func)
629			printf(", func=%p", pnode->sysctl_func);
630		printf(", ver=%d", pnode->sysctl_ver);
631		printf("\n");
632		if (type != CTLTYPE_NODE) {
633			*sp = *dp = '\0';
634			return;
635		}
636	}
637
638	if (dflag && pnode != &my_root) {
639		if (Aflag || type != CTLTYPE_NODE) {
640			if (pnode->sysctl_desc == NULL)
641				getdesc1(name, namelen, pnode);
642			if (Aflag || !add ||
643			    (pnode->sysctl_desc != NULL &&
644			     pnode->sysctl_desc != (const char*)-1)) {
645				if (!nflag)
646					printf("%s: ", gsname);
647				if (pnode->sysctl_desc == NULL ||
648				    pnode->sysctl_desc == (const char*)-1)
649					printf("(no description)\n");
650				else
651					printf("%s\n", pnode->sysctl_desc);
652			}
653		}
654
655		if (type != CTLTYPE_NODE) {
656			*sp = *dp = '\0';
657			return;
658		}
659	}
660
661	/*
662	 * if this is an alias and we added our name, that means we
663	 * got here by recursing down into the tree, so skip it.  The
664	 * only way to print an aliased node is with either -M or by
665	 * name specifically.
666	 */
667	if (SYSCTL_FLAGS(pnode->sysctl_flags) & CTLFLAG_ALIAS && add) {
668		*sp = *dp = '\0';
669		return;
670	}
671
672	canonicalize(gsname, canonname);
673	p = findhandler(canonname, 0, re, lastcompiled);
674	if (type != CTLTYPE_NODE && p != NULL) {
675		(*p->ps_p)(gsname, gdname, NULL, name, namelen, pnode, type,
676			   __UNCONST(p->ps_d));
677		*sp = *dp = '\0';
678		return;
679	}
680
681	if (type != CTLTYPE_NODE && pnode->sysctl_size == 0) {
682		rc = prog_sysctl(&name[0], namelen, NULL, &sz, NULL, 0);
683		if (rc == -1) {
684			sysctlerror(1);
685			*sp = *dp = '\0';
686			return;
687		}
688		if (sz == 0) {
689			if ((Aflag || req) && !Mflag)
690				printf("%s: node contains no data\n", gsname);
691			*sp = *dp = '\0';
692			return;
693		}
694	}
695	else
696		sz = pnode->sysctl_size;
697
698	switch (type) {
699	case CTLTYPE_NODE: {
700		__learn_tree(name, namelen, pnode);
701		node = pnode->sysctl_child;
702		if (node == NULL) {
703			if (dflag)
704				/* do nothing */;
705			else if (p != NULL)
706				(*p->ps_p)(gsname, gdname, NULL, name, namelen,
707					   pnode, type, __UNCONST(p->ps_d));
708			else if ((Aflag || req) && !Mflag)
709				printf("%s: no children\n", gsname);
710		}
711		else {
712			if (dflag)
713				/*
714				 * get all descriptions for next level
715				 * in one chunk
716				 */
717				getdesc(name, namelen, pnode);
718			req = 0;
719			for (ni = 0; ni < pnode->sysctl_clen; ni++) {
720				name[namelen] = node[ni].sysctl_num;
721				if ((node[ni].sysctl_flags & CTLFLAG_HIDDEN) &&
722				    !(Aflag || req))
723					continue;
724				print_tree(name, namelen + 1, &node[ni],
725					   SYSCTL_TYPE(node[ni].sysctl_flags),
726					   1, re, lastcompiled);
727			}
728		}
729		break;
730	}
731	case CTLTYPE_INT: {
732		int i;
733		rc = prog_sysctl(name, namelen, &i, &sz, NULL, 0);
734		if (rc == -1) {
735			sysctlerror(1);
736			break;
737		}
738		display_number(pnode, gsname, &i, sizeof(i), DISPLAY_VALUE);
739		break;
740	}
741	case CTLTYPE_BOOL: {
742		bool b;
743		rc = prog_sysctl(name, namelen, &b, &sz, NULL, 0);
744		if (rc == -1) {
745			sysctlerror(1);
746			break;
747		}
748		display_number(pnode, gsname, &b, sizeof(b), DISPLAY_VALUE);
749		break;
750	}
751	case CTLTYPE_STRING: {
752		unsigned char buf[1024], *tbuf;
753		tbuf = buf;
754		sz = sizeof(buf);
755		rc = prog_sysctl(&name[0], namelen, tbuf, &sz, NULL, 0);
756		if (rc == -1 && errno == ENOMEM) {
757			tbuf = malloc(sz);
758			if (tbuf == NULL) {
759				sysctlerror(1);
760				break;
761			}
762			rc = prog_sysctl(&name[0], namelen, tbuf, &sz, NULL, 0);
763		}
764		if (rc == -1)
765			sysctlerror(1);
766		else
767			display_string(pnode, gsname, tbuf, sz, DISPLAY_VALUE);
768		if (tbuf != buf)
769			free(tbuf);
770		break;
771	}
772	case CTLTYPE_QUAD: {
773		u_quad_t q;
774		sz = sizeof(q);
775		rc = prog_sysctl(&name[0], namelen, &q, &sz, NULL, 0);
776		if (rc == -1) {
777			sysctlerror(1);
778			break;
779		}
780		display_number(pnode, gsname, &q, sizeof(q), DISPLAY_VALUE);
781		break;
782	}
783	case CTLTYPE_STRUCT: {
784		/*
785		 * we shouldn't actually get here, but if we
786		 * do, would it be nice to have *something* to
787		 * do other than completely ignore the
788		 * request.
789		 */
790		unsigned char *d;
791		if ((d = malloc(sz)) == NULL) {
792			fprintf(warnfp, "%s: !malloc failed!\n", gsname);
793			break;
794		}
795		rc = prog_sysctl(&name[0], namelen, d, &sz, NULL, 0);
796		if (rc == -1) {
797			sysctlerror(1);
798			break;
799		}
800		display_struct(pnode, gsname, d, sz, DISPLAY_VALUE);
801		free(d);
802		break;
803	}
804	default:
805		/* should i print an error here? */
806		break;
807	}
808
809	*sp = *dp = '\0';
810}
811
812/*
813 * ********************************************************************
814 * parse a request, possibly determining that it's a create or destroy
815 * request
816 * ********************************************************************
817 */
818static void
819parse(char *l, regex_t *re, size_t *lastcompiled)
820{
821	struct sysctlnode *node;
822	const struct handlespec *w;
823	int name[CTL_MAXNAME], dodesc = 0;
824	u_int namelen, type;
825	char *key, *value, *dot;
826	size_t sz;
827	bool optional = false;
828
829	req = 1;
830	key = l;
831
832	if ((value = strchr(l, '=')) != NULL) {
833		if (value > l && value[-1] == '?') {
834			value[-1] = '\0';
835			optional = true;
836		}
837		*value++ = '\0';
838	}
839
840	if ((dot = strpbrk(key, "./")) == NULL)
841		sep[0] = '.';
842	else
843		sep[0] = dot[0];
844	sep[1] = '\0';
845
846	while (key[0] == sep[0] && key[1] == sep[0]) {
847		if (value != NULL)
848			value[-1] = '=';
849		if (strncmp(key + 2, "create", 6) == 0 &&
850		    (key[8] == '=' || key[8] == sep[0]))
851			parse_create(key + 8 + (key[8] == '=' ? 1 : 0));
852		else if (strncmp(key + 2, "destroy", 7) == 0 &&
853			 (key[9] == '=' || key[9] == sep[0]))
854			parse_destroy(key + 9 + (key[9] == '=' ? 1 : 0));
855		else if (strncmp(key + 2, "describe", 8) == 0 &&
856			 (key[10] == '=' || key[10] == sep[0])) {
857			key += 10 + (key[10] == '=');
858			if ((value = strchr(key, '=')) != NULL)
859				parse_describe(key);
860			else {
861				if (!dflag)
862					dodesc = 1;
863				break;
864			}
865		}
866		else
867			sysctlperror("unable to parse '%s'\n", key);
868		return;
869	}
870
871	if (stale) {
872		purge_tree(&my_root);
873		stale = 0;
874	}
875	node = &my_root;
876	namelen = CTL_MAXNAME;
877	sz = sizeof(gsname);
878
879	if (sysctlgetmibinfo(key, &name[0], &namelen, gsname, &sz, &node,
880			     SYSCTL_VERSION) == -1) {
881		if (optional)
882			return;
883		sysctlparseerror(namelen, l);
884		EXIT(1);
885	}
886
887	type = SYSCTL_TYPE(node->sysctl_flags);
888
889	if (value == NULL) {
890		if (dodesc)
891			dflag = 1;
892		print_tree(&name[0], namelen, node, type, 0, re, lastcompiled);
893		if (dodesc)
894			dflag = 0;
895		gsname[0] = '\0';
896		return;
897	}
898
899	if (fn)
900		trim_whitespace(value, 1);
901
902	if (!wflag) {
903		sysctlperror("Must specify -w to set variables\n");
904		exit(1);
905	}
906
907	canonicalize(gsname, canonname);
908	if (type != CTLTYPE_NODE && (w = findhandler(canonname, 1, re,
909	    lastcompiled)) != NULL) {
910		(*w->ps_w)(gsname, gdname, value, name, namelen, node, type,
911			   __UNCONST(w->ps_d));
912		gsname[0] = '\0';
913		return;
914	}
915
916	switch (type) {
917	case CTLTYPE_NODE:
918		/*
919		 * XXX old behavior is to print.  should we error instead?
920		 */
921		print_tree(&name[0], namelen, node, CTLTYPE_NODE, 1, re,
922		    lastcompiled);
923		break;
924	case CTLTYPE_INT:
925	case CTLTYPE_BOOL:
926	case CTLTYPE_QUAD:
927		write_number(&name[0], namelen, node, value);
928		break;
929	case CTLTYPE_STRING:
930		write_string(&name[0], namelen, node, value);
931		break;
932	case CTLTYPE_STRUCT:
933		/*
934		 * XXX old behavior is to print.  should we error instead?
935		 */
936		/* fprintf(warnfp, "you can't write to %s\n", gsname); */
937		print_tree(&name[0], namelen, node, type, 0, re, lastcompiled);
938		break;
939	}
940}
941
942/*
943
944  //create=foo.bar.whatever...,
945  [type=(int|quad|string|struct|node),]
946  [size=###,]
947  [n=###,]
948  [flags=(iohxparw12),]
949  [addr=0x####,|symbol=...|value=...]
950
951  size is optional for some types.  type must be set before anything
952  else.  nodes can have [rwhp], but nothing else applies.  if no
953  size or type is given, node is asserted.  writeable is the default,
954  with [rw] being read-only and unconditionally writeable
955  respectively.  if you specify addr, it is assumed to be the name of
956  a kernel symbol, if value, CTLFLAG_OWNDATA will be asserted for
957  strings, CTLFLAG_IMMEDIATE for ints and u_quad_ts.  you cannot
958  specify both value and addr.
959
960*/
961
962static void
963parse_create(char *l)
964{
965	struct sysctlnode node;
966	size_t sz;
967	char *nname, *key, *value, *data, *addr, *c, *t;
968	int name[CTL_MAXNAME], i, rc, method, flags, rw;
969	u_int namelen, type;
970	u_quad_t uq;
971	quad_t q;
972	bool b;
973
974	if (!wflag) {
975		sysctlperror("Must specify -w to create nodes\n");
976		exit(1);
977	}
978
979	/*
980	 * these are the pieces that make up the description of a new
981	 * node
982	 */
983	memset(&node, 0, sizeof(node));
984	node.sysctl_num = CTL_CREATE;  /* any number is fine */
985	flags = 0;
986	rw = -1;
987	type = 0;
988	sz = 0;
989	data = addr = NULL;
990	memset(name, 0, sizeof(name));
991	namelen = 0;
992	method = 0;
993
994	/*
995	 * misc stuff used when constructing
996	 */
997	i = 0;
998	b = false;
999	uq = 0;
1000	key = NULL;
1001	value = NULL;
1002
1003	/*
1004	 * the name of the thing we're trying to create is first, so
1005	 * pick it off.
1006	 */
1007	nname = l;
1008	if ((c = strchr(nname, ',')) != NULL)
1009		*c++ = '\0';
1010
1011	while (c != NULL) {
1012
1013		/*
1014		 * pull off the next "key=value" pair
1015		 */
1016		key = c;
1017		if ((t = strchr(key, '=')) != NULL) {
1018			*t++ = '\0';
1019			value = t;
1020		}
1021		else
1022			value = NULL;
1023
1024		/*
1025		 * if the "key" is "value", then that eats the rest of
1026		 * the string, so we're done, otherwise bite it off at
1027		 * the next comma.
1028		 */
1029		if (strcmp(key, "value") == 0) {
1030			c = NULL;
1031			data = value;
1032			break;
1033		}
1034		else if (value) {
1035			if ((c = strchr(value, ',')) != NULL)
1036				*c++ = '\0';
1037		}
1038
1039		/*
1040		 * note that we (mostly) let the invoker of prog_sysctl(8)
1041		 * play rampant here and depend on the kernel to tell
1042		 * them that they were wrong.  well...within reason.
1043		 * we later check the various parameters against each
1044		 * other to make sure it makes some sort of sense.
1045		 */
1046		if (strcmp(key, "addr") == 0) {
1047			/*
1048			 * we can't check these two.  only the kernel
1049			 * can tell us when it fails to find the name
1050			 * (or if the address is invalid).
1051			 */
1052			if (method != 0) {
1053				sysctlperror(
1054				    "%s: already have %s for new node\n",
1055				    nname,
1056				    method == CTL_CREATE ? "addr" : "symbol");
1057				EXIT(1);
1058			}
1059			if (value == NULL) {
1060				sysctlperror("%s: missing value\n", nname);
1061				EXIT(1);
1062			}
1063			errno = 0;
1064			addr = (void*)strtoul(value, &t, 0);
1065			if (t == value || *t != '\0' || errno != 0) {
1066				sysctlperror(
1067				    "%s: '%s' is not a valid address\n",
1068				    nname, value);
1069				EXIT(1);
1070			}
1071			method = CTL_CREATE;
1072		}
1073		else if (strcmp(key, "symbol") == 0) {
1074			if (method != 0) {
1075				sysctlperror(
1076				    "%s: already have %s for new node\n",
1077				    nname,
1078				    method == CTL_CREATE ? "addr" : "symbol");
1079				EXIT(1);
1080			}
1081			addr = value;
1082			method = CTL_CREATESYM;
1083		}
1084		else if (strcmp(key, "type") == 0) {
1085			if (value == NULL) {
1086				sysctlperror("%s: missing value\n", nname);
1087				EXIT(1);
1088			}
1089			if (strcmp(value, "node") == 0)
1090				type = CTLTYPE_NODE;
1091			else if (strcmp(value, "int") == 0) {
1092				sz = sizeof(int);
1093				type = CTLTYPE_INT;
1094			}
1095			else if (strcmp(value, "bool") == 0) {
1096				sz = sizeof(bool);
1097				type = CTLTYPE_BOOL;
1098			}
1099			else if (strcmp(value, "string") == 0)
1100				type = CTLTYPE_STRING;
1101			else if (strcmp(value, "quad") == 0) {
1102				sz = sizeof(u_quad_t);
1103				type = CTLTYPE_QUAD;
1104			}
1105			else if (strcmp(value, "struct") == 0)
1106				type = CTLTYPE_STRUCT;
1107			else {
1108				sysctlperror(
1109					"%s: '%s' is not a valid type\n",
1110					nname, value);
1111				EXIT(1);
1112			}
1113		}
1114		else if (strcmp(key, "size") == 0) {
1115			if (value == NULL) {
1116				sysctlperror("%s: missing value\n", nname);
1117				EXIT(1);
1118			}
1119			errno = 0;
1120			/*
1121			 * yes, i know size_t is not an unsigned long,
1122			 * but we can all agree that it ought to be,
1123			 * right?
1124			 */
1125			sz = strtoul(value, &t, 0);
1126			if (t == value || *t != '\0' || errno != 0) {
1127				sysctlperror(
1128					"%s: '%s' is not a valid size\n",
1129					nname, value);
1130				EXIT(1);
1131			}
1132		}
1133		else if (strcmp(key, "n") == 0) {
1134			if (value == NULL) {
1135				sysctlperror("%s: missing value\n", nname);
1136				EXIT(1);
1137			}
1138			errno = 0;
1139			q = strtoll(value, &t, 0);
1140			if (t == value || *t != '\0' || errno != 0 ||
1141			    q < INT_MIN || q > UINT_MAX) {
1142				sysctlperror(
1143				    "%s: '%s' is not a valid mib number\n",
1144				    nname, value);
1145				EXIT(1);
1146			}
1147			node.sysctl_num = (int)q;
1148		}
1149		else if (strcmp(key, "flags") == 0) {
1150			if (value == NULL) {
1151				sysctlperror("%s: missing value\n", nname);
1152				EXIT(1);
1153			}
1154			t = value;
1155			while (*t != '\0') {
1156				switch (*t) {
1157				case 'a':
1158					flags |= CTLFLAG_ANYWRITE;
1159					break;
1160				case 'h':
1161					flags |= CTLFLAG_HIDDEN;
1162					break;
1163				case 'i':
1164					flags |= CTLFLAG_IMMEDIATE;
1165					break;
1166				case 'o':
1167					flags |= CTLFLAG_OWNDATA;
1168					break;
1169				case 'p':
1170					flags |= CTLFLAG_PRIVATE;
1171					break;
1172				case 'x':
1173					flags |= CTLFLAG_HEX;
1174					break;
1175
1176				case 'r':
1177					rw = CTLFLAG_READONLY;
1178					break;
1179				case 'w':
1180					rw = CTLFLAG_READWRITE;
1181					break;
1182				default:
1183					sysctlperror(
1184					   "%s: '%c' is not a valid flag\n",
1185					    nname, *t);
1186					EXIT(1);
1187				}
1188				t++;
1189			}
1190		}
1191		else {
1192			sysctlperror("%s: unrecognized keyword '%s'\n",
1193				     nname, key);
1194			EXIT(1);
1195		}
1196	}
1197
1198	/*
1199	 * now that we've finished parsing the given string, fill in
1200	 * anything they didn't specify
1201	 */
1202	if (type == 0)
1203		type = CTLTYPE_NODE;
1204
1205	/*
1206	 * the "data" can be interpreted various ways depending on the
1207	 * type of node we're creating, as can the size
1208	 */
1209	if (data != NULL) {
1210		if (addr != NULL) {
1211			sysctlperror(
1212				"%s: cannot specify both value and "
1213				"address\n", nname);
1214			EXIT(1);
1215		}
1216
1217		switch (type) {
1218		case CTLTYPE_INT:
1219			errno = 0;
1220			q = strtoll(data, &t, 0);
1221			if (t == data || *t != '\0' || errno != 0 ||
1222				q < INT_MIN || q > UINT_MAX) {
1223				sysctlperror(
1224				    "%s: '%s' is not a valid integer\n",
1225				    nname, value);
1226				EXIT(1);
1227			}
1228			i = (int)q;
1229			if (!(flags & CTLFLAG_OWNDATA)) {
1230				flags |= CTLFLAG_IMMEDIATE;
1231				node.sysctl_idata = i;
1232			}
1233			else
1234				node.sysctl_data = &i;
1235			if (sz == 0)
1236				sz = sizeof(int);
1237			break;
1238		case CTLTYPE_BOOL:
1239			errno = 0;
1240			q = strtoll(data, &t, 0);
1241			if (t == data || *t != '\0' || errno != 0 ||
1242				(q != 0 && q != 1)) {
1243				sysctlperror(
1244				    "%s: '%s' is not a valid bool\n",
1245				    nname, value);
1246				EXIT(1);
1247			}
1248			b = q == 1;
1249			if (!(flags & CTLFLAG_OWNDATA)) {
1250				flags |= CTLFLAG_IMMEDIATE;
1251				node.sysctl_idata = b;
1252			}
1253			else
1254				node.sysctl_data = &b;
1255			if (sz == 0)
1256				sz = sizeof(bool);
1257			break;
1258		case CTLTYPE_STRING:
1259			flags |= CTLFLAG_OWNDATA;
1260			node.sysctl_data = data;
1261			if (sz == 0)
1262				sz = strlen(data) + 1;
1263			else if (sz < strlen(data) + 1) {
1264				sysctlperror("%s: ignoring size=%zu for "
1265					"string node, too small for given "
1266					"value\n", nname, sz);
1267				sz = strlen(data) + 1;
1268			}
1269			break;
1270		case CTLTYPE_QUAD:
1271			errno = 0;
1272			uq = strtouq(data, &t, 0);
1273			if (t == data || *t != '\0' || errno != 0) {
1274				sysctlperror(
1275					"%s: '%s' is not a valid quad\n",
1276					nname, value);
1277				EXIT(1);
1278			}
1279			if (!(flags & CTLFLAG_OWNDATA)) {
1280				flags |= CTLFLAG_IMMEDIATE;
1281				node.sysctl_qdata = uq;
1282			}
1283			else
1284				node.sysctl_data = &uq;
1285			if (sz == 0)
1286				sz = sizeof(u_quad_t);
1287			break;
1288		case CTLTYPE_STRUCT:
1289			sysctlperror("%s: struct not initializable\n",
1290				     nname);
1291			EXIT(1);
1292		}
1293
1294		/*
1295		 * these methods have all provided local starting
1296		 * values that the kernel must copy in
1297		 */
1298	}
1299
1300	/*
1301	 * hmm...no data, but we have an address of data.  that's
1302	 * fine.
1303	 */
1304	else if (addr != 0)
1305		node.sysctl_data = (void*)addr;
1306
1307	/*
1308	 * no data and no address?  well...okay.  we might be able to
1309	 * manage that.
1310	 */
1311	else if (type != CTLTYPE_NODE) {
1312		if (sz == 0) {
1313			sysctlperror(
1314			    "%s: need a size or a starting value\n",
1315			    nname);
1316                        EXIT(1);
1317                }
1318		if (!(flags & CTLFLAG_IMMEDIATE))
1319			flags |= CTLFLAG_OWNDATA;
1320	}
1321
1322	/*
1323	 * now we do a few sanity checks on the description we've
1324	 * assembled
1325	 */
1326	if ((flags & CTLFLAG_IMMEDIATE) &&
1327	    (type == CTLTYPE_STRING || type == CTLTYPE_STRUCT)) {
1328		sysctlperror("%s: cannot make an immediate %s\n",
1329			     nname,
1330			     (type == CTLTYPE_STRING) ? "string" : "struct");
1331		EXIT(1);
1332	}
1333	if (type == CTLTYPE_NODE && node.sysctl_data != NULL) {
1334		sysctlperror("%s: nodes do not have data\n", nname);
1335		EXIT(1);
1336	}
1337
1338	/*
1339	 * some types must have a particular size
1340	 */
1341	if (sz != 0) {
1342		if ((type == CTLTYPE_INT && sz != sizeof(int)) ||
1343		    (type == CTLTYPE_BOOL && sz != sizeof(bool)) ||
1344		    (type == CTLTYPE_QUAD && sz != sizeof(u_quad_t)) ||
1345		    (type == CTLTYPE_NODE && sz != 0)) {
1346			sysctlperror("%s: wrong size for type\n", nname);
1347			EXIT(1);
1348		}
1349	}
1350	else if (type == CTLTYPE_STRUCT) {
1351		sysctlperror("%s: struct must have size\n", nname);
1352		EXIT(1);
1353	}
1354
1355	/*
1356	 * now...if no one said anything yet, we default nodes or
1357	 * any type that owns data being writeable, and everything
1358	 * else being readonly.
1359	 */
1360	if (rw == -1) {
1361		if (type == CTLTYPE_NODE ||
1362		    (flags & (CTLFLAG_OWNDATA|CTLFLAG_IMMEDIATE)))
1363			rw = CTLFLAG_READWRITE;
1364		else
1365			rw = CTLFLAG_READONLY;
1366	}
1367
1368	/*
1369	 * if a kernel address was specified, that can't be made
1370	 * writeable by us.
1371	if (rw != CTLFLAG_READONLY && addr) {
1372		sysctlperror("%s: kernel data can only be readable\n", nname);
1373		EXIT(1);
1374	}
1375	 */
1376
1377	/*
1378	 * what separator were they using in the full name of the new
1379	 * node?
1380	 */
1381	if ((t = strpbrk(nname, "./")) == NULL)
1382		sep[0] = '.';
1383	else
1384		sep[0] = t[0];
1385	sep[1] = '\0';
1386
1387	/*
1388	 * put it all together, now.  t'ain't much, is it?
1389	 */
1390	node.sysctl_flags = SYSCTL_VERSION|flags|rw|type;
1391	node.sysctl_size = sz;
1392	t = strrchr(nname, sep[0]);
1393	if (t != NULL)
1394		strlcpy(node.sysctl_name, t + 1, sizeof(node.sysctl_name));
1395	else
1396		strlcpy(node.sysctl_name, nname, sizeof(node.sysctl_name));
1397	if (t == nname)
1398		t = NULL;
1399
1400	/*
1401	 * if this is a new top-level node, then we don't need to find
1402	 * the mib for its parent
1403	 */
1404	if (t == NULL) {
1405		namelen = 0;
1406		gsname[0] = '\0';
1407	}
1408
1409	/*
1410	 * on the other hand, if it's not a top-level node...
1411	 */
1412	else {
1413		namelen = sizeof(name) / sizeof(name[0]);
1414		sz = sizeof(gsname);
1415		*t = '\0';
1416		rc = sysctlgetmibinfo(nname, &name[0], &namelen,
1417				      gsname, &sz, NULL, SYSCTL_VERSION);
1418		*t = sep[0];
1419		if (rc == -1) {
1420			sysctlparseerror(namelen, nname);
1421			EXIT(1);
1422		}
1423	}
1424
1425	/*
1426	 * yes, a new node is being created
1427	 */
1428	if (method != 0)
1429		name[namelen++] = method;
1430	else
1431		name[namelen++] = CTL_CREATE;
1432
1433	sz = sizeof(node);
1434	rc = prog_sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node));
1435
1436	if (rc == -1) {
1437		sysctlperror("%s: CTL_CREATE failed: %s\n",
1438			     nname, strerror(errno));
1439		EXIT(1);
1440	}
1441	else {
1442		if (!qflag && !nflag)
1443			printf("%s(%s): (created)\n", nname, st(type));
1444		stale = 1;
1445	}
1446}
1447
1448static void
1449parse_destroy(char *l)
1450{
1451	struct sysctlnode node;
1452	size_t sz;
1453	int name[CTL_MAXNAME], rc;
1454	u_int namelen;
1455
1456	if (!wflag) {
1457		sysctlperror("Must specify -w to destroy nodes\n");
1458		exit(1);
1459	}
1460
1461	memset(name, 0, sizeof(name));
1462	namelen = sizeof(name) / sizeof(name[0]);
1463	sz = sizeof(gsname);
1464	rc = sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL,
1465			      SYSCTL_VERSION);
1466	if (rc == -1) {
1467		sysctlparseerror(namelen, l);
1468		EXIT(1);
1469	}
1470
1471	memset(&node, 0, sizeof(node));
1472	node.sysctl_flags = SYSCTL_VERSION;
1473	node.sysctl_num = name[namelen - 1];
1474	name[namelen - 1] = CTL_DESTROY;
1475
1476	sz = sizeof(node);
1477	rc = prog_sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node));
1478
1479	if (rc == -1) {
1480		sysctlperror("%s: CTL_DESTROY failed: %s\n",
1481			     l, strerror(errno));
1482		EXIT(1);
1483	}
1484	else {
1485		if (!qflag && !nflag)
1486			printf("%s(%s): (destroyed)\n", gsname,
1487			       st(SYSCTL_TYPE(node.sysctl_flags)));
1488		stale = 1;
1489	}
1490}
1491
1492static void
1493parse_describe(char *l)
1494{
1495	struct sysctlnode newdesc;
1496	char buf[1024], *value;
1497	struct sysctldesc *d = (void*)&buf[0];
1498	int name[CTL_MAXNAME], rc;
1499	u_int namelen;
1500	size_t sz;
1501
1502	if (!wflag) {
1503		sysctlperror("Must specify -w to set descriptions\n");
1504		exit(1);
1505	}
1506
1507	value = strchr(l, '=');
1508	*value++ = '\0';
1509
1510	memset(name, 0, sizeof(name));
1511	namelen = sizeof(name) / sizeof(name[0]);
1512	sz = sizeof(gsname);
1513	rc = sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL,
1514			      SYSCTL_VERSION);
1515	if (rc == -1) {
1516		sysctlparseerror(namelen, l);
1517		EXIT(1);
1518	}
1519
1520	sz = sizeof(buf);
1521	memset(&newdesc, 0, sizeof(newdesc));
1522	newdesc.sysctl_flags = SYSCTL_VERSION|CTLFLAG_OWNDESC;
1523	newdesc.sysctl_num = name[namelen - 1];
1524	newdesc.sysctl_desc = value;
1525	name[namelen - 1] = CTL_DESCRIBE;
1526	rc = prog_sysctl(name, namelen, d, &sz, &newdesc, sizeof(newdesc));
1527	if (rc == -1)
1528		sysctlperror("%s: CTL_DESCRIBE failed: %s\n",
1529			     gsname, strerror(errno));
1530	else if (d->descr_len == 1)
1531		sysctlperror("%s: description not set\n", gsname);
1532	else if (!qflag && !nflag)
1533		printf("%s: %s\n", gsname, d->descr_str);
1534}
1535
1536/*
1537 * ********************************************************************
1538 * when things go wrong...
1539 * ********************************************************************
1540 */
1541static void
1542usage(void)
1543{
1544	const char *progname = getprogname();
1545
1546	(void)fprintf(stderr,
1547		      "usage:\t%s %s\n"
1548		      "\t%s %s\n"
1549		      "\t%s %s\n"
1550		      "\t%s %s\n"
1551		      "\t%s %s\n"
1552		      "\t%s %s\n",
1553		      progname, "[-dneq] [-x[x]|-r] variable ...",
1554		      progname, "[-ne] [-q] -w variable=value ...",
1555		      progname, "[-dne] -a",
1556		      progname, "[-dne] -A",
1557		      progname, "[-ne] -M",
1558		      progname, "[-dne] [-q] -f file");
1559	exit(1);
1560}
1561
1562static void
1563getdesc1(int *name, u_int namelen, struct sysctlnode *pnode)
1564{
1565	struct sysctlnode node;
1566	char buf[1024], *desc;
1567	struct sysctldesc *d = (void*)buf;
1568	size_t sz = sizeof(buf);
1569	int rc;
1570
1571	memset(&node, 0, sizeof(node));
1572	node.sysctl_flags = SYSCTL_VERSION;
1573	node.sysctl_num = name[namelen - 1];
1574	name[namelen - 1] = CTL_DESCRIBE;
1575	rc = prog_sysctl(name, namelen, d, &sz, &node, sizeof(node));
1576
1577	if (rc == -1 ||
1578	    d->descr_len == 1 ||
1579	    d->descr_num != pnode->sysctl_num ||
1580	    d->descr_ver != pnode->sysctl_ver)
1581		desc = (char *)-1;
1582	else
1583		desc = malloc(d->descr_len);
1584
1585	if (desc == NULL)
1586		desc = (char *)-1;
1587	if (desc != (char *)-1)
1588		memcpy(desc, &d->descr_str[0], d->descr_len);
1589	name[namelen - 1] = node.sysctl_num;
1590	if (pnode->sysctl_desc != NULL &&
1591	    pnode->sysctl_desc != (const char *)-1)
1592		free(__UNCONST(pnode->sysctl_desc));
1593	pnode->sysctl_desc = desc;
1594}
1595
1596static void
1597getdesc(int *name, u_int namelen, struct sysctlnode *pnode)
1598{
1599	struct sysctlnode *node = pnode->sysctl_child;
1600	struct sysctldesc *d, *p, *plim;
1601	char *desc;
1602	size_t i, sz;
1603	int rc;
1604
1605	sz = 128 * pnode->sysctl_clen;
1606	name[namelen] = CTL_DESCRIBE;
1607
1608	/*
1609	 * attempt *twice* to get the description chunk.  if two tries
1610	 * doesn't work, give up.
1611	 */
1612	i = 0;
1613	do {
1614		d = malloc(sz);
1615		if (d == NULL)
1616			return;
1617		rc = prog_sysctl(name, namelen + 1, d, &sz, NULL, 0);
1618		if (rc == -1) {
1619			free(d);
1620			d = NULL;
1621			if (i == 0 && errno == ENOMEM)
1622				i = 1;
1623			else
1624				return;
1625		}
1626	} while (d == NULL);
1627
1628	/*
1629	 * hokey nested loop here, giving O(n**2) behavior, but should
1630	 * suffice for now
1631	 */
1632	plim = /*LINTED ptr cast*/(struct sysctldesc *)((char*)d + sz);
1633	for (i = 0; i < pnode->sysctl_clen; i++) {
1634		node = &pnode->sysctl_child[i];
1635		for (p = d; p < plim; p = NEXT_DESCR(p))
1636			if (node->sysctl_num == p->descr_num)
1637				break;
1638		if (p < plim && node->sysctl_ver == p->descr_ver) {
1639			/*
1640			 * match found, attempt to attach description
1641			 */
1642			if (p->descr_len == 1)
1643				desc = NULL;
1644			else
1645				desc = malloc(p->descr_len);
1646			if (desc == NULL)
1647				desc = (char *)-1;
1648			else
1649				memcpy(desc, &p->descr_str[0], p->descr_len);
1650			node->sysctl_desc = desc;
1651		}
1652	}
1653
1654	free(d);
1655}
1656
1657static void
1658trim_whitespace(char *s, int dir)
1659{
1660	char *i, *o;
1661
1662	i = o = s;
1663	if (dir & 1)
1664		while (isspace((unsigned char)*i))
1665			i++;
1666	while ((*o++ = *i++) != '\0');
1667	o -= 2; /* already past nul, skip back to before it */
1668	if (dir & 2)
1669		while (o > s && isspace((unsigned char)*o))
1670			*o-- = '\0';
1671}
1672
1673void
1674sysctlerror(int soft)
1675{
1676	if (soft) {
1677		switch (errno) {
1678		case ENOENT:
1679		case ENOPROTOOPT:
1680		case ENOTDIR:
1681		case EINVAL:
1682		case EOPNOTSUPP:
1683		case EPROTONOSUPPORT:
1684			if (Aflag || req)
1685				sysctlperror("%s: the value is not available\n",
1686					     gsname);
1687			return;
1688		}
1689	}
1690
1691	if (Aflag || req)
1692		sysctlperror("%s: %s\n", gsname, strerror(errno));
1693	if (!soft)
1694		EXIT(1);
1695}
1696
1697void
1698sysctlparseerror(u_int namelen, const char *pname)
1699{
1700
1701	if (qflag) {
1702		errs++;
1703		return;
1704	}
1705	sysctlperror("%s level name '%s' in '%s' is invalid\n",
1706		     lname[namelen], gsname, pname);
1707}
1708
1709static void
1710sysctlperror(const char *fmt, ...)
1711{
1712	va_list ap;
1713
1714	(void)fprintf(warnfp, "%s: ", getprogname());
1715	if (fn)
1716		(void)fprintf(warnfp, "%s#%zu: ", fn, nr);
1717	va_start(ap, fmt);
1718	(void)vfprintf(warnfp, fmt, ap);
1719	va_end(ap);
1720	errs++;
1721}
1722
1723
1724/*
1725 * ********************************************************************
1726 * how to write to a "simple" node
1727 * ********************************************************************
1728 */
1729static void
1730write_number(int *name, u_int namelen, struct sysctlnode *node, char *value)
1731{
1732	u_int ii, io;
1733	u_quad_t qi, qo;
1734	size_t si, so;
1735	bool bi, bo;
1736	int rc;
1737	void *i, *o;
1738	char *t;
1739
1740	if (fn)
1741		trim_whitespace(value, 3);
1742
1743	si = so = 0;
1744	i = o = NULL;
1745	bi = bo = false;
1746	errno = 0;
1747	qi = strtouq(value, &t, 0);
1748	if (qi == UQUAD_MAX && errno == ERANGE) {
1749		sysctlperror("%s: %s\n", value, strerror(errno));
1750		EXIT(1);
1751	}
1752	if (t == value || *t != '\0') {
1753		sysctlperror("%s: not a number\n", value);
1754		EXIT(1);
1755	}
1756
1757	switch (SYSCTL_TYPE(node->sysctl_flags)) {
1758	case CTLTYPE_INT:
1759		ii = (u_int)qi;
1760		io = (u_int)(qi >> 32);
1761		if (io != (u_int)-1 && io != 0) {
1762			sysctlperror("%s: %s\n", value, strerror(ERANGE));
1763			EXIT(1);
1764		}
1765		o = &io;
1766		so = sizeof(io);
1767		i = &ii;
1768		si = sizeof(ii);
1769		break;
1770	case CTLTYPE_BOOL:
1771		bi = (bool)qi;
1772		o = &bo;
1773		so = sizeof(bo);
1774		i = &bi;
1775		si = sizeof(bi);
1776		break;
1777	case CTLTYPE_QUAD:
1778		o = &qo;
1779		so = sizeof(qo);
1780		i = &qi;
1781		si = sizeof(qi);
1782		break;
1783	}
1784
1785	rc = prog_sysctl(name, namelen, o, &so, i, si);
1786	if (rc == -1) {
1787		sysctlerror(0);
1788		return;
1789	}
1790
1791	switch (SYSCTL_TYPE(node->sysctl_flags)) {
1792	case CTLTYPE_INT:
1793		display_number(node, gsname, &io, sizeof(io), DISPLAY_OLD);
1794		display_number(node, gsname, &ii, sizeof(ii), DISPLAY_NEW);
1795		break;
1796	case CTLTYPE_BOOL:
1797		display_number(node, gsname, &bo, sizeof(bo), DISPLAY_OLD);
1798		display_number(node, gsname, &bi, sizeof(bi), DISPLAY_NEW);
1799		break;
1800	case CTLTYPE_QUAD:
1801		display_number(node, gsname, &qo, sizeof(qo), DISPLAY_OLD);
1802		display_number(node, gsname, &qi, sizeof(qi), DISPLAY_NEW);
1803		break;
1804	}
1805}
1806
1807static void
1808write_string(int *name, u_int namelen, struct sysctlnode *node, char *value)
1809{
1810	char *i, *o;
1811	size_t si, so;
1812	int rc;
1813
1814	i = value;
1815	si = strlen(i) + 1;
1816	so = node->sysctl_size;
1817	if (si > so && so != 0) {
1818		sysctlperror("%s: string too long\n", value);
1819		EXIT(1);
1820	}
1821	o = malloc(so);
1822	if (o == NULL) {
1823		sysctlperror("%s: !malloc failed!\n", gsname);
1824		exit(1);
1825	}
1826
1827	rc = prog_sysctl(name, namelen, o, &so, i, si);
1828	if (rc == -1) {
1829		sysctlerror(0);
1830		return;
1831	}
1832
1833	display_string(node, gsname, o, so, DISPLAY_OLD);
1834	display_string(node, gsname, i, si, DISPLAY_NEW);
1835	free(o);
1836}
1837
1838/*
1839 * ********************************************************************
1840 * simple ways to print stuff consistently
1841 * ********************************************************************
1842 */
1843static void
1844display_number(const struct sysctlnode *node, const char *name,
1845	       const void *data, size_t sz, int n)
1846{
1847	u_quad_t q;
1848	bool b;
1849	int i;
1850
1851	if (qflag)
1852		return;
1853	if ((nflag || rflag) && (n == DISPLAY_OLD))
1854		return;
1855
1856	if (rflag && n != DISPLAY_OLD) {
1857		fwrite(data, sz, 1, stdout);
1858		return;
1859	}
1860
1861	if (!nflag) {
1862		if (n == DISPLAY_VALUE)
1863			printf("%s%s", name, eq);
1864		else if (n == DISPLAY_OLD)
1865			printf("%s: ", name);
1866	}
1867
1868	if (xflag > 1) {
1869		if (n != DISPLAY_NEW)
1870			printf("\n");
1871		hex_dump(data, sz);
1872		return;
1873	}
1874
1875	switch (SYSCTL_TYPE(node->sysctl_flags)) {
1876	case CTLTYPE_INT:
1877		memcpy(&i, data, sz);
1878		if (xflag)
1879			printf("0x%0*x", (int)sz * 2, i);
1880		else if (node->sysctl_flags & CTLFLAG_HEX)
1881			printf("%#x", i);
1882		else
1883			printf("%d", i);
1884		break;
1885	case CTLTYPE_BOOL:
1886		memcpy(&b, data, sz);
1887		if (xflag)
1888			printf("0x%0*x", (int)sz * 2, b);
1889		else if (node->sysctl_flags & CTLFLAG_HEX)
1890			printf("%#x", b);
1891		else
1892			printf("%d", b);
1893		break;
1894	case CTLTYPE_QUAD:
1895		memcpy(&q, data, sz);
1896		if (xflag)
1897			printf("0x%0*" PRIx64, (int)sz * 2, q);
1898		else if (node->sysctl_flags & CTLFLAG_HEX)
1899			printf("%#" PRIx64, q);
1900		else
1901			printf("%" PRIu64, q);
1902		break;
1903	}
1904
1905	if (n == DISPLAY_OLD)
1906		printf(" -> ");
1907	else
1908		printf("\n");
1909}
1910
1911static void
1912display_string(const struct sysctlnode *node, const char *name,
1913	       const void *data, size_t sz, int n)
1914{
1915	const unsigned char *buf = data;
1916	int ni;
1917
1918	if (qflag)
1919		return;
1920	if ((nflag || rflag) && (n == DISPLAY_OLD))
1921		return;
1922
1923	if (rflag && n != DISPLAY_OLD) {
1924		fwrite(data, sz, 1, stdout);
1925		return;
1926	}
1927
1928	if (!nflag) {
1929		if (n == DISPLAY_VALUE)
1930			printf("%s%s", name, eq);
1931		else if (n == DISPLAY_OLD)
1932			printf("%s: ", name);
1933	}
1934
1935	if (xflag > 1) {
1936		if (n != DISPLAY_NEW)
1937			printf("\n");
1938		hex_dump(data, sz);
1939		return;
1940	}
1941
1942	if (xflag || node->sysctl_flags & CTLFLAG_HEX) {
1943		for (ni = 0; ni < (int)sz; ni++) {
1944			if (xflag)
1945				printf("%02x", buf[ni]);
1946			if (buf[ni] == '\0')
1947				break;
1948			if (!xflag)
1949				printf("\\x%2.2x", buf[ni]);
1950		}
1951	}
1952	else
1953		printf("%.*s", (int)sz, buf);
1954
1955	if (n == DISPLAY_OLD)
1956		printf(" -> ");
1957	else
1958		printf("\n");
1959}
1960
1961/*ARGSUSED*/
1962static void
1963display_struct(const struct sysctlnode *node, const char *name,
1964	       const void *data, size_t sz, int n)
1965{
1966	const unsigned char *buf = data;
1967	int ni;
1968	size_t more;
1969
1970	if (qflag)
1971		return;
1972	if (!(xflag || rflag)) {
1973		if (Aflag || req)
1974			sysctlperror(
1975			    "%s: this type is unknown to this program\n",
1976			    gsname);
1977		return;
1978	}
1979	if ((nflag || rflag) && (n == DISPLAY_OLD))
1980		return;
1981
1982	if (rflag && n != DISPLAY_OLD) {
1983		fwrite(data, sz, 1, stdout);
1984		return;
1985	}
1986
1987        if (!nflag) {
1988                if (n == DISPLAY_VALUE)
1989                        printf("%s%s", name, eq);
1990                else if (n == DISPLAY_OLD)
1991                        printf("%s: ", name);
1992        }
1993
1994	if (xflag > 1) {
1995		if (n != DISPLAY_NEW)
1996			printf("\n");
1997		hex_dump(data, sz);
1998		return;
1999	}
2000
2001	if (sz > 16) {
2002		more = sz - 16;
2003		sz = 16;
2004	}
2005	else
2006		more = 0;
2007	for (ni = 0; ni < (int)sz; ni++)
2008		printf("%02x", buf[ni]);
2009	if (more)
2010		printf("...(%zu more bytes)", more);
2011	printf("\n");
2012}
2013
2014static void
2015hex_dump(const unsigned char *buf, size_t len)
2016{
2017	unsigned int i;
2018	int j;
2019	char line[80], tmp[12];
2020
2021	memset(line, ' ', sizeof(line));
2022	for (i = 0, j = 15; i < len; i++) {
2023		j = i % 16;
2024		/* reset line */
2025		if (j == 0) {
2026			line[58] = '|';
2027			line[77] = '|';
2028			line[78] = 0;
2029			snprintf(tmp, sizeof(tmp), "%07x", i);
2030			memcpy(&line[0], tmp, 7);
2031		}
2032		/* copy out hex version of byte */
2033		snprintf(tmp, sizeof(tmp), "%02x", buf[i]);
2034		memcpy(&line[9 + j * 3], tmp, 2);
2035		/* copy out plain version of byte */
2036		line[60 + j] = (isprint(buf[i])) ? buf[i] : '.';
2037		/* print a full line and erase it */
2038		if (j == 15) {
2039			printf("%s\n", line);
2040			memset(line, ' ', sizeof(line));
2041		}
2042	}
2043	if (line[0] != ' ')
2044		printf("%s\n", line);
2045	printf("%07zu bytes\n", len);
2046}
2047
2048/*
2049 * ********************************************************************
2050 * functions that handle particular nodes
2051 * ********************************************************************
2052 */
2053/*ARGSUSED*/
2054static void
2055printother(HANDLER_ARGS)
2056{
2057	int rc;
2058	void *p;
2059	size_t sz1, sz2;
2060
2061	if (!(Aflag || req) || Mflag)
2062		return;
2063
2064	/*
2065	 * okay...you asked for it, so let's give it a go
2066	 */
2067	while (type != CTLTYPE_NODE && (xflag || rflag)) {
2068		rc = prog_sysctl(name, namelen, NULL, &sz1, NULL, 0);
2069		if (rc == -1 || sz1 == 0)
2070			break;
2071		p = malloc(sz1);
2072		if (p == NULL)
2073			break;
2074		sz2 = sz1;
2075		rc = prog_sysctl(name, namelen, p, &sz2, NULL, 0);
2076		if (rc == -1 || sz1 != sz2) {
2077			free(p);
2078			break;
2079		}
2080		display_struct(pnode, gsname, p, sz1, DISPLAY_VALUE);
2081		free(p);
2082		return;
2083	}
2084
2085	/*
2086	 * that didn't work...do we have a specific message for this
2087	 * thing?
2088	 */
2089	if (v != NULL) {
2090		sysctlperror("%s: use '%s' to view this information\n",
2091			     gsname, (const char *)v);
2092		return;
2093	}
2094
2095	/*
2096	 * hmm...i wonder if we have any generic hints?
2097	 */
2098	switch (name[0]) {
2099	case CTL_NET:
2100		sysctlperror("%s: use 'netstat' to view this information\n",
2101			     sname);
2102		break;
2103	case CTL_DEBUG:
2104		sysctlperror("%s: missing 'options DEBUG' from kernel?\n",
2105			     sname);
2106		break;
2107	case CTL_DDB:
2108		sysctlperror("%s: missing 'options DDB' from kernel?\n",
2109			     sname);
2110		break;
2111	case CTL_VENDOR:
2112		sysctlperror("%s: no vendor extensions installed\n",
2113			     sname);
2114		break;
2115	}
2116}
2117
2118/*ARGSUSED*/
2119static void
2120kern_clockrate(HANDLER_ARGS)
2121{
2122	struct clockinfo clkinfo;
2123	size_t sz;
2124	int rc;
2125
2126	sz = sizeof(clkinfo);
2127	rc = prog_sysctl(name, namelen, &clkinfo, &sz, NULL, 0);
2128	if (rc == -1) {
2129		sysctlerror(1);
2130		return;
2131	}
2132	if (sz != sizeof(clkinfo))
2133		errx(1, "%s: !returned size wrong!", sname);
2134
2135	if (xflag || rflag) {
2136		display_struct(pnode, sname, &clkinfo, sz,
2137			       DISPLAY_VALUE);
2138		return;
2139	}
2140	else if (!nflag)
2141		printf("%s: ", sname);
2142	printf("tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
2143	       clkinfo.tick, clkinfo.tickadj,
2144	       clkinfo.hz, clkinfo.profhz, clkinfo.stathz);
2145}
2146
2147/*ARGSUSED*/
2148static void
2149kern_boottime(HANDLER_ARGS)
2150{
2151	struct timeval timeval;
2152	time_t boottime;
2153	size_t sz;
2154	int rc;
2155
2156	sz = sizeof(timeval);
2157	rc = prog_sysctl(name, namelen, &timeval, &sz, NULL, 0);
2158	if (rc == -1) {
2159		sysctlerror(1);
2160		return;
2161	}
2162	if (sz != sizeof(timeval))
2163		errx(1, "%s: !returned size wrong!", sname);
2164
2165	boottime = timeval.tv_sec;
2166	if (xflag || rflag)
2167		display_struct(pnode, sname, &timeval, sz,
2168			       DISPLAY_VALUE);
2169	else if (!nflag)
2170		/* ctime() provides the \n */
2171		printf("%s%s%s", sname, eq, ctime(&boottime));
2172	else if (nflag == 1)
2173		printf("%ld\n", (long)boottime);
2174	else
2175		printf("%ld.%06ld\n", (long)timeval.tv_sec,
2176		       (long)timeval.tv_usec);
2177}
2178
2179/*ARGSUSED*/
2180static void
2181kern_consdev(HANDLER_ARGS)
2182{
2183	dev_t cons;
2184	size_t sz;
2185	int rc;
2186
2187	sz = sizeof(cons);
2188	rc = prog_sysctl(name, namelen, &cons, &sz, NULL, 0);
2189	if (rc == -1) {
2190		sysctlerror(1);
2191		return;
2192	}
2193	if (sz != sizeof(cons))
2194		errx(1, "%s: !returned size wrong!", sname);
2195
2196	if (xflag || rflag)
2197		display_struct(pnode, sname, &cons, sz,
2198			       DISPLAY_VALUE);
2199	else {
2200		if (!nflag)
2201			printf("%s%s", sname, eq);
2202		if (nflag < 2 && (sname = devname(cons, S_IFCHR)) != NULL)
2203			printf("%s\n", sname);
2204		else
2205			printf("0x%llx\n", (unsigned long long)cons);
2206	}
2207}
2208
2209/*ARGSUSED*/
2210static void
2211kern_cp_time(HANDLER_ARGS)
2212{
2213	u_int64_t *cp_time;
2214	size_t sz, osz;
2215	int rc, i, n;
2216	char s[sizeof("kern.cp_time.nnnnnn")];
2217	const char *tname;
2218
2219	/*
2220	 * three things to do here.
2221	 * case 1: get sum (no Aflag and namelen == 2)
2222	 * case 2: get specific processor (namelen == 3)
2223	 * case 3: get all processors (Aflag and namelen == 2)
2224	 */
2225
2226	if (namelen == 2 && Aflag) {
2227		sz = sizeof(n);
2228		rc = sysctlbyname("hw.ncpu", &n, &sz, NULL, 0);
2229		if (rc != 0)
2230			return; /* XXX print an error, eh? */
2231		n++; /* Add on space for the sum. */
2232		sz = n * sizeof(u_int64_t) * CPUSTATES;
2233	}
2234	else {
2235		n = -1; /* Just print one data set. */
2236		sz = sizeof(u_int64_t) * CPUSTATES;
2237	}
2238
2239	cp_time = malloc(sz);
2240	if (cp_time == NULL) {
2241		sysctlerror(1);
2242		return;
2243	}
2244
2245	osz = sz;
2246	rc = prog_sysctl(name, namelen, cp_time + (n != -1) * CPUSTATES, &osz,
2247		    NULL, 0);
2248
2249	if (rc == -1) {
2250		sysctlerror(1);
2251		free(cp_time);
2252		return;
2253	}
2254
2255	/*
2256	 * Check, but account for space we'll occupy with the sum.
2257	 */
2258	if (osz != sz - (n != -1) * CPUSTATES * sizeof(u_int64_t))
2259		errx(1, "%s: !returned size wrong!", sname);
2260
2261	/*
2262	 * Compute the actual sum.  Two calls would be easier (we
2263	 * could just call ourselves recursively above), but the
2264	 * numbers wouldn't add up.
2265	 */
2266	if (n != -1) {
2267		memset(cp_time, 0, sizeof(u_int64_t) * CPUSTATES);
2268		for (i = 1; i < n; i++) {
2269			cp_time[CP_USER] += cp_time[i * CPUSTATES + CP_USER];
2270                        cp_time[CP_NICE] += cp_time[i * CPUSTATES + CP_NICE];
2271                        cp_time[CP_SYS] += cp_time[i * CPUSTATES + CP_SYS];
2272                        cp_time[CP_INTR] += cp_time[i * CPUSTATES + CP_INTR];
2273                        cp_time[CP_IDLE] += cp_time[i * CPUSTATES + CP_IDLE];
2274		}
2275	}
2276
2277	tname = sname;
2278	for (i = 0; n == -1 || i < n; i++) {
2279		if (i > 0) {
2280			(void)snprintf(s, sizeof(s), "%s%s%d", sname, sep,
2281				       i - 1);
2282			tname = s;
2283		}
2284		if (xflag || rflag)
2285			display_struct(pnode, tname, cp_time + (i * CPUSTATES),
2286				       sizeof(u_int64_t) * CPUSTATES,
2287				       DISPLAY_VALUE);
2288		else {
2289			if (!nflag)
2290				printf("%s: ", tname);
2291			printf("user = %" PRIu64
2292			       ", nice = %" PRIu64
2293			       ", sys = %" PRIu64
2294			       ", intr = %" PRIu64
2295			       ", idle = %" PRIu64
2296			       "\n",
2297			       cp_time[i * CPUSTATES + CP_USER],
2298			       cp_time[i * CPUSTATES + CP_NICE],
2299			       cp_time[i * CPUSTATES + CP_SYS],
2300			       cp_time[i * CPUSTATES + CP_INTR],
2301			       cp_time[i * CPUSTATES + CP_IDLE]);
2302		}
2303		/*
2304		 * Just printing the one node.
2305		 */
2306		if (n == -1)
2307			break;
2308	}
2309
2310	free(cp_time);
2311}
2312
2313/*ARGSUSED*/
2314static void
2315kern_drivers(HANDLER_ARGS)
2316{
2317	struct kinfo_drivers *kd;
2318	size_t sz, i;
2319	int rc;
2320	const char *comma;
2321
2322	rc = prog_sysctl(name, namelen, NULL, &sz, NULL, 0);
2323	if (rc == -1) {
2324		sysctlerror(1);
2325		return;
2326	}
2327
2328	if (sz % sizeof(*kd))
2329		err(1, "bad size %zu for kern.drivers", sz);
2330
2331	kd = malloc(sz);
2332	if (kd == NULL) {
2333		sysctlerror(1);
2334		return;
2335	}
2336
2337	rc = prog_sysctl(name, namelen, kd, &sz, NULL, 0);
2338	if (rc == -1) {
2339		sysctlerror(1);
2340		free(kd);
2341		return;
2342	}
2343
2344	comma = "";
2345	if (!nflag)
2346		printf("%s%s", sname, eq);
2347	for (i = 0, sz /= sizeof(*kd); i < sz; i++) {
2348		(void)printf("%s[%d %d %s]", comma, kd[i].d_cmajor,
2349		    kd[i].d_bmajor, kd[i].d_name);
2350		comma = ", ";
2351	}
2352	(void)printf("\n");
2353	free(kd);
2354}
2355
2356/*ARGSUSED*/
2357static void
2358kern_cp_id(HANDLER_ARGS)
2359{
2360	u_int64_t *cp_id;
2361	size_t sz, osz;
2362	int rc, i, n;
2363	char s[sizeof("kern.cp_id.nnnnnn")];
2364	const char *tname;
2365	struct sysctlnode node = *pnode;
2366
2367	/*
2368	 * three things to do here.
2369	 * case 1: print a specific cpu id (namelen == 3)
2370	 * case 2: print all cpu ids separately (Aflag set)
2371	 * case 3: print all cpu ids on one line
2372	 */
2373
2374	if (namelen == 2) {
2375		sz = sizeof(n);
2376		rc = sysctlbyname("hw.ncpu", &n, &sz, NULL, 0);
2377		if (rc != 0)
2378			return; /* XXX print an error, eh? */
2379		sz = n * sizeof(u_int64_t);
2380	}
2381	else {
2382		n = -1; /* Just print one cpu id. */
2383		sz = sizeof(u_int64_t);
2384	}
2385
2386	cp_id = malloc(sz);
2387	if (cp_id == NULL) {
2388		sysctlerror(1);
2389		return;
2390	}
2391
2392	osz = sz;
2393	rc = prog_sysctl(name, namelen, cp_id, &osz, NULL, 0);
2394	if (rc == -1) {
2395		sysctlerror(1);
2396		free(cp_id);
2397		return;
2398	}
2399
2400	/*
2401	 * Check that we got back what we asked for.
2402	 */
2403	if (osz != sz)
2404		errx(1, "%s: !returned size wrong!", sname);
2405
2406	/* pretend for output purposes */
2407	node.sysctl_flags = SYSCTL_FLAGS(pnode->sysctl_flags) |
2408		SYSCTL_TYPE(CTLTYPE_QUAD);
2409
2410	tname = sname;
2411	if (namelen == 3)
2412		display_number(&node, tname, cp_id,
2413			       sizeof(u_int64_t),
2414			       DISPLAY_VALUE);
2415	else if (Aflag) {
2416		for (i = 0; i < n; i++)
2417			(void)snprintf(s, sizeof(s), "%s%s%d", sname, sep, i);
2418			tname = s;
2419			display_number(&node, tname, &cp_id[i],
2420				       sizeof(u_int64_t),
2421				       DISPLAY_VALUE);
2422	}
2423	else {
2424		if (xflag || rflag)
2425			display_struct(pnode, tname, cp_id, sz, DISPLAY_VALUE);
2426		else {
2427			if (!nflag)
2428				printf("%s: ", tname);
2429			for (i = 0; i < n; i++) {
2430				if (i)
2431					printf(", ");
2432				printf("%d = %" PRIu64, i, cp_id[i]);
2433			}
2434			printf("\n");
2435		}
2436	}
2437
2438	free(cp_id);
2439}
2440
2441/*ARGSUSED*/
2442static void
2443vm_loadavg(HANDLER_ARGS)
2444{
2445	struct loadavg loadavg;
2446	size_t sz;
2447	int rc;
2448
2449	sz = sizeof(loadavg);
2450	rc = prog_sysctl(name, namelen, &loadavg, &sz, NULL, 0);
2451	if (rc == -1) {
2452		sysctlerror(1);
2453		return;
2454	}
2455	if (sz != sizeof(loadavg))
2456		errx(1, "%s: !returned size wrong!", sname);
2457
2458	if (xflag || rflag) {
2459		display_struct(pnode, sname, &loadavg, sz,
2460			       DISPLAY_VALUE);
2461		return;
2462	}
2463	if (!nflag)
2464		printf("%s: ", sname);
2465	printf("%.2f %.2f %.2f\n",
2466	       (double) loadavg.ldavg[0] / loadavg.fscale,
2467	       (double) loadavg.ldavg[1] / loadavg.fscale,
2468	       (double) loadavg.ldavg[2] / loadavg.fscale);
2469}
2470
2471/*ARGSUSED*/
2472static void
2473proc_limit(HANDLER_ARGS)
2474{
2475	u_quad_t olim, *newp, nlim;
2476	size_t osz, nsz;
2477	char *t;
2478	int rc;
2479
2480	if (fn)
2481		trim_whitespace(value, 3);
2482
2483	osz = sizeof(olim);
2484	if (value != NULL) {
2485		nsz = sizeof(nlim);
2486		newp = &nlim;
2487		if (strcmp(value, "unlimited") == 0)
2488			nlim = RLIM_INFINITY;
2489		else {
2490			errno = 0;
2491			nlim = strtouq(value, &t, 0);
2492			if (t == value || *t != '\0' || errno != 0) {
2493				sysctlperror("%s: '%s' is not a valid limit\n",
2494					     sname, value);
2495				EXIT(1);
2496			}
2497		}
2498	}
2499	else {
2500		nsz = 0;
2501		newp = NULL;
2502	}
2503
2504	rc = prog_sysctl(name, namelen, &olim, &osz, newp, nsz);
2505	if (rc == -1) {
2506		sysctlerror(newp == NULL);
2507		return;
2508	}
2509
2510	if (newp && qflag)
2511		return;
2512
2513	if (rflag || xflag || olim != RLIM_INFINITY)
2514		display_number(pnode, sname, &olim, sizeof(olim),
2515			       newp ? DISPLAY_OLD : DISPLAY_VALUE);
2516	else
2517		display_string(pnode, sname, "unlimited", 10,
2518			       newp ? DISPLAY_OLD : DISPLAY_VALUE);
2519
2520	if (newp) {
2521		if (rflag || xflag || nlim != RLIM_INFINITY)
2522			display_number(pnode, sname, &nlim, sizeof(nlim),
2523				       DISPLAY_NEW);
2524		else
2525			display_string(pnode, sname, "unlimited", 10,
2526				       DISPLAY_NEW);
2527	}
2528}
2529
2530#ifdef CPU_DISKINFO
2531/*ARGSUSED*/
2532static void
2533machdep_diskinfo(HANDLER_ARGS)
2534{
2535	struct disklist *dl;
2536	struct biosdisk_info *bi;
2537	struct nativedisk_info *ni;
2538	int rc;
2539	size_t sz;
2540	uint i, b, lim;
2541
2542	rc = prog_sysctl(name, namelen, NULL, &sz, NULL, 0);
2543	if (rc == -1) {
2544		sysctlerror(1);
2545		return;
2546	}
2547	dl = malloc(sz);
2548	if (dl == NULL) {
2549		sysctlerror(1);
2550		return;
2551	}
2552	rc = prog_sysctl(name, namelen, dl, &sz, NULL, 0);
2553	if (rc == -1) {
2554		sysctlerror(1);
2555		return;
2556	}
2557
2558	if (!nflag)
2559		printf("%s: ", sname);
2560	lim = dl->dl_nbiosdisks;
2561	if (lim > MAX_BIOSDISKS)
2562		lim = MAX_BIOSDISKS;
2563	for (bi = dl->dl_biosdisks, i = 0; i < lim; bi++, i++)
2564		printf("%x:%" PRIu64 "(%d/%d/%d),%x ",
2565		       bi->bi_dev, bi->bi_lbasecs,
2566		       bi->bi_cyl, bi->bi_head, bi->bi_sec,
2567		       bi->bi_flags);
2568	lim = dl->dl_nnativedisks;
2569	ni = dl->dl_nativedisks;
2570	bi = dl->dl_biosdisks;
2571	/* LINTED -- pointer casts are tedious */
2572	if ((char *)&ni[lim] != (char *)dl + sz) {
2573		sysctlperror("%s: size mismatch\n", gsname);
2574		return;
2575	}
2576	for (i = 0; i < lim; ni++, i++) {
2577		char t = ':';
2578		printf(" %.*s", (int)sizeof ni->ni_devname,
2579		       ni->ni_devname);
2580		for (b = 0; b < (unsigned int)ni->ni_nmatches; t = ',', b++)
2581			printf("%c%x", t,
2582			       bi[ni->ni_biosmatches[b]].bi_dev);
2583	}
2584	printf("\n");
2585	free(dl);
2586}
2587#endif /* CPU_DISKINFO */
2588
2589/*ARGSUSED*/
2590static void
2591mode_bits(HANDLER_ARGS)
2592{
2593	char buf[12], outbuf[100];
2594	int o, m, *newp, rc;
2595	size_t osz, nsz;
2596	mode_t om, mm;
2597
2598	if (fn)
2599		trim_whitespace(value, 3);
2600
2601	newp = NULL;
2602	osz = sizeof(o);
2603	if (value != NULL) {
2604		void *foo;
2605		int tt;
2606		size_t ttsz = sizeof(tt);
2607		mode_t old_umask;
2608
2609		nsz = sizeof(m);
2610		newp = &m;
2611		errno = 0;
2612		rc = prog_sysctl(name, namelen, &tt, &ttsz, NULL, 0);
2613		if (rc == -1) {
2614			sysctlperror("%s: failed query\n", sname);
2615			return;
2616		}
2617
2618		old_umask = umask(0);
2619		foo = setmode(value);
2620		umask(old_umask);
2621		if (foo == NULL) {
2622			sysctlperror("%s: '%s' is an invalid mode\n", sname,
2623				     value);
2624			EXIT(1);
2625		}
2626		old_umask = umask(0);
2627		m = getmode(foo, (mode_t)tt);
2628		umask(old_umask);
2629		if (errno) {
2630			sysctlperror("%s: '%s' is an invalid mode\n", sname,
2631				     value);
2632			EXIT(1);
2633		}
2634	}
2635	else {
2636		nsz = 0;
2637		newp = NULL;
2638	}
2639
2640	rc = prog_sysctl(name, namelen, &o, &osz, newp, nsz);
2641	if (rc == -1) {
2642		sysctlerror(newp == NULL);
2643		return;
2644	}
2645
2646	if (newp && qflag)
2647		return;
2648
2649	om = (mode_t)o;
2650	mm = (mode_t)m;
2651
2652	if (rflag || xflag)
2653		display_number(pnode, sname, &o, sizeof(o),
2654			       newp ? DISPLAY_OLD : DISPLAY_VALUE);
2655	else {
2656		memset(buf, 0, sizeof(buf));
2657		strmode(om, buf);
2658		rc = snprintf(outbuf, sizeof(outbuf), "%04o (%s)", om, buf + 1);
2659		display_string(pnode, sname, outbuf, rc, newp ? DISPLAY_OLD : DISPLAY_VALUE);
2660	}
2661
2662	if (newp) {
2663		if (rflag || xflag)
2664			display_number(pnode, sname, &m, sizeof(m),
2665				       DISPLAY_NEW);
2666		else {
2667			memset(buf, 0, sizeof(buf));
2668			strmode(mm, buf);
2669			rc = snprintf(outbuf, sizeof(outbuf), "%04o (%s)", mm, buf + 1);
2670			display_string(pnode, sname, outbuf, rc, DISPLAY_NEW);
2671		}
2672	}
2673}
2674