[git commit] nslookup: rework option parsing

Denys Vlasenko vda.linux at googlemail.com
Sun Apr 15 10:01:46 UTC 2018


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

function                                             old     new   delta
nslookup_main                                       2715    2754     +39
packed_usage                                       32179   32211     +32
add_ns                                                65      66      +1
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/0 up/down: 72/0)               Total: 72 bytes
   text	   data	    bss	    dec	    hex	filename
 926262	    555	   5740	 932557	  e3acd	busybox_old
 926239	    555	   5740	 932534	  e3ab6	busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 networking/nslookup.c | 204 ++++++++++++++++++++++++++++----------------------
 1 file changed, 113 insertions(+), 91 deletions(-)

diff --git a/networking/nslookup.c b/networking/nslookup.c
index c6f431347..112e8763c 100644
--- a/networking/nslookup.c
+++ b/networking/nslookup.c
@@ -6,7 +6,7 @@
 //config:	help
 //config:	nslookup is a tool to query Internet name servers.
 //config:
-//config:config NSLOOKUP_BIG
+//config:config FEATURE_NSLOOKUP_BIG
 //config:	bool "Use internal resolver code instead of libc"
 //config:	depends on NSLOOKUP
 //config:	default y
@@ -14,17 +14,16 @@
 //config:config FEATURE_NSLOOKUP_LONG_OPTIONS
 //config:	bool "Enable long options"
 //config:	default y
-//config:	depends on NSLOOKUP_BIG && LONG_OPTS
+//config:	depends on FEATURE_NSLOOKUP_BIG && LONG_OPTS
 
 //applet:IF_NSLOOKUP(APPLET(nslookup, BB_DIR_USR_BIN, BB_SUID_DROP))
 
 //kbuild:lib-$(CONFIG_NSLOOKUP) += nslookup.o
 
 //usage:#define nslookup_trivial_usage
-//usage:       "[HOST] [SERVER]"
+//usage:       IF_FEATURE_NSLOOKUP_BIG("[-type=QUERY_TYPE] ") "HOST [DNS_SERVER]"
 //usage:#define nslookup_full_usage "\n\n"
-//usage:       "Query the nameserver for the IP address of the given HOST\n"
-//usage:       "optionally using a specified DNS server"
+//usage:       "Query DNS about HOST"
 //usage:
 //usage:#define nslookup_example_usage
 //usage:       "$ nslookup localhost\n"
@@ -42,7 +41,7 @@
 #include "common_bufsiz.h"
 
 
-#if !ENABLE_NSLOOKUP_BIG
+#if !ENABLE_FEATURE_NSLOOKUP_BIG
 
 /*
  * Mini nslookup implementation for busybox
@@ -326,7 +325,7 @@ struct globals {
 } while (0)
 
 enum {
-	OPT_stats = (1 << 4),
+	OPT_stats = (1 << 0),
 };
 
 static int parse_reply(const unsigned char *msg, size_t len)
@@ -687,7 +686,7 @@ static void add_ns(const char *addr)
 	G.server = xrealloc_vector(G.server, /*8=2^3:*/ 3, count);
 	ns = &G.server[count];
 	ns->name = addr;
-	ns->lsa = xhost2sockaddr(addr, 53);
+	ns->lsa = xhost2sockaddr(addr, G.default_port);
 	/*ns->replies = 0; - already is */
 	/*ns->failures = 0; - already is */
 }
