chiark / gitweb /
enums: Add `sizeforce' member value
[adns.git] / client / adh-main.c
index 33b1f59b9b2431337d753b7ca9643f4c0cc1ecbf..c77aa5d4847beacf938be05fd2f44754b6281860 100644 (file)
@@ -4,16 +4,16 @@
  *   main program and useful subroutines
  */
 /*
- *  This file is
- *    Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk>
- *
- *  It is part of adns, which is
- *    Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk>
- *    Copyright (C) 1999 Tony Finch <dot@dotat.at>
+ *  This file is part of adns, which is
+ *    Copyright (C) 1997-2000,2003,2006,2014  Ian Jackson
+ *    Copyright (C) 2014  Mark Wooding
+ *    Copyright (C) 1999-2000,2003,2006  Tony Finch
+ *    Copyright (C) 1991 Massachusetts Institute of Technology
+ *  (See the file INSTALL for full details.)
  *  
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2, or (at your option)
+ *  the Free Software Foundation; either version 3, or (at your option)
  *  any later version.
  *  
  *  This program is distributed in the hope that it will be useful,
  *  GNU General Public License for more details.
  *  
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software Foundation,
- *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
+ *  along with this program; if not, write to the Free Software Foundation.
  */
 
 #include "adnshost.h"
 
+int rcode;
+const char *config_text;
+
+static int used, avail;
+static char *buf;
+
+void quitnow(int rc) {
+  if (ads) adns_finish(ads);
+  free(buf);
+  free(ov_id);
+  exit(rc);
+}
+
 void sysfail(const char *what, int errnoval) {
   fprintf(stderr,"adnshost failed: %s: %s\n",what,strerror(errnoval));
-  exit(10);
+  quitnow(10);
 }
 
 void usageerr(const char *fmt, ...) {
@@ -40,19 +52,13 @@ void usageerr(const char *fmt, ...) {
   vfprintf(stderr,fmt,al);
   va_end(al);
   putc('\n',stderr);
-  exit(11);
+  quitnow(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");
-  ensure_adns_init();
-  query_do(domain);
-}
-
 void *xmalloc(size_t sz) {
   void *p;
 
@@ -68,62 +74,173 @@ char *xstrsave(const char *str) {
   return p;
 }
 
-void of_type(const struct optioninfo *oi, const char *arg) { abort(); }
+void of_config(const struct optioninfo *oi, const char *arg, const char *arg2) {
+  config_text= arg;
+}
 
-int rcode;
+void of_type(const struct optioninfo *oi, const char *arg, const char *arg2) {
+  static const struct typename {
+    adns_rrtype type;
+    const char *desc;
+  } typenames[]= {
+    /* enhanced versions */
+    { adns_r_ns,     "ns"     },
+    { adns_r_soa,    "soa"    },
+    { adns_r_ptr,    "ptr"    },
+    { adns_r_mx,     "mx"     },
+    { adns_r_rp,     "rp"     },
+    { adns_r_srv,    "srv"    },
+    { adns_r_addr,   "addr"   },
+    
+    /* types with only one version */
+    { adns_r_cname,  "cname"  },
+    { adns_r_hinfo,  "hinfo"  },
+    { adns_r_txt,    "txt"    },
+    
+    /* raw versions */
+    { adns_r_a,        "a"    },
+    { adns_r_aaaa,     "aaaa" },
+    { adns_r_ns_raw,   "ns-"  },
+    { adns_r_soa_raw,  "soa-" },
+    { adns_r_ptr_raw,  "ptr-" },
+    { adns_r_mx_raw,   "mx-"  },
+    { adns_r_rp_raw,   "rp-"  },
+    { adns_r_srv_raw,  "srv-" },
 
-void setnonblock(int fd, int nonblock) { }
+    { adns_r_none, 0 }
+  };
 
-static void read_query(void) { abort(); }
+  const struct typename *tnp;
+  unsigned long unknowntype;
+  char *ep;
 
-int main(int argc, const char *const *argv) {
-  const char *arg;
+  if (strlen(arg) > 4 && !memcmp(arg,"type",4) &&
+      (unknowntype= strtoul(arg+4, &ep, 10), !*ep) && unknowntype < 65536) {
+    ov_type= unknowntype | adns_r_unknown;
+    return;
+  }
+
+  for (tnp=typenames;
+       tnp->type && strcmp(arg,tnp->desc);
+       tnp++);
+  if (!tnp->type) usageerr("unknown RR type %s",arg);
+  ov_type= tnp->type;
+}
+
+static void process_optarg(const char *arg,
+                          const char *const **argv_p,
+                          const char *value) {
   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] == '-') {
-      if (arg[1] == '-') {
+  const char *arg2;
+  int invert;
+
+  if (arg[0] == '-' || arg[0] == '+') {
+    if (arg[0] == '-' && arg[1] == '-') {
+      if (!strncmp(arg,"--no-",5)) {
+       invert= 1;
+       oip= opt_findl(arg+5);
+      } else {
+       invert= 0;
        oip= opt_findl(arg+2);
+      }
+      if (oip->type == ot_funcarg) {
+       arg= argv_p ? *++(*argv_p) : value;
+       if (!arg) usageerr("option --%s requires a value argument",oip->lopt);
+       arg2= 0;
+      } else if (oip->type == ot_funcarg2) {
+       assert(argv_p);
+       arg= *++(*argv_p);
+       arg2= arg ? *++(*argv_p) : 0;
+       if (!arg || !arg2)
+         usageerr("option --%s requires two more arguments", oip->lopt);
+      } else {
+       if (value) usageerr("option --%s does not take a value",oip->lopt);
+       arg= 0;
+       arg2= 0;
+      }
+      opt_do(oip,invert,arg,arg2);
+    } else if (arg[0] == '-' && arg[1] == 0) {
+      arg= argv_p ? *++(*argv_p) : value;
+      if (!arg) usageerr("option `-' must be followed by a domain");
+      query_do(arg);
+    } else { /* arg[1] != '-', != '\0' */
+      invert= (arg[0] == '+');
+      ++arg;
+      while (*arg) {
+       oip= opt_finds(&arg);
        if (oip->type == ot_funcarg) {
-         arg= *++argv;
-         if (!arg) usageerr("option --%s requires a value argument",oip->lopt);
-       } else {
-         arg= 0;
-       }
-       opt_do(oip,arg);
-      } else if (arg[1] == 0) {
-       arg= *++argv;
-       if (!arg) usageerr("option `-' must be followed by a domain");
-       domain_do_arg(arg);
-      } else { /* arg[1] != '-', != '\0' */
-       ++arg;
-       while (*arg) {
-         oip= opt_finds(&arg);
-         if (oip->type == ot_funcarg) {
-           if (!*arg) {
-             arg= *++argv;
-             if (!arg) usageerr("option -%s requires a value argument",oip->sopt);
-           }
-           arg= "";
+         if (!*arg) {
+           arg= argv_p ? *++(*argv_p) : value;
+           if (!arg) usageerr("option -%s requires a value argument",oip->sopt);
          } else {
-           arg= 0;
+           if (value) usageerr("two values for option -%s given !",oip->sopt);
          }
-         opt_do(oip,arg);
+         opt_do(oip,invert,arg,0);
+         arg= "";
+       } else {
+         if (value) usageerr("option -%s does not take a value",oip->sopt);
+         opt_do(oip,invert,0,0);
        }
       }
-    } else { /* arg[0] != '-' */
-      domain_do_arg(arg);
     }
+  } else { /* arg[0] != '-' */
+    query_do(arg);
   }
