updated on Mon Jan 16 00:01:41 UTC 2012
[aur-mirror.git] / qmail / ext_todo-20030105.patch
blobe82347799e060fed2b90f76bcb29c117ed73efd0
1 diff -u --new-file qmail-1.03-orig/EXTTODO qmail-1.03/EXTTODO
2 --- qmail-1.03-orig/EXTTODO 1969-12-31 21:00:00.000000000 -0300
3 +++ qmail-1.03/EXTTODO 2006-03-21 17:00:59.000000000 -0300
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.
9 +The EXTTODO patch is a part of the qmail-ldap patch.
10 +This patches for qmail come with NO WARRANTY.
12 +These patches are under the BSD license.
14 +RELEASE: 5. Jan. 2003
16 +EXTTODO:
17 +======================
19 +TOC:
20 + WHAT DOES IT DO
21 + INSTALL
22 + CONFIG FILES
23 + SETUP
24 + BIG PICTURE
26 +NEWS:
28 + This is the first release of the EXTTODO patch.
30 +================================================================================
32 +WHAT DOES IT DO
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.
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.
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.
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.
59 +INSTALL
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).
64 + NOTE: the exttodo patch can also be used on qmail systems without the
65 + qmail-ldap patch.
67 +================================================================================
69 +CONFIG FILES
71 + No additional control files are used or needed.
73 +================================================================================
75 +SETUP
77 + qmail-todo will be started by qmail-start and therefor no additional setup
78 + is needed.
80 + To verify that exttodo is running just check if qmail-todo is running.
82 +================================================================================
84 +BIG PICTURE
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 + +-------+
102 +Communication between qmail-send and qmail-todo
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.
115 +qmail-todo sends "\0" terminated messages whereas qmail-send just send one
116 +character to qmail-todo.
119 diff -u --new-file qmail-1.03-orig/EXTTODO-INFO qmail-1.03/EXTTODO-INFO
120 --- qmail-1.03-orig/EXTTODO-INFO 1969-12-31 21:00:00.000000000 -0300
121 +++ qmail-1.03/EXTTODO-INFO 2006-03-21 17:01:26.000000000 -0300
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
134 diff -u --new-file qmail-1.03-orig/FILES qmail-1.03/FILES
135 --- qmail-1.03-orig/FILES 2006-03-21 16:58:51.000000000 -0300
136 +++ qmail-1.03/FILES 2006-03-21 17:01:51.000000000 -0300
137 @@ -431,3 +431,4 @@
138 tcp-environ.5
139 constmap.h
140 constmap.c
141 +qmail-todo.c
142 diff -u --new-file qmail-1.03-orig/hier.c qmail-1.03/hier.c
143 --- qmail-1.03-orig/hier.c 2006-03-21 16:58:51.000000000 -0300
144 +++ qmail-1.03/hier.c 2006-03-21 17:05:28.000000000 -0300
145 @@ -133,6 +133,9 @@
146 c(auto_qmail,"bin","qmail-rspawn",auto_uido,auto_gidq,0711);
147 c(auto_qmail,"bin","qmail-clean",auto_uido,auto_gidq,0711);
148 c(auto_qmail,"bin","qmail-send",auto_uido,auto_gidq,0711);
149 +#ifdef EXTERNAL_TODO
150 + c(auto_qmail,"bin","qmail-todo",auto_uido,auto_gidq,0711);
151 +#endif
152 c(auto_qmail,"bin","splogger",auto_uido,auto_gidq,0711);
153 c(auto_qmail,"bin","qmail-newu",auto_uido,auto_gidq,0700);
154 c(auto_qmail,"bin","qmail-newmrh",auto_uido,auto_gidq,0700);
155 diff -u --new-file qmail-1.03-orig/install-big.c qmail-1.03/install-big.c
156 --- qmail-1.03-orig/install-big.c 2006-03-21 16:58:51.000000000 -0300
157 +++ qmail-1.03/install-big.c 2006-03-21 17:05:53.000000000 -0300
158 @@ -130,6 +130,9 @@
159 c(auto_qmail,"bin","qmail-rspawn",auto_uido,auto_gidq,0711);
160 c(auto_qmail,"bin","qmail-clean",auto_uido,auto_gidq,0711);
161 c(auto_qmail,"bin","qmail-send",auto_uido,auto_gidq,0711);
162 +#ifdef EXTERNAL_TODO
163 + c(auto_qmail,"bin","qmail-todo",auto_uido,auto_gidq,0711);
164 +#endif
165 c(auto_qmail,"bin","splogger",auto_uido,auto_gidq,0711);
166 c(auto_qmail,"bin","qmail-newu",auto_uido,auto_gidq,0700);
167 c(auto_qmail,"bin","qmail-newmrh",auto_uido,auto_gidq,0700);
168 diff -u --new-file qmail-1.03-orig/Makefile qmail-1.03/Makefile
169 --- qmail-1.03-orig/Makefile 2006-03-21 16:58:51.000000000 -0300
170 +++ qmail-1.03/Makefile 2006-03-21 17:04:19.000000000 -0300
171 @@ -1,5 +1,7 @@
172 # Don't edit Makefile! Use conf-* for configuration.
174 +DEFINES=-DEXTERNAL_TODO # use to enable external todo
176 SHELL=/bin/sh
178 default: it
179 @@ -671,7 +673,7 @@
181 hier.o: \
182 compile hier.c auto_split.h auto_uids.h fmt.h fifo.h
183 - ./compile hier.c
184 + ./compile $(DEFINES) hier.c
186 home: \
187 home.sh conf-qmail
188 @@ -774,7 +776,7 @@
189 forward preline condredirect bouncesaying except maildirmake make-owners \
190 maildir2mbox maildirwatch qail elq pinq idedit install-big install \
191 instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
192 -binm3 binm3+df
193 +binm3 binm3+df qmail-todo
195 load: \
196 make-load warn-auto.sh systype
197 @@ -1482,7 +1484,7 @@
198 scan.h case.h auto_qmail.h trigger.h newfield.h stralloc.h quote.h \
199 qmail.h substdio.h qsutil.h prioq.h datetime.h gen_alloc.h constmap.h \
200 fmtqfn.h readsubdir.h direntry.h
201 - ./compile qmail-send.c
202 + ./compile $(DEFINES) qmail-send.c
204 qmail-showctl: \
205 load qmail-showctl.o auto_uids.o control.o open.a getln.a stralloc.a \
206 @@ -1549,7 +1551,7 @@
208 qmail-start.o: \
209 compile qmail-start.c fd.h prot.h exit.h fork.h auto_uids.h
210 - ./compile qmail-start.c
211 + ./compile $(DEFINES) qmail-start.c
213 qmail-tcpok: \
214 load qmail-tcpok.o open.a lock.a strerr.a substdio.a error.a str.a \
215 @@ -1581,6 +1583,21 @@
216 fmt.h ip.h lock.h error.h exit.h datetime.h now.h datetime.h
217 ./compile qmail-tcpto.c
220 +qmail-todo: \
221 +load qmail-todo.o control.o constmap.o trigger.o fmtqfn.o now.o \
222 +readsubdir.o case.a ndelay.a getln.a sig.a open.a stralloc.a alloc.a \
223 +substdio.a error.a str.a fs.a auto_qmail.o auto_split.o
224 + ./load qmail-todo control.o constmap.o trigger.o fmtqfn.o now.o \
225 + readsubdir.o case.a ndelay.a getln.a sig.a open.a stralloc.a \
226 + alloc.a substdio.a error.a str.a fs.a auto_qmail.o auto_split.o
228 +qmail-todo.o: \
229 +compile alloc.h auto_qmail.h byte.h constmap.h control.h direntry.h error.h \
230 +exit.h fmt.h fmtqfn.h getln.h open.h ndelay.h now.h readsubdir.h readwrite.h \
231 +scan.h select.h str.h stralloc.h substdio.h trigger.h
232 + ./compile $(DEFINES) qmail-todo.c
234 qmail-upq: \
235 warn-auto.sh qmail-upq.sh conf-qmail conf-break conf-split
236 cat warn-auto.sh qmail-upq.sh \
237 Subdirectorios comunes: qmail-1.03-orig/qmail-rhinit y qmail-1.03/qmail-rhinit
238 diff -u --new-file qmail-1.03-orig/qmail-send.c qmail-1.03/qmail-send.c
239 --- qmail-1.03-orig/qmail-send.c 2006-03-21 16:58:51.000000000 -0300
240 +++ qmail-1.03/qmail-send.c 2006-03-21 17:12:01.000000000 -0300
241 @@ -1218,6 +1218,7 @@
243 /* this file is too long ---------------------------------------------- TODO */
245 +#ifndef EXTERNAL_TODO
246 datetime_sec nexttodorun;
247 int flagtododir = 0; /* if 0, have to readsubdir_init again */
248 readsubdir todosubdir;
249 @@ -1435,6 +1436,143 @@
250 if (fdchan[c] != -1) close(fdchan[c]);
253 +#endif
255 +/* this file is too long ------------------------------------- EXTERNAL TODO */
257 +#ifdef EXTERNAL_TODO
258 +stralloc todoline = {0};
259 +char todobuf[2048];
260 +int todofdin;
261 +int todofdout;
262 +int flagtodoalive;
264 +void tododied() { log1("alert: oh no! lost qmail-todo connection! dying...\n");
265 + flagexitasap = 1; flagtodoalive = 0; }
267 +void todo_init()
269 + todofdout = 7;
270 + todofdin = 8;
271 + flagtodoalive = 1;
272 + /* sync with external todo */
273 + if (write(todofdout, "S", 1) != 1) tododied();
275 + return;
278 +void todo_selprep(nfds,rfds,wakeup)
279 +int *nfds;
280 +fd_set *rfds;
281 +datetime_sec *wakeup;
283 + if (flagexitasap) {
284 + if (flagtodoalive) {
285 + write(todofdout, "X", 1);
288 + if (flagtodoalive) {
289 + FD_SET(todofdin,rfds);
290 + if (*nfds <= todofdin)
291 + *nfds = todofdin + 1;
295 +void todo_del(char* s)
297 + int flagchan[CHANNELS];
298 + struct prioq_elt pe;
299 + unsigned long id;
300 + unsigned int len;
301 + int c;
303 + for (c = 0;c < CHANNELS;++c) flagchan[c] = 0;
304 + switch(*s++) {
305 + case 'L':
306 + flagchan[0] = 1;
307 + break;
308 + case 'R':
309 + flagchan[1] = 1;
310 + break;
311 + case 'B':
312 + flagchan[0] = 1;
313 + flagchan[1] = 1;
314 + break;
315 + case 'X':
316 + break;
317 + default:
318 + log1("warning: qmail-send unable to understand qmail-todo\n");
319 + return;
322 + len = scan_ulong(s,&id);
323 + if (!len || s[len]) {
324 + log1("warning: qmail-send unable to understand qmail-todo\n");
325 + return;
328 + pe.id = id; pe.dt = now();
329 + for (c = 0;c < CHANNELS;++c)
330 + if (flagchan[c])
331 + while (!prioq_insert(&pqchan[c],&pe)) nomem();
333 + for (c = 0;c < CHANNELS;++c) if (flagchan[c]) break;
334 + if (c == CHANNELS)
335 + while (!prioq_insert(&pqdone,&pe)) nomem();
337 + return;
340 +void todo_do(rfds)
341 +fd_set *rfds;
343 + int r;
344 + char ch;
345 + int i;
347 + if (!flagtodoalive) return;
348 + if (!FD_ISSET(todofdin,rfds)) return;
350 + r = read(todofdin,todobuf,sizeof(todobuf));
351 + if (r == -1) return;
352 + if (r == 0) {
353 + if (flagexitasap)
354 + flagtodoalive = 0;
355 + else
356 + tododied();
357 + return;
359 + for (i = 0;i < r;++i) {
360 + ch = todobuf[i];
361 + while (!stralloc_append(&todoline,&ch)) nomem();
362 + if (todoline.len > REPORTMAX)
363 + todoline.len = REPORTMAX;
364 + /* qmail-todo is responsible for keeping it short */
365 + if (!ch && (todoline.len > 1)) {
366 + switch (todoline.s[0]) {
367 + case 'D':
368 + if (flagexitasap) break;
369 + todo_del(todoline.s + 1);
370 + break;
371 + case 'L':
372 + log1(todoline.s + 1);
373 + break;
374 + case 'X':
375 + if (flagexitasap)
376 + flagtodoalive = 0;
377 + else
378 + tododied();
379 + break;
380 + default:
381 + log1("warning: qmail-send unable to understand qmail-todo: report mangled\n");
382 + break;
384 + todoline.len = 0;
389 +#endif
391 /* this file is too long ---------------------------------------------- MAIN */
393 @@ -1501,6 +1639,9 @@
394 log1("alert: unable to reread controls: unable to switch to home directory\n");
395 return;
397 +#ifdef EXTERNAL_TODO
398 + write(todofdout, "H", 1);
399 +#endif
400 regetcontrols();
401 while (chdir("queue") == -1)
403 @@ -1571,7 +1712,11 @@
404 todo_init();
405 cleanup_init();
407 +#ifdef EXTERNAL_TODO
408 + while (!flagexitasap || !del_canexit() || flagtodoalive)
409 +#else
410 while (!flagexitasap || !del_canexit())
411 +#endif
413 recent = now();
415 diff -u --new-file qmail-1.03-orig/qmail-start.c qmail-1.03/qmail-start.c
416 --- qmail-1.03-orig/qmail-start.c 2006-03-21 16:58:51.000000000 -0300
417 +++ qmail-1.03/qmail-start.c 2006-03-21 17:14:50.000000000 -0300
418 @@ -8,6 +8,9 @@
419 char *(qcargs[]) = { "qmail-clean", 0 };
420 char *(qlargs[]) = { "qmail-lspawn", "./Mailbox", 0 };
421 char *(qrargs[]) = { "qmail-rspawn", 0 };
422 +#ifdef EXTERNAL_TODO
423 +char *(qtargs[]) = { "qmail-todo", 0};
424 +#endif
426 void die() { _exit(111); }
428 @@ -19,12 +22,27 @@
429 int pi5[2];
430 int pi6[2];
432 -void close23456() { close(2); close(3); close(4); close(5); close(6); }
434 +#ifdef EXTERNAL_TODO
435 +int pi7[2];
436 +int pi8[2];
437 +int pi9[2];
438 +int pi10[2];
439 +#endif
441 +void close23456() {
442 + close(2); close(3); close(4); close(5); close(6);
443 +#ifdef EXTERNAL_TODO
444 + close(7); close(8);
445 +#endif
447 void closepipes() {
448 close(pi1[0]); close(pi1[1]); close(pi2[0]); close(pi2[1]);
449 close(pi3[0]); close(pi3[1]); close(pi4[0]); close(pi4[1]);
450 close(pi5[0]); close(pi5[1]); close(pi6[0]); close(pi6[1]);
451 +#ifdef EXTERNAL_TODO
452 + close(pi7[0]); close(pi7[1]); close(pi8[0]); close(pi8[1]);
453 + close(pi9[0]); close(pi9[1]); close(pi10[0]); close(pi10[1]);
454 +#endif
457 void main(argc,argv)
458 @@ -40,7 +58,10 @@
459 if (fd_copy(4,0) == -1) die();
460 if (fd_copy(5,0) == -1) die();
461 if (fd_copy(6,0) == -1) die();
463 +#ifdef EXTERNAL_TODO
464 + if (fd_copy(7,0) == -1) die();
465 + if (fd_copy(8,0) == -1) die();
466 +#endif
467 if (argv[1]) {
468 qlargs[1] = argv[1];
469 ++argv;
470 @@ -70,7 +91,12 @@
471 if (pipe(pi4) == -1) die();
472 if (pipe(pi5) == -1) die();
473 if (pipe(pi6) == -1) die();
475 +#ifdef EXTERNAL_TODO
476 + if (pipe(pi7) == -1) die();
477 + if (pipe(pi8) == -1) die();
478 + if (pipe(pi9) == -1) die();
479 + if (pipe(pi10) == -1) die();
480 +#endif
481 switch(fork()) {
482 case -1: die();
483 case 0:
484 @@ -105,6 +131,34 @@
485 execvp(*qcargs,qcargs);
486 die();
489 +#ifdef EXTERNAL_TODO
490 + switch(fork()) {
491 + case -1: die();
492 + case 0:
493 + if (prot_uid(auto_uids) == -1) die();
494 + if (fd_copy(0,pi7[0]) == -1) die();
495 + if (fd_copy(1,pi8[1]) == -1) die();
496 + close23456();
497 + if (fd_copy(2,pi9[1]) == -1) die();
498 + if (fd_copy(3,pi10[0]) == -1) die();
499 + closepipes();
500 + execvp(*qtargs,qtargs);
501 + die();
504 + switch(fork()) {
505 + case -1: die();
506 + case 0:
507 + if (prot_uid(auto_uidq) == -1) die();
508 + if (fd_copy(0,pi9[0]) == -1) die();
509 + if (fd_copy(1,pi10[1]) == -1) die();
510 + close23456();
511 + closepipes();
512 + execvp(*qcargs,qcargs);
513 + die();
515 +#endif
517 if (prot_uid(auto_uids) == -1) die();
518 if (fd_copy(0,1) == -1) die();
519 @@ -114,6 +168,10 @@
520 if (fd_copy(4,pi4[0]) == -1) die();
521 if (fd_copy(5,pi5[1]) == -1) die();
522 if (fd_copy(6,pi6[0]) == -1) die();
523 +#ifdef EXTERNAL_TODO
524 + if (fd_copy(7,pi7[1]) == -1) die();
525 + if (fd_copy(8,pi8[0]) == -1) die();
526 +#endif
527 closepipes();
528 execvp(*qsargs,qsargs);
529 die();
530 diff -u --new-file qmail-1.03-orig/qmail-todo.c qmail-1.03/qmail-todo.c
531 --- qmail-1.03-orig/qmail-todo.c 1969-12-31 21:00:00.000000000 -0300
532 +++ qmail-1.03/qmail-todo.c 2006-03-21 17:15:17.000000000 -0300
533 @@ -0,0 +1,689 @@
534 +#include <sys/types.h>
535 +#include <sys/stat.h>
536 +#include "alloc.h"
537 +#include "auto_qmail.h"
538 +#include "byte.h"
539 +#include "constmap.h"
540 +#include "control.h"
541 +#include "direntry.h"
542 +#include "error.h"
543 +#include "exit.h"
544 +#include "fmt.h"
545 +#include "fmtqfn.h"
546 +#include "getln.h"
547 +#include "open.h"
548 +#include "ndelay.h"
549 +#include "now.h"
550 +#include "readsubdir.h"
551 +#include "readwrite.h"
552 +#include "scan.h"
553 +#include "select.h"
554 +#include "str.h"
555 +#include "stralloc.h"
556 +#include "substdio.h"
557 +#include "trigger.h"
559 +/* critical timing feature #1: if not triggered, do not busy-loop */
560 +/* critical timing feature #2: if triggered, respond within fixed time */
561 +/* important timing feature: when triggered, respond instantly */
562 +#define SLEEP_TODO 1500 /* check todo/ every 25 minutes in any case */
563 +#define SLEEP_FUZZ 1 /* slop a bit on sleeps to avoid zeno effect */
564 +#define SLEEP_FOREVER 86400 /* absolute maximum time spent in select() */
565 +#define SLEEP_SYSFAIL 123
567 +stralloc percenthack = {0};
568 +struct constmap mappercenthack;
569 +stralloc locals = {0};
570 +struct constmap maplocals;
571 +stralloc vdoms = {0};
572 +struct constmap mapvdoms;
573 +stralloc envnoathost = {0};
575 +char strnum[FMT_ULONG];
577 +/* XXX not good, if qmail-send.c changes this has to be updated */
578 +#define CHANNELS 2
579 +char *chanaddr[CHANNELS] = { "local/", "remote/" };
581 +datetime_sec recent;
583 +void log1(char *x);
584 +void log3(char* x, char* y, char* z);
586 +int flagstopasap = 0;
587 +void sigterm(void)
589 + if (flagstopasap == 0)
590 + log1("status: qmail-todo stop processing asap\n");
591 + flagstopasap = 1;
594 +int flagreadasap = 0; void sighup(void) { flagreadasap = 1; }
595 +int flagsendalive = 1; void senddied(void) { flagsendalive = 0; }
597 +void nomem() { log1("alert: out of memory, sleeping...\n"); sleep(10); }
598 +void pausedir(dir) char *dir;
599 +{ log3("alert: unable to opendir ",dir,", sleeping...\n"); sleep(10); }
601 +void cleandied()
603 + log1("alert: qmail-todo: oh no! lost qmail-clean connection! dying...\n");
604 + flagstopasap = 1;
608 +/* this file is not so long ------------------------------------- FILENAMES */
610 +stralloc fn = {0};
612 +void fnmake_init(void)
614 + while (!stralloc_ready(&fn,FMTQFN)) nomem();
617 +void fnmake_info(unsigned long id) { fn.len = fmtqfn(fn.s,"info/",id,1); }
618 +void fnmake_todo(unsigned long id) { fn.len = fmtqfn(fn.s,"todo/",id,0); }
619 +void fnmake_mess(unsigned long id) { fn.len = fmtqfn(fn.s,"mess/",id,1); }
620 +void fnmake_chanaddr(unsigned long id, int c)
621 +{ fn.len = fmtqfn(fn.s,chanaddr[c],id,1); }
624 +/* this file is not so long ------------------------------------- REWRITING */
626 +stralloc rwline = {0};
628 +/* 1 if by land, 2 if by sea, 0 if out of memory. not allowed to barf. */
629 +/* may trash recip. must set up rwline, between a T and a \0. */
630 +int rewrite(char *recip)
632 + int i;
633 + int j;
634 + char *x;
635 + static stralloc addr = {0};
636 + int at;
638 + if (!stralloc_copys(&rwline,"T")) return 0;
639 + if (!stralloc_copys(&addr,recip)) return 0;
641 + i = byte_rchr(addr.s,addr.len,'@');
642 + if (i == addr.len) {
643 + if (!stralloc_cats(&addr,"@")) return 0;
644 + if (!stralloc_cat(&addr,&envnoathost)) return 0;
647 + while (constmap(&mappercenthack,addr.s + i + 1,addr.len - i - 1)) {
648 + j = byte_rchr(addr.s,i,'%');
649 + if (j == i) break;
650 + addr.len = i;
651 + i = j;
652 + addr.s[i] = '@';
655 + at = byte_rchr(addr.s,addr.len,'@');
657 + if (constmap(&maplocals,addr.s + at + 1,addr.len - at - 1)) {
658 + if (!stralloc_cat(&rwline,&addr)) return 0;
659 + if (!stralloc_0(&rwline)) return 0;
660 + return 1;
663 + for (i = 0;i <= addr.len;++i)
664 + if (!i || (i == at + 1) || (i == addr.len) || ((i > at) && (addr.s[i] == '.')))
665 + if (x = constmap(&mapvdoms,addr.s + i,addr.len - i)) {
666 + if (!*x) break;
667 + if (!stralloc_cats(&rwline,x)) return 0;
668 + if (!stralloc_cats(&rwline,"-")) return 0;
669 + if (!stralloc_cat(&rwline,&addr)) return 0;
670 + if (!stralloc_0(&rwline)) return 0;
671 + return 1;
674 + if (!stralloc_cat(&rwline,&addr)) return 0;
675 + if (!stralloc_0(&rwline)) return 0;
676 + return 2;
679 +/* this file is not so long --------------------------------- COMMUNICATION */
681 +substdio sstoqc; char sstoqcbuf[1024];
682 +substdio ssfromqc; char ssfromqcbuf[1024];
683 +stralloc comm_buf = {0};
684 +int comm_pos;
685 +int fdout = -1;
686 +int fdin = -1;
688 +void comm_init(void)
690 + substdio_fdbuf(&sstoqc,write,2,sstoqcbuf,sizeof(sstoqcbuf));
691 + substdio_fdbuf(&ssfromqc,read,3,ssfromqcbuf,sizeof(ssfromqcbuf));
693 + fdout = 1; /* stdout */
694 + fdin = 0; /* stdin */
695 + if (ndelay_on(fdout) == -1)
696 + /* this is so stupid: NDELAY semantics should be default on write */
697 + senddied(); /* drastic, but better than risking deadlock */
699 + while (!stralloc_ready(&comm_buf,1024)) nomem();
702 +int comm_canwrite(void)
704 + /* XXX: could allow a bigger buffer; say 10 recipients */
705 + /* XXX: returns true if there is something in the buffer */
706 + if (!flagsendalive) return 0;
707 + if (comm_buf.s && comm_buf.len) return 1;
708 + return 0;
711 +void log1(char* x)
713 + int pos;
715 + pos = comm_buf.len;
716 + if (!stralloc_cats(&comm_buf,"L")) goto fail;
717 + if (!stralloc_cats(&comm_buf,x)) goto fail;
718 + if (!stralloc_0(&comm_buf)) goto fail;
719 + return;
721 +fail:
722 + /* either all or nothing */
723 + comm_buf.len = pos;
726 +void log3(char* x, char *y, char *z)
728 + int pos;
730 + pos = comm_buf.len;
731 + if (!stralloc_cats(&comm_buf,"L")) goto fail;
732 + if (!stralloc_cats(&comm_buf,x)) goto fail;
733 + if (!stralloc_cats(&comm_buf,y)) goto fail;
734 + if (!stralloc_cats(&comm_buf,z)) goto fail;
735 + if (!stralloc_0(&comm_buf)) goto fail;
736 + return;
738 +fail:
739 + /* either all or nothing */
740 + comm_buf.len = pos;
743 +void comm_write(unsigned long id, int local, int remote)
745 + int pos;
746 + char *s;
748 + if(local && remote) s="B";
749 + else if(local) s="L";
750 + else if(remote) s="R";
751 + else s="X";
753 + pos = comm_buf.len;
754 + strnum[fmt_ulong(strnum,id)] = 0;
755 + if (!stralloc_cats(&comm_buf,"D")) goto fail;
756 + if (!stralloc_cats(&comm_buf,s)) goto fail;
757 + if (!stralloc_cats(&comm_buf,strnum)) goto fail;
758 + if (!stralloc_0(&comm_buf)) goto fail;
759 + return;
761 +fail:
762 + /* either all or nothing */
763 + comm_buf.len = pos;
766 +static int issafe(char ch)
768 + if (ch == '%') return 0; /* general principle: allman's code is crap */
769 + if (ch < 33) return 0;
770 + if (ch > 126) return 0;
771 + return 1;
774 +void comm_info(unsigned long id, unsigned long size, char* from, unsigned long pid, unsigned long uid)
776 + int pos;
777 + int i;
779 + pos = comm_buf.len;
780 + if (!stralloc_cats(&comm_buf,"Linfo msg ")) goto fail;
781 + strnum[fmt_ulong(strnum,id)] = 0;
782 + if (!stralloc_cats(&comm_buf,strnum)) goto fail;
783 + if (!stralloc_cats(&comm_buf,": bytes ")) goto fail;
784 + strnum[fmt_ulong(strnum,size)] = 0;
785 + if (!stralloc_cats(&comm_buf,strnum)) goto fail;
786 + if (!stralloc_cats(&comm_buf," from <")) goto fail;
787 + i = comm_buf.len;
788 + if (!stralloc_cats(&comm_buf,from)) goto fail;
789 + for (;i < comm_buf.len;++i)
790 + if (comm_buf.s[i] == '\n')
791 + comm_buf.s[i] = '/';
792 + else
793 + if (!issafe(comm_buf.s[i]))
794 + comm_buf.s[i] = '_';
795 + if (!stralloc_cats(&comm_buf,"> qp ")) goto fail;
796 + strnum[fmt_ulong(strnum,pid)] = 0;
797 + if (!stralloc_cats(&comm_buf,strnum)) goto fail;
798 + if (!stralloc_cats(&comm_buf," uid ")) goto fail;
799 + strnum[fmt_ulong(strnum,uid)] = 0;
800 + if (!stralloc_cats(&comm_buf,strnum)) goto fail;
801 + if (!stralloc_cats(&comm_buf,"\n")) goto fail;
802 + if (!stralloc_0(&comm_buf)) goto fail;
803 + return;
805 +fail:
806 + /* either all or nothing */
807 + comm_buf.len = pos;
810 +void comm_exit(void)
812 + int w;
814 + /* if it fails exit, we have already stoped */
815 + if (!stralloc_cats(&comm_buf,"X")) _exit(1);
816 + if (!stralloc_0(&comm_buf)) _exit(1);
819 +void comm_selprep(int *nfds, fd_set *wfds, fd_set *rfds)
821 + if (flagsendalive) {
822 + if (flagstopasap && comm_canwrite() == 0)
823 + comm_exit();
824 + if (comm_canwrite()) {
825 + FD_SET(fdout,wfds);
826 + if (*nfds <= fdout)
827 + *nfds = fdout + 1;
829 + FD_SET(fdin,rfds);
830 + if (*nfds <= fdin)
831 + *nfds = fdin + 1;
835 +void comm_do(fd_set *wfds, fd_set *rfds)
837 + /* first write then read */
838 + if (flagsendalive)
839 + if (comm_canwrite())
840 + if (FD_ISSET(fdout,wfds)) {
841 + int w;
842 + int len;
843 + len = comm_buf.len;
844 + w = write(fdout,comm_buf.s + comm_pos,len - comm_pos);
845 + if (w <= 0) {
846 + if ((w == -1) && (errno == error_pipe))
847 + senddied();
848 + } else {
849 + comm_pos += w;
850 + if (comm_pos == len) {
851 + comm_buf.len = 0;
852 + comm_pos = 0;
856 + if (flagsendalive)
857 + if (FD_ISSET(fdin,rfds)) {
858 + /* there are only two messages 'H' and 'X' */
859 + char c;
860 + int r;
861 + r = read(fdin, &c, 1);
862 + if (r <= 0) {
863 + if ((r == -1) && (errno != error_intr))
864 + senddied();
865 + } else {
866 + switch(c) {
867 + case 'H':
868 + sighup();
869 + break;
870 + case 'X':
871 + sigterm();
872 + break;
873 + default:
874 + log1("warning: qmail-todo: qmail-send speaks an obscure dialect\n");
875 + break;
881 +/* this file is not so long ------------------------------------------ TODO */
883 +datetime_sec nexttodorun;
884 +DIR *tododir; /* if 0, have to opendir again */
885 +stralloc todoline = {0};
886 +char todobuf[SUBSTDIO_INSIZE];
887 +char todobufinfo[512];
888 +char todobufchan[CHANNELS][1024];
890 +void todo_init(void)
892 + tododir = 0;
893 + nexttodorun = now();
894 + trigger_set();
897 +void todo_selprep(int *nfds, fd_set *rfds, datetime_sec *wakeup)
899 + if (flagstopasap) return;
900 + trigger_selprep(nfds,rfds);
901 + if (tododir) *wakeup = 0;
902 + if (*wakeup > nexttodorun) *wakeup = nexttodorun;
905 +void todo_do(fd_set *rfds)
907 + struct stat st;
908 + substdio ss; int fd;
909 + substdio ssinfo; int fdinfo;
910 + substdio sschan[CHANNELS];
911 + int fdchan[CHANNELS];
912 + int flagchan[CHANNELS];
913 + char ch;
914 + int match;
915 + unsigned long id;
916 + unsigned int len;
917 + direntry *d;
918 + int c;
919 + unsigned long uid;
920 + unsigned long pid;
922 + fd = -1;
923 + fdinfo = -1;
924 + for (c = 0;c < CHANNELS;++c) fdchan[c] = -1;
926 + if (flagstopasap) return;
928 + if (!tododir)
930 + if (!trigger_pulled(rfds))
931 + if (recent < nexttodorun)
932 + return;
933 + trigger_set();
934 + tododir = opendir("todo");
935 + if (!tododir)
937 + pausedir("todo");
938 + return;
940 + nexttodorun = recent + SLEEP_TODO;
943 + d = readdir(tododir);
944 + if (!d)
946 + closedir(tododir);
947 + tododir = 0;
948 + return;
950 + if (str_equal(d->d_name,".")) return;
951 + if (str_equal(d->d_name,"..")) return;
952 + len = scan_ulong(d->d_name,&id);
953 + if (!len || d->d_name[len]) return;
955 + fnmake_todo(id);
957 + fd = open_read(fn.s);
958 + if (fd == -1) { log3("warning: qmail-todo: unable to open ",fn.s,"\n"); return; }
960 + fnmake_mess(id);
961 + /* just for the statistics */
962 + if (stat(fn.s,&st) == -1)
963 + { log3("warning: qmail-todo: unable to stat ",fn.s,"\n"); goto fail; }
965 + for (c = 0;c < CHANNELS;++c)
967 + fnmake_chanaddr(id,c);
968 + if (unlink(fn.s) == -1) if (errno != error_noent)
969 + { log3("warning: qmail-todo: unable to unlink ",fn.s,"\n"); goto fail; }
972 + fnmake_info(id);
973 + if (unlink(fn.s) == -1) if (errno != error_noent)
974 + { log3("warning: qmail-todo: unable to unlink ",fn.s,"\n"); goto fail; }
976 + fdinfo = open_excl(fn.s);
977 + if (fdinfo == -1)
978 + { log3("warning: qmail-todo: unable to create ",fn.s,"\n"); goto fail; }
980 + strnum[fmt_ulong(strnum,id)] = 0;
981 + log3("new msg ",strnum,"\n");
983 + for (c = 0;c < CHANNELS;++c) flagchan[c] = 0;
985 + substdio_fdbuf(&ss,read,fd,todobuf,sizeof(todobuf));
986 + substdio_fdbuf(&ssinfo,write,fdinfo,todobufinfo,sizeof(todobufinfo));
988 + uid = 0;
989 + pid = 0;
991 + for (;;)
993 + if (getln(&ss,&todoline,&match,'\0') == -1)
995 + /* perhaps we're out of memory, perhaps an I/O error */
996 + fnmake_todo(id);
997 + log3("warning: qmail-todo: trouble reading ",fn.s,"\n"); goto fail;
999 + if (!match) break;
1001 + switch(todoline.s[0])
1003 + case 'u':
1004 + scan_ulong(todoline.s + 1,&uid);
1005 + break;
1006 + case 'p':
1007 + scan_ulong(todoline.s + 1,&pid);
1008 + break;
1009 + case 'F':
1010 + if (substdio_putflush(&ssinfo,todoline.s,todoline.len) == -1)
1012 + fnmake_info(id);
1013 + log3("warning: qmail-todo: trouble writing to ",fn.s,"\n"); goto fail;
1015 + comm_info(id, (unsigned long) st.st_size, todoline.s + 1, pid, uid);
1016 + break;
1017 + case 'T':
1018 + switch(rewrite(todoline.s + 1))
1020 + case 0: nomem(); goto fail;
1021 + case 2: c = 1; break;
1022 + default: c = 0; break;
1024 + if (fdchan[c] == -1)
1026 + fnmake_chanaddr(id,c);
1027 + fdchan[c] = open_excl(fn.s);
1028 + if (fdchan[c] == -1)
1029 + { log3("warning: qmail-todo: unable to create ",fn.s,"\n"); goto fail; }
1030 + substdio_fdbuf(&sschan[c]
1031 + ,write,fdchan[c],todobufchan[c],sizeof(todobufchan[c]));
1032 + flagchan[c] = 1;
1034 + if (substdio_bput(&sschan[c],rwline.s,rwline.len) == -1)
1036 + fnmake_chanaddr(id,c);
1037 + log3("warning: qmail-todo: trouble writing to ",fn.s,"\n"); goto fail;
1039 + break;
1040 + default:
1041 + fnmake_todo(id);
1042 + log3("warning: qmail-todo: unknown record type in ",fn.s,"\n"); goto fail;
1046 + close(fd); fd = -1;
1048 + fnmake_info(id);
1049 + if (substdio_flush(&ssinfo) == -1)
1050 + { log3("warning: qmail-todo: trouble writing to ",fn.s,"\n"); goto fail; }
1051 + if (fsync(fdinfo) == -1)
1052 + { log3("warning: qmail-todo: trouble fsyncing ",fn.s,"\n"); goto fail; }
1053 + close(fdinfo); fdinfo = -1;
1055 + for (c = 0;c < CHANNELS;++c)
1056 + if (fdchan[c] != -1)
1058 + fnmake_chanaddr(id,c);
1059 + if (substdio_flush(&sschan[c]) == -1)
1060 + { log3("warning: qmail-todo: trouble writing to ",fn.s,"\n"); goto fail; }
1061 + if (fsync(fdchan[c]) == -1)
1062 + { log3("warning: qmail-todo: trouble fsyncing ",fn.s,"\n"); goto fail; }
1063 + close(fdchan[c]); fdchan[c] = -1;
1066 + fnmake_todo(id);
1067 + if (substdio_putflush(&sstoqc,fn.s,fn.len) == -1) { cleandied(); return; }
1068 + if (substdio_get(&ssfromqc,&ch,1) != 1) { cleandied(); return; }
1069 + if (ch != '+')
1071 + log3("warning: qmail-clean unable to clean up ",fn.s,"\n");
1072 + return;
1075 + comm_write(id, flagchan[0], flagchan[1]);
1077 + return;
1079 + fail:
1080 + if (fd != -1) close(fd);
1081 + if (fdinfo != -1) close(fdinfo);
1082 + for (c = 0;c < CHANNELS;++c)
1083 + if (fdchan[c] != -1) close(fdchan[c]);
1086 +/* this file is too long ---------------------------------------------- MAIN */
1088 +int getcontrols(void)
1090 + if (control_init() == -1) return 0;
1091 + if (control_rldef(&envnoathost,"control/envnoathost",1,"envnoathost") != 1) return 0;
1092 + if (control_readfile(&locals,"control/locals",1) != 1) return 0;
1093 + if (!constmap_init(&maplocals,locals.s,locals.len,0)) return 0;
1094 + switch(control_readfile(&percenthack,"control/percenthack",0))
1096 + case -1: return 0;
1097 + case 0: if (!constmap_init(&mappercenthack,"",0,0)) return 0; break;
1098 + case 1: if (!constmap_init(&mappercenthack,percenthack.s,percenthack.len,0)) return 0; break;
1100 + switch(control_readfile(&vdoms,"control/virtualdomains",0))
1102 + case -1: return 0;
1103 + case 0: if (!constmap_init(&mapvdoms,"",0,1)) return 0; break;
1104 + case 1: if (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) return 0; break;
1106 + return 1;
1109 +stralloc newlocals = {0};
1110 +stralloc newvdoms = {0};
1112 +void regetcontrols(void)
1114 + int r;
1116 + if (control_readfile(&newlocals,"control/locals",1) != 1)
1117 + { log1("alert: qmail-todo: unable to reread control/locals\n"); return; }
1118 + r = control_readfile(&newvdoms,"control/virtualdomains",0);
1119 + if (r == -1)
1120 + { log1("alert: qmail-todo: unable to reread control/virtualdomains\n"); return; }
1122 + constmap_free(&maplocals);
1123 + constmap_free(&mapvdoms);
1125 + while (!stralloc_copy(&locals,&newlocals)) nomem();
1126 + while (!constmap_init(&maplocals,locals.s,locals.len,0)) nomem();
1128 + if (r)
1130 + while (!stralloc_copy(&vdoms,&newvdoms)) nomem();
1131 + while (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) nomem();
1133 + else
1134 + while (!constmap_init(&mapvdoms,"",0,1)) nomem();
1137 +void reread(void)
1139 + if (chdir(auto_qmail) == -1)
1141 + log1("alert: qmail-todo: unable to reread controls: unable to switch to home directory\n");
1142 + return;
1144 + regetcontrols();
1145 + while (chdir("queue") == -1)
1147 + log1("alert: qmail-todo: unable to switch back to queue directory; HELP! sleeping...\n");
1148 + sleep(10);
1152 +void main()
1154 + datetime_sec wakeup;
1155 + fd_set rfds;
1156 + fd_set wfds;
1157 + int nfds;
1158 + struct timeval tv;
1159 + int r;
1160 + char c;
1162 + if (chdir(auto_qmail) == -1)
1163 + { log1("alert: qmail-todo: cannot start: unable to switch to home directory\n"); _exit(111); }
1164 + if (!getcontrols())
1165 + { log1("alert: qmail-todo: cannot start: unable to read controls\n"); _exit(111); }
1166 + if (chdir("queue") == -1)
1167 + { log1("alert: qmail-todo: cannot start: unable to switch to queue directory\n"); _exit(111); }
1168 + sig_pipeignore();
1169 + umask(077);
1171 + fnmake_init();
1173 + todo_init();
1174 + comm_init();
1176 + do {
1177 + r = read(fdin, &c, 1);
1178 + if ((r == -1) && (errno != error_intr))
1179 + _exit(100); /* read failed probably qmail-send died */
1180 + } while (r =! 1); /* we assume it is a 'S' */
1182 + for (;;)
1184 + recent = now();
1186 + if (flagreadasap) { flagreadasap = 0; reread(); }
1187 + if (!flagsendalive) {
1188 + /* qmail-send finaly exited, so do the same. */
1189 + if (flagstopasap) _exit(0);
1190 + /* qmail-send died. We can not log and we can not work therefor _exit(1). */
1191 + _exit(1);
1194 + wakeup = recent + SLEEP_FOREVER;
1195 + FD_ZERO(&rfds);
1196 + FD_ZERO(&wfds);
1197 + nfds = 1;
1199 + todo_selprep(&nfds,&rfds,&wakeup);
1200 + comm_selprep(&nfds,&wfds,&rfds);
1202 + if (wakeup <= recent) tv.tv_sec = 0;
1203 + else tv.tv_sec = wakeup - recent + SLEEP_FUZZ;
1204 + tv.tv_usec = 0;
1206 + if (select(nfds,&rfds,&wfds,(fd_set *) 0,&tv) == -1)
1207 + if (errno == error_intr)
1209 + else
1210 + log1("warning: qmail-todo: trouble in select\n");
1211 + else
1213 + recent = now();
1215 + todo_do(&rfds);
1216 + comm_do(&wfds, &rfds);
1219 + /* NOTREACHED */
1223 diff -u --new-file qmail-1.03-orig/TARGETS qmail-1.03/TARGETS
1224 --- qmail-1.03-orig/TARGETS 2006-03-21 16:58:51.000000000 -0300
1225 +++ qmail-1.03/TARGETS 2006-03-21 17:04:41.000000000 -0300
1226 @@ -381,3 +381,6 @@
1228 setup
1229 check
1230 +qmail-todo.o
1231 +qmail-todo