summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2012-12-13 23:32:47 +0000
committerdelphij <delphij@FreeBSD.org>2012-12-13 23:32:47 +0000
commit976943f3a93bdb52ea2fb077b56f27c14b99da8c (patch)
tree7538275738edecd1f058054c8be372f37d487d93
parent52a49d45767202eda504865adcfda6c27523ef1e (diff)
downloadFreeBSD-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-xetc/rc.d/sysctl50
-rw-r--r--sbin/sysctl/sysctl.88
-rw-r--r--sbin/sysctl/sysctl.c229
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. */
OpenPOWER on IntegriCloud