Changeset View
Changeset View
Standalone View
Standalone View
head/sbin/sysctl/sysctl.c
Show All 23 Lines | |||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
#ifndef lint | #include <sys/cdefs.h> | ||||
static const char copyright[] = | __FBSDID("$FreeBSD$"); | ||||
"@(#) Copyright (c) 1993\n\ | |||||
The Regents of the University of California. All rights reserved.\n"; | |||||
#endif /* not lint */ | |||||
#ifndef lint | |||||
#if 0 | |||||
static char sccsid[] = "@(#)from: sysctl.c 8.1 (Berkeley) 6/6/93"; | |||||
#endif | |||||
static const char rcsid[] = | |||||
"$FreeBSD$"; | |||||
#endif /* not lint */ | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/time.h> | #include <sys/time.h> | ||||
#include <sys/resource.h> | #include <sys/resource.h> | ||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/vmmeter.h> | #include <sys/vmmeter.h> | ||||
#include <dev/evdev/input.h> | #include <dev/evdev/input.h> | ||||
▲ Show 20 Lines • Show All 162 Lines • ▼ Show 20 Lines | while ((ch = getopt(argc, argv, "AabB:def:hiNnoqtTwWxX")) != -1) { | ||||
} | } | ||||
} | } | ||||
argc -= optind; | argc -= optind; | ||||
argv += optind; | argv += optind; | ||||
if (Nflag && nflag) | if (Nflag && nflag) | ||||
usage(); | usage(); | ||||
if (aflag && argc == 0) | if (aflag && argc == 0) | ||||
exit(sysctl_all(0, 0)); | exit(sysctl_all(NULL, 0)); | ||||
if (argc == 0 && conffile == NULL) | if (argc == 0 && conffile == NULL) | ||||
usage(); | usage(); | ||||
warncount = 0; | warncount = 0; | ||||
if (conffile != NULL) | if (conffile != NULL) | ||||
warncount += parsefile(conffile); | warncount += parsefile(conffile); | ||||
while (argc-- > 0) | while (argc-- > 0) | ||||
▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | parse(const char *string, int lineno) | ||||
char *cp, *bufp, buf[BUFSIZ], fmt[BUFSIZ], line[BUFSIZ]; | char *cp, *bufp, buf[BUFSIZ], fmt[BUFSIZ], line[BUFSIZ]; | ||||
u_int kind; | u_int kind; | ||||
if (lineno) | if (lineno) | ||||
snprintf(line, sizeof(line), " at line %d", lineno); | snprintf(line, sizeof(line), " at line %d", lineno); | ||||
else | else | ||||
line[0] = '\0'; | line[0] = '\0'; | ||||
/* | |||||
* Split the string into name and value. | |||||
* | |||||
* Either = or : may be used as the delimiter. | |||||
* Whitespace surrounding the delimiter is trimmed. | |||||
* Quotes around the value are stripped. | |||||
*/ | |||||
cp = buf; | cp = buf; | ||||
if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) { | if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) { | ||||
warnx("oid too long: '%s'%s", string, line); | warnx("oid too long: '%s'%s", string, line); | ||||
return (1); | return (1); | ||||
} | } | ||||
bufp = strsep(&cp, "=:"); | bufp = strsep(&cp, "=:"); | ||||
if (cp != NULL) { | if (cp != NULL) { | ||||
/* Tflag just lists tunables, do not allow assignment */ | /* Tflag just lists tunables, do not allow assignment */ | ||||
if (Tflag || Wflag) { | if (Tflag || Wflag) { | ||||
warnx("Can't set variables when using -T or -W"); | warnx("Can't set variables when using -T or -W"); | ||||
usage(); | usage(); | ||||
} | } | ||||
/* Trim whitespace before the value. */ | |||||
while (isspace(*cp)) | while (isspace(*cp)) | ||||
cp++; | cp++; | ||||
/* Strip a pair of " or ' if any. */ | /* Strip a pair of " or ' if any. */ | ||||
switch (*cp) { | switch (*cp) { | ||||
case '\"': | case '\"': | ||||
case '\'': | case '\'': | ||||
if (cp[strlen(cp) - 1] == *cp) | if (cp[strlen(cp) - 1] == *cp) | ||||
cp[strlen(cp) - 1] = '\0'; | cp[strlen(cp) - 1] = '\0'; | ||||
cp++; | cp++; | ||||
} | } | ||||
newvalstr = cp; | newvalstr = cp; | ||||
newsize = strlen(cp); | newsize = strlen(cp); | ||||
} | } | ||||
/* Trim spaces */ | /* Trim whitespace after the name. */ | ||||
cp = bufp + strlen(bufp) - 1; | cp = bufp + strlen(bufp) - 1; | ||||
while (cp >= bufp && isspace((int)*cp)) { | while (cp >= bufp && isspace((int)*cp)) { | ||||
*cp = '\0'; | *cp = '\0'; | ||||
cp--; | cp--; | ||||
} | } | ||||
len = name2oid(bufp, mib); | |||||
/* | |||||
* Check the name is a useable oid. | |||||
*/ | |||||
len = name2oid(bufp, mib); | |||||
if (len < 0) { | if (len < 0) { | ||||
if (iflag) | if (iflag) | ||||
return (0); | return (0); | ||||
if (qflag) | if (qflag) | ||||
return (1); | return (1); | ||||
else { | else { | ||||
if (errno == ENOENT) { | if (errno == ENOENT) { | ||||
warnx("unknown oid '%s'%s", bufp, line); | warnx("unknown oid '%s'%s", bufp, line); | ||||
} else { | } else { | ||||
warn("unknown oid '%s'%s", bufp, line); | warn("unknown oid '%s'%s", bufp, line); | ||||
} | } | ||||
return (1); | return (1); | ||||
} | } | ||||
} | } | ||||
if (oidfmt(mib, len, fmt, &kind)) { | if (oidfmt(mib, len, fmt, &kind)) { | ||||
warn("couldn't find format of oid '%s'%s", bufp, line); | warn("couldn't find format of oid '%s'%s", bufp, line); | ||||
if (iflag) | if (iflag) | ||||
return (1); | return (1); | ||||
else | else | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* | |||||
* We have a useable oid to work with. If there is no value given, | |||||
* show the node and its children. Otherwise, set the new value. | |||||
*/ | |||||
if (newvalstr == NULL || dflag) { | if (newvalstr == NULL || dflag) { | ||||
if ((kind & CTLTYPE) == CTLTYPE_NODE) { | if ((kind & CTLTYPE) == CTLTYPE_NODE) { | ||||
if (dflag) { | if (dflag) { | ||||
i = show_var(mib, len, false); | i = show_var(mib, len, false); | ||||
if (!i && !bflag) | if (!i && !bflag) | ||||
putchar('\n'); | putchar('\n'); | ||||
} | } | ||||
sysctl_all(mib, len); | sysctl_all(mib, len); | ||||
} else { | } else { | ||||
i = show_var(mib, len, false); | i = show_var(mib, len, false); | ||||
if (!i && !bflag) | if (!i && !bflag) | ||||
putchar('\n'); | putchar('\n'); | ||||
} | } | ||||
} else { | return (0); | ||||
} | |||||
/* | |||||
* We have a new value to set. Check its validity and parse if numeric. | |||||
*/ | |||||
if ((kind & CTLTYPE) == CTLTYPE_NODE) { | if ((kind & CTLTYPE) == CTLTYPE_NODE) { | ||||
warnx("oid '%s' isn't a leaf node%s", bufp, line); | warnx("oid '%s' isn't a leaf node%s", bufp, line); | ||||
return (1); | return (1); | ||||
} | } | ||||
if (!(kind & CTLFLAG_WR)) { | if (!(kind & CTLFLAG_WR)) { | ||||
if (kind & CTLFLAG_TUN) { | if (kind & CTLFLAG_TUN) { | ||||
warnx("oid '%s' is a read only tunable%s", bufp, line); | warnx("oid '%s' is a read only tunable%s", bufp, line); | ||||
warnx("Tunable values are set in /boot/loader.conf"); | warnx("Tunable values are set in /boot/loader.conf"); | ||||
} else | } else | ||||
warnx("oid '%s' is read only%s", bufp, line); | warnx("oid '%s' is read only%s", bufp, line); | ||||
return (1); | return (1); | ||||
} | } | ||||
switch (kind & CTLTYPE) { | switch (kind & CTLTYPE) { | ||||
case CTLTYPE_INT: | case CTLTYPE_INT: | ||||
case CTLTYPE_UINT: | case CTLTYPE_UINT: | ||||
case CTLTYPE_LONG: | case CTLTYPE_LONG: | ||||
case CTLTYPE_ULONG: | case CTLTYPE_ULONG: | ||||
case CTLTYPE_S8: | case CTLTYPE_S8: | ||||
case CTLTYPE_S16: | case CTLTYPE_S16: | ||||
case CTLTYPE_S32: | case CTLTYPE_S32: | ||||
case CTLTYPE_S64: | case CTLTYPE_S64: | ||||
case CTLTYPE_U8: | case CTLTYPE_U8: | ||||
case CTLTYPE_U16: | case CTLTYPE_U16: | ||||
case CTLTYPE_U32: | case CTLTYPE_U32: | ||||
case CTLTYPE_U64: | case CTLTYPE_U64: | ||||
if (strlen(newvalstr) == 0) { | if (strlen(newvalstr) == 0) { | ||||
warnx("empty numeric value"); | warnx("empty numeric value"); | ||||
return (1); | return (1); | ||||
} | } | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case CTLTYPE_STRING: | case CTLTYPE_STRING: | ||||
break; | break; | ||||
default: | default: | ||||
warnx("oid '%s' is type %d," | warnx("oid '%s' is type %d, cannot set that%s", | ||||
" cannot set that%s", bufp, | bufp, kind & CTLTYPE, line); | ||||
kind & CTLTYPE, line); | |||||
return (1); | return (1); | ||||
} | } | ||||
newbuf = NULL; | newbuf = NULL; | ||||
switch (kind & CTLTYPE) { | switch (kind & CTLTYPE) { | ||||
case CTLTYPE_STRING: | case CTLTYPE_STRING: | ||||
newval = newvalstr; | newval = newvalstr; | ||||
break; | break; | ||||
default: | default: | ||||
newsize = 0; | newsize = 0; | ||||
while ((cp = strsep(&newvalstr, " ,")) != NULL) { | while ((cp = strsep(&newvalstr, " ,")) != NULL) { | ||||
if (*cp == '\0') | if (*cp == '\0') | ||||
continue; | continue; | ||||
if (!parse_numeric(cp, fmt, kind, &newbuf, | if (!parse_numeric(cp, fmt, kind, &newbuf, &newsize)) { | ||||
&newsize)) { | |||||
warnx("invalid %s '%s'%s", | warnx("invalid %s '%s'%s", | ||||
ctl_typename[kind & CTLTYPE], | ctl_typename[kind & CTLTYPE], cp, line); | ||||
cp, line); | |||||
free(newbuf); | free(newbuf); | ||||
return (1); | return (1); | ||||
} | } | ||||
} | } | ||||
newval = newbuf; | newval = newbuf; | ||||
break; | break; | ||||
} | } | ||||
/* | |||||
* Show the current value, then set and show the new value. | |||||
*/ | |||||
i = show_var(mib, len, false); | i = show_var(mib, len, false); | ||||
if (sysctl(mib, len, 0, 0, newval, newsize) == -1) { | if (sysctl(mib, len, 0, 0, newval, newsize) == -1) { | ||||
free(newbuf); | free(newbuf); | ||||
if (!i && !bflag) | if (!i && !bflag) | ||||
putchar('\n'); | putchar('\n'); | ||||
switch (errno) { | switch (errno) { | ||||
case EOPNOTSUPP: | case EOPNOTSUPP: | ||||
warnx("%s: value is not available%s", | warnx("%s: value is not available%s", | ||||
string, line); | string, line); | ||||
return (1); | return (1); | ||||
case ENOTDIR: | case ENOTDIR: | ||||
warnx("%s: specification is incomplete%s", | warnx("%s: specification is incomplete%s", | ||||
string, line); | string, line); | ||||
return (1); | return (1); | ||||
case ENOMEM: | case ENOMEM: | ||||
warnx("%s: type is unknown to this program%s", | warnx("%s: type is unknown to this program%s", | ||||
string, line); | string, line); | ||||
return (1); | return (1); | ||||
default: | default: | ||||
warn("%s%s", string, line); | warn("%s%s", string, line); | ||||
return (1); | return (1); | ||||
} | } | ||||
} | } | ||||
free(newbuf); | free(newbuf); | ||||
if (!bflag) | if (!bflag) | ||||
printf(" -> "); | printf(" -> "); | ||||
i = nflag; | i = nflag; | ||||
nflag = 1; | nflag = 1; | ||||
j = show_var(mib, len, false); | j = show_var(mib, len, false); | ||||
if (!j && !bflag) | if (!j && !bflag) | ||||
putchar('\n'); | putchar('\n'); | ||||
nflag = i; | nflag = i; | ||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
parsefile(const char *filename) | parsefile(const char *filename) | ||||
{ | { | ||||
FILE *file; | FILE *file; | ||||
▲ Show 20 Lines • Show All 345 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
name2oid(const char *name, int *oidp) | name2oid(const char *name, int *oidp) | ||||
{ | { | ||||
int oid[2]; | int oid[2]; | ||||
int i; | int i; | ||||
size_t j; | size_t j; | ||||
oid[0] = 0; | oid[0] = CTL_SYSCTL; | ||||
oid[1] = 3; | oid[1] = CTL_SYSCTL_NAME2OID; | ||||
j = CTL_MAXNAME * sizeof(int); | j = CTL_MAXNAME * sizeof(int); | ||||
i = sysctl(oid, 2, oidp, &j, name, strlen(name)); | i = sysctl(oid, 2, oidp, &j, name, strlen(name)); | ||||
if (i < 0) | if (i < 0) | ||||
return (i); | return (i); | ||||
j /= sizeof(int); | j /= sizeof(int); | ||||
return (j); | return (j); | ||||
} | } | ||||
static int | static int | ||||
oidfmt(int *oid, int len, char *fmt, u_int *kind) | oidfmt(int *oid, int len, char *fmt, u_int *kind) | ||||
{ | { | ||||
int qoid[CTL_MAXNAME+2]; | int qoid[CTL_MAXNAME+2]; | ||||
u_char buf[BUFSIZ]; | u_char buf[BUFSIZ]; | ||||
int i; | int i; | ||||
size_t j; | size_t j; | ||||
qoid[0] = 0; | qoid[0] = CTL_SYSCTL; | ||||
qoid[1] = 4; | qoid[1] = CTL_SYSCTL_OIDFMT; | ||||
memcpy(qoid + 2, oid, len * sizeof(int)); | memcpy(qoid + 2, oid, len * sizeof(int)); | ||||
j = sizeof(buf); | j = sizeof(buf); | ||||
i = sysctl(qoid, len + 2, buf, &j, 0, 0); | i = sysctl(qoid, len + 2, buf, &j, 0, 0); | ||||
if (i) | if (i) | ||||
err(1, "sysctl fmt %d %zu %d", i, j, errno); | err(1, "sysctl fmt %d %zu %d", i, j, errno); | ||||
if (kind) | if (kind) | ||||
Show All 29 Lines | show_var(int *oid, int nlen, bool honor_skip) | ||||
int prec; | int prec; | ||||
/* Silence GCC. */ | /* Silence GCC. */ | ||||
umv = mv = intlen = 0; | umv = mv = intlen = 0; | ||||
bzero(buf, BUFSIZ); | bzero(buf, BUFSIZ); | ||||
bzero(fmt, BUFSIZ); | bzero(fmt, BUFSIZ); | ||||
bzero(name, BUFSIZ); | bzero(name, BUFSIZ); | ||||
qoid[0] = 0; | qoid[0] = CTL_SYSCTL; | ||||
memcpy(qoid + 2, oid, nlen * sizeof(int)); | memcpy(qoid + 2, oid, nlen * sizeof(int)); | ||||
qoid[1] = 1; | qoid[1] = CTL_SYSCTL_NAME; | ||||
j = sizeof(name); | j = sizeof(name); | ||||
i = sysctl(qoid, nlen + 2, name, &j, 0, 0); | i = sysctl(qoid, nlen + 2, name, &j, 0, 0); | ||||
if (i || !j) | if (i || !j) | ||||
err(1, "sysctl name %d %zu %d", i, j, errno); | err(1, "sysctl name %d %zu %d", i, j, errno); | ||||
oidfmt(oid, nlen, fmt, &kind); | oidfmt(oid, nlen, fmt, &kind); | ||||
/* if Wflag then only list sysctls that are writeable and not stats. */ | /* if Wflag then only list sysctls that are writeable and not stats. */ | ||||
if (Wflag && ((kind & CTLFLAG_WR) == 0 || (kind & CTLFLAG_STATS) != 0)) | if (Wflag && ((kind & CTLFLAG_WR) == 0 || (kind & CTLFLAG_STATS) != 0)) | ||||
Show All 22 Lines | if (!nflag) | ||||
else | else | ||||
prntype = "unknown"; | prntype = "unknown"; | ||||
if (tflag && dflag) | if (tflag && dflag) | ||||
printf("%s%s", prntype, sep); | printf("%s%s", prntype, sep); | ||||
else if (tflag) { | else if (tflag) { | ||||
printf("%s", prntype); | printf("%s", prntype); | ||||
return (0); | return (0); | ||||
} | } | ||||
qoid[1] = 5; | qoid[1] = CTL_SYSCTL_OIDDESCR; | ||||
j = sizeof(buf); | j = sizeof(buf); | ||||
i = sysctl(qoid, nlen + 2, buf, &j, 0, 0); | i = sysctl(qoid, nlen + 2, buf, &j, 0, 0); | ||||
printf("%s", buf); | printf("%s", buf); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* bail before fetching the value if we're honoring skip */ | /* bail before fetching the value if we're honoring skip */ | ||||
if (honor_skip && (kind & CTLFLAG_SKIP) != 0) | if (honor_skip && (kind & CTLFLAG_SKIP) != 0) | ||||
▲ Show 20 Lines • Show All 204 Lines • ▼ Show 20 Lines | if (j < 0) { | ||||
err(1, "sysctl(getnext) %d %zu", j, l2); | err(1, "sysctl(getnext) %d %zu", j, l2); | ||||
} | } | ||||
l2 /= sizeof(int); | l2 /= sizeof(int); | ||||
if (len < 0 || l2 < (unsigned int)len) | if (len < 0 || l2 < (unsigned int)len) | ||||
return (0); | return (0); | ||||
for (i = 0; i < len; i++) | if (memcmp(name2, oid, len * sizeof(int)) != 0) | ||||
if (name2[i] != oid[i]) | |||||
return (0); | return (0); | ||||
i = show_var(name2, l2, honor_skip); | i = show_var(name2, l2, honor_skip); | ||||
if (!i && !bflag) | if (!i && !bflag) | ||||
putchar('\n'); | putchar('\n'); | ||||
memcpy(name1 + 2, name2, l2 * sizeof(int)); | memcpy(name1 + 2, name2, l2 * sizeof(int)); | ||||
l1 = 2 + l2; | l1 = 2 + l2; | ||||
honor_skip = true; | honor_skip = true; | ||||
} | } | ||||
} | } |