Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 6 Jan 2005 13:59:23 -0800
From:      Brooks Davis <brooks@one-eyed-alien.net>
To:        freebsd-ipfw@freebsd.org
Subject:   [PATCH] deprecating abrevations in ipfw
Message-ID:  <20050106215923.GA31004@odin.ac.hmc.edu>

next in thread | raw e-mail | index | archive | help
The ipfw program's code is littered with unmaintainable uses of strncmp
to implement abbreviations.  The following patch replaces those with
two new functions which simplify the code and produce warnings that the
syntax is deprecated.  In a future release, those can be converted to
hard errors and then finally the code can revert to using strcmp.  The
intention is to explicitly support a small number of abbreviations that
actually make sense rather then allowing arbitrary shortening of some
words.

When I examined the code, I found three types of uses of strncmp.  Most
commonly, strncmp(av, "string", sizeof(av)) was used to allow av to
match string or any shortened form of it.  I have replaced this with a
new function _substrcmp(av, "string") which returns 0 if av is a
substring of "string", but emits a warning if av is not exactly
"string".

The next type was two instances of strncmp(av, "by", 2) which allowed
the abbreviation of bytes to "by", "byt", etc.  Unfortunately, it also
supports "bykHUygh&*g&*7*ui".  I added a second new function
_substrcmp2(av, "by", "bytes") which acts like the strncmp did, but
complains if the user doesn't spell out the word "bytes".

There was also one correct use of strncmp to match "table(" which might
have another token after it.

Since I was changing all the lines anyway, also fixed the treatment of 
strncmp's return as a boolean in many cases.  I did modify a few strcmp
cases as well to be fully consistent.

Once final feature of this patch is a slight rewrite of match_token and
match_value.  The match_token changes make the code more readable in my
opinion.  However, it's possible that for very large rule files, the
old form is enough cheaper then the new form that it's noticeable.  The
changes to match_value simply make its variable names and flow more like
match_token.  I'd probably commit the separately.

Any objections to this patch?

I plan to MFC this to RELENG_5 after a commit to HEAD.

-- Brooks

==== //depot/user/brooks/dingo/sbin/ipfw/ipfw2.c#1 - /home/brooks/working/freebsd/p4/dingo/sbin/ipfw/ipfw2.c ====
@@ -427,10 +427,12 @@
 match_token(struct _s_x *table, char *string)
 {
 	struct _s_x *pt;
-	uint i = strlen(string);
+
+	if (strlen(string) == 0)
+		return -1;
 
-	for (pt = table ; i && pt->s != NULL ; pt++)
-		if (strlen(pt->s) == i && !bcmp(string, pt->s, i))
+	for (pt = table ; pt->s != NULL ; pt++)
+		if (strcmp(string, pt->s) == 0)
 			return pt->x;
 	return -1;
 }
@@ -440,15 +442,67 @@
  * with the value (NULL in case of failure).
  */
 static char const *
-match_value(struct _s_x *p, int value)
+match_value(struct _s_x *table, int value)
 {
-	for (; p->s != NULL; p++)
-		if (p->x == value)
-			return p->s;
+	struct _s_x *pt;
+
+	for (pt = table; pt->s != NULL; pt++)
+		if (pt->x == value)
+			return pt->s;
 	return NULL;
 }
 
 /*
+ * _substrcmp takes two strings and returns 1 if they do not match,
+ * and 0 if they match exactly or the first string is a sub-string
+ * of the second.  A warning is printed to stderr in the case that the
+ * first string is a sub-string of the second.
+ *
+ * This function will be removed in the future through the usual
+ * deprecation process.
+ */
+static int
+_substrcmp(const char *str1, const char* str2)
+{
+	
+	if (strncmp(str1, str2, strlen(str1)) != 0)
+		return 1;
+
+	if (strlen(str1) != strlen(str2))
+		warnx("DEPRECATED: '%s' matched '%s' as a sub-string",
+		    str1, str2);
+	return 0;
+}
+
+/*
+ * _substrcmp2 takes three strings and returns 1 if the first two do not match,
+ * and 0 if they match exactly or the second string is a sub-string
+ * of the first.  A warning is printed to stderr in the case that the
+ * first string does not match the third.
+ *
+ * This function exists to warn about the bizzare construction
+ * strncmp(str, "by", 2) which is used to allow people to use a shotcut
+ * for "bytes".  The problem is that in addition to accepting "by",
+ * "byt", "byte", and "bytes", it also excepts "by_rabid_dogs" and any
+ * other string beginning with "by".
+ *
+ * This function will be removed in the future through the usual
+ * deprecation process.
+ */
+static int
+_substrcmp2(const char *str1, const char* str2, const char* str3)
+{
+	
+	if (strncmp(str1, str2, strlen(str2)) != 0)
+		return 1;
+
+	if (strcmp(str1, str3) != 0)
+		warnx("DEPRECATED: '%s' matched '%s'",
+		    str1, str3);
+	return 0;
+}
+
+/*
  * prints one port, symbolic or numeric
  */
 static void
