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