Author: luigi
Date: Mon Jan 26 14:03:39 2009
New Revision: 187713
URL: http://svn.freebsd.org/changeset/base/187713

Log:
  Some implementations of getopt() expect that argv[0] is always the
  program name, and ignore that entry.  ipfw2.c code instead skips
  this entry and starts with options at offset 0, relying on a more
  tolerant implementation of the library.
  
  This change fixes the issue by always passing a program name
  in the first entry to getopt. The motivation for this change
  is to remove a potential compatibility issue should we use
  a different getopt() implementation in the future.
  
  No functional changes.
  
  Submitted by: Marta Carbone (parts)
  MFC after:    4 weeks

Modified:
  head/sbin/ipfw/ipfw2.c

Modified: head/sbin/ipfw/ipfw2.c
==============================================================================
--- head/sbin/ipfw/ipfw2.c      Mon Jan 26 14:00:50 2009        (r187712)
+++ head/sbin/ipfw/ipfw2.c      Mon Jan 26 14:03:39 2009        (r187713)
@@ -6090,7 +6090,8 @@ show_nat(int ac, char **av)
 }
 
 /*
- * Called with the arguments (excluding program name).
+ * Called with the arguments, including program name because getopt
+ * wants it to be present.
  * Returns 0 if successful, 1 if empty command, errx() in case of errors.
  */
 static int
@@ -6102,16 +6103,16 @@ ipfw_main(int oldac, char **oldav)
        int do_acct = 0;                /* Show packet/byte count */
 
 #define WHITESP                " \t\f\v\n\r"
-       if (oldac == 0)
-               return 1;
-       else if (oldac == 1) {
+       if (oldac < 2)
+               return 1;       /* need at least one argument */
+       if (oldac == 2) {
                /*
                 * If we are called with a single string, try to split it into
                 * arguments for subsequent parsing.
                 * But first, remove spaces after a ',', by copying the string
                 * in-place.
                 */
-               char *arg = oldav[0];   /* The string... */
+               char *arg = oldav[1];   /* The string is the first arg. */
                int l = strlen(arg);
                int copy = 0;           /* 1 if we need to copy, 0 otherwise */
                int i, j;
@@ -6142,13 +6143,17 @@ ipfw_main(int oldac, char **oldav)
                        if (index(WHITESP, arg[i]) != NULL)
                                ac++;
 
-               av = calloc(ac, sizeof(char *));
+               /*
+                * Allocate the argument list, including one entry for
+                * the program name because getopt expects it.
+                */
+               av = calloc(ac + 1, sizeof(char *));
 
                /*
-                * Second, copy arguments from cmd[] to av[]. For each one,
+                * Second, copy arguments from arg[] to av[]. For each one,
                 * j is the initial character, i is the one past the end.
                 */
-               for (ac = 0, i = j = 0; i < l; i++)
+               for (ac = 1, i = j = 0; i < l; i++)
                        if (index(WHITESP, arg[i]) != NULL || i == l-1) {
                                if (i == l-1)
                                        i++;
@@ -6164,7 +6169,7 @@ ipfw_main(int oldac, char **oldav)
                int first, i, l;
 
                av = calloc(oldac, sizeof(char *));
-               for (first = i = ac = 0, l = 0; i < oldac; i++) {
+               for (first = i = ac = 1, l = 0; i < oldac; i++) {
                        char *arg = oldav[i];
                        int k = strlen(arg);
 
@@ -6183,6 +6188,7 @@ ipfw_main(int oldac, char **oldav)
                }
        }
 
+       av[0] = strdup(oldav[0]);       /* copy progname from the caller */
        /* Set the force flag for non-interactive processes */
        if (!do_force)
                do_force = !isatty(STDIN_FILENO);
@@ -6191,7 +6197,7 @@ ipfw_main(int oldac, char **oldav)
        save_ac = ac;
        save_av = av;
 
-       optind = optreset = 0;
+       optind = optreset = 1;  /* restart getopt() */
        while ((ch = getopt(ac, av, "abcdefhinNqs:STtv")) != -1)
                switch (ch) {
                case 'a':
@@ -6371,13 +6377,13 @@ ipfw_readfile(int ac, char *av[])
 {
 #define MAX_ARGS       32
        char    buf[BUFSIZ];
-       char    *cmd = NULL, *filename = av[ac-1];
+       const char *progname = av[0];           /* original program name */
+       const char *cmd = NULL;         /* preprocessor name, if any */
+       const char *filename = av[ac-1]; /* file to read */
        int     c, lineno=0;
        FILE    *f = NULL;
        pid_t   preproc = 0;
 
-       filename = av[ac-1];
-
        while ((c = getopt(ac, av, "cfNnp:qS")) != -1) {
                switch(c) {
                case 'c':
@@ -6397,18 +6403,28 @@ ipfw_readfile(int ac, char *av[])
                        break;
 
                case 'p':
-                       cmd = optarg;
                        /*
-                        * Skip previous args and delete last one, so we
-                        * pass all but the last argument to the preprocessor
-                        * via av[optind-1]
+                        * ipfw -p cmd [args] filename
+                        *
+                        * We are done with getopt(). All arguments
+                        * except the filename go to the preprocessor,
+                        * so we need to do the following:
+                        * - check that a filename is actually present;
+                        * - advance av by optind-1 to skip arguments
+                        *   already processed;
+                        * - decrease ac by optind, to remove the args
+                        *   already processed and the final filename;
+                        * - set the last entry in av[] to NULL so
+                        *   popen() can detect the end of the array;
+                        * - set optind=ac to let getopt() terminate.
                         */
-                       av += optind - 1;
-                       ac -= optind - 1;
-                       if (ac < 2)
+                       if (optind == ac)
                                errx(EX_USAGE, "no filename argument");
+                       cmd = optarg;
                        av[ac-1] = NULL;
-                       fprintf(stderr, "command is %s\n", av[0]);
+                       av += optind - 1;
+                       ac -= optind;
+                       optind = ac;
                        break;
 
                case 'q':
@@ -6424,8 +6440,6 @@ ipfw_readfile(int ac, char *av[])
                             " summary ``ipfw''");
                }
 
-               if (cmd != NULL)
-                       break;
        }
 
        if (cmd == NULL && ac != optind + 1) {
@@ -6474,13 +6488,14 @@ ipfw_readfile(int ac, char *av[])
 
        while (fgets(buf, BUFSIZ, f)) {         /* read commands */
                char linename[10];
-               char *args[1];
+               char *args[2];
 
                lineno++;
                sprintf(linename, "Line %d", lineno);
                setprogname(linename); /* XXX */
-               args[0] = buf;
-               ipfw_main(1, args);
+               args[0] = strdup(progname);
+               args[1] = buf;
+               ipfw_main(2, args);
        }
        fclose(f);
        if (cmd != NULL) {
@@ -6510,7 +6525,7 @@ main(int ac, char *av[])
        if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0)
                ipfw_readfile(ac, av);
        else {
-               if (ipfw_main(ac-1, av+1))
+               if (ipfw_main(ac, av))
                        show_usage();
        }
        return EX_OK;
_______________________________________________
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