]> git.saurik.com Git - apple/system_cmds.git/blame - sysctl.tproj/sysctl.c
system_cmds-496.tar.gz
[apple/system_cmds.git] / sysctl.tproj / sysctl.c
CommitLineData
1815bff5 1/*
34d340d7 2 * Copyright (c) 1999-2005 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
34d340d7 90#include <sys/cdefs.h>
1815bff5 91#ifndef lint
34d340d7 92__unused static char copyright[] =
1815bff5
A
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
34d340d7 98__unused static char sccsid[] = "@(#)sysctl.c 8.5 (Berkeley) 5/9/95";
1815bff5
A
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__ */
1815bff5
A
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 */
c3a08f59 149 { 0, 0 }, /* CTL_NET */
1815bff5 150 { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */
83f6dbe8 151 { hwname, HW_MAXID }, /* CTL_HW */
1815bff5
A
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;
34d340d7 162static int invalid_name_used = 0;
1815bff5
A
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 217 parse(*argv, 1);
34d340d7 218 exit(invalid_name_used ? 1 : 0);
1815bff5
A
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
34d340d7
A
353 case CTL_VM: break;
354#if 0 /* XXX Handled by the new sysctl mechanism */
2fc1e207
A
355 switch (mib[1]) {
356 case VM_LOADAVG: { /* XXX this is bogus */
1815bff5
A
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 }
2fc1e207
A
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 }
1815bff5
A
393 if (flags == 0)
394 return;
395 fprintf(stderr,
396 "Use vmstat or systat to view %s information\n", string);
397 return;
34d340d7 398#endif
1815bff5
A
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) {
34d340d7
A
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 }
1815bff5
A
454 newval = &uintval;
455 newsize = sizeof uintval;
456 } else {
34d340d7
A
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;
1815bff5
A
465 }
466 break;
467
468 case CTLTYPE_QUAD:
34d340d7
A
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 }
1815bff5
A
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) {
34d340d7 485 case ENOTSUP:
1815bff5
A
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;
ef8ad44b
A
496 case ENOENT:
497 fprintf(stderr, "%s: no such MIB\n",
498 string);
499 return;
1815bff5
A
500 default:
501 perror(string);
502 return;
503 }
504 }
505 if (special & CLOCK) {
506 struct clockinfo *clkp = (struct clockinfo *)buf;
507
508 if (!nflag)
509 fprintf(stdout, "%s: ", string);
510 fprintf(stdout,
511 "hz = %d, tick = %d, profhz = %d, stathz = %d\n",
512 clkp->hz, clkp->tick, clkp->profhz, clkp->stathz);
513 return;
514 }
515 if (special & BOOTTIME) {
516 struct timeval *btp = (struct timeval *)buf;
517
518 if (!nflag)
519 fprintf(stdout, "%s = %s\n", string,
520 ctime((time_t *) &btp->tv_sec));
521 else
34d340d7 522 fprintf(stdout, "%ld\n", btp->tv_sec);
1815bff5
A
523 return;
524 }
525 if (special & CONSDEV) {
526 dev_t dev = *(dev_t *)buf;
527
528 if (!nflag)
529 fprintf(stdout, "%s = %s\n", string,
530 devname(dev, S_IFCHR));
531 else
532 fprintf(stdout, "0x%x\n", dev);
533 return;
534 }
535 switch (type) {
536 case CTLTYPE_INT:
537 if (newsize == 0) {
538 if (!nflag)
539 fprintf(stdout, "%s = ", string);
540 fprintf(stdout, useUnsignedInt ? "%u\n" : "%d\n", *(int *)buf);
541 } else {
542 if (!nflag)
543 fprintf(stdout, useUnsignedInt ? "%s: %u -> " : "%s: %d -> ",
544 string, *(int *)buf);
545 fprintf(stdout, useUnsignedInt ? "%u\n" : "%d\n", *(int *)newval);
546 }
547 return;
548
549 case CTLTYPE_STRING:
550 if (newsize == 0) {
551 if (!nflag)
552 fprintf(stdout, "%s = ", string);
553 fprintf(stdout, "%s\n", buf);
554 } else {
555 if (!nflag)
556 fprintf(stdout, "%s: %s -> ", string, buf);
557 fprintf(stdout, "%s\n", (char *) newval);
558 }
559 return;
560
561 case CTLTYPE_QUAD:
562 if (newsize == 0) {
563 if (!nflag)
564 fprintf(stdout, "%s = ", string);
565 fprintf(stdout, "%qd\n", *(quad_t *)buf);
566 } else {
567 if (!nflag)
568 fprintf(stdout, "%s: %qd -> ", string,
569 *(quad_t *)buf);
570 fprintf(stdout, "%qd\n", *(quad_t *)newval);
571 }
572 return;
573
ef8ad44b 574 case CTLTYPE_NODE:
1815bff5
A
575 case CTLTYPE_STRUCT:
576 return;
577
578 default:
1815bff5
A
579 fprintf(stderr, "%s: unknown type returned\n",
580 string);
581 return;
582 }
583}
584
585/*
586 * Initialize the set of debugging names
587 */
588void debuginit()
589{
590 int mib[3], loc, i;
591 size_t size;
592
593 if (secondlevel[CTL_DEBUG].list != 0)
594 return;
595 secondlevel[CTL_DEBUG].list = debugname;
596 mib[0] = CTL_DEBUG;
597 mib[2] = CTL_DEBUG_NAME;
598 for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
599 mib[1] = i;
600 size = BUFSIZ - loc;
601 if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
602 continue;
603 debugname[i].ctl_name = &names[loc];
604 debugname[i].ctl_type = CTLTYPE_INT;
605 loc += size;
606 }
607 lastused = loc;
608}
609
610/*
611 * Initialize the set of filesystem names
612 */
613void vfsinit()
614{
615 int mib[4], maxtypenum, cnt, loc, size;
616 struct vfsconf vfc;
617 size_t buflen;
618
619 if (secondlevel[CTL_VFS].list != 0)
620 return;
621 mib[0] = CTL_VFS;
622 mib[1] = VFS_GENERIC;
623 mib[2] = VFS_MAXTYPENUM;
624 buflen = 4;
625 if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
626 return;
627 if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == 0)
628 return;
629 memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
630 mib[2] = VFS_CONF;
631 buflen = sizeof vfc;
632 for (loc = lastused, cnt = 0; cnt < maxtypenum; cnt++) {
633 mib[3] = cnt;
634 if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
34d340d7 635 if (errno == ENOTSUP)
1815bff5
A
636 continue;
637 perror("vfsinit");
638 free(vfsname);
639 return;
640 }
641 strcat(&names[loc], vfc.vfc_name);
642 vfsname[cnt].ctl_name = &names[loc];
643 vfsname[cnt].ctl_type = CTLTYPE_INT;
644 size = strlen(vfc.vfc_name) + 1;
645 loc += size;
646 }
647 lastused = loc;
648 secondlevel[CTL_VFS].list = vfsname;
649 secondlevel[CTL_VFS].size = maxtypenum;
650 return;
651}
652
653/*
654 * Scan a list of names searching for a particular name.
655 */
656int
657findname(string, level, bufp, namelist)
658 char *string;
659 char *level;
660 char **bufp;
661 struct list *namelist;
662{
663 char *name;
664 int i;
665
83f6dbe8
A
666 /* Make 'sysctl kern.' style behave the same as 'sysctl kern' 3360872*/
667 if (bufp[0][strlen(*bufp)-1] == '.')
668 bufp[0][strlen(*bufp)-1]='\0';
1815bff5 669 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
ef8ad44b
A
670 if (!foundSome) {
671 fprintf(stderr, "%s: incomplete specification\n", string);
672 invalid_name_used = 1;
673 }
1815bff5
A
674 return (-1);
675 }
676 for (i = 0; i < namelist->size; i++)
677 if (namelist->list[i].ctl_name != NULL &&
678 strcmp(name, namelist->list[i].ctl_name) == 0)
679 break;
680 if (i == namelist->size) {
ef8ad44b
A
681 if (!foundSome) {
682 fprintf(stderr, "%s level name %s in %s is invalid\n",
683 level, name, string);
684 invalid_name_used = 1;
685 }
1815bff5
A
686 return (-1);
687 }
688 return (i);
689}
690
691void usage()
692{
693
694 (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
695 "usage: sysctl [-bn] variable ...",
696 " sysctl [-bn] -w variable=value ...",
697 " sysctl [-bn] -a",
698 " sysctl [-bn] -A",
699 " sysctl [-bn] -X");
700 exit(1);
701}
702
703/*
704 * Parse a name into a MIB entry.
705 * Lookup and print out the MIB entry if it exists.
706 * Set a new value if requested.
707 */
708static void
709parse(char *string, int flags)
710{
711 int len, i, j;
712 void *newval = 0;
713 int intval, newsize = 0;
714 unsigned int uintval;
715 quad_t quadval;
716 int mib[CTL_MAXNAME];
717 char *cp, *bufp, buf[BUFSIZ], fmt[BUFSIZ];
718 u_int kind;
719
720 bufp = buf;
ef8ad44b
A
721 if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ)
722 errx(1, "MIB too long");
1815bff5
A
723 snprintf(buf, BUFSIZ, "%s", string);
724 if ((cp = strchr(string, '=')) != NULL) {
725 if (!wflag)
726 errx(2, "must specify -w to set variables");
727 *strchr(buf, '=') = '\0';
728 *cp++ = '\0';
729 while (isspace(*cp))
730 cp++;
731 newval = cp;
732 newsize = strlen(cp);
733 } else {
734 if (wflag)
735 usage();
736 }
737 len = name2oid(bufp, mib);
738
739 if (len < 0) {
740 if (cp != NULL) {
741 while (*cp != '\0') cp--;
742 *cp = '=';
743 }
744 old_parse (string, flags);
745 return;
746 }
747
748 if (oidfmt(mib, len, fmt, &kind))
749 err(1, "couldn't find format of oid '%s'", bufp);
750
751 if (!wflag) {
752 if ((kind & CTLTYPE) == CTLTYPE_NODE) {
753 sysctl_all(mib, len);
754 foundSome = 1;
755 old_parse (string, flags);
756 } else {
c3a08f59 757 i = show_var(mib, len, 1);
1815bff5
A
758 if (!i && !bflag)
759 putchar('\n');
760 }
761 } else {
762 if ((kind & CTLTYPE) == CTLTYPE_NODE)
763 errx(1, "oid '%s' isn't a leaf node", bufp);
764
765 if (!(kind&CTLFLAG_WR))
766 errx(1, "oid '%s' is read only", bufp);
767
768 switch (kind & CTLTYPE) {
769 case CTLTYPE_INT:
770 if ((*fmt == 'I') && (*(fmt + 1) == 'U')) {
771 uintval = (unsigned int) strtoul (newval, NULL, 0);
34d340d7
A
772 if ((uintval == 0) &&
773 (errno == EINVAL)) {
774 errx(1, "invalid argument: %s",
775 newval);
776 return;
777 }
1815bff5
A
778 newval = &uintval;
779 newsize = sizeof uintval;
780 } else {
781 intval = (int) strtol(newval, NULL, 0);
34d340d7
A
782 if ((intval == 0) &&
783 (errno == EINVAL)) {
784 errx(1, "invalid argument: %s",
785 newval);
786 return;
787 }
1815bff5
A
788 newval = &intval;
789 newsize = sizeof intval;
790 }
791 break;
792 case CTLTYPE_STRING:
793 break;
794 case CTLTYPE_QUAD:
2fc1e207 795 quadval = strtoq(newval, NULL, 0);
34d340d7
A
796 if ((quadval == 0) && (errno == EINVAL)) {
797 errx(1, "invalid argument %s", newval);
798 return;
799 }
1815bff5
A
800 newval = &quadval;
801 newsize = sizeof quadval;
802 break;
803 default:
804 errx(1, "oid '%s' is type %d,"
805 " cannot set that", bufp,
806 kind & CTLTYPE);
807 }
808
c3a08f59 809 i = show_var(mib, len, 1);
1815bff5
A
810 if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
811 if (!i && !bflag)
812 putchar('\n');
813 switch (errno) {
34d340d7 814 case ENOTSUP:
1815bff5
A
815 errx(1, "%s: value is not available",
816 string);
817 case ENOTDIR:
818 errx(1, "%s: specification is incomplete",
819 string);
820 case ENOMEM:
821 errx(1, "%s: type is unknown to this program",
822 string);
823 default:
824 warn("%s", string);
825 return;
826 }
827 }
828 if (!bflag)
829 printf(" -> ");
830 i = nflag;
831 nflag = 1;
c3a08f59 832 j = show_var(mib, len, 1);
1815bff5
A
833 if (!j && !bflag)
834 putchar('\n');
835 nflag = i;
836 }
837}
838
839/* These functions will dump out various interesting structures. */
840
841static int
842S_clockinfo(int l2, void *p)
843{
844 struct clockinfo *ci = (struct clockinfo*)p;
845 if (l2 != sizeof *ci)
846 err(1, "S_clockinfo %d != %d", l2, sizeof *ci);
847 printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
848 ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz);
849 return (0);
850}
851
852static int
853S_loadavg(int l2, void *p)
854{
855 struct loadavg *tv = (struct loadavg*)p;
856
857 if (l2 != sizeof *tv)
858 err(1, "S_loadavg %d != %d", l2, sizeof *tv);
859
860 printf("{ %.2f %.2f %.2f }",
861 (double)tv->ldavg[0]/(double)tv->fscale,
862 (double)tv->ldavg[1]/(double)tv->fscale,
863 (double)tv->ldavg[2]/(double)tv->fscale);
864 return (0);
865}
866
867static int
868S_timeval(int l2, void *p)
869{
870 struct timeval *tv = (struct timeval*)p;
871 time_t tv_sec;
872 char *p1, *p2;
873
874 if (l2 != sizeof *tv)
875 err(1, "S_timeval %d != %d", l2, sizeof *tv);
876 printf("{ sec = %ld, usec = %ld } ",
877 (long) tv->tv_sec, (long) tv->tv_usec);
878 tv_sec = tv->tv_sec;
879 p1 = strdup(ctime(&tv_sec));
880 for (p2=p1; *p2 ; p2++)
881 if (*p2 == '\n')
882 *p2 = '\0';
883 fputs(p1, stdout);
884 return (0);
885}
886
34d340d7
A
887static int
888S_xswusage(int l2, void *p)
889{
890 struct xsw_usage *xsu = (struct xsw_usage *)p;
891
892 if(l2 != sizeof (*xsu))
893 err(1, "S_xswusage %d != %d", l2, sizeof *xsu);
894
895 fprintf(stdout,
896 "total = %.2fM used = %.2fM free = %.2fM %s",
897 ((double) xsu->xsu_total) / (1024.0 * 1024.0),
898 ((double) xsu->xsu_used) / (1024.0 * 1024.0),
899 ((double) xsu->xsu_avail) / (1024.0 * 1024.0),
900 xsu->xsu_encrypted ? "(encrypted)" : "");
901 return 0;
902}
903
1815bff5
A
904static int
905T_dev_t(int l2, void *p)
906{
907 dev_t *d = (dev_t *)p;
908 if (l2 != sizeof *d)
909 err(1, "T_dev_T %d != %d", l2, sizeof *d);
910 if ((int)(*d) != -1) {
911 if (minor(*d) > 255 || minor(*d) < 0)
912 printf("{ major = %d, minor = 0x%x }",
913 major(*d), minor(*d));
914 else
915 printf("{ major = %d, minor = %d }",
916 major(*d), minor(*d));
917 }
918 return (0);
919}
920
921/*
922 * These functions uses a presently undocumented interface to the kernel
923 * to walk the tree and get the type so it can print the value.
924 * This interface is under work and consideration, and should probably
925 * be killed with a big axe by the first person who can find the time.
926 * (be aware though, that the proper interface isn't as obvious as it
927 * may seem, there are various conflicting requirements.
928 */
929
930static int
931name2oid(char *name, int *oidp)
932{
933 int oid[2];
934 int i;
935 size_t j;
936
937 oid[0] = 0;
938 oid[1] = 3;
939
940 j = CTL_MAXNAME * sizeof (int);
941 i = sysctl(oid, 2, oidp, &j, name, strlen(name));
942 if (i < 0)
943 return i;
944 j /= sizeof (int);
945 return (j);
946}
947
948static int
949oidfmt(int *oid, int len, char *fmt, u_int *kind)
950{
951 int qoid[CTL_MAXNAME+2];
952 u_char buf[BUFSIZ];
953 int i;
954 size_t j;
955
956 qoid[0] = 0;
957 qoid[1] = 4;
958 memcpy(qoid + 2, oid, len * sizeof(int));
959
960 j = sizeof buf;
961 i = sysctl(qoid, len + 2, buf, &j, 0, 0);
962 if (i)
963 err(1, "sysctl fmt %d %d %d", i, j, errno);
964
965 if (kind)
966 *kind = *(u_int *)buf;
967
968 if (fmt)
969 strcpy(fmt, (char *)(buf + sizeof(u_int)));
970 return 0;
971}
972
973/*
974 * This formats and outputs the value of one variable
975 *
976 * Returns zero if anything was actually output.
977 * Returns one if didn't know what to do with this.
978 * Return minus one if we had errors.
979 */
980
981static int
c3a08f59 982show_var(int *oid, int nlen, int show_masked)
1815bff5 983{
b51d5b5f 984 u_char buf[BUFSIZ], *val, *mval, *p;
1815bff5
A
985 char name[BUFSIZ], /* descr[BUFSIZ], */ *fmt;
986 int qoid[CTL_MAXNAME+2];
987 int i;
b51d5b5f 988 int retval;
1815bff5
A
989 size_t j, len;
990 u_int kind;
991 int (*func)(int, void *) = 0;
992
993 qoid[0] = 0;
994 memcpy(qoid + 2, oid, nlen * sizeof(int));
995
996 qoid[1] = 1;
997 j = sizeof name;
998 i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
999 if (i || !j)
1000 err(1, "sysctl name %d %d %d", i, j, errno);
1001
1002 /* find an estimate of how much we need for this var */
1003 j = 0;
1004 i = sysctl(oid, nlen, 0, &j, 0, 0);
1005 j += j; /* we want to be sure :-) */
1006
b51d5b5f 1007 val = mval = malloc(j);
1815bff5
A
1008 len = j;
1009 i = sysctl(oid, nlen, val, &len, 0, 0);
b51d5b5f
A
1010 if (i || !len) {
1011 retval = 1;
1012 goto RETURN;
1013 }
1815bff5
A
1014
1015 if (bflag) {
1016 fwrite(val, 1, len, stdout);
b51d5b5f
A
1017 retval = 0;
1018 goto RETURN;
1815bff5
A
1019 }
1020
1021 qoid[1] = 4;
1022 j = sizeof buf;
1023 i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
1024 if (i || !j)
1025 err(1, "sysctl fmt %d %d %d", i, j, errno);
1026
1027 kind = *(u_int *)buf;
c3a08f59
A
1028 if (!show_masked && (kind & CTLFLAG_MASKED)) {
1029 retval = 1;
1030 goto RETURN;
1031 }
1815bff5
A
1032
1033 fmt = (char *)(buf + sizeof(u_int));
1034
1035 p = val;
1036 switch (*fmt) {
c3a08f59
A
1037 case '-':
1038 /* deprecated, do not print */
1039 retval = 0;
1040 goto RETURN;
1041
1042
1815bff5
A
1043 case 'A':
1044 if (!nflag)
1045 printf("%s: ", name);
1046 printf("%s", p);
b51d5b5f
A
1047 retval = 0;
1048 goto RETURN;
1815bff5
A
1049
1050 case 'I':
1051 if (!nflag)
1052 printf("%s: ", name);
1053 fmt++;
34d340d7 1054 val = (unsigned char *)"";
1815bff5
A
1055 while (len >= sizeof(int)) {
1056 if(*fmt == 'U')
1057 printf("%s%u", val, *(unsigned int *)p);
1058 else
1059 printf("%s%d", val, *(int *)p);
34d340d7 1060 val = (unsigned char *)" ";
1815bff5
A
1061 len -= sizeof (int);
1062 p += sizeof (int);
1063 }
b51d5b5f
A
1064 retval = 0;
1065 goto RETURN;
1815bff5
A
1066
1067 case 'L':
1068 if (!nflag)
1069 printf("%s: ", name);
1070 fmt++;
34d340d7 1071 val = (unsigned char *)"";
1815bff5
A
1072 while (len >= sizeof(long)) {
1073 if(*fmt == 'U')
1074 printf("%s%lu", val, *(unsigned long *)p);
1075 else
1076 printf("%s%ld", val, *(long *)p);
34d340d7 1077 val = (unsigned char *)" ";
1815bff5
A
1078 len -= sizeof (long);
1079 p += sizeof (long);
1080 }
b51d5b5f
A
1081 retval = 0;
1082 goto RETURN;
1815bff5
A
1083
1084 case 'P':
1085 if (!nflag)
1086 printf("%s: ", name);
1087 printf("%p", *(void **)p);
b51d5b5f
A
1088 retval = 0;
1089 goto RETURN;
1815bff5 1090
c3a08f59
A
1091 case 'Q':
1092 if (!nflag)
1093 printf("%s: ", name);
1094 fmt++;
34d340d7 1095 val = (unsigned char *)"";
c3a08f59
A
1096 while (len >= sizeof(long long)) {
1097 if(*fmt == 'U')
1098 printf("%s%llu", val, *(unsigned long long *)p);
1099 else
1100 printf("%s%lld", val, *(long long *)p);
34d340d7 1101 val = (unsigned char *)" ";
c3a08f59
A
1102 len -= sizeof (long long);
1103 p += sizeof (long long);
1104 }
1105 retval = 0;
1106 goto RETURN;
1107
1108
1815bff5
A
1109 case 'T':
1110 case 'S':
1111 i = 0;
1112 if (!strcmp(fmt, "S,clockinfo")) func = S_clockinfo;
1113 else if (!strcmp(fmt, "S,timeval")) func = S_timeval;
1114 else if (!strcmp(fmt, "S,loadavg")) func = S_loadavg;
34d340d7 1115 else if (!strcmp(fmt, "S,xsw_usage")) func = S_xswusage;
1815bff5
A
1116 else if (!strcmp(fmt, "T,dev_t")) func = T_dev_t;
1117 if (func) {
1118 if (!nflag)
1119 printf("%s: ", name);
b51d5b5f
A
1120 retval = (*func)(len, p);
1121 goto RETURN;
1815bff5
A
1122 }
1123 /* FALL THROUGH */
1124 default:
b51d5b5f
A
1125 if (!Aflag) {
1126 retval = 1;
1127 goto RETURN;
1128 }
1815bff5
A
1129 if (!nflag)
1130 printf("%s: ", name);
1131 printf("Format:%s Length:%ld Dump:0x", fmt, len);
1132 while (len--) {
1133 printf("%02x", *p++);
1134 if (Xflag || p < val+16)
1135 continue;
1136 printf("...");
1137 break;
1138 }
b51d5b5f
A
1139 retval = 0;
1140 goto RETURN;
1815bff5 1141 }
b51d5b5f
A
1142
1143 retval = 1;
1144 RETURN:
1145 free(mval);
1146 return (retval);
1815bff5
A
1147}
1148
1149static int
1150sysctl_all (int *oid, int len)
1151{
1152 int name1[22], name2[22];
1153 int i, j;
1154 size_t l1, l2;
1155
1156 name1[0] = 0;
1157 name1[1] = 2;
1158 l1 = 2;
1159 if (len) {
1160 memcpy(name1+2, oid, len*sizeof (int));
1161 l1 += len;
1162 } else {
1163 name1[2] = 1;
1164 l1++;
1165 }
1166 while (1) {
1167 l2 = sizeof name2;
1168 j = sysctl(name1, l1, name2, &l2, 0, 0);
1169 if (j < 0) {
1170 if (errno == ENOENT)
1171 return 0;
1172 else
1173 err(1, "sysctl(getnext) %d %d", j, l2);
1174 }
1175
1176 l2 /= sizeof (int);
1177
1178 if (l2 < len)
1179 return 0;
1180
1181 for (i = 0; i < len; i++)
1182 if (name2[i] != oid[i])
1183 return 0;
1184
c3a08f59 1185 i = show_var(name2, l2, 0);
1815bff5
A
1186 if (!i && !bflag)
1187 putchar('\n');
1188
1189 memcpy(name1+2, name2, l2*sizeof (int));
1190 l1 = 2 + l2;
1191 }
1192}