[git commit] udhcp: support string user options, closes 10946

Denys Vlasenko vda.linux at googlemail.com
Fri Apr 13 11:27:52 UTC 2018


commit: https://git.busybox.net/busybox/commit/?id=266f6f19732f9b35487a87a346e58c1c3a0af43d
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
udhcp_str2optset                                     536     628     +92
packed_usage                                       32757   32760      +3
udhcpc_main                                         2708    2692     -16
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 95/-16)             Total: 79 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 examples/udhcp/udhcpd.conf  |  3 +-
 networking/udhcp/common.c   | 71 ++++++++++++++++++++++++++++-----------------
 networking/udhcp/d6_dhcpc.c | 11 ++-----
 networking/udhcp/dhcpc.c    | 11 ++-----
 4 files changed, 52 insertions(+), 44 deletions(-)

diff --git a/examples/udhcp/udhcpd.conf b/examples/udhcp/udhcpd.conf
index eca44c0ab..90714bcdf 100644
--- a/examples/udhcp/udhcpd.conf
+++ b/examples/udhcp/udhcpd.conf
@@ -70,8 +70,9 @@ option	domain	local
 option	lease	864000		# default: 10 days
 option	msstaticroutes	10.0.0.0/8 10.127.0.1		# single static route
 option	staticroutes	10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1
-# Arbitrary option in hex form:
+# Arbitrary option in hex or string form:
 option	0x08	01020304	# option 8: "cookie server IP addr: 1.2.3.4"
+option	14	"dumpfile"
 
 # Currently supported options (for more info, see options.c):
 #opt lease      NUM
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index d3eea5def..fbf9c6878 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -378,34 +378,24 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg)
  * Called to parse "udhcpc -x OPTNAME:OPTVAL"
  * and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives.
  */
-/* helper for the helper */
-static char *allocate_tempopt_if_needed(
+/* helper: add an option to the opt_list */
+static NOINLINE void attach_option(
+		struct option_set **opt_list,
 		const struct dhcp_optflag *optflag,
 		char *buffer,
-		int *length_p)
+		int length)
 {
+	struct option_set *existing;
 	char *allocated = NULL;
+
 	if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_BIN) {
 		const char *end;
 		allocated = xstrdup(buffer); /* more than enough */
 		end = hex2bin(allocated, buffer, 255);
 		if (errno)
 			bb_error_msg_and_die("malformed hex string '%s'", buffer);
-		*length_p = end - allocated;
+		length = end - allocated;
 	}
