Import ezmlm-idx 0.40
[ezmlm] / ezmlm-return.c
index 3bc2421..7ca3fb2 100644 (file)
@@ -1,3 +1,7 @@
+/*$Id: ezmlm-return.c,v 1.26 1999/08/07 20:50:52 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include <sys/types.h>
+#include "direntry.h"
 #include "stralloc.h"
 #include "str.h"
 #include "env.h"
 #include "now.h"
 #include "cookie.h"
 #include "subscribe.h"
-#include "issub.h"
+#include "errtxt.h"
+#include "idx.h"
 
 #define FATAL "ezmlm-return: fatal: "
-void die_usage() { strerr_die1x(100,"ezmlm-return: usage: ezmlm-return dir"); }
-void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); }
+#define INFO "ezmlm-return: info: "
+void die_usage()
+{ strerr_die1x(100,"ezmlm-return: usage: ezmlm-return [-dD] dir"); }
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
 void die_badaddr()
 {
-  strerr_die2x(100,FATAL,"I do not accept messages at this address (#5.1.1)");
+  strerr_die2x(100,FATAL,ERR_BAD_RETURN_ADDRESS);
 }
 void die_trash()
 {
-  strerr_die1x(0,"ezmlm-return: info: trash address");
+  strerr_die2x(99,INFO,"trash address");
 }
 
 char outbuf[1024];
@@ -38,21 +45,37 @@ substdio ssin;
 char strnum[FMT_ULONG];
 char hash[COOKIE];
 char hashcopy[COOKIE];
+char *hashp = (char *) 0;
 unsigned long cookiedate;
+unsigned long addrno = 0L;
+unsigned long addrno1 = 0L;
+stralloc fndir = {0};
 stralloc fndate = {0};
 stralloc fndatenew = {0};
 stralloc fnhash = {0};
 stralloc fnhashnew = {0};
+void *psql = (void *) 0;
 
 stralloc quoted = {0};
+stralloc ddir = {0};
 char *sender;
+char *dir;
+char *workdir;
 
 void die_hashnew()
-{ strerr_die4sys(111,FATAL,"unable to write ",fnhashnew.s,": "); }
+{ strerr_die4sys(111,FATAL,ERR_WRITE,fnhashnew.s,": "); }
 void die_datenew()
-{ strerr_die4sys(111,FATAL,"unable to write ",fndatenew.s,": "); }
+{ strerr_die4sys(111,FATAL,ERR_WRITE,fndatenew.s,": "); }
 void die_msgin()
-{ strerr_die2sys(111,FATAL,"unable to read input: "); }
+{ strerr_die2sys(111,FATAL,ERR_READ_INPUT); }
+
+void makedir(s)
+char *s;
+{
+  if (mkdir(s,0755) == -1)
+    if (errno != error_exist)
+      strerr_die4x(111,FATAL,ERR_CREATE,s,": ");
+}
 
 void dowit(addr,when,bounce)
 char *addr;
@@ -60,16 +83,31 @@ unsigned long when;
 stralloc *bounce;
 {
   int fd;
+  unsigned int wpos;
+  unsigned long wdir,wfile;
 
-  if (!issub(addr)) return;
+  if (!issub(workdir,addr,(char *) 0,FATAL)) return;
 
-  if (!stralloc_copys(&fndate,"bounce/w")) die_nomem();
-  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,when))) die_nomem();
+  if (!stralloc_copys(&fndate,workdir)) die_nomem();
+  if (!stralloc_cats(&fndate,"/bounce/d")) die_nomem();
+  if (!stralloc_0(&fndate)) die_nomem();
+  fndate.s[fndate.len - 1] = '/';      /* replace '\0' */
+  wpos = fndate.len - 1;
+  wdir = when / 10000;
+  wfile = when - 10000 * wdir;
+  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,wdir))) die_nomem();
+  if (!stralloc_0(&fndate)) die_nomem();
+  makedir(fndate.s);
+  --fndate.len;                                /* remove terminal '\0' */
+  if (!stralloc_cats(&fndate,"/w")) die_nomem();
+  wpos = fndate.len - 1;
+  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,wfile))) die_nomem();
   if (!stralloc_cats(&fndate,".")) die_nomem();
