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