-	return allocated;
-}
-/* helper: add an option to the opt_list */
-static NOINLINE void attach_option(
-		struct option_set **opt_list,
-		const struct dhcp_optflag *optflag,
-		char *buffer,
-		int length)
-{
-	struct option_set *existing;
-	char *allocated;
-
-	allocated = allocate_tempopt_if_needed(optflag, buffer, &length);
 #if ENABLE_FEATURE_UDHCP_RFC3397
 	if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
 		/* reuse buffer and length for RFC1035-formatted string */
@@ -463,12 +453,12 @@ static NOINLINE void attach_option(
 int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dhcp_optflag *optflags, const char *option_strings)
 {
 	struct option_set **opt_list = arg;
-	char *opt, *val;
+	char *opt;
 	char *str;
 	const struct dhcp_optflag *optflag;
-	struct dhcp_optflag bin_optflag;
+	struct dhcp_optflag userdef_optflag;
 	unsigned optcode;
-	int retval, length;
+	int retval;
 	/* IP_PAIR needs 8 bytes, STATIC_ROUTES needs 9 max */
 	char buffer[9] ALIGNED(4);
 	uint16_t *result_u16 = (uint16_t *) buffer;
@@ -476,28 +466,40 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dh
 
 	/* Cheat, the only *const* str possible is "" */
 	str = (char *) const_str;
-	opt = strtok(str, " \t=");
+	opt = strtok(str, " \t=:");
 	if (!opt)
 		return 0;
 
 	optcode = bb_strtou(opt, NULL, 0);
 	if (!errno && optcode < 255) {
-		/* Raw (numeric) option code */
-		bin_optflag.flags = OPTION_BIN;
-		bin_optflag.code = optcode;
-		optflag = &bin_optflag;
+		/* Raw (numeric) option code.
+		 * Initially assume binary (hex-str), but if "str" or 'str'
+		 * is seen later, switch to STRING.
+		 */
+		userdef_optflag.flags = OPTION_BIN;
+		userdef_optflag.code = optcode;
+		optflag = &userdef_optflag;
 	} else {
 		optflag = &optflags[udhcp_option_idx(opt, option_strings)];
 	}
 
+	/* Loop to handle OPTION_LIST case, else execute just once */
 	retval = 0;
 	do {
-		val = strtok(NULL, ", \t");
+		int length;
+		char *val;
+
+		if (optflag->flags == OPTION_BIN)
+			val = trim(strtok(NULL, "")); /* do not split "'q w e'" */
+		else
+			val = strtok(NULL, ", \t");
 		if (!val)
 			break;
+
 		length = dhcp_option_lengths[optflag->flags & OPTION_TYPE_MASK];
 		retval = 0;
 		opt = buffer; /* new meaning for variable opt */
+
 		switch (optflag->flags & OPTION_TYPE_MASK) {
 		case OPTION_IP:
 			retval = udhcp_str2nip(val, buffer);
@@ -510,6 +512,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dh
 			if (retval)
 				retval = udhcp_str2nip(val, buffer + 4);
 			break;
+case_OPTION_STRING:
 		case OPTION_STRING:
 		case OPTION_STRING_HOST:
 #if ENABLE_FEATURE_UDHCP_RFC3397
@@ -577,12 +580,26 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dh
 			}
 			break;
 		}
-		case OPTION_BIN: /* handled in attach_option() */
+		case OPTION_BIN:
+			/* Raw (numeric) option code. Is it a string? */
+			if (val[0] == '"' || val[0] == '\'') {
+				char delim = val[0];
+				char *end = last_char_is(val + 1, delim);
+				if (end) {
+					*end = '\0';
+					val++;
+					userdef_optflag.flags = OPTION_STRING;
+					goto case_OPTION_STRING;
+				}
+			}
+			/* No: hex-str option, handled in attach_option() */
 			opt = val;
 			retval = 1;
+			break;
 		default:
 			break;
 		}
+
 		if (retval)
 			attach_option(opt_list, optflag, opt, length);
 	} while (retval && (optflag->flags & OPTION_LIST));
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 289df66ee..85d9da724 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -1063,6 +1063,7 @@ static void client_background(void)
 //usage:     "\n			-x hostname:bbox - option 12"
 //usage:     "\n			-x lease:3600 - option 51 (lease time)"
 //usage:     "\n			-x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
+//usage:     "\n			-x 14:'\"dumpfile\"' - option 14 (shell-quoted)"
 //usage:	IF_UDHCP_VERBOSE(
 //usage:     "\n	-v		Verbose"
 //usage:	)
@@ -1155,15 +1156,9 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
 		}
 	}
 	while (list_x) {
-		char *optstr = llist_pop(&list_x);
-		char *colon = strchr(optstr, ':');
-		if (colon)
-			*colon = ' ';
-		/* now it looks similar to udhcpd's config file line:
-		 * "optname optval", using the common routine: */
+		char *optstr = xstrdup(llist_pop(&list_x));
 		udhcp_str2optset(optstr, &client_config.options, d6_optflags, d6_option_strings);
-		if (colon)
-			*colon = ':'; /* restore it for NOMMU reexec */
+		free(optstr);
 	}
 
 	if (d6_read_interface(client_config.interface,
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 90b07bf4b..bd9e8fdc2 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -1224,6 +1224,7 @@ static void client_background(void)
 //usage:     "\n			-x hostname:bbox - option 12"
 //usage:     "\n			-x lease:3600 - option 51 (lease time)"
 //usage:     "\n			-x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
+//usage:     "\n			-x 14:'\"dumpfile\"' - option 14 (shell-quoted)"
 //usage:     "\n	-F NAME		Ask server to update DNS mapping for NAME"
 //usage:     "\n	-V VENDOR	Vendor identifier (default 'udhcp VERSION')"
 //usage:     "\n	-C		Don't send MAC as client identifier"
@@ -1335,15 +1336,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
 		}
 	}
 	while (list_x) {
-		char *optstr = llist_pop(&list_x);
-		char *colon = strchr(optstr, ':');
-		if (colon)
-			*colon = ' ';
-		/* now it looks similar to udhcpd's config file line:
-		 * "optname optval", using the common routine: */
+		char *optstr = xstrdup(llist_pop(&list_x));
 		udhcp_str2optset(optstr, &client_config.options, dhcp_optflags, dhcp_option_strings);
-		if (colon)
-			*colon = ':'; /* restore it for NOMMU reexec */
+		free(optstr);
 	}
 
 	if (udhcp_read_interface(client_config.interface,


More information about the busybox-cvs mailing list