-  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid())))
+       die_nomem();
   if (!stralloc_0(&fndate)) die_nomem();
   if (!stralloc_copy(&fndatenew,&fndate)) die_nomem();
-  fndatenew.s[7] = 'W';
+  fndatenew.s[wpos] = 'W';
 
   fd = open_trunc(fndatenew.s);
   if (fd == -1) die_datenew();
@@ -86,7 +124,7 @@ stralloc *bounce;
   if (close(fd) == -1) die_datenew(); /* NFS stupidity */
 
   if (rename(fndatenew.s,fndate.s) == -1)
-    strerr_die6sys(111,FATAL,"unable to rename ",fndatenew.s," to ",fndate.s,": ");
+    strerr_die6sys(111,FATAL,ERR_MOVE,fndatenew.s," to ",fndate.s,": ");
 }
 
 void doit(addr,msgnum,when,bounce)
@@ -97,16 +135,37 @@ stralloc *bounce;
 {
   int fd;
   int fdnew;
+  unsigned int pos;
+  unsigned long ddir,dfile;
 
-  if (!issub(addr)) return;
+  if (!issub(workdir,addr,(char *) 0,FATAL)) return;
 
-  if (!stralloc_copys(&fndate,"bounce/d")) die_nomem();
-  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,when))) die_nomem();
+  if (!stralloc_copys(&fndate,workdir)) die_nomem();
+  if (!stralloc_cats(&fndate,"/bounce/d")) die_nomem();
+  if (!stralloc_0(&fndate)) die_nomem();
+  makedir(fndate.s);
+  fndate.s[fndate.len-1] = '/';                /* replace terminal '\0' */
+  ddir = when / 10000;
+  dfile = when - 10000 * ddir;
+  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,ddir))) die_nomem();
+  if (!stralloc_copy(&fndir,&fndate)) die_nomem();
+  if (!stralloc_0(&fndir)) die_nomem();        /* make later if necessary (new addr)*/
+  if (!stralloc_cats(&fndate,"/d")) die_nomem();
+  pos = fndate.len - 2;
+  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,dfile))) die_nomem();
   if (!stralloc_cats(&fndate,".")) die_nomem();
-  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid())))
+        die_nomem();
+  if (addrno) {        /* so that pre-VERP bounces make a d... file per address */
+               /* for the first one we use the std-style fname */
+    if (!stralloc_cats(&fndate,".")) die_nomem();
+    if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,addrno))) die_nomem();
+  }
+  addrno++;    /* get ready for next */
   if (!stralloc_0(&fndate)) die_nomem();
   if (!stralloc_copy(&fndatenew,&fndate)) die_nomem();
-  fndatenew.s[7] = 'D';
+  fndatenew.s[pos] = '_';      /* fndate = bounce/d/nnnn/dmmmmmm */
+                               /* fndatenew = bounce/d/nnnn_dmmmmmm */
 
   fd = open_trunc(fndatenew.s);
   if (fd == -1) die_datenew();
@@ -123,11 +182,21 @@ stralloc *bounce;
   if (close(fd) == -1) die_datenew(); /* NFS stupidity */
 
   cookie(hash,"",0,"",addr,"");
-  if (!stralloc_copys(&fnhash,"bounce/h")) die_nomem();
-  if (!stralloc_catb(&fnhash,hash,COOKIE)) die_nomem();
+  if (!stralloc_copys(&fnhash,workdir)) die_nomem();
+  if (!stralloc_cats(&fnhash,"/bounce/h")) die_nomem();
+  if (!stralloc_0(&fnhash)) die_nomem();
+  makedir(fnhash.s);
+  fnhash.s[fnhash.len - 1] = '/';              /* replace terminal '\0' */
+  if (!stralloc_catb(&fnhash,hash,1)) die_nomem();
+  if (!stralloc_0(&fnhash)) die_nomem();
+  makedir(fnhash.s);
+  --fnhash.len;                                        /* remove terminal '\0' */
+  if (!stralloc_cats(&fnhash,"/h")) die_nomem();
+  pos = fnhash.len - 1;
+  if (!stralloc_catb(&fnhash,hash+1,COOKIE-1)) die_nomem();
   if (!stralloc_0(&fnhash)) die_nomem();
   if (!stralloc_copy(&fnhashnew,&fnhash)) die_nomem();
