exit(11);
}
+void outerr(void) {
+ sysfail("write to stdout",errno);
+}
+
static void domain_do_arg(const char *domain) {
if (ov_pipe) usageerr("-f/--pipe not consistent with domains on command line");
- domain_do(domain);
+ ensure_adns_init();
+ query_do(domain);
}
void *xmalloc(size_t sz) {
void of_type(const struct optioninfo *oi, const char *arg) { abort(); }
+int rcode;
+
+void setnonblock(int fd, int nonblock) { }
+
+static void read_query(void) { abort(); }
+
int main(int argc, const char *const *argv) {
const char *arg;
const struct optioninfo *oip;
+ struct timeval *tv, tvbuf;
+ adns_query qu;
+ void *qun_v;
+ adns_answer *answer;
+ int r, maxfd;
+ fd_set readfds, writefds, exceptfds;
while ((arg= *++argv)) {
if (arg[0] == '-') {
domain_do_arg(arg);
}
}
+
if (!ov_pipe && !ads) usageerr("no domains given, and -f/--pipe not used; try --help");
- abort();
+
+ for (;;) {
+ for (;;) {
+ qu= ov_asynch ? 0 : outstanding.head ? outstanding.head->qu : 0;
+ r= adns_check(ads,&qu,&answer,&qun_v);
+ if (r == EAGAIN) break;
+ if (r == ESRCH) { if (!ov_pipe) goto x_quit; else break; }
+ assert(!r);
+ query_done(qun_v,answer);
+ }
+ maxfd= 0;
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_ZERO(&exceptfds);
+ if (ov_pipe) {
+ maxfd= 1;
+ FD_SET(0,&readfds);
+ }
+ tv= 0;
+ adns_beforeselect(ads, &maxfd, &readfds,&writefds,&exceptfds, &tv,&tvbuf,0);
+ r= select(maxfd, &readfds,&writefds,&exceptfds, tv);
+ if (r == -1) {
+ if (errno == EINTR) continue;
+ sysfail("select",errno);
+ }
+ adns_afterselect(ads, maxfd, &readfds,&writefds,&exceptfds, 0);
+ if (ov_pipe && FD_ISSET(0,&readfds)) read_query();
+ }
+x_quit:
+ if (fclose(stdout)) outerr();
+ exit(rcode);
}
#include "adnshost.h"
adns_state ads;
+struct outstanding_list outstanding;
-struct query_node {
- struct query_node *next, *back;
- struct perqueryflags_remember pqfr;
- char *id;
- adns_query qu;
+static unsigned long idcounter;
+
+#define STATUSTYPEMAX(v) { adns_s_max_##v, #v }
+static const struct statustypemax {
+ adns_status smax;
+ const char *abbrev;
+} statustypemaxes[]= {
+ { adns_s_ok, "ok" },
+ STATUSTYPEMAX(localfail),
+ STATUSTYPEMAX(remotefail),
+ STATUSTYPEMAX(tempfail),
+ STATUSTYPEMAX(misconfig),
+ STATUSTYPEMAX(misquery),
+ STATUSTYPEMAX(permfail),
};
-static struct { struct query_node *head, *tail; } outstanding;
+void ensure_adns_init(void) {
+ int r;
+
+ if (ads) return;
-static unsigned long idcounter;
+ if (signal(SIGPIPE,SIG_IGN) == SIG_ERR) sysfail("ignore SIGPIPE",errno);
+ r= adns_init(&ads,
+ adns_if_noautosys|adns_if_nosigpipe |
+ (ov_env ? 0 : adns_if_noenv) |
+ ov_verbose,
+ 0);
+ if (r) sysfail("adns_init",r);
+}
-void domain_do(const char *domain) {
+void query_do(const char *domain) {
struct query_node *qun;
char idbuf[20];
int r;
- if (!ads) {
- if (signal(SIGPIPE,SIG_IGN) == SIG_ERR) sysfail("ignore SIGPIPE",errno);
- r= adns_init(&ads,
- adns_if_noautosys|adns_if_nosigpipe |
- (ov_env ? 0 : adns_if_noenv) |
- ov_verbose,
- 0);
- if (r) sysfail("adns_init",r);
- }
-
qun= malloc(sizeof(*qun));
qun->pqfr= ov_pqfr;
if (ov_id) {
LIST_LINK_TAIL(outstanding,qun);
}
-void of_asynch_id(const struct optioninfo *oi, const char *arg) { abort(); }
+static void print_withspace(const char *str) {
+ if (printf("%s ", str) == EOF) outerr();
+}
+
+static void print_ttl(struct query_node *qun, adns_answer *answer) {
+ unsigned long ttl;
+ time_t now;
+
+ switch (qun->pqfr.ttl) {
+ case tm_none:
+ return;
+ case tm_rel:
+ if (time(&now) == (time_t)-1) sysfail("get current time",errno);
+ ttl= answer->expires < now ? 0 : answer->expires - now;
+ break;
+ case tm_abs:
+ ttl= answer->expires;
+ break;
+ default:
+ abort();
+ }
+ if (printf("%lu ",ttl) == EOF) outerr();
+}
+
+static void print_owner_ttl(struct query_node *qun, adns_answer *answer) {
+ if (qun->pqfr.show_owner) print_withspace(answer->owner);
+ print_ttl(qun,answer);
+}
+
+static void print_status(adns_status st, struct query_node *qun, adns_answer *answer) {
+ int stnmin, stnmax, stn;
+ const char *statusabbrev, *statusstring;
+
+ stnmin= 0;
+ stnmax= sizeof(statustypemaxes)/sizeof(statustypemaxes[0]);
+ while (stnmin < stnmax) {
+ stn= (stnmin+stnmax)>>1;
+ if (st > statustypemaxes[stn].smax) stnmin= stn+1; else stnmax= stn;
+ }
+ stn= stnmin;
+ assert(statustypemaxes[stn].smax >= st);
+
+ if (rcode < stn) rcode= stn;
+
+ statusabbrev= adns_errabbrev(st);
+ statusstring= adns_strerror(st);
+ assert(!strchr(statusstring,'"'));
+
+ if (printf("%s %d %s ", statustypemaxes[stn].abbrev, st, statusabbrev)
+ == EOF) outerr();
+ print_owner_ttl(qun,answer);
+ if (qun->pqfr.show_cname)
+ print_withspace(answer->cname ? answer->cname : "$");
+ if (printf("\"%s\"\n", statusstring) == EOF) outerr();
+}
+
+void query_done(struct query_node *qun, adns_answer *answer) {
+ adns_status st, ist;
+ int rrn, nrrs;
+ const char *rrp, *realowner, *typename;
+ char *datastr;
+
+ if (ov_pipe) setnonblock(1,0);
+
+ st= answer->status;
+ nrrs= answer->nrrs;
+ if (ov_asynch) {
+ if (printf("%s %d", qun->id, nrrs) == EOF) outerr();
+ print_status(st,qun,answer);
+ } else {
+ if (st) {
+ if (fputs("; failed",stdout) == EOF) outerr();
+ print_status(st,qun,answer);
+ } else if (answer->cname) {
+ print_owner_ttl(qun,answer);
+ if (printf("CNAME %s\n",answer->cname) == EOF) outerr();
+ }
+ }
+ if (qun->pqfr.show_owner) {
+ realowner= answer->cname ? answer->cname : answer->owner;;
+ assert(realowner);
+ } else {
+ realowner= 0;
+ }
+ if (nrrs) {
+ for (rrn=0, rrp = answer->rrs.untyped;
+ rrn < nrrs;
+ rrn++, rrp += answer->rrsz) {
+ if (realowner) print_withspace(realowner);
+ print_ttl(qun,answer);
+ ist= adns_rr_info(answer->type, &typename, 0, 0, rrp, &datastr);
+ if (ist == adns_s_nomemory) sysfail("adns_rr_info failed",ENOMEM);
+ assert(!ist);
+ if (qun->pqfr.show_type) print_withspace(typename);
+ if (printf("%s\n",datastr) == EOF) outerr();
+ free(datastr);
+ }
+ }
+ if (fflush(stdout)) outerr();
+ LIST_UNLINK(outstanding,qun);
+ free(answer);
+ free(qun->id);
+ free(qun);
+}
+
+void of_asynch_id(const struct optioninfo *oi, const char *arg) {
+ free(ov_id);
+ ov_id= xstrsave(arg);
+}
+
void of_cancel_id(const struct optioninfo *oi, const char *arg) { abort(); }
+
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
+#include <stdlib.h>
#include <assert.h>
#include "config.h"
/* declarations related to query processing */
+struct query_node {
+ struct query_node *next, *back;
+ struct perqueryflags_remember pqfr;
+ char *id;
+ adns_query qu;
+};
+
extern adns_state ads;
+extern struct outstanding_list { struct query_node *head, *tail; } outstanding;
-void domain_do(const char *domain);
+void ensure_adns_init(void);
+void query_do(const char *domain);
+void query_done(struct query_node *qun, adns_answer *answer);
void of_asynch_id(const struct optioninfo *oi, const char *arg);
void of_cancel_id(const struct optioninfo *oi, const char *arg);
void sysfail(const char *what, int errnoval) NONRETURNING;
void usageerr(const char *what, ...) NONRETURNPRINTFFORMAT(1,2);
+void outerr(void) NONRETURNING;
+void setnonblock(int fd, int nonblock);
void *xmalloc(size_t sz);
char *xstrsave(const char *str);
+extern int rcode;
+
#endif