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