@@ -747,107 +746,130 @@ int nslookup_main(int argc UNUSED_PARAM, char **argv)
 {
 	struct ns *ns;
 	struct query *queries;
-	llist_t *type_strings;
 	int n_queries;
 	unsigned types;
-	int opts;
 	int rc;
 	int err;
 
 	INIT_G();
 
-	type_strings = NULL;
-#if ENABLE_FEATURE_NSLOOKUP_LONG_OPTIONS
-	opts = getopt32long(argv, "^"
-			"+" /* '+': stop at first non-option (why?) */
-			"q:*p:+r:+t:+s"
-			"\0"
-			"-1:q::", /* minimum 1 arg, -q is a list */
-				"type\0"      Required_argument "q"
-				"querytype\0" Required_argument "q"
-				"port\0"      Required_argument "p"
-				"retry\0"     Required_argument "r"
-				"timeout\0"   Required_argument "t"
-				"stats\0"     No_argument       "s",
-	                &type_strings, &G.default_port,
-	                &G.default_retry, &G.default_timeout
-	);
-#else
-	opts = getopt32(argv, "^"
-			"+" /* '+': stop at first non-option (why?) */
-			"q:*p:+r:+t:+s"
-			"\0"
-			"-1:q::", /* minimum 1 arg, -q is a list */
-	                &type_strings, &G.default_port,
-	                &G.default_retry, &G.default_timeout
-	);
-#endif
-	if (G.default_port > 65535)
-		bb_error_msg_and_die("invalid server port");
-	if (G.default_retry == 0)
-		bb_error_msg_and_die("invalid retry value");
-	if (G.default_timeout == 0)
-		bb_error_msg_and_die("invalid timeout value");
-
+	/* manpage: "Options can also be specified on the command line
+	 * if they precede the arguments and are prefixed with a hyphen."
+	 */
 	types = 0;
-	while (type_strings) {
-		int c;
-		char *ptr, *chr;
-
-		ptr = llist_pop(&type_strings);
-
-		/* skip leading text, e.g. when invoked with -querytype=AAAA */
-		chr = strchr(ptr, '=');
-		if (chr)
-			ptr = chr + 1;
+	argv++;
+	for (;;) {
+		const char *options =
+// bind-utils-9.11.3 accept these:
+// class=   cl=
+// type=    ty= querytype= query= qu= q=
+// domain=  do=
+// port=    po=
+// timeout= t=
+// retry=   ret=
+// ndots=
+// recurse
+// norecurse
+// defname
+// nodefname
+// vc
+// novc
+// debug
+// nodebug
+// d2
+// nod2
+// search
+// nosearch
+// sil
+// fail
+// nofail
+// ver (prints version and exits)
+			"type\0"      /* 0 */
+			"querytype\0" /* 1 */
+			"port\0"      /* 2 */
+			"retry\0"     /* 3 */
+			"stats\0"     /* 4 */
+			"t\0" /* disambiguate with "type": else -t=2 fails */
+			"timeout\0"   /* 6 */
+			"";
+		int i;
+		char *arg;
+		char *val;
+
+		if (!*argv)
+			bb_show_usage();
+		if (argv[0][0] != '-')
+			break;
 
-		for (c = 0;; c++) {
-			if (c == ARRAY_SIZE(qtypes))
-				bb_error_msg_and_die("invalid query type \"%s\"", ptr);
-			if (strcmp(qtypes[c].name, ptr) == 0)
-				break;
+		/* Separate out "=val" part */
+		arg = (*argv++) + 1;
+		val = strchrnul(arg, '=');
+		if (*val)
+			*val++ = '\0';
+
+		i = index_in_substrings(options, arg);
+		//bb_error_msg("i:%d arg:'%s' val:'%s'", i, arg, val);
+		if (i < 0)
+			bb_show_usage();
+
+		if (i <= 1) {
+			for (i = 0;; i++) {
+				if (i == ARRAY_SIZE(qtypes))
+					bb_error_msg_and_die("invalid query type \"%s\"", val);
+				if (strcmp(qtypes[i].name, val) == 0)
+					break;
+			}
+			types |= (1 << i);
+			continue;
+		}
+		if (i == 2) {
+			G.default_port = xatou_range(val, 1, 0xffff);
+		}
+		if (i == 3) {
+			G.default_retry = xatou_range(val, 1, INT_MAX);
+		}
+		if (i == 4) {
+			option_mask32 |= OPT_stats;
+		}
+		if (i > 4) {
+			G.default_timeout = xatou_range(val, 1, INT_MAX / 1000);
 		}
-
-		types |= (1 << c);
 	}
 
-	argv += optind;
-
 	n_queries = 0;
 	queries = NULL;
-	do {
-		if (types == 0) {
-			/* No explicit type given, guess query type.
-			 * If we can convert the domain argument into a ptr (means that
-			 * inet_pton() could read it) we assume a PTR request, else
-			 * we issue A+AAAA queries and switch to an output format
-			 * mimicking the one of the traditional nslookup applet.
-			 */
-			char *ptr;
-			char buf80[80];
-
-			ptr = make_ptr(buf80, *argv);
-			if (ptr) {
-				add_query(&queries, &n_queries, T_PTR, xstrdup(ptr));
-			} else {
-				add_query(&queries, &n_queries, T_A, *argv);
+	if (types == 0) {
+		/* No explicit type given, guess query type.
+		 * If we can convert the domain argument into a ptr (means that
+		 * inet_pton() could read it) we assume a PTR request, else
+		 * we issue A+AAAA queries and switch to an output format
+		 * mimicking the one of the traditional nslookup applet.
+		 */
+		char *ptr;
+		char buf80[80];
+
+		ptr = make_ptr(buf80, argv[0]);
+		if (ptr) {
+			add_query(&queries, &n_queries, T_PTR, xstrdup(ptr));
+		} else {
+			add_query(&queries, &n_queries, T_A, argv[0]);
 #if ENABLE_FEATURE_IPV6
-				add_query(&queries, &n_queries, T_AAAA, *argv);
+			add_query(&queries, &n_queries, T_AAAA, argv[0]);
 #endif
-			}
-		} else {
-			int c;
-			for (c = 0; c < ARRAY_SIZE(qtypes); c++) {
-				if (types & (1 << c))
-					add_query(&queries, &n_queries, qtypes[c].type,	*argv);
-			}
 		}
-		argv++;
-	} while (argv[0] && argv[1]);
+	} else {
+		int c;
+		for (c = 0; c < ARRAY_SIZE(qtypes); c++) {
+			if (types & (1 << c))
+				add_query(&queries, &n_queries, qtypes[c].type,	argv[0]);
+		}
+	}
 
 	/* Use given DNS server if present */
-	if (argv[0]) {
-		add_ns(argv[0]);
+	if (argv[1]) {
+		if (argv[2])
+			bb_show_usage();
+		add_ns(argv[1]);
 	} else {
 		parse_resolvconf();
 		/* Fall back to localhost if we could not find NS in resolv.conf */
@@ -861,7 +883,7 @@ int nslookup_main(int argc UNUSED_PARAM, char **argv)
 		c = send_queries(&G.server[rc], queries, n_queries);
 		if (c > 0) {
 			/* more than zero replies received */
-			if (opts & OPT_stats) {
+			if (option_mask32 & OPT_stats) {
 				printf("Replies:\t%d\n", G.server[rc].replies);
 				printf("Failures:\t%d\n\n", G.server[rc].failures);
 			}


More information about the busybox-cvs mailing list