nslookup: rework option parsing

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@googlemail.com>
This commit is contained in:
Denys Vlasenko 2018-04-15 12:01:46 +02:00
parent a980109c6a
commit d4461ef9fb

View File

@ -6,7 +6,7 @@
//config: help //config: help
//config: nslookup is a tool to query Internet name servers. //config: nslookup is a tool to query Internet name servers.
//config: //config:
//config:config NSLOOKUP_BIG //config:config FEATURE_NSLOOKUP_BIG
//config: bool "Use internal resolver code instead of libc" //config: bool "Use internal resolver code instead of libc"
//config: depends on NSLOOKUP //config: depends on NSLOOKUP
//config: default y //config: default y
@ -14,17 +14,16 @@
//config:config FEATURE_NSLOOKUP_LONG_OPTIONS //config:config FEATURE_NSLOOKUP_LONG_OPTIONS
//config: bool "Enable long options" //config: bool "Enable long options"
//config: default y //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)) //applet:IF_NSLOOKUP(APPLET(nslookup, BB_DIR_USR_BIN, BB_SUID_DROP))
//kbuild:lib-$(CONFIG_NSLOOKUP) += nslookup.o //kbuild:lib-$(CONFIG_NSLOOKUP) += nslookup.o
//usage:#define nslookup_trivial_usage //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:#define nslookup_full_usage "\n\n"
//usage: "Query the nameserver for the IP address of the given HOST\n" //usage: "Query DNS about HOST"
//usage: "optionally using a specified DNS server"
//usage: //usage:
//usage:#define nslookup_example_usage //usage:#define nslookup_example_usage
//usage: "$ nslookup localhost\n" //usage: "$ nslookup localhost\n"
@ -42,7 +41,7 @@
#include "common_bufsiz.h" #include "common_bufsiz.h"
#if !ENABLE_NSLOOKUP_BIG #if !ENABLE_FEATURE_NSLOOKUP_BIG
/* /*
* Mini nslookup implementation for busybox * Mini nslookup implementation for busybox
@ -326,7 +325,7 @@ struct globals {
} while (0) } while (0)
enum { enum {
OPT_stats = (1 << 4), OPT_stats = (1 << 0),
}; };
static int parse_reply(const unsigned char *msg, size_t len) 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); G.server = xrealloc_vector(G.server, /*8=2^3:*/ 3, count);
ns = &G.server[count]; ns = &G.server[count];
ns->name = addr; ns->name = addr;
ns->lsa = xhost2sockaddr(addr, 53); ns->lsa = xhost2sockaddr(addr, G.default_port);
/*ns->replies = 0; - already is */ /*ns->replies = 0; - already is */
/*ns->failures = 0; - already is */ /*ns->failures = 0; - already is */
} }
@ -747,75 +746,98 @@ int nslookup_main(int argc UNUSED_PARAM, char **argv)
{ {
struct ns *ns; struct ns *ns;
struct query *queries; struct query *queries;
llist_t *type_strings;
int n_queries; int n_queries;
unsigned types; unsigned types;
int opts;
int rc; int rc;
int err; int err;
INIT_G(); INIT_G();
type_strings = NULL; /* manpage: "Options can also be specified on the command line
#if ENABLE_FEATURE_NSLOOKUP_LONG_OPTIONS * if they precede the arguments and are prefixed with a hyphen."
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");
types = 0; types = 0;
while (type_strings) { argv++;
int c; for (;;) {
char *ptr, *chr; 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;
ptr = llist_pop(&type_strings); if (!*argv)
bb_show_usage();
if (argv[0][0] != '-')
break;
/* skip leading text, e.g. when invoked with -querytype=AAAA */ /* Separate out "=val" part */
chr = strchr(ptr, '='); arg = (*argv++) + 1;
if (chr) val = strchrnul(arg, '=');
ptr = chr + 1; if (*val)
*val++ = '\0';
for (c = 0;; c++) { i = index_in_substrings(options, arg);
if (c == ARRAY_SIZE(qtypes)) //bb_error_msg("i:%d arg:'%s' val:'%s'", i, arg, val);
bb_error_msg_and_die("invalid query type \"%s\"", ptr); if (i < 0)
if (strcmp(qtypes[c].name, ptr) == 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; break;
} }
types |= (1 << i);
types |= (1 << c); 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);
}
} }
argv += optind;
n_queries = 0; n_queries = 0;
queries = NULL; queries = NULL;
do {
if (types == 0) { if (types == 0) {
/* No explicit type given, guess query type. /* No explicit type given, guess query type.
* If we can convert the domain argument into a ptr (means that * If we can convert the domain argument into a ptr (means that
@ -826,28 +848,28 @@ int nslookup_main(int argc UNUSED_PARAM, char **argv)
char *ptr; char *ptr;
char buf80[80]; char buf80[80];
ptr = make_ptr(buf80, *argv); ptr = make_ptr(buf80, argv[0]);
if (ptr) { if (ptr) {
add_query(&queries, &n_queries, T_PTR, xstrdup(ptr)); add_query(&queries, &n_queries, T_PTR, xstrdup(ptr));
} else { } else {
add_query(&queries, &n_queries, T_A, *argv); add_query(&queries, &n_queries, T_A, argv[0]);
#if ENABLE_FEATURE_IPV6 #if ENABLE_FEATURE_IPV6
add_query(&queries, &n_queries, T_AAAA, *argv); add_query(&queries, &n_queries, T_AAAA, argv[0]);
#endif #endif
} }
} else { } else {
int c; int c;
for (c = 0; c < ARRAY_SIZE(qtypes); c++) { for (c = 0; c < ARRAY_SIZE(qtypes); c++) {
if (types & (1 << c)) if (types & (1 << c))
add_query(&queries, &n_queries, qtypes[c].type, *argv); add_query(&queries, &n_queries, qtypes[c].type, argv[0]);
} }
} }
argv++;
} while (argv[0] && argv[1]);
/* Use given DNS server if present */ /* Use given DNS server if present */
if (argv[0]) { if (argv[1]) {
add_ns(argv[0]); if (argv[2])
bb_show_usage();
add_ns(argv[1]);
} else { } else {
parse_resolvconf(); parse_resolvconf();
/* Fall back to localhost if we could not find NS in resolv.conf */ /* 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); c = send_queries(&G.server[rc], queries, n_queries);
if (c > 0) { if (c > 0) {
/* more than zero replies received */ /* more than zero replies received */
if (opts & OPT_stats) { if (option_mask32 & OPT_stats) {
printf("Replies:\t%d\n", G.server[rc].replies); printf("Replies:\t%d\n", G.server[rc].replies);
printf("Failures:\t%d\n\n", G.server[rc].failures); printf("Failures:\t%d\n\n", G.server[rc].failures);
} }