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