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