]> git.saurik.com Git - apple/system_cmds.git/blame - sysctl.tproj/sysctl.c
system_cmds-230.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:
b51d5b5f 349 useUnsignedInt = 1;
1815bff5
A
350 break;
351
352 case CTL_VM:
353 if (mib[1] == VM_LOADAVG) {
354 double loads[3];
355
356 getloadavg(loads, 3);
357 if (!nflag)
358 fprintf(stdout, "%s: ", string);
359 fprintf(stdout, "%.2f %.2f %.2f\n",
360 loads[0], loads[1], loads[2]);
361 return;
362 }
363 if (flags == 0)
364 return;
365 fprintf(stderr,
366 "Use vmstat or systat to view %s information\n", string);
367 return;
368
369 case CTL_DEBUG:
370 mib[2] = CTL_DEBUG_VALUE;
371 len = 3;
372 break;
373
374 case CTL_MACHDEP:
375#ifdef CPU_CONSDEV
376 if (mib[1] == CPU_CONSDEV)
377 special |= CONSDEV;
378#endif
379 break;
380
381 case CTL_VFS:
382 mib[3] = mib[1];
383 mib[1] = VFS_GENERIC;
384 mib[2] = VFS_CONF;
385 len = 4;
386 size = sizeof vfc;
387 if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
388 perror("vfs print");
389 return;
390 }
391 if (flags == 0 && vfc.vfc_refcount == 0)
392 return;
393 if (!nflag)
394 fprintf(stdout, "%s has %d mounted instance%s\n",
395 string, vfc.vfc_refcount,
396 vfc.vfc_refcount != 1 ? "s" : "");
397 else
398 fprintf(stdout, "%d\n", vfc.vfc_refcount);
399 return;
400
401 case CTL_USER:
402 break;
403
404 default:
405 fprintf(stderr, "Illegal top level value: %d\n", mib[0]);
406 return;
407
408 }
409 if (bufp) {
410 fprintf(stderr, "name %s in %s is unknown\n", bufp, string);
411 return;
412 }
413 if (newsize > 0) {
414 switch (type) {
415 case CTLTYPE_INT:
416 if (useUnsignedInt) {
417 uintval = strtoul(newval, 0, 0);
418 newval = &uintval;
419 newsize = sizeof uintval;
420 } else {
421 intval = atoi(newval);
422 newval = &intval;
423 newsize = sizeof intval;
424 }
425 break;
426
427 case CTLTYPE_QUAD:
428 sscanf(newval, "%qd", &quadval);
429 newval = &quadval;
430 newsize = sizeof quadval;
431 break;
432 }
433 }
434 size = BUFSIZ;
435 if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
436 if (flags == 0)
437 return;
438 switch (errno) {
439 case EOPNOTSUPP:
440 fprintf(stderr, "%s: value is not available\n", string);
441 return;
442 case ENOTDIR:
443 fprintf(stderr, "%s: specification is incomplete\n",
444 string);
445 return;
446 case ENOMEM:
447 fprintf(stderr, "%s: type is unknown to this program\n",
448 string);
449 return;
450 default:
451 perror(string);
452 return;
453 }
454 }
455 if (special & CLOCK) {
456 struct clockinfo *clkp = (struct clockinfo *)buf;
457
458 if (!nflag)
459 fprintf(stdout, "%s: ", string);
460 fprintf(stdout,
461 "hz = %d, tick = %d, profhz = %d, stathz = %d\n",
462 clkp->hz, clkp->tick, clkp->profhz, clkp->stathz);
463 return;
464 }
465 if (special & BOOTTIME) {
466 struct timeval *btp = (struct timeval *)buf;
467
468 if (!nflag)
469 fprintf(stdout, "%s = %s\n", string,
470 ctime((time_t *) &btp->tv_sec));
471 else
472 fprintf(stdout, "%d\n", btp->tv_sec);
473 return;
474 }
475 if (special & CONSDEV) {
476 dev_t dev = *(dev_t *)buf;
477
478 if (!nflag)
479 fprintf(stdout, "%s = %s\n", string,
480 devname(dev, S_IFCHR));
481 else
482 fprintf(stdout, "0x%x\n", dev);
483 return;
484 }
485 switch (type) {
486 case CTLTYPE_INT:
487 if (newsize == 0) {
488 if (!nflag)
489 fprintf(stdout, "%s = ", string);
490 fprintf(stdout, useUnsignedInt ? "%u\n" : "%d\n", *(int *)buf);
491 } else {
492 if (!nflag)
493 fprintf(stdout, useUnsignedInt ? "%s: %u -> " : "%s: %d -> ",
494 string, *(int *)buf);
495 fprintf(stdout, useUnsignedInt ? "%u\n" : "%d\n", *(int *)newval);
496 }
497 return;
498
499 case CTLTYPE_STRING:
500 if (newsize == 0) {
501 if (!nflag)
502 fprintf(stdout, "%s = ", string);
503 fprintf(stdout, "%s\n", buf);
504 } else {
505 if (!nflag)
506 fprintf(stdout, "%s: %s -> ", string, buf);
507 fprintf(stdout, "%s\n", (char *) newval);
508 }
509 return;
510
511 case CTLTYPE_QUAD:
512 if (newsize == 0) {
513 if (!nflag)
514 fprintf(stdout, "%s = ", string);
515 fprintf(stdout, "%qd\n", *(quad_t *)buf);
516 } else {
517 if (!nflag)
518 fprintf(stdout, "%s: %qd -> ", string,
519 *(quad_t *)buf);
520 fprintf(stdout, "%qd\n", *(quad_t *)newval);
521 }
522 return;
523
524 case CTLTYPE_STRUCT:
525 return;
526
527 default:
528 case CTLTYPE_NODE:
529 fprintf(stderr, "%s: unknown type returned\n",
530 string);
531 return;
532 }
533}
534
535/*
536 * Initialize the set of debugging names
537 */
538void debuginit()
539{
540 int mib[3], loc, i;
541 size_t size;
542
543 if (secondlevel[CTL_DEBUG].list != 0)
544 return;
545 secondlevel[CTL_DEBUG].list = debugname;
546 mib[0] = CTL_DEBUG;
547 mib[2] = CTL_DEBUG_NAME;
548 for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
549 mib[1] = i;
550 size = BUFSIZ - loc;
551 if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
552 continue;
553 debugname[i].ctl_name = &names[loc];
554 debugname[i].ctl_type = CTLTYPE_INT;
555 loc += size;
556 }
557 lastused = loc;
558}
559
560/*
561 * Initialize the set of filesystem names
562 */
563void vfsinit()
564{
565 int mib[4], maxtypenum, cnt, loc, size;
566 struct vfsconf vfc;
567 size_t buflen;
568
569 if (secondlevel[CTL_VFS].list != 0)
570 return;
571 mib[0] = CTL_VFS;
572 mib[1] = VFS_GENERIC;
573 mib[2] = VFS_MAXTYPENUM;
574 buflen = 4;
575 if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
576 return;
577 if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == 0)
578 return;
579 memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
580 mib[2] = VFS_CONF;
581 buflen = sizeof vfc;
582 for (loc = lastused, cnt = 0; cnt < maxtypenum; cnt++) {
583 mib[3] = cnt;
584 if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
585 if (errno == EOPNOTSUPP)
586 continue;
587 perror("vfsinit");
588 free(vfsname);
589 return;
590 }
591 strcat(&names[loc], vfc.vfc_name);
592 vfsname[cnt].ctl_name = &names[loc];
593 vfsname[cnt].ctl_type = CTLTYPE_INT;
594 size = strlen(vfc.vfc_name) + 1;
595 loc += size;
596 }
597 lastused = loc;
598 secondlevel[CTL_VFS].list = vfsname;
599 secondlevel[CTL_VFS].size = maxtypenum;
600 return;
601}
602
603/*
604 * Scan a list of names searching for a particular name.
605 */
606int
607findname(string, level, bufp, namelist)
608 char *string;
609 char *level;
610 char **bufp;
611 struct list *namelist;
612{
613 char *name;
614 int i;
615
616 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
617 fprintf(stderr, "%s: incomplete specification\n", string);
618 return (-1);
619 }
620 for (i = 0; i < namelist->size; i++)
621 if (namelist->list[i].ctl_name != NULL &&
622 strcmp(name, namelist->list[i].ctl_name) == 0)
623 break;
624 if (i == namelist->size) {
625 fprintf(stderr, "%s level name %s in %s is invalid\n",
626 level, name, string);
627 return (-1);
628 }
629 return (i);
630}
631
632void usage()
633{
634
635 (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
636 "usage: sysctl [-bn] variable ...",
637 " sysctl [-bn] -w variable=value ...",
638 " sysctl [-bn] -a",
639 " sysctl [-bn] -A",
640 " sysctl [-bn] -X");
641 exit(1);
642}
643
644/*
645 * Parse a name into a MIB entry.
646 * Lookup and print out the MIB entry if it exists.
647 * Set a new value if requested.
648 */
649static void
650parse(char *string, int flags)
651{
652 int len, i, j;
653 void *newval = 0;
654 int intval, newsize = 0;
655 unsigned int uintval;
656 quad_t quadval;
657 int mib[CTL_MAXNAME];
658 char *cp, *bufp, buf[BUFSIZ], fmt[BUFSIZ];
659 u_int kind;
660
661 bufp = buf;
662 snprintf(buf, BUFSIZ, "%s", string);
663 if ((cp = strchr(string, '=')) != NULL) {
664 if (!wflag)
665 errx(2, "must specify -w to set variables");
666 *strchr(buf, '=') = '\0';
667 *cp++ = '\0';
668 while (isspace(*cp))
669 cp++;
670 newval = cp;
671 newsize = strlen(cp);
672 } else {
673 if (wflag)
674 usage();
675 }
676 len = name2oid(bufp, mib);
677
678 if (len < 0) {
679 if (cp != NULL) {
680 while (*cp != '\0') cp--;
681 *cp = '=';
682 }
683 old_parse (string, flags);
684 return;
685 }
686
687 if (oidfmt(mib, len, fmt, &kind))
688 err(1, "couldn't find format of oid '%s'", bufp);
689
690 if (!wflag) {
691 if ((kind & CTLTYPE) == CTLTYPE_NODE) {
692 sysctl_all(mib, len);
693 foundSome = 1;
694 old_parse (string, flags);
695 } else {
696 i = show_var(mib, len);
697 if (!i && !bflag)
698 putchar('\n');
699 }
700 } else {
701 if ((kind & CTLTYPE) == CTLTYPE_NODE)
702 errx(1, "oid '%s' isn't a leaf node", bufp);
703
704 if (!(kind&CTLFLAG_WR))
705 errx(1, "oid '%s' is read only", bufp);
706
707 switch (kind & CTLTYPE) {
708 case CTLTYPE_INT:
709 if ((*fmt == 'I') && (*(fmt + 1) == 'U')) {
710 uintval = (unsigned int) strtoul (newval, NULL, 0);
711 newval = &uintval;
712 newsize = sizeof uintval;
713 } else {
714 intval = (int) strtol(newval, NULL, 0);
715 newval = &intval;
716 newsize = sizeof intval;
717 }
718 break;
719 case CTLTYPE_STRING:
720 break;
721 case CTLTYPE_QUAD:
722 break;
723 sscanf(newval, "%qd", &quadval);
724 newval = &quadval;
725 newsize = sizeof quadval;
726 break;
727 default:
728 errx(1, "oid '%s' is type %d,"
729 " cannot set that", bufp,
730 kind & CTLTYPE);
731 }
732
733 i = show_var(mib, len);
734 if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
735 if (!i && !bflag)
736 putchar('\n');
737 switch (errno) {
738 case EOPNOTSUPP:
739 errx(1, "%s: value is not available",
740 string);
741 case ENOTDIR:
742 errx(1, "%s: specification is incomplete",
743 string);
744 case ENOMEM:
745 errx(1, "%s: type is unknown to this program",
746 string);
747 default:
748 warn("%s", string);
749 return;
750 }
751 }
752 if (!bflag)
753 printf(" -> ");
754 i = nflag;
755 nflag = 1;
756 j = show_var(mib, len);
757 if (!j && !bflag)
758 putchar('\n');
759 nflag = i;
760 }
761}
762
763/* These functions will dump out various interesting structures. */
764
765static int
766S_clockinfo(int l2, void *p)
767{
768 struct clockinfo *ci = (struct clockinfo*)p;
769 if (l2 != sizeof *ci)
770 err(1, "S_clockinfo %d != %d", l2, sizeof *ci);
771 printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
772 ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz);
773 return (0);
774}
775
776static int
777S_loadavg(int l2, void *p)
778{
779 struct loadavg *tv = (struct loadavg*)p;
780
781 if (l2 != sizeof *tv)
782 err(1, "S_loadavg %d != %d", l2, sizeof *tv);
783
784 printf("{ %.2f %.2f %.2f }",
785 (double)tv->ldavg[0]/(double)tv->fscale,
786 (double)tv->ldavg[1]/(double)tv->fscale,
787 (double)tv->ldavg[2]/(double)tv->fscale);
788 return (0);
789}
790
791static int
792S_timeval(int l2, void *p)
793{
794 struct timeval *tv = (struct timeval*)p;
795 time_t tv_sec;
796 char *p1, *p2;
797
798 if (l2 != sizeof *tv)
799 err(1, "S_timeval %d != %d", l2, sizeof *tv);
800 printf("{ sec = %ld, usec = %ld } ",
801 (long) tv->tv_sec, (long) tv->tv_usec);
802 tv_sec = tv->tv_sec;
803 p1 = strdup(ctime(&tv_sec));
804 for (p2=p1; *p2 ; p2++)
805 if (*p2 == '\n')
806 *p2 = '\0';
807 fputs(p1, stdout);
808 return (0);
809}
810
811static int
812T_dev_t(int l2, void *p)
813{
814 dev_t *d = (dev_t *)p;
815 if (l2 != sizeof *d)
816 err(1, "T_dev_T %d != %d", l2, sizeof *d);
817 if ((int)(*d) != -1) {
818 if (minor(*d) > 255 || minor(*d) < 0)
819 printf("{ major = %d, minor = 0x%x }",
820 major(*d), minor(*d));
821 else
822 printf("{ major = %d, minor = %d }",
823 major(*d), minor(*d));
824 }
825 return (0);
826}
827
828/*
829 * These functions uses a presently undocumented interface to the kernel
830 * to walk the tree and get the type so it can print the value.
831 * This interface is under work and consideration, and should probably
832 * be killed with a big axe by the first person who can find the time.
833 * (be aware though, that the proper interface isn't as obvious as it
834 * may seem, there are various conflicting requirements.
835 */
836
837static int
838name2oid(char *name, int *oidp)
839{
840 int oid[2];
841 int i;
842 size_t j;
843
844 oid[0] = 0;
845 oid[1] = 3;
846
847 j = CTL_MAXNAME * sizeof (int);
848 i = sysctl(oid, 2, oidp, &j, name, strlen(name));
849 if (i < 0)
850 return i;
851 j /= sizeof (int);
852 return (j);
853}
854
855static int
856oidfmt(int *oid, int len, char *fmt, u_int *kind)
857{
858 int qoid[CTL_MAXNAME+2];
859 u_char buf[BUFSIZ];
860 int i;
861 size_t j;
862
863 qoid[0] = 0;
864 qoid[1] = 4;
865 memcpy(qoid + 2, oid, len * sizeof(int));
866
867 j = sizeof buf;
868 i = sysctl(qoid, len + 2, buf, &j, 0, 0);
869 if (i)
870 err(1, "sysctl fmt %d %d %d", i, j, errno);
871
872 if (kind)
873 *kind = *(u_int *)buf;
874
875 if (fmt)
876 strcpy(fmt, (char *)(buf + sizeof(u_int)));
877 return 0;
878}
879
880/*
881 * This formats and outputs the value of one variable
882 *
883 * Returns zero if anything was actually output.
884 * Returns one if didn't know what to do with this.
885 * Return minus one if we had errors.
886 */
887
888static int
889show_var(int *oid, int nlen)
890{
b51d5b5f 891 u_char buf[BUFSIZ], *val, *mval, *p;
1815bff5
A
892 char name[BUFSIZ], /* descr[BUFSIZ], */ *fmt;
893 int qoid[CTL_MAXNAME+2];
894 int i;
b51d5b5f 895 int retval;
1815bff5
A
896 size_t j, len;
897 u_int kind;
898 int (*func)(int, void *) = 0;
899
900 qoid[0] = 0;
901 memcpy(qoid + 2, oid, nlen * sizeof(int));
902
903 qoid[1] = 1;
904 j = sizeof name;
905 i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
906 if (i || !j)
907 err(1, "sysctl name %d %d %d", i, j, errno);
908
909 /* find an estimate of how much we need for this var */
910 j = 0;
911 i = sysctl(oid, nlen, 0, &j, 0, 0);
912 j += j; /* we want to be sure :-) */
913
b51d5b5f 914 val = mval = malloc(j);
1815bff5
A
915 len = j;
916 i = sysctl(oid, nlen, val, &len, 0, 0);
b51d5b5f
A
917 if (i || !len) {
918 retval = 1;
919 goto RETURN;
920 }
1815bff5
A
921
922 if (bflag) {
923 fwrite(val, 1, len, stdout);
b51d5b5f
A
924 retval = 0;
925 goto RETURN;
1815bff5
A
926 }
927
928 qoid[1] = 4;
929 j = sizeof buf;
930 i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
931 if (i || !j)
932 err(1, "sysctl fmt %d %d %d", i, j, errno);
933
934 kind = *(u_int *)buf;
935
936 fmt = (char *)(buf + sizeof(u_int));
937
938 p = val;
939 switch (*fmt) {
940 case 'A':
941 if (!nflag)
942 printf("%s: ", name);
943 printf("%s", p);
b51d5b5f
A
944 retval = 0;
945 goto RETURN;
1815bff5
A
946
947 case 'I':
948 if (!nflag)
949 printf("%s: ", name);
950 fmt++;
951 val = "";
952 while (len >= sizeof(int)) {
953 if(*fmt == 'U')
954 printf("%s%u", val, *(unsigned int *)p);
955 else
956 printf("%s%d", val, *(int *)p);
957 val = " ";
958 len -= sizeof (int);
959 p += sizeof (int);
960 }
b51d5b5f
A
961 retval = 0;
962 goto RETURN;
1815bff5
A
963
964 case 'L':
965 if (!nflag)
966 printf("%s: ", name);
967 fmt++;
968 val = "";
969 while (len >= sizeof(long)) {
970 if(*fmt == 'U')
971 printf("%s%lu", val, *(unsigned long *)p);
972 else
973 printf("%s%ld", val, *(long *)p);
974 val = " ";
975 len -= sizeof (long);
976 p += sizeof (long);
977 }
b51d5b5f
A
978 retval = 0;
979 goto RETURN;
1815bff5
A
980
981 case 'P':
982 if (!nflag)
983 printf("%s: ", name);
984 printf("%p", *(void **)p);
b51d5b5f
A
985 retval = 0;
986 goto RETURN;
1815bff5
A
987
988 case 'T':
989 case 'S':
990 i = 0;
991 if (!strcmp(fmt, "S,clockinfo")) func = S_clockinfo;
992 else if (!strcmp(fmt, "S,timeval")) func = S_timeval;
993 else if (!strcmp(fmt, "S,loadavg")) func = S_loadavg;
994 else if (!strcmp(fmt, "T,dev_t")) func = T_dev_t;
995 if (func) {
996 if (!nflag)
997 printf("%s: ", name);
b51d5b5f
A
998 retval = (*func)(len, p);
999 goto RETURN;
1815bff5
A
1000 }
1001 /* FALL THROUGH */
1002 default:
b51d5b5f
A
1003 if (!Aflag) {
1004 retval = 1;
1005 goto RETURN;
1006 }
1815bff5
A
1007 if (!nflag)
1008 printf("%s: ", name);
1009 printf("Format:%s Length:%ld Dump:0x", fmt, len);
1010 while (len--) {
1011 printf("%02x", *p++);
1012 if (Xflag || p < val+16)
1013 continue;
1014 printf("...");
1015 break;
1016 }
b51d5b5f
A
1017 retval = 0;
1018 goto RETURN;
1815bff5 1019 }
b51d5b5f
A
1020
1021 retval = 1;
1022 RETURN:
1023 free(mval);
1024 return (retval);
1815bff5
A
1025}
1026
1027static int
1028sysctl_all (int *oid, int len)
1029{
1030 int name1[22], name2[22];
1031 int i, j;
1032 size_t l1, l2;
1033
1034 name1[0] = 0;
1035 name1[1] = 2;
1036 l1 = 2;
1037 if (len) {
1038 memcpy(name1+2, oid, len*sizeof (int));
1039 l1 += len;
1040 } else {
1041 name1[2] = 1;
1042 l1++;
1043 }
1044 while (1) {
1045 l2 = sizeof name2;
1046 j = sysctl(name1, l1, name2, &l2, 0, 0);
1047 if (j < 0) {
1048 if (errno == ENOENT)
1049 return 0;
1050 else
1051 err(1, "sysctl(getnext) %d %d", j, l2);
1052 }
1053
1054 l2 /= sizeof (int);
1055
1056 if (l2 < len)
1057 return 0;
1058
1059 for (i = 0; i < len; i++)
1060 if (name2[i] != oid[i])
1061 return 0;
1062
1063 i = show_var(name2, l2);
1064 if (!i && !bflag)
1065 putchar('\n');
1066
1067 memcpy(name1+2, name2, l2*sizeof (int));
1068 l1 = 2 + l2;
1069 }
1070}