]>
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>
70 static int aflag
, bflag
, dflag
, eflag
, hflag
, iflag
;
71 static int Nflag
, nflag
, oflag
, qflag
, xflag
, warncount
;
73 static int oidfmt(int *, int, char *, u_int
*);
74 static void parse(const char *);
76 static int show_var(int *, int, int);
78 static int show_var(int *, int);
80 static int sysctl_all(int *oid
, int len
);
81 static int name2oid(char *, int *);
84 static int set_IK(const char *, int *);
88 // Shims for FreeBSD source compatibility.
89 #define CTLTYPE_UINT 0xa
90 #define CTLTYPE_LONG 0xb
91 #define CTLTYPE_ULONG 0xc
92 #define CTLTYPE_S64 0xd
93 #define CTLTYPE_U64 0xe
97 // Support for CTL_USER
98 const struct ctlname names
[] = CTL_NAMES
;
99 const struct ctlname user_names
[] = CTL_USER_NAMES
;
100 const int user_names_count
= sizeof(user_names
) / sizeof(*user_names
);
107 (void)fprintf(stderr
, "%s\n%s\n",
108 "usage: sysctl [-bdehiNnoqx] name[=value] ...",
109 " sysctl [-bdehNnoqx] -a");
114 main(int argc
, char **argv
)
118 setlocale(LC_NUMERIC
, "");
122 while ((ch
= getopt(argc
, argv
, "AabdehiNnoqwxX")) != -1) {
178 if (aflag
&& argc
== 0)
179 exit(sysctl_all(0, 0));
190 * Parse a name into a MIB entry.
191 * Lookup and print out the MIB entry if it exists.
192 * Set a new value if requested.
195 parse(const char *string
)
200 unsigned int uintval
;
202 unsigned long ulongval
;
206 int mib
[CTL_MAXNAME
];
207 char *cp
, *bufp
, buf
[BUFSIZ
], *endptr
, fmt
[BUFSIZ
];
211 if (snprintf(buf
, BUFSIZ
, "%s", string
) >= BUFSIZ
)
212 errx(1, "oid too long: '%s'", string
);
213 bufp
= strsep(&cp
, "=");
218 newsize
= strlen(cp
);
220 len
= name2oid(bufp
, mib
);
228 errx(1, "unknown oid '%s'", bufp
);
231 if (oidfmt(mib
, len
, fmt
, &kind
))
232 err(1, "couldn't find format of oid '%s'", bufp
);
234 if (newval
== NULL
|| dflag
) {
235 if ((kind
& CTLTYPE
) == CTLTYPE_NODE
) {
238 i
= show_var(mib
, len
, 1);
240 i
= show_var(mib
, len
);
245 sysctl_all(mib
, len
);
248 i
= show_var(mib
, len
, 1);
250 i
= show_var(mib
, len
);
256 if ((kind
& CTLTYPE
) == CTLTYPE_NODE
)
257 errx(1, "oid '%s' isn't a leaf node", bufp
);
259 if (!(kind
& CTLFLAG_WR
)) {
260 if (kind
& CTLFLAG_TUN
) {
261 warnx("oid '%s' is a read only tunable", bufp
);
262 errx(1, "Tunable values are set in /boot/loader.conf");
264 errx(1, "oid '%s' is read only", bufp
);
268 if ((kind
& CTLTYPE
) == CTLTYPE_INT
||
269 (kind
& CTLTYPE
) == CTLTYPE_UINT
||
270 (kind
& CTLTYPE
) == CTLTYPE_LONG
||
271 (kind
& CTLTYPE
) == CTLTYPE_ULONG
||
272 (kind
& CTLTYPE
) == CTLTYPE_S64
||
273 (kind
& CTLTYPE
) == CTLTYPE_U64
) {
274 if (strlen(newval
) == 0)
275 errx(1, "empty numeric value");
278 switch (kind
& CTLTYPE
) {
280 if (strcmp(fmt
, "IK") == 0) {
282 if (!set_IK(newval
, &intval
))
284 errx(1, "invalid value '%s'",
287 intval
= (int)strtol(newval
, &endptr
,
289 if (endptr
== newval
|| *endptr
!= '\0')
290 errx(1, "invalid integer '%s'",
294 newsize
= sizeof(intval
);
297 uintval
= (int) strtoul(newval
, &endptr
, 0);
298 if (endptr
== newval
|| *endptr
!= '\0')
299 errx(1, "invalid unsigned integer '%s'",
302 newsize
= sizeof(uintval
);
305 longval
= strtol(newval
, &endptr
, 0);
306 if (endptr
== newval
|| *endptr
!= '\0')
307 errx(1, "invalid long integer '%s'",
310 newsize
= sizeof(longval
);
313 ulongval
= strtoul(newval
, &endptr
, 0);
314 if (endptr
== newval
|| *endptr
!= '\0')
315 errx(1, "invalid unsigned long integer"
316 " '%s'", (char *)newval
);
318 newsize
= sizeof(ulongval
);
323 i64val
= strtoimax(newval
, &endptr
, 0);
324 if (endptr
== newval
|| *endptr
!= '\0')
325 errx(1, "invalid int64_t '%s'",
328 newsize
= sizeof(i64val
);
331 u64val
= strtoumax(newval
, &endptr
, 0);
332 if (endptr
== newval
|| *endptr
!= '\0')
333 errx(1, "invalid uint64_t '%s'",
336 newsize
= sizeof(u64val
);
341 errx(1, "oid '%s' is type %d,"
342 " cannot set that", bufp
,
347 i
= show_var(mib
, len
, 1);
349 i
= show_var(mib
, len
);
351 if (sysctl(mib
, len
, 0, 0, newval
, newsize
) == -1) {
359 errx(1, "%s: value is not available",
362 errx(1, "%s: specification is incomplete",
365 errx(1, "%s: type is unknown to this program",
378 j
= show_var(mib
, len
, 1);
380 j
= show_var(mib
, len
);
388 /* These functions will dump out various interesting structures. */
391 S_clockinfo(int l2
, void *p
)
393 struct clockinfo
*ci
= (struct clockinfo
*)p
;
395 if (l2
!= sizeof(*ci
)) {
396 warnx("S_clockinfo %d != %zu", l2
, sizeof(*ci
));
400 printf(hflag
? "{ hz = %'d, tick = %'d, tickadj = %'d, profhz = %'d, stathz = %'d }" :
401 "{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
402 ci
->hz
, ci
->tick
, ci
->tickadj
, ci
->profhz
, ci
->stathz
);
404 printf(hflag
? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
405 "{ hz = %d, tick = %d, profhz = %d, stathz = %d }",
406 ci
->hz
, ci
->tick
, ci
->profhz
, ci
->stathz
);
412 S_loadavg(int l2
, void *p
)
414 struct loadavg
*tv
= (struct loadavg
*)p
;
416 if (l2
!= sizeof(*tv
)) {
417 warnx("S_loadavg %d != %zu", l2
, sizeof(*tv
));
420 printf(hflag
? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
421 (double)tv
->ldavg
[0]/(double)tv
->fscale
,
422 (double)tv
->ldavg
[1]/(double)tv
->fscale
,
423 (double)tv
->ldavg
[2]/(double)tv
->fscale
);
428 S_timeval(int l2
, void *p
)
430 struct timeval
*tv
= (struct timeval
*)p
;
434 if (l2
!= sizeof(*tv
)) {
435 warnx("S_timeval %d != %zu", l2
, sizeof(*tv
));
438 printf(hflag
? "{ sec = %'jd, usec = %'ld } " :
439 "{ sec = %jd, usec = %ld } ",
440 (intmax_t)tv
->tv_sec
, (long)tv
->tv_usec
);
442 p1
= strdup(ctime(&tv_sec
));
443 for (p2
=p1
; *p2
; p2
++)
453 S_vmtotal(int l2
, void *p
)
455 struct vmtotal
*v
= (struct vmtotal
*)p
;
456 int pageKilo
= getpagesize() / 1024;
458 if (l2
!= sizeof(*v
)) {
459 warnx("S_vmtotal %d != %zu", l2
, sizeof(*v
));
464 "\nSystem wide totals computed every five seconds:"
465 " (values in kilobytes)\n");
466 printf("===============================================\n");
468 "Processes:\t\t(RUNQ: %hd Disk Wait: %hd Page Wait: "
470 v
->t_rq
, v
->t_dw
, v
->t_pw
, v
->t_sl
);
472 "Virtual Memory:\t\t(Total: %dK Active: %dK)\n",
473 v
->t_vm
* pageKilo
, v
->t_avm
* pageKilo
);
474 printf("Real Memory:\t\t(Total: %dK Active: %dK)\n",
475 v
->t_rm
* pageKilo
, v
->t_arm
* pageKilo
);
476 printf("Shared Virtual Memory:\t(Total: %dK Active: %dK)\n",
477 v
->t_vmshr
* pageKilo
, v
->t_avmshr
* pageKilo
);
478 printf("Shared Real Memory:\t(Total: %dK Active: %dK)\n",
479 v
->t_rmshr
* pageKilo
, v
->t_armshr
* pageKilo
);
480 printf("Free Memory:\t%dK\n", v
->t_free
* pageKilo
);
486 set_IK(const char *str
, int *val
)
493 if ((len
= strlen(str
)) == 0)
496 if (*p
== 'C' || *p
== 'F') {
497 temp
= strtof(str
, &endptr
);
498 if (endptr
== str
|| endptr
!= p
)
501 temp
= (temp
- 32) * 5 / 9;
502 kelv
= temp
* 10 + 2732;
504 kelv
= (int)strtol(str
, &endptr
, 10);
505 if (endptr
== str
|| *endptr
!= '\0')
515 S_xswusage(int l2
, void *p
)
517 struct xsw_usage
*xsu
= (struct xsw_usage
*)p
;
519 if (l2
!= sizeof(*xsu
)) {
520 warnx("S_xswusage %d != %ld", l2
, sizeof(*xsu
));
524 "total = %.2fM used = %.2fM free = %.2fM %s",
525 ((double)xsu
->xsu_total
) / (1024.0 * 1024.0),
526 ((double)xsu
->xsu_used
) / (1024.0 * 1024.0),
527 ((double)xsu
->xsu_avail
) / (1024.0 * 1024.0),
528 xsu
->xsu_encrypted
? "(encrypted)" : "");
533 T_dev_t(int l2
, void *p
)
535 dev_t
*d
= (dev_t
*)p
;
537 if (l2
!= sizeof(*d
)) {
538 warnx("T_dev_T %d != %ld", l2
, sizeof(*d
));
541 if ((int)(*d
) != -1) {
542 if (minor(*d
) > 255 || minor(*d
) < 0)
543 printf("{ major = %d, minor = 0x%x }",
544 major(*d
), minor(*d
));
546 printf("{ major = %d, minor = %d }",
547 major(*d
), minor(*d
));
553 S_quads(int len
, void *p
)
555 size_t size
= sizeof(int64_t);
556 if (len
& (size
-1)) {
560 int64_t i
= *(int64_t *)p
;
564 p
= (uintptr_t)p
+ size
;
575 * These functions uses a presently undocumented interface to the kernel
576 * to walk the tree and get the type so it can print the value.
577 * This interface is under work and consideration, and should probably
578 * be killed with a big axe by the first person who can find the time.
579 * (be aware though, that the proper interface isn't as obvious as it
580 * may seem, there are various conflicting requirements.
584 name2oid(char *name
, int *oidp
)
591 // Support for CTL_USER
592 const char *user
= names
[CTL_USER
].ctl_name
;
594 if (!strncmp(name
, user
, j
)) {
596 if (name
[j
] == '.') {
597 for (i
= 1; i
< user_names_count
; ++i
) {
598 if (!strcmp(&name
[j
+1], user_names
[i
].ctl_name
)) {
604 } else if (name
[j
] == 0) {
614 j
= CTL_MAXNAME
* sizeof(int);
615 i
= sysctl(oid
, 2, oidp
, &j
, name
, strlen(name
));
623 oidfmt(int *oid
, int len
, char *fmt
, u_int
*kind
)
625 int qoid
[CTL_MAXNAME
+2];
632 memcpy(qoid
+ 2, oid
, len
* sizeof(int));
635 i
= sysctl(qoid
, len
+ 2, buf
, &j
, 0, 0);
637 if (i
&& errno
== ENOENT
) {
638 // Support for CTL_USER
639 if (oid
[0] == CTL_USER
) {
641 *kind
= CTLTYPE_NODE
;
643 } else if (len
== 2 && oid
[1] < user_names_count
) {
644 *kind
= user_names
[oid
[1]].ctl_type
;
652 err(1, "sysctl fmt %d %zu %d", i
, j
, errno
);
656 memcpy(kind
, buf
, sizeof(*kind
));
658 *kind
= *(u_int
*)buf
;
662 strcpy(fmt
, (char *)(buf
+ sizeof(u_int
)));
665 // Map Darwin sysctl types to FreeBSD types.
666 // - 0 with "I" -> CTLTYPE_INT
667 // - 0 with "S," -> CTLTYPE_STRUCT
668 // - CTLTYPE_INT with "IU" -> CTLTYPE_UINT
669 // - CTLTYPE_INT with "L" -> CTLTYPE_LONG
670 // - CTLTYPE_QUAD -> CTLTYPE_S64
671 // - CTLTYPE_QUAD with "*U" -> CTLTYPE_U64
673 switch (*kind
& CTLTYPE
) {
676 if (buf
[sizeof(u_int
)] == 'S') {
677 *kind
= (*kind
& ~CTLTYPE
) | CTLTYPE_STRUCT
;
678 } else if (buf
[sizeof(u_int
)] == 'I') {
679 *kind
= (*kind
& ~CTLTYPE
) | CTLTYPE_INT
;
680 if (buf
[sizeof(u_int
)+1] == 'U') {
681 *kind
= (*kind
& ~CTLTYPE
) | CTLTYPE_UINT
;
683 } else if (buf
[sizeof(u_int
)] == 'L') {
684 *kind
= (*kind
& ~CTLTYPE
) | CTLTYPE_LONG
;
685 if (buf
[sizeof(u_int
)+1] == 'U') {
686 *kind
= (*kind
& ~CTLTYPE
) | CTLTYPE_ULONG
;
691 *kind
= (*kind
& ~CTLTYPE
);
692 if (fmt
&& strchr(fmt
, 'U')) {
693 *kind
|= CTLTYPE_U64
;
695 *kind
|= CTLTYPE_S64
;
705 static int ctl_sign
[CTLTYPE
+1] = {
711 static int ctl_size
[CTLTYPE
+1] = {
712 [CTLTYPE_INT
] = sizeof(int),
713 [CTLTYPE_UINT
] = sizeof(u_int
),
714 [CTLTYPE_LONG
] = sizeof(long),
715 [CTLTYPE_ULONG
] = sizeof(u_long
),
716 [CTLTYPE_S64
] = sizeof(int64_t),
717 [CTLTYPE_U64
] = sizeof(int64_t),
721 * This formats and outputs the value of one variable
723 * Returns zero if anything was actually output.
724 * Returns one if didn't know what to do with this.
725 * Return minus one if we had errors.
729 show_var(int *oid
, int nlen
, int show_masked
)
731 show_var(int *oid
, int nlen
)
734 u_char buf
[BUFSIZ
], *val
, *oval
, *p
;
735 char name
[BUFSIZ
], *fmt
;
736 const char *sep
, *sep1
;
737 int qoid
[CTL_MAXNAME
+2];
740 int i
, hexlen
, sign
, ctltype
;
744 int (*func
)(int, void *);
747 umv
= mv
= intlen
= 0;
752 memcpy(qoid
+ 2, oid
, nlen
* sizeof(int));
754 oidfmt(oid
, nlen
, fmt
, &kind
);
757 if (!show_masked
&& (kind
& CTLFLAG_MASKED
)) {
763 // Support for CTL_USER
764 if (nlen
>= 1 && oid
[0] == CTL_USER
) {
765 const char *user_name
= "";
768 if (nlen
== 2 && i
> 0 && i
< user_names_count
) {
769 user_name
= user_names
[i
].ctl_name
;
772 j
= snprintf(name
, sizeof(name
), "%s%s%s",
773 names
[CTL_USER
].ctl_name
, sep
, user_name
);
779 i
= sysctl(qoid
, nlen
+ 2, name
, &j
, 0, 0);
781 err(1, "sysctl name %d %zu %d", i
, j
, errno
);
796 if (dflag
) { /* just print description */
799 i
= sysctl(qoid
, nlen
+ 2, buf
, &j
, 0, 0);
801 printf("%s%s", name
, sep
);
805 /* find an estimate of how much we need for this var */
807 i
= sysctl(oid
, nlen
, 0, &j
, 0, 0);
808 j
+= j
; /* we want to be sure :-) */
810 val
= oval
= malloc(j
+ 1);
812 warnx("malloc failed");
816 i
= sysctl(oid
, nlen
, val
, &len
, 0, 0);
823 fwrite(val
, 1, len
, stdout
);
829 ctltype
= (kind
& CTLTYPE
);
830 sign
= ctl_sign
[ctltype
];
831 intlen
= ctl_size
[ctltype
];
836 printf("%s%s", name
, sep
);
837 printf("%.*s", (int)len
, p
);
848 printf("%s%s", name
, sep
);
849 hexlen
= (int)(2 + (intlen
* CHAR_BIT
+ 3) / 4);
851 while (len
>= intlen
) {
852 switch (kind
& CTLTYPE
) {
855 umv
= *(u_int
*)(void *)p
;
856 mv
= *(int *)(void *)p
;
860 umv
= *(u_long
*)(void *)p
;
861 mv
= *(long *)(void *)p
;
865 umv
= *(uint64_t *)(void *)p
;
866 mv
= *(int64_t *)(void *)p
;
871 printf("%#0*jx", hexlen
, umv
);
873 printf(hflag
? "%'ju" : "%ju", umv
);
874 else if (fmt
[1] == 'K') {
878 printf("%.1fC", (mv
- 2732.0) / 10);
880 printf(hflag
? "%'jd" : "%jd", mv
);
890 if (strcmp(fmt
, "S,clockinfo") == 0)
892 else if (strcmp(fmt
, "S,timeval") == 0)
894 else if (strcmp(fmt
, "S,loadavg") == 0)
897 else if (!strcmp(fmt
, "S,xsw_usage"))
899 else if (!strcmp(fmt
, "T,dev_t"))
901 else if (!strcmp(fmt
, "Q"))
904 else if (strcmp(fmt
, "S,vmtotal") == 0)
911 printf("%s%s", name
, sep
);
912 i
= (*func
)((int)len
, p
);
918 if (!oflag
&& !xflag
) {
923 printf("%s%s", name
, sep
);
924 printf("Format:%s Length:%zu Dump:0x", fmt
, len
);
925 while (len
-- && (xflag
|| p
< val
+ 16))
926 printf("%02x", *p
++);
927 if (!xflag
&& len
> 16)
937 // Support for CTL_USER
939 sysctl_all_user(int *oid
, int len
)
942 if (len
> 1 || (len
== 1 && oid
[0] != CTL_USER
)) {
945 for (i
= 0; i
< user_names_count
; ++i
) {
946 int oid
[2] = { CTL_USER
, i
};
947 j
= show_var(oid
, 2, 0);
956 sysctl_all(int *oid
, int len
)
961 int name1
[22], name2
[22];
966 sysctl_all_user(oid
, len
);
973 memcpy(name1
+2, oid
, len
* sizeof(int));
981 j
= sysctl(name1
, (u_int
)l1
, name2
, &l2
, 0, 0);
986 err(1, "sysctl(getnext) %d %zu", j
, l2
);
991 if (len
< 0 || l2
< (unsigned int)len
)
994 for (i
= 0; i
< len
; i
++)
995 if (name2
[i
] != oid
[i
])
999 i
= show_var(name2
, (u_int
)l2
, 0);
1001 i
= show_var(name2
, (u_int
)l2
);
1006 memcpy(name1
+2, name2
, l2
* sizeof(int));