]> granicus.if.org Git - ipset/commitdiff
ipset: Rework the "fake" argument parsing for ipset restore.
authorOliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>
Sun, 22 Sep 2013 18:56:34 +0000 (20:56 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Mon, 23 Sep 2013 12:01:34 +0000 (14:01 +0200)
This reworks the argument parsing functionality of ipset to handle
quote-delimited lines in such a way that they are considered to be a
single argument.

This commit is necessary for ipset to successfully restore sets that
have comments.

Signed-off-by: Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
src/ipset.c

index 4f308da8d90fb05edf76aaa5c6124a42118f1b8a..2c4fa100d09f790fced1610acc26f821fe09f2d2 100644 (file)
@@ -159,25 +159,57 @@ ipset_print_file(const char *fmt, ...)
 static void
 build_argv(char *buffer)
 {
-       char *ptr;
+       char *tmp, *arg;
        int i;
+       bool quoted = false;
 
        /* Reset */
-       for (i = 1; i < newargc; i++)
+       for (i = 1; i < newargc; i++) {
+               if (newargv[i])
+                       free(newargv[i]);
                newargv[i] = NULL;
+       }
        newargc = 1;
 
-       ptr = strtok(buffer, " \t\r\n");
-       newargv[newargc++] = ptr;
-       while ((ptr = strtok(NULL, " \t\r\n")) != NULL) {
-               if ((newargc + 1) < (int)(sizeof(newargv)/sizeof(char *)))
-                       newargv[newargc++] = ptr;
-               else {
+       arg = calloc(strlen(buffer) + 1, sizeof(*buffer));
+       for (tmp = buffer, i = 0; *tmp; tmp++) {
+               if ((newargc + 1) == (int)(sizeof(newargv)/sizeof(char *))) {
                        exit_error(PARAMETER_PROBLEM,
                                   "Line is too long to parse.");
                        return;
                }
+               switch (*tmp) {
+               case '"':
+                       quoted = !quoted;
+                       if (*(tmp+1))
+                               continue;
+                       break;
+               case ' ':
+               case '\r':
+               case '\n':
+               case '\t':
+                       if (!quoted)
+                               break;
+                       arg[i++] = *tmp;
+                       continue;
+               default:
+                       arg[i++] = *tmp;
+                       if (*(tmp+1))
+                               continue;
+                       break;
+               }
+               if (!*(tmp+1) && quoted) {
+                       exit_error(PARAMETER_PROBLEM, "Missing close quote!");
+                       return;
+               }
+               if (!*arg)
+                       continue;
+               newargv[newargc] = calloc(strlen(arg) + 1, sizeof(*arg));
+               ipset_strlcpy(newargv[newargc++], arg, strlen(arg) + 1);
+               memset(arg, 0, strlen(arg) + 1);
+               i = 0;
        }
+       free(arg);
 }
 
 /* Main parser function, workhorse */
@@ -195,7 +227,8 @@ restore(char *argv0)
 
        /* Initialize newargv/newargc */
        newargc = 0;
-       newargv[newargc++] = argv0;
+       newargv[newargc] = calloc(strlen(argv0) + 1, sizeof(*argv0));
+       ipset_strlcpy(newargv[newargc++], argv0, strlen(argv0) + 1);
        if (filename) {
                fd = fopen(filename, "r");
                if (!fd) {
@@ -232,6 +265,7 @@ restore(char *argv0)
        if (ret < 0)
                handle_error();
 
+       free(newargv[0]);
        return ret;
 }