+}
+    
+static void read_stdin(void) {
+  int anydone, r;
+  char *newline, *space;
+
+  anydone= 0;
+  while (!anydone || used) {
+    while (!(newline= memchr(buf,'\n',used))) {
+      if (used == avail) {
+       avail += 20; avail <<= 1;
+       buf= realloc(buf,avail);
+       if (!buf) sysfail("realloc stdin buffer",errno);
+      }
+      do {
+       r= read(0,buf+used,avail-used);
+      } while (r < 0 && errno == EINTR);
+      if (r == 0) {
+       if (used) {
+         /* fake up final newline */
+         buf[used++]= '\n';
+         r= 1;
+       } else {
+         ov_pipe= 0;
+         return;
+       }
+      }
+      if (r < 0) sysfail("read stdin",errno);
+      used += r;
+    }
+    *newline++= 0;
+    space= strchr(buf,' ');
+    if (space) *space++= 0;
+    process_optarg(buf,0,space);
+    used -= (newline-buf);
+    memmove(buf,newline,used);
+    anydone= 1;
+  }
+}
+
+int main(int argc, const char *const *argv) {
+  struct timeval *tv, tvbuf;
+  adns_query qu;
+  void *qun_v;
+  adns_answer *answer;
+  int r, maxfd;
+  fd_set readfds, writefds, exceptfds;
+  const char *arg;
+  
+  while ((arg= *++argv)) process_optarg(arg,&argv,0);
 
   if (!ov_pipe && !ads) usageerr("no domains given, and -f/--pipe not used; try --help");
 
+  ensure_adns_init();
+
   for (;;) {
     for (;;) {
       qu= ov_asynch ? 0 : outstanding.head ? outstanding.head->qu : 0;
@@ -149,9 +266,9 @@ int main(int argc, const char *const *argv) {
       sysfail("select",errno);
     }
     adns_afterselect(ads, maxfd, &readfds,&writefds,&exceptfds, 0);
-    if (ov_pipe && FD_ISSET(0,&readfds)) read_query();
+    if (ov_pipe && FD_ISSET(0,&readfds)) read_stdin();
   }
 x_quit:
   if (fclose(stdout)) outerr();
-  exit(rcode);
+  quitnow(rcode);
 }