@@ -1760,7 +1814,7 @@
 
 	if (!ac)
 		errx(EX_USAGE, "set needs command");
-	if (!strncmp(*av, "show", strlen(*av)) ) {
+	if (_substrcmp(*av, "show") == 0) {
 		void *data;
 		char const *msg;
 
@@ -1784,7 +1838,7 @@
 				msg = "";
 			}
 		printf("\n");
-	} else if (!strncmp(*av, "swap", strlen(*av))) {
+	} else if (_substrcmp(*av, "swap") == 0) {
 		ac--; av++;
 		if (ac != 2)
 			errx(EX_USAGE, "set swap needs 2 set numbers\n");
@@ -1796,14 +1850,14 @@
 			errx(EX_DATAERR, "invalid set number %s\n", av[1]);
 		masks[0] = (4 << 24) | (new_set << 16) | (rulenum);
 		i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t));
-	} else if (!strncmp(*av, "move", strlen(*av))) {
+	} else if (_substrcmp(*av, "move") == 0) {
 		ac--; av++;
-		if (ac && !strncmp(*av, "rule", strlen(*av))) {
+		if (ac && _substrcmp(*av, "rule") == 0) {
 			cmd = 2;
 			ac--; av++;
 		} else
 			cmd = 3;
-		if (ac != 3 || strncmp(av[1], "to", strlen(*av)))
+		if (ac != 3 || _substrcmp(av[1], "to") != 0)
 			errx(EX_USAGE, "syntax: set move [rule] X to Y\n");
 		rulenum = atoi(av[0]);
 		new_set = atoi(av[2]);
@@ -1814,9 +1868,9 @@
 			errx(EX_DATAERR, "invalid dest. set %s\n", av[1]);
 		masks[0] = (cmd << 24) | (new_set << 16) | (rulenum);
 		i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t));
-	} else if (!strncmp(*av, "disable", strlen(*av)) ||
-		   !strncmp(*av, "enable",  strlen(*av)) ) {
-		int which = !strncmp(*av, "enable",  strlen(*av)) ? 1 : 0;
+	} else if (_substrcmp(*av, "disable") == 0 ||
+		   _substrcmp(*av, "enable") == 0 ) {
+		int which = _substrcmp(*av, "enable") == 0 ? 1 : 0;
 
 		ac--; av++;
 		masks[0] = masks[1] = 0;
@@ -1828,9 +1882,9 @@
 					errx(EX_DATAERR,
 					    "invalid set number %d\n", i);
 				masks[which] |= (1<<i);
-			} else if (!strncmp(*av, "disable", strlen(*av)))
+			} else if (_substrcmp(*av, "disable") == 0)
 				which = 0;
-			else if (!strncmp(*av, "enable", strlen(*av)))
+			else if (_substrcmp(*av, "enable") == 0)
 				which = 1;
 			else
 				errx(EX_DATAERR,
@@ -1856,22 +1910,22 @@
 
 	if (ac == 0) {
 		warnx("missing keyword to enable/disable\n");
-	} else if (strncmp(*av, "firewall", strlen(*av)) == 0) {
+	} else if (_substrcmp(*av, "firewall") == 0) {
 		sysctlbyname("net.inet.ip.fw.enable", NULL, 0,
 		    &which, sizeof(which));
-	} else if (strncmp(*av, "one_pass", strlen(*av)) == 0) {
+	} else if (_substrcmp(*av, "one_pass") == 0) {
 		sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0,
 		    &which, sizeof(which));
-	} else if (strncmp(*av, "debug", strlen(*av)) == 0) {
+	} else if (_substrcmp(*av, "debug") == 0) {
 		sysctlbyname("net.inet.ip.fw.debug", NULL, 0,
 		    &which, sizeof(which));
-	} else if (strncmp(*av, "verbose", strlen(*av)) == 0) {
+	} else if (_substrcmp(*av, "verbose") == 0) {
 		sysctlbyname("net.inet.ip.fw.verbose", NULL, 0,
 		    &which, sizeof(which));
-	} else if (strncmp(*av, "dyn_keepalive", strlen(*av)) == 0) {
+	} else if (_substrcmp(*av, "dyn_keepalive") == 0) {
 		sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0,
 		    &which, sizeof(which));
