chiark / gitweb /
Merge branches 'idx/verh' and 'idx/qmqpc'
[qmail] / qmail-queue.c
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include "readwrite.h"
4 #include "sig.h"
5 #include "exit.h"
6 #include "open.h"
7 #include "seek.h"
8 #include "fmt.h"
9 #include "alloc.h"
10 #include "substdio.h"
11 #include "datetime.h"
12 #include "now.h"
13 #include "triggerpull.h"
14 #include "extra.h"
15 #include "auto_qmail.h"
16 #include "auto_uids.h"
17 #include "date822fmt.h"
18 #include "fmtqfn.h"
19
20 #define DEATH 86400 /* 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */
21 #define ADDR 1003
22
23 char inbuf[2048];
24 struct substdio ssin;
25 char outbuf[256];
26 struct substdio ssout;
27
28 datetime_sec starttime;
29 struct datetime dt;
30 unsigned long mypid;
31 unsigned long uid;
32 char *pidfn;
33 struct stat pidst;
34 unsigned long messnum;
35 char *messfn;
36 char *todofn;
37 char *intdfn;
38 int messfd;
39 int intdfd;
40 int flagmademess = 0;
41 int flagmadeintd = 0;
42
43 void cleanup()
44 {
45  if (flagmadeintd)
46   {
47    seek_trunc(intdfd,0);
48    if (unlink(intdfn) == -1) return;
49   }
50  if (flagmademess)
51   {
52    seek_trunc(messfd,0);
53    if (unlink(messfn) == -1) return;
54   }
55 }
56
57 void die(e) int e; { _exit(e); }
58 void die_write() { cleanup(); die(53); }
59 void die_read() { cleanup(); die(54); }
60 void sigalrm() { /* thou shalt not clean up here */ die(52); }
61 void sigbug() { die(81); }
62
63 unsigned int receivedlen;
64 char *received;
65 /* "Received: (qmail-queue invoked by alias); 26 Sep 1995 04:46:54 -0000\n" */
66
67 static unsigned int receivedfmt(s)
68 char *s;
69 {
70  unsigned int i;
71  unsigned int len;
72  len = 0;
73  i = fmt_str(s,"Received: (qmail "); len += i; if (s) s += i;
74  i = fmt_ulong(s,mypid); len += i; if (s) s += i;
75  i = fmt_str(s," invoked "); len += i; if (s) s += i;
76  if (uid == auto_uida)
77   { i = fmt_str(s,"by alias"); len += i; if (s) s += i; }
78  else if (uid == auto_uidd)
79   { i = fmt_str(s,"from network"); len += i; if (s) s += i; }
80  else if (uid == auto_uids)
81   { i = fmt_str(s,"for bounce"); len += i; if (s) s += i; }
82  else
83   {
84    i = fmt_str(s,"by uid "); len += i; if (s) s += i;
85    i = fmt_ulong(s,uid); len += i; if (s) s += i;
86   }
87  i = fmt_str(s,"); "); len += i; if (s) s += i;
88  i = date822fmt(s,&dt); len += i; if (s) s += i;
89  return len;
90 }
91
92 void received_setup()
93 {
94  receivedlen = receivedfmt((char *) 0);
95  received = alloc(receivedlen + 1);
96  if (!received) die(51);
97  receivedfmt(received);
98 }
99
100 unsigned int pidfmt(s,seq)
101 char *s;
102 unsigned long seq;
103 {
104  unsigned int i;
105  unsigned int len;
106
107  len = 0;
108  i = fmt_str(s,"pid/"); len += i; if (s) s += i;
109  i = fmt_ulong(s,mypid); len += i; if (s) s += i;
110  i = fmt_str(s,"."); len += i; if (s) s += i;
111  i = fmt_ulong(s,starttime); len += i; if (s) s += i;
112  i = fmt_str(s,"."); len += i; if (s) s += i;
113  i = fmt_ulong(s,seq); len += i; if (s) s += i;
114  ++len; if (s) *s++ = 0;
115
116  return len;
117 }
118
119 char *fnnum(dirslash,flagsplit)
120 char *dirslash;
121 int flagsplit;
122 {
123  char *s;
124
125  s = alloc(fmtqfn((char *) 0,dirslash,messnum,flagsplit));
126  if (!s) die(51);
127  fmtqfn(s,dirslash,messnum,flagsplit);
128  return s;
129 }
130
131 void pidopen()
132 {
133  unsigned int len;
134  unsigned long seq;
135
136  seq = 1;
137  len = pidfmt((char *) 0,seq);
138  pidfn = alloc(len);
139  if (!pidfn) die(51);
140
141  for (seq = 1;seq < 10;++seq)
142   {
143    if (pidfmt((char *) 0,seq) > len) die(81); /* paranoia */
144    pidfmt(pidfn,seq);
145    messfd = open_excl(pidfn);
146    if (messfd != -1) return;
147   }
148
149  die(63);
150 }
151
152 char tmp[FMT_ULONG];
153
154 void main()
155 {
156  unsigned int len;
157  char ch;
158
159  sig_blocknone();
160  umask(033);
161  if (chdir(auto_qmail) == -1) die(61);
162  if (chdir("queue") == -1) die(62);
163
164  mypid = getpid();
165  uid = getuid();
166  starttime = now();
167  datetime_tai(&dt,starttime);
168
169  received_setup();
170
171  sig_pipeignore();
172  sig_miscignore();
173  sig_alarmcatch(sigalrm);
174  sig_bugcatch(sigbug);
175
176  alarm(DEATH);
177
178  pidopen();
179  if (fstat(messfd,&pidst) == -1) die(63);
180
181  messnum = pidst.st_ino;
182  messfn = fnnum("mess/",1);
183  todofn = fnnum("todo/",0);
184  intdfn = fnnum("intd/",0);
185
186  if (link(pidfn,messfn) == -1) die(64);
187  if (unlink(pidfn) == -1) die(63);
188  flagmademess = 1;
189
190  substdio_fdbuf(&ssout,write,messfd,outbuf,sizeof(outbuf));
191  substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
192
193  if (substdio_bput(&ssout,received,receivedlen) == -1) die_write();
194
195  switch(substdio_copy(&ssout,&ssin))
196   {
197    case -2: die_read();
198    case -3: die_write();
199   }
200
201  if (substdio_flush(&ssout) == -1) die_write();
202  if (fsync(messfd) == -1) die_write();
203
204  intdfd = open_excl(intdfn);
205  if (intdfd == -1) die(65);
206  flagmadeintd = 1;
207
208  substdio_fdbuf(&ssout,write,intdfd,outbuf,sizeof(outbuf));
209  substdio_fdbuf(&ssin,read,1,inbuf,sizeof(inbuf));
210
211  if (substdio_bput(&ssout,"u",1) == -1) die_write();
212  if (substdio_bput(&ssout,tmp,fmt_ulong(tmp,uid)) == -1) die_write();
213  if (substdio_bput(&ssout,"",1) == -1) die_write();
214
215  if (substdio_bput(&ssout,"p",1) == -1) die_write();
216  if (substdio_bput(&ssout,tmp,fmt_ulong(tmp,mypid)) == -1) die_write();
217  if (substdio_bput(&ssout,"",1) == -1) die_write();
218
219  if (substdio_get(&ssin,&ch,1) < 1) die_read();
220  if (ch != 'F') die(91);
221  if (substdio_bput(&ssout,&ch,1) == -1) die_write();
222  for (len = 0;len < ADDR;++len)
223   {
224    if (substdio_get(&ssin,&ch,1) < 1) die_read();
225    if (substdio_put(&ssout,&ch,1) == -1) die_write();
226    if (!ch) break;
227   }
228  if (len >= ADDR) die(11);
229
230  if (substdio_bput(&ssout,QUEUE_EXTRA,QUEUE_EXTRALEN) == -1) die_write();
231
232  for (;;)
233   {
234    if (substdio_get(&ssin,&ch,1) < 1) die_read();
235    if (!ch) break;
236    if (ch != 'T') die(91);
237    if (substdio_bput(&ssout,&ch,1) == -1) die_write();
238    for (len = 0;len < ADDR;++len)
239     {
240      if (substdio_get(&ssin,&ch,1) < 1) die_read();
241      if (substdio_bput(&ssout,&ch,1) == -1) die_write();
242      if (!ch) break;
243     }
244    if (len >= ADDR) die(11);
245   }
246
247  if (substdio_flush(&ssout) == -1) die_write();
248  if (fsync(intdfd) == -1) die_write();
249
250  if (link(intdfn,todofn) == -1) die(66);
251
252  triggerpull();
253  die(0);
254 }