Commit | Line | Data |
---|---|---|
f8beb284 MW |
1 | /*$Id: ezmlm-warn.c,v 1.27 1999/08/07 20:47:26 lindberg Exp $*/ |
2 | /*$Name: ezmlm-idx-040 $*/ | |
5b62e993 MW |
3 | #include <sys/types.h> |
4 | #include <sys/stat.h> | |
5 | #include "direntry.h" | |
6 | #include "readwrite.h" | |
7 | #include "getln.h" | |
8 | #include "substdio.h" | |
9 | #include "stralloc.h" | |
10 | #include "slurp.h" | |
f8beb284 | 11 | #include "sgetopt.h" |
5b62e993 MW |
12 | #include "getconf.h" |
13 | #include "byte.h" | |
14 | #include "error.h" | |
15 | #include "str.h" | |
16 | #include "strerr.h" | |
17 | #include "sig.h" | |
18 | #include "now.h" | |
19 | #include "datetime.h" | |
20 | #include "date822fmt.h" | |
21 | #include "fmt.h" | |
22 | #include "cookie.h" | |
23 | #include "qmail.h" | |
f8beb284 MW |
24 | #include "errtxt.h" |
25 | #include "mime.h" | |
26 | #include "idx.h" | |
27 | #include "subscribe.h" | |
5b62e993 MW |
28 | |
29 | #define FATAL "ezmlm-warn: fatal: " | |
f8beb284 MW |
30 | void die_usage() |
31 | { | |
32 | strerr_die1x(100,"ezmlm-warn: usage: ezmlm-warn -dD -l secs -t days dir"); | |
33 | } | |
34 | ||
35 | void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); } | |
5b62e993 MW |
36 | |
37 | stralloc key = {0}; | |
38 | stralloc outhost = {0}; | |
39 | stralloc outlocal = {0}; | |
40 | stralloc mailinglist = {0}; | |
f8beb284 MW |
41 | stralloc digdir = {0}; |
42 | stralloc charset = {0}; | |
43 | char boundary[COOKIE]; | |
44 | ||
45 | substdio ssout; | |
46 | char outbuf[16]; | |
5b62e993 MW |
47 | |
48 | unsigned long when; | |
49 | char *dir; | |
f8beb284 MW |
50 | char *workdir; |
51 | int flagdig = 0; | |
52 | char flagcd = '\0'; /* default: don't use transfer encoding */ | |
5b62e993 | 53 | stralloc fn = {0}; |
f8beb284 MW |
54 | stralloc bdname = {0}; |
55 | stralloc fnlasth = {0}; | |
56 | stralloc fnlastd = {0}; | |
57 | stralloc lasth = {0}; | |
58 | stralloc lastd = {0}; | |
5b62e993 | 59 | struct stat st; |
f8beb284 | 60 | void *psql = (void *) 0; |
5b62e993 | 61 | |
f8beb284 MW |
62 | void die_read() { strerr_die4sys(111,FATAL,ERR_READ,fn.s,": "); } |
63 | ||
64 | void makedir(s) | |
65 | char *s; | |
66 | { | |
67 | if (mkdir(s,0755) == -1) | |
68 | if (errno != error_exist) | |
69 | strerr_die4x(111,FATAL,ERR_CREATE,s,": "); | |
70 | } | |
5b62e993 MW |
71 | |
72 | char inbuf[1024]; | |
73 | substdio ssin; | |
74 | char textbuf[1024]; | |
75 | substdio sstext; | |
76 | ||
77 | stralloc addr = {0}; | |
78 | char strnum[FMT_ULONG]; | |
79 | char hash[COOKIE]; | |
80 | stralloc fnhash = {0}; | |
81 | stralloc quoted = {0}; | |
82 | stralloc line = {0}; | |
f8beb284 | 83 | stralloc qline = {0}; |
5b62e993 MW |
84 | |
85 | struct qmail qq; | |
86 | int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len; | |
87 | { | |
88 | qmail_put(&qq,buf,len); | |
89 | return len; | |
90 | } | |
91 | char qqbuf[1]; | |
92 | substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf)); | |
93 | struct datetime dt; | |
94 | char date[DATE822FMT]; | |
95 | ||
f8beb284 MW |
96 | void code_qput(s,n) |
97 | char *s; | |
98 | unsigned int n; | |
5b62e993 | 99 | { |
f8beb284 MW |
100 | if (!flagcd) |
101 | qmail_put(&qq,s,n); | |
102 | else { | |
103 | if (flagcd == 'B') | |
104 | encodeB(s,n,&qline,0,FATAL); | |
105 | else | |
106 | encodeQ(s,n,&qline,FATAL); | |
107 | qmail_put(&qq,qline.s,qline.len); | |
108 | } | |
5b62e993 MW |
109 | } |
110 | ||
111 | void doit(flagw) | |
112 | int flagw; | |
113 | { | |
f8beb284 | 114 | unsigned int i; |
5b62e993 MW |
115 | int fd; |
116 | int match; | |
117 | int fdhash; | |
f8beb284 | 118 | char *err; |
5b62e993 MW |
119 | datetime_sec msgwhen; |
120 | ||
121 | fd = open_read(fn.s); | |
122 | if (fd == -1) die_read(); | |
123 | substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); | |
124 | ||
125 | if (getln(&ssin,&addr,&match,'\0') == -1) die_read(); | |
126 | if (!match) { close(fd); return; } | |
f8beb284 MW |
127 | if (!issub(workdir,addr.s,(char *) 0,FATAL)) { close(fd); |
128 | /*XXX*/unlink(fn.s); return; } | |
5b62e993 | 129 | cookie(hash,"",0,"",addr.s,""); |
f8beb284 MW |
130 | if (!stralloc_copys(&fnhash,workdir)) die_nomem(); |
131 | if (!stralloc_cats(&fnhash,"/bounce/h/")) die_nomem(); | |
132 | if (!stralloc_catb(&fnhash,hash,1)) die_nomem(); | |
133 | if (!stralloc_cats(&fnhash,"/h")) die_nomem(); | |
134 | if (!stralloc_catb(&fnhash,hash+1,COOKIE-1)) die_nomem(); | |
5b62e993 MW |
135 | if (!stralloc_0(&fnhash)) die_nomem(); |
136 | ||
f8beb284 MW |
137 | if (qmail_open(&qq, (stralloc *) 0) == -1) |
138 | strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE); | |
5b62e993 MW |
139 | |
140 | msgwhen = now(); | |
141 | qmail_puts(&qq,"Mailing-List: "); | |
142 | qmail_put(&qq,mailinglist.s,mailinglist.len); | |
f8beb284 MW |
143 | if (getconf_line(&line,"listid",0,FATAL,dir)) { |
144 | qmail_puts(&qq,"\nList-ID: "); | |
145 | qmail_put(&qq,line.s,line.len); | |
146 | } | |
5b62e993 MW |
147 | qmail_puts(&qq,"\nDate: "); |
148 | datetime_tai(&dt,msgwhen); | |
149 | qmail_put(&qq,date,date822fmt(date,&dt)); | |
f8beb284 MW |
150 | if (!stralloc_copys(&line,"Message-ID: <")) die_nomem(); |
151 | if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,(unsigned long) msgwhen))) | |
152 | die_nomem(); | |
153 | if (!stralloc_cats(&line,".")) die_nomem(); | |
154 | if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) | |
155 | die_nomem(); | |
156 | if (!stralloc_cats(&line,".ezmlm-warn@")) die_nomem(); | |
157 | if (!stralloc_catb(&line,outhost.s,outhost.len)) die_nomem(); | |
158 | qmail_put(&qq,line.s,line.len); | |
159 | if (flagcd) { | |
160 | if (!stralloc_0(&line)) die_nomem(); | |
161 | cookie(boundary,"",0,"",line.s,""); /* universal MIME boundary */ | |
162 | } | |
5b62e993 MW |
163 | qmail_puts(&qq,">\nFrom: "); |
164 | if (!quote("ed,&outlocal)) die_nomem(); | |
165 | qmail_put(&qq,quoted.s,quoted.len); | |
166 | qmail_puts(&qq,"-help@"); | |
167 | qmail_put(&qq,outhost.s,outhost.len); | |
168 | qmail_puts(&qq,"\nTo: "); | |
169 | if (!quote2("ed,addr.s)) die_nomem(); | |
170 | qmail_put(&qq,quoted.s,quoted.len); | |
f8beb284 MW |
171 | if (flagcd) { /* to accomodate transfer-encoding */ |
172 | qmail_puts(&qq,"\nMIME-Version: 1.0\n"); | |
173 | qmail_puts(&qq,"Content-Type: multipart/mixed; boundary="); | |
174 | qmail_put(&qq,boundary,COOKIE); | |
175 | } else { | |
176 | qmail_puts(&qq,"\nContent-type: text/plain; charset="); | |
177 | qmail_puts(&qq,charset.s); | |
178 | } | |
179 | qmail_puts(&qq,flagw ? "\nSubject: ezmlm probe\n" : "\nSubject: ezmlm warning\n"); | |
180 | ||
181 | if (flagcd) { /* first part for QP/base64 multipart msg */ | |
182 | qmail_puts(&qq,"\n\n--"); | |
183 | qmail_put(&qq,boundary,COOKIE); | |
184 | qmail_puts(&qq,"\nContent-Type: text/plain; charset="); | |
185 | qmail_puts(&qq,charset.s); | |
186 | qmail_puts(&qq,"\nContent-Transfer-Encoding: "); | |
187 | if (flagcd == 'Q') | |
188 | qmail_puts(&qq,"Quoted-printable\n\n"); | |
189 | else | |
190 | qmail_puts(&qq,"base64\n\n"); | |
191 | } else | |
192 | qmail_puts(&qq,"\n"); | |
193 | ||
194 | copy(&qq,"text/top",flagcd,FATAL); | |
195 | copy(&qq,flagw ? "text/bounce-probe" : "text/bounce-warn",flagcd,FATAL); | |
5b62e993 MW |
196 | |
197 | if (!flagw) { | |
f8beb284 MW |
198 | if (flagdig) |
199 | copy(&qq,"text/dig-bounce-num",flagcd,FATAL); | |
200 | else | |
201 | copy(&qq,"text/bounce-num",flagcd,FATAL); | |
202 | if (!flagcd) { | |
203 | fdhash = open_read(fnhash.s); | |
204 | if (fdhash == -1) { | |
205 | if (errno != error_noent) | |
206 | strerr_die4sys(111,FATAL,ERR_OPEN,fnhash.s,": "); | |
207 | } else { | |
208 | substdio_fdbuf(&sstext,read,fdhash,textbuf,sizeof(textbuf)); | |
209 | for(;;) { | |
210 | if (getln(&sstext,&line,&match,'\n') == -1) | |
211 | strerr_die4sys(111,FATAL,ERR_READ,fnhash.s,": "); | |
212 | if (!match) break; | |
213 | code_qput(line.s,line.len); | |
214 | } | |
215 | } | |
5b62e993 | 216 | close(fdhash); |
f8beb284 MW |
217 | } else { |
218 | if (!stralloc_copys(&line,"")) die_nomem(); /* slurp adds! */ | |
219 | if (slurp(fnhash.s,&line,256) < 0) | |
220 | strerr_die4sys(111,FATAL,ERR_OPEN,fnhash.s,": "); | |
221 | code_qput(line.s,line.len); | |
5b62e993 MW |
222 | } |
223 | } | |
224 | ||
f8beb284 MW |
225 | copy(&qq,"text/bounce-bottom",flagcd,FATAL); |
226 | if (flagcd) { | |
227 | if (flagcd == 'B') { | |
228 | encodeB("",0,&line,2,FATAL); | |
229 | qmail_put(&qq,line.s,line.len); /* flush */ | |
230 | } | |
231 | qmail_puts(&qq,"\n\n--"); | |
232 | qmail_put(&qq,boundary,COOKIE); | |
233 | qmail_puts(&qq,"\nContent-Type: message/rfc822\n\n"); | |
234 | } | |
5b62e993 MW |
235 | if (substdio_copy(&ssqq,&ssin) < 0) die_read(); |
236 | close(fd); | |
237 | ||
f8beb284 MW |
238 | if (flagcd) { /* end multipart/mixed */ |
239 | qmail_puts(&qq,"\n--"); | |
240 | qmail_put(&qq,boundary,COOKIE); | |
241 | qmail_puts(&qq,"--\n"); | |
242 | } | |
243 | ||
5b62e993 MW |
244 | strnum[fmt_ulong(strnum,when)] = 0; |
245 | cookie(hash,key.s,key.len,strnum,addr.s,flagw ? "P" : "W"); | |
246 | if (!stralloc_copy(&line,&outlocal)) die_nomem(); | |
f8beb284 MW |
247 | if (!stralloc_cats(&line,flagw ? "-return-probe-" : "-return-warn-")) |
248 | die_nomem(); | |
5b62e993 MW |
249 | if (!stralloc_cats(&line,strnum)) die_nomem(); |
250 | if (!stralloc_cats(&line,".")) die_nomem(); | |
251 | if (!stralloc_catb(&line,hash,COOKIE)) die_nomem(); | |
252 | if (!stralloc_cats(&line,"-")) die_nomem(); | |
253 | i = str_chr(addr.s,'@'); | |
254 | if (!stralloc_catb(&line,addr.s,i)) die_nomem(); | |
255 | if (addr.s[i]) { | |
256 | if (!stralloc_cats(&line,"=")) die_nomem(); | |
257 | if (!stralloc_cats(&line,addr.s + i + 1)) die_nomem(); | |
258 | } | |
259 | if (!stralloc_cats(&line,"@")) die_nomem(); | |
260 | if (!stralloc_cat(&line,&outhost)) die_nomem(); | |
261 | if (!stralloc_0(&line)) die_nomem(); | |
262 | qmail_from(&qq,line.s); | |
263 | ||
264 | qmail_to(&qq,addr.s); | |
f8beb284 MW |
265 | if (*(err = qmail_close(&qq)) != '\0') |
266 | strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE, err + 1); | |
5b62e993 MW |
267 | |
268 | strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; | |
269 | strerr_warn2("ezmlm-warn: info: qp ",strnum,0); | |
270 | ||
271 | if (!flagw) { | |
272 | if (unlink(fnhash.s) == -1) | |
273 | if (errno != error_noent) | |
f8beb284 | 274 | strerr_die4sys(111,FATAL,ERR_DELETE,fnhash.s,": "); |
5b62e993 MW |
275 | } |
276 | if (unlink(fn.s) == -1) | |
f8beb284 | 277 | strerr_die4sys(111,FATAL,ERR_DELETE,fn.s,": "); |
5b62e993 MW |
278 | } |
279 | ||
280 | void main(argc,argv) | |
281 | int argc; | |
282 | char **argv; | |
283 | { | |
f8beb284 MW |
284 | DIR *bouncedir, *bsdir, *hdir; |
285 | direntry *d, *ds; | |
5b62e993 | 286 | unsigned long bouncedate; |
f8beb284 MW |
287 | unsigned long bouncetimeout = BOUNCE_TIMEOUT; |
288 | unsigned long lockout = 0L; | |
289 | unsigned long ld; | |
290 | unsigned long ddir,dfile; | |
291 | int fdlock,fd; | |
292 | char *err; | |
293 | int opt; | |
294 | char ch; | |
295 | ||
296 | (void) umask(022); | |
5b62e993 MW |
297 | sig_pipeignore(); |
298 | when = (unsigned long) now(); | |
f8beb284 MW |
299 | while ((opt = getopt(argc,argv,"dDl:t:vV")) != opteof) |
300 | switch(opt) { | |
301 | case 'd': flagdig = 1; break; | |
302 | case 'D': flagdig = 0; break; | |
303 | case 'l': | |
304 | if (optarg) { /* lockout in seconds */ | |
305 | (void) scan_ulong(optarg,&lockout); | |
306 | } | |
307 | break; | |
308 | case 't': | |
309 | if (optarg) { /* bouncetimeout in days */ | |
310 | (void) scan_ulong(optarg,&bouncetimeout); | |
311 | bouncetimeout *= 3600L * 24L; | |
312 | } | |
313 | break; | |
314 | case 'v': | |
315 | case 'V': strerr_die2x(0, | |
316 | "ezmlm-warn version: ezmlm-0.53+",EZIDX_VERSION); | |
317 | default: | |
318 | die_usage(); | |
319 | } | |
320 | dir = argv[optind]; | |
5b62e993 | 321 | if (!dir) die_usage(); |
5b62e993 | 322 | if (chdir(dir) == -1) |
f8beb284 MW |
323 | strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": "); |
324 | if (flagdig) { | |
325 | if (!stralloc_copys(&digdir,dir)) die_nomem(); | |
326 | if (!stralloc_cats(&digdir,"/digest")) die_nomem(); | |
327 | if (!stralloc_0(&digdir)) die_nomem(); | |
328 | workdir = digdir.s; | |
329 | } else | |
330 | workdir = dir; | |
331 | ||
332 | if (!stralloc_copys(&fnlastd,workdir)) die_nomem(); | |
333 | if (!stralloc_cats(&fnlastd,"/bounce/lastd")) die_nomem(); | |
334 | if (!stralloc_0(&fnlastd)) die_nomem(); | |
335 | if (slurp(fnlastd.s,&lastd,16) == -1) /* last time d was scanned */ | |
336 | strerr_die4sys(111,FATAL,ERR_READ,fnlastd.s,": "); | |
337 | if (!stralloc_0(&lastd)) die_nomem(); | |
338 | (void) scan_ulong(lastd.s,&ld); | |
339 | if (!lockout) | |
340 | lockout = bouncetimeout / 50; /* 5.6 h for default timeout */ | |
341 | if (ld + lockout > when && ld < when) | |
342 | _exit(0); /* exit silently. Second check is to prevent lockup */ | |
343 | /* if lastd gets corrupted */ | |
344 | ||
345 | if (!stralloc_copy(&fnlasth,&fnlastd)) die_nomem(); | |
346 | fnlasth.s[fnlasth.len - 2] = 'h'; /* bad, but feels good ... */ | |
5b62e993 MW |
347 | |
348 | switch(slurp("key",&key,32)) { | |
349 | case -1: | |
f8beb284 | 350 | strerr_die4sys(111,FATAL,ERR_READ,dir,"/key: "); |
5b62e993 | 351 | case 0: |
f8beb284 | 352 | strerr_die4x(100,FATAL,dir,"/key",ERR_NOEXIST); |
5b62e993 MW |
353 | } |
354 | getconf_line(&outhost,"outhost",1,FATAL,dir); | |
355 | getconf_line(&outlocal,"outlocal",1,FATAL,dir); | |
f8beb284 MW |
356 | if (flagdig) |
357 | if (!stralloc_cats(&outlocal,"-digest")) die_nomem(); | |
5b62e993 | 358 | getconf_line(&mailinglist,"mailinglist",1,FATAL,dir); |
f8beb284 MW |
359 | if (getconf_line(&charset,"charset",0,FATAL,dir)) { |
360 | if (charset.len >= 2 && charset.s[charset.len - 2] == ':') { | |
361 | if (charset.s[charset.len - 1] == 'B' || | |
362 | charset.s[charset.len - 1] == 'Q') { | |
363 | flagcd = charset.s[charset.len - 1]; | |
364 | charset.s[charset.len - 2] = '\0'; | |
365 | } | |
366 | } | |
367 | } else | |
368 | if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem(); | |
369 | if (!stralloc_0(&charset)) die_nomem(); | |
370 | ||
371 | set_cpoutlocal(&outlocal); /* for copy */ | |
372 | set_cpouthost(&outhost); /* for copy */ | |
373 | ddir = when / 10000; | |
374 | dfile = when - 10000 * ddir; | |
5b62e993 | 375 | |
f8beb284 MW |
376 | if (!stralloc_copys(&line,workdir)) die_nomem(); |
377 | if (!stralloc_cats(&line,"/lockbounce")) die_nomem(); | |
378 | if (!stralloc_0(&line)) die_nomem(); | |
379 | fdlock = open_append(line.s); | |
5b62e993 | 380 | if (fdlock == -1) |
f8beb284 | 381 | strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": "); |
5b62e993 | 382 | if (lock_ex(fdlock) == -1) |
f8beb284 | 383 | strerr_die4sys(111,FATAL,ERR_OBTAIN,line.s,": "); |
5b62e993 | 384 | |
f8beb284 MW |
385 | if (!stralloc_copys(&line,workdir)) die_nomem(); |
386 | if (!stralloc_cats(&line,"/bounce/d")) die_nomem(); | |
387 | if (!stralloc_0(&line)) die_nomem(); | |
388 | bouncedir = opendir(line.s); | |
5b62e993 | 389 | if (!bouncedir) |
f8beb284 MW |
390 | if (errno != error_noent) |
391 | strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": "); | |
392 | else | |
393 | _exit(0); /* no bouncedir - no bounces! */ | |
5b62e993 | 394 | |
f8beb284 | 395 | while ((d = readdir(bouncedir))) { /* dxxx/ */ |
5b62e993 MW |
396 | if (str_equal(d->d_name,".")) continue; |
397 | if (str_equal(d->d_name,"..")) continue; | |
398 | ||
f8beb284 MW |
399 | scan_ulong(d->d_name,&bouncedate); |
400 | /* since we do entire dir, we do files that are not old enough. */ | |
401 | /* to not do this and accept a delay of 10000s (2.8h) of the oldest */ | |
402 | /* bounce we add to bouncedate. We don't if bouncetimeout=0 so that */ | |
403 | /* that setting still processes _all_ bounces. */ | |
404 | if (bouncetimeout) ++bouncedate; | |
405 | if (when >= bouncedate * 10000 + bouncetimeout) { | |
406 | if (!stralloc_copys(&bdname,workdir)) die_nomem(); | |
407 | if (!stralloc_cats(&bdname,"/bounce/d/")) die_nomem(); | |
408 | if (!stralloc_cats(&bdname,d->d_name)) die_nomem(); | |
409 | if (!stralloc_0(&bdname)) die_nomem(); | |
410 | bsdir = opendir(bdname.s); | |
411 | if (!bsdir) { | |
412 | if (errno != error_notdir) | |
413 | strerr_die4sys(111,FATAL,ERR_OPEN,bdname.s,":y "); | |
414 | else { /* leftover nnnnn_dmmmmm file */ | |
415 | if (unlink(bdname.s) == -1) | |
416 | strerr_die4sys(111,FATAL,ERR_DELETE,bdname.s,": "); | |
417 | continue; | |
418 | } | |
419 | } | |
420 | while ((ds = readdir(bsdir))) { /* dxxxx/yyyy */ | |
421 | if (str_equal(ds->d_name,".")) continue; | |
422 | if (str_equal(ds->d_name,"..")) continue; | |
423 | if (!stralloc_copy(&fn,&bdname)) die_nomem(); /* '\0' at end */ | |
424 | fn.s[fn.len - 1] = '/'; | |
425 | if (!stralloc_cats(&fn,ds->d_name)) die_nomem(); | |
426 | if (!stralloc_0(&fn)) die_nomem(); | |
427 | if ((ds->d_name[0] == 'd') || (ds->d_name[0] == 'w')) | |
428 | doit(ds->d_name[0] == 'w'); | |
429 | else /* other stuff is junk */ | |
430 | if (unlink(fn.s) == -1) | |
431 | strerr_die4sys(111,FATAL,ERR_DELETE,fn.s,": "); | |
432 | } | |
433 | closedir(bsdir); | |
434 | if (rmdir(bdname.s) == -1) /* the directory itself */ | |
435 | if (errno != error_noent) | |
436 | strerr_die4sys(111,FATAL,ERR_DELETE,bdname.s,": "); | |
5b62e993 | 437 | } |
f8beb284 MW |
438 | } |
439 | closedir(bouncedir); | |
5b62e993 | 440 | |
f8beb284 MW |
441 | if (!stralloc_copy(&line,&fnlastd)) die_nomem(); |
442 | line.s[line.len - 2] = 'D'; | |
443 | fd = open_trunc(line.s); /* write lastd. Do safe */ | |
444 | /* since we read before lock*/ | |
445 | if (fd == -1) strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": "); | |
446 | substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf)); | |
447 | if (substdio_put(&ssout,strnum,fmt_ulong(strnum,when)) == -1) | |
448 | strerr_die4sys(111,FATAL,ERR_WRITE,line.s,": "); | |
449 | if (substdio_put(&ssout,"\n",1) == -1) /* prettier */ | |
450 | strerr_die4sys(111,FATAL,ERR_WRITE,line.s,": "); | |
451 | if (substdio_flush(&ssout) == -1) | |
452 | strerr_die4sys(111,FATAL,ERR_FLUSH,line.s,": "); | |
453 | if (fsync(fd) == -1) | |
454 | strerr_die4sys(111,FATAL,ERR_SYNC,line.s,": "); | |
455 | if (close(fd) == -1) | |
456 | strerr_die4sys(111,FATAL,ERR_CLOSE,line.s,": "); | |
457 | ||
458 | if (rename(line.s,fnlastd.s) == -1) | |
459 | strerr_die4sys(111,FATAL,ERR_MOVE,fnlastd.s,": "); | |
460 | ||
461 | /* no need to do h dir cleaning more than */ | |
462 | /* once per 1-2 days (17-30 days for all) */ | |
463 | if (stat(fnlasth.s,&st) == -1) { | |
464 | if (errno != error_noent) | |
465 | strerr_die4sys(111,FATAL,ERR_STAT,fnlasth.s,": "); | |
466 | } else if (when < st.st_mtime + 100000 && when > st.st_mtime) | |
467 | _exit(0); /* 2nd comp to guard against corruption */ | |
468 | ||
469 | if (slurp(fnlasth.s,&lasth,16) == -1) /* last h cleaned */ | |
470 | strerr_die4sys(111,FATAL,ERR_READ,fnlasth.s,": "); | |
471 | if (!stralloc_0(&lasth)) die_nomem(); | |
472 | ch = lasth.s[0]; /* clean h */ | |
473 | if (ch >= 'a' && ch <= 'o') | |
474 | ++ch; | |
475 | else | |
476 | ch = 'a'; | |
477 | lasth.s[0] = ch; | |
478 | if (!stralloc_copys(&line,workdir)) die_nomem(); | |
479 | if (!stralloc_cats(&line,"/bounce/h/")) die_nomem(); | |
480 | if (!stralloc_catb(&line,lasth.s,1)) die_nomem(); | |
481 | if (!stralloc_0(&line)) die_nomem(); | |
482 | hdir = opendir(line.s); /* clean ./h/xxxxxx */ | |
483 | ||
484 | if (!hdir) { | |
485 | if (errno != error_noent) | |
486 | strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": "); | |
487 | } else { | |
488 | ||
489 | while ((d = readdir(hdir))) { | |
490 | if (str_equal(d->d_name,".")) continue; | |
491 | if (str_equal(d->d_name,"..")) continue; | |
492 | if (!stralloc_copys(&fn,line.s)) die_nomem(); | |
493 | if (!stralloc_append(&fn,"/")) die_nomem(); | |
494 | if (!stralloc_cats(&fn,d->d_name)) die_nomem(); | |
495 | if (!stralloc_0(&fn)) die_nomem(); | |
496 | if (stat(fn.s,&st) == -1) { | |
497 | if (errno == error_noent) continue; | |
498 | strerr_die4sys(111,FATAL,ERR_STAT,fn.s,": "); | |
499 | } | |
500 | if (when > st.st_mtime + 3 * bouncetimeout) | |
501 | if (unlink(fn.s) == -1) | |
502 | strerr_die4sys(111,FATAL,ERR_DELETE,fn.s,": "); | |
5b62e993 | 503 | } |
f8beb284 | 504 | closedir(hdir); |
5b62e993 MW |
505 | } |
506 | ||
f8beb284 MW |
507 | fd = open_trunc(fnlasth.s); /* write lasth */ |
508 | if (fd == -1) strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": "); | |
509 | substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf)); | |
510 | if (substdio_put(&ssout,lasth.s,1) == -1) | |
511 | strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": "); | |
512 | if (substdio_put(&ssout,"\n",1) == -1) /* prettier */ | |
513 | strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": "); | |
514 | if (substdio_flush(&ssout) == -1) | |
515 | strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": "); | |
516 | (void) close(fd); /* no big loss. No reason to flush/sync */ | |
517 | /* See check of ld above to guard against */ | |
518 | /* it being corrupted and > when */ | |
519 | ||
520 | closesql(); | |
5b62e993 MW |
521 | _exit(0); |
522 | } |