Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 1 Dec 2012 16:30:15 -0800
From:      Garrett Cooper <yanegomi@gmail.com>
To:        Konstantin Belousov <kostikbel@gmail.com>
Cc:        rc@freebsd.org, current@freebsd.org
Subject:   Re: RFC: sysctl -f filename
Message-ID:  <CAGH67wQ1=Nx7DjWB1zdvDUMGSx09t_L-OX-cJNh-DiFihjA43A@mail.gmail.com>
In-Reply-To: <20121201233756.GS3013@kib.kiev.ua>
References:  <20121202.015048.1122480556487090170.hrs@allbsd.org> <CAGH67wTC50X1M2uUo0g=Nm6PmpOXPzYnp4tbXDCQyA9eOKB%2B7Q@mail.gmail.com> <CAGH67wShpcmOKhc09%2BMP5c-AOm7EAPG%2BGqv=J0PRq0sGuTzKRQ@mail.gmail.com> <20121202.082150.896017277887885294.hrs@allbsd.org> <20121201233756.GS3013@kib.kiev.ua>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, Dec 1, 2012 at 3:37 PM, Konstantin Belousov <kostikbel@gmail.com> wrote:
> On Sun, Dec 02, 2012 at 08:21:50AM +0900, Hiroki Sato wrote:
>> Garrett Cooper <yanegomi@gmail.com> wrote
>>   in <CAGH67wShpcmOKhc09+MP5c-AOm7EAPG+Gqv=J0PRq0sGuTzKRQ@mail.gmail.com>:
>>
>> ya> On Sat, Dec 1, 2012 at 2:10 PM, Garrett Cooper <yanegomi@gmail.com> wrote:
>> ya> >     Why change the tool when we can change the rc script to do the
>> ya> > right thing? I have a patch I'm working on to resolve this (you hit an
>> ya> > itch I've been meaning to scratch for a little while).
>> ya>
>> ya>     This should work. I also refactored the script to get it down to
>> ya> 80 columns. I've attached the debug output and the diff for the debug
>> ya> version of the script.
>>
>>  You will find out the following test case does not work (this is one
>>  of the test strings I used):
>>
>>  kern.domainname="c$EDITOR.\"\ hoge\ \"\#hoge2\\$ \# h$$\#oge"#
>>
>>  The reason why I changed sysctl(8) was that the rc.d/sysctl script
>>  was too complex and slow even if it could support meta characters in
>>  shell script syntax.  I created several prototypes as script but
>>  noticed that keeping consistency was quite difficult and
>>  maintainability was poor due to tricky handling of variables.
>>
>>  Although my patch in the previous email does not support meta
>>  characters completely, I still think it is more reasonable to
>>  implement this functionality on the sysctl(8) side.
>
> I fully agree with the proposal to add the -f switch to the sysctl(8).
> This is consistent with several other administrative tools. Putting
> the ability to parse and apply arbitrary sysctl.conf-like file into
> the rc script is weird.

    The point was to augment rc.d/sysctl to do the right thing in most
sane cases. What's shown above frankly doesn't make sense for a domain
name, and while I agree that it's a good negative test, it seems a bit
on the insane side for a real world example.
    I was trying to provide an alternative using an existing
functioning system, instead of having to go and hack a widely used
utility to function in a way that isn't standard.
    With that in mind, reviewing the original proposed code...

...

+.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.

gcooper> This doesn't discuss the file format in complete, gory
detail, and no examples were added to aid the reader in how things can
be done in the new world order.

 .It Fl h
 Format output for human, rather than machine, readability.
 .It Fl i
Index: sbin/sysctl/sysctl.c
===================================================================
--- sbin/sysctl/sysctl.c	(revision 243756)
+++ sbin/sysctl/sysctl.c	(working copy)
@@ -56,13 +56,16 @@
 #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, xflag, warncount;
+static int	Nflag, nflag, oflag, qflag, xflag;

 static int	oidfmt(int *, int, char *, u_int *);
-static void	parse(char *);
+static int	parsefile(const char *);
+static int	parse(char *, int);
 static int	show_var(int *, int);
 static int	sysctl_all(int *oid, int len);
 static int	name2oid(char *, int *);
@@ -74,7 +77,7 @@
 {

 	(void)fprintf(stderr, "%s\n%s\n",
-	    "usage: sysctl [-bdehiNnoqx] name[=value] ...",
+	    "usage: sysctl [-bdehiNnoqx] [-f filename] name[=value] ...",
 	    "       sysctl [-bdehNnoqx] -a");
 	exit(1);
 }
@@ -83,12 +86,13 @@
 main(int argc, char **argv)
 {
 	int ch;
+	int warncount = 0;

gcooper> style bug.

 	setlocale(LC_NUMERIC, "");
 	setbuf(stdout,0);
 	setbuf(stderr,0);

-	while ((ch = getopt(argc, argv, "AabdehiNnoqwxX")) != -1) {
+	while ((ch = getopt(argc, argv, "Aabdef:hiNnoqwxX")) != -1) {
 		switch (ch) {
 		case 'A':
 			/* compatibility */
@@ -106,6 +110,9 @@
 		case 'e':
 			eflag = 1;
 			break;
+		case 'f':
+			conffile = strdup(optarg);

gcooper> Not checking for != NULL.

...

 /*
@@ -160,8 +169,8 @@
  * Lookup and print out the MIB entry if it exists.
  * Set a new value if requested.
  */
-static void
-parse(char *string)
+static int
+parse(char *string, int lineno)

gcooper> Since this is being modified, could string be changed to
const char * for completeness?

...

@@ -191,15 +213,20 @@

 	if (len < 0) {
 		if (iflag)
-			return;
-		if (qflag)
+			return (1);

gcooper> This should be return (0);

+		if (qflag)
 			exit(1);
 		else
-			errx(1, "unknown oid '%s'", bufp);
+			errx(1, "unknown oid '%s'%s", bufp, line);
 	}

-	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)
+			exit(1);
+		else
+			return (1);

gcooper> This should be arguably be `return (0);` too.

...

+static int
+parsefile(const char *filename)
+{
+	FILE *file;
+	char line[BUFSIZ], *p;
+	int warncount = 0, lineno = 0;

gcooper> Style bugs (declaring and initializing on the same line).

+
+	file = fopen(filename, "r");
+	if (file == NULL)
+		err(EX_NOINPUT, "%s", filename);
+	while (fgets(line, sizeof(line), file) != NULL) {
+		lineno++;
+		p = line;
+		/* Replace the first # with \0. */
+		while((p = strchr(p, '#')) != NULL) {

gcooper> Style bug (needs space between `while` and `(`).

+			if (p == line || *(p-1) != '\\') {

gcooper> Why are you allowing '\#' ?

+				*p = '\0';

...

 static int
Index: etc/rc.d/sysctl
===================================================================
--- etc/rc.d/sysctl	(revision 243756)
+++ etc/rc.d/sysctl	(working copy)
@@ -8,51 +8,27 @@
 . /etc/rc.subr

 name="sysctl"
+command=/sbin/sysctl

gcooper> Please quote this for consistency with the bulk majority of
rc.d scripts.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAGH67wQ1=Nx7DjWB1zdvDUMGSx09t_L-OX-cJNh-DiFihjA43A>