print a message for jobs that disappear between reading the queue
[unix-history] / usr / src / usr.sbin / sendmail / src / queue.c
CommitLineData
b2a81223 1/*
dc45ba8c 2 * Copyright (c) 1983 Eric P. Allman
eb0bafab
KB
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
bee79b64 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
4ba6a6f4 13static char sccsid[] = "@(#)queue.c 8.16 (Berkeley) %G% (with queueing)";
bee79b64 14#else
4ba6a6f4 15static char sccsid[] = "@(#)queue.c 8.16 (Berkeley) %G% (without queueing)";
bee79b64
KB
16#endif
17#endif /* not lint */
18
81b7d258 19# include <errno.h>
3fbc69d6 20# include <pwd.h>
6feb509e 21# include <dirent.h>
4287d84d 22
76b607b2
EA
23# ifdef QUEUE
24
81b7d258 25/*
7338e3d4
EA
26** Work queue.
27*/
28
29struct work
30{
31 char *w_name; /* name of control file */
32 long w_pri; /* priority of message, see below */
f746582a 33 time_t w_ctime; /* creation time of message */
7338e3d4
EA
34 struct work *w_next; /* next in queue */
35};
36
37typedef struct work WORK;
38
39WORK *WorkQ; /* queue of things to be done */
40\f/*
81b7d258
EA
41** QUEUEUP -- queue a message up for future transmission.
42**
81b7d258 43** Parameters:
dd1fe05b 44** e -- the envelope to queue up.
d0bd03ce
EA
45** queueall -- if TRUE, queue all addresses, rather than
46** just those with the QQUEUEUP flag set.
7338e3d4 47** announce -- if TRUE, tell when you are queueing up.
81b7d258
EA
48**
49** Returns:
3620ad97 50** none.
81b7d258
EA
51**
52** Side Effects:
7338e3d4 53** The current request are saved in a control file.
3620ad97 54** The queue file is left locked.
81b7d258
EA
55*/
56
7338e3d4 57queueup(e, queueall, announce)
dd1fe05b 58 register ENVELOPE *e;
d0bd03ce 59 bool queueall;
7338e3d4 60 bool announce;
81b7d258 61{
2cce0c26 62 char *qf;
2cce0c26 63 register FILE *tfp;
81b7d258 64 register HDR *h;
d4f42161 65 register ADDRESS *q;
3620ad97
EA
66 int fd;
67 int i;
68 bool newid;
22293c34 69 register char *p;
4db45bf1 70 MAILER nullmailer;
3620ad97 71 char buf[MAXLINE], tf[MAXLINE];
81b7d258 72
9ccf54c4 73 /*
11e3f8b5 74 ** Create control file.
9ccf54c4 75 */
81b7d258 76
3620ad97 77 newid = (e->e_id == NULL);
e3778690
EA
78
79 /* if newid, queuename will create a locked qf file in e->lockfp */
3620ad97
EA
80 strcpy(tf, queuename(e, 't'));
81 tfp = e->e_lockfp;
82 if (tfp == NULL)
83 newid = FALSE;
e3778690
EA
84
85 /* if newid, just write the qf file directly (instead of tf file) */
3620ad97 86 if (newid)
4287d84d 87 {
3620ad97
EA
88 tfp = e->e_lockfp;
89 }
90 else
91 {
92 /* get a locked tf file */
b1c8be09 93 for (i = 0; i < 128; i++)
4287d84d 94 {
3620ad97
EA
95 fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
96 if (fd < 0)
4287d84d 97 {
b1c8be09
EA
98 if (errno != EEXIST)
99 break;
100#ifdef LOG
101 if (LogLevel > 0 && (i % 32) == 0)
102 syslog(LOG_ALERT, "queueup: cannot create %s: %s",
103 tf, errstring(errno));
104#endif
105 continue;
6680179d 106 }
f8a31c8e 107
71936fbe 108 if (lockfile(fd, tf, NULL, LOCK_EX|LOCK_NB))
3620ad97 109 break;
b1c8be09
EA
110#ifdef LOG
111 else if (LogLevel > 0 && (i % 32) == 0)
112 syslog(LOG_ALERT, "queueup: cannot lock %s: %s",
113 tf, errstring(errno));
114#endif
f8a31c8e 115
3620ad97 116 close(fd);
b1c8be09
EA
117
118 if ((i % 32) == 31)
119 {
120 /* save the old temp file away */
121 (void) rename(tf, queuename(e, 'T'));
122 }
123 else
124 sleep(i % 32);
6680179d 125 }
dc2cbc87 126 if (fd < 0)
b1c8be09 127 syserr("!queueup: cannot create temp file %s", tf);
6680179d 128
3620ad97
EA
129 tfp = fdopen(fd, "w");
130 }
81b7d258 131
9678c96d 132 if (tTd(40, 1))
51458e80 133 printf("\n>>>>> queueing %s >>>>>\n", e->e_id);
81b7d258 134
dd1fe05b
EA
135 /*
136 ** If there is no data file yet, create one.
137 */
138
139 if (e->e_df == NULL)
140 {
141 register FILE *dfp;
80482eb5 142 extern putbody();
dd1fe05b 143
f4318163
EA
144 e->e_df = queuename(e, 'd');
145 e->e_df = newstr(e->e_df);
3f9ac8ea
RA
146 fd = open(e->e_df, O_WRONLY|O_CREAT, FileMode);
147 if (fd < 0)
e0539260 148 syserr("!queueup: cannot create %s", e->e_df);
3f9ac8ea 149 dfp = fdopen(fd, "w");
2f6a8a78 150 (*e->e_putbody)(dfp, FileMailer, e, NULL);
bc854e30 151 (void) xfclose(dfp, "queueup dfp", e->e_id);
80482eb5 152 e->e_putbody = putbody;
dd1fe05b
EA
153 }
154
81b7d258
EA
155 /*
156 ** Output future work requests.
4e969be0
EA
157 ** Priority and creation time should be first, since
158 ** they are required by orderq.
81b7d258
EA
159 */
160
7338e3d4
EA
161 /* output message priority */
162 fprintf(tfp, "P%ld\n", e->e_msgpriority);
163
64912e7e
EA
164 /* output creation time */
165 fprintf(tfp, "T%ld\n", e->e_ctime);
166
96bfbc2c
EA
167 /* output type and name of data file */
168 if (e->e_bodytype != NULL)
169 fprintf(tfp, "B%s\n", e->e_bodytype);
2cce0c26 170 fprintf(tfp, "D%s\n", e->e_df);
81b7d258 171
baa0c390
EA
172 /* message from envelope, if it exists */
173 if (e->e_message != NULL)
174 fprintf(tfp, "M%s\n", e->e_message);
175
c2bdb1dd
EA
176 /* send various flag bits through */
177 p = buf;
178 if (bitset(EF_WARNING, e->e_flags))
179 *p++ = 'w';
180 if (bitset(EF_RESPONSE, e->e_flags))
181 *p++ = 'r';
182 *p++ = '\0';
183 if (buf[0] != '\0')
184 fprintf(tfp, "F%s\n", buf);
185
a9bac7a9 186 /* $r and $s and $_ macro values */
22293c34
EA
187 if ((p = macvalue('r', e)) != NULL)
188 fprintf(tfp, "$r%s\n", p);
189 if ((p = macvalue('s', e)) != NULL)
190 fprintf(tfp, "$s%s\n", p);
a9bac7a9
EA
191 if ((p = macvalue('_', e)) != NULL)
192 fprintf(tfp, "$_%s\n", p);
22293c34 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 */
31739b4e 198 printctladdr(NULL, NULL);
ca4d0c0b
EA
199 for (q = e->e_errorqueue; q != NULL; q = q->q_next)
200 {
bc854e30 201 if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
ca4d0c0b 202 {
9cdb0b30 203 printctladdr(q, tfp);
ca4d0c0b
EA
204 fprintf(tfp, "E%s\n", q->q_paddr);
205 }
206 }
207
208 /* output list of recipient addresses */
dd1fe05b 209 for (q = e->e_sendqueue; q != NULL; q = q->q_next)
81b7d258 210 {
374579b6 211 if (bitset(QQUEUEUP, q->q_flags) ||
bc854e30 212 (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)))
4d237f16 213 {
9cdb0b30 214 printctladdr(q, tfp);
2cce0c26 215 fprintf(tfp, "R%s\n", q->q_paddr);
7338e3d4
EA
216 if (announce)
217 {
218 e->e_to = q->q_paddr;
b6edea3d 219 message("queued");
68f7099c 220 if (LogLevel > 8)
c0ae0b24 221 logdelivery(NULL, NULL, "queued", e);
7338e3d4
EA
222 e->e_to = NULL;
223 }
b9accadd
EA
224 if (tTd(40, 1))
225 {
226 printf("queueing ");
227 printaddr(q, FALSE);
228 }
4d237f16 229 }
81b7d258
EA
230 }
231
7338e3d4
EA
232 /*
233 ** Output headers for this message.
234 ** Expand macros completely here. Queue run will deal with
235 ** everything as absolute headers.
236 ** All headers that must be relative to the recipient
237 ** can be cracked later.
4db45bf1
EA
238 ** We set up a "null mailer" -- i.e., a mailer that will have
239 ** no effect on the addresses as they are output.
7338e3d4
EA
240 */
241
1dbda134 242 bzero((char *) &nullmailer, sizeof nullmailer);
68f7099c
EA
243 nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
244 nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
281ef7f0 245 nullmailer.m_eol = "\n";
4db45bf1 246
2bee003d 247 define('g', "\201f", e);
dd1fe05b 248 for (h = e->e_header; h != NULL; h = h->h_link)
81b7d258 249 {
1dbda134
EA
250 extern bool bitzerop();
251
83e9910e 252 /* don't output null headers */
81b7d258
EA
253 if (h->h_value == NULL || h->h_value[0] == '\0')
254 continue;
83e9910e
EA
255
256 /* don't output resent headers on non-resent messages */
257 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
258 continue;
259
260 /* output this header */
2cce0c26 261 fprintf(tfp, "H");
83e9910e
EA
262
263 /* if conditional, output the set of conditions */
1dbda134
EA
264 if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
265 {
266 int j;
267
0e306e7f 268 (void) putc('?', tfp);
1dbda134
EA
269 for (j = '\0'; j <= '\177'; j++)
270 if (bitnset(j, h->h_mflags))
0e306e7f
EA
271 (void) putc(j, tfp);
272 (void) putc('?', tfp);
1dbda134 273 }
83e9910e
EA
274
275 /* output the header: expand macros, convert addresses */
9416f3a0
EA
276 if (bitset(H_DEFAULT, h->h_flags))
277 {
278 (void) expand(h->h_value, buf, &buf[sizeof buf], e);
3ba0846a 279 fprintf(tfp, "%s: %s\n", h->h_field, buf);
9416f3a0 280 }
4d237f16 281 else if (bitset(H_FROM|H_RCPT, h->h_flags))
611b763d 282 {
c2bdb1dd 283 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
8e5c6745
EA
284 FILE *savetrace = TrafficLogFile;
285
286 TrafficLogFile = NULL;
c2bdb1dd
EA
287
288 if (bitset(H_FROM, h->h_flags))
289 oldstyle = FALSE;
290
291 commaize(h, h->h_value, tfp, oldstyle,
a4076aed 292 &nullmailer, e);
8e5c6745
EA
293
294 TrafficLogFile = savetrace;
611b763d 295 }
4d237f16
EA
296 else
297 fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
81b7d258
EA
298 }
299
300 /*
301 ** Clean up.
302 */
303
e6d43796 304 fflush(tfp);
b6212c1e 305 fsync(fileno(tfp));
e6d43796
EA
306 if (ferror(tfp))
307 {
308 if (newid)
309 syserr("!552 Error writing control file %s", tf);
310 else
311 syserr("!452 Error writing control file %s", tf);
312 }
313
3620ad97
EA
314 if (!newid)
315 {
e3778690 316 /* rename (locked) tf to be (locked) qf */
3620ad97
EA
317 qf = queuename(e, 'q');
318 if (rename(tf, qf) < 0)
319 syserr("cannot rename(%s, %s), df=%s", tf, qf, e->e_df);
e3778690
EA
320
321 /* close and unlock old (locked) qf */
3620ad97 322 if (e->e_lockfp != NULL)
bc854e30 323 (void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id);
3620ad97
EA
324 e->e_lockfp = tfp;
325 }
326 else
327 qf = tf;
6680179d 328 errno = 0;
1a13ccd8 329
9678c96d
EA
330# ifdef LOG
331 /* save log info */
68f7099c 332 if (LogLevel > 79)
a8f5bbff 333 syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df);
f3d8f6d6 334# endif /* LOG */
51458e80
EA
335
336 if (tTd(40, 1))
337 printf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
3620ad97 338 return;
81b7d258 339}
d2213d6c
EA
340
341printctladdr(a, tfp)
9cdb0b30 342 register ADDRESS *a;
d2213d6c
EA
343 FILE *tfp;
344{
9cdb0b30
EA
345 char *uname;
346 register struct passwd *pw;
347 register ADDRESS *q;
348 uid_t uid;
349 static ADDRESS *lastctladdr;
350 static uid_t lastuid;
d2213d6c 351
9cdb0b30 352 /* initialization */
c6c403f7 353 if (a == NULL || a->q_alias == NULL || tfp == NULL)
d2213d6c 354 {
31739b4e 355 if (lastctladdr != NULL && tfp != NULL)
9cdb0b30
EA
356 fprintf(tfp, "C\n");
357 lastctladdr = NULL;
358 lastuid = 0;
d2213d6c
EA
359 return;
360 }
9cdb0b30
EA
361
362 /* find the active uid */
363 q = getctladdr(a);
364 if (q == NULL)
365 uid = 0;
366 else
367 uid = q->q_uid;
c6c403f7 368 a = a->q_alias;
9cdb0b30
EA
369
370 /* check to see if this is the same as last time */
371 if (lastctladdr != NULL && uid == lastuid &&
372 strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
373 return;
374 lastuid = uid;
375 lastctladdr = a;
376
377 if (uid == 0 || (pw = getpwuid(uid)) == NULL)
f7894324 378 uname = "";
d2213d6c 379 else
9cdb0b30
EA
380 uname = pw->pw_name;
381
382 fprintf(tfp, "C%s:%s\n", uname, a->q_paddr);
d2213d6c
EA
383}
384
81b7d258
EA
385\f/*
386** RUNQUEUE -- run the jobs in the queue.
387**
388** Gets the stuff out of the queue in some presumably logical
389** order and processes them.
390**
391** Parameters:
2e3062fe
EA
392** forkflag -- TRUE if the queue scanning should be done in
393** a child process. We double-fork so it is not our
394** child and we don't have to clean up after it.
81b7d258
EA
395**
396** Returns:
397** none.
398**
399** Side Effects:
400** runs things in the mail queue.
401*/
402
ca4d0c0b
EA
403ENVELOPE QueueEnvelope; /* the queue run envelope */
404
405runqueue(forkflag)
2cf55cb7 406 bool forkflag;
81b7d258 407{
ca4d0c0b
EA
408 register ENVELOPE *e;
409 extern ENVELOPE BlankEnvelope;
4bc44f60
EA
410
411 /*
412 ** If no work will ever be selected, don't even bother reading
413 ** the queue.
414 */
415
3620ad97 416 CurrentLA = getla(); /* get load average */
3f9ac8ea 417
986065ef 418 if (shouldqueue(0L, curtime()))
4bc44f60
EA
419 {
420 if (Verbose)
421 printf("Skipping queue run -- load average too high\n");
fe80f8e1
EA
422 if (forkflag && QueueIntvl != 0)
423 (void) setevent(QueueIntvl, runqueue, TRUE);
ca4d0c0b 424 return;
4bc44f60
EA
425 }
426
b6dffdf5
EA
427 /*
428 ** See if we want to go off and do other useful work.
429 */
2cf55cb7
EA
430
431 if (forkflag)
432 {
6d06102a
EA
433 int pid;
434
435 pid = dofork();
436 if (pid != 0)
2cf55cb7 437 {
0df908a9 438 extern void reapchild();
c8ad461a 439
6d06102a 440 /* parent -- pick up intermediate zombie */
c8ad461a 441#ifndef SIGCHLD
7338e3d4 442 (void) waitfor(pid);
f3d8f6d6 443#else /* SIGCHLD */
39270cfd 444 (void) setsignal(SIGCHLD, reapchild);
f3d8f6d6 445#endif /* SIGCHLD */
c4442979 446 if (QueueIntvl != 0)
611b763d 447 (void) setevent(QueueIntvl, runqueue, TRUE);
2cf55cb7
EA
448 return;
449 }
6d06102a 450 /* child -- double fork */
c8ad461a 451#ifndef SIGCHLD
6d06102a
EA
452 if (fork() != 0)
453 exit(EX_OK);
f3d8f6d6 454#else /* SIGCHLD */
39270cfd 455 (void) setsignal(SIGCHLD, SIG_DFL);
f3d8f6d6 456#endif /* SIGCHLD */
b6dffdf5 457 }
2e3062fe 458
3f9ac8ea 459 setproctitle("running queue: %s", QueueDir);
2e3062fe 460
36a4e219 461# ifdef LOG
68f7099c 462 if (LogLevel > 69)
ca4d0c0b
EA
463 syslog(LOG_DEBUG, "runqueue %s, pid=%d, forkflag=%d",
464 QueueDir, getpid(), forkflag);
f3d8f6d6 465# endif /* LOG */
81b7d258 466
eb8af3ce
EA
467 /*
468 ** Release any resources used by the daemon code.
469 */
470
471# ifdef DAEMON
472 clrdaemon();
f3d8f6d6 473# endif /* DAEMON */
eb8af3ce 474
ca4d0c0b
EA
475 /*
476 ** Create ourselves an envelope
477 */
478
479 CurEnv = &QueueEnvelope;
fda58daa 480 e = newenvelope(&QueueEnvelope, CurEnv);
ca4d0c0b
EA
481 e->e_flags = BlankEnvelope.e_flags;
482
a78155b0
EA
483 /*
484 ** Make sure the alias database is open.
485 */
486
36b09297 487 initmaps(FALSE, e);
a78155b0 488
b6dffdf5
EA
489 /*
490 ** Start making passes through the queue.
491 ** First, read and sort the entire queue.
492 ** Then, process the work in that order.
493 ** But if you take too long, start over.
b6dffdf5 494 */
81b7d258 495
6d06102a 496 /* order the existing work requests */
8ff78b51 497 (void) orderq(FALSE);
291fa573 498
6d06102a
EA
499 /* process them once at a time */
500 while (WorkQ != NULL)
2cf55cb7 501 {
6d06102a 502 WORK *w = WorkQ;
2cf55cb7 503
6d06102a 504 WorkQ = WorkQ->w_next;
a7dc53bd
EA
505
506 /*
507 ** Ignore jobs that are too expensive for the moment.
508 */
509
510 if (shouldqueue(w->w_pri, w->w_ctime))
511 {
512 if (Verbose)
513 printf("\nSkipping %s\n", w->w_name + 2);
a7dc53bd 514 }
1c791deb
EA
515 else
516 {
d0268270
EA
517 pid_t pid;
518 extern pid_t dowork();
519
520 pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
521 errno = 0;
522 (void) waitfor(pid);
1c791deb 523 }
6d06102a
EA
524 free(w->w_name);
525 free((char *) w);
2cf55cb7 526 }
37ea3cbf
EA
527
528 /* exit without the usual cleanup */
4e20c4d2
EA
529 e->e_id = NULL;
530 finis();
aba51985
EA
531}
532\f/*
81b7d258
EA
533** ORDERQ -- order the work queue.
534**
535** Parameters:
2e3062fe
EA
536** doall -- if set, include everything in the queue (even
537** the jobs that cannot be run because the load
538** average is too high). Otherwise, exclude those
539** jobs.
81b7d258
EA
540**
541** Returns:
e65b95c4
EA
542** The number of request in the queue (not necessarily
543** the number of requests in WorkQ however).
81b7d258
EA
544**
545** Side Effects:
546** Sets WorkQ to the queue of available work, in order.
547*/
548
4e969be0
EA
549# define NEED_P 001
550# define NEED_T 002
d6c28d1a
EA
551# define NEED_R 004
552# define NEED_S 010
81b7d258 553
38d3b461
EA
554# ifndef DIR
555# define DIR FILE
556# define direct dir
557# define opendir(d) fopen(d, "r")
07a8f29b 558# define readdir(f) ((fread(&dbuf, sizeof dbuf, 1, f) > 0) ? &dbuf : 0)
38d3b461
EA
559static struct dir dbuf;
560# define closedir(f) fclose(f)
561# endif DIR
562
2e3062fe
EA
563orderq(doall)
564 bool doall;
81b7d258 565{
9114f86c 566 register struct dirent *d;
81b7d258 567 register WORK *w;
ccd1d833 568 DIR *f;
81b7d258 569 register int i;
4e969be0 570 WORK wlist[QUEUESIZE+1];
0490b7d7 571 int wn = -1;
81b7d258 572 extern workcmpf();
81b7d258 573
d6c28d1a
EA
574 if (tTd(41, 1))
575 {
576 printf("orderq:\n");
577 if (QueueLimitId != NULL)
578 printf("\tQueueLimitId = %s\n", QueueLimitId);
579 if (QueueLimitSender != NULL)
580 printf("\tQueueLimitSender = %s\n", QueueLimitSender);
581 if (QueueLimitRecipient != NULL)
582 printf("\tQueueLimitRecipient = %s\n", QueueLimitRecipient);
583 }
584
81b7d258
EA
585 /* clear out old WorkQ */
586 for (w = WorkQ; w != NULL; )
587 {
588 register WORK *nw = w->w_next;
589
590 WorkQ = nw;
591 free(w->w_name);
592 free((char *) w);
593 w = nw;
594 }
595
596 /* open the queue directory */
6bbaf971 597 f = opendir(".");
81b7d258
EA
598 if (f == NULL)
599 {
6bbaf971 600 syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
0490b7d7 601 return (0);
81b7d258
EA
602 }
603
604 /*
605 ** Read the work directory.
606 */
607
0490b7d7 608 while ((d = readdir(f)) != NULL)
81b7d258 609 {
81b7d258 610 FILE *cf;
7338e3d4 611 char lbuf[MAXNAME];
d6c28d1a 612 extern bool strcontainedin();
81b7d258
EA
613
614 /* is this an interesting entry? */
07a8f29b
EA
615 if (d->d_ino == 0)
616 continue;
617# ifdef DEBUG
618 if (tTd(40, 10))
619 printf("orderq: %12s\n", d->d_name);
620# endif DEBUG
2cce0c26 621 if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
81b7d258
EA
622 continue;
623
d6c28d1a
EA
624 if (QueueLimitId != NULL &&
625 !strcontainedin(QueueLimitId, d->d_name))
626 continue;
627
45ce4b34
EA
628 /*
629 ** Check queue name for plausibility. This handles
630 ** both old and new type ids.
631 */
632
633 i = strlen(d->d_name);
634 if (i != 9 && i != 10)
68f7099c
EA
635 {
636 if (Verbose)
637 printf("orderq: bogus qf name %s\n", d->d_name);
638#ifdef LOG
639 if (LogLevel > 3)
73f6752a 640 syslog(LOG_CRIT, "orderq: bogus qf name %s",
68f7099c
EA
641 d->d_name);
642#endif
643 if (strlen(d->d_name) >= MAXNAME)
644 d->d_name[MAXNAME - 1] = '\0';
645 strcpy(lbuf, d->d_name);
646 lbuf[0] = 'Q';
647 (void) rename(d->d_name, lbuf);
648 continue;
649 }
650
0490b7d7 651 /* yes -- open control file (if not too many files) */
4e969be0 652 if (++wn >= QUEUESIZE)
0490b7d7 653 continue;
d6c28d1a 654
6bbaf971 655 cf = fopen(d->d_name, "r");
81b7d258
EA
656 if (cf == NULL)
657 {
91f69adf
EA
658 /* this may be some random person sending hir msgs */
659 /* syserr("orderq: cannot open %s", cbuf); */
bd0712bd
EA
660 if (tTd(41, 2))
661 printf("orderq: cannot open %s (%d)\n",
662 d->d_name, errno);
91f69adf 663 errno = 0;
bd0712bd 664 wn--;
81b7d258
EA
665 continue;
666 }
4e969be0
EA
667 w = &wlist[wn];
668 w->w_name = newstr(d->d_name);
81b7d258 669
4ff794a3 670 /* make sure jobs in creation don't clog queue */
4e969be0
EA
671 w->w_pri = 0x7fffffff;
672 w->w_ctime = 0;
4ff794a3 673
81b7d258 674 /* extract useful information */
4e969be0 675 i = NEED_P | NEED_T;
d6c28d1a
EA
676 if (QueueLimitSender != NULL)
677 i |= NEED_S;
678 if (QueueLimitRecipient != NULL)
679 i |= NEED_R;
4e969be0 680 while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
81b7d258 681 {
8ff78b51 682 extern long atol();
d6c28d1a 683 extern bool strcontainedin();
8ff78b51 684
2e3062fe 685 switch (lbuf[0])
81b7d258 686 {
2e3062fe 687 case 'P':
4e969be0
EA
688 w->w_pri = atol(&lbuf[1]);
689 i &= ~NEED_P;
2e3062fe 690 break;
f746582a
EA
691
692 case 'T':
4e969be0
EA
693 w->w_ctime = atol(&lbuf[1]);
694 i &= ~NEED_T;
f746582a 695 break;
d6c28d1a
EA
696
697 case 'R':
698 if (QueueLimitRecipient != NULL &&
699 strcontainedin(QueueLimitRecipient, &lbuf[1]))
700 i &= ~NEED_R;
701 break;
702
703 case 'S':
704 if (QueueLimitSender != NULL &&
705 strcontainedin(QueueLimitSender, &lbuf[1]))
706 i &= ~NEED_S;
707 break;
81b7d258
EA
708 }
709 }
81b7d258 710 (void) fclose(cf);
4bc44f60 711
d6c28d1a
EA
712 if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
713 bitset(NEED_R|NEED_S, i))
4bc44f60
EA
714 {
715 /* don't even bother sorting this job in */
716 wn--;
717 }
81b7d258 718 }
ccd1d833 719 (void) closedir(f);
bd0712bd 720 wn++;
81b7d258
EA
721
722 /*
723 ** Sort the work directory.
724 */
725
4e969be0 726 qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf);
81b7d258
EA
727
728 /*
729 ** Convert the work list into canonical form.
7338e3d4 730 ** Should be turning it into a list of envelopes here perhaps.
81b7d258
EA
731 */
732
a0225d08 733 WorkQ = NULL;
4e969be0 734 for (i = min(wn, QUEUESIZE); --i >= 0; )
81b7d258
EA
735 {
736 w = (WORK *) xalloc(sizeof *w);
737 w->w_name = wlist[i].w_name;
81b7d258 738 w->w_pri = wlist[i].w_pri;
f746582a 739 w->w_ctime = wlist[i].w_ctime;
a0225d08
EA
740 w->w_next = WorkQ;
741 WorkQ = w;
81b7d258
EA
742 }
743
9678c96d 744 if (tTd(40, 1))
81b7d258
EA
745 {
746 for (w = WorkQ; w != NULL; w = w->w_next)
9ccf54c4 747 printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
81b7d258 748 }
0490b7d7 749
bd0712bd 750 return (wn);
81b7d258
EA
751}
752\f/*
9678c96d 753** WORKCMPF -- compare function for ordering work.
81b7d258
EA
754**
755** Parameters:
756** a -- the first argument.
757** b -- the second argument.
758**
759** Returns:
a0225d08
EA
760** -1 if a < b
761** 0 if a == b
762** +1 if a > b
81b7d258
EA
763**
764** Side Effects:
765** none.
766*/
767
81b7d258 768workcmpf(a, b)
9ccf54c4
EA
769 register WORK *a;
770 register WORK *b;
81b7d258 771{
abccefc9
EA
772 long pa = a->w_pri;
773 long pb = b->w_pri;
2e3062fe
EA
774
775 if (pa == pb)
81b7d258 776 return (0);
2e3062fe 777 else if (pa > pb)
e65b95c4 778 return (1);
a0225d08
EA
779 else
780 return (-1);
81b7d258
EA
781}
782\f/*
783** DOWORK -- do a work request.
784**
785** Parameters:
a7dc53bd
EA
786** id -- the ID of the job to run.
787** forkflag -- if set, run this in background.
f5303697
EA
788** requeueflag -- if set, reinstantiate the queue quickly.
789** This is used when expanding aliases in the queue.
8d00c219
EA
790** If forkflag is also set, it doesn't wait for the
791** child.
a7dc53bd 792** e - the envelope in which to run it.
81b7d258
EA
793**
794** Returns:
d0268270 795** process id of process that is running the queue job.
81b7d258
EA
796**
797** Side Effects:
798** The work request is satisfied if possible.
799*/
800
d0268270 801pid_t
f5303697 802dowork(id, forkflag, requeueflag, e)
a7dc53bd
EA
803 char *id;
804 bool forkflag;
f5303697 805 bool requeueflag;
a4076aed 806 register ENVELOPE *e;
81b7d258 807{
d0268270 808 register pid_t pid;
3620ad97 809 extern bool readqf();
81b7d258 810
9678c96d 811 if (tTd(40, 1))
a7dc53bd 812 printf("dowork(%s)\n", id);
81b7d258 813
2e3062fe
EA
814 /*
815 ** Fork for work.
816 */
817
a7dc53bd 818 if (forkflag)
2e3062fe 819 {
d0268270
EA
820 pid = fork();
821 if (pid < 0)
2e3062fe
EA
822 {
823 syserr("dowork: cannot fork");
d0268270 824 return 0;
2e3062fe
EA
825 }
826 }
827 else
828 {
d0268270 829 pid = 0;
2e3062fe
EA
830 }
831
d0268270 832 if (pid == 0)
81b7d258
EA
833 {
834 /*
835 ** CHILD
6bbaf971
EA
836 ** Lock the control file to avoid duplicate deliveries.
837 ** Then run the file as though we had just read it.
68f0b54c
EA
838 ** We save an idea of the temporary name so we
839 ** can recover on interrupt.
81b7d258
EA
840 */
841
9416f3a0 842 /* set basic modes, etc. */
37eaaadb 843 (void) alarm(0);
a4076aed 844 clearenvelope(e, FALSE);
c2bdb1dd 845 e->e_flags |= EF_QUEUERUN;
8c8e8e94 846 e->e_errormode = EM_MAIL;
a7dc53bd 847 e->e_id = id;
47e2f242 848 if (forkflag)
d0268270 849 disconnect(1, e);
36a4e219 850# ifdef LOG
68f7099c 851 if (LogLevel > 76)
a4076aed 852 syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id,
291fa573 853 getpid());
f3d8f6d6 854# endif /* LOG */
9416f3a0
EA
855
856 /* don't use the headers from sendmail.cf... */
a4076aed 857 e->e_header = NULL;
9416f3a0 858
3620ad97 859 /* read the queue control file -- return if locked */
c6c403f7 860 if (!readqf(e, !requeueflag))
dd1fe05b 861 {
a7dc53bd
EA
862 if (tTd(40, 4))
863 printf("readqf(%s) failed\n", e->e_id);
864 if (forkflag)
2e3062fe
EA
865 exit(EX_OK);
866 else
867 return;
dd1fe05b 868 }
dd1fe05b 869
a4076aed 870 e->e_flags |= EF_INQUEUE;
959cf51d 871 eatheader(e, requeueflag);
dd1fe05b 872
f5303697
EA
873 if (requeueflag)
874 queueup(e, TRUE, FALSE);
875
dd1fe05b 876 /* do the delivery */
e678ee95 877 sendall(e, SM_DELIVER);
dd1fe05b 878
dd1fe05b 879 /* finish up and exit */
a7dc53bd 880 if (forkflag)
2e3062fe
EA
881 finis();
882 else
a4076aed 883 dropenvelope(e);
81b7d258 884 }
d0268270
EA
885 e->e_id = NULL;
886 return pid;
81b7d258
EA
887}
888\f/*
889** READQF -- read queue file and set up environment.
890**
891** Parameters:
7338e3d4 892** e -- the envelope of the job to run.
c6c403f7
EA
893** announcefile -- if set, announce the name of the queue
894** file in error messages.
81b7d258
EA
895**
896** Returns:
3620ad97
EA
897** TRUE if it successfully read the queue file.
898** FALSE otherwise.
81b7d258
EA
899**
900** Side Effects:
3620ad97 901** The queue file is returned locked.
81b7d258
EA
902*/
903
3620ad97 904bool
c6c403f7 905readqf(e, announcefile)
7338e3d4 906 register ENVELOPE *e;
c6c403f7 907 bool announcefile;
81b7d258 908{
11e3f8b5 909 register FILE *qfp;
d2213d6c 910 ADDRESS *ctladdr;
dcbc04c7 911 struct stat st;
07b49560 912 char *bp;
e678ee95 913 char qf[20];
07b49560 914 char buf[MAXLINE];
8ff78b51 915 extern long atol();
d2213d6c 916 extern ADDRESS *setctluser();
abae7b2d 917 extern ADDRESS *sendto();
81b7d258 918
81b7d258
EA
919 /*
920 ** Read and process the file.
921 */
922
e678ee95 923 strcpy(qf, queuename(e, 'q'));
76b607b2 924 qfp = fopen(qf, "r+");
11e3f8b5
EA
925 if (qfp == NULL)
926 {
a7dc53bd
EA
927 if (tTd(40, 8))
928 printf("readqf(%s): fopen failure (%s)\n",
929 qf, errstring(errno));
3f9ac8ea
RA
930 if (errno != ENOENT)
931 syserr("readqf: no control file %s", qf);
3620ad97 932 return FALSE;
3f9ac8ea
RA
933 }
934
71936fbe 935 if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
e3778690
EA
936 {
937 /* being processed by another queuer */
938 if (tTd(40, 8))
939 printf("readqf(%s): locked\n", qf);
940 if (Verbose)
941 printf("%s: locked\n", e->e_id);
942# ifdef LOG
943 if (LogLevel > 19)
944 syslog(LOG_DEBUG, "%s: locked", e->e_id);
945# endif /* LOG */
946 (void) fclose(qfp);
947 return FALSE;
948 }
949
dcbc04c7
EA
950 /*
951 ** Check the queue file for plausibility to avoid attacks.
952 */
953
954 if (fstat(fileno(qfp), &st) < 0)
955 {
956 /* must have been being processed by someone else */
a7dc53bd
EA
957 if (tTd(40, 8))
958 printf("readqf(%s): fstat failure (%s)\n",
959 qf, errstring(errno));
dcbc04c7
EA
960 fclose(qfp);
961 return FALSE;
962 }
963
d4d2f9a9 964 if (st.st_uid != geteuid())
dcbc04c7
EA
965 {
966# ifdef LOG
967 if (LogLevel > 0)
968 {
969 syslog(LOG_ALERT, "%s: bogus queue file, uid=%d, mode=%o",
970 e->e_id, st.st_uid, st.st_mode);
971 }
f3d8f6d6 972# endif /* LOG */
a7dc53bd
EA
973 if (tTd(40, 8))
974 printf("readqf(%s): bogus file\n", qf);
8e5c6745 975 rename(qf, queuename(e, 'Q'));
e3778690 976 fclose(qfp);
dcbc04c7
EA
977 return FALSE;
978 }
979
e3778690 980 if (st.st_size == 0)
3f9ac8ea 981 {
e3778690
EA
982 /* must be a bogus file -- just remove it */
983 (void) unlink(qf);
984 fclose(qfp);
3620ad97 985 return FALSE;
11e3f8b5 986 }
3f9ac8ea 987
e3778690 988 if (st.st_nlink == 0)
c87034b7 989 {
e3778690
EA
990 /*
991 ** Race condition -- we got a file just as it was being
992 ** unlinked. Just assume it is zero length.
993 */
994
c87034b7
EA
995 fclose(qfp);
996 return FALSE;
997 }
998
e3778690 999 /* good file -- save this lock */
3620ad97
EA
1000 e->e_lockfp = qfp;
1001
3f9ac8ea 1002 /* do basic system initialization */
a4076aed 1003 initsys(e);
3f9ac8ea 1004
c6c403f7
EA
1005 if (announcefile)
1006 FileName = qf;
560a80d9 1007 LineNumber = 0;
c6c403f7
EA
1008 e->e_flags |= EF_GLOBALERRS;
1009 OpMode = MD_DELIVER;
3620ad97 1010 if (Verbose)
7338e3d4 1011 printf("\nRunning %s\n", e->e_id);
d2213d6c 1012 ctladdr = NULL;
07b49560 1013 while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
81b7d258 1014 {
c2bdb1dd 1015 register char *p;
65b5adb6
EA
1016 struct stat st;
1017
795590e2 1018 if (tTd(40, 4))
07b49560
EA
1019 printf("+++++ %s\n", bp);
1020 switch (bp[0])
81b7d258 1021 {
3fbc69d6 1022 case 'C': /* specify controlling user */
07b49560 1023 ctladdr = setctluser(&bp[1]);
3fbc69d6
KB
1024 break;
1025
81b7d258 1026 case 'R': /* specify recipient */
abae7b2d 1027 (void) sendto(&buf[1], 1, (ADDRESS *) NULL, 0);
81b7d258
EA
1028 break;
1029
4e969be0 1030 case 'E': /* specify error recipient */
1c7897ef 1031 (void) sendtolist(&bp[1], ctladdr, &e->e_errorqueue, e);
4e969be0
EA
1032 break;
1033
81b7d258 1034 case 'H': /* header */
07b49560 1035 (void) chompheader(&bp[1], FALSE, e);
81b7d258
EA
1036 break;
1037
baa0c390 1038 case 'M': /* message */
07b49560 1039 e->e_message = newstr(&bp[1]);
baa0c390
EA
1040 break;
1041
81b7d258 1042 case 'S': /* sender */
4a2da288 1043 setsender(newstr(&bp[1]), e, NULL, TRUE);
81b7d258
EA
1044 break;
1045
96bfbc2c
EA
1046 case 'B': /* body type */
1047 e->e_bodytype = newstr(&bp[1]);
1048 break;
1049
81b7d258 1050 case 'D': /* data file name */
07b49560 1051 e->e_df = newstr(&bp[1]);
912acb74
EA
1052 e->e_dfp = fopen(e->e_df, "r");
1053 if (e->e_dfp == NULL)
68f7099c 1054 {
7338e3d4 1055 syserr("readqf: cannot open %s", e->e_df);
68f7099c
EA
1056 e->e_msgsize = -1;
1057 }
1058 else if (fstat(fileno(e->e_dfp), &st) >= 0)
65b5adb6 1059 e->e_msgsize = st.st_size;
81b7d258
EA
1060 break;
1061
96476cab 1062 case 'T': /* init time */
07b49560 1063 e->e_ctime = atol(&bp[1]);
81b7d258
EA
1064 break;
1065
aba51985 1066 case 'P': /* message priority */
07b49560 1067 e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
dd1fe05b
EA
1068 break;
1069
c2bdb1dd
EA
1070 case 'F': /* flag bits */
1071 for (p = &bp[1]; *p != '\0'; p++)
1072 {
1073 switch (*p)
1074 {
1075 case 'w': /* warning sent */
1076 e->e_flags |= EF_WARNING;
1077 break;
1078
1079 case 'r': /* response */
1080 e->e_flags |= EF_RESPONSE;
1081 break;
1082 }
1083 }
1084 break;
1085
22293c34 1086 case '$': /* define macro */
07b49560 1087 define(bp[1], newstr(&bp[2]), e);
22293c34
EA
1088 break;
1089
2e3062fe
EA
1090 case '\0': /* blank line; ignore */
1091 break;
1092
81b7d258 1093 default:
ef3bc6b1 1094 syserr("readqf: bad line \"%s\"", e->e_id,
07b49560 1095 LineNumber, bp);
8e5c6745
EA
1096 fclose(qfp);
1097 rename(qf, queuename(e, 'Q'));
1098 return FALSE;
81b7d258 1099 }
07b49560
EA
1100
1101 if (bp != buf)
1102 free(bp);
81b7d258 1103 }
7338e3d4
EA
1104
1105 FileName = NULL;
2e3062fe
EA
1106
1107 /*
1108 ** If we haven't read any lines, this queue file is empty.
1109 ** Arrange to remove it without referencing any null pointers.
1110 */
1111
1112 if (LineNumber == 0)
1113 {
1114 errno = 0;
1115 e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
1116 }
3620ad97 1117 return TRUE;
81b7d258
EA
1118}
1119\f/*
64912e7e
EA
1120** PRINTQUEUE -- print out a representation of the mail queue
1121**
1122** Parameters:
1123** none.
1124**
1125** Returns:
1126** none.
1127**
1128** Side Effects:
1129** Prints a listing of the mail queue on the standard output.
1130*/
1131
1132printqueue()
1133{
1134 register WORK *w;
1135 FILE *f;
0490b7d7 1136 int nrequests;
64912e7e
EA
1137 char buf[MAXLINE];
1138
374579b6
EA
1139 /*
1140 ** Check for permission to print the queue
1141 */
1142
fd178efd 1143 if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
374579b6
EA
1144 {
1145 struct stat st;
3afbc0f1
EA
1146# ifdef NGROUPS
1147 int n;
e6cb9fc4 1148 GIDSET_T gidset[NGROUPS];
3afbc0f1 1149# endif
374579b6 1150
7c8b3fd4 1151 if (stat(QueueDir, &st) < 0)
374579b6
EA
1152 {
1153 syserr("Cannot stat %s", QueueDir);
1154 return;
1155 }
3afbc0f1
EA
1156# ifdef NGROUPS
1157 n = getgroups(NGROUPS, gidset);
1158 while (--n >= 0)
1159 {
1160 if (gidset[n] == st.st_gid)
1161 break;
1162 }
1163 if (n < 0)
1164# else
fd57f063 1165 if (RealGid != st.st_gid)
3afbc0f1 1166# endif
374579b6
EA
1167 {
1168 usrerr("510 You are not permitted to see the queue");
1169 setstat(EX_NOPERM);
1170 return;
1171 }
1172 }
1173
64912e7e
EA
1174 /*
1175 ** Read and order the queue.
1176 */
1177
2e3062fe 1178 nrequests = orderq(TRUE);
64912e7e
EA
1179
1180 /*
1181 ** Print the work list that we have read.
1182 */
1183
1184 /* first see if there is anything */
0490b7d7 1185 if (nrequests <= 0)
64912e7e 1186 {
0490b7d7 1187 printf("Mail queue is empty\n");
64912e7e
EA
1188 return;
1189 }
1190
3620ad97 1191 CurrentLA = getla(); /* get load average */
3f9ac8ea 1192
d7b5594c 1193 printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
4e969be0
EA
1194 if (nrequests > QUEUESIZE)
1195 printf(", only %d printed", QUEUESIZE);
f4b05990 1196 if (Verbose)
fbab5052 1197 printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
f4b05990 1198 else
fbab5052 1199 printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
64912e7e
EA
1200 for (w = WorkQ; w != NULL; w = w->w_next)
1201 {
1202 struct stat st;
0490b7d7
EA
1203 auto time_t submittime = 0;
1204 long dfsize = -1;
c2bdb1dd 1205 int flags = 0;
baa0c390 1206 char message[MAXLINE];
96bfbc2c 1207 char bodytype[MAXNAME];
64912e7e 1208
4ba6a6f4 1209 printf("%8s", w->w_name + 2);
560a80d9
EA
1210 f = fopen(w->w_name, "r");
1211 if (f == NULL)
1212 {
4ba6a6f4 1213 printf(" (job completed)\n");
560a80d9
EA
1214 errno = 0;
1215 continue;
1216 }
71936fbe 1217 if (!lockfile(fileno(f), w->w_name, NULL, LOCK_SH|LOCK_NB))
0490b7d7 1218 printf("*");
abccefc9 1219 else if (shouldqueue(w->w_pri, w->w_ctime))
2e3062fe 1220 printf("X");
0490b7d7
EA
1221 else
1222 printf(" ");
1223 errno = 0;
560a80d9 1224
96bfbc2c 1225 message[0] = bodytype[0] = '\0';
64912e7e
EA
1226 while (fgets(buf, sizeof buf, f) != NULL)
1227 {
22293c34 1228 register int i;
c2bdb1dd 1229 register char *p;
22293c34 1230
64912e7e
EA
1231 fixcrlf(buf, TRUE);
1232 switch (buf[0])
1233 {
baa0c390 1234 case 'M': /* error message */
22293c34 1235 if ((i = strlen(&buf[1])) >= sizeof message)
c2bdb1dd 1236 i = sizeof message - 1;
22293c34
EA
1237 bcopy(&buf[1], message, i);
1238 message[i] = '\0';
baa0c390
EA
1239 break;
1240
96bfbc2c
EA
1241 case 'B': /* body type */
1242 if ((i = strlen(&buf[1])) >= sizeof bodytype)
1243 i = sizeof bodytype - 1;
1244 bcopy(&buf[1], bodytype, i);
1245 bodytype[i] = '\0';
1246 break;
1247
64912e7e 1248 case 'S': /* sender name */
f4b05990 1249 if (Verbose)
c2bdb1dd
EA
1250 printf("%8ld %10ld%c%.12s %.38s",
1251 dfsize,
1252 w->w_pri,
1253 bitset(EF_WARNING, flags) ? '+' : ' ',
1254 ctime(&submittime) + 4,
f4b05990
EA
1255 &buf[1]);
1256 else
1257 printf("%8ld %.16s %.45s", dfsize,
1258 ctime(&submittime), &buf[1]);
96bfbc2c
EA
1259 if (message[0] != '\0' || bodytype[0] != '\0')
1260 {
1261 printf("\n %10.10s", bodytype);
1262 if (message[0] != '\0')
1263 printf(" (%.60s)", message);
1264 }
64912e7e 1265 break;
3620ad97 1266
3fbc69d6 1267 case 'C': /* controlling user */
d2213d6c 1268 if (Verbose)
fbab5052
EA
1269 printf("\n\t\t\t\t (---%.34s---)",
1270 &buf[1]);
3fbc69d6 1271 break;
64912e7e
EA
1272
1273 case 'R': /* recipient name */
f4b05990 1274 if (Verbose)
fbab5052 1275 printf("\n\t\t\t\t\t %.38s", &buf[1]);
f4b05990 1276 else
fbab5052 1277 printf("\n\t\t\t\t %.45s", &buf[1]);
64912e7e
EA
1278 break;
1279
1280 case 'T': /* creation time */
2e3062fe 1281 submittime = atol(&buf[1]);
0490b7d7
EA
1282 break;
1283
1284 case 'D': /* data file name */
1285 if (stat(&buf[1], &st) >= 0)
1286 dfsize = st.st_size;
64912e7e 1287 break;
c2bdb1dd
EA
1288
1289 case 'F': /* flag bits */
1290 for (p = &buf[1]; *p != '\0'; p++)
1291 {
1292 switch (*p)
1293 {
1294 case 'w':
1295 flags |= EF_WARNING;
1296 break;
1297 }
1298 }
64912e7e
EA
1299 }
1300 }
0490b7d7
EA
1301 if (submittime == (time_t) 0)
1302 printf(" (no control file)");
64912e7e 1303 printf("\n");
0e306e7f 1304 (void) fclose(f);
64912e7e
EA
1305 }
1306}
884a20cb 1307
f3d8f6d6 1308# endif /* QUEUE */
560a80d9
EA
1309\f/*
1310** QUEUENAME -- build a file name in the queue directory for this envelope.
1311**
1312** Assigns an id code if one does not already exist.
1313** This code is very careful to avoid trashing existing files
1314** under any circumstances.
560a80d9
EA
1315**
1316** Parameters:
1317** e -- envelope to build it in/from.
1318** type -- the file type, used as the first character
1319** of the file name.
1320**
1321** Returns:
1322** a pointer to the new file name (in a static buffer).
1323**
1324** Side Effects:
3620ad97
EA
1325** If no id code is already assigned, queuename will
1326** assign an id code, create a qf file, and leave a
1327** locked, open-for-write file pointer in the envelope.
560a80d9
EA
1328*/
1329
1330char *
1331queuename(e, type)
1332 register ENVELOPE *e;
ef3bc6b1 1333 int type;
560a80d9 1334{
560a80d9 1335 static int pid = -1;
e3bb0d32
EA
1336 static char c0;
1337 static char c1;
1338 static char c2;
fbab5052
EA
1339 time_t now;
1340 struct tm *tm;
f8a31c8e 1341 static char buf[MAXNAME];
560a80d9
EA
1342
1343 if (e->e_id == NULL)
1344 {
1345 char qf[20];
560a80d9
EA
1346
1347 /* find a unique id */
1348 if (pid != getpid())
1349 {
1350 /* new process -- start back at "AA" */
1351 pid = getpid();
fbab5052
EA
1352 now = curtime();
1353 tm = localtime(&now);
1354 c0 = 'A' + tm->tm_hour;
560a80d9
EA
1355 c1 = 'A';
1356 c2 = 'A' - 1;
1357 }
fbab5052 1358 (void) sprintf(qf, "qf%cAA%05d", c0, pid);
560a80d9
EA
1359
1360 while (c1 < '~' || c2 < 'Z')
1361 {
1362 int i;
1363
1364 if (c2 >= 'Z')
1365 {
1366 c1++;
1367 c2 = 'A' - 1;
1368 }
fbab5052
EA
1369 qf[3] = c1;
1370 qf[4] = ++c2;
560a80d9 1371 if (tTd(7, 20))
3f9ac8ea 1372 printf("queuename: trying \"%s\"\n", qf);
560a80d9 1373
3f9ac8ea 1374 i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
3620ad97
EA
1375 if (i < 0)
1376 {
1377 if (errno == EEXIST)
1378 continue;
1379 syserr("queuename: Cannot create \"%s\" in \"%s\"",
1380 qf, QueueDir);
1381 exit(EX_UNAVAILABLE);
1382 }
71936fbe 1383 if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB))
3620ad97
EA
1384 {
1385 e->e_lockfp = fdopen(i, "w");
bb09c502 1386 break;
3f9ac8ea 1387 }
3620ad97
EA
1388
1389 /* a reader got the file; abandon it and try again */
1390 (void) close(i);
560a80d9
EA
1391 }
1392 if (c1 >= '~' && c2 >= 'Z')
1393 {
1394 syserr("queuename: Cannot create \"%s\" in \"%s\"",
1395 qf, QueueDir);
1396 exit(EX_OSERR);
1397 }
1398 e->e_id = newstr(&qf[2]);
1399 define('i', e->e_id, e);
560a80d9
EA
1400 if (tTd(7, 1))
1401 printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
1402# ifdef LOG
68f7099c 1403 if (LogLevel > 93)
560a80d9 1404 syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
f3d8f6d6 1405# endif /* LOG */
560a80d9
EA
1406 }
1407
1408 if (type == '\0')
1409 return (NULL);
1410 (void) sprintf(buf, "%cf%s", type, e->e_id);
560a80d9
EA
1411 if (tTd(7, 2))
1412 printf("queuename: %s\n", buf);
560a80d9
EA
1413 return (buf);
1414}
1415\f/*
1416** UNLOCKQUEUE -- unlock the queue entry for a specified envelope
1417**
1418** Parameters:
1419** e -- the envelope to unlock.
1420**
1421** Returns:
1422** none
1423**
1424** Side Effects:
1425** unlocks the queue for `e'.
1426*/
1427
1428unlockqueue(e)
1429 ENVELOPE *e;
1430{
bc854e30
EA
1431 if (tTd(51, 4))
1432 printf("unlockqueue(%s)\n", e->e_id);
1433
3620ad97
EA
1434 /* if there is a lock file in the envelope, close it */
1435 if (e->e_lockfp != NULL)
bc854e30 1436 xfclose(e->e_lockfp, "unlockqueue", e->e_id);
3620ad97
EA
1437 e->e_lockfp = NULL;
1438
32061c38
EA
1439 /* don't create a queue id if we don't already have one */
1440 if (e->e_id == NULL)
1441 return;
1442
560a80d9 1443 /* remove the transcript */
560a80d9 1444# ifdef LOG
68f7099c 1445 if (LogLevel > 87)
560a80d9 1446 syslog(LOG_DEBUG, "%s: unlock", e->e_id);
f3d8f6d6 1447# endif /* LOG */
bc854e30 1448 if (!tTd(51, 104))
560a80d9
EA
1449 xunlink(queuename(e, 'x'));
1450
560a80d9 1451}
3fbc69d6 1452\f/*
d2213d6c 1453** SETCTLUSER -- create a controlling address
3fbc69d6 1454**
d2213d6c
EA
1455** Create a fake "address" given only a local login name; this is
1456** used as a "controlling user" for future recipient addresses.
3fbc69d6
KB
1457**
1458** Parameters:
d2213d6c 1459** user -- the user name of the controlling user.
3fbc69d6
KB
1460**
1461** Returns:
d2213d6c 1462** An address descriptor for the controlling user.
3fbc69d6
KB
1463**
1464** Side Effects:
1465** none.
1466*/
1467
d2213d6c
EA
1468ADDRESS *
1469setctluser(user)
1470 char *user;
3fbc69d6 1471{
d2213d6c 1472 register ADDRESS *a;
3fbc69d6 1473 struct passwd *pw;
9cdb0b30 1474 char *p;
3fbc69d6
KB
1475
1476 /*
d2213d6c 1477 ** See if this clears our concept of controlling user.
3fbc69d6
KB
1478 */
1479
c6c403f7
EA
1480 if (user == NULL || *user == '\0')
1481 return NULL;
3fbc69d6
KB
1482
1483 /*
d2213d6c 1484 ** Set up addr fields for controlling user.
3fbc69d6
KB
1485 */
1486
d2213d6c
EA
1487 a = (ADDRESS *) xalloc(sizeof *a);
1488 bzero((char *) a, sizeof *a);
9cdb0b30
EA
1489
1490 p = strchr(user, ':');
1491 if (p != NULL)
1492 *p++ = '\0';
f7894324 1493 if (*user != '\0' && (pw = getpwnam(user)) != NULL)
3fbc69d6 1494 {
3fbc69d6
KB
1495 a->q_home = newstr(pw->pw_dir);
1496 a->q_uid = pw->pw_uid;
1497 a->q_gid = pw->pw_gid;
6e99f903 1498 a->q_user = newstr(user);
f7894324 1499 a->q_flags |= QGOODUID;
3fbc69d6
KB
1500 }
1501 else
1502 {
6e99f903 1503 a->q_user = newstr(DefUser);
3fbc69d6
KB
1504 }
1505
f7894324 1506 a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */
d0a69620 1507 a->q_mailer = LocalMailer;
9cdb0b30
EA
1508 if (p == NULL)
1509 a->q_paddr = a->q_user;
1510 else
1511 a->q_paddr = newstr(p);
d2213d6c 1512 return a;
3fbc69d6 1513}