-  fnhashnew.s[7] = 'H';
+  fnhashnew.s[pos] = 'H';
 
   fdnew = open_trunc(fnhashnew.s);
   if (fdnew == -1) die_hashnew();
@@ -136,9 +205,10 @@ stralloc *bounce;
   fd = open_read(fnhash.s);
   if (fd == -1) {
     if (errno != error_noent)
-      strerr_die4sys(111,FATAL,"unable to read ",fnhash.s,": ");
+      strerr_die4sys(111,FATAL,ERR_READ,fnhash.s,": ");
+    makedir(fndir.s);
     if (rename(fndatenew.s,fndate.s) == -1)
-      strerr_die6sys(111,FATAL,"unable to rename ",fndatenew.s," to ",fndate.s,": ");
+      strerr_die6sys(111,FATAL,ERR_MOVE,fndatenew.s," to ",fndate.s,": ");
   }
   else {
     substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
@@ -148,7 +218,7 @@ stralloc *bounce;
     }
     close(fd);
     if (unlink(fndatenew.s) == -1)
-      strerr_die4sys(111,FATAL,"unable to unlink ",fndatenew.s,": ");
+      strerr_die4sys(111,FATAL,ERR_DELETE,fndatenew.s,": ");
   }
   if (substdio_puts(&ssout,"   ") == -1) die_hashnew();
   if (substdio_put(&ssout,strnum,fmt_ulong(strnum,msgnum)) == -1) die_hashnew();
@@ -158,7 +228,7 @@ stralloc *bounce;
   if (close(fdnew) == -1) die_hashnew(); /* NFS stupidity */
 
   if (rename(fnhashnew.s,fnhash.s) == -1)
-    strerr_die6sys(111,FATAL,"unable to rename ",fnhashnew.s," to ",fnhash.s,": ");
+    strerr_die6sys(111,FATAL,ERR_MOVE,fnhashnew.s," to ",fnhash.s,": ");
 }
 
 stralloc bounce = {0};
@@ -167,14 +237,11 @@ stralloc header = {0};
 stralloc intro = {0};
 stralloc failure = {0};
 stralloc paragraph = {0};
+int flagmasterbounce = 0;
 int flaghaveheader;
 int flaghaveintro;
 
 stralloc key = {0};
-stralloc inhost = {0};
-stralloc outhost = {0};
-stralloc inlocal = {0};
-stralloc outlocal = {0};
 
 char msginbuf[1024];
 substdio ssmsgin;
@@ -183,16 +250,22 @@ void main(argc,argv)
 int argc;
 char **argv;
 {
-  char *dir;
-  char *host;
   char *local;
   char *action;
+  char *def;
+  char *ret;
+  char *cp;
   unsigned long msgnum;
   unsigned long cookiedate;
   unsigned long when;
+  unsigned long listno = 0L;
   int match;
-  int i;
+  unsigned int i;
+  int flagdig = 0;
+  int flagmaster = 0;
+  int flagreceipt = 0;
   int fdlock;
+  register char ch;
 
   umask(022);
   sig_pipeignore();
@@ -200,104 +273,158 @@ char **argv;
 
   dir = argv[1];
   if (!dir) die_usage();
+  if (*dir == '-') {                   /* for normal use */
+    if (dir[1] == 'd') {
+      flagdig = 1;
+    } else if (dir[1] == 'D') {
+      flagdig = 0;
+    } else
+      die_usage();
+    dir = argv[2];
+    if (!dir) die_usage();
+  }
 
   sender = env_get("SENDER");
-  if (!sender) strerr_die2x(100,FATAL,"SENDER not set");
+  if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER);
   local = env_get("LOCAL");
