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