]> git.saurik.com Git - apple/system_cmds.git/blob - sysctl.tproj/sysctl.c
system_cmds-279.tar.gz
[apple/system_cmds.git] / sysctl.tproj / sysctl.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1993
27 * The Regents of the University of California. All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58 /*
59 Modified November 1, 2000, by Ryan Rempel, ryan.rempel@utoronto.ca
60
61 The Darwin sysctl mechanism is in a state of flux. Parts of the kernel use the old
62 style of BSD sysctl definition, and other parts use the new style. The sysctl (8)
63 command that shipped with Darwin 1.2 (OS X PB) did not allow you to access
64 all possible sysctl values. In particular, it did not permit access to sysctl values
65 created by kernel extensions--hence my particular interest. The freeBSD sysctl (8)
66 command compiled and ran under Darwin 1.2, and it did permit access to
67 sysctl values created by kernel extensions, as well as several others. However, it
68 did not permit access to many other values which the Darwin 1.2 sysctl could access.
69
70 What I have done is merge the Darwin 1.2 sysctl and the freeBSD sysctl. Essentially,
71 there are two points of merger. When showing all values (i.e. -a, -A, or -X), sysctl now
72 runs the Darwin 1.2 routine to show all values, and then the freeBSD routine. This does
73 result in some duplication. When getting or setting a particular value, sysctl now tries
74 the freeBSD way first. If it cannot find the value, then it tries the Darwin 1.2 way.
75
76 There are a few oddities which this creates (aside from some duplication with -a, -A,
77 and -X). The freeBSD version of sysctl now supports two extra options, -b and -X.
78 In this syctl, those options are supported where the value is retrieved by the freeBSD
79 routine, and have no effect where the value is retrieved by the Darwin 1.2 routine.
80 The freeBSD sysctl uses a ':' to separate the name and the value, whereas Darwin 1.2's
81 sysctl uses a '='. I have left this way, as it lets you know which routine was used,
82 should it matter.
83
84 I have also fixed several lines which gave warnings previously, one of which appears
85 to have been an actual bug (bufp was dereferenced when it shouldn't have been).
86 I have also incoporated my previous patch to permit setting kern.hostid as an unsigned
87 integer. In the freeBSD side of the code, I have incorporated a general fix for
88 setting values where the format is specified as unsigned integer.
89 */
90
91 #ifndef lint
92 static char copyright[] =
93 "@(#) Copyright (c) 1993\n\
94 The Regents of the University of California. All rights reserved.\n";
95 #endif /* not lint */
96
97 #ifndef lint
98 static char sccsid[] = "@(#)sysctl.c 8.5 (Berkeley) 5/9/95";
99 #endif /* not lint */
100
101 #include <sys/param.h>
102 #include <sys/gmon.h>
103 #include <sys/mount.h>
104 #include <sys/stat.h>
105 #include <sys/sysctl.h>
106 #include <sys/socket.h>
107 #ifdef __APPLE__
108 #include <mach/machine/vm_param.h>
109 #include <mach/machine/vm_types.h>
110 #include <mach/mach_types.h>
111 #else
112 #include <vm/vm_param.h>
113 #endif /* __APPLE__ */
114 #include <machine/cpu.h>
115
116 #include <errno.h>
117 #include <ctype.h>
118 #include <unistd.h>
119 #include <stdio.h>
120 #include <stdlib.h>
121 #include <string.h>
122
123 #include <sys/types.h>
124 #include <sys/resource.h>
125 #include <err.h>
126
127 struct ctlname topname[] = CTL_NAMES;
128 struct ctlname kernname[] = CTL_KERN_NAMES;
129 struct ctlname vmname[] = CTL_VM_NAMES;
130 struct ctlname hwname[] = CTL_HW_NAMES;
131 struct ctlname username[] = CTL_USER_NAMES;
132 struct ctlname debugname[CTL_DEBUG_MAXID];
133 struct ctlname *vfsname;
134 #ifdef CTL_MACHDEP_NAMES
135 struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
136 #endif
137 char names[BUFSIZ];
138 int lastused;
139
140 struct list {
141 struct ctlname *list;
142 int size;
143 };
144 struct list toplist = { topname, CTL_MAXID };
145 struct list secondlevel[] = {
146 { 0, 0 }, /* CTL_UNSPEC */
147 { kernname, KERN_MAXID }, /* CTL_KERN */
148 { vmname, VM_MAXID }, /* CTL_VM */
149 { 0, 0 }, /* CTL_VFS */
150 { 0, 0 }, /* CTL_NET */
151 { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */
152 { 0, 0 }, /* CTL_HW */
153 #ifdef CTL_MACHDEP_NAMES
154 { machdepname, CPU_MAXID }, /* CTL_MACHDEP */
155 #else
156 { 0, 0 }, /* CTL_MACHDEP */
157 #endif
158 { username, USER_MAXID }, /* CTL_USER_NAMES */
159 };
160
161 static int Aflag, aflag, bflag, nflag, wflag, Xflag;
162 static int foundSome = 0;
163
164 void listall(char *prefix, struct list *lp);
165 void old_parse(char *string, int flags);
166 void debuginit();
167 void vfsinit();
168 int findname(char *string, char *level, char **bufp, struct list *namelist);
169 void usage();
170
171 static void parse(char *string, int flags);
172 static int oidfmt(int *, int, char *, u_int *);
173 static int show_var(int *, int, int);
174 static int sysctl_all (int *oid, int len);
175 static int name2oid(char *, int *);
176
177 /*
178 * Variables requiring special processing.
179 */
180 #define CLOCK 0x00000001
181 #define BOOTTIME 0x00000002
182 #define CONSDEV 0x00000004
183
184 int
185 main(argc, argv)
186 int argc;
187 char *argv[];
188 {
189 // extern char *optarg; // unused
190 extern int optind;
191 int ch, lvl1;
192
193 while ((ch = getopt(argc, argv, "AabnwX")) != EOF) {
194 switch (ch) {
195 case 'A': Aflag = 1; break;
196 case 'a': aflag = 1; break;
197 case 'b': bflag = 1; break;
198 case 'n': nflag = 1; break;
199 case 'w': wflag = 1; break;
200 case 'X': Xflag = Aflag = 1; break;
201 default: usage();
202 }
203 }
204 argc -= optind;
205 argv += optind;
206
207 if (argc == 0 && (Aflag || aflag)) {
208 debuginit();
209 vfsinit();
210 for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
211 listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
212 exit (sysctl_all(0, 0));
213 }
214 if (argc == 0)
215 usage();
216 for (; *argv != NULL; ++argv)
217 parse(*argv, 1);
218 exit(0);
219 }
220
221 /*
222 * List all variables known to the system.
223 */
224 void
225 listall(prefix, lp)
226 char *prefix;
227 struct list *lp;
228 {
229 int lvl2;
230 char *cp, name[BUFSIZ];
231
232 if (lp->list == 0)
233 return;
234 strcpy(name, prefix);
235 cp = &name[strlen(name)];
236 *cp++ = '.';
237 for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
238 if (lp->list[lvl2].ctl_name == 0)
239 continue;
240 strcpy(cp, lp->list[lvl2].ctl_name);
241 old_parse(name, Aflag);
242 }
243 }
244
245 /*
246 * Parse a name into a MIB entry.
247 * Lookup and print out the MIB entry if it exists.
248 * Set a new value if requested.
249 */
250 void
251 old_parse(string, flags)
252 char *string;
253 int flags;
254 {
255 int indx, type, state, len;
256 size_t size;
257 int special = 0;
258 void *newval = 0;
259 int intval, newsize = 0;
260 unsigned int uintval;
261 int useUnsignedInt = 0;
262 quad_t quadval;
263 struct list *lp;
264 struct vfsconf vfc;
265 int mib[CTL_MAXNAME];
266 char *cp, *bufp, buf[BUFSIZ] /*, strval[BUFSIZ] */ ;
267
268 bufp = buf;
269 snprintf(buf, BUFSIZ, "%s", string);
270 if ((cp = strchr(string, '=')) != NULL) {
271 if (!wflag) {
272 fprintf(stderr, "Must specify -w to set variables\n");
273 exit(2);
274 }
275 *strchr(buf, '=') = '\0';
276 *cp++ = '\0';
277 while (isspace(*cp))
278 cp++;
279 newval = cp;
280 newsize = strlen(cp);
281 }
282 if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
283 return;
284 mib[0] = indx;
285 if (indx == CTL_VFS)
286 vfsinit();
287 if (indx == CTL_DEBUG)
288 debuginit();
289 lp = &secondlevel[indx];
290 if (lp->list == 0) {
291 if (!foundSome) fprintf(stderr, "%s: class is not implemented\n",
292 topname[indx].ctl_name);
293 return;
294 }
295 if (bufp == NULL) {
296 listall(topname[indx].ctl_name, lp);
297 return;
298 }
299 if ((indx = findname(string, "second", &bufp, lp)) == -1)
300 return;
301 mib[1] = indx;
302 type = lp->list[indx].ctl_type;
303 len = 2;
304 switch (mib[0]) {
305
306 case CTL_KERN:
307 switch (mib[1]) {
308 case KERN_PROF:
309 mib[2] = GPROF_STATE;
310 size = sizeof state;
311 if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) {
312 if (flags == 0)
313 return;
314 if (!nflag)
315 fprintf(stdout, "%s: ", string);
316 fprintf(stderr,
317 "kernel is not compiled for profiling\n");
318 return;
319 }
320 if (!nflag)
321 fprintf(stdout, "%s: %s\n", string,
322 state == GMON_PROF_OFF ? "off" : "running");
323 return;
324 case KERN_VNODE:
325 case KERN_FILE:
326 if (flags == 0)
327 return;
328 fprintf(stderr,
329 "Use pstat to view %s information\n", string);
330 return;
331 case KERN_PROC:
332 if (flags == 0)
333 return;
334 fprintf(stderr,
335 "Use ps to view %s information\n", string);
336 return;
337 case KERN_CLOCKRATE:
338 special |= CLOCK;
339 break;
340 case KERN_BOOTTIME:
341 special |= BOOTTIME;
342 break;
343 case KERN_HOSTID:
344 useUnsignedInt = 1;
345 break;
346 }
347 break;
348
349 case CTL_HW:
350 useUnsignedInt = 1;
351 break;
352
353 case CTL_VM:
354 if (mib[1] == VM_LOADAVG) { /* XXX this is bogus */
355 double loads[3];
356
357 getloadavg(loads, 3);
358 if (!nflag)
359 fprintf(stdout, "%s: ", string);
360 fprintf(stdout, "%.2f %.2f %.2f\n",
361 loads[0], loads[1], loads[2]);
362 return;
363 }
364 if (flags == 0)
365 return;
366 fprintf(stderr,
367 "Use vmstat or systat to view %s information\n", string);
368 return;
369
370 case CTL_DEBUG:
371 mib[2] = CTL_DEBUG_VALUE;
372 len = 3;
373 break;
374
375 case CTL_MACHDEP:
376 #ifdef CPU_CONSDEV
377 if (mib[1] == CPU_CONSDEV)
378 special |= CONSDEV;
379 #endif
380 break;
381
382 case CTL_VFS:
383 mib[3] = mib[1];
384 mib[1] = VFS_GENERIC;
385 mib[2] = VFS_CONF;
386 len = 4;
387 size = sizeof vfc;
388 if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
389 perror("vfs print");
390 return;
391 }
392 if (flags == 0 && vfc.vfc_refcount == 0)
393 return;
394 if (!nflag)
395 fprintf(stdout, "%s has %d mounted instance%s\n",
396 string, vfc.vfc_refcount,
397 vfc.vfc_refcount != 1 ? "s" : "");
398 else
399 fprintf(stdout, "%d\n", vfc.vfc_refcount);
400 return;
401
402 case CTL_USER:
403 break;
404
405 default:
406 fprintf(stderr, "Illegal top level value: %d\n", mib[0]);
407 return;
408
409 }
410 if (bufp) {
411 fprintf(stderr, "name %s in %s is unknown\n", bufp, string);
412 return;
413 }
414 if (newsize > 0) {
415 switch (type) {
416 case CTLTYPE_INT:
417 if (useUnsignedInt) {
418 uintval = strtoul(newval, 0, 0);
419 newval = &uintval;
420 newsize = sizeof uintval;
421 } else {
422 intval = atoi(newval);
423 newval = &intval;
424 newsize = sizeof intval;
425 }
426 break;
427
428 case CTLTYPE_QUAD:
429 sscanf(newval, "%qd", &quadval);
430 newval = &quadval;
431 newsize = sizeof quadval;
432 break;
433 }
434 }
435 size = BUFSIZ;
436 if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
437 if (flags == 0)
438 return;
439 switch (errno) {
440 case EOPNOTSUPP:
441 fprintf(stderr, "%s: value is not available\n", string);
442 return;
443 case ENOTDIR:
444 fprintf(stderr, "%s: specification is incomplete\n",
445 string);
446 return;
447 case ENOMEM:
448 fprintf(stderr, "%s: type is unknown to this program\n",
449 string);
450 return;
451 default:
452 perror(string);
453 return;
454 }
455 }
456 if (special & CLOCK) {
457 struct clockinfo *clkp = (struct clockinfo *)buf;
458
459 if (!nflag)
460 fprintf(stdout, "%s: ", string);
461 fprintf(stdout,
462 "hz = %d, tick = %d, profhz = %d, stathz = %d\n",
463 clkp->hz, clkp->tick, clkp->profhz, clkp->stathz);
464 return;
465 }
466 if (special & BOOTTIME) {
467 struct timeval *btp = (struct timeval *)buf;
468
469 if (!nflag)
470 fprintf(stdout, "%s = %s\n", string,
471 ctime((time_t *) &btp->tv_sec));
472 else
473 fprintf(stdout, "%d\n", btp->tv_sec);
474 return;
475 }
476 if (special & CONSDEV) {
477 dev_t dev = *(dev_t *)buf;
478
479 if (!nflag)
480 fprintf(stdout, "%s = %s\n", string,
481 devname(dev, S_IFCHR));
482 else
483 fprintf(stdout, "0x%x\n", dev);
484 return;
485 }
486 switch (type) {
487 case CTLTYPE_INT:
488 if (newsize == 0) {
489 if (!nflag)
490 fprintf(stdout, "%s = ", string);
491 fprintf(stdout, useUnsignedInt ? "%u\n" : "%d\n", *(int *)buf);
492 } else {
493 if (!nflag)
494 fprintf(stdout, useUnsignedInt ? "%s: %u -> " : "%s: %d -> ",
495 string, *(int *)buf);
496 fprintf(stdout, useUnsignedInt ? "%u\n" : "%d\n", *(int *)newval);
497 }
498 return;
499
500 case CTLTYPE_STRING:
501 if (newsize == 0) {
502 if (!nflag)
503 fprintf(stdout, "%s = ", string);
504 fprintf(stdout, "%s\n", buf);
505 } else {
506 if (!nflag)
507 fprintf(stdout, "%s: %s -> ", string, buf);
508 fprintf(stdout, "%s\n", (char *) newval);
509 }
510 return;
511
512 case CTLTYPE_QUAD:
513 if (newsize == 0) {
514 if (!nflag)
515 fprintf(stdout, "%s = ", string);
516 fprintf(stdout, "%qd\n", *(quad_t *)buf);
517 } else {
518 if (!nflag)
519 fprintf(stdout, "%s: %qd -> ", string,
520 *(quad_t *)buf);
521 fprintf(stdout, "%qd\n", *(quad_t *)newval);
522 }
523 return;
524
525 case CTLTYPE_STRUCT:
526 return;
527
528 default:
529 case CTLTYPE_NODE:
530 fprintf(stderr, "%s: unknown type returned\n",
531 string);
532 return;
533 }
534 }
535
536 /*
537 * Initialize the set of debugging names
538 */
539 void debuginit()
540 {
541 int mib[3], loc, i;
542 size_t size;
543
544 if (secondlevel[CTL_DEBUG].list != 0)
545 return;
546 secondlevel[CTL_DEBUG].list = debugname;
547 mib[0] = CTL_DEBUG;
548 mib[2] = CTL_DEBUG_NAME;
549 for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
550 mib[1] = i;
551 size = BUFSIZ - loc;
552 if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
553 continue;
554 debugname[i].ctl_name = &names[loc];
555 debugname[i].ctl_type = CTLTYPE_INT;
556 loc += size;
557 }
558 lastused = loc;
559 }
560
561 /*
562 * Initialize the set of filesystem names
563 */
564 void vfsinit()
565 {
566 int mib[4], maxtypenum, cnt, loc, size;
567 struct vfsconf vfc;
568 size_t buflen;
569
570 if (secondlevel[CTL_VFS].list != 0)
571 return;
572 mib[0] = CTL_VFS;
573 mib[1] = VFS_GENERIC;
574 mib[2] = VFS_MAXTYPENUM;
575 buflen = 4;
576 if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
577 return;
578 if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == 0)
579 return;
580 memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
581 mib[2] = VFS_CONF;
582 buflen = sizeof vfc;
583 for (loc = lastused, cnt = 0; cnt < maxtypenum; cnt++) {
584 mib[3] = cnt;
585 if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
586 if (errno == EOPNOTSUPP)
587 continue;
588 perror("vfsinit");
589 free(vfsname);
590 return;
591 }
592 strcat(&names[loc], vfc.vfc_name);
593 vfsname[cnt].ctl_name = &names[loc];
594 vfsname[cnt].ctl_type = CTLTYPE_INT;
595 size = strlen(vfc.vfc_name) + 1;
596 loc += size;
597 }
598 lastused = loc;
599 secondlevel[CTL_VFS].list = vfsname;
600 secondlevel[CTL_VFS].size = maxtypenum;
601 return;
602 }
603
604 /*
605 * Scan a list of names searching for a particular name.
606 */
607 int
608 findname(string, level, bufp, namelist)
609 char *string;
610 char *level;
611 char **bufp;
612 struct list *namelist;
613 {
614 char *name;
615 int i;
616
617 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
618 fprintf(stderr, "%s: incomplete specification\n", string);
619 return (-1);
620 }
621 for (i = 0; i < namelist->size; i++)
622 if (namelist->list[i].ctl_name != NULL &&
623 strcmp(name, namelist->list[i].ctl_name) == 0)
624 break;
625 if (i == namelist->size) {
626 fprintf(stderr, "%s level name %s in %s is invalid\n",
627 level, name, string);
628 return (-1);
629 }
630 return (i);
631 }
632
633 void usage()
634 {
635
636 (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
637 "usage: sysctl [-bn] variable ...",
638 " sysctl [-bn] -w variable=value ...",
639 " sysctl [-bn] -a",
640 " sysctl [-bn] -A",
641 " sysctl [-bn] -X");
642 exit(1);
643 }
644
645 /*
646 * Parse a name into a MIB entry.
647 * Lookup and print out the MIB entry if it exists.
648 * Set a new value if requested.
649 */
650 static void
651 parse(char *string, int flags)
652 {
653 int len, i, j;
654 void *newval = 0;
655 int intval, newsize = 0;
656 unsigned int uintval;
657 quad_t quadval;
658 int mib[CTL_MAXNAME];
659 char *cp, *bufp, buf[BUFSIZ], fmt[BUFSIZ];
660 u_int kind;
661
662 bufp = buf;
663 snprintf(buf, BUFSIZ, "%s", string);
664 if ((cp = strchr(string, '=')) != NULL) {
665 if (!wflag)
666 errx(2, "must specify -w to set variables");
667 *strchr(buf, '=') = '\0';
668 *cp++ = '\0';
669 while (isspace(*cp))
670 cp++;
671 newval = cp;
672 newsize = strlen(cp);
673 } else {
674 if (wflag)
675 usage();
676 }
677 len = name2oid(bufp, mib);
678
679 if (len < 0) {
680 if (cp != NULL) {
681 while (*cp != '\0') cp--;
682 *cp = '=';
683 }
684 old_parse (string, flags);
685 return;
686 }
687
688 if (oidfmt(mib, len, fmt, &kind))
689 err(1, "couldn't find format of oid '%s'", bufp);
690
691 if (!wflag) {
692 if ((kind & CTLTYPE) == CTLTYPE_NODE) {
693 sysctl_all(mib, len);
694 foundSome = 1;
695 old_parse (string, flags);
696 } else {
697 i = show_var(mib, len, 1);
698 if (!i && !bflag)
699 putchar('\n');
700 }
701 } else {
702 if ((kind & CTLTYPE) == CTLTYPE_NODE)
703 errx(1, "oid '%s' isn't a leaf node", bufp);
704
705 if (!(kind&CTLFLAG_WR))
706 errx(1, "oid '%s' is read only", bufp);
707
708 switch (kind & CTLTYPE) {
709 case CTLTYPE_INT:
710 if ((*fmt == 'I') && (*(fmt + 1) == 'U')) {
711 uintval = (unsigned int) strtoul (newval, NULL, 0);
712 newval = &uintval;
713 newsize = sizeof uintval;
714 } else {
715 intval = (int) strtol(newval, NULL, 0);
716 newval = &intval;
717 newsize = sizeof intval;
718 }
719 break;
720 case CTLTYPE_STRING:
721 break;
722 case CTLTYPE_QUAD:
723 break;
724 sscanf(newval, "%qd", &quadval);
725 newval = &quadval;
726 newsize = sizeof quadval;
727 break;
728 default:
729 errx(1, "oid '%s' is type %d,"
730 " cannot set that", bufp,
731 kind & CTLTYPE);
732 }
733
734 i = show_var(mib, len, 1);
735 if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
736 if (!i && !bflag)
737 putchar('\n');
738 switch (errno) {
739 case EOPNOTSUPP:
740 errx(1, "%s: value is not available",
741 string);
742 case ENOTDIR:
743 errx(1, "%s: specification is incomplete",
744 string);
745 case ENOMEM:
746 errx(1, "%s: type is unknown to this program",
747 string);
748 default:
749 warn("%s", string);
750 return;
751 }
752 }
753 if (!bflag)
754 printf(" -> ");
755 i = nflag;
756 nflag = 1;
757 j = show_var(mib, len, 1);
758 if (!j && !bflag)
759 putchar('\n');
760 nflag = i;
761 }
762 }
763
764 /* These functions will dump out various interesting structures. */
765
766 static int
767 S_clockinfo(int l2, void *p)
768 {
769 struct clockinfo *ci = (struct clockinfo*)p;
770 if (l2 != sizeof *ci)
771 err(1, "S_clockinfo %d != %d", l2, sizeof *ci);
772 printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
773 ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz);
774 return (0);
775 }
776
777 static int
778 S_loadavg(int l2, void *p)
779 {
780 struct loadavg *tv = (struct loadavg*)p;
781
782 if (l2 != sizeof *tv)
783 err(1, "S_loadavg %d != %d", l2, sizeof *tv);
784
785 printf("{ %.2f %.2f %.2f }",
786 (double)tv->ldavg[0]/(double)tv->fscale,
787 (double)tv->ldavg[1]/(double)tv->fscale,
788 (double)tv->ldavg[2]/(double)tv->fscale);
789 return (0);
790 }
791
792 static int
793 S_timeval(int l2, void *p)
794 {
795 struct timeval *tv = (struct timeval*)p;
796 time_t tv_sec;
797 char *p1, *p2;
798
799 if (l2 != sizeof *tv)
800 err(1, "S_timeval %d != %d", l2, sizeof *tv);
801 printf("{ sec = %ld, usec = %ld } ",
802 (long) tv->tv_sec, (long) tv->tv_usec);
803 tv_sec = tv->tv_sec;
804 p1 = strdup(ctime(&tv_sec));
805 for (p2=p1; *p2 ; p2++)
806 if (*p2 == '\n')
807 *p2 = '\0';
808 fputs(p1, stdout);
809 return (0);
810 }
811
812 static int
813 T_dev_t(int l2, void *p)
814 {
815 dev_t *d = (dev_t *)p;
816 if (l2 != sizeof *d)
817 err(1, "T_dev_T %d != %d", l2, sizeof *d);
818 if ((int)(*d) != -1) {
819 if (minor(*d) > 255 || minor(*d) < 0)
820 printf("{ major = %d, minor = 0x%x }",
821 major(*d), minor(*d));
822 else
823 printf("{ major = %d, minor = %d }",
824 major(*d), minor(*d));
825 }
826 return (0);
827 }
828
829 /*
830 * These functions uses a presently undocumented interface to the kernel
831 * to walk the tree and get the type so it can print the value.
832 * This interface is under work and consideration, and should probably
833 * be killed with a big axe by the first person who can find the time.
834 * (be aware though, that the proper interface isn't as obvious as it
835 * may seem, there are various conflicting requirements.
836 */
837
838 static int
839 name2oid(char *name, int *oidp)
840 {
841 int oid[2];
842 int i;
843 size_t j;
844
845 oid[0] = 0;
846 oid[1] = 3;
847
848 j = CTL_MAXNAME * sizeof (int);
849 i = sysctl(oid, 2, oidp, &j, name, strlen(name));
850 if (i < 0)
851 return i;
852 j /= sizeof (int);
853 return (j);
854 }
855
856 static int
857 oidfmt(int *oid, int len, char *fmt, u_int *kind)
858 {
859 int qoid[CTL_MAXNAME+2];
860 u_char buf[BUFSIZ];
861 int i;
862 size_t j;
863
864 qoid[0] = 0;
865 qoid[1] = 4;
866 memcpy(qoid + 2, oid, len * sizeof(int));
867
868 j = sizeof buf;
869 i = sysctl(qoid, len + 2, buf, &j, 0, 0);
870 if (i)
871 err(1, "sysctl fmt %d %d %d", i, j, errno);
872
873 if (kind)
874 *kind = *(u_int *)buf;
875
876 if (fmt)
877 strcpy(fmt, (char *)(buf + sizeof(u_int)));
878 return 0;
879 }
880
881 /*
882 * This formats and outputs the value of one variable
883 *
884 * Returns zero if anything was actually output.
885 * Returns one if didn't know what to do with this.
886 * Return minus one if we had errors.
887 */
888
889 static int
890 show_var(int *oid, int nlen, int show_masked)
891 {
892 u_char buf[BUFSIZ], *val, *mval, *p;
893 char name[BUFSIZ], /* descr[BUFSIZ], */ *fmt;
894 int qoid[CTL_MAXNAME+2];
895 int i;
896 int retval;
897 size_t j, len;
898 u_int kind;
899 int (*func)(int, void *) = 0;
900
901 qoid[0] = 0;
902 memcpy(qoid + 2, oid, nlen * sizeof(int));
903
904 qoid[1] = 1;
905 j = sizeof name;
906 i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
907 if (i || !j)
908 err(1, "sysctl name %d %d %d", i, j, errno);
909
910 /* find an estimate of how much we need for this var */
911 j = 0;
912 i = sysctl(oid, nlen, 0, &j, 0, 0);
913 j += j; /* we want to be sure :-) */
914
915 val = mval = malloc(j);
916 len = j;
917 i = sysctl(oid, nlen, val, &len, 0, 0);
918 if (i || !len) {
919 retval = 1;
920 goto RETURN;
921 }
922
923 if (bflag) {
924 fwrite(val, 1, len, stdout);
925 retval = 0;
926 goto RETURN;
927 }
928
929 qoid[1] = 4;
930 j = sizeof buf;
931 i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
932 if (i || !j)
933 err(1, "sysctl fmt %d %d %d", i, j, errno);
934
935 kind = *(u_int *)buf;
936 if (!show_masked && (kind & CTLFLAG_MASKED)) {
937 retval = 1;
938 goto RETURN;
939 }
940
941 fmt = (char *)(buf + sizeof(u_int));
942
943 p = val;
944 switch (*fmt) {
945 case '-':
946 /* deprecated, do not print */
947 retval = 0;
948 goto RETURN;
949
950
951 case 'A':
952 if (!nflag)
953 printf("%s: ", name);
954 printf("%s", p);
955 retval = 0;
956 goto RETURN;
957
958 case 'I':
959 if (!nflag)
960 printf("%s: ", name);
961 fmt++;
962 val = "";
963 while (len >= sizeof(int)) {
964 if(*fmt == 'U')
965 printf("%s%u", val, *(unsigned int *)p);
966 else
967 printf("%s%d", val, *(int *)p);
968 val = " ";
969 len -= sizeof (int);
970 p += sizeof (int);
971 }
972 retval = 0;
973 goto RETURN;
974
975 case 'L':
976 if (!nflag)
977 printf("%s: ", name);
978 fmt++;
979 val = "";
980 while (len >= sizeof(long)) {
981 if(*fmt == 'U')
982 printf("%s%lu", val, *(unsigned long *)p);
983 else
984 printf("%s%ld", val, *(long *)p);
985 val = " ";
986 len -= sizeof (long);
987 p += sizeof (long);
988 }
989 retval = 0;
990 goto RETURN;
991
992 case 'P':
993 if (!nflag)
994 printf("%s: ", name);
995 printf("%p", *(void **)p);
996 retval = 0;
997 goto RETURN;
998
999 case 'Q':
1000 if (!nflag)
1001 printf("%s: ", name);
1002 fmt++;
1003 val = "";
1004 while (len >= sizeof(long long)) {
1005 if(*fmt == 'U')
1006 printf("%s%llu", val, *(unsigned long long *)p);
1007 else
1008 printf("%s%lld", val, *(long long *)p);
1009 val = " ";
1010 len -= sizeof (long long);
1011 p += sizeof (long long);
1012 }
1013 retval = 0;
1014 goto RETURN;
1015
1016
1017 case 'T':
1018 case 'S':
1019 i = 0;
1020 if (!strcmp(fmt, "S,clockinfo")) func = S_clockinfo;
1021 else if (!strcmp(fmt, "S,timeval")) func = S_timeval;
1022 else if (!strcmp(fmt, "S,loadavg")) func = S_loadavg;
1023 else if (!strcmp(fmt, "T,dev_t")) func = T_dev_t;
1024 if (func) {
1025 if (!nflag)
1026 printf("%s: ", name);
1027 retval = (*func)(len, p);
1028 goto RETURN;
1029 }
1030 /* FALL THROUGH */
1031 default:
1032 if (!Aflag) {
1033 retval = 1;
1034 goto RETURN;
1035 }
1036 if (!nflag)
1037 printf("%s: ", name);
1038 printf("Format:%s Length:%ld Dump:0x", fmt, len);
1039 while (len--) {
1040 printf("%02x", *p++);
1041 if (Xflag || p < val+16)
1042 continue;
1043 printf("...");
1044 break;
1045 }
1046 retval = 0;
1047 goto RETURN;
1048 }
1049
1050 retval = 1;
1051 RETURN:
1052 free(mval);
1053 return (retval);
1054 }
1055
1056 static int
1057 sysctl_all (int *oid, int len)
1058 {
1059 int name1[22], name2[22];
1060 int i, j;
1061 size_t l1, l2;
1062
1063 name1[0] = 0;
1064 name1[1] = 2;
1065 l1 = 2;
1066 if (len) {
1067 memcpy(name1+2, oid, len*sizeof (int));
1068 l1 += len;
1069 } else {
1070 name1[2] = 1;
1071 l1++;
1072 }
1073 while (1) {
1074 l2 = sizeof name2;
1075 j = sysctl(name1, l1, name2, &l2, 0, 0);
1076 if (j < 0) {
1077 if (errno == ENOENT)
1078 return 0;
1079 else
1080 err(1, "sysctl(getnext) %d %d", j, l2);
1081 }
1082
1083 l2 /= sizeof (int);
1084
1085 if (l2 < len)
1086 return 0;
1087
1088 for (i = 0; i < len; i++)
1089 if (name2[i] != oid[i])
1090 return 0;
1091
1092 i = show_var(name2, l2, 0);
1093 if (!i && !bflag)
1094 putchar('\n');
1095
1096 memcpy(name1+2, name2, l2*sizeof (int));
1097 l1 = 2 + l2;
1098 }
1099 }