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