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