-  if (!local) strerr_die2x(100,FATAL,"LOCAL not set");
-  host = env_get("HOST");
-  if (!host) strerr_die2x(100,FATAL,"HOST not set");
+  if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL);
+  def = env_get("DEFAULT");            /* qmail-1.02 */
 
   if (chdir(dir) == -1)
-    strerr_die4sys(111,FATAL,"unable to switch to ",dir,": ");
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
 
   switch(slurp("key",&key,32)) {
     case -1:
-      strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: ");
+      strerr_die4sys(111,FATAL,ERR_READ,dir,"/key: ");
     case 0:
-      strerr_die3x(100,FATAL,dir,"/key does not exist");
+      strerr_die4x(100,FATAL,dir,"/key",ERR_NOEXIST);
   }
-  getconf_line(&inhost,"inhost",1,FATAL,dir);
-  getconf_line(&inlocal,"inlocal",1,FATAL,dir);
-  getconf_line(&outhost,"outhost",1,FATAL,dir);
-  getconf_line(&outlocal,"outlocal",1,FATAL,dir);
-
-  if (inhost.len != str_len(host)) die_badaddr();
-  if (case_diffb(inhost.s,inhost.len,host)) die_badaddr();
-  if (inlocal.len > str_len(local)) die_badaddr();
-  if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr();
+  workdir = dir;
+  action = def;
 
-  action = local + inlocal.len;
-
-  if (!str_start(action,"-return-")) die_badaddr();
-  action += 8;
+    if (str_start(action,"receipt-")) {
+      flagreceipt = 1;
+      action += 8;
+    }
+    ch = *action;              /* -d -digest, -m -master, -g -getmaster */
+    if (ch && action[1] == '-') {
+      switch (ch) {
+       case 'g': flagmaster = 1; flagdig = 1; action += 2; break;
+       case 'm': flagmaster = 1; action += 2; break;
+       default: break;
+      }
+    }
+  if (flagdig) {
+    if (!stralloc_copys(&ddir,dir)) die_nomem();
+    if (!stralloc_cats(&ddir,"/digest")) die_nomem();
+    if (!stralloc_0(&ddir)) die_nomem();
+    workdir = ddir.s;
+  }
 
   if (!*action) die_trash();
 
