]> git.saurik.com Git - apple/system_cmds.git/blame - sysctl.tproj/sysctl.c
system_cmds-336.23.tar.gz
[apple/system_cmds.git] / sysctl.tproj / sysctl.c
CommitLineData
1815bff5 1/*
2fc1e207 2 * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved.
1815bff5
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
2fc1e207
A
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.
1815bff5
A
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,
2fc1e207
A
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."
1815bff5
A
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__ */
1815bff5
A
113
114#include <errno.h>
115#include <ctype.h>
116#include <unistd.h>
117#include <stdio.h>
118#include <stdlib.h>
119#include <string.h>
120
121#include <sys/types.h>
122#include <sys/resource.h>
123#include <err.h>
124
125struct ctlname topname[] = CTL_NAMES;
126struct ctlname kernname[] = CTL_KERN_NAMES;
127struct ctlname vmname[] = CTL_VM_NAMES;
128struct ctlname hwname[] = CTL_HW_NAMES;
129struct ctlname username[] = CTL_USER_NAMES;
130struct ctlname debugname[CTL_DEBUG_MAXID];
131struct ctlname *vfsname;
132#ifdef CTL_MACHDEP_NAMES
133struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
134#endif
135char names[BUFSIZ];
136int lastused;
137
138struct list {
139 struct ctlname *list;
140 int size;
141};
142struct list toplist = { topname, CTL_MAXID };
143struct list secondlevel[] = {
144 { 0, 0 }, /* CTL_UNSPEC */
145 { kernname, KERN_MAXID }, /* CTL_KERN */
146 { vmname, VM_MAXID }, /* CTL_VM */
147 { 0, 0 }, /* CTL_VFS */
c3a08f59 148 { 0, 0 }, /* CTL_NET */
1815bff5 149 { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */
83f6dbe8 150 { hwname, HW_MAXID }, /* CTL_HW */
1815bff5
A
151#ifdef CTL_MACHDEP_NAMES
152 { machdepname, CPU_MAXID }, /* CTL_MACHDEP */
153#else
154 { 0, 0 }, /* CTL_MACHDEP */
155#endif
156 { username, USER_MAXID }, /* CTL_USER_NAMES */
157};
158
159static int Aflag, aflag, bflag, nflag, wflag, Xflag;
160static int foundSome = 0;
161
162void listall(char *prefix, struct list *lp);
163void old_parse(char *string, int flags);
164void debuginit();
165void vfsinit();
166int findname(char *string, char *level, char **bufp, struct list *namelist);
167void usage();
168
169static void parse(char *string, int flags);
170static int oidfmt(int *, int, char *, u_int *);
c3a08f59 171static int show_var(int *, int, int);
1815bff5
A
172static int sysctl_all (int *oid, int len);
173static int name2oid(char *, int *);
174
175/*
176 * Variables requiring special processing.
177 */
178#define CLOCK 0x00000001
179#define BOOTTIME 0x00000002
180#define CONSDEV 0x00000004
181
182int
183main(argc, argv)
184 int argc;
185 char *argv[];
186{
187// extern char *optarg; // unused
188 extern int optind;
189 int ch, lvl1;
190
191 while ((ch = getopt(argc, argv, "AabnwX")) != EOF) {
192 switch (ch) {
193 case 'A': Aflag = 1; break;
194 case 'a': aflag = 1; break;
195 case 'b': bflag = 1; break;
196 case 'n': nflag = 1; break;
197 case 'w': wflag = 1; break;
198 case 'X': Xflag = Aflag = 1; break;
199 default: usage();
200 }
201 }
202 argc -= optind;
203 argv += optind;
204
205 if (argc == 0 && (Aflag || aflag)) {
206 debuginit();
207 vfsinit();
208 for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
209 listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
210 exit (sysctl_all(0, 0));
211 }
212 if (argc == 0)
213 usage();
83f6dbe8 214 for (; *argv != NULL; ++argv)
1815bff5
A
215 parse(*argv, 1);
216 exit(0);
217}
218
219/*
220 * List all variables known to the system.
221 */
222void
223listall(prefix, lp)
224 char *prefix;
225 struct list *lp;
226{
227 int lvl2;
228 char *cp, name[BUFSIZ];
229
230 if (lp->list == 0)
231 return;
232 strcpy(name, prefix);
233 cp = &name[strlen(name)];
234 *cp++ = '.';
235 for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
236 if (lp->list[lvl2].ctl_name == 0)
237 continue;
238 strcpy(cp, lp->list[lvl2].ctl_name);
239 old_parse(name, Aflag);
240 }
241}
242
243/*
244 * Parse a name into a MIB entry.
245 * Lookup and print out the MIB entry if it exists.
246 * Set a new value if requested.
247 */
248void
249old_parse(string, flags)
250 char *string;
251 int flags;
252{
253 int indx, type, state, len;
254 size_t size;
255 int special = 0;
256 void *newval = 0;
257 int intval, newsize = 0;
258 unsigned int uintval;
259 int useUnsignedInt = 0;
260 quad_t quadval;
261 struct list *lp;
262 struct vfsconf vfc;
263 int mib[CTL_MAXNAME];
264 char *cp, *bufp, buf[BUFSIZ] /*, strval[BUFSIZ] */ ;
265
266 bufp = buf;
267 snprintf(buf, BUFSIZ, "%s", string);
268 if ((cp = strchr(string, '=')) != NULL) {
269 if (!wflag) {
270 fprintf(stderr, "Must specify -w to set variables\n");
271 exit(2);
272 }
273 *strchr(buf, '=') = '\0';
274 *cp++ = '\0';
275 while (isspace(*cp))
276 cp++;
277 newval = cp;
278 newsize = strlen(cp);
279 }
280 if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
281 return;
282 mib[0] = indx;
283 if (indx == CTL_VFS)
284 vfsinit();
285 if (indx == CTL_DEBUG)
286 debuginit();
287 lp = &secondlevel[indx];
288 if (lp->list == 0) {
289 if (!foundSome) fprintf(stderr, "%s: class is not implemented\n",
290 topname[indx].ctl_name);
291 return;
292 }
293 if (bufp == NULL) {
294 listall(topname[indx].ctl_name, lp);
295 return;
296 }
297 if ((indx = findname(string, "second", &bufp, lp)) == -1)
298 return;
299 mib[1] = indx;
300 type = lp->list[indx].ctl_type;
301 len = 2;
302 switch (mib[0]) {
303
304 case CTL_KERN:
305 switch (mib[1]) {
306 case KERN_PROF:
307 mib[2] = GPROF_STATE;
308 size = sizeof state;
309 if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) {
310 if (flags == 0)
311 return;
312 if (!nflag)
313 fprintf(stdout, "%s: ", string);
314 fprintf(stderr,
315 "kernel is not compiled for profiling\n");
316 return;
317 }
318 if (!nflag)
319 fprintf(stdout, "%s: %s\n", string,
320 state == GMON_PROF_OFF ? "off" : "running");
321 return;
322 case KERN_VNODE:
323 case KERN_FILE:
324 if (flags == 0)
325 return;
326 fprintf(stderr,
327 "Use pstat to view %s information\n", string);
328 return;
329 case KERN_PROC:
330 if (flags == 0)
331 return;
332 fprintf(stderr,
333 "Use ps to view %s information\n", string);
334 return;
335 case KERN_CLOCKRATE:
336 special |= CLOCK;
337 break;
338 case KERN_BOOTTIME:
339 special |= BOOTTIME;
340 break;
341 case KERN_HOSTID:
342 useUnsignedInt = 1;
343 break;
344 }
345 break;
346
347 case CTL_HW:
b51d5b5f 348 useUnsignedInt = 1;
1815bff5
A
349 break;
350
351 case CTL_VM:
2fc1e207
A
352 switch (mib[1]) {
353 case VM_LOADAVG: { /* XXX this is bogus */
1815bff5
A
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 }
2fc1e207
A
363 case VM_SWAPUSAGE: {
364 struct xsw_usage xsu;
365 int saved_errno;
366
367 size = sizeof (xsu);
368 if (sysctl(mib, 2, &xsu, &size, NULL, 0) != 0) {
369 if (flags == 0)
370 return;
371 saved_errno = errno;
372 if (!nflag)
373 fprintf(stderr, "%s: ", string);
374 fprintf(stderr, "sysctl(VM_SWAPUSAGE): %s\n",
375 strerror(saved_errno));
376 return;
377 }
378
379 if (!nflag)
380 fprintf(stdout, "%s: ", string);
381 fprintf(stdout,
382 "total = %.2fM used = %.2fM free = %.2fM %s\n",
383 ((double) xsu.xsu_total) / (1024.0 * 1024.0),
384 ((double) xsu.xsu_used) / (1024.0 * 1024.0),
385 ((double) xsu.xsu_avail) / (1024.0 * 1024.0),
386 xsu.xsu_encrypted ? "(encrypted)" : "");
387 return;
388 }
389 }
1815bff5
A
390 if (flags == 0)
391 return;
392 fprintf(stderr,
393 "Use vmstat or systat to view %s information\n", string);
394 return;
395
396 case CTL_DEBUG:
397 mib[2] = CTL_DEBUG_VALUE;
398 len = 3;
399 break;
400
401 case CTL_MACHDEP:
402#ifdef CPU_CONSDEV
403 if (mib[1] == CPU_CONSDEV)
404 special |= CONSDEV;
405#endif
406 break;
407
408 case CTL_VFS:
409 mib[3] = mib[1];
410 mib[1] = VFS_GENERIC;
411 mib[2] = VFS_CONF;
412 len = 4;
413 size = sizeof vfc;
414 if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
415 perror("vfs print");
416 return;
417 }
418 if (flags == 0 && vfc.vfc_refcount == 0)
419 return;
420 if (!nflag)
421 fprintf(stdout, "%s has %d mounted instance%s\n",
422 string, vfc.vfc_refcount,
423 vfc.vfc_refcount != 1 ? "s" : "");
424 else
425 fprintf(stdout, "%d\n", vfc.vfc_refcount);
426 return;
427
428 case CTL_USER:
429 break;
430
431 default:
432 fprintf(stderr, "Illegal top level value: %d\n", mib[0]);
433 return;
434
435 }
436 if (bufp) {
437 fprintf(stderr, "name %s in %s is unknown\n", bufp, string);
438 return;
439 }
440 if (newsize > 0) {
441 switch (type) {
442 case CTLTYPE_INT:
443 if (useUnsignedInt) {
444 uintval = strtoul(newval, 0, 0);
445 newval = &uintval;
446 newsize = sizeof uintval;
447 } else {
448 intval = atoi(newval);
449 newval = &intval;
450 newsize = sizeof intval;
451 }
452 break;
453
454 case CTLTYPE_QUAD:
455 sscanf(newval, "%qd", &quadval);
456 newval = &quadval;
457 newsize = sizeof quadval;
458 break;
459 }
460 }
461 size = BUFSIZ;
462 if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
463 if (flags == 0)
464 return;
465 switch (errno) {
466 case EOPNOTSUPP:
467 fprintf(stderr, "%s: value is not available\n", string);
468 return;
469 case ENOTDIR:
470 fprintf(stderr, "%s: specification is incomplete\n",
471 string);
472 return;
473 case ENOMEM:
474 fprintf(stderr, "%s: type is unknown to this program\n",
475 string);
476 return;
477 default:
478 perror(string);
479 return;
480 }
481 }
482 if (special & CLOCK) {
483 struct clockinfo *clkp = (struct clockinfo *)buf;
484
485 if (!nflag)
486 fprintf(stdout, "%s: ", string);
487 fprintf(stdout,
488 "hz = %d, tick = %d, profhz = %d, stathz = %d\n",
489 clkp->hz, clkp->tick, clkp->profhz, clkp->stathz);
490 return;
491 }
492 if (special & BOOTTIME) {
493 struct timeval *btp = (struct timeval *)buf;
494
495 if (!nflag)
496 fprintf(stdout, "%s = %s\n", string,
497 ctime((time_t *) &btp->tv_sec));
498 else
499 fprintf(stdout, "%d\n", btp->tv_sec);
500 return;
501 }
502 if (special & CONSDEV) {
503 dev_t dev = *(dev_t *)buf;
504
505 if (!nflag)
506 fprintf(stdout, "%s = %s\n", string,
507 devname(dev, S_IFCHR));
508 else
509 fprintf(stdout, "0x%x\n", dev);
510 return;
511 }
512 switch (type) {
513 case CTLTYPE_INT:
514 if (newsize == 0) {
515 if (!nflag)
516 fprintf(stdout, "%s = ", string);
517 fprintf(stdout, useUnsignedInt ? "%u\n" : "%d\n", *(int *)buf);
518 } else {
519 if (!nflag)
520 fprintf(stdout, useUnsignedInt ? "%s: %u -> " : "%s: %d -> ",
521 string, *(int *)buf);
522 fprintf(stdout, useUnsignedInt ? "%u\n" : "%d\n", *(int *)newval);
523 }
524 return;
525
526 case CTLTYPE_STRING:
527 if (newsize == 0) {
528 if (!nflag)
529 fprintf(stdout, "%s = ", string);
530 fprintf(stdout, "%s\n", buf);
531 } else {
532 if (!nflag)
533 fprintf(stdout, "%s: %s -> ", string, buf);
534 fprintf(stdout, "%s\n", (char *) newval);
535 }
536 return;
537
538 case CTLTYPE_QUAD:
539 if (newsize == 0) {
540 if (!nflag)
541 fprintf(stdout, "%s = ", string);
542 fprintf(stdout, "%qd\n", *(quad_t *)buf);
543 } else {
544 if (!nflag)
545 fprintf(stdout, "%s: %qd -> ", string,
546 *(quad_t *)buf);
547 fprintf(stdout, "%qd\n", *(quad_t *)newval);
548 }
549 return;
550
551 case CTLTYPE_STRUCT:
552 return;
553
554 default:
555 case CTLTYPE_NODE:
556 fprintf(stderr, "%s: unknown type returned\n",
557 string);
558 return;
559 }
560}
561
562/*
563 * Initialize the set of debugging names
564 */
565void debuginit()
566{
567 int mib[3], loc, i;
568 size_t size;
569
570 if (secondlevel[CTL_DEBUG].list != 0)
571 return;
572 secondlevel[CTL_DEBUG].list = debugname;
573 mib[0] = CTL_DEBUG;
574 mib[2] = CTL_DEBUG_NAME;
575 for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
576 mib[1] = i;
577 size = BUFSIZ - loc;
578 if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
579 continue;
580 debugname[i].ctl_name = &names[loc];
581 debugname[i].ctl_type = CTLTYPE_INT;
582 loc += size;
583 }
584 lastused = loc;
585}
586
587/*
588 * Initialize the set of filesystem names
589 */
590void vfsinit()
591{
592 int mib[4], maxtypenum, cnt, loc, size;
593 struct vfsconf vfc;
594 size_t buflen;
595
596 if (secondlevel[CTL_VFS].list != 0)
597 return;
598 mib[0] = CTL_VFS;
599 mib[1] = VFS_GENERIC;
600 mib[2] = VFS_MAXTYPENUM;
601 buflen = 4;
602 if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
603 return;
604 if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == 0)
605 return;
606 memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
607 mib[2] = VFS_CONF;
608 buflen = sizeof vfc;
609 for (loc = lastused, cnt = 0; cnt < maxtypenum; cnt++) {
610 mib[3] = cnt;
611 if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
612 if (errno == EOPNOTSUPP)
613 continue;
614 perror("vfsinit");
615 free(vfsname);
616 return;
617 }
618 strcat(&names[loc], vfc.vfc_name);
619 vfsname[cnt].ctl_name = &names[loc];
620 vfsname[cnt].ctl_type = CTLTYPE_INT;
621 size = strlen(vfc.vfc_name) + 1;
622 loc += size;
623 }
624 lastused = loc;
625 secondlevel[CTL_VFS].list = vfsname;
626 secondlevel[CTL_VFS].size = maxtypenum;
627 return;
628}
629
630/*
631 * Scan a list of names searching for a particular name.
632 */
633int
634findname(string, level, bufp, namelist)
635 char *string;
636 char *level;
637 char **bufp;
638 struct list *namelist;
639{
640 char *name;
641 int i;
642
83f6dbe8
A
643 /* Make 'sysctl kern.' style behave the same as 'sysctl kern' 3360872*/
644 if (bufp[0][strlen(*bufp)-1] == '.')
645 bufp[0][strlen(*bufp)-1]='\0';
1815bff5
A
646 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
647 fprintf(stderr, "%s: incomplete specification\n", string);
648 return (-1);
649 }
650 for (i = 0; i < namelist->size; i++)
651 if (namelist->list[i].ctl_name != NULL &&
652 strcmp(name, namelist->list[i].ctl_name) == 0)
653 break;
654 if (i == namelist->size) {
655 fprintf(stderr, "%s level name %s in %s is invalid\n",
656 level, name, string);
657 return (-1);
658 }
659 return (i);
660}
661
662void usage()
663{
664
665 (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
666 "usage: sysctl [-bn] variable ...",
667 " sysctl [-bn] -w variable=value ...",
668 " sysctl [-bn] -a",
669 " sysctl [-bn] -A",
670 " sysctl [-bn] -X");
671 exit(1);
672}
673
674/*
675 * Parse a name into a MIB entry.
676 * Lookup and print out the MIB entry if it exists.
677 * Set a new value if requested.
678 */
679static void
680parse(char *string, int flags)
681{
682 int len, i, j;
683 void *newval = 0;
684 int intval, newsize = 0;
685 unsigned int uintval;
686 quad_t quadval;
687 int mib[CTL_MAXNAME];
688 char *cp, *bufp, buf[BUFSIZ], fmt[BUFSIZ];
689 u_int kind;
690
691 bufp = buf;
692 snprintf(buf, BUFSIZ, "%s", string);
693 if ((cp = strchr(string, '=')) != NULL) {
694 if (!wflag)
695 errx(2, "must specify -w to set variables");
696 *strchr(buf, '=') = '\0';
697 *cp++ = '\0';
698 while (isspace(*cp))
699 cp++;
700 newval = cp;
701 newsize = strlen(cp);
702 } else {
703 if (wflag)
704 usage();
705 }
706 len = name2oid(bufp, mib);
707
708 if (len < 0) {
709 if (cp != NULL) {
710 while (*cp != '\0') cp--;
711 *cp = '=';
712 }
713 old_parse (string, flags);
714 return;
715 }
716
717 if (oidfmt(mib, len, fmt, &kind))
718 err(1, "couldn't find format of oid '%s'", bufp);
719
720 if (!wflag) {
721 if ((kind & CTLTYPE) == CTLTYPE_NODE) {
722 sysctl_all(mib, len);
723 foundSome = 1;
724 old_parse (string, flags);
725 } else {
c3a08f59 726 i = show_var(mib, len, 1);
1815bff5
A
727 if (!i && !bflag)
728 putchar('\n');
729 }
730 } else {
731 if ((kind & CTLTYPE) == CTLTYPE_NODE)
732 errx(1, "oid '%s' isn't a leaf node", bufp);
733
734 if (!(kind&CTLFLAG_WR))
735 errx(1, "oid '%s' is read only", bufp);
736
737 switch (kind & CTLTYPE) {
738 case CTLTYPE_INT:
739 if ((*fmt == 'I') && (*(fmt + 1) == 'U')) {
740 uintval = (unsigned int) strtoul (newval, NULL, 0);
741 newval = &uintval;
742 newsize = sizeof uintval;
743 } else {
744 intval = (int) strtol(newval, NULL, 0);
745 newval = &intval;
746 newsize = sizeof intval;
747 }
748 break;
749 case CTLTYPE_STRING:
750 break;
751 case CTLTYPE_QUAD:
2fc1e207 752 quadval = strtoq(newval, NULL, 0);
1815bff5
A
753 newval = &quadval;
754 newsize = sizeof quadval;
755 break;
756 default:
757 errx(1, "oid '%s' is type %d,"
758 " cannot set that", bufp,
759 kind & CTLTYPE);
760 }
761
c3a08f59 762 i = show_var(mib, len, 1);
1815bff5
A
763 if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
764 if (!i && !bflag)
765 putchar('\n');
766 switch (errno) {
767 case EOPNOTSUPP:
768 errx(1, "%s: value is not available",
769 string);
770 case ENOTDIR:
771 errx(1, "%s: specification is incomplete",
772 string);
773 case ENOMEM:
774 errx(1, "%s: type is unknown to this program",
775 string);
776 default:
777 warn("%s", string);
778 return;
779 }
780 }
781 if (!bflag)
782 printf(" -> ");
783 i = nflag;
784 nflag = 1;
c3a08f59 785 j = show_var(mib, len, 1);
1815bff5
A
786 if (!j && !bflag)
787 putchar('\n');
788 nflag = i;
789 }
790}
791
792/* These functions will dump out various interesting structures. */
793
794static int
795S_clockinfo(int l2, void *p)
796{
797 struct clockinfo *ci = (struct clockinfo*)p;
798 if (l2 != sizeof *ci)
799 err(1, "S_clockinfo %d != %d", l2, sizeof *ci);
800 printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
801 ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz);
802 return (0);
803}
804
805static int
806S_loadavg(int l2, void *p)
807{
808 struct loadavg *tv = (struct loadavg*)p;
809
810 if (l2 != sizeof *tv)
811 err(1, "S_loadavg %d != %d", l2, sizeof *tv);
812
813 printf("{ %.2f %.2f %.2f }",
814 (double)tv->ldavg[0]/(double)tv->fscale,
815 (double)tv->ldavg[1]/(double)tv->fscale,
816 (double)tv->ldavg[2]/(double)tv->fscale);
817 return (0);
818}
819
820static int
821S_timeval(int l2, void *p)
822{
823 struct timeval *tv = (struct timeval*)p;
824 time_t tv_sec;
825 char *p1, *p2;
826
827 if (l2 != sizeof *tv)
828 err(1, "S_timeval %d != %d", l2, sizeof *tv);
829 printf("{ sec = %ld, usec = %ld } ",
830 (long) tv->tv_sec, (long) tv->tv_usec);
831 tv_sec = tv->tv_sec;
832 p1 = strdup(ctime(&tv_sec));
833 for (p2=p1; *p2 ; p2++)
834 if (*p2 == '\n')
835 *p2 = '\0';
836 fputs(p1, stdout);
837 return (0);
838}
839
840static int
841T_dev_t(int l2, void *p)
842{
843 dev_t *d = (dev_t *)p;
844 if (l2 != sizeof *d)
845 err(1, "T_dev_T %d != %d", l2, sizeof *d);
846 if ((int)(*d) != -1) {
847 if (minor(*d) > 255 || minor(*d) < 0)
848 printf("{ major = %d, minor = 0x%x }",
849 major(*d), minor(*d));
850 else
851 printf("{ major = %d, minor = %d }",
852 major(*d), minor(*d));
853 }
854 return (0);
855}
856
857/*
858 * These functions uses a presently undocumented interface to the kernel
859 * to walk the tree and get the type so it can print the value.
860 * This interface is under work and consideration, and should probably
861 * be killed with a big axe by the first person who can find the time.
862 * (be aware though, that the proper interface isn't as obvious as it
863 * may seem, there are various conflicting requirements.
864 */
865
866static int
867name2oid(char *name, int *oidp)
868{
869 int oid[2];
870 int i;
871 size_t j;
872
873 oid[0] = 0;
874 oid[1] = 3;
875
876 j = CTL_MAXNAME * sizeof (int);
877 i = sysctl(oid, 2, oidp, &j, name, strlen(name));
878 if (i < 0)
879 return i;
880 j /= sizeof (int);
881 return (j);
882}
883
884static int
885oidfmt(int *oid, int len, char *fmt, u_int *kind)
886{
887 int qoid[CTL_MAXNAME+2];
888 u_char buf[BUFSIZ];
889 int i;
890 size_t j;
891
892 qoid[0] = 0;
893 qoid[1] = 4;
894 memcpy(qoid + 2, oid, len * sizeof(int));
895
896 j = sizeof buf;
897 i = sysctl(qoid, len + 2, buf, &j, 0, 0);
898 if (i)
899 err(1, "sysctl fmt %d %d %d", i, j, errno);
900
901 if (kind)
902 *kind = *(u_int *)buf;
903
904 if (fmt)
905 strcpy(fmt, (char *)(buf + sizeof(u_int)));
906 return 0;
907}
908
909/*
910 * This formats and outputs the value of one variable
911 *
912 * Returns zero if anything was actually output.
913 * Returns one if didn't know what to do with this.
914 * Return minus one if we had errors.
915 */
916
917static int
c3a08f59 918show_var(int *oid, int nlen, int show_masked)
1815bff5 919{
b51d5b5f 920 u_char buf[BUFSIZ], *val, *mval, *p;
1815bff5
A
921 char name[BUFSIZ], /* descr[BUFSIZ], */ *fmt;
922 int qoid[CTL_MAXNAME+2];
923 int i;
b51d5b5f 924 int retval;
1815bff5
A
925 size_t j, len;
926 u_int kind;
927 int (*func)(int, void *) = 0;
928
929 qoid[0] = 0;
930 memcpy(qoid + 2, oid, nlen * sizeof(int));
931
932 qoid[1] = 1;
933 j = sizeof name;
934 i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
935 if (i || !j)
936 err(1, "sysctl name %d %d %d", i, j, errno);
937
938 /* find an estimate of how much we need for this var */
939 j = 0;
940 i = sysctl(oid, nlen, 0, &j, 0, 0);
941 j += j; /* we want to be sure :-) */
942
b51d5b5f 943 val = mval = malloc(j);
1815bff5
A
944 len = j;
945 i = sysctl(oid, nlen, val, &len, 0, 0);
b51d5b5f
A
946 if (i || !len) {
947 retval = 1;
948 goto RETURN;
949 }
1815bff5
A
950
951 if (bflag) {
952 fwrite(val, 1, len, stdout);
b51d5b5f
A
953 retval = 0;
954 goto RETURN;
1815bff5
A
955 }
956
957 qoid[1] = 4;
958 j = sizeof buf;
959 i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
960 if (i || !j)
961 err(1, "sysctl fmt %d %d %d", i, j, errno);
962
963 kind = *(u_int *)buf;
c3a08f59
A
964 if (!show_masked && (kind & CTLFLAG_MASKED)) {
965 retval = 1;
966 goto RETURN;
967 }
1815bff5
A
968
969 fmt = (char *)(buf + sizeof(u_int));
970
971 p = val;
972 switch (*fmt) {
c3a08f59
A
973 case '-':
974 /* deprecated, do not print */
975 retval = 0;
976 goto RETURN;
977
978
1815bff5
A
979 case 'A':
980 if (!nflag)
981 printf("%s: ", name);
982 printf("%s", p);
b51d5b5f
A
983 retval = 0;
984 goto RETURN;
1815bff5
A
985
986 case 'I':
987 if (!nflag)
988 printf("%s: ", name);
989 fmt++;
990 val = "";
991 while (len >= sizeof(int)) {
992 if(*fmt == 'U')
993 printf("%s%u", val, *(unsigned int *)p);
994 else
995 printf("%s%d", val, *(int *)p);
996 val = " ";
997 len -= sizeof (int);
998 p += sizeof (int);
999 }
b51d5b5f
A
1000 retval = 0;
1001 goto RETURN;
1815bff5
A
1002
1003 case 'L':
1004 if (!nflag)
1005 printf("%s: ", name);
1006 fmt++;
1007 val = "";
1008 while (len >= sizeof(long)) {
1009 if(*fmt == 'U')
1010 printf("%s%lu", val, *(unsigned long *)p);
1011 else
1012 printf("%s%ld", val, *(long *)p);
1013 val = " ";
1014 len -= sizeof (long);
1015 p += sizeof (long);
1016 }
b51d5b5f
A
1017 retval = 0;
1018 goto RETURN;
1815bff5
A
1019
1020 case 'P':
1021 if (!nflag)
1022 printf("%s: ", name);
1023 printf("%p", *(void **)p);
b51d5b5f
A
1024 retval = 0;
1025 goto RETURN;
1815bff5 1026
c3a08f59
A
1027 case 'Q':
1028 if (!nflag)
1029 printf("%s: ", name);
1030 fmt++;
1031 val = "";
1032 while (len >= sizeof(long long)) {
1033 if(*fmt == 'U')
1034 printf("%s%llu", val, *(unsigned long long *)p);
1035 else
1036 printf("%s%lld", val, *(long long *)p);
1037 val = " ";
1038 len -= sizeof (long long);
1039 p += sizeof (long long);
1040 }
1041 retval = 0;
1042 goto RETURN;
1043
1044
1815bff5
A
1045 case 'T':
1046 case 'S':
1047 i = 0;
1048 if (!strcmp(fmt, "S,clockinfo")) func = S_clockinfo;
1049 else if (!strcmp(fmt, "S,timeval")) func = S_timeval;
1050 else if (!strcmp(fmt, "S,loadavg")) func = S_loadavg;
1051 else if (!strcmp(fmt, "T,dev_t")) func = T_dev_t;
1052 if (func) {
1053 if (!nflag)
1054 printf("%s: ", name);
b51d5b5f
A
1055 retval = (*func)(len, p);
1056 goto RETURN;
1815bff5
A
1057 }
1058 /* FALL THROUGH */
1059 default:
b51d5b5f
A
1060 if (!Aflag) {
1061 retval = 1;
1062 goto RETURN;
1063 }
1815bff5
A
1064 if (!nflag)
1065 printf("%s: ", name);
1066 printf("Format:%s Length:%ld Dump:0x", fmt, len);
1067 while (len--) {
1068 printf("%02x", *p++);
1069 if (Xflag || p < val+16)
1070 continue;
1071 printf("...");
1072 break;
1073 }
b51d5b5f
A
1074 retval = 0;
1075 goto RETURN;
1815bff5 1076 }
b51d5b5f
A
1077
1078 retval = 1;
1079 RETURN:
1080 free(mval);
1081 return (retval);
1815bff5
A
1082}
1083
1084static int
1085sysctl_all (int *oid, int len)
1086{
1087 int name1[22], name2[22];
1088 int i, j;
1089 size_t l1, l2;
1090
1091 name1[0] = 0;
1092 name1[1] = 2;
1093 l1 = 2;
1094 if (len) {
1095 memcpy(name1+2, oid, len*sizeof (int));
1096 l1 += len;
1097 } else {
1098 name1[2] = 1;
1099 l1++;
1100 }
1101 while (1) {
1102 l2 = sizeof name2;
1103 j = sysctl(name1, l1, name2, &l2, 0, 0);
1104 if (j < 0) {
1105 if (errno == ENOENT)
1106 return 0;
1107 else
1108 err(1, "sysctl(getnext) %d %d", j, l2);
1109 }
1110
1111 l2 /= sizeof (int);
1112
1113 if (l2 < len)
1114 return 0;
1115
1116 for (i = 0; i < len; i++)
1117 if (name2[i] != oid[i])
1118 return 0;
1119
c3a08f59 1120 i = show_var(name2, l2, 0);
1815bff5
A
1121 if (!i && !bflag)
1122 putchar('\n');
1123
1124 memcpy(name1+2, name2, l2*sizeof (int));
1125 l1 = 2 + l2;
1126 }
1127}