udhcp: dname_dec may return NULL, account for that case

Other random cleanips included...

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/networking/udhcp/script.c b/networking/udhcp/script.c
index 7ebef35..94dabf4 100644
--- a/networking/udhcp/script.c
+++ b/networking/udhcp/script.c
@@ -14,7 +14,7 @@
 
 
 /* get a rough idea of how long an option will be (rounding up...) */
-static const uint8_t max_option_length[] = {
+static const uint8_t len_of_option_as_string[] = {
 	[OPTION_IP] =		sizeof("255.255.255.255 "),
 	[OPTION_IP_PAIR] =	sizeof("255.255.255.255 ") * 2,
 	[OPTION_STRING] =	1,
@@ -30,17 +30,10 @@
 };
 
 
-static inline int upper_length(int length, int opt_index)
-{
-	return max_option_length[opt_index] *
-		(length / dhcp_option_lengths[opt_index]);
-}
-
-
 /* note: ip is a pointer to an IP in network order, possibly misaliged */
 static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
 {
-	return sprintf(dest, "%s%d.%d.%d.%d", pre, ip[0], ip[1], ip[2], ip[3]);
+	return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
 }
 
 
@@ -57,9 +50,10 @@
 }
 
 
-/* Allocate and fill with the text of option 'option'. */
-static char *alloc_fill_opts(uint8_t *option, const struct dhcp_option *type_p, const char *opt_name)
+/* Create "opt_name=opt_value" string */
+static char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_option *type_p, const char *opt_name)
 {
+	unsigned upper_length;
 	int len, type, optlen;
 	uint16_t val_u16;
 	int16_t val_s16;
@@ -67,14 +61,16 @@
 	int32_t val_s32;
 	char *dest, *ret;
 
-	len = option[OPT_LEN - 2];
+	/* option points to OPT_DATA, need to go back and get OPT_LEN */
+	len = option[OPT_LEN - OPT_DATA];
 	type = type_p->flags & TYPE_MASK;
 	optlen = dhcp_option_lengths[type];
+	upper_length = len_of_option_as_string[type] * (len / optlen);
 
-	dest = ret = xmalloc(upper_length(len, type) + strlen(opt_name) + 2);
+	dest = ret = xmalloc(upper_length + strlen(opt_name) + 2);
 	dest += sprintf(ret, "%s=", opt_name);
 
-	for (;;) {
+	while (len >= optlen) {
 		switch (type) {
 		case OPTION_IP_PAIR:
 			dest += sprint_nip(dest, "", option);
@@ -114,15 +110,20 @@
 		case OPTION_STR1035:
 			/* unpack option into dest; use ret for prefix (i.e., "optname=") */
 			dest = dname_dec(option, len, ret);
-			free(ret);
-			return dest;
+			if (dest) {
+				free(ret);
+				return dest;
+			}
+			/* error. return "optname=" string */
+			return ret;
 #endif
 		}
 		option += optlen;
 		len -= optlen;
 		if (len <= 0)
 			break;
-		dest += sprintf(dest, " ");
+		*dest++ = ' ';
+		*dest = '\0';
 	}
 	return ret;
 }
@@ -174,7 +175,7 @@
 		temp = get_option(packet, dhcp_options[i].code);
 		if (!temp)
 			goto next;
-		*curr = alloc_fill_opts(temp, &dhcp_options[i], opt_name);
+		*curr = xmalloc_optname_optval(temp, &dhcp_options[i], opt_name);
 		putenv(*curr++);
 
 		/* Fill in a subnet bits option for things like /24 */