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 = ⅈ
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, ×pec, &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, ×pec, 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