sysctl.c revision 1.82 1 /* $NetBSD: sysctl.c,v 1.82 2004/03/20 05:22:41 atatat 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.82 2004/03/20 05:22:41 atatat 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 <stdarg.h>
105 #include <stdio.h>
106 #include <stdlib.h>
107 #include <string.h>
108 #include <time.h>
109 #include <unistd.h>
110
111 /*
112 * this needs to be able to do the printing and the setting
113 */
114 #define HANDLER_PROTO const char *, const char *, char *, \
115 int *, u_int, const struct sysctlnode *, \
116 u_int, void *
117 #define HANDLER_ARGS const char *sname, const char *dname, char *value, \
118 int *name, u_int namelen, const struct sysctlnode *pnode, \
119 u_int type, void *v
120 #define DISPLAY_VALUE 0
121 #define DISPLAY_OLD 1
122 #define DISPLAY_NEW 2
123
124 /*
125 * generic routines
126 */
127 static struct handlespec *findprinter(const int *, u_int);
128 static struct handlespec *findwriter(const int *, u_int);
129 static void print_tree(int *, u_int, struct sysctlnode *, u_int, int);
130 static void write_number(int *, u_int, struct sysctlnode *, char *);
131 static void write_string(int *, u_int, struct sysctlnode *, char *);
132 static void display_number(const struct sysctlnode *, const char *,
133 const void *, size_t, int);
134 static void display_string(const struct sysctlnode *, const char *,
135 const void *, size_t, int);
136 static void display_struct(const struct sysctlnode *, const char *,
137 const void *, size_t, int);
138 static void hex_dump(const unsigned char *, size_t);
139 static void usage(void);
140 static void parse(char *);
141 static void parse_create(char *);
142 static void parse_destroy(char *);
143 static void sysctlerror(int);
144
145 /*
146 * unexported from some place else (XXX tbd)
147 */
148 int learn_tree(int *, u_int, struct sysctlnode *);
149 int sysctlbyname(const char *, void *, size_t *, void *, size_t);
150 int sysctlgetmibinfo(const char *, int *, u_int *,
151 char *, size_t *, struct sysctlnode **);
152
153 /*
154 * "handlers"
155 */
156 static void printother(HANDLER_PROTO);
157 static void kern_clockrate(HANDLER_PROTO);
158 static void kern_boottime(HANDLER_PROTO);
159 static void kern_consdev(HANDLER_PROTO);
160 static void kern_cp_time(HANDLER_PROTO);
161 static void vm_loadavg(HANDLER_PROTO);
162 static void proc_limit(HANDLER_PROTO);
163 #ifdef CPU_DISKINFO
164 static void machdep_diskinfo(HANDLER_PROTO);
165 #endif /* CPU_DISKINFO */
166
167 struct handlespec {
168 int ps_name[CTL_MAXNAME];
169 void (*ps_p)(HANDLER_PROTO);
170 void (*ps_w)(HANDLER_PROTO);
171 void *ps_d;
172 } handlers[] = {
173 { { CTL_KERN, KERN_CLOCKRATE }, kern_clockrate },
174 { { CTL_KERN, KERN_VNODE }, printother, NULL, "pstat" },
175 { { CTL_KERN, KERN_PROC }, printother, NULL, "ps" },
176 { { CTL_KERN, KERN_PROC2 }, printother, NULL, "ps" },
177 { { CTL_KERN, KERN_PROC_ARGS }, printother, NULL, "ps" },
178 { { CTL_KERN, KERN_FILE }, printother, NULL, "pstat" },
179 { { CTL_KERN, KERN_NTPTIME }, printother, NULL,
180 "ntpdc -c kerninfo" },
181 { { CTL_KERN, KERN_MSGBUF }, printother, NULL, "dmesg" },
182 { { CTL_KERN, KERN_BOOTTIME }, kern_boottime },
183 { { CTL_KERN, KERN_CONSDEV }, kern_consdev },
184 { { CTL_KERN, KERN_CP_TIME, -1 }, kern_cp_time },
185 { { CTL_KERN, KERN_CP_TIME }, kern_cp_time },
186 { { CTL_KERN, KERN_SYSVIPC_INFO }, printother, NULL, "ipcs" },
187 { { CTL_VM, VM_METER }, printother, NULL,
188 "vmstat' or 'systat" },
189 { { CTL_VM, VM_LOADAVG }, vm_loadavg },
190 { { CTL_VM, VM_UVMEXP }, printother, NULL,
191 "vmstat' or 'systat" },
192 { { CTL_VM, VM_UVMEXP2 }, printother, NULL,
193 "vmstat' or 'systat" },
194 { { CTL_VFS, 2 /* NFS */, NFS_NFSSTATS },
195 printother, NULL, "nfsstat" },
196 { { CTL_NET }, printother, NULL, NULL },
197 { { CTL_NET, PF_LOCAL }, printother, NULL, NULL },
198 { { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_IDENT },
199 printother, NULL, "identd" },
200 { { CTL_NET, PF_INET6, IPPROTO_TCP, TCPCTL_IDENT },
201 printother, NULL, "identd" },
202
203 { { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST },
204 printother, NULL, "ndp" },
205 { { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST },
206 printother, NULL, "ndp" },
207
208
209 { { CTL_NET, PF_KEY, KEYCTL_DUMPSA },
210 printother, NULL, "setkey" },
211 { { CTL_NET, PF_KEY, KEYCTL_DUMPSP },
212 printother, NULL, "setkey" },
213 /* { { CTL_DEBUG }, printother, NULL, NULL }, */
214 { { CTL_HW, HW_DISKSTATS }, printother, NULL, "iostat" },
215 #ifdef CPU_CONSDEV
216 { { CTL_MACHDEP, CPU_CONSDEV }, kern_consdev },
217 #endif /* CPU_CONSDEV */
218 #ifdef CPU_DISKINFO
219 { { CTL_MACHDEP, CPU_DISKINFO },machdep_diskinfo },
220 #endif /* CPU_CONSDEV */
221 { { CTL_DDB }, printother, NULL, NULL },
222 { { CTL_PROC, -1, PROC_PID_LIMIT, -1, -1 }, proc_limit, proc_limit },
223 { { CTL_UNSPEC }, },
224 };
225
226 struct sysctlnode my_root = {
227 #if defined(lint)
228 0
229 #else /* defined(lint) */
230 .sysctl_flags = SYSCTL_ROOT|
231 SYSCTL_TYPE(CTLTYPE_NODE),
232 .sysctl_size = sizeof(struct sysctlnode),
233 .sysctl_num = 0,
234 .sysctl_name = "(prog_root)",
235 #endif /* defined(lint) */
236 };
237
238 int Aflag, aflag, Mflag, nflag, qflag, rflag, wflag, xflag;
239 int req;
240 FILE *warnfp = stderr;
241
242 /*
243 * vah-riables n stuff
244 */
245 char gsname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME],
246 gdname[10 * CTL_MAXNAME + CTL_MAXNAME];
247 char sep[2] = ".", *eq = " = ";
248 const char *lname[] = {
249 "top", "second", "third", "fourth", "fifth", "sixth",
250 "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth"
251 };
252
253 /*
254 * you've heard of main, haven't you?
255 */
256 int
257 main(int argc, char *argv[])
258 {
259 char *fn = NULL;
260 int name[CTL_MAXNAME];
261 int ch;
262
263 while ((ch = getopt(argc, argv, "Aabef:Mnqrwx")) != -1) {
264 switch (ch) {
265 case 'A':
266 Aflag++;
267 break;
268 case 'a':
269 aflag++;
270 break;
271 case 'e':
272 eq = "=";
273 break;
274 case 'f':
275 fn = optarg;
276 wflag++;
277 break;
278 case 'M':
279 Mflag++;
280 break;
281 case 'n':
282 nflag++;
283 break;
284 case 'q':
285 qflag++;
286 break;
287 case 'b': /* FreeBSD compat */
288 case 'r':
289 rflag++;
290 break;
291 case 'w':
292 wflag++;
293 break;
294 case 'x':
295 xflag++;
296 break;
297 default:
298 usage();
299 }
300 }
301
302 argc -= optind;
303 argv += optind;
304
305 if (qflag && !wflag)
306 usage();
307 if (xflag && rflag)
308 usage();
309 /* if ((xflag || rflag) && wflag)
310 usage(); */
311 /* if (aflag && Mflag)
312 usage(); */
313 if ((Aflag || Mflag) && argc == 0 && fn == NULL)
314 aflag = 1;
315
316 if (Aflag)
317 warnfp = stdout;
318 req = 0;
319
320 if (aflag) {
321 print_tree(&name[0], 0, NULL, CTLTYPE_NODE, 1);
322 /* if (argc == 0) */
323 return (0);
324 }
325
326 if (fn) {
327 FILE *fp;
328 char *l;
329
330 fp = fopen(fn, "r");
331 if (fp == NULL) {
332 err(1, "%s", fn);
333 } else {
334 while ((l = fparseln(fp, NULL, NULL, NULL, 0)) != NULL)
335 {
336 if (*l) {
337 parse(l);
338 free(l);
339 }
340 }
341 fclose(fp);
342 }
343 return (0);
344 }
345
346 if (argc == 0)
347 usage();
348
349 while (argc-- > 0)
350 parse(*argv++);
351
352 return (0);
353 }
354
355 /*
356 * ********************************************************************
357 * how to find someone special to handle the reading (or maybe even
358 * writing) of a particular node
359 * ********************************************************************
360 */
361 static struct handlespec *
362 findprinter(const int *name, u_int namelen)
363 {
364 struct handlespec *p;
365 int i, j;
366
367 if (namelen < 1)
368 return (NULL);
369
370 p = &handlers[0];
371 for (i = 0; p[i].ps_name[0] != CTL_UNSPEC; i++) {
372 for (j = 0; j < namelen; j++)
373 if (p[i].ps_name[j] != name[j] &&
374 p[i].ps_name[j] != -1)
375 break;
376 if (j == namelen && p[i].ps_p != NULL)
377 return (&p[i]);
378 }
379
380 return (NULL);
381 }
382
383 static struct handlespec *
384 findwriter(const int *name, u_int namelen)
385 {
386 struct handlespec *p;
387 int i, j;
388
389 if (namelen < 1)
390 return (NULL);
391
392 p = &handlers[0];
393 for (i = 0; p[i].ps_name[0] != CTL_UNSPEC; i++) {
394 for (j = 0; j < namelen; j++)
395 if (p[i].ps_name[j] != name[j] &&
396 p[i].ps_name[j] != -1)
397 break;
398 if (j == namelen && p[i].ps_w != NULL)
399 return (&p[i]);
400 }
401
402 return (NULL);
403 }
404
405 /*
406 * ********************************************************************
407 * convert this special number to a special string so we can print the
408 * mib
409 * ********************************************************************
410 */
411 static const char *
412 sf(u_int f)
413 {
414 static char s[256];
415 char *c;
416
417 s[0] = '\0';
418 c = "";
419
420 #define print_flag(_f, _s, _c, _q, _x) \
421 if ((/*CONSTCOND*/_x) ? \
422 (((_f) & (_x)) == (__CONCAT(SYSCTL_,_q))) : \
423 ((_f) & (__CONCAT(SYSCTL_,_q)))) { \
424 strlcat((_s), (_c), sizeof(_s)); \
425 strlcat((_s), __STRING(_q), sizeof(_s)); \
426 (_c) = ","; \
427 (_f) &= ~(__CONCAT(SYSCTL_,_q)|(_x)); \
428 }
429 print_flag(f, s, c, READONLY, SYSCTL_READWRITE);
430 print_flag(f, s, c, READONLY1, SYSCTL_READWRITE);
431 print_flag(f, s, c, READONLY2, SYSCTL_READWRITE);
432 print_flag(f, s, c, READWRITE, SYSCTL_READWRITE);
433 print_flag(f, s, c, ANYWRITE, 0);
434 print_flag(f, s, c, PRIVATE, 0);
435 print_flag(f, s, c, PERMANENT, 0);
436 print_flag(f, s, c, OWNDATA, 0);
437 print_flag(f, s, c, IMMEDIATE, 0);
438 print_flag(f, s, c, HEX, 0);
439 print_flag(f, s, c, ROOT, 0);
440 print_flag(f, s, c, ANYNUMBER, 0);
441 print_flag(f, s, c, HIDDEN, 0);
442 print_flag(f, s, c, ALIAS, 0);
443 #undef print_flag
444
445 if (f) {
446 char foo[9];
447 snprintf(foo, sizeof(foo), "%x", f);
448 strlcat(s, c, sizeof(s));
449 strlcat(s, foo, sizeof(s));
450 }
451
452 return (s);
453 }
454
455 static const char *
456 st(u_int t)
457 {
458
459 switch (t) {
460 case CTLTYPE_NODE:
461 return "NODE";
462 case CTLTYPE_INT:
463 return "INT";
464 case CTLTYPE_STRING:
465 return "STRING";
466 case CTLTYPE_QUAD:
467 return "QUAD";
468 case CTLTYPE_STRUCT:
469 return "STRUCT";
470 }
471
472 return "???";
473 }
474
475 /*
476 * ********************************************************************
477 * print this node and any others underneath it
478 * ********************************************************************
479 */
480 static void
481 print_tree(int *name, u_int namelen, struct sysctlnode *pnode, u_int type,
482 int add)
483 {
484 struct sysctlnode *node;
485 int rc, ni;
486 size_t sz;
487 char *sp, *dp, n[20];
488 struct handlespec *p;
489
490 sp = &gsname[strlen(gsname)];
491 dp = &gdname[strlen(gdname)];
492
493 if (sp != &gsname[0] && dp == &gdname[0]) {
494 /*
495 * aw...shucks. now we must play catch up
496 */
497 for (ni = 0; ni < namelen; ni++) {
498 (void)snprintf(n, sizeof(n), "%d", name[ni]);
499 if (ni > 0)
500 strncat(gdname, ".", sizeof(gdname));
501 strncat(gdname, n, sizeof(gdname));
502 }
503 }
504
505 if (pnode == NULL)
506 pnode = &my_root;
507 else if (add) {
508 snprintf(n, sizeof(n), "%d", pnode->sysctl_num);
509 if (namelen > 1) {
510 strncat(gsname, sep, sizeof(gsname));
511 strncat(gdname, ".", sizeof(gdname));
512 }
513 strncat(gsname, pnode->sysctl_name, sizeof(gsname));
514 strncat(gdname, n, sizeof(gdname));
515 }
516
517 if (Mflag && pnode != &my_root) {
518 if (nflag)
519 printf("%s: ", gdname);
520 else
521 printf("%s (%s): ", gsname, gdname);
522 printf("CTLTYPE_%s", st(type));
523 if (type == CTLTYPE_NODE) {
524 if (SYSCTL_FLAGS(pnode->sysctl_flags) & SYSCTL_ALIAS)
525 printf(", alias %d",
526 pnode->sysctl_alias);
527 else
528 printf(", children %d/%d",
529 pnode->sysctl_clen,
530 pnode->sysctl_csize);
531 }
532 printf(", size %zu", pnode->sysctl_size);
533 printf(", flags 0x%x<%s>",
534 SYSCTL_FLAGS(pnode->sysctl_flags),
535 sf(SYSCTL_FLAGS(pnode->sysctl_flags)));
536 if (pnode->sysctl_func)
537 printf(", func=%p", pnode->sysctl_func);
538 printf(", ver=%d", pnode->sysctl_ver);
539 printf("\n");
540 if (type != CTLTYPE_NODE) {
541 *sp = *dp = '\0';
542 return;
543 }
544 }
545
546 /*
547 * if this is an alias and we added our name, that means we
548 * got here by recursing down into the tree, so skip it. The
549 * only way to print an aliased node is with either -M or by
550 * name specifically.
551 */
552 if (SYSCTL_FLAGS(pnode->sysctl_flags) & SYSCTL_ALIAS && add) {
553 *sp = *dp = '\0';
554 return;
555 }
556
557 p = findprinter(name, namelen);
558 if (type != CTLTYPE_NODE && p != NULL) {
559 (*p->ps_p)(gsname, gdname, NULL, name, namelen, pnode, type,
560 p->ps_d);
561 *sp = *dp = '\0';
562 return;
563 }
564
565 if (type != CTLTYPE_NODE && pnode->sysctl_size == 0) {
566 rc = sysctl(&name[0], namelen, NULL, &sz, NULL, 0);
567 if (rc == -1) {
568 sysctlerror(1);
569 *sp = *dp = '\0';
570 return;
571 }
572 if (sz == 0) {
573 if ((Aflag || req) && !Mflag)
574 printf("%s: node contains no data\n", gsname);
575 *sp = *dp = '\0';
576 return;
577 }
578 }
579 else
580 sz = pnode->sysctl_size;
581
582 switch (type) {
583 case CTLTYPE_NODE: {
584 learn_tree(name, namelen, pnode);
585 node = pnode->sysctl_child;
586 if (node == NULL) {
587 if (p != NULL)
588 (*p->ps_p)(gsname, gdname, NULL, name, namelen,
589 pnode, type, p->ps_d);
590 else if ((Aflag || req) && !Mflag)
591 printf("%s: no children\n", gsname);
592 }
593 else {
594 req = 0;
595 for (ni = 0; ni < pnode->sysctl_clen; ni++) {
596 name[namelen] = node[ni].sysctl_num;
597 if ((node[ni].sysctl_flags & SYSCTL_HIDDEN) &&
598 !(Aflag || req))
599 continue;
600 print_tree(name, namelen + 1, &node[ni],
601 SYSCTL_TYPE(node[ni].sysctl_flags),
602 1);
603 }
604 }
605 break;
606 }
607 case CTLTYPE_INT: {
608 int i;
609 rc = sysctl(name, namelen, &i, &sz, NULL, 0);
610 if (rc == -1) {
611 sysctlerror(1);
612 break;
613 }
614 display_number(pnode, gsname, &i, sizeof(i), DISPLAY_VALUE);
615 break;
616 }
617 case CTLTYPE_STRING: {
618 unsigned char buf[1024], *tbuf;
619 tbuf = buf;
620 sz = sizeof(buf);
621 rc = sysctl(&name[0], namelen, tbuf, &sz, NULL, 0);
622 if (rc == -1 && errno == ENOMEM) {
623 tbuf = malloc(sz);
624 if (tbuf == NULL) {
625 sysctlerror(1);
626 break;
627 }
628 rc = sysctl(&name[0], namelen, tbuf, &sz, NULL, 0);
629 }
630 if (rc == -1)
631 sysctlerror(1);
632 else
633 display_string(pnode, gsname, buf, sz, DISPLAY_VALUE);
634 if (tbuf != buf)
635 free(tbuf);
636 break;
637 }
638 case CTLTYPE_QUAD: {
639 u_quad_t q;
640 sz = sizeof(q);
641 rc = sysctl(&name[0], namelen, &q, &sz, NULL, 0);
642 if (rc == -1) {
643 sysctlerror(1);
644 break;
645 }
646 display_number(pnode, gsname, &q, sizeof(q), DISPLAY_VALUE);
647 break;
648 }
649 case CTLTYPE_STRUCT: {
650 /*
651 * we shouldn't actually get here, but if we
652 * do, would it be nice to have *something* to
653 * do other than completely ignore the
654 * request.
655 */
656 unsigned char *d;
657 if ((d = malloc(sz)) == NULL) {
658 fprintf(warnfp, "%s: !malloc failed!\n", gsname);
659 break;
660 }
661 rc = sysctl(&name[0], namelen, d, &sz, NULL, 0);
662 if (rc == -1) {
663 sysctlerror(1);
664 break;
665 }
666 display_struct(pnode, gsname, d, sz, DISPLAY_VALUE);
667 free(d);
668 break;
669 }
670 default:
671 /* should i print an error here? */
672 break;
673 }
674
675 *sp = *dp = '\0';
676 }
677
678 /*
679 * ********************************************************************
680 * parse a request, possibly determining that it's a create or destroy
681 * request
682 * ********************************************************************
683 */
684 static void
685 parse(char *l)
686 {
687 struct sysctlnode *node;
688 struct handlespec *w;
689 int name[CTL_MAXNAME];
690 u_int namelen, type;
691 char *key, *value, *dot;
692 size_t sz;
693
694 req = 1;
695 key = l;
696 value = strchr(l, '=');
697 if (value != NULL)
698 *value++ = '\0';
699
700 if ((dot = strpbrk(key, "./")) == NULL)
701 sep[0] = '.';
702 else
703 sep[0] = dot[0];
704 sep[1] = '\0';
705
706 while (key[0] == sep[0] && key[1] == sep[0]) {
707 if (value != NULL)
708 value[-1] = '=';
709 if (strncmp(key + 2, "create", 6) == 0 &&
710 (key[8] == '=' || key[8] == sep[0]))
711 parse_create(key + 8 + (key[8] == '='));
712 else if (strncmp(key + 2, "destroy", 7) == 0 &&
713 (key[9] == '=' || key[9] == sep[0]))
714 parse_destroy(key + 9 + (key[9] == '='));
715 else
716 fprintf(warnfp, "%s: unable to parse '%s'\n",
717 getprogname(), key);
718 return;
719 }
720
721 node = &my_root;
722 namelen = CTL_MAXNAME;
723 sz = sizeof(gsname);
724
725 if (sysctlgetmibinfo(key, &name[0], &namelen, gsname, &sz, &node) == -1)
726 {
727 fprintf(warnfp, "%s: %s level name '%s' in '%s' is invalid\n",
728 getprogname(), lname[namelen], gsname, l);
729 exit(1);
730 }
731
732 type = SYSCTL_TYPE(node->sysctl_flags);
733
734 if (value == NULL) {
735 print_tree(&name[0], namelen, node, type, 0);
736 gsname[0] = '\0';
737 return;
738 }
739
740 if (!wflag) {
741 fprintf(warnfp, "%s: Must specify -w to set variables\n",
742 getprogname());
743 exit(1);
744 }
745
746 if (type != CTLTYPE_NODE && (w = findwriter(name, namelen)) != NULL) {
747 (*w->ps_w)(gsname, gdname, value, name, namelen, node, type,
748 w->ps_d);
749 gsname[0] = '\0';
750 return;
751 }
752
753 switch (type) {
754 case CTLTYPE_NODE:
755 /*
756 * XXX old behavior is to print. should we error instead?
757 */
758 print_tree(&name[0], namelen, node, CTLTYPE_NODE, 1);
759 break;
760 case CTLTYPE_INT:
761 write_number(&name[0], namelen, node, value);
762 break;
763 case CTLTYPE_STRING:
764 write_string(&name[0], namelen, node, value);
765 break;
766 case CTLTYPE_QUAD:
767 write_number(&name[0], namelen, node, value);
768 break;
769 case CTLTYPE_STRUCT:
770 /*
771 * XXX old behavior is to print. should we error instead?
772 */
773 /* fprintf(warnfp, "you can't write to %s\n", gsname); */
774 print_tree(&name[0], namelen, node, type, 0);
775 break;
776 }
777 }
778
779 /*
780
781 //create=foo.bar.whatever...,
782 [type=(int|quad|string|struct|node),]
783 [size=###,]
784 [n=###,]
785 [flags=(iohxparw12),]
786 [addr=0x####,|symbol=...|value=...]
787
788 size is optional for some types. type must be set before anything
789 else. nodes can have [r12whp], but nothing else applies. if no
790 size or type is given, node is asserted. writeable is the default,
791 with [r12w] being read-only, writeable below securelevel 1,
792 writeable below securelevel 2, and unconditionally writeable
793 respectively. if you specify addr, it is assumed to be the name of
794 a kernel symbol, if value, SYSCTL_OWNDATA will be asserted for
795 strings, SYSCTL_IMMEDIATE for ints and u_quad_ts. you cannot
796 specify both value and addr.
797
798 */
799
800 static void
801 parse_create(char *l)
802 {
803 struct sysctlnode node;
804 size_t sz;
805 char *nname, *key, *value, *data, *addr, *c, *t;
806 int name[CTL_MAXNAME], i, rc, method, flags, rw;
807 u_int namelen, type;
808 u_quad_t q;
809 long li, lo;
810
811 if (!wflag) {
812 fprintf(warnfp, "%s: Must specify -w to create nodes\n",
813 getprogname());
814 exit(1);
815 }
816
817 /*
818 * these are the pieces that make up the description of a new
819 * node
820 */
821 memset(&node, 0, sizeof(node));
822 node.sysctl_num = CTL_CREATE; /* any number is fine */
823 flags = 0;
824 rw = -1;
825 type = 0;
826 sz = 0;
827 data = addr = NULL;
828 memset(name, 0, sizeof(name));
829 namelen = 0;
830 method = 0;
831
832 /*
833 * misc stuff used when constructing
834 */
835 i = 0;
836 q = 0;
837 key = NULL;
838 value = NULL;
839
840 /*
841 * the name of the thing we're trying to create is first, so
842 * pick it off.
843 */
844 nname = l;
845 if ((c = strchr(nname, ',')) != NULL)
846 *c++ = '\0';
847
848 while (c != NULL) {
849
850 /*
851 * pull off the next "key=value" pair
852 */
853 key = c;
854 if ((t = strchr(key, '=')) != NULL) {
855 *t++ = '\0';
856 value = t;
857 }
858 else
859 value = NULL;
860
861 /*
862 * if the "key" is "value", then that eats the rest of
863 * the string, so we're done, otherwise bite it off at
864 * the next comma.
865 */
866 if (strcmp(key, "value") == 0) {
867 c = NULL;
868 data = value;
869 break;
870 }
871 else {
872 if ((c = strchr(value, ',')) != NULL)
873 *c++ = '\0';
874 }
875
876 /*
877 * note that we (mostly) let the invoker of sysctl(8)
878 * play rampant here and depend on the kernel to tell
879 * them that they were wrong. well...within reason.
880 * we later check the various parameters against each
881 * other to make sure it makes some sort of sense.
882 */
883 if (strcmp(key, "addr") == 0) {
884 /*
885 * we can't check these two. only the kernel
886 * can tell us when it fails to find the name
887 * (or if the address is invalid).
888 */
889 if (method != 0) {
890 fprintf(warnfp,
891 "%s: %s: already have %s for new node\n",
892 getprogname(), nname,
893 method == CTL_CREATE ? "addr" : "symbol");
894 exit(1);
895 }
896 errno = 0;
897 addr = (void*)strtoul(value, &t, 0);
898 if (*t != '\0' || errno != 0) {
899 fprintf(warnfp,
900 "%s: %s: '%s' is not a valid address\n",
901 getprogname(), nname, value);
902 exit(1);
903 }
904 method = CTL_CREATE;
905 }
906 else if (strcmp(key, "symbol") == 0) {
907 if (method != 0) {
908 fprintf(warnfp,
909 "%s: %s: already have %s for new node\n",
910 getprogname(), nname,
911 method == CTL_CREATE ? "addr" : "symbol");
912 exit(1);
913 }
914 addr = value;
915 method = CTL_CREATESYM;
916 }
917 else if (strcmp(key, "type") == 0) {
918 if (strcmp(value, "node") == 0)
919 type = CTLTYPE_NODE;
920 else if (strcmp(value, "int") == 0) {
921 sz = sizeof(int);
922 type = CTLTYPE_INT;
923 }
924 else if (strcmp(value, "string") == 0)
925 type = CTLTYPE_STRING;
926 else if (strcmp(value, "quad") == 0) {
927 sz = sizeof(u_quad_t);
928 type = CTLTYPE_QUAD;
929 }
930 else if (strcmp(value, "struct") == 0)
931 type = CTLTYPE_STRUCT;
932 else {
933 fprintf(warnfp,
934 "%s: %s: '%s' is not a valid type\n",
935 getprogname(), nname, value);
936 exit(1);
937 }
938 }
939 else if (strcmp(key, "size") == 0) {
940 errno = 0;
941 /*
942 * yes, i know size_t is not an unsigned long,
943 * but we can all agree that it ought to be,
944 * right?
945 */
946 sz = strtoul(value, &t, 0);
947 if (*t != '\0' || errno != 0) {
948 fprintf(warnfp,
949 "%s: %s: '%s' is not a valid size\n",
950 getprogname(), nname, value);
951 exit(1);
952 }
953 }
954 else if (strcmp(key, "n") == 0) {
955 errno = 0;
956 li = strtol(value, &t, 0);
957 node.sysctl_num = li;
958 lo = node.sysctl_num;
959 if (*t != '\0' || errno != 0 || li != lo || lo < 0) {
960 fprintf(warnfp,
961 "%s: %s: '%s' is not a valid mib number\n",
962 getprogname(), nname, value);
963 exit(1);
964 }
965 }
966 else if (strcmp(key, "flags") == 0) {
967 t = value;
968 while (*t != '\0') {
969 switch (*t) {
970 case 'a':
971 flags |= SYSCTL_ANYWRITE;
972 break;
973 case 'h':
974 flags |= SYSCTL_HIDDEN;
975 break;
976 case 'i':
977 flags |= SYSCTL_IMMEDIATE;
978 break;
979 case 'o':
980 flags |= SYSCTL_OWNDATA;
981 break;
982 case 'p':
983 flags |= SYSCTL_PRIVATE;
984 break;
985 case 'x':
986 flags |= SYSCTL_HEX;
987 break;
988
989 case 'r':
990 rw = SYSCTL_READONLY;
991 break;
992 case '1':
993 rw = SYSCTL_READONLY1;
994 break;
995 case '2':
996 rw = SYSCTL_READONLY2;
997 break;
998 case 'w':
999 rw = SYSCTL_READWRITE;
1000 break;
1001 default:
1002 fprintf(warnfp,
1003 "%s: %s: '%c' is not a valid flag\n",
1004 getprogname(), nname, *t);
1005 exit(1);
1006 }
1007 t++;
1008 }
1009 }
1010 else {
1011 fprintf(warnfp, "%s: %s: unrecognized keyword '%s'\n",
1012 getprogname(), nname, key);
1013 exit(1);
1014 }
1015 }
1016
1017 /*
1018 * now that we've finished parsing the given string, fill in
1019 * anything they didn't specify
1020 */
1021 if (type == 0)
1022 type = CTLTYPE_NODE;
1023
1024 /*
1025 * the "data" can be interpreted various ways depending on the
1026 * type of node we're creating, as can the size
1027 */
1028 if (data != NULL) {
1029 if (addr != NULL) {
1030 fprintf(warnfp,
1031 "%s: %s: cannot specify both value and "
1032 "address\n", getprogname(), nname);
1033 exit(1);
1034 }
1035
1036 switch (type) {
1037 case CTLTYPE_INT:
1038 errno = 0;
1039 li = strtol(data, &t, 0);
1040 i = li;
1041 lo = i;
1042 if (*t != '\0' || errno != 0 || li != lo || lo < 0) {
1043 fprintf(warnfp,
1044 "%s: %s: '%s' is not a valid integer\n",
1045 getprogname(), nname, value);
1046 exit(1);
1047 }
1048 if (!(flags & SYSCTL_OWNDATA)) {
1049 flags |= SYSCTL_IMMEDIATE;
1050 node.sysctl_idata = i;
1051 }
1052 else
1053 node.sysctl_data = &i;
1054 if (sz == 0)
1055 sz = sizeof(int);
1056 break;
1057 case CTLTYPE_STRING:
1058 flags |= SYSCTL_OWNDATA;
1059 node.sysctl_data = data;
1060 if (sz == 0)
1061 sz = strlen(data) + 1;
1062 else if (sz < strlen(data) + 1) {
1063 fprintf(warnfp, "%s: %s: ignoring size=%zu for "
1064 "string node, too small for given "
1065 "value\n", getprogname(), nname, sz);
1066 sz = strlen(data) + 1;
1067 }
1068 break;
1069 case CTLTYPE_QUAD:
1070 errno = 0;
1071 q = strtouq(data, &t, 0);
1072 if (*t != '\0' || errno != 0) {
1073 fprintf(warnfp,
1074 "%s: %s: '%s' is not a valid quad\n",
1075 getprogname(), nname, value);
1076 exit(1);
1077 }
1078 if (!(flags & SYSCTL_OWNDATA)) {
1079 flags |= SYSCTL_IMMEDIATE;
1080 node.sysctl_qdata = q;
1081 }
1082 else
1083 node.sysctl_data = &q;
1084 if (sz == 0)
1085 sz = sizeof(u_quad_t);
1086 break;
1087 case CTLTYPE_STRUCT:
1088 fprintf(warnfp,
1089 "%s: %s: struct not initializable\n",
1090 getprogname(), nname);
1091 exit(1);
1092 }
1093
1094 /*
1095 * these methods have all provided local starting
1096 * values that the kernel must copy in
1097 */
1098 }
1099
1100 /*
1101 * hmm...no data, but we have an address of data. that's
1102 * fine.
1103 */
1104 else if (addr != 0)
1105 node.sysctl_data = (void*)addr;
1106
1107 /*
1108 * no data and no address? well...okay. we might be able to
1109 * manage that.
1110 */
1111 else if (type != CTLTYPE_NODE) {
1112 if (sz == 0) {
1113 fprintf(warnfp,
1114 "%s: %s: need a size or a starting value\n",
1115 getprogname(), nname);
1116 exit(1);
1117 }
1118 if (!(flags & SYSCTL_IMMEDIATE))
1119 flags |= SYSCTL_OWNDATA;
1120 }
1121
1122 /*
1123 * now we do a few sanity checks on the description we've
1124 * assembled
1125 */
1126 if ((flags & SYSCTL_IMMEDIATE) &&
1127 (type == CTLTYPE_STRING || type == CTLTYPE_STRUCT)) {
1128 fprintf(warnfp,
1129 "%s: %s: cannot make an immediate %s\n",
1130 getprogname(), nname,
1131 (type == CTLTYPE_STRING) ? "string" : "struct");
1132 exit(1);
1133 }
1134 if (type == CTLTYPE_NODE && node.sysctl_data != NULL) {
1135 fprintf(warnfp, "%s: %s: nodes do not have data\n",
1136 getprogname(), nname);
1137 exit(1);
1138 }
1139
1140 /*
1141 * some types must have a particular size
1142 */
1143 if (sz != 0) {
1144 if ((type == CTLTYPE_INT && sz != sizeof(int)) ||
1145 (type == CTLTYPE_QUAD && sz != sizeof(u_quad_t)) ||
1146 (type == CTLTYPE_NODE && sz != 0)) {
1147 fprintf(warnfp, "%s: %s: wrong size for type\n",
1148 getprogname(), nname);
1149 exit(1);
1150 }
1151 }
1152 else if (type == CTLTYPE_STRUCT) {
1153 fprintf(warnfp, "%s: %s: struct must have size\n",
1154 getprogname(), nname);
1155 exit(1);
1156 }
1157
1158 /*
1159 * now...if no one said anything yet, we default nodes or
1160 * any type that owns data being writeable, and everything
1161 * else being readonly.
1162 */
1163 if (rw == -1) {
1164 if (type == CTLTYPE_NODE ||
1165 (flags & (SYSCTL_OWNDATA|SYSCTL_IMMEDIATE)))
1166 rw = SYSCTL_READWRITE;
1167 else
1168 rw = SYSCTL_READONLY;
1169 }
1170
1171 /*
1172 * if a kernel address was specified, that can't be made
1173 * writeable by us.
1174 if (rw != SYSCTL_READONLY && addr) {
1175 fprintf(warnfp, "%s: %s: kernel data can only be readable\n",
1176 getprogname(), nname);
1177 exit(1);
1178 }
1179 */
1180
1181 /*
1182 * what separator were they using in the full name of the new
1183 * node?
1184 */
1185 if ((t = strpbrk(nname, "./")) == NULL)
1186 sep[0] = '.';
1187 else
1188 sep[0] = t[0];
1189 sep[1] = '\0';
1190
1191 /*
1192 * put it all together, now. t'ain't much, is it?
1193 */
1194 node.sysctl_flags = flags|rw|type;
1195 node.sysctl_size = sz;
1196 t = strrchr(nname, sep[0]);
1197 if (t != NULL)
1198 strlcpy(node.sysctl_name, t + 1, sizeof(node.sysctl_name));
1199 else
1200 strlcpy(node.sysctl_name, nname, sizeof(node.sysctl_name));
1201 if (t == nname)
1202 t = NULL;
1203
1204 /*
1205 * if this is a new top-level node, then we don't need to find
1206 * the mib for its parent
1207 */
1208 if (t == NULL) {
1209 namelen = 0;
1210 gsname[0] = '\0';
1211 }
1212
1213 /*
1214 * on the other hand, if it's not a top-level node...
1215 */
1216 else {
1217 namelen = sizeof(name) / sizeof(name[0]);
1218 sz = sizeof(gsname);
1219 *t = '\0';
1220 rc = sysctlgetmibinfo(nname, &name[0], &namelen,
1221 gsname, &sz, NULL);
1222 *t = sep[0];
1223 if (rc == -1) {
1224 fprintf(warnfp,
1225 "%s: %s level name '%s' in '%s' is invalid\n",
1226 getprogname(), lname[namelen], gsname, nname);
1227 exit(1);
1228 }
1229 }
1230
1231 /*
1232 * yes, a new node is being created
1233 */
1234 if (method != 0)
1235 name[namelen++] = method;
1236 else
1237 name[namelen++] = CTL_CREATE;
1238
1239 sz = sizeof(node);
1240 rc = sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node));
1241
1242 if (rc == -1) {
1243 fprintf(warnfp,
1244 "%s: %s: CTL_CREATE failed: %s\n",
1245 getprogname(), nname, strerror(errno));
1246 exit(1);
1247 }
1248 else if (!qflag && !nflag)
1249 printf("%s(%s): (created)\n", nname, st(type));
1250 }
1251
1252 static void
1253 parse_destroy(char *l)
1254 {
1255 struct sysctlnode node;
1256 size_t sz;
1257 int name[CTL_MAXNAME], rc;
1258 u_int namelen;
1259
1260 if (!wflag) {
1261 fprintf(warnfp, "%s: Must specify -w to destroy nodes\n",
1262 getprogname());
1263 exit(1);
1264 }
1265
1266 memset(name, 0, sizeof(name));
1267 namelen = sizeof(name) / sizeof(name[0]);
1268 sz = sizeof(gsname);
1269 rc = sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL);
1270 if (rc == -1) {
1271 fprintf(warnfp,
1272 "%s: %s level name '%s' in '%s' is invalid\n",
1273 getprogname(), lname[namelen], gsname, l);
1274 exit(1);
1275 }
1276
1277 memset(&node, 0, sizeof(node));
1278 node.sysctl_num = name[namelen - 1];
1279 name[namelen - 1] = CTL_DESTROY;
1280
1281 sz = sizeof(node);
1282 rc = sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node));
1283
1284 if (rc == -1) {
1285 fprintf(warnfp,
1286 "%s: %s: CTL_DESTROY failed: %s\n",
1287 getprogname(), l, strerror(errno));
1288 exit(1);
1289 }
1290 else if (!qflag && !nflag)
1291 printf("%s(%s): (destroyed)\n", gsname,
1292 st(SYSCTL_TYPE(node.sysctl_flags)));
1293 }
1294
1295 /*
1296 * ********************************************************************
1297 * when things go wrong...
1298 * ********************************************************************
1299 */
1300 static void
1301 usage(void)
1302 {
1303 const char *progname = getprogname();
1304
1305 (void)fprintf(stderr,
1306 "usage:\t%s %s\n"
1307 "\t%s %s\n"
1308 "\t%s %s\n"
1309 "\t%s %s\n"
1310 "\t%s %s\n"
1311 "\t%s %s\n",
1312 progname, "[-ne] [-x[x]|-r] variable ...",
1313 progname, "[-ne] [-q] -w variable=value ...",
1314 progname, "[-ne] -a",
1315 progname, "[-ne] -A",
1316 progname, "[-ne] -M",
1317 progname, "[-ne] [-q] -f file");
1318 exit(1);
1319 }
1320
1321 void
1322 sysctlerror(int soft)
1323 {
1324 if (soft) {
1325 switch (errno) {
1326 case ENOENT:
1327 case ENOPROTOOPT:
1328 case ENOTDIR:
1329 case EOPNOTSUPP:
1330 case EPROTONOSUPPORT:
1331 if (Aflag || req)
1332 fprintf(warnfp,
1333 "%s: the value is not available\n",
1334 gsname);
1335 return;
1336 }
1337 }
1338
1339 fprintf(warnfp, "%s: sysctl() failed with %s\n",
1340 gsname, strerror(errno));
1341 if (!soft)
1342 exit(1);
1343 }
1344
1345 /*
1346 * ********************************************************************
1347 * how to write to a "simple" node
1348 * ********************************************************************
1349 */
1350 static void
1351 write_number(int *name, u_int namelen, struct sysctlnode *node, char *value)
1352 {
1353 int ii, io;
1354 u_quad_t qi, qo;
1355 size_t si, so;
1356 int rc;
1357 void *i, *o;
1358 char *t;
1359
1360 si = so = 0;
1361 i = o = NULL;
1362 errno = 0;
1363 qi = strtouq(value, &t, 0);
1364 if (errno != 0) {
1365 fprintf(warnfp, "%s: value too large\n", value);
1366 exit(1);
1367 }
1368 if (*t != '\0') {
1369 fprintf(warnfp, "%s: not a number\n", value);
1370 exit(1);
1371 }
1372
1373 switch (SYSCTL_TYPE(node->sysctl_flags)) {
1374 case CTLTYPE_INT:
1375 ii = (int)qi;
1376 qo = ii;
1377 if (qo != qi) {
1378 fprintf(warnfp, "%s: value too large\n", value);
1379 exit(1);
1380 }
1381 o = &io;
1382 so = sizeof(io);
1383 i = ⅈ
1384 si = sizeof(ii);
1385 break;
1386 case CTLTYPE_QUAD:
1387 o = &qo;
1388 so = sizeof(qo);
1389 i = &qi;
1390 si = sizeof(qi);
1391 break;
1392 }
1393
1394 rc = sysctl(name, namelen, o, &so, i, si);
1395 if (rc == -1)
1396 sysctlerror(0);
1397
1398 switch (SYSCTL_TYPE(node->sysctl_flags)) {
1399 case CTLTYPE_INT:
1400 display_number(node, gsname, &io, sizeof(io), DISPLAY_OLD);
1401 display_number(node, gsname, &ii, sizeof(ii), DISPLAY_NEW);
1402 break;
1403 case CTLTYPE_QUAD:
1404 display_number(node, gsname, &qo, sizeof(qo), DISPLAY_OLD);
1405 display_number(node, gsname, &qi, sizeof(qi), DISPLAY_NEW);
1406 break;
1407 }
1408 }
1409
1410 static void
1411 write_string(int *name, u_int namelen, struct sysctlnode *node, char *value)
1412 {
1413 char *i, *o;
1414 size_t si, so;
1415 int rc;
1416
1417 i = value;
1418 si = strlen(i) + 1;
1419 so = node->sysctl_size;
1420 if (si > so && so != 0) {
1421 fprintf(warnfp, "%s: string too long\n", value);
1422 exit(1);
1423 }
1424 o = malloc(so);
1425 if (o == NULL) {
1426 fprintf(warnfp, "%s: !malloc failed!\n", gsname);
1427 exit(1);
1428 }
1429
1430 rc = sysctl(name, namelen, o, &so, i, si);
1431 if (rc == -1)
1432 sysctlerror(0);
1433
1434 display_string(node, gsname, o, so, DISPLAY_OLD);
1435 display_string(node, gsname, i, si, DISPLAY_NEW);
1436 free(o);
1437 }
1438
1439 /*
1440 * ********************************************************************
1441 * simple ways to print stuff consistently
1442 * ********************************************************************
1443 */
1444 static void
1445 display_number(const struct sysctlnode *node, const char *name,
1446 const void *data, size_t sz, int n)
1447 {
1448 u_quad_t q;
1449 int i;
1450
1451 if (qflag)
1452 return;
1453 if ((nflag || rflag) && (n == DISPLAY_OLD))
1454 return;
1455
1456 if (rflag && n != DISPLAY_OLD) {
1457 fwrite(data, sz, 1, stdout);
1458 return;
1459 }
1460
1461 if (!nflag) {
1462 if (n == DISPLAY_VALUE)
1463 printf("%s%s", name, eq);
1464 else if (n == DISPLAY_OLD)
1465 printf("%s: ", name);
1466 }
1467
1468 if (xflag > 1) {
1469 if (n != DISPLAY_NEW)
1470 printf("\n");
1471 hex_dump(data, sz);
1472 return;
1473 }
1474
1475 switch (SYSCTL_TYPE(node->sysctl_flags)) {
1476 case CTLTYPE_INT:
1477 memcpy(&i, data, sz);
1478 if (xflag)
1479 printf("0x%0*x", (int)sz * 2, i);
1480 else if (node->sysctl_flags & SYSCTL_HEX)
1481 printf("%#x", i);
1482 else
1483 printf("%d", i);
1484 break;
1485 case CTLTYPE_QUAD:
1486 memcpy(&q, data, sz);
1487 if (xflag)
1488 printf("0x%0*" PRIx64, (int)sz * 2, q);
1489 else if (node->sysctl_flags & SYSCTL_HEX)
1490 printf("%#" PRIx64, q);
1491 else
1492 printf("%" PRIu64, q);
1493 break;
1494 }
1495
1496 if (n == DISPLAY_OLD)
1497 printf(" -> ");
1498 else
1499 printf("\n");
1500 }
1501
1502 static void
1503 display_string(const struct sysctlnode *node, const char *name,
1504 const void *data, size_t sz, int n)
1505 {
1506 const unsigned char *buf = data;
1507 int ni;
1508
1509 if (qflag)
1510 return;
1511 if ((nflag || rflag) && (n == DISPLAY_OLD))
1512 return;
1513
1514 if (rflag && n != DISPLAY_OLD) {
1515 fwrite(data, sz, 1, stdout);
1516 return;
1517 }
1518
1519 if (!nflag) {
1520 if (n == DISPLAY_VALUE)
1521 printf("%s%s", name, eq);
1522 else if (n == DISPLAY_OLD)
1523 printf("%s: ", name);
1524 }
1525
1526 if (xflag > 1) {
1527 if (n != DISPLAY_NEW)
1528 printf("\n");
1529 hex_dump(data, sz);
1530 return;
1531 }
1532
1533 if (xflag || node->sysctl_flags & SYSCTL_HEX) {
1534 for (ni = 0; ni < (int)sz; ni++) {
1535 if (xflag)
1536 printf("%02x", buf[ni]);
1537 if (buf[ni] == '\0')
1538 break;
1539 if (!xflag)
1540 printf("\\x%2.2x", buf[ni]);
1541 }
1542 }
1543 else
1544 printf("%.*s", (int)sz, buf);
1545
1546 if (n == DISPLAY_OLD)
1547 printf(" -> ");
1548 else
1549 printf("\n");
1550 }
1551
1552 /*ARGSUSED*/
1553 static void
1554 display_struct(const struct sysctlnode *node, const char *name,
1555 const void *data, size_t sz, int n)
1556 {
1557 const unsigned char *buf = data;
1558 int ni;
1559 size_t more;
1560
1561 if (qflag)
1562 return;
1563 if (!(xflag || rflag)) {
1564 if (Aflag || req)
1565 fprintf(warnfp,
1566 "%s: this type is unknown to this program\n",
1567 gsname);
1568 return;
1569 }
1570 if ((nflag || rflag) && (n == DISPLAY_OLD))
1571 return;
1572
1573 if (rflag && n != DISPLAY_OLD) {
1574 fwrite(data, sz, 1, stdout);
1575 return;
1576 }
1577
1578 if (!nflag) {
1579 if (n == DISPLAY_VALUE)
1580 printf("%s%s", name, eq);
1581 else if (n == DISPLAY_OLD)
1582 printf("%s: ", name);
1583 }
1584
1585 if (xflag > 1) {
1586 if (n != DISPLAY_NEW)
1587 printf("\n");
1588 hex_dump(data, sz);
1589 return;
1590 }
1591
1592 if (sz > 16) {
1593 more = sz - 16;
1594 sz = 16;
1595 }
1596 else
1597 more = 0;
1598 for (ni = 0; ni < (int)sz; ni++)
1599 printf("%02x", buf[ni]);
1600 if (more)
1601 printf("...(%zu more bytes)", more);
1602 printf("\n");
1603 }
1604
1605 static void
1606 hex_dump(const unsigned char *buf, size_t len)
1607 {
1608 int i, j;
1609 char line[80], tmp[12];
1610
1611 memset(line, ' ', sizeof(line));
1612 for (i = 0, j = 15; i < len; i++) {
1613 j = i % 16;
1614 /* reset line */
1615 if (j == 0) {
1616 line[58] = '|';
1617 line[77] = '|';
1618 line[78] = 0;
1619 snprintf(tmp, sizeof(tmp), "%07d", i);
1620 memcpy(&line[0], tmp, 7);
1621 }
1622 /* copy out hex version of byte */
1623 snprintf(tmp, sizeof(tmp), "%02x", buf[i]);
1624 memcpy(&line[9 + j * 3], tmp, 2);
1625 /* copy out plain version of byte */
1626 line[60 + j] = (isprint(buf[i])) ? buf[i] : '.';
1627 /* print a full line and erase it */
1628 if (j == 15) {
1629 printf("%s\n", line);
1630 memset(line, ' ', sizeof(line));
1631 }
1632 }
1633 if (line[0] != ' ')
1634 printf("%s\n", line);
1635 printf("%07zu bytes\n", len);
1636 }
1637
1638 /*
1639 * ********************************************************************
1640 * functions that handle particular nodes
1641 * ********************************************************************
1642 */
1643 /*ARGSUSED*/
1644 static void
1645 printother(HANDLER_ARGS)
1646 {
1647 int rc;
1648 void *p;
1649 size_t sz1, sz2;
1650
1651 if (!(Aflag || req) || Mflag)
1652 return;
1653
1654 /*
1655 * okay...you asked for it, so let's give it a go
1656 */
1657 while (type != CTLTYPE_NODE && (xflag || rflag)) {
1658 rc = sysctl(name, namelen, NULL, &sz1, NULL, 0);
1659 if (rc == -1 || sz1 == 0)
1660 break;
1661 p = malloc(sz1);
1662 if (p == NULL)
1663 break;
1664 sz2 = sz1;
1665 rc = sysctl(name, namelen, p, &sz2, NULL, 0);
1666 if (rc == -1 || sz1 != sz2) {
1667 free(p);
1668 break;
1669 }
1670 display_struct(pnode, gsname, p, sz1, DISPLAY_VALUE);
1671 free(p);
1672 return;
1673 }
1674
1675 /*
1676 * that didn't work...do we have a specific message for this
1677 * thing?
1678 */
1679 if (v != NULL) {
1680 fprintf(warnfp, "%s: use '%s' to view this information\n",
1681 gsname, (const char *)v);
1682 return;
1683 }
1684
1685 /*
1686 * hmm...i wonder if we have any generic hints?
1687 */
1688 switch (name[0]) {
1689 case CTL_NET:
1690 fprintf(warnfp, "%s: use 'netstat' to view this information\n",
1691 sname);
1692 break;
1693 case CTL_DEBUG:
1694 fprintf(warnfp, "%s: missing 'options DEBUG' from kernel?\n",
1695 sname);
1696 break;
1697 case CTL_DDB:
1698 fprintf(warnfp, "%s: missing 'options DDB' from kernel?\n",
1699 sname);
1700 break;
1701 }
1702 }
1703
1704 /*ARGSUSED*/
1705 static void
1706 kern_clockrate(HANDLER_ARGS)
1707 {
1708 struct clockinfo clkinfo;
1709 size_t sz;
1710 int rc;
1711
1712 sz = sizeof(clkinfo);
1713 rc = sysctl(name, namelen, &clkinfo, &sz, NULL, 0);
1714 if (rc == -1) {
1715 sysctlerror(1);
1716 return;
1717 }
1718 if (sz != sizeof(clkinfo))
1719 errx(1, "%s: !returned size wrong!", sname);
1720
1721 if (xflag || rflag) {
1722 display_struct(pnode, sname, &clkinfo, sz,
1723 DISPLAY_VALUE);
1724 return;
1725 }
1726 else if (!nflag)
1727 printf("%s: ", sname);
1728 printf("tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
1729 clkinfo.tick, clkinfo.tickadj,
1730 clkinfo.hz, clkinfo.profhz, clkinfo.stathz);
1731 }
1732
1733 /*ARGSUSED*/
1734 static void
1735 kern_boottime(HANDLER_ARGS)
1736 {
1737 struct timeval timeval;
1738 time_t boottime;
1739 size_t sz;
1740 int rc;
1741
1742 sz = sizeof(timeval);
1743 rc = sysctl(name, namelen, &timeval, &sz, NULL, 0);
1744 if (rc == -1) {
1745 sysctlerror(1);
1746 return;
1747 }
1748 if (sz != sizeof(timeval))
1749 errx(1, "%s: !returned size wrong!", sname);
1750
1751 boottime = timeval.tv_sec;
1752 if (xflag || rflag)
1753 display_struct(pnode, sname, &timeval, sz,
1754 DISPLAY_VALUE);
1755 else if (!nflag)
1756 /* ctime() provides the \n */
1757 printf("%s%s%s", sname, eq, ctime(&boottime));
1758 else if (nflag == 1)
1759 printf("%ld\n", (long)boottime);
1760 else
1761 printf("%ld.%06ld\n", (long)timeval.tv_sec,
1762 (long)timeval.tv_usec);
1763 }
1764
1765 /*ARGSUSED*/
1766 static void
1767 kern_consdev(HANDLER_ARGS)
1768 {
1769 dev_t cons;
1770 size_t sz;
1771 int rc;
1772
1773 sz = sizeof(cons);
1774 rc = sysctl(name, namelen, &cons, &sz, NULL, 0);
1775 if (rc == -1) {
1776 sysctlerror(1);
1777 return;
1778 }
1779 if (sz != sizeof(cons))
1780 errx(1, "%s: !returned size wrong!", sname);
1781
1782 if (xflag || rflag)
1783 display_struct(pnode, sname, &cons, sz,
1784 DISPLAY_VALUE);
1785 else if (!nflag)
1786 printf("%s%s%s\n", sname, eq, devname(cons, S_IFCHR));
1787 else
1788 printf("0x%x\n", cons);
1789 }
1790
1791 /*ARGSUSED*/
1792 static void
1793 kern_cp_time(HANDLER_ARGS)
1794 {
1795 u_int64_t *cp_time;
1796 size_t sz, osz;
1797 int rc, i, n;
1798 char s[sizeof("kern.cp_time.nnnnnn")];
1799 const char *tname;
1800
1801 /*
1802 * three things to do here.
1803 * case 1: get sum (no Aflag and namelen == 2)
1804 * case 2: get specific processor (namelen == 3)
1805 * case 3: get all processors (Aflag and namelen == 2)
1806 */
1807
1808 if (namelen == 2 && Aflag) {
1809 sz = sizeof(n);
1810 rc = sysctlbyname("hw.ncpu", &n, &sz, NULL, 0);
1811 if (rc != 0)
1812 return; /* XXX print an error, eh? */
1813 n++; /* Add on space for the sum. */
1814 sz = n * sizeof(u_int64_t) * CPUSTATES;
1815 }
1816 else {
1817 n = -1; /* Just print one data set. */
1818 sz = sizeof(u_int64_t) * CPUSTATES;
1819 }
1820
1821 cp_time = malloc(sz);
1822 if (cp_time == NULL) {
1823 sysctlerror(1);
1824 return;
1825 }
1826
1827 osz = sz;
1828 rc = sysctl(name, namelen, cp_time + (n != -1) * CPUSTATES, &osz,
1829 NULL, 0);
1830
1831 if (rc == -1) {
1832 sysctlerror(1);
1833 free(cp_time);
1834 return;
1835 }
1836
1837 /*
1838 * Check, but account for space we'll occupy with the sum.
1839 */
1840 if (osz != sz - (n != -1) * CPUSTATES * sizeof(u_int64_t))
1841 errx(1, "%s: !returned size wrong!", sname);
1842
1843 /*
1844 * Compute the actual sum. Two calls would be easier (we
1845 * could just call ourselves recursively above), but the
1846 * numbers wouldn't add up.
1847 */
1848 if (n != -1) {
1849 memset(cp_time, 0, sizeof(u_int64_t) * CPUSTATES);
1850 for (i = 1; i < n; i++) {
1851 cp_time[CP_USER] += cp_time[i * CPUSTATES + CP_USER];
1852 cp_time[CP_NICE] += cp_time[i * CPUSTATES + CP_NICE];
1853 cp_time[CP_SYS] += cp_time[i * CPUSTATES + CP_SYS];
1854 cp_time[CP_INTR] += cp_time[i * CPUSTATES + CP_INTR];
1855 cp_time[CP_IDLE] += cp_time[i * CPUSTATES + CP_IDLE];
1856 }
1857 }
1858
1859 tname = sname;
1860 for (i = 0; n == -1 || i < n; i++) {
1861 if (i > 0) {
1862 (void)snprintf(s, sizeof(s), "%s%s%d", sname, sep,
1863 i - 1);
1864 tname = s;
1865 }
1866 if (xflag || rflag)
1867 display_struct(pnode, tname, cp_time + (i * CPUSTATES),
1868 sizeof(u_int64_t) * CPUSTATES,
1869 DISPLAY_VALUE);
1870 else {
1871 if (!nflag)
1872 printf("%s: ", tname);
1873 printf("user = %" PRIu64
1874 ", nice = %" PRIu64
1875 ", sys = %" PRIu64
1876 ", intr = %" PRIu64
1877 ", idle = %" PRIu64
1878 "\n",
1879 cp_time[i * CPUSTATES + CP_USER],
1880 cp_time[i * CPUSTATES + CP_NICE],
1881 cp_time[i * CPUSTATES + CP_SYS],
1882 cp_time[i * CPUSTATES + CP_INTR],
1883 cp_time[i * CPUSTATES + CP_IDLE]);
1884 }
1885 /*
1886 * Just printing the one node.
1887 */
1888 if (n == -1)
1889 break;
1890 }
1891
1892 free(cp_time);
1893 }
1894
1895 /*ARGSUSED*/
1896 static void
1897 vm_loadavg(HANDLER_ARGS)
1898 {
1899 struct loadavg loadavg;
1900 size_t sz;
1901 int rc;
1902
1903 sz = sizeof(loadavg);
1904 rc = sysctl(name, namelen, &loadavg, &sz, NULL, 0);
1905 if (rc == -1) {
1906 sysctlerror(1);
1907 return;
1908 }
1909 if (sz != sizeof(loadavg))
1910 errx(1, "%s: !returned size wrong!", sname);
1911
1912 if (xflag || rflag) {
1913 display_struct(pnode, sname, &loadavg, sz,
1914 DISPLAY_VALUE);
1915 return;
1916 }
1917 if (!nflag)
1918 printf("%s: ", sname);
1919 printf("%.2f %.2f %.2f\n",
1920 (double) loadavg.ldavg[0] / loadavg.fscale,
1921 (double) loadavg.ldavg[1] / loadavg.fscale,
1922 (double) loadavg.ldavg[2] / loadavg.fscale);
1923 }
1924
1925 /*ARGSUSED*/
1926 static void
1927 proc_limit(HANDLER_ARGS)
1928 {
1929 u_quad_t olim, *newp, nlim;
1930 size_t osz, nsz;
1931 char *t;
1932 int rc;
1933
1934 osz = sizeof(olim);
1935 if (value != NULL) {
1936 nsz = sizeof(nlim);
1937 newp = &nlim;
1938 if (strcmp(value, "unlimited") == 0)
1939 nlim = RLIM_INFINITY;
1940 else {
1941 errno = 0;
1942 nlim = strtouq(value, &t, 0);
1943 if (*t != '\0' || errno != 0) {
1944 fprintf(warnfp,
1945 "%s: %s: '%s' is not a valid limit\n",
1946 getprogname(), sname, value);
1947 exit(1);
1948 }
1949 }
1950 }
1951 else {
1952 nsz = 0;
1953 newp = NULL;
1954 }
1955
1956 rc = sysctl(name, namelen, &olim, &osz, newp, nsz);
1957 if (rc == -1) {
1958 sysctlerror(newp == NULL);
1959 return;
1960 }
1961
1962 if (newp && qflag)
1963 return;
1964
1965 if (rflag || xflag || olim != RLIM_INFINITY)
1966 display_number(pnode, sname, &olim, sizeof(olim),
1967 newp ? DISPLAY_OLD : DISPLAY_VALUE);
1968 else
1969 display_string(pnode, sname, "unlimited", 10,
1970 newp ? DISPLAY_OLD : DISPLAY_VALUE);
1971
1972 if (newp) {
1973 if (rflag || xflag || nlim != RLIM_INFINITY)
1974 display_number(pnode, sname, &nlim, sizeof(nlim),
1975 DISPLAY_NEW);
1976 else
1977 display_string(pnode, sname, "unlimited", 10,
1978 DISPLAY_NEW);
1979 }
1980 }
1981
1982 #ifdef CPU_DISKINFO
1983 /*ARGSUSED*/
1984 static void
1985 machdep_diskinfo(HANDLER_ARGS)
1986 {
1987 struct disklist *dl;
1988 struct biosdisk_info *bi;
1989 struct nativedisk_info *ni;
1990 int rc;
1991 size_t sz;
1992 uint i, b, lim;
1993
1994 rc = sysctl(name, namelen, NULL, &sz, NULL, 0);
1995 if (rc == -1) {
1996 sysctlerror(1);
1997 return;
1998 }
1999 dl = malloc(sz);
2000 if (dl == NULL) {
2001 sysctlerror(1);
2002 return;
2003 }
2004 rc = sysctl(name, namelen, dl, &sz, NULL, 0);
2005 if (rc == -1) {
2006 sysctlerror(1);
2007 return;
2008 }
2009
2010 if (!nflag)
2011 printf("%s: ", sname);
2012 lim = dl->dl_nbiosdisks;
2013 if (lim > MAX_BIOSDISKS)
2014 lim = MAX_BIOSDISKS;
2015 for (bi = dl->dl_biosdisks, i = 0; i < lim; bi++, i++)
2016 printf("%x:%" PRIu64 "(%d/%d/%d),%x ",
2017 bi->bi_dev, bi->bi_lbasecs,
2018 bi->bi_cyl, bi->bi_head, bi->bi_sec,
2019 bi->bi_flags);
2020 lim = dl->dl_nnativedisks;
2021 ni = dl->dl_nativedisks;
2022 bi = dl->dl_biosdisks;
2023 /* LINTED -- pointer casts are tedious */
2024 if ((char *)&ni[lim] != (char *)dl + sz) {
2025 fprintf(warnfp, "size mismatch\n");
2026 return;
2027 }
2028 for (i = 0; i < lim; ni++, i++) {
2029 char t = ':';
2030 printf(" %.*s", (int)sizeof ni->ni_devname,
2031 ni->ni_devname);
2032 for (b = 0; b < ni->ni_nmatches; t = ',', b++)
2033 printf("%c%x", t,
2034 bi[ni->ni_biosmatches[b]].bi_dev);
2035 }
2036 printf("\n");
2037 }
2038 #endif /* CPU_DISKINFO */
2039