sample code to set MaxChildren (not now!)
[unix-history] / usr / src / usr.sbin / sendmail / src / queue.c
CommitLineData
b2a81223 1/*
792e6158 2 * Copyright (c) 1983, 1995 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
ab3de76b 13static char sccsid[] = "@(#)queue.c 8.86 (Berkeley) %G% (with queueing)";
bee79b64 14#else
ab3de76b 15static char sccsid[] = "@(#)queue.c 8.86 (Berkeley) %G% (without queueing)";
bee79b64
KB
16#endif
17#endif /* not lint */
18
81b7d258 19# include <errno.h>
6feb509e 20# include <dirent.h>
4287d84d 21
76b607b2
EA
22# ifdef QUEUE
23
81b7d258 24/*
7338e3d4
EA
25** Work queue.
26*/
27
28struct work
29{
30 char *w_name; /* name of control file */
a9ca3259
EA
31 char *w_host; /* name of recipient host */
32 bool w_lock; /* is message locked? */
7338e3d4 33 long w_pri; /* priority of message, see below */
f746582a 34 time_t w_ctime; /* creation time of message */
7338e3d4
EA
35 struct work *w_next; /* next in queue */
36};
37
38typedef struct work WORK;
39
40WORK *WorkQ; /* queue of things to be done */
68d9129a
EA
41
42#define QF_VERSION 1 /* version number of this queue format */
7338e3d4 43\f/*
81b7d258
EA
44** QUEUEUP -- queue a message up for future transmission.
45**
81b7d258 46** Parameters:
dd1fe05b 47** e -- the envelope to queue up.
d0bd03ce
EA
48** queueall -- if TRUE, queue all addresses, rather than
49** just those with the QQUEUEUP flag set.
7338e3d4 50** announce -- if TRUE, tell when you are queueing up.
81b7d258
EA
51**
52** Returns:
3620ad97 53** none.
81b7d258
EA
54**
55** Side Effects:
7338e3d4 56** The current request are saved in a control file.
3620ad97 57** The queue file is left locked.
81b7d258
EA
58*/
59
179d940c 60void
7338e3d4 61queueup(e, queueall, announce)
dd1fe05b 62 register ENVELOPE *e;
d0bd03ce 63 bool queueall;
7338e3d4 64 bool announce;
81b7d258 65{
2cce0c26 66 char *qf;
2cce0c26 67 register FILE *tfp;
81b7d258 68 register HDR *h;
d4f42161 69 register ADDRESS *q;
3620ad97
EA
70 int fd;
71 int i;
72 bool newid;
22293c34 73 register char *p;
4db45bf1 74 MAILER nullmailer;
23fafb99 75 MCI mcibuf;
3620ad97 76 char buf[MAXLINE], tf[MAXLINE];
179d940c 77 extern void printctladdr __P((ADDRESS *, FILE *));
81b7d258 78
9ccf54c4 79 /*
11e3f8b5 80 ** Create control file.
9ccf54c4 81 */
81b7d258 82
eead656c 83 newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
e3778690
EA
84
85 /* if newid, queuename will create a locked qf file in e->lockfp */
3620ad97
EA
86 strcpy(tf, queuename(e, 't'));
87 tfp = e->e_lockfp;
88 if (tfp == NULL)
89 newid = FALSE;
e3778690
EA
90
91 /* if newid, just write the qf file directly (instead of tf file) */
eead656c 92 if (!newid)
3620ad97
EA
93 {
94 /* get a locked tf file */
b1c8be09 95 for (i = 0; i < 128; i++)
4287d84d 96 {
3620ad97
EA
97 fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
98 if (fd < 0)
4287d84d 99 {
b1c8be09
EA
100 if (errno != EEXIST)
101 break;
102#ifdef LOG
103 if (LogLevel > 0 && (i % 32) == 0)
e8f51a65
EA
104 syslog(LOG_ALERT, "queueup: cannot create %s, uid=%d: %s",
105 tf, geteuid(), errstring(errno));
b1c8be09 106#endif
6680179d 107 }
e8f51a65
EA
108 else
109 {
110 if (lockfile(fd, tf, NULL, LOCK_EX|LOCK_NB))
111 break;
b1c8be09 112#ifdef LOG
e8f51a65
EA
113 else if (LogLevel > 0 && (i % 32) == 0)
114 syslog(LOG_ALERT, "queueup: cannot lock %s: %s",
115 tf, errstring(errno));
b1c8be09 116#endif
e8f51a65
EA
117 close(fd);
118 }
b1c8be09
EA
119
120 if ((i % 32) == 31)
121 {
122 /* save the old temp file away */
123 (void) rename(tf, queuename(e, 'T'));
124 }
125 else
126 sleep(i % 32);
6680179d 127 }
e9d81da2 128 if (fd < 0 || (tfp = fdopen(fd, "w")) == NULL)
cea561e2
EA
129 {
130 printopenfds(TRUE);
e8f51a65
EA
131 syserr("!queueup: cannot create queue temp file %s, uid=%d",
132 tf, geteuid());
cea561e2 133 }
3620ad97 134 }
81b7d258 135
9678c96d 136 if (tTd(40, 1))
68d9129a
EA
137 printf("\n>>>>> queueing %s%s queueall=%d >>>>>\n", e->e_id,
138 newid ? " (new id)" : "", queueall);
66d16835
EA
139 if (tTd(40, 3))
140 {
141 extern void printenvflags();
142
143 printf(" e_flags=");
144 printenvflags(e);
145 }
68d9129a
EA
146 if (tTd(40, 32))
147 {
148 printf(" sendq=");
149 printaddr(e->e_sendqueue, TRUE);
150 }
eead656c
EA
151 if (tTd(40, 9))
152 {
153 printf(" tfp=");
154 dumpfd(fileno(tfp), TRUE, FALSE);
155 printf(" lockfp=");
156 if (e->e_lockfp == NULL)
157 printf("NULL\n");
158 else
159 dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
160 }
81b7d258 161
dd1fe05b
EA
162 /*
163 ** If there is no data file yet, create one.
164 */
165
18a81ac0 166 if (!bitset(EF_HAS_DF, e->e_flags))
dd1fe05b
EA
167 {
168 register FILE *dfp;
18a81ac0 169 char dfname[20];
f009d24b 170 struct stat stbuf;
dd1fe05b 171
18a81ac0
EA
172 strcpy(dfname, queuename(e, 'd'));
173 fd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode);
e9d81da2 174 if (fd < 0 || (dfp = fdopen(fd, "w")) == NULL)
e8f51a65 175 syserr("!queueup: cannot create data temp file %s, uid=%d",
18a81ac0 176 dfname, geteuid());
f009d24b
EA
177 if (fstat(fd, &stbuf) < 0)
178 e->e_dfino = -1;
179 else
bb4fde22
EA
180 {
181 e->e_dfdev = stbuf.st_dev;
f009d24b 182 e->e_dfino = stbuf.st_ino;
bb4fde22 183 }
18a81ac0 184 e->e_flags |= EF_HAS_DF;
23fafb99
EA
185 bzero(&mcibuf, sizeof mcibuf);
186 mcibuf.mci_out = dfp;
187 mcibuf.mci_mailer = FileMailer;
51d448e5 188 (*e->e_putbody)(&mcibuf, e, NULL);
bc854e30 189 (void) xfclose(dfp, "queueup dfp", e->e_id);
80482eb5 190 e->e_putbody = putbody;
dd1fe05b
EA
191 }
192
81b7d258
EA
193 /*
194 ** Output future work requests.
4e969be0
EA
195 ** Priority and creation time should be first, since
196 ** they are required by orderq.
81b7d258
EA
197 */
198
68d9129a
EA
199 /* output queue version number (must be first!) */
200 fprintf(tfp, "V%d\n", QF_VERSION);
201
7338e3d4
EA
202 /* output message priority */
203 fprintf(tfp, "P%ld\n", e->e_msgpriority);
204
64912e7e
EA
205 /* output creation time */
206 fprintf(tfp, "T%ld\n", e->e_ctime);
207
f009d24b
EA
208 /* output last delivery time */
209 fprintf(tfp, "K%ld\n", e->e_dtime);
210
211 /* output number of delivery attempts */
212 fprintf(tfp, "N%d\n", e->e_ntries);
213
bb4fde22
EA
214 /* output inode number of data file */
215 /* XXX should probably include device major/minor too */
216 if (e->e_dfino != -1)
217 fprintf(tfp, "I%d/%d/%ld\n",
218 major(e->e_dfdev), minor(e->e_dfdev), e->e_dfino);
219
18a81ac0 220 /* output body type */
96bfbc2c
EA
221 if (e->e_bodytype != NULL)
222 fprintf(tfp, "B%s\n", e->e_bodytype);
81b7d258 223
baa0c390
EA
224 /* message from envelope, if it exists */
225 if (e->e_message != NULL)
dcf45886 226 fprintf(tfp, "M%s\n", denlstring(e->e_message, TRUE, FALSE));
baa0c390 227
c2bdb1dd
EA
228 /* send various flag bits through */
229 p = buf;
230 if (bitset(EF_WARNING, e->e_flags))
231 *p++ = 'w';
232 if (bitset(EF_RESPONSE, e->e_flags))
233 *p++ = 'r';
e3c84ea8
EA
234 if (bitset(EF_HAS8BIT, e->e_flags))
235 *p++ = '8';
c2bdb1dd
EA
236 *p++ = '\0';
237 if (buf[0] != '\0')
238 fprintf(tfp, "F%s\n", buf);
239
a9bac7a9 240 /* $r and $s and $_ macro values */
22293c34 241 if ((p = macvalue('r', e)) != NULL)
dcf45886 242 fprintf(tfp, "$r%s\n", denlstring(p, TRUE, FALSE));
22293c34 243 if ((p = macvalue('s', e)) != NULL)
dcf45886 244 fprintf(tfp, "$s%s\n", denlstring(p, TRUE, FALSE));
a9bac7a9 245 if ((p = macvalue('_', e)) != NULL)
dcf45886 246 fprintf(tfp, "$_%s\n", denlstring(p, TRUE, FALSE));
22293c34 247
81b7d258 248 /* output name of sender */
b2af5ecf 249 fprintf(tfp, "S%s\n", denlstring(p, TRUE, FALSE));
81b7d258 250
6da3ba01
EA
251 /* output ESMTP-supplied "original" information */
252 if (e->e_envid != NULL)
6da3ba01 253
ca4d0c0b 254 /* output list of recipient addresses */
b7b719e4 255 printctladdr(NULL, NULL);
dd1fe05b 256 for (q = e->e_sendqueue; q != NULL; q = q->q_next)
81b7d258 257 {
374579b6 258 if (bitset(QQUEUEUP, q->q_flags) ||
bc854e30 259 (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)))
4d237f16 260 {
9cdb0b30 261 printctladdr(q, tfp);
3b6c2253 262 if (q->q_orcpt != NULL)
b2af5ecf 263 fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE));
7338e3d4
EA
264 if (announce)
265 {
266 e->e_to = q->q_paddr;
b6edea3d 267 message("queued");
68f7099c 268 if (LogLevel > 8)
3500a891
EA
269 logdelivery(NULL, NULL, "queued",
270 NULL, (time_t) 0, e);
7338e3d4
EA
271 e->e_to = NULL;
272 }
b9accadd
EA
273 if (tTd(40, 1))
274 {
275 printf("queueing ");
276 printaddr(q, FALSE);
277 }
4d237f16 278 }
81b7d258
EA
279 }
280
7338e3d4
EA
281 /*
282 ** Output headers for this message.
283 ** Expand macros completely here. Queue run will deal with
284 ** everything as absolute headers.
285 ** All headers that must be relative to the recipient
286 ** can be cracked later.
4db45bf1
EA
287 ** We set up a "null mailer" -- i.e., a mailer that will have
288 ** no effect on the addresses as they are output.
7338e3d4
EA
289 */
290
1dbda134 291 bzero((char *) &nullmailer, sizeof nullmailer);
68f7099c 292 nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
21efe526 293 nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
281ef7f0 294 nullmailer.m_eol = "\n";
23fafb99
EA
295 bzero(&mcibuf, sizeof mcibuf);
296 mcibuf.mci_mailer = &nullmailer;
297 mcibuf.mci_out = tfp;
4db45bf1 298
2bee003d 299 define('g', "\201f", e);
dd1fe05b 300 for (h = e->e_header; h != NULL; h = h->h_link)
81b7d258 301 {
1dbda134
EA
302 extern bool bitzerop();
303
83e9910e 304 /* don't output null headers */
81b7d258
EA
305 if (h->h_value == NULL || h->h_value[0] == '\0')
306 continue;
83e9910e
EA
307
308 /* don't output resent headers on non-resent messages */
309 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
310 continue;
311
d27723b2
EA
312 /* expand macros; if null, don't output header at all */
313 if (bitset(H_DEFAULT, h->h_flags))
314 {
832e8a27 315 (void) expand(h->h_value, buf, sizeof buf, e);
d27723b2
EA
316 if (buf[0] == '\0')
317 continue;
318 }
319
83e9910e 320 /* output this header */
2cce0c26 321 fprintf(tfp, "H");
83e9910e
EA
322
323 /* if conditional, output the set of conditions */
1dbda134
EA
324 if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
325 {
326 int j;
327
0e306e7f 328 (void) putc('?', tfp);
1dbda134
EA
329 for (j = '\0'; j <= '\177'; j++)
330 if (bitnset(j, h->h_mflags))
0e306e7f
EA
331 (void) putc(j, tfp);
332 (void) putc('?', tfp);
1dbda134 333 }
83e9910e
EA
334
335 /* output the header: expand macros, convert addresses */
9416f3a0
EA
336 if (bitset(H_DEFAULT, h->h_flags))
337 {
d27723b2 338 fprintf(tfp, "%s: %s\n", h->h_field, buf);
9416f3a0 339 }
4d237f16 340 else if (bitset(H_FROM|H_RCPT, h->h_flags))
611b763d 341 {
c2bdb1dd 342 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
8e5c6745
EA
343 FILE *savetrace = TrafficLogFile;
344
345 TrafficLogFile = NULL;
c2bdb1dd
EA
346
347 if (bitset(H_FROM, h->h_flags))
348 oldstyle = FALSE;
349
23fafb99 350 commaize(h, h->h_value, oldstyle, &mcibuf, e);
8e5c6745
EA
351
352 TrafficLogFile = savetrace;
611b763d 353 }
4d237f16
EA
354 else
355 fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
81b7d258
EA
356 }
357
358 /*
359 ** Clean up.
360 */
361
eb1ada3c 362 if (fflush(tfp) < 0 || fsync(fileno(tfp)) < 0 || ferror(tfp))
e6d43796
EA
363 {
364 if (newid)
365 syserr("!552 Error writing control file %s", tf);
366 else
367 syserr("!452 Error writing control file %s", tf);
368 }
369
3620ad97
EA
370 if (!newid)
371 {
e3778690 372 /* rename (locked) tf to be (locked) qf */
3620ad97
EA
373 qf = queuename(e, 'q');
374 if (rename(tf, qf) < 0)
18a81ac0
EA
375 syserr("cannot rename(%s, %s), uid=%d",
376 tf, qf, geteuid());
e3778690
EA
377
378 /* close and unlock old (locked) qf */
3620ad97 379 if (e->e_lockfp != NULL)
bc854e30 380 (void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id);
3620ad97
EA
381 e->e_lockfp = tfp;
382 }
383 else
384 qf = tf;
6680179d 385 errno = 0;
eead656c 386 e->e_flags |= EF_INQUEUE;
1a13ccd8 387
9678c96d
EA
388# ifdef LOG
389 /* save log info */
68f7099c 390 if (LogLevel > 79)
18a81ac0 391 syslog(LOG_DEBUG, "%s: queueup, qf=%s", e->e_id, qf);
f3d8f6d6 392# endif /* LOG */
51458e80
EA
393
394 if (tTd(40, 1))
395 printf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
3620ad97 396 return;
81b7d258 397}
d2213d6c 398
179d940c 399void
d2213d6c 400printctladdr(a, tfp)
9cdb0b30 401 register ADDRESS *a;
d2213d6c
EA
402 FILE *tfp;
403{
9cdb0b30
EA
404 char *uname;
405 register struct passwd *pw;
406 register ADDRESS *q;
407 uid_t uid;
408 static ADDRESS *lastctladdr;
409 static uid_t lastuid;
d2213d6c 410
9cdb0b30 411 /* initialization */
c6c403f7 412 if (a == NULL || a->q_alias == NULL || tfp == NULL)
d2213d6c 413 {
31739b4e 414 if (lastctladdr != NULL && tfp != NULL)
9cdb0b30
EA
415 fprintf(tfp, "C\n");
416 lastctladdr = NULL;
417 lastuid = 0;
d2213d6c
EA
418 return;
419 }
9cdb0b30
EA
420
421 /* find the active uid */
422 q = getctladdr(a);
423 if (q == NULL)
424 uid = 0;
425 else
426 uid = q->q_uid;
c6c403f7 427 a = a->q_alias;
9cdb0b30
EA
428
429 /* check to see if this is the same as last time */
430 if (lastctladdr != NULL && uid == lastuid &&
431 strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
432 return;
433 lastuid = uid;
434 lastctladdr = a;
435
5b7a2dfe 436 if (uid == 0 || (pw = sm_getpwuid(uid)) == NULL)
f7894324 437 uname = "";
d2213d6c 438 else
9cdb0b30
EA
439 uname = pw->pw_name;
440
dcf45886 441 fprintf(tfp, "C%s:%s\n", uname, denlstring(a->q_paddr, TRUE, FALSE));
d2213d6c 442}
81b7d258
EA
443\f/*
444** RUNQUEUE -- run the jobs in the queue.
445**
446** Gets the stuff out of the queue in some presumably logical
447** order and processes them.
448**
449** Parameters:
2e3062fe
EA
450** forkflag -- TRUE if the queue scanning should be done in
451** a child process. We double-fork so it is not our
452** child and we don't have to clean up after it.
81b7d258
EA
453**
454** Returns:
455** none.
456**
457** Side Effects:
458** runs things in the mail queue.
459*/
460
ca4d0c0b
EA
461ENVELOPE QueueEnvelope; /* the queue run envelope */
462
ea07b2d2 463void
ca4d0c0b 464runqueue(forkflag)
2cf55cb7 465 bool forkflag;
81b7d258 466{
ca4d0c0b 467 register ENVELOPE *e;
d3a63a56
EA
468 int njobs;
469 int sequenceno = 0;
ca4d0c0b 470 extern ENVELOPE BlankEnvelope;
4bc44f60
EA
471
472 /*
473 ** If no work will ever be selected, don't even bother reading
474 ** the queue.
475 */
476
3620ad97 477 CurrentLA = getla(); /* get load average */
3f9ac8ea 478
986065ef 479 if (shouldqueue(0L, curtime()))
4bc44f60 480 {
303d144e
EA
481 char *msg = "Skipping queue run -- load average too high";
482
4bc44f60 483 if (Verbose)
303d144e
EA
484 printf("%s\n", msg);
485#ifdef LOG
486 if (LogLevel > 8)
487 syslog(LOG_INFO, "runqueue: %s", msg);
488#endif
fe80f8e1
EA
489 if (forkflag && QueueIntvl != 0)
490 (void) setevent(QueueIntvl, runqueue, TRUE);
ca4d0c0b 491 return;
4bc44f60
EA
492 }
493
b6dffdf5
EA
494 /*
495 ** See if we want to go off and do other useful work.
496 */
2cf55cb7
EA
497
498 if (forkflag)
499 {
6d06102a 500 int pid;
a72af781
EA
501#ifdef SIGCHLD
502 extern void reapchild();
503
504 (void) setsignal(SIGCHLD, reapchild);
505#endif
6d06102a
EA
506
507 pid = dofork();
508 if (pid != 0)
2cf55cb7 509 {
6d06102a 510 /* parent -- pick up intermediate zombie */
c8ad461a 511#ifndef SIGCHLD
7338e3d4 512 (void) waitfor(pid);
f3d8f6d6 513#endif /* SIGCHLD */
c4442979 514 if (QueueIntvl != 0)
611b763d 515 (void) setevent(QueueIntvl, runqueue, TRUE);
2cf55cb7
EA
516 return;
517 }
6d06102a 518 /* child -- double fork */
c8ad461a 519#ifndef SIGCHLD
6d06102a
EA
520 if (fork() != 0)
521 exit(EX_OK);
f3d8f6d6 522#else /* SIGCHLD */
39270cfd 523 (void) setsignal(SIGCHLD, SIG_DFL);
f3d8f6d6 524#endif /* SIGCHLD */
b6dffdf5 525 }
2e3062fe 526
3f9ac8ea 527 setproctitle("running queue: %s", QueueDir);
2e3062fe 528
36a4e219 529# ifdef LOG
68f7099c 530 if (LogLevel > 69)
ca4d0c0b
EA
531 syslog(LOG_DEBUG, "runqueue %s, pid=%d, forkflag=%d",
532 QueueDir, getpid(), forkflag);
f3d8f6d6 533# endif /* LOG */
81b7d258 534
eb8af3ce
EA
535 /*
536 ** Release any resources used by the daemon code.
537 */
538
539# ifdef DAEMON
540 clrdaemon();
f3d8f6d6 541# endif /* DAEMON */
eb8af3ce 542
6b951123
EA
543 /* force it to run expensive jobs */
544 NoConnect = FALSE;
545
ca4d0c0b
EA
546 /*
547 ** Create ourselves an envelope
548 */
549
550 CurEnv = &QueueEnvelope;
fda58daa 551 e = newenvelope(&QueueEnvelope, CurEnv);
ca4d0c0b
EA
552 e->e_flags = BlankEnvelope.e_flags;
553
a78155b0
EA
554 /*
555 ** Make sure the alias database is open.
556 */
557
36b09297 558 initmaps(FALSE, e);
a78155b0 559
b6dffdf5
EA
560 /*
561 ** Start making passes through the queue.
562 ** First, read and sort the entire queue.
563 ** Then, process the work in that order.
564 ** But if you take too long, start over.
b6dffdf5 565 */
81b7d258 566
6d06102a 567 /* order the existing work requests */
d3a63a56 568 njobs = orderq(FALSE);
291fa573 569
6d06102a
EA
570 /* process them once at a time */
571 while (WorkQ != NULL)
2cf55cb7 572 {
6d06102a 573 WORK *w = WorkQ;
2cf55cb7 574
6d06102a 575 WorkQ = WorkQ->w_next;
a7dc53bd
EA
576
577 /*
578 ** Ignore jobs that are too expensive for the moment.
579 */
580
d3a63a56 581 sequenceno++;
a7dc53bd
EA
582 if (shouldqueue(w->w_pri, w->w_ctime))
583 {
584 if (Verbose)
d3a63a56
EA
585 printf("\nSkipping %s (sequence %d of %d)\n",
586 w->w_name + 2, sequenceno, njobs);
a7dc53bd 587 }
1c791deb
EA
588 else
589 {
d0268270
EA
590 pid_t pid;
591 extern pid_t dowork();
592
d3a63a56
EA
593 if (Verbose)
594 printf("\nRunning %s (sequence %d of %d)\n",
595 w->w_name + 2, sequenceno, njobs);
d0268270
EA
596 pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
597 errno = 0;
a9927082
EA
598 if (pid != 0)
599 (void) waitfor(pid);
1c791deb 600 }
6d06102a 601 free(w->w_name);
a9ca3259
EA
602 if (w->w_host)
603 free(w->w_host);
6d06102a 604 free((char *) w);
2cf55cb7 605 }
37ea3cbf
EA
606
607 /* exit without the usual cleanup */
4e20c4d2
EA
608 e->e_id = NULL;
609 finis();
aba51985
EA
610}
611\f/*
81b7d258
EA
612** ORDERQ -- order the work queue.
613**
614** Parameters:
2e3062fe
EA
615** doall -- if set, include everything in the queue (even
616** the jobs that cannot be run because the load
617** average is too high). Otherwise, exclude those
618** jobs.
81b7d258
EA
619**
620** Returns:
e65b95c4
EA
621** The number of request in the queue (not necessarily
622** the number of requests in WorkQ however).
81b7d258
EA
623**
624** Side Effects:
625** Sets WorkQ to the queue of available work, in order.
626*/
627
4e969be0
EA
628# define NEED_P 001
629# define NEED_T 002
d6c28d1a
EA
630# define NEED_R 004
631# define NEED_S 010
81b7d258 632
8a6b1962
EA
633static WORK *WorkList = NULL;
634static int WorkListSize = 0;
635
179d940c 636int
38d3b461
EA
637# ifndef DIR
638# define DIR FILE
639# define direct dir
640# define opendir(d) fopen(d, "r")
07a8f29b 641# define readdir(f) ((fread(&dbuf, sizeof dbuf, 1, f) > 0) ? &dbuf : 0)
38d3b461
EA
642static struct dir dbuf;
643# define closedir(f) fclose(f)
644# endif DIR
645
2e3062fe
EA
646orderq(doall)
647 bool doall;
81b7d258 648{
9114f86c 649 register struct dirent *d;
81b7d258 650 register WORK *w;
ccd1d833 651 DIR *f;
81b7d258 652 register int i;
0490b7d7 653 int wn = -1;
a9ca3259 654 int wc;
81b7d258 655
d6c28d1a
EA
656 if (tTd(41, 1))
657 {
658 printf("orderq:\n");
659 if (QueueLimitId != NULL)
660 printf("\tQueueLimitId = %s\n", QueueLimitId);
661 if (QueueLimitSender != NULL)
662 printf("\tQueueLimitSender = %s\n", QueueLimitSender);
663 if (QueueLimitRecipient != NULL)
664 printf("\tQueueLimitRecipient = %s\n", QueueLimitRecipient);
665 }
666
81b7d258
EA
667 /* clear out old WorkQ */
668 for (w = WorkQ; w != NULL; )
669 {
670 register WORK *nw = w->w_next;
671
672 WorkQ = nw;
673 free(w->w_name);
a9ca3259
EA
674 if (w->w_host)
675 free(w->w_host);
81b7d258
EA
676 free((char *) w);
677 w = nw;
678 }
679
680 /* open the queue directory */
6bbaf971 681 f = opendir(".");
81b7d258
EA
682 if (f == NULL)
683 {
6bbaf971 684 syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
0490b7d7 685 return (0);
81b7d258
EA
686 }
687
688 /*
689 ** Read the work directory.
690 */
691
0490b7d7 692 while ((d = readdir(f)) != NULL)
81b7d258 693 {
81b7d258 694 FILE *cf;
bb530db4 695 register char *p;
8446c922 696 char lbuf[MAXNAME + 1];
d6c28d1a 697 extern bool strcontainedin();
81b7d258
EA
698
699 /* is this an interesting entry? */
07a8f29b
EA
700 if (d->d_ino == 0)
701 continue;
702# ifdef DEBUG
703 if (tTd(40, 10))
704 printf("orderq: %12s\n", d->d_name);
705# endif DEBUG
2cce0c26 706 if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
81b7d258
EA
707 continue;
708
d6c28d1a
EA
709 if (QueueLimitId != NULL &&
710 !strcontainedin(QueueLimitId, d->d_name))
711 continue;
712
6502fd93 713#ifdef PICKY_QF_NAME_CHECK
45ce4b34
EA
714 /*
715 ** Check queue name for plausibility. This handles
716 ** both old and new type ids.
717 */
718
bb530db4
EA
719 p = d->d_name + 2;
720 if (isupper(p[0]) && isupper(p[2]))
721 p += 3;
722 else if (isupper(p[1]))
723 p += 2;
724 else
725 p = d->d_name;
726 for (i = 0; isdigit(*p); p++)
727 i++;
728 if (i < 5 || *p != '\0')
68f7099c
EA
729 {
730 if (Verbose)
731 printf("orderq: bogus qf name %s\n", d->d_name);
6502fd93
EA
732# ifdef LOG
733 if (LogLevel > 0)
734 syslog(LOG_ALERT, "orderq: bogus qf name %s",
68f7099c 735 d->d_name);
6502fd93 736# endif
2604d017 737 if (strlen(d->d_name) > (SIZE_T) MAXNAME)
8446c922 738 d->d_name[MAXNAME] = '\0';
68f7099c
EA
739 strcpy(lbuf, d->d_name);
740 lbuf[0] = 'Q';
741 (void) rename(d->d_name, lbuf);
742 continue;
743 }
6502fd93 744#endif
68f7099c 745
6502fd93 746 /* open control file (if not too many files) */
28b647b8
EA
747 if (++wn > MaxQueueRun && MaxQueueRun > 0)
748 {
749# ifdef LOG
750 if (wn == MaxQueueRun + 1 && LogLevel > 0)
751 syslog(LOG_ALERT, "WorkList for %s maxed out at %d",
752 QueueDir, MaxQueueRun);
753# endif
754 continue;
755 }
756 if (wn >= WorkListSize)
8a6b1962 757 {
179d940c
EA
758 extern void grow_wlist __P((void));
759
8a6b1962
EA
760 grow_wlist();
761 if (wn >= WorkListSize)
762 continue;
763 }
d6c28d1a 764
6bbaf971 765 cf = fopen(d->d_name, "r");
81b7d258
EA
766 if (cf == NULL)
767 {
91f69adf
EA
768 /* this may be some random person sending hir msgs */
769 /* syserr("orderq: cannot open %s", cbuf); */
bd0712bd
EA
770 if (tTd(41, 2))
771 printf("orderq: cannot open %s (%d)\n",
772 d->d_name, errno);
91f69adf 773 errno = 0;
bd0712bd 774 wn--;
81b7d258
EA
775 continue;
776 }
8a6b1962 777 w = &WorkList[wn];
4e969be0 778 w->w_name = newstr(d->d_name);
a9ca3259
EA
779 w->w_host = NULL;
780 w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB);
81b7d258 781
4ff794a3 782 /* make sure jobs in creation don't clog queue */
4e969be0
EA
783 w->w_pri = 0x7fffffff;
784 w->w_ctime = 0;
4ff794a3 785
81b7d258 786 /* extract useful information */
4e969be0 787 i = NEED_P | NEED_T;
d6c28d1a
EA
788 if (QueueLimitSender != NULL)
789 i |= NEED_S;
92830179 790 if (QueueSortOrder == QS_BYHOST || QueueLimitRecipient != NULL)
d6c28d1a 791 i |= NEED_R;
4e969be0 792 while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
81b7d258 793 {
d6c28d1a 794 extern bool strcontainedin();
8ff78b51 795
2e3062fe 796 switch (lbuf[0])
81b7d258 797 {
2e3062fe 798 case 'P':
4e969be0
EA
799 w->w_pri = atol(&lbuf[1]);
800 i &= ~NEED_P;
2e3062fe 801 break;
f746582a
EA
802
803 case 'T':
4e969be0
EA
804 w->w_ctime = atol(&lbuf[1]);
805 i &= ~NEED_T;
f746582a 806 break;
d6c28d1a
EA
807
808 case 'R':
a9ca3259
EA
809 if (w->w_host == NULL &&
810 (p = strrchr(&lbuf[1], '@')) != NULL)
811 w->w_host = newstr(&p[1]);
812 if (QueueLimitRecipient == NULL ||
d6c28d1a
EA
813 strcontainedin(QueueLimitRecipient, &lbuf[1]))
814 i &= ~NEED_R;
815 break;
816
817 case 'S':
818 if (QueueLimitSender != NULL &&
819 strcontainedin(QueueLimitSender, &lbuf[1]))
820 i &= ~NEED_S;
821 break;
81b7d258
EA
822 }
823 }
81b7d258 824 (void) fclose(cf);
4bc44f60 825
d6c28d1a
EA
826 if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
827 bitset(NEED_R|NEED_S, i))
4bc44f60
EA
828 {
829 /* don't even bother sorting this job in */
a9ca3259
EA
830 free(w->w_name);
831 if (w->w_host)
832 free(w->w_host);
4bc44f60
EA
833 wn--;
834 }
81b7d258 835 }
ccd1d833 836 (void) closedir(f);
bd0712bd 837 wn++;
81b7d258 838
8a6b1962 839 wc = min(wn, WorkListSize);
a9ca3259 840
92830179 841 if (QueueSortOrder == QS_BYHOST)
a9ca3259
EA
842 {
843 extern workcmpf1();
844 extern workcmpf2();
845
846 /*
847 ** Sort the work directory for the first time,
848 ** based on host name, lock status, and priority.
849 */
850
8a6b1962 851 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1);
a9ca3259
EA
852
853 /*
854 ** If one message to host is locked, "lock" all messages
855 ** to that host.
856 */
857
858 i = 0;
859 while (i < wc)
860 {
8a6b1962 861 if (!WorkList[i].w_lock)
a9ca3259
EA
862 {
863 i++;
864 continue;
865 }
8a6b1962 866 w = &WorkList[i];
a9ca3259
EA
867 while (++i < wc)
868 {
8a6b1962 869 if (WorkList[i].w_host == NULL &&
a9ca3259 870 w->w_host == NULL)
8a6b1962
EA
871 WorkList[i].w_lock = TRUE;
872 else if (WorkList[i].w_host != NULL &&
a9ca3259 873 w->w_host != NULL &&
8a6b1962
EA
874 strcmp(WorkList[i].w_host, w->w_host) == 0)
875 WorkList[i].w_lock = TRUE;
a9ca3259
EA
876 else
877 break;
878 }
879 }
880
881 /*
882 ** Sort the work directory for the second time,
883 ** based on lock status, host name, and priority.
884 */
885
8a6b1962 886 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2);
a9ca3259 887 }
92830179
EA
888 else
889 {
890 extern workcmpf0();
891
892 /*
893 ** Simple sort based on queue priority only.
894 */
895
8a6b1962 896 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0);
92830179 897 }
81b7d258
EA
898
899 /*
900 ** Convert the work list into canonical form.
7338e3d4 901 ** Should be turning it into a list of envelopes here perhaps.
81b7d258
EA
902 */
903
a0225d08 904 WorkQ = NULL;
a9ca3259 905 for (i = wc; --i >= 0; )
81b7d258
EA
906 {
907 w = (WORK *) xalloc(sizeof *w);
8a6b1962
EA
908 w->w_name = WorkList[i].w_name;
909 w->w_host = WorkList[i].w_host;
910 w->w_lock = WorkList[i].w_lock;
911 w->w_pri = WorkList[i].w_pri;
912 w->w_ctime = WorkList[i].w_ctime;
a0225d08
EA
913 w->w_next = WorkQ;
914 WorkQ = w;
81b7d258 915 }
8a6b1962
EA
916 free(WorkList);
917 WorkList = NULL;
81b7d258 918
9678c96d 919 if (tTd(40, 1))
81b7d258
EA
920 {
921 for (w = WorkQ; w != NULL; w = w->w_next)
9ccf54c4 922 printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
81b7d258 923 }
0490b7d7 924
bd0712bd 925 return (wn);
81b7d258 926}
28b647b8
EA
927\f/*
928** GROW_WLIST -- make the work list larger
929**
930** Parameters:
931** none.
932**
933** Returns:
934** none.
935**
936** Side Effects:
937** Adds another QUEUESEGSIZE entries to WorkList if possible.
938** It can fail if there isn't enough memory, so WorkListSize
939** should be checked again upon return.
940*/
8a6b1962 941
179d940c 942void
8a6b1962
EA
943grow_wlist()
944{
945 if (tTd(41, 1))
946 printf("grow_wlist: WorkListSize=%d\n", WorkListSize);
28b647b8 947 if (WorkList == NULL)
8a6b1962
EA
948 {
949 WorkList = (WORK *) xalloc(sizeof(WORK) * (QUEUESEGSIZE + 1));
950 WorkListSize = QUEUESEGSIZE;
951 }
952 else
953 {
954 int newsize = WorkListSize + QUEUESEGSIZE;
955 WORK *newlist = (WORK *) realloc((char *)WorkList,
956 (unsigned)sizeof(WORK) * (newsize + 1));
957
958 if (newlist != NULL)
959 {
960 WorkListSize = newsize;
961 WorkList = newlist;
962# ifdef LOG
963 if (LogLevel > 1)
964 {
965 syslog(LOG_NOTICE, "grew WorkList for %s to %d",
966 QueueDir, WorkListSize);
967 }
968 }
969 else if (LogLevel > 0)
970 {
971 syslog(LOG_ALERT, "FAILED to grow WorkList for %s to %d",
972 QueueDir, newsize);
973# endif
974 }
975 }
976 if (tTd(41, 1))
977 printf("grow_wlist: WorkListSize now %d\n", WorkListSize);
978}
81b7d258 979\f/*
a9ca3259 980** WORKCMPF0 -- simple priority-only compare function.
81b7d258
EA
981**
982** Parameters:
983** a -- the first argument.
984** b -- the second argument.
985**
986** Returns:
a0225d08
EA
987** -1 if a < b
988** 0 if a == b
989** +1 if a > b
81b7d258
EA
990**
991** Side Effects:
992** none.
993*/
994
179d940c 995int
a9ca3259 996workcmpf0(a, b)
9ccf54c4
EA
997 register WORK *a;
998 register WORK *b;
81b7d258 999{
abccefc9
EA
1000 long pa = a->w_pri;
1001 long pb = b->w_pri;
2e3062fe
EA
1002
1003 if (pa == pb)
a9ca3259 1004 return 0;
2e3062fe 1005 else if (pa > pb)
a9ca3259 1006 return 1;
a0225d08 1007 else
a9ca3259
EA
1008 return -1;
1009}
1010\f/*
1011** WORKCMPF1 -- first compare function for ordering work based on host name.
1012**
1013** Sorts on host name, lock status, and priority in that order.
1014**
1015** Parameters:
1016** a -- the first argument.
1017** b -- the second argument.
1018**
1019** Returns:
1020** <0 if a < b
1021** 0 if a == b
1022** >0 if a > b
1023**
1024** Side Effects:
1025** none.
1026*/
1027
179d940c 1028int
a9ca3259
EA
1029workcmpf1(a, b)
1030 register WORK *a;
1031 register WORK *b;
1032{
1033 int i;
1034
1035 /* host name */
1036 if (a->w_host != NULL && b->w_host == NULL)
1037 return 1;
1038 else if (a->w_host == NULL && b->w_host != NULL)
1039 return -1;
1040 if (a->w_host != NULL && b->w_host != NULL &&
1041 (i = strcmp(a->w_host, b->w_host)))
1042 return i;
1043
1044 /* lock status */
1045 if (a->w_lock != b->w_lock)
1046 return b->w_lock - a->w_lock;
1047
1048 /* job priority */
1049 return a->w_pri - b->w_pri;
1050}
1051\f/*
1052** WORKCMPF2 -- second compare function for ordering work based on host name.
1053**
1054** Sorts on lock status, host name, and priority in that order.
1055**
1056** Parameters:
1057** a -- the first argument.
1058** b -- the second argument.
1059**
1060** Returns:
1061** <0 if a < b
1062** 0 if a == b
1063** >0 if a > b
1064**
1065** Side Effects:
1066** none.
1067*/
1068
179d940c 1069int
a9ca3259
EA
1070workcmpf2(a, b)
1071 register WORK *a;
1072 register WORK *b;
1073{
1074 int i;
1075
1076 /* lock status */
1077 if (a->w_lock != b->w_lock)
1078 return a->w_lock - b->w_lock;
1079
1080 /* host name */
1081 if (a->w_host != NULL && b->w_host == NULL)
1082 return 1;
1083 else if (a->w_host == NULL && b->w_host != NULL)
1084 return -1;
1085 if (a->w_host != NULL && b->w_host != NULL &&
1086 (i = strcmp(a->w_host, b->w_host)))
1087 return i;
1088
1089 /* job priority */
1090 return a->w_pri - b->w_pri;
81b7d258
EA
1091}
1092\f/*
1093** DOWORK -- do a work request.
1094**
1095** Parameters:
a7dc53bd
EA
1096** id -- the ID of the job to run.
1097** forkflag -- if set, run this in background.
f5303697
EA
1098** requeueflag -- if set, reinstantiate the queue quickly.
1099** This is used when expanding aliases in the queue.
8d00c219
EA
1100** If forkflag is also set, it doesn't wait for the
1101** child.
a7dc53bd 1102** e - the envelope in which to run it.
81b7d258
EA
1103**
1104** Returns:
d0268270 1105** process id of process that is running the queue job.
81b7d258
EA
1106**
1107** Side Effects:
1108** The work request is satisfied if possible.
1109*/
1110
d0268270 1111pid_t
f5303697 1112dowork(id, forkflag, requeueflag, e)
a7dc53bd
EA
1113 char *id;
1114 bool forkflag;
f5303697 1115 bool requeueflag;
a4076aed 1116 register ENVELOPE *e;
81b7d258 1117{
d0268270 1118 register pid_t pid;
3620ad97 1119 extern bool readqf();
81b7d258 1120
9678c96d 1121 if (tTd(40, 1))
a7dc53bd 1122 printf("dowork(%s)\n", id);
81b7d258 1123
2e3062fe
EA
1124 /*
1125 ** Fork for work.
1126 */
1127
a7dc53bd 1128 if (forkflag)
2e3062fe 1129 {
d0268270
EA
1130 pid = fork();
1131 if (pid < 0)
2e3062fe
EA
1132 {
1133 syserr("dowork: cannot fork");
d0268270 1134 return 0;
2e3062fe 1135 }
5cf47fbf
EA
1136 else if (pid > 0)
1137 {
1138 /* parent -- clean out connection cache */
1139 mci_flush(FALSE, NULL);
1140 }
2e3062fe
EA
1141 }
1142 else
1143 {
d0268270 1144 pid = 0;
2e3062fe
EA
1145 }
1146
d0268270 1147 if (pid == 0)
81b7d258
EA
1148 {
1149 /*
1150 ** CHILD
6bbaf971
EA
1151 ** Lock the control file to avoid duplicate deliveries.
1152 ** Then run the file as though we had just read it.
68f0b54c
EA
1153 ** We save an idea of the temporary name so we
1154 ** can recover on interrupt.
81b7d258
EA
1155 */
1156
9416f3a0 1157 /* set basic modes, etc. */
37eaaadb 1158 (void) alarm(0);
a4076aed 1159 clearenvelope(e, FALSE);
164f3011 1160 e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
8c8e8e94 1161 e->e_errormode = EM_MAIL;
a7dc53bd 1162 e->e_id = id;
48cb554d 1163 GrabTo = UseErrorsTo = FALSE;
a9927082 1164 ExitStat = EX_OK;
47e2f242 1165 if (forkflag)
164f3011 1166 {
d0268270 1167 disconnect(1, e);
164f3011
EA
1168 OpMode = MD_DELIVER;
1169 }
36a4e219 1170# ifdef LOG
68f7099c 1171 if (LogLevel > 76)
a4076aed 1172 syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id,
291fa573 1173 getpid());
f3d8f6d6 1174# endif /* LOG */
9416f3a0
EA
1175
1176 /* don't use the headers from sendmail.cf... */
a4076aed 1177 e->e_header = NULL;
9416f3a0 1178
3620ad97 1179 /* read the queue control file -- return if locked */
63a34fcd 1180 if (!readqf(e))
dd1fe05b 1181 {
a7dc53bd
EA
1182 if (tTd(40, 4))
1183 printf("readqf(%s) failed\n", e->e_id);
1184 if (forkflag)
2e3062fe
EA
1185 exit(EX_OK);
1186 else
a9927082 1187 return 0;
dd1fe05b 1188 }
dd1fe05b 1189
a4076aed 1190 e->e_flags |= EF_INQUEUE;
dd1fe05b 1191
3df50535 1192 /* if this has been tried recently, let it be */
1b9b1753 1193 if (e->e_ntries > 0 && (curtime() - e->e_dtime) < MinQueueAge)
3df50535
EA
1194 {
1195 char *howlong = pintvl(curtime() - e->e_dtime, TRUE);
f5303697 1196
3df50535
EA
1197 e->e_flags |= EF_KEEPQUEUE;
1198 if (Verbose || tTd(40, 8))
1199 printf("%s: too young (%s)\n",
1200 e->e_id, howlong);
1201#ifdef LOG
1202 if (LogLevel > 19)
1203 syslog(LOG_DEBUG, "%s: too young (%s)",
1204 e->e_id, howlong);
1205#endif
1206 }
1207 else
1208 {
1209 eatheader(e, requeueflag);
1210
1211 if (requeueflag)
1212 queueup(e, TRUE, FALSE);
1213
1214 /* do the delivery */
1215 sendall(e, SM_DELIVER);
1216 }
dd1fe05b 1217
dd1fe05b 1218 /* finish up and exit */
a7dc53bd 1219 if (forkflag)
2e3062fe
EA
1220 finis();
1221 else
a4076aed 1222 dropenvelope(e);
81b7d258 1223 }
d0268270
EA
1224 e->e_id = NULL;
1225 return pid;
81b7d258
EA
1226}
1227\f/*
1228** READQF -- read queue file and set up environment.
1229**
1230** Parameters:
7338e3d4 1231** e -- the envelope of the job to run.
81b7d258
EA
1232**
1233** Returns:
3620ad97
EA
1234** TRUE if it successfully read the queue file.
1235** FALSE otherwise.
81b7d258
EA
1236**
1237** Side Effects:
3620ad97 1238** The queue file is returned locked.
81b7d258
EA
1239*/
1240
3620ad97 1241bool
63a34fcd 1242readqf(e)
7338e3d4 1243 register ENVELOPE *e;
81b7d258 1244{
11e3f8b5 1245 register FILE *qfp;
d2213d6c 1246 ADDRESS *ctladdr;
dcbc04c7 1247 struct stat st;
07b49560 1248 char *bp;
68d9129a
EA
1249 int qfver = 0;
1250 register char *p;
3b6c2253 1251 char *orcpt = NULL;
e678ee95 1252 char qf[20];
07b49560 1253 char buf[MAXLINE];
d2213d6c 1254 extern ADDRESS *setctluser();
99fd9645 1255 extern void loseqfile();
abae7b2d 1256 extern ADDRESS *sendto();
81b7d258 1257
81b7d258
EA
1258 /*
1259 ** Read and process the file.
1260 */
1261
e678ee95 1262 strcpy(qf, queuename(e, 'q'));
76b607b2 1263 qfp = fopen(qf, "r+");
11e3f8b5
EA
1264 if (qfp == NULL)
1265 {
a7dc53bd
EA
1266 if (tTd(40, 8))
1267 printf("readqf(%s): fopen failure (%s)\n",
1268 qf, errstring(errno));
3f9ac8ea
RA
1269 if (errno != ENOENT)
1270 syserr("readqf: no control file %s", qf);
3620ad97 1271 return FALSE;
3f9ac8ea
RA
1272 }
1273
71936fbe 1274 if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
e3778690
EA
1275 {
1276 /* being processed by another queuer */
3df50535 1277 if (Verbose || tTd(40, 8))
e3778690
EA
1278 printf("%s: locked\n", e->e_id);
1279# ifdef LOG
1280 if (LogLevel > 19)
1281 syslog(LOG_DEBUG, "%s: locked", e->e_id);
1282# endif /* LOG */
1283 (void) fclose(qfp);
1284 return FALSE;
1285 }
1286
dcbc04c7
EA
1287 /*
1288 ** Check the queue file for plausibility to avoid attacks.
1289 */
1290
1291 if (fstat(fileno(qfp), &st) < 0)
1292 {
1293 /* must have been being processed by someone else */
a7dc53bd
EA
1294 if (tTd(40, 8))
1295 printf("readqf(%s): fstat failure (%s)\n",
1296 qf, errstring(errno));
dcbc04c7
EA
1297 fclose(qfp);
1298 return FALSE;
1299 }
1300
6502fd93 1301 if (st.st_uid != geteuid() || bitset(S_IWOTH|S_IWGRP, st.st_mode))
dcbc04c7
EA
1302 {
1303# ifdef LOG
1304 if (LogLevel > 0)
1305 {
1306 syslog(LOG_ALERT, "%s: bogus queue file, uid=%d, mode=%o",
1307 e->e_id, st.st_uid, st.st_mode);
1308 }
f3d8f6d6 1309# endif /* LOG */
a7dc53bd
EA
1310 if (tTd(40, 8))
1311 printf("readqf(%s): bogus file\n", qf);
99fd9645 1312 loseqfile(e, "bogus file uid in mqueue");
e3778690 1313 fclose(qfp);
dcbc04c7
EA
1314 return FALSE;
1315 }
1316
e3778690 1317 if (st.st_size == 0)
3f9ac8ea 1318 {
e3778690
EA
1319 /* must be a bogus file -- just remove it */
1320 (void) unlink(qf);
1321 fclose(qfp);
3620ad97 1322 return FALSE;
11e3f8b5 1323 }
3f9ac8ea 1324
e3778690 1325 if (st.st_nlink == 0)
c87034b7 1326 {
e3778690
EA
1327 /*
1328 ** Race condition -- we got a file just as it was being
1329 ** unlinked. Just assume it is zero length.
1330 */
1331
c87034b7
EA
1332 fclose(qfp);
1333 return FALSE;
1334 }
1335
e3778690 1336 /* good file -- save this lock */
3620ad97
EA
1337 e->e_lockfp = qfp;
1338
3f9ac8ea 1339 /* do basic system initialization */
a4076aed 1340 initsys(e);
b276598d 1341 define('i', e->e_id, e);
3f9ac8ea 1342
560a80d9 1343 LineNumber = 0;
c6c403f7
EA
1344 e->e_flags |= EF_GLOBALERRS;
1345 OpMode = MD_DELIVER;
d2213d6c 1346 ctladdr = NULL;
bb4fde22 1347 e->e_dfino = -1;
18a81ac0 1348 e->e_msgsize = -1;
07b49560 1349 while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
81b7d258 1350 {
c2bdb1dd 1351 register char *p;
68d9129a
EA
1352 u_long qflags;
1353 ADDRESS *q;
65b5adb6 1354
795590e2 1355 if (tTd(40, 4))
07b49560
EA
1356 printf("+++++ %s\n", bp);
1357 switch (bp[0])
81b7d258 1358 {
68d9129a
EA
1359 case 'V': /* queue file version number */
1360 qfver = atoi(&bp[1]);
1361 if (qfver > QF_VERSION)
1362 {
1363 syserr("Version number in qf (%d) greater than max (%d)",
1364 qfver, QF_VERSION);
1365 }
1366 break;
1367
3fbc69d6 1368 case 'C': /* specify controlling user */
07b49560 1369 ctladdr = setctluser(&bp[1]);
3fbc69d6
KB
1370 break;
1371
3b6c2253
EA
1372 case 'Q': /* original recipient */
1373 orcpt = newstr(&bp[1]);
1374 break;
1375
81b7d258 1376 case 'R': /* specify recipient */
abae7b2d 1377 (void) sendto(&buf[1], 1, (ADDRESS *) NULL, 0);
81b7d258
EA
1378 break;
1379
4e969be0 1380 case 'E': /* specify error recipient */
b7b719e4 1381 /* no longer used */
4e969be0
EA
1382 break;
1383
81b7d258 1384 case 'H': /* header */
9905202c 1385 (void) chompheader(&bp[1], FALSE, NULL, e);
81b7d258
EA
1386 break;
1387
baa0c390 1388 case 'M': /* message */
82530719 1389 /* ignore this; we want a new message next time */
baa0c390
EA
1390 break;
1391
81b7d258 1392 case 'S': /* sender */
4a2da288 1393 setsender(newstr(&bp[1]), e, NULL, TRUE);
81b7d258
EA
1394 break;
1395
96bfbc2c
EA
1396 case 'B': /* body type */
1397 e->e_bodytype = newstr(&bp[1]);
1398 break;
1399
81b7d258 1400 case 'D': /* data file name */
18a81ac0 1401 /* obsolete -- ignore */
81b7d258
EA
1402 break;
1403
96476cab 1404 case 'T': /* init time */
07b49560 1405 e->e_ctime = atol(&bp[1]);
81b7d258
EA
1406 break;
1407
f009d24b 1408 case 'I': /* data file's inode number */
bb4fde22
EA
1409 if (e->e_dfino == -1)
1410 e->e_dfino = atol(&buf[1]);
f009d24b
EA
1411 break;
1412
1413 case 'K': /* time of last deliver attempt */
1414 e->e_dtime = atol(&buf[1]);
1415 break;
1416
1417 case 'N': /* number of delivery attempts */
1418 e->e_ntries = atoi(&buf[1]);
1419 break;
1420
aba51985 1421 case 'P': /* message priority */
07b49560 1422 e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
dd1fe05b
EA
1423 break;
1424
c2bdb1dd
EA
1425 case 'F': /* flag bits */
1426 for (p = &bp[1]; *p != '\0'; p++)
1427 {
1428 switch (*p)
1429 {
1430 case 'w': /* warning sent */
1431 e->e_flags |= EF_WARNING;
1432 break;
1433
1434 case 'r': /* response */
1435 e->e_flags |= EF_RESPONSE;
1436 break;
e3c84ea8
EA
1437
1438 case '8': /* has 8 bit data */
1439 e->e_flags |= EF_HAS8BIT;
1440 break;
c2bdb1dd
EA
1441 }
1442 }
1443 break;
1444
6da3ba01 1445 case 'Z': /* original envelope id from ESMTP */
36c7ff6a 1446 e->e_envid = newstr(&bp[1]);
6da3ba01
EA
1447 break;
1448
22293c34 1449 case '$': /* define macro */
07b49560 1450 define(bp[1], newstr(&bp[2]), e);
22293c34
EA
1451 break;
1452
2e3062fe
EA
1453 case '\0': /* blank line; ignore */
1454 break;
1455
81b7d258 1456 default:
5e90e563 1457 syserr("readqf: %s: line %d: bad line \"%s\"",
63a34fcd 1458 qf, LineNumber, bp);
8e5c6745 1459 fclose(qfp);
99fd9645 1460 loseqfile(e, "unrecognized line");
8e5c6745 1461 return FALSE;
81b7d258 1462 }
07b49560
EA
1463
1464 if (bp != buf)
1465 free(bp);
81b7d258 1466 }
7338e3d4 1467
2e3062fe
EA
1468 /*
1469 ** If we haven't read any lines, this queue file is empty.
1470 ** Arrange to remove it without referencing any null pointers.
1471 */
1472
1473 if (LineNumber == 0)
1474 {
1475 errno = 0;
1476 e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
1477 }
18a81ac0
EA
1478 else
1479 {
1480 /*
1481 ** Arrange to read the data file.
1482 */
1483
1484 p = queuename(e, 'd');
1485 e->e_dfp = fopen(p, "r");
1486 if (e->e_dfp == NULL)
1487 {
1488 syserr("readqf: cannot open %s", p);
1489 }
66d16835 1490 else
18a81ac0 1491 {
66d16835
EA
1492 e->e_flags |= EF_HAS_DF;
1493 if (fstat(fileno(e->e_dfp), &st) >= 0)
1494 {
1495 e->e_msgsize = st.st_size;
1496 e->e_dfdev = st.st_dev;
1497 e->e_dfino = st.st_ino;
1498 }
18a81ac0
EA
1499 }
1500 }
1501
3620ad97 1502 return TRUE;
81b7d258
EA
1503}
1504\f/*
64912e7e
EA
1505** PRINTQUEUE -- print out a representation of the mail queue
1506**
1507** Parameters:
1508** none.
1509**
1510** Returns:
1511** none.
1512**
1513** Side Effects:
1514** Prints a listing of the mail queue on the standard output.
1515*/
1516
179d940c 1517void
64912e7e
EA
1518printqueue()
1519{
1520 register WORK *w;
1521 FILE *f;
0490b7d7 1522 int nrequests;
64912e7e
EA
1523 char buf[MAXLINE];
1524
374579b6
EA
1525 /*
1526 ** Check for permission to print the queue
1527 */
1528
fd178efd 1529 if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
374579b6
EA
1530 {
1531 struct stat st;
3afbc0f1
EA
1532# ifdef NGROUPS
1533 int n;
e6cb9fc4 1534 GIDSET_T gidset[NGROUPS];
3afbc0f1 1535# endif
374579b6 1536
7c8b3fd4 1537 if (stat(QueueDir, &st) < 0)
374579b6
EA
1538 {
1539 syserr("Cannot stat %s", QueueDir);
1540 return;
1541 }
3afbc0f1
EA
1542# ifdef NGROUPS
1543 n = getgroups(NGROUPS, gidset);
1544 while (--n >= 0)
1545 {
1546 if (gidset[n] == st.st_gid)
1547 break;
1548 }
ab3de76b 1549 if (n < 0 && RealGid != st.st_gid)
3afbc0f1 1550# else
fd57f063 1551 if (RealGid != st.st_gid)
3afbc0f1 1552# endif
374579b6
EA
1553 {
1554 usrerr("510 You are not permitted to see the queue");
1555 setstat(EX_NOPERM);
1556 return;
1557 }
1558 }
1559
64912e7e
EA
1560 /*
1561 ** Read and order the queue.
1562 */
1563
2e3062fe 1564 nrequests = orderq(TRUE);
64912e7e
EA
1565
1566 /*
1567 ** Print the work list that we have read.
1568 */
1569
1570 /* first see if there is anything */
0490b7d7 1571 if (nrequests <= 0)
64912e7e 1572 {
0490b7d7 1573 printf("Mail queue is empty\n");
64912e7e
EA
1574 return;
1575 }
1576
3620ad97 1577 CurrentLA = getla(); /* get load average */
3f9ac8ea 1578
d7b5594c 1579 printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
8a6b1962
EA
1580 if (nrequests > WorkListSize)
1581 printf(", only %d printed", WorkListSize);
f4b05990 1582 if (Verbose)
fbab5052 1583 printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
f4b05990 1584 else
fbab5052 1585 printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
64912e7e
EA
1586 for (w = WorkQ; w != NULL; w = w->w_next)
1587 {
1588 struct stat st;
0490b7d7 1589 auto time_t submittime = 0;
73af81f9 1590 long dfsize;
c2bdb1dd 1591 int flags = 0;
68d9129a 1592 int qfver;
0c6ce473 1593 char statmsg[MAXLINE];
8446c922 1594 char bodytype[MAXNAME + 1];
64912e7e 1595
4ba6a6f4 1596 printf("%8s", w->w_name + 2);
560a80d9
EA
1597 f = fopen(w->w_name, "r");
1598 if (f == NULL)
1599 {
4ba6a6f4 1600 printf(" (job completed)\n");
560a80d9
EA
1601 errno = 0;
1602 continue;
1603 }
73af81f9
EA
1604 w->w_name[0] = 'd';
1605 if (stat(w->w_name, &st) >= 0)
1606 dfsize = st.st_size;
1607 else
1608 dfsize = -1;
a9ca3259 1609 if (w->w_lock)
0490b7d7 1610 printf("*");
abccefc9 1611 else if (shouldqueue(w->w_pri, w->w_ctime))
2e3062fe 1612 printf("X");
0490b7d7
EA
1613 else
1614 printf(" ");
1615 errno = 0;
560a80d9 1616
0c6ce473 1617 statmsg[0] = bodytype[0] = '\0';
68d9129a 1618 qfver = 0;
64912e7e
EA
1619 while (fgets(buf, sizeof buf, f) != NULL)
1620 {
22293c34 1621 register int i;
c2bdb1dd 1622 register char *p;
22293c34 1623
64912e7e
EA
1624 fixcrlf(buf, TRUE);
1625 switch (buf[0])
1626 {
68d9129a
EA
1627 case 'V': /* queue file version */
1628 qfver = atoi(&buf[1]);
1629 break;
1630
baa0c390 1631 case 'M': /* error message */
0c6ce473
EA
1632 if ((i = strlen(&buf[1])) >= sizeof statmsg)
1633 i = sizeof statmsg - 1;
1634 bcopy(&buf[1], statmsg, i);
1635 statmsg[i] = '\0';
baa0c390
EA
1636 break;
1637
96bfbc2c
EA
1638 case 'B': /* body type */
1639 if ((i = strlen(&buf[1])) >= sizeof bodytype)
1640 i = sizeof bodytype - 1;
1641 bcopy(&buf[1], bodytype, i);
1642 bodytype[i] = '\0';
1643 break;
1644
64912e7e 1645 case 'S': /* sender name */
f4b05990 1646 if (Verbose)
c2bdb1dd
EA
1647 printf("%8ld %10ld%c%.12s %.38s",
1648 dfsize,
1649 w->w_pri,
1650 bitset(EF_WARNING, flags) ? '+' : ' ',
1651 ctime(&submittime) + 4,
f4b05990
EA
1652 &buf[1]);
1653 else
1654 printf("%8ld %.16s %.45s", dfsize,
1655 ctime(&submittime), &buf[1]);
0c6ce473 1656 if (statmsg[0] != '\0' || bodytype[0] != '\0')
96bfbc2c
EA
1657 {
1658 printf("\n %10.10s", bodytype);
0c6ce473
EA
1659 if (statmsg[0] != '\0')
1660 printf(" (%.60s)", statmsg);
96bfbc2c 1661 }
64912e7e 1662 break;
3620ad97 1663
3fbc69d6 1664 case 'C': /* controlling user */
d2213d6c 1665 if (Verbose)
fbab5052
EA
1666 printf("\n\t\t\t\t (---%.34s---)",
1667 &buf[1]);
3fbc69d6 1668 break;
64912e7e
EA
1669
1670 case 'R': /* recipient name */
68d9129a
EA
1671 p = &buf[1];
1672 if (qfver >= 1)
1673 {
1674 p = strchr(p, ':');
1675 if (p == NULL)
1676 break;
1677 p++;
1678 }
f4b05990 1679 if (Verbose)
68d9129a 1680 printf("\n\t\t\t\t\t %.38s", p);
f4b05990 1681 else
68d9129a 1682 printf("\n\t\t\t\t %.45s", p);
64912e7e
EA
1683 break;
1684
1685 case 'T': /* creation time */
2e3062fe 1686 submittime = atol(&buf[1]);
0490b7d7
EA
1687 break;
1688
c2bdb1dd
EA
1689 case 'F': /* flag bits */
1690 for (p = &buf[1]; *p != '\0'; p++)
1691 {
1692 switch (*p)
1693 {
1694 case 'w':
1695 flags |= EF_WARNING;
1696 break;
1697 }
1698 }
64912e7e
EA
1699 }
1700 }
0490b7d7
EA
1701 if (submittime == (time_t) 0)
1702 printf(" (no control file)");
64912e7e 1703 printf("\n");
0e306e7f 1704 (void) fclose(f);
64912e7e
EA
1705 }
1706}
884a20cb 1707
f3d8f6d6 1708# endif /* QUEUE */
560a80d9
EA
1709\f/*
1710** QUEUENAME -- build a file name in the queue directory for this envelope.
1711**
1712** Assigns an id code if one does not already exist.
1713** This code is very careful to avoid trashing existing files
1714** under any circumstances.
560a80d9
EA
1715**
1716** Parameters:
1717** e -- envelope to build it in/from.
1718** type -- the file type, used as the first character
1719** of the file name.
1720**
1721** Returns:
1722** a pointer to the new file name (in a static buffer).
1723**
1724** Side Effects:
3620ad97
EA
1725** If no id code is already assigned, queuename will
1726** assign an id code, create a qf file, and leave a
1727** locked, open-for-write file pointer in the envelope.
560a80d9
EA
1728*/
1729
1730char *
1731queuename(e, type)
1732 register ENVELOPE *e;
ef3bc6b1 1733 int type;
560a80d9 1734{
560a80d9 1735 static int pid = -1;
e3bb0d32
EA
1736 static char c0;
1737 static char c1;
1738 static char c2;
fbab5052
EA
1739 time_t now;
1740 struct tm *tm;
8446c922 1741 static char buf[MAXNAME + 1];
560a80d9
EA
1742
1743 if (e->e_id == NULL)
1744 {
1745 char qf[20];
560a80d9
EA
1746
1747 /* find a unique id */
1748 if (pid != getpid())
1749 {
1750 /* new process -- start back at "AA" */
1751 pid = getpid();
fbab5052
EA
1752 now = curtime();
1753 tm = localtime(&now);
1754 c0 = 'A' + tm->tm_hour;
560a80d9
EA
1755 c1 = 'A';
1756 c2 = 'A' - 1;
1757 }
fbab5052 1758 (void) sprintf(qf, "qf%cAA%05d", c0, pid);
560a80d9
EA
1759
1760 while (c1 < '~' || c2 < 'Z')
1761 {
1762 int i;
1763
1764 if (c2 >= 'Z')
1765 {
1766 c1++;
1767 c2 = 'A' - 1;
1768 }
fbab5052
EA
1769 qf[3] = c1;
1770 qf[4] = ++c2;
560a80d9 1771 if (tTd(7, 20))
3f9ac8ea 1772 printf("queuename: trying \"%s\"\n", qf);
560a80d9 1773
3f9ac8ea 1774 i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
3620ad97
EA
1775 if (i < 0)
1776 {
1777 if (errno == EEXIST)
1778 continue;
82530719
EA
1779 syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
1780 qf, QueueDir, geteuid());
3620ad97
EA
1781 exit(EX_UNAVAILABLE);
1782 }
71936fbe 1783 if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB))
3620ad97
EA
1784 {
1785 e->e_lockfp = fdopen(i, "w");
bb09c502 1786 break;
3f9ac8ea 1787 }
3620ad97
EA
1788
1789 /* a reader got the file; abandon it and try again */
1790 (void) close(i);
560a80d9
EA
1791 }
1792 if (c1 >= '~' && c2 >= 'Z')
1793 {
82530719
EA
1794 syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
1795 qf, QueueDir, geteuid());
560a80d9
EA
1796 exit(EX_OSERR);
1797 }
1798 e->e_id = newstr(&qf[2]);
1799 define('i', e->e_id, e);
560a80d9
EA
1800 if (tTd(7, 1))
1801 printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
eead656c
EA
1802 if (tTd(7, 9))
1803 {
1804 printf(" lockfd=");
1805 dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
1806 }
560a80d9 1807# ifdef LOG
68f7099c 1808 if (LogLevel > 93)
560a80d9 1809 syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
f3d8f6d6 1810# endif /* LOG */
560a80d9
EA
1811 }
1812
1813 if (type == '\0')
1814 return (NULL);
1815 (void) sprintf(buf, "%cf%s", type, e->e_id);
560a80d9
EA
1816 if (tTd(7, 2))
1817 printf("queuename: %s\n", buf);
560a80d9
EA
1818 return (buf);
1819}
1820\f/*
1821** UNLOCKQUEUE -- unlock the queue entry for a specified envelope
1822**
1823** Parameters:
1824** e -- the envelope to unlock.
1825**
1826** Returns:
1827** none
1828**
1829** Side Effects:
1830** unlocks the queue for `e'.
1831*/
1832
179d940c 1833void
560a80d9
EA
1834unlockqueue(e)
1835 ENVELOPE *e;
1836{
bc854e30
EA
1837 if (tTd(51, 4))
1838 printf("unlockqueue(%s)\n", e->e_id);
1839
3620ad97
EA
1840 /* if there is a lock file in the envelope, close it */
1841 if (e->e_lockfp != NULL)
bc854e30 1842 xfclose(e->e_lockfp, "unlockqueue", e->e_id);
3620ad97
EA
1843 e->e_lockfp = NULL;
1844
32061c38
EA
1845 /* don't create a queue id if we don't already have one */
1846 if (e->e_id == NULL)
1847 return;
1848
560a80d9 1849 /* remove the transcript */
560a80d9 1850# ifdef LOG
68f7099c 1851 if (LogLevel > 87)
560a80d9 1852 syslog(LOG_DEBUG, "%s: unlock", e->e_id);
f3d8f6d6 1853# endif /* LOG */
bc854e30 1854 if (!tTd(51, 104))
560a80d9
EA
1855 xunlink(queuename(e, 'x'));
1856
560a80d9 1857}
3fbc69d6 1858\f/*
d2213d6c 1859** SETCTLUSER -- create a controlling address
3fbc69d6 1860**
d2213d6c
EA
1861** Create a fake "address" given only a local login name; this is
1862** used as a "controlling user" for future recipient addresses.
3fbc69d6
KB
1863**
1864** Parameters:
d2213d6c 1865** user -- the user name of the controlling user.
3fbc69d6
KB
1866**
1867** Returns:
d2213d6c 1868** An address descriptor for the controlling user.
3fbc69d6
KB
1869**
1870** Side Effects:
1871** none.
1872*/
1873
d2213d6c
EA
1874ADDRESS *
1875setctluser(user)
1876 char *user;
3fbc69d6 1877{
d2213d6c 1878 register ADDRESS *a;
3fbc69d6 1879 struct passwd *pw;
9cdb0b30 1880 char *p;
3fbc69d6
KB
1881
1882 /*
d2213d6c 1883 ** See if this clears our concept of controlling user.
3fbc69d6
KB
1884 */
1885
c6c403f7
EA
1886 if (user == NULL || *user == '\0')
1887 return NULL;
3fbc69d6
KB
1888
1889 /*
d2213d6c 1890 ** Set up addr fields for controlling user.
3fbc69d6
KB
1891 */
1892
d2213d6c
EA
1893 a = (ADDRESS *) xalloc(sizeof *a);
1894 bzero((char *) a, sizeof *a);
9cdb0b30
EA
1895
1896 p = strchr(user, ':');
1897 if (p != NULL)
1898 *p++ = '\0';
5b7a2dfe 1899 if (*user != '\0' && (pw = sm_getpwnam(user)) != NULL)
3fbc69d6 1900 {
c841d671
EA
1901 if (strcmp(pw->pw_dir, "/") == 0)
1902 a->q_home = "";
1903 else
1904 a->q_home = newstr(pw->pw_dir);
3fbc69d6
KB
1905 a->q_uid = pw->pw_uid;
1906 a->q_gid = pw->pw_gid;
f7894324 1907 a->q_flags |= QGOODUID;
3fbc69d6 1908 }
66d16835
EA
1909
1910 if (*user != '\0')
1911 a->q_user = newstr(user);
1912 else if (p != NULL)
1913 a->q_user = newstr(p);
3fbc69d6 1914 else
6e99f903 1915 a->q_user = newstr(DefUser);
3fbc69d6 1916
f7894324 1917 a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */
d0a69620 1918 a->q_mailer = LocalMailer;
9cdb0b30
EA
1919 if (p == NULL)
1920 a->q_paddr = a->q_user;
1921 else
1922 a->q_paddr = newstr(p);
d2213d6c 1923 return a;
3fbc69d6 1924}
99fd9645
EA
1925\f/*
1926** LOSEQFILE -- save the qf as Qf and try to let someone know
1927**
1928** Parameters:
1929** e -- the envelope (e->e_id will be used).
1930** why -- reported to whomever can hear.
1931**
1932** Returns:
1933** none.
1934*/
1935
1936void
1937loseqfile(e, why)
1938 register ENVELOPE *e;
1939 char *why;
1940{
6502fd93 1941 char *p;
99fd9645
EA
1942 char buf[40];
1943
1944 if (e == NULL || e->e_id == NULL)
1945 return;
1946 if (strlen(e->e_id) > sizeof buf - 4)
1947 return;
1948 strcpy(buf, queuename(e, 'q'));
6502fd93
EA
1949 p = queuename(e, 'Q');
1950 if (rename(buf, p) < 0)
1951 syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid());
99fd9645 1952#ifdef LOG
6502fd93
EA
1953 else if (LogLevel > 0)
1954 syslog(LOG_ALERT, "Losing %s: %s", buf, why);
99fd9645
EA
1955#endif
1956}