diff options
author | delphij <delphij@FreeBSD.org> | 2012-12-13 23:32:47 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2012-12-13 23:32:47 +0000 |
commit | 976943f3a93bdb52ea2fb077b56f27c14b99da8c (patch) | |
tree | 7538275738edecd1f058054c8be372f37d487d93 | |
parent | 52a49d45767202eda504865adcfda6c27523ef1e (diff) | |
download | FreeBSD-src-976943f3a93bdb52ea2fb077b56f27c14b99da8c.zip FreeBSD-src-976943f3a93bdb52ea2fb077b56f27c14b99da8c.tar.gz |
Teach sysctl(8) about parsing a file (while I'm there also give it
capability of parsing both = and : formats).
Submitted by: hrs (initial version, bugs are mine)
MFC after: 3 months
-rwxr-xr-x | etc/rc.d/sysctl | 50 | ||||
-rw-r--r-- | sbin/sysctl/sysctl.8 | 8 | ||||
-rw-r--r-- | sbin/sysctl/sysctl.c | 229 |
3 files changed, 188 insertions, 99 deletions
diff --git a/etc/rc.d/sysctl b/etc/rc.d/sysctl index 34fb3b5..cc3e801 100755 --- a/etc/rc.d/sysctl +++ b/etc/rc.d/sysctl @@ -8,51 +8,27 @@ . /etc/rc.subr name="sysctl" +command="/sbin/sysctl" stop_cmd=":" start_cmd="sysctl_start" reload_cmd="sysctl_start" lastload_cmd="sysctl_start last" extra_commands="reload lastload" -# -# Read in a file containing sysctl settings and set things accordingly. -# -parse_file() -{ - if [ -f $1 ]; then - while read var comments - do - case ${var} in - \#*|'') - ;; - *) - mib=${var%=*} - val=${var#*=} - - if current_value=`${SYSCTL} -n ${mib} 2>/dev/null`; then - case ${current_value} in - ${val}) - ;; - *) - if ! sysctl "${var}" >/dev/null 2>&1; then - warn "unable to set ${var}" - fi - ;; - esac - elif [ "$2" = "last" ]; then - warn "sysctl ${mib} does not exist." - fi - ;; - esac - done < $1 - fi -} - sysctl_start() { - - parse_file /etc/sysctl.conf $1 - parse_file /etc/sysctl.conf.local $1 + case $1 in + last) + command_args="-i -f" + ;; + *) + command_args="-f" + ;; + esac + + for _f in /etc/sysctl.conf /etc/sysctl.conf.local; do + [ -r ${_f} ] && ${command} ${command_args} ${_f} > /dev/null + done } load_rc_config $name diff --git a/sbin/sysctl/sysctl.8 b/sbin/sysctl/sysctl.8 index 514acd1..fe0a75a 100644 --- a/sbin/sysctl/sysctl.8 +++ b/sbin/sysctl/sysctl.8 @@ -28,7 +28,7 @@ .\" From: @(#)sysctl.8 8.1 (Berkeley) 6/6/93 .\" $FreeBSD$ .\" -.Dd January 17, 2011 +.Dd December 13, 2012 .Dt SYSCTL 8 .Os .Sh NAME @@ -37,6 +37,7 @@ .Sh SYNOPSIS .Nm .Op Fl bdehiNnoRTqx +.Op Fl f Ar filename .Ar name Ns Op = Ns Ar value .Ar ... .Nm @@ -80,6 +81,11 @@ This option is ignored if either or .Fl n is specified, or a variable is being set. +.It Fl f Ar filename +Specify a file which contains a pair of name and value in each line. +.Nm +reads and processes the specified file first and then processes the name +and value pairs in the command line argument. .It Fl h Format output for human, rather than machine, readability. .It Fl i diff --git a/sbin/sysctl/sysctl.c b/sbin/sysctl/sysctl.c index a9c2b7a..8fad089 100644 --- a/sbin/sysctl/sysctl.c +++ b/sbin/sysctl/sysctl.c @@ -56,13 +56,17 @@ static const char rcsid[] = #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sysexits.h> #include <unistd.h> +static const char *conffile; + static int aflag, bflag, dflag, eflag, hflag, iflag; -static int Nflag, nflag, oflag, qflag, Tflag, Wflag, xflag, warncount; +static int Nflag, nflag, oflag, qflag, Tflag, Wflag, xflag; static int oidfmt(int *, int, char *, u_int *); -static void parse(const char *); +static int parsefile(const char *); +static int parse(const char *, int); static int show_var(int *, int); static int sysctl_all(int *oid, int len); static int name2oid(char *, int *); @@ -74,7 +78,7 @@ usage(void) { (void)fprintf(stderr, "%s\n%s\n", - "usage: sysctl [-bdehiNnoqTWx] name[=value] ...", + "usage: sysctl [-bdehiNnoqTWx] [-f filename] name[=value] ...", " sysctl [-bdehNnoqTWx] -a"); exit(1); } @@ -83,12 +87,13 @@ int main(int argc, char **argv) { int ch; + int warncount = 0; setlocale(LC_NUMERIC, ""); setbuf(stdout,0); setbuf(stderr,0); - while ((ch = getopt(argc, argv, "AabdehiNnoqTwWxX")) != -1) { + while ((ch = getopt(argc, argv, "Aabdef:hiNnoqTwWxX")) != -1) { switch (ch) { case 'A': /* compatibility */ @@ -106,6 +111,9 @@ main(int argc, char **argv) case 'e': eflag = 1; break; + case 'f': + conffile = optarg; + break; case 'h': hflag = 1; break; @@ -152,13 +160,17 @@ main(int argc, char **argv) usage(); if (aflag && argc == 0) exit(sysctl_all(0, 0)); - if (argc == 0) + if (argc == 0 && conffile == NULL) usage(); warncount = 0; + if (conffile != NULL) + warncount += parsefile(conffile); + while (argc-- > 0) - parse(*argv++); - exit(warncount); + warncount += parse(*argv++, 0); + + return (warncount); } /* @@ -166,8 +178,8 @@ main(int argc, char **argv) * Lookup and print out the MIB entry if it exists. * Set a new value if requested. */ -static void -parse(const char *string) +static int +parse(const char *string, int lineno) { int len, i, j; void *newval = 0; @@ -179,13 +191,20 @@ parse(const char *string) int64_t i64val; uint64_t u64val; int mib[CTL_MAXNAME]; - char *cp, *bufp, buf[BUFSIZ], *endptr, fmt[BUFSIZ]; + char *cp, *bufp, buf[BUFSIZ], *endptr, fmt[BUFSIZ], line[BUFSIZ]; u_int kind; + if (lineno) + snprintf(line, sizeof(line), " at line %d", lineno); + else + line[0] = '\0'; + cp = buf; - if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) - errx(1, "oid too long: '%s'", string); - bufp = strsep(&cp, "="); + if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) { + warn("oid too long: '%s'%s", string, line); + return (1); + } + bufp = strsep(&cp, "=:"); if (cp != NULL) { /* Tflag just lists tunables, do not allow assignment */ if (Tflag || Wflag) { @@ -194,6 +213,14 @@ parse(const char *string) } while (isspace(*cp)) cp++; + /* Strip a pair of " or ' if any. */ + switch (*cp) { + case '\"': + case '\'': + if (cp[strlen(cp) - 1] == *cp) + cp[strlen(cp) - 1] = '\0'; + cp++; + } newval = cp; newsize = strlen(cp); } @@ -201,15 +228,22 @@ parse(const char *string) if (len < 0) { if (iflag) - return; + return (0); if (qflag) - exit(1); - else - errx(1, "unknown oid '%s'", bufp); + return (1); + else { + warn("unknown oid '%s'%s", bufp, line); + return (1); + } } - if (oidfmt(mib, len, fmt, &kind)) - err(1, "couldn't find format of oid '%s'", bufp); + if (oidfmt(mib, len, fmt, &kind)) { + warn("couldn't find format of oid '%s'%s", bufp, line); + if (iflag) + return (1); + else + exit(1); + } if (newval == NULL || dflag) { if ((kind & CTLTYPE) == CTLTYPE_NODE) { @@ -225,16 +259,18 @@ parse(const char *string) putchar('\n'); } } else { - if ((kind & CTLTYPE) == CTLTYPE_NODE) - errx(1, "oid '%s' isn't a leaf node", bufp); + if ((kind & CTLTYPE) == CTLTYPE_NODE) { + warn("oid '%s' isn't a leaf node%s", bufp, line); + return (1); + } 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); - } + warnx("oid '%s' is a read only tunable%p", bufp, line); + warnx("Tunable values are set in /boot/loader.conf"); + } else + warnx("oid '%s' is read only%s", bufp, line); + return (1); } if ((kind & CTLTYPE) == CTLTYPE_INT || @@ -243,47 +279,59 @@ parse(const char *string) (kind & CTLTYPE) == CTLTYPE_ULONG || (kind & CTLTYPE) == CTLTYPE_S64 || (kind & CTLTYPE) == CTLTYPE_U64) { - if (strlen(newval) == 0) - errx(1, "empty numeric value"); + if (strlen(newval) == 0) { + warnx("empty numeric value"); + return (1); + } } switch (kind & CTLTYPE) { case CTLTYPE_INT: if (strcmp(fmt, "IK") == 0) { - if (!set_IK(newval, &intval)) - errx(1, "invalid value '%s'", - (char *)newval); + if (!set_IK(newval, &intval)) { + warnx("invalid value '%s'%s", + (char *)newval, line); + return (1); + } } else { intval = (int)strtol(newval, &endptr, 0); - if (endptr == newval || *endptr != '\0') - errx(1, "invalid integer '%s'", - (char *)newval); + if (endptr == newval || *endptr != '\0') { + warnx("invalid integer '%s'%s", + (char *)newval, line); + return (1); + } } 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); + if (endptr == newval || *endptr != '\0') { + warnx("invalid unsigned integer '%s'%s", + (char *)newval, line); + return (1); + } 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); + if (endptr == newval || *endptr != '\0') { + warnx("invalid long integer '%s'%s", + (char *)newval, line); + return (1); + } 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); + if (endptr == newval || *endptr != '\0') { + warnx("invalid unsigned long integer" + " '%s'%s", (char *)newval, line); + return (1); + } newval = &ulongval; newsize = sizeof(ulongval); break; @@ -291,26 +339,31 @@ parse(const char *string) break; case CTLTYPE_S64: i64val = strtoimax(newval, &endptr, 0); - if (endptr == newval || *endptr != '\0') - errx(1, "invalid int64_t '%s'", - (char *)newval); + if (endptr == newval || *endptr != '\0') { + warnx("invalid int64_t '%s'%s", + (char *)newval, line); + return (1); + } newval = &i64val; newsize = sizeof(i64val); break; case CTLTYPE_U64: u64val = strtoumax(newval, &endptr, 0); - if (endptr == newval || *endptr != '\0') - errx(1, "invalid uint64_t '%s'", - (char *)newval); + if (endptr == newval || *endptr != '\0') { + warnx("invalid uint64_t '%s'%s", + (char *)newval, line); + return (1); + } newval = &u64val; newsize = sizeof(u64val); break; case CTLTYPE_OPAQUE: /* FALLTHROUGH */ default: - errx(1, "oid '%s' is type %d," - " cannot set that", bufp, - kind & CTLTYPE); + warnx("oid '%s' is type %d," + " cannot set that%s", bufp, + kind & CTLTYPE, line); + return (1); } i = show_var(mib, len); @@ -319,18 +372,20 @@ parse(const char *string) putchar('\n'); switch (errno) { case EOPNOTSUPP: - errx(1, "%s: value is not available", - string); + warnx("%s: value is not available%s", + string, line); + return (1); case ENOTDIR: - errx(1, "%s: specification is incomplete", - string); + warnx("%s: specification is incomplete%s", + string, line); + return (1); case ENOMEM: - errx(1, "%s: type is unknown to this program", - string); + warnx("%s: type is unknown to this program%s", + string, line); + return (1); default: - warn("%s", string); - warncount++; - return; + warn("%s%s", string, line); + return (1); } } if (!bflag) @@ -342,6 +397,58 @@ parse(const char *string) putchar('\n'); nflag = i; } + + return (0); +} + +static int +parsefile(const char *filename) +{ + FILE *file; + char line[BUFSIZ], *p, *pq, *pdq; + int warncount = 0, lineno = 0; + + file = fopen(filename, "r"); + if (file == NULL) + err(EX_NOINPUT, "%s", filename); + while (fgets(line, sizeof(line), file) != NULL) { + lineno++; + p = line; + pq = strchr(line, '\''); + pdq = strchr(line, '\"'); + /* Replace the first # with \0. */ + while((p = strchr(p, '#')) != NULL) { + if (pq != NULL && p > pq) { + if ((p = strchr(pq+1, '\'')) != NULL) + *(++p) = '\0'; + break; + } else if (pdq != NULL && p > pdq) { + if ((p = strchr(pdq+1, '\"')) != NULL) + *(++p) = '\0'; + break; + } else if (p == line || *(p-1) != '\\') { + *p = '\0'; + break; + } + p++; + } + /* Trim spaces */ + p = line + strlen(line) - 1; + while (p >= line && isspace((int)*p)) { + *p = '\0'; + p--; + } + p = line; + while (isspace((int)*p)) + p++; + if (*p == '\0') + continue; + else + warncount += parse(p, lineno); + } + fclose(file); + + return (warncount); } /* These functions will dump out various interesting structures. */ |