1 /* 2 * adh-main.c 3 * - useful general-purpose resolver client program 4 * main program and useful subroutines 5 */ 6 /* 7 * This file is 8 * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk> 9 * 10 * It is part of adns, which is 11 * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk> 12 * Copyright (C) 1999-2000 Tony Finch <dot@dotat.at> 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 2, or (at your option) 17 * any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program; if not, write to the Free Software Foundation, 26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 27 */ 28 29 #ifdef ADNS_JGAA_WIN32 30 # include "adns_win32.h" 31 # include <io.h> 32 #endif 33 34 #include "adnshost.h" 35 36 int rcode; 37 const char *config_text; 38 39 static int used, avail; 40 static char *buf; 41 42 void quitnow(int rc) { 43 if (ads) adns_finish(ads); 44 free(buf); 45 free(ov_id); 46 exit(rc); 47 } 48 49 void sysfail(const char *what, int errnoval) { 50 fprintf(stderr,"adnshost failed: %s: %s\n",what,strerror(errnoval)); 51 quitnow(10); 52 } 53 54 void usageerr(const char *fmt, ...) { 55 va_list al; 56 fputs("adnshost usage error: ",stderr); 57 va_start(al,fmt); 58 vfprintf(stderr,fmt,al); 59 va_end(al); 60 putc('\n',stderr); 61 quitnow(11); 62 } 63 64 void outerr(void) { 65 sysfail("write to stdout",errno); 66 } 67 68 void *xmalloc(size_t sz) { 69 void *p; 70 71 p= malloc(sz); if (!p) sysfail("malloc",sz); 72 return p; 73 } 74 75 char *xstrsave(const char *str) { 76 char *p; 77 78 p= xmalloc(strlen(str)+1); 79 strcpy(p,str); 80 return p; 81 } 82 83 void of_config(const struct optioninfo *oi, const char *arg, const char *arg2) { 84 config_text= arg; 85 } 86 87 void of_type(const struct optioninfo *oi, const char *arg, const char *arg2) { 88 static const struct typename { 89 adns_rrtype type; 90 const char *desc; 91 } typenames[]= { 92 /* enhanced versions */ 93 { adns_r_ns, "ns" }, 94 { adns_r_soa, "soa" }, 95 { adns_r_ptr, "ptr" }, 96 { adns_r_mx, "mx" }, 97 { adns_r_rp, "rp" }, 98 { adns_r_addr, "addr" }, 99 100 /* types with only one version */ 101 { adns_r_cname, "cname" }, 102 { adns_r_hinfo, "hinfo" }, 103 { adns_r_txt, "txt" }, 104 105 /* raw versions */ 106 { adns_r_a, "a" }, 107 { adns_r_ns_raw, "ns-" }, 108 { adns_r_soa_raw, "soa-" }, 109 { adns_r_ptr_raw, "ptr-" }, 110 { adns_r_mx_raw, "mx-" }, 111 { adns_r_rp_raw, "rp-" }, 112 113 { adns_r_none, 0 } 114 }; 115 116 const struct typename *tnp; 117 118 for (tnp=typenames; 119 tnp->type && strcmp(arg,tnp->desc); 120 tnp++); 121 if (!tnp->type) usageerr("unknown RR type %s",arg); 122 ov_type= tnp->type; 123 } 124 125 static void process_optarg(const char *arg, 126 const char *const **argv_p, 127 const char *value) { 128 const struct optioninfo *oip; 129 const char *arg2; 130 int invert; 131 132 if (arg[0] == '-' || arg[0] == '+') { 133 if (arg[0] == '-' && arg[1] == '-') { 134 if (!strncmp(arg,"--no-",5)) { 135 invert= 1; 136 oip= opt_findl(arg+5); 137 } else { 138 invert= 0; 139 oip= opt_findl(arg+2); 140 } 141 if (oip->type == ot_funcarg) { 142 arg= argv_p ? *++(*argv_p) : value; 143 if (!arg) usageerr("option --%s requires a value argument",oip->lopt); 144 arg2= 0; 145 } else if (oip->type == ot_funcarg2) { 146 assert(argv_p); 147 arg= *++(*argv_p); 148 arg2= arg ? *++(*argv_p) : 0; 149 if (!arg || !arg2) 150 usageerr("option --%s requires two more arguments", oip->lopt); 151 } else { 152 if (value) usageerr("option --%s does not take a value",oip->lopt); 153 arg= 0; 154 arg2= 0; 155 } 156 opt_do(oip,invert,arg,arg2); 157 } else if (arg[0] == '-' && arg[1] == 0) { 158 arg= argv_p ? *++(*argv_p) : value; 159 if (!arg) usageerr("option `-' must be followed by a domain"); 160 query_do(arg); 161 } else { /* arg[1] != '-', != '\0' */ 162 invert= (arg[0] == '+'); 163 ++arg; 164 while (*arg) { 165 oip= opt_finds(&arg); 166 if (oip->type == ot_funcarg) { 167 if (!*arg) { 168 arg= argv_p ? *++(*argv_p) : value; 169 if (!arg) usageerr("option -%s requires a value argument",oip->sopt); 170 } else { 171 if (value) usageerr("two values for option -%s given !",oip->sopt); 172 } 173 opt_do(oip,invert,arg,0); 174 arg= ""; 175 } else { 176 if (value) usageerr("option -%s does not take a value",oip->sopt); 177 opt_do(oip,invert,0,0); 178 } 179 } 180 } 181 } else { /* arg[0] != '-' */ 182 query_do(arg); 183 } 184 } 185 186 static void read_stdin(void) { 187 int anydone, r; 188 char *newline, *space; 189 190 anydone= 0; 191 while (!anydone || used) { 192 while (!(newline= memchr(buf,'\n',used))) { 193 if (used == avail) { 194 avail += 20; avail <<= 1; 195 buf= realloc(buf,avail); 196 if (!buf) sysfail("realloc stdin buffer",errno); 197 } 198 do { 199 r= read(0,buf+used,avail-used); 200 } while (r < 0 && errno == EINTR); 201 if (r == 0) { 202 if (used) { 203 /* fake up final newline */ 204 buf[used++]= '\n'; 205 r= 1; 206 } else { 207 ov_pipe= 0; 208 return; 209 } 210 } 211 if (r < 0) sysfail("read stdin",errno); 212 used += r; 213 } 214 *newline++= 0; 215 space= strchr(buf,' '); 216 if (space) *space++= 0; 217 process_optarg(buf,0,space); 218 used -= (newline-buf); 219 memmove(buf,newline,used); 220 anydone= 1; 221 } 222 } 223 224 int main(int argc, const char *const *argv) { 225 struct timeval *tv, tvbuf; 226 adns_query qu; 227 void *qun_v; 228 adns_answer *answer; 229 int r, maxfd; 230 fd_set readfds, writefds, exceptfds; 231 const char *arg; 232 233 ensure_adns_init(); 234 235 while ((arg= *++argv)) process_optarg(arg,&argv,0); 236 237 if (!ov_pipe && !ads) usageerr("no domains given, and -f/--pipe not used; try --help"); 238 239 for (;;) { 240 for (;;) { 241 qu= ov_asynch ? 0 : outstanding.head ? outstanding.head->qu : 0; 242 r= adns_check(ads,&qu,&answer,&qun_v); 243 if ((r == EAGAIN) || (r == EWOULDBLOCK)) break; 244 if (r == ESRCH) { if (!ov_pipe) goto x_quit; else break; } 245 assert(!r); 246 query_done(qun_v,answer); 247 } 248 maxfd= 0; 249 FD_ZERO(&readfds); 250 FD_ZERO(&writefds); 251 FD_ZERO(&exceptfds); 252 if (ov_pipe) { 253 maxfd= 1; 254 FD_SET(0,&readfds); 255 } 256 tv= 0; 257 adns_beforeselect(ads, &maxfd, &readfds,&writefds,&exceptfds, &tv,&tvbuf,0); 258 ADNS_CLEAR_ERRNO; 259 r= select(maxfd, &readfds,&writefds,&exceptfds, tv); 260 ADNS_CAPTURE_ERRNO; 261 if (r == -1) { 262 if (errno == EINTR) continue; 263 sysfail("select",errno); 264 } 265 adns_afterselect(ads, maxfd, &readfds,&writefds,&exceptfds, 0); 266 if (ov_pipe && FD_ISSET(0,&readfds)) read_stdin(); 267 } 268 x_quit: 269 if (fclose(stdout)) outerr(); 270 quitnow(rcode); 271 } 272