1 /* $NetBSD: sysctl.c,v 1.129 2009/04/01 15:55:27 christos 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.129 2009/04/01 15:55:27 christos 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 <netinet/in.h>
84 #include <netinet/ip_var.h>
85 #include <netinet/tcp.h>
86 #include <netinet/tcp_timer.h>
87 #include <netinet/tcp_var.h>
88 #include <netinet/icmp6.h>
89 #include <nfs/rpcv2.h>
90 #include <nfs/nfsproto.h>
92 #include <machine/cpu.h>
93 #include <netkey/key_var.h>
109 * this needs to be able to do the printing and the setting
111 #define HANDLER_PROTO const char *, const char *, char *, \
112 int *, u_int, const struct sysctlnode *, \
114 #define HANDLER_ARGS const char *sname, const char *dname, char *value, \
115 int *name, u_int namelen, const struct sysctlnode *pnode, \
117 #define DISPLAY_VALUE 0
118 #define DISPLAY_OLD 1
119 #define DISPLAY_NEW 2
124 static const struct handlespec
*findhandler(const char *, int);
125 static void canonicalize(const char *, char *);
126 static void purge_tree(struct sysctlnode
*);
127 static void print_tree(int *, u_int
, struct sysctlnode
*, u_int
, int);
128 static void write_number(int *, u_int
, struct sysctlnode
*, char *);
129 static void write_string(int *, u_int
, struct sysctlnode
*, char *);
130 static void display_number(const struct sysctlnode
*, const char *,
131 const void *, size_t, int);
132 static void display_string(const struct sysctlnode
*, const char *,
133 const void *, size_t, int);
134 static void display_struct(const struct sysctlnode
*, const char *,
135 const void *, size_t, int);
136 static void hex_dump(const unsigned char *, size_t);
137 static void usage(void);
138 static void parse(char *);
139 static void parse_create(char *);
140 static void parse_destroy(char *);
141 static void parse_describe(char *);
142 static void getdesc1(int *, u_int
, struct sysctlnode
*);
143 static void getdesc(int *, u_int
, struct sysctlnode
*);
144 static void trim_whitespace(char *, int);
145 static void sysctlerror(int);
146 static void sysctlparseerror(u_int
, const char *);
147 static void sysctlperror(const char *, ...);
148 #define EXIT(n) do { \
149 if (fn == NULL) exit(n); else return; } while (/*CONSTCOND*/0)
152 * "borrowed" from libc:sysctlgetmibinfo.c
154 int __learn_tree(int *, u_int
, struct sysctlnode
*);
159 static void printother(HANDLER_PROTO
);
160 static void kern_clockrate(HANDLER_PROTO
);
161 static void kern_boottime(HANDLER_PROTO
);
162 static void kern_consdev(HANDLER_PROTO
);
163 static void kern_cp_time(HANDLER_PROTO
);
164 static void kern_cp_id(HANDLER_PROTO
);
165 static void kern_drivers(HANDLER_PROTO
);
166 static void vm_loadavg(HANDLER_PROTO
);
167 static void proc_limit(HANDLER_PROTO
);
169 static void machdep_diskinfo(HANDLER_PROTO
);
170 #endif /* CPU_DISKINFO */
171 static void mode_bits(HANDLER_PROTO
);
173 static const struct handlespec
{
175 void (*ps_p
)(HANDLER_PROTO
);
176 void (*ps_w
)(HANDLER_PROTO
);
179 { "/kern/clockrate", kern_clockrate
, NULL
, NULL
},
180 { "/kern/vnode", printother
, NULL
, "pstat" },
181 { "/kern/proc(2|_args)?", printother
, NULL
, "ps" },
182 { "/kern/file2?", printother
, NULL
, "pstat" },
183 { "/kern/ntptime", printother
, NULL
,
184 "ntpdc -c kerninfo" },
185 { "/kern/msgbuf", printother
, NULL
, "dmesg" },
186 { "/kern/boottime", kern_boottime
, NULL
, NULL
},
187 { "/kern/consdev", kern_consdev
, NULL
, NULL
},
188 { "/kern/cp_time(/[0-9]+)?", kern_cp_time
, NULL
, NULL
},
189 { "/kern/sysvipc_info", printother
, NULL
, "ipcs" },
190 { "/kern/cp_id(/[0-9]+)?", kern_cp_id
, NULL
, NULL
},
192 { "/kern/coredump/setid/mode", mode_bits
, mode_bits
, NULL
},
193 { "/kern/drivers", kern_drivers
, NULL
, NULL
},
195 { "/vm/vmmeter", printother
, NULL
,
196 "vmstat' or 'systat" },
197 { "/vm/loadavg", vm_loadavg
, NULL
, NULL
},
198 { "/vm/uvmexp2?", printother
, NULL
,
199 "vmstat' or 'systat" },
201 { "/vfs/nfs/nfsstats", printother
, NULL
, "nfsstat" },
203 { "/net/inet6?/tcp6?/ident", printother
, NULL
, "identd" },
204 { "/net/inet6/icmp6/nd6_[dp]rlist", printother
, NULL
, "ndp" },
205 { "/net/key/dumps[ap]", printother
, NULL
, "setkey" },
206 { "/net/[^/]+/[^/]+/pcblist", printother
, NULL
,
207 "netstat' or 'sockstat" },
208 { "/net/(inet|inet6)/[^/]+/stats", printother
, NULL
, "netstat"},
209 { "/net/bpf/(stats|peers)", printother
, NULL
, "netstat"},
211 { "/net/inet.*/tcp.*/deb.*", printother
, NULL
, "trpt" },
213 { "/net/ns/spp/deb.*", printother
, NULL
, "trsp" },
215 { "/hw/diskstats", printother
, NULL
, "iostat" },
218 { "/machdep/consdev", kern_consdev
, NULL
, NULL
},
219 #endif /* CPU_CONSDEV */
221 { "/machdep/diskinfo", machdep_diskinfo
, NULL
, NULL
},
222 #endif /* CPU_CONSDEV */
224 { "/proc/[^/]+/rlimit/[^/]+/[^/]+", proc_limit
, proc_limit
, NULL
},
227 * these will only be called when the given node has no children
229 { "/net/[^/]+", printother
, NULL
, NULL
},
230 { "/debug", printother
, NULL
, NULL
},
231 { "/ddb", printother
, NULL
, NULL
},
232 { "/vendor", printother
, NULL
, NULL
},
234 { NULL
, NULL
, NULL
, NULL
},
237 struct sysctlnode my_root
= {
238 .sysctl_flags
= SYSCTL_VERSION
|CTLFLAG_ROOT
|CTLTYPE_NODE
,
239 sysc_init_field(_sysctl_size
, sizeof(struct sysctlnode
)),
241 .sysctl_name
= "(prog_root)",
244 int Aflag
, aflag
, dflag
, Mflag
, nflag
, qflag
, rflag
, wflag
, xflag
;
247 int req
, stale
, errs
;
248 FILE *warnfp
= stderr
;
251 * vah-riables n stuff
253 char gsname
[SYSCTL_NAMELEN
* CTL_MAXNAME
+ CTL_MAXNAME
],
254 canonname
[SYSCTL_NAMELEN
* CTL_MAXNAME
+ CTL_MAXNAME
],
255 gdname
[10 * CTL_MAXNAME
+ CTL_MAXNAME
];
257 const char *eq
= " = ";
258 const char *lname
[] = {
259 "top", "second", "third", "fourth", "fifth", "sixth",
260 "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth"
264 * you've heard of main, haven't you?
267 main(int argc
, char *argv
[])
269 int name
[CTL_MAXNAME
];
272 while ((ch
= getopt(argc
, argv
, "Aabdef:Mnqrwx")) != -1) {
299 case 'b': /* FreeBSD compat */
321 /* if ((xflag || rflag) && wflag)
323 /* if (aflag && Mflag)
325 if ((Aflag
|| Mflag
|| dflag
) && argc
== 0 && fn
== NULL
)
333 print_tree(&name
[0], 0, NULL
, CTLTYPE_NODE
, 1);
347 while ((l
= fparseln(fp
, NULL
, &nr
, NULL
, 0)) != NULL
)
369 * ********************************************************************
370 * how to find someone special to handle the reading (or maybe even
371 * writing) of a particular node
372 * ********************************************************************
374 static const struct handlespec
*
375 findhandler(const char *s
, int w
)
377 const struct handlespec
*p
;
385 for (i
= 0; p
[i
].ps_re
!= NULL
; i
++) {
386 j
= regcomp(&re
, p
[i
].ps_re
, REG_EXTENDED
);
388 regerror(j
, &re
, eb
, sizeof(eb
));
389 errx(1, "regcomp: %s: %s", p
[i
].ps_re
, eb
);
391 j
= regexec(&re
, s
, 1, match
, 0);
393 if (match
[0].rm_so
== 0 && match
[0].rm_eo
== l
&&
394 (w
? p
[i
].ps_w
: p
[i
].ps_p
) != NULL
) {
399 else if (j
!= REG_NOMATCH
) {
400 regerror(j
, &re
, eb
, sizeof(eb
));
401 errx(1, "regexec: %s: %s", p
[i
].ps_re
, eb
);
410 * after sysctlgetmibinfo is done with the name, we convert all
411 * separators to / and stuff one at the front if it was missing
414 canonicalize(const char *i
, char *o
)
417 char p
[SYSCTL_NAMELEN
+ 1];
430 t
= strchr(i
, sep
[0]);
445 * ********************************************************************
446 * convert this special number to a special string so we can print the
448 * ********************************************************************
459 #define print_flag(_f, _s, _c, _q, _x) \
460 if (((_f) & (__CONCAT(CTLFLAG_,_x))) == (__CONCAT(CTLFLAG_,_q))) { \
461 strlcat((_s), (_c), sizeof(_s)); \
462 strlcat((_s), __STRING(_q), sizeof(_s)); \
464 (_f) &= ~(__CONCAT(CTLFLAG_,_x)); \
466 print_flag(f
, s
, c
, READONLY
, READWRITE
);
467 print_flag(f
, s
, c
, READWRITE
, READWRITE
);
468 print_flag(f
, s
, c
, ANYWRITE
, ANYWRITE
);
469 print_flag(f
, s
, c
, PRIVATE
, PRIVATE
);
470 print_flag(f
, s
, c
, PERMANENT
, PERMANENT
);
471 print_flag(f
, s
, c
, OWNDATA
, OWNDATA
);
472 print_flag(f
, s
, c
, IMMEDIATE
, IMMEDIATE
);
473 print_flag(f
, s
, c
, HEX
, HEX
);
474 print_flag(f
, s
, c
, ROOT
, ROOT
);
475 print_flag(f
, s
, c
, ANYNUMBER
, ANYNUMBER
);
476 print_flag(f
, s
, c
, HIDDEN
, HIDDEN
);
477 print_flag(f
, s
, c
, ALIAS
, ALIAS
);
482 snprintf(foo
, sizeof(foo
), "%x", f
);
483 strlcat(s
, c
, sizeof(s
));
484 strlcat(s
, foo
, sizeof(s
));
511 * ********************************************************************
512 * recursively eliminate all data belonging to the given node
513 * ********************************************************************
516 purge_tree(struct sysctlnode
*rnode
)
518 struct sysctlnode
*node
;
521 SYSCTL_TYPE(rnode
->sysctl_flags
) != CTLTYPE_NODE
||
522 rnode
->sysctl_child
== NULL
)
525 for (node
= rnode
->sysctl_child
;
526 node
< &rnode
->sysctl_child
[rnode
->sysctl_clen
];
529 free(rnode
->sysctl_child
);
530 rnode
->sysctl_csize
= 0;
531 rnode
->sysctl_clen
= 0;
532 rnode
->sysctl_child
= NULL
;
534 if (rnode
->sysctl_desc
== (const char*)-1)
535 rnode
->sysctl_desc
= NULL
;
536 if (rnode
->sysctl_desc
!= NULL
)
537 free(__UNCONST(rnode
->sysctl_desc
));
538 rnode
->sysctl_desc
= NULL
;
542 * ********************************************************************
543 * print this node and any others underneath it
544 * ********************************************************************
547 print_tree(int *name
, u_int namelen
, struct sysctlnode
*pnode
, u_int type
,
550 struct sysctlnode
*node
;
553 char *sp
, *dp
, n
[20];
554 const struct handlespec
*p
;
556 sp
= &gsname
[strlen(gsname
)];
557 dp
= &gdname
[strlen(gdname
)];
559 if (sp
!= &gsname
[0] && dp
== &gdname
[0]) {
561 * aw...shucks. now we must play catch up
563 for (ni
= 0; ni
< namelen
; ni
++) {
564 (void)snprintf(n
, sizeof(n
), "%d", name
[ni
]);
566 strncat(gdname
, ".", sizeof(gdname
));
567 strncat(gdname
, n
, sizeof(gdname
));
574 snprintf(n
, sizeof(n
), "%d", pnode
->sysctl_num
);
576 strncat(gsname
, sep
, sizeof(gsname
));
577 strncat(gdname
, ".", sizeof(gdname
));
579 strncat(gsname
, pnode
->sysctl_name
, sizeof(gsname
));
580 strncat(gdname
, n
, sizeof(gdname
));
583 if (Mflag
&& pnode
!= &my_root
) {
585 printf("%s: ", gdname
);
587 printf("%s (%s): ", gsname
, gdname
);
588 printf("CTLTYPE_%s", st(type
));
589 if (type
== CTLTYPE_NODE
) {
590 if (SYSCTL_FLAGS(pnode
->sysctl_flags
) & CTLFLAG_ALIAS
)
592 pnode
->sysctl_alias
);
594 printf(", children %d/%d",
596 pnode
->sysctl_csize
);
598 printf(", size %zu", pnode
->sysctl_size
);
599 printf(", flags 0x%x<%s>",
600 SYSCTL_FLAGS(pnode
->sysctl_flags
),
601 sf(SYSCTL_FLAGS(pnode
->sysctl_flags
)));
602 if (pnode
->sysctl_func
)
603 printf(", func=%p", pnode
->sysctl_func
);
604 printf(", ver=%d", pnode
->sysctl_ver
);
606 if (type
!= CTLTYPE_NODE
) {
612 if (dflag
&& pnode
!= &my_root
) {
613 if (Aflag
|| type
!= CTLTYPE_NODE
) {
614 if (pnode
->sysctl_desc
== NULL
)
615 getdesc1(name
, namelen
, pnode
);
617 (pnode
->sysctl_desc
!= NULL
&&
618 pnode
->sysctl_desc
!= (const char*)-1)) {
620 printf("%s: ", gsname
);
621 if (pnode
->sysctl_desc
== NULL
||
622 pnode
->sysctl_desc
== (const char*)-1)
623 printf("(no description)\n");
625 printf("%s\n", pnode
->sysctl_desc
);
629 if (type
!= CTLTYPE_NODE
) {
636 * if this is an alias and we added our name, that means we
637 * got here by recursing down into the tree, so skip it. The
638 * only way to print an aliased node is with either -M or by
641 if (SYSCTL_FLAGS(pnode
->sysctl_flags
) & CTLFLAG_ALIAS
&& add
) {
646 canonicalize(gsname
, canonname
);
647 p
= findhandler(canonname
, 0);
648 if (type
!= CTLTYPE_NODE
&& p
!= NULL
) {
649 (*p
->ps_p
)(gsname
, gdname
, NULL
, name
, namelen
, pnode
, type
,
655 if (type
!= CTLTYPE_NODE
&& pnode
->sysctl_size
== 0) {
656 rc
= sysctl(&name
[0], namelen
, NULL
, &sz
, NULL
, 0);
663 if ((Aflag
|| req
) && !Mflag
)
664 printf("%s: node contains no data\n", gsname
);
670 sz
= pnode
->sysctl_size
;
674 __learn_tree(name
, namelen
, pnode
);
675 node
= pnode
->sysctl_child
;
680 (*p
->ps_p
)(gsname
, gdname
, NULL
, name
, namelen
,
681 pnode
, type
, __UNCONST(p
->ps_d
));
682 else if ((Aflag
|| req
) && !Mflag
)
683 printf("%s: no children\n", gsname
);
688 * get all descriptions for next level
691 getdesc(name
, namelen
, pnode
);
693 for (ni
= 0; ni
< pnode
->sysctl_clen
; ni
++) {
694 name
[namelen
] = node
[ni
].sysctl_num
;
695 if ((node
[ni
].sysctl_flags
& CTLFLAG_HIDDEN
) &&
698 print_tree(name
, namelen
+ 1, &node
[ni
],
699 SYSCTL_TYPE(node
[ni
].sysctl_flags
),
707 rc
= sysctl(name
, namelen
, &i
, &sz
, NULL
, 0);
712 display_number(pnode
, gsname
, &i
, sizeof(i
), DISPLAY_VALUE
);
715 case CTLTYPE_STRING
: {
716 unsigned char buf
[1024], *tbuf
;
719 rc
= sysctl(&name
[0], namelen
, tbuf
, &sz
, NULL
, 0);
720 if (rc
== -1 && errno
== ENOMEM
) {
726 rc
= sysctl(&name
[0], namelen
, tbuf
, &sz
, NULL
, 0);
731 display_string(pnode
, gsname
, tbuf
, sz
, DISPLAY_VALUE
);
739 rc
= sysctl(&name
[0], namelen
, &q
, &sz
, NULL
, 0);
744 display_number(pnode
, gsname
, &q
, sizeof(q
), DISPLAY_VALUE
);
747 case CTLTYPE_STRUCT
: {
749 * we shouldn't actually get here, but if we
750 * do, would it be nice to have *something* to
751 * do other than completely ignore the
755 if ((d
= malloc(sz
)) == NULL
) {
756 fprintf(warnfp
, "%s: !malloc failed!\n", gsname
);
759 rc
= sysctl(&name
[0], namelen
, d
, &sz
, NULL
, 0);
764 display_struct(pnode
, gsname
, d
, sz
, DISPLAY_VALUE
);
769 /* should i print an error here? */
777 * ********************************************************************
778 * parse a request, possibly determining that it's a create or destroy
780 * ********************************************************************
785 struct sysctlnode
*node
;
786 const struct handlespec
*w
;
787 int name
[CTL_MAXNAME
], dodesc
= 0;
789 char *key
, *value
, *dot
;
791 bool optional
= false;
796 if ((value
= strchr(l
, '=')) != NULL
) {
797 if (value
> l
&& value
[-1] == '?') {
804 if ((dot
= strpbrk(key
, "./")) == NULL
)
810 while (key
[0] == sep
[0] && key
[1] == sep
[0]) {
813 if (strncmp(key
+ 2, "create", 6) == 0 &&
814 (key
[8] == '=' || key
[8] == sep
[0]))
815 parse_create(key
+ 8 + (key
[8] == '=' ? 1 : 0));
816 else if (strncmp(key
+ 2, "destroy", 7) == 0 &&
817 (key
[9] == '=' || key
[9] == sep
[0]))
818 parse_destroy(key
+ 9 + (key
[9] == '=' ? 1 : 0));
819 else if (strncmp(key
+ 2, "describe", 8) == 0 &&
820 (key
[10] == '=' || key
[10] == sep
[0])) {
821 key
+= 10 + (key
[10] == '=');
822 if ((value
= strchr(key
, '=')) != NULL
)
831 sysctlperror("unable to parse '%s'\n", key
);
836 purge_tree(&my_root
);
840 namelen
= CTL_MAXNAME
;
843 if (sysctlgetmibinfo(key
, &name
[0], &namelen
, gsname
, &sz
, &node
,
844 SYSCTL_VERSION
) == -1) {
847 sysctlparseerror(namelen
, l
);
851 type
= SYSCTL_TYPE(node
->sysctl_flags
);
856 print_tree(&name
[0], namelen
, node
, type
, 0);
864 trim_whitespace(value
, 1);
867 sysctlperror("Must specify -w to set variables\n");
871 canonicalize(gsname
, canonname
);
872 if (type
!= CTLTYPE_NODE
&& (w
= findhandler(canonname
, 1)) != NULL
) {
873 (*w
->ps_w
)(gsname
, gdname
, value
, name
, namelen
, node
, type
,
882 * XXX old behavior is to print. should we error instead?
884 print_tree(&name
[0], namelen
, node
, CTLTYPE_NODE
, 1);
887 write_number(&name
[0], namelen
, node
, value
);
890 write_string(&name
[0], namelen
, node
, value
);
893 write_number(&name
[0], namelen
, node
, value
);
897 * XXX old behavior is to print. should we error instead?
899 /* fprintf(warnfp, "you can't write to %s\n", gsname); */
900 print_tree(&name
[0], namelen
, node
, type
, 0);
907 //create=foo.bar.whatever...,
908 [type=(int|quad|string|struct|node),]
911 [flags=(iohxparw12),]
912 [addr=0x####,|symbol=...|value=...]
914 size is optional for some types. type must be set before anything
915 else. nodes can have [rwhp], but nothing else applies. if no
916 size or type is given, node is asserted. writeable is the default,
917 with [rw] being read-only and unconditionally writeable
918 respectively. if you specify addr, it is assumed to be the name of
919 a kernel symbol, if value, CTLFLAG_OWNDATA will be asserted for
920 strings, CTLFLAG_IMMEDIATE for ints and u_quad_ts. you cannot
921 specify both value and addr.
926 parse_create(char *l
)
928 struct sysctlnode node
;
930 char *nname
, *key
, *value
, *data
, *addr
, *c
, *t
;
931 int name
[CTL_MAXNAME
], i
, rc
, method
, flags
, rw
;
937 sysctlperror("Must specify -w to create nodes\n");
942 * these are the pieces that make up the description of a new
945 memset(&node
, 0, sizeof(node
));
946 node
.sysctl_num
= CTL_CREATE
; /* any number is fine */
952 memset(name
, 0, sizeof(name
));
957 * misc stuff used when constructing
965 * the name of the thing we're trying to create is first, so
969 if ((c
= strchr(nname
, ',')) != NULL
)
975 * pull off the next "key=value" pair
978 if ((t
= strchr(key
, '=')) != NULL
) {
986 * if the "key" is "value", then that eats the rest of
987 * the string, so we're done, otherwise bite it off at
990 if (strcmp(key
, "value") == 0) {
996 if ((c
= strchr(value
, ',')) != NULL
)
1001 * note that we (mostly) let the invoker of sysctl(8)
1002 * play rampant here and depend on the kernel to tell
1003 * them that they were wrong. well...within reason.
1004 * we later check the various parameters against each
1005 * other to make sure it makes some sort of sense.
1007 if (strcmp(key
, "addr") == 0) {
1009 * we can't check these two. only the kernel
1010 * can tell us when it fails to find the name
1011 * (or if the address is invalid).
1015 "%s: already have %s for new node\n",
1017 method
== CTL_CREATE
? "addr" : "symbol");
1020 if (value
== NULL
) {
1021 sysctlperror("%s: missing value\n", nname
);
1025 addr
= (void*)strtoul(value
, &t
, 0);
1026 if (t
== value
|| *t
!= '\0' || errno
!= 0) {
1028 "%s: '%s' is not a valid address\n",
1032 method
= CTL_CREATE
;
1034 else if (strcmp(key
, "symbol") == 0) {
1037 "%s: already have %s for new node\n",
1039 method
== CTL_CREATE
? "addr" : "symbol");
1043 method
= CTL_CREATESYM
;
1045 else if (strcmp(key
, "type") == 0) {
1046 if (value
== NULL
) {
1047 sysctlperror("%s: missing value\n", nname
);
1050 if (strcmp(value
, "node") == 0)
1051 type
= CTLTYPE_NODE
;
1052 else if (strcmp(value
, "int") == 0) {
1056 else if (strcmp(value
, "string") == 0)
1057 type
= CTLTYPE_STRING
;
1058 else if (strcmp(value
, "quad") == 0) {
1059 sz
= sizeof(u_quad_t
);
1060 type
= CTLTYPE_QUAD
;
1062 else if (strcmp(value
, "struct") == 0)
1063 type
= CTLTYPE_STRUCT
;
1066 "%s: '%s' is not a valid type\n",
1071 else if (strcmp(key
, "size") == 0) {
1072 if (value
== NULL
) {
1073 sysctlperror("%s: missing value\n", nname
);
1078 * yes, i know size_t is not an unsigned long,
1079 * but we can all agree that it ought to be,
1082 sz
= strtoul(value
, &t
, 0);
1083 if (t
== value
|| *t
!= '\0' || errno
!= 0) {
1085 "%s: '%s' is not a valid size\n",
1090 else if (strcmp(key
, "n") == 0) {
1091 if (value
== NULL
) {
1092 sysctlperror("%s: missing value\n", nname
);
1096 q
= strtoll(value
, &t
, 0);
1097 if (t
== value
|| *t
!= '\0' || errno
!= 0 ||
1098 q
< INT_MIN
|| q
> UINT_MAX
) {
1100 "%s: '%s' is not a valid mib number\n",
1104 node
.sysctl_num
= (int)q
;
1106 else if (strcmp(key
, "flags") == 0) {
1107 if (value
== NULL
) {
1108 sysctlperror("%s: missing value\n", nname
);
1112 while (*t
!= '\0') {
1115 flags
|= CTLFLAG_ANYWRITE
;
1118 flags
|= CTLFLAG_HIDDEN
;
1121 flags
|= CTLFLAG_IMMEDIATE
;
1124 flags
|= CTLFLAG_OWNDATA
;
1127 flags
|= CTLFLAG_PRIVATE
;
1130 flags
|= CTLFLAG_HEX
;
1134 rw
= CTLFLAG_READONLY
;
1137 rw
= CTLFLAG_READWRITE
;
1141 "%s: '%c' is not a valid flag\n",
1149 sysctlperror("%s: unrecognized keyword '%s'\n",
1156 * now that we've finished parsing the given string, fill in
1157 * anything they didn't specify
1160 type
= CTLTYPE_NODE
;
1163 * the "data" can be interpreted various ways depending on the
1164 * type of node we're creating, as can the size
1169 "%s: cannot specify both value and "
1170 "address\n", nname
);
1177 q
= strtoll(data
, &t
, 0);
1178 if (t
== data
|| *t
!= '\0' || errno
!= 0 ||
1179 q
< INT_MIN
|| q
> UINT_MAX
) {
1181 "%s: '%s' is not a valid integer\n",
1186 if (!(flags
& CTLFLAG_OWNDATA
)) {
1187 flags
|= CTLFLAG_IMMEDIATE
;
1188 node
.sysctl_idata
= i
;
1191 node
.sysctl_data
= &i
;
1195 case CTLTYPE_STRING
:
1196 flags
|= CTLFLAG_OWNDATA
;
1197 node
.sysctl_data
= data
;
1199 sz
= strlen(data
) + 1;
1200 else if (sz
< strlen(data
) + 1) {
1201 sysctlperror("%s: ignoring size=%zu for "
1202 "string node, too small for given "
1203 "value\n", nname
, sz
);
1204 sz
= strlen(data
) + 1;
1209 uq
= strtouq(data
, &t
, 0);
1210 if (t
== data
|| *t
!= '\0' || errno
!= 0) {
1212 "%s: '%s' is not a valid quad\n",
1216 if (!(flags
& CTLFLAG_OWNDATA
)) {
1217 flags
|= CTLFLAG_IMMEDIATE
;
1218 node
.sysctl_qdata
= uq
;
1221 node
.sysctl_data
= &uq
;
1223 sz
= sizeof(u_quad_t
);
1225 case CTLTYPE_STRUCT
:
1226 sysctlperror("%s: struct not initializable\n",
1232 * these methods have all provided local starting
1233 * values that the kernel must copy in
1238 * hmm...no data, but we have an address of data. that's
1242 node
.sysctl_data
= (void*)addr
;
1245 * no data and no address? well...okay. we might be able to
1248 else if (type
!= CTLTYPE_NODE
) {
1251 "%s: need a size or a starting value\n",
1255 if (!(flags
& CTLFLAG_IMMEDIATE
))
1256 flags
|= CTLFLAG_OWNDATA
;
1260 * now we do a few sanity checks on the description we've
1263 if ((flags
& CTLFLAG_IMMEDIATE
) &&
1264 (type
== CTLTYPE_STRING
|| type
== CTLTYPE_STRUCT
)) {
1265 sysctlperror("%s: cannot make an immediate %s\n",
1267 (type
== CTLTYPE_STRING
) ? "string" : "struct");
1270 if (type
== CTLTYPE_NODE
&& node
.sysctl_data
!= NULL
) {
1271 sysctlperror("%s: nodes do not have data\n", nname
);
1276 * some types must have a particular size
1279 if ((type
== CTLTYPE_INT
&& sz
!= sizeof(int)) ||
1280 (type
== CTLTYPE_QUAD
&& sz
!= sizeof(u_quad_t
)) ||
1281 (type
== CTLTYPE_NODE
&& sz
!= 0)) {
1282 sysctlperror("%s: wrong size for type\n", nname
);
1286 else if (type
== CTLTYPE_STRUCT
) {
1287 sysctlperror("%s: struct must have size\n", nname
);
1292 * now...if no one said anything yet, we default nodes or
1293 * any type that owns data being writeable, and everything
1294 * else being readonly.
1297 if (type
== CTLTYPE_NODE
||
1298 (flags
& (CTLFLAG_OWNDATA
|CTLFLAG_IMMEDIATE
)))
1299 rw
= CTLFLAG_READWRITE
;
1301 rw
= CTLFLAG_READONLY
;
1305 * if a kernel address was specified, that can't be made
1307 if (rw != CTLFLAG_READONLY && addr) {
1308 sysctlperror("%s: kernel data can only be readable\n", nname);
1314 * what separator were they using in the full name of the new
1317 if ((t
= strpbrk(nname
, "./")) == NULL
)
1324 * put it all together, now. t'ain't much, is it?
1326 node
.sysctl_flags
= SYSCTL_VERSION
|flags
|rw
|type
;
1327 node
.sysctl_size
= sz
;
1328 t
= strrchr(nname
, sep
[0]);
1330 strlcpy(node
.sysctl_name
, t
+ 1, sizeof(node
.sysctl_name
));
1332 strlcpy(node
.sysctl_name
, nname
, sizeof(node
.sysctl_name
));
1337 * if this is a new top-level node, then we don't need to find
1338 * the mib for its parent
1346 * on the other hand, if it's not a top-level node...
1349 namelen
= sizeof(name
) / sizeof(name
[0]);
1350 sz
= sizeof(gsname
);
1352 rc
= sysctlgetmibinfo(nname
, &name
[0], &namelen
,
1353 gsname
, &sz
, NULL
, SYSCTL_VERSION
);
1356 sysctlparseerror(namelen
, nname
);
1362 * yes, a new node is being created
1365 name
[namelen
++] = method
;
1367 name
[namelen
++] = CTL_CREATE
;
1370 rc
= sysctl(&name
[0], namelen
, &node
, &sz
, &node
, sizeof(node
));
1373 sysctlperror("%s: CTL_CREATE failed: %s\n",
1374 nname
, strerror(errno
));
1378 if (!qflag
&& !nflag
)
1379 printf("%s(%s): (created)\n", nname
, st(type
));
1385 parse_destroy(char *l
)
1387 struct sysctlnode node
;
1389 int name
[CTL_MAXNAME
], rc
;
1393 sysctlperror("Must specify -w to destroy nodes\n");
1397 memset(name
, 0, sizeof(name
));
1398 namelen
= sizeof(name
) / sizeof(name
[0]);
1399 sz
= sizeof(gsname
);
1400 rc
= sysctlgetmibinfo(l
, &name
[0], &namelen
, gsname
, &sz
, NULL
,
1403 sysctlparseerror(namelen
, l
);
1407 memset(&node
, 0, sizeof(node
));
1408 node
.sysctl_flags
= SYSCTL_VERSION
;
1409 node
.sysctl_num
= name
[namelen
- 1];
1410 name
[namelen
- 1] = CTL_DESTROY
;
1413 rc
= sysctl(&name
[0], namelen
, &node
, &sz
, &node
, sizeof(node
));
1416 sysctlperror("%s: CTL_DESTROY failed: %s\n",
1417 l
, strerror(errno
));
1421 if (!qflag
&& !nflag
)
1422 printf("%s(%s): (destroyed)\n", gsname
,
1423 st(SYSCTL_TYPE(node
.sysctl_flags
)));
1429 parse_describe(char *l
)
1431 struct sysctlnode newdesc
;
1432 char buf
[1024], *value
;
1433 struct sysctldesc
*d
= (void*)&buf
[0];
1434 int name
[CTL_MAXNAME
], rc
;
1439 sysctlperror("Must specify -w to set descriptions\n");
1443 value
= strchr(l
, '=');
1446 memset(name
, 0, sizeof(name
));
1447 namelen
= sizeof(name
) / sizeof(name
[0]);
1448 sz
= sizeof(gsname
);
1449 rc
= sysctlgetmibinfo(l
, &name
[0], &namelen
, gsname
, &sz
, NULL
,
1452 sysctlparseerror(namelen
, l
);
1457 memset(&newdesc
, 0, sizeof(newdesc
));
1458 newdesc
.sysctl_flags
= SYSCTL_VERSION
|CTLFLAG_OWNDESC
;
1459 newdesc
.sysctl_num
= name
[namelen
- 1];
1460 newdesc
.sysctl_desc
= value
;
1461 name
[namelen
- 1] = CTL_DESCRIBE
;
1462 rc
= sysctl(name
, namelen
, d
, &sz
, &newdesc
, sizeof(newdesc
));
1464 sysctlperror("%s: CTL_DESCRIBE failed: %s\n",
1465 gsname
, strerror(errno
));
1466 else if (d
->descr_len
== 1)
1467 sysctlperror("%s: description not set\n", gsname
);
1468 else if (!qflag
&& !nflag
)
1469 printf("%s: %s\n", gsname
, d
->descr_str
);
1473 * ********************************************************************
1474 * when things go wrong...
1475 * ********************************************************************
1480 const char *progname
= getprogname();
1482 (void)fprintf(stderr
,
1489 progname
, "[-dne] [-x[x]|-r] variable ...",
1490 progname
, "[-ne] [-q] -w variable=value ...",
1491 progname
, "[-dne] -a",
1492 progname
, "[-dne] -A",
1493 progname
, "[-ne] -M",
1494 progname
, "[-dne] [-q] -f file");
1499 getdesc1(int *name
, u_int namelen
, struct sysctlnode
*pnode
)
1501 struct sysctlnode node
;
1502 char buf
[1024], *desc
;
1503 struct sysctldesc
*d
= (void*)buf
;
1504 size_t sz
= sizeof(buf
);
1507 memset(&node
, 0, sizeof(node
));
1508 node
.sysctl_flags
= SYSCTL_VERSION
;
1509 node
.sysctl_num
= name
[namelen
- 1];
1510 name
[namelen
- 1] = CTL_DESCRIBE
;
1511 rc
= sysctl(name
, namelen
, d
, &sz
, &node
, sizeof(node
));
1514 d
->descr_len
== 1 ||
1515 d
->descr_num
!= pnode
->sysctl_num
||
1516 d
->descr_ver
!= pnode
->sysctl_ver
)
1519 desc
= malloc(d
->descr_len
);
1523 if (desc
!= (char *)-1)
1524 memcpy(desc
, &d
->descr_str
[0], d
->descr_len
);
1525 name
[namelen
- 1] = node
.sysctl_num
;
1526 if (pnode
->sysctl_desc
!= NULL
&&
1527 pnode
->sysctl_desc
!= (const char *)-1)
1528 free(__UNCONST(pnode
->sysctl_desc
));
1529 pnode
->sysctl_desc
= desc
;
1533 getdesc(int *name
, u_int namelen
, struct sysctlnode
*pnode
)
1535 struct sysctlnode
*node
= pnode
->sysctl_child
;
1536 struct sysctldesc
*d
, *p
, *plim
;
1541 sz
= 128 * pnode
->sysctl_clen
;
1542 name
[namelen
] = CTL_DESCRIBE
;
1545 * attempt *twice* to get the description chunk. if two tries
1546 * doesn't work, give up.
1553 rc
= sysctl(name
, namelen
+ 1, d
, &sz
, NULL
, 0);
1557 if (i
== 0 && errno
== ENOMEM
)
1562 } while (d
== NULL
);
1565 * hokey nested loop here, giving O(n**2) behavior, but should
1568 plim
= /*LINTED ptr cast*/(struct sysctldesc
*)((char*)d
+ sz
);
1569 for (i
= 0; i
< pnode
->sysctl_clen
; i
++) {
1570 node
= &pnode
->sysctl_child
[i
];
1571 for (p
= d
; p
< plim
; p
= NEXT_DESCR(p
))
1572 if (node
->sysctl_num
== p
->descr_num
)
1574 if (p
< plim
&& node
->sysctl_ver
== p
->descr_ver
) {
1576 * match found, attempt to attach description
1578 if (p
->descr_len
== 1)
1581 desc
= malloc(p
->descr_len
);
1585 memcpy(desc
, &p
->descr_str
[0], p
->descr_len
);
1586 node
->sysctl_desc
= desc
;
1594 trim_whitespace(char *s
, int dir
)
1600 while (isspace((unsigned char)*i
))
1602 while ((*o
++ = *i
++) != '\0');
1603 o
-= 2; /* already past nul, skip back to before it */
1605 while (o
> s
&& isspace((unsigned char)*o
))
1610 sysctlerror(int soft
)
1619 case EPROTONOSUPPORT
:
1621 sysctlperror("%s: the value is not available\n",
1627 sysctlperror("%s: sysctl() failed with %s\n",
1628 gsname
, strerror(errno
));
1634 sysctlparseerror(u_int namelen
, const char *pname
)
1637 sysctlperror("%s level name '%s' in '%s' is invalid\n",
1638 lname
[namelen
], gsname
, pname
);
1642 sysctlperror(const char *fmt
, ...)
1646 (void)fprintf(warnfp
, "%s: ", getprogname());
1648 (void)fprintf(warnfp
, "%s#%zu: ", fn
, nr
);
1650 (void)vfprintf(warnfp
, fmt
, ap
);
1657 * ********************************************************************
1658 * how to write to a "simple" node
1659 * ********************************************************************
1662 write_number(int *name
, u_int namelen
, struct sysctlnode
*node
, char *value
)
1672 trim_whitespace(value
, 3);
1677 qi
= strtouq(value
, &t
, 0);
1678 if (qi
== UQUAD_MAX
&& errno
== ERANGE
) {
1679 sysctlperror("%s: %s\n", value
, strerror(errno
));
1682 if (t
== value
|| *t
!= '\0') {
1683 sysctlperror("%s: not a number\n", value
);
1687 switch (SYSCTL_TYPE(node
->sysctl_flags
)) {
1690 io
= (u_int
)(qi
>> 32);
1691 if (io
!= (u_int
)-1 && io
!= 0) {
1692 sysctlperror("%s: %s\n", value
, strerror(ERANGE
));
1708 rc
= sysctl(name
, namelen
, o
, &so
, i
, si
);
1714 switch (SYSCTL_TYPE(node
->sysctl_flags
)) {
1716 display_number(node
, gsname
, &io
, sizeof(io
), DISPLAY_OLD
);
1717 display_number(node
, gsname
, &ii
, sizeof(ii
), DISPLAY_NEW
);
1720 display_number(node
, gsname
, &qo
, sizeof(qo
), DISPLAY_OLD
);
1721 display_number(node
, gsname
, &qi
, sizeof(qi
), DISPLAY_NEW
);
1727 write_string(int *name
, u_int namelen
, struct sysctlnode
*node
, char *value
)
1735 so
= node
->sysctl_size
;
1736 if (si
> so
&& so
!= 0) {
1737 sysctlperror("%s: string too long\n", value
);
1742 sysctlperror("%s: !malloc failed!\n", gsname
);
1746 rc
= sysctl(name
, namelen
, o
, &so
, i
, si
);
1752 display_string(node
, gsname
, o
, so
, DISPLAY_OLD
);
1753 display_string(node
, gsname
, i
, si
, DISPLAY_NEW
);
1758 * ********************************************************************
1759 * simple ways to print stuff consistently
1760 * ********************************************************************
1763 display_number(const struct sysctlnode
*node
, const char *name
,
1764 const void *data
, size_t sz
, int n
)
1771 if ((nflag
|| rflag
) && (n
== DISPLAY_OLD
))
1774 if (rflag
&& n
!= DISPLAY_OLD
) {
1775 fwrite(data
, sz
, 1, stdout
);
1780 if (n
== DISPLAY_VALUE
)
1781 printf("%s%s", name
, eq
);
1782 else if (n
== DISPLAY_OLD
)
1783 printf("%s: ", name
);
1787 if (n
!= DISPLAY_NEW
)
1793 switch (SYSCTL_TYPE(node
->sysctl_flags
)) {
1795 memcpy(&i
, data
, sz
);
1797 printf("0x%0*x", (int)sz
* 2, i
);
1798 else if (node
->sysctl_flags
& CTLFLAG_HEX
)
1804 memcpy(&q
, data
, sz
);
1806 printf("0x%0*" PRIx64
, (int)sz
* 2, q
);
1807 else if (node
->sysctl_flags
& CTLFLAG_HEX
)
1808 printf("%#" PRIx64
, q
);
1810 printf("%" PRIu64
, q
);
1814 if (n
== DISPLAY_OLD
)
1821 display_string(const struct sysctlnode
*node
, const char *name
,
1822 const void *data
, size_t sz
, int n
)
1824 const unsigned char *buf
= data
;
1829 if ((nflag
|| rflag
) && (n
== DISPLAY_OLD
))
1832 if (rflag
&& n
!= DISPLAY_OLD
) {
1833 fwrite(data
, sz
, 1, stdout
);
1838 if (n
== DISPLAY_VALUE
)
1839 printf("%s%s", name
, eq
);
1840 else if (n
== DISPLAY_OLD
)
1841 printf("%s: ", name
);
1845 if (n
!= DISPLAY_NEW
)
1851 if (xflag
|| node
->sysctl_flags
& CTLFLAG_HEX
) {
1852 for (ni
= 0; ni
< (int)sz
; ni
++) {
1854 printf("%02x", buf
[ni
]);
1855 if (buf
[ni
] == '\0')
1858 printf("\\x%2.2x", buf
[ni
]);
1862 printf("%.*s", (int)sz
, buf
);
1864 if (n
== DISPLAY_OLD
)
1872 display_struct(const struct sysctlnode
*node
, const char *name
,
1873 const void *data
, size_t sz
, int n
)
1875 const unsigned char *buf
= data
;
1881 if (!(xflag
|| rflag
)) {
1884 "%s: this type is unknown to this program\n",
1888 if ((nflag
|| rflag
) && (n
== DISPLAY_OLD
))
1891 if (rflag
&& n
!= DISPLAY_OLD
) {
1892 fwrite(data
, sz
, 1, stdout
);
1897 if (n
== DISPLAY_VALUE
)
1898 printf("%s%s", name
, eq
);
1899 else if (n
== DISPLAY_OLD
)
1900 printf("%s: ", name
);
1904 if (n
!= DISPLAY_NEW
)
1916 for (ni
= 0; ni
< (int)sz
; ni
++)
1917 printf("%02x", buf
[ni
]);
1919 printf("...(%zu more bytes)", more
);
1924 hex_dump(const unsigned char *buf
, size_t len
)
1928 char line
[80], tmp
[12];
1930 memset(line
, ' ', sizeof(line
));
1931 for (i
= 0, j
= 15; i
< len
; i
++) {
1938 snprintf(tmp
, sizeof(tmp
), "%07x", i
);
1939 memcpy(&line
[0], tmp
, 7);
1941 /* copy out hex version of byte */
1942 snprintf(tmp
, sizeof(tmp
), "%02x", buf
[i
]);
1943 memcpy(&line
[9 + j
* 3], tmp
, 2);
1944 /* copy out plain version of byte */
1945 line
[60 + j
] = (isprint(buf
[i
])) ? buf
[i
] : '.';
1946 /* print a full line and erase it */
1948 printf("%s\n", line
);
1949 memset(line
, ' ', sizeof(line
));
1953 printf("%s\n", line
);
1954 printf("%07zu bytes\n", len
);
1958 * ********************************************************************
1959 * functions that handle particular nodes
1960 * ********************************************************************
1964 printother(HANDLER_ARGS
)
1970 if (!(Aflag
|| req
) || Mflag
)
1974 * okay...you asked for it, so let's give it a go
1976 while (type
!= CTLTYPE_NODE
&& (xflag
|| rflag
)) {
1977 rc
= sysctl(name
, namelen
, NULL
, &sz1
, NULL
, 0);
1978 if (rc
== -1 || sz1
== 0)
1984 rc
= sysctl(name
, namelen
, p
, &sz2
, NULL
, 0);
1985 if (rc
== -1 || sz1
!= sz2
) {
1989 display_struct(pnode
, gsname
, p
, sz1
, DISPLAY_VALUE
);
1995 * that didn't work...do we have a specific message for this
1999 sysctlperror("%s: use '%s' to view this information\n",
2000 gsname
, (const char *)v
);
2005 * hmm...i wonder if we have any generic hints?
2009 sysctlperror("%s: use 'netstat' to view this information\n",
2013 sysctlperror("%s: missing 'options DEBUG' from kernel?\n",
2017 sysctlperror("%s: missing 'options DDB' from kernel?\n",
2021 sysctlperror("%s: no vendor extensions installed\n",
2029 kern_clockrate(HANDLER_ARGS
)
2031 struct clockinfo clkinfo
;
2035 sz
= sizeof(clkinfo
);
2036 rc
= sysctl(name
, namelen
, &clkinfo
, &sz
, NULL
, 0);
2041 if (sz
!= sizeof(clkinfo
))
2042 errx(1, "%s: !returned size wrong!", sname
);
2044 if (xflag
|| rflag
) {
2045 display_struct(pnode
, sname
, &clkinfo
, sz
,
2050 printf("%s: ", sname
);
2051 printf("tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
2052 clkinfo
.tick
, clkinfo
.tickadj
,
2053 clkinfo
.hz
, clkinfo
.profhz
, clkinfo
.stathz
);
2058 kern_boottime(HANDLER_ARGS
)
2060 struct timeval timeval
;
2065 sz
= sizeof(timeval
);
2066 rc
= sysctl(name
, namelen
, &timeval
, &sz
, NULL
, 0);
2071 if (sz
!= sizeof(timeval
))
2072 errx(1, "%s: !returned size wrong!", sname
);
2074 boottime
= timeval
.tv_sec
;
2076 display_struct(pnode
, sname
, &timeval
, sz
,
2079 /* ctime() provides the \n */
2080 printf("%s%s%s", sname
, eq
, ctime(&boottime
));
2081 else if (nflag
== 1)
2082 printf("%ld\n", (long)boottime
);
2084 printf("%ld.%06ld\n", (long)timeval
.tv_sec
,
2085 (long)timeval
.tv_usec
);
2090 kern_consdev(HANDLER_ARGS
)
2097 rc
= sysctl(name
, namelen
, &cons
, &sz
, NULL
, 0);
2102 if (sz
!= sizeof(cons
))
2103 errx(1, "%s: !returned size wrong!", sname
);
2106 display_struct(pnode
, sname
, &cons
, sz
,
2110 printf("%s%s", sname
, eq
);
2111 if (nflag
< 2 && (sname
= devname(cons
, S_IFCHR
)) != NULL
)
2112 printf("%s\n", sname
);
2114 printf("0x%llx\n", (unsigned long long)cons
);
2120 kern_cp_time(HANDLER_ARGS
)
2125 char s
[sizeof("kern.cp_time.nnnnnn")];
2129 * three things to do here.
2130 * case 1: get sum (no Aflag and namelen == 2)
2131 * case 2: get specific processor (namelen == 3)
2132 * case 3: get all processors (Aflag and namelen == 2)
2135 if (namelen
== 2 && Aflag
) {
2137 rc
= sysctlbyname("hw.ncpu", &n
, &sz
, NULL
, 0);
2139 return; /* XXX print an error, eh? */
2140 n
++; /* Add on space for the sum. */
2141 sz
= n
* sizeof(u_int64_t
) * CPUSTATES
;
2144 n
= -1; /* Just print one data set. */
2145 sz
= sizeof(u_int64_t
) * CPUSTATES
;
2148 cp_time
= malloc(sz
);
2149 if (cp_time
== NULL
) {
2155 rc
= sysctl(name
, namelen
, cp_time
+ (n
!= -1) * CPUSTATES
, &osz
,
2165 * Check, but account for space we'll occupy with the sum.
2167 if (osz
!= sz
- (n
!= -1) * CPUSTATES
* sizeof(u_int64_t
))
2168 errx(1, "%s: !returned size wrong!", sname
);
2171 * Compute the actual sum. Two calls would be easier (we
2172 * could just call ourselves recursively above), but the
2173 * numbers wouldn't add up.
2176 memset(cp_time
, 0, sizeof(u_int64_t
) * CPUSTATES
);
2177 for (i
= 1; i
< n
; i
++) {
2178 cp_time
[CP_USER
] += cp_time
[i
* CPUSTATES
+ CP_USER
];
2179 cp_time
[CP_NICE
] += cp_time
[i
* CPUSTATES
+ CP_NICE
];
2180 cp_time
[CP_SYS
] += cp_time
[i
* CPUSTATES
+ CP_SYS
];
2181 cp_time
[CP_INTR
] += cp_time
[i
* CPUSTATES
+ CP_INTR
];
2182 cp_time
[CP_IDLE
] += cp_time
[i
* CPUSTATES
+ CP_IDLE
];
2187 for (i
= 0; n
== -1 || i
< n
; i
++) {
2189 (void)snprintf(s
, sizeof(s
), "%s%s%d", sname
, sep
,
2194 display_struct(pnode
, tname
, cp_time
+ (i
* CPUSTATES
),
2195 sizeof(u_int64_t
) * CPUSTATES
,
2199 printf("%s: ", tname
);
2200 printf("user = %" PRIu64
2206 cp_time
[i
* CPUSTATES
+ CP_USER
],
2207 cp_time
[i
* CPUSTATES
+ CP_NICE
],
2208 cp_time
[i
* CPUSTATES
+ CP_SYS
],
2209 cp_time
[i
* CPUSTATES
+ CP_INTR
],
2210 cp_time
[i
* CPUSTATES
+ CP_IDLE
]);
2213 * Just printing the one node.
2224 kern_drivers(HANDLER_ARGS
)
2226 struct kinfo_drivers
*kd
;
2231 rc
= sysctl(name
, namelen
, NULL
, &sz
, NULL
, 0);
2237 if (sz
% sizeof(*kd
))
2238 err(1, "bad size %zu for kern.drivers", sz
);
2246 rc
= sysctl(name
, namelen
, kd
, &sz
, NULL
, 0);
2254 printf("%s%s", sname
, eq
);
2255 for (i
= 0, sz
/= sizeof(*kd
); i
< sz
; i
++) {
2256 (void)printf("%s[%d %d %s]", comma
, kd
[i
].d_cmajor
,
2257 kd
[i
].d_bmajor
, kd
[i
].d_name
);
2266 kern_cp_id(HANDLER_ARGS
)
2271 char s
[sizeof("kern.cp_id.nnnnnn")];
2273 struct sysctlnode node
= *pnode
;
2276 * three things to do here.
2277 * case 1: print a specific cpu id (namelen == 3)
2278 * case 2: print all cpu ids separately (Aflag set)
2279 * case 3: print all cpu ids on one line
2284 rc
= sysctlbyname("hw.ncpu", &n
, &sz
, NULL
, 0);
2286 return; /* XXX print an error, eh? */
2287 sz
= n
* sizeof(u_int64_t
);
2290 n
= -1; /* Just print one cpu id. */
2291 sz
= sizeof(u_int64_t
);
2295 if (cp_id
== NULL
) {
2301 rc
= sysctl(name
, namelen
, cp_id
, &osz
, NULL
, 0);
2309 * Check that we got back what we asked for.
2312 errx(1, "%s: !returned size wrong!", sname
);
2314 /* pretend for output purposes */
2315 node
.sysctl_flags
= SYSCTL_FLAGS(pnode
->sysctl_flags
) |
2316 SYSCTL_TYPE(CTLTYPE_QUAD
);
2320 display_number(&node
, tname
, cp_id
,
2324 for (i
= 0; i
< n
; i
++)
2325 (void)snprintf(s
, sizeof(s
), "%s%s%d", sname
, sep
, i
);
2327 display_number(&node
, tname
, &cp_id
[i
],
2333 display_struct(pnode
, tname
, cp_id
, sz
, DISPLAY_VALUE
);
2336 printf("%s: ", tname
);
2337 for (i
= 0; i
< n
; i
++) {
2340 printf("%d = %" PRIu64
, i
, cp_id
[i
]);
2351 vm_loadavg(HANDLER_ARGS
)
2353 struct loadavg loadavg
;
2357 sz
= sizeof(loadavg
);
2358 rc
= sysctl(name
, namelen
, &loadavg
, &sz
, NULL
, 0);
2363 if (sz
!= sizeof(loadavg
))
2364 errx(1, "%s: !returned size wrong!", sname
);
2366 if (xflag
|| rflag
) {
2367 display_struct(pnode
, sname
, &loadavg
, sz
,
2372 printf("%s: ", sname
);
2373 printf("%.2f %.2f %.2f\n",
2374 (double) loadavg
.ldavg
[0] / loadavg
.fscale
,
2375 (double) loadavg
.ldavg
[1] / loadavg
.fscale
,
2376 (double) loadavg
.ldavg
[2] / loadavg
.fscale
);
2381 proc_limit(HANDLER_ARGS
)
2383 u_quad_t olim
, *newp
, nlim
;
2389 trim_whitespace(value
, 3);
2392 if (value
!= NULL
) {
2395 if (strcmp(value
, "unlimited") == 0)
2396 nlim
= RLIM_INFINITY
;
2399 nlim
= strtouq(value
, &t
, 0);
2400 if (t
== value
|| *t
!= '\0' || errno
!= 0) {
2401 sysctlperror("%s: '%s' is not a valid limit\n",
2412 rc
= sysctl(name
, namelen
, &olim
, &osz
, newp
, nsz
);
2414 sysctlerror(newp
== NULL
);
2421 if (rflag
|| xflag
|| olim
!= RLIM_INFINITY
)
2422 display_number(pnode
, sname
, &olim
, sizeof(olim
),
2423 newp
? DISPLAY_OLD
: DISPLAY_VALUE
);
2425 display_string(pnode
, sname
, "unlimited", 10,
2426 newp
? DISPLAY_OLD
: DISPLAY_VALUE
);
2429 if (rflag
|| xflag
|| nlim
!= RLIM_INFINITY
)
2430 display_number(pnode
, sname
, &nlim
, sizeof(nlim
),
2433 display_string(pnode
, sname
, "unlimited", 10,
2441 machdep_diskinfo(HANDLER_ARGS
)
2443 struct disklist
*dl
;
2444 struct biosdisk_info
*bi
;
2445 struct nativedisk_info
*ni
;
2450 rc
= sysctl(name
, namelen
, NULL
, &sz
, NULL
, 0);
2460 rc
= sysctl(name
, namelen
, dl
, &sz
, NULL
, 0);
2467 printf("%s: ", sname
);
2468 lim
= dl
->dl_nbiosdisks
;
2469 if (lim
> MAX_BIOSDISKS
)
2470 lim
= MAX_BIOSDISKS
;
2471 for (bi
= dl
->dl_biosdisks
, i
= 0; i
< lim
; bi
++, i
++)
2472 printf("%x:%" PRIu64
"(%d/%d/%d),%x ",
2473 bi
->bi_dev
, bi
->bi_lbasecs
,
2474 bi
->bi_cyl
, bi
->bi_head
, bi
->bi_sec
,
2476 lim
= dl
->dl_nnativedisks
;
2477 ni
= dl
->dl_nativedisks
;
2478 bi
= dl
->dl_biosdisks
;
2479 /* LINTED -- pointer casts are tedious */
2480 if ((char *)&ni
[lim
] != (char *)dl
+ sz
) {
2481 sysctlperror("%s: size mismatch\n", gsname
);
2484 for (i
= 0; i
< lim
; ni
++, i
++) {
2486 printf(" %.*s", (int)sizeof ni
->ni_devname
,
2488 for (b
= 0; b
< (unsigned int)ni
->ni_nmatches
; t
= ',', b
++)
2490 bi
[ni
->ni_biosmatches
[b
]].bi_dev
);
2495 #endif /* CPU_DISKINFO */
2499 mode_bits(HANDLER_ARGS
)
2501 char buf
[12], outbuf
[100];
2502 int o
, m
, *newp
, rc
;
2507 trim_whitespace(value
, 3);
2511 if (value
!= NULL
) {
2514 size_t ttsz
= sizeof(tt
);
2520 rc
= sysctl(name
, namelen
, &tt
, &ttsz
, NULL
, 0);
2522 sysctlperror("%s: failed query\n", sname
);
2526 old_umask
= umask(0);
2527 foo
= setmode(value
);
2530 sysctlperror("%s: '%s' is an invalid mode\n", sname
,
2534 old_umask
= umask(0);
2535 m
= getmode(foo
, (mode_t
)tt
);
2538 sysctlperror("%s: '%s' is an invalid mode\n", sname
,
2548 rc
= sysctl(name
, namelen
, &o
, &osz
, newp
, nsz
);
2550 sysctlerror(newp
== NULL
);
2561 display_number(pnode
, sname
, &o
, sizeof(o
),
2562 newp
? DISPLAY_OLD
: DISPLAY_VALUE
);
2564 memset(buf
, 0, sizeof(buf
));
2566 rc
= snprintf(outbuf
, sizeof(outbuf
), "%04o (%s)", om
, buf
+ 1);
2567 display_string(pnode
, sname
, outbuf
, rc
, newp
? DISPLAY_OLD
: DISPLAY_VALUE
);
2572 display_number(pnode
, sname
, &m
, sizeof(m
),
2575 memset(buf
, 0, sizeof(buf
));
2577 rc
= snprintf(outbuf
, sizeof(outbuf
), "%04o (%s)", mm
, buf
+ 1);
2578 display_string(pnode
, sname
, outbuf
, rc
, DISPLAY_NEW
);