Author: delphij
Date: Thu Dec 13 23:32:47 2012
New Revision: 244198
URL: http://svnweb.freebsd.org/changeset/base/244198

Log:
  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

Modified:
  head/etc/rc.d/sysctl
  head/sbin/sysctl/sysctl.8
  head/sbin/sysctl/sysctl.c

Modified: head/etc/rc.d/sysctl
==============================================================================
--- head/etc/rc.d/sysctl        Thu Dec 13 23:19:13 2012        (r244197)
+++ head/etc/rc.d/sysctl        Thu Dec 13 23:32:47 2012        (r244198)
@@ -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

Modified: head/sbin/sysctl/sysctl.8
==============================================================================
--- head/sbin/sysctl/sysctl.8   Thu Dec 13 23:19:13 2012        (r244197)
+++ head/sbin/sysctl/sysctl.8   Thu Dec 13 23:32:47 2012        (r244198)
@@ -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

Modified: head/sbin/sysctl/sysctl.c
==============================================================================
--- head/sbin/sysctl/sysctl.c   Thu Dec 13 23:19:13 2012        (r244197)
+++ head/sbin/sysctl/sysctl.c   Thu Dec 13 23:32:47 2012        (r244198)
@@ -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. */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to