1 /* $NetBSD: sysctl.c,v 1.156 2015/08/17 06:42:46 knakahara Exp $ */
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
34 * The Regents of the University of California. All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 #include <sys/cdefs.h>
63 __COPYRIGHT("@(#) Copyright (c) 1993\
64 The Regents of the University of California. All rights reserved.");
69 static char sccsid
[] = "@(#)sysctl.c 8.1 (Berkeley) 6/6/93";
71 __RCSID("$NetBSD: sysctl.c,v 1.156 2015/08/17 06:42:46 knakahara Exp $");
75 #include <sys/types.h>
76 #include <sys/param.h>
77 #include <sys/sysctl.h>
78 #include <sys/mount.h>
79 #include <sys/resource.h>
81 #include <sys/sched.h>
82 #include <sys/socket.h>
83 #include <sys/bitops.h>
84 #include <netinet/in.h>
85 #include <netinet/ip_var.h>
86 #include <netinet/tcp.h>
88 #include <netinet/tcp_timer.h>
89 #include <netinet/tcp_var.h>
90 #include <netinet/icmp6.h>
91 #include <nfs/rpcv2.h>
92 #include <nfs/nfsproto.h>
95 #include <machine/cpu.h>
101 #include <inttypes.h>
110 #include "prog_ops.h"
113 * this needs to be able to do the printing and the setting
115 #define HANDLER_PROTO const char *, const char *, char *, \
116 int *, u_int, const struct sysctlnode *, \
118 #define HANDLER_ARGS const char *sname, const char *dname, char *value, \
119 int *name, u_int namelen, const struct sysctlnode *pnode, \
121 #define DISPLAY_VALUE 0
122 #define DISPLAY_OLD 1
123 #define DISPLAY_NEW 2
128 static const struct handlespec
*findhandler(const char *, regex_t
*, size_t *);
129 static void canonicalize(const char *, char *);
130 static void purge_tree(struct sysctlnode
*);
131 static void print_tree(int *, u_int
, struct sysctlnode
*, u_int
, int, regex_t
*,
133 static void write_number(int *, u_int
, struct sysctlnode
*, char *);
134 static void write_string(int *, u_int
, struct sysctlnode
*, char *);
135 static void display_number(const struct sysctlnode
*, const char *,
136 const void *, size_t, int);
137 static void display_string(const struct sysctlnode
*, const char *,
138 const void *, size_t, int);
139 static void display_struct(const struct sysctlnode
*, const char *,
140 const void *, size_t, int);
141 static void hex_dump(const unsigned char *, size_t);
142 __dead
static void usage(void);
143 static void parse(char *, regex_t
*, size_t *);
144 static void parse_create(char *);
145 static void parse_destroy(char *);
146 static void parse_describe(char *);
147 static void getdesc1(int *, u_int
, struct sysctlnode
*);
148 static void getdesc(int *, u_int
, struct sysctlnode
*);
149 static void trim_whitespace(char *, int);
150 static void sysctlerror(int);
151 static void sysctlparseerror(u_int
, const char *);
152 static void sysctlperror(const char *, ...) __printflike(1, 2);
153 #define EXIT(n) do { \
154 if (fn == NULL) exit(n); else return; } while (/*CONSTCOND*/0)
157 * "borrowed" from libc:sysctlgetmibinfo.c
159 int __learn_tree(int *, u_int
, struct sysctlnode
*);
164 static void printother(HANDLER_PROTO
);
165 static void kern_clockrate(HANDLER_PROTO
);
166 static void kern_boottime(HANDLER_PROTO
);
167 static void kern_consdev(HANDLER_PROTO
);
168 static void kern_cp_time(HANDLER_PROTO
);
169 static void kern_cp_id(HANDLER_PROTO
);
170 static void kern_drivers(HANDLER_PROTO
);
171 static void vm_loadavg(HANDLER_PROTO
);
172 static void proc_limit(HANDLER_PROTO
);
174 static void machdep_diskinfo(HANDLER_PROTO
);
175 #endif /* CPU_DISKINFO */
176 static void mode_bits(HANDLER_PROTO
);
177 static void reserve(HANDLER_PROTO
);
179 static const struct handlespec
{
181 void (*ps_p
)(HANDLER_PROTO
);
182 void (*ps_w
)(HANDLER_PROTO
);
185 { "/kern/clockrate", kern_clockrate
, NULL
, NULL
},
186 { "/kern/evcnt", printother
, NULL
, "vmstat -e" },
187 { "/kern/vnode", printother
, NULL
, "pstat" },
188 { "/kern/proc(2|_args)?", printother
, NULL
, "ps" },
189 { "/kern/file2?", printother
, NULL
, "pstat" },
190 { "/kern/ntptime", printother
, NULL
,
191 "ntpdc -c kerninfo" },
192 { "/kern/msgbuf", printother
, NULL
, "dmesg" },
193 { "/kern/boottime", kern_boottime
, NULL
, NULL
},
194 { "/kern/consdev", kern_consdev
, NULL
, NULL
},
195 { "/kern/cp_time(/[0-9]+)?", kern_cp_time
, NULL
, NULL
},
196 { "/kern/sysvipc_info", printother
, NULL
, "ipcs" },
197 { "/kern/cp_id(/[0-9]+)?", kern_cp_id
, NULL
, NULL
},
199 { "/kern/coredump/setid/mode", mode_bits
, mode_bits
, NULL
},
200 { "/kern/drivers", kern_drivers
, NULL
, NULL
},
202 { "/kern/intr/list", printother
, NULL
, "intrctl" },
203 { "/kern/intr/affinity", printother
, NULL
, "intrctl" },
204 { "/kern/intr/intr", printother
, NULL
, "intrctl" },
205 { "/kern/intr/nointr", printother
, NULL
, "intrctl" },
207 { "/vm/vmmeter", printother
, NULL
,
208 "vmstat' or 'systat" },
209 { "/vm/loadavg", vm_loadavg
, NULL
, NULL
},
210 { "/vm/uvmexp2?", printother
, NULL
,
211 "vmstat' or 'systat" },
213 { "/vfs/nfs/nfsstats", printother
, NULL
, "nfsstat" },
215 { "/net/inet6?/tcp6?/ident", printother
, NULL
, "identd" },
216 { "/net/inet6/icmp6/nd6_[dp]rlist", printother
, NULL
, "ndp" },
217 { "/net/key/dumps[ap]", printother
, NULL
, "setkey" },
218 { "/net/[^/]+/[^/]+/pcblist", printother
, NULL
,
219 "netstat' or 'sockstat" },
220 { "/net/(inet|inet6)/[^/]+/stats", printother
, NULL
, "netstat"},
221 { "/net/bpf/(stats|peers)", printother
, NULL
, "netstat"},
223 { "/net/inet.*/tcp.*/deb.*", printother
, NULL
, "trpt" },
225 { "/net/inet.*/ip.*/anonportalgo/reserve", reserve
, reserve
, NULL
},
227 { "/net/ns/spp/deb.*", printother
, NULL
, "trsp" },
229 { "/hw/diskstats", printother
, NULL
, "iostat" },
232 { "/machdep/consdev", kern_consdev
, NULL
, NULL
},
233 #endif /* CPU_CONSDEV */
235 { "/machdep/diskinfo", machdep_diskinfo
, NULL
, NULL
},
236 #endif /* CPU_CONSDEV */
238 { "/proc/[^/]+/rlimit/[^/]+/[^/]+", proc_limit
, proc_limit
, NULL
},
241 * these will only be called when the given node has no children
243 { "/net/[^/]+", printother
, NULL
, NULL
},
244 { "/debug", printother
, NULL
, NULL
},
245 { "/ddb", printother
, NULL
, NULL
},
246 { "/vendor", printother
, NULL
, NULL
},
248 { NULL
, NULL
, NULL
, NULL
},
251 struct sysctlnode my_root
= {
252 .sysctl_flags
= SYSCTL_VERSION
|CTLFLAG_ROOT
|CTLTYPE_NODE
,
253 .sysctl_size
= sizeof(struct sysctlnode
),
255 .sysctl_name
= "(prog_root)",
258 int Aflag
, aflag
, dflag
, Mflag
, nflag
, qflag
, rflag
, wflag
, xflag
;
261 int req
, stale
, errs
;
262 FILE *warnfp
= stderr
;
264 #define MAXPORTS 0x10000
267 * vah-riables n stuff
269 char gsname
[SYSCTL_NAMELEN
* CTL_MAXNAME
+ CTL_MAXNAME
],
270 canonname
[SYSCTL_NAMELEN
* CTL_MAXNAME
+ CTL_MAXNAME
],
271 gdname
[10 * CTL_MAXNAME
+ CTL_MAXNAME
];
273 const char *eq
= " = ";
274 const char *lname
[] = {
275 "top", "second", "third", "fourth", "fifth", "sixth",
276 "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth"
280 * you've heard of main, haven't you?
283 main(int argc
, char *argv
[])
285 int name
[CTL_MAXNAME
];
287 size_t lastcompiled
= 0;
290 setprogname(argv
[0]);
291 while ((ch
= getopt(argc
, argv
, "Aabdef:Mnqrwx")) != -1) {
318 case 'b': /* FreeBSD compat */
338 /* if ((xflag || rflag) && wflag)
340 /* if (aflag && (Mflag || qflag))
342 if ((aflag
|| Aflag
) && qflag
)
344 if ((Aflag
|| Mflag
|| dflag
) && argc
== 0 && fn
== NULL
)
347 if (prog_init
&& prog_init() == -1)
348 err(EXIT_FAILURE
, "prog init failed");
354 if ((re
= malloc(sizeof(*re
) * __arraycount(handlers
))) == NULL
)
355 err(EXIT_FAILURE
, "malloc regex");
358 print_tree(&name
[0], 0, NULL
, CTLTYPE_NODE
, 1,
370 err(EXIT_FAILURE
, "%s", fn
);
373 while ((l
= fparseln(fp
, NULL
, &nr
, NULL
, 0)) != NULL
)
376 parse(l
, re
, &lastcompiled
);
389 parse(*argv
++, re
, &lastcompiled
);
391 return errs
? EXIT_FAILURE
: EXIT_SUCCESS
;
395 * ********************************************************************
396 * how to find someone special to handle the reading (or maybe even
397 * writing) of a particular node
398 * ********************************************************************
400 static const struct handlespec
*
401 findhandler(const char *s
, regex_t
*re
, size_t *lastcompiled
)
403 const struct handlespec
*p
;
411 for (i
= 0; p
[i
].ps_re
!= NULL
; i
++) {
412 if (i
>= *lastcompiled
) {
413 j
= regcomp(&re
[i
], p
[i
].ps_re
, REG_EXTENDED
);
415 regerror(j
, &re
[i
], eb
, sizeof(eb
));
416 errx(EXIT_FAILURE
, "regcomp: %s: %s", p
[i
].ps_re
, eb
);
418 *lastcompiled
= i
+ 1;
420 j
= regexec(&re
[i
], s
, 1, &match
, 0);
422 if (match
.rm_so
== 0 && match
.rm_eo
== (int)l
)
425 else if (j
!= REG_NOMATCH
) {
426 regerror(j
, &re
[i
], eb
, sizeof(eb
));
427 errx(EXIT_FAILURE
, "regexec: %s: %s", p
[i
].ps_re
, eb
);
435 * after sysctlgetmibinfo is done with the name, we convert all
436 * separators to / and stuff one at the front if it was missing
439 canonicalize(const char *i
, char *o
)
442 char p
[SYSCTL_NAMELEN
+ 1];
455 t
= strchr(i
, sep
[0]);
470 * ********************************************************************
471 * convert this special number to a special string so we can print the
473 * ********************************************************************
484 #define print_flag(_f, _s, _c, _q, _x) \
485 if (((_f) & (__CONCAT(CTLFLAG_,_x))) == (__CONCAT(CTLFLAG_,_q))) { \
486 strlcat((_s), (_c), sizeof(_s)); \
487 strlcat((_s), __STRING(_q), sizeof(_s)); \
489 (_f) &= ~(__CONCAT(CTLFLAG_,_x)); \
491 print_flag(f
, s
, c
, READONLY
, READWRITE
);
492 print_flag(f
, s
, c
, READWRITE
, READWRITE
);
493 print_flag(f
, s
, c
, ANYWRITE
, ANYWRITE
);
494 print_flag(f
, s
, c
, PRIVATE
, PRIVATE
);
495 print_flag(f
, s
, c
, PERMANENT
, PERMANENT
);
496 print_flag(f
, s
, c
, OWNDATA
, OWNDATA
);
497 print_flag(f
, s
, c
, IMMEDIATE
, IMMEDIATE
);
498 print_flag(f
, s
, c
, HEX
, HEX
);
499 print_flag(f
, s
, c
, ROOT
, ROOT
);
500 print_flag(f
, s
, c
, ANYNUMBER
, ANYNUMBER
);
501 print_flag(f
, s
, c
, HIDDEN
, HIDDEN
);
502 print_flag(f
, s
, c
, ALIAS
, ALIAS
);
507 snprintf(foo
, sizeof(foo
), "%x", f
);
508 strlcat(s
, c
, sizeof(s
));
509 strlcat(s
, foo
, sizeof(s
));
538 * ********************************************************************
539 * recursively eliminate all data belonging to the given node
540 * ********************************************************************
543 purge_tree(struct sysctlnode
*rnode
)
545 struct sysctlnode
*node
;
548 SYSCTL_TYPE(rnode
->sysctl_flags
) != CTLTYPE_NODE
||
549 rnode
->sysctl_child
== NULL
)
552 for (node
= rnode
->sysctl_child
;
553 node
< &rnode
->sysctl_child
[rnode
->sysctl_clen
];
556 free(rnode
->sysctl_child
);
557 rnode
->sysctl_csize
= 0;
558 rnode
->sysctl_clen
= 0;
559 rnode
->sysctl_child
= NULL
;
561 if (rnode
->sysctl_desc
== (const char*)-1)
562 rnode
->sysctl_desc
= NULL
;
563 if (rnode
->sysctl_desc
!= NULL
)
564 free(__UNCONST(rnode
->sysctl_desc
));
565 rnode
->sysctl_desc
= NULL
;
568 static void __attribute__((__format__(__printf__
, 3, 4)))
569 appendprintf(char **bp
, size_t *lbp
, const char *fmt
, ...)
575 r
= vsnprintf(*bp
, *lbp
, fmt
, ap
);
577 if (r
< 0 || (size_t)r
> *lbp
)
584 * ********************************************************************
585 * print this node and any others underneath it
586 * ********************************************************************
589 print_tree(int *name
, u_int namelen
, struct sysctlnode
*pnode
, u_int type
,
590 int add
, regex_t
*re
, size_t *lastcompiled
)
592 struct sysctlnode
*node
;
594 size_t ni
, sz
, ldp
, lsp
;
595 char *sp
, *dp
, *tsp
, *tdp
;
596 const struct handlespec
*p
;
598 sp
= tsp
= &gsname
[strlen(gsname
)];
599 dp
= tdp
= &gdname
[strlen(gdname
)];
600 ldp
= sizeof(gdname
) - (dp
- gdname
);
601 lsp
= sizeof(gsname
) - (sp
- gsname
);
603 if (sp
!= &gsname
[0] && dp
== &gdname
[0]) {
605 * aw...shucks. now we must play catch up
607 for (ni
= 0; ni
< namelen
; ni
++)
608 appendprintf(&tdp
, &ldp
, "%s%d", ni
> 0 ? "." : "",
615 appendprintf(&tsp
, &lsp
, "%s%s", namelen
> 1 ? sep
: "",
617 appendprintf(&tdp
, &ldp
, "%s%d", namelen
> 1 ? "." : "",
621 if (Mflag
&& pnode
!= &my_root
) {
623 printf("%s: ", gdname
);
625 printf("%s (%s): ", gsname
, gdname
);
626 printf("CTLTYPE_%s", st(type
));
627 if (type
== CTLTYPE_NODE
) {
628 if (SYSCTL_FLAGS(pnode
->sysctl_flags
) & CTLFLAG_ALIAS
)
630 pnode
->sysctl_alias
);
632 printf(", children %d/%d",
634 pnode
->sysctl_csize
);
636 printf(", size %zu", pnode
->sysctl_size
);
637 printf(", flags 0x%x<%s>",
638 SYSCTL_FLAGS(pnode
->sysctl_flags
),
639 sf(SYSCTL_FLAGS(pnode
->sysctl_flags
)));
640 if (pnode
->sysctl_func
)
641 printf(", func=%p", pnode
->sysctl_func
);
642 printf(", ver=%d", pnode
->sysctl_ver
);
644 if (type
!= CTLTYPE_NODE
) {
650 if (dflag
&& pnode
!= &my_root
) {
651 if (Aflag
|| type
!= CTLTYPE_NODE
) {
652 if (pnode
->sysctl_desc
== NULL
)
653 getdesc1(name
, namelen
, pnode
);
655 (pnode
->sysctl_desc
!= NULL
&&
656 pnode
->sysctl_desc
!= (const char*)-1)) {
658 printf("%s: ", gsname
);
659 if (pnode
->sysctl_desc
== NULL
||
660 pnode
->sysctl_desc
== (const char*)-1)
661 printf("(no description)\n");
663 printf("%s\n", pnode
->sysctl_desc
);
667 if (type
!= CTLTYPE_NODE
) {
674 * if this is an alias and we added our name, that means we
675 * got here by recursing down into the tree, so skip it. The
676 * only way to print an aliased node is with either -M or by
679 if (SYSCTL_FLAGS(pnode
->sysctl_flags
) & CTLFLAG_ALIAS
&& add
) {
684 canonicalize(gsname
, canonname
);
685 p
= findhandler(canonname
, re
, lastcompiled
);
686 if (type
!= CTLTYPE_NODE
&& p
!= NULL
) {
687 if (p
->ps_p
== NULL
) {
688 sysctlperror("Cannot print `%s': %s\n", gsname
,
689 strerror(EOPNOTSUPP
));
692 (*p
->ps_p
)(gsname
, gdname
, NULL
, name
, namelen
, pnode
, type
,
698 if (type
!= CTLTYPE_NODE
&& pnode
->sysctl_size
== 0) {
699 rc
= prog_sysctl(&name
[0], namelen
, NULL
, &sz
, NULL
, 0);
706 if ((Aflag
|| req
) && !Mflag
)
707 printf("%s: node contains no data\n", gsname
);
713 sz
= pnode
->sysctl_size
;
717 __learn_tree(name
, namelen
, pnode
);
718 node
= pnode
->sysctl_child
;
723 (*p
->ps_p
)(gsname
, gdname
, NULL
, name
, namelen
,
724 pnode
, type
, __UNCONST(p
->ps_d
));
725 else if ((Aflag
|| req
) && !Mflag
)
726 printf("%s: no children\n", gsname
);
731 * get all descriptions for next level
734 getdesc(name
, namelen
, pnode
);
736 for (ni
= 0; ni
< pnode
->sysctl_clen
; ni
++) {
737 name
[namelen
] = node
[ni
].sysctl_num
;
738 if ((node
[ni
].sysctl_flags
& CTLFLAG_HIDDEN
) &&
741 print_tree(name
, namelen
+ 1, &node
[ni
],
742 SYSCTL_TYPE(node
[ni
].sysctl_flags
),
743 1, re
, lastcompiled
);
750 rc
= prog_sysctl(name
, namelen
, &i
, &sz
, NULL
, 0);
755 display_number(pnode
, gsname
, &i
, sizeof(i
), DISPLAY_VALUE
);
760 rc
= prog_sysctl(name
, namelen
, &b
, &sz
, NULL
, 0);
765 display_number(pnode
, gsname
, &b
, sizeof(b
), DISPLAY_VALUE
);
768 case CTLTYPE_STRING
: {
769 unsigned char buf
[1024], *tbuf
;
772 rc
= prog_sysctl(&name
[0], namelen
, tbuf
, &sz
, NULL
, 0);
773 if (rc
== -1 && errno
== ENOMEM
) {
779 rc
= prog_sysctl(&name
[0], namelen
, tbuf
, &sz
, NULL
, 0);
784 display_string(pnode
, gsname
, tbuf
, sz
, DISPLAY_VALUE
);
792 rc
= prog_sysctl(&name
[0], namelen
, &q
, &sz
, NULL
, 0);
797 display_number(pnode
, gsname
, &q
, sizeof(q
), DISPLAY_VALUE
);
800 case CTLTYPE_STRUCT
: {
802 * we shouldn't actually get here, but if we
803 * do, would it be nice to have *something* to
804 * do other than completely ignore the
808 if ((d
= malloc(sz
)) == NULL
) {
809 fprintf(warnfp
, "%s: !malloc failed!\n", gsname
);
812 rc
= prog_sysctl(&name
[0], namelen
, d
, &sz
, NULL
, 0);
817 display_struct(pnode
, gsname
, d
, sz
, DISPLAY_VALUE
);
822 /* should i print an error here? */
830 * ********************************************************************
831 * parse a request, possibly determining that it's a create or destroy
833 * ********************************************************************
836 parse(char *l
, regex_t
*re
, size_t *lastcompiled
)
838 struct sysctlnode
*node
;
839 const struct handlespec
*w
;
840 int name
[CTL_MAXNAME
], dodesc
= 0;
842 char *key
, *value
, *dot
;
844 bool optional
= false;
849 if ((value
= strchr(l
, '=')) != NULL
) {
850 if (value
> l
&& value
[-1] == '?') {
857 if ((dot
= strpbrk(key
, "./")) == NULL
)
863 while (key
[0] == sep
[0] && key
[1] == sep
[0]) {
866 if (strncmp(key
+ 2, "create", 6) == 0 &&
867 (key
[8] == '=' || key
[8] == sep
[0]))
868 parse_create(key
+ 8 + (key
[8] == '=' ? 1 : 0));
869 else if (strncmp(key
+ 2, "destroy", 7) == 0 &&
870 (key
[9] == '=' || key
[9] == sep
[0]))
871 parse_destroy(key
+ 9 + (key
[9] == '=' ? 1 : 0));
872 else if (strncmp(key
+ 2, "describe", 8) == 0 &&
873 (key
[10] == '=' || key
[10] == sep
[0])) {
874 key
+= 10 + (key
[10] == '=');
875 if ((value
= strchr(key
, '=')) != NULL
)
884 sysctlperror("unable to parse '%s'\n", key
);
889 purge_tree(&my_root
);
893 namelen
= CTL_MAXNAME
;
896 if (sysctlgetmibinfo(key
, &name
[0], &namelen
, gsname
, &sz
, &node
,
897 SYSCTL_VERSION
) == -1) {
900 sysctlparseerror(namelen
, l
);
904 type
= SYSCTL_TYPE(node
->sysctl_flags
);
909 print_tree(&name
[0], namelen
, node
, type
, 0, re
, lastcompiled
);
917 trim_whitespace(value
, 1);
920 sysctlperror("Must specify -w to set variables\n");
924 canonicalize(gsname
, canonname
);
925 if (type
!= CTLTYPE_NODE
&& (w
= findhandler(canonname
, re
,
926 lastcompiled
)) != NULL
) {
927 if (w
->ps_w
== NULL
) {
928 sysctlperror("Cannot write `%s': %s\n", gsname
,
929 strerror(EOPNOTSUPP
));
932 (*w
->ps_w
)(gsname
, gdname
, value
, name
, namelen
, node
, type
,
941 * XXX old behavior is to print. should we error instead?
943 print_tree(&name
[0], namelen
, node
, CTLTYPE_NODE
, 1, re
,
949 write_number(&name
[0], namelen
, node
, value
);
952 write_string(&name
[0], namelen
, node
, value
);
956 * XXX old behavior is to print. should we error instead?
958 /* fprintf(warnfp, "you can't write to %s\n", gsname); */
959 print_tree(&name
[0], namelen
, node
, type
, 0, re
, lastcompiled
);
966 //create=foo.bar.whatever...,
967 [type=(int|quad|string|struct|node),]
970 [flags=(iohxparw12),]
971 [addr=0x####,|symbol=...|value=...]
973 size is optional for some types. type must be set before anything
974 else. nodes can have [rwhp], but nothing else applies. if no
975 size or type is given, node is asserted. writeable is the default,
976 with [rw] being read-only and unconditionally writeable
977 respectively. if you specify addr, it is assumed to be the name of
978 a kernel symbol, if value, CTLFLAG_OWNDATA will be asserted for
979 strings, CTLFLAG_IMMEDIATE for ints and u_quad_ts. you cannot
980 specify both value and addr.
985 parse_create(char *l
)
987 struct sysctlnode node
;
989 char *nname
, *key
, *value
, *data
, *addr
, *c
, *t
;
990 int name
[CTL_MAXNAME
], i
, rc
, method
, flags
, rw
;
997 sysctlperror("Must specify -w to create nodes\n");
1002 * these are the pieces that make up the description of a new
1005 memset(&node
, 0, sizeof(node
));
1006 node
.sysctl_num
= CTL_CREATE
; /* any number is fine */
1012 memset(name
, 0, sizeof(name
));
1017 * misc stuff used when constructing
1026 * the name of the thing we're trying to create is first, so
1030 if ((c
= strchr(nname
, ',')) != NULL
)
1036 * pull off the next "key=value" pair
1039 if ((t
= strchr(key
, '=')) != NULL
) {
1047 * if the "key" is "value", then that eats the rest of
1048 * the string, so we're done, otherwise bite it off at
1051 if (strcmp(key
, "value") == 0) {
1057 if ((c
= strchr(value
, ',')) != NULL
)
1062 * note that we (mostly) let the invoker of prog_sysctl(8)
1063 * play rampant here and depend on the kernel to tell
1064 * them that they were wrong. well...within reason.
1065 * we later check the various parameters against each
1066 * other to make sure it makes some sort of sense.
1068 if (strcmp(key
, "addr") == 0) {
1070 * we can't check these two. only the kernel
1071 * can tell us when it fails to find the name
1072 * (or if the address is invalid).
1076 "%s: already have %s for new node\n",
1078 method
== CTL_CREATE
? "addr" : "symbol");
1081 if (value
== NULL
) {
1082 sysctlperror("%s: missing value\n", nname
);
1086 addr
= (void*)strtoul(value
, &t
, 0);
1087 if (t
== value
|| *t
!= '\0' || errno
!= 0) {
1089 "%s: '%s' is not a valid address\n",
1093 method
= CTL_CREATE
;
1095 else if (strcmp(key
, "symbol") == 0) {
1098 "%s: already have %s for new node\n",
1100 method
== CTL_CREATE
? "addr" : "symbol");
1104 method
= CTL_CREATESYM
;
1106 else if (strcmp(key
, "type") == 0) {
1107 if (value
== NULL
) {
1108 sysctlperror("%s: missing value\n", nname
);
1111 if (strcmp(value
, "node") == 0)
1112 type
= CTLTYPE_NODE
;
1113 else if (strcmp(value
, "int") == 0) {
1117 else if (strcmp(value
, "bool") == 0) {
1119 type
= CTLTYPE_BOOL
;
1121 else if (strcmp(value
, "string") == 0)
1122 type
= CTLTYPE_STRING
;
1123 else if (strcmp(value
, "quad") == 0) {
1124 sz
= sizeof(u_quad_t
);
1125 type
= CTLTYPE_QUAD
;
1127 else if (strcmp(value
, "struct") == 0)
1128 type
= CTLTYPE_STRUCT
;
1131 "%s: '%s' is not a valid type\n",
1136 else if (strcmp(key
, "size") == 0) {
1137 if (value
== NULL
) {
1138 sysctlperror("%s: missing value\n", nname
);
1143 * yes, i know size_t is not an unsigned long,
1144 * but we can all agree that it ought to be,
1147 sz
= strtoul(value
, &t
, 0);
1148 if (t
== value
|| *t
!= '\0' || errno
!= 0) {
1150 "%s: '%s' is not a valid size\n",
1155 else if (strcmp(key
, "n") == 0) {
1156 if (value
== NULL
) {
1157 sysctlperror("%s: missing value\n", nname
);
1161 q
= strtoll(value
, &t
, 0);
1162 if (t
== value
|| *t
!= '\0' || errno
!= 0 ||
1163 q
< INT_MIN
|| q
> UINT_MAX
) {
1165 "%s: '%s' is not a valid mib number\n",
1169 node
.sysctl_num
= (int)q
;
1171 else if (strcmp(key
, "flags") == 0) {
1172 if (value
== NULL
) {
1173 sysctlperror("%s: missing value\n", nname
);
1177 while (*t
!= '\0') {
1180 flags
|= CTLFLAG_ANYWRITE
;
1183 flags
|= CTLFLAG_HIDDEN
;
1186 flags
|= CTLFLAG_IMMEDIATE
;
1189 flags
|= CTLFLAG_OWNDATA
;
1192 flags
|= CTLFLAG_PRIVATE
;
1195 flags
|= CTLFLAG_UNSIGNED
;
1198 flags
|= CTLFLAG_HEX
;
1202 rw
= CTLFLAG_READONLY
;
1205 rw
= CTLFLAG_READWRITE
;
1209 "%s: '%c' is not a valid flag\n",
1217 sysctlperror("%s: unrecognized keyword '%s'\n",
1224 * now that we've finished parsing the given string, fill in
1225 * anything they didn't specify
1228 type
= CTLTYPE_NODE
;
1231 * the "data" can be interpreted various ways depending on the
1232 * type of node we're creating, as can the size
1237 "%s: cannot specify both value and "
1238 "address\n", nname
);
1245 q
= strtoll(data
, &t
, 0);
1246 if (t
== data
|| *t
!= '\0' || errno
!= 0 ||
1247 q
< INT_MIN
|| q
> UINT_MAX
) {
1249 "%s: '%s' is not a valid integer\n",
1254 if (!(flags
& CTLFLAG_OWNDATA
)) {
1255 flags
|= CTLFLAG_IMMEDIATE
;
1256 node
.sysctl_idata
= i
;
1259 node
.sysctl_data
= &i
;
1265 q
= strtoll(data
, &t
, 0);
1266 if (t
== data
|| *t
!= '\0' || errno
!= 0 ||
1267 (q
!= 0 && q
!= 1)) {
1269 "%s: '%s' is not a valid bool\n",
1274 if (!(flags
& CTLFLAG_OWNDATA
)) {
1275 flags
|= CTLFLAG_IMMEDIATE
;
1276 node
.sysctl_idata
= b
;
1279 node
.sysctl_data
= &b
;
1283 case CTLTYPE_STRING
:
1284 flags
|= CTLFLAG_OWNDATA
;
1285 node
.sysctl_data
= data
;
1287 sz
= strlen(data
) + 1;
1288 else if (sz
< strlen(data
) + 1) {
1289 sysctlperror("%s: ignoring size=%zu for "
1290 "string node, too small for given "
1291 "value\n", nname
, sz
);
1292 sz
= strlen(data
) + 1;
1297 uq
= strtouq(data
, &t
, 0);
1298 if (t
== data
|| *t
!= '\0' || errno
!= 0) {
1300 "%s: '%s' is not a valid quad\n",
1304 if (!(flags
& CTLFLAG_OWNDATA
)) {
1305 flags
|= CTLFLAG_IMMEDIATE
;
1306 node
.sysctl_qdata
= uq
;
1309 node
.sysctl_data
= &uq
;
1311 sz
= sizeof(u_quad_t
);
1313 case CTLTYPE_STRUCT
:
1314 sysctlperror("%s: struct not initializable\n",
1320 * these methods have all provided local starting
1321 * values that the kernel must copy in
1326 * hmm...no data, but we have an address of data. that's
1330 node
.sysctl_data
= (void*)addr
;
1333 * no data and no address? well...okay. we might be able to
1336 else if (type
!= CTLTYPE_NODE
) {
1339 "%s: need a size or a starting value\n",
1343 if (!(flags
& CTLFLAG_IMMEDIATE
))
1344 flags
|= CTLFLAG_OWNDATA
;
1348 * now we do a few sanity checks on the description we've
1351 if ((flags
& CTLFLAG_IMMEDIATE
) &&
1352 (type
== CTLTYPE_STRING
|| type
== CTLTYPE_STRUCT
)) {
1353 sysctlperror("%s: cannot make an immediate %s\n",
1355 (type
== CTLTYPE_STRING
) ? "string" : "struct");
1358 if (type
== CTLTYPE_NODE
&& node
.sysctl_data
!= NULL
) {
1359 sysctlperror("%s: nodes do not have data\n", nname
);
1364 * some types must have a particular size
1367 if ((type
== CTLTYPE_INT
&& sz
!= sizeof(int)) ||
1368 (type
== CTLTYPE_BOOL
&& sz
!= sizeof(bool)) ||
1369 (type
== CTLTYPE_QUAD
&& sz
!= sizeof(u_quad_t
)) ||
1370 (type
== CTLTYPE_NODE
&& sz
!= 0)) {
1371 sysctlperror("%s: wrong size for type\n", nname
);
1375 else if (type
== CTLTYPE_STRUCT
) {
1376 sysctlperror("%s: struct must have size\n", nname
);
1381 * now...if no one said anything yet, we default nodes or
1382 * any type that owns data being writeable, and everything
1383 * else being readonly.
1386 if (type
== CTLTYPE_NODE
||
1387 (flags
& (CTLFLAG_OWNDATA
|CTLFLAG_IMMEDIATE
)))
1388 rw
= CTLFLAG_READWRITE
;
1390 rw
= CTLFLAG_READONLY
;
1394 * if a kernel address was specified, that can't be made
1396 if (rw != CTLFLAG_READONLY && addr) {
1397 sysctlperror("%s: kernel data can only be readable\n", nname);
1403 * what separator were they using in the full name of the new
1406 if ((t
= strpbrk(nname
, "./")) == NULL
)
1413 * put it all together, now. t'ain't much, is it?
1415 node
.sysctl_flags
= SYSCTL_VERSION
|flags
|rw
|type
;
1416 node
.sysctl_size
= sz
;
1417 t
= strrchr(nname
, sep
[0]);
1419 strlcpy(node
.sysctl_name
, t
+ 1, sizeof(node
.sysctl_name
));
1421 strlcpy(node
.sysctl_name
, nname
, sizeof(node
.sysctl_name
));
1426 * if this is a new top-level node, then we don't need to find
1427 * the mib for its parent
1435 * on the other hand, if it's not a top-level node...
1438 namelen
= sizeof(name
) / sizeof(name
[0]);
1439 sz
= sizeof(gsname
);
1441 rc
= sysctlgetmibinfo(nname
, &name
[0], &namelen
,
1442 gsname
, &sz
, NULL
, SYSCTL_VERSION
);
1445 sysctlparseerror(namelen
, nname
);
1451 * yes, a new node is being created
1454 name
[namelen
++] = method
;
1456 name
[namelen
++] = CTL_CREATE
;
1459 rc
= prog_sysctl(&name
[0], namelen
, &node
, &sz
, &node
, sizeof(node
));
1462 sysctlperror("%s: CTL_CREATE failed: %s\n",
1463 nname
, strerror(errno
));
1467 if (!qflag
&& !nflag
)
1468 printf("%s(%s): (created)\n", nname
, st(type
));
1474 parse_destroy(char *l
)
1476 struct sysctlnode node
;
1478 int name
[CTL_MAXNAME
], rc
;
1482 sysctlperror("Must specify -w to destroy nodes\n");
1486 memset(name
, 0, sizeof(name
));
1487 namelen
= sizeof(name
) / sizeof(name
[0]);
1488 sz
= sizeof(gsname
);
1489 rc
= sysctlgetmibinfo(l
, &name
[0], &namelen
, gsname
, &sz
, NULL
,
1492 sysctlparseerror(namelen
, l
);
1496 memset(&node
, 0, sizeof(node
));
1497 node
.sysctl_flags
= SYSCTL_VERSION
;
1498 node
.sysctl_num
= name
[namelen
- 1];
1499 name
[namelen
- 1] = CTL_DESTROY
;
1502 rc
= prog_sysctl(&name
[0], namelen
, &node
, &sz
, &node
, sizeof(node
));
1505 sysctlperror("%s: CTL_DESTROY failed: %s\n",
1506 l
, strerror(errno
));
1510 if (!qflag
&& !nflag
)
1511 printf("%s(%s): (destroyed)\n", gsname
,
1512 st(SYSCTL_TYPE(node
.sysctl_flags
)));
1518 parse_describe(char *l
)
1520 struct sysctlnode newdesc
;
1521 char buf
[1024], *value
;
1522 struct sysctldesc
*d
= (void*)&buf
[0];
1523 int name
[CTL_MAXNAME
], rc
;
1528 sysctlperror("Must specify -w to set descriptions\n");
1532 value
= strchr(l
, '=');
1535 memset(name
, 0, sizeof(name
));
1536 namelen
= sizeof(name
) / sizeof(name
[0]);
1537 sz
= sizeof(gsname
);
1538 rc
= sysctlgetmibinfo(l
, &name
[0], &namelen
, gsname
, &sz
, NULL
,
1541 sysctlparseerror(namelen
, l
);
1546 memset(&newdesc
, 0, sizeof(newdesc
));
1547 newdesc
.sysctl_flags
= SYSCTL_VERSION
|CTLFLAG_OWNDESC
;
1548 newdesc
.sysctl_num
= name
[namelen
- 1];
1549 newdesc
.sysctl_desc
= value
;
1550 name
[namelen
- 1] = CTL_DESCRIBE
;
1551 rc
= prog_sysctl(name
, namelen
, d
, &sz
, &newdesc
, sizeof(newdesc
));
1553 sysctlperror("%s: CTL_DESCRIBE failed: %s\n",
1554 gsname
, strerror(errno
));
1555 else if (d
->descr_len
== 1)
1556 sysctlperror("%s: description not set\n", gsname
);
1557 else if (!qflag
&& !nflag
)
1558 printf("%s: %s\n", gsname
, d
->descr_str
);
1562 * ********************************************************************
1563 * when things go wrong...
1564 * ********************************************************************
1569 const char *progname
= getprogname();
1571 (void)fprintf(stderr
,
1578 progname
, "[-dneq] [-x[x]|-r] variable ...",
1579 progname
, "[-ne] [-q] -w variable=value ...",
1580 progname
, "[-dne] -a",
1581 progname
, "[-dne] -A",
1582 progname
, "[-ne] -M",
1583 progname
, "[-dne] [-q] -f file");
1588 getdesc1(int *name
, u_int namelen
, struct sysctlnode
*pnode
)
1590 struct sysctlnode node
;
1591 char buf
[1024], *desc
;
1592 struct sysctldesc
*d
= (void*)buf
;
1593 size_t sz
= sizeof(buf
);
1596 memset(&node
, 0, sizeof(node
));
1597 node
.sysctl_flags
= SYSCTL_VERSION
;
1598 node
.sysctl_num
= name
[namelen
- 1];
1599 name
[namelen
- 1] = CTL_DESCRIBE
;
1600 rc
= prog_sysctl(name
, namelen
, d
, &sz
, &node
, sizeof(node
));
1603 d
->descr_len
== 1 ||
1604 d
->descr_num
!= pnode
->sysctl_num
||
1605 d
->descr_ver
!= pnode
->sysctl_ver
)
1608 desc
= malloc(d
->descr_len
);
1612 if (desc
!= (char *)-1)
1613 memcpy(desc
, &d
->descr_str
[0], d
->descr_len
);
1614 name
[namelen
- 1] = node
.sysctl_num
;
1615 if (pnode
->sysctl_desc
!= NULL
&&
1616 pnode
->sysctl_desc
!= (const char *)-1)
1617 free(__UNCONST(pnode
->sysctl_desc
));
1618 pnode
->sysctl_desc
= desc
;
1622 getdesc(int *name
, u_int namelen
, struct sysctlnode
*pnode
)
1624 struct sysctlnode
*node
= pnode
->sysctl_child
;
1625 struct sysctldesc
*d
, *p
, *plim
;
1627 size_t i
, sz
, child_cnt
;
1630 sz
= 128 * pnode
->sysctl_clen
;
1631 name
[namelen
] = CTL_DESCRIBE
;
1634 * attempt *twice* to get the description chunk. if two tries
1635 * doesn't work, give up.
1642 rc
= prog_sysctl(name
, namelen
+ 1, d
, &sz
, NULL
, 0);
1646 if (i
== 0 && errno
== ENOMEM
)
1651 } while (d
== NULL
);
1654 * hokey nested loop here, giving O(n**2) behavior, but should
1657 plim
= /*LINTED ptr cast*/(struct sysctldesc
*)((char*)d
+ sz
);
1658 child_cnt
= (pnode
->sysctl_flags
& CTLTYPE_NODE
) ? pnode
->sysctl_clen
1660 for (i
= 0; i
< child_cnt
; i
++) {
1661 node
= &pnode
->sysctl_child
[i
];
1662 for (p
= d
; p
< plim
; p
= NEXT_DESCR(p
))
1663 if (node
->sysctl_num
== p
->descr_num
)
1665 if (p
< plim
&& node
->sysctl_ver
== p
->descr_ver
) {
1667 * match found, attempt to attach description
1669 if (p
->descr_len
== 1)
1672 desc
= malloc(p
->descr_len
);
1676 memcpy(desc
, &p
->descr_str
[0], p
->descr_len
);
1677 node
->sysctl_desc
= desc
;
1685 trim_whitespace(char *s
, int dir
)
1691 while (isspace((unsigned char)*i
))
1693 while ((*o
++ = *i
++) != '\0');
1694 o
-= 2; /* already past nul, skip back to before it */
1696 while (o
> s
&& isspace((unsigned char)*o
))
1701 sysctlerror(int soft
)
1710 case EPROTONOSUPPORT
:
1712 sysctlperror("%s: the value is not available "
1713 "(%s)\n", gsname
, strerror(errno
));
1719 sysctlperror("%s: %s\n", gsname
, strerror(errno
));
1725 sysctlparseerror(u_int namelen
, const char *pname
)
1732 sysctlperror("%s level name '%s' in '%s' is invalid\n",
1733 lname
[namelen
], gsname
, pname
);
1737 sysctlperror(const char *fmt
, ...)
1741 (void)fprintf(warnfp
, "%s: ", getprogname());
1743 (void)fprintf(warnfp
, "%s#%zu: ", fn
, nr
);
1745 (void)vfprintf(warnfp
, fmt
, ap
);
1752 * ********************************************************************
1753 * how to write to a "simple" node
1754 * ********************************************************************
1757 write_number(int *name
, u_int namelen
, struct sysctlnode
*node
, char *value
)
1768 trim_whitespace(value
, 3);
1774 qi
= strtouq(value
, &t
, 0);
1775 if (qi
== UQUAD_MAX
&& errno
== ERANGE
) {
1776 sysctlperror("%s: %s\n", value
, strerror(errno
));
1779 if (t
== value
|| *t
!= '\0') {
1780 sysctlperror("%s: not a number\n", value
);
1784 switch (SYSCTL_TYPE(node
->sysctl_flags
)) {
1787 io
= (u_int
)(qi
>> 32);
1788 if (io
!= (u_int
)-1 && io
!= 0) {
1789 sysctlperror("%s: %s\n", value
, strerror(ERANGE
));
1812 rc
= prog_sysctl(name
, namelen
, o
, &so
, i
, si
);
1818 switch (SYSCTL_TYPE(node
->sysctl_flags
)) {
1820 display_number(node
, gsname
, &io
, sizeof(io
), DISPLAY_OLD
);
1821 display_number(node
, gsname
, &ii
, sizeof(ii
), DISPLAY_NEW
);
1824 display_number(node
, gsname
, &bo
, sizeof(bo
), DISPLAY_OLD
);
1825 display_number(node
, gsname
, &bi
, sizeof(bi
), DISPLAY_NEW
);
1828 display_number(node
, gsname
, &qo
, sizeof(qo
), DISPLAY_OLD
);
1829 display_number(node
, gsname
, &qi
, sizeof(qi
), DISPLAY_NEW
);
1835 write_string(int *name
, u_int namelen
, struct sysctlnode
*node
, char *value
)
1843 so
= node
->sysctl_size
;
1844 if (si
> so
&& so
!= 0) {
1845 sysctlperror("%s: string too long\n", value
);
1850 sysctlperror("%s: !malloc failed!\n", gsname
);
1854 rc
= prog_sysctl(name
, namelen
, o
, &so
, i
, si
);
1860 display_string(node
, gsname
, o
, so
, DISPLAY_OLD
);
1861 display_string(node
, gsname
, i
, si
, DISPLAY_NEW
);
1866 * ********************************************************************
1867 * simple ways to print stuff consistently
1868 * ********************************************************************
1871 display_number(const struct sysctlnode
*node
, const char *name
,
1872 const void *data
, size_t sz
, int n
)
1880 if ((nflag
|| rflag
) && (n
== DISPLAY_OLD
))
1883 if (rflag
&& n
!= DISPLAY_OLD
) {
1884 fwrite(data
, sz
, 1, stdout
);
1889 if (n
== DISPLAY_VALUE
)
1890 printf("%s%s", name
, eq
);
1891 else if (n
== DISPLAY_OLD
)
1892 printf("%s: ", name
);
1896 if (n
!= DISPLAY_NEW
)
1902 switch (SYSCTL_TYPE(node
->sysctl_flags
)) {
1904 memcpy(&i
, data
, sz
);
1906 printf("0x%0*x", (int)sz
* 2, i
);
1907 else if (node
->sysctl_flags
& CTLFLAG_HEX
)
1909 else if (node
->sysctl_flags
& CTLFLAG_UNSIGNED
)
1915 memcpy(&b
, data
, sz
);
1917 printf("0x%0*x", (int)sz
* 2, b
);
1918 else if (node
->sysctl_flags
& CTLFLAG_HEX
)
1924 memcpy(&q
, data
, sz
);
1926 printf("0x%0*" PRIx64
, (int)sz
* 2, q
);
1927 else if (node
->sysctl_flags
& CTLFLAG_HEX
)
1928 printf("%#" PRIx64
, q
);
1929 else if (node
->sysctl_flags
& CTLFLAG_UNSIGNED
)
1930 printf("%" PRIu64
, q
);
1932 printf("%" PRIu64
, q
);
1936 if (n
== DISPLAY_OLD
)
1943 display_string(const struct sysctlnode
*node
, const char *name
,
1944 const void *data
, size_t sz
, int n
)
1946 const unsigned char *buf
= data
;
1951 if ((nflag
|| rflag
) && (n
== DISPLAY_OLD
))
1954 if (rflag
&& n
!= DISPLAY_OLD
) {
1955 fwrite(data
, sz
, 1, stdout
);
1960 if (n
== DISPLAY_VALUE
)
1961 printf("%s%s", name
, eq
);
1962 else if (n
== DISPLAY_OLD
)
1963 printf("%s: ", name
);
1967 if (n
!= DISPLAY_NEW
)
1973 if (xflag
|| node
->sysctl_flags
& CTLFLAG_HEX
) {
1974 for (ni
= 0; ni
< (int)sz
; ni
++) {
1976 printf("%02x", buf
[ni
]);
1977 if (buf
[ni
] == '\0')
1980 printf("\\x%2.2x", buf
[ni
]);
1984 printf("%.*s", (int)sz
, buf
);
1986 if (n
== DISPLAY_OLD
)
1994 display_struct(const struct sysctlnode
*node
, const char *name
,
1995 const void *data
, size_t sz
, int n
)
1997 const unsigned char *buf
= data
;
2003 if (!(xflag
|| rflag
)) {
2006 "%s: this type is unknown to this program\n",
2010 if ((nflag
|| rflag
) && (n
== DISPLAY_OLD
))
2013 if (rflag
&& n
!= DISPLAY_OLD
) {
2014 fwrite(data
, sz
, 1, stdout
);
2019 if (n
== DISPLAY_VALUE
)
2020 printf("%s%s", name
, eq
);
2021 else if (n
== DISPLAY_OLD
)
2022 printf("%s: ", name
);
2026 if (n
!= DISPLAY_NEW
)
2038 for (ni
= 0; ni
< (int)sz
; ni
++)
2039 printf("%02x", buf
[ni
]);
2041 printf("...(%zu more bytes)", more
);
2046 hex_dump(const unsigned char *buf
, size_t len
)
2050 char line
[80], tmp
[12];
2052 memset(line
, ' ', sizeof(line
));
2053 for (i
= 0, j
= 15; i
< len
; i
++) {
2060 snprintf(tmp
, sizeof(tmp
), "%07x", i
);
2061 memcpy(&line
[0], tmp
, 7);
2063 /* copy out hex version of byte */
2064 snprintf(tmp
, sizeof(tmp
), "%02x", buf
[i
]);
2065 memcpy(&line
[9 + j
* 3], tmp
, 2);
2066 /* copy out plain version of byte */
2067 line
[60 + j
] = (isprint(buf
[i
])) ? buf
[i
] : '.';
2068 /* print a full line and erase it */
2070 printf("%s\n", line
);
2071 memset(line
, ' ', sizeof(line
));
2075 printf("%s\n", line
);
2076 printf("%07zu bytes\n", len
);
2080 * ********************************************************************
2081 * functions that handle particular nodes
2082 * ********************************************************************
2086 printother(HANDLER_ARGS
)
2092 if (!(Aflag
|| req
) || Mflag
)
2096 * okay...you asked for it, so let's give it a go
2098 while (type
!= CTLTYPE_NODE
&& (xflag
|| rflag
)) {
2099 rc
= prog_sysctl(name
, namelen
, NULL
, &sz1
, NULL
, 0);
2100 if (rc
== -1 || sz1
== 0)
2106 rc
= prog_sysctl(name
, namelen
, p
, &sz2
, NULL
, 0);
2107 if (rc
== -1 || sz1
!= sz2
) {
2111 display_struct(pnode
, gsname
, p
, sz1
, DISPLAY_VALUE
);
2117 * that didn't work...do we have a specific message for this
2121 sysctlperror("%s: use '%s' to view this information\n",
2122 gsname
, (const char *)v
);
2127 * hmm...i wonder if we have any generic hints?
2131 sysctlperror("%s: use 'netstat' to view this information\n",
2135 sysctlperror("%s: missing 'options DEBUG' from kernel?\n",
2139 sysctlperror("%s: missing 'options DDB' from kernel?\n",
2143 sysctlperror("%s: no vendor extensions installed\n",
2151 kern_clockrate(HANDLER_ARGS
)
2153 struct clockinfo clkinfo
;
2157 sz
= sizeof(clkinfo
);
2158 rc
= prog_sysctl(name
, namelen
, &clkinfo
, &sz
, NULL
, 0);
2163 if (sz
!= sizeof(clkinfo
))
2164 errx(EXIT_FAILURE
, "%s: !returned size wrong!", sname
);
2166 if (xflag
|| rflag
) {
2167 display_struct(pnode
, sname
, &clkinfo
, sz
,
2172 printf("%s: ", sname
);
2173 printf("tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
2174 clkinfo
.tick
, clkinfo
.tickadj
,
2175 clkinfo
.hz
, clkinfo
.profhz
, clkinfo
.stathz
);
2180 kern_boottime(HANDLER_ARGS
)
2182 struct timeval timeval
;
2187 sz
= sizeof(timeval
);
2188 rc
= prog_sysctl(name
, namelen
, &timeval
, &sz
, NULL
, 0);
2193 if (sz
!= sizeof(timeval
))
2194 errx(EXIT_FAILURE
, "%s: !returned size wrong!", sname
);
2196 boottime
= timeval
.tv_sec
;
2198 display_struct(pnode
, sname
, &timeval
, sz
,
2201 /* ctime() provides the \n */
2202 printf("%s%s%s", sname
, eq
, ctime(&boottime
));
2203 else if (nflag
== 1)
2204 printf("%ld\n", (long)boottime
);
2206 printf("%ld.%06ld\n", (long)timeval
.tv_sec
,
2207 (long)timeval
.tv_usec
);
2212 kern_consdev(HANDLER_ARGS
)
2219 rc
= prog_sysctl(name
, namelen
, &cons
, &sz
, NULL
, 0);
2224 if (sz
!= sizeof(cons
))
2225 errx(EXIT_FAILURE
, "%s: !returned size wrong!", sname
);
2228 display_struct(pnode
, sname
, &cons
, sz
,
2232 printf("%s%s", sname
, eq
);
2233 if (nflag
< 2 && (sname
= devname(cons
, S_IFCHR
)) != NULL
)
2234 printf("%s\n", sname
);
2236 printf("0x%llx\n", (unsigned long long)cons
);
2242 kern_cp_time(HANDLER_ARGS
)
2247 char s
[sizeof("kern.cp_time.nnnnnn")];
2251 * three things to do here.
2252 * case 1: get sum (no Aflag and namelen == 2)
2253 * case 2: get specific processor (namelen == 3)
2254 * case 3: get all processors (Aflag and namelen == 2)
2257 if (namelen
== 2 && Aflag
) {
2259 rc
= sysctlbyname("hw.ncpu", &n
, &sz
, NULL
, 0);
2261 return; /* XXX print an error, eh? */
2262 n
++; /* Add on space for the sum. */
2263 sz
= n
* sizeof(u_int64_t
) * CPUSTATES
;
2266 n
= -1; /* Just print one data set. */
2267 sz
= sizeof(u_int64_t
) * CPUSTATES
;
2270 cp_time
= malloc(sz
);
2271 if (cp_time
== NULL
) {
2277 rc
= prog_sysctl(name
, namelen
, cp_time
+ (n
!= -1) * CPUSTATES
, &osz
,
2287 * Check, but account for space we'll occupy with the sum.
2289 if (osz
!= sz
- (n
!= -1) * CPUSTATES
* sizeof(u_int64_t
))
2290 errx(EXIT_FAILURE
, "%s: !returned size wrong!", sname
);
2293 * Compute the actual sum. Two calls would be easier (we
2294 * could just call ourselves recursively above), but the
2295 * numbers wouldn't add up.
2298 memset(cp_time
, 0, sizeof(u_int64_t
) * CPUSTATES
);
2299 for (i
= 1; i
< n
; i
++) {
2300 cp_time
[CP_USER
] += cp_time
[i
* CPUSTATES
+ CP_USER
];
2301 cp_time
[CP_NICE
] += cp_time
[i
* CPUSTATES
+ CP_NICE
];
2302 cp_time
[CP_SYS
] += cp_time
[i
* CPUSTATES
+ CP_SYS
];
2303 cp_time
[CP_INTR
] += cp_time
[i
* CPUSTATES
+ CP_INTR
];
2304 cp_time
[CP_IDLE
] += cp_time
[i
* CPUSTATES
+ CP_IDLE
];
2309 for (i
= 0; n
== -1 || i
< n
; i
++) {
2311 (void)snprintf(s
, sizeof(s
), "%s%s%d", sname
, sep
,
2316 display_struct(pnode
, tname
, cp_time
+ (i
* CPUSTATES
),
2317 sizeof(u_int64_t
) * CPUSTATES
,
2321 printf("%s: ", tname
);
2322 printf("user = %" PRIu64
2328 cp_time
[i
* CPUSTATES
+ CP_USER
],
2329 cp_time
[i
* CPUSTATES
+ CP_NICE
],
2330 cp_time
[i
* CPUSTATES
+ CP_SYS
],
2331 cp_time
[i
* CPUSTATES
+ CP_INTR
],
2332 cp_time
[i
* CPUSTATES
+ CP_IDLE
]);
2335 * Just printing the one node.
2346 kern_drivers(HANDLER_ARGS
)
2348 struct kinfo_drivers
*kd
;
2353 rc
= prog_sysctl(name
, namelen
, NULL
, &sz
, NULL
, 0);
2359 if (sz
% sizeof(*kd
))
2360 err(EXIT_FAILURE
, "bad size %zu for kern.drivers", sz
);
2368 rc
= prog_sysctl(name
, namelen
, kd
, &sz
, NULL
, 0);
2377 printf("%s%s", sname
, eq
);
2378 for (i
= 0, sz
/= sizeof(*kd
); i
< sz
; i
++) {
2379 (void)printf("%s[%d %d %s]", comma
, kd
[i
].d_cmajor
,
2380 kd
[i
].d_bmajor
, kd
[i
].d_name
);
2389 kern_cp_id(HANDLER_ARGS
)
2394 char s
[sizeof("kern.cp_id.nnnnnn")];
2396 struct sysctlnode node
= *pnode
;
2399 * three things to do here.
2400 * case 1: print a specific cpu id (namelen == 3)
2401 * case 2: print all cpu ids separately (Aflag set)
2402 * case 3: print all cpu ids on one line
2407 rc
= sysctlbyname("hw.ncpu", &n
, &sz
, NULL
, 0);
2409 return; /* XXX print an error, eh? */
2410 sz
= n
* sizeof(u_int64_t
);
2413 n
= -1; /* Just print one cpu id. */
2414 sz
= sizeof(u_int64_t
);
2418 if (cp_id
== NULL
) {
2424 rc
= prog_sysctl(name
, namelen
, cp_id
, &osz
, NULL
, 0);
2432 * Check that we got back what we asked for.
2435 errx(EXIT_FAILURE
, "%s: !returned size wrong!", sname
);
2437 /* pretend for output purposes */
2438 node
.sysctl_flags
= SYSCTL_FLAGS(pnode
->sysctl_flags
) |
2439 SYSCTL_TYPE(CTLTYPE_QUAD
);
2443 display_number(&node
, tname
, cp_id
,
2447 for (i
= 0; i
< n
; i
++)
2448 (void)snprintf(s
, sizeof(s
), "%s%s%d", sname
, sep
, i
);
2450 display_number(&node
, tname
, &cp_id
[i
],
2456 display_struct(pnode
, tname
, cp_id
, sz
, DISPLAY_VALUE
);
2459 printf("%s: ", tname
);
2460 for (i
= 0; i
< n
; i
++) {
2463 printf("%d = %" PRIu64
, i
, cp_id
[i
]);
2474 vm_loadavg(HANDLER_ARGS
)
2476 struct loadavg loadavg
;
2480 sz
= sizeof(loadavg
);
2481 rc
= prog_sysctl(name
, namelen
, &loadavg
, &sz
, NULL
, 0);
2486 if (sz
!= sizeof(loadavg
))
2487 errx(EXIT_FAILURE
, "%s: !returned size wrong!", sname
);
2489 if (xflag
|| rflag
) {
2490 display_struct(pnode
, sname
, &loadavg
, sz
,
2495 printf("%s: ", sname
);
2496 printf("%.2f %.2f %.2f\n",
2497 (double) loadavg
.ldavg
[0] / loadavg
.fscale
,
2498 (double) loadavg
.ldavg
[1] / loadavg
.fscale
,
2499 (double) loadavg
.ldavg
[2] / loadavg
.fscale
);
2504 proc_limit(HANDLER_ARGS
)
2506 u_quad_t olim
, *newp
, nlim
;
2512 trim_whitespace(value
, 3);
2515 if (value
!= NULL
) {
2518 if (strcmp(value
, "unlimited") == 0)
2519 nlim
= RLIM_INFINITY
;
2522 nlim
= strtouq(value
, &t
, 0);
2523 if (t
== value
|| *t
!= '\0' || errno
!= 0) {
2524 sysctlperror("%s: '%s' is not a valid limit\n",
2535 rc
= prog_sysctl(name
, namelen
, &olim
, &osz
, newp
, nsz
);
2537 sysctlerror(newp
== NULL
);
2544 if (rflag
|| xflag
|| olim
!= RLIM_INFINITY
)
2545 display_number(pnode
, sname
, &olim
, sizeof(olim
),
2546 newp
? DISPLAY_OLD
: DISPLAY_VALUE
);
2548 display_string(pnode
, sname
, "unlimited", 10,
2549 newp
? DISPLAY_OLD
: DISPLAY_VALUE
);
2552 if (rflag
|| xflag
|| nlim
!= RLIM_INFINITY
)
2553 display_number(pnode
, sname
, &nlim
, sizeof(nlim
),
2556 display_string(pnode
, sname
, "unlimited", 10,
2564 machdep_diskinfo(HANDLER_ARGS
)
2566 struct disklist
*dl
;
2567 struct biosdisk_info
*bi
;
2568 struct nativedisk_info
*ni
;
2573 rc
= prog_sysctl(name
, namelen
, NULL
, &sz
, NULL
, 0);
2583 rc
= prog_sysctl(name
, namelen
, dl
, &sz
, NULL
, 0);
2590 printf("%s: ", sname
);
2591 lim
= dl
->dl_nbiosdisks
;
2592 if (lim
> MAX_BIOSDISKS
)
2593 lim
= MAX_BIOSDISKS
;
2594 for (bi
= dl
->dl_biosdisks
, i
= 0; i
< lim
; bi
++, i
++)
2595 printf("%x:%" PRIu64
"(%d/%d/%d),%x ",
2596 bi
->bi_dev
, bi
->bi_lbasecs
,
2597 bi
->bi_cyl
, bi
->bi_head
, bi
->bi_sec
,
2599 lim
= dl
->dl_nnativedisks
;
2600 ni
= dl
->dl_nativedisks
;
2601 bi
= dl
->dl_biosdisks
;
2602 /* LINTED -- pointer casts are tedious */
2603 if ((char *)&ni
[lim
] != (char *)dl
+ sz
) {
2604 sysctlperror("%s: size mismatch\n", gsname
);
2607 for (i
= 0; i
< lim
; ni
++, i
++) {
2609 printf(" %.*s", (int)sizeof ni
->ni_devname
,
2611 for (b
= 0; b
< (unsigned int)ni
->ni_nmatches
; t
= ',', b
++)
2613 bi
[ni
->ni_biosmatches
[b
]].bi_dev
);
2618 #endif /* CPU_DISKINFO */
2622 mode_bits(HANDLER_ARGS
)
2624 char buf
[12], outbuf
[100];
2625 int o
, m
, *newp
, rc
;
2630 trim_whitespace(value
, 3);
2634 if (value
!= NULL
) {
2637 size_t ttsz
= sizeof(tt
);
2643 rc
= prog_sysctl(name
, namelen
, &tt
, &ttsz
, NULL
, 0);
2645 sysctlperror("%s: failed query\n", sname
);
2649 old_umask
= umask(0);
2650 foo
= setmode(value
);
2653 sysctlperror("%s: '%s' is an invalid mode\n", sname
,
2657 old_umask
= umask(0);
2658 m
= getmode(foo
, (mode_t
)tt
);
2661 sysctlperror("%s: '%s' is an invalid mode\n", sname
,
2671 rc
= prog_sysctl(name
, namelen
, &o
, &osz
, newp
, nsz
);
2673 sysctlerror(newp
== NULL
);
2684 display_number(pnode
, sname
, &o
, sizeof(o
),
2685 newp
? DISPLAY_OLD
: DISPLAY_VALUE
);
2687 memset(buf
, 0, sizeof(buf
));
2689 rc
= snprintf(outbuf
, sizeof(outbuf
), "%04o (%s)", om
, buf
+ 1);
2690 display_string(pnode
, sname
, outbuf
, rc
, newp
? DISPLAY_OLD
: DISPLAY_VALUE
);
2695 display_number(pnode
, sname
, &m
, sizeof(m
),
2698 memset(buf
, 0, sizeof(buf
));
2700 rc
= snprintf(outbuf
, sizeof(outbuf
), "%04o (%s)", mm
, buf
+ 1);
2701 display_string(pnode
, sname
, outbuf
, rc
, DISPLAY_NEW
);
2706 typedef __BITMAP_TYPE(, uint32_t, 0x10000) bitmap
;
2709 bitmask_print(const bitmap
*o
)
2714 for (size_t i
= 0; i
< MAXPORTS
; i
++)
2715 if (__BITMAP_ISSET(i
, o
)) {
2719 rv
= asprintf(&s
, "%s,%zu", os
, i
);
2721 rv
= asprintf(&s
, "%zu", i
);
2723 err(EXIT_FAILURE
, "%s 1", __func__
);
2727 if (s
== NULL
&& (s
= strdup("")) == NULL
)
2728 err(EXIT_FAILURE
, "%s 2", __func__
);
2733 bitmask_scan(const void *v
, bitmap
*o
)
2735 char *s
= strdup(v
);
2737 err(EXIT_FAILURE
, "%s", __func__
);
2740 for (s
= strtok(s
, ","); s
; s
= strtok(NULL
, ",")) {
2743 unsigned long l
= strtoul(s
, &e
, 0);
2744 if ((l
== ULONG_MAX
&& errno
== ERANGE
) || s
== e
|| *e
)
2745 errx(EXIT_FAILURE
, "Invalid port: %s", s
);
2747 errx(EXIT_FAILURE
, "Port out of range: %s", s
);
2754 reserve(HANDLER_ARGS
)
2761 trim_whitespace(value
, 3);
2765 bitmask_scan(value
, &n
);
2771 rc
= prog_sysctl(name
, namelen
, &o
, &osz
, value
, nsz
);
2773 sysctlerror(value
== NULL
);
2781 display_struct(pnode
, sname
, &o
, sizeof(o
),
2782 value
? DISPLAY_OLD
: DISPLAY_VALUE
);
2784 char *s
= bitmask_print(&o
);
2785 display_string(pnode
, sname
, s
, strlen(s
),
2786 value
? DISPLAY_OLD
: DISPLAY_VALUE
);
2792 display_struct(pnode
, sname
, &n
, sizeof(n
),
2795 char *s
= bitmask_print(&n
);
2796 display_string(pnode
, sname
, s
, strlen(s
), DISPLAY_NEW
);