]> git.saurik.com Git - apple/system_cmds.git/blame - sysctl.tproj/sysctl.c
system_cmds-300.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 *
83f6dbe8
A
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.
1815bff5
A
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,
83f6dbe8
A
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.
1815bff5
A
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
92static 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
98static 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
127struct ctlname topname[] = CTL_NAMES;
128struct ctlname kernname[] = CTL_KERN_NAMES;
129struct ctlname vmname[] = CTL_VM_NAMES;
130struct ctlname hwname[] = CTL_HW_NAMES;
131struct ctlname username[] = CTL_USER_NAMES;
132struct ctlname debugname[CTL_DEBUG_MAXID];
133struct ctlname *vfsname;
134#ifdef CTL_MACHDEP_NAMES
135struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
136#endif
137char names[BUFSIZ];
138int lastused;
139
140struct list {
141 struct ctlname *list;
142 int size;
143};
144struct list toplist = { topname, CTL_MAXID };
145struct list secondlevel[] = {
146 { 0, 0 }, /* CTL_UNSPEC */
147 { kernname, KERN_MAXID }, /* CTL_KERN */
148 { vmname, VM_MAXID }, /* CTL_VM */
149 { 0, 0 }, /* CTL_VFS */
c3a08f59 150 { 0, 0 }, /* CTL_NET */
1815bff5 151 { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */
83f6dbe8 152 { hwname, HW_MAXID }, /* CTL_HW */
1815bff5
A
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
161static int Aflag, aflag, bflag, nflag, wflag, Xflag;
162static int foundSome = 0;
163
164void listall(char *prefix, struct list *lp);
165void old_parse(char *string, int flags);
166void debuginit();
167void vfsinit();
168int findname(char *string, char *level, char **bufp, struct list *namelist);
169void usage();
170
171static void parse(char *string, int flags);
172static int oidfmt(int *, int, char *, u_int *);
c3a08f59 173static int show_var(int *, int, int);
1815bff5
A
174static int sysctl_all (int *oid, int len);
175static 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
184int
185main(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();
83f6dbe8 216 for (; *argv != NULL; ++argv)
1815bff5
A
217 parse(*argv, 1);
218 exit(0);
219}
220
221/*
222 * List all variables known to the system.
223 */
224void
225listall(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 */
250void
251old_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:
b51d5b5f 350 useUnsignedInt = 1;
1815bff5
A
351 break;
352
353 case CTL_VM:
c3a08f59 354 if (mib[1] == VM_LOADAVG) { /* XXX this is bogus */
1815bff5
A
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 */
539void 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 */
564void 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 */
607int
608findname(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
83f6dbe8
A
617 /* Make 'sysctl kern.' style behave the same as 'sysctl kern' 3360872*/
618 if (bufp[0][strlen(*bufp)-1] == '.')
619 bufp[0][strlen(*bufp)-1]='\0';
1815bff5
A
620 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
621 fprintf(stderr, "%s: incomplete specification\n", string);
622 return (-1);
623 }
624 for (i = 0; i < namelist->size; i++)
625 if (namelist->list[i].ctl_name != NULL &&
626 strcmp(name, namelist->list[i].ctl_name) == 0)
627 break;
628 if (i == namelist->size) {
629 fprintf(stderr, "%s level name %s in %s is invalid\n",
630 level, name, string);
631 return (-1);
632 }
633 return (i);
634}
635
636void usage()
637{
638
639 (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
640 "usage: sysctl [-bn] variable ...",
641 " sysctl [-bn] -w variable=value ...",
642 " sysctl [-bn] -a",
643 " sysctl [-bn] -A",
644 " sysctl [-bn] -X");
645 exit(1);
646}
647
648/*
649 * Parse a name into a MIB entry.
650 * Lookup and print out the MIB entry if it exists.
651 * Set a new value if requested.
652 */
653static void
654parse(char *string, int flags)
655{
656 int len, i, j;
657 void *newval = 0;
658 int intval, newsize = 0;
659 unsigned int uintval;
660 quad_t quadval;
661 int mib[CTL_MAXNAME];
662 char *cp, *bufp, buf[BUFSIZ], fmt[BUFSIZ];
663 u_int kind;
664
665 bufp = buf;
666 snprintf(buf, BUFSIZ, "%s", string);
667 if ((cp = strchr(string, '=')) != NULL) {
668 if (!wflag)
669 errx(2, "must specify -w to set variables");
670 *strchr(buf, '=') = '\0';
671 *cp++ = '\0';
672 while (isspace(*cp))
673 cp++;
674 newval = cp;
675 newsize = strlen(cp);
676 } else {
677 if (wflag)
678 usage();
679 }
680 len = name2oid(bufp, mib);
681
682 if (len < 0) {
683 if (cp != NULL) {
684 while (*cp != '\0') cp--;
685 *cp = '=';
686 }
687 old_parse (string, flags);
688 return;
689 }
690
691 if (oidfmt(mib, len, fmt, &kind))
692 err(1, "couldn't find format of oid '%s'", bufp);
693
694 if (!wflag) {
695 if ((kind & CTLTYPE) == CTLTYPE_NODE) {
696 sysctl_all(mib, len);
697 foundSome = 1;
698 old_parse (string, flags);
699 } else {
c3a08f59 700 i = show_var(mib, len, 1);
1815bff5
A
701 if (!i && !bflag)
702 putchar('\n');
703 }
704 } else {
705 if ((kind & CTLTYPE) == CTLTYPE_NODE)
706 errx(1, "oid '%s' isn't a leaf node", bufp);
707
708 if (!(kind&CTLFLAG_WR))
709 errx(1, "oid '%s' is read only", bufp);
710
711 switch (kind & CTLTYPE) {
712 case CTLTYPE_INT:
713 if ((*fmt == 'I') && (*(fmt + 1) == 'U')) {
714 uintval = (unsigned int) strtoul (newval, NULL, 0);
715 newval = &uintval;
716 newsize = sizeof uintval;
717 } else {
718 intval = (int) strtol(newval, NULL, 0);
719 newval = &intval;
720 newsize = sizeof intval;
721 }
722 break;
723 case CTLTYPE_STRING:
724 break;
725 case CTLTYPE_QUAD:
726 break;
727 sscanf(newval, "%qd", &quadval);
728 newval = &quadval;
729 newsize = sizeof quadval;
730 break;
731 default:
732 errx(1, "oid '%s' is type %d,"
733 " cannot set that", bufp,
734 kind & CTLTYPE);
735 }
736
c3a08f59 737 i = show_var(mib, len, 1);
1815bff5
A
738 if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
739 if (!i && !bflag)
740 putchar('\n');
741 switch (errno) {
742 case EOPNOTSUPP:
743 errx(1, "%s: value is not available",
744 string);
745 case ENOTDIR:
746 errx(1, "%s: specification is incomplete",
747 string);
748 case ENOMEM:
749 errx(1, "%s: type is unknown to this program",
750 string);
751 default:
752 warn("%s", string);
753 return;
754 }
755 }
756 if (!bflag)
757 printf(" -> ");
758 i = nflag;
759 nflag = 1;
c3a08f59 760 j = show_var(mib, len, 1);
1815bff5
A
761 if (!j && !bflag)
762 putchar('\n');
763 nflag = i;
764 }
765}
766
767/* These functions will dump out various interesting structures. */
768
769static int
770S_clockinfo(int l2, void *p)
771{
772 struct clockinfo *ci = (struct clockinfo*)p;
773 if (l2 != sizeof *ci)
774 err(1, "S_clockinfo %d != %d", l2, sizeof *ci);
775 printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
776 ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz);
777 return (0);
778}
779
780static int
781S_loadavg(int l2, void *p)
782{
783 struct loadavg *tv = (struct loadavg*)p;
784
785 if (l2 != sizeof *tv)
786 err(1, "S_loadavg %d != %d", l2, sizeof *tv);
787
788 printf("{ %.2f %.2f %.2f }",
789 (double)tv->ldavg[0]/(double)tv->fscale,
790 (double)tv->ldavg[1]/(double)tv->fscale,
791 (double)tv->ldavg[2]/(double)tv->fscale);
792 return (0);
793}
794
795static int
796S_timeval(int l2, void *p)
797{
798 struct timeval *tv = (struct timeval*)p;
799 time_t tv_sec;
800 char *p1, *p2;
801
802 if (l2 != sizeof *tv)
803 err(1, "S_timeval %d != %d", l2, sizeof *tv);
804 printf("{ sec = %ld, usec = %ld } ",
805 (long) tv->tv_sec, (long) tv->tv_usec);
806 tv_sec = tv->tv_sec;
807 p1 = strdup(ctime(&tv_sec));
808 for (p2=p1; *p2 ; p2++)
809 if (*p2 == '\n')
810 *p2 = '\0';
811 fputs(p1, stdout);
812 return (0);
813}
814
815static int
816T_dev_t(int l2, void *p)
817{
818 dev_t *d = (dev_t *)p;
819 if (l2 != sizeof *d)
820 err(1, "T_dev_T %d != %d", l2, sizeof *d);
821 if ((int)(*d) != -1) {
822 if (minor(*d) > 255 || minor(*d) < 0)
823 printf("{ major = %d, minor = 0x%x }",
824 major(*d), minor(*d));
825 else
826 printf("{ major = %d, minor = %d }",
827 major(*d), minor(*d));
828 }
829 return (0);
830}
831
832/*
833 * These functions uses a presently undocumented interface to the kernel
834 * to walk the tree and get the type so it can print the value.
835 * This interface is under work and consideration, and should probably
836 * be killed with a big axe by the first person who can find the time.
837 * (be aware though, that the proper interface isn't as obvious as it
838 * may seem, there are various conflicting requirements.
839 */
840
841static int
842name2oid(char *name, int *oidp)
843{
844 int oid[2];
845 int i;
846 size_t j;
847
848 oid[0] = 0;
849 oid[1] = 3;
850
851 j = CTL_MAXNAME * sizeof (int);
852 i = sysctl(oid, 2, oidp, &j, name, strlen(name));
853 if (i < 0)
854 return i;
855 j /= sizeof (int);
856 return (j);
857}
858
859static int
860oidfmt(int *oid, int len, char *fmt, u_int *kind)
861{
862 int qoid[CTL_MAXNAME+2];
863 u_char buf[BUFSIZ];
864 int i;
865 size_t j;
866
867 qoid[0] = 0;
868 qoid[1] = 4;
869 memcpy(qoid + 2, oid, len * sizeof(int));
870
871 j = sizeof buf;
872 i = sysctl(qoid, len + 2, buf, &j, 0, 0);
873 if (i)
874 err(1, "sysctl fmt %d %d %d", i, j, errno);
875
876 if (kind)
877 *kind = *(u_int *)buf;
878
879 if (fmt)
880 strcpy(fmt, (char *)(buf + sizeof(u_int)));
881 return 0;
882}
883
884/*
885 * This formats and outputs the value of one variable
886 *
887 * Returns zero if anything was actually output.
888 * Returns one if didn't know what to do with this.
889 * Return minus one if we had errors.
890 */
891
892static int
c3a08f59 893show_var(int *oid, int nlen, int show_masked)
1815bff5 894{
b51d5b5f 895 u_char buf[BUFSIZ], *val, *mval, *p;
1815bff5
A
896 char name[BUFSIZ], /* descr[BUFSIZ], */ *fmt;
897 int qoid[CTL_MAXNAME+2];
898 int i;
b51d5b5f 899 int retval;
1815bff5
A
900 size_t j, len;
901 u_int kind;
902 int (*func)(int, void *) = 0;
903
904 qoid[0] = 0;
905 memcpy(qoid + 2, oid, nlen * sizeof(int));
906
907 qoid[1] = 1;
908 j = sizeof name;
909 i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
910 if (i || !j)
911 err(1, "sysctl name %d %d %d", i, j, errno);
912
913 /* find an estimate of how much we need for this var */
914 j = 0;
915 i = sysctl(oid, nlen, 0, &j, 0, 0);
916 j += j; /* we want to be sure :-) */
917
b51d5b5f 918 val = mval = malloc(j);
1815bff5
A
919 len = j;
920 i = sysctl(oid, nlen, val, &len, 0, 0);
b51d5b5f
A
921 if (i || !len) {
922 retval = 1;
923 goto RETURN;
924 }
1815bff5
A
925
926 if (bflag) {
927 fwrite(val, 1, len, stdout);
b51d5b5f
A
928 retval = 0;
929 goto RETURN;
1815bff5
A
930 }
931
932 qoid[1] = 4;
933 j = sizeof buf;
934 i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
935 if (i || !j)
936 err(1, "sysctl fmt %d %d %d", i, j, errno);
937
938 kind = *(u_int *)buf;
c3a08f59
A
939 if (!show_masked && (kind & CTLFLAG_MASKED)) {
940 retval = 1;
941 goto RETURN;
942 }
1815bff5
A
943
944 fmt = (char *)(buf + sizeof(u_int));
945
946 p = val;
947 switch (*fmt) {
c3a08f59
A
948 case '-':
949 /* deprecated, do not print */
950 retval = 0;
951 goto RETURN;
952
953
1815bff5
A
954 case 'A':
955 if (!nflag)
956 printf("%s: ", name);
957 printf("%s", p);
b51d5b5f
A
958 retval = 0;
959 goto RETURN;
1815bff5
A
960
961 case 'I':
962 if (!nflag)
963 printf("%s: ", name);
964 fmt++;
965 val = "";
966 while (len >= sizeof(int)) {
967 if(*fmt == 'U')
968 printf("%s%u", val, *(unsigned int *)p);
969 else
970 printf("%s%d", val, *(int *)p);
971 val = " ";
972 len -= sizeof (int);
973 p += sizeof (int);
974 }
b51d5b5f
A
975 retval = 0;
976 goto RETURN;
1815bff5
A
977
978 case 'L':
979 if (!nflag)
980 printf("%s: ", name);
981 fmt++;
982 val = "";
983 while (len >= sizeof(long)) {
984 if(*fmt == 'U')
985 printf("%s%lu", val, *(unsigned long *)p);
986 else
987 printf("%s%ld", val, *(long *)p);
988 val = " ";
989 len -= sizeof (long);
990 p += sizeof (long);
991 }
b51d5b5f
A
992 retval = 0;
993 goto RETURN;
1815bff5
A
994
995 case 'P':
996 if (!nflag)
997 printf("%s: ", name);
998 printf("%p", *(void **)p);
b51d5b5f
A
999 retval = 0;
1000 goto RETURN;
1815bff5 1001
c3a08f59
A
1002 case 'Q':
1003 if (!nflag)
1004 printf("%s: ", name);
1005 fmt++;
1006 val = "";
1007 while (len >= sizeof(long long)) {
1008 if(*fmt == 'U')
1009 printf("%s%llu", val, *(unsigned long long *)p);
1010 else
1011 printf("%s%lld", val, *(long long *)p);
1012 val = " ";
1013 len -= sizeof (long long);
1014 p += sizeof (long long);
1015 }
1016 retval = 0;
1017 goto RETURN;
1018
1019
1815bff5
A
1020 case 'T':
1021 case 'S':
1022 i = 0;
1023 if (!strcmp(fmt, "S,clockinfo")) func = S_clockinfo;
1024 else if (!strcmp(fmt, "S,timeval")) func = S_timeval;
1025 else if (!strcmp(fmt, "S,loadavg")) func = S_loadavg;
1026 else if (!strcmp(fmt, "T,dev_t")) func = T_dev_t;
1027 if (func) {
1028 if (!nflag)
1029 printf("%s: ", name);
b51d5b5f
A
1030 retval = (*func)(len, p);
1031 goto RETURN;
1815bff5
A
1032 }
1033 /* FALL THROUGH */
1034 default:
b51d5b5f
A
1035 if (!Aflag) {
1036 retval = 1;
1037 goto RETURN;
1038 }
1815bff5
A
1039 if (!nflag)
1040 printf("%s: ", name);
1041 printf("Format:%s Length:%ld Dump:0x", fmt, len);
1042 while (len--) {
1043 printf("%02x", *p++);
1044 if (Xflag || p < val+16)
1045 continue;
1046 printf("...");
1047 break;
1048 }
b51d5b5f
A
1049 retval = 0;
1050 goto RETURN;
1815bff5 1051 }
b51d5b5f
A
1052
1053 retval = 1;
1054 RETURN:
1055 free(mval);
1056 return (retval);
1815bff5
A
1057}
1058
1059static int
1060sysctl_all (int *oid, int len)
1061{
1062 int name1[22], name2[22];
1063 int i, j;
1064 size_t l1, l2;
1065
1066 name1[0] = 0;
1067 name1[1] = 2;
1068 l1 = 2;
1069 if (len) {
1070 memcpy(name1+2, oid, len*sizeof (int));
1071 l1 += len;
1072 } else {
1073 name1[2] = 1;
1074 l1++;
1075 }
1076 while (1) {
1077 l2 = sizeof name2;
1078 j = sysctl(name1, l1, name2, &l2, 0, 0);
1079 if (j < 0) {
1080 if (errno == ENOENT)
1081 return 0;
1082 else
1083 err(1, "sysctl(getnext) %d %d", j, l2);
1084 }
1085
1086 l2 /= sizeof (int);
1087
1088 if (l2 < len)
1089 return 0;
1090
1091 for (i = 0; i < len; i++)
1092 if (name2[i] != oid[i])
1093 return 0;
1094
c3a08f59 1095 i = show_var(name2, l2, 0);
1815bff5
A
1096 if (!i && !bflag)
1097 putchar('\n');
1098
1099 memcpy(name1+2, name2, l2*sizeof (int));
1100 l1 = 2 + l2;
1101 }
1102}