xref: /reactos/sdk/lib/3rdparty/adns/client/adh-main.c (revision 845faec4)
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