-  if (str_start(action,"probe-")) {
-    action += 6;
-    action += scan_ulong(action,&cookiedate);
-    if (now() - cookiedate > 3000000) die_trash();
-    if (*action++ != '.') die_trash();
-    i = str_chr(action,'-');
-    if (i != COOKIE) die_trash();
-    byte_copy(hashcopy,COOKIE,action);
-    action += COOKIE;
-    if (*action++ != '-') die_trash();
-    i = str_rchr(action,'=');
-    if (!stralloc_copyb(&line,action,i)) die_nomem();
-    if (action[i]) {
-      if (!stralloc_cats(&line,"@")) die_nomem();
-      if (!stralloc_cats(&line,action + i + 1)) die_nomem();
-    }
-    if (!stralloc_0(&line)) die_nomem();
-    strnum[fmt_ulong(strnum,cookiedate)] = 0;
-    cookie(hash,key.s,key.len,strnum,line.s,"P");
-    if (byte_diff(hash,COOKIE,hashcopy)) die_trash();
-
-    if (subscribe(line.s,0) == 1) log("-probe",line.s);
-    _exit(0);
+  if (flagreceipt || flagmaster)                       /* check cookie */
+    if (str_chr(action,'-') == COOKIE) {
+      action[COOKIE] = '\0';
+      hashp = action;
+      action += COOKIE + 1;
   }
 
-  fdlock = open_append("lockbounce");
-  if (fdlock == -1)
-    strerr_die4sys(111,FATAL,"unable to open ",dir,"/lockbounce: ");
-  if (lock_ex(fdlock) == -1)
-    strerr_die4sys(111,FATAL,"unable to lock ",dir,"/lockbounce: ");
-
-  if (str_start(action,"warn-")) {
-    action += 5;
-    action += scan_ulong(action,&cookiedate);
-    if (now() - cookiedate > 3000000) die_trash();
-    if (*action++ != '.') die_trash();
-    i = str_chr(action,'-');
-    if (i != COOKIE) die_trash();
-    byte_copy(hashcopy,COOKIE,action);
-    action += COOKIE;
-    if (*action++ != '-') die_trash();
-    i = str_rchr(action,'=');
-    if (!stralloc_copyb(&line,action,i)) die_nomem();
-    if (action[i]) {
-      if (!stralloc_cats(&line,"@")) die_nomem();
-      if (!stralloc_cats(&line,action + i + 1)) die_nomem();
+  if (!flagreceipt) {
+    if (!flagmaster && str_start(action,"probe-")) {
+      action += 6;
+      action += scan_ulong(action,&cookiedate);
+      if (now() - cookiedate > 3000000) die_trash();
+      if (*action++ != '.') die_trash();
+      i = str_chr(action,'-');
+      if (i != COOKIE) die_trash();
+      byte_copy(hashcopy,COOKIE,action);
+      action += COOKIE;
+      if (*action++ != '-') die_trash();
+      i = str_rchr(action,'=');
+      if (!stralloc_copyb(&line,action,i)) die_nomem();
+      if (action[i]) {
+       if (!stralloc_cats(&line,"@")) die_nomem();
+       if (!stralloc_cats(&line,action + i + 1)) die_nomem();
+      }
+      if (!stralloc_0(&line)) die_nomem();
+      strnum[fmt_ulong(strnum,cookiedate)] = 0;
+      cookie(hash,key.s,key.len,strnum,line.s,"P");
+      if (byte_diff(hash,COOKIE,hashcopy)) die_trash();
+
+      (void) subscribe(workdir,line.s,0,"","-probe",1,-1,(char *) 0,FATAL);
+      _exit(99);
     }
+
+    if (!stralloc_copys(&line,workdir)) die_nomem();
+    if (!stralloc_cats(&line,"/lockbounce")) die_nomem();
     if (!stralloc_0(&line)) die_nomem();
-    strnum[fmt_ulong(strnum,cookiedate)] = 0;
-    cookie(hash,key.s,key.len,strnum,line.s,"W");
-    if (byte_diff(hash,COOKIE,hashcopy)) die_trash();
 
-    if (slurpclose(0,&bounce,1024) == -1) die_msgin();
-    dowit(line.s,when,&bounce);
-    _exit(0);
+    fdlock = open_append(line.s);
+    if (fdlock == -1)
+      strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
+    if (lock_ex(fdlock) == -1)
+      strerr_die4sys(111,FATAL,ERR_OBTAIN,line.s,": ");
+
+    if (!flagmaster && str_start(action,"warn-")) {
+      action += 5;
+      action += scan_ulong(action,&cookiedate);
+      if (now() - cookiedate > 3000000) die_trash();
+      if (*action++ != '.') die_trash();
+      i = str_chr(action,'-');
+      if (i != COOKIE) die_trash();
+      byte_copy(hashcopy,COOKIE,action);
+      action += COOKIE;
+      if (*action++ != '-') die_trash();
+      i = str_rchr(action,'=');
+      if (!stralloc_copyb(&line,action,i)) die_nomem();
+      if (action[i]) {
+        if (!stralloc_cats(&line,"@")) die_nomem();
+        if (!stralloc_cats(&line,action + i + 1)) die_nomem();
+      }
+      if (!stralloc_0(&line)) die_nomem();
+      strnum[fmt_ulong(strnum,cookiedate)] = 0;
+      cookie(hash,key.s,key.len,strnum,line.s,"W");
+      if (byte_diff(hash,COOKIE,hashcopy)) die_trash();
+
+      if (slurpclose(0,&bounce,1024) == -1) die_msgin();
+      dowit(line.s,when,&bounce);
+      _exit(99);
+    }
   }
-
   action += scan_ulong(action,&msgnum);
-  if (*action != '-') die_badaddr();
-  ++action;
+  if (*action++ != '-') die_badaddr();
+  cp = action;
+  if (*action >= '0' && *action <= '9') {              /* listno */
+    action += scan_ulong(action,&listno);
+    listno++;                                  /* logging is 1-53, not 0-52 */
+  }
 
-  if (*action) {
-    if (slurpclose(0,&bounce,1024) == -1) die_msgin();
+  if (hashp) {         /* scrap bad cookies */
+      if ((ret = checktag(workdir,msgnum,0L,"x",(char *) 0,hashp))) {
+        if (*ret)
+         strerr_die2x(111,FATAL,*ret);
+       else
+         die_trash();
+      } else if (flagreceipt) {
+       if (!(ret = logmsg(dir,msgnum,listno,0L,5))) {
+         closesql();
+         strerr_die6x(99,INFO,"receipt:",cp," [",hashp,"]");
+       }
+       if (*ret) strerr_die2x(111,FATAL,ret);
+       else strerr_die2x(0,INFO,ERR_DONE);
+      } else if (*action) {    /* post VERP master bounce */
+       if ((ret = logmsg(dir,msgnum,listno,0L,-1))) {
+         closesql();
+         strerr_die4x(0,INFO,"bounce [",hashp,"]");
+       }
+       if (*ret) strerr_die2x(111,FATAL,ret);
+       else strerr_die2x(99,INFO,ERR_DONE);
+      }
+   } else if (flagreceipt || flagmaster)
+       die_badaddr();
 
+  if (*action) {
     i = str_rchr(action,'=');
     if (!stralloc_copyb(&line,action,i)) die_nomem();
     if (action[i]) {
@@ -305,11 +432,12 @@ char **argv;
       if (!stralloc_cats(&line,action + i + 1)) die_nomem();
     }
     if (!stralloc_0(&line)) die_nomem();
+    if (slurpclose(0,&bounce,1024) == -1) die_msgin();
     doit(line.s,msgnum,when,&bounce);
-    _exit(0);
+    _exit(99);
   }
 
-  /* pre-VERP bounce, in QSBMF format */
+  /* pre-VERP bounce, in QSBMF format. Receipts are never pre-VERP */
 
   substdio_fdbuf(&ssmsgin,read,0,msginbuf,sizeof(msginbuf));
 
@@ -332,6 +460,8 @@ char **argv;
     }
 
     if (!flaghaveintro) {
+      if (paragraph.s[0] == '-' && paragraph.s[1] == '-')
+        continue;              /* skip MIME boundary if it exists */
       if (paragraph.len < 15) die_trash();
       if (str_diffn(paragraph.s,"Hi. This is the",15)) die_trash();
       if (!stralloc_copy(&intro,&paragraph)) die_nomem();
@@ -355,10 +485,23 @@ char **argv;
       if (!stralloc_copyb(&line,failure.s + 1,i - 3)) die_nomem();
       if (byte_chr(line.s,line.len,'\0') == line.len) {
         if (!stralloc_0(&line)) die_nomem();
-        doit(line.s,msgnum,when,&bounce);
+        if (flagmaster) {                              /* bounced msg slave! */
+         if ((i = str_rchr(line.s,'@')) >= 5) {        /* 00_52@host */
+           line.s[i] = '\0';                           /* 00_52 */
+           (void) scan_ulong(line.s + i - 5,&listno);
+             if ((ret = logmsg(dir,msgnum,listno + 1,0L,-1)) && *ret)
+               strerr_die2x(111,FATAL,ret);
+           strerr_warn3(INFO,"bounce ",line.s + i - 5,(struct strerr *) 0);
+           flagmasterbounce = 1;
+         }
+       } else
+         doit(line.s,msgnum,when,&bounce);
       }
     }
   }
-
-  _exit(0);
+  closesql();
+  if (flagmasterbounce)
+    strerr_die3x(0,"[",hashp,"]");
+  else
+    _exit(99);
 }