]>
git.saurik.com Git - apple/system_cmds.git/blob - sysctl.tproj/sysctl.c
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
32 __unused
static const char copyright
[] =
33 "@(#) Copyright (c) 1993\n\
34 The Regents of the University of California. All rights reserved.\n";
39 static char sccsid
[] = "@(#)from: sysctl.c 8.1 (Berkeley) 6/6/93";
41 __unused
static const char rcsid
[] =
45 #include <sys/param.h>
47 #include <sys/resource.h>
49 #include <sys/sysctl.h>
51 #include <mach/machine/vm_param.h>
52 #include <mach/machine/vm_types.h>
53 #include <mach/mach_types.h>
55 #include <sys/vmmeter.h>
68 static int aflag
, bflag
, dflag
, eflag
, hflag
, iflag
;
69 static int Nflag
, nflag
, oflag
, qflag
, xflag
, warncount
;
71 static int oidfmt(int *, int, char *, u_int
*);
72 static void parse(const char *);
74 static int show_var(int *, int, int);
76 static int show_var(int *, int);
78 static int sysctl_all(int *oid
, int len
);
79 static int name2oid(char *, int *);
82 static int set_IK(const char *, int *);
86 // Shims for FreeBSD source compatibility.
87 #define CTLTYPE_UINT 0xa
88 #define CTLTYPE_LONG 0xb
89 #define CTLTYPE_ULONG 0xc
90 #define CTLTYPE_S64 0xd
91 #define CTLTYPE_U64 0xe
95 // Support for CTL_USER
96 const struct ctlname names
[] = CTL_NAMES
;
97 const struct ctlname user_names
[] = CTL_USER_NAMES
;
98 const int user_names_count
= sizeof(user_names
) / sizeof(*user_names
);
105 (void)fprintf(stderr
, "%s\n%s\n",
106 "usage: sysctl [-bdehiNnoqx] name[=value] ...",
107 " sysctl [-bdehNnoqx] -a");
112 main(int argc
, char **argv
)
116 setlocale(LC_NUMERIC
, "");
120 while ((ch
= getopt(argc
, argv
, "AabdehiNnoqwxX")) != -1) {
176 if (aflag
&& argc
== 0)
177 exit(sysctl_all(0, 0));
188 * Parse a name into a MIB entry.
189 * Lookup and print out the MIB entry if it exists.
190 * Set a new value if requested.
193 parse(const char *string
)
198 unsigned int uintval
;
200 unsigned long ulongval
;
204 int mib
[CTL_MAXNAME
];
205 char *cp
, *bufp
, buf
[BUFSIZ
], *endptr
, fmt
[BUFSIZ
];
209 if (snprintf(buf
, BUFSIZ
, "%s", string
) >= BUFSIZ
)
210 errx(1, "oid too long: '%s'", string
);
211 bufp
= strsep(&cp
, "=");
216 newsize
= strlen(cp
);
218 len
= name2oid(bufp
, mib
);
226 errx(1, "unknown oid '%s'", bufp
);
229 if (oidfmt(mib
, len
, fmt
, &kind
))
230 err(1, "couldn't find format of oid '%s'", bufp
);
232 if (newval
== NULL
|| dflag
) {
233 if ((kind
& CTLTYPE
) == CTLTYPE_NODE
) {
236 i
= show_var(mib
, len
, 1);
238 i
= show_var(mib
, len
);
243 sysctl_all(mib
, len
);
246 i
= show_var(mib
, len
, 1);
248 i
= show_var(mib
, len
);
254 if ((kind
& CTLTYPE
) == CTLTYPE_NODE
)
255 errx(1, "oid '%s' isn't a leaf node", bufp
);
257 if (!(kind
& CTLFLAG_WR
)) {
258 if (kind
& CTLFLAG_TUN
) {
259 warnx("oid '%s' is a read only tunable", bufp
);
260 errx(1, "Tunable values are set in /boot/loader.conf");
262 errx(1, "oid '%s' is read only", bufp
);
266 if ((kind
& CTLTYPE
) == CTLTYPE_INT
||
267 (kind
& CTLTYPE
) == CTLTYPE_UINT
||
268 (kind
& CTLTYPE
) == CTLTYPE_LONG
||
269 (kind
& CTLTYPE
) == CTLTYPE_ULONG
||
270 (kind
& CTLTYPE
) == CTLTYPE_S64
||
271 (kind
& CTLTYPE
) == CTLTYPE_U64
) {
272 if (strlen(newval
) == 0)
273 errx(1, "empty numeric value");
276 switch (kind
& CTLTYPE
) {
278 if (strcmp(fmt
, "IK") == 0) {
280 if (!set_IK(newval
, &intval
))
282 errx(1, "invalid value '%s'",
285 intval
= (int)strtol(newval
, &endptr
,
287 if (endptr
== newval
|| *endptr
!= '\0')
288 errx(1, "invalid integer '%s'",
292 newsize
= sizeof(intval
);
295 uintval
= (int) strtoul(newval
, &endptr
, 0);
296 if (endptr
== newval
|| *endptr
!= '\0')
297 errx(1, "invalid unsigned integer '%s'",
300 newsize
= sizeof(uintval
);
303 longval
= strtol(newval
, &endptr
, 0);
304 if (endptr
== newval
|| *endptr
!= '\0')
305 errx(1, "invalid long integer '%s'",
308 newsize
= sizeof(longval
);
311 ulongval
= strtoul(newval
, &endptr
, 0);
312 if (endptr
== newval
|| *endptr
!= '\0')
313 errx(1, "invalid unsigned long integer"
314 " '%s'", (char *)newval
);
316 newsize
= sizeof(ulongval
);
321 i64val
= strtoimax(newval
, &endptr
, 0);
322 if (endptr
== newval
|| *endptr
!= '\0')
323 errx(1, "invalid int64_t '%s'",
326 newsize
= sizeof(i64val
);
329 u64val
= strtoumax(newval
, &endptr
, 0);
330 if (endptr
== newval
|| *endptr
!= '\0')
331 errx(1, "invalid uint64_t '%s'",
334 newsize
= sizeof(u64val
);
339 errx(1, "oid '%s' is type %d,"
340 " cannot set that", bufp
,
345 i
= show_var(mib
, len
, 1);
347 i
= show_var(mib
, len
);
349 if (sysctl(mib
, len
, 0, 0, newval
, newsize
) == -1) {
357 errx(1, "%s: value is not available",
360 errx(1, "%s: specification is incomplete",
363 errx(1, "%s: type is unknown to this program",
376 j
= show_var(mib
, len
, 1);
378 j
= show_var(mib
, len
);
386 /* These functions will dump out various interesting structures. */
389 S_clockinfo(int l2
, void *p
)
391 struct clockinfo
*ci
= (struct clockinfo
*)p
;
393 if (l2
!= sizeof(*ci
)) {
394 warnx("S_clockinfo %d != %zu", l2
, sizeof(*ci
));
398 printf(hflag
? "{ hz = %'d, tick = %'d, tickadj = %'d, profhz = %'d, stathz = %'d }" :
399 "{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
400 ci
->hz
, ci
->tick
, ci
->tickadj
, ci
->profhz
, ci
->stathz
);
402 printf(hflag
? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
403 "{ hz = %d, tick = %d, profhz = %d, stathz = %d }",
404 ci
->hz
, ci
->tick
, ci
->profhz
, ci
->stathz
);
410 S_loadavg(int l2
, void *p
)
412 struct loadavg
*tv
= (struct loadavg
*)p
;
414 if (l2
!= sizeof(*tv
)) {
415 warnx("S_loadavg %d != %zu", l2
, sizeof(*tv
));
418 printf(hflag
? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
419 (double)tv
->ldavg
[0]/(double)tv
->fscale
,
420 (double)tv
->ldavg
[1]/(double)tv
->fscale
,
421 (double)tv
->ldavg
[2]/(double)tv
->fscale
);
426 S_timeval(int l2
, void *p
)
428 struct timeval
*tv
= (struct timeval
*)p
;
432 if (l2
!= sizeof(*tv
)) {
433 warnx("S_timeval %d != %zu", l2
, sizeof(*tv
));
436 printf(hflag
? "{ sec = %'jd, usec = %'ld } " :
437 "{ sec = %jd, usec = %ld } ",
438 (intmax_t)tv
->tv_sec
, (long)tv
->tv_usec
);
440 p1
= strdup(ctime(&tv_sec
));
441 for (p2
=p1
; *p2
; p2
++)
451 S_vmtotal(int l2
, void *p
)
453 struct vmtotal
*v
= (struct vmtotal
*)p
;
454 int pageKilo
= getpagesize() / 1024;
456 if (l2
!= sizeof(*v
)) {
457 warnx("S_vmtotal %d != %zu", l2
, sizeof(*v
));
462 "\nSystem wide totals computed every five seconds:"
463 " (values in kilobytes)\n");
464 printf("===============================================\n");
466 "Processes:\t\t(RUNQ: %hd Disk Wait: %hd Page Wait: "
468 v
->t_rq
, v
->t_dw
, v
->t_pw
, v
->t_sl
);
470 "Virtual Memory:\t\t(Total: %dK Active: %dK)\n",
471 v
->t_vm
* pageKilo
, v
->t_avm
* pageKilo
);
472 printf("Real Memory:\t\t(Total: %dK Active: %dK)\n",
473 v
->t_rm
* pageKilo
, v
->t_arm
* pageKilo
);
474 printf("Shared Virtual Memory:\t(Total: %dK Active: %dK)\n",
475 v
->t_vmshr
* pageKilo
, v
->t_avmshr
* pageKilo
);
476 printf("Shared Real Memory:\t(Total: %dK Active: %dK)\n",
477 v
->t_rmshr
* pageKilo
, v
->t_armshr
* pageKilo
);
478 printf("Free Memory:\t%dK\n", v
->t_free
* pageKilo
);
484 set_IK(const char *str
, int *val
)
491 if ((len
= strlen(str
)) == 0)
494 if (*p
== 'C' || *p
== 'F') {
495 temp
= strtof(str
, &endptr
);
496 if (endptr
== str
|| endptr
!= p
)
499 temp
= (temp
- 32) * 5 / 9;
500 kelv
= temp
* 10 + 2732;
502 kelv
= (int)strtol(str
, &endptr
, 10);
503 if (endptr
== str
|| *endptr
!= '\0')
513 S_xswusage(int l2
, void *p
)
515 struct xsw_usage
*xsu
= (struct xsw_usage
*)p
;
517 if (l2
!= sizeof(*xsu
)) {
518 warnx("S_xswusage %d != %ld", l2
, sizeof(*xsu
));
522 "total = %.2fM used = %.2fM free = %.2fM %s",
523 ((double)xsu
->xsu_total
) / (1024.0 * 1024.0),
524 ((double)xsu
->xsu_used
) / (1024.0 * 1024.0),
525 ((double)xsu
->xsu_avail
) / (1024.0 * 1024.0),
526 xsu
->xsu_encrypted
? "(encrypted)" : "");
531 T_dev_t(int l2
, void *p
)
533 dev_t
*d
= (dev_t
*)p
;
535 if (l2
!= sizeof(*d
)) {
536 warnx("T_dev_T %d != %ld", l2
, sizeof(*d
));
539 if ((int)(*d
) != -1) {
540 if (minor(*d
) > 255 || minor(*d
) < 0)
541 printf("{ major = %d, minor = 0x%x }",
542 major(*d
), minor(*d
));
544 printf("{ major = %d, minor = %d }",
545 major(*d
), minor(*d
));
551 S_quads(int len
, void *p
)
553 size_t size
= sizeof(int64_t);
554 if (len
& (size
-1)) {
558 int64_t i
= *(int64_t *)p
;
562 p
= (uintptr_t)p
+ size
;
573 * These functions uses a presently undocumented interface to the kernel
574 * to walk the tree and get the type so it can print the value.
575 * This interface is under work and consideration, and should probably
576 * be killed with a big axe by the first person who can find the time.
577 * (be aware though, that the proper interface isn't as obvious as it
578 * may seem, there are various conflicting requirements.
582 name2oid(char *name
, int *oidp
)
589 // Support for CTL_USER
590 const char *user
= names
[CTL_USER
].ctl_name
;
592 if (!strncmp(name
, user
, j
)) {
594 if (name
[j
] == '.') {
595 for (i
= 1; i
< user_names_count
; ++i
) {
596 if (!strcmp(&name
[j
+1], user_names
[i
].ctl_name
)) {
602 } else if (name
[j
] == 0) {
612 j
= CTL_MAXNAME
* sizeof(int);
613 i
= sysctl(oid
, 2, oidp
, &j
, name
, strlen(name
));
621 oidfmt(int *oid
, int len
, char *fmt
, u_int
*kind
)
623 int qoid
[CTL_MAXNAME
+2];
630 memcpy(qoid
+ 2, oid
, len
* sizeof(int));
633 i
= sysctl(qoid
, len
+ 2, buf
, &j
, 0, 0);
635 if (i
&& errno
== ENOENT
) {
636 // Support for CTL_USER
637 if (oid
[0] == CTL_USER
) {
639 *kind
= CTLTYPE_NODE
;
641 } else if (len
== 2 && oid
[1] < user_names_count
) {
642 *kind
= user_names
[oid
[1]].ctl_type
;
650 err(1, "sysctl fmt %d %zu %d", i
, j
, errno
);
654 memcpy(kind
, buf
, sizeof(*kind
));
656 *kind
= *(u_int
*)buf
;
660 strcpy(fmt
, (char *)(buf
+ sizeof(u_int
)));
663 // Map Darwin sysctl types to FreeBSD types.
664 // - 0 with "I" -> CTLTYPE_INT
665 // - 0 with "S," -> CTLTYPE_STRUCT
666 // - CTLTYPE_INT with "IU" -> CTLTYPE_UINT
667 // - CTLTYPE_INT with "L" -> CTLTYPE_LONG
668 // - CTLTYPE_QUAD -> CTLTYPE_S64
669 // - CTLTYPE_QUAD with "*U" -> CTLTYPE_U64
671 switch (*kind
& CTLTYPE
) {
674 if (buf
[sizeof(u_int
)] == 'S') {
675 *kind
= (*kind
& ~CTLTYPE
) | CTLTYPE_STRUCT
;
676 } else if (buf
[sizeof(u_int
)] == 'I') {
677 *kind
= (*kind
& ~CTLTYPE
) | CTLTYPE_INT
;
678 if (buf
[sizeof(u_int
)+1] == 'U') {
679 *kind
= (*kind
& ~CTLTYPE
) | CTLTYPE_UINT
;
681 } else if (buf
[sizeof(u_int
)] == 'L') {
682 *kind
= (*kind
& ~CTLTYPE
) | CTLTYPE_LONG
;
683 if (buf
[sizeof(u_int
)+1] == 'U') {
684 *kind
= (*kind
& ~CTLTYPE
) | CTLTYPE_ULONG
;
689 *kind
= (*kind
& ~CTLTYPE
);
690 if (fmt
&& strchr(fmt
, 'U')) {
691 *kind
|= CTLTYPE_U64
;
693 *kind
|= CTLTYPE_S64
;
703 static int ctl_sign
[CTLTYPE
+1] = {
709 static int ctl_size
[CTLTYPE
+1] = {
710 [CTLTYPE_INT
] = sizeof(int),
711 [CTLTYPE_UINT
] = sizeof(u_int
),
712 [CTLTYPE_LONG
] = sizeof(long),
713 [CTLTYPE_ULONG
] = sizeof(u_long
),
714 [CTLTYPE_S64
] = sizeof(int64_t),
715 [CTLTYPE_U64
] = sizeof(int64_t),
719 * This formats and outputs the value of one variable
721 * Returns zero if anything was actually output.
722 * Returns one if didn't know what to do with this.
723 * Return minus one if we had errors.
727 show_var(int *oid
, int nlen
, int show_masked
)
729 show_var(int *oid
, int nlen
)
732 u_char buf
[BUFSIZ
], *val
, *oval
, *p
;
733 char name
[BUFSIZ
], *fmt
;
734 const char *sep
, *sep1
;
735 int qoid
[CTL_MAXNAME
+2];
738 int i
, hexlen
, sign
, ctltype
;
742 int (*func
)(int, void *);
745 umv
= mv
= intlen
= 0;
750 memcpy(qoid
+ 2, oid
, nlen
* sizeof(int));
753 // Support for CTL_USER
754 if (nlen
>= 1 && oid
[0] == CTL_USER
) {
755 const char *user_name
= "";
758 if (nlen
== 2 && i
> 0 && i
< user_names_count
) {
759 user_name
= user_names
[i
].ctl_name
;
762 j
= snprintf(name
, sizeof(name
), "%s%s%s",
763 names
[CTL_USER
].ctl_name
, sep
, user_name
);
769 i
= sysctl(qoid
, nlen
+ 2, name
, &j
, 0, 0);
771 err(1, "sysctl name %d %zu %d", i
, j
, errno
);
786 if (dflag
) { /* just print description */
789 i
= sysctl(qoid
, nlen
+ 2, buf
, &j
, 0, 0);
791 printf("%s%s", name
, sep
);
795 /* find an estimate of how much we need for this var */
797 i
= sysctl(oid
, nlen
, 0, &j
, 0, 0);
798 j
+= j
; /* we want to be sure :-) */
800 val
= oval
= malloc(j
+ 1);
802 warnx("malloc failed");
806 i
= sysctl(oid
, nlen
, val
, &len
, 0, 0);
813 fwrite(val
, 1, len
, stdout
);
819 oidfmt(oid
, nlen
, fmt
, &kind
);
821 ctltype
= (kind
& CTLTYPE
);
822 sign
= ctl_sign
[ctltype
];
823 intlen
= ctl_size
[ctltype
];
826 if (!show_masked
&& (kind
& CTLFLAG_MASKED
)) {
835 printf("%s%s", name
, sep
);
836 printf("%.*s", (int)len
, p
);
847 printf("%s%s", name
, sep
);
848 hexlen
= (int)(2 + (intlen
* CHAR_BIT
+ 3) / 4);
850 while (len
>= intlen
) {
851 switch (kind
& CTLTYPE
) {
854 umv
= *(u_int
*)(void *)p
;
855 mv
= *(int *)(void *)p
;
859 umv
= *(u_long
*)(void *)p
;
860 mv
= *(long *)(void *)p
;
864 umv
= *(uint64_t *)(void *)p
;
865 mv
= *(int64_t *)(void *)p
;
870 printf("%#0*jx", hexlen
, umv
);
872 printf(hflag
? "%'ju" : "%ju", umv
);
873 else if (fmt
[1] == 'K') {
877 printf("%.1fC", (mv
- 2732.0) / 10);
879 printf(hflag
? "%'jd" : "%jd", mv
);
889 if (strcmp(fmt
, "S,clockinfo") == 0)
891 else if (strcmp(fmt
, "S,timeval") == 0)
893 else if (strcmp(fmt
, "S,loadavg") == 0)
896 else if (!strcmp(fmt
, "S,xsw_usage"))
898 else if (!strcmp(fmt
, "T,dev_t"))
900 else if (!strcmp(fmt
, "Q"))
903 else if (strcmp(fmt
, "S,vmtotal") == 0)
910 printf("%s%s", name
, sep
);
911 i
= (*func
)((int)len
, p
);
917 if (!oflag
&& !xflag
) {
922 printf("%s%s", name
, sep
);
923 printf("Format:%s Length:%zu Dump:0x", fmt
, len
);
924 while (len
-- && (xflag
|| p
< val
+ 16))
925 printf("%02x", *p
++);
926 if (!xflag
&& len
> 16)
936 // Support for CTL_USER
938 sysctl_all_user(int *oid
, int len
)
941 if (len
> 1 || (len
== 1 && oid
[0] != CTL_USER
)) {
944 for (i
= 0; i
< user_names_count
; ++i
) {
945 int oid
[2] = { CTL_USER
, i
};
946 j
= show_var(oid
, 2, 0);
955 sysctl_all(int *oid
, int len
)
957 int name1
[22], name2
[22];
962 sysctl_all_user(oid
, len
);
969 memcpy(name1
+2, oid
, len
* sizeof(int));
977 j
= sysctl(name1
, (u_int
)l1
, name2
, &l2
, 0, 0);
982 err(1, "sysctl(getnext) %d %zu", j
, l2
);
987 if (len
< 0 || l2
< (unsigned int)len
)
990 for (i
= 0; i
< len
; i
++)
991 if (name2
[i
] != oid
[i
])
995 i
= show_var(name2
, (u_int
)l2
, 0);
997 i
= show_var(name2
, (u_int
)l2
);
1002 memcpy(name1
+2, name2
, l2
* sizeof(int));