Commit | Line | Data |
---|---|---|
b2a81223 | 1 | /* |
dc45ba8c | 2 | * Copyright (c) 1983 Eric P. Allman |
bee79b64 KB |
3 | * Copyright (c) 1988 Regents of the University of California. |
4 | * All rights reserved. | |
5 | * | |
417f7a11 | 6 | * %sccs.include.redist.c% |
bee79b64 | 7 | */ |
b2a81223 | 8 | |
81b7d258 | 9 | # include "sendmail.h" |
bee79b64 KB |
10 | |
11 | #ifndef lint | |
12 | #ifdef QUEUE | |
4e20c4d2 | 13 | static char sccsid[] = "@(#)queue.c 5.47 (Berkeley) %G% (with queueing)"; |
bee79b64 | 14 | #else |
4e20c4d2 | 15 | static char sccsid[] = "@(#)queue.c 5.47 (Berkeley) %G% (without queueing)"; |
bee79b64 KB |
16 | #endif |
17 | #endif /* not lint */ | |
18 | ||
81b7d258 | 19 | # include <sys/stat.h> |
a2cb9a08 | 20 | # include <sys/dir.h> |
3f9ac8ea | 21 | # include <sys/file.h> |
aba51985 | 22 | # include <signal.h> |
81b7d258 | 23 | # include <errno.h> |
3fbc69d6 | 24 | # include <pwd.h> |
4287d84d | 25 | # ifdef LOCKF |
76b607b2 | 26 | # include <fcntl.h> |
4287d84d EA |
27 | # endif |
28 | ||
76b607b2 EA |
29 | # ifdef QUEUE |
30 | ||
81b7d258 | 31 | /* |
7338e3d4 EA |
32 | ** Work queue. |
33 | */ | |
34 | ||
35 | struct work | |
36 | { | |
37 | char *w_name; /* name of control file */ | |
38 | long w_pri; /* priority of message, see below */ | |
f746582a | 39 | time_t w_ctime; /* creation time of message */ |
7338e3d4 EA |
40 | struct work *w_next; /* next in queue */ |
41 | }; | |
42 | ||
43 | typedef struct work WORK; | |
44 | ||
45 | WORK *WorkQ; /* queue of things to be done */ | |
46 | \f/* | |
81b7d258 EA |
47 | ** QUEUEUP -- queue a message up for future transmission. |
48 | ** | |
81b7d258 | 49 | ** Parameters: |
dd1fe05b | 50 | ** e -- the envelope to queue up. |
d0bd03ce EA |
51 | ** queueall -- if TRUE, queue all addresses, rather than |
52 | ** just those with the QQUEUEUP flag set. | |
7338e3d4 | 53 | ** announce -- if TRUE, tell when you are queueing up. |
81b7d258 EA |
54 | ** |
55 | ** Returns: | |
3620ad97 | 56 | ** none. |
81b7d258 EA |
57 | ** |
58 | ** Side Effects: | |
7338e3d4 | 59 | ** The current request are saved in a control file. |
3620ad97 | 60 | ** The queue file is left locked. |
81b7d258 EA |
61 | */ |
62 | ||
7338e3d4 | 63 | queueup(e, queueall, announce) |
dd1fe05b | 64 | register ENVELOPE *e; |
d0bd03ce | 65 | bool queueall; |
7338e3d4 | 66 | bool announce; |
81b7d258 | 67 | { |
2cce0c26 | 68 | char *qf; |
2cce0c26 | 69 | register FILE *tfp; |
81b7d258 | 70 | register HDR *h; |
d4f42161 | 71 | register ADDRESS *q; |
3620ad97 EA |
72 | int fd; |
73 | int i; | |
74 | bool newid; | |
22293c34 | 75 | register char *p; |
4db45bf1 | 76 | MAILER nullmailer; |
d2213d6c | 77 | ADDRESS *lastctladdr; |
f8a74171 | 78 | static ADDRESS *nullctladdr = NULL; |
3620ad97 | 79 | char buf[MAXLINE], tf[MAXLINE]; |
22293c34 | 80 | extern char *macvalue(); |
d2213d6c | 81 | extern ADDRESS *getctladdr(); |
81b7d258 | 82 | |
f8a74171 EA |
83 | /* |
84 | ** If we don't have nullctladdr, create one | |
85 | */ | |
86 | ||
87 | if (nullctladdr == NULL) | |
88 | { | |
89 | nullctladdr = (ADDRESS *) xalloc(sizeof *nullctladdr); | |
90 | bzero((char *) nullctladdr, sizeof nullctladdr); | |
91 | } | |
92 | ||
9ccf54c4 | 93 | /* |
11e3f8b5 | 94 | ** Create control file. |
9ccf54c4 | 95 | */ |
81b7d258 | 96 | |
3620ad97 EA |
97 | newid = (e->e_id == NULL); |
98 | strcpy(tf, queuename(e, 't')); | |
99 | tfp = e->e_lockfp; | |
100 | if (tfp == NULL) | |
101 | newid = FALSE; | |
102 | if (newid) | |
4287d84d | 103 | { |
3620ad97 EA |
104 | tfp = e->e_lockfp; |
105 | } | |
106 | else | |
107 | { | |
108 | /* get a locked tf file */ | |
109 | for (i = 100; --i >= 0; ) | |
4287d84d | 110 | { |
76b607b2 EA |
111 | # ifdef LOCKF |
112 | struct flock lfd; | |
113 | # endif | |
114 | ||
3620ad97 EA |
115 | fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode); |
116 | if (fd < 0) | |
4287d84d | 117 | { |
3620ad97 EA |
118 | if (errno == EEXIST) |
119 | continue; | |
120 | syserr("queueup: cannot create temp file %s", tf); | |
121 | return; | |
6680179d | 122 | } |
4287d84d | 123 | # ifdef LOCKF |
76b607b2 EA |
124 | lfd.l_type = F_WRLCK; |
125 | lfd.l_whence = lfd.l_start = lfd.l_len = 0; | |
126 | if (fcntl(fd, F_SETLK, &lfd) >= 0) | |
3620ad97 EA |
127 | break; |
128 | if (errno != EACCES && errno != EAGAIN) | |
129 | syserr("cannot lockf(%s)", tf); | |
4287d84d | 130 | # else |
3620ad97 EA |
131 | if (flock(fd, LOCK_EX|LOCK_NB) >= 0) |
132 | break; | |
133 | if (errno != EWOULDBLOCK) | |
134 | syserr("cannot flock(%s)", tf); | |
4287d84d | 135 | # endif |
3620ad97 | 136 | close(fd); |
6680179d | 137 | } |
6680179d | 138 | |
3620ad97 EA |
139 | tfp = fdopen(fd, "w"); |
140 | } | |
81b7d258 | 141 | |
9678c96d | 142 | if (tTd(40, 1)) |
560a80d9 | 143 | printf("queueing %s\n", e->e_id); |
81b7d258 | 144 | |
dd1fe05b EA |
145 | /* |
146 | ** If there is no data file yet, create one. | |
147 | */ | |
148 | ||
149 | if (e->e_df == NULL) | |
150 | { | |
151 | register FILE *dfp; | |
80482eb5 | 152 | extern putbody(); |
dd1fe05b | 153 | |
2cce0c26 | 154 | e->e_df = newstr(queuename(e, 'd')); |
3f9ac8ea RA |
155 | fd = open(e->e_df, O_WRONLY|O_CREAT, FileMode); |
156 | if (fd < 0) | |
dd1fe05b EA |
157 | { |
158 | syserr("queueup: cannot create %s", e->e_df); | |
3620ad97 EA |
159 | if (!newid) |
160 | (void) fclose(tfp); | |
161 | return; | |
dd1fe05b | 162 | } |
3f9ac8ea | 163 | dfp = fdopen(fd, "w"); |
4db45bf1 | 164 | (*e->e_putbody)(dfp, ProgMailer, e); |
f9566d23 | 165 | (void) fclose(dfp); |
80482eb5 | 166 | e->e_putbody = putbody; |
dd1fe05b EA |
167 | } |
168 | ||
81b7d258 EA |
169 | /* |
170 | ** Output future work requests. | |
4e969be0 EA |
171 | ** Priority and creation time should be first, since |
172 | ** they are required by orderq. | |
81b7d258 EA |
173 | */ |
174 | ||
7338e3d4 EA |
175 | /* output message priority */ |
176 | fprintf(tfp, "P%ld\n", e->e_msgpriority); | |
177 | ||
64912e7e EA |
178 | /* output creation time */ |
179 | fprintf(tfp, "T%ld\n", e->e_ctime); | |
180 | ||
81b7d258 | 181 | /* output name of data file */ |
2cce0c26 | 182 | fprintf(tfp, "D%s\n", e->e_df); |
81b7d258 | 183 | |
baa0c390 EA |
184 | /* message from envelope, if it exists */ |
185 | if (e->e_message != NULL) | |
186 | fprintf(tfp, "M%s\n", e->e_message); | |
187 | ||
22293c34 EA |
188 | /* $r and $s macro values */ |
189 | if ((p = macvalue('r', e)) != NULL) | |
190 | fprintf(tfp, "$r%s\n", p); | |
191 | if ((p = macvalue('s', e)) != NULL) | |
192 | fprintf(tfp, "$s%s\n", p); | |
193 | ||
81b7d258 | 194 | /* output name of sender */ |
2cce0c26 | 195 | fprintf(tfp, "S%s\n", e->e_from.q_paddr); |
81b7d258 | 196 | |
ca4d0c0b | 197 | /* output list of error recipients */ |
d2213d6c | 198 | lastctladdr = NULL; |
ca4d0c0b EA |
199 | for (q = e->e_errorqueue; q != NULL; q = q->q_next) |
200 | { | |
201 | if (!bitset(QDONTSEND, q->q_flags)) | |
202 | { | |
203 | ADDRESS *ctladdr; | |
204 | ||
205 | ctladdr = getctladdr(q); | |
206 | if (ctladdr == NULL && q->q_alias != NULL) | |
207 | ctladdr = nullctladdr; | |
208 | if (ctladdr != lastctladdr) | |
209 | { | |
210 | printctladdr(ctladdr, tfp); | |
211 | lastctladdr = ctladdr; | |
212 | } | |
213 | fprintf(tfp, "E%s\n", q->q_paddr); | |
214 | } | |
215 | } | |
216 | ||
217 | /* output list of recipient addresses */ | |
dd1fe05b | 218 | for (q = e->e_sendqueue; q != NULL; q = q->q_next) |
81b7d258 | 219 | { |
8dcff118 | 220 | if (queueall ? !bitset(QDONTSEND|QSENT, q->q_flags) : |
9416f3a0 | 221 | bitset(QQUEUEUP, q->q_flags)) |
4d237f16 | 222 | { |
d2213d6c | 223 | ADDRESS *ctladdr; |
3fbc69d6 | 224 | |
f8a74171 EA |
225 | ctladdr = getctladdr(q); |
226 | if (ctladdr == NULL && q->q_alias != NULL) | |
227 | ctladdr = nullctladdr; | |
228 | if (ctladdr != lastctladdr) | |
d2213d6c EA |
229 | { |
230 | printctladdr(ctladdr, tfp); | |
231 | lastctladdr = ctladdr; | |
232 | } | |
2cce0c26 | 233 | fprintf(tfp, "R%s\n", q->q_paddr); |
7338e3d4 EA |
234 | if (announce) |
235 | { | |
236 | e->e_to = q->q_paddr; | |
237 | message(Arpa_Info, "queued"); | |
238 | if (LogLevel > 4) | |
f2e44ded | 239 | logdelivery("queued", e); |
7338e3d4 EA |
240 | e->e_to = NULL; |
241 | } | |
b9accadd EA |
242 | if (tTd(40, 1)) |
243 | { | |
244 | printf("queueing "); | |
245 | printaddr(q, FALSE); | |
246 | } | |
4d237f16 | 247 | } |
81b7d258 EA |
248 | } |
249 | ||
7338e3d4 EA |
250 | /* |
251 | ** Output headers for this message. | |
252 | ** Expand macros completely here. Queue run will deal with | |
253 | ** everything as absolute headers. | |
254 | ** All headers that must be relative to the recipient | |
255 | ** can be cracked later. | |
4db45bf1 EA |
256 | ** We set up a "null mailer" -- i.e., a mailer that will have |
257 | ** no effect on the addresses as they are output. | |
7338e3d4 EA |
258 | */ |
259 | ||
1dbda134 | 260 | bzero((char *) &nullmailer, sizeof nullmailer); |
4db45bf1 | 261 | nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1; |
281ef7f0 | 262 | nullmailer.m_eol = "\n"; |
4db45bf1 | 263 | |
a73ae8ac | 264 | define('g', "\001f", e); |
dd1fe05b | 265 | for (h = e->e_header; h != NULL; h = h->h_link) |
81b7d258 | 266 | { |
1dbda134 EA |
267 | extern bool bitzerop(); |
268 | ||
83e9910e | 269 | /* don't output null headers */ |
81b7d258 EA |
270 | if (h->h_value == NULL || h->h_value[0] == '\0') |
271 | continue; | |
83e9910e EA |
272 | |
273 | /* don't output resent headers on non-resent messages */ | |
274 | if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) | |
275 | continue; | |
276 | ||
277 | /* output this header */ | |
2cce0c26 | 278 | fprintf(tfp, "H"); |
83e9910e EA |
279 | |
280 | /* if conditional, output the set of conditions */ | |
1dbda134 EA |
281 | if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags)) |
282 | { | |
283 | int j; | |
284 | ||
0e306e7f | 285 | (void) putc('?', tfp); |
1dbda134 EA |
286 | for (j = '\0'; j <= '\177'; j++) |
287 | if (bitnset(j, h->h_mflags)) | |
0e306e7f EA |
288 | (void) putc(j, tfp); |
289 | (void) putc('?', tfp); | |
1dbda134 | 290 | } |
83e9910e EA |
291 | |
292 | /* output the header: expand macros, convert addresses */ | |
9416f3a0 EA |
293 | if (bitset(H_DEFAULT, h->h_flags)) |
294 | { | |
295 | (void) expand(h->h_value, buf, &buf[sizeof buf], e); | |
3ba0846a | 296 | fprintf(tfp, "%s: %s\n", h->h_field, buf); |
9416f3a0 | 297 | } |
4d237f16 | 298 | else if (bitset(H_FROM|H_RCPT, h->h_flags)) |
611b763d | 299 | { |
a4076aed EA |
300 | commaize(h, h->h_value, tfp, |
301 | bitset(EF_OLDSTYLE, e->e_flags), | |
302 | &nullmailer, e); | |
611b763d | 303 | } |
4d237f16 EA |
304 | else |
305 | fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); | |
81b7d258 EA |
306 | } |
307 | ||
308 | /* | |
309 | ** Clean up. | |
310 | */ | |
311 | ||
3620ad97 EA |
312 | if (!newid) |
313 | { | |
314 | qf = queuename(e, 'q'); | |
315 | if (rename(tf, qf) < 0) | |
316 | syserr("cannot rename(%s, %s), df=%s", tf, qf, e->e_df); | |
317 | if (e->e_lockfp != NULL) | |
318 | (void) fclose(e->e_lockfp); | |
319 | e->e_lockfp = tfp; | |
320 | } | |
321 | else | |
322 | qf = tf; | |
6680179d | 323 | errno = 0; |
1a13ccd8 | 324 | |
9678c96d EA |
325 | # ifdef LOG |
326 | /* save log info */ | |
a8f5bbff EA |
327 | if (LogLevel > 15) |
328 | syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df); | |
9678c96d | 329 | # endif LOG |
3f9ac8ea | 330 | fflush(tfp); |
3620ad97 | 331 | return; |
81b7d258 | 332 | } |
d2213d6c EA |
333 | |
334 | printctladdr(a, tfp) | |
335 | ADDRESS *a; | |
336 | FILE *tfp; | |
337 | { | |
338 | char *u; | |
339 | struct passwd *pw; | |
340 | extern struct passwd *getpwuid(); | |
341 | ||
342 | if (a == NULL) | |
343 | { | |
344 | fprintf(tfp, "C\n"); | |
345 | return; | |
346 | } | |
347 | if (a->q_uid == 0 || (pw = getpwuid(a->q_uid)) == NULL) | |
348 | u = DefUser; | |
349 | else | |
350 | u = pw->pw_name; | |
351 | fprintf(tfp, "C%s\n", u); | |
352 | } | |
353 | ||
81b7d258 EA |
354 | \f/* |
355 | ** RUNQUEUE -- run the jobs in the queue. | |
356 | ** | |
357 | ** Gets the stuff out of the queue in some presumably logical | |
358 | ** order and processes them. | |
359 | ** | |
360 | ** Parameters: | |
2e3062fe EA |
361 | ** forkflag -- TRUE if the queue scanning should be done in |
362 | ** a child process. We double-fork so it is not our | |
363 | ** child and we don't have to clean up after it. | |
81b7d258 EA |
364 | ** |
365 | ** Returns: | |
366 | ** none. | |
367 | ** | |
368 | ** Side Effects: | |
369 | ** runs things in the mail queue. | |
370 | */ | |
371 | ||
ca4d0c0b EA |
372 | ENVELOPE QueueEnvelope; /* the queue run envelope */ |
373 | ||
374 | runqueue(forkflag) | |
2cf55cb7 | 375 | bool forkflag; |
81b7d258 | 376 | { |
4bc44f60 | 377 | extern bool shouldqueue(); |
ca4d0c0b EA |
378 | register ENVELOPE *e; |
379 | extern ENVELOPE BlankEnvelope; | |
380 | extern ENVELOPE *newenvelope(); | |
4bc44f60 EA |
381 | |
382 | /* | |
383 | ** If no work will ever be selected, don't even bother reading | |
384 | ** the queue. | |
385 | */ | |
386 | ||
3620ad97 | 387 | CurrentLA = getla(); /* get load average */ |
3f9ac8ea | 388 | |
4bc44f60 EA |
389 | if (shouldqueue(-100000000L)) |
390 | { | |
391 | if (Verbose) | |
392 | printf("Skipping queue run -- load average too high\n"); | |
ca4d0c0b | 393 | return; |
4bc44f60 EA |
394 | } |
395 | ||
b6dffdf5 EA |
396 | /* |
397 | ** See if we want to go off and do other useful work. | |
398 | */ | |
2cf55cb7 EA |
399 | |
400 | if (forkflag) | |
401 | { | |
6d06102a EA |
402 | int pid; |
403 | ||
404 | pid = dofork(); | |
405 | if (pid != 0) | |
2cf55cb7 | 406 | { |
0df908a9 | 407 | extern void reapchild(); |
c8ad461a | 408 | |
6d06102a | 409 | /* parent -- pick up intermediate zombie */ |
c8ad461a | 410 | #ifndef SIGCHLD |
7338e3d4 | 411 | (void) waitfor(pid); |
c8ad461a EA |
412 | #else SIGCHLD |
413 | (void) signal(SIGCHLD, reapchild); | |
414 | #endif SIGCHLD | |
c4442979 | 415 | if (QueueIntvl != 0) |
611b763d | 416 | (void) setevent(QueueIntvl, runqueue, TRUE); |
2cf55cb7 EA |
417 | return; |
418 | } | |
6d06102a | 419 | /* child -- double fork */ |
c8ad461a | 420 | #ifndef SIGCHLD |
6d06102a EA |
421 | if (fork() != 0) |
422 | exit(EX_OK); | |
c8ad461a EA |
423 | #else SIGCHLD |
424 | (void) signal(SIGCHLD, SIG_DFL); | |
425 | #endif SIGCHLD | |
b6dffdf5 | 426 | } |
2e3062fe | 427 | |
3f9ac8ea | 428 | setproctitle("running queue: %s", QueueDir); |
2e3062fe | 429 | |
36a4e219 EA |
430 | # ifdef LOG |
431 | if (LogLevel > 11) | |
ca4d0c0b EA |
432 | syslog(LOG_DEBUG, "runqueue %s, pid=%d, forkflag=%d", |
433 | QueueDir, getpid(), forkflag); | |
36a4e219 | 434 | # endif LOG |
81b7d258 | 435 | |
eb8af3ce EA |
436 | /* |
437 | ** Release any resources used by the daemon code. | |
438 | */ | |
439 | ||
440 | # ifdef DAEMON | |
441 | clrdaemon(); | |
442 | # endif DAEMON | |
443 | ||
ca4d0c0b EA |
444 | /* |
445 | ** Create ourselves an envelope | |
446 | */ | |
447 | ||
448 | CurEnv = &QueueEnvelope; | |
449 | e = newenvelope(&QueueEnvelope); | |
450 | e->e_flags = BlankEnvelope.e_flags; | |
451 | ||
a78155b0 EA |
452 | /* |
453 | ** Make sure the alias database is open. | |
454 | */ | |
455 | ||
a4076aed | 456 | initaliases(AliasFile, FALSE, e); |
a78155b0 | 457 | |
b6dffdf5 EA |
458 | /* |
459 | ** Start making passes through the queue. | |
460 | ** First, read and sort the entire queue. | |
461 | ** Then, process the work in that order. | |
462 | ** But if you take too long, start over. | |
b6dffdf5 | 463 | */ |
81b7d258 | 464 | |
6d06102a | 465 | /* order the existing work requests */ |
8ff78b51 | 466 | (void) orderq(FALSE); |
291fa573 | 467 | |
6d06102a EA |
468 | /* process them once at a time */ |
469 | while (WorkQ != NULL) | |
2cf55cb7 | 470 | { |
6d06102a | 471 | WORK *w = WorkQ; |
2cf55cb7 | 472 | |
6d06102a | 473 | WorkQ = WorkQ->w_next; |
a4076aed | 474 | dowork(w, e); |
6d06102a EA |
475 | free(w->w_name); |
476 | free((char *) w); | |
2cf55cb7 | 477 | } |
37ea3cbf EA |
478 | |
479 | /* exit without the usual cleanup */ | |
4e20c4d2 EA |
480 | e->e_id = NULL; |
481 | finis(); | |
aba51985 EA |
482 | } |
483 | \f/* | |
81b7d258 EA |
484 | ** ORDERQ -- order the work queue. |
485 | ** | |
486 | ** Parameters: | |
2e3062fe EA |
487 | ** doall -- if set, include everything in the queue (even |
488 | ** the jobs that cannot be run because the load | |
489 | ** average is too high). Otherwise, exclude those | |
490 | ** jobs. | |
81b7d258 EA |
491 | ** |
492 | ** Returns: | |
e65b95c4 EA |
493 | ** The number of request in the queue (not necessarily |
494 | ** the number of requests in WorkQ however). | |
81b7d258 EA |
495 | ** |
496 | ** Side Effects: | |
497 | ** Sets WorkQ to the queue of available work, in order. | |
498 | */ | |
499 | ||
4e969be0 EA |
500 | # define NEED_P 001 |
501 | # define NEED_T 002 | |
81b7d258 | 502 | |
38d3b461 EA |
503 | # ifndef DIR |
504 | # define DIR FILE | |
505 | # define direct dir | |
506 | # define opendir(d) fopen(d, "r") | |
07a8f29b | 507 | # define readdir(f) ((fread(&dbuf, sizeof dbuf, 1, f) > 0) ? &dbuf : 0) |
38d3b461 EA |
508 | static struct dir dbuf; |
509 | # define closedir(f) fclose(f) | |
510 | # endif DIR | |
511 | ||
2e3062fe EA |
512 | orderq(doall) |
513 | bool doall; | |
81b7d258 | 514 | { |
ccd1d833 | 515 | register struct direct *d; |
81b7d258 | 516 | register WORK *w; |
ccd1d833 | 517 | DIR *f; |
81b7d258 | 518 | register int i; |
4e969be0 | 519 | WORK wlist[QUEUESIZE+1]; |
0490b7d7 | 520 | int wn = -1; |
81b7d258 | 521 | extern workcmpf(); |
81b7d258 EA |
522 | |
523 | /* clear out old WorkQ */ | |
524 | for (w = WorkQ; w != NULL; ) | |
525 | { | |
526 | register WORK *nw = w->w_next; | |
527 | ||
528 | WorkQ = nw; | |
529 | free(w->w_name); | |
530 | free((char *) w); | |
531 | w = nw; | |
532 | } | |
533 | ||
534 | /* open the queue directory */ | |
6bbaf971 | 535 | f = opendir("."); |
81b7d258 EA |
536 | if (f == NULL) |
537 | { | |
6bbaf971 | 538 | syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); |
0490b7d7 | 539 | return (0); |
81b7d258 EA |
540 | } |
541 | ||
542 | /* | |
543 | ** Read the work directory. | |
544 | */ | |
545 | ||
0490b7d7 | 546 | while ((d = readdir(f)) != NULL) |
81b7d258 | 547 | { |
81b7d258 | 548 | FILE *cf; |
7338e3d4 | 549 | char lbuf[MAXNAME]; |
81b7d258 EA |
550 | |
551 | /* is this an interesting entry? */ | |
07a8f29b EA |
552 | if (d->d_ino == 0) |
553 | continue; | |
554 | # ifdef DEBUG | |
555 | if (tTd(40, 10)) | |
556 | printf("orderq: %12s\n", d->d_name); | |
557 | # endif DEBUG | |
2cce0c26 | 558 | if (d->d_name[0] != 'q' || d->d_name[1] != 'f') |
81b7d258 EA |
559 | continue; |
560 | ||
0490b7d7 | 561 | /* yes -- open control file (if not too many files) */ |
4e969be0 | 562 | if (++wn >= QUEUESIZE) |
0490b7d7 | 563 | continue; |
6bbaf971 | 564 | cf = fopen(d->d_name, "r"); |
81b7d258 EA |
565 | if (cf == NULL) |
566 | { | |
91f69adf EA |
567 | /* this may be some random person sending hir msgs */ |
568 | /* syserr("orderq: cannot open %s", cbuf); */ | |
bd0712bd EA |
569 | if (tTd(41, 2)) |
570 | printf("orderq: cannot open %s (%d)\n", | |
571 | d->d_name, errno); | |
91f69adf | 572 | errno = 0; |
bd0712bd | 573 | wn--; |
81b7d258 EA |
574 | continue; |
575 | } | |
4e969be0 EA |
576 | w = &wlist[wn]; |
577 | w->w_name = newstr(d->d_name); | |
81b7d258 | 578 | |
4ff794a3 | 579 | /* make sure jobs in creation don't clog queue */ |
4e969be0 EA |
580 | w->w_pri = 0x7fffffff; |
581 | w->w_ctime = 0; | |
4ff794a3 | 582 | |
81b7d258 | 583 | /* extract useful information */ |
4e969be0 EA |
584 | i = NEED_P | NEED_T; |
585 | while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL) | |
81b7d258 | 586 | { |
8ff78b51 EA |
587 | extern long atol(); |
588 | ||
2e3062fe | 589 | switch (lbuf[0]) |
81b7d258 | 590 | { |
2e3062fe | 591 | case 'P': |
4e969be0 EA |
592 | w->w_pri = atol(&lbuf[1]); |
593 | i &= ~NEED_P; | |
2e3062fe | 594 | break; |
f746582a EA |
595 | |
596 | case 'T': | |
4e969be0 EA |
597 | w->w_ctime = atol(&lbuf[1]); |
598 | i &= ~NEED_T; | |
f746582a | 599 | break; |
81b7d258 EA |
600 | } |
601 | } | |
81b7d258 | 602 | (void) fclose(cf); |
4bc44f60 | 603 | |
4e969be0 | 604 | if (!doall && shouldqueue(w->w_pri)) |
4bc44f60 EA |
605 | { |
606 | /* don't even bother sorting this job in */ | |
607 | wn--; | |
608 | } | |
81b7d258 | 609 | } |
ccd1d833 | 610 | (void) closedir(f); |
bd0712bd | 611 | wn++; |
81b7d258 EA |
612 | |
613 | /* | |
614 | ** Sort the work directory. | |
615 | */ | |
616 | ||
4e969be0 | 617 | qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf); |
81b7d258 EA |
618 | |
619 | /* | |
620 | ** Convert the work list into canonical form. | |
7338e3d4 | 621 | ** Should be turning it into a list of envelopes here perhaps. |
81b7d258 EA |
622 | */ |
623 | ||
a0225d08 | 624 | WorkQ = NULL; |
4e969be0 | 625 | for (i = min(wn, QUEUESIZE); --i >= 0; ) |
81b7d258 EA |
626 | { |
627 | w = (WORK *) xalloc(sizeof *w); | |
628 | w->w_name = wlist[i].w_name; | |
81b7d258 | 629 | w->w_pri = wlist[i].w_pri; |
f746582a | 630 | w->w_ctime = wlist[i].w_ctime; |
a0225d08 EA |
631 | w->w_next = WorkQ; |
632 | WorkQ = w; | |
81b7d258 EA |
633 | } |
634 | ||
9678c96d | 635 | if (tTd(40, 1)) |
81b7d258 EA |
636 | { |
637 | for (w = WorkQ; w != NULL; w = w->w_next) | |
9ccf54c4 | 638 | printf("%32s: pri=%ld\n", w->w_name, w->w_pri); |
81b7d258 | 639 | } |
0490b7d7 | 640 | |
bd0712bd | 641 | return (wn); |
81b7d258 EA |
642 | } |
643 | \f/* | |
9678c96d | 644 | ** WORKCMPF -- compare function for ordering work. |
81b7d258 EA |
645 | ** |
646 | ** Parameters: | |
647 | ** a -- the first argument. | |
648 | ** b -- the second argument. | |
649 | ** | |
650 | ** Returns: | |
a0225d08 EA |
651 | ** -1 if a < b |
652 | ** 0 if a == b | |
653 | ** +1 if a > b | |
81b7d258 EA |
654 | ** |
655 | ** Side Effects: | |
656 | ** none. | |
657 | */ | |
658 | ||
81b7d258 | 659 | workcmpf(a, b) |
9ccf54c4 EA |
660 | register WORK *a; |
661 | register WORK *b; | |
81b7d258 | 662 | { |
f746582a EA |
663 | long pa = a->w_pri + a->w_ctime; |
664 | long pb = b->w_pri + b->w_ctime; | |
2e3062fe EA |
665 | |
666 | if (pa == pb) | |
81b7d258 | 667 | return (0); |
2e3062fe | 668 | else if (pa > pb) |
e65b95c4 | 669 | return (1); |
a0225d08 EA |
670 | else |
671 | return (-1); | |
81b7d258 EA |
672 | } |
673 | \f/* | |
674 | ** DOWORK -- do a work request. | |
675 | ** | |
676 | ** Parameters: | |
677 | ** w -- the work request to be satisfied. | |
678 | ** | |
679 | ** Returns: | |
680 | ** none. | |
681 | ** | |
682 | ** Side Effects: | |
683 | ** The work request is satisfied if possible. | |
684 | */ | |
685 | ||
a4076aed | 686 | dowork(w, e) |
81b7d258 | 687 | register WORK *w; |
a4076aed | 688 | register ENVELOPE *e; |
81b7d258 EA |
689 | { |
690 | register int i; | |
2e3062fe | 691 | extern bool shouldqueue(); |
3620ad97 | 692 | extern bool readqf(); |
81b7d258 | 693 | |
9678c96d | 694 | if (tTd(40, 1)) |
9ccf54c4 | 695 | printf("dowork: %s pri %ld\n", w->w_name, w->w_pri); |
81b7d258 EA |
696 | |
697 | /* | |
2e3062fe | 698 | ** Ignore jobs that are too expensive for the moment. |
81b7d258 EA |
699 | */ |
700 | ||
2e3062fe | 701 | if (shouldqueue(w->w_pri)) |
81b7d258 | 702 | { |
2e3062fe | 703 | if (Verbose) |
559f8745 | 704 | printf("\nSkipping %s\n", w->w_name + 2); |
81b7d258 EA |
705 | return; |
706 | } | |
707 | ||
2e3062fe EA |
708 | /* |
709 | ** Fork for work. | |
710 | */ | |
711 | ||
712 | if (ForkQueueRuns) | |
713 | { | |
714 | i = fork(); | |
715 | if (i < 0) | |
716 | { | |
717 | syserr("dowork: cannot fork"); | |
718 | return; | |
719 | } | |
720 | } | |
721 | else | |
722 | { | |
723 | i = 0; | |
724 | } | |
725 | ||
81b7d258 EA |
726 | if (i == 0) |
727 | { | |
728 | /* | |
729 | ** CHILD | |
6bbaf971 EA |
730 | ** Lock the control file to avoid duplicate deliveries. |
731 | ** Then run the file as though we had just read it. | |
68f0b54c EA |
732 | ** We save an idea of the temporary name so we |
733 | ** can recover on interrupt. | |
81b7d258 EA |
734 | */ |
735 | ||
9416f3a0 | 736 | /* set basic modes, etc. */ |
37eaaadb | 737 | (void) alarm(0); |
a4076aed | 738 | clearenvelope(e, FALSE); |
81b7d258 | 739 | QueueRun = TRUE; |
7338e3d4 | 740 | ErrorMode = EM_MAIL; |
a4076aed | 741 | e->e_id = &w->w_name[2]; |
36a4e219 | 742 | # ifdef LOG |
ca4d0c0b | 743 | if (LogLevel > 12) |
a4076aed | 744 | syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id, |
291fa573 | 745 | getpid()); |
36a4e219 | 746 | # endif LOG |
9416f3a0 EA |
747 | |
748 | /* don't use the headers from sendmail.cf... */ | |
a4076aed | 749 | e->e_header = NULL; |
9416f3a0 | 750 | |
3620ad97 | 751 | /* read the queue control file -- return if locked */ |
a4076aed | 752 | if (!readqf(e)) |
dd1fe05b | 753 | { |
2e3062fe EA |
754 | if (ForkQueueRuns) |
755 | exit(EX_OK); | |
756 | else | |
757 | return; | |
dd1fe05b | 758 | } |
dd1fe05b | 759 | |
a4076aed EA |
760 | e->e_flags |= EF_INQUEUE; |
761 | eatheader(e); | |
dd1fe05b EA |
762 | |
763 | /* do the delivery */ | |
a4076aed EA |
764 | if (!bitset(EF_FATALERRS, e->e_flags)) |
765 | sendall(e, SM_DELIVER); | |
dd1fe05b | 766 | |
dd1fe05b | 767 | /* finish up and exit */ |
2e3062fe EA |
768 | if (ForkQueueRuns) |
769 | finis(); | |
770 | else | |
a4076aed | 771 | dropenvelope(e); |
81b7d258 | 772 | } |
2e3062fe EA |
773 | else |
774 | { | |
775 | /* | |
776 | ** Parent -- pick up results. | |
777 | */ | |
81b7d258 | 778 | |
2e3062fe EA |
779 | errno = 0; |
780 | (void) waitfor(i); | |
781 | } | |
81b7d258 EA |
782 | } |
783 | \f/* | |
784 | ** READQF -- read queue file and set up environment. | |
785 | ** | |
786 | ** Parameters: | |
7338e3d4 | 787 | ** e -- the envelope of the job to run. |
81b7d258 EA |
788 | ** |
789 | ** Returns: | |
3620ad97 EA |
790 | ** TRUE if it successfully read the queue file. |
791 | ** FALSE otherwise. | |
81b7d258 EA |
792 | ** |
793 | ** Side Effects: | |
3620ad97 | 794 | ** The queue file is returned locked. |
81b7d258 EA |
795 | */ |
796 | ||
3620ad97 EA |
797 | bool |
798 | readqf(e) | |
7338e3d4 | 799 | register ENVELOPE *e; |
81b7d258 | 800 | { |
11e3f8b5 EA |
801 | char *qf; |
802 | register FILE *qfp; | |
d2213d6c | 803 | ADDRESS *ctladdr; |
6a86d693 | 804 | char buf[MAXFIELD]; |
611b763d | 805 | extern char *fgetfolded(); |
8ff78b51 | 806 | extern long atol(); |
d2213d6c | 807 | extern ADDRESS *setctluser(); |
76b607b2 EA |
808 | # ifdef LOCKF |
809 | struct flock lfd; | |
810 | # endif | |
abae7b2d | 811 | extern ADDRESS *sendto(); |
81b7d258 | 812 | |
81b7d258 EA |
813 | /* |
814 | ** Read and process the file. | |
815 | */ | |
816 | ||
11e3f8b5 | 817 | qf = queuename(e, 'q'); |
76b607b2 | 818 | qfp = fopen(qf, "r+"); |
11e3f8b5 EA |
819 | if (qfp == NULL) |
820 | { | |
3f9ac8ea RA |
821 | if (errno != ENOENT) |
822 | syserr("readqf: no control file %s", qf); | |
3620ad97 | 823 | return FALSE; |
3f9ac8ea RA |
824 | } |
825 | ||
4287d84d | 826 | # ifdef LOCKF |
76b607b2 EA |
827 | lfd.l_type = F_WRLCK; |
828 | lfd.l_whence = lfd.l_start = lfd.l_len = 0; | |
829 | if (fcntl(fileno(qfp), F_SETLK, &lfd) < 0) | |
4287d84d | 830 | # else |
3f9ac8ea | 831 | if (flock(fileno(qfp), LOCK_EX|LOCK_NB) < 0) |
4287d84d | 832 | # endif |
3f9ac8ea | 833 | { |
3f9ac8ea RA |
834 | /* being processed by another queuer */ |
835 | if (Verbose) | |
a4076aed | 836 | printf("%s: locked\n", e->e_id); |
3620ad97 | 837 | # ifdef LOG |
01e8020e | 838 | if (LogLevel > 10) |
a4076aed | 839 | syslog(LOG_DEBUG, "%s: locked", e->e_id); |
3f9ac8ea RA |
840 | # endif LOG |
841 | (void) fclose(qfp); | |
3620ad97 | 842 | return FALSE; |
11e3f8b5 | 843 | } |
3f9ac8ea | 844 | |
3620ad97 EA |
845 | /* save this lock */ |
846 | e->e_lockfp = qfp; | |
847 | ||
3f9ac8ea | 848 | /* do basic system initialization */ |
a4076aed | 849 | initsys(e); |
3f9ac8ea | 850 | |
11e3f8b5 | 851 | FileName = qf; |
560a80d9 | 852 | LineNumber = 0; |
3620ad97 | 853 | if (Verbose) |
7338e3d4 | 854 | printf("\nRunning %s\n", e->e_id); |
d2213d6c | 855 | ctladdr = NULL; |
560a80d9 | 856 | while (fgetfolded(buf, sizeof buf, qfp) != NULL) |
81b7d258 | 857 | { |
795590e2 EA |
858 | if (tTd(40, 4)) |
859 | printf("+++++ %s\n", buf); | |
81b7d258 EA |
860 | switch (buf[0]) |
861 | { | |
3fbc69d6 | 862 | case 'C': /* specify controlling user */ |
d2213d6c | 863 | ctladdr = setctluser(&buf[1]); |
3fbc69d6 KB |
864 | break; |
865 | ||
81b7d258 | 866 | case 'R': /* specify recipient */ |
abae7b2d | 867 | (void) sendto(&buf[1], 1, (ADDRESS *) NULL, 0); |
81b7d258 EA |
868 | break; |
869 | ||
4e969be0 | 870 | case 'E': /* specify error recipient */ |
a4076aed | 871 | sendtolist(&buf[1], ctladdr, &e->e_errorqueue, e); |
4e969be0 EA |
872 | break; |
873 | ||
81b7d258 | 874 | case 'H': /* header */ |
a4076aed | 875 | (void) chompheader(&buf[1], FALSE, e); |
81b7d258 EA |
876 | break; |
877 | ||
baa0c390 EA |
878 | case 'M': /* message */ |
879 | e->e_message = newstr(&buf[1]); | |
880 | break; | |
881 | ||
81b7d258 | 882 | case 'S': /* sender */ |
a4076aed | 883 | setsender(newstr(&buf[1]), e); |
81b7d258 EA |
884 | break; |
885 | ||
886 | case 'D': /* data file name */ | |
7338e3d4 | 887 | e->e_df = newstr(&buf[1]); |
912acb74 EA |
888 | e->e_dfp = fopen(e->e_df, "r"); |
889 | if (e->e_dfp == NULL) | |
7338e3d4 | 890 | syserr("readqf: cannot open %s", e->e_df); |
81b7d258 EA |
891 | break; |
892 | ||
96476cab | 893 | case 'T': /* init time */ |
2e3062fe | 894 | e->e_ctime = atol(&buf[1]); |
81b7d258 EA |
895 | break; |
896 | ||
aba51985 | 897 | case 'P': /* message priority */ |
6c1e806e | 898 | e->e_msgpriority = atol(&buf[1]) + WkTimeFact; |
dd1fe05b EA |
899 | break; |
900 | ||
22293c34 EA |
901 | case '$': /* define macro */ |
902 | define(buf[1], newstr(&buf[2]), e); | |
903 | break; | |
904 | ||
2e3062fe EA |
905 | case '\0': /* blank line; ignore */ |
906 | break; | |
907 | ||
81b7d258 | 908 | default: |
2e3062fe EA |
909 | syserr("readqf(%s:%d): bad line \"%s\"", e->e_id, |
910 | LineNumber, buf); | |
81b7d258 EA |
911 | break; |
912 | } | |
913 | } | |
7338e3d4 EA |
914 | |
915 | FileName = NULL; | |
2e3062fe EA |
916 | |
917 | /* | |
918 | ** If we haven't read any lines, this queue file is empty. | |
919 | ** Arrange to remove it without referencing any null pointers. | |
920 | */ | |
921 | ||
922 | if (LineNumber == 0) | |
923 | { | |
924 | errno = 0; | |
925 | e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE; | |
926 | } | |
3620ad97 | 927 | return TRUE; |
81b7d258 EA |
928 | } |
929 | \f/* | |
64912e7e EA |
930 | ** PRINTQUEUE -- print out a representation of the mail queue |
931 | ** | |
932 | ** Parameters: | |
933 | ** none. | |
934 | ** | |
935 | ** Returns: | |
936 | ** none. | |
937 | ** | |
938 | ** Side Effects: | |
939 | ** Prints a listing of the mail queue on the standard output. | |
940 | */ | |
941 | ||
942 | printqueue() | |
943 | { | |
944 | register WORK *w; | |
945 | FILE *f; | |
0490b7d7 | 946 | int nrequests; |
64912e7e EA |
947 | char buf[MAXLINE]; |
948 | ||
949 | /* | |
950 | ** Read and order the queue. | |
951 | */ | |
952 | ||
2e3062fe | 953 | nrequests = orderq(TRUE); |
64912e7e EA |
954 | |
955 | /* | |
956 | ** Print the work list that we have read. | |
957 | */ | |
958 | ||
959 | /* first see if there is anything */ | |
0490b7d7 | 960 | if (nrequests <= 0) |
64912e7e | 961 | { |
0490b7d7 | 962 | printf("Mail queue is empty\n"); |
64912e7e EA |
963 | return; |
964 | } | |
965 | ||
3620ad97 | 966 | CurrentLA = getla(); /* get load average */ |
3f9ac8ea | 967 | |
d7b5594c | 968 | printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); |
4e969be0 EA |
969 | if (nrequests > QUEUESIZE) |
970 | printf(", only %d printed", QUEUESIZE); | |
f4b05990 | 971 | if (Verbose) |
1367e7bd | 972 | printf(")\n--QID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n"); |
f4b05990 EA |
973 | else |
974 | printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); | |
64912e7e EA |
975 | for (w = WorkQ; w != NULL; w = w->w_next) |
976 | { | |
977 | struct stat st; | |
0490b7d7 EA |
978 | auto time_t submittime = 0; |
979 | long dfsize = -1; | |
baa0c390 | 980 | char message[MAXLINE]; |
76b607b2 EA |
981 | # ifdef LOCKF |
982 | struct flock lfd; | |
983 | # endif | |
2e3062fe | 984 | extern bool shouldqueue(); |
64912e7e | 985 | |
560a80d9 EA |
986 | f = fopen(w->w_name, "r"); |
987 | if (f == NULL) | |
988 | { | |
989 | errno = 0; | |
990 | continue; | |
991 | } | |
64912e7e | 992 | printf("%7s", w->w_name + 2); |
4287d84d | 993 | # ifdef LOCKF |
76b607b2 EA |
994 | lfd.l_type = F_RDLCK; |
995 | lfd.l_whence = lfd.l_start = lfd.l_len = 0; | |
996 | if (fcntl(fileno(f), F_GETLK, &lfd) < 0 || lfd.l_type != F_UNLCK) | |
4287d84d | 997 | # else |
3f9ac8ea | 998 | if (flock(fileno(f), LOCK_SH|LOCK_NB) < 0) |
4287d84d | 999 | # endif |
0490b7d7 | 1000 | printf("*"); |
2e3062fe EA |
1001 | else if (shouldqueue(w->w_pri)) |
1002 | printf("X"); | |
0490b7d7 EA |
1003 | else |
1004 | printf(" "); | |
1005 | errno = 0; | |
560a80d9 | 1006 | |
baa0c390 | 1007 | message[0] = '\0'; |
64912e7e EA |
1008 | while (fgets(buf, sizeof buf, f) != NULL) |
1009 | { | |
22293c34 EA |
1010 | register int i; |
1011 | ||
64912e7e EA |
1012 | fixcrlf(buf, TRUE); |
1013 | switch (buf[0]) | |
1014 | { | |
baa0c390 | 1015 | case 'M': /* error message */ |
22293c34 EA |
1016 | if ((i = strlen(&buf[1])) >= sizeof message) |
1017 | i = sizeof message; | |
1018 | bcopy(&buf[1], message, i); | |
1019 | message[i] = '\0'; | |
baa0c390 EA |
1020 | break; |
1021 | ||
64912e7e | 1022 | case 'S': /* sender name */ |
f4b05990 | 1023 | if (Verbose) |
4ff794a3 EA |
1024 | printf("%8ld %10ld %.12s %.38s", dfsize, |
1025 | w->w_pri, ctime(&submittime) + 4, | |
f4b05990 EA |
1026 | &buf[1]); |
1027 | else | |
1028 | printf("%8ld %.16s %.45s", dfsize, | |
1029 | ctime(&submittime), &buf[1]); | |
1742e60b | 1030 | if (message[0] != '\0') |
4ff794a3 | 1031 | printf("\n\t\t (%.60s)", message); |
64912e7e | 1032 | break; |
3620ad97 | 1033 | |
3fbc69d6 | 1034 | case 'C': /* controlling user */ |
d2213d6c | 1035 | if (Verbose) |
f8a74171 | 1036 | printf("\n\t\t\t\t (---%.34s---)", &buf[1]); |
3fbc69d6 | 1037 | break; |
64912e7e EA |
1038 | |
1039 | case 'R': /* recipient name */ | |
f4b05990 | 1040 | if (Verbose) |
4ff794a3 | 1041 | printf("\n\t\t\t\t\t %.38s", &buf[1]); |
f4b05990 EA |
1042 | else |
1043 | printf("\n\t\t\t\t %.45s", &buf[1]); | |
64912e7e EA |
1044 | break; |
1045 | ||
1046 | case 'T': /* creation time */ | |
2e3062fe | 1047 | submittime = atol(&buf[1]); |
0490b7d7 EA |
1048 | break; |
1049 | ||
1050 | case 'D': /* data file name */ | |
1051 | if (stat(&buf[1], &st) >= 0) | |
1052 | dfsize = st.st_size; | |
64912e7e EA |
1053 | break; |
1054 | } | |
1055 | } | |
0490b7d7 EA |
1056 | if (submittime == (time_t) 0) |
1057 | printf(" (no control file)"); | |
64912e7e | 1058 | printf("\n"); |
0e306e7f | 1059 | (void) fclose(f); |
64912e7e EA |
1060 | } |
1061 | } | |
884a20cb EA |
1062 | |
1063 | # endif QUEUE | |
560a80d9 EA |
1064 | \f/* |
1065 | ** QUEUENAME -- build a file name in the queue directory for this envelope. | |
1066 | ** | |
1067 | ** Assigns an id code if one does not already exist. | |
1068 | ** This code is very careful to avoid trashing existing files | |
1069 | ** under any circumstances. | |
560a80d9 EA |
1070 | ** |
1071 | ** Parameters: | |
1072 | ** e -- envelope to build it in/from. | |
1073 | ** type -- the file type, used as the first character | |
1074 | ** of the file name. | |
1075 | ** | |
1076 | ** Returns: | |
1077 | ** a pointer to the new file name (in a static buffer). | |
1078 | ** | |
1079 | ** Side Effects: | |
3620ad97 EA |
1080 | ** If no id code is already assigned, queuename will |
1081 | ** assign an id code, create a qf file, and leave a | |
1082 | ** locked, open-for-write file pointer in the envelope. | |
560a80d9 EA |
1083 | */ |
1084 | ||
1085 | char * | |
1086 | queuename(e, type) | |
1087 | register ENVELOPE *e; | |
1088 | char type; | |
1089 | { | |
1090 | static char buf[MAXNAME]; | |
1091 | static int pid = -1; | |
1092 | char c1 = 'A'; | |
1093 | char c2 = 'A'; | |
1094 | ||
1095 | if (e->e_id == NULL) | |
1096 | { | |
1097 | char qf[20]; | |
560a80d9 EA |
1098 | |
1099 | /* find a unique id */ | |
1100 | if (pid != getpid()) | |
1101 | { | |
1102 | /* new process -- start back at "AA" */ | |
1103 | pid = getpid(); | |
1104 | c1 = 'A'; | |
1105 | c2 = 'A' - 1; | |
1106 | } | |
1107 | (void) sprintf(qf, "qfAA%05d", pid); | |
560a80d9 EA |
1108 | |
1109 | while (c1 < '~' || c2 < 'Z') | |
1110 | { | |
1111 | int i; | |
76b607b2 EA |
1112 | # ifdef LOCKF |
1113 | struct flock lfd; | |
1114 | # endif | |
560a80d9 EA |
1115 | |
1116 | if (c2 >= 'Z') | |
1117 | { | |
1118 | c1++; | |
1119 | c2 = 'A' - 1; | |
1120 | } | |
3f9ac8ea RA |
1121 | qf[2] = c1; |
1122 | qf[3] = ++c2; | |
560a80d9 | 1123 | if (tTd(7, 20)) |
3f9ac8ea | 1124 | printf("queuename: trying \"%s\"\n", qf); |
560a80d9 | 1125 | |
3f9ac8ea | 1126 | i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode); |
3620ad97 EA |
1127 | if (i < 0) |
1128 | { | |
1129 | if (errno == EEXIST) | |
1130 | continue; | |
1131 | syserr("queuename: Cannot create \"%s\" in \"%s\"", | |
1132 | qf, QueueDir); | |
1133 | exit(EX_UNAVAILABLE); | |
1134 | } | |
1135 | # ifdef LOCKF | |
76b607b2 EA |
1136 | lfd.l_type = F_WRLCK; |
1137 | lfd.l_whence = lfd.l_start = lfd.l_len = 0; | |
1138 | if (fcntl(i, F_SETLK, &lfd) >= 0) | |
3620ad97 EA |
1139 | # else |
1140 | if (flock(i, LOCK_EX|LOCK_NB) >= 0) | |
1141 | # endif | |
1142 | { | |
1143 | e->e_lockfp = fdopen(i, "w"); | |
bb09c502 | 1144 | break; |
3f9ac8ea | 1145 | } |
3620ad97 EA |
1146 | |
1147 | /* a reader got the file; abandon it and try again */ | |
1148 | (void) close(i); | |
560a80d9 EA |
1149 | } |
1150 | if (c1 >= '~' && c2 >= 'Z') | |
1151 | { | |
1152 | syserr("queuename: Cannot create \"%s\" in \"%s\"", | |
1153 | qf, QueueDir); | |
1154 | exit(EX_OSERR); | |
1155 | } | |
1156 | e->e_id = newstr(&qf[2]); | |
1157 | define('i', e->e_id, e); | |
560a80d9 EA |
1158 | if (tTd(7, 1)) |
1159 | printf("queuename: assigned id %s, env=%x\n", e->e_id, e); | |
1160 | # ifdef LOG | |
1161 | if (LogLevel > 16) | |
1162 | syslog(LOG_DEBUG, "%s: assigned id", e->e_id); | |
1163 | # endif LOG | |
560a80d9 EA |
1164 | } |
1165 | ||
1166 | if (type == '\0') | |
1167 | return (NULL); | |
1168 | (void) sprintf(buf, "%cf%s", type, e->e_id); | |
560a80d9 EA |
1169 | if (tTd(7, 2)) |
1170 | printf("queuename: %s\n", buf); | |
560a80d9 EA |
1171 | return (buf); |
1172 | } | |
1173 | \f/* | |
1174 | ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope | |
1175 | ** | |
1176 | ** Parameters: | |
1177 | ** e -- the envelope to unlock. | |
1178 | ** | |
1179 | ** Returns: | |
1180 | ** none | |
1181 | ** | |
1182 | ** Side Effects: | |
1183 | ** unlocks the queue for `e'. | |
1184 | */ | |
1185 | ||
1186 | unlockqueue(e) | |
1187 | ENVELOPE *e; | |
1188 | { | |
3620ad97 EA |
1189 | /* if there is a lock file in the envelope, close it */ |
1190 | if (e->e_lockfp != NULL) | |
1191 | fclose(e->e_lockfp); | |
1192 | e->e_lockfp = NULL; | |
1193 | ||
560a80d9 | 1194 | /* remove the transcript */ |
560a80d9 EA |
1195 | # ifdef LOG |
1196 | if (LogLevel > 19) | |
1197 | syslog(LOG_DEBUG, "%s: unlock", e->e_id); | |
1198 | # endif LOG | |
1199 | if (!tTd(51, 4)) | |
560a80d9 EA |
1200 | xunlink(queuename(e, 'x')); |
1201 | ||
560a80d9 | 1202 | } |
3fbc69d6 | 1203 | \f/* |
d2213d6c | 1204 | ** SETCTLUSER -- create a controlling address |
3fbc69d6 | 1205 | ** |
d2213d6c EA |
1206 | ** Create a fake "address" given only a local login name; this is |
1207 | ** used as a "controlling user" for future recipient addresses. | |
3fbc69d6 KB |
1208 | ** |
1209 | ** Parameters: | |
d2213d6c | 1210 | ** user -- the user name of the controlling user. |
3fbc69d6 KB |
1211 | ** |
1212 | ** Returns: | |
d2213d6c | 1213 | ** An address descriptor for the controlling user. |
3fbc69d6 KB |
1214 | ** |
1215 | ** Side Effects: | |
1216 | ** none. | |
1217 | */ | |
1218 | ||
d2213d6c EA |
1219 | ADDRESS * |
1220 | setctluser(user) | |
1221 | char *user; | |
3fbc69d6 | 1222 | { |
d2213d6c | 1223 | register ADDRESS *a; |
3fbc69d6 | 1224 | struct passwd *pw; |
3fbc69d6 KB |
1225 | |
1226 | /* | |
d2213d6c | 1227 | ** See if this clears our concept of controlling user. |
3fbc69d6 KB |
1228 | */ |
1229 | ||
d2213d6c EA |
1230 | if (user == NULL || *user == '\0') |
1231 | return NULL; | |
3fbc69d6 KB |
1232 | |
1233 | /* | |
d2213d6c | 1234 | ** Set up addr fields for controlling user. |
3fbc69d6 KB |
1235 | */ |
1236 | ||
d2213d6c EA |
1237 | a = (ADDRESS *) xalloc(sizeof *a); |
1238 | bzero((char *) a, sizeof *a); | |
1239 | if ((pw = getpwnam(user)) != NULL) | |
3fbc69d6 | 1240 | { |
3fbc69d6 KB |
1241 | a->q_home = newstr(pw->pw_dir); |
1242 | a->q_uid = pw->pw_uid; | |
1243 | a->q_gid = pw->pw_gid; | |
d2213d6c | 1244 | a->q_ruser = newstr(user); |
3fbc69d6 KB |
1245 | } |
1246 | else | |
1247 | { | |
1248 | a->q_uid = DefUid; | |
1249 | a->q_gid = DefGid; | |
1250 | a->q_ruser = newstr(DefUser); | |
1251 | } | |
1252 | ||
1253 | a->q_flags |= QGOODUID; /* flag as a "ctladdr" */ | |
d2213d6c | 1254 | return a; |
3fbc69d6 | 1255 | } |