-	} else if (strncmp(*av, "altq", strlen(*av)) == 0) {
+	} else if (_substrcmp(*av, "altq") == 0) {
 		altq_set_enabled(which);
 	} else {
 		warnx("unrecognize enable/disable keyword: %s\n", *av);
@@ -2122,15 +2176,15 @@
 
 	cmd->o.len &= ~F_LEN_MASK;	/* zero len */
 
-	if (!strncmp(av, "any", strlen(av)))
+	if (_substrcmp(av, "any") == 0)
 		return;
 
-	if (!strncmp(av, "me", strlen(av))) {
+	if (_substrcmp(av, "me") == 0) {
 		cmd->o.len |= F_INSN_SIZE(ipfw_insn);
 		return;
 	}
 
-	if (!strncmp(av, "table(", 6)) {
+	if (strncmp(av, "table(", 6) == 0) {
 		char *p = strchr(av + 6, ',');
 
 		if (p)
@@ -2341,7 +2395,7 @@
 
 	av++; ac--;
 	NEED1("missing rule specification");
-	if (ac > 0 && !strncmp(*av, "set", strlen(*av))) {
+	if (ac > 0 && _substrcmp(*av, "set") == 0) {
 		do_set = 1;	/* delete set */
 		ac--; av++;
 	}
@@ -2389,7 +2443,7 @@
 	cmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
 
 	/* Parse the interface or address */
-	if (!strcmp(arg, "any"))
+	if (strcmp(arg, "any") == 0)
 		cmd->o.len = 0;		/* effectively ignore this command */
 	else if (!isdigit(*arg)) {
 		strlcpy(cmd->name, arg, sizeof(cmd->name));
@@ -2446,7 +2500,8 @@
 			if (*end == 'K' || *end == 'k') {
 				p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
 				p.fs.qsize *= 1024;
-			} else if (*end == 'B' || !strncmp(end, "by", 2)) {
+			} else if (*end == 'B' ||
+			    _substrcmp2(end, "by", "bytes") == 0) {
 				p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
 			}
 			ac--; av++;
@@ -2603,7 +2658,8 @@
 				end++;
 				p.bandwidth *= 1000000;
 			    }
-			    if (*end == 'B' || !strncmp(end, "by", 2))
+			    if (*end == 'B' ||
+			        _substrcmp2(end, "by", "bytes") == 0)
 				p.bandwidth *= 8;
 			    if (p.bandwidth < 0)
 				errx(EX_DATAERR, "bandwidth too large");
@@ -2736,7 +2792,7 @@
 
 	for (i=0; i<6; i++)
 		addr[i] = mask[i] = 0;
-	if (!strcmp(p, "any"))
+	if (strcmp(p, "any") == 0)
 		return;
 
 	for (i=0; *p && i<6;i++, p++) {
@@ -2857,7 +2913,7 @@
 	struct protoent *pe;
 	u_char proto = 0;
 
-	if (!strncmp(av, "all", strlen(av)))
+	if (_substrcmp(av, "all") == 0)
 		; /* same as "ip" */
 	else if ((proto = atoi(av)) > 0)
 		; /* all done! */
@@ -2907,7 +2963,7 @@
 static ipfw_insn *
 add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)
 {
-	if (!strncmp(av, "any", strlen(av))) {
+	if (_substrcmp(av, "any") == 0) {
 		return NULL;
 	} else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) {
 		/* XXX todo: check that we have a protocol with ports */
@@ -2979,7 +3035,7 @@
 	}
 
 	/* [set N]	-- set number (0..RESVD_SET), optional */
-	if (ac > 1 && !strncmp(*av, "set", strlen(*av))) {
+	if (ac > 1 && _substrcmp(*av, "set") == 0) {
 		int set = strtoul(av[1], NULL, 10);
 		if (set < 0 || set > RESVD_SET)
 			errx(EX_DATAERR, "illegal set %s", av[1]);
@@ -2988,7 +3044,7 @@
 	}
 
 	/* [prob D]	-- match probability, optional */
-	if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) {
+	if (ac > 1 && _substrcmp(*av, "prob") == 0) {
 		match_prob = strtod(av[1], NULL);
 
 		if (match_prob <= 0 || match_prob > 1)
@@ -3132,7 +3188,7 @@
 			have_log = (ipfw_insn *)c;
 			cmd->len = F_INSN_SIZE(ipfw_insn_log);
 			cmd->opcode = O_LOG;
-			if (ac && !strncmp(*av, "logamount", strlen(*av))) {
+			if (ac && _substrcmp(*av, "logamount") == 0) {
 				ac--; av++;
 				NEED1("logamount requires argument");
 				l = atoi(*av);
@@ -3193,8 +3249,8 @@
 #define	CLOSE_PAR						\
 	if (open_par) {						\
 		if (ac && (					\
-		    !strncmp(*av, ")", strlen(*av)) ||		\
-		    !strncmp(*av, "}", strlen(*av)) )) {	\
+		    strcmp(*av, ")") == 0 ||			\
+		    strcmp(*av, "}") == 0)) {			\
 			prev = NULL;				\
 			open_par = 0;				\
 			ac--; av++;				\
@@ -3203,7 +3259,7 @@
 	}
 
 #define NOT_BLOCK						\
-	if (ac && !strncmp(*av, "not", strlen(*av))) {		\
+	if (ac && _substrcmp(*av, "not") == 0) {		\
 		if (cmd->len & F_NOT)				\
 			errx(EX_USAGE, "double \"not\" not allowed\n"); \
 		cmd->len |= F_NOT;				\
@@ -3211,7 +3267,7 @@
 	}
 
 #define OR_BLOCK(target)					\
-	if (ac && !strncmp(*av, "or", strlen(*av))) {		\
+	if (ac && _substrcmp(*av, "or") == 0) {		\
 		if (prev == NULL || open_par == 0)		\
 			errx(EX_DATAERR, "invalid OR block");	\
 		prev->len |= F_OR;				\
@@ -3230,8 +3286,8 @@
 	 */
 	NOT_BLOCK;
 	NEED1("missing protocol");
-	if (!strncmp(*av, "MAC", strlen(*av)) ||
-	    !strncmp(*av, "mac", strlen(*av))) {
+	if (_substrcmp(*av, "MAC") == 0 ||
+	    _substrcmp(*av, "mac") == 0) {
 		ac--; av++;	/* the "MAC" keyword */
 		add_mac(cmd, ac, av); /* exits in case of errors */
 		cmd = next_cmd(cmd);
@@ -3269,7 +3325,7 @@
 	/*
 	 * "from", mandatory
 	 */
-	if (!ac || strncmp(*av, "from", strlen(*av)))
+	if (!ac || _substrcmp(*av, "from") != 0)
 		errx(EX_USAGE, "missing ``from''");
 	ac--; av++;
 
@@ -3293,7 +3349,7 @@
 	 */
 	NOT_BLOCK;	/* optional "not" */
 	if (ac) {
-		if (!strncmp(*av, "any", strlen(*av)) ||
+		if (_substrcmp(*av, "any") == 0 ||
 		    add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
 			ac--; av++;
 			if (F_LEN(cmd) != 0)
@@ -3304,7 +3360,7 @@
 	/*
 	 * "to", mandatory
 	 */
-	if (!ac || strncmp(*av, "to", strlen(*av)))
+	if (!ac || _substrcmp(*av, "to") != 0)
 		errx(EX_USAGE, "missing ``to''");
 	av++; ac--;
 
@@ -3328,7 +3384,7 @@
 	 */
 	NOT_BLOCK;	/* optional "not" */
 	if (ac) {
-		if (!strncmp(*av, "any", strlen(*av)) ||
+		if (_substrcmp(*av, "any") == 0 ||
 		    add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
 			ac--; av++;
 			if (F_LEN(cmd) != 0)
@@ -3665,7 +3721,7 @@
 
 		case TOK_SRCPORT:
 			NEED1("missing source port");
-			if (!strncmp(*av, "any", strlen(*av)) ||
+			if (_substrcmp(*av, "any") == 0 ||
 			    add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
 				ac--; av++;
 			} else
@@ -3674,7 +3730,7 @@
 
 		case TOK_DSTPORT:
 			NEED1("missing destination port");
-			if (!strncmp(*av, "any", strlen(*av)) ||
+			if (_substrcmp(*av, "any") == 0 ||
 			    add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
 				ac--; av++;
 			} else
@@ -3920,8 +3976,8 @@
 	} else
 		errx(EX_USAGE, "table number required");
 	NEED1("table needs command");
-	if (strncmp(*av, "add", strlen(*av)) == 0 ||
-	    strncmp(*av, "delete", strlen(*av)) == 0) {
+	if (_substrcmp(*av, "add") == 0 ||
+	    _substrcmp(*av, "delete") == 0) {
 		do_add = **av == 'a';
 		ac--; av++;
 		if (!ac)
@@ -3945,10 +4001,10 @@
 		    &ent, sizeof(ent)) < 0)
 			err(EX_OSERR, "setsockopt(IP_FW_TABLE_%s)",
 			    do_add ? "ADD" : "DEL");
-	} else if (strncmp(*av, "flush", strlen(*av)) == 0) {
+	} else if (_substrcmp(*av, "flush") == 0) {
 		if (do_cmd(IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) < 0)
 			err(EX_OSERR, "setsockopt(IP_FW_TABLE_FLUSH)");
-	} else if (strncmp(*av, "list", strlen(*av)) == 0) {
+	} else if (_substrcmp(*av, "list") == 0) {
 		a = ent.tbl;
 		l = sizeof(a);
 		if (do_cmd(IP_FW_TABLE_GETSIZE, &a, (uintptr_t)&l) < 0)
@@ -4160,9 +4216,9 @@
 	 * optional: pipe or queue
 	 */
 	do_pipe = 0;
-	if (!strncmp(*av, "pipe", strlen(*av)))
+	if (_substrcmp(*av, "pipe") == 0)
 		do_pipe = 1;
-	else if (!strncmp(*av, "queue", strlen(*av)))
+	else if (_substrcmp(*av, "queue") == 0)
 		do_pipe = 2;
 	if (do_pipe) {
 		ac--;
@@ -4182,30 +4238,30 @@
 		av[1] = p;
 	}
 
-	if (!strncmp(*av, "add", strlen(*av)))
+	if (_substrcmp(*av, "add") == 0)
 		add(ac, av);
-	else if (do_pipe && !strncmp(*av, "config", strlen(*av)))
+	else if (do_pipe && _substrcmp(*av, "config") == 0)
 		config_pipe(ac, av);
-	else if (!strncmp(*av, "delete", strlen(*av)))
+	else if (_substrcmp(*av, "delete") == 0)
 		delete(ac, av);
-	else if (!strncmp(*av, "flush", strlen(*av)))
+	else if (_substrcmp(*av, "flush") == 0)
 		flush(do_force);
-	else if (!strncmp(*av, "zero", strlen(*av)))
+	else if (_substrcmp(*av, "zero") == 0)
 		zero(ac, av, IP_FW_ZERO);
-	else if (!strncmp(*av, "resetlog", strlen(*av)))
+	else if (_substrcmp(*av, "resetlog") == 0)
 		zero(ac, av, IP_FW_RESETLOG);
-	else if (!strncmp(*av, "print", strlen(*av)) ||
-	         !strncmp(*av, "list", strlen(*av)))
+	else if (_substrcmp(*av, "print") == 0 ||
+	         _substrcmp(*av, "list") == 0)
 		list(ac, av, do_acct);
-	else if (!strncmp(*av, "set", strlen(*av)))
+	else if (_substrcmp(*av, "set") == 0)
 		sets_handler(ac, av);
-	else if (!strncmp(*av, "table", strlen(*av)))
+	else if (_substrcmp(*av, "table") == 0)
 		table_handler(ac, av);
-	else if (!strncmp(*av, "enable", strlen(*av)))
+	else if (_substrcmp(*av, "enable") == 0)
 		sysctl_handler(ac, av, 1);
-	else if (!strncmp(*av, "disable", strlen(*av)))
+	else if (_substrcmp(*av, "disable") == 0)
 		sysctl_handler(ac, av, 0);
-	else if (!strncmp(*av, "show", strlen(*av)))
+	else if (_substrcmp(*av, "show") == 0)
 		list(ac, av, 1 /* show counters */);
 	else
 		errx(EX_USAGE, "bad command `%s'", *av);
==== //depot/user/brooks/ports/slimserver/Makefile#20 - /home/brooks/working/freebsd/p4/ports/slimserver/Makefile ====
@@ -26,7 +26,7 @@
 RUN_DEPENDS+=	${SLIM_CPAN_DEPS:S|^|${SITE_PERL}/|:S|:|:${PORTSDIR}/|}
 
 .if ${PERL_LEVEL} < 500800
-IGNORE=		Need Perl 5.8.x
+IGNORE=	"Perl 5.8 or newer required. Install lang/perl5.8 and try again."
 .endif
 
 .if ${OSVERSION} < 502110



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20050106215923.GA31004>