hacks so it will compile -- but I don't see making a lot of use
[unix-history] / usr / src / usr.sbin / sendmail / src / queue.c
CommitLineData
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 13static char sccsid[] = "@(#)queue.c 5.47 (Berkeley) %G% (with queueing)";
bee79b64 14#else
4e20c4d2 15static 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
35struct 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
43typedef struct work WORK;
44
45WORK *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 63queueup(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
334printctladdr(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
372ENVELOPE QueueEnvelope; /* the queue run envelope */
373
374runqueue(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
508static struct dir dbuf;
509# define closedir(f) fclose(f)
510# endif DIR
511
2e3062fe
EA
512orderq(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 659workcmpf(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 686dowork(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
797bool
798readqf(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
942printqueue()
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
1085char *
1086queuename(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
1186unlockqueue(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
1219ADDRESS *
1220setctluser(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}