#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(); }
-void of_cancel_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) {
+ assert(!"implemented");
+}
+