nslookup: add support for search domains, closes 11161

function                                             old     new   delta
parse_resolvconf                                       -     311    +311
add_query_with_search                                  -     105    +105
nslookup_main                                        873     757    -116
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 0/1 up/down: 416/-116)          Total: 300 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/networking/nslookup.c b/networking/nslookup.c
index 3a614b0..e153eb5 100644
--- a/networking/nslookup.c
+++ b/networking/nslookup.c
@@ -318,6 +318,8 @@
 	unsigned serv_count;
 	struct ns *server;
 	struct query *query;
+	char *search;
+	smalluint have_search_directive;
 } FIX_ALIASING;
 #define G (*(struct globals*)bb_common_bufsiz1)
 #define INIT_G() do { \
@@ -667,24 +669,60 @@
 
 	resolv = fopen("/etc/resolv.conf", "r");
 	if (resolv) {
-		char line[128], *p;
+		char line[512];	/* "search" is defined to be up to 256 chars */
 
 		while (fgets(line, sizeof(line), resolv)) {
+			char *p, *arg;
+
 			p = strtok(line, " \t\n");
-
-			if (!p || strcmp(p, "nameserver") != 0)
-				continue;
-
-			p = strtok(NULL, " \t\n");
-
 			if (!p)
 				continue;
+			dbg("resolv_key:'%s'\n", p);
+			arg = strtok(NULL, "\n");
+			dbg("resolv_arg:'%s'\n", arg);
+			if (!arg)
+				continue;
 
-			add_ns(xstrdup(p));
+			if (strcmp(p, "domain") == 0) {
+				/* domain DOM */
+				if (!G.have_search_directive)
+					goto set_search;
+				continue;
+			}
+			if (strcmp(p, "search") == 0) {
+				/* search DOM1 DOM2... */
+				G.have_search_directive = 1;
+ set_search:
+				free(G.search);
+				G.search = xstrdup(arg);
+				dbg("search='%s'\n", G.search);
+				continue;
+			}
+
+			if (strcmp(p, "nameserver") != 0)
+				continue;
+
+			/* nameserver DNS */
+			add_ns(xstrdup(arg));
 		}
 
 		fclose(resolv);
 	}
+
+	if (!G.search) {
+		/* default search domain is domain part of hostname */
+		char *h = safe_gethostname();
+		char *d = strchr(h, '.');
+		if (d) {
+			G.search = d + 1;
+			dbg("search='%s' (from hostname)\n", G.search);
+		}
+		/* else free(h); */
+	}
+
+	/* Cater for case of "domain ." in resolv.conf */
+	if (G.search && LONE_CHAR(G.search, '.'))
+		G.search = NULL;
 }
 
 static void add_query(int type, const char *dname)
@@ -695,7 +733,7 @@
 
 	count = G.query_count++;
 
-	G.query = xrealloc_vector(G.query, /*2=2^1:*/ 1, count);
+	G.query = xrealloc_vector(G.query, /*4=2^2:*/ 2, count);
 	new_q = &G.query[count];
 
 	dbg("new query#%u type %u for '%s'\n", count, type, dname);
@@ -709,6 +747,28 @@
 	new_q->qlen = qlen;
 }
 
+static void add_query_with_search(int type, const char *dname)
+{
+	char *s;
+
+	if (type == T_PTR || !G.search || strchr(dname, '.')) {
+		add_query(type, dname);
+		return;
+	}
+
+	s = G.search;
+	for (;;) {
+		char *fullname, *e;
+
+		e = skip_non_whitespace(s);
+		fullname = xasprintf("%s.%.*s", dname, (int)(e - s), s);
+		add_query(type, fullname);
+		s = skip_whitespace(e);
+		if (!*s)
+			break;
+	}
+}
+
 static char *make_ptr(const char *addrstr)
 {
 	unsigned char addr[16];
@@ -833,6 +893,18 @@
 		}
 	}
 
+	/* Use given DNS server if present */
+	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 */
+		if (G.serv_count == 0)
+			add_ns("127.0.0.1");
+	}
+
 	if (types == 0) {
 		/* No explicit type given, guess query type.
 		 * If we can convert the domain argument into a ptr (means that
@@ -846,31 +918,19 @@
 		if (ptr) {
 			add_query(T_PTR, ptr);
 		} else {
-			add_query(T_A, argv[0]);
+			add_query_with_search(T_A, argv[0]);
 #if ENABLE_FEATURE_IPV6
-			add_query(T_AAAA, argv[0]);
+			add_query_with_search(T_AAAA, argv[0]);
 #endif
 		}
 	} else {
 		int c;
 		for (c = 0; c < ARRAY_SIZE(qtypes); c++) {
 			if (types & (1 << c))
-				add_query(qtypes[c].type, argv[0]);
+				add_query_with_search(qtypes[c].type, argv[0]);
 		}
 	}
 
-	/* Use given DNS server if present */
-	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 */
-		if (G.serv_count == 0)
-			add_ns("127.0.0.1");
-	}
-
 	for (rc = 0; rc < G.serv_count;) {
 		int c;