count children. Someday we might reject connections on this basis.
[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
4fdb944e 13static char sccsid[] = "@(#)queue.c 8.87 (Berkeley) %G% (with queueing)";
bee79b64 14#else
4fdb944e 15static char sccsid[] = "@(#)queue.c 8.87 (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);
4fdb944e
EA
513#else
514 CurChildren++;
f3d8f6d6 515#endif /* SIGCHLD */
c4442979 516 if (QueueIntvl != 0)
611b763d 517 (void) setevent(QueueIntvl, runqueue, TRUE);
2cf55cb7
EA
518 return;
519 }
6d06102a 520 /* child -- double fork */
c8ad461a 521#ifndef SIGCHLD
6d06102a
EA
522 if (fork() != 0)
523 exit(EX_OK);
f3d8f6d6 524#else /* SIGCHLD */
39270cfd 525 (void) setsignal(SIGCHLD, SIG_DFL);
f3d8f6d6 526#endif /* SIGCHLD */
b6dffdf5 527 }
2e3062fe 528
3f9ac8ea 529 setproctitle("running queue: %s", QueueDir);
2e3062fe 530
36a4e219 531# ifdef LOG
68f7099c 532 if (LogLevel > 69)
ca4d0c0b
EA
533 syslog(LOG_DEBUG, "runqueue %s, pid=%d, forkflag=%d",
534 QueueDir, getpid(), forkflag);
f3d8f6d6 535# endif /* LOG */
81b7d258 536
eb8af3ce
EA
537 /*
538 ** Release any resources used by the daemon code.
539 */
540
541# ifdef DAEMON
542 clrdaemon();
f3d8f6d6 543# endif /* DAEMON */
eb8af3ce 544
6b951123
EA
545 /* force it to run expensive jobs */
546 NoConnect = FALSE;
547
ca4d0c0b
EA
548 /*
549 ** Create ourselves an envelope
550 */
551
552 CurEnv = &QueueEnvelope;
fda58daa 553 e = newenvelope(&QueueEnvelope, CurEnv);
ca4d0c0b
EA
554 e->e_flags = BlankEnvelope.e_flags;
555
a78155b0
EA
556 /*
557 ** Make sure the alias database is open.
558 */
559
36b09297 560 initmaps(FALSE, e);
a78155b0 561
b6dffdf5
EA
562 /*
563 ** Start making passes through the queue.
564 ** First, read and sort the entire queue.
565 ** Then, process the work in that order.
566 ** But if you take too long, start over.
b6dffdf5 567 */
81b7d258 568
6d06102a 569 /* order the existing work requests */
d3a63a56 570 njobs = orderq(FALSE);
291fa573 571
6d06102a
EA
572 /* process them once at a time */
573 while (WorkQ != NULL)
2cf55cb7 574 {
6d06102a 575 WORK *w = WorkQ;
2cf55cb7 576
6d06102a 577 WorkQ = WorkQ->w_next;
a7dc53bd
EA
578
579 /*
580 ** Ignore jobs that are too expensive for the moment.
581 */
582
d3a63a56 583 sequenceno++;
a7dc53bd
EA
584 if (shouldqueue(w->w_pri, w->w_ctime))
585 {
586 if (Verbose)
d3a63a56
EA
587 printf("\nSkipping %s (sequence %d of %d)\n",
588 w->w_name + 2, sequenceno, njobs);
a7dc53bd 589 }
1c791deb
EA
590 else
591 {
d0268270
EA
592 pid_t pid;
593 extern pid_t dowork();
594
d3a63a56
EA
595 if (Verbose)
596 printf("\nRunning %s (sequence %d of %d)\n",
597 w->w_name + 2, sequenceno, njobs);
d0268270
EA
598 pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
599 errno = 0;
a9927082
EA
600 if (pid != 0)
601 (void) waitfor(pid);
1c791deb 602 }
6d06102a 603 free(w->w_name);
a9ca3259
EA
604 if (w->w_host)
605 free(w->w_host);
6d06102a 606 free((char *) w);
2cf55cb7 607 }
37ea3cbf
EA
608
609 /* exit without the usual cleanup */
4e20c4d2
EA
610 e->e_id = NULL;
611 finis();
aba51985
EA
612}
613\f/*
81b7d258
EA
614** ORDERQ -- order the work queue.
615**
616** Parameters:
2e3062fe
EA
617** doall -- if set, include everything in the queue (even
618** the jobs that cannot be run because the load
619** average is too high). Otherwise, exclude those
620** jobs.
81b7d258
EA
621**
622** Returns:
e65b95c4
EA
623** The number of request in the queue (not necessarily
624** the number of requests in WorkQ however).
81b7d258
EA
625**
626** Side Effects:
627** Sets WorkQ to the queue of available work, in order.
628*/
629
4e969be0
EA
630# define NEED_P 001
631# define NEED_T 002
d6c28d1a
EA
632# define NEED_R 004
633# define NEED_S 010
81b7d258 634
8a6b1962
EA
635static WORK *WorkList = NULL;
636static int WorkListSize = 0;
637
179d940c 638int
38d3b461
EA
639# ifndef DIR
640# define DIR FILE
641# define direct dir
642# define opendir(d) fopen(d, "r")
07a8f29b 643# define readdir(f) ((fread(&dbuf, sizeof dbuf, 1, f) > 0) ? &dbuf : 0)
38d3b461
EA
644static struct dir dbuf;
645# define closedir(f) fclose(f)
646# endif DIR
647
2e3062fe
EA
648orderq(doall)
649 bool doall;
81b7d258 650{
9114f86c 651 register struct dirent *d;
81b7d258 652 register WORK *w;
ccd1d833 653 DIR *f;
81b7d258 654 register int i;
0490b7d7 655 int wn = -1;
a9ca3259 656 int wc;
81b7d258 657
d6c28d1a
EA
658 if (tTd(41, 1))
659 {
660 printf("orderq:\n");
661 if (QueueLimitId != NULL)
662 printf("\tQueueLimitId = %s\n", QueueLimitId);
663 if (QueueLimitSender != NULL)
664 printf("\tQueueLimitSender = %s\n", QueueLimitSender);
665 if (QueueLimitRecipient != NULL)
666 printf("\tQueueLimitRecipient = %s\n", QueueLimitRecipient);
667 }
668
81b7d258
EA
669 /* clear out old WorkQ */
670 for (w = WorkQ; w != NULL; )
671 {
672 register WORK *nw = w->w_next;
673
674 WorkQ = nw;
675 free(w->w_name);
a9ca3259
EA
676 if (w->w_host)
677 free(w->w_host);
81b7d258
EA
678 free((char *) w);
679 w = nw;
680 }
681
682 /* open the queue directory */
6bbaf971 683 f = opendir(".");
81b7d258
EA
684 if (f == NULL)
685 {
6bbaf971 686 syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
0490b7d7 687 return (0);
81b7d258
EA
688 }
689
690 /*
691 ** Read the work directory.
692 */
693
0490b7d7 694 while ((d = readdir(f)) != NULL)
81b7d258 695 {
81b7d258 696 FILE *cf;
bb530db4 697 register char *p;
8446c922 698 char lbuf[MAXNAME + 1];
d6c28d1a 699 extern bool strcontainedin();
81b7d258
EA
700
701 /* is this an interesting entry? */
07a8f29b
EA
702 if (d->d_ino == 0)
703 continue;
704# ifdef DEBUG
705 if (tTd(40, 10))
706 printf("orderq: %12s\n", d->d_name);
707# endif DEBUG
2cce0c26 708 if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
81b7d258
EA
709 continue;
710
d6c28d1a
EA
711 if (QueueLimitId != NULL &&
712 !strcontainedin(QueueLimitId, d->d_name))
713 continue;
714
6502fd93 715#ifdef PICKY_QF_NAME_CHECK
45ce4b34
EA
716 /*
717 ** Check queue name for plausibility. This handles
718 ** both old and new type ids.
719 */
720
bb530db4
EA
721 p = d->d_name + 2;
722 if (isupper(p[0]) && isupper(p[2]))
723 p += 3;
724 else if (isupper(p[1]))
725 p += 2;
726 else
727 p = d->d_name;
728 for (i = 0; isdigit(*p); p++)
729 i++;
730 if (i < 5 || *p != '\0')
68f7099c
EA
731 {
732 if (Verbose)
733 printf("orderq: bogus qf name %s\n", d->d_name);
6502fd93
EA
734# ifdef LOG
735 if (LogLevel > 0)
736 syslog(LOG_ALERT, "orderq: bogus qf name %s",
68f7099c 737 d->d_name);
6502fd93 738# endif
2604d017 739 if (strlen(d->d_name) > (SIZE_T) MAXNAME)
8446c922 740 d->d_name[MAXNAME] = '\0';
68f7099c
EA
741 strcpy(lbuf, d->d_name);
742 lbuf[0] = 'Q';
743 (void) rename(d->d_name, lbuf);
744 continue;
745 }
6502fd93 746#endif
68f7099c 747
6502fd93 748 /* open control file (if not too many files) */
28b647b8
EA
749 if (++wn > MaxQueueRun && MaxQueueRun > 0)
750 {
751# ifdef LOG
752 if (wn == MaxQueueRun + 1 && LogLevel > 0)
753 syslog(LOG_ALERT, "WorkList for %s maxed out at %d",
754 QueueDir, MaxQueueRun);
755# endif
756 continue;
757 }
758 if (wn >= WorkListSize)
8a6b1962 759 {
179d940c
EA
760 extern void grow_wlist __P((void));
761
8a6b1962
EA
762 grow_wlist();
763 if (wn >= WorkListSize)
764 continue;
765 }
d6c28d1a 766
6bbaf971 767 cf = fopen(d->d_name, "r");
81b7d258
EA
768 if (cf == NULL)
769 {
91f69adf
EA
770 /* this may be some random person sending hir msgs */
771 /* syserr("orderq: cannot open %s", cbuf); */
bd0712bd
EA
772 if (tTd(41, 2))
773 printf("orderq: cannot open %s (%d)\n",
774 d->d_name, errno);
91f69adf 775 errno = 0;
bd0712bd 776 wn--;
81b7d258
EA
777 continue;
778 }
8a6b1962 779 w = &WorkList[wn];
4e969be0 780 w->w_name = newstr(d->d_name);
a9ca3259
EA
781 w->w_host = NULL;
782 w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB);
81b7d258 783
4ff794a3 784 /* make sure jobs in creation don't clog queue */
4e969be0
EA
785 w->w_pri = 0x7fffffff;
786 w->w_ctime = 0;
4ff794a3 787
81b7d258 788 /* extract useful information */
4e969be0 789 i = NEED_P | NEED_T;
d6c28d1a
EA
790 if (QueueLimitSender != NULL)
791 i |= NEED_S;
92830179 792 if (QueueSortOrder == QS_BYHOST || QueueLimitRecipient != NULL)
d6c28d1a 793 i |= NEED_R;
4e969be0 794 while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
81b7d258 795 {
d6c28d1a 796 extern bool strcontainedin();
8ff78b51 797
2e3062fe 798 switch (lbuf[0])
81b7d258 799 {
2e3062fe 800 case 'P':
4e969be0
EA
801 w->w_pri = atol(&lbuf[1]);
802 i &= ~NEED_P;
2e3062fe 803 break;
f746582a
EA
804
805 case 'T':
4e969be0
EA
806 w->w_ctime = atol(&lbuf[1]);
807 i &= ~NEED_T;
f746582a 808 break;
d6c28d1a
EA
809
810 case 'R':
a9ca3259
EA
811 if (w->w_host == NULL &&
812 (p = strrchr(&lbuf[1], '@')) != NULL)
813 w->w_host = newstr(&p[1]);
814 if (QueueLimitRecipient == NULL ||
d6c28d1a
EA
815 strcontainedin(QueueLimitRecipient, &lbuf[1]))
816 i &= ~NEED_R;
817 break;
818
819 case 'S':
820 if (QueueLimitSender != NULL &&
821 strcontainedin(QueueLimitSender, &lbuf[1]))
822 i &= ~NEED_S;
823 break;
81b7d258
EA
824 }
825 }
81b7d258 826 (void) fclose(cf);
4bc44f60 827
d6c28d1a
EA
828 if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
829 bitset(NEED_R|NEED_S, i))
4bc44f60
EA
830 {
831 /* don't even bother sorting this job in */
a9ca3259
EA
832 free(w->w_name);
833 if (w->w_host)
834 free(w->w_host);
4bc44f60
EA
835 wn--;
836 }
81b7d258 837 }
ccd1d833 838 (void) closedir(f);
bd0712bd 839 wn++;
81b7d258 840
8a6b1962 841 wc = min(wn, WorkListSize);
a9ca3259 842
92830179 843 if (QueueSortOrder == QS_BYHOST)
a9ca3259
EA
844 {
845 extern workcmpf1();
846 extern workcmpf2();
847
848 /*
849 ** Sort the work directory for the first time,
850 ** based on host name, lock status, and priority.
851 */
852
8a6b1962 853 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1);
a9ca3259
EA
854
855 /*
856 ** If one message to host is locked, "lock" all messages
857 ** to that host.
858 */
859
860 i = 0;
861 while (i < wc)
862 {
8a6b1962 863 if (!WorkList[i].w_lock)
a9ca3259
EA
864 {
865 i++;
866 continue;
867 }
8a6b1962 868 w = &WorkList[i];
a9ca3259
EA
869 while (++i < wc)
870 {
8a6b1962 871 if (WorkList[i].w_host == NULL &&
a9ca3259 872 w->w_host == NULL)
8a6b1962
EA
873 WorkList[i].w_lock = TRUE;
874 else if (WorkList[i].w_host != NULL &&
a9ca3259 875 w->w_host != NULL &&
8a6b1962
EA
876 strcmp(WorkList[i].w_host, w->w_host) == 0)
877 WorkList[i].w_lock = TRUE;
a9ca3259
EA
878 else
879 break;
880 }
881 }
882
883 /*
884 ** Sort the work directory for the second time,
885 ** based on lock status, host name, and priority.
886 */
887
8a6b1962 888 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2);
a9ca3259 889 }
92830179
EA
890 else
891 {
892 extern workcmpf0();
893
894 /*
895 ** Simple sort based on queue priority only.
896 */
897
8a6b1962 898 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0);
92830179 899 }
81b7d258
EA
900
901 /*
902 ** Convert the work list into canonical form.
7338e3d4 903 ** Should be turning it into a list of envelopes here perhaps.
81b7d258
EA
904 */
905
a0225d08 906 WorkQ = NULL;
a9ca3259 907 for (i = wc; --i >= 0; )
81b7d258
EA
908 {
909 w = (WORK *) xalloc(sizeof *w);
8a6b1962
EA
910 w->w_name = WorkList[i].w_name;
911 w->w_host = WorkList[i].w_host;
912 w->w_lock = WorkList[i].w_lock;
913 w->w_pri = WorkList[i].w_pri;
914 w->w_ctime = WorkList[i].w_ctime;
a0225d08
EA
915 w->w_next = WorkQ;
916 WorkQ = w;
81b7d258 917 }
8a6b1962
EA
918 free(WorkList);
919 WorkList = NULL;
81b7d258 920
9678c96d 921 if (tTd(40, 1))
81b7d258
EA
922 {
923 for (w = WorkQ; w != NULL; w = w->w_next)
9ccf54c4 924 printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
81b7d258 925 }
0490b7d7 926
bd0712bd 927 return (wn);
81b7d258 928}
28b647b8
EA
929\f/*
930** GROW_WLIST -- make the work list larger
931**
932** Parameters:
933** none.
934**
935** Returns:
936** none.
937**
938** Side Effects:
939** Adds another QUEUESEGSIZE entries to WorkList if possible.
940** It can fail if there isn't enough memory, so WorkListSize
941** should be checked again upon return.
942*/
8a6b1962 943
179d940c 944void
8a6b1962
EA
945grow_wlist()
946{
947 if (tTd(41, 1))
948 printf("grow_wlist: WorkListSize=%d\n", WorkListSize);
28b647b8 949 if (WorkList == NULL)
8a6b1962
EA
950 {
951 WorkList = (WORK *) xalloc(sizeof(WORK) * (QUEUESEGSIZE + 1));
952 WorkListSize = QUEUESEGSIZE;
953 }
954 else
955 {
956 int newsize = WorkListSize + QUEUESEGSIZE;
957 WORK *newlist = (WORK *) realloc((char *)WorkList,
958 (unsigned)sizeof(WORK) * (newsize + 1));
959
960 if (newlist != NULL)
961 {
962 WorkListSize = newsize;
963 WorkList = newlist;
964# ifdef LOG
965 if (LogLevel > 1)
966 {
967 syslog(LOG_NOTICE, "grew WorkList for %s to %d",
968 QueueDir, WorkListSize);
969 }
970 }
971 else if (LogLevel > 0)
972 {
973 syslog(LOG_ALERT, "FAILED to grow WorkList for %s to %d",
974 QueueDir, newsize);
975# endif
976 }
977 }
978 if (tTd(41, 1))
979 printf("grow_wlist: WorkListSize now %d\n", WorkListSize);
980}
81b7d258 981\f/*
a9ca3259 982** WORKCMPF0 -- simple priority-only compare function.
81b7d258
EA
983**
984** Parameters:
985** a -- the first argument.
986** b -- the second argument.
987**
988** Returns:
a0225d08
EA
989** -1 if a < b
990** 0 if a == b
991** +1 if a > b
81b7d258
EA
992**
993** Side Effects:
994** none.
995*/
996
179d940c 997int
a9ca3259 998workcmpf0(a, b)
9ccf54c4
EA
999 register WORK *a;
1000 register WORK *b;
81b7d258 1001{
abccefc9
EA
1002 long pa = a->w_pri;
1003 long pb = b->w_pri;
2e3062fe
EA
1004
1005 if (pa == pb)
a9ca3259 1006 return 0;
2e3062fe 1007 else if (pa > pb)
a9ca3259 1008 return 1;
a0225d08 1009 else
a9ca3259
EA
1010 return -1;
1011}
1012\f/*
1013** WORKCMPF1 -- first compare function for ordering work based on host name.
1014**
1015** Sorts on host name, lock status, and priority in that order.
1016**
1017** Parameters:
1018** a -- the first argument.
1019** b -- the second argument.
1020**
1021** Returns:
1022** <0 if a < b
1023** 0 if a == b
1024** >0 if a > b
1025**
1026** Side Effects:
1027** none.
1028*/
1029
179d940c 1030int
a9ca3259
EA
1031workcmpf1(a, b)
1032 register WORK *a;
1033 register WORK *b;
1034{
1035 int i;
1036
1037 /* host name */
1038 if (a->w_host != NULL && b->w_host == NULL)
1039 return 1;
1040 else if (a->w_host == NULL && b->w_host != NULL)
1041 return -1;
1042 if (a->w_host != NULL && b->w_host != NULL &&
1043 (i = strcmp(a->w_host, b->w_host)))
1044 return i;
1045
1046 /* lock status */
1047 if (a->w_lock != b->w_lock)
1048 return b->w_lock - a->w_lock;
1049
1050 /* job priority */
1051 return a->w_pri - b->w_pri;
1052}
1053\f/*
1054** WORKCMPF2 -- second compare function for ordering work based on host name.
1055**
1056** Sorts on lock status, host name, and priority in that order.
1057**
1058** Parameters:
1059** a -- the first argument.
1060** b -- the second argument.
1061**
1062** Returns:
1063** <0 if a < b
1064** 0 if a == b
1065** >0 if a > b
1066**
1067** Side Effects:
1068** none.
1069*/
1070
179d940c 1071int
a9ca3259
EA
1072workcmpf2(a, b)
1073 register WORK *a;
1074 register WORK *b;
1075{
1076 int i;
1077
1078 /* lock status */
1079 if (a->w_lock != b->w_lock)
1080 return a->w_lock - b->w_lock;
1081
1082 /* host name */
1083 if (a->w_host != NULL && b->w_host == NULL)
1084 return 1;
1085 else if (a->w_host == NULL && b->w_host != NULL)
1086 return -1;
1087 if (a->w_host != NULL && b->w_host != NULL &&
1088 (i = strcmp(a->w_host, b->w_host)))
1089 return i;
1090
1091 /* job priority */
1092 return a->w_pri - b->w_pri;
81b7d258
EA
1093}
1094\f/*
1095** DOWORK -- do a work request.
1096**
1097** Parameters:
a7dc53bd
EA
1098** id -- the ID of the job to run.
1099** forkflag -- if set, run this in background.
f5303697
EA
1100** requeueflag -- if set, reinstantiate the queue quickly.
1101** This is used when expanding aliases in the queue.
8d00c219
EA
1102** If forkflag is also set, it doesn't wait for the
1103** child.
a7dc53bd 1104** e - the envelope in which to run it.
81b7d258
EA
1105**
1106** Returns:
d0268270 1107** process id of process that is running the queue job.
81b7d258
EA
1108**
1109** Side Effects:
1110** The work request is satisfied if possible.
1111*/
1112
d0268270 1113pid_t
f5303697 1114dowork(id, forkflag, requeueflag, e)
a7dc53bd
EA
1115 char *id;
1116 bool forkflag;
f5303697 1117 bool requeueflag;
a4076aed 1118 register ENVELOPE *e;
81b7d258 1119{
d0268270 1120 register pid_t pid;
3620ad97 1121 extern bool readqf();
81b7d258 1122
9678c96d 1123 if (tTd(40, 1))
a7dc53bd 1124 printf("dowork(%s)\n", id);
81b7d258 1125
2e3062fe
EA
1126 /*
1127 ** Fork for work.
1128 */
1129
a7dc53bd 1130 if (forkflag)
2e3062fe 1131 {
d0268270
EA
1132 pid = fork();
1133 if (pid < 0)
2e3062fe
EA
1134 {
1135 syserr("dowork: cannot fork");
d0268270 1136 return 0;
2e3062fe 1137 }
5cf47fbf
EA
1138 else if (pid > 0)
1139 {
1140 /* parent -- clean out connection cache */
1141 mci_flush(FALSE, NULL);
1142 }
2e3062fe
EA
1143 }
1144 else
1145 {
d0268270 1146 pid = 0;
2e3062fe
EA
1147 }
1148
d0268270 1149 if (pid == 0)
81b7d258
EA
1150 {
1151 /*
1152 ** CHILD
6bbaf971
EA
1153 ** Lock the control file to avoid duplicate deliveries.
1154 ** Then run the file as though we had just read it.
68f0b54c
EA
1155 ** We save an idea of the temporary name so we
1156 ** can recover on interrupt.
81b7d258
EA
1157 */
1158
9416f3a0 1159 /* set basic modes, etc. */
37eaaadb 1160 (void) alarm(0);
a4076aed 1161 clearenvelope(e, FALSE);
164f3011 1162 e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
8c8e8e94 1163 e->e_errormode = EM_MAIL;
a7dc53bd 1164 e->e_id = id;
48cb554d 1165 GrabTo = UseErrorsTo = FALSE;
a9927082 1166 ExitStat = EX_OK;
47e2f242 1167 if (forkflag)
164f3011 1168 {
d0268270 1169 disconnect(1, e);
164f3011
EA
1170 OpMode = MD_DELIVER;
1171 }
36a4e219 1172# ifdef LOG
68f7099c 1173 if (LogLevel > 76)
a4076aed 1174 syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id,
291fa573 1175 getpid());
f3d8f6d6 1176# endif /* LOG */
9416f3a0
EA
1177
1178 /* don't use the headers from sendmail.cf... */
a4076aed 1179 e->e_header = NULL;
9416f3a0 1180
3620ad97 1181 /* read the queue control file -- return if locked */
63a34fcd 1182 if (!readqf(e))
dd1fe05b 1183 {
a7dc53bd
EA
1184 if (tTd(40, 4))
1185 printf("readqf(%s) failed\n", e->e_id);
1186 if (forkflag)
2e3062fe
EA
1187 exit(EX_OK);
1188 else
a9927082 1189 return 0;
dd1fe05b 1190 }
dd1fe05b 1191
a4076aed 1192 e->e_flags |= EF_INQUEUE;
dd1fe05b 1193
3df50535 1194 /* if this has been tried recently, let it be */
1b9b1753 1195 if (e->e_ntries > 0 && (curtime() - e->e_dtime) < MinQueueAge)
3df50535
EA
1196 {
1197 char *howlong = pintvl(curtime() - e->e_dtime, TRUE);
f5303697 1198
3df50535
EA
1199 e->e_flags |= EF_KEEPQUEUE;
1200 if (Verbose || tTd(40, 8))
1201 printf("%s: too young (%s)\n",
1202 e->e_id, howlong);
1203#ifdef LOG
1204 if (LogLevel > 19)
1205 syslog(LOG_DEBUG, "%s: too young (%s)",
1206 e->e_id, howlong);
1207#endif
1208 }
1209 else
1210 {
1211 eatheader(e, requeueflag);
1212
1213 if (requeueflag)
1214 queueup(e, TRUE, FALSE);
1215
1216 /* do the delivery */
1217 sendall(e, SM_DELIVER);
1218 }
dd1fe05b 1219
dd1fe05b 1220 /* finish up and exit */
a7dc53bd 1221 if (forkflag)
2e3062fe
EA
1222 finis();
1223 else
a4076aed 1224 dropenvelope(e);
81b7d258 1225 }
d0268270
EA
1226 e->e_id = NULL;
1227 return pid;
81b7d258
EA
1228}
1229\f/*
1230** READQF -- read queue file and set up environment.
1231**
1232** Parameters:
7338e3d4 1233** e -- the envelope of the job to run.
81b7d258
EA
1234**
1235** Returns:
3620ad97
EA
1236** TRUE if it successfully read the queue file.
1237** FALSE otherwise.
81b7d258
EA
1238**
1239** Side Effects:
3620ad97 1240** The queue file is returned locked.
81b7d258
EA
1241*/
1242
3620ad97 1243bool
63a34fcd 1244readqf(e)
7338e3d4 1245 register ENVELOPE *e;
81b7d258 1246{
11e3f8b5 1247 register FILE *qfp;
d2213d6c 1248 ADDRESS *ctladdr;
dcbc04c7 1249 struct stat st;
07b49560 1250 char *bp;
68d9129a
EA
1251 int qfver = 0;
1252 register char *p;
3b6c2253 1253 char *orcpt = NULL;
e678ee95 1254 char qf[20];
07b49560 1255 char buf[MAXLINE];
d2213d6c 1256 extern ADDRESS *setctluser();
99fd9645 1257 extern void loseqfile();
abae7b2d 1258 extern ADDRESS *sendto();
81b7d258 1259
81b7d258
EA
1260 /*
1261 ** Read and process the file.
1262 */
1263
e678ee95 1264 strcpy(qf, queuename(e, 'q'));
76b607b2 1265 qfp = fopen(qf, "r+");
11e3f8b5
EA
1266 if (qfp == NULL)
1267 {
a7dc53bd
EA
1268 if (tTd(40, 8))
1269 printf("readqf(%s): fopen failure (%s)\n",
1270 qf, errstring(errno));
3f9ac8ea
RA
1271 if (errno != ENOENT)
1272 syserr("readqf: no control file %s", qf);
3620ad97 1273 return FALSE;
3f9ac8ea
RA
1274 }
1275
71936fbe 1276 if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
e3778690
EA
1277 {
1278 /* being processed by another queuer */
3df50535 1279 if (Verbose || tTd(40, 8))
e3778690
EA
1280 printf("%s: locked\n", e->e_id);
1281# ifdef LOG
1282 if (LogLevel > 19)
1283 syslog(LOG_DEBUG, "%s: locked", e->e_id);
1284# endif /* LOG */
1285 (void) fclose(qfp);
1286 return FALSE;
1287 }
1288
dcbc04c7
EA
1289 /*
1290 ** Check the queue file for plausibility to avoid attacks.
1291 */
1292
1293 if (fstat(fileno(qfp), &st) < 0)
1294 {
1295 /* must have been being processed by someone else */
a7dc53bd
EA
1296 if (tTd(40, 8))
1297 printf("readqf(%s): fstat failure (%s)\n",
1298 qf, errstring(errno));
dcbc04c7
EA
1299 fclose(qfp);
1300 return FALSE;
1301 }
1302
6502fd93 1303 if (st.st_uid != geteuid() || bitset(S_IWOTH|S_IWGRP, st.st_mode))
dcbc04c7
EA
1304 {
1305# ifdef LOG
1306 if (LogLevel > 0)
1307 {
1308 syslog(LOG_ALERT, "%s: bogus queue file, uid=%d, mode=%o",
1309 e->e_id, st.st_uid, st.st_mode);
1310 }
f3d8f6d6 1311# endif /* LOG */
a7dc53bd
EA
1312 if (tTd(40, 8))
1313 printf("readqf(%s): bogus file\n", qf);
99fd9645 1314 loseqfile(e, "bogus file uid in mqueue");
e3778690 1315 fclose(qfp);
dcbc04c7
EA
1316 return FALSE;
1317 }
1318
e3778690 1319 if (st.st_size == 0)
3f9ac8ea 1320 {
e3778690
EA
1321 /* must be a bogus file -- just remove it */
1322 (void) unlink(qf);
1323 fclose(qfp);
3620ad97 1324 return FALSE;
11e3f8b5 1325 }
3f9ac8ea 1326
e3778690 1327 if (st.st_nlink == 0)
c87034b7 1328 {
e3778690
EA
1329 /*
1330 ** Race condition -- we got a file just as it was being
1331 ** unlinked. Just assume it is zero length.
1332 */
1333
c87034b7
EA
1334 fclose(qfp);
1335 return FALSE;
1336 }
1337
e3778690 1338 /* good file -- save this lock */
3620ad97
EA
1339 e->e_lockfp = qfp;
1340
3f9ac8ea 1341 /* do basic system initialization */
a4076aed 1342 initsys(e);
b276598d 1343 define('i', e->e_id, e);
3f9ac8ea 1344
560a80d9 1345 LineNumber = 0;
c6c403f7
EA
1346 e->e_flags |= EF_GLOBALERRS;
1347 OpMode = MD_DELIVER;
d2213d6c 1348 ctladdr = NULL;
bb4fde22 1349 e->e_dfino = -1;
18a81ac0 1350 e->e_msgsize = -1;
07b49560 1351 while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
81b7d258 1352 {
c2bdb1dd 1353 register char *p;
68d9129a
EA
1354 u_long qflags;
1355 ADDRESS *q;
65b5adb6 1356
795590e2 1357 if (tTd(40, 4))
07b49560
EA
1358 printf("+++++ %s\n", bp);
1359 switch (bp[0])
81b7d258 1360 {
68d9129a
EA
1361 case 'V': /* queue file version number */
1362 qfver = atoi(&bp[1]);
1363 if (qfver > QF_VERSION)
1364 {
1365 syserr("Version number in qf (%d) greater than max (%d)",
1366 qfver, QF_VERSION);
1367 }
1368 break;
1369
3fbc69d6 1370 case 'C': /* specify controlling user */
07b49560 1371 ctladdr = setctluser(&bp[1]);
3fbc69d6
KB
1372 break;
1373
3b6c2253
EA
1374 case 'Q': /* original recipient */
1375 orcpt = newstr(&bp[1]);
1376 break;
1377
81b7d258 1378 case 'R': /* specify recipient */
abae7b2d 1379 (void) sendto(&buf[1], 1, (ADDRESS *) NULL, 0);
81b7d258
EA
1380 break;
1381
4e969be0 1382 case 'E': /* specify error recipient */
b7b719e4 1383 /* no longer used */
4e969be0
EA
1384 break;
1385
81b7d258 1386 case 'H': /* header */
9905202c 1387 (void) chompheader(&bp[1], FALSE, NULL, e);
81b7d258
EA
1388 break;
1389
baa0c390 1390 case 'M': /* message */
82530719 1391 /* ignore this; we want a new message next time */
baa0c390
EA
1392 break;
1393
81b7d258 1394 case 'S': /* sender */
4a2da288 1395 setsender(newstr(&bp[1]), e, NULL, TRUE);
81b7d258
EA
1396 break;
1397
96bfbc2c
EA
1398 case 'B': /* body type */
1399 e->e_bodytype = newstr(&bp[1]);
1400 break;
1401
81b7d258 1402 case 'D': /* data file name */
18a81ac0 1403 /* obsolete -- ignore */
81b7d258
EA
1404 break;
1405
96476cab 1406 case 'T': /* init time */
07b49560 1407 e->e_ctime = atol(&bp[1]);
81b7d258
EA
1408 break;
1409
f009d24b 1410 case 'I': /* data file's inode number */
bb4fde22
EA
1411 if (e->e_dfino == -1)
1412 e->e_dfino = atol(&buf[1]);
f009d24b
EA
1413 break;
1414
1415 case 'K': /* time of last deliver attempt */
1416 e->e_dtime = atol(&buf[1]);
1417 break;
1418
1419 case 'N': /* number of delivery attempts */
1420 e->e_ntries = atoi(&buf[1]);
1421 break;
1422
aba51985 1423 case 'P': /* message priority */
07b49560 1424 e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
dd1fe05b
EA
1425 break;
1426
c2bdb1dd
EA
1427 case 'F': /* flag bits */
1428 for (p = &bp[1]; *p != '\0'; p++)
1429 {
1430 switch (*p)
1431 {
1432 case 'w': /* warning sent */
1433 e->e_flags |= EF_WARNING;
1434 break;
1435
1436 case 'r': /* response */
1437 e->e_flags |= EF_RESPONSE;
1438 break;
e3c84ea8
EA
1439
1440 case '8': /* has 8 bit data */
1441 e->e_flags |= EF_HAS8BIT;
1442 break;
c2bdb1dd
EA
1443 }
1444 }
1445 break;
1446
6da3ba01 1447 case 'Z': /* original envelope id from ESMTP */
36c7ff6a 1448 e->e_envid = newstr(&bp[1]);
6da3ba01
EA
1449 break;
1450
22293c34 1451 case '$': /* define macro */
07b49560 1452 define(bp[1], newstr(&bp[2]), e);
22293c34
EA
1453 break;
1454
2e3062fe
EA
1455 case '\0': /* blank line; ignore */
1456 break;
1457
81b7d258 1458 default:
5e90e563 1459 syserr("readqf: %s: line %d: bad line \"%s\"",
63a34fcd 1460 qf, LineNumber, bp);
8e5c6745 1461 fclose(qfp);
99fd9645 1462 loseqfile(e, "unrecognized line");
8e5c6745 1463 return FALSE;
81b7d258 1464 }
07b49560
EA
1465
1466 if (bp != buf)
1467 free(bp);
81b7d258 1468 }
7338e3d4 1469
2e3062fe
EA
1470 /*
1471 ** If we haven't read any lines, this queue file is empty.
1472 ** Arrange to remove it without referencing any null pointers.
1473 */
1474
1475 if (LineNumber == 0)
1476 {
1477 errno = 0;
1478 e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
1479 }
18a81ac0
EA
1480 else
1481 {
1482 /*
1483 ** Arrange to read the data file.
1484 */
1485
1486 p = queuename(e, 'd');
1487 e->e_dfp = fopen(p, "r");
1488 if (e->e_dfp == NULL)
1489 {
1490 syserr("readqf: cannot open %s", p);
1491 }
66d16835 1492 else
18a81ac0 1493 {
66d16835
EA
1494 e->e_flags |= EF_HAS_DF;
1495 if (fstat(fileno(e->e_dfp), &st) >= 0)
1496 {
1497 e->e_msgsize = st.st_size;
1498 e->e_dfdev = st.st_dev;
1499 e->e_dfino = st.st_ino;
1500 }
18a81ac0
EA
1501 }
1502 }
1503
3620ad97 1504 return TRUE;
81b7d258
EA
1505}
1506\f/*
64912e7e
EA
1507** PRINTQUEUE -- print out a representation of the mail queue
1508**
1509** Parameters:
1510** none.
1511**
1512** Returns:
1513** none.
1514**
1515** Side Effects:
1516** Prints a listing of the mail queue on the standard output.
1517*/
1518
179d940c 1519void
64912e7e
EA
1520printqueue()
1521{
1522 register WORK *w;
1523 FILE *f;
0490b7d7 1524 int nrequests;
64912e7e
EA
1525 char buf[MAXLINE];
1526
374579b6
EA
1527 /*
1528 ** Check for permission to print the queue
1529 */
1530
fd178efd 1531 if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
374579b6
EA
1532 {
1533 struct stat st;
3afbc0f1
EA
1534# ifdef NGROUPS
1535 int n;
e6cb9fc4 1536 GIDSET_T gidset[NGROUPS];
3afbc0f1 1537# endif
374579b6 1538
7c8b3fd4 1539 if (stat(QueueDir, &st) < 0)
374579b6
EA
1540 {
1541 syserr("Cannot stat %s", QueueDir);
1542 return;
1543 }
3afbc0f1
EA
1544# ifdef NGROUPS
1545 n = getgroups(NGROUPS, gidset);
1546 while (--n >= 0)
1547 {
1548 if (gidset[n] == st.st_gid)
1549 break;
1550 }
ab3de76b 1551 if (n < 0 && RealGid != st.st_gid)
3afbc0f1 1552# else
fd57f063 1553 if (RealGid != st.st_gid)
3afbc0f1 1554# endif
374579b6
EA
1555 {
1556 usrerr("510 You are not permitted to see the queue");
1557 setstat(EX_NOPERM);
1558 return;
1559 }
1560 }
1561
64912e7e
EA
1562 /*
1563 ** Read and order the queue.
1564 */
1565
2e3062fe 1566 nrequests = orderq(TRUE);
64912e7e
EA
1567
1568 /*
1569 ** Print the work list that we have read.
1570 */
1571
1572 /* first see if there is anything */
0490b7d7 1573 if (nrequests <= 0)
64912e7e 1574 {
0490b7d7 1575 printf("Mail queue is empty\n");
64912e7e
EA
1576 return;
1577 }
1578
3620ad97 1579 CurrentLA = getla(); /* get load average */
3f9ac8ea 1580
d7b5594c 1581 printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
8a6b1962
EA
1582 if (nrequests > WorkListSize)
1583 printf(", only %d printed", WorkListSize);
f4b05990 1584 if (Verbose)
fbab5052 1585 printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
f4b05990 1586 else
fbab5052 1587 printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
64912e7e
EA
1588 for (w = WorkQ; w != NULL; w = w->w_next)
1589 {
1590 struct stat st;
0490b7d7 1591 auto time_t submittime = 0;
73af81f9 1592 long dfsize;
c2bdb1dd 1593 int flags = 0;
68d9129a 1594 int qfver;
0c6ce473 1595 char statmsg[MAXLINE];
8446c922 1596 char bodytype[MAXNAME + 1];
64912e7e 1597
4ba6a6f4 1598 printf("%8s", w->w_name + 2);
560a80d9
EA
1599 f = fopen(w->w_name, "r");
1600 if (f == NULL)
1601 {
4ba6a6f4 1602 printf(" (job completed)\n");
560a80d9
EA
1603 errno = 0;
1604 continue;
1605 }
73af81f9
EA
1606 w->w_name[0] = 'd';
1607 if (stat(w->w_name, &st) >= 0)
1608 dfsize = st.st_size;
1609 else
1610 dfsize = -1;
a9ca3259 1611 if (w->w_lock)
0490b7d7 1612 printf("*");
abccefc9 1613 else if (shouldqueue(w->w_pri, w->w_ctime))
2e3062fe 1614 printf("X");
0490b7d7
EA
1615 else
1616 printf(" ");
1617 errno = 0;
560a80d9 1618
0c6ce473 1619 statmsg[0] = bodytype[0] = '\0';
68d9129a 1620 qfver = 0;
64912e7e
EA
1621 while (fgets(buf, sizeof buf, f) != NULL)
1622 {
22293c34 1623 register int i;
c2bdb1dd 1624 register char *p;
22293c34 1625
64912e7e
EA
1626 fixcrlf(buf, TRUE);
1627 switch (buf[0])
1628 {
68d9129a
EA
1629 case 'V': /* queue file version */
1630 qfver = atoi(&buf[1]);
1631 break;
1632
baa0c390 1633 case 'M': /* error message */
0c6ce473
EA
1634 if ((i = strlen(&buf[1])) >= sizeof statmsg)
1635 i = sizeof statmsg - 1;
1636 bcopy(&buf[1], statmsg, i);
1637 statmsg[i] = '\0';
baa0c390
EA
1638 break;
1639
96bfbc2c
EA
1640 case 'B': /* body type */
1641 if ((i = strlen(&buf[1])) >= sizeof bodytype)
1642 i = sizeof bodytype - 1;
1643 bcopy(&buf[1], bodytype, i);
1644 bodytype[i] = '\0';
1645 break;
1646
64912e7e 1647 case 'S': /* sender name */
f4b05990 1648 if (Verbose)
c2bdb1dd
EA
1649 printf("%8ld %10ld%c%.12s %.38s",
1650 dfsize,
1651 w->w_pri,
1652 bitset(EF_WARNING, flags) ? '+' : ' ',
1653 ctime(&submittime) + 4,
f4b05990
EA
1654 &buf[1]);
1655 else
1656 printf("%8ld %.16s %.45s", dfsize,
1657 ctime(&submittime), &buf[1]);
0c6ce473 1658 if (statmsg[0] != '\0' || bodytype[0] != '\0')
96bfbc2c
EA
1659 {
1660 printf("\n %10.10s", bodytype);
0c6ce473
EA
1661 if (statmsg[0] != '\0')
1662 printf(" (%.60s)", statmsg);
96bfbc2c 1663 }
64912e7e 1664 break;
3620ad97 1665
3fbc69d6 1666 case 'C': /* controlling user */
d2213d6c 1667 if (Verbose)
fbab5052
EA
1668 printf("\n\t\t\t\t (---%.34s---)",
1669 &buf[1]);
3fbc69d6 1670 break;
64912e7e
EA
1671
1672 case 'R': /* recipient name */
68d9129a
EA
1673 p = &buf[1];
1674 if (qfver >= 1)
1675 {
1676 p = strchr(p, ':');
1677 if (p == NULL)
1678 break;
1679 p++;
1680 }
f4b05990 1681 if (Verbose)
68d9129a 1682 printf("\n\t\t\t\t\t %.38s", p);
f4b05990 1683 else
68d9129a 1684 printf("\n\t\t\t\t %.45s", p);
64912e7e
EA
1685 break;
1686
1687 case 'T': /* creation time */
2e3062fe 1688 submittime = atol(&buf[1]);
0490b7d7
EA
1689 break;
1690
c2bdb1dd
EA
1691 case 'F': /* flag bits */
1692 for (p = &buf[1]; *p != '\0'; p++)
1693 {
1694 switch (*p)
1695 {
1696 case 'w':
1697 flags |= EF_WARNING;
1698 break;
1699 }
1700 }
64912e7e
EA
1701 }
1702 }
0490b7d7
EA
1703 if (submittime == (time_t) 0)
1704 printf(" (no control file)");
64912e7e 1705 printf("\n");
0e306e7f 1706 (void) fclose(f);
64912e7e
EA
1707 }
1708}
884a20cb 1709
f3d8f6d6 1710# endif /* QUEUE */
560a80d9
EA
1711\f/*
1712** QUEUENAME -- build a file name in the queue directory for this envelope.
1713**
1714** Assigns an id code if one does not already exist.
1715** This code is very careful to avoid trashing existing files
1716** under any circumstances.
560a80d9
EA
1717**
1718** Parameters:
1719** e -- envelope to build it in/from.
1720** type -- the file type, used as the first character
1721** of the file name.
1722**
1723** Returns:
1724** a pointer to the new file name (in a static buffer).
1725**
1726** Side Effects:
3620ad97
EA
1727** If no id code is already assigned, queuename will
1728** assign an id code, create a qf file, and leave a
1729** locked, open-for-write file pointer in the envelope.
560a80d9
EA
1730*/
1731
1732char *
1733queuename(e, type)
1734 register ENVELOPE *e;
ef3bc6b1 1735 int type;
560a80d9 1736{
560a80d9 1737 static int pid = -1;
e3bb0d32
EA
1738 static char c0;
1739 static char c1;
1740 static char c2;
fbab5052
EA
1741 time_t now;
1742 struct tm *tm;
8446c922 1743 static char buf[MAXNAME + 1];
560a80d9
EA
1744
1745 if (e->e_id == NULL)
1746 {
1747 char qf[20];
560a80d9
EA
1748
1749 /* find a unique id */
1750 if (pid != getpid())
1751 {
1752 /* new process -- start back at "AA" */
1753 pid = getpid();
fbab5052
EA
1754 now = curtime();
1755 tm = localtime(&now);
1756 c0 = 'A' + tm->tm_hour;
560a80d9
EA
1757 c1 = 'A';
1758 c2 = 'A' - 1;
1759 }
fbab5052 1760 (void) sprintf(qf, "qf%cAA%05d", c0, pid);
560a80d9
EA
1761
1762 while (c1 < '~' || c2 < 'Z')
1763 {
1764 int i;
1765
1766 if (c2 >= 'Z')
1767 {
1768 c1++;
1769 c2 = 'A' - 1;
1770 }
fbab5052
EA
1771 qf[3] = c1;
1772 qf[4] = ++c2;
560a80d9 1773 if (tTd(7, 20))
3f9ac8ea 1774 printf("queuename: trying \"%s\"\n", qf);
560a80d9 1775
3f9ac8ea 1776 i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
3620ad97
EA
1777 if (i < 0)
1778 {
1779 if (errno == EEXIST)
1780 continue;
82530719
EA
1781 syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
1782 qf, QueueDir, geteuid());
3620ad97
EA
1783 exit(EX_UNAVAILABLE);
1784 }
71936fbe 1785 if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB))
3620ad97
EA
1786 {
1787 e->e_lockfp = fdopen(i, "w");
bb09c502 1788 break;
3f9ac8ea 1789 }
3620ad97
EA
1790
1791 /* a reader got the file; abandon it and try again */
1792 (void) close(i);
560a80d9
EA
1793 }
1794 if (c1 >= '~' && c2 >= 'Z')
1795 {
82530719
EA
1796 syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
1797 qf, QueueDir, geteuid());
560a80d9
EA
1798 exit(EX_OSERR);
1799 }
1800 e->e_id = newstr(&qf[2]);
1801 define('i', e->e_id, e);
560a80d9
EA
1802 if (tTd(7, 1))
1803 printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
eead656c
EA
1804 if (tTd(7, 9))
1805 {
1806 printf(" lockfd=");
1807 dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
1808 }
560a80d9 1809# ifdef LOG
68f7099c 1810 if (LogLevel > 93)
560a80d9 1811 syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
f3d8f6d6 1812# endif /* LOG */
560a80d9
EA
1813 }
1814
1815 if (type == '\0')
1816 return (NULL);
1817 (void) sprintf(buf, "%cf%s", type, e->e_id);
560a80d9
EA
1818 if (tTd(7, 2))
1819 printf("queuename: %s\n", buf);
560a80d9
EA
1820 return (buf);
1821}
1822\f/*
1823** UNLOCKQUEUE -- unlock the queue entry for a specified envelope
1824**
1825** Parameters:
1826** e -- the envelope to unlock.
1827**
1828** Returns:
1829** none
1830**
1831** Side Effects:
1832** unlocks the queue for `e'.
1833*/
1834
179d940c 1835void
560a80d9
EA
1836unlockqueue(e)
1837 ENVELOPE *e;
1838{
bc854e30
EA
1839 if (tTd(51, 4))
1840 printf("unlockqueue(%s)\n", e->e_id);
1841
3620ad97
EA
1842 /* if there is a lock file in the envelope, close it */
1843 if (e->e_lockfp != NULL)
bc854e30 1844 xfclose(e->e_lockfp, "unlockqueue", e->e_id);
3620ad97
EA
1845 e->e_lockfp = NULL;
1846
32061c38
EA
1847 /* don't create a queue id if we don't already have one */
1848 if (e->e_id == NULL)
1849 return;
1850
560a80d9 1851 /* remove the transcript */
560a80d9 1852# ifdef LOG
68f7099c 1853 if (LogLevel > 87)
560a80d9 1854 syslog(LOG_DEBUG, "%s: unlock", e->e_id);
f3d8f6d6 1855# endif /* LOG */
bc854e30 1856 if (!tTd(51, 104))
560a80d9
EA
1857 xunlink(queuename(e, 'x'));
1858
560a80d9 1859}
3fbc69d6 1860\f/*
d2213d6c 1861** SETCTLUSER -- create a controlling address
3fbc69d6 1862**
d2213d6c
EA
1863** Create a fake "address" given only a local login name; this is
1864** used as a "controlling user" for future recipient addresses.
3fbc69d6
KB
1865**
1866** Parameters:
d2213d6c 1867** user -- the user name of the controlling user.
3fbc69d6
KB
1868**
1869** Returns:
d2213d6c 1870** An address descriptor for the controlling user.
3fbc69d6
KB
1871**
1872** Side Effects:
1873** none.
1874*/
1875
d2213d6c
EA
1876ADDRESS *
1877setctluser(user)
1878 char *user;
3fbc69d6 1879{
d2213d6c 1880 register ADDRESS *a;
3fbc69d6 1881 struct passwd *pw;
9cdb0b30 1882 char *p;
3fbc69d6
KB
1883
1884 /*
d2213d6c 1885 ** See if this clears our concept of controlling user.
3fbc69d6
KB
1886 */
1887
c6c403f7
EA
1888 if (user == NULL || *user == '\0')
1889 return NULL;
3fbc69d6
KB
1890
1891 /*
d2213d6c 1892 ** Set up addr fields for controlling user.
3fbc69d6
KB
1893 */
1894
d2213d6c
EA
1895 a = (ADDRESS *) xalloc(sizeof *a);
1896 bzero((char *) a, sizeof *a);
9cdb0b30
EA
1897
1898 p = strchr(user, ':');
1899 if (p != NULL)
1900 *p++ = '\0';
5b7a2dfe 1901 if (*user != '\0' && (pw = sm_getpwnam(user)) != NULL)
3fbc69d6 1902 {
c841d671
EA
1903 if (strcmp(pw->pw_dir, "/") == 0)
1904 a->q_home = "";
1905 else
1906 a->q_home = newstr(pw->pw_dir);
3fbc69d6
KB
1907 a->q_uid = pw->pw_uid;
1908 a->q_gid = pw->pw_gid;
f7894324 1909 a->q_flags |= QGOODUID;
3fbc69d6 1910 }
66d16835
EA
1911
1912 if (*user != '\0')
1913 a->q_user = newstr(user);
1914 else if (p != NULL)
1915 a->q_user = newstr(p);
3fbc69d6 1916 else
6e99f903 1917 a->q_user = newstr(DefUser);
3fbc69d6 1918
f7894324 1919 a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */
d0a69620 1920 a->q_mailer = LocalMailer;
9cdb0b30
EA
1921 if (p == NULL)
1922 a->q_paddr = a->q_user;
1923 else
1924 a->q_paddr = newstr(p);
d2213d6c 1925 return a;
3fbc69d6 1926}
99fd9645
EA
1927\f/*
1928** LOSEQFILE -- save the qf as Qf and try to let someone know
1929**
1930** Parameters:
1931** e -- the envelope (e->e_id will be used).
1932** why -- reported to whomever can hear.
1933**
1934** Returns:
1935** none.
1936*/
1937
1938void
1939loseqfile(e, why)
1940 register ENVELOPE *e;
1941 char *why;
1942{
6502fd93 1943 char *p;
99fd9645
EA
1944 char buf[40];
1945
1946 if (e == NULL || e->e_id == NULL)
1947 return;
1948 if (strlen(e->e_id) > sizeof buf - 4)
1949 return;
1950 strcpy(buf, queuename(e, 'q'));
6502fd93
EA
1951 p = queuename(e, 'Q');
1952 if (rename(buf, p) < 0)
1953 syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid());
99fd9645 1954#ifdef LOG
6502fd93
EA
1955 else if (LogLevel > 0)
1956 syslog(LOG_ALERT, "Losing %s: %s", buf, why);
99fd9645
EA
1957#endif
1958}