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