pristine/ext_todo-20030105.patch
changeset 1 b375914441b2
equal deleted inserted replaced
0:5766d031ef25 1:b375914441b2
       
     1 diff -uN qmail-1.03/EXTTODO qmail-exttodo/EXTTODO
       
     2 --- qmail-1.03/EXTTODO	Thu Jan  1 01:00:00 1970
       
     3 +++ qmail-exttodo/EXTTODO	Sun Jan  5 22:12:01 2003
       
     4 @@ -0,0 +1,114 @@
       
     5 +EXTTODO by Claudio Jeker <jeker@n-r-g.com> and 
       
     6 +Andre Oppermann <opi@nrg4u.com>
       
     7 +(c) 1998,1999,2000,2001,2002 Internet Business Solutions Ltd.
       
     8 +
       
     9 +The EXTTODO patch is a part of the qmail-ldap patch.
       
    10 +This patches for qmail come with NO WARRANTY.
       
    11 +
       
    12 +These patches are under the BSD license.
       
    13 +
       
    14 +RELEASE: 5. Jan. 2003
       
    15 +
       
    16 +EXTTODO:
       
    17 +======================
       
    18 +
       
    19 +TOC:
       
    20 + WHAT DOES IT DO
       
    21 + INSTALL
       
    22 + CONFIG FILES
       
    23 + SETUP
       
    24 + BIG PICTURE
       
    25 +
       
    26 +NEWS:
       
    27 + 
       
    28 + This is the first release of the EXTTODO patch.
       
    29 +
       
    30 +================================================================================
       
    31 +
       
    32 +WHAT DOES IT DO
       
    33 +
       
    34 + The exttodo patch addresses a problem known as the silly qmail (queue)
       
    35 + problem. This problem is found only on system with high injection rates.
       
    36 +
       
    37 + qmail with a big local and remote concurrency could deliver a tremendous 
       
    38 + amount of messages but normally this can not be achieved because qmail-send
       
    39 + becomes a bottleneck on those high volumes servers.
       
    40 + qmail-send preprocesses all new messages before distributing them for local
       
    41 + or remote delivering. In one run qmail-send does one todo run but has the 
       
    42 + ability to close multiple jobs. Because of this layout qmail-send can not 
       
    43 + feed all the new available (local/remote) delivery slots and therefor it is 
       
    44 + not possible to achieve the maximum throughput.
       
    45 + This would be a minor problem if one qmail-send run could be done in extreme
       
    46 + short time but because of many file system calls (fsync and (un)link) a todo
       
    47 + run is expensive and throttles the throughput.
       
    48 +
       
    49 + The exttodo patch tries to solve the problem by moving the todo routine into 
       
    50 + an external program. This reduces the run time in qmail-send.
       
    51 +
       
    52 + exttodo adds a new program to qmail called qmail-todo. qmail-todo prepares
       
    53 + incoming messages for local and remote delivering (by creating info/<messid>
       
    54 + local/<messid> and remote/<messid> and removing todo/<messid>). See also
       
    55 + INTERNALS. As next qmail-todo transmits the <messid> to qmail-send which will
       
    56 + add this message into the priority queue which schedules the message for 
       
    57 + delivery. 
       
    58 +
       
    59 +INSTALL
       
    60 +
       
    61 + To enable the exttodo patch you need to define EXTERNAL_TODO while compiling
       
    62 + qmail(-ldap) this can be done with the -D flag of cc (e.g. cc -DEXTERNAL_TODO).
       
    63 +
       
    64 + NOTE: the exttodo patch can also be used on qmail systems without the 
       
    65 + qmail-ldap patch.
       
    66 + 
       
    67 +================================================================================
       
    68 +
       
    69 +CONFIG FILES
       
    70 +
       
    71 + No additional control files are used or needed.
       
    72 +
       
    73 +================================================================================
       
    74 +
       
    75 +SETUP
       
    76 +
       
    77 + qmail-todo will be started by qmail-start and therefor no additional setup
       
    78 + is needed.
       
    79 +
       
    80 + To verify that exttodo is running just check if qmail-todo is running.
       
    81 +
       
    82 +================================================================================
       
    83 +
       
    84 +BIG PICTURE
       
    85 +
       
    86 +               +-------+   +-------+
       
    87 +               | clean |   | clean |
       
    88 +               +--0-1--+   +--0-1--+       +-----------+
       
    89 +         trigger  ^ |         ^ |        +->0,1 lspawn |
       
    90 +            |     | v         | v       /  +-----------+
       
    91 + +-------+  v  +--2-3--+   +--5-6--+   /
       
    92 + |       |  |  |       0<--7     1,2<-+
       
    93 + | queue |--+--| todo  |   | send  |
       
    94 + |       |  |  |       1-->8     3,4<-+
       
    95 + +-------+     +-------+   +---0---+   \
       
    96 +                               |        \  +-----------+
       
    97 +                               v         +->0,1 rspwan |
       
    98 +                           +---0---+       +-----------+
       
    99 +                           | logger|
       
   100 +                           +-------+
       
   101 +
       
   102 +Communication between qmail-send and qmail-todo
       
   103 +
       
   104 +todo -> send:
       
   105 +   D[LRB]<mesgid>\0
       
   106 +          Start delivery for new message with id <messid>.
       
   107 +          the character L, R or B defines the type
       
   108 +          of delivery, local, remote or both respectively.
       
   109 +   L<string>\0
       
   110 +          Dump string to the logger without adding additional \n or similar.
       
   111 +send -> todo:
       
   112 +   H      Got a SIGHUP reread ~/control/locals and ~/control/virtualdomains
       
   113 +   X      Quit ASAP.
       
   114 +
       
   115 +qmail-todo sends "\0" terminated messages whereas qmail-send just send one
       
   116 +character to qmail-todo.
       
   117 +
       
   118 +
       
   119 diff -uN qmail-1.03/EXTTODO-INFO qmail-exttodo/EXTTODO-INFO
       
   120 --- qmail-1.03/EXTTODO-INFO	Thu Jan  1 01:00:00 1970
       
   121 +++ qmail-exttodo/EXTTODO-INFO	Tue Apr 30 16:49:02 2002
       
   122 @@ -0,0 +1,11 @@
       
   123 +Files modified:
       
   124 +Makefile
       
   125 +EXTTODO
       
   126 +FILES
       
   127 +TARGETS
       
   128 +qmail-send.c
       
   129 +qmail-todo.c
       
   130 +qmail-start.c
       
   131 +hier.c
       
   132 +install-big.c
       
   133 +
       
   134 diff -uN qmail-1.03/FILES qmail-exttodo/FILES
       
   135 --- qmail-1.03/FILES	Mon Jun 15 12:53:16 1998
       
   136 +++ qmail-exttodo/FILES	Mon Apr 22 13:59:28 2002
       
   137 @@ -431,3 +431,4 @@
       
   138  tcp-environ.5
       
   139  constmap.h
       
   140  constmap.c
       
   141 +qmail-todo.c
       
   142 diff -uN qmail-1.03/Makefile qmail-exttodo/Makefile
       
   143 --- qmail-1.03/Makefile	Mon Jun 15 12:53:16 1998
       
   144 +++ qmail-exttodo/Makefile	Mon Apr 22 14:55:59 2002
       
   145 @@ -1,5 +1,7 @@
       
   146  # Don't edit Makefile! Use conf-* for configuration.
       
   147  
       
   148 +DEFINES=-DEXTERNAL_TODO # use to enable external todo
       
   149 +
       
   150  SHELL=/bin/sh
       
   151  
       
   152  default: it
       
   153 @@ -703,7 +705,7 @@
       
   154  
       
   155  hier.o: \
       
   156  compile hier.c auto_qmail.h auto_split.h auto_uids.h fmt.h fifo.h
       
   157 -	./compile hier.c
       
   158 +	./compile $(DEFINES) hier.c
       
   159  
       
   160  home: \
       
   161  home.sh conf-qmail
       
   162 @@ -755,7 +757,7 @@
       
   163  install-big.o: \
       
   164  compile install-big.c auto_qmail.h auto_split.h auto_uids.h fmt.h \
       
   165  fifo.h
       
   166 -	./compile install-big.c
       
   167 +	./compile $(DEFINES) install-big.c
       
   168  
       
   169  install.o: \
       
   170  compile install.c substdio.h strerr.h error.h open.h readwrite.h \
       
   171 @@ -808,7 +810,7 @@
       
   172  forward preline condredirect bouncesaying except maildirmake \
       
   173  maildir2mbox maildirwatch qail elq pinq idedit install-big install \
       
   174  instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
       
   175 -binm3 binm3+df
       
   176 +binm3 binm3+df qmail-todo
       
   177  
       
   178  load: \
       
   179  make-load warn-auto.sh systype
       
   180 @@ -1509,7 +1511,7 @@
       
   181  scan.h case.h auto_qmail.h trigger.h newfield.h stralloc.h quote.h \
       
   182  qmail.h substdio.h qsutil.h prioq.h datetime.h gen_alloc.h constmap.h \
       
   183  fmtqfn.h readsubdir.h direntry.h
       
   184 -	./compile qmail-send.c
       
   185 +	./compile $(DEFINES) qmail-send.c
       
   186  
       
   187  qmail-showctl: \
       
   188  load qmail-showctl.o auto_uids.o control.o open.a getln.a stralloc.a \
       
   189 @@ -1574,7 +1576,7 @@
       
   190  
       
   191  qmail-start.o: \
       
   192  compile qmail-start.c fd.h prot.h exit.h fork.h auto_uids.h
       
   193 -	./compile qmail-start.c
       
   194 +	./compile $(DEFINES) qmail-start.c
       
   195  
       
   196  qmail-tcpok: \
       
   197  load qmail-tcpok.o open.a lock.a strerr.a substdio.a error.a str.a \
       
   198 @@ -1605,6 +1607,20 @@
       
   199  compile qmail-tcpto.c substdio.h subfd.h substdio.h auto_qmail.h \
       
   200  fmt.h ip.h lock.h error.h exit.h datetime.h now.h datetime.h
       
   201  	./compile qmail-tcpto.c
       
   202 +
       
   203 +qmail-todo: \
       
   204 +load qmail-todo.o control.o constmap.o trigger.o fmtqfn.o now.o \
       
   205 +readsubdir.o case.a ndelay.a getln.a sig.a open.a stralloc.a alloc.a \
       
   206 +substdio.a error.a str.a fs.a auto_qmail.o auto_split.o
       
   207 +	./load qmail-todo control.o constmap.o trigger.o fmtqfn.o now.o \
       
   208 +	readsubdir.o case.a ndelay.a getln.a sig.a open.a stralloc.a \
       
   209 +	alloc.a substdio.a error.a str.a fs.a auto_qmail.o auto_split.o
       
   210 +
       
   211 +qmail-todo.o: \
       
   212 +compile alloc.h auto_qmail.h byte.h constmap.h control.h direntry.h error.h \
       
   213 +exit.h fmt.h fmtqfn.h getln.h open.h ndelay.h now.h readsubdir.h readwrite.h \
       
   214 +scan.h select.h str.h stralloc.h substdio.h trigger.h
       
   215 +	./compile $(DEFINES) qmail-todo.c
       
   216  
       
   217  qmail-upq: \
       
   218  warn-auto.sh qmail-upq.sh conf-qmail conf-break conf-split
       
   219 diff -uN qmail-1.03/TARGETS qmail-exttodo/TARGETS
       
   220 --- qmail-1.03/TARGETS	Mon Jun 15 12:53:16 1998
       
   221 +++ qmail-exttodo/TARGETS	Mon Apr 22 13:59:32 2002
       
   222 @@ -385,3 +385,5 @@
       
   223  man
       
   224  setup
       
   225  check
       
   226 +qmail-todo.o
       
   227 +qmail-todo
       
   228 diff -uN qmail-1.03/hier.c qmail-exttodo/hier.c
       
   229 --- qmail-1.03/hier.c	Mon Jun 15 12:53:16 1998
       
   230 +++ qmail-exttodo/hier.c	Mon Apr 22 14:01:58 2002
       
   231 @@ -108,6 +108,9 @@
       
   232    c(auto_qmail,"bin","qmail-rspawn",auto_uido,auto_gidq,0711);
       
   233    c(auto_qmail,"bin","qmail-clean",auto_uido,auto_gidq,0711);
       
   234    c(auto_qmail,"bin","qmail-send",auto_uido,auto_gidq,0711);
       
   235 +#ifdef EXTERNAL_TODO
       
   236 +  c(auto_qmail,"bin","qmail-todo",auto_uido,auto_gidq,0711);
       
   237 +#endif
       
   238    c(auto_qmail,"bin","splogger",auto_uido,auto_gidq,0711);
       
   239    c(auto_qmail,"bin","qmail-newu",auto_uido,auto_gidq,0700);
       
   240    c(auto_qmail,"bin","qmail-newmrh",auto_uido,auto_gidq,0700);
       
   241 diff -uN qmail-1.03/install-big.c qmail-exttodo/install-big.c
       
   242 --- qmail-1.03/install-big.c	Mon Jun 15 12:53:16 1998
       
   243 +++ qmail-exttodo/install-big.c	Mon Apr 22 14:02:11 2002
       
   244 @@ -108,6 +108,9 @@
       
   245    c(auto_qmail,"bin","qmail-rspawn",auto_uido,auto_gidq,0711);
       
   246    c(auto_qmail,"bin","qmail-clean",auto_uido,auto_gidq,0711);
       
   247    c(auto_qmail,"bin","qmail-send",auto_uido,auto_gidq,0711);
       
   248 +#ifdef EXTERNAL_TODO
       
   249 +  c(auto_qmail,"bin","qmail-todo",auto_uido,auto_gidq,0711);
       
   250 +#endif
       
   251    c(auto_qmail,"bin","splogger",auto_uido,auto_gidq,0711);
       
   252    c(auto_qmail,"bin","qmail-newu",auto_uido,auto_gidq,0700);
       
   253    c(auto_qmail,"bin","qmail-newmrh",auto_uido,auto_gidq,0700);
       
   254 diff -uN qmail-1.03/qmail-send.c qmail-exttodo/qmail-send.c
       
   255 --- qmail-1.03/qmail-send.c	Mon Jun 15 12:53:16 1998
       
   256 +++ qmail-exttodo/qmail-send.c	Sun Jan  5 22:09:42 2003
       
   257 @@ -1215,6 +1215,7 @@
       
   258  
       
   259  /* this file is too long ---------------------------------------------- TODO */
       
   260  
       
   261 +#ifndef EXTERNAL_TODO
       
   262  datetime_sec nexttodorun;
       
   263  DIR *tododir; /* if 0, have to opendir again */
       
   264  stralloc todoline = {0};
       
   265 @@ -1438,6 +1439,143 @@
       
   266     if (fdchan[c] != -1) close(fdchan[c]);
       
   267  }
       
   268  
       
   269 +#endif
       
   270 +
       
   271 +/* this file is too long ------------------------------------- EXTERNAL TODO */
       
   272 +
       
   273 +#ifdef EXTERNAL_TODO
       
   274 +stralloc todoline = {0};
       
   275 +char todobuf[2048];
       
   276 +int todofdin;
       
   277 +int todofdout;
       
   278 +int flagtodoalive;
       
   279 +
       
   280 +void tododied() { log1("alert: oh no! lost qmail-todo connection! dying...\n");
       
   281 + flagexitasap = 1; flagtodoalive = 0; }
       
   282 +
       
   283 +void todo_init()
       
   284 +{
       
   285 +  todofdout = 7;
       
   286 +  todofdin = 8;
       
   287 +  flagtodoalive = 1;
       
   288 +  /* sync with external todo */
       
   289 +  if (write(todofdout, "S", 1) != 1) tododied();
       
   290 +  
       
   291 +  return;
       
   292 +}
       
   293 +
       
   294 +void todo_selprep(nfds,rfds,wakeup)
       
   295 +int *nfds;
       
   296 +fd_set *rfds;
       
   297 +datetime_sec *wakeup;
       
   298 +{
       
   299 +  if (flagexitasap) {
       
   300 +    if (flagtodoalive) {
       
   301 +      write(todofdout, "X", 1);
       
   302 +    }
       
   303 +  }
       
   304 +  if (flagtodoalive) {
       
   305 +    FD_SET(todofdin,rfds);
       
   306 +    if (*nfds <= todofdin)
       
   307 +      *nfds = todofdin + 1;
       
   308 +  }
       
   309 +}
       
   310 +
       
   311 +void todo_del(char* s)
       
   312 +{
       
   313 + int flagchan[CHANNELS];
       
   314 + struct prioq_elt pe;
       
   315 + unsigned long id;
       
   316 + unsigned int len;
       
   317 + int c;
       
   318 +
       
   319 + for (c = 0;c < CHANNELS;++c) flagchan[c] = 0;
       
   320 + switch(*s++) {
       
   321 +  case 'L':
       
   322 +    flagchan[0] = 1;
       
   323 +    break;
       
   324 +  case 'R':
       
   325 +    flagchan[1] = 1;
       
   326 +    break;
       
   327 +  case 'B':
       
   328 +    flagchan[0] = 1;
       
   329 +    flagchan[1] = 1;
       
   330 +    break;
       
   331 +  case 'X':
       
   332 +    break;
       
   333 +  default:
       
   334 +    log1("warning: qmail-send unable to understand qmail-todo\n");
       
   335 +    return;
       
   336 + }
       
   337 + 
       
   338 + len = scan_ulong(s,&id);
       
   339 + if (!len || s[len]) {
       
   340 +  log1("warning: qmail-send unable to understand qmail-todo\n");
       
   341 +  return;
       
   342 + }
       
   343 +
       
   344 + pe.id = id; pe.dt = now();
       
   345 + for (c = 0;c < CHANNELS;++c)
       
   346 +   if (flagchan[c])
       
   347 +     while (!prioq_insert(&pqchan[c],&pe)) nomem();
       
   348 +
       
   349 + for (c = 0;c < CHANNELS;++c) if (flagchan[c]) break;
       
   350 + if (c == CHANNELS)
       
   351 +   while (!prioq_insert(&pqdone,&pe)) nomem();
       
   352 +
       
   353 + return;
       
   354 +}
       
   355 +
       
   356 +void todo_do(rfds)
       
   357 +fd_set *rfds;
       
   358 +{
       
   359 +  int r;
       
   360 +  char ch;
       
   361 +  int i;
       
   362 +  
       
   363 +  if (!flagtodoalive) return;
       
   364 +  if (!FD_ISSET(todofdin,rfds)) return;
       
   365 +
       
   366 +  r = read(todofdin,todobuf,sizeof(todobuf));
       
   367 +  if (r == -1) return;
       
   368 +  if (r == 0) {
       
   369 +    if (flagexitasap)
       
   370 +      flagtodoalive = 0;
       
   371 +    else
       
   372 +      tododied();
       
   373 +    return;
       
   374 +  }
       
   375 +  for (i = 0;i < r;++i) {
       
   376 +    ch = todobuf[i];
       
   377 +    while (!stralloc_append(&todoline,&ch)) nomem();
       
   378 +    if (todoline.len > REPORTMAX)
       
   379 +      todoline.len = REPORTMAX;
       
   380 +      /* qmail-todo is responsible for keeping it short */
       
   381 +    if (!ch && (todoline.len > 1)) {
       
   382 +      switch (todoline.s[0]) {
       
   383 +	case 'D':
       
   384 +	  if (flagexitasap) break;
       
   385 +	  todo_del(todoline.s + 1);
       
   386 +	  break;
       
   387 +	case 'L':
       
   388 +	  log1(todoline.s + 1);
       
   389 +	  break;
       
   390 +	case 'X':
       
   391 +	  if (flagexitasap)
       
   392 +	    flagtodoalive = 0;
       
   393 +	  else
       
   394 +	    tododied();
       
   395 +	  break;
       
   396 +	default:
       
   397 +	  log1("warning: qmail-send unable to understand qmail-todo: report mangled\n");
       
   398 +	  break;
       
   399 +      }
       
   400 +      todoline.len = 0;
       
   401 +    }
       
   402 +  }
       
   403 +}
       
   404 +
       
   405 +#endif
       
   406  
       
   407  /* this file is too long ---------------------------------------------- MAIN */
       
   408  
       
   409 @@ -1504,6 +1642,9 @@
       
   410     log1("alert: unable to reread controls: unable to switch to home directory\n");
       
   411     return;
       
   412    }
       
   413 +#ifdef EXTERNAL_TODO
       
   414 + write(todofdout, "H", 1);
       
   415 +#endif
       
   416   regetcontrols();
       
   417   while (chdir("queue") == -1)
       
   418    {
       
   419 @@ -1568,8 +1709,12 @@
       
   420   todo_init();
       
   421   cleanup_init();
       
   422  
       
   423 +#ifdef EXTERNAL_TODO
       
   424 + while (!flagexitasap || !del_canexit() || flagtodoalive)
       
   425 +#else
       
   426   while (!flagexitasap || !del_canexit())
       
   427 -  {
       
   428 +#endif
       
   429 + {
       
   430     recent = now();
       
   431  
       
   432     if (flagrunasap) { flagrunasap = 0; pqrun(); }
       
   433 diff -uN qmail-1.03/qmail-start.c qmail-exttodo/qmail-start.c
       
   434 --- qmail-1.03/qmail-start.c	Mon Jun 15 12:53:16 1998
       
   435 +++ qmail-exttodo/qmail-start.c	Mon Apr 22 13:55:48 2002
       
   436 @@ -8,6 +8,9 @@
       
   437  char *(qcargs[]) = { "qmail-clean", 0 };
       
   438  char *(qlargs[]) = { "qmail-lspawn", "./Mailbox", 0 };
       
   439  char *(qrargs[]) = { "qmail-rspawn", 0 };
       
   440 +#ifdef EXTERNAL_TODO
       
   441 +char *(qtargs[]) = { "qmail-todo", 0};
       
   442 +#endif
       
   443  
       
   444  void die() { _exit(111); }
       
   445  
       
   446 @@ -18,13 +21,28 @@
       
   447  int pi4[2];
       
   448  int pi5[2];
       
   449  int pi6[2];
       
   450 -
       
   451 -void close23456() { close(2); close(3); close(4); close(5); close(6); }
       
   452 +#ifdef EXTERNAL_TODO
       
   453 +int pi7[2];
       
   454 +int pi8[2];
       
   455 +int pi9[2];
       
   456 +int pi10[2];
       
   457 +#endif
       
   458 +
       
   459 +void close23456() { 
       
   460 +  close(2); close(3); close(4); close(5); close(6); 
       
   461 +#ifdef EXTERNAL_TODO
       
   462 +  close(7); close(8);
       
   463 +#endif
       
   464 +}
       
   465  
       
   466  void closepipes() {
       
   467    close(pi1[0]); close(pi1[1]); close(pi2[0]); close(pi2[1]);
       
   468    close(pi3[0]); close(pi3[1]); close(pi4[0]); close(pi4[1]);
       
   469    close(pi5[0]); close(pi5[1]); close(pi6[0]); close(pi6[1]);
       
   470 +#ifdef EXTERNAL_TODO
       
   471 +  close(pi7[0]); close(pi7[1]); close(pi8[0]); close(pi8[1]);
       
   472 +	close(pi9[0]); close(pi9[1]); close(pi10[0]); close(pi10[1]);
       
   473 +#endif
       
   474  }
       
   475  
       
   476  void main(argc,argv)
       
   477 @@ -40,6 +58,10 @@
       
   478    if (fd_copy(4,0) == -1) die();
       
   479    if (fd_copy(5,0) == -1) die();
       
   480    if (fd_copy(6,0) == -1) die();
       
   481 +#ifdef EXTERNAL_TODO
       
   482 +  if (fd_copy(7,0) == -1) die();
       
   483 +  if (fd_copy(8,0) == -1) die();
       
   484 +#endif
       
   485  
       
   486    if (argv[1]) {
       
   487      qlargs[1] = argv[1];
       
   488 @@ -70,6 +92,12 @@
       
   489    if (pipe(pi4) == -1) die();
       
   490    if (pipe(pi5) == -1) die();
       
   491    if (pipe(pi6) == -1) die();
       
   492 +#ifdef EXTERNAL_TODO
       
   493 +  if (pipe(pi7) == -1) die();
       
   494 +  if (pipe(pi8) == -1) die();
       
   495 +  if (pipe(pi9) == -1) die();
       
   496 +  if (pipe(pi10) == -1) die();
       
   497 +#endif
       
   498   
       
   499    switch(fork()) {
       
   500      case -1: die();
       
   501 @@ -105,6 +133,34 @@
       
   502        execvp(*qcargs,qcargs);
       
   503        die();
       
   504    }
       
   505 +
       
   506 +#ifdef EXTERNAL_TODO
       
   507 +  switch(fork()) {
       
   508 +    case -1: die();
       
   509 +    case 0:
       
   510 +      if (prot_uid(auto_uids) == -1) die();
       
   511 +      if (fd_copy(0,pi7[0]) == -1) die();
       
   512 +      if (fd_copy(1,pi8[1]) == -1) die();
       
   513 +      close23456();
       
   514 +      if (fd_copy(2,pi9[1]) == -1) die();
       
   515 +      if (fd_copy(3,pi10[0]) == -1) die();
       
   516 +      closepipes();
       
   517 +      execvp(*qtargs,qtargs);
       
   518 +      die();
       
   519 +  }
       
   520 +
       
   521 +  switch(fork()) {
       
   522 +    case -1: die();
       
   523 +    case 0:
       
   524 +      if (prot_uid(auto_uidq) == -1) die();
       
   525 +      if (fd_copy(0,pi9[0]) == -1) die();
       
   526 +      if (fd_copy(1,pi10[1]) == -1) die();
       
   527 +      close23456();
       
   528 +      closepipes();
       
   529 +      execvp(*qcargs,qcargs);
       
   530 +      die();
       
   531 +  }
       
   532 +#endif
       
   533   
       
   534    if (prot_uid(auto_uids) == -1) die();
       
   535    if (fd_copy(0,1) == -1) die();
       
   536 @@ -114,6 +170,10 @@
       
   537    if (fd_copy(4,pi4[0]) == -1) die();
       
   538    if (fd_copy(5,pi5[1]) == -1) die();
       
   539    if (fd_copy(6,pi6[0]) == -1) die();
       
   540 +#ifdef EXTERNAL_TODO
       
   541 +  if (fd_copy(7,pi7[1]) == -1) die();
       
   542 +  if (fd_copy(8,pi8[0]) == -1) die();
       
   543 +#endif
       
   544    closepipes();
       
   545    execvp(*qsargs,qsargs);
       
   546    die();
       
   547 diff -uN qmail-1.03/qmail-todo.c qmail-exttodo/qmail-todo.c
       
   548 --- qmail-1.03/qmail-todo.c	Thu Jan  1 01:00:00 1970
       
   549 +++ qmail-exttodo/qmail-todo.c	Sun Jan  5 22:16:34 2003
       
   550 @@ -0,0 +1,688 @@
       
   551 +#include <sys/types.h>
       
   552 +#include <sys/stat.h>
       
   553 +#include "alloc.h"
       
   554 +#include "auto_qmail.h"
       
   555 +#include "byte.h"
       
   556 +#include "constmap.h"
       
   557 +#include "control.h"
       
   558 +#include "direntry.h"
       
   559 +#include "error.h"
       
   560 +#include "exit.h"
       
   561 +#include "fmt.h"
       
   562 +#include "fmtqfn.h"
       
   563 +#include "getln.h"
       
   564 +#include "open.h"
       
   565 +#include "ndelay.h"
       
   566 +#include "now.h"
       
   567 +#include "readsubdir.h"
       
   568 +#include "readwrite.h"
       
   569 +#include "scan.h"
       
   570 +#include "select.h"
       
   571 +#include "str.h"
       
   572 +#include "stralloc.h"
       
   573 +#include "substdio.h"
       
   574 +#include "trigger.h"
       
   575 +
       
   576 +/* critical timing feature #1: if not triggered, do not busy-loop */
       
   577 +/* critical timing feature #2: if triggered, respond within fixed time */
       
   578 +/* important timing feature: when triggered, respond instantly */
       
   579 +#define SLEEP_TODO 1500 /* check todo/ every 25 minutes in any case */
       
   580 +#define SLEEP_FUZZ 1 /* slop a bit on sleeps to avoid zeno effect */
       
   581 +#define SLEEP_FOREVER 86400 /* absolute maximum time spent in select() */
       
   582 +#define SLEEP_SYSFAIL 123
       
   583 +
       
   584 +stralloc percenthack = {0};
       
   585 +struct constmap mappercenthack;
       
   586 +stralloc locals = {0};
       
   587 +struct constmap maplocals;
       
   588 +stralloc vdoms = {0};
       
   589 +struct constmap mapvdoms;
       
   590 +stralloc envnoathost = {0};
       
   591 +
       
   592 +char strnum[FMT_ULONG];
       
   593 +
       
   594 +/* XXX not good, if qmail-send.c changes this has to be updated */
       
   595 +#define CHANNELS 2
       
   596 +char *chanaddr[CHANNELS] = { "local/", "remote/" };
       
   597 +
       
   598 +datetime_sec recent;
       
   599 +
       
   600 +void log1(char *x);
       
   601 +void log3(char* x, char* y, char* z);
       
   602 +
       
   603 +int flagstopasap = 0;
       
   604 +void sigterm(void)
       
   605 +{
       
   606 +  if (flagstopasap == 0)
       
   607 +    log1("status: qmail-todo stop processing asap\n");
       
   608 +  flagstopasap = 1;
       
   609 +}
       
   610 +
       
   611 +int flagreadasap = 0; void sighup(void) { flagreadasap = 1; }
       
   612 +int flagsendalive = 1; void senddied(void) { flagsendalive = 0; }
       
   613 +
       
   614 +void nomem() { log1("alert: out of memory, sleeping...\n"); sleep(10); }
       
   615 +void pausedir(dir) char *dir;
       
   616 +{ log3("alert: unable to opendir ",dir,", sleeping...\n"); sleep(10); }
       
   617 +
       
   618 +void cleandied()
       
   619 +{ 
       
   620 +  log1("alert: qmail-todo: oh no! lost qmail-clean connection! dying...\n");
       
   621 +  flagstopasap = 1;
       
   622 +}
       
   623 +
       
   624 +
       
   625 +/* this file is not so long ------------------------------------- FILENAMES */
       
   626 +
       
   627 +stralloc fn = {0};
       
   628 +
       
   629 +void fnmake_init(void)
       
   630 +{
       
   631 + while (!stralloc_ready(&fn,FMTQFN)) nomem();
       
   632 +}
       
   633 +
       
   634 +void fnmake_info(unsigned long id) { fn.len = fmtqfn(fn.s,"info/",id,1); }
       
   635 +void fnmake_todo(unsigned long id) { fn.len = fmtqfn(fn.s,"todo/",id,0); }
       
   636 +void fnmake_mess(unsigned long id) { fn.len = fmtqfn(fn.s,"mess/",id,1); }
       
   637 +void fnmake_chanaddr(unsigned long id, int c)
       
   638 +{ fn.len = fmtqfn(fn.s,chanaddr[c],id,1); }
       
   639 +
       
   640 +
       
   641 +/* this file is not so long ------------------------------------- REWRITING */
       
   642 +
       
   643 +stralloc rwline = {0};
       
   644 +
       
   645 +/* 1 if by land, 2 if by sea, 0 if out of memory. not allowed to barf. */
       
   646 +/* may trash recip. must set up rwline, between a T and a \0. */
       
   647 +int rewrite(char *recip)
       
   648 +{
       
   649 +  int i;
       
   650 +  int j;
       
   651 +  char *x;
       
   652 +  static stralloc addr = {0};
       
   653 +  int at;
       
   654 +
       
   655 +  if (!stralloc_copys(&rwline,"T")) return 0;
       
   656 +  if (!stralloc_copys(&addr,recip)) return 0;
       
   657 +
       
   658 +  i = byte_rchr(addr.s,addr.len,'@');
       
   659 +  if (i == addr.len) {
       
   660 +    if (!stralloc_cats(&addr,"@")) return 0;
       
   661 +    if (!stralloc_cat(&addr,&envnoathost)) return 0;
       
   662 +  }
       
   663 +
       
   664 +  while (constmap(&mappercenthack,addr.s + i + 1,addr.len - i - 1)) {
       
   665 +    j = byte_rchr(addr.s,i,'%');
       
   666 +    if (j == i) break;
       
   667 +    addr.len = i;
       
   668 +    i = j;
       
   669 +    addr.s[i] = '@';
       
   670 +  }
       
   671 +
       
   672 +  at = byte_rchr(addr.s,addr.len,'@');
       
   673 +
       
   674 +  if (constmap(&maplocals,addr.s + at + 1,addr.len - at - 1)) {
       
   675 +    if (!stralloc_cat(&rwline,&addr)) return 0;
       
   676 +    if (!stralloc_0(&rwline)) return 0;
       
   677 +    return 1;
       
   678 +  }
       
   679 +
       
   680 +  for (i = 0;i <= addr.len;++i)
       
   681 +    if (!i || (i == at + 1) || (i == addr.len) || ((i > at) && (addr.s[i] == '.')))
       
   682 +      if (x = constmap(&mapvdoms,addr.s + i,addr.len - i)) {
       
   683 +        if (!*x) break;
       
   684 +        if (!stralloc_cats(&rwline,x)) return 0;
       
   685 +        if (!stralloc_cats(&rwline,"-")) return 0;
       
   686 +        if (!stralloc_cat(&rwline,&addr)) return 0;
       
   687 +        if (!stralloc_0(&rwline)) return 0;
       
   688 +        return 1;
       
   689 +      }
       
   690 + 
       
   691 +  if (!stralloc_cat(&rwline,&addr)) return 0;
       
   692 +  if (!stralloc_0(&rwline)) return 0;
       
   693 +  return 2;
       
   694 +}
       
   695 +
       
   696 +/* this file is not so long --------------------------------- COMMUNICATION */
       
   697 +
       
   698 +substdio sstoqc; char sstoqcbuf[1024];
       
   699 +substdio ssfromqc; char ssfromqcbuf[1024];
       
   700 +stralloc comm_buf = {0};
       
   701 +int comm_pos;
       
   702 +int fdout = -1;
       
   703 +int fdin = -1;
       
   704 +
       
   705 +void comm_init(void)
       
   706 +{
       
   707 + substdio_fdbuf(&sstoqc,write,2,sstoqcbuf,sizeof(sstoqcbuf));
       
   708 + substdio_fdbuf(&ssfromqc,read,3,ssfromqcbuf,sizeof(ssfromqcbuf));
       
   709 +
       
   710 + fdout = 1; /* stdout */
       
   711 + fdin = 0;  /* stdin */
       
   712 + if (ndelay_on(fdout) == -1)
       
   713 + /* this is so stupid: NDELAY semantics should be default on write */
       
   714 +   senddied(); /* drastic, but better than risking deadlock */
       
   715 +
       
   716 + while (!stralloc_ready(&comm_buf,1024)) nomem();
       
   717 +}
       
   718 +
       
   719 +int comm_canwrite(void)
       
   720 +{
       
   721 + /* XXX: could allow a bigger buffer; say 10 recipients */
       
   722 + /* XXX: returns true if there is something in the buffer */
       
   723 + if (!flagsendalive) return 0;
       
   724 + if (comm_buf.s && comm_buf.len) return 1;
       
   725 + return 0;
       
   726 +}
       
   727 +
       
   728 +void log1(char* x)
       
   729 +{
       
   730 +  int pos;
       
   731 +  
       
   732 +  pos = comm_buf.len;
       
   733 +  if (!stralloc_cats(&comm_buf,"L")) goto fail;
       
   734 +  if (!stralloc_cats(&comm_buf,x)) goto fail;
       
   735 +  if (!stralloc_0(&comm_buf)) goto fail;
       
   736 +  return;
       
   737 +  
       
   738 +fail:
       
   739 +  /* either all or nothing */
       
   740 +  comm_buf.len = pos;
       
   741 +}
       
   742 +
       
   743 +void log3(char* x, char *y, char *z)
       
   744 +{
       
   745 +  int pos;
       
   746 +  
       
   747 +  pos = comm_buf.len;
       
   748 +  if (!stralloc_cats(&comm_buf,"L")) goto fail;
       
   749 +  if (!stralloc_cats(&comm_buf,x)) goto fail;
       
   750 +  if (!stralloc_cats(&comm_buf,y)) goto fail;
       
   751 +  if (!stralloc_cats(&comm_buf,z)) goto fail;
       
   752 +  if (!stralloc_0(&comm_buf)) goto fail;
       
   753 +  return;
       
   754 +  
       
   755 +fail:
       
   756 +  /* either all or nothing */
       
   757 +  comm_buf.len = pos;
       
   758 +}
       
   759 +
       
   760 +void comm_write(unsigned long id, int local, int remote)
       
   761 +{
       
   762 +  int pos;
       
   763 +  char *s;
       
   764 +  
       
   765 +  if(local && remote) s="B";
       
   766 +  else if(local) s="L";
       
   767 +  else if(remote) s="R";
       
   768 +  else s="X";
       
   769 +  
       
   770 +  pos = comm_buf.len;
       
   771 +  strnum[fmt_ulong(strnum,id)] = 0;
       
   772 +  if (!stralloc_cats(&comm_buf,"D")) goto fail;
       
   773 +  if (!stralloc_cats(&comm_buf,s)) goto fail;
       
   774 +  if (!stralloc_cats(&comm_buf,strnum)) goto fail;
       
   775 +  if (!stralloc_0(&comm_buf)) goto fail;
       
   776 +  return;
       
   777 +  
       
   778 +fail:
       
   779 +  /* either all or nothing */
       
   780 +  comm_buf.len = pos;
       
   781 +}
       
   782 +
       
   783 +static int issafe(char ch)
       
   784 +{
       
   785 + if (ch == '%') return 0; /* general principle: allman's code is crap */
       
   786 + if (ch < 33) return 0;
       
   787 + if (ch > 126) return 0;
       
   788 + return 1;
       
   789 +}
       
   790 +
       
   791 +void comm_info(unsigned long id, unsigned long size, char* from, unsigned long pid, unsigned long uid)
       
   792 +{
       
   793 +  int pos;
       
   794 +  int i;
       
   795 +  
       
   796 +  pos = comm_buf.len;
       
   797 +  if (!stralloc_cats(&comm_buf,"Linfo msg ")) goto fail;
       
   798 +  strnum[fmt_ulong(strnum,id)] = 0;
       
   799 +  if (!stralloc_cats(&comm_buf,strnum)) goto fail;
       
   800 +  if (!stralloc_cats(&comm_buf,": bytes ")) goto fail;
       
   801 +  strnum[fmt_ulong(strnum,size)] = 0;
       
   802 +  if (!stralloc_cats(&comm_buf,strnum)) goto fail;
       
   803 +  if (!stralloc_cats(&comm_buf," from <")) goto fail;
       
   804 +  i = comm_buf.len;
       
   805 +  if (!stralloc_cats(&comm_buf,from)) goto fail;
       
   806 +  for (;i < comm_buf.len;++i)
       
   807 +    if (comm_buf.s[i] == '\n')
       
   808 +      comm_buf.s[i] = '/';
       
   809 +    else
       
   810 +      if (!issafe(comm_buf.s[i]))
       
   811 +	comm_buf.s[i] = '_';
       
   812 +  if (!stralloc_cats(&comm_buf,"> qp ")) goto fail;
       
   813 +  strnum[fmt_ulong(strnum,pid)] = 0;
       
   814 +  if (!stralloc_cats(&comm_buf,strnum)) goto fail;
       
   815 +  if (!stralloc_cats(&comm_buf," uid ")) goto fail;
       
   816 +  strnum[fmt_ulong(strnum,uid)] = 0;
       
   817 +  if (!stralloc_cats(&comm_buf,strnum)) goto fail;
       
   818 +  if (!stralloc_cats(&comm_buf,"\n")) goto fail;
       
   819 +  if (!stralloc_0(&comm_buf)) goto fail;
       
   820 +  return;
       
   821 +  
       
   822 +fail:
       
   823 +  /* either all or nothing */
       
   824 +  comm_buf.len = pos;
       
   825 +}
       
   826 +
       
   827 +void comm_exit(void)
       
   828 +{
       
   829 +  int w;
       
   830 +  
       
   831 +  /* if it fails exit, we have already stoped */
       
   832 +  if (!stralloc_cats(&comm_buf,"X")) _exit(1);
       
   833 +  if (!stralloc_0(&comm_buf)) _exit(1);
       
   834 +}
       
   835 +
       
   836 +void comm_selprep(int *nfds, fd_set *wfds, fd_set *rfds)
       
   837 +{
       
   838 +  if (flagsendalive) {
       
   839 +    if (flagstopasap && comm_canwrite() == 0)
       
   840 +      comm_exit();
       
   841 +    if (comm_canwrite()) {
       
   842 +      FD_SET(fdout,wfds);
       
   843 +      if (*nfds <= fdout)
       
   844 +	*nfds = fdout + 1;
       
   845 +    }
       
   846 +    FD_SET(fdin,rfds);
       
   847 +    if (*nfds <= fdin)
       
   848 +      *nfds = fdin + 1;
       
   849 +  }
       
   850 +}
       
   851 +
       
   852 +void comm_do(fd_set *wfds, fd_set *rfds)
       
   853 +{
       
   854 +  /* first write then read */
       
   855 +  if (flagsendalive)
       
   856 +    if (comm_canwrite())
       
   857 +      if (FD_ISSET(fdout,wfds)) {
       
   858 +	int w;
       
   859 +	int len;
       
   860 +	len = comm_buf.len;
       
   861 +	w = write(fdout,comm_buf.s + comm_pos,len - comm_pos);
       
   862 +	if (w <= 0) {
       
   863 +	  if ((w == -1) && (errno == error_pipe))
       
   864 +	    senddied();
       
   865 +	} else {
       
   866 +	  comm_pos += w;
       
   867 +	  if (comm_pos == len) {
       
   868 +	    comm_buf.len = 0;
       
   869 +	    comm_pos = 0;
       
   870 +	  }
       
   871 +	}
       
   872 +      }
       
   873 +  if (flagsendalive)
       
   874 +    if (FD_ISSET(fdin,rfds)) {
       
   875 +      /* there are only two messages 'H' and 'X' */
       
   876 +      char c;
       
   877 +      int r;
       
   878 +      r = read(fdin, &c, 1);
       
   879 +      if (r <= 0) {
       
   880 +	if ((r == -1) && (errno != error_intr))
       
   881 +	  senddied();
       
   882 +      } else {
       
   883 +	switch(c) {
       
   884 +	  case 'H':
       
   885 +	    sighup();
       
   886 +	    break;
       
   887 +	  case 'X':
       
   888 +	    sigterm();
       
   889 +	    break;
       
   890 +	  default:
       
   891 +	    log1("warning: qmail-todo: qmail-send speaks an obscure dialect\n");
       
   892 +	    break;
       
   893 +	}
       
   894 +      }
       
   895 +    }
       
   896 +}
       
   897 +
       
   898 +/* this file is not so long ------------------------------------------ TODO */
       
   899 +
       
   900 +datetime_sec nexttodorun;
       
   901 +DIR *tododir; /* if 0, have to opendir again */
       
   902 +stralloc todoline = {0};
       
   903 +char todobuf[SUBSTDIO_INSIZE];
       
   904 +char todobufinfo[512];
       
   905 +char todobufchan[CHANNELS][1024];
       
   906 +
       
   907 +void todo_init(void)
       
   908 +{
       
   909 + tododir = 0;
       
   910 + nexttodorun = now();
       
   911 + trigger_set();
       
   912 +}
       
   913 +
       
   914 +void todo_selprep(int *nfds, fd_set *rfds, datetime_sec *wakeup)
       
   915 +{
       
   916 + if (flagstopasap) return;
       
   917 + trigger_selprep(nfds,rfds);
       
   918 + if (tododir) *wakeup = 0;
       
   919 + if (*wakeup > nexttodorun) *wakeup = nexttodorun;
       
   920 +}
       
   921 +
       
   922 +void todo_do(fd_set *rfds)
       
   923 +{
       
   924 + struct stat st;
       
   925 + substdio ss; int fd;
       
   926 + substdio ssinfo; int fdinfo;
       
   927 + substdio sschan[CHANNELS];
       
   928 + int fdchan[CHANNELS];
       
   929 + int flagchan[CHANNELS];
       
   930 + char ch;
       
   931 + int match;
       
   932 + unsigned long id;
       
   933 + unsigned int len;
       
   934 + direntry *d;
       
   935 + int c;
       
   936 + unsigned long uid;
       
   937 + unsigned long pid;
       
   938 +
       
   939 + fd = -1;
       
   940 + fdinfo = -1;
       
   941 + for (c = 0;c < CHANNELS;++c) fdchan[c] = -1;
       
   942 +
       
   943 + if (flagstopasap) return;
       
   944 +
       
   945 + if (!tododir)
       
   946 +  {
       
   947 +   if (!trigger_pulled(rfds))
       
   948 +     if (recent < nexttodorun)
       
   949 +       return;
       
   950 +   trigger_set();
       
   951 +   tododir = opendir("todo");
       
   952 +   if (!tododir)
       
   953 +    {
       
   954 +     pausedir("todo");
       
   955 +     return;
       
   956 +    }
       
   957 +   nexttodorun = recent + SLEEP_TODO;
       
   958 +  }
       
   959 +
       
   960 + d = readdir(tododir);
       
   961 + if (!d)
       
   962 +  {
       
   963 +   closedir(tododir);
       
   964 +   tododir = 0;
       
   965 +   return;
       
   966 +  }
       
   967 + if (str_equal(d->d_name,".")) return;
       
   968 + if (str_equal(d->d_name,"..")) return;
       
   969 + len = scan_ulong(d->d_name,&id);
       
   970 + if (!len || d->d_name[len]) return;
       
   971 +
       
   972 + fnmake_todo(id);
       
   973 +
       
   974 + fd = open_read(fn.s);
       
   975 + if (fd == -1) { log3("warning: qmail-todo: unable to open ",fn.s,"\n"); return; }
       
   976 +
       
   977 + fnmake_mess(id);
       
   978 + /* just for the statistics */
       
   979 + if (stat(fn.s,&st) == -1)
       
   980 +  { log3("warning: qmail-todo: unable to stat ",fn.s,"\n"); goto fail; }
       
   981 +
       
   982 + for (c = 0;c < CHANNELS;++c)
       
   983 +  {
       
   984 +   fnmake_chanaddr(id,c);
       
   985 +   if (unlink(fn.s) == -1) if (errno != error_noent)
       
   986 +    { log3("warning: qmail-todo: unable to unlink ",fn.s,"\n"); goto fail; }
       
   987 +  }
       
   988 +
       
   989 + fnmake_info(id);
       
   990 + if (unlink(fn.s) == -1) if (errno != error_noent)
       
   991 +  { log3("warning: qmail-todo: unable to unlink ",fn.s,"\n"); goto fail; }
       
   992 +
       
   993 + fdinfo = open_excl(fn.s);
       
   994 + if (fdinfo == -1)
       
   995 +  { log3("warning: qmail-todo: unable to create ",fn.s,"\n"); goto fail; }
       
   996 +
       
   997 + strnum[fmt_ulong(strnum,id)] = 0;
       
   998 + log3("new msg ",strnum,"\n");
       
   999 +
       
  1000 + for (c = 0;c < CHANNELS;++c) flagchan[c] = 0;
       
  1001 +
       
  1002 + substdio_fdbuf(&ss,read,fd,todobuf,sizeof(todobuf));
       
  1003 + substdio_fdbuf(&ssinfo,write,fdinfo,todobufinfo,sizeof(todobufinfo));
       
  1004 +
       
  1005 + uid = 0;
       
  1006 + pid = 0;
       
  1007 +
       
  1008 + for (;;)
       
  1009 +  {
       
  1010 +   if (getln(&ss,&todoline,&match,'\0') == -1)
       
  1011 +    {
       
  1012 +     /* perhaps we're out of memory, perhaps an I/O error */
       
  1013 +     fnmake_todo(id);
       
  1014 +     log3("warning: qmail-todo: trouble reading ",fn.s,"\n"); goto fail;
       
  1015 +    }
       
  1016 +   if (!match) break;
       
  1017 +
       
  1018 +   switch(todoline.s[0])
       
  1019 +    {
       
  1020 +     case 'u':
       
  1021 +       scan_ulong(todoline.s + 1,&uid);
       
  1022 +       break;
       
  1023 +     case 'p':
       
  1024 +       scan_ulong(todoline.s + 1,&pid);
       
  1025 +       break;
       
  1026 +     case 'F':
       
  1027 +       if (substdio_putflush(&ssinfo,todoline.s,todoline.len) == -1)
       
  1028 +	{
       
  1029 +	 fnmake_info(id);
       
  1030 +         log3("warning: qmail-todo: trouble writing to ",fn.s,"\n"); goto fail;
       
  1031 +	}
       
  1032 +	comm_info(id, (unsigned long) st.st_size, todoline.s + 1, pid, uid);
       
  1033 +       break;
       
  1034 +     case 'T':
       
  1035 +       switch(rewrite(todoline.s + 1))
       
  1036 +	{
       
  1037 +	 case 0: nomem(); goto fail;
       
  1038 +	 case 2: c = 1; break;
       
  1039 +	 default: c = 0; break;
       
  1040 +        }
       
  1041 +       if (fdchan[c] == -1)
       
  1042 +	{
       
  1043 +	 fnmake_chanaddr(id,c);
       
  1044 +	 fdchan[c] = open_excl(fn.s);
       
  1045 +	 if (fdchan[c] == -1)
       
  1046 +          { log3("warning: qmail-todo: unable to create ",fn.s,"\n"); goto fail; }
       
  1047 +	 substdio_fdbuf(&sschan[c]
       
  1048 +	   ,write,fdchan[c],todobufchan[c],sizeof(todobufchan[c]));
       
  1049 +	 flagchan[c] = 1;
       
  1050 +	}
       
  1051 +       if (substdio_bput(&sschan[c],rwline.s,rwline.len) == -1)
       
  1052 +        {
       
  1053 +	 fnmake_chanaddr(id,c);
       
  1054 +         log3("warning: qmail-todo: trouble writing to ",fn.s,"\n"); goto fail;
       
  1055 +        }
       
  1056 +       break;
       
  1057 +     default:
       
  1058 +       fnmake_todo(id);
       
  1059 +       log3("warning: qmail-todo: unknown record type in ",fn.s,"\n"); goto fail;
       
  1060 +    }
       
  1061 +  }
       
  1062 +
       
  1063 + close(fd); fd = -1;
       
  1064 +
       
  1065 + fnmake_info(id);
       
  1066 + if (substdio_flush(&ssinfo) == -1)
       
  1067 +  { log3("warning: qmail-todo: trouble writing to ",fn.s,"\n"); goto fail; }
       
  1068 + if (fsync(fdinfo) == -1)
       
  1069 +  { log3("warning: qmail-todo: trouble fsyncing ",fn.s,"\n"); goto fail; }
       
  1070 + close(fdinfo); fdinfo = -1;
       
  1071 +
       
  1072 + for (c = 0;c < CHANNELS;++c)
       
  1073 +   if (fdchan[c] != -1)
       
  1074 +    {
       
  1075 +     fnmake_chanaddr(id,c);
       
  1076 +     if (substdio_flush(&sschan[c]) == -1)
       
  1077 +      { log3("warning: qmail-todo: trouble writing to ",fn.s,"\n"); goto fail; }
       
  1078 +     if (fsync(fdchan[c]) == -1)
       
  1079 +      { log3("warning: qmail-todo: trouble fsyncing ",fn.s,"\n"); goto fail; }
       
  1080 +     close(fdchan[c]); fdchan[c] = -1;
       
  1081 +    }
       
  1082 +
       
  1083 + fnmake_todo(id);
       
  1084 + if (substdio_putflush(&sstoqc,fn.s,fn.len) == -1) { cleandied(); return; }
       
  1085 + if (substdio_get(&ssfromqc,&ch,1) != 1) { cleandied(); return; }
       
  1086 + if (ch != '+')
       
  1087 +  {
       
  1088 +   log3("warning: qmail-clean unable to clean up ",fn.s,"\n");
       
  1089 +   return;
       
  1090 +  }
       
  1091 +
       
  1092 + comm_write(id, flagchan[0], flagchan[1]);
       
  1093 + 
       
  1094 + return;
       
  1095 + 
       
  1096 + fail:
       
  1097 + if (fd != -1) close(fd);
       
  1098 + if (fdinfo != -1) close(fdinfo);
       
  1099 + for (c = 0;c < CHANNELS;++c)
       
  1100 +   if (fdchan[c] != -1) close(fdchan[c]);
       
  1101 +}
       
  1102 +
       
  1103 +/* this file is too long ---------------------------------------------- MAIN */
       
  1104 +
       
  1105 +int getcontrols(void)
       
  1106 +{
       
  1107 + if (control_init() == -1) return 0;
       
  1108 + if (control_rldef(&envnoathost,"control/envnoathost",1,"envnoathost") != 1) return 0;
       
  1109 + if (control_readfile(&locals,"control/locals",1) != 1) return 0;
       
  1110 + if (!constmap_init(&maplocals,locals.s,locals.len,0)) return 0;
       
  1111 + switch(control_readfile(&percenthack,"control/percenthack",0))
       
  1112 +  {
       
  1113 +   case -1: return 0;
       
  1114 +   case 0: if (!constmap_init(&mappercenthack,"",0,0)) return 0; break;
       
  1115 +   case 1: if (!constmap_init(&mappercenthack,percenthack.s,percenthack.len,0)) return 0; break;
       
  1116 +  }
       
  1117 + switch(control_readfile(&vdoms,"control/virtualdomains",0))
       
  1118 +  {
       
  1119 +   case -1: return 0;
       
  1120 +   case 0: if (!constmap_init(&mapvdoms,"",0,1)) return 0; break;
       
  1121 +   case 1: if (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) return 0; break;
       
  1122 +  }
       
  1123 + return 1;
       
  1124 +}
       
  1125 +
       
  1126 +stralloc newlocals = {0};
       
  1127 +stralloc newvdoms = {0};
       
  1128 +
       
  1129 +void regetcontrols(void)
       
  1130 +{
       
  1131 + int r;
       
  1132 +
       
  1133 + if (control_readfile(&newlocals,"control/locals",1) != 1)
       
  1134 +  { log1("alert: qmail-todo: unable to reread control/locals\n"); return; }
       
  1135 + r = control_readfile(&newvdoms,"control/virtualdomains",0);
       
  1136 + if (r == -1)
       
  1137 +  { log1("alert: qmail-todo: unable to reread control/virtualdomains\n"); return; }
       
  1138 +
       
  1139 + constmap_free(&maplocals);
       
  1140 + constmap_free(&mapvdoms);
       
  1141 +
       
  1142 + while (!stralloc_copy(&locals,&newlocals)) nomem();
       
  1143 + while (!constmap_init(&maplocals,locals.s,locals.len,0)) nomem();
       
  1144 +
       
  1145 + if (r)
       
  1146 +  {
       
  1147 +   while (!stralloc_copy(&vdoms,&newvdoms)) nomem();
       
  1148 +   while (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) nomem();
       
  1149 +  }
       
  1150 + else
       
  1151 +   while (!constmap_init(&mapvdoms,"",0,1)) nomem();
       
  1152 +}
       
  1153 +
       
  1154 +void reread(void)
       
  1155 +{
       
  1156 + if (chdir(auto_qmail) == -1)
       
  1157 +  {
       
  1158 +   log1("alert: qmail-todo: unable to reread controls: unable to switch to home directory\n");
       
  1159 +   return;
       
  1160 +  }
       
  1161 + regetcontrols();
       
  1162 + while (chdir("queue") == -1)
       
  1163 +  {
       
  1164 +   log1("alert: qmail-todo: unable to switch back to queue directory; HELP! sleeping...\n");
       
  1165 +   sleep(10);
       
  1166 +  }
       
  1167 +}
       
  1168 +
       
  1169 +void main()
       
  1170 +{
       
  1171 + datetime_sec wakeup;
       
  1172 + fd_set rfds;
       
  1173 + fd_set wfds;
       
  1174 + int nfds;
       
  1175 + struct timeval tv;
       
  1176 + int r;
       
  1177 + char c;
       
  1178 +
       
  1179 + if (chdir(auto_qmail) == -1)
       
  1180 +  { log1("alert: qmail-todo: cannot start: unable to switch to home directory\n"); _exit(111); }
       
  1181 + if (!getcontrols())
       
  1182 +  { log1("alert: qmail-todo: cannot start: unable to read controls\n"); _exit(111); }
       
  1183 + if (chdir("queue") == -1)
       
  1184 +  { log1("alert: qmail-todo: cannot start: unable to switch to queue directory\n"); _exit(111); }
       
  1185 + sig_pipeignore();
       
  1186 + umask(077);
       
  1187 +
       
  1188 + fnmake_init();
       
  1189 +
       
  1190 + todo_init();
       
  1191 + comm_init();
       
  1192 + 
       
  1193 + do {
       
  1194 +   r = read(fdin, &c, 1);
       
  1195 +   if ((r == -1) && (errno != error_intr))
       
  1196 +     _exit(100); /* read failed probably qmail-send died */
       
  1197 + } while (r =! 1); /* we assume it is a 'S' */
       
  1198 + 
       
  1199 + for (;;)
       
  1200 +  {
       
  1201 +   recent = now();
       
  1202 +
       
  1203 +   if (flagreadasap) { flagreadasap = 0; reread(); }
       
  1204 +   if (!flagsendalive) {
       
  1205 +     /* qmail-send finaly exited, so do the same. */
       
  1206 +     if (flagstopasap) _exit(0);
       
  1207 +     /* qmail-send died. We can not log and we can not work therefor _exit(1). */
       
  1208 +     _exit(1);
       
  1209 +   }
       
  1210 +
       
  1211 +   wakeup = recent + SLEEP_FOREVER;
       
  1212 +   FD_ZERO(&rfds);
       
  1213 +   FD_ZERO(&wfds);
       
  1214 +   nfds = 1;
       
  1215 +
       
  1216 +   todo_selprep(&nfds,&rfds,&wakeup);
       
  1217 +   comm_selprep(&nfds,&wfds,&rfds);
       
  1218 +
       
  1219 +   if (wakeup <= recent) tv.tv_sec = 0;
       
  1220 +   else tv.tv_sec = wakeup - recent + SLEEP_FUZZ;
       
  1221 +   tv.tv_usec = 0;
       
  1222 +
       
  1223 +   if (select(nfds,&rfds,&wfds,(fd_set *) 0,&tv) == -1)
       
  1224 +     if (errno == error_intr)
       
  1225 +       ;
       
  1226 +     else
       
  1227 +       log1("warning: qmail-todo: trouble in select\n");
       
  1228 +   else
       
  1229 +    {
       
  1230 +     recent = now();
       
  1231 +
       
  1232 +     todo_do(&rfds);
       
  1233 +     comm_do(&wfds, &rfds);
       
  1234 +    }
       
  1235 +  }
       
  1236 +  /* NOTREACHED */
       
  1237 +}
       
  1238 +