From owner-svn-src-all@FreeBSD.ORG Mon Jan 26 14:03:39 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6C054106567C; Mon, 26 Jan 2009 14:03:39 +0000 (UTC) (envelope-from luigi@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 598718FC21; Mon, 26 Jan 2009 14:03:39 +0000 (UTC) (envelope-from luigi@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n0QE3d8v051860; Mon, 26 Jan 2009 14:03:39 GMT (envelope-from luigi@svn.freebsd.org) Received: (from luigi@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n0QE3dKJ051858; Mon, 26 Jan 2009 14:03:39 GMT (envelope-from luigi@svn.freebsd.org) Message-Id: <200901261403.n0QE3dKJ051858@svn.freebsd.org> From: Luigi Rizzo Date: Mon, 26 Jan 2009 14:03:39 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r187713 - head/sbin/ipfw X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 26 Jan 2009 14:03:40 -0000 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;