xref: /netbsd-src/sbin/sysctl/sysctl.c (revision 65f9de9e0d833777821040f998047a7c37363e7b)
1*65f9de9eSryo /*	$NetBSD: sysctl.c,v 1.165 2023/04/02 18:15:24 ryo Exp $ */
2c915b316Satatat 
3c915b316Satatat /*-
4c915b316Satatat  * Copyright (c) 2003 The NetBSD Foundation, Inc.
5c915b316Satatat  *	All rights reserved.
6c915b316Satatat  *
7c915b316Satatat  * This code is derived from software contributed to The NetBSD Foundation
8c915b316Satatat  * by Andrew Brown.
9c915b316Satatat  *
10c915b316Satatat  * Redistribution and use in source and binary forms, with or without
11c915b316Satatat  * modification, are permitted provided that the following conditions
12c915b316Satatat  * are met:
13c915b316Satatat  * 1. Redistributions of source code must retain the above copyright
14c915b316Satatat  *    notice, this list of conditions and the following disclaimer.
15c915b316Satatat  * 2. Redistributions in binary form must reproduce the above copyright
16c915b316Satatat  *    notice, this list of conditions and the following disclaimer in the
17c915b316Satatat  *    documentation and/or other materials provided with the distribution.
18c915b316Satatat  *
19c915b316Satatat  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20c915b316Satatat  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21c915b316Satatat  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22c915b316Satatat  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23c915b316Satatat  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24c915b316Satatat  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25c915b316Satatat  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26c915b316Satatat  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27c915b316Satatat  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28c915b316Satatat  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29c915b316Satatat  * POSSIBILITY OF SUCH DAMAGE.
30c915b316Satatat  */
310af5938cSitojun 
320af5938cSitojun /*
330af5938cSitojun  * Copyright (c) 1993
340af5938cSitojun  *	The Regents of the University of California.  All rights reserved.
350af5938cSitojun  *
360af5938cSitojun  * Redistribution and use in source and binary forms, with or without
370af5938cSitojun  * modification, are permitted provided that the following conditions
380af5938cSitojun  * are met:
390af5938cSitojun  * 1. Redistributions of source code must retain the above copyright
400af5938cSitojun  *    notice, this list of conditions and the following disclaimer.
410af5938cSitojun  * 2. Redistributions in binary form must reproduce the above copyright
420af5938cSitojun  *    notice, this list of conditions and the following disclaimer in the
430af5938cSitojun  *    documentation and/or other materials provided with the distribution.
44276d62f6Sagc  * 3. Neither the name of the University nor the names of its contributors
450af5938cSitojun  *    may be used to endorse or promote products derived from this software
460af5938cSitojun  *    without specific prior written permission.
470af5938cSitojun  *
480af5938cSitojun  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
490af5938cSitojun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
500af5938cSitojun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
510af5938cSitojun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
520af5938cSitojun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
530af5938cSitojun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
540af5938cSitojun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
550af5938cSitojun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
560af5938cSitojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
570af5938cSitojun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
580af5938cSitojun  * SUCH DAMAGE.
590af5938cSitojun  */
600af5938cSitojun 
610af5938cSitojun #include <sys/cdefs.h>
620af5938cSitojun #ifndef lint
636543a91fSlukem __COPYRIGHT("@(#) Copyright (c) 1993\
646543a91fSlukem  The Regents of the University of California.  All rights reserved.");
650af5938cSitojun #endif /* not lint */
660af5938cSitojun 
670af5938cSitojun #ifndef lint
680af5938cSitojun #if 0
690af5938cSitojun static char sccsid[] = "@(#)sysctl.c	8.1 (Berkeley) 6/6/93";
700af5938cSitojun #else
71*65f9de9eSryo __RCSID("$NetBSD: sysctl.c,v 1.165 2023/04/02 18:15:24 ryo Exp $");
720af5938cSitojun #endif
730af5938cSitojun #endif /* not lint */
740af5938cSitojun 
75c915b316Satatat #include <sys/types.h>
760af5938cSitojun #include <sys/param.h>
770af5938cSitojun #include <sys/sysctl.h>
780af5938cSitojun #include <sys/mount.h>
790af5938cSitojun #include <sys/resource.h>
80c915b316Satatat #include <sys/stat.h>
81c915b316Satatat #include <sys/sched.h>
82c915b316Satatat #include <sys/socket.h>
83f9868bf9Schristos #include <sys/bitops.h>
840af5938cSitojun #include <netinet/in.h>
850af5938cSitojun #include <netinet/ip_var.h>
860af5938cSitojun #include <netinet/tcp.h>
870af5938cSitojun #include <netinet/tcp_timer.h>
880af5938cSitojun #include <netinet/tcp_var.h>
89787fb293Sitojun #include <netinet/icmp6.h>
90c915b316Satatat #include <nfs/rpcv2.h>
91c915b316Satatat #include <nfs/nfsproto.h>
92c915b316Satatat #include <nfs/nfs.h>
93c915b316Satatat #include <machine/cpu.h>
940af5938cSitojun 
95c915b316Satatat #include <assert.h>
960af5938cSitojun #include <ctype.h>
97c915b316Satatat #include <err.h>
980af5938cSitojun #include <errno.h>
99c915b316Satatat #include <inttypes.h>
10064dd54edSatatat #include <regex.h>
101c915b316Satatat #include <stdarg.h>
1020af5938cSitojun #include <stdio.h>
1030af5938cSitojun #include <stdlib.h>
1040af5938cSitojun #include <string.h>
105c915b316Satatat #include <time.h>
1060af5938cSitojun #include <unistd.h>
1070af5938cSitojun 
108f9740adaSpooka #include "prog_ops.h"
10908fc937cSpooka 
110c915b316Satatat /*
111c915b316Satatat  * this needs to be able to do the printing and the setting
112c915b316Satatat  */
113c915b316Satatat #define HANDLER_PROTO const char *, const char *, char *, \
114c915b316Satatat 	int *, u_int, const struct sysctlnode *, \
115c915b316Satatat 	u_int, void *
116c915b316Satatat #define HANDLER_ARGS const char *sname, const char *dname, char *value, \
117c915b316Satatat 	int *name, u_int namelen, const struct sysctlnode *pnode, \
118c915b316Satatat 	u_int type, void *v
119c915b316Satatat #define DISPLAY_VALUE	0
120c915b316Satatat #define DISPLAY_OLD	1
121c915b316Satatat #define DISPLAY_NEW	2
12258d46185Schristos 
123c915b316Satatat /*
124c915b316Satatat  * generic routines
125c915b316Satatat  */
1263ddbe03fSchristos static const struct handlespec *findhandler(const char *, regex_t *, size_t *);
12764dd54edSatatat static void canonicalize(const char *, char *);
1280f48b536Satatat static void purge_tree(struct sysctlnode *);
12900740dd4Schristos static void print_tree(int *, u_int, struct sysctlnode *, u_int, int, regex_t *,
13000740dd4Schristos     size_t *);
13105ce5c42Sdholland static void write_number(int *, u_int, struct sysctlnode *, char *, bool);
13205ce5c42Sdholland static void write_string(int *, u_int, struct sysctlnode *, char *, bool);
133c915b316Satatat static void display_number(const struct sysctlnode *, const char *,
134c915b316Satatat 			   const void *, size_t, int);
135c915b316Satatat static void display_string(const struct sysctlnode *, const char *,
136c915b316Satatat 			   const void *, size_t, int);
137c915b316Satatat static void display_struct(const struct sysctlnode *, const char *,
138c915b316Satatat 			   const void *, size_t, int);
139c915b316Satatat static void hex_dump(const unsigned char *, size_t);
140baa8e84bSjoerg __dead static void usage(void);
14100740dd4Schristos static void parse(char *, regex_t *, size_t *);
142299501e0Satatat static void parse_create(char *);
143299501e0Satatat static void parse_destroy(char *);
14438c4183bSatatat static void parse_describe(char *);
14538c4183bSatatat static void getdesc1(int *, u_int, struct sysctlnode *);
14638c4183bSatatat static void getdesc(int *, u_int, struct sysctlnode *);
147d528f2f4Satatat static void trim_whitespace(char *, int);
148c915b316Satatat static void sysctlerror(int);
149d528f2f4Satatat static void sysctlparseerror(u_int, const char *);
15066dd2755Sjoerg static void sysctlperror(const char *, ...) __printflike(1, 2);
151d528f2f4Satatat #define EXIT(n) do { \
152d528f2f4Satatat 	if (fn == NULL) exit(n); else return; } while (/*CONSTCOND*/0)
1530af5938cSitojun 
154c915b316Satatat /*
15529e15c79Satatat  * "borrowed" from libc:sysctlgetmibinfo.c
156c915b316Satatat  */
15729e15c79Satatat int __learn_tree(int *, u_int, struct sysctlnode *);
1580af5938cSitojun 
159c915b316Satatat /*
160c915b316Satatat  * "handlers"
161c915b316Satatat  */
162c915b316Satatat static void printother(HANDLER_PROTO);
163c915b316Satatat static void kern_clockrate(HANDLER_PROTO);
164c915b316Satatat static void kern_boottime(HANDLER_PROTO);
165c915b316Satatat static void kern_consdev(HANDLER_PROTO);
166c915b316Satatat static void kern_cp_time(HANDLER_PROTO);
16729a64650Schristos static void kern_cp_id(HANDLER_PROTO);
1685bc3ea6cSchristos static void kern_drivers(HANDLER_PROTO);
169c915b316Satatat static void vm_loadavg(HANDLER_PROTO);
170c915b316Satatat static void proc_limit(HANDLER_PROTO);
171c915b316Satatat #ifdef CPU_DISKINFO
172c915b316Satatat static void machdep_diskinfo(HANDLER_PROTO);
173c915b316Satatat #endif /* CPU_DISKINFO */
174202872dbSelad static void mode_bits(HANDLER_PROTO);
17597613513Schristos static void reserve(HANDLER_PROTO);
17658d46185Schristos 
1770154132fSjdolecek static const struct handlespec {
17864dd54edSatatat 	const char *ps_re;
179c915b316Satatat 	void (*ps_p)(HANDLER_PROTO);
180c915b316Satatat 	void (*ps_w)(HANDLER_PROTO);
1812c6eadc9Schristos 	const void *ps_d;
182c915b316Satatat } handlers[] = {
1835bc3ea6cSchristos 	{ "/kern/clockrate",			kern_clockrate, NULL, NULL },
18466d4eaa7Schristos 	{ "/kern/evcnt",			printother, NULL, "vmstat -e" },
18564dd54edSatatat 	{ "/kern/vnode",			printother, NULL, "pstat" },
18664dd54edSatatat 	{ "/kern/proc(2|_args)?",		printother, NULL, "ps" },
18764dd54edSatatat 	{ "/kern/file2?",			printother, NULL, "pstat" },
18864dd54edSatatat 	{ "/kern/ntptime",			printother, NULL,
189c915b316Satatat 						"ntpdc -c kerninfo" },
19064dd54edSatatat 	{ "/kern/msgbuf",			printother, NULL, "dmesg" },
1915bc3ea6cSchristos 	{ "/kern/boottime",			kern_boottime, NULL, NULL },
1925bc3ea6cSchristos 	{ "/kern/consdev",			kern_consdev, NULL, NULL },
1935bc3ea6cSchristos 	{ "/kern/cp_time(/[0-9]+)?",		kern_cp_time, NULL, NULL },
194962d2193Schristos 	{ "/kern/hashstat",			printother, NULL, "vmstat -H" },
19564dd54edSatatat 	{ "/kern/sysvipc_info",			printother, NULL, "ipcs" },
1965bc3ea6cSchristos 	{ "/kern/cp_id(/[0-9]+)?",		kern_cp_id, NULL, NULL },
197c915b316Satatat 
1985bc3ea6cSchristos 	{ "/kern/coredump/setid/mode",		mode_bits, mode_bits, NULL },
1995bc3ea6cSchristos 	{ "/kern/drivers",			kern_drivers, NULL, NULL },
2001c8d298bSelad 
20184f76c9cSknakahara 	{ "/kern/intr/list",			printother, NULL, "intrctl" },
20284f76c9cSknakahara 	{ "/kern/intr/affinity",		printother, NULL, "intrctl" },
20384f76c9cSknakahara 	{ "/kern/intr/intr",			printother, NULL, "intrctl" },
20484f76c9cSknakahara 	{ "/kern/intr/nointr",			printother, NULL, "intrctl" },
20584f76c9cSknakahara 
20664dd54edSatatat 	{ "/vm/vmmeter",			printother, NULL,
20764dd54edSatatat 						"vmstat' or 'systat" },
2085bc3ea6cSchristos 	{ "/vm/loadavg",			vm_loadavg, NULL, NULL },
20964dd54edSatatat 	{ "/vm/uvmexp2?",			printother, NULL,
21064dd54edSatatat 						"vmstat' or 'systat" },
211c915b316Satatat 
21264dd54edSatatat 	{ "/vfs/nfs/nfsstats",			printother, NULL, "nfsstat" },
213c915b316Satatat 
21464dd54edSatatat 	{ "/net/inet6?/tcp6?/ident",		printother, NULL, "identd" },
21564dd54edSatatat 	{ "/net/inet6/icmp6/nd6_[dp]rlist",	printother, NULL, "ndp" },
21694ae268aSchristos 	{ "/net/inet6/ip6/addctlpolicy",	printother, NULL,
21794ae268aSchristos 						"ip6addrctl" },
21864dd54edSatatat 	{ "/net/key/dumps[ap]",			printother, NULL, "setkey" },
21964dd54edSatatat 	{ "/net/[^/]+/[^/]+/pcblist",		printother, NULL,
22064dd54edSatatat 						"netstat' or 'sockstat" },
221a4963894Srpaulo 	{ "/net/(inet|inet6)/[^/]+/stats",	printother, NULL, "netstat"},
222a22e7bc9Schristos 	{ "/net/inet/(ipip|esp|ah|ipcomp)/.*_stats",
223a22e7bc9Schristos 						printother, NULL, "netstat"},
224a22e7bc9Schristos 	{ "/net/inet/ipsec/ipsecstats",		printother, NULL, "netstat"},
22578d05017Srpaulo 	{ "/net/bpf/(stats|peers)",		printother, NULL, "netstat"},
22664dd54edSatatat 
227b8e38193Schristos 	{ "/net/inet.*/tcp.*/deb.*",		printother, NULL, "trpt" },
228b8e38193Schristos 
22997613513Schristos 	{ "/net/inet.*/ip.*/anonportalgo/reserve", reserve, reserve, NULL },
230dcc35c7fSrpaulo 
231dcc35c7fSrpaulo 	{ "/net/ns/spp/deb.*",			printother, NULL, "trsp" },
232dcc35c7fSrpaulo 
23364dd54edSatatat 	{ "/hw/diskstats",			printother, NULL, "iostat" },
23464dd54edSatatat 
235c915b316Satatat #ifdef CPU_CONSDEV
2365bc3ea6cSchristos 	{ "/machdep/consdev",			kern_consdev, NULL, NULL },
237c915b316Satatat #endif /* CPU_CONSDEV */
238c915b316Satatat #ifdef CPU_DISKINFO
2395bc3ea6cSchristos 	{ "/machdep/diskinfo",			machdep_diskinfo, NULL, NULL },
240c915b316Satatat #endif /* CPU_CONSDEV */
24164dd54edSatatat 
2425bc3ea6cSchristos 	{ "/proc/[^/]+/rlimit/[^/]+/[^/]+",	proc_limit, proc_limit, NULL },
24364dd54edSatatat 
24464dd54edSatatat 	/*
24564dd54edSatatat 	 * these will only be called when the given node has no children
24664dd54edSatatat 	 */
24764dd54edSatatat 	{ "/net/[^/]+",				printother, NULL, NULL },
24864dd54edSatatat 	{ "/debug",				printother, NULL, NULL },
24964dd54edSatatat 	{ "/ddb",				printother, NULL, NULL },
25064dd54edSatatat 	{ "/vendor",				printother, NULL, NULL },
25164dd54edSatatat 
2525bc3ea6cSchristos 	{ NULL,					NULL, NULL, NULL },
2530af5938cSitojun };
2540af5938cSitojun 
255c915b316Satatat struct sysctlnode my_root = {
25619af35fdSatatat 	.sysctl_flags = SYSCTL_VERSION|CTLFLAG_ROOT|CTLTYPE_NODE,
257804dc5f9Smartin 	.sysctl_size = sizeof(struct sysctlnode),
258c915b316Satatat 	.sysctl_num = 0,
259c915b316Satatat 	.sysctl_name = "(prog_root)",
260c915b316Satatat };
261c915b316Satatat 
26238c4183bSatatat int	Aflag, aflag, dflag, Mflag, nflag, qflag, rflag, wflag, xflag;
263d528f2f4Satatat size_t	nr;
264d528f2f4Satatat char	*fn;
265b311ec9dSchristos int	req, stale, errs;
266ea56af7bSlukem FILE	*warnfp = stderr;
2670af5938cSitojun 
268f9868bf9Schristos #define MAXPORTS	0x10000
269f9868bf9Schristos 
2700af5938cSitojun /*
271c915b316Satatat  * vah-riables n stuff
2720af5938cSitojun  */
273c915b316Satatat char gsname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME],
27464dd54edSatatat 	canonname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME],
275c915b316Satatat 	gdname[10 * CTL_MAXNAME + CTL_MAXNAME];
2762c6eadc9Schristos char sep[] = ".";
2772c6eadc9Schristos const char *eq = " = ";
278c915b316Satatat const char *lname[] = {
279c915b316Satatat 	"top", "second", "third", "fourth", "fifth", "sixth",
280c915b316Satatat 	"seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth"
281c915b316Satatat };
2820af5938cSitojun 
2830af5938cSitojun /*
284c915b316Satatat  * you've heard of main, haven't you?
2850af5938cSitojun  */
2860af5938cSitojun int
main(int argc,char * argv[])287750526acSsimonb main(int argc, char *argv[])
2880af5938cSitojun {
289c915b316Satatat 	int name[CTL_MAXNAME];
290c915b316Satatat 	int ch;
29100740dd4Schristos 	size_t lastcompiled = 0;
29200740dd4Schristos 	regex_t *re;
2930af5938cSitojun 
29400740dd4Schristos 	setprogname(argv[0]);
29538c4183bSatatat 	while ((ch = getopt(argc, argv, "Aabdef:Mnqrwx")) != -1) {
2960af5938cSitojun 		switch (ch) {
2970af5938cSitojun 		case 'A':
298c915b316Satatat 			Aflag++;
2990af5938cSitojun 			break;
3000af5938cSitojun 		case 'a':
301c915b316Satatat 			aflag++;
3020af5938cSitojun 			break;
30338c4183bSatatat 		case 'd':
30438c4183bSatatat 			dflag++;
30538c4183bSatatat 			break;
30676036feaSgrant 		case 'e':
307c915b316Satatat 			eq = "=";
30876036feaSgrant 			break;
3094f90f5ceStsarna 		case 'f':
3104f90f5ceStsarna 			fn = optarg;
311c915b316Satatat 			wflag++;
3124f90f5ceStsarna 			break;
313c915b316Satatat 		case 'M':
314c915b316Satatat 			Mflag++;
315c915b316Satatat 			break;
3160af5938cSitojun 		case 'n':
317c915b316Satatat 			nflag++;
3180af5938cSitojun 			break;
3191803fb93Ssommerfeld 		case 'q':
320c915b316Satatat 			qflag++;
3211803fb93Ssommerfeld 			break;
322299501e0Satatat 		case 'b':	/* FreeBSD compat */
323c915b316Satatat 		case 'r':
324c915b316Satatat 			rflag++;
325c915b316Satatat 			break;
3260af5938cSitojun 		case 'w':
327c915b316Satatat 			wflag++;
3280af5938cSitojun 			break;
329c915b316Satatat 		case 'x':
330c915b316Satatat 			xflag++;
331c915b316Satatat 			break;
3320af5938cSitojun 		default:
3330af5938cSitojun 			usage();
3340af5938cSitojun 		}
3350af5938cSitojun 	}
3361803fb93Ssommerfeld 
3370af5938cSitojun 	argc -= optind;
3380af5938cSitojun 	argv += optind;
3390af5938cSitojun 
340c915b316Satatat 	if (xflag && rflag)
341c915b316Satatat 		usage();
342c915b316Satatat 	/* if ((xflag || rflag) && wflag)
343c915b316Satatat 		usage(); */
34494a8b135Schristos 	/* if (aflag && (Mflag || qflag))
345c915b316Satatat 		usage(); */
34694a8b135Schristos 	if ((aflag || Aflag) && qflag)
34794a8b135Schristos 		usage();
34838c4183bSatatat 	if ((Aflag || Mflag || dflag) && argc == 0 && fn == NULL)
349c915b316Satatat 		aflag = 1;
350c915b316Satatat 
351f9740adaSpooka 	if (prog_init && prog_init() == -1)
35281c8b4d0Schristos 		err(EXIT_FAILURE, "prog init failed");
353f9740adaSpooka 
354c915b316Satatat 	if (Aflag)
355ea56af7bSlukem 		warnfp = stdout;
3560f48b536Satatat 	stale = req = 0;
357c915b316Satatat 
35800740dd4Schristos 	if ((re = malloc(sizeof(*re) * __arraycount(handlers))) == NULL)
35981c8b4d0Schristos 		err(EXIT_FAILURE, "malloc regex");
36000740dd4Schristos 
361c915b316Satatat 	if (aflag) {
36200740dd4Schristos 		print_tree(&name[0], 0, NULL, CTLTYPE_NODE, 1,
36300740dd4Schristos 		    re, &lastcompiled);
364c915b316Satatat 		/* if (argc == 0) */
365c915b316Satatat 		return (0);
3660af5938cSitojun 	}
3674f90f5ceStsarna 
3684f90f5ceStsarna 	if (fn) {
3694f90f5ceStsarna 		FILE *fp;
3704f90f5ceStsarna 		char *l;
3714f90f5ceStsarna 
3724f90f5ceStsarna 		fp = fopen(fn, "r");
3734f90f5ceStsarna 		if (fp == NULL) {
37481c8b4d0Schristos 			err(EXIT_FAILURE, "%s", fn);
3754f90f5ceStsarna 		} else {
376d528f2f4Satatat 			nr = 0;
377d528f2f4Satatat 			while ((l = fparseln(fp, NULL, &nr, NULL, 0)) != NULL)
378c915b316Satatat 			{
379c915b316Satatat 				if (*l) {
38000740dd4Schristos 					parse(l, re, &lastcompiled);
381c915b316Satatat 					free(l);
382c915b316Satatat 				}
3834f90f5ceStsarna 			}
3844f90f5ceStsarna 			fclose(fp);
3854f90f5ceStsarna 		}
386b311ec9dSchristos 		return errs ? 1 : 0;
387c915b316Satatat 	}
388c915b316Satatat 
3890af5938cSitojun 	if (argc == 0)
3900af5938cSitojun 		usage();
391c915b316Satatat 
3920af5938cSitojun 	while (argc-- > 0)
39300740dd4Schristos 		parse(*argv++, re, &lastcompiled);
394c915b316Satatat 
39581c8b4d0Schristos 	return errs ? EXIT_FAILURE : EXIT_SUCCESS;
3960af5938cSitojun }
3970af5938cSitojun 
3980af5938cSitojun /*
399c915b316Satatat  * ********************************************************************
400c915b316Satatat  * how to find someone special to handle the reading (or maybe even
401c915b316Satatat  * writing) of a particular node
402c915b316Satatat  * ********************************************************************
4030af5938cSitojun  */
4040154132fSjdolecek static const struct handlespec *
findhandler(const char * s,regex_t * re,size_t * lastcompiled)4053ddbe03fSchristos findhandler(const char *s, regex_t *re, size_t *lastcompiled)
4060af5938cSitojun {
4070154132fSjdolecek 	const struct handlespec *p;
40800740dd4Schristos 	size_t i, l;
40900740dd4Schristos 	int j;
41064dd54edSatatat 	char eb[64];
41100740dd4Schristos 	regmatch_t match;
412c915b316Satatat 
413c915b316Satatat 	p = &handlers[0];
41464dd54edSatatat 	l = strlen(s);
41564dd54edSatatat 	for (i = 0; p[i].ps_re != NULL; i++) {
41600740dd4Schristos 		if (i >= *lastcompiled) {
41700740dd4Schristos 			j = regcomp(&re[i], p[i].ps_re, REG_EXTENDED);
41864dd54edSatatat 			if (j != 0) {
41900740dd4Schristos 				regerror(j, &re[i], eb, sizeof(eb));
42081c8b4d0Schristos 				errx(EXIT_FAILURE, "regcomp: %s: %s", p[i].ps_re, eb);
42164dd54edSatatat 			}
42200740dd4Schristos 			*lastcompiled = i + 1;
4230af5938cSitojun 		}
42400740dd4Schristos 		j = regexec(&re[i], s, 1, &match, 0);
42500740dd4Schristos 		if (j == 0) {
4263ddbe03fSchristos 			if (match.rm_so == 0 && match.rm_eo == (int)l)
42700740dd4Schristos 				return &p[i];
4289f4a7c8cSchristos 		}
42964dd54edSatatat 		else if (j != REG_NOMATCH) {
43000740dd4Schristos 			regerror(j, &re[i], eb, sizeof(eb));
43181c8b4d0Schristos 			errx(EXIT_FAILURE, "regexec: %s: %s", p[i].ps_re, eb);
43264dd54edSatatat 		}
43364dd54edSatatat 	}
434c915b316Satatat 
43500740dd4Schristos 	return NULL;
436c915b316Satatat }
437c915b316Satatat 
43864dd54edSatatat /*
43964dd54edSatatat  * after sysctlgetmibinfo is done with the name, we convert all
44064dd54edSatatat  * separators to / and stuff one at the front if it was missing
44164dd54edSatatat  */
44264dd54edSatatat static void
canonicalize(const char * i,char * o)44364dd54edSatatat canonicalize(const char *i, char *o)
444c915b316Satatat {
44564dd54edSatatat 	const char *t;
44664dd54edSatatat 	char p[SYSCTL_NAMELEN + 1];
44764dd54edSatatat 	int l;
448c915b316Satatat 
44964dd54edSatatat 	if (i[0] != *sep) {
45064dd54edSatatat 		o[0] = '/';
45164dd54edSatatat 		o[1] = '\0';
452c915b316Satatat 	}
45364dd54edSatatat 	else
45464dd54edSatatat 		o[0] = '\0';
455c915b316Satatat 
45664dd54edSatatat 	t = i;
45764dd54edSatatat 	do {
45864dd54edSatatat 		i = t;
45964dd54edSatatat 		t = strchr(i, sep[0]);
46064dd54edSatatat 		if (t == NULL)
46164dd54edSatatat 			strcat(o, i);
46264dd54edSatatat 		else {
46364dd54edSatatat 			l = t - i;
46464dd54edSatatat 			t++;
46564dd54edSatatat 			memcpy(p, i, l);
46664dd54edSatatat 			p[l] = '\0';
46764dd54edSatatat 			strcat(o, p);
46864dd54edSatatat 			strcat(o, "/");
46964dd54edSatatat 		}
47064dd54edSatatat 	} while (t != NULL);
4710af5938cSitojun }
4720af5938cSitojun 
4730af5938cSitojun /*
474c915b316Satatat  * ********************************************************************
475c915b316Satatat  * convert this special number to a special string so we can print the
476c915b316Satatat  * mib
477c915b316Satatat  * ********************************************************************
4780af5938cSitojun  */
479c915b316Satatat static const char *
sf(u_int f)480c915b316Satatat sf(u_int f)
4810af5938cSitojun {
482c915b316Satatat 	static char s[256];
4832c6eadc9Schristos 	const char *c;
4840af5938cSitojun 
485c915b316Satatat 	s[0] = '\0';
486c915b316Satatat 	c = "";
48776036feaSgrant 
488c915b316Satatat #define print_flag(_f, _s, _c, _q, _x) \
48919af35fdSatatat 	if (((_f) & (__CONCAT(CTLFLAG_,_x))) == (__CONCAT(CTLFLAG_,_q))) { \
490c915b316Satatat 		strlcat((_s), (_c), sizeof(_s)); \
491c915b316Satatat 		strlcat((_s), __STRING(_q), sizeof(_s)); \
492c915b316Satatat 		(_c) = ","; \
49319af35fdSatatat 		(_f) &= ~(__CONCAT(CTLFLAG_,_x)); \
4940af5938cSitojun 	}
49519af35fdSatatat 	print_flag(f, s, c, READONLY,  READWRITE);
49619af35fdSatatat 	print_flag(f, s, c, READWRITE, READWRITE);
49719af35fdSatatat 	print_flag(f, s, c, ANYWRITE,  ANYWRITE);
49819af35fdSatatat 	print_flag(f, s, c, PRIVATE,   PRIVATE);
49919af35fdSatatat 	print_flag(f, s, c, PERMANENT, PERMANENT);
50019af35fdSatatat 	print_flag(f, s, c, OWNDATA,   OWNDATA);
50119af35fdSatatat 	print_flag(f, s, c, IMMEDIATE, IMMEDIATE);
50219af35fdSatatat 	print_flag(f, s, c, HEX,       HEX);
50319af35fdSatatat 	print_flag(f, s, c, ROOT,      ROOT);
50419af35fdSatatat 	print_flag(f, s, c, ANYNUMBER, ANYNUMBER);
50519af35fdSatatat 	print_flag(f, s, c, HIDDEN,    HIDDEN);
50619af35fdSatatat 	print_flag(f, s, c, ALIAS,     ALIAS);
507c915b316Satatat #undef print_flag
5080af5938cSitojun 
509c915b316Satatat 	if (f) {
510c915b316Satatat 		char foo[9];
511c915b316Satatat 		snprintf(foo, sizeof(foo), "%x", f);
512c915b316Satatat 		strlcat(s, c, sizeof(s));
513c915b316Satatat 		strlcat(s, foo, sizeof(s));
514f8f69590Sdsl 	}
515b02df6b9Sfvdl 
516c915b316Satatat 	return (s);
5170af5938cSitojun }
5180af5938cSitojun 
519c915b316Satatat static const char *
st(u_int t)520c915b316Satatat st(u_int t)
521c915b316Satatat {
5220af5938cSitojun 
523c915b316Satatat 	switch (t) {
5240af5938cSitojun 	case CTLTYPE_NODE:
525c915b316Satatat 		return "NODE";
526c915b316Satatat 	case CTLTYPE_INT:
527c915b316Satatat 		return "INT";
528c915b316Satatat 	case CTLTYPE_STRING:
529c915b316Satatat 		return "STRING";
530c915b316Satatat 	case CTLTYPE_QUAD:
531c915b316Satatat                 return "QUAD";
532c915b316Satatat 	case CTLTYPE_STRUCT:
533c915b316Satatat 		return "STRUCT";
534e00e7bd5Smrg 	case CTLTYPE_BOOL:
535e00e7bd5Smrg 		return "BOOL";
5360af5938cSitojun 	}
537c915b316Satatat 
538c915b316Satatat 	return "???";
5390af5938cSitojun }
5400af5938cSitojun 
5410af5938cSitojun /*
542c915b316Satatat  * ********************************************************************
5430f48b536Satatat  * recursively eliminate all data belonging to the given node
5440f48b536Satatat  * ********************************************************************
5450f48b536Satatat  */
5460f48b536Satatat static void
purge_tree(struct sysctlnode * rnode)5470f48b536Satatat purge_tree(struct sysctlnode *rnode)
5480f48b536Satatat {
5490f48b536Satatat 	struct sysctlnode *node;
5500f48b536Satatat 
5510f48b536Satatat 	if (rnode == NULL ||
5520f48b536Satatat 	    SYSCTL_TYPE(rnode->sysctl_flags) != CTLTYPE_NODE ||
5530f48b536Satatat 	    rnode->sysctl_child == NULL)
5540f48b536Satatat 		return;
5550f48b536Satatat 
5560f48b536Satatat 	for (node = rnode->sysctl_child;
5570f48b536Satatat 	     node < &rnode->sysctl_child[rnode->sysctl_clen];
5580f48b536Satatat 	     node++)
5590f48b536Satatat 		purge_tree(node);
5600f48b536Satatat 	free(rnode->sysctl_child);
5610f48b536Satatat 	rnode->sysctl_csize = 0;
5620f48b536Satatat 	rnode->sysctl_clen = 0;
5630f48b536Satatat 	rnode->sysctl_child = NULL;
5640f48b536Satatat 
5650f48b536Satatat 	if (rnode->sysctl_desc == (const char*)-1)
5660f48b536Satatat 		rnode->sysctl_desc = NULL;
5670f48b536Satatat 	if (rnode->sysctl_desc != NULL)
5682c6eadc9Schristos 		free(__UNCONST(rnode->sysctl_desc));
5690f48b536Satatat 	rnode->sysctl_desc = NULL;
5700f48b536Satatat }
5710f48b536Satatat 
572a14203e9Schristos static void __attribute__((__format__(__printf__, 3, 4)))
appendprintf(char ** bp,size_t * lbp,const char * fmt,...)573a14203e9Schristos appendprintf(char **bp, size_t *lbp, const char *fmt, ...)
574a14203e9Schristos {
575a14203e9Schristos 	int r;
576a14203e9Schristos 	va_list ap;
577a14203e9Schristos 
578a14203e9Schristos 	va_start(ap, fmt);
579a14203e9Schristos 	r = vsnprintf(*bp, *lbp, fmt, ap);
580a14203e9Schristos 	va_end(ap);
581a14203e9Schristos 	if (r < 0 || (size_t)r > *lbp)
582a14203e9Schristos 		r = *lbp;
583a14203e9Schristos 	*bp += r;
584a14203e9Schristos 	*lbp -= r;
585a14203e9Schristos }
586a14203e9Schristos 
5870f48b536Satatat /*
5880f48b536Satatat  * ********************************************************************
589c915b316Satatat  * print this node and any others underneath it
590c915b316Satatat  * ********************************************************************
5910af5938cSitojun  */
5920af5938cSitojun static void
print_tree(int * name,u_int namelen,struct sysctlnode * pnode,u_int type,int add,regex_t * re,size_t * lastcompiled)593c915b316Satatat print_tree(int *name, u_int namelen, struct sysctlnode *pnode, u_int type,
59400740dd4Schristos    int add, regex_t *re, size_t *lastcompiled)
5950af5938cSitojun {
596c915b316Satatat 	struct sysctlnode *node;
597deb4c0bbSlukem 	int rc;
598a14203e9Schristos 	size_t ni, sz, ldp, lsp;
599a14203e9Schristos 	char *sp, *dp, *tsp, *tdp;
6000154132fSjdolecek 	const struct handlespec *p;
6010af5938cSitojun 
602a14203e9Schristos 	sp = tsp = &gsname[strlen(gsname)];
603a14203e9Schristos 	dp = tdp = &gdname[strlen(gdname)];
604a14203e9Schristos 	ldp = sizeof(gdname) - (dp - gdname);
605a14203e9Schristos 	lsp = sizeof(gsname) - (sp - gsname);
606c915b316Satatat 
607c915b316Satatat 	if (sp != &gsname[0] && dp == &gdname[0]) {
608c915b316Satatat 		/*
609c915b316Satatat 		 * aw...shucks.  now we must play catch up
610c915b316Satatat 		 */
611a14203e9Schristos 		for (ni = 0; ni < namelen; ni++)
612a14203e9Schristos 			appendprintf(&tdp, &ldp, "%s%d", ni > 0 ? "." : "",
613a14203e9Schristos 			    name[ni]);
614c915b316Satatat 	}
615c915b316Satatat 
616c915b316Satatat 	if (pnode == NULL)
617c915b316Satatat 		pnode = &my_root;
618c915b316Satatat 	else if (add) {
619a14203e9Schristos 		appendprintf(&tsp, &lsp, "%s%s", namelen > 1 ? sep : "",
620a14203e9Schristos 			pnode->sysctl_name);
621a14203e9Schristos 		appendprintf(&tdp, &ldp, "%s%d", namelen > 1 ? "." : "",
622a14203e9Schristos 			pnode->sysctl_num);
623c915b316Satatat 	}
624c915b316Satatat 
625c915b316Satatat 	if (Mflag && pnode != &my_root) {
626c915b316Satatat 		if (nflag)
627c915b316Satatat 			printf("%s: ", gdname);
628c915b316Satatat 		else
629c915b316Satatat 			printf("%s (%s): ", gsname, gdname);
630c915b316Satatat 		printf("CTLTYPE_%s", st(type));
631c915b316Satatat 		if (type == CTLTYPE_NODE) {
63219af35fdSatatat 			if (SYSCTL_FLAGS(pnode->sysctl_flags) & CTLFLAG_ALIAS)
633c915b316Satatat 				printf(", alias %d",
634c915b316Satatat 				       pnode->sysctl_alias);
635c915b316Satatat 			else
636c915b316Satatat 				printf(", children %d/%d",
637c915b316Satatat 				       pnode->sysctl_clen,
638c915b316Satatat 				       pnode->sysctl_csize);
639c915b316Satatat 		}
640c915b316Satatat 		printf(", size %zu", pnode->sysctl_size);
641c915b316Satatat 		printf(", flags 0x%x<%s>",
642c915b316Satatat 		       SYSCTL_FLAGS(pnode->sysctl_flags),
643c915b316Satatat 		       sf(SYSCTL_FLAGS(pnode->sysctl_flags)));
644c915b316Satatat 		if (pnode->sysctl_func)
645c915b316Satatat 			printf(", func=%p", pnode->sysctl_func);
646c915b316Satatat 		printf(", ver=%d", pnode->sysctl_ver);
647c915b316Satatat 		printf("\n");
648c915b316Satatat 		if (type != CTLTYPE_NODE) {
649c915b316Satatat 			*sp = *dp = '\0';
6500af5938cSitojun 			return;
6510af5938cSitojun 		}
6520af5938cSitojun 	}
6530af5938cSitojun 
65438c4183bSatatat 	if (dflag && pnode != &my_root) {
65538c4183bSatatat 		if (Aflag || type != CTLTYPE_NODE) {
65638c4183bSatatat 			if (pnode->sysctl_desc == NULL)
65738c4183bSatatat 				getdesc1(name, namelen, pnode);
658de37b593Satatat 			if (Aflag || !add ||
65938c4183bSatatat 			    (pnode->sysctl_desc != NULL &&
66038c4183bSatatat 			     pnode->sysctl_desc != (const char*)-1)) {
66138c4183bSatatat 				if (!nflag)
66238c4183bSatatat 					printf("%s: ", gsname);
66338c4183bSatatat 				if (pnode->sysctl_desc == NULL ||
66438c4183bSatatat 				    pnode->sysctl_desc == (const char*)-1)
66538c4183bSatatat 					printf("(no description)\n");
66638c4183bSatatat 				else
66738c4183bSatatat 					printf("%s\n", pnode->sysctl_desc);
66838c4183bSatatat 			}
66938c4183bSatatat 		}
67038c4183bSatatat 
67138c4183bSatatat 		if (type != CTLTYPE_NODE) {
67238c4183bSatatat 			*sp = *dp = '\0';
67338c4183bSatatat 			return;
67438c4183bSatatat 		}
67538c4183bSatatat 	}
67638c4183bSatatat 
6770af5938cSitojun 	/*
678c915b316Satatat 	 * if this is an alias and we added our name, that means we
679c915b316Satatat 	 * got here by recursing down into the tree, so skip it.  The
680c915b316Satatat 	 * only way to print an aliased node is with either -M or by
681c915b316Satatat 	 * name specifically.
6820af5938cSitojun 	 */
68319af35fdSatatat 	if (SYSCTL_FLAGS(pnode->sysctl_flags) & CTLFLAG_ALIAS && add) {
684c915b316Satatat 		*sp = *dp = '\0';
685c915b316Satatat 		return;
6860af5938cSitojun 	}
687c915b316Satatat 
68864dd54edSatatat 	canonicalize(gsname, canonname);
6893ddbe03fSchristos 	p = findhandler(canonname, re, lastcompiled);
690c915b316Satatat 	if (type != CTLTYPE_NODE && p != NULL) {
6913ddbe03fSchristos 		if (p->ps_p == NULL) {
6923ddbe03fSchristos 			sysctlperror("Cannot print `%s': %s\n", gsname,
6933ddbe03fSchristos 			    strerror(EOPNOTSUPP));
69481c8b4d0Schristos 			exit(EXIT_FAILURE);
6953ddbe03fSchristos 		}
696c915b316Satatat 		(*p->ps_p)(gsname, gdname, NULL, name, namelen, pnode, type,
6972c6eadc9Schristos 			   __UNCONST(p->ps_d));
698c915b316Satatat 		*sp = *dp = '\0';
699c915b316Satatat 		return;
700c915b316Satatat 	}
701c915b316Satatat 
702c915b316Satatat 	if (type != CTLTYPE_NODE && pnode->sysctl_size == 0) {
703f9740adaSpooka 		rc = prog_sysctl(&name[0], namelen, NULL, &sz, NULL, 0);
704c915b316Satatat 		if (rc == -1) {
705c915b316Satatat 			sysctlerror(1);
706c915b316Satatat 			*sp = *dp = '\0';
707c915b316Satatat 			return;
708c915b316Satatat 		}
709c915b316Satatat 		if (sz == 0) {
710c915b316Satatat 			if ((Aflag || req) && !Mflag)
711c915b316Satatat 				printf("%s: node contains no data\n", gsname);
712c915b316Satatat 			*sp = *dp = '\0';
713c915b316Satatat 			return;
714c915b316Satatat 		}
715c915b316Satatat 	}
716c915b316Satatat 	else
717c915b316Satatat 		sz = pnode->sysctl_size;
718c915b316Satatat 
719c915b316Satatat 	switch (type) {
720c915b316Satatat 	case CTLTYPE_NODE: {
72129e15c79Satatat 		__learn_tree(name, namelen, pnode);
722c915b316Satatat 		node = pnode->sysctl_child;
723c915b316Satatat 		if (node == NULL) {
7244f406ff7Satatat 			if (dflag)
7254f406ff7Satatat 				/* do nothing */;
7264f406ff7Satatat 			else if (p != NULL)
727c915b316Satatat 				(*p->ps_p)(gsname, gdname, NULL, name, namelen,
7282c6eadc9Schristos 					   pnode, type, __UNCONST(p->ps_d));
7294f406ff7Satatat 			else if ((Aflag || req) && !Mflag)
730c915b316Satatat 				printf("%s: no children\n", gsname);
731c915b316Satatat 		}
732c915b316Satatat 		else {
73338c4183bSatatat 			if (dflag)
73438c4183bSatatat 				/*
73538c4183bSatatat 				 * get all descriptions for next level
73638c4183bSatatat 				 * in one chunk
73738c4183bSatatat 				 */
73838c4183bSatatat 				getdesc(name, namelen, pnode);
739c915b316Satatat 			req = 0;
740c915b316Satatat 			for (ni = 0; ni < pnode->sysctl_clen; ni++) {
741c915b316Satatat 				name[namelen] = node[ni].sysctl_num;
74219af35fdSatatat 				if ((node[ni].sysctl_flags & CTLFLAG_HIDDEN) &&
743c915b316Satatat 				    !(Aflag || req))
744c915b316Satatat 					continue;
745c915b316Satatat 				print_tree(name, namelen + 1, &node[ni],
746c915b316Satatat 					   SYSCTL_TYPE(node[ni].sysctl_flags),
74700740dd4Schristos 					   1, re, lastcompiled);
748c915b316Satatat 			}
749c915b316Satatat 		}
750c915b316Satatat 		break;
751c915b316Satatat 	}
752c915b316Satatat 	case CTLTYPE_INT: {
753c915b316Satatat 		int i;
754f9740adaSpooka 		rc = prog_sysctl(name, namelen, &i, &sz, NULL, 0);
755c915b316Satatat 		if (rc == -1) {
756c915b316Satatat 			sysctlerror(1);
757c915b316Satatat 			break;
758c915b316Satatat 		}
759c915b316Satatat 		display_number(pnode, gsname, &i, sizeof(i), DISPLAY_VALUE);
760c915b316Satatat 		break;
761c915b316Satatat 	}
762e00e7bd5Smrg 	case CTLTYPE_BOOL: {
763e00e7bd5Smrg 		bool b;
764f9740adaSpooka 		rc = prog_sysctl(name, namelen, &b, &sz, NULL, 0);
765e00e7bd5Smrg 		if (rc == -1) {
766e00e7bd5Smrg 			sysctlerror(1);
767e00e7bd5Smrg 			break;
768e00e7bd5Smrg 		}
769e00e7bd5Smrg 		display_number(pnode, gsname, &b, sizeof(b), DISPLAY_VALUE);
770e00e7bd5Smrg 		break;
771e00e7bd5Smrg 	}
772c915b316Satatat 	case CTLTYPE_STRING: {
773c915b316Satatat 		unsigned char buf[1024], *tbuf;
774c915b316Satatat 		tbuf = buf;
775c915b316Satatat 		sz = sizeof(buf);
776f9740adaSpooka 		rc = prog_sysctl(&name[0], namelen, tbuf, &sz, NULL, 0);
777c915b316Satatat 		if (rc == -1 && errno == ENOMEM) {
778c915b316Satatat 			tbuf = malloc(sz);
779c915b316Satatat 			if (tbuf == NULL) {
780c915b316Satatat 				sysctlerror(1);
781c915b316Satatat 				break;
782c915b316Satatat 			}
783f9740adaSpooka 			rc = prog_sysctl(&name[0], namelen, tbuf, &sz, NULL, 0);
784c915b316Satatat 		}
785c915b316Satatat 		if (rc == -1)
786c915b316Satatat 			sysctlerror(1);
787c915b316Satatat 		else
7882971543eSatatat 			display_string(pnode, gsname, tbuf, sz, DISPLAY_VALUE);
789c915b316Satatat 		if (tbuf != buf)
790c915b316Satatat 			free(tbuf);
791c915b316Satatat 		break;
792c915b316Satatat 	}
793c915b316Satatat 	case CTLTYPE_QUAD: {
794c915b316Satatat 		u_quad_t q;
795c915b316Satatat 		sz = sizeof(q);
796f9740adaSpooka 		rc = prog_sysctl(&name[0], namelen, &q, &sz, NULL, 0);
797c915b316Satatat 		if (rc == -1) {
798c915b316Satatat 			sysctlerror(1);
799c915b316Satatat 			break;
800c915b316Satatat 		}
801c915b316Satatat 		display_number(pnode, gsname, &q, sizeof(q), DISPLAY_VALUE);
802c915b316Satatat 		break;
803c915b316Satatat 	}
804c915b316Satatat 	case CTLTYPE_STRUCT: {
805c915b316Satatat 		/*
806c915b316Satatat 		 * we shouldn't actually get here, but if we
807c915b316Satatat 		 * do, would it be nice to have *something* to
808c915b316Satatat 		 * do other than completely ignore the
809c915b316Satatat 		 * request.
810c915b316Satatat 		 */
811c915b316Satatat 		unsigned char *d;
812c915b316Satatat 		if ((d = malloc(sz)) == NULL) {
813c915b316Satatat 			fprintf(warnfp, "%s: !malloc failed!\n", gsname);
814c915b316Satatat 			break;
815c915b316Satatat 		}
816f9740adaSpooka 		rc = prog_sysctl(&name[0], namelen, d, &sz, NULL, 0);
817c915b316Satatat 		if (rc == -1) {
818c915b316Satatat 			sysctlerror(1);
819c915b316Satatat 			break;
820c915b316Satatat 		}
821c915b316Satatat 		display_struct(pnode, gsname, d, sz, DISPLAY_VALUE);
822c915b316Satatat 		free(d);
823c915b316Satatat 		break;
824c915b316Satatat 	}
825c915b316Satatat 	default:
826c915b316Satatat 		/* should i print an error here? */
827c915b316Satatat 		break;
828c915b316Satatat 	}
829c915b316Satatat 
830c915b316Satatat 	*sp = *dp = '\0';
831c915b316Satatat }
832c915b316Satatat 
833c915b316Satatat /*
834c915b316Satatat  * ********************************************************************
835c915b316Satatat  * parse a request, possibly determining that it's a create or destroy
836c915b316Satatat  * request
837c915b316Satatat  * ********************************************************************
838c915b316Satatat  */
839c915b316Satatat static void
parse(char * l,regex_t * re,size_t * lastcompiled)84000740dd4Schristos parse(char *l, regex_t *re, size_t *lastcompiled)
841c915b316Satatat {
842c915b316Satatat 	struct sysctlnode *node;
8430154132fSjdolecek 	const struct handlespec *w;
84438c4183bSatatat 	int name[CTL_MAXNAME], dodesc = 0;
845c915b316Satatat 	u_int namelen, type;
846c915b316Satatat 	char *key, *value, *dot;
847c915b316Satatat 	size_t sz;
848e048bed6Schristos 	bool optional = false;
849c915b316Satatat 
850c915b316Satatat 	req = 1;
851c915b316Satatat 	key = l;
852e048bed6Schristos 
853e048bed6Schristos 	if ((value = strchr(l, '=')) != NULL) {
854e048bed6Schristos 		if (value > l && value[-1] == '?') {
855e048bed6Schristos 			value[-1] = '\0';
856e048bed6Schristos 			optional = true;
857e048bed6Schristos 		}
858c915b316Satatat 		*value++ = '\0';
859e048bed6Schristos 	}
860c915b316Satatat 
861c915b316Satatat 	if ((dot = strpbrk(key, "./")) == NULL)
862c915b316Satatat 		sep[0] = '.';
863c915b316Satatat 	else
864c915b316Satatat 		sep[0] = dot[0];
865c915b316Satatat 	sep[1] = '\0';
866c915b316Satatat 
867299501e0Satatat 	while (key[0] == sep[0] && key[1] == sep[0]) {
868c915b316Satatat 		if (value != NULL)
869c915b316Satatat 			value[-1] = '=';
870299501e0Satatat 		if (strncmp(key + 2, "create", 6) == 0 &&
871299501e0Satatat 		    (key[8] == '=' || key[8] == sep[0]))
872d528f2f4Satatat 			parse_create(key + 8 + (key[8] == '=' ? 1 : 0));
873299501e0Satatat 		else if (strncmp(key + 2, "destroy", 7) == 0 &&
874299501e0Satatat 			 (key[9] == '=' || key[9] == sep[0]))
875d528f2f4Satatat 			parse_destroy(key + 9 + (key[9] == '=' ? 1 : 0));
87638c4183bSatatat 		else if (strncmp(key + 2, "describe", 8) == 0 &&
87738c4183bSatatat 			 (key[10] == '=' || key[10] == sep[0])) {
87838c4183bSatatat 			key += 10 + (key[10] == '=');
87938c4183bSatatat 			if ((value = strchr(key, '=')) != NULL)
88038c4183bSatatat 				parse_describe(key);
88138c4183bSatatat 			else {
88238c4183bSatatat 				if (!dflag)
88338c4183bSatatat 					dodesc = 1;
88438c4183bSatatat 				break;
88538c4183bSatatat 			}
88638c4183bSatatat 		}
887c915b316Satatat 		else
888d528f2f4Satatat 			sysctlperror("unable to parse '%s'\n", key);
889c915b316Satatat 		return;
890c915b316Satatat 	}
891c915b316Satatat 
8920f48b536Satatat 	if (stale) {
8930f48b536Satatat 		purge_tree(&my_root);
8940f48b536Satatat 		stale = 0;
8950f48b536Satatat 	}
896c915b316Satatat 	node = &my_root;
897c915b316Satatat 	namelen = CTL_MAXNAME;
898c915b316Satatat 	sz = sizeof(gsname);
899c915b316Satatat 
900997c4cdcSkamil 	if (prog_sysctlgetmibinfo(key, &name[0], &namelen, gsname, &sz, &node,
90119af35fdSatatat 			     SYSCTL_VERSION) == -1) {
902e048bed6Schristos 		if (optional)
903e048bed6Schristos 			return;
904d528f2f4Satatat 		sysctlparseerror(namelen, l);
90581c8b4d0Schristos 		EXIT(EXIT_FAILURE);
906c915b316Satatat 	}
907c915b316Satatat 
908c915b316Satatat 	type = SYSCTL_TYPE(node->sysctl_flags);
909c915b316Satatat 
910c915b316Satatat 	if (value == NULL) {
91138c4183bSatatat 		if (dodesc)
91238c4183bSatatat 			dflag = 1;
91300740dd4Schristos 		print_tree(&name[0], namelen, node, type, 0, re, lastcompiled);
91438c4183bSatatat 		if (dodesc)
91538c4183bSatatat 			dflag = 0;
916c915b316Satatat 		gsname[0] = '\0';
917c915b316Satatat 		return;
918c915b316Satatat 	}
919c915b316Satatat 
920d528f2f4Satatat 	if (fn)
921d528f2f4Satatat 		trim_whitespace(value, 1);
922d528f2f4Satatat 
923299501e0Satatat 	if (!wflag) {
924d528f2f4Satatat 		sysctlperror("Must specify -w to set variables\n");
92581c8b4d0Schristos 		exit(EXIT_FAILURE);
926299501e0Satatat 	}
927299501e0Satatat 
92864dd54edSatatat 	canonicalize(gsname, canonname);
9293ddbe03fSchristos 	if (type != CTLTYPE_NODE && (w = findhandler(canonname, re,
93000740dd4Schristos 	    lastcompiled)) != NULL) {
9313ddbe03fSchristos 		if (w->ps_w == NULL) {
9323ddbe03fSchristos 			sysctlperror("Cannot write `%s': %s\n", gsname,
9333ddbe03fSchristos 			    strerror(EOPNOTSUPP));
93481c8b4d0Schristos 			exit(EXIT_FAILURE);
9353ddbe03fSchristos 		}
936c915b316Satatat 		(*w->ps_w)(gsname, gdname, value, name, namelen, node, type,
9372c6eadc9Schristos 			   __UNCONST(w->ps_d));
938c915b316Satatat 		gsname[0] = '\0';
939c915b316Satatat 		return;
940c915b316Satatat 	}
941c915b316Satatat 
942c915b316Satatat 	switch (type) {
943c915b316Satatat 	case CTLTYPE_INT:
944e00e7bd5Smrg 	case CTLTYPE_BOOL:
945e00e7bd5Smrg 	case CTLTYPE_QUAD:
94605ce5c42Sdholland 		write_number(&name[0], namelen, node, value, optional);
947c915b316Satatat 		break;
948c915b316Satatat 	case CTLTYPE_STRING:
94905ce5c42Sdholland 		write_string(&name[0], namelen, node, value, optional);
950c915b316Satatat 		break;
951*65f9de9eSryo 	case CTLTYPE_NODE:
952c915b316Satatat 	case CTLTYPE_STRUCT:
953c915b316Satatat 		/*
954c915b316Satatat 		 * XXX old behavior is to print.  should we error instead?
955c915b316Satatat 		 */
956c915b316Satatat 		/* fprintf(warnfp, "you can't write to %s\n", gsname); */
95700740dd4Schristos 		print_tree(&name[0], namelen, node, type, 0, re, lastcompiled);
958c915b316Satatat 		break;
959c915b316Satatat 	}
960c915b316Satatat }
961c915b316Satatat 
962c915b316Satatat /*
963c915b316Satatat 
964c915b316Satatat   //create=foo.bar.whatever...,
965c915b316Satatat   [type=(int|quad|string|struct|node),]
966c915b316Satatat   [size=###,]
967c915b316Satatat   [n=###,]
968299501e0Satatat   [flags=(iohxparw12),]
969c915b316Satatat   [addr=0x####,|symbol=...|value=...]
970c915b316Satatat 
971c915b316Satatat   size is optional for some types.  type must be set before anything
97255a6f2a9Selad   else.  nodes can have [rwhp], but nothing else applies.  if no
973c915b316Satatat   size or type is given, node is asserted.  writeable is the default,
97455a6f2a9Selad   with [rw] being read-only and unconditionally writeable
975c915b316Satatat   respectively.  if you specify addr, it is assumed to be the name of
97619af35fdSatatat   a kernel symbol, if value, CTLFLAG_OWNDATA will be asserted for
97719af35fdSatatat   strings, CTLFLAG_IMMEDIATE for ints and u_quad_ts.  you cannot
978c915b316Satatat   specify both value and addr.
979c915b316Satatat 
980c915b316Satatat */
981c915b316Satatat 
982c915b316Satatat static void
parse_create(char * l)983299501e0Satatat parse_create(char *l)
984c915b316Satatat {
985c915b316Satatat 	struct sysctlnode node;
986c915b316Satatat 	size_t sz;
987c915b316Satatat 	char *nname, *key, *value, *data, *addr, *c, *t;
988c915b316Satatat 	int name[CTL_MAXNAME], i, rc, method, flags, rw;
989c915b316Satatat 	u_int namelen, type;
990d528f2f4Satatat 	u_quad_t uq;
991d528f2f4Satatat 	quad_t q;
992e00e7bd5Smrg 	bool b;
993c915b316Satatat 
994299501e0Satatat 	if (!wflag) {
995d528f2f4Satatat 		sysctlperror("Must specify -w to create nodes\n");
99681c8b4d0Schristos 		exit(EXIT_FAILURE);
997299501e0Satatat 	}
998299501e0Satatat 
999c915b316Satatat 	/*
1000c915b316Satatat 	 * these are the pieces that make up the description of a new
1001c915b316Satatat 	 * node
1002c915b316Satatat 	 */
1003c915b316Satatat 	memset(&node, 0, sizeof(node));
1004c915b316Satatat 	node.sysctl_num = CTL_CREATE;  /* any number is fine */
1005c915b316Satatat 	flags = 0;
1006c915b316Satatat 	rw = -1;
1007c915b316Satatat 	type = 0;
1008c915b316Satatat 	sz = 0;
1009c915b316Satatat 	data = addr = NULL;
1010c915b316Satatat 	memset(name, 0, sizeof(name));
1011c915b316Satatat 	namelen = 0;
1012c915b316Satatat 	method = 0;
1013c915b316Satatat 
1014c915b316Satatat 	/*
1015c915b316Satatat 	 * misc stuff used when constructing
1016c915b316Satatat 	 */
1017c915b316Satatat 	i = 0;
1018e00e7bd5Smrg 	b = false;
1019d528f2f4Satatat 	uq = 0;
1020c915b316Satatat 	key = NULL;
1021c915b316Satatat 	value = NULL;
1022c915b316Satatat 
1023c915b316Satatat 	/*
1024c915b316Satatat 	 * the name of the thing we're trying to create is first, so
1025c915b316Satatat 	 * pick it off.
1026c915b316Satatat 	 */
1027c915b316Satatat 	nname = l;
1028c915b316Satatat 	if ((c = strchr(nname, ',')) != NULL)
1029c915b316Satatat 		*c++ = '\0';
1030c915b316Satatat 
1031c915b316Satatat 	while (c != NULL) {
1032c915b316Satatat 
1033c915b316Satatat 		/*
1034c915b316Satatat 		 * pull off the next "key=value" pair
1035c915b316Satatat 		 */
1036c915b316Satatat 		key = c;
1037c915b316Satatat 		if ((t = strchr(key, '=')) != NULL) {
1038c915b316Satatat 			*t++ = '\0';
1039c915b316Satatat 			value = t;
1040c915b316Satatat 		}
1041c915b316Satatat 		else
1042c915b316Satatat 			value = NULL;
1043c915b316Satatat 
1044c915b316Satatat 		/*
1045c915b316Satatat 		 * if the "key" is "value", then that eats the rest of
1046c915b316Satatat 		 * the string, so we're done, otherwise bite it off at
1047c915b316Satatat 		 * the next comma.
1048c915b316Satatat 		 */
1049c915b316Satatat 		if (strcmp(key, "value") == 0) {
1050c915b316Satatat 			c = NULL;
1051c915b316Satatat 			data = value;
1052c915b316Satatat 			break;
1053c915b316Satatat 		}
105486bc6ef9Schristos 		else if (value) {
1055c915b316Satatat 			if ((c = strchr(value, ',')) != NULL)
1056c915b316Satatat 				*c++ = '\0';
1057c915b316Satatat 		}
1058c915b316Satatat 
1059c915b316Satatat 		/*
1060f9740adaSpooka 		 * note that we (mostly) let the invoker of prog_sysctl(8)
1061c915b316Satatat 		 * play rampant here and depend on the kernel to tell
1062c915b316Satatat 		 * them that they were wrong.  well...within reason.
1063c915b316Satatat 		 * we later check the various parameters against each
1064c915b316Satatat 		 * other to make sure it makes some sort of sense.
1065c915b316Satatat 		 */
1066c915b316Satatat 		if (strcmp(key, "addr") == 0) {
1067c915b316Satatat 			/*
1068c915b316Satatat 			 * we can't check these two.  only the kernel
1069c915b316Satatat 			 * can tell us when it fails to find the name
1070c915b316Satatat 			 * (or if the address is invalid).
1071c915b316Satatat 			 */
1072c915b316Satatat 			if (method != 0) {
1073d528f2f4Satatat 				sysctlperror(
1074d528f2f4Satatat 				    "%s: already have %s for new node\n",
1075d528f2f4Satatat 				    nname,
1076c915b316Satatat 				    method == CTL_CREATE ? "addr" : "symbol");
107781c8b4d0Schristos 				EXIT(EXIT_FAILURE);
1078c915b316Satatat 			}
107948ce3c5dSchristos 			if (value == NULL) {
108048ce3c5dSchristos 				sysctlperror("%s: missing value\n", nname);
108181c8b4d0Schristos 				EXIT(EXIT_FAILURE);
108248ce3c5dSchristos 			}
1083fbe98edeSchristos 			errno = 0;
1084c915b316Satatat 			addr = (void*)strtoul(value, &t, 0);
1085605d2000Satatat 			if (t == value || *t != '\0' || errno != 0) {
1086d528f2f4Satatat 				sysctlperror(
1087d528f2f4Satatat 				    "%s: '%s' is not a valid address\n",
1088d528f2f4Satatat 				    nname, value);
108981c8b4d0Schristos 				EXIT(EXIT_FAILURE);
1090c915b316Satatat 			}
1091c915b316Satatat 			method = CTL_CREATE;
1092c915b316Satatat 		}
1093c915b316Satatat 		else if (strcmp(key, "symbol") == 0) {
1094c915b316Satatat 			if (method != 0) {
1095d528f2f4Satatat 				sysctlperror(
1096d528f2f4Satatat 				    "%s: already have %s for new node\n",
1097d528f2f4Satatat 				    nname,
1098c915b316Satatat 				    method == CTL_CREATE ? "addr" : "symbol");
109981c8b4d0Schristos 				EXIT(EXIT_FAILURE);
1100c915b316Satatat 			}
1101c915b316Satatat 			addr = value;
1102c915b316Satatat 			method = CTL_CREATESYM;
1103c915b316Satatat 		}
1104c915b316Satatat 		else if (strcmp(key, "type") == 0) {
1105fbe98edeSchristos 			if (value == NULL) {
1106fbe98edeSchristos 				sysctlperror("%s: missing value\n", nname);
110781c8b4d0Schristos 				EXIT(EXIT_FAILURE);
1108fbe98edeSchristos 			}
1109c915b316Satatat 			if (strcmp(value, "node") == 0)
1110c915b316Satatat 				type = CTLTYPE_NODE;
1111c915b316Satatat 			else if (strcmp(value, "int") == 0) {
1112c915b316Satatat 				sz = sizeof(int);
1113c915b316Satatat 				type = CTLTYPE_INT;
1114c915b316Satatat 			}
1115e00e7bd5Smrg 			else if (strcmp(value, "bool") == 0) {
1116e00e7bd5Smrg 				sz = sizeof(bool);
1117e00e7bd5Smrg 				type = CTLTYPE_BOOL;
1118e00e7bd5Smrg 			}
1119c915b316Satatat 			else if (strcmp(value, "string") == 0)
1120c915b316Satatat 				type = CTLTYPE_STRING;
1121c915b316Satatat 			else if (strcmp(value, "quad") == 0) {
1122c915b316Satatat 				sz = sizeof(u_quad_t);
1123c915b316Satatat 				type = CTLTYPE_QUAD;
1124c915b316Satatat 			}
1125c915b316Satatat 			else if (strcmp(value, "struct") == 0)
1126c915b316Satatat 				type = CTLTYPE_STRUCT;
11270af5938cSitojun 			else {
1128d528f2f4Satatat 				sysctlperror(
1129d528f2f4Satatat 					"%s: '%s' is not a valid type\n",
1130d528f2f4Satatat 					nname, value);
113181c8b4d0Schristos 				EXIT(EXIT_FAILURE);
11320af5938cSitojun 			}
11330af5938cSitojun 		}
1134c915b316Satatat 		else if (strcmp(key, "size") == 0) {
11357b95c004Sjnemeth 			if (value == NULL) {
11367b95c004Sjnemeth 				sysctlperror("%s: missing value\n", nname);
113781c8b4d0Schristos 				EXIT(EXIT_FAILURE);
11387b95c004Sjnemeth 			}
1139c915b316Satatat 			errno = 0;
11400af5938cSitojun 			/*
1141c915b316Satatat 			 * yes, i know size_t is not an unsigned long,
1142c915b316Satatat 			 * but we can all agree that it ought to be,
1143c915b316Satatat 			 * right?
11440af5938cSitojun 			 */
1145c915b316Satatat 			sz = strtoul(value, &t, 0);
1146605d2000Satatat 			if (t == value || *t != '\0' || errno != 0) {
1147d528f2f4Satatat 				sysctlperror(
1148d528f2f4Satatat 					"%s: '%s' is not a valid size\n",
1149d528f2f4Satatat 					nname, value);
115081c8b4d0Schristos 				EXIT(EXIT_FAILURE);
11510af5938cSitojun 			}
11520af5938cSitojun 		}
1153c915b316Satatat 		else if (strcmp(key, "n") == 0) {
1154fbe98edeSchristos 			if (value == NULL) {
1155fbe98edeSchristos 				sysctlperror("%s: missing value\n", nname);
115681c8b4d0Schristos 				EXIT(EXIT_FAILURE);
1157fbe98edeSchristos 			}
1158c915b316Satatat 			errno = 0;
1159404831daSchristos 			q = strtoll(value, &t, 0);
1160605d2000Satatat 			if (t == value || *t != '\0' || errno != 0 ||
1161d528f2f4Satatat 			    q < INT_MIN || q > UINT_MAX) {
1162d528f2f4Satatat 				sysctlperror(
1163d528f2f4Satatat 				    "%s: '%s' is not a valid mib number\n",
1164d528f2f4Satatat 				    nname, value);
116581c8b4d0Schristos 				EXIT(EXIT_FAILURE);
11660af5938cSitojun 			}
1167d528f2f4Satatat 			node.sysctl_num = (int)q;
11680af5938cSitojun 		}
1169c915b316Satatat 		else if (strcmp(key, "flags") == 0) {
1170fbe98edeSchristos 			if (value == NULL) {
1171fbe98edeSchristos 				sysctlperror("%s: missing value\n", nname);
117281c8b4d0Schristos 				EXIT(EXIT_FAILURE);
1173fbe98edeSchristos 			}
1174c915b316Satatat 			t = value;
1175c915b316Satatat 			while (*t != '\0') {
1176c915b316Satatat 				switch (*t) {
1177c915b316Satatat 				case 'a':
117819af35fdSatatat 					flags |= CTLFLAG_ANYWRITE;
11790af5938cSitojun 					break;
1180c915b316Satatat 				case 'h':
118119af35fdSatatat 					flags |= CTLFLAG_HIDDEN;
1182c915b316Satatat 					break;
1183c915b316Satatat 				case 'i':
118419af35fdSatatat 					flags |= CTLFLAG_IMMEDIATE;
1185c915b316Satatat 					break;
1186c915b316Satatat 				case 'o':
118719af35fdSatatat 					flags |= CTLFLAG_OWNDATA;
1188c915b316Satatat 					break;
1189c915b316Satatat 				case 'p':
119019af35fdSatatat 					flags |= CTLFLAG_PRIVATE;
1191c915b316Satatat 					break;
11920836a9f5Sdsl 				case 'u':
11930836a9f5Sdsl 					flags |= CTLFLAG_UNSIGNED;
11940836a9f5Sdsl 					break;
1195c915b316Satatat 				case 'x':
119619af35fdSatatat 					flags |= CTLFLAG_HEX;
1197c915b316Satatat 					break;
1198c915b316Satatat 
1199c915b316Satatat 				case 'r':
120019af35fdSatatat 					rw = CTLFLAG_READONLY;
1201c915b316Satatat 					break;
1202c915b316Satatat 				case 'w':
120319af35fdSatatat 					rw = CTLFLAG_READWRITE;
1204c915b316Satatat 					break;
1205c915b316Satatat 				default:
1206d528f2f4Satatat 					sysctlperror(
1207d528f2f4Satatat 					   "%s: '%c' is not a valid flag\n",
1208d528f2f4Satatat 					    nname, *t);
120981c8b4d0Schristos 					EXIT(EXIT_FAILURE);
12100af5938cSitojun 				}
1211c915b316Satatat 				t++;
1212c915b316Satatat 			}
1213c915b316Satatat 		}
1214c915b316Satatat 		else {
1215d528f2f4Satatat 			sysctlperror("%s: unrecognized keyword '%s'\n",
1216d528f2f4Satatat 				     nname, key);
121781c8b4d0Schristos 			EXIT(EXIT_FAILURE);
1218c915b316Satatat 		}
12190af5938cSitojun 	}
12200af5938cSitojun 
1221c915b316Satatat 	/*
1222c915b316Satatat 	 * now that we've finished parsing the given string, fill in
1223c915b316Satatat 	 * anything they didn't specify
1224c915b316Satatat 	 */
1225c915b316Satatat 	if (type == 0)
1226c915b316Satatat 		type = CTLTYPE_NODE;
1227c915b316Satatat 
1228c915b316Satatat 	/*
1229c915b316Satatat 	 * the "data" can be interpreted various ways depending on the
1230c915b316Satatat 	 * type of node we're creating, as can the size
1231c915b316Satatat 	 */
1232c915b316Satatat 	if (data != NULL) {
1233c915b316Satatat 		if (addr != NULL) {
1234d528f2f4Satatat 			sysctlperror(
1235d528f2f4Satatat 				"%s: cannot specify both value and "
1236d528f2f4Satatat 				"address\n", nname);
123781c8b4d0Schristos 			EXIT(EXIT_FAILURE);
1238c915b316Satatat 		}
1239c915b316Satatat 
1240c915b316Satatat 		switch (type) {
1241c915b316Satatat 		case CTLTYPE_INT:
1242c915b316Satatat 			errno = 0;
1243404831daSchristos 			q = strtoll(data, &t, 0);
1244605d2000Satatat 			if (t == data || *t != '\0' || errno != 0 ||
1245d528f2f4Satatat 				q < INT_MIN || q > UINT_MAX) {
1246d528f2f4Satatat 				sysctlperror(
1247d528f2f4Satatat 				    "%s: '%s' is not a valid integer\n",
1248d528f2f4Satatat 				    nname, value);
124981c8b4d0Schristos 				EXIT(EXIT_FAILURE);
1250c915b316Satatat 			}
1251d528f2f4Satatat 			i = (int)q;
125219af35fdSatatat 			if (!(flags & CTLFLAG_OWNDATA)) {
125319af35fdSatatat 				flags |= CTLFLAG_IMMEDIATE;
1254c915b316Satatat 				node.sysctl_idata = i;
1255c915b316Satatat 			}
1256c915b316Satatat 			else
1257c915b316Satatat 				node.sysctl_data = &i;
1258c915b316Satatat 			if (sz == 0)
1259c915b316Satatat 				sz = sizeof(int);
1260c915b316Satatat 			break;
1261e00e7bd5Smrg 		case CTLTYPE_BOOL:
1262e00e7bd5Smrg 			errno = 0;
1263e00e7bd5Smrg 			q = strtoll(data, &t, 0);
1264e00e7bd5Smrg 			if (t == data || *t != '\0' || errno != 0 ||
1265e00e7bd5Smrg 				(q != 0 && q != 1)) {
1266e00e7bd5Smrg 				sysctlperror(
1267e00e7bd5Smrg 				    "%s: '%s' is not a valid bool\n",
1268e00e7bd5Smrg 				    nname, value);
126981c8b4d0Schristos 				EXIT(EXIT_FAILURE);
1270e00e7bd5Smrg 			}
1271e00e7bd5Smrg 			b = q == 1;
1272e00e7bd5Smrg 			if (!(flags & CTLFLAG_OWNDATA)) {
1273e00e7bd5Smrg 				flags |= CTLFLAG_IMMEDIATE;
1274e00e7bd5Smrg 				node.sysctl_idata = b;
1275e00e7bd5Smrg 			}
1276e00e7bd5Smrg 			else
1277e00e7bd5Smrg 				node.sysctl_data = &b;
1278e00e7bd5Smrg 			if (sz == 0)
1279e00e7bd5Smrg 				sz = sizeof(bool);
1280e00e7bd5Smrg 			break;
1281c915b316Satatat 		case CTLTYPE_STRING:
128219af35fdSatatat 			flags |= CTLFLAG_OWNDATA;
1283c915b316Satatat 			node.sysctl_data = data;
1284c915b316Satatat 			if (sz == 0)
1285c915b316Satatat 				sz = strlen(data) + 1;
1286c915b316Satatat 			else if (sz < strlen(data) + 1) {
1287d528f2f4Satatat 				sysctlperror("%s: ignoring size=%zu for "
1288c915b316Satatat 					"string node, too small for given "
1289d528f2f4Satatat 					"value\n", nname, sz);
1290c915b316Satatat 				sz = strlen(data) + 1;
1291c915b316Satatat 			}
1292c915b316Satatat 			break;
1293c915b316Satatat 		case CTLTYPE_QUAD:
1294c915b316Satatat 			errno = 0;
1295d528f2f4Satatat 			uq = strtouq(data, &t, 0);
1296605d2000Satatat 			if (t == data || *t != '\0' || errno != 0) {
1297d528f2f4Satatat 				sysctlperror(
1298d528f2f4Satatat 					"%s: '%s' is not a valid quad\n",
1299d528f2f4Satatat 					nname, value);
130081c8b4d0Schristos 				EXIT(EXIT_FAILURE);
1301c915b316Satatat 			}
130219af35fdSatatat 			if (!(flags & CTLFLAG_OWNDATA)) {
130319af35fdSatatat 				flags |= CTLFLAG_IMMEDIATE;
1304d528f2f4Satatat 				node.sysctl_qdata = uq;
1305c915b316Satatat 			}
1306c915b316Satatat 			else
1307d528f2f4Satatat 				node.sysctl_data = &uq;
1308c915b316Satatat 			if (sz == 0)
1309c915b316Satatat 				sz = sizeof(u_quad_t);
1310c915b316Satatat 			break;
1311c915b316Satatat 		case CTLTYPE_STRUCT:
1312d528f2f4Satatat 			sysctlperror("%s: struct not initializable\n",
1313d528f2f4Satatat 				     nname);
131481c8b4d0Schristos 			EXIT(EXIT_FAILURE);
1315c915b316Satatat 		}
1316c915b316Satatat 
1317c915b316Satatat 		/*
1318c915b316Satatat 		 * these methods have all provided local starting
1319c915b316Satatat 		 * values that the kernel must copy in
1320c915b316Satatat 		 */
1321c915b316Satatat 	}
1322c915b316Satatat 
1323c915b316Satatat 	/*
1324c915b316Satatat 	 * hmm...no data, but we have an address of data.  that's
1325c915b316Satatat 	 * fine.
1326c915b316Satatat 	 */
1327c915b316Satatat 	else if (addr != 0)
1328c915b316Satatat 		node.sysctl_data = (void*)addr;
1329c915b316Satatat 
1330c915b316Satatat 	/*
1331c915b316Satatat 	 * no data and no address?  well...okay.  we might be able to
1332c915b316Satatat 	 * manage that.
1333c915b316Satatat 	 */
1334c915b316Satatat 	else if (type != CTLTYPE_NODE) {
1335c915b316Satatat 		if (sz == 0) {
1336d528f2f4Satatat 			sysctlperror(
1337d528f2f4Satatat 			    "%s: need a size or a starting value\n",
1338d528f2f4Satatat 			    nname);
133981c8b4d0Schristos                         EXIT(EXIT_FAILURE);
1340c915b316Satatat                 }
134119af35fdSatatat 		if (!(flags & CTLFLAG_IMMEDIATE))
134219af35fdSatatat 			flags |= CTLFLAG_OWNDATA;
1343c915b316Satatat 	}
1344c915b316Satatat 
1345c915b316Satatat 	/*
1346c915b316Satatat 	 * now we do a few sanity checks on the description we've
1347c915b316Satatat 	 * assembled
1348c915b316Satatat 	 */
134919af35fdSatatat 	if ((flags & CTLFLAG_IMMEDIATE) &&
1350c915b316Satatat 	    (type == CTLTYPE_STRING || type == CTLTYPE_STRUCT)) {
1351d528f2f4Satatat 		sysctlperror("%s: cannot make an immediate %s\n",
1352d528f2f4Satatat 			     nname,
1353c915b316Satatat 			     (type == CTLTYPE_STRING) ? "string" : "struct");
135481c8b4d0Schristos 		EXIT(EXIT_FAILURE);
1355c915b316Satatat 	}
1356c915b316Satatat 	if (type == CTLTYPE_NODE && node.sysctl_data != NULL) {
1357d528f2f4Satatat 		sysctlperror("%s: nodes do not have data\n", nname);
135881c8b4d0Schristos 		EXIT(EXIT_FAILURE);
1359c915b316Satatat 	}
1360c915b316Satatat 
1361c915b316Satatat 	/*
1362c915b316Satatat 	 * some types must have a particular size
1363c915b316Satatat 	 */
1364c915b316Satatat 	if (sz != 0) {
1365c915b316Satatat 		if ((type == CTLTYPE_INT && sz != sizeof(int)) ||
1366e00e7bd5Smrg 		    (type == CTLTYPE_BOOL && sz != sizeof(bool)) ||
1367c915b316Satatat 		    (type == CTLTYPE_QUAD && sz != sizeof(u_quad_t)) ||
1368c915b316Satatat 		    (type == CTLTYPE_NODE && sz != 0)) {
1369d528f2f4Satatat 			sysctlperror("%s: wrong size for type\n", nname);
137081c8b4d0Schristos 			EXIT(EXIT_FAILURE);
1371c915b316Satatat 		}
1372c915b316Satatat 	}
1373c915b316Satatat 	else if (type == CTLTYPE_STRUCT) {
1374d528f2f4Satatat 		sysctlperror("%s: struct must have size\n", nname);
137581c8b4d0Schristos 		EXIT(EXIT_FAILURE);
1376c915b316Satatat 	}
1377c915b316Satatat 
1378c915b316Satatat 	/*
1379c915b316Satatat 	 * now...if no one said anything yet, we default nodes or
1380c915b316Satatat 	 * any type that owns data being writeable, and everything
1381c915b316Satatat 	 * else being readonly.
1382c915b316Satatat 	 */
1383c915b316Satatat 	if (rw == -1) {
1384c915b316Satatat 		if (type == CTLTYPE_NODE ||
138519af35fdSatatat 		    (flags & (CTLFLAG_OWNDATA|CTLFLAG_IMMEDIATE)))
138619af35fdSatatat 			rw = CTLFLAG_READWRITE;
1387c915b316Satatat 		else
138819af35fdSatatat 			rw = CTLFLAG_READONLY;
1389c915b316Satatat 	}
1390c915b316Satatat 
1391c915b316Satatat 	/*
1392c915b316Satatat 	 * if a kernel address was specified, that can't be made
1393c915b316Satatat 	 * writeable by us.
139419af35fdSatatat 	if (rw != CTLFLAG_READONLY && addr) {
1395d528f2f4Satatat 		sysctlperror("%s: kernel data can only be readable\n", nname);
139681c8b4d0Schristos 		EXIT(EXIT_FAILURE);
1397c915b316Satatat 	}
1398c915b316Satatat 	 */
1399c915b316Satatat 
1400c915b316Satatat 	/*
1401c915b316Satatat 	 * what separator were they using in the full name of the new
1402c915b316Satatat 	 * node?
1403c915b316Satatat 	 */
1404c915b316Satatat 	if ((t = strpbrk(nname, "./")) == NULL)
1405c915b316Satatat 		sep[0] = '.';
1406c915b316Satatat 	else
1407c915b316Satatat 		sep[0] = t[0];
1408c915b316Satatat 	sep[1] = '\0';
1409c915b316Satatat 
1410c915b316Satatat 	/*
1411c915b316Satatat 	 * put it all together, now.  t'ain't much, is it?
1412c915b316Satatat 	 */
141319af35fdSatatat 	node.sysctl_flags = SYSCTL_VERSION|flags|rw|type;
1414c915b316Satatat 	node.sysctl_size = sz;
1415c915b316Satatat 	t = strrchr(nname, sep[0]);
1416c915b316Satatat 	if (t != NULL)
1417c915b316Satatat 		strlcpy(node.sysctl_name, t + 1, sizeof(node.sysctl_name));
1418c915b316Satatat 	else
1419c915b316Satatat 		strlcpy(node.sysctl_name, nname, sizeof(node.sysctl_name));
1420299501e0Satatat 	if (t == nname)
1421299501e0Satatat 		t = NULL;
1422c915b316Satatat 
1423c915b316Satatat 	/*
1424c915b316Satatat 	 * if this is a new top-level node, then we don't need to find
1425c915b316Satatat 	 * the mib for its parent
1426c915b316Satatat 	 */
1427c915b316Satatat 	if (t == NULL) {
1428c915b316Satatat 		namelen = 0;
1429c915b316Satatat 		gsname[0] = '\0';
1430c915b316Satatat 	}
1431c915b316Satatat 
1432c915b316Satatat 	/*
1433c915b316Satatat 	 * on the other hand, if it's not a top-level node...
1434c915b316Satatat 	 */
1435c915b316Satatat 	else {
1436c915b316Satatat 		namelen = sizeof(name) / sizeof(name[0]);
1437c915b316Satatat 		sz = sizeof(gsname);
1438c915b316Satatat 		*t = '\0';
1439997c4cdcSkamil 		rc = prog_sysctlgetmibinfo(nname, &name[0], &namelen,
144019af35fdSatatat 				      gsname, &sz, NULL, SYSCTL_VERSION);
1441c915b316Satatat 		*t = sep[0];
1442c915b316Satatat 		if (rc == -1) {
1443d528f2f4Satatat 			sysctlparseerror(namelen, nname);
144481c8b4d0Schristos 			EXIT(EXIT_FAILURE);
1445c915b316Satatat 		}
1446c915b316Satatat 	}
1447c915b316Satatat 
1448c915b316Satatat 	/*
1449c915b316Satatat 	 * yes, a new node is being created
1450c915b316Satatat 	 */
1451c915b316Satatat 	if (method != 0)
1452c915b316Satatat 		name[namelen++] = method;
1453c915b316Satatat 	else
1454c915b316Satatat 		name[namelen++] = CTL_CREATE;
1455c915b316Satatat 
1456c915b316Satatat 	sz = sizeof(node);
1457f9740adaSpooka 	rc = prog_sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node));
1458c915b316Satatat 
1459c915b316Satatat 	if (rc == -1) {
1460d528f2f4Satatat 		sysctlperror("%s: CTL_CREATE failed: %s\n",
1461d528f2f4Satatat 			     nname, strerror(errno));
146281c8b4d0Schristos 		EXIT(EXIT_FAILURE);
1463c915b316Satatat 	}
14640f48b536Satatat 	else {
14650f48b536Satatat 		if (!qflag && !nflag)
1466c915b316Satatat 			printf("%s(%s): (created)\n", nname, st(type));
14670f48b536Satatat 		stale = 1;
14680f48b536Satatat 	}
1469c915b316Satatat }
1470c915b316Satatat 
1471c915b316Satatat static void
parse_destroy(char * l)1472299501e0Satatat parse_destroy(char *l)
1473c915b316Satatat {
1474c915b316Satatat 	struct sysctlnode node;
1475c915b316Satatat 	size_t sz;
1476c915b316Satatat 	int name[CTL_MAXNAME], rc;
1477c915b316Satatat 	u_int namelen;
1478c915b316Satatat 
1479299501e0Satatat 	if (!wflag) {
1480d528f2f4Satatat 		sysctlperror("Must specify -w to destroy nodes\n");
148181c8b4d0Schristos 		exit(EXIT_FAILURE);
1482299501e0Satatat 	}
1483299501e0Satatat 
1484c915b316Satatat 	memset(name, 0, sizeof(name));
1485c915b316Satatat 	namelen = sizeof(name) / sizeof(name[0]);
1486c915b316Satatat 	sz = sizeof(gsname);
1487997c4cdcSkamil 	rc = prog_sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL,
148819af35fdSatatat 			      SYSCTL_VERSION);
1489c915b316Satatat 	if (rc == -1) {
1490d528f2f4Satatat 		sysctlparseerror(namelen, l);
149181c8b4d0Schristos 		EXIT(EXIT_FAILURE);
1492c915b316Satatat 	}
1493c915b316Satatat 
1494c915b316Satatat 	memset(&node, 0, sizeof(node));
149519af35fdSatatat 	node.sysctl_flags = SYSCTL_VERSION;
1496c915b316Satatat 	node.sysctl_num = name[namelen - 1];
1497c915b316Satatat 	name[namelen - 1] = CTL_DESTROY;
1498c915b316Satatat 
1499c915b316Satatat 	sz = sizeof(node);
1500f9740adaSpooka 	rc = prog_sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node));
1501c915b316Satatat 
1502c915b316Satatat 	if (rc == -1) {
1503d528f2f4Satatat 		sysctlperror("%s: CTL_DESTROY failed: %s\n",
1504d528f2f4Satatat 			     l, strerror(errno));
150581c8b4d0Schristos 		EXIT(EXIT_FAILURE);
1506c915b316Satatat 	}
15070f48b536Satatat 	else {
15080f48b536Satatat 		if (!qflag && !nflag)
1509c915b316Satatat 			printf("%s(%s): (destroyed)\n", gsname,
1510c915b316Satatat 			       st(SYSCTL_TYPE(node.sysctl_flags)));
15110f48b536Satatat 		stale = 1;
15120f48b536Satatat 	}
1513c915b316Satatat }
1514c915b316Satatat 
151538c4183bSatatat static void
parse_describe(char * l)151638c4183bSatatat parse_describe(char *l)
151738c4183bSatatat {
151838c4183bSatatat 	struct sysctlnode newdesc;
151938c4183bSatatat 	char buf[1024], *value;
152038c4183bSatatat 	struct sysctldesc *d = (void*)&buf[0];
152138c4183bSatatat 	int name[CTL_MAXNAME], rc;
152238c4183bSatatat 	u_int namelen;
152338c4183bSatatat 	size_t sz;
152438c4183bSatatat 
152538c4183bSatatat 	if (!wflag) {
1526d528f2f4Satatat 		sysctlperror("Must specify -w to set descriptions\n");
152781c8b4d0Schristos 		exit(EXIT_FAILURE);
152838c4183bSatatat 	}
152938c4183bSatatat 
153038c4183bSatatat 	value = strchr(l, '=');
153138c4183bSatatat 	*value++ = '\0';
153238c4183bSatatat 
153338c4183bSatatat 	memset(name, 0, sizeof(name));
153438c4183bSatatat 	namelen = sizeof(name) / sizeof(name[0]);
153538c4183bSatatat 	sz = sizeof(gsname);
1536997c4cdcSkamil 	rc = prog_sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL,
153738c4183bSatatat 			      SYSCTL_VERSION);
153838c4183bSatatat 	if (rc == -1) {
1539d528f2f4Satatat 		sysctlparseerror(namelen, l);
154081c8b4d0Schristos 		EXIT(EXIT_FAILURE);
154138c4183bSatatat 	}
154238c4183bSatatat 
154338c4183bSatatat 	sz = sizeof(buf);
154438c4183bSatatat 	memset(&newdesc, 0, sizeof(newdesc));
154538c4183bSatatat 	newdesc.sysctl_flags = SYSCTL_VERSION|CTLFLAG_OWNDESC;
154638c4183bSatatat 	newdesc.sysctl_num = name[namelen - 1];
154738c4183bSatatat 	newdesc.sysctl_desc = value;
154838c4183bSatatat 	name[namelen - 1] = CTL_DESCRIBE;
1549f9740adaSpooka 	rc = prog_sysctl(name, namelen, d, &sz, &newdesc, sizeof(newdesc));
155038c4183bSatatat 	if (rc == -1)
1551d528f2f4Satatat 		sysctlperror("%s: CTL_DESCRIBE failed: %s\n",
1552d528f2f4Satatat 			     gsname, strerror(errno));
155338c4183bSatatat 	else if (d->descr_len == 1)
1554d528f2f4Satatat 		sysctlperror("%s: description not set\n", gsname);
155538c4183bSatatat 	else if (!qflag && !nflag)
155638c4183bSatatat 		printf("%s: %s\n", gsname, d->descr_str);
155738c4183bSatatat }
155838c4183bSatatat 
1559c915b316Satatat /*
1560c915b316Satatat  * ********************************************************************
1561c915b316Satatat  * when things go wrong...
1562c915b316Satatat  * ********************************************************************
1563c915b316Satatat  */
15640af5938cSitojun static void
usage(void)1565750526acSsimonb usage(void)
15660af5938cSitojun {
15678a986b2eScgd 	const char *progname = getprogname();
15688a986b2eScgd 
15696de0e99dSlukem 	(void)fprintf(stderr,
1570b635f565Sjmmv 		      "usage:\t%s %s\n"
1571c915b316Satatat 		      "\t%s %s\n"
1572c915b316Satatat 		      "\t%s %s\n"
1573c915b316Satatat 		      "\t%s %s\n"
1574c915b316Satatat 		      "\t%s %s\n"
1575c915b316Satatat 		      "\t%s %s\n",
1576daf90d37Schristos 		      progname, "[-dneq] [-x[x]|-r] variable ...",
1577c915b316Satatat 		      progname, "[-ne] [-q] -w variable=value ...",
1578fcc6bb17Satatat 		      progname, "[-dne] -a",
1579fcc6bb17Satatat 		      progname, "[-dne] -A",
1580c915b316Satatat 		      progname, "[-ne] -M",
1581fcc6bb17Satatat 		      progname, "[-dne] [-q] -f file");
158281c8b4d0Schristos 	exit(EXIT_FAILURE);
15830af5938cSitojun }
1584c915b316Satatat 
158538c4183bSatatat static void
getdesc1(int * name,u_int namelen,struct sysctlnode * pnode)158638c4183bSatatat getdesc1(int *name, u_int namelen, struct sysctlnode *pnode)
158738c4183bSatatat {
158838c4183bSatatat 	struct sysctlnode node;
158938c4183bSatatat 	char buf[1024], *desc;
159038c4183bSatatat 	struct sysctldesc *d = (void*)buf;
159138c4183bSatatat 	size_t sz = sizeof(buf);
159238c4183bSatatat 	int rc;
159338c4183bSatatat 
159438c4183bSatatat 	memset(&node, 0, sizeof(node));
159538c4183bSatatat 	node.sysctl_flags = SYSCTL_VERSION;
159638c4183bSatatat 	node.sysctl_num = name[namelen - 1];
159738c4183bSatatat 	name[namelen - 1] = CTL_DESCRIBE;
1598f9740adaSpooka 	rc = prog_sysctl(name, namelen, d, &sz, &node, sizeof(node));
159938c4183bSatatat 
160038c4183bSatatat 	if (rc == -1 ||
160138c4183bSatatat 	    d->descr_len == 1 ||
160238c4183bSatatat 	    d->descr_num != pnode->sysctl_num ||
160338c4183bSatatat 	    d->descr_ver != pnode->sysctl_ver)
160438c4183bSatatat 		desc = (char *)-1;
160538c4183bSatatat 	else
160638c4183bSatatat 		desc = malloc(d->descr_len);
160738c4183bSatatat 
160838c4183bSatatat 	if (desc == NULL)
160938c4183bSatatat 		desc = (char *)-1;
161038c4183bSatatat 	if (desc != (char *)-1)
1611610ed0d0Satatat 		memcpy(desc, &d->descr_str[0], d->descr_len);
161238c4183bSatatat 	name[namelen - 1] = node.sysctl_num;
161338c4183bSatatat 	if (pnode->sysctl_desc != NULL &&
161438c4183bSatatat 	    pnode->sysctl_desc != (const char *)-1)
16152c6eadc9Schristos 		free(__UNCONST(pnode->sysctl_desc));
161638c4183bSatatat 	pnode->sysctl_desc = desc;
161738c4183bSatatat }
161838c4183bSatatat 
161938c4183bSatatat static void
getdesc(int * name,u_int namelen,struct sysctlnode * pnode)162038c4183bSatatat getdesc(int *name, u_int namelen, struct sysctlnode *pnode)
162138c4183bSatatat {
162238c4183bSatatat 	struct sysctlnode *node = pnode->sysctl_child;
1623d528f2f4Satatat 	struct sysctldesc *d, *p, *plim;
162438c4183bSatatat 	char *desc;
1625722b7febSmartin 	size_t i, sz, child_cnt;
1626deb4c0bbSlukem 	int rc;
162738c4183bSatatat 
162838c4183bSatatat 	sz = 128 * pnode->sysctl_clen;
162938c4183bSatatat 	name[namelen] = CTL_DESCRIBE;
163038c4183bSatatat 
163138c4183bSatatat 	/*
163238c4183bSatatat 	 * attempt *twice* to get the description chunk.  if two tries
163338c4183bSatatat 	 * doesn't work, give up.
163438c4183bSatatat 	 */
163538c4183bSatatat 	i = 0;
163638c4183bSatatat 	do {
1637a929f1c4Satatat 		d = malloc(sz);
163838c4183bSatatat 		if (d == NULL)
163938c4183bSatatat 			return;
1640f9740adaSpooka 		rc = prog_sysctl(name, namelen + 1, d, &sz, NULL, 0);
164138c4183bSatatat 		if (rc == -1) {
164238c4183bSatatat 			free(d);
164338c4183bSatatat 			d = NULL;
164438c4183bSatatat 			if (i == 0 && errno == ENOMEM)
164538c4183bSatatat 				i = 1;
164638c4183bSatatat 			else
164738c4183bSatatat 				return;
164838c4183bSatatat 		}
164938c4183bSatatat 	} while (d == NULL);
165038c4183bSatatat 
165138c4183bSatatat 	/*
165238c4183bSatatat 	 * hokey nested loop here, giving O(n**2) behavior, but should
165338c4183bSatatat 	 * suffice for now
165438c4183bSatatat 	 */
1655d528f2f4Satatat 	plim = /*LINTED ptr cast*/(struct sysctldesc *)((char*)d + sz);
1656722b7febSmartin 	child_cnt = (pnode->sysctl_flags & CTLTYPE_NODE) ? pnode->sysctl_clen
1657722b7febSmartin 	    : 0;
1658722b7febSmartin 	for (i = 0; i < child_cnt; i++) {
165938c4183bSatatat 		node = &pnode->sysctl_child[i];
1660d528f2f4Satatat 		for (p = d; p < plim; p = NEXT_DESCR(p))
166138c4183bSatatat 			if (node->sysctl_num == p->descr_num)
166238c4183bSatatat 				break;
166316043823Satatat 		if (p < plim && node->sysctl_ver == p->descr_ver) {
166438c4183bSatatat 			/*
166538c4183bSatatat 			 * match found, attempt to attach description
166638c4183bSatatat 			 */
166738c4183bSatatat 			if (p->descr_len == 1)
166838c4183bSatatat 				desc = NULL;
166938c4183bSatatat 			else
167038c4183bSatatat 				desc = malloc(p->descr_len);
167138c4183bSatatat 			if (desc == NULL)
167238c4183bSatatat 				desc = (char *)-1;
167338c4183bSatatat 			else
167467f14f8fSatatat 				memcpy(desc, &p->descr_str[0], p->descr_len);
167538c4183bSatatat 			node->sysctl_desc = desc;
167638c4183bSatatat 		}
167738c4183bSatatat 	}
167838c4183bSatatat 
167938c4183bSatatat 	free(d);
168038c4183bSatatat }
168138c4183bSatatat 
1682d528f2f4Satatat static void
trim_whitespace(char * s,int dir)1683d528f2f4Satatat trim_whitespace(char *s, int dir)
1684d528f2f4Satatat {
1685d528f2f4Satatat 	char *i, *o;
1686d528f2f4Satatat 
1687d528f2f4Satatat 	i = o = s;
1688d528f2f4Satatat 	if (dir & 1)
1689d528f2f4Satatat 		while (isspace((unsigned char)*i))
1690d528f2f4Satatat 			i++;
1691d528f2f4Satatat 	while ((*o++ = *i++) != '\0');
1692d528f2f4Satatat 	o -= 2; /* already past nul, skip back to before it */
1693d528f2f4Satatat 	if (dir & 2)
1694d528f2f4Satatat 		while (o > s && isspace((unsigned char)*o))
1695d528f2f4Satatat 			*o-- = '\0';
1696d528f2f4Satatat }
1697d528f2f4Satatat 
1698c915b316Satatat void
sysctlerror(int soft)1699c915b316Satatat sysctlerror(int soft)
1700c915b316Satatat {
1701c915b316Satatat 	if (soft) {
1702c915b316Satatat 		switch (errno) {
1703c915b316Satatat 		case ENOENT:
1704c915b316Satatat 		case ENOPROTOOPT:
1705c915b316Satatat 		case ENOTDIR:
17066472d0c3Satatat 		case EINVAL:
1707c915b316Satatat 		case EOPNOTSUPP:
1708c915b316Satatat 		case EPROTONOSUPPORT:
1709c915b316Satatat 			if (Aflag || req)
171066d4eaa7Schristos 				sysctlperror("%s: the value is not available "
171166d4eaa7Schristos 				    "(%s)\n", gsname, strerror(errno));
1712c915b316Satatat 			return;
1713c915b316Satatat 		}
1714c915b316Satatat 	}
1715c915b316Satatat 
1716b678a11dSchristos 	if (Aflag || req)
1717b678a11dSchristos 		sysctlperror("%s: %s\n", gsname, strerror(errno));
1718c915b316Satatat 	if (!soft)
171981c8b4d0Schristos 		EXIT(EXIT_FAILURE);
1720c915b316Satatat }
1721c915b316Satatat 
1722d528f2f4Satatat void
sysctlparseerror(u_int namelen,const char * pname)1723d528f2f4Satatat sysctlparseerror(u_int namelen, const char *pname)
1724d528f2f4Satatat {
1725d528f2f4Satatat 
1726daf90d37Schristos 	if (qflag) {
1727daf90d37Schristos 		errs++;
1728daf90d37Schristos 		return;
1729daf90d37Schristos 	}
1730d528f2f4Satatat 	sysctlperror("%s level name '%s' in '%s' is invalid\n",
1731d528f2f4Satatat 		     lname[namelen], gsname, pname);
1732d528f2f4Satatat }
1733d528f2f4Satatat 
1734d528f2f4Satatat static void
sysctlperror(const char * fmt,...)1735d528f2f4Satatat sysctlperror(const char *fmt, ...)
1736d528f2f4Satatat {
1737d528f2f4Satatat 	va_list ap;
1738d528f2f4Satatat 
1739d528f2f4Satatat 	(void)fprintf(warnfp, "%s: ", getprogname());
1740d528f2f4Satatat 	if (fn)
1741d528f2f4Satatat 		(void)fprintf(warnfp, "%s#%zu: ", fn, nr);
1742d528f2f4Satatat 	va_start(ap, fmt);
1743d528f2f4Satatat 	(void)vfprintf(warnfp, fmt, ap);
1744d528f2f4Satatat 	va_end(ap);
1745b311ec9dSchristos 	errs++;
1746d528f2f4Satatat }
1747d528f2f4Satatat 
1748d528f2f4Satatat 
1749c915b316Satatat /*
1750c915b316Satatat  * ********************************************************************
1751c915b316Satatat  * how to write to a "simple" node
1752c915b316Satatat  * ********************************************************************
1753c915b316Satatat  */
1754c915b316Satatat static void
write_number(int * name,u_int namelen,struct sysctlnode * node,char * value,bool optional)175505ce5c42Sdholland write_number(int *name, u_int namelen, struct sysctlnode *node, char *value,
175605ce5c42Sdholland 	bool optional)
1757c915b316Satatat {
1758404831daSchristos 	u_int ii, io;
1759c915b316Satatat 	u_quad_t qi, qo;
1760c915b316Satatat 	size_t si, so;
1761e00e7bd5Smrg 	bool bi, bo;
1762c915b316Satatat 	int rc;
1763c915b316Satatat 	void *i, *o;
1764c915b316Satatat 	char *t;
1765c915b316Satatat 
1766d528f2f4Satatat 	if (fn)
1767d528f2f4Satatat 		trim_whitespace(value, 3);
1768d528f2f4Satatat 
1769c915b316Satatat 	si = so = 0;
1770c915b316Satatat 	i = o = NULL;
1771e00e7bd5Smrg 	bi = bo = false;
1772c915b316Satatat 	errno = 0;
1773c915b316Satatat 	qi = strtouq(value, &t, 0);
1774404831daSchristos 	if (qi == UQUAD_MAX && errno == ERANGE) {
1775404831daSchristos 		sysctlperror("%s: %s\n", value, strerror(errno));
177681c8b4d0Schristos 		EXIT(EXIT_FAILURE);
1777c915b316Satatat 	}
1778605d2000Satatat 	if (t == value || *t != '\0') {
1779d528f2f4Satatat 		sysctlperror("%s: not a number\n", value);
178081c8b4d0Schristos 		EXIT(EXIT_FAILURE);
1781c915b316Satatat 	}
1782c915b316Satatat 
1783c915b316Satatat 	switch (SYSCTL_TYPE(node->sysctl_flags)) {
1784c915b316Satatat 	case CTLTYPE_INT:
1785404831daSchristos 		ii = (u_int)qi;
1786238f1027Schristos 		io = (u_int)(qi >> 32);
1787238f1027Schristos 		if (io != (u_int)-1 && io != 0) {
1788404831daSchristos 			sysctlperror("%s: %s\n", value, strerror(ERANGE));
178981c8b4d0Schristos 			EXIT(EXIT_FAILURE);
1790c915b316Satatat 		}
1791c915b316Satatat 		o = &io;
1792c915b316Satatat 		so = sizeof(io);
1793c915b316Satatat 		i = &ii;
1794c915b316Satatat 		si = sizeof(ii);
1795c915b316Satatat 		break;
1796e00e7bd5Smrg 	case CTLTYPE_BOOL:
1797e00e7bd5Smrg 		bi = (bool)qi;
1798e00e7bd5Smrg 		o = &bo;
1799e00e7bd5Smrg 		so = sizeof(bo);
1800e00e7bd5Smrg 		i = &bi;
1801e00e7bd5Smrg 		si = sizeof(bi);
1802e00e7bd5Smrg 		break;
1803c915b316Satatat 	case CTLTYPE_QUAD:
1804c915b316Satatat 		o = &qo;
1805c915b316Satatat 		so = sizeof(qo);
1806c915b316Satatat 		i = &qi;
1807c915b316Satatat 		si = sizeof(qi);
1808c915b316Satatat 		break;
1809c915b316Satatat 	}
1810c915b316Satatat 
1811f9740adaSpooka 	rc = prog_sysctl(name, namelen, o, &so, i, si);
1812d528f2f4Satatat 	if (rc == -1) {
181305ce5c42Sdholland 		if (!optional || errno != EPERM) {
1814c915b316Satatat 			sysctlerror(0);
181505ce5c42Sdholland 		}
1816d528f2f4Satatat 		return;
1817d528f2f4Satatat 	}
1818c915b316Satatat 
1819c915b316Satatat 	switch (SYSCTL_TYPE(node->sysctl_flags)) {
1820c915b316Satatat 	case CTLTYPE_INT:
1821c915b316Satatat 		display_number(node, gsname, &io, sizeof(io), DISPLAY_OLD);
1822c915b316Satatat 		display_number(node, gsname, &ii, sizeof(ii), DISPLAY_NEW);
1823c915b316Satatat 		break;
1824e00e7bd5Smrg 	case CTLTYPE_BOOL:
1825e00e7bd5Smrg 		display_number(node, gsname, &bo, sizeof(bo), DISPLAY_OLD);
1826e00e7bd5Smrg 		display_number(node, gsname, &bi, sizeof(bi), DISPLAY_NEW);
1827e00e7bd5Smrg 		break;
1828c915b316Satatat 	case CTLTYPE_QUAD:
1829c915b316Satatat 		display_number(node, gsname, &qo, sizeof(qo), DISPLAY_OLD);
1830c915b316Satatat 		display_number(node, gsname, &qi, sizeof(qi), DISPLAY_NEW);
1831c915b316Satatat 		break;
1832c915b316Satatat 	}
1833c915b316Satatat }
1834c915b316Satatat 
1835c915b316Satatat static void
write_string(int * name,u_int namelen,struct sysctlnode * node,char * value,bool optional)183605ce5c42Sdholland write_string(int *name, u_int namelen, struct sysctlnode *node, char *value,
183705ce5c42Sdholland 	bool optional)
1838c915b316Satatat {
1839c915b316Satatat 	char *i, *o;
1840c915b316Satatat 	size_t si, so;
1841c915b316Satatat 	int rc;
1842c915b316Satatat 
1843c915b316Satatat 	i = value;
1844c915b316Satatat 	si = strlen(i) + 1;
1845c915b316Satatat 	so = node->sysctl_size;
1846c915b316Satatat 	if (si > so && so != 0) {
1847d528f2f4Satatat 		sysctlperror("%s: string too long\n", value);
184881c8b4d0Schristos 		EXIT(EXIT_FAILURE);
1849c915b316Satatat 	}
1850c915b316Satatat 	o = malloc(so);
1851c915b316Satatat 	if (o == NULL) {
1852d528f2f4Satatat 		sysctlperror("%s: !malloc failed!\n", gsname);
185381c8b4d0Schristos 		exit(EXIT_FAILURE);
1854c915b316Satatat 	}
1855c915b316Satatat 
1856f9740adaSpooka 	rc = prog_sysctl(name, namelen, o, &so, i, si);
1857d528f2f4Satatat 	if (rc == -1) {
185805ce5c42Sdholland 		if (!optional || errno != EPERM) {
1859c915b316Satatat 			sysctlerror(0);
186005ce5c42Sdholland 		}
186105ce5c42Sdholland 		free(o);
1862d528f2f4Satatat 		return;
1863d528f2f4Satatat 	}
1864c915b316Satatat 
1865c915b316Satatat 	display_string(node, gsname, o, so, DISPLAY_OLD);
1866c915b316Satatat 	display_string(node, gsname, i, si, DISPLAY_NEW);
1867c915b316Satatat 	free(o);
1868c915b316Satatat }
1869c915b316Satatat 
1870c915b316Satatat /*
1871c915b316Satatat  * ********************************************************************
1872c915b316Satatat  * simple ways to print stuff consistently
1873c915b316Satatat  * ********************************************************************
1874c915b316Satatat  */
1875c915b316Satatat static void
display_number(const struct sysctlnode * node,const char * name,const void * data,size_t sz,int n)1876c915b316Satatat display_number(const struct sysctlnode *node, const char *name,
1877c915b316Satatat 	       const void *data, size_t sz, int n)
1878c915b316Satatat {
1879c915b316Satatat 	u_quad_t q;
1880e00e7bd5Smrg 	bool b;
1881c915b316Satatat 	int i;
1882c915b316Satatat 
1883c915b316Satatat 	if (qflag)
1884c915b316Satatat 		return;
1885c915b316Satatat 	if ((nflag || rflag) && (n == DISPLAY_OLD))
1886c915b316Satatat 		return;
1887c915b316Satatat 
1888c915b316Satatat 	if (rflag && n != DISPLAY_OLD) {
1889c915b316Satatat 		fwrite(data, sz, 1, stdout);
1890c915b316Satatat 		return;
1891c915b316Satatat 	}
1892c915b316Satatat 
1893c915b316Satatat 	if (!nflag) {
1894c915b316Satatat 		if (n == DISPLAY_VALUE)
1895c915b316Satatat 			printf("%s%s", name, eq);
1896c915b316Satatat 		else if (n == DISPLAY_OLD)
1897c915b316Satatat 			printf("%s: ", name);
1898c915b316Satatat 	}
1899c915b316Satatat 
1900c915b316Satatat 	if (xflag > 1) {
19015e111b3cSatatat 		if (n != DISPLAY_NEW)
1902c915b316Satatat 			printf("\n");
1903c915b316Satatat 		hex_dump(data, sz);
1904c915b316Satatat 		return;
1905c915b316Satatat 	}
1906c915b316Satatat 
1907c915b316Satatat 	switch (SYSCTL_TYPE(node->sysctl_flags)) {
1908c915b316Satatat 	case CTLTYPE_INT:
1909c915b316Satatat 		memcpy(&i, data, sz);
1910c915b316Satatat 		if (xflag)
1911c915b316Satatat 			printf("0x%0*x", (int)sz * 2, i);
191219af35fdSatatat 		else if (node->sysctl_flags & CTLFLAG_HEX)
1913c915b316Satatat 			printf("%#x", i);
19140836a9f5Sdsl 		else if (node->sysctl_flags & CTLFLAG_UNSIGNED)
19150836a9f5Sdsl 			printf("%u", i);
1916c915b316Satatat 		else
1917c915b316Satatat 			printf("%d", i);
1918c915b316Satatat 		break;
1919e00e7bd5Smrg 	case CTLTYPE_BOOL:
1920e00e7bd5Smrg 		memcpy(&b, data, sz);
1921e00e7bd5Smrg 		if (xflag)
1922e00e7bd5Smrg 			printf("0x%0*x", (int)sz * 2, b);
1923e00e7bd5Smrg 		else if (node->sysctl_flags & CTLFLAG_HEX)
1924e00e7bd5Smrg 			printf("%#x", b);
1925e00e7bd5Smrg 		else
1926e00e7bd5Smrg 			printf("%d", b);
1927e00e7bd5Smrg 		break;
1928c915b316Satatat 	case CTLTYPE_QUAD:
1929c915b316Satatat 		memcpy(&q, data, sz);
1930c915b316Satatat 		if (xflag)
1931c915b316Satatat 			printf("0x%0*" PRIx64, (int)sz * 2, q);
193219af35fdSatatat 		else if (node->sysctl_flags & CTLFLAG_HEX)
1933c915b316Satatat 			printf("%#" PRIx64, q);
19340836a9f5Sdsl 		else if (node->sysctl_flags & CTLFLAG_UNSIGNED)
19350836a9f5Sdsl 			printf("%" PRIu64, q);
1936c915b316Satatat 		else
1937c915b316Satatat 			printf("%" PRIu64, q);
1938c915b316Satatat 		break;
1939c915b316Satatat 	}
1940c915b316Satatat 
1941c915b316Satatat 	if (n == DISPLAY_OLD)
1942c915b316Satatat 		printf(" -> ");
1943c915b316Satatat 	else
1944c915b316Satatat 		printf("\n");
1945c915b316Satatat }
1946c915b316Satatat 
1947c915b316Satatat static void
display_string(const struct sysctlnode * node,const char * name,const void * data,size_t sz,int n)1948c915b316Satatat display_string(const struct sysctlnode *node, const char *name,
1949c915b316Satatat 	       const void *data, size_t sz, int n)
1950c915b316Satatat {
1951c915b316Satatat 	const unsigned char *buf = data;
1952c915b316Satatat 	int ni;
1953c915b316Satatat 
1954c915b316Satatat 	if (qflag)
1955c915b316Satatat 		return;
1956c915b316Satatat 	if ((nflag || rflag) && (n == DISPLAY_OLD))
1957c915b316Satatat 		return;
1958c915b316Satatat 
1959c915b316Satatat 	if (rflag && n != DISPLAY_OLD) {
1960c915b316Satatat 		fwrite(data, sz, 1, stdout);
1961c915b316Satatat 		return;
1962c915b316Satatat 	}
1963c915b316Satatat 
1964c915b316Satatat 	if (!nflag) {
1965c915b316Satatat 		if (n == DISPLAY_VALUE)
1966c915b316Satatat 			printf("%s%s", name, eq);
1967c915b316Satatat 		else if (n == DISPLAY_OLD)
1968c915b316Satatat 			printf("%s: ", name);
1969c915b316Satatat 	}
1970c915b316Satatat 
1971c915b316Satatat 	if (xflag > 1) {
19725e111b3cSatatat 		if (n != DISPLAY_NEW)
1973c915b316Satatat 			printf("\n");
1974c915b316Satatat 		hex_dump(data, sz);
1975c915b316Satatat 		return;
1976c915b316Satatat 	}
1977c915b316Satatat 
197819af35fdSatatat 	if (xflag || node->sysctl_flags & CTLFLAG_HEX) {
1979c915b316Satatat 		for (ni = 0; ni < (int)sz; ni++) {
1980c915b316Satatat 			if (xflag)
1981c915b316Satatat 				printf("%02x", buf[ni]);
1982c915b316Satatat 			if (buf[ni] == '\0')
1983c915b316Satatat 				break;
1984c915b316Satatat 			if (!xflag)
1985c915b316Satatat 				printf("\\x%2.2x", buf[ni]);
1986c915b316Satatat 		}
1987c915b316Satatat 	}
1988c915b316Satatat 	else
1989c915b316Satatat 		printf("%.*s", (int)sz, buf);
1990c915b316Satatat 
1991c915b316Satatat 	if (n == DISPLAY_OLD)
1992c915b316Satatat 		printf(" -> ");
1993c915b316Satatat 	else
1994c915b316Satatat 		printf("\n");
1995c915b316Satatat }
1996c915b316Satatat 
1997c915b316Satatat /*ARGSUSED*/
1998c915b316Satatat static void
display_struct(const struct sysctlnode * node,const char * name,const void * data,size_t sz,int n)1999c915b316Satatat display_struct(const struct sysctlnode *node, const char *name,
2000c915b316Satatat 	       const void *data, size_t sz, int n)
2001c915b316Satatat {
2002c915b316Satatat 	const unsigned char *buf = data;
2003c915b316Satatat 	int ni;
2004c915b316Satatat 	size_t more;
2005c915b316Satatat 
2006c915b316Satatat 	if (qflag)
2007c915b316Satatat 		return;
2008c915b316Satatat 	if (!(xflag || rflag)) {
2009c915b316Satatat 		if (Aflag || req)
2010d528f2f4Satatat 			sysctlperror(
2011c915b316Satatat 			    "%s: this type is unknown to this program\n",
2012c915b316Satatat 			    gsname);
2013c915b316Satatat 		return;
2014c915b316Satatat 	}
2015c915b316Satatat 	if ((nflag || rflag) && (n == DISPLAY_OLD))
2016c915b316Satatat 		return;
2017c915b316Satatat 
2018c915b316Satatat 	if (rflag && n != DISPLAY_OLD) {
2019c915b316Satatat 		fwrite(data, sz, 1, stdout);
2020c915b316Satatat 		return;
2021c915b316Satatat 	}
2022c915b316Satatat 
2023c915b316Satatat         if (!nflag) {
2024c915b316Satatat                 if (n == DISPLAY_VALUE)
2025c915b316Satatat                         printf("%s%s", name, eq);
2026c915b316Satatat                 else if (n == DISPLAY_OLD)
2027c915b316Satatat                         printf("%s: ", name);
2028c915b316Satatat         }
2029c915b316Satatat 
2030c915b316Satatat 	if (xflag > 1) {
20315e111b3cSatatat 		if (n != DISPLAY_NEW)
2032c915b316Satatat 			printf("\n");
2033c915b316Satatat 		hex_dump(data, sz);
2034c915b316Satatat 		return;
2035c915b316Satatat 	}
2036c915b316Satatat 
2037c915b316Satatat 	if (sz > 16) {
2038c915b316Satatat 		more = sz - 16;
2039c915b316Satatat 		sz = 16;
2040c915b316Satatat 	}
2041c915b316Satatat 	else
2042c915b316Satatat 		more = 0;
2043c915b316Satatat 	for (ni = 0; ni < (int)sz; ni++)
2044c915b316Satatat 		printf("%02x", buf[ni]);
2045c915b316Satatat 	if (more)
2046c915b316Satatat 		printf("...(%zu more bytes)", more);
2047c915b316Satatat 	printf("\n");
2048c915b316Satatat }
2049c915b316Satatat 
2050c915b316Satatat static void
hex_dump(const unsigned char * buf,size_t len)2051c915b316Satatat hex_dump(const unsigned char *buf, size_t len)
2052c915b316Satatat {
2053deb4c0bbSlukem 	unsigned int i;
2054deb4c0bbSlukem 	int j;
2055c915b316Satatat 	char line[80], tmp[12];
2056c915b316Satatat 
2057c915b316Satatat 	memset(line, ' ', sizeof(line));
2058c915b316Satatat 	for (i = 0, j = 15; i < len; i++) {
2059c915b316Satatat 		j = i % 16;
2060c915b316Satatat 		/* reset line */
2061c915b316Satatat 		if (j == 0) {
2062c915b316Satatat 			line[58] = '|';
2063c915b316Satatat 			line[77] = '|';
2064c915b316Satatat 			line[78] = 0;
2065dab2b670Spgoyette 			snprintf(tmp, sizeof(tmp), "%07x", i);
2066c915b316Satatat 			memcpy(&line[0], tmp, 7);
2067c915b316Satatat 		}
2068c915b316Satatat 		/* copy out hex version of byte */
2069c915b316Satatat 		snprintf(tmp, sizeof(tmp), "%02x", buf[i]);
2070c915b316Satatat 		memcpy(&line[9 + j * 3], tmp, 2);
2071c915b316Satatat 		/* copy out plain version of byte */
2072c915b316Satatat 		line[60 + j] = (isprint(buf[i])) ? buf[i] : '.';
2073c915b316Satatat 		/* print a full line and erase it */
2074c915b316Satatat 		if (j == 15) {
2075c915b316Satatat 			printf("%s\n", line);
2076c915b316Satatat 			memset(line, ' ', sizeof(line));
2077c915b316Satatat 		}
2078c915b316Satatat 	}
2079c915b316Satatat 	if (line[0] != ' ')
2080c915b316Satatat 		printf("%s\n", line);
2081c915b316Satatat 	printf("%07zu bytes\n", len);
2082c915b316Satatat }
2083c915b316Satatat 
2084c915b316Satatat /*
2085c915b316Satatat  * ********************************************************************
2086c915b316Satatat  * functions that handle particular nodes
2087c915b316Satatat  * ********************************************************************
2088c915b316Satatat  */
2089c915b316Satatat /*ARGSUSED*/
2090c915b316Satatat static void
printother(HANDLER_ARGS)2091c915b316Satatat printother(HANDLER_ARGS)
2092c915b316Satatat {
2093c915b316Satatat 	int rc;
2094c915b316Satatat 	void *p;
2095c915b316Satatat 	size_t sz1, sz2;
2096c915b316Satatat 
2097c915b316Satatat 	if (!(Aflag || req) || Mflag)
2098c915b316Satatat 		return;
2099c915b316Satatat 
2100c915b316Satatat 	/*
2101c915b316Satatat 	 * okay...you asked for it, so let's give it a go
2102c915b316Satatat 	 */
2103c915b316Satatat 	while (type != CTLTYPE_NODE && (xflag || rflag)) {
2104f9740adaSpooka 		rc = prog_sysctl(name, namelen, NULL, &sz1, NULL, 0);
2105c915b316Satatat 		if (rc == -1 || sz1 == 0)
2106c915b316Satatat 			break;
2107c915b316Satatat 		p = malloc(sz1);
2108c915b316Satatat 		if (p == NULL)
2109c915b316Satatat 			break;
2110c915b316Satatat 		sz2 = sz1;
2111f9740adaSpooka 		rc = prog_sysctl(name, namelen, p, &sz2, NULL, 0);
2112c915b316Satatat 		if (rc == -1 || sz1 != sz2) {
2113c915b316Satatat 			free(p);
2114c915b316Satatat 			break;
2115c915b316Satatat 		}
2116c915b316Satatat 		display_struct(pnode, gsname, p, sz1, DISPLAY_VALUE);
2117c915b316Satatat 		free(p);
2118c915b316Satatat 		return;
2119c915b316Satatat 	}
2120c915b316Satatat 
2121c915b316Satatat 	/*
2122c915b316Satatat 	 * that didn't work...do we have a specific message for this
2123c915b316Satatat 	 * thing?
2124c915b316Satatat 	 */
2125c915b316Satatat 	if (v != NULL) {
2126d528f2f4Satatat 		sysctlperror("%s: use '%s' to view this information\n",
2127c915b316Satatat 			     gsname, (const char *)v);
2128c915b316Satatat 		return;
2129c915b316Satatat 	}
2130c915b316Satatat 
2131c915b316Satatat 	/*
2132c915b316Satatat 	 * hmm...i wonder if we have any generic hints?
2133c915b316Satatat 	 */
2134c915b316Satatat 	switch (name[0]) {
2135c915b316Satatat 	case CTL_NET:
2136d528f2f4Satatat 		sysctlperror("%s: use 'netstat' to view this information\n",
2137c915b316Satatat 			     sname);
2138c915b316Satatat 		break;
2139c915b316Satatat 	case CTL_DEBUG:
2140d528f2f4Satatat 		sysctlperror("%s: missing 'options DEBUG' from kernel?\n",
2141c915b316Satatat 			     sname);
2142c915b316Satatat 		break;
2143c915b316Satatat 	case CTL_DDB:
2144d528f2f4Satatat 		sysctlperror("%s: missing 'options DDB' from kernel?\n",
2145c915b316Satatat 			     sname);
2146c915b316Satatat 		break;
214764dd54edSatatat 	case CTL_VENDOR:
214864dd54edSatatat 		sysctlperror("%s: no vendor extensions installed\n",
214964dd54edSatatat 			     sname);
215064dd54edSatatat 		break;
2151c915b316Satatat 	}
2152c915b316Satatat }
2153c915b316Satatat 
2154c915b316Satatat /*ARGSUSED*/
2155c915b316Satatat static void
kern_clockrate(HANDLER_ARGS)2156c915b316Satatat kern_clockrate(HANDLER_ARGS)
2157c915b316Satatat {
2158c915b316Satatat 	struct clockinfo clkinfo;
2159c915b316Satatat 	size_t sz;
2160c915b316Satatat 	int rc;
2161c915b316Satatat 
2162c915b316Satatat 	sz = sizeof(clkinfo);
2163f9740adaSpooka 	rc = prog_sysctl(name, namelen, &clkinfo, &sz, NULL, 0);
2164c915b316Satatat 	if (rc == -1) {
2165c915b316Satatat 		sysctlerror(1);
2166c915b316Satatat 		return;
2167c915b316Satatat 	}
2168c915b316Satatat 	if (sz != sizeof(clkinfo))
216981c8b4d0Schristos 		errx(EXIT_FAILURE, "%s: !returned size wrong!", sname);
2170c915b316Satatat 
21715e111b3cSatatat 	if (xflag || rflag) {
2172c915b316Satatat 		display_struct(pnode, sname, &clkinfo, sz,
2173c915b316Satatat 			       DISPLAY_VALUE);
21745e111b3cSatatat 		return;
21755e111b3cSatatat 	}
2176c915b316Satatat 	else if (!nflag)
2177c915b316Satatat 		printf("%s: ", sname);
2178c915b316Satatat 	printf("tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
2179c915b316Satatat 	       clkinfo.tick, clkinfo.tickadj,
2180c915b316Satatat 	       clkinfo.hz, clkinfo.profhz, clkinfo.stathz);
2181c915b316Satatat }
2182c915b316Satatat 
2183c915b316Satatat /*ARGSUSED*/
2184c915b316Satatat static void
kern_boottime(HANDLER_ARGS)2185c915b316Satatat kern_boottime(HANDLER_ARGS)
2186c915b316Satatat {
2187c576beb7Skre 	struct timespec timespec;
2188c915b316Satatat 	time_t boottime;
2189c915b316Satatat 	size_t sz;
2190c915b316Satatat 	int rc;
2191c915b316Satatat 
2192c576beb7Skre 	sz = sizeof(timespec);
2193c576beb7Skre 	rc = prog_sysctl(name, namelen, &timespec, &sz, NULL, 0);
2194c915b316Satatat 	if (rc == -1) {
2195c915b316Satatat 		sysctlerror(1);
2196c915b316Satatat 		return;
2197c915b316Satatat 	}
2198c576beb7Skre 	if (sz != sizeof(timespec))
219981c8b4d0Schristos 		errx(EXIT_FAILURE, "%s: !returned size wrong!", sname);
2200c915b316Satatat 
2201c576beb7Skre 	boottime = timespec.tv_sec;
2202c915b316Satatat 	if (xflag || rflag)
2203c576beb7Skre 		display_struct(pnode, sname, &timespec, sz,
2204c915b316Satatat 			       DISPLAY_VALUE);
2205c915b316Satatat 	else if (!nflag)
2206c915b316Satatat 		/* ctime() provides the \n */
2207c915b316Satatat 		printf("%s%s%s", sname, eq, ctime(&boottime));
2208c915b316Satatat 	else if (nflag == 1)
2209c576beb7Skre 		printf("%lld\n", (long long)boottime);
2210c915b316Satatat 	else
2211c576beb7Skre 		printf("%lld.%9.9ld\n", (long long)timespec.tv_sec,
2212c576beb7Skre 		       timespec.tv_nsec);
2213c915b316Satatat }
2214c915b316Satatat 
2215c915b316Satatat /*ARGSUSED*/
2216c915b316Satatat static void
kern_consdev(HANDLER_ARGS)2217c915b316Satatat kern_consdev(HANDLER_ARGS)
2218c915b316Satatat {
2219c915b316Satatat 	dev_t cons;
2220c915b316Satatat 	size_t sz;
2221c915b316Satatat 	int rc;
2222c915b316Satatat 
2223c915b316Satatat 	sz = sizeof(cons);
2224f9740adaSpooka 	rc = prog_sysctl(name, namelen, &cons, &sz, NULL, 0);
2225c915b316Satatat 	if (rc == -1) {
2226c915b316Satatat 		sysctlerror(1);
2227c915b316Satatat 		return;
2228c915b316Satatat 	}
2229c915b316Satatat 	if (sz != sizeof(cons))
223081c8b4d0Schristos 		errx(EXIT_FAILURE, "%s: !returned size wrong!", sname);
2231c915b316Satatat 
2232c915b316Satatat 	if (xflag || rflag)
2233c915b316Satatat 		display_struct(pnode, sname, &cons, sz,
2234c915b316Satatat 			       DISPLAY_VALUE);
22357a221682Schristos 	else {
22367a221682Schristos 		if (!nflag)
22377a221682Schristos 			printf("%s%s", sname, eq);
2238ad6c31ceSchristos 		if (nflag < 2 && (sname = devname(cons, S_IFCHR)) != NULL)
2239ad6c31ceSchristos 			printf("%s\n", sname);
2240c915b316Satatat 		else
2241118c87a6Schristos 			printf("0x%llx\n", (unsigned long long)cons);
2242c915b316Satatat 	}
22437a221682Schristos }
2244c915b316Satatat 
2245c915b316Satatat /*ARGSUSED*/
2246c915b316Satatat static void
kern_cp_time(HANDLER_ARGS)2247c915b316Satatat kern_cp_time(HANDLER_ARGS)
2248c915b316Satatat {
2249589a0803Satatat 	u_int64_t *cp_time;
2250589a0803Satatat 	size_t sz, osz;
2251589a0803Satatat 	int rc, i, n;
2252589a0803Satatat 	char s[sizeof("kern.cp_time.nnnnnn")];
2253589a0803Satatat 	const char *tname;
2254c915b316Satatat 
2255589a0803Satatat 	/*
2256589a0803Satatat 	 * three things to do here.
2257589a0803Satatat 	 * case 1: get sum (no Aflag and namelen == 2)
2258589a0803Satatat 	 * case 2: get specific processor (namelen == 3)
2259589a0803Satatat 	 * case 3: get all processors (Aflag and namelen == 2)
2260589a0803Satatat 	 */
2261589a0803Satatat 
2262589a0803Satatat 	if (namelen == 2 && Aflag) {
2263589a0803Satatat 		sz = sizeof(n);
2264997c4cdcSkamil 		rc = prog_sysctlbyname("hw.ncpu", &n, &sz, NULL, 0);
2265589a0803Satatat 		if (rc != 0)
2266589a0803Satatat 			return; /* XXX print an error, eh? */
2267f9965453Satatat 		n++; /* Add on space for the sum. */
2268589a0803Satatat 		sz = n * sizeof(u_int64_t) * CPUSTATES;
2269589a0803Satatat 	}
2270589a0803Satatat 	else {
2271f9965453Satatat 		n = -1; /* Just print one data set. */
2272589a0803Satatat 		sz = sizeof(u_int64_t) * CPUSTATES;
2273589a0803Satatat 	}
2274589a0803Satatat 
2275589a0803Satatat 	cp_time = malloc(sz);
2276589a0803Satatat 	if (cp_time == NULL) {
2277c915b316Satatat 		sysctlerror(1);
2278c915b316Satatat 		return;
2279c915b316Satatat 	}
2280c915b316Satatat 
2281589a0803Satatat 	osz = sz;
2282f9740adaSpooka 	rc = prog_sysctl(name, namelen, cp_time + (n != -1) * CPUSTATES, &osz,
2283f9965453Satatat 		    NULL, 0);
2284589a0803Satatat 
2285589a0803Satatat 	if (rc == -1) {
2286589a0803Satatat 		sysctlerror(1);
2287589a0803Satatat 		free(cp_time);
22885e111b3cSatatat 		return;
22895e111b3cSatatat 	}
2290f9965453Satatat 
2291f9965453Satatat 	/*
2292f9965453Satatat 	 * Check, but account for space we'll occupy with the sum.
2293f9965453Satatat 	 */
2294f9965453Satatat 	if (osz != sz - (n != -1) * CPUSTATES * sizeof(u_int64_t))
229581c8b4d0Schristos 		errx(EXIT_FAILURE, "%s: !returned size wrong!", sname);
2296589a0803Satatat 
2297f9965453Satatat 	/*
2298f9965453Satatat 	 * Compute the actual sum.  Two calls would be easier (we
2299f9965453Satatat 	 * could just call ourselves recursively above), but the
2300f9965453Satatat 	 * numbers wouldn't add up.
2301f9965453Satatat 	 */
2302f9965453Satatat 	if (n != -1) {
2303f9965453Satatat 		memset(cp_time, 0, sizeof(u_int64_t) * CPUSTATES);
2304f9965453Satatat 		for (i = 1; i < n; i++) {
2305f9965453Satatat 			cp_time[CP_USER] += cp_time[i * CPUSTATES + CP_USER];
2306f9965453Satatat                         cp_time[CP_NICE] += cp_time[i * CPUSTATES + CP_NICE];
2307f9965453Satatat                         cp_time[CP_SYS] += cp_time[i * CPUSTATES + CP_SYS];
2308f9965453Satatat                         cp_time[CP_INTR] += cp_time[i * CPUSTATES + CP_INTR];
2309f9965453Satatat                         cp_time[CP_IDLE] += cp_time[i * CPUSTATES + CP_IDLE];
2310f9965453Satatat 		}
2311f9965453Satatat 	}
2312f9965453Satatat 
2313589a0803Satatat 	tname = sname;
2314589a0803Satatat 	for (i = 0; n == -1 || i < n; i++) {
2315f9965453Satatat 		if (i > 0) {
2316f9965453Satatat 			(void)snprintf(s, sizeof(s), "%s%s%d", sname, sep,
2317f9965453Satatat 				       i - 1);
2318589a0803Satatat 			tname = s;
2319589a0803Satatat 		}
2320589a0803Satatat 		if (xflag || rflag)
2321589a0803Satatat 			display_struct(pnode, tname, cp_time + (i * CPUSTATES),
2322589a0803Satatat 				       sizeof(u_int64_t) * CPUSTATES,
2323589a0803Satatat 				       DISPLAY_VALUE);
2324589a0803Satatat 		else {
2325589a0803Satatat 			if (!nflag)
2326589a0803Satatat 				printf("%s: ", tname);
2327c915b316Satatat 			printf("user = %" PRIu64
2328c915b316Satatat 			       ", nice = %" PRIu64
2329c915b316Satatat 			       ", sys = %" PRIu64
2330c915b316Satatat 			       ", intr = %" PRIu64
2331c915b316Satatat 			       ", idle = %" PRIu64
2332c915b316Satatat 			       "\n",
2333589a0803Satatat 			       cp_time[i * CPUSTATES + CP_USER],
2334589a0803Satatat 			       cp_time[i * CPUSTATES + CP_NICE],
2335589a0803Satatat 			       cp_time[i * CPUSTATES + CP_SYS],
2336589a0803Satatat 			       cp_time[i * CPUSTATES + CP_INTR],
2337589a0803Satatat 			       cp_time[i * CPUSTATES + CP_IDLE]);
2338589a0803Satatat 		}
2339f9965453Satatat 		/*
2340f9965453Satatat 		 * Just printing the one node.
2341f9965453Satatat 		 */
2342589a0803Satatat 		if (n == -1)
2343589a0803Satatat 			break;
2344589a0803Satatat 	}
2345589a0803Satatat 
2346589a0803Satatat 	free(cp_time);
2347c915b316Satatat }
2348c915b316Satatat 
2349c915b316Satatat /*ARGSUSED*/
2350c915b316Satatat static void
kern_drivers(HANDLER_ARGS)23515bc3ea6cSchristos kern_drivers(HANDLER_ARGS)
23525bc3ea6cSchristos {
23535bc3ea6cSchristos 	struct kinfo_drivers *kd;
23545bc3ea6cSchristos 	size_t sz, i;
23555bc3ea6cSchristos 	int rc;
23565bc3ea6cSchristos 	const char *comma;
23575bc3ea6cSchristos 
2358f9740adaSpooka 	rc = prog_sysctl(name, namelen, NULL, &sz, NULL, 0);
23595bc3ea6cSchristos 	if (rc == -1) {
23605bc3ea6cSchristos 		sysctlerror(1);
23615bc3ea6cSchristos 		return;
23625bc3ea6cSchristos 	}
23635bc3ea6cSchristos 
23645bc3ea6cSchristos 	if (sz % sizeof(*kd))
236581c8b4d0Schristos 		err(EXIT_FAILURE, "bad size %zu for kern.drivers", sz);
23665bc3ea6cSchristos 
23675bc3ea6cSchristos 	kd = malloc(sz);
23685bc3ea6cSchristos 	if (kd == NULL) {
23695bc3ea6cSchristos 		sysctlerror(1);
23705bc3ea6cSchristos 		return;
23715bc3ea6cSchristos 	}
23725bc3ea6cSchristos 
2373f9740adaSpooka 	rc = prog_sysctl(name, namelen, kd, &sz, NULL, 0);
23745bc3ea6cSchristos 	if (rc == -1) {
23755bc3ea6cSchristos 		sysctlerror(1);
2376a4771072Smsaitoh 		free(kd);
23775bc3ea6cSchristos 		return;
23785bc3ea6cSchristos 	}
23795bc3ea6cSchristos 
23805bc3ea6cSchristos 	comma = "";
238109012c96Schristos 	if (!nflag)
238209012c96Schristos 		printf("%s%s", sname, eq);
23835bc3ea6cSchristos 	for (i = 0, sz /= sizeof(*kd); i < sz; i++) {
23845bc3ea6cSchristos 		(void)printf("%s[%d %d %s]", comma, kd[i].d_cmajor,
23855bc3ea6cSchristos 		    kd[i].d_bmajor, kd[i].d_name);
23865bc3ea6cSchristos 		comma = ", ";
23875bc3ea6cSchristos 	}
23885bc3ea6cSchristos 	(void)printf("\n");
23895bc3ea6cSchristos 	free(kd);
23905bc3ea6cSchristos }
23915bc3ea6cSchristos 
23925bc3ea6cSchristos /*ARGSUSED*/
23935bc3ea6cSchristos static void
kern_cp_id(HANDLER_ARGS)239429a64650Schristos kern_cp_id(HANDLER_ARGS)
239529a64650Schristos {
239629a64650Schristos 	u_int64_t *cp_id;
239729a64650Schristos 	size_t sz, osz;
239829a64650Schristos 	int rc, i, n;
239929a64650Schristos 	char s[sizeof("kern.cp_id.nnnnnn")];
240029a64650Schristos 	const char *tname;
240129a64650Schristos 	struct sysctlnode node = *pnode;
240229a64650Schristos 
240329a64650Schristos 	/*
240429a64650Schristos 	 * three things to do here.
240529a64650Schristos 	 * case 1: print a specific cpu id (namelen == 3)
240629a64650Schristos 	 * case 2: print all cpu ids separately (Aflag set)
240729a64650Schristos 	 * case 3: print all cpu ids on one line
240829a64650Schristos 	 */
240929a64650Schristos 
241029a64650Schristos 	if (namelen == 2) {
241129a64650Schristos 		sz = sizeof(n);
2412997c4cdcSkamil 		rc = prog_sysctlbyname("hw.ncpu", &n, &sz, NULL, 0);
241329a64650Schristos 		if (rc != 0)
241429a64650Schristos 			return; /* XXX print an error, eh? */
241529a64650Schristos 		sz = n * sizeof(u_int64_t);
241629a64650Schristos 	}
241729a64650Schristos 	else {
241829a64650Schristos 		n = -1; /* Just print one cpu id. */
241929a64650Schristos 		sz = sizeof(u_int64_t);
242029a64650Schristos 	}
242129a64650Schristos 
242229a64650Schristos 	cp_id = malloc(sz);
242329a64650Schristos 	if (cp_id == NULL) {
242429a64650Schristos 		sysctlerror(1);
242529a64650Schristos 		return;
242629a64650Schristos 	}
242729a64650Schristos 
242829a64650Schristos 	osz = sz;
2429f9740adaSpooka 	rc = prog_sysctl(name, namelen, cp_id, &osz, NULL, 0);
243029a64650Schristos 	if (rc == -1) {
243129a64650Schristos 		sysctlerror(1);
243229a64650Schristos 		free(cp_id);
243329a64650Schristos 		return;
243429a64650Schristos 	}
243529a64650Schristos 
243629a64650Schristos 	/*
243729a64650Schristos 	 * Check that we got back what we asked for.
243829a64650Schristos 	 */
243929a64650Schristos 	if (osz != sz)
244081c8b4d0Schristos 		errx(EXIT_FAILURE, "%s: !returned size wrong!", sname);
244129a64650Schristos 
244229a64650Schristos 	/* pretend for output purposes */
244329a64650Schristos 	node.sysctl_flags = SYSCTL_FLAGS(pnode->sysctl_flags) |
244429a64650Schristos 		SYSCTL_TYPE(CTLTYPE_QUAD);
244529a64650Schristos 
244629a64650Schristos 	tname = sname;
244729a64650Schristos 	if (namelen == 3)
244829a64650Schristos 		display_number(&node, tname, cp_id,
244929a64650Schristos 			       sizeof(u_int64_t),
245029a64650Schristos 			       DISPLAY_VALUE);
245129a64650Schristos 	else if (Aflag) {
2452845c916aSmrg 		for (i = 0; i < n; i++) {
245329a64650Schristos 			(void)snprintf(s, sizeof(s), "%s%s%d", sname, sep, i);
245429a64650Schristos 			tname = s;
245529a64650Schristos 			display_number(&node, tname, &cp_id[i],
245629a64650Schristos 				       sizeof(u_int64_t),
245729a64650Schristos 				       DISPLAY_VALUE);
245829a64650Schristos 		}
2459845c916aSmrg 	}
246029a64650Schristos 	else {
246129a64650Schristos 		if (xflag || rflag)
246229a64650Schristos 			display_struct(pnode, tname, cp_id, sz, DISPLAY_VALUE);
246329a64650Schristos 		else {
246429a64650Schristos 			if (!nflag)
246529a64650Schristos 				printf("%s: ", tname);
246629a64650Schristos 			for (i = 0; i < n; i++) {
246729a64650Schristos 				if (i)
246829a64650Schristos 					printf(", ");
246929a64650Schristos 				printf("%d = %" PRIu64, i, cp_id[i]);
247029a64650Schristos 			}
247129a64650Schristos 			printf("\n");
247229a64650Schristos 		}
247329a64650Schristos 	}
247429a64650Schristos 
247529a64650Schristos 	free(cp_id);
247629a64650Schristos }
247729a64650Schristos 
247829a64650Schristos /*ARGSUSED*/
247929a64650Schristos static void
vm_loadavg(HANDLER_ARGS)2480c915b316Satatat vm_loadavg(HANDLER_ARGS)
2481c915b316Satatat {
2482c915b316Satatat 	struct loadavg loadavg;
2483c915b316Satatat 	size_t sz;
2484c915b316Satatat 	int rc;
2485c915b316Satatat 
2486c915b316Satatat 	sz = sizeof(loadavg);
2487f9740adaSpooka 	rc = prog_sysctl(name, namelen, &loadavg, &sz, NULL, 0);
2488c915b316Satatat 	if (rc == -1) {
2489c915b316Satatat 		sysctlerror(1);
2490c915b316Satatat 		return;
2491c915b316Satatat 	}
2492c915b316Satatat 	if (sz != sizeof(loadavg))
249381c8b4d0Schristos 		errx(EXIT_FAILURE, "%s: !returned size wrong!", sname);
2494c915b316Satatat 
24955e111b3cSatatat 	if (xflag || rflag) {
2496c915b316Satatat 		display_struct(pnode, sname, &loadavg, sz,
2497c915b316Satatat 			       DISPLAY_VALUE);
24985e111b3cSatatat 		return;
24995e111b3cSatatat 	}
25005e111b3cSatatat 	if (!nflag)
2501c915b316Satatat 		printf("%s: ", sname);
2502c915b316Satatat 	printf("%.2f %.2f %.2f\n",
2503c915b316Satatat 	       (double) loadavg.ldavg[0] / loadavg.fscale,
2504c915b316Satatat 	       (double) loadavg.ldavg[1] / loadavg.fscale,
2505c915b316Satatat 	       (double) loadavg.ldavg[2] / loadavg.fscale);
2506c915b316Satatat }
2507c915b316Satatat 
2508c915b316Satatat /*ARGSUSED*/
2509c915b316Satatat static void
proc_limit(HANDLER_ARGS)2510c915b316Satatat proc_limit(HANDLER_ARGS)
2511c915b316Satatat {
2512c915b316Satatat 	u_quad_t olim, *newp, nlim;
2513c915b316Satatat 	size_t osz, nsz;
2514c915b316Satatat 	char *t;
2515c915b316Satatat 	int rc;
2516c915b316Satatat 
2517d528f2f4Satatat 	if (fn)
2518d528f2f4Satatat 		trim_whitespace(value, 3);
2519d528f2f4Satatat 
2520c915b316Satatat 	osz = sizeof(olim);
2521c915b316Satatat 	if (value != NULL) {
2522c915b316Satatat 		nsz = sizeof(nlim);
2523c915b316Satatat 		newp = &nlim;
2524c915b316Satatat 		if (strcmp(value, "unlimited") == 0)
2525c915b316Satatat 			nlim = RLIM_INFINITY;
2526c915b316Satatat 		else {
2527c915b316Satatat 			errno = 0;
2528c915b316Satatat 			nlim = strtouq(value, &t, 0);
2529605d2000Satatat 			if (t == value || *t != '\0' || errno != 0) {
2530d528f2f4Satatat 				sysctlperror("%s: '%s' is not a valid limit\n",
2531d528f2f4Satatat 					     sname, value);
253281c8b4d0Schristos 				EXIT(EXIT_FAILURE);
2533c915b316Satatat 			}
2534c915b316Satatat 		}
2535c915b316Satatat 	}
2536c915b316Satatat 	else {
2537c915b316Satatat 		nsz = 0;
2538c915b316Satatat 		newp = NULL;
2539c915b316Satatat 	}
2540c915b316Satatat 
2541f9740adaSpooka 	rc = prog_sysctl(name, namelen, &olim, &osz, newp, nsz);
2542c915b316Satatat 	if (rc == -1) {
2543c915b316Satatat 		sysctlerror(newp == NULL);
2544c915b316Satatat 		return;
2545c915b316Satatat 	}
2546c915b316Satatat 
2547c915b316Satatat 	if (newp && qflag)
2548c915b316Satatat 		return;
2549c915b316Satatat 
2550c915b316Satatat 	if (rflag || xflag || olim != RLIM_INFINITY)
2551c915b316Satatat 		display_number(pnode, sname, &olim, sizeof(olim),
2552c915b316Satatat 			       newp ? DISPLAY_OLD : DISPLAY_VALUE);
2553c915b316Satatat 	else
2554c915b316Satatat 		display_string(pnode, sname, "unlimited", 10,
2555c915b316Satatat 			       newp ? DISPLAY_OLD : DISPLAY_VALUE);
2556c915b316Satatat 
2557c915b316Satatat 	if (newp) {
2558c915b316Satatat 		if (rflag || xflag || nlim != RLIM_INFINITY)
2559c915b316Satatat 			display_number(pnode, sname, &nlim, sizeof(nlim),
2560c915b316Satatat 				       DISPLAY_NEW);
2561c915b316Satatat 		else
2562c915b316Satatat 			display_string(pnode, sname, "unlimited", 10,
2563c915b316Satatat 				       DISPLAY_NEW);
2564c915b316Satatat 	}
2565c915b316Satatat }
2566c915b316Satatat 
2567c915b316Satatat #ifdef CPU_DISKINFO
2568c915b316Satatat /*ARGSUSED*/
2569c915b316Satatat static void
machdep_diskinfo(HANDLER_ARGS)2570c915b316Satatat machdep_diskinfo(HANDLER_ARGS)
2571c915b316Satatat {
2572c915b316Satatat 	struct disklist *dl;
2573c915b316Satatat 	struct biosdisk_info *bi;
2574c915b316Satatat 	struct nativedisk_info *ni;
2575c915b316Satatat 	int rc;
2576c915b316Satatat 	size_t sz;
2577c915b316Satatat 	uint i, b, lim;
2578c915b316Satatat 
2579f9740adaSpooka 	rc = prog_sysctl(name, namelen, NULL, &sz, NULL, 0);
2580c915b316Satatat 	if (rc == -1) {
2581c915b316Satatat 		sysctlerror(1);
2582c915b316Satatat 		return;
2583c915b316Satatat 	}
2584c915b316Satatat 	dl = malloc(sz);
2585c915b316Satatat 	if (dl == NULL) {
2586c915b316Satatat 		sysctlerror(1);
2587c915b316Satatat 		return;
2588c915b316Satatat 	}
2589f9740adaSpooka 	rc = prog_sysctl(name, namelen, dl, &sz, NULL, 0);
2590c915b316Satatat 	if (rc == -1) {
2591c915b316Satatat 		sysctlerror(1);
2592c915b316Satatat 		return;
2593c915b316Satatat 	}
2594c915b316Satatat 
2595c915b316Satatat 	if (!nflag)
2596c915b316Satatat 		printf("%s: ", sname);
2597c915b316Satatat 	lim = dl->dl_nbiosdisks;
2598c915b316Satatat 	if (lim > MAX_BIOSDISKS)
2599c915b316Satatat 		lim = MAX_BIOSDISKS;
2600c915b316Satatat 	for (bi = dl->dl_biosdisks, i = 0; i < lim; bi++, i++)
2601c915b316Satatat 		printf("%x:%" PRIu64 "(%d/%d/%d),%x ",
2602c915b316Satatat 		       bi->bi_dev, bi->bi_lbasecs,
2603c915b316Satatat 		       bi->bi_cyl, bi->bi_head, bi->bi_sec,
2604c915b316Satatat 		       bi->bi_flags);
2605c915b316Satatat 	lim = dl->dl_nnativedisks;
2606c915b316Satatat 	ni = dl->dl_nativedisks;
2607c915b316Satatat 	bi = dl->dl_biosdisks;
2608c915b316Satatat 	/* LINTED -- pointer casts are tedious */
2609c915b316Satatat 	if ((char *)&ni[lim] != (char *)dl + sz) {
2610d528f2f4Satatat 		sysctlperror("%s: size mismatch\n", gsname);
2611c915b316Satatat 		return;
2612c915b316Satatat 	}
2613c915b316Satatat 	for (i = 0; i < lim; ni++, i++) {
2614c915b316Satatat 		char t = ':';
2615c915b316Satatat 		printf(" %.*s", (int)sizeof ni->ni_devname,
2616c915b316Satatat 		       ni->ni_devname);
2617deb4c0bbSlukem 		for (b = 0; b < (unsigned int)ni->ni_nmatches; t = ',', b++)
2618c915b316Satatat 			printf("%c%x", t,
2619c915b316Satatat 			       bi[ni->ni_biosmatches[b]].bi_dev);
2620c915b316Satatat 	}
2621c915b316Satatat 	printf("\n");
2622e4bf6d92Snjoly 	free(dl);
2623c915b316Satatat }
2624c915b316Satatat #endif /* CPU_DISKINFO */
2625202872dbSelad 
2626202872dbSelad /*ARGSUSED*/
2627202872dbSelad static void
mode_bits(HANDLER_ARGS)2628202872dbSelad mode_bits(HANDLER_ARGS)
2629202872dbSelad {
2630aede3e59Selad 	char buf[12], outbuf[100];
2631202872dbSelad 	int o, m, *newp, rc;
2632202872dbSelad 	size_t osz, nsz;
2633202872dbSelad 	mode_t om, mm;
2634202872dbSelad 
2635202872dbSelad 	if (fn)
2636202872dbSelad 		trim_whitespace(value, 3);
2637202872dbSelad 
2638202872dbSelad 	newp = NULL;
2639202872dbSelad 	osz = sizeof(o);
2640202872dbSelad 	if (value != NULL) {
2641202872dbSelad 		void *foo;
2642202872dbSelad 		int tt;
2643202872dbSelad 		size_t ttsz = sizeof(tt);
2644202872dbSelad 		mode_t old_umask;
2645202872dbSelad 
2646202872dbSelad 		nsz = sizeof(m);
2647202872dbSelad 		newp = &m;
2648202872dbSelad 		errno = 0;
2649f9740adaSpooka 		rc = prog_sysctl(name, namelen, &tt, &ttsz, NULL, 0);
2650202872dbSelad 		if (rc == -1) {
2651202872dbSelad 			sysctlperror("%s: failed query\n", sname);
2652202872dbSelad 			return;
2653202872dbSelad 		}
2654202872dbSelad 
2655202872dbSelad 		old_umask = umask(0);
2656202872dbSelad 		foo = setmode(value);
2657202872dbSelad 		umask(old_umask);
2658202872dbSelad 		if (foo == NULL) {
2659202872dbSelad 			sysctlperror("%s: '%s' is an invalid mode\n", sname,
2660202872dbSelad 				     value);
266181c8b4d0Schristos 			EXIT(EXIT_FAILURE);
2662202872dbSelad 		}
2663202872dbSelad 		old_umask = umask(0);
2664202872dbSelad 		m = getmode(foo, (mode_t)tt);
2665202872dbSelad 		umask(old_umask);
2666202872dbSelad 		if (errno) {
2667202872dbSelad 			sysctlperror("%s: '%s' is an invalid mode\n", sname,
2668202872dbSelad 				     value);
266981c8b4d0Schristos 			EXIT(EXIT_FAILURE);
2670202872dbSelad 		}
2671202872dbSelad 	}
2672202872dbSelad 	else {
2673202872dbSelad 		nsz = 0;
2674202872dbSelad 		newp = NULL;
2675202872dbSelad 	}
2676202872dbSelad 
2677f9740adaSpooka 	rc = prog_sysctl(name, namelen, &o, &osz, newp, nsz);
2678202872dbSelad 	if (rc == -1) {
2679202872dbSelad 		sysctlerror(newp == NULL);
2680202872dbSelad 		return;
2681202872dbSelad 	}
2682202872dbSelad 
2683202872dbSelad 	if (newp && qflag)
2684202872dbSelad 		return;
2685202872dbSelad 
2686202872dbSelad 	om = (mode_t)o;
2687202872dbSelad 	mm = (mode_t)m;
2688202872dbSelad 
2689202872dbSelad 	if (rflag || xflag)
2690202872dbSelad 		display_number(pnode, sname, &o, sizeof(o),
2691202872dbSelad 			       newp ? DISPLAY_OLD : DISPLAY_VALUE);
2692202872dbSelad 	else {
2693202872dbSelad 		memset(buf, 0, sizeof(buf));
2694202872dbSelad 		strmode(om, buf);
2695202872dbSelad 		rc = snprintf(outbuf, sizeof(outbuf), "%04o (%s)", om, buf + 1);
2696202872dbSelad 		display_string(pnode, sname, outbuf, rc, newp ? DISPLAY_OLD : DISPLAY_VALUE);
2697202872dbSelad 	}
2698202872dbSelad 
2699202872dbSelad 	if (newp) {
2700202872dbSelad 		if (rflag || xflag)
2701202872dbSelad 			display_number(pnode, sname, &m, sizeof(m),
2702202872dbSelad 				       DISPLAY_NEW);
2703202872dbSelad 		else {
2704202872dbSelad 			memset(buf, 0, sizeof(buf));
2705202872dbSelad 			strmode(mm, buf);
2706202872dbSelad 			rc = snprintf(outbuf, sizeof(outbuf), "%04o (%s)", mm, buf + 1);
2707202872dbSelad 			display_string(pnode, sname, outbuf, rc, DISPLAY_NEW);
2708202872dbSelad 		}
2709202872dbSelad 	}
2710202872dbSelad }
271197613513Schristos 
27129878d5e5Schristos typedef __BITMAP_TYPE(, uint32_t, 0x10000) bitmap;
27139878d5e5Schristos 
271497613513Schristos static char *
bitmask_print(const bitmap * o)27159878d5e5Schristos bitmask_print(const bitmap *o)
271697613513Schristos {
271797613513Schristos 	char *s, *os;
271897613513Schristos 
271997613513Schristos 	s = os = NULL;
2720f9868bf9Schristos 	for (size_t i = 0; i < MAXPORTS; i++)
2721f9868bf9Schristos 		if (__BITMAP_ISSET(i, o)) {
272297613513Schristos 			int rv;
272397613513Schristos 
272497613513Schristos 			if (os)
272597613513Schristos 			    	rv = asprintf(&s, "%s,%zu", os, i);
272697613513Schristos 			else
272797613513Schristos 			    	rv = asprintf(&s, "%zu", i);
272897613513Schristos 			if (rv == -1)
272981c8b4d0Schristos 				err(EXIT_FAILURE, "%s 1", __func__);
273097613513Schristos 			free(os);
273197613513Schristos 			os = s;
273297613513Schristos 		}
273397613513Schristos 	if (s == NULL && (s = strdup("")) == NULL)
273481c8b4d0Schristos 		err(EXIT_FAILURE, "%s 2", __func__);
273597613513Schristos 	return s;
273697613513Schristos }
273797613513Schristos 
273897613513Schristos static void
bitmask_scan(const void * v,bitmap * o)27399878d5e5Schristos bitmask_scan(const void *v, bitmap *o)
274097613513Schristos {
274197613513Schristos 	char *s = strdup(v);
274297613513Schristos 	if (s == NULL)
274381c8b4d0Schristos 		err(EXIT_FAILURE, "%s", __func__);
274487e18d03Schristos 
27459878d5e5Schristos 	__BITMAP_ZERO(o);
274697613513Schristos 	for (s = strtok(s, ","); s; s = strtok(NULL, ",")) {
274797613513Schristos 		char *e;
274897613513Schristos 		errno = 0;
274997613513Schristos 		unsigned long l = strtoul(s, &e, 0);
275097613513Schristos 		if ((l == ULONG_MAX && errno == ERANGE) || s == e || *e)
275181c8b4d0Schristos 			errx(EXIT_FAILURE, "Invalid port: %s", s);
2752f9868bf9Schristos 		if (l >= MAXPORTS)
275381c8b4d0Schristos 			errx(EXIT_FAILURE, "Port out of range: %s", s);
2754f9868bf9Schristos 		__BITMAP_SET(l, o);
275597613513Schristos 	}
275697613513Schristos }
275797613513Schristos 
275897613513Schristos 
275997613513Schristos static void
reserve(HANDLER_ARGS)276097613513Schristos reserve(HANDLER_ARGS)
276197613513Schristos {
276297613513Schristos 	int rc;
276397613513Schristos 	size_t osz, nsz;
27649878d5e5Schristos 	bitmap o, n;
276597613513Schristos 
276697613513Schristos 	if (fn)
276797613513Schristos 		trim_whitespace(value, 3);
276897613513Schristos 
276997613513Schristos 	osz = sizeof(o);
277097613513Schristos 	if (value) {
27719878d5e5Schristos 		bitmask_scan(value, &n);
27729878d5e5Schristos 		value = (char *)&n;
277397613513Schristos 		nsz = sizeof(n);
277497613513Schristos 	} else
277597613513Schristos 		nsz = 0;
277697613513Schristos 
277797613513Schristos 	rc = prog_sysctl(name, namelen, &o, &osz, value, nsz);
277897613513Schristos 	if (rc == -1) {
277997613513Schristos 		sysctlerror(value == NULL);
278097613513Schristos 		return;
278197613513Schristos 	}
278297613513Schristos 
278397613513Schristos 	if (value && qflag)
278497613513Schristos 		return;
278597613513Schristos 
278697613513Schristos 	if (rflag || xflag)
27879878d5e5Schristos 		display_struct(pnode, sname, &o, sizeof(o),
278897613513Schristos 		    value ? DISPLAY_OLD : DISPLAY_VALUE);
278997613513Schristos 	else {
27909878d5e5Schristos 		char *s = bitmask_print(&o);
279197613513Schristos 		display_string(pnode, sname, s, strlen(s),
279297613513Schristos 		    value ? DISPLAY_OLD : DISPLAY_VALUE);
279397613513Schristos 		free(s);
279497613513Schristos 	}
279597613513Schristos 
279697613513Schristos 	if (value) {
279797613513Schristos 		if (rflag || xflag)
27989878d5e5Schristos 			display_struct(pnode, sname, &n, sizeof(n),
279997613513Schristos 			    DISPLAY_NEW);
280097613513Schristos 		else {
28019878d5e5Schristos 			char *s = bitmask_print(&n);
280297613513Schristos 			display_string(pnode, sname, s, strlen(s), DISPLAY_NEW);
280397613513Schristos 			free(s);
280497613513Schristos 		}
280597613513Schristos 	}
280697613513Schristos }
2807