X-Git-Url: https://git.saurik.com/apple/system_cmds.git/blobdiff_plain/6d658acdb5f61932718109ed8f339604b778ab80..c40d5e067506b677a9941a31cf3fadf56025c9a7:/sysctl.tproj/sysctl.c diff --git a/sysctl.tproj/sysctl.c b/sysctl.tproj/sysctl.c index 76b8a6f..606459a 100644 --- a/sysctl.tproj/sysctl.c +++ b/sysctl.tproj/sysctl.c @@ -1,27 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. @@ -34,10 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -55,591 +27,161 @@ * SUCH DAMAGE. */ - /* - Modified November 1, 2000, by Ryan Rempel, ryan.rempel@utoronto.ca - - The Darwin sysctl mechanism is in a state of flux. Parts of the kernel use the old - style of BSD sysctl definition, and other parts use the new style. The sysctl (8) - command that shipped with Darwin 1.2 (OS X PB) did not allow you to access - all possible sysctl values. In particular, it did not permit access to sysctl values - created by kernel extensions--hence my particular interest. The freeBSD sysctl (8) - command compiled and ran under Darwin 1.2, and it did permit access to - sysctl values created by kernel extensions, as well as several others. However, it - did not permit access to many other values which the Darwin 1.2 sysctl could access. - - What I have done is merge the Darwin 1.2 sysctl and the freeBSD sysctl. Essentially, - there are two points of merger. When showing all values (i.e. -a, -A, or -X), sysctl now - runs the Darwin 1.2 routine to show all values, and then the freeBSD routine. This does - result in some duplication. When getting or setting a particular value, sysctl now tries - the freeBSD way first. If it cannot find the value, then it tries the Darwin 1.2 way. - - There are a few oddities which this creates (aside from some duplication with -a, -A, - and -X). The freeBSD version of sysctl now supports two extra options, -b and -X. - In this syctl, those options are supported where the value is retrieved by the freeBSD - routine, and have no effect where the value is retrieved by the Darwin 1.2 routine. - The freeBSD sysctl uses a ':' to separate the name and the value, whereas Darwin 1.2's - sysctl uses a '='. I have left this way, as it lets you know which routine was used, - should it matter. - - I have also fixed several lines which gave warnings previously, one of which appears - to have been an actual bug (bufp was dereferenced when it shouldn't have been). - I have also incoporated my previous patch to permit setting kern.hostid as an unsigned - integer. In the freeBSD side of the code, I have incorporated a general fix for - setting values where the format is specified as unsigned integer. - */ - +#include #ifndef lint -static char copyright[] = +__unused static const char copyright[] = "@(#) Copyright (c) 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)sysctl.c 8.5 (Berkeley) 5/9/95"; +#if 0 +static char sccsid[] = "@(#)from: sysctl.c 8.1 (Berkeley) 6/6/93"; +#endif +__unused static const char rcsid[] = + "$FreeBSD$"; #endif /* not lint */ #include -#include -#include +#include +#include #include #include -#include #ifdef __APPLE__ #include #include #include -#else -#include -#endif /* __APPLE__ */ -#include +#else // !__APPLE__ +#include +#endif // !__APPLE__ -#include #include -#include +#include +#include +#include +#include #include #include #include +#include -#include -#include -#include - -struct ctlname topname[] = CTL_NAMES; -struct ctlname kernname[] = CTL_KERN_NAMES; -struct ctlname vmname[] = CTL_VM_NAMES; -struct ctlname hwname[] = CTL_HW_NAMES; -struct ctlname username[] = CTL_USER_NAMES; -struct ctlname debugname[CTL_DEBUG_MAXID]; -struct ctlname *vfsname; -#ifdef CTL_MACHDEP_NAMES -struct ctlname machdepname[] = CTL_MACHDEP_NAMES; -#endif -char names[BUFSIZ]; -int lastused; - -struct list { - struct ctlname *list; - int size; -}; -struct list toplist = { topname, CTL_MAXID }; -struct list secondlevel[] = { - { 0, 0 }, /* CTL_UNSPEC */ - { kernname, KERN_MAXID }, /* CTL_KERN */ - { vmname, VM_MAXID }, /* CTL_VM */ - { 0, 0 }, /* CTL_VFS */ - { 0, 0 }, /* CTL_NET */ - { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */ - { 0,0 }, /* CTL_HW */ -#ifdef CTL_MACHDEP_NAMES - { machdepname, CPU_MAXID }, /* CTL_MACHDEP */ -#else - { 0, 0 }, /* CTL_MACHDEP */ -#endif - { username, USER_MAXID }, /* CTL_USER_NAMES */ -}; - -static int Aflag, aflag, bflag, nflag, wflag, Xflag; -static int foundSome = 0; - -void listall(char *prefix, struct list *lp); -void old_parse(char *string, int flags); -void debuginit(); -void vfsinit(); -int findname(char *string, char *level, char **bufp, struct list *namelist); -void usage(); +static int aflag, bflag, dflag, eflag, hflag, iflag; +static int Nflag, nflag, oflag, qflag, xflag, warncount; -static void parse(char *string, int flags); static int oidfmt(int *, int, char *, u_int *); +static void parse(const char *); +#ifdef __APPLE__ static int show_var(int *, int, int); -static int sysctl_all (int *oid, int len); +#else +static int show_var(int *, int); +#endif +static int sysctl_all(int *oid, int len); static int name2oid(char *, int *); -/* - * Variables requiring special processing. - */ -#define CLOCK 0x00000001 -#define BOOTTIME 0x00000002 -#define CONSDEV 0x00000004 +#ifndef __APPLE__ +static int set_IK(const char *, int *); +#endif -int -main(argc, argv) - int argc; - char *argv[]; -{ -// extern char *optarg; // unused - extern int optind; - int ch, lvl1; +#ifdef __APPLE__ +// Shims for FreeBSD source compatibility. +#define CTLTYPE_UINT 0xa +#define CTLTYPE_LONG 0xb +#define CTLTYPE_ULONG 0xc +#define CTLTYPE_S64 0xd +#define CTLTYPE_U64 0xe + +#define CTLFLAG_TUN 0 + +// Support for CTL_USER +const struct ctlname names[] = CTL_NAMES; +const struct ctlname user_names[] = CTL_USER_NAMES; +const int user_names_count = sizeof(user_names) / sizeof(*user_names); +#endif - while ((ch = getopt(argc, argv, "AabnwX")) != EOF) { - switch (ch) { - case 'A': Aflag = 1; break; - case 'a': aflag = 1; break; - case 'b': bflag = 1; break; - case 'n': nflag = 1; break; - case 'w': wflag = 1; break; - case 'X': Xflag = Aflag = 1; break; - default: usage(); - } - } - argc -= optind; - argv += optind; +static void +usage(void) +{ - if (argc == 0 && (Aflag || aflag)) { - debuginit(); - vfsinit(); - for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) - listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); - exit (sysctl_all(0, 0)); - } - if (argc == 0) - usage(); - for (; *argv != NULL; ++argv) - parse(*argv, 1); - exit(0); + (void)fprintf(stderr, "%s\n%s\n", + "usage: sysctl [-bdehiNnoqx] name[=value] ...", + " sysctl [-bdehNnoqx] -a"); + exit(1); } -/* - * List all variables known to the system. - */ -void -listall(prefix, lp) - char *prefix; - struct list *lp; +int +main(int argc, char **argv) { - int lvl2; - char *cp, name[BUFSIZ]; + int ch; - if (lp->list == 0) - return; - strcpy(name, prefix); - cp = &name[strlen(name)]; - *cp++ = '.'; - for (lvl2 = 0; lvl2 < lp->size; lvl2++) { - if (lp->list[lvl2].ctl_name == 0) - continue; - strcpy(cp, lp->list[lvl2].ctl_name); - old_parse(name, Aflag); - } -} + setlocale(LC_NUMERIC, ""); + setbuf(stdout,0); + setbuf(stderr,0); -/* - * Parse a name into a MIB entry. - * Lookup and print out the MIB entry if it exists. - * Set a new value if requested. - */ -void -old_parse(string, flags) - char *string; - int flags; -{ - int indx, type, state, len; - size_t size; - int special = 0; - void *newval = 0; - int intval, newsize = 0; - unsigned int uintval; - int useUnsignedInt = 0; - quad_t quadval; - struct list *lp; - struct vfsconf vfc; - int mib[CTL_MAXNAME]; - char *cp, *bufp, buf[BUFSIZ] /*, strval[BUFSIZ] */ ; - - bufp = buf; - snprintf(buf, BUFSIZ, "%s", string); - if ((cp = strchr(string, '=')) != NULL) { - if (!wflag) { - fprintf(stderr, "Must specify -w to set variables\n"); - exit(2); - } - *strchr(buf, '=') = '\0'; - *cp++ = '\0'; - while (isspace(*cp)) - cp++; - newval = cp; - newsize = strlen(cp); - } - if ((indx = findname(string, "top", &bufp, &toplist)) == -1) - return; - mib[0] = indx; - if (indx == CTL_VFS) - vfsinit(); - if (indx == CTL_DEBUG) - debuginit(); - lp = &secondlevel[indx]; - if (lp->list == 0) { - if (!foundSome) fprintf(stderr, "%s: class is not implemented\n", - topname[indx].ctl_name); - return; - } - if (bufp == NULL) { - listall(topname[indx].ctl_name, lp); - return; - } - if ((indx = findname(string, "second", &bufp, lp)) == -1) - return; - mib[1] = indx; - type = lp->list[indx].ctl_type; - len = 2; - switch (mib[0]) { - - case CTL_KERN: - switch (mib[1]) { - case KERN_PROF: - mib[2] = GPROF_STATE; - size = sizeof state; - if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) { - if (flags == 0) - return; - if (!nflag) - fprintf(stdout, "%s: ", string); - fprintf(stderr, - "kernel is not compiled for profiling\n"); - return; - } - if (!nflag) - fprintf(stdout, "%s: %s\n", string, - state == GMON_PROF_OFF ? "off" : "running"); - return; - case KERN_VNODE: - case KERN_FILE: - if (flags == 0) - return; - fprintf(stderr, - "Use pstat to view %s information\n", string); - return; - case KERN_PROC: - if (flags == 0) - return; - fprintf(stderr, - "Use ps to view %s information\n", string); - return; - case KERN_CLOCKRATE: - special |= CLOCK; + while ((ch = getopt(argc, argv, "AabdehiNnoqwxX")) != -1) { + switch (ch) { + case 'A': + /* compatibility */ + aflag = oflag = 1; break; - case KERN_BOOTTIME: - special |= BOOTTIME; + case 'a': + aflag = 1; break; - case KERN_HOSTID: - useUnsignedInt = 1; + case 'b': + bflag = 1; break; - } - break; - - case CTL_HW: - useUnsignedInt = 1; - break; - - case CTL_VM: - if (mib[1] == VM_LOADAVG) { /* XXX this is bogus */ - double loads[3]; - - getloadavg(loads, 3); - if (!nflag) - fprintf(stdout, "%s: ", string); - fprintf(stdout, "%.2f %.2f %.2f\n", - loads[0], loads[1], loads[2]); - return; - } - if (flags == 0) - return; - fprintf(stderr, - "Use vmstat or systat to view %s information\n", string); - return; - - case CTL_DEBUG: - mib[2] = CTL_DEBUG_VALUE; - len = 3; - break; - - case CTL_MACHDEP: -#ifdef CPU_CONSDEV - if (mib[1] == CPU_CONSDEV) - special |= CONSDEV; -#endif - break; - - case CTL_VFS: - mib[3] = mib[1]; - mib[1] = VFS_GENERIC; - mib[2] = VFS_CONF; - len = 4; - size = sizeof vfc; - if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) { - perror("vfs print"); - return; - } - if (flags == 0 && vfc.vfc_refcount == 0) - return; - if (!nflag) - fprintf(stdout, "%s has %d mounted instance%s\n", - string, vfc.vfc_refcount, - vfc.vfc_refcount != 1 ? "s" : ""); - else - fprintf(stdout, "%d\n", vfc.vfc_refcount); - return; - - case CTL_USER: - break; - - default: - fprintf(stderr, "Illegal top level value: %d\n", mib[0]); - return; - - } - if (bufp) { - fprintf(stderr, "name %s in %s is unknown\n", bufp, string); - return; - } - if (newsize > 0) { - switch (type) { - case CTLTYPE_INT: - if (useUnsignedInt) { - uintval = strtoul(newval, 0, 0); - newval = &uintval; - newsize = sizeof uintval; - } else { - intval = atoi(newval); - newval = &intval; - newsize = sizeof intval; - } + case 'd': + dflag = 1; break; - - case CTLTYPE_QUAD: - sscanf(newval, "%qd", &quadval); - newval = &quadval; - newsize = sizeof quadval; + case 'e': + eflag = 1; + break; + case 'h': + hflag = 1; + break; + case 'i': + iflag = 1; + break; + case 'N': + Nflag = 1; + break; + case 'n': + nflag = 1; + break; + case 'o': + oflag = 1; + break; + case 'q': + qflag = 1; + break; + case 'w': + /* compatibility */ + /* ignored */ + break; + case 'X': + /* compatibility */ + aflag = xflag = 1; + break; + case 'x': + xflag = 1; break; - } - } - size = BUFSIZ; - if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) { - if (flags == 0) - return; - switch (errno) { - case EOPNOTSUPP: - fprintf(stderr, "%s: value is not available\n", string); - return; - case ENOTDIR: - fprintf(stderr, "%s: specification is incomplete\n", - string); - return; - case ENOMEM: - fprintf(stderr, "%s: type is unknown to this program\n", - string); - return; default: - perror(string); - return; - } - } - if (special & CLOCK) { - struct clockinfo *clkp = (struct clockinfo *)buf; - - if (!nflag) - fprintf(stdout, "%s: ", string); - fprintf(stdout, - "hz = %d, tick = %d, profhz = %d, stathz = %d\n", - clkp->hz, clkp->tick, clkp->profhz, clkp->stathz); - return; - } - if (special & BOOTTIME) { - struct timeval *btp = (struct timeval *)buf; - - if (!nflag) - fprintf(stdout, "%s = %s\n", string, - ctime((time_t *) &btp->tv_sec)); - else - fprintf(stdout, "%d\n", btp->tv_sec); - return; - } - if (special & CONSDEV) { - dev_t dev = *(dev_t *)buf; - - if (!nflag) - fprintf(stdout, "%s = %s\n", string, - devname(dev, S_IFCHR)); - else - fprintf(stdout, "0x%x\n", dev); - return; - } - switch (type) { - case CTLTYPE_INT: - if (newsize == 0) { - if (!nflag) - fprintf(stdout, "%s = ", string); - fprintf(stdout, useUnsignedInt ? "%u\n" : "%d\n", *(int *)buf); - } else { - if (!nflag) - fprintf(stdout, useUnsignedInt ? "%s: %u -> " : "%s: %d -> ", - string, *(int *)buf); - fprintf(stdout, useUnsignedInt ? "%u\n" : "%d\n", *(int *)newval); - } - return; - - case CTLTYPE_STRING: - if (newsize == 0) { - if (!nflag) - fprintf(stdout, "%s = ", string); - fprintf(stdout, "%s\n", buf); - } else { - if (!nflag) - fprintf(stdout, "%s: %s -> ", string, buf); - fprintf(stdout, "%s\n", (char *) newval); - } - return; - - case CTLTYPE_QUAD: - if (newsize == 0) { - if (!nflag) - fprintf(stdout, "%s = ", string); - fprintf(stdout, "%qd\n", *(quad_t *)buf); - } else { - if (!nflag) - fprintf(stdout, "%s: %qd -> ", string, - *(quad_t *)buf); - fprintf(stdout, "%qd\n", *(quad_t *)newval); - } - return; - - case CTLTYPE_STRUCT: - return; - - default: - case CTLTYPE_NODE: - fprintf(stderr, "%s: unknown type returned\n", - string); - return; - } -} - -/* - * Initialize the set of debugging names - */ -void debuginit() -{ - int mib[3], loc, i; - size_t size; - - if (secondlevel[CTL_DEBUG].list != 0) - return; - secondlevel[CTL_DEBUG].list = debugname; - mib[0] = CTL_DEBUG; - mib[2] = CTL_DEBUG_NAME; - for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) { - mib[1] = i; - size = BUFSIZ - loc; - if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1) - continue; - debugname[i].ctl_name = &names[loc]; - debugname[i].ctl_type = CTLTYPE_INT; - loc += size; - } - lastused = loc; -} - -/* - * Initialize the set of filesystem names - */ -void vfsinit() -{ - int mib[4], maxtypenum, cnt, loc, size; - struct vfsconf vfc; - size_t buflen; - - if (secondlevel[CTL_VFS].list != 0) - return; - mib[0] = CTL_VFS; - mib[1] = VFS_GENERIC; - mib[2] = VFS_MAXTYPENUM; - buflen = 4; - if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0) - return; - if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == 0) - return; - memset(vfsname, 0, maxtypenum * sizeof(*vfsname)); - mib[2] = VFS_CONF; - buflen = sizeof vfc; - for (loc = lastused, cnt = 0; cnt < maxtypenum; cnt++) { - mib[3] = cnt; - if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) { - if (errno == EOPNOTSUPP) - continue; - perror("vfsinit"); - free(vfsname); - return; + usage(); } - strcat(&names[loc], vfc.vfc_name); - vfsname[cnt].ctl_name = &names[loc]; - vfsname[cnt].ctl_type = CTLTYPE_INT; - size = strlen(vfc.vfc_name) + 1; - loc += size; - } - lastused = loc; - secondlevel[CTL_VFS].list = vfsname; - secondlevel[CTL_VFS].size = maxtypenum; - return; -} - -/* - * Scan a list of names searching for a particular name. - */ -int -findname(string, level, bufp, namelist) - char *string; - char *level; - char **bufp; - struct list *namelist; -{ - char *name; - int i; - - if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { - fprintf(stderr, "%s: incomplete specification\n", string); - return (-1); } - for (i = 0; i < namelist->size; i++) - if (namelist->list[i].ctl_name != NULL && - strcmp(name, namelist->list[i].ctl_name) == 0) - break; - if (i == namelist->size) { - fprintf(stderr, "%s level name %s in %s is invalid\n", - level, name, string); - return (-1); - } - return (i); -} + argc -= optind; + argv += optind; -void usage() -{ + if (Nflag && nflag) + usage(); + if (aflag && argc == 0) + exit(sysctl_all(0, 0)); + if (argc == 0) + usage(); - (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", - "usage: sysctl [-bn] variable ...", - " sysctl [-bn] -w variable=value ...", - " sysctl [-bn] -a", - " sysctl [-bn] -A", - " sysctl [-bn] -X"); - exit(1); + warncount = 0; + while (argc-- > 0) + parse(*argv++); + exit(warncount); } /* @@ -648,53 +190,63 @@ void usage() * Set a new value if requested. */ static void -parse(char *string, int flags) +parse(const char *string) { int len, i, j; void *newval = 0; - int intval, newsize = 0; + int intval; unsigned int uintval; - quad_t quadval; + long longval; + unsigned long ulongval; + size_t newsize = 0; + int64_t i64val; + uint64_t u64val; int mib[CTL_MAXNAME]; - char *cp, *bufp, buf[BUFSIZ], fmt[BUFSIZ]; + char *cp, *bufp, buf[BUFSIZ], *endptr, fmt[BUFSIZ]; u_int kind; - bufp = buf; - snprintf(buf, BUFSIZ, "%s", string); - if ((cp = strchr(string, '=')) != NULL) { - if (!wflag) - errx(2, "must specify -w to set variables"); - *strchr(buf, '=') = '\0'; - *cp++ = '\0'; + cp = buf; + if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) + errx(1, "oid too long: '%s'", string); + bufp = strsep(&cp, "="); + if (cp != NULL) { while (isspace(*cp)) cp++; newval = cp; newsize = strlen(cp); - } else { - if (wflag) - usage(); } len = name2oid(bufp, mib); if (len < 0) { - if (cp != NULL) { - while (*cp != '\0') cp--; - *cp = '='; - } - old_parse (string, flags); - return; + if (iflag) + return; + if (qflag) + exit(1); + else + errx(1, "unknown oid '%s'", bufp); } if (oidfmt(mib, len, fmt, &kind)) err(1, "couldn't find format of oid '%s'", bufp); - if (!wflag) { + if (newval == NULL || dflag) { if ((kind & CTLTYPE) == CTLTYPE_NODE) { + if (dflag) { +#ifdef __APPLE__ + i = show_var(mib, len, 1); +#else + i = show_var(mib, len); +#endif + if (!i && !bflag) + putchar('\n'); + } sysctl_all(mib, len); - foundSome = 1; - old_parse (string, flags); } else { +#ifdef __APPLE__ i = show_var(mib, len, 1); +#else + i = show_var(mib, len); +#endif if (!i && !bflag) putchar('\n'); } @@ -702,51 +254,117 @@ parse(char *string, int flags) if ((kind & CTLTYPE) == CTLTYPE_NODE) errx(1, "oid '%s' isn't a leaf node", bufp); - if (!(kind&CTLFLAG_WR)) - errx(1, "oid '%s' is read only", bufp); - + if (!(kind & CTLFLAG_WR)) { + if (kind & CTLFLAG_TUN) { + warnx("oid '%s' is a read only tunable", bufp); + errx(1, "Tunable values are set in /boot/loader.conf"); + } else { + errx(1, "oid '%s' is read only", bufp); + } + } + + if ((kind & CTLTYPE) == CTLTYPE_INT || + (kind & CTLTYPE) == CTLTYPE_UINT || + (kind & CTLTYPE) == CTLTYPE_LONG || + (kind & CTLTYPE) == CTLTYPE_ULONG || + (kind & CTLTYPE) == CTLTYPE_S64 || + (kind & CTLTYPE) == CTLTYPE_U64) { + if (strlen(newval) == 0) + errx(1, "empty numeric value"); + } + switch (kind & CTLTYPE) { case CTLTYPE_INT: - if ((*fmt == 'I') && (*(fmt + 1) == 'U')) { - uintval = (unsigned int) strtoul (newval, NULL, 0); - newval = &uintval; - newsize = sizeof uintval; - } else { - intval = (int) strtol(newval, NULL, 0); - newval = &intval; - newsize = sizeof intval; + if (strcmp(fmt, "IK") == 0) { +#ifndef __APPLE__ + if (!set_IK(newval, &intval)) +#endif + errx(1, "invalid value '%s'", + (char *)newval); + } else { + intval = (int)strtol(newval, &endptr, + 0); + if (endptr == newval || *endptr != '\0') + errx(1, "invalid integer '%s'", + (char *)newval); } + newval = &intval; + newsize = sizeof(intval); + break; + case CTLTYPE_UINT: + uintval = (int) strtoul(newval, &endptr, 0); + if (endptr == newval || *endptr != '\0') + errx(1, "invalid unsigned integer '%s'", + (char *)newval); + newval = &uintval; + newsize = sizeof(uintval); + break; + case CTLTYPE_LONG: + longval = strtol(newval, &endptr, 0); + if (endptr == newval || *endptr != '\0') + errx(1, "invalid long integer '%s'", + (char *)newval); + newval = &longval; + newsize = sizeof(longval); + break; + case CTLTYPE_ULONG: + ulongval = strtoul(newval, &endptr, 0); + if (endptr == newval || *endptr != '\0') + errx(1, "invalid unsigned long integer" + " '%s'", (char *)newval); + newval = &ulongval; + newsize = sizeof(ulongval); break; case CTLTYPE_STRING: break; - case CTLTYPE_QUAD: + case CTLTYPE_S64: + i64val = strtoimax(newval, &endptr, 0); + if (endptr == newval || *endptr != '\0') + errx(1, "invalid int64_t '%s'", + (char *)newval); + newval = &i64val; + newsize = sizeof(i64val); break; - sscanf(newval, "%qd", &quadval); - newval = &quadval; - newsize = sizeof quadval; + case CTLTYPE_U64: + u64val = strtoumax(newval, &endptr, 0); + if (endptr == newval || *endptr != '\0') + errx(1, "invalid uint64_t '%s'", + (char *)newval); + newval = &u64val; + newsize = sizeof(u64val); break; + case CTLTYPE_OPAQUE: + /* FALLTHROUGH */ default: errx(1, "oid '%s' is type %d," " cannot set that", bufp, kind & CTLTYPE); } +#ifdef __APPLE__ i = show_var(mib, len, 1); +#else + i = show_var(mib, len); +#endif if (sysctl(mib, len, 0, 0, newval, newsize) == -1) { if (!i && !bflag) putchar('\n'); switch (errno) { +#ifdef __APPLE__ + case ENOTSUP: +#endif // __APPLE__ case EOPNOTSUPP: - errx(1, "%s: value is not available", + errx(1, "%s: value is not available", string); case ENOTDIR: - errx(1, "%s: specification is incomplete", + errx(1, "%s: specification is incomplete", string); case ENOMEM: - errx(1, "%s: type is unknown to this program", + errx(1, "%s: type is unknown to this program", string); default: warn("%s", string); + warncount++; return; } } @@ -754,7 +372,11 @@ parse(char *string, int flags) printf(" -> "); i = nflag; nflag = 1; +#ifdef __APPLE__ j = show_var(mib, len, 1); +#else + j = show_var(mib, len); +#endif if (!j && !bflag) putchar('\n'); nflag = i; @@ -767,10 +389,20 @@ static int S_clockinfo(int l2, void *p) { struct clockinfo *ci = (struct clockinfo*)p; - if (l2 != sizeof *ci) - err(1, "S_clockinfo %d != %d", l2, sizeof *ci); - printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }", - ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz); + + if (l2 != sizeof(*ci)) { + warnx("S_clockinfo %d != %zu", l2, sizeof(*ci)); + return (1); + } +#ifdef __APPLE__ + printf(hflag ? "{ hz = %'d, tick = %'d, tickadj = %'d, profhz = %'d, stathz = %'d }" : + "{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }", + ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz); +#else + printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" : + "{ hz = %d, tick = %d, profhz = %d, stathz = %d }", + ci->hz, ci->tick, ci->profhz, ci->stathz); +#endif return (0); } @@ -779,10 +411,11 @@ S_loadavg(int l2, void *p) { struct loadavg *tv = (struct loadavg*)p; - if (l2 != sizeof *tv) - err(1, "S_loadavg %d != %d", l2, sizeof *tv); - - printf("{ %.2f %.2f %.2f }", + if (l2 != sizeof(*tv)) { + warnx("S_loadavg %d != %zu", l2, sizeof(*tv)); + return (1); + } + printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }", (double)tv->ldavg[0]/(double)tv->fscale, (double)tv->ldavg[1]/(double)tv->fscale, (double)tv->ldavg[2]/(double)tv->fscale); @@ -796,16 +429,101 @@ S_timeval(int l2, void *p) time_t tv_sec; char *p1, *p2; - if (l2 != sizeof *tv) - err(1, "S_timeval %d != %d", l2, sizeof *tv); - printf("{ sec = %ld, usec = %ld } ", - (long) tv->tv_sec, (long) tv->tv_usec); + if (l2 != sizeof(*tv)) { + warnx("S_timeval %d != %zu", l2, sizeof(*tv)); + return (1); + } + printf(hflag ? "{ sec = %'jd, usec = %'ld } " : + "{ sec = %jd, usec = %ld } ", + (intmax_t)tv->tv_sec, (long)tv->tv_usec); tv_sec = tv->tv_sec; p1 = strdup(ctime(&tv_sec)); for (p2=p1; *p2 ; p2++) if (*p2 == '\n') *p2 = '\0'; fputs(p1, stdout); + free(p1); + return (0); +} + +#ifndef __APPLE__ +static int +S_vmtotal(int l2, void *p) +{ + struct vmtotal *v = (struct vmtotal *)p; + int pageKilo = getpagesize() / 1024; + + if (l2 != sizeof(*v)) { + warnx("S_vmtotal %d != %zu", l2, sizeof(*v)); + return (1); + } + + printf( + "\nSystem wide totals computed every five seconds:" + " (values in kilobytes)\n"); + printf("===============================================\n"); + printf( + "Processes:\t\t(RUNQ: %hd Disk Wait: %hd Page Wait: " + "%hd Sleep: %hd)\n", + v->t_rq, v->t_dw, v->t_pw, v->t_sl); + printf( + "Virtual Memory:\t\t(Total: %dK Active: %dK)\n", + v->t_vm * pageKilo, v->t_avm * pageKilo); + printf("Real Memory:\t\t(Total: %dK Active: %dK)\n", + v->t_rm * pageKilo, v->t_arm * pageKilo); + printf("Shared Virtual Memory:\t(Total: %dK Active: %dK)\n", + v->t_vmshr * pageKilo, v->t_avmshr * pageKilo); + printf("Shared Real Memory:\t(Total: %dK Active: %dK)\n", + v->t_rmshr * pageKilo, v->t_armshr * pageKilo); + printf("Free Memory:\t%dK\n", v->t_free * pageKilo); + + return (0); +} + +static int +set_IK(const char *str, int *val) +{ + float temp; + int len, kelv; + const char *p; + char *endptr; + + if ((len = strlen(str)) == 0) + return (0); + p = &str[len - 1]; + if (*p == 'C' || *p == 'F') { + temp = strtof(str, &endptr); + if (endptr == str || endptr != p) + return (0); + if (*p == 'F') + temp = (temp - 32) * 5 / 9; + kelv = temp * 10 + 2732; + } else { + kelv = (int)strtol(str, &endptr, 10); + if (endptr == str || *endptr != '\0') + return (0); + } + *val = kelv; + return (1); +} +#endif // !__APPLE__ + +#ifdef __APPLE__ +static int +S_xswusage(int l2, void *p) +{ + struct xsw_usage *xsu = (struct xsw_usage *)p; + + if (l2 != sizeof(*xsu)) { + warnx("S_xswusage %d != %ld", l2, sizeof(*xsu)); + return (1); + } + fprintf(stdout, + "total = %.2fM used = %.2fM free = %.2fM %s", + ((double)xsu->xsu_total) / (1024.0 * 1024.0), + ((double)xsu->xsu_used) / (1024.0 * 1024.0), + ((double)xsu->xsu_avail) / (1024.0 * 1024.0), + xsu->xsu_encrypted ? "(encrypted)" : ""); return (0); } @@ -813,8 +531,11 @@ static int T_dev_t(int l2, void *p) { dev_t *d = (dev_t *)p; - if (l2 != sizeof *d) - err(1, "T_dev_T %d != %d", l2, sizeof *d); + + if (l2 != sizeof(*d)) { + warnx("T_dev_T %d != %ld", l2, sizeof(*d)); + return (1); + } if ((int)(*d) != -1) { if (minor(*d) > 255 || minor(*d) < 0) printf("{ major = %d, minor = 0x%x }", @@ -826,6 +547,28 @@ T_dev_t(int l2, void *p) return (0); } +static int +S_quads(int len, void *p) +{ + size_t size = sizeof(int64_t); + if (len & (size-1)) { + return 1; + } + while (len > 0) { + int64_t i = *(int64_t *)p; + printf("%llu", i); + if (len > size) { + len -= size; + p = (uintptr_t)p + size; + printf(" "); + } else { + break; + } + } + return 0; +} +#endif // __APPLE__ + /* * These functions uses a presently undocumented interface to the kernel * to walk the tree and get the type so it can print the value. @@ -842,15 +585,36 @@ name2oid(char *name, int *oidp) int i; size_t j; +#ifdef __APPLE__ + // Support for CTL_USER + const char *user = names[CTL_USER].ctl_name; + j = strlen(user); + if (!strncmp(name, user, j)) { + oidp[0] = CTL_USER; + if (name[j] == '.') { + for (i = 1; i < user_names_count; ++i) { + if (!strcmp(&name[j+1], user_names[i].ctl_name)) { + oidp[1] = i; + return 2; + } + } + return -1; + } else if (name[j] == 0) { + return 1; + } + return -1; + } +#endif + oid[0] = 0; oid[1] = 3; - j = CTL_MAXNAME * sizeof (int); + j = CTL_MAXNAME * sizeof(int); i = sysctl(oid, 2, oidp, &j, name, strlen(name)); - if (i < 0) - return i; - j /= sizeof (int); - return (j); + if (i < 0) + return (i); + j /= sizeof(int); + return (int)j; } static int @@ -865,19 +629,92 @@ oidfmt(int *oid, int len, char *fmt, u_int *kind) qoid[1] = 4; memcpy(qoid + 2, oid, len * sizeof(int)); - j = sizeof buf; + j = sizeof(buf); i = sysctl(qoid, len + 2, buf, &j, 0, 0); +#ifdef __APPLE__ + if (i && errno == ENOENT) { + // Support for CTL_USER + if (oid[0] == CTL_USER) { + if (len == 1) { + *kind = CTLTYPE_NODE; + return 0; + } else if (len == 2 && oid[1] < user_names_count) { + *kind = user_names[oid[1]].ctl_type; + return 0; + } + } + return 1; + } +#endif if (i) - err(1, "sysctl fmt %d %d %d", i, j, errno); + err(1, "sysctl fmt %d %zu %d", i, j, errno); if (kind) +#ifdef __APPLE__ + memcpy(kind, buf, sizeof(*kind)); +#else *kind = *(u_int *)buf; +#endif if (fmt) strcpy(fmt, (char *)(buf + sizeof(u_int))); - return 0; + +#ifdef __APPLE__ + // Map Darwin sysctl types to FreeBSD types. + // - 0 with "I" -> CTLTYPE_INT + // - 0 with "S," -> CTLTYPE_STRUCT + // - CTLTYPE_INT with "IU" -> CTLTYPE_UINT + // - CTLTYPE_INT with "L" -> CTLTYPE_LONG + // - CTLTYPE_QUAD -> CTLTYPE_S64 + // - CTLTYPE_QUAD with "*U" -> CTLTYPE_U64 + if (kind) { + switch (*kind & CTLTYPE) { + case 0: + case CTLTYPE_INT: + if (buf[sizeof(u_int)] == 'S') { + *kind = (*kind & ~CTLTYPE) | CTLTYPE_STRUCT; + } else if (buf[sizeof(u_int)] == 'I') { + *kind = (*kind & ~CTLTYPE) | CTLTYPE_INT; + if (buf[sizeof(u_int)+1] == 'U') { + *kind = (*kind & ~CTLTYPE) | CTLTYPE_UINT; + } + } else if (buf[sizeof(u_int)] == 'L') { + *kind = (*kind & ~CTLTYPE) | CTLTYPE_LONG; + if (buf[sizeof(u_int)+1] == 'U') { + *kind = (*kind & ~CTLTYPE) | CTLTYPE_ULONG; + } + } + break; + case CTLTYPE_QUAD: + *kind = (*kind & ~CTLTYPE); + if (fmt && strchr(fmt, 'U')) { + *kind |= CTLTYPE_U64; + } else { + *kind |= CTLTYPE_S64; + } + break; + } + } +#endif + + return (0); } +static int ctl_sign[CTLTYPE+1] = { + [CTLTYPE_INT] = 1, + [CTLTYPE_LONG] = 1, + [CTLTYPE_S64] = 1, +}; + +static int ctl_size[CTLTYPE+1] = { + [CTLTYPE_INT] = sizeof(int), + [CTLTYPE_UINT] = sizeof(u_int), + [CTLTYPE_LONG] = sizeof(long), + [CTLTYPE_ULONG] = sizeof(u_long), + [CTLTYPE_S64] = sizeof(int64_t), + [CTLTYPE_U64] = sizeof(int64_t), +}; + /* * This formats and outputs the value of one variable * @@ -885,219 +722,284 @@ oidfmt(int *oid, int len, char *fmt, u_int *kind) * Returns one if didn't know what to do with this. * Return minus one if we had errors. */ - static int +#ifdef __APPLE__ show_var(int *oid, int nlen, int show_masked) +#else +show_var(int *oid, int nlen) +#endif { - u_char buf[BUFSIZ], *val, *mval, *p; - char name[BUFSIZ], /* descr[BUFSIZ], */ *fmt; + u_char buf[BUFSIZ], *val, *oval, *p; + char name[BUFSIZ], *fmt; + const char *sep, *sep1; int qoid[CTL_MAXNAME+2]; - int i; - int retval; + uintmax_t umv; + intmax_t mv; + int i, hexlen, sign, ctltype; + size_t intlen; size_t j, len; u_int kind; - int (*func)(int, void *) = 0; + int (*func)(int, void *); + + /* Silence GCC. */ + umv = mv = intlen = 0; + bzero(buf, BUFSIZ); + bzero(name, BUFSIZ); qoid[0] = 0; memcpy(qoid + 2, oid, nlen * sizeof(int)); +#ifdef __APPLE__ + // Support for CTL_USER + if (nlen >= 1 && oid[0] == CTL_USER) { + const char *user_name = ""; + sep = ""; + i = oid[1]; + if (nlen == 2 && i > 0 && i < user_names_count) { + user_name = user_names[i].ctl_name; + sep = "."; + } + j = snprintf(name, sizeof(name), "%s%s%s", + names[CTL_USER].ctl_name, sep, user_name); + i = 0; + } else { +#endif qoid[1] = 1; - j = sizeof name; + j = sizeof(name); i = sysctl(qoid, nlen + 2, name, &j, 0, 0); if (i || !j) - err(1, "sysctl name %d %d %d", i, j, errno); + err(1, "sysctl name %d %zu %d", i, j, errno); +#ifdef __APPLE__ + } +#endif + + if (Nflag) { + printf("%s", name); + return (0); + } + if (eflag) + sep = "="; + else + sep = ": "; + + if (dflag) { /* just print description */ + qoid[1] = 5; + j = sizeof(buf); + i = sysctl(qoid, nlen + 2, buf, &j, 0, 0); + if (!nflag) + printf("%s%s", name, sep); + printf("%s", buf); + return (0); + } /* find an estimate of how much we need for this var */ j = 0; i = sysctl(oid, nlen, 0, &j, 0, 0); j += j; /* we want to be sure :-) */ - val = mval = malloc(j); + val = oval = malloc(j + 1); + if (val == NULL) { + warnx("malloc failed"); + return (1); + } len = j; i = sysctl(oid, nlen, val, &len, 0, 0); if (i || !len) { - retval = 1; - goto RETURN; + free(oval); + return (1); } if (bflag) { fwrite(val, 1, len, stdout); - retval = 0; - goto RETURN; + free(oval); + return (0); } + val[len] = '\0'; + fmt = (char *)buf; + oidfmt(oid, nlen, fmt, &kind); + p = val; + ctltype = (kind & CTLTYPE); + sign = ctl_sign[ctltype]; + intlen = ctl_size[ctltype]; - qoid[1] = 4; - j = sizeof buf; - i = sysctl(qoid, nlen + 2, buf, &j, 0, 0); - if (i || !j) - err(1, "sysctl fmt %d %d %d", i, j, errno); - - kind = *(u_int *)buf; +#ifdef __APPLE__ if (!show_masked && (kind & CTLFLAG_MASKED)) { - retval = 1; - goto RETURN; + free(oval); + return (1); } +#endif - fmt = (char *)(buf + sizeof(u_int)); - - /* XXX special-case hack for hw.physmem */ - if ((oid[0] == CTL_HW) && (oid[1] == HW_PHYSMEM)) - fmt = "IU"; - - p = val; - switch (*fmt) { - case '-': - /* deprecated, do not print */ - retval = 0; - goto RETURN; - - - case 'A': - if (!nflag) - printf("%s: ", name); - printf("%s", p); - retval = 0; - goto RETURN; - - case 'I': - if (!nflag) - printf("%s: ", name); - fmt++; - val = ""; - while (len >= sizeof(int)) { - if(*fmt == 'U') - printf("%s%u", val, *(unsigned int *)p); - else - printf("%s%d", val, *(int *)p); - val = " "; - len -= sizeof (int); - p += sizeof (int); - } - retval = 0; - goto RETURN; - - case 'L': - if (!nflag) - printf("%s: ", name); - fmt++; - val = ""; - while (len >= sizeof(long)) { - if(*fmt == 'U') - printf("%s%lu", val, *(unsigned long *)p); - else - printf("%s%ld", val, *(long *)p); - val = " "; - len -= sizeof (long); - p += sizeof (long); - } - retval = 0; - goto RETURN; - - case 'P': + switch (ctltype) { + case CTLTYPE_STRING: if (!nflag) - printf("%s: ", name); - printf("%p", *(void **)p); - retval = 0; - goto RETURN; + printf("%s%s", name, sep); + printf("%.*s", (int)len, p); + free(oval); + return (0); - case 'Q': + case CTLTYPE_INT: + case CTLTYPE_UINT: + case CTLTYPE_LONG: + case CTLTYPE_ULONG: + case CTLTYPE_S64: + case CTLTYPE_U64: if (!nflag) - printf("%s: ", name); - fmt++; - val = ""; - while (len >= sizeof(long long)) { - if(*fmt == 'U') - printf("%s%llu", val, *(unsigned long long *)p); - else - printf("%s%lld", val, *(long long *)p); - val = " "; - len -= sizeof (long long); - p += sizeof (long long); + printf("%s%s", name, sep); + hexlen = (int)(2 + (intlen * CHAR_BIT + 3) / 4); + sep1 = ""; + while (len >= intlen) { + switch (kind & CTLTYPE) { + case CTLTYPE_INT: + case CTLTYPE_UINT: + umv = *(u_int *)(void *)p; + mv = *(int *)(void *)p; + break; + case CTLTYPE_LONG: + case CTLTYPE_ULONG: + umv = *(u_long *)(void *)p; + mv = *(long *)(void *)p; + break; + case CTLTYPE_S64: + case CTLTYPE_U64: + umv = *(uint64_t *)(void *)p; + mv = *(int64_t *)(void *)p; + break; + } + fputs(sep1, stdout); + if (xflag) + printf("%#0*jx", hexlen, umv); + else if (!sign) + printf(hflag ? "%'ju" : "%ju", umv); + else if (fmt[1] == 'K') { + if (mv < 0) + printf("%jd", mv); + else + printf("%.1fC", (mv - 2732.0) / 10); + } else + printf(hflag ? "%'jd" : "%jd", mv); + sep1 = " "; + len -= intlen; + p += intlen; } - retval = 0; - goto RETURN; - + free(oval); + return (0); - case 'T': - case 'S': + case CTLTYPE_OPAQUE: i = 0; - if (!strcmp(fmt, "S,clockinfo")) func = S_clockinfo; - else if (!strcmp(fmt, "S,timeval")) func = S_timeval; - else if (!strcmp(fmt, "S,loadavg")) func = S_loadavg; - else if (!strcmp(fmt, "T,dev_t")) func = T_dev_t; + if (strcmp(fmt, "S,clockinfo") == 0) + func = S_clockinfo; + else if (strcmp(fmt, "S,timeval") == 0) + func = S_timeval; + else if (strcmp(fmt, "S,loadavg") == 0) + func = S_loadavg; +#ifdef __APPLE__ + else if (!strcmp(fmt, "S,xsw_usage")) + func = S_xswusage; + else if (!strcmp(fmt, "T,dev_t")) + func = T_dev_t; + else if (!strcmp(fmt, "Q")) + func = S_quads; +#else // !__APPLE__ + else if (strcmp(fmt, "S,vmtotal") == 0) + func = S_vmtotal; +#endif // !__APPLE__ + else + func = NULL; if (func) { if (!nflag) - printf("%s: ", name); - retval = (*func)(len, p); - goto RETURN; + printf("%s%s", name, sep); + i = (*func)((int)len, p); + free(oval); + return (i); } - /* FALL THROUGH */ + /* FALLTHROUGH */ default: - if (!Aflag) { - retval = 1; - goto RETURN; + if (!oflag && !xflag) { + free(oval); + return (1); } if (!nflag) - printf("%s: ", name); - printf("Format:%s Length:%ld Dump:0x", fmt, len); - while (len--) { + printf("%s%s", name, sep); + printf("Format:%s Length:%zu Dump:0x", fmt, len); + while (len-- && (xflag || p < val + 16)) printf("%02x", *p++); - if (Xflag || p < val+16) - continue; + if (!xflag && len > 16) printf("..."); - break; - } - retval = 0; - goto RETURN; + free(oval); + return (0); } + free(oval); + return (1); +} - retval = 1; - RETURN: - free(mval); - return (retval); +#ifdef __APPLE__ +// Support for CTL_USER +static void +sysctl_all_user(int *oid, int len) +{ + int i, j; + if (len > 1 || (len == 1 && oid[0] != CTL_USER)) { + return; + } + for (i = 0; i < user_names_count; ++i) { + int oid[2] = { CTL_USER, i }; + j = show_var(oid, 2, 0); + if (!j && !bflag) { + putchar('\n'); + } + } } +#endif static int -sysctl_all (int *oid, int len) +sysctl_all(int *oid, int len) { int name1[22], name2[22]; int i, j; size_t l1, l2; +#ifdef __APPLE__ + sysctl_all_user(oid, len); +#endif + name1[0] = 0; name1[1] = 2; l1 = 2; if (len) { - memcpy(name1+2, oid, len*sizeof (int)); + memcpy(name1+2, oid, len * sizeof(int)); l1 += len; } else { name1[2] = 1; l1++; } - while (1) { - l2 = sizeof name2; - j = sysctl(name1, l1, name2, &l2, 0, 0); + for (;;) { + l2 = sizeof(name2); + j = sysctl(name1, (u_int)l1, name2, &l2, 0, 0); if (j < 0) { if (errno == ENOENT) - return 0; + return (0); else - err(1, "sysctl(getnext) %d %d", j, l2); + err(1, "sysctl(getnext) %d %zu", j, l2); } - l2 /= sizeof (int); + l2 /= sizeof(int); - if (l2 < len) - return 0; + if (len < 0 || l2 < (unsigned int)len) + return (0); for (i = 0; i < len; i++) if (name2[i] != oid[i]) - return 0; + return (0); - i = show_var(name2, l2, 0); +#ifdef __APPLE__ + i = show_var(name2, (u_int)l2, 0); +#else + i = show_var(name2, (u_int)l2); +#endif if (!i && !bflag) putchar('\n'); - memcpy(name1+2, name2, l2*sizeof (int)); + memcpy(name1+2, name2, l2 * sizeof(int)); l1 = 2 + l2; } }