queue.c revision 66494
1/*
2 * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
3 *	All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5 * Copyright (c) 1988, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14
15#include <sendmail.h>
16
17#ifndef lint
18# if QUEUE
19static char id[] = "@(#)$Id: queue.c,v 8.343.4.17 2000/09/15 03:34:51 gshapiro Exp $ (with queueing)";
20# else /* QUEUE */
21static char id[] = "@(#)$Id: queue.c,v 8.343.4.17 2000/09/15 03:34:51 gshapiro Exp $ (without queueing)";
22# endif /* QUEUE */
23#endif /* ! lint */
24
25# include <dirent.h>
26
27#if QUEUE
28
29# if _FFR_QUEUEDELAY
30#  define QF_VERSION	5	/* version number of this queue format */
31static time_t	queuedelay __P((ENVELOPE *));
32# else /* _FFR_QUEUEDELAY */
33#  define QF_VERSION	4	/* version number of this queue format */
34#  define queuedelay(e)	MinQueueAge
35# endif /* _FFR_QUEUEDELAY */
36
37/*
38**  Work queue.
39*/
40
41struct work
42{
43	char		*w_name;	/* name of control file */
44	char		*w_host;	/* name of recipient host */
45	bool		w_lock;		/* is message locked? */
46	bool		w_tooyoung;	/* is it too young to run? */
47	long		w_pri;		/* priority of message, see below */
48	time_t		w_ctime;	/* creation time of message */
49	struct work	*w_next;	/* next in queue */
50};
51
52typedef struct work	WORK;
53
54static WORK	*WorkQ;			/* queue of things to be done */
55
56static void	grow_wlist __P((int));
57static int	orderq __P((int, bool));
58static void	printctladdr __P((ADDRESS *, FILE *));
59static int	print_single_queue __P((int));
60static bool	readqf __P((ENVELOPE *));
61static void	runqueueevent __P((void));
62static int	run_single_queue __P((int, bool, bool));
63static char	*strrev __P((char *));
64static ADDRESS	*setctluser __P((char *, int));
65static int	workcmpf0();
66static int	workcmpf1();
67static int	workcmpf2();
68static int	workcmpf3();
69static int	workcmpf4();
70
71/*
72**  QUEUEUP -- queue a message up for future transmission.
73**
74**	Parameters:
75**		e -- the envelope to queue up.
76**		announce -- if TRUE, tell when you are queueing up.
77**
78**	Returns:
79**		none.
80**
81**	Side Effects:
82**		The current request are saved in a control file.
83**		The queue file is left locked.
84*/
85
86# define TEMPQF_LETTER 'T'
87
88void
89queueup(e, announce)
90	register ENVELOPE *e;
91	bool announce;
92{
93	char *qf;
94	register FILE *tfp;
95	register HDR *h;
96	register ADDRESS *q;
97	int tfd = -1;
98	int i;
99	bool newid;
100	register char *p;
101	MAILER nullmailer;
102	MCI mcibuf;
103	char tf[MAXPATHLEN];
104	char buf[MAXLINE];
105
106	/*
107	**  Create control file.
108	*/
109
110	newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
111
112	/* if newid, queuename will create a locked qf file in e->lockfp */
113	(void) strlcpy(tf, queuename(e, 't'), sizeof tf);
114	tfp = e->e_lockfp;
115	if (tfp == NULL)
116		newid = FALSE;
117
118	/* if newid, just write the qf file directly (instead of tf file) */
119	if (!newid)
120	{
121		int flags;
122
123		flags = O_CREAT|O_WRONLY|O_EXCL;
124
125		/* get a locked tf file */
126		for (i = 0; i < 128; i++)
127		{
128			if (tfd < 0)
129			{
130#if _FFR_QUEUE_FILE_MODE
131				MODE_T oldumask;
132
133				if (bitset(S_IWGRP, QueueFileMode))
134					oldumask = umask(002);
135				tfd = open(tf, flags, QueueFileMode);
136				if (bitset(S_IWGRP, QueueFileMode))
137					(void) umask(oldumask);
138#else /* _FFR_QUEUE_FILE_MODE */
139				tfd = open(tf, flags, FileMode);
140#endif /* _FFR_QUEUE_FILE_MODE */
141
142				if (tfd < 0)
143				{
144					if (errno != EEXIST)
145						break;
146					if (LogLevel > 0 && (i % 32) == 0)
147						sm_syslog(LOG_ALERT, e->e_id,
148							  "queueup: cannot create %s, uid=%d: %s",
149							  tf, geteuid(), errstring(errno));
150				}
151			}
152			if (tfd >= 0)
153			{
154				if (lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB))
155					break;
156				else if (LogLevel > 0 && (i % 32) == 0)
157					sm_syslog(LOG_ALERT, e->e_id,
158						  "queueup: cannot lock %s: %s",
159						  tf, errstring(errno));
160				if ((i % 32) == 31)
161				{
162					(void) close(tfd);
163					tfd = -1;
164				}
165			}
166
167			if ((i % 32) == 31)
168			{
169				/* save the old temp file away */
170				(void) rename(tf, queuename(e, TEMPQF_LETTER));
171			}
172			else
173				(void) sleep(i % 32);
174		}
175		if (tfd < 0 || (tfp = fdopen(tfd, "w")) == NULL)
176		{
177			int save_errno = errno;
178
179			printopenfds(TRUE);
180			errno = save_errno;
181			syserr("!queueup: cannot create queue temp file %s, uid=%d",
182				tf, geteuid());
183		}
184	}
185
186	if (tTd(40, 1))
187		dprintf("\n>>>>> queueing %s/qf%s%s >>>>>\n",
188			qid_printqueue(e->e_queuedir), e->e_id,
189			newid ? " (new id)" : "");
190	if (tTd(40, 3))
191	{
192		dprintf("  e_flags=");
193		printenvflags(e);
194	}
195	if (tTd(40, 32))
196	{
197		dprintf("  sendq=");
198		printaddr(e->e_sendqueue, TRUE);
199	}
200	if (tTd(40, 9))
201	{
202		dprintf("  tfp=");
203		dumpfd(fileno(tfp), TRUE, FALSE);
204		dprintf("  lockfp=");
205		if (e->e_lockfp == NULL)
206			dprintf("NULL\n");
207		else
208			dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
209	}
210
211	/*
212	**  If there is no data file yet, create one.
213	*/
214
215	if (bitset(EF_HAS_DF, e->e_flags))
216	{
217		if (e->e_dfp != NULL && bfcommit(e->e_dfp) < 0)
218			syserr("!queueup: cannot commit data file %s, uid=%d",
219				queuename(e, 'd'), geteuid());
220	}
221	else
222	{
223		int dfd;
224		register FILE *dfp = NULL;
225		char dfname[MAXPATHLEN];
226		struct stat stbuf;
227
228		if (e->e_dfp != NULL && bftest(e->e_dfp))
229			syserr("committing over bf file");
230
231		(void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname);
232#if _FFR_QUEUE_FILE_MODE
233		{
234			MODE_T oldumask;
235
236			if (bitset(S_IWGRP, QueueFileMode))
237				oldumask = umask(002);
238			dfd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC,
239				   QueueFileMode);
240			if (bitset(S_IWGRP, QueueFileMode))
241				(void) umask(oldumask);
242		}
243#else /* _FFR_QUEUE_FILE_MODE */
244		dfd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode);
245#endif /* _FFR_QUEUE_FILE_MODE */
246		if (dfd < 0 || (dfp = fdopen(dfd, "w")) == NULL)
247			syserr("!queueup: cannot create data temp file %s, uid=%d",
248				dfname, geteuid());
249		if (fstat(dfd, &stbuf) < 0)
250			e->e_dfino = -1;
251		else
252		{
253			e->e_dfdev = stbuf.st_dev;
254			e->e_dfino = stbuf.st_ino;
255		}
256		e->e_flags |= EF_HAS_DF;
257		memset(&mcibuf, '\0', sizeof mcibuf);
258		mcibuf.mci_out = dfp;
259		mcibuf.mci_mailer = FileMailer;
260		(*e->e_putbody)(&mcibuf, e, NULL);
261		if (fclose(dfp) < 0)
262			syserr("!queueup: cannot save data temp file %s, uid=%d",
263				dfname, geteuid());
264		e->e_putbody = putbody;
265	}
266
267	/*
268	**  Output future work requests.
269	**	Priority and creation time should be first, since
270	**	they are required by orderq.
271	*/
272
273	/* output queue version number (must be first!) */
274	fprintf(tfp, "V%d\n", QF_VERSION);
275
276	/* output creation time */
277	fprintf(tfp, "T%ld\n", (long) e->e_ctime);
278
279	/* output last delivery time */
280# if _FFR_QUEUEDELAY
281	fprintf(tfp, "K%ld\n", (long) e->e_dtime);
282	fprintf(tfp, "G%d\n", e->e_queuealg);
283	fprintf(tfp, "Y%ld\n", (long) e->e_queuedelay);
284	if (tTd(40, 64))
285		sm_syslog(LOG_INFO, e->e_id,
286			"queue alg: %d delay %ld next: %ld (now: %ld)\n",
287			e->e_queuealg, e->e_queuedelay, e->e_dtime, curtime());
288# else /* _FFR_QUEUEDELAY */
289	fprintf(tfp, "K%ld\n", (long) e->e_dtime);
290# endif /* _FFR_QUEUEDELAY */
291
292	/* output number of delivery attempts */
293	fprintf(tfp, "N%d\n", e->e_ntries);
294
295	/* output message priority */
296	fprintf(tfp, "P%ld\n", e->e_msgpriority);
297
298	/* output inode number of data file */
299	/* XXX should probably include device major/minor too */
300	if (e->e_dfino != -1)
301	{
302		/*CONSTCOND*/
303		if (sizeof e->e_dfino > sizeof(long))
304			fprintf(tfp, "I%ld/%ld/%s\n",
305				(long) major(e->e_dfdev),
306				(long) minor(e->e_dfdev),
307				quad_to_string(e->e_dfino));
308		else
309			fprintf(tfp, "I%ld/%ld/%lu\n",
310				(long) major(e->e_dfdev),
311				(long) minor(e->e_dfdev),
312				(unsigned long) e->e_dfino);
313	}
314
315	/* output body type */
316	if (e->e_bodytype != NULL)
317		fprintf(tfp, "B%s\n", denlstring(e->e_bodytype, TRUE, FALSE));
318
319# if _FFR_SAVE_CHARSET
320	if (e->e_charset != NULL)
321		fprintf(tfp, "X%s\n", denlstring(e->e_charset, TRUE, FALSE));
322# endif /* _FFR_SAVE_CHARSET */
323
324	/* message from envelope, if it exists */
325	if (e->e_message != NULL)
326		fprintf(tfp, "M%s\n", denlstring(e->e_message, TRUE, FALSE));
327
328	/* send various flag bits through */
329	p = buf;
330	if (bitset(EF_WARNING, e->e_flags))
331		*p++ = 'w';
332	if (bitset(EF_RESPONSE, e->e_flags))
333		*p++ = 'r';
334	if (bitset(EF_HAS8BIT, e->e_flags))
335		*p++ = '8';
336	if (bitset(EF_DELETE_BCC, e->e_flags))
337		*p++ = 'b';
338	if (bitset(EF_RET_PARAM, e->e_flags))
339		*p++ = 'd';
340	if (bitset(EF_NO_BODY_RETN, e->e_flags))
341		*p++ = 'n';
342	*p++ = '\0';
343	if (buf[0] != '\0')
344		fprintf(tfp, "F%s\n", buf);
345
346	/* save $={persistentMacros} macro values */
347	queueup_macros(macid("{persistentMacros}", NULL), tfp, e);
348
349	/* output name of sender */
350	if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
351		p = e->e_sender;
352	else
353		p = e->e_from.q_paddr;
354	fprintf(tfp, "S%s\n", denlstring(p, TRUE, FALSE));
355
356	/* output ESMTP-supplied "original" information */
357	if (e->e_envid != NULL)
358		fprintf(tfp, "Z%s\n", denlstring(e->e_envid, TRUE, FALSE));
359
360	/* output AUTH= parameter */
361	if (e->e_auth_param != NULL)
362		fprintf(tfp, "A%s\n", denlstring(e->e_auth_param,
363						 TRUE, FALSE));
364
365	/* output list of recipient addresses */
366	printctladdr(NULL, NULL);
367	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
368	{
369		if (!QS_IS_UNDELIVERED(q->q_state))
370			continue;
371
372		printctladdr(q, tfp);
373		if (q->q_orcpt != NULL)
374			fprintf(tfp, "Q%s\n",
375				denlstring(q->q_orcpt, TRUE, FALSE));
376		(void) putc('R', tfp);
377		if (bitset(QPRIMARY, q->q_flags))
378			(void) putc('P', tfp);
379		if (bitset(QHASNOTIFY, q->q_flags))
380			(void) putc('N', tfp);
381		if (bitset(QPINGONSUCCESS, q->q_flags))
382			(void) putc('S', tfp);
383		if (bitset(QPINGONFAILURE, q->q_flags))
384			(void) putc('F', tfp);
385		if (bitset(QPINGONDELAY, q->q_flags))
386			(void) putc('D', tfp);
387		(void) putc(':', tfp);
388		(void) fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE));
389		if (announce)
390		{
391			e->e_to = q->q_paddr;
392			message("queued");
393			if (LogLevel > 8)
394				logdelivery(q->q_mailer, NULL, q->q_status,
395					    "queued", NULL, (time_t) 0, e);
396			e->e_to = NULL;
397		}
398		if (tTd(40, 1))
399		{
400			dprintf("queueing ");
401			printaddr(q, FALSE);
402		}
403	}
404
405	/*
406	**  Output headers for this message.
407	**	Expand macros completely here.  Queue run will deal with
408	**	everything as absolute headers.
409	**		All headers that must be relative to the recipient
410	**		can be cracked later.
411	**	We set up a "null mailer" -- i.e., a mailer that will have
412	**	no effect on the addresses as they are output.
413	*/
414
415	memset((char *) &nullmailer, '\0', sizeof nullmailer);
416	nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
417			nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
418	nullmailer.m_eol = "\n";
419	memset(&mcibuf, '\0', sizeof mcibuf);
420	mcibuf.mci_mailer = &nullmailer;
421	mcibuf.mci_out = tfp;
422
423	define('g', "\201f", e);
424	for (h = e->e_header; h != NULL; h = h->h_link)
425	{
426		if (h->h_value == NULL)
427			continue;
428
429		/* don't output resent headers on non-resent messages */
430		if (bitset(H_RESENT, h->h_flags) &&
431		    !bitset(EF_RESENT, e->e_flags))
432			continue;
433
434		/* expand macros; if null, don't output header at all */
435		if (bitset(H_DEFAULT, h->h_flags))
436		{
437			(void) expand(h->h_value, buf, sizeof buf, e);
438			if (buf[0] == '\0')
439				continue;
440		}
441
442		/* output this header */
443		fprintf(tfp, "H?");
444
445		/* output conditional macro if present */
446		if (h->h_macro != '\0')
447		{
448			if (bitset(0200, h->h_macro))
449				fprintf(tfp, "${%s}",
450					macname(h->h_macro & 0377));
451			else
452				fprintf(tfp, "$%c", h->h_macro);
453		}
454		else if (!bitzerop(h->h_mflags) &&
455			 bitset(H_CHECK|H_ACHECK, h->h_flags))
456		{
457			int j;
458
459			/* if conditional, output the set of conditions */
460			for (j = '\0'; j <= '\177'; j++)
461				if (bitnset(j, h->h_mflags))
462					(void) putc(j, tfp);
463		}
464		(void) putc('?', tfp);
465
466		/* output the header: expand macros, convert addresses */
467		if (bitset(H_DEFAULT, h->h_flags) &&
468		    !bitset(H_BINDLATE, h->h_flags))
469		{
470			fprintf(tfp, "%s: %s\n",
471				h->h_field,
472				denlstring(buf, FALSE, TRUE));
473		}
474		else if (bitset(H_FROM|H_RCPT, h->h_flags) &&
475			 !bitset(H_BINDLATE, h->h_flags))
476		{
477			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
478			FILE *savetrace = TrafficLogFile;
479
480			TrafficLogFile = NULL;
481
482			if (bitset(H_FROM, h->h_flags))
483				oldstyle = FALSE;
484
485			commaize(h, h->h_value, oldstyle, &mcibuf, e);
486
487			TrafficLogFile = savetrace;
488		}
489		else
490		{
491			fprintf(tfp, "%s: %s\n",
492				h->h_field,
493				denlstring(h->h_value, FALSE, TRUE));
494		}
495	}
496
497	/*
498	**  Clean up.
499	**
500	**	Write a terminator record -- this is to prevent
501	**	scurrilous crackers from appending any data.
502	*/
503
504	fprintf(tfp, ".\n");
505
506	if (fflush(tfp) < 0 ||
507	    (SuperSafe && fsync(fileno(tfp)) < 0) ||
508	    ferror(tfp))
509	{
510		if (newid)
511			syserr("!552 Error writing control file %s", tf);
512		else
513			syserr("!452 Error writing control file %s", tf);
514	}
515
516	if (!newid)
517	{
518		/* rename (locked) tf to be (locked) qf */
519		qf = queuename(e, 'q');
520		if (rename(tf, qf) < 0)
521			syserr("cannot rename(%s, %s), uid=%d",
522				tf, qf, geteuid());
523
524		/*
525		**  fsync() after renaming to make sure
526		**  metadata is written to disk on
527		**  filesystems in which renames are
528		**  not guaranteed such as softupdates.
529		*/
530
531		if (tfd >= 0 && SuperSafe && fsync(tfd) < 0)
532			syserr("!queueup: cannot fsync queue temp file %s",
533			       tf);
534
535		/* close and unlock old (locked) qf */
536		if (e->e_lockfp != NULL)
537			(void) fclose(e->e_lockfp);
538		e->e_lockfp = tfp;
539	}
540	else
541		qf = tf;
542	errno = 0;
543	e->e_flags |= EF_INQUEUE;
544
545	/* save log info */
546	if (LogLevel > 79)
547		sm_syslog(LOG_DEBUG, e->e_id, "queueup, qf=%s", qf);
548
549	if (tTd(40, 1))
550		dprintf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
551	return;
552}
553
554static void
555printctladdr(a, tfp)
556	register ADDRESS *a;
557	FILE *tfp;
558{
559	char *user;
560	register ADDRESS *q;
561	uid_t uid;
562	gid_t gid;
563	static ADDRESS *lastctladdr = NULL;
564	static uid_t lastuid;
565
566	/* initialization */
567	if (a == NULL || a->q_alias == NULL || tfp == NULL)
568	{
569		if (lastctladdr != NULL && tfp != NULL)
570			fprintf(tfp, "C\n");
571		lastctladdr = NULL;
572		lastuid = 0;
573		return;
574	}
575
576	/* find the active uid */
577	q = getctladdr(a);
578	if (q == NULL)
579	{
580		user = NULL;
581		uid = 0;
582		gid = 0;
583	}
584	else
585	{
586		user = q->q_ruser != NULL ? q->q_ruser : q->q_user;
587		uid = q->q_uid;
588		gid = q->q_gid;
589	}
590	a = a->q_alias;
591
592	/* check to see if this is the same as last time */
593	if (lastctladdr != NULL && uid == lastuid &&
594	    strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
595		return;
596	lastuid = uid;
597	lastctladdr = a;
598
599	if (uid == 0 || user == NULL || user[0] == '\0')
600		fprintf(tfp, "C");
601	else
602		fprintf(tfp, "C%s:%ld:%ld",
603			denlstring(user, TRUE, FALSE), (long) uid, (long) gid);
604	fprintf(tfp, ":%s\n", denlstring(a->q_paddr, TRUE, FALSE));
605}
606/*
607**  RUNQUEUE -- run the jobs in the queue.
608**
609**	Gets the stuff out of the queue in some presumably logical
610**	order and processes them.
611**
612**	Parameters:
613**		forkflag -- TRUE if the queue scanning should be done in
614**			a child process.  We double-fork so it is not our
615**			child and we don't have to clean up after it.
616**			FALSE can be ignored if we have multiple queues.
617**		verbose -- if TRUE, print out status information.
618**
619**	Returns:
620**		TRUE if the queue run successfully began.
621**
622**	Side Effects:
623**		runs things in the mail queue.
624*/
625
626static ENVELOPE	QueueEnvelope;		/* the queue run envelope */
627int		NumQueues = 0;		/* number of queues */
628static time_t	LastQueueTime = 0;	/* last time a queue ID assigned */
629static pid_t	LastQueuePid = -1;	/* last PID which had a queue ID */
630
631struct qpaths_s
632{
633	char	*qp_name;	/* name of queue dir */
634	short	qp_subdirs;	/* use subdirs? */
635};
636
637typedef struct qpaths_s QPATHS;
638
639/* values for qp_supdirs */
640#define QP_NOSUB	0x0000	/* No subdirectories */
641#define QP_SUBDF	0x0001	/* "df" subdirectory */
642#define QP_SUBQF	0x0002	/* "qf" subdirectory */
643#define QP_SUBXF	0x0004	/* "xf" subdirectory */
644
645static QPATHS	*QPaths = NULL;		/* list of queue directories */
646
647bool
648runqueue(forkflag, verbose)
649	bool forkflag;
650	bool verbose;
651{
652	int i;
653	bool ret = TRUE;
654	static int curnum = 0;
655
656	if (!forkflag && NumQueues > 1 && !verbose)
657		forkflag = TRUE;
658
659	for (i = 0; i < NumQueues; i++)
660	{
661		/*
662		**  Pick up where we left off, in case we
663		**  used up all the children last time
664		**  without finishing.
665		*/
666
667		ret = run_single_queue(curnum, forkflag, verbose);
668
669		/*
670		**  Failure means a message was printed for ETRN
671		**  and subsequent queues are likely to fail as well.
672		*/
673
674		if (!ret)
675			break;
676
677		if (++curnum >= NumQueues)
678			curnum = 0;
679	}
680	if (QueueIntvl != 0)
681		(void) setevent(QueueIntvl, runqueueevent, 0);
682	return ret;
683}
684/*
685**  RUN_SINGLE_QUEUE -- run the jobs in a single queue.
686**
687**	Gets the stuff out of the queue in some presumably logical
688**	order and processes them.
689**
690**	Parameters:
691**		queuedir -- queue to process
692**		forkflag -- TRUE if the queue scanning should be done in
693**			a child process.  We double-fork so it is not our
694**			child and we don't have to clean up after it.
695**		verbose -- if TRUE, print out status information.
696**
697**	Returns:
698**		TRUE if the queue run successfully began.
699**
700**	Side Effects:
701**		runs things in the mail queue.
702*/
703
704static bool
705run_single_queue(queuedir, forkflag, verbose)
706	int queuedir;
707	bool forkflag;
708	bool verbose;
709{
710	register ENVELOPE *e;
711	int njobs;
712	int sequenceno = 0;
713	time_t current_la_time;
714	extern ENVELOPE BlankEnvelope;
715
716	DoQueueRun = FALSE;
717
718	/*
719	**  If no work will ever be selected, don't even bother reading
720	**  the queue.
721	*/
722
723	CurrentLA = sm_getla(NULL);	/* get load average */
724	current_la_time = curtime();
725
726	if (shouldqueue(WkRecipFact, current_la_time))
727	{
728		char *msg = "Skipping queue run -- load average too high";
729
730		if (verbose)
731			message("458 %s\n", msg);
732		if (LogLevel > 8)
733			sm_syslog(LOG_INFO, NOQID,
734				  "runqueue: %s",
735				  msg);
736		return FALSE;
737	}
738
739	/*
740	**  See if we already have too many children.
741	*/
742
743	if (forkflag && QueueIntvl != 0 &&
744	    MaxChildren > 0 && CurChildren >= MaxChildren)
745	{
746		char *msg = "Skipping queue run -- too many children";
747
748		if (verbose)
749			message("458 %s (%d)\n", msg, CurChildren);
750		if (LogLevel > 8)
751			sm_syslog(LOG_INFO, NOQID,
752				  "runqueue: %s (%d)",
753				  msg, CurChildren);
754		return FALSE;
755	}
756
757	/*
758	**  See if we want to go off and do other useful work.
759	*/
760
761	if (forkflag)
762	{
763		pid_t pid;
764
765		(void) blocksignal(SIGCHLD);
766		(void) setsignal(SIGCHLD, reapchild);
767
768		pid = dofork();
769		if (pid == -1)
770		{
771			const char *msg = "Skipping queue run -- fork() failed";
772			const char *err = errstring(errno);
773
774			if (verbose)
775				message("458 %s: %s\n", msg, err);
776			if (LogLevel > 8)
777				sm_syslog(LOG_INFO, NOQID,
778					  "runqueue: %s: %s",
779					  msg, err);
780			(void) releasesignal(SIGCHLD);
781			return FALSE;
782		}
783		if (pid != 0)
784		{
785			/* parent -- pick up intermediate zombie */
786			(void) blocksignal(SIGALRM);
787			proc_list_add(pid, "Queue runner", PROC_QUEUE);
788			(void) releasesignal(SIGALRM);
789			(void) releasesignal(SIGCHLD);
790			return TRUE;
791		}
792		/* child -- clean up signals */
793		clrcontrol();
794		proc_list_clear();
795
796		/* Add parent process as first child item */
797		proc_list_add(getpid(), "Queue runner child process",
798			      PROC_QUEUE_CHILD);
799		(void) releasesignal(SIGCHLD);
800		(void) setsignal(SIGCHLD, SIG_DFL);
801		(void) setsignal(SIGHUP, intsig);
802
803	}
804
805	sm_setproctitle(TRUE, CurEnv, "running queue: %s",
806			qid_printqueue(queuedir));
807
808	if (LogLevel > 69 || tTd(63, 99))
809		sm_syslog(LOG_DEBUG, NOQID,
810			  "runqueue %s, pid=%d, forkflag=%d",
811			  qid_printqueue(queuedir), getpid(), forkflag);
812
813	/*
814	**  Release any resources used by the daemon code.
815	*/
816
817# if DAEMON
818	clrdaemon();
819# endif /* DAEMON */
820
821	/* force it to run expensive jobs */
822	NoConnect = FALSE;
823
824	/* drop privileges */
825	if (geteuid() == (uid_t) 0)
826		(void) drop_privileges(FALSE);
827
828	/*
829	**  Create ourselves an envelope
830	*/
831
832	CurEnv = &QueueEnvelope;
833	e = newenvelope(&QueueEnvelope, CurEnv);
834	e->e_flags = BlankEnvelope.e_flags;
835
836	/* make sure we have disconnected from parent */
837	if (forkflag)
838	{
839		disconnect(1, e);
840		QuickAbort = FALSE;
841	}
842
843	/*
844	**  If we are running part of the queue, always ignore stored
845	**  host status.
846	*/
847
848	if (QueueLimitId != NULL || QueueLimitSender != NULL ||
849	    QueueLimitRecipient != NULL)
850	{
851		IgnoreHostStatus = TRUE;
852		MinQueueAge = 0;
853	}
854
855	/*
856	**  Start making passes through the queue.
857	**	First, read and sort the entire queue.
858	**	Then, process the work in that order.
859	**		But if you take too long, start over.
860	*/
861
862	/* order the existing work requests */
863	njobs = orderq(queuedir, FALSE);
864
865
866	/* process them once at a time */
867	while (WorkQ != NULL)
868	{
869		WORK *w = WorkQ;
870
871		WorkQ = WorkQ->w_next;
872		e->e_to = NULL;
873
874		/*
875		**  Ignore jobs that are too expensive for the moment.
876		**
877		**	Get new load average every 30 seconds.
878		*/
879
880		if (current_la_time < curtime() - 30)
881		{
882			CurrentLA = sm_getla(e);
883			current_la_time = curtime();
884		}
885		if (shouldqueue(WkRecipFact, current_la_time))
886		{
887			char *msg = "Aborting queue run: load average too high";
888
889			if (Verbose)
890				message("%s", msg);
891			if (LogLevel > 8)
892				sm_syslog(LOG_INFO, NOQID,
893					  "runqueue: %s",
894					  msg);
895			break;
896		}
897		sequenceno++;
898		if (shouldqueue(w->w_pri, w->w_ctime))
899		{
900			if (Verbose)
901				message("");
902			if (QueueSortOrder == QSO_BYPRIORITY)
903			{
904				if (Verbose)
905					message("Skipping %s/%s (sequence %d of %d) and flushing rest of queue",
906						qid_printqueue(queuedir),
907						w->w_name + 2,
908						sequenceno,
909						njobs);
910				if (LogLevel > 8)
911					sm_syslog(LOG_INFO, NOQID,
912						  "runqueue: Flushing queue from %s/%s (pri %ld, LA %d, %d of %d)",
913						  qid_printqueue(queuedir),
914						  w->w_name + 2,
915						  w->w_pri,
916						  CurrentLA,
917						  sequenceno,
918						  njobs);
919				break;
920			}
921			else if (Verbose)
922				message("Skipping %s/%s (sequence %d of %d)",
923					qid_printqueue(queuedir),
924					w->w_name + 2,
925					sequenceno, njobs);
926		}
927		else
928		{
929			pid_t pid;
930
931			if (Verbose)
932			{
933				message("");
934				message("Running %s/%s (sequence %d of %d)",
935					qid_printqueue(queuedir),
936					w->w_name + 2,
937					sequenceno, njobs);
938			}
939			if (tTd(63, 100))
940				sm_syslog(LOG_DEBUG, NOQID,
941					  "runqueue %s dowork(%s)",
942					  qid_printqueue(queuedir),
943					  w->w_name + 2);
944
945			pid = dowork(queuedir, w->w_name + 2,
946				     ForkQueueRuns, FALSE, e);
947			errno = 0;
948			if (pid != 0)
949				(void) waitfor(pid);
950		}
951		free(w->w_name);
952		if (w->w_host)
953			free(w->w_host);
954		free((char *) w);
955	}
956
957	/* exit without the usual cleanup */
958	e->e_id = NULL;
959	if (forkflag)
960		finis(TRUE, ExitStat);
961	/* NOTREACHED */
962	return TRUE;
963}
964
965/*
966**  RUNQUEUEEVENT -- stub for use in setevent
967*/
968
969static void
970runqueueevent()
971{
972	DoQueueRun = TRUE;
973}
974/*
975**  ORDERQ -- order the work queue.
976**
977**	Parameters:
978**		queuedir -- the index of the queue directory.
979**		doall -- if set, include everything in the queue (even
980**			the jobs that cannot be run because the load
981**			average is too high).  Otherwise, exclude those
982**			jobs.
983**
984**	Returns:
985**		The number of request in the queue (not necessarily
986**		the number of requests in WorkQ however).
987**
988**	Side Effects:
989**		Sets WorkQ to the queue of available work, in order.
990*/
991
992# define NEED_P		001
993# define NEED_T		002
994# define NEED_R		004
995# define NEED_S		010
996
997static WORK	*WorkList = NULL;
998static int	WorkListSize = 0;
999
1000static int
1001orderq(queuedir, doall)
1002	int queuedir;
1003	bool doall;
1004{
1005	register struct dirent *d;
1006	register WORK *w;
1007	register char *p;
1008	DIR *f;
1009	register int i;
1010	int wn = -1;
1011	int wc;
1012	QUEUE_CHAR *check;
1013	char qd[MAXPATHLEN];
1014	char qf[MAXPATHLEN];
1015
1016	if (queuedir == NOQDIR)
1017		(void) strlcpy(qd, ".", sizeof qd);
1018	else
1019		(void) snprintf(qd, sizeof qd, "%s%s",
1020				QPaths[queuedir].qp_name,
1021				(bitset(QP_SUBQF, QPaths[queuedir].qp_subdirs) ? "/qf" : ""));
1022
1023	if (tTd(41, 1))
1024	{
1025		dprintf("orderq:\n");
1026
1027		check = QueueLimitId;
1028		while (check != NULL)
1029		{
1030			dprintf("\tQueueLimitId = %s\n",
1031				check->queue_match);
1032			check = check->queue_next;
1033		}
1034
1035		check = QueueLimitSender;
1036		while (check != NULL)
1037		{
1038			dprintf("\tQueueLimitSender = %s\n",
1039				check->queue_match);
1040			check = check->queue_next;
1041		}
1042
1043		check = QueueLimitRecipient;
1044		while (check != NULL)
1045		{
1046			dprintf("\tQueueLimitRecipient = %s\n",
1047				check->queue_match);
1048			check = check->queue_next;
1049		}
1050	}
1051
1052	/* clear out old WorkQ */
1053	for (w = WorkQ; w != NULL; )
1054	{
1055		register WORK *nw = w->w_next;
1056
1057		WorkQ = nw;
1058		free(w->w_name);
1059		if (w->w_host != NULL)
1060			free(w->w_host);
1061		free((char *) w);
1062		w = nw;
1063	}
1064
1065	/* open the queue directory */
1066	f = opendir(qd);
1067	if (f == NULL)
1068	{
1069		syserr("orderq: cannot open \"%s\"", qid_printqueue(queuedir));
1070		return 0;
1071	}
1072
1073	/*
1074	**  Read the work directory.
1075	*/
1076
1077	while ((d = readdir(f)) != NULL)
1078	{
1079		FILE *cf;
1080		int qfver = 0;
1081		char lbuf[MAXNAME + 1];
1082		struct stat sbuf;
1083
1084		if (tTd(41, 50))
1085			dprintf("orderq: checking %s\n", d->d_name);
1086
1087		/* is this an interesting entry? */
1088		if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
1089			continue;
1090
1091		if (strlen(d->d_name) >= MAXQFNAME)
1092		{
1093			if (Verbose)
1094				printf("orderq: %s too long, %d max characters\n",
1095					d->d_name, MAXQFNAME);
1096			if (LogLevel > 0)
1097				sm_syslog(LOG_ALERT, NOQID,
1098					  "orderq: %s too long, %d max characters",
1099					  d->d_name, MAXQFNAME);
1100			continue;
1101		}
1102
1103		check = QueueLimitId;
1104		while (check != NULL)
1105		{
1106			if (strcontainedin(check->queue_match, d->d_name))
1107				break;
1108			else
1109				check = check->queue_next;
1110		}
1111		if (QueueLimitId != NULL && check == NULL)
1112			continue;
1113
1114		/* grow work list if necessary */
1115		if (++wn >= MaxQueueRun && MaxQueueRun > 0)
1116		{
1117			if (wn == MaxQueueRun && LogLevel > 0)
1118				sm_syslog(LOG_WARNING, NOQID,
1119					  "WorkList for %s maxed out at %d",
1120					  qid_printqueue(queuedir),
1121					  MaxQueueRun);
1122			continue;
1123		}
1124		if (wn >= WorkListSize)
1125		{
1126			grow_wlist(queuedir);
1127			if (wn >= WorkListSize)
1128				continue;
1129		}
1130		w = &WorkList[wn];
1131
1132		(void) snprintf(qf, sizeof qf, "%s/%s", qd, d->d_name);
1133		if (stat(qf, &sbuf) < 0)
1134		{
1135			if (errno != ENOENT)
1136				sm_syslog(LOG_INFO, NOQID,
1137					  "orderq: can't stat %s/%s",
1138					  qid_printqueue(queuedir), d->d_name);
1139			wn--;
1140			continue;
1141		}
1142		if (!bitset(S_IFREG, sbuf.st_mode))
1143		{
1144			/* Yikes!  Skip it or we will hang on open! */
1145			syserr("orderq: %s/%s is not a regular file",
1146			       qid_printqueue(queuedir), d->d_name);
1147			wn--;
1148			continue;
1149		}
1150
1151		/* avoid work if possible */
1152		if (QueueSortOrder == QSO_BYFILENAME &&
1153		    QueueLimitSender == NULL &&
1154		    QueueLimitRecipient == NULL)
1155		{
1156			w->w_name = newstr(d->d_name);
1157			w->w_host = NULL;
1158			w->w_lock = w->w_tooyoung = FALSE;
1159			w->w_pri = 0;
1160			w->w_ctime = 0;
1161			continue;
1162		}
1163
1164		/* open control file */
1165		cf = fopen(qf, "r");
1166		if (cf == NULL)
1167		{
1168			/* this may be some random person sending hir msgs */
1169			/* syserr("orderq: cannot open %s", cbuf); */
1170			if (tTd(41, 2))
1171				dprintf("orderq: cannot open %s: %s\n",
1172					d->d_name, errstring(errno));
1173			errno = 0;
1174			wn--;
1175			continue;
1176		}
1177		w->w_name = newstr(d->d_name);
1178		w->w_host = NULL;
1179		w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB);
1180		w->w_tooyoung = FALSE;
1181
1182		/* make sure jobs in creation don't clog queue */
1183		w->w_pri = 0x7fffffff;
1184		w->w_ctime = 0;
1185
1186		/* extract useful information */
1187		i = NEED_P | NEED_T;
1188		if (QueueLimitSender != NULL)
1189			i |= NEED_S;
1190		if (QueueLimitRecipient != NULL)
1191			i |= NEED_R;
1192		while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
1193		{
1194			int c;
1195			time_t age;
1196
1197			p = strchr(lbuf, '\n');
1198			if (p != NULL)
1199				*p = '\0';
1200			else
1201			{
1202				/* flush rest of overly long line */
1203				while ((c = getc(cf)) != EOF && c != '\n')
1204					continue;
1205			}
1206
1207			switch (lbuf[0])
1208			{
1209			  case 'V':
1210				qfver = atoi(&lbuf[1]);
1211				break;
1212
1213			  case 'P':
1214				w->w_pri = atol(&lbuf[1]);
1215				i &= ~NEED_P;
1216				break;
1217
1218			  case 'T':
1219				w->w_ctime = atol(&lbuf[1]);
1220				i &= ~NEED_T;
1221				break;
1222
1223			  case 'R':
1224				if (w->w_host == NULL &&
1225				    (p = strrchr(&lbuf[1], '@')) != NULL)
1226				{
1227					w->w_host = strrev(&p[1]);
1228					makelower(w->w_host);
1229				}
1230				if (QueueLimitRecipient == NULL)
1231				{
1232					i &= ~NEED_R;
1233					break;
1234				}
1235				if (qfver > 0)
1236				{
1237					p = strchr(&lbuf[1], ':');
1238					if (p == NULL)
1239						p = &lbuf[1];
1240				}
1241				else
1242					p = &lbuf[1];
1243				check = QueueLimitRecipient;
1244				while (check != NULL)
1245				{
1246					if (strcontainedin(check->queue_match,
1247							   p))
1248						break;
1249					else
1250						check = check->queue_next;
1251				}
1252				if (check != NULL)
1253					i &= ~NEED_R;
1254				break;
1255
1256			  case 'S':
1257				check = QueueLimitSender;
1258				while (check != NULL)
1259				{
1260					if (strcontainedin(check->queue_match,
1261							   &lbuf[1]))
1262						break;
1263					else
1264						check = check->queue_next;
1265				}
1266				if (check != NULL)
1267					i &= ~NEED_S;
1268				break;
1269
1270			  case 'K':
1271				age = curtime() - (time_t) atol(&lbuf[1]);
1272				if (age >= 0 && MinQueueAge > 0 &&
1273				    age < MinQueueAge)
1274					w->w_tooyoung = TRUE;
1275				break;
1276
1277			  case 'N':
1278				if (atol(&lbuf[1]) == 0)
1279					w->w_tooyoung = FALSE;
1280				break;
1281
1282# if _FFR_QUEUEDELAY
1283/*
1284			  case 'G':
1285				queuealg = atoi(lbuf[1]);
1286				break;
1287			  case 'Y':
1288				queuedelay = (time_t) atol(&lbuf[1]);
1289				break;
1290*/
1291# endif /* _FFR_QUEUEDELAY */
1292			}
1293		}
1294		(void) fclose(cf);
1295
1296		if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
1297		    bitset(NEED_R|NEED_S, i))
1298		{
1299			/* don't even bother sorting this job in */
1300			if (tTd(41, 49))
1301				dprintf("skipping %s (%x)\n", w->w_name, i);
1302			free(w->w_name);
1303			if (w->w_host)
1304				free(w->w_host);
1305			wn--;
1306		}
1307	}
1308	(void) closedir(f);
1309	wn++;
1310
1311	WorkQ = NULL;
1312	if (WorkList == NULL)
1313		return 0;
1314	wc = min(wn, WorkListSize);
1315	if (wc > MaxQueueRun && MaxQueueRun > 0)
1316		wc = MaxQueueRun;
1317
1318	if (QueueSortOrder == QSO_BYHOST)
1319	{
1320		/*
1321		**  Sort the work directory for the first time,
1322		**  based on host name, lock status, and priority.
1323		*/
1324
1325		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1);
1326
1327		/*
1328		**  If one message to host is locked, "lock" all messages
1329		**  to that host.
1330		*/
1331
1332		i = 0;
1333		while (i < wc)
1334		{
1335			if (!WorkList[i].w_lock)
1336			{
1337				i++;
1338				continue;
1339			}
1340			w = &WorkList[i];
1341			while (++i < wc)
1342			{
1343				if (WorkList[i].w_host == NULL &&
1344				    w->w_host == NULL)
1345					WorkList[i].w_lock = TRUE;
1346				else if (WorkList[i].w_host != NULL &&
1347					 w->w_host != NULL &&
1348					 sm_strcasecmp(WorkList[i].w_host, w->w_host) == 0)
1349					WorkList[i].w_lock = TRUE;
1350				else
1351					break;
1352			}
1353		}
1354
1355		/*
1356		**  Sort the work directory for the second time,
1357		**  based on lock status, host name, and priority.
1358		*/
1359
1360		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2);
1361	}
1362	else if (QueueSortOrder == QSO_BYTIME)
1363	{
1364		/*
1365		**  Simple sort based on submission time only.
1366		*/
1367
1368		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf3);
1369	}
1370	else if (QueueSortOrder == QSO_BYFILENAME)
1371	{
1372		/*
1373		**  Sort based on qf filename.
1374		*/
1375
1376		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf4);
1377	}
1378	else
1379	{
1380		/*
1381		**  Simple sort based on queue priority only.
1382		*/
1383
1384		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0);
1385	}
1386
1387	/*
1388	**  Convert the work list into canonical form.
1389	**	Should be turning it into a list of envelopes here perhaps.
1390	*/
1391
1392	for (i = wc; --i >= 0; )
1393	{
1394		w = (WORK *) xalloc(sizeof *w);
1395		w->w_name = WorkList[i].w_name;
1396		w->w_host = WorkList[i].w_host;
1397		w->w_lock = WorkList[i].w_lock;
1398		w->w_tooyoung = WorkList[i].w_tooyoung;
1399		w->w_pri = WorkList[i].w_pri;
1400		w->w_ctime = WorkList[i].w_ctime;
1401		w->w_next = WorkQ;
1402		WorkQ = w;
1403	}
1404	if (WorkList != NULL)
1405		free(WorkList);
1406	WorkList = NULL;
1407	WorkListSize = 0;
1408
1409	if (tTd(40, 1))
1410	{
1411		for (w = WorkQ; w != NULL; w = w->w_next)
1412		{
1413			if (w->w_host != NULL)
1414				dprintf("%22s: pri=%ld %s\n",
1415					w->w_name, w->w_pri, w->w_host);
1416			else
1417				dprintf("%32s: pri=%ld\n",
1418					w->w_name, w->w_pri);
1419		}
1420	}
1421
1422	return wn;
1423}
1424/*
1425**  GROW_WLIST -- make the work list larger
1426**
1427**	Parameters:
1428**		queuedir -- the index for the queue directory.
1429**
1430**	Returns:
1431**		none.
1432**
1433**	Side Effects:
1434**		Adds another QUEUESEGSIZE entries to WorkList if possible.
1435**		It can fail if there isn't enough memory, so WorkListSize
1436**		should be checked again upon return.
1437*/
1438
1439static void
1440grow_wlist(queuedir)
1441	int queuedir;
1442{
1443	if (tTd(41, 1))
1444		dprintf("grow_wlist: WorkListSize=%d\n", WorkListSize);
1445	if (WorkList == NULL)
1446	{
1447		WorkList = (WORK *) xalloc((sizeof *WorkList) *
1448					   (QUEUESEGSIZE + 1));
1449		WorkListSize = QUEUESEGSIZE;
1450	}
1451	else
1452	{
1453		int newsize = WorkListSize + QUEUESEGSIZE;
1454		WORK *newlist = (WORK *) realloc((char *)WorkList,
1455					  (unsigned)sizeof(WORK) * (newsize + 1));
1456
1457		if (newlist != NULL)
1458		{
1459			WorkListSize = newsize;
1460			WorkList = newlist;
1461			if (LogLevel > 1)
1462			{
1463				sm_syslog(LOG_INFO, NOQID,
1464					  "grew WorkList for %s to %d",
1465					  qid_printqueue(queuedir),
1466					  WorkListSize);
1467			}
1468		}
1469		else if (LogLevel > 0)
1470		{
1471			sm_syslog(LOG_ALERT, NOQID,
1472				  "FAILED to grow WorkList for %s to %d",
1473				  qid_printqueue(queuedir), newsize);
1474		}
1475	}
1476	if (tTd(41, 1))
1477		dprintf("grow_wlist: WorkListSize now %d\n", WorkListSize);
1478}
1479/*
1480**  WORKCMPF0 -- simple priority-only compare function.
1481**
1482**	Parameters:
1483**		a -- the first argument.
1484**		b -- the second argument.
1485**
1486**	Returns:
1487**		-1 if a < b
1488**		 0 if a == b
1489**		+1 if a > b
1490**
1491**	Side Effects:
1492**		none.
1493*/
1494
1495static int
1496workcmpf0(a, b)
1497	register WORK *a;
1498	register WORK *b;
1499{
1500	long pa = a->w_pri;
1501	long pb = b->w_pri;
1502
1503	if (pa == pb)
1504		return 0;
1505	else if (pa > pb)
1506		return 1;
1507	else
1508		return -1;
1509}
1510/*
1511**  WORKCMPF1 -- first compare function for ordering work based on host name.
1512**
1513**	Sorts on host name, lock status, and priority in that order.
1514**
1515**	Parameters:
1516**		a -- the first argument.
1517**		b -- the second argument.
1518**
1519**	Returns:
1520**		<0 if a < b
1521**		 0 if a == b
1522**		>0 if a > b
1523**
1524**	Side Effects:
1525**		none.
1526*/
1527
1528static int
1529workcmpf1(a, b)
1530	register WORK *a;
1531	register WORK *b;
1532{
1533	int i;
1534
1535	/* host name */
1536	if (a->w_host != NULL && b->w_host == NULL)
1537		return 1;
1538	else if (a->w_host == NULL && b->w_host != NULL)
1539		return -1;
1540	if (a->w_host != NULL && b->w_host != NULL &&
1541	    (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
1542		return i;
1543
1544	/* lock status */
1545	if (a->w_lock != b->w_lock)
1546		return b->w_lock - a->w_lock;
1547
1548	/* job priority */
1549	return a->w_pri - b->w_pri;
1550}
1551/*
1552**  WORKCMPF2 -- second compare function for ordering work based on host name.
1553**
1554**	Sorts on lock status, host name, and priority in that order.
1555**
1556**	Parameters:
1557**		a -- the first argument.
1558**		b -- the second argument.
1559**
1560**	Returns:
1561**		<0 if a < b
1562**		 0 if a == b
1563**		>0 if a > b
1564**
1565**	Side Effects:
1566**		none.
1567*/
1568
1569static int
1570workcmpf2(a, b)
1571	register WORK *a;
1572	register WORK *b;
1573{
1574	int i;
1575
1576	/* lock status */
1577	if (a->w_lock != b->w_lock)
1578		return a->w_lock - b->w_lock;
1579
1580	/* host name */
1581	if (a->w_host != NULL && b->w_host == NULL)
1582		return 1;
1583	else if (a->w_host == NULL && b->w_host != NULL)
1584		return -1;
1585	if (a->w_host != NULL && b->w_host != NULL &&
1586	    (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
1587		return i;
1588
1589	/* job priority */
1590	return a->w_pri - b->w_pri;
1591}
1592/*
1593**  WORKCMPF3 -- simple submission-time-only compare function.
1594**
1595**	Parameters:
1596**		a -- the first argument.
1597**		b -- the second argument.
1598**
1599**	Returns:
1600**		-1 if a < b
1601**		 0 if a == b
1602**		+1 if a > b
1603**
1604**	Side Effects:
1605**		none.
1606*/
1607
1608static int
1609workcmpf3(a, b)
1610	register WORK *a;
1611	register WORK *b;
1612{
1613	if (a->w_ctime > b->w_ctime)
1614		return 1;
1615	else if (a->w_ctime < b->w_ctime)
1616		return -1;
1617	else
1618		return 0;
1619}
1620/*
1621**  WORKCMPF4 -- compare based on file name
1622**
1623**	Parameters:
1624**		a -- the first argument.
1625**		b -- the second argument.
1626**
1627**	Returns:
1628**		-1 if a < b
1629**		 0 if a == b
1630**		+1 if a > b
1631**
1632**	Side Effects:
1633**		none.
1634*/
1635
1636static int
1637workcmpf4(a, b)
1638	register WORK *a;
1639	register WORK *b;
1640{
1641	return strcmp(a->w_name, b->w_name);
1642}
1643/*
1644**  STRREV -- reverse string
1645**
1646**	Returns a pointer to a new string that is the reverse of
1647**	the string pointed to by fwd.  The space for the new
1648**	string is obtained using xalloc().
1649**
1650**	Parameters:
1651**		fwd -- the string to reverse.
1652**
1653**	Returns:
1654**		the reversed string.
1655*/
1656
1657static char *
1658strrev(fwd)
1659	char *fwd;
1660{
1661	char *rev = NULL;
1662	int len, cnt;
1663
1664	len = strlen(fwd);
1665	rev = xalloc(len + 1);
1666	for (cnt = 0; cnt < len; ++cnt)
1667		rev[cnt] = fwd[len - cnt - 1];
1668	rev[len] = '\0';
1669	return rev;
1670}
1671/*
1672**  DOWORK -- do a work request.
1673**
1674**	Parameters:
1675**		queuedir -- the index of the queue directory for the job.
1676**		id -- the ID of the job to run.
1677**		forkflag -- if set, run this in background.
1678**		requeueflag -- if set, reinstantiate the queue quickly.
1679**			This is used when expanding aliases in the queue.
1680**			If forkflag is also set, it doesn't wait for the
1681**			child.
1682**		e - the envelope in which to run it.
1683**
1684**	Returns:
1685**		process id of process that is running the queue job.
1686**
1687**	Side Effects:
1688**		The work request is satisfied if possible.
1689*/
1690
1691pid_t
1692dowork(queuedir, id, forkflag, requeueflag, e)
1693	int queuedir;
1694	char *id;
1695	bool forkflag;
1696	bool requeueflag;
1697	register ENVELOPE *e;
1698{
1699	register pid_t pid;
1700
1701	if (tTd(40, 1))
1702		dprintf("dowork(%s/%s)\n", qid_printqueue(queuedir), id);
1703
1704	/*
1705	**  Fork for work.
1706	*/
1707
1708	if (forkflag)
1709	{
1710		/*
1711		**  Since the delivery may happen in a child and the
1712		**  parent does not wait, the parent may close the
1713		**  maps thereby removing any shared memory used by
1714		**  the map.  Therefore, close the maps now so the
1715		**  child will dynamically open them if necessary.
1716		*/
1717
1718		closemaps();
1719
1720		pid = fork();
1721		if (pid < 0)
1722		{
1723			syserr("dowork: cannot fork");
1724			return 0;
1725		}
1726		else if (pid > 0)
1727		{
1728			/* parent -- clean out connection cache */
1729			mci_flush(FALSE, NULL);
1730		}
1731		else
1732		{
1733			/* child -- error messages to the transcript */
1734			QuickAbort = OnlyOneError = FALSE;
1735		}
1736	}
1737	else
1738	{
1739		pid = 0;
1740	}
1741
1742	if (pid == 0)
1743	{
1744		/*
1745		**  CHILD
1746		**	Lock the control file to avoid duplicate deliveries.
1747		**		Then run the file as though we had just read it.
1748		**	We save an idea of the temporary name so we
1749		**		can recover on interrupt.
1750		*/
1751
1752		/* set basic modes, etc. */
1753		(void) alarm(0);
1754		clearstats();
1755		clearenvelope(e, FALSE);
1756		e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
1757		set_delivery_mode(SM_DELIVER, e);
1758		e->e_errormode = EM_MAIL;
1759		e->e_id = id;
1760		e->e_queuedir = queuedir;
1761		GrabTo = UseErrorsTo = FALSE;
1762		ExitStat = EX_OK;
1763		if (forkflag)
1764		{
1765			disconnect(1, e);
1766			OpMode = MD_QUEUERUN;
1767		}
1768		sm_setproctitle(TRUE, e, "%s: from queue", qid_printname(e));
1769		if (LogLevel > 76)
1770			sm_syslog(LOG_DEBUG, e->e_id,
1771				  "dowork, pid=%d",
1772				  getpid());
1773
1774		/* don't use the headers from sendmail.cf... */
1775		e->e_header = NULL;
1776
1777		/* read the queue control file -- return if locked */
1778		if (!readqf(e))
1779		{
1780			if (tTd(40, 4) && e->e_id != NULL)
1781				dprintf("readqf(%s) failed\n",
1782					qid_printname(e));
1783			e->e_id = NULL;
1784			if (forkflag)
1785				finis(FALSE, EX_OK);
1786			else
1787				return 0;
1788		}
1789
1790		e->e_flags |= EF_INQUEUE;
1791		eatheader(e, requeueflag);
1792
1793		if (requeueflag)
1794			queueup(e, FALSE);
1795
1796		/* do the delivery */
1797		sendall(e, SM_DELIVER);
1798
1799		/* finish up and exit */
1800		if (forkflag)
1801			finis(TRUE, ExitStat);
1802		else
1803			dropenvelope(e, TRUE);
1804	}
1805	e->e_id = NULL;
1806	return pid;
1807}
1808/*
1809**  READQF -- read queue file and set up environment.
1810**
1811**	Parameters:
1812**		e -- the envelope of the job to run.
1813**
1814**	Returns:
1815**		TRUE if it successfully read the queue file.
1816**		FALSE otherwise.
1817**
1818**	Side Effects:
1819**		The queue file is returned locked.
1820*/
1821
1822static bool
1823readqf(e)
1824	register ENVELOPE *e;
1825{
1826	register FILE *qfp;
1827	ADDRESS *ctladdr;
1828	struct stat st;
1829	char *bp;
1830	int qfver = 0;
1831	long hdrsize = 0;
1832	register char *p;
1833	char *orcpt = NULL;
1834	bool nomore = FALSE;
1835	MODE_T qsafe;
1836	char qf[MAXPATHLEN];
1837	char buf[MAXLINE];
1838
1839	/*
1840	**  Read and process the file.
1841	*/
1842
1843	(void) strlcpy(qf, queuename(e, 'q'), sizeof qf);
1844	qfp = fopen(qf, "r+");
1845	if (qfp == NULL)
1846	{
1847		int save_errno = errno;
1848
1849		if (tTd(40, 8))
1850			dprintf("readqf(%s): fopen failure (%s)\n",
1851				qf, errstring(errno));
1852		errno = save_errno;
1853		if (errno != ENOENT
1854		    )
1855			syserr("readqf: no control file %s", qf);
1856		return FALSE;
1857	}
1858
1859	if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
1860	{
1861		/* being processed by another queuer */
1862		if (Verbose)
1863			printf("%s: locked\n", e->e_id);
1864		if (tTd(40, 8))
1865			dprintf("%s: locked\n", e->e_id);
1866		if (LogLevel > 19)
1867			sm_syslog(LOG_DEBUG, e->e_id, "locked");
1868		(void) fclose(qfp);
1869		return FALSE;
1870	}
1871
1872	/*
1873	**  Check the queue file for plausibility to avoid attacks.
1874	*/
1875
1876	if (fstat(fileno(qfp), &st) < 0)
1877	{
1878		/* must have been being processed by someone else */
1879		if (tTd(40, 8))
1880			dprintf("readqf(%s): fstat failure (%s)\n",
1881				qf, errstring(errno));
1882		(void) fclose(qfp);
1883		return FALSE;
1884	}
1885
1886	qsafe = S_IWOTH|S_IWGRP;
1887#if _FFR_QUEUE_FILE_MODE
1888	if (bitset(S_IWGRP, QueueFileMode))
1889		qsafe &= ~S_IWGRP;
1890#endif /* _FFR_QUEUE_FILE_MODE */
1891
1892	if ((st.st_uid != geteuid() &&
1893	     st.st_uid != TrustedUid &&
1894	     geteuid() != RealUid) ||
1895	    bitset(qsafe, st.st_mode))
1896	{
1897		if (LogLevel > 0)
1898		{
1899			sm_syslog(LOG_ALERT, e->e_id,
1900				  "bogus queue file, uid=%d, mode=%o",
1901				  st.st_uid, st.st_mode);
1902		}
1903		if (tTd(40, 8))
1904			dprintf("readqf(%s): bogus file\n", qf);
1905		loseqfile(e, "bogus file uid in mqueue");
1906		(void) fclose(qfp);
1907		return FALSE;
1908	}
1909
1910	if (st.st_size == 0)
1911	{
1912		/* must be a bogus file -- if also old, just remove it */
1913		if (st.st_ctime + 10 * 60 < curtime())
1914		{
1915			(void) xunlink(queuename(e, 'd'));
1916			(void) xunlink(queuename(e, 'q'));
1917		}
1918		(void) fclose(qfp);
1919		return FALSE;
1920	}
1921
1922	if (st.st_nlink == 0)
1923	{
1924		/*
1925		**  Race condition -- we got a file just as it was being
1926		**  unlinked.  Just assume it is zero length.
1927		*/
1928
1929		(void) fclose(qfp);
1930		return FALSE;
1931	}
1932
1933	/* good file -- save this lock */
1934	e->e_lockfp = qfp;
1935
1936	/* do basic system initialization */
1937	initsys(e);
1938	define('i', e->e_id, e);
1939
1940	LineNumber = 0;
1941	e->e_flags |= EF_GLOBALERRS;
1942	OpMode = MD_QUEUERUN;
1943	ctladdr = NULL;
1944	e->e_dfino = -1;
1945	e->e_msgsize = -1;
1946# if _FFR_QUEUEDELAY
1947	e->e_queuealg = QD_LINEAR;
1948	e->e_queuedelay = (time_t) 0;
1949# endif /* _FFR_QUEUEDELAY */
1950	while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
1951	{
1952		u_long qflags;
1953		ADDRESS *q;
1954		int mid;
1955		auto char *ep;
1956
1957		if (tTd(40, 4))
1958			dprintf("+++++ %s\n", bp);
1959		if (nomore)
1960		{
1961			/* hack attack */
1962			syserr("SECURITY ALERT: extra data in qf: %s", bp);
1963			(void) fclose(qfp);
1964			loseqfile(e, "bogus queue line");
1965			return FALSE;
1966		}
1967		switch (bp[0])
1968		{
1969		  case 'V':		/* queue file version number */
1970			qfver = atoi(&bp[1]);
1971			if (qfver <= QF_VERSION)
1972				break;
1973			syserr("Version number in qf (%d) greater than max (%d)",
1974				qfver, QF_VERSION);
1975			(void) fclose(qfp);
1976			loseqfile(e, "unsupported qf file version");
1977			return FALSE;
1978
1979		  case 'C':		/* specify controlling user */
1980			ctladdr = setctluser(&bp[1], qfver);
1981			break;
1982
1983		  case 'Q':		/* original recipient */
1984			orcpt = newstr(&bp[1]);
1985			break;
1986
1987		  case 'R':		/* specify recipient */
1988			p = bp;
1989			qflags = 0;
1990			if (qfver >= 1)
1991			{
1992				/* get flag bits */
1993				while (*++p != '\0' && *p != ':')
1994				{
1995					switch (*p)
1996					{
1997					  case 'N':
1998						qflags |= QHASNOTIFY;
1999						break;
2000
2001					  case 'S':
2002						qflags |= QPINGONSUCCESS;
2003						break;
2004
2005					  case 'F':
2006						qflags |= QPINGONFAILURE;
2007						break;
2008
2009					  case 'D':
2010						qflags |= QPINGONDELAY;
2011						break;
2012
2013					  case 'P':
2014						qflags |= QPRIMARY;
2015						break;
2016					}
2017				}
2018			}
2019			else
2020				qflags |= QPRIMARY;
2021			q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e);
2022			if (q != NULL)
2023			{
2024				q->q_alias = ctladdr;
2025				if (qfver >= 1)
2026					q->q_flags &= ~Q_PINGFLAGS;
2027				q->q_flags |= qflags;
2028				q->q_orcpt = orcpt;
2029				(void) recipient(q, &e->e_sendqueue, 0, e);
2030			}
2031			orcpt = NULL;
2032			break;
2033
2034		  case 'E':		/* specify error recipient */
2035			/* no longer used */
2036			break;
2037
2038		  case 'H':		/* header */
2039			(void) chompheader(&bp[1], CHHDR_QUEUE, NULL, e);
2040			hdrsize += strlen(&bp[1]);
2041			break;
2042
2043		  case 'L':		/* Solaris Content-Length: */
2044		  case 'M':		/* message */
2045			/* ignore this; we want a new message next time */
2046			break;
2047
2048		  case 'S':		/* sender */
2049			setsender(newstr(&bp[1]), e, NULL, '\0', TRUE);
2050			break;
2051
2052		  case 'B':		/* body type */
2053			e->e_bodytype = newstr(&bp[1]);
2054			break;
2055
2056# if _FFR_SAVE_CHARSET
2057		  case 'X':		/* character set */
2058			e->e_charset = newstr(&bp[1]);
2059			break;
2060# endif /* _FFR_SAVE_CHARSET */
2061
2062		  case 'D':		/* data file name */
2063			/* obsolete -- ignore */
2064			break;
2065
2066		  case 'T':		/* init time */
2067			e->e_ctime = atol(&bp[1]);
2068			break;
2069
2070		  case 'I':		/* data file's inode number */
2071			/* regenerated below */
2072			break;
2073
2074		  case 'K':	/* time of last delivery attempt */
2075			e->e_dtime = atol(&buf[1]);
2076			break;
2077
2078# if _FFR_QUEUEDELAY
2079		  case 'G':	/* queue delay algorithm */
2080			e->e_queuealg = atoi(&buf[1]);
2081			break;
2082		  case 'Y':	/* current delay */
2083			e->e_queuedelay = (time_t) atol(&buf[1]);
2084			break;
2085# endif /* _FFR_QUEUEDELAY */
2086
2087		  case 'N':		/* number of delivery attempts */
2088			e->e_ntries = atoi(&buf[1]);
2089
2090			/* if this has been tried recently, let it be */
2091			if (e->e_ntries > 0 && e->e_dtime <= curtime() &&
2092			    curtime() < e->e_dtime + queuedelay(e))
2093			{
2094				char *howlong;
2095
2096				howlong = pintvl(curtime() - e->e_dtime, TRUE);
2097				if (Verbose)
2098					printf("%s: too young (%s)\n",
2099					       e->e_id, howlong);
2100				if (tTd(40, 8))
2101					dprintf("%s: too young (%s)\n",
2102						e->e_id, howlong);
2103				if (LogLevel > 19)
2104					sm_syslog(LOG_DEBUG, e->e_id,
2105						  "too young (%s)",
2106						  howlong);
2107				e->e_id = NULL;
2108				unlockqueue(e);
2109				return FALSE;
2110			}
2111			define(macid("{ntries}", NULL), newstr(&buf[1]), e);
2112
2113# if NAMED_BIND
2114			/* adjust BIND parameters immediately */
2115			if (e->e_ntries == 0)
2116			{
2117				_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
2118				_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
2119			}
2120			else
2121			{
2122				_res.retry = TimeOuts.res_retry[RES_TO_NORMAL];
2123				_res.retrans = TimeOuts.res_retrans[RES_TO_NORMAL];
2124			}
2125# endif /* NAMED_BIND */
2126			break;
2127
2128		  case 'P':		/* message priority */
2129			e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
2130			break;
2131
2132		  case 'F':		/* flag bits */
2133			if (strncmp(bp, "From ", 5) == 0)
2134			{
2135				/* we are being spoofed! */
2136				syserr("SECURITY ALERT: bogus qf line %s", bp);
2137				(void) fclose(qfp);
2138				loseqfile(e, "bogus queue line");
2139				return FALSE;
2140			}
2141			for (p = &bp[1]; *p != '\0'; p++)
2142			{
2143				switch (*p)
2144				{
2145				  case 'w':	/* warning sent */
2146					e->e_flags |= EF_WARNING;
2147					break;
2148
2149				  case 'r':	/* response */
2150					e->e_flags |= EF_RESPONSE;
2151					break;
2152
2153				  case '8':	/* has 8 bit data */
2154					e->e_flags |= EF_HAS8BIT;
2155					break;
2156
2157				  case 'b':	/* delete Bcc: header */
2158					e->e_flags |= EF_DELETE_BCC;
2159					break;
2160
2161				  case 'd':	/* envelope has DSN RET= */
2162					e->e_flags |= EF_RET_PARAM;
2163					break;
2164
2165				  case 'n':	/* don't return body */
2166					e->e_flags |= EF_NO_BODY_RETN;
2167					break;
2168				}
2169			}
2170			break;
2171
2172		  case 'Z':		/* original envelope id from ESMTP */
2173			e->e_envid = newstr(&bp[1]);
2174			define(macid("{dsn_envid}", NULL), newstr(&bp[1]), e);
2175			break;
2176
2177		  case 'A':		/* AUTH= parameter */
2178			e->e_auth_param = newstr(&bp[1]);
2179			break;
2180
2181		  case '$':		/* define macro */
2182			{
2183				char *p;
2184
2185				mid = macid(&bp[1], &ep);
2186				p = newstr(ep);
2187				define(mid, p, e);
2188
2189				/*
2190				**  HACK ALERT: Unfortunately, 8.10 and
2191				**  8.11 reused the ${if_addr} and
2192				**  ${if_family} macros for both the incoming
2193				**  interface address/family (getrequests())
2194				**  and the outgoing interface address/family
2195				**  (makeconnection()).  In order for D_BINDIF
2196				**  to work properly, have to preserve the
2197				**  incoming information in the queue file for
2198				**  later delivery attempts.  The original
2199				**  information is stored in the envelope
2200				**  in readqf() so it can be stored in
2201				**  queueup_macros().  This should be fixed
2202				**  in 8.12.
2203				*/
2204
2205				if (strcmp(macname(mid), "if_addr") == 0)
2206					e->e_if_macros[EIF_ADDR] = p;
2207			}
2208			break;
2209
2210		  case '.':		/* terminate file */
2211			nomore = TRUE;
2212			break;
2213
2214		  default:
2215			syserr("readqf: %s: line %d: bad line \"%s\"",
2216				qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
2217			(void) fclose(qfp);
2218			loseqfile(e, "unrecognized line");
2219			return FALSE;
2220		}
2221
2222		if (bp != buf)
2223			free(bp);
2224	}
2225
2226	/*
2227	**  If we haven't read any lines, this queue file is empty.
2228	**  Arrange to remove it without referencing any null pointers.
2229	*/
2230
2231	if (LineNumber == 0)
2232	{
2233		errno = 0;
2234		e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
2235		return TRUE;
2236	}
2237
2238	/* possibly set ${dsn_ret} macro */
2239	if (bitset(EF_RET_PARAM, e->e_flags))
2240	{
2241		if (bitset(EF_NO_BODY_RETN, e->e_flags))
2242			define(macid("{dsn_ret}", NULL), "hdrs", e);
2243		else
2244			define(macid("{dsn_ret}", NULL), "full", e);
2245	}
2246
2247	/*
2248	**  Arrange to read the data file.
2249	*/
2250
2251	p = queuename(e, 'd');
2252	e->e_dfp = fopen(p, "r");
2253	if (e->e_dfp == NULL)
2254	{
2255		syserr("readqf: cannot open %s", p);
2256	}
2257	else
2258	{
2259		e->e_flags |= EF_HAS_DF;
2260		if (fstat(fileno(e->e_dfp), &st) >= 0)
2261		{
2262			e->e_msgsize = st.st_size + hdrsize;
2263			e->e_dfdev = st.st_dev;
2264			e->e_dfino = st.st_ino;
2265		}
2266	}
2267
2268	return TRUE;
2269}
2270/*
2271**  PRTSTR -- print a string, "unprintable" characters are shown as \oct
2272**
2273**	Parameters:
2274**		s -- string to print
2275**		ml -- maximum length of output
2276**
2277**	Returns:
2278**		none.
2279**
2280**	Side Effects:
2281**		Prints a string on stdout.
2282*/
2283
2284static void
2285prtstr(s, ml)
2286	char *s;
2287	int ml;
2288{
2289	char c;
2290
2291	if (s == NULL)
2292		return;
2293	while (ml-- > 0 && ((c = *s++) != '\0'))
2294	{
2295		if (c == '\\')
2296		{
2297			if (ml-- > 0)
2298			{
2299				putchar(c);
2300				putchar(c);
2301			}
2302		}
2303		else if (isascii(c) && isprint(c))
2304			putchar(c);
2305		else
2306		{
2307			if ((ml -= 3) > 0)
2308				printf("\\%03o", c);
2309		}
2310	}
2311}
2312/*
2313**  PRINTQUEUE -- print out a representation of the mail queue
2314**
2315**	Parameters:
2316**		none.
2317**
2318**	Returns:
2319**		none.
2320**
2321**	Side Effects:
2322**		Prints a listing of the mail queue on the standard output.
2323*/
2324
2325void
2326printqueue()
2327{
2328	int i, nrequests = 0;
2329
2330	for (i = 0; i < NumQueues; i++)
2331		nrequests += print_single_queue(i);
2332	if (NumQueues > 1)
2333		printf("\t\tTotal Requests: %d\n", nrequests);
2334}
2335/*
2336**  PRINT_SINGLE_QUEUE -- print out a representation of a single mail queue
2337**
2338**	Parameters:
2339**		queuedir -- queue directory
2340**
2341**	Returns:
2342**		none.
2343**
2344**	Side Effects:
2345**		Prints a listing of the mail queue on the standard output.
2346*/
2347
2348static int
2349print_single_queue(queuedir)
2350	int queuedir;
2351{
2352	register WORK *w;
2353	FILE *f;
2354	int nrequests;
2355	char qd[MAXPATHLEN];
2356	char qddf[MAXPATHLEN];
2357	char buf[MAXLINE];
2358
2359	if (queuedir == NOQDIR)
2360	{
2361		(void) strlcpy(qd, ".", sizeof qd);
2362		(void) strlcpy(qddf, ".", sizeof qddf);
2363	}
2364	else
2365	{
2366		(void) snprintf(qd, sizeof qd, "%s%s",
2367				QPaths[queuedir].qp_name,
2368				(bitset(QP_SUBQF, QPaths[queuedir].qp_subdirs) ? "/qf" : ""));
2369		(void) snprintf(qddf, sizeof qddf, "%s%s",
2370				QPaths[queuedir].qp_name,
2371				(bitset(QP_SUBDF, QPaths[queuedir].qp_subdirs) ? "/df" : ""));
2372	}
2373
2374	/*
2375	**  Check for permission to print the queue
2376	*/
2377
2378	if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
2379	{
2380		struct stat st;
2381# ifdef NGROUPS_MAX
2382		int n;
2383		extern GIDSET_T InitialGidSet[NGROUPS_MAX];
2384# endif /* NGROUPS_MAX */
2385
2386		if (stat(qd, &st) < 0)
2387		{
2388			syserr("Cannot stat %s", qid_printqueue(queuedir));
2389			return 0;
2390		}
2391# ifdef NGROUPS_MAX
2392		n = NGROUPS_MAX;
2393		while (--n >= 0)
2394		{
2395			if (InitialGidSet[n] == st.st_gid)
2396				break;
2397		}
2398		if (n < 0 && RealGid != st.st_gid)
2399# else /* NGROUPS_MAX */
2400		if (RealGid != st.st_gid)
2401# endif /* NGROUPS_MAX */
2402		{
2403			usrerr("510 You are not permitted to see the queue");
2404			setstat(EX_NOPERM);
2405			return 0;
2406		}
2407	}
2408
2409	/*
2410	**  Read and order the queue.
2411	*/
2412
2413	nrequests = orderq(queuedir, TRUE);
2414
2415	/*
2416	**  Print the work list that we have read.
2417	*/
2418
2419	/* first see if there is anything */
2420	if (nrequests <= 0)
2421	{
2422		printf("%s is empty\n", qid_printqueue(queuedir));
2423		return 0;
2424	}
2425
2426	CurrentLA = sm_getla(NULL);	/* get load average */
2427
2428	printf("\t\t%s (%d request%s", qid_printqueue(queuedir), nrequests,
2429	       nrequests == 1 ? "" : "s");
2430	if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
2431		printf(", only %d printed", MaxQueueRun);
2432	if (Verbose)
2433		printf(")\n----Q-ID---- --Size-- -Priority- ---Q-Time--- ---------Sender/Recipient--------\n");
2434	else
2435		printf(")\n----Q-ID---- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
2436	for (w = WorkQ; w != NULL; w = w->w_next)
2437	{
2438		struct stat st;
2439		auto time_t submittime = 0;
2440		long dfsize;
2441		int flags = 0;
2442		int qfver;
2443		char statmsg[MAXLINE];
2444		char bodytype[MAXNAME + 1];
2445		char qf[MAXPATHLEN];
2446
2447		printf("%12s", w->w_name + 2);
2448		(void) snprintf(qf, sizeof qf, "%s/%s", qd, w->w_name);
2449		f = fopen(qf, "r");
2450		if (f == NULL)
2451		{
2452			printf(" (job completed)\n");
2453			errno = 0;
2454			continue;
2455		}
2456		w->w_name[0] = 'd';
2457		(void) snprintf(qf, sizeof qf, "%s/%s", qddf, w->w_name);
2458		if (stat(qf, &st) >= 0)
2459			dfsize = st.st_size;
2460		else
2461			dfsize = -1;
2462		if (w->w_lock)
2463			printf("*");
2464		else if (w->w_tooyoung)
2465			printf("-");
2466		else if (shouldqueue(w->w_pri, w->w_ctime))
2467			printf("X");
2468		else
2469			printf(" ");
2470		errno = 0;
2471
2472		statmsg[0] = bodytype[0] = '\0';
2473		qfver = 0;
2474		while (fgets(buf, sizeof buf, f) != NULL)
2475		{
2476			register int i;
2477			register char *p;
2478
2479			fixcrlf(buf, TRUE);
2480			switch (buf[0])
2481			{
2482			  case 'V':	/* queue file version */
2483				qfver = atoi(&buf[1]);
2484				break;
2485
2486			  case 'M':	/* error message */
2487				if ((i = strlen(&buf[1])) >= sizeof statmsg)
2488					i = sizeof statmsg - 1;
2489				memmove(statmsg, &buf[1], i);
2490				statmsg[i] = '\0';
2491				break;
2492
2493			  case 'B':	/* body type */
2494				if ((i = strlen(&buf[1])) >= sizeof bodytype)
2495					i = sizeof bodytype - 1;
2496				memmove(bodytype, &buf[1], i);
2497				bodytype[i] = '\0';
2498				break;
2499
2500			  case 'S':	/* sender name */
2501				if (Verbose)
2502				{
2503					printf("%8ld %10ld%c%.12s ",
2504					       dfsize,
2505					       w->w_pri,
2506					       bitset(EF_WARNING, flags) ? '+' : ' ',
2507					       ctime(&submittime) + 4);
2508					prtstr(&buf[1], 78);
2509				}
2510				else
2511				{
2512					printf("%8ld %.16s ", dfsize,
2513					    ctime(&submittime));
2514					prtstr(&buf[1], 40);
2515				}
2516				if (statmsg[0] != '\0' || bodytype[0] != '\0')
2517				{
2518					printf("\n    %10.10s", bodytype);
2519					if (statmsg[0] != '\0')
2520						printf("   (%.*s)",
2521						       Verbose ? 100 : 60,
2522						       statmsg);
2523				}
2524				break;
2525
2526			  case 'C':	/* controlling user */
2527				if (Verbose)
2528					printf("\n\t\t\t\t      (---%.74s---)",
2529					       &buf[1]);
2530				break;
2531
2532			  case 'R':	/* recipient name */
2533				p = &buf[1];
2534				if (qfver >= 1)
2535				{
2536					p = strchr(p, ':');
2537					if (p == NULL)
2538						break;
2539					p++;
2540				}
2541				if (Verbose)
2542				{
2543					printf("\n\t\t\t\t\t      ");
2544					prtstr(p, 73);
2545				}
2546				else
2547				{
2548					printf("\n\t\t\t\t       ");
2549					prtstr(p, 40);
2550				}
2551				break;
2552
2553			  case 'T':	/* creation time */
2554				submittime = atol(&buf[1]);
2555				break;
2556
2557			  case 'F':	/* flag bits */
2558				for (p = &buf[1]; *p != '\0'; p++)
2559				{
2560					switch (*p)
2561					{
2562					  case 'w':
2563						flags |= EF_WARNING;
2564						break;
2565					}
2566				}
2567			}
2568		}
2569		if (submittime == (time_t) 0)
2570			printf(" (no control file)");
2571		printf("\n");
2572		(void) fclose(f);
2573	}
2574	return nrequests;
2575}
2576/*
2577**  QUEUENAME -- build a file name in the queue directory for this envelope.
2578**
2579**	Parameters:
2580**		e -- envelope to build it in/from.
2581**		type -- the file type, used as the first character
2582**			of the file name.
2583**
2584**	Returns:
2585**		a pointer to the queue name (in a static buffer).
2586**
2587**	Side Effects:
2588**		If no id code is already assigned, queuename() will
2589**		assign an id code with assign_queueid().  If no queue
2590**		directory is assigned, one will be set with setnewqueue().
2591*/
2592
2593char *
2594queuename(e, type)
2595	register ENVELOPE *e;
2596	int type;
2597{
2598	char *sub = "";
2599	static char buf[MAXPATHLEN];
2600
2601	/* Assign an ID if needed */
2602	if (e->e_id == NULL)
2603		assign_queueid(e);
2604
2605	/* Assign a queue directory if needed */
2606	if (e->e_queuedir == NOQDIR)
2607		setnewqueue(e);
2608
2609	if (e->e_queuedir == NOQDIR)
2610		(void) snprintf(buf, sizeof buf, "%cf%s",
2611				type, e->e_id);
2612	else
2613	{
2614		switch (type)
2615		{
2616		  case 'd':
2617			if (bitset(QP_SUBDF, QPaths[e->e_queuedir].qp_subdirs))
2618				sub = "/df";
2619			break;
2620
2621		  case 'T':
2622		  case 't':
2623		  case 'Q':
2624		  case 'q':
2625			if (bitset(QP_SUBQF, QPaths[e->e_queuedir].qp_subdirs))
2626				sub = "/qf";
2627			break;
2628
2629		  case 'x':
2630			if (bitset(QP_SUBXF, QPaths[e->e_queuedir].qp_subdirs))
2631				sub = "/xf";
2632			break;
2633		}
2634
2635		(void) snprintf(buf, sizeof buf, "%s%s/%cf%s",
2636				QPaths[e->e_queuedir].qp_name,
2637				sub, type, e->e_id);
2638	}
2639
2640	if (tTd(7, 2))
2641		dprintf("queuename: %s\n", buf);
2642	return buf;
2643}
2644/*
2645**  ASSIGN_QUEUEID -- assign a queue ID for this envelope.
2646**
2647**	Assigns an id code if one does not already exist.
2648**	This code assumes that nothing will remain in the queue for
2649**	longer than 60 years.  It is critical that files with the given
2650**	name not already exist in the queue.
2651**	Also initializes e_queuedir to NOQDIR.
2652**
2653**	Parameters:
2654**		e -- envelope to set it in.
2655**
2656**	Returns:
2657**		none.
2658*/
2659
2660static char	Base60Code[] =	"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx";
2661
2662void
2663assign_queueid(e)
2664	register ENVELOPE *e;
2665{
2666	pid_t pid = getpid();
2667	static char cX = 0;
2668	static long random_offset;
2669	struct tm *tm;
2670	char idbuf[MAXQFNAME - 2];
2671
2672	if (e->e_id != NULL)
2673		return;
2674
2675	/* see if we need to get a new base time/pid */
2676	if (cX >= 60 || LastQueueTime == 0 || LastQueuePid != pid)
2677	{
2678		time_t then = LastQueueTime;
2679
2680		/* if the first time through, pick a random offset */
2681		if (LastQueueTime == 0)
2682			random_offset = get_random();
2683
2684		while ((LastQueueTime = curtime()) == then &&
2685		       LastQueuePid == pid)
2686		{
2687			(void) sleep(1);
2688		}
2689		LastQueuePid = getpid();
2690		cX = 0;
2691	}
2692	if (tTd(7, 50))
2693		dprintf("assign_queueid: random_offset = %ld (%d)\n",
2694			random_offset, (int)(cX + random_offset) % 60);
2695
2696	tm = gmtime(&LastQueueTime);
2697	idbuf[0] = Base60Code[tm->tm_year % 60];
2698	idbuf[1] = Base60Code[tm->tm_mon];
2699	idbuf[2] = Base60Code[tm->tm_mday];
2700	idbuf[3] = Base60Code[tm->tm_hour];
2701	idbuf[4] = Base60Code[tm->tm_min];
2702	idbuf[5] = Base60Code[tm->tm_sec];
2703	idbuf[6] = Base60Code[((int)cX++ + random_offset) % 60];
2704	(void) snprintf(&idbuf[7], sizeof idbuf - 7, "%05d",
2705			(int) LastQueuePid);
2706	e->e_id = newstr(idbuf);
2707	define('i', e->e_id, e);
2708	e->e_queuedir = NOQDIR;
2709	if (tTd(7, 1))
2710		dprintf("assign_queueid: assigned id %s, e=%lx\n",
2711			e->e_id, (u_long) e);
2712	if (LogLevel > 93)
2713		sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
2714}
2715/*
2716**  SYNC_QUEUE_TIME -- Assure exclusive PID in any given second
2717**
2718**	Make sure one PID can't be used by two processes in any one second.
2719**
2720**		If the system rotates PIDs fast enough, may get the
2721**		same pid in the same second for two distinct processes.
2722**		This will interfere with the queue file naming system.
2723**
2724**	Parameters:
2725**		none
2726**
2727**	Returns:
2728**		none
2729*/
2730void
2731sync_queue_time()
2732{
2733# if FAST_PID_RECYCLE
2734	if (OpMode != MD_TEST &&
2735	    OpMode != MD_VERIFY &&
2736	    LastQueueTime > 0 &&
2737	    LastQueuePid == getpid() &&
2738	    curtime() == LastQueueTime)
2739		(void) sleep(1);
2740# endif /* FAST_PID_RECYCLE */
2741}
2742/*
2743**  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
2744**
2745**	Parameters:
2746**		e -- the envelope to unlock.
2747**
2748**	Returns:
2749**		none
2750**
2751**	Side Effects:
2752**		unlocks the queue for `e'.
2753*/
2754
2755void
2756unlockqueue(e)
2757	ENVELOPE *e;
2758{
2759	if (tTd(51, 4))
2760		dprintf("unlockqueue(%s)\n",
2761			e->e_id == NULL ? "NOQUEUE" : e->e_id);
2762
2763
2764	/* if there is a lock file in the envelope, close it */
2765	if (e->e_lockfp != NULL)
2766		(void) fclose(e->e_lockfp);
2767	e->e_lockfp = NULL;
2768
2769	/* don't create a queue id if we don't already have one */
2770	if (e->e_id == NULL)
2771		return;
2772
2773	/* remove the transcript */
2774	if (LogLevel > 87)
2775		sm_syslog(LOG_DEBUG, e->e_id, "unlock");
2776	if (!tTd(51, 104))
2777		xunlink(queuename(e, 'x'));
2778
2779}
2780/*
2781**  SETCTLUSER -- create a controlling address
2782**
2783**	Create a fake "address" given only a local login name; this is
2784**	used as a "controlling user" for future recipient addresses.
2785**
2786**	Parameters:
2787**		user -- the user name of the controlling user.
2788**		qfver -- the version stamp of this qf file.
2789**
2790**	Returns:
2791**		An address descriptor for the controlling user.
2792**
2793**	Side Effects:
2794**		none.
2795*/
2796
2797static ADDRESS *
2798setctluser(user, qfver)
2799	char *user;
2800	int qfver;
2801{
2802	register ADDRESS *a;
2803	struct passwd *pw;
2804	char *p;
2805
2806	/*
2807	**  See if this clears our concept of controlling user.
2808	*/
2809
2810	if (user == NULL || *user == '\0')
2811		return NULL;
2812
2813	/*
2814	**  Set up addr fields for controlling user.
2815	*/
2816
2817	a = (ADDRESS *) xalloc(sizeof *a);
2818	memset((char *) a, '\0', sizeof *a);
2819
2820	if (*user == '\0')
2821	{
2822		p = NULL;
2823		a->q_user = newstr(DefUser);
2824	}
2825	else if (*user == ':')
2826	{
2827		p = &user[1];
2828		a->q_user = newstr(p);
2829	}
2830	else
2831	{
2832		p = strtok(user, ":");
2833		a->q_user = newstr(user);
2834		if (qfver >= 2)
2835		{
2836			if ((p = strtok(NULL, ":")) != NULL)
2837				a->q_uid = atoi(p);
2838			if ((p = strtok(NULL, ":")) != NULL)
2839				a->q_gid = atoi(p);
2840			if ((p = strtok(NULL, ":")) != NULL)
2841				a->q_flags |= QGOODUID;
2842		}
2843		else if ((pw = sm_getpwnam(user)) != NULL)
2844		{
2845			if (*pw->pw_dir == '\0')
2846				a->q_home = NULL;
2847			else if (strcmp(pw->pw_dir, "/") == 0)
2848				a->q_home = "";
2849			else
2850				a->q_home = newstr(pw->pw_dir);
2851			a->q_uid = pw->pw_uid;
2852			a->q_gid = pw->pw_gid;
2853			a->q_flags |= QGOODUID;
2854		}
2855	}
2856
2857	a->q_flags |= QPRIMARY;		/* flag as a "ctladdr" */
2858	a->q_mailer = LocalMailer;
2859	if (p == NULL)
2860		a->q_paddr = newstr(a->q_user);
2861	else
2862		a->q_paddr = newstr(p);
2863	return a;
2864}
2865/*
2866**  LOSEQFILE -- save the qf as Qf and try to let someone know
2867**
2868**	Parameters:
2869**		e -- the envelope (e->e_id will be used).
2870**		why -- reported to whomever can hear.
2871**
2872**	Returns:
2873**		none.
2874*/
2875
2876# define LOSEQF_LETTER 'Q'
2877
2878void
2879loseqfile(e, why)
2880	register ENVELOPE *e;
2881	char *why;
2882{
2883	char *p;
2884	char buf[MAXPATHLEN];
2885
2886	if (e == NULL || e->e_id == NULL)
2887		return;
2888	p = queuename(e, 'q');
2889	if (strlen(p) >= (SIZE_T) sizeof buf)
2890		return;
2891	(void) strlcpy(buf, p, sizeof buf);
2892	p = queuename(e, LOSEQF_LETTER);
2893	if (rename(buf, p) < 0)
2894		syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid());
2895	else if (LogLevel > 0)
2896		sm_syslog(LOG_ALERT, e->e_id,
2897			  "Losing %s: %s", buf, why);
2898}
2899/*
2900**  QID_PRINTNAME -- create externally printable version of queue id
2901**
2902**	Parameters:
2903**		e -- the envelope.
2904**
2905**	Returns:
2906**		a printable version
2907*/
2908
2909char *
2910qid_printname(e)
2911	ENVELOPE *e;
2912{
2913	char *id;
2914	static char idbuf[MAXQFNAME + 34];
2915
2916	if (e == NULL)
2917		return "";
2918
2919	if (e->e_id == NULL)
2920		id = "";
2921	else
2922		id = e->e_id;
2923
2924	if (e->e_queuedir == NOQDIR)
2925		return id;
2926
2927	(void) snprintf(idbuf, sizeof idbuf, "%.32s/%s",
2928			QPaths[e->e_queuedir].qp_name, id);
2929	return idbuf;
2930}
2931/*
2932**  QID_PRINTQUEUE -- create full version of queue directory for df files
2933**
2934**	Parameters:
2935**		queuedir -- the short version of the queue directory
2936**
2937**	Returns:
2938**		the full pathname to the queue (static)
2939*/
2940
2941char *
2942qid_printqueue(queuedir)
2943	int queuedir;
2944{
2945	char *subdir;
2946	static char dir[MAXPATHLEN];
2947
2948	if (queuedir == NOQDIR)
2949		return QueueDir;
2950
2951	if (strcmp(QPaths[queuedir].qp_name, ".") == 0)
2952		subdir = NULL;
2953	else
2954		subdir = QPaths[queuedir].qp_name;
2955
2956	(void) snprintf(dir, sizeof dir, "%s%s%s%s", QueueDir,
2957			subdir == NULL ? "" : "/",
2958			subdir == NULL ? "" : subdir,
2959			(bitset(QP_SUBDF, QPaths[queuedir].qp_subdirs) ? "/df" : ""));
2960	return dir;
2961}
2962/*
2963**  SETNEWQUEUE -- Sets a new queue directory
2964**
2965**	Assign a queue directory to an envelope and store the directory
2966**	in e->e_queuedir.  The queue is chosen at random.
2967**
2968**	This routine may be improved in the future to allow for more
2969**	elaborate queueing schemes.  Suggestions and code contributions
2970**	are welcome.
2971**
2972**	Parameters:
2973**		e -- envelope to assign a queue for.
2974**
2975**	Returns:
2976**		none.
2977*/
2978
2979void
2980setnewqueue(e)
2981	ENVELOPE *e;
2982{
2983	int idx;
2984
2985	if (tTd(41, 20))
2986		dprintf("setnewqueue: called\n");
2987
2988	if (e->e_queuedir != NOQDIR)
2989	{
2990		if (tTd(41, 20))
2991			dprintf("setnewqueue: e_queuedir already assigned (%s)\n",
2992				qid_printqueue(e->e_queuedir));
2993		return;
2994	}
2995
2996	if (NumQueues == 1)
2997		idx = 0;
2998	else
2999	{
3000#if RANDOMSHIFT
3001		/* lower bits are not random "enough", select others */
3002		idx = (get_random() >> RANDOMSHIFT) % NumQueues;
3003#else /* RANDOMSHIFT */
3004		idx = get_random() % NumQueues;
3005#endif /* RANDOMSHIFT */
3006		if (tTd(41, 15))
3007			dprintf("setnewqueue: get_random() %% %d = %d\n",
3008				NumQueues, idx);
3009	}
3010
3011	e->e_queuedir = idx;
3012	if (tTd(41, 3))
3013		dprintf("setnewqueue: Assigned queue directory %s\n",
3014			qid_printqueue(e->e_queuedir));
3015}
3016
3017/*
3018**  CHKQDIR -- check a queue directory
3019**
3020**	Parameters:
3021**		name -- name of queue directory
3022**		sff -- flags for safefile()
3023**
3024**	Returns:
3025**		is it a queue directory?
3026*/
3027
3028static bool
3029chkqdir(name, sff)
3030	char *name;
3031	long sff;
3032{
3033	struct stat statb;
3034	int i;
3035
3036	/* skip over . and .. directories */
3037	if (name[0] == '.' &&
3038	    (name[1] == '\0' || (name[2] == '.' && name[3] == '\0')))
3039		return FALSE;
3040# if HASLSTAT
3041	if (lstat(name, &statb) < 0)
3042# else /* HASLSTAT */
3043	if (stat(name, &statb) < 0)
3044# endif /* HASLSTAT */
3045	{
3046		if (tTd(41, 2))
3047			dprintf("multiqueue_cache: stat(\"%s\"): %s\n",
3048				name, errstring(errno));
3049		return FALSE;
3050	}
3051# if HASLSTAT
3052	if (S_ISLNK(statb.st_mode))
3053	{
3054		/*
3055		**  For a symlink we need to make sure the
3056		**  target is a directory
3057		*/
3058		if (stat(name, &statb) < 0)
3059		{
3060			if (tTd(41, 2))
3061				dprintf("multiqueue_cache: stat(\"%s\"): %s\n",
3062					name, errstring(errno));
3063			return FALSE;
3064		}
3065	}
3066# endif /* HASLSTAT */
3067
3068	if (!S_ISDIR(statb.st_mode))
3069	{
3070		if (tTd(41, 2))
3071			dprintf("multiqueue_cache: \"%s\": Not a directory\n",
3072				name);
3073		return FALSE;
3074	}
3075
3076	/* Print a warning if unsafe (but still use it) */
3077	i = safedirpath(name, RunAsUid, RunAsGid, NULL, sff, 0, 0);
3078	if (i != 0 && tTd(41, 2))
3079		dprintf("multiqueue_cache: \"%s\": Not safe: %s\n",
3080			name, errstring(i));
3081	return TRUE;
3082}
3083
3084/*
3085**  MULTIQUEUE_CACHE -- cache a list of paths to queues.
3086**
3087**	Each potential queue is checked as the cache is built.
3088**	Thereafter, each is blindly trusted.
3089**	Note that we can be called again after a timeout to rebuild
3090**	(although code for that is not ready yet).
3091**
3092**	Parameters:
3093**		none
3094**
3095**	Returns:
3096**		none
3097*/
3098
3099void
3100multiqueue_cache()
3101{
3102	register DIR *dp;
3103	register struct dirent *d;
3104	char *cp;
3105	int i, len;
3106	int slotsleft = 0;
3107	long sff = SFF_ANYFILE;
3108	char qpath[MAXPATHLEN];
3109	char subdir[MAXPATHLEN];
3110
3111	if (tTd(41, 20))
3112		dprintf("multiqueue_cache: called\n");
3113
3114	if (NumQueues != 0 && QPaths != NULL)
3115	{
3116		for (i = 0; i < NumQueues; i++)
3117		{
3118			if (QPaths[i].qp_name != NULL)
3119				(void) free(QPaths[i].qp_name);
3120		}
3121		(void) free((char *)QPaths);
3122		QPaths = NULL;
3123		NumQueues = 0;
3124	}
3125
3126	/* If running as root, allow safedirpath() checks to use privs */
3127	if (RunAsUid == 0)
3128		sff |= SFF_ROOTOK;
3129
3130	(void) snprintf(qpath, sizeof qpath, "%s", QueueDir);
3131	len = strlen(qpath) - 1;
3132	cp = &qpath[len];
3133	if (*cp == '*')
3134	{
3135		*cp = '\0';
3136		if ((cp = strrchr(qpath, '/')) == NULL)
3137		{
3138			syserr("QueueDirectory: can not wildcard relative path");
3139			if (tTd(41, 2))
3140				dprintf("multiqueue_cache: \"%s\": Can not wildcard relative path.\n",
3141					QueueDir);
3142			ExitStat = EX_CONFIG;
3143			return;
3144		}
3145		if (cp == qpath)
3146		{
3147			/*
3148			**  Special case of top level wildcard, like /foo*
3149			*/
3150
3151			(void) snprintf(qpath + 1, sizeof qpath - 1,
3152					"%s", qpath);
3153			++cp;
3154		}
3155		*(cp++) = '\0';
3156		len = strlen(cp);
3157
3158		if (tTd(41, 2))
3159			dprintf("multiqueue_cache: prefix=\"%s\"\n", cp);
3160
3161		QueueDir = newstr(qpath);
3162
3163		/*
3164		**  XXX Should probably wrap this whole loop in a timeout
3165		**  in case some wag decides to NFS mount the queues.
3166		*/
3167
3168		/* test path to get warning messages */
3169		i= safedirpath(QueueDir, RunAsUid, RunAsGid, NULL, sff, 0, 0);
3170		if (i != 0 && tTd(41, 2))
3171			dprintf("multiqueue_cache: \"%s\": Not safe: %s\n",
3172				QueueDir, errstring(i));
3173
3174		if (chdir(QueueDir) < 0)
3175		{
3176			syserr("can not chdir(%s)", QueueDir);
3177			if (tTd(41, 2))
3178				dprintf("multiqueue_cache: \"%s\": %s\n",
3179					qpath, errstring(errno));
3180			ExitStat = EX_CONFIG;
3181			return;
3182		}
3183
3184		if ((dp = opendir(".")) == NULL)
3185		{
3186			syserr("can not opendir(%s)", QueueDir);
3187			if (tTd(41, 2))
3188				dprintf("multiqueue_cache: opendir(\"%s\"): %s\n",
3189					QueueDir, errstring(errno));
3190			ExitStat = EX_CONFIG;
3191			return;
3192		}
3193		while ((d = readdir(dp)) != NULL)
3194		{
3195			if (strncmp(d->d_name, cp, len) != 0)
3196			{
3197				if (tTd(41, 5))
3198					dprintf("multiqueue_cache: \"%s\", skipped\n",
3199						d->d_name);
3200				continue;
3201			}
3202			if (!chkqdir(d->d_name, sff))
3203				continue;
3204
3205			if (QPaths == NULL)
3206			{
3207				slotsleft = 20;
3208				QPaths = (QPATHS *)xalloc((sizeof *QPaths) *
3209							  slotsleft);
3210				NumQueues = 0;
3211			}
3212			else if (slotsleft < 1)
3213			{
3214				QPaths = (QPATHS *)realloc((char *)QPaths,
3215							  (sizeof *QPaths) *
3216							  (NumQueues + 10));
3217				if (QPaths == NULL)
3218				{
3219					(void) closedir(dp);
3220					return;
3221				}
3222				slotsleft += 10;
3223			}
3224
3225			/* check subdirs */
3226			QPaths[NumQueues].qp_subdirs = QP_NOSUB;
3227			(void) snprintf(subdir, sizeof subdir, "%s/%s/%s",
3228					qpath, d->d_name, "qf");
3229			if (chkqdir(subdir, sff))
3230				QPaths[NumQueues].qp_subdirs |= QP_SUBQF;
3231
3232			(void) snprintf(subdir, sizeof subdir, "%s/%s/%s",
3233					qpath, d->d_name, "df");
3234			if (chkqdir(subdir, sff))
3235				QPaths[NumQueues].qp_subdirs |= QP_SUBDF;
3236
3237			(void) snprintf(subdir, sizeof subdir, "%s/%s/%s",
3238					qpath, d->d_name, "xf");
3239			if (chkqdir(subdir, sff))
3240				QPaths[NumQueues].qp_subdirs |= QP_SUBXF;
3241
3242			/* assert(strlen(d->d_name) < MAXPATHLEN - 14) */
3243			/* maybe even - 17 (subdirs) */
3244			QPaths[NumQueues].qp_name = newstr(d->d_name);
3245			if (tTd(41, 2))
3246				dprintf("multiqueue_cache: %d: \"%s\" cached (%x).\n",
3247					NumQueues, d->d_name,
3248					QPaths[NumQueues].qp_subdirs);
3249			NumQueues++;
3250			slotsleft--;
3251		}
3252		(void) closedir(dp);
3253	}
3254	if (NumQueues == 0)
3255	{
3256		if (*cp != '*' && tTd(41, 2))
3257			dprintf("multiqueue_cache: \"%s\": No wildcard suffix character\n",
3258				QueueDir);
3259		QPaths = (QPATHS *)xalloc(sizeof *QPaths);
3260		QPaths[0].qp_name = newstr(".");
3261		QPaths[0].qp_subdirs = QP_NOSUB;
3262		NumQueues = 1;
3263
3264		/* test path to get warning messages */
3265		(void) safedirpath(QueueDir, RunAsUid, RunAsGid,
3266				   NULL, sff, 0, 0);
3267		if (chdir(QueueDir) < 0)
3268		{
3269			syserr("can not chdir(%s)", QueueDir);
3270			if (tTd(41, 2))
3271				dprintf("multiqueue_cache: \"%s\": %s\n",
3272					QueueDir, errstring(errno));
3273			ExitStat = EX_CONFIG;
3274		}
3275
3276		/* check subdirs */
3277		(void) snprintf(subdir, sizeof subdir, "%s/qf", QueueDir);
3278		if (chkqdir(subdir, sff))
3279			QPaths[0].qp_subdirs |= QP_SUBQF;
3280
3281		(void) snprintf(subdir, sizeof subdir, "%s/df",	QueueDir);
3282		if (chkqdir(subdir, sff))
3283			QPaths[0].qp_subdirs |= QP_SUBDF;
3284
3285		(void) snprintf(subdir, sizeof subdir, "%s/xf", QueueDir);
3286		if (chkqdir(subdir, sff))
3287			QPaths[0].qp_subdirs |= QP_SUBXF;
3288	}
3289}
3290
3291# if 0
3292/*
3293**  HASHFQN -- calculate a hash value for a fully qualified host name
3294**
3295**	Arguments:
3296**		fqn -- an all lower-case host.domain string
3297**		buckets -- the number of buckets (queue directories)
3298**
3299**	Returns:
3300**		a bucket number (signed integer)
3301**		-1 on error
3302**
3303**	Contributed by Exactis.com, Inc.
3304*/
3305
3306int
3307hashfqn(fqn, buckets)
3308	register char *fqn;
3309	int buckets;
3310{
3311	register char *p;
3312	register int h = 0, hash, cnt;
3313#  define WATERINC (1000)
3314
3315	if (fqn == NULL)
3316		return -1;
3317
3318	/*
3319	**  A variation on the gdb hash
3320	**  This is the best as of Feb 19, 1996 --bcx
3321	*/
3322
3323	p = fqn;
3324	h = 0x238F13AF * strlen(p);
3325	for (cnt = 0; *p != 0; ++p, cnt++)
3326	{
3327		h = (h + (*p << (cnt * 5 % 24))) & 0x7FFFFFFF;
3328	}
3329	h = (1103515243 * h + 12345) & 0x7FFFFFFF;
3330	if (buckets < 2)
3331		hash = 0;
3332	else
3333		hash = (h % buckets);
3334
3335	return hash;
3336}
3337# endif /* 0 */
3338
3339# if _FFR_QUEUEDELAY
3340/*
3341**  QUEUEDELAY -- compute queue delay time
3342**
3343**	Parameters:
3344**		e -- the envelope to queue up.
3345**
3346**	Returns:
3347**		queue delay time
3348**
3349**	Side Effects:
3350**		may change e_queuedelay
3351*/
3352
3353static time_t
3354queuedelay(e)
3355	ENVELOPE *e;
3356{
3357	time_t qd;
3358
3359	if (e->e_queuealg == QD_EXP)
3360	{
3361		if (e->e_queuedelay == 0)
3362			e->e_queuedelay = QueueInitDelay;
3363		else
3364		{
3365			e->e_queuedelay *= 2;
3366			if (e->e_queuedelay > QueueMaxDelay)
3367				e->e_queuedelay = QueueMaxDelay;
3368		}
3369		qd = e->e_queuedelay;
3370	}
3371	else
3372		qd = MinQueueAge;
3373	return qd;
3374}
3375# endif /* _FFR_QUEUEDELAY */
3376#endif /* QUEUE */
3377