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