queue.c revision 111823
1/*
2 * Copyright (c) 1998-2003 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#include <sendmail.h>
15
16SM_RCSID("@(#)$Id: queue.c,v 8.863.2.28 2003/02/11 17:17:22 ca Exp $")
17
18#include <dirent.h>
19
20# define RELEASE_QUEUE	(void) 0
21# define ST_INODE(st)	(st).st_ino
22
23
24/*
25**  Historical notes:
26**     QF_VERSION == 4 was sendmail 8.10/8.11 without _FFR_QUEUEDELAY
27**     QF_VERSION == 5 was sendmail 8.10/8.11 with    _FFR_QUEUEDELAY
28**     QF_VERSION == 6 is  sendmail 8.12      without _FFR_QUEUEDELAY
29**     QF_VERSION == 7 is  sendmail 8.12      with    _FFR_QUEUEDELAY
30*/
31
32#if _FFR_QUEUEDELAY
33# define QF_VERSION	7	/* version number of this queue format */
34static time_t	queuedelay __P((ENVELOPE *));
35#define queuedelay_qfver_unsupported(qfver) false
36#else /* _FFR_QUEUEDELAY */
37# define QF_VERSION	6	/* version number of this queue format */
38# define queuedelay(e)	MinQueueAge
39#define queuedelay_qfver_unsupported(qfver) ((qfver) == 5 || (qfver) == 7)
40#endif /* _FFR_QUEUEDELAY */
41#if _FFR_QUARANTINE
42static char	queue_letter __P((ENVELOPE *, int));
43static bool	quarantine_queue_item __P((int, int, ENVELOPE *, char *));
44#endif /* _FFR_QUARANTINE */
45
46/* Naming convention: qgrp: index of queue group, qg: QUEUEGROUP */
47
48/*
49**  Work queue.
50*/
51
52struct work
53{
54	char		*w_name;	/* name of control file */
55	char		*w_host;	/* name of recipient host */
56	bool		w_lock;		/* is message locked? */
57	bool		w_tooyoung;	/* is it too young to run? */
58	long		w_pri;		/* priority of message, see below */
59	time_t		w_ctime;	/* creation time */
60	time_t		w_mtime;	/* modification time */
61	int		w_qgrp;		/* queue group located in */
62	int		w_qdir;		/* queue directory located in */
63	struct work	*w_next;	/* next in queue */
64};
65
66typedef struct work	WORK;
67
68static WORK	*WorkQ;		/* queue of things to be done */
69static int	NumWorkGroups;	/* number of work groups */
70
71/*
72**  DoQueueRun indicates that a queue run is needed.
73**	Notice: DoQueueRun is modified in a signal handler!
74*/
75
76static bool	volatile DoQueueRun; /* non-interrupt time queue run needed */
77
78/*
79**  Work group definition structure.
80**	Each work group contains one or more queue groups. This is done
81**	to manage the number of queue group runners active at the same time
82**	to be within the constraints of MaxQueueChildren (if it is set).
83**	The number of queue groups that can be run on the next work run
84**	is kept track of. The queue groups are run in a round robin.
85*/
86
87struct workgrp
88{
89	int		wg_numqgrp;	/* number of queue groups in work grp */
90	int		wg_runners;	/* total runners */
91	int		wg_curqgrp;	/* current queue group */
92	QUEUEGRP	**wg_qgs;	/* array of queue groups */
93	int		wg_maxact;	/* max # of active runners */
94	time_t		wg_lowqintvl;	/* lowest queue interval */
95	int		wg_restart;	/* needs restarting? */
96	int		wg_restartcnt;	/* count of times restarted */
97};
98
99typedef struct workgrp WORKGRP;
100
101static WORKGRP	volatile WorkGrp[MAXWORKGROUPS + 1];	/* work groups */
102
103#if SM_HEAP_CHECK
104static SM_DEBUG_T DebugLeakQ = SM_DEBUG_INITIALIZER("leak_q",
105	"@(#)$Debug: leak_q - trace memory leaks during queue processing $");
106#endif /* SM_HEAP_CHECK */
107
108/*
109**  We use EmptyString instead of "" to avoid
110**  'zero-length format string' warnings from gcc
111*/
112
113static const char EmptyString[] = "";
114
115static void	grow_wlist __P((int, int));
116static int	multiqueue_cache __P((char *, int, QUEUEGRP *, int, unsigned int *));
117static int	gatherq __P((int, int, bool, bool *, bool *));
118static int	sortq __P((int));
119static void	printctladdr __P((ADDRESS *, SM_FILE_T *));
120static bool	readqf __P((ENVELOPE *, bool));
121static void	restart_work_group __P((int));
122static void	runner_work __P((ENVELOPE *, int, bool, int, int));
123static void	schedule_queue_runs __P((bool, int, bool));
124static char	*strrev __P((char *));
125static ADDRESS	*setctluser __P((char *, int, ENVELOPE *));
126#if _FFR_RHS
127static int	sm_strshufflecmp __P((char *, char *));
128static void	init_shuffle_alphabet __P(());
129#endif /* _FFR_RHS */
130static int	workcmpf0();
131static int	workcmpf1();
132static int	workcmpf2();
133static int	workcmpf3();
134static int	workcmpf4();
135static int	randi = 3;	/* index for workcmpf5() */
136static int	workcmpf5();
137static int	workcmpf6();
138#if _FFR_RHS
139static int	workcmpf7();
140#endif /* _FFR_RHS */
141
142#if RANDOMSHIFT
143# define get_rand_mod(m)	((get_random() >> RANDOMSHIFT) % (m))
144#else /* RANDOMSHIFT */
145# define get_rand_mod(m)	(get_random() % (m))
146#endif /* RANDOMSHIFT */
147
148/*
149**  File system definition.
150**	Used to keep track of how much free space is available
151**	on a file system in which one or more queue directories reside.
152*/
153
154typedef struct filesys_shared	FILESYS;
155
156struct filesys_shared
157{
158	dev_t	fs_dev;		/* unique device id */
159	long	fs_avail;	/* number of free blocks available */
160	long	fs_blksize;	/* block size, in bytes */
161};
162
163/* probably kept in shared memory */
164static FILESYS	FileSys[MAXFILESYS];	/* queue file systems */
165static char	*FSPath[MAXFILESYS];	/* pathnames for file systems */
166
167#if SM_CONF_SHM
168
169/*
170**  Shared memory data
171**
172**  Current layout:
173**	size -- size of shared memory segment
174**	pid -- pid of owner, should be a unique id to avoid misinterpretations
175**		by other processes.
176**	tag -- should be a unique id to avoid misinterpretations by others.
177**		idea: hash over configuration data that will be stored here.
178**	NumFileSys -- number of file systems.
179**	FileSys -- (arrary of) structure for used file systems.
180**	RSATmpCnt -- counter for number of uses of ephemeral RSA key.
181**	QShm -- (array of) structure for information about queue directories.
182*/
183
184/*
185**  Queue data in shared memory
186*/
187
188typedef struct queue_shared	QUEUE_SHM_T;
189
190struct queue_shared
191{
192	int	qs_entries;	/* number of entries */
193	/* XXX more to follow? */
194};
195
196static void	*Pshm;		/* pointer to shared memory */
197static FILESYS	*PtrFileSys;	/* pointer to queue file system array */
198int		ShmId = SM_SHM_NO_ID;	/* shared memory id */
199static QUEUE_SHM_T	*QShm;		/* pointer to shared queue data */
200static size_t shms;
201
202# define SHM_OFF_PID(p)	(((char *) (p)) + sizeof(int))
203# define SHM_OFF_TAG(p)	(((char *) (p)) + sizeof(pid_t) + sizeof(int))
204# define SHM_OFF_HEAD	(sizeof(pid_t) + sizeof(int) * 2)
205
206/* how to access FileSys */
207# define FILE_SYS(i)	(PtrFileSys[i])
208
209/* first entry is a tag, for now just the size */
210# define OFF_FILE_SYS(p)	(((char *) (p)) + SHM_OFF_HEAD)
211
212/* offset for PNumFileSys */
213# define OFF_NUM_FILE_SYS(p)	(((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys))
214
215/* offset for PRSATmpCnt */
216# define OFF_RSA_TMP_CNT(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int))
217int	*PRSATmpCnt;
218
219/* offset for queue_shm */
220# define OFF_QUEUE_SHM(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2)
221
222#define QSHM_ENTRIES(i)	QShm[i].qs_entries
223
224/* basic size of shared memory segment */
225# define SM_T_SIZE	(SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2)
226
227static unsigned int	hash_q __P((char *, unsigned int));
228
229/*
230**  HASH_Q -- simple hash function
231**
232**	Parameters:
233**		p -- string to hash.
234**		h -- hash start value (from previous run).
235**
236**	Returns:
237**		hash value.
238*/
239
240static unsigned int
241hash_q(p, h)
242	char *p;
243	unsigned int h;
244{
245	int c, d;
246
247	while (*p != '\0')
248	{
249		d = *p++;
250		c = d;
251		c ^= c<<6;
252		h += (c<<11) ^ (c>>1);
253		h ^= (d<<14) + (d<<7) + (d<<4) + d;
254	}
255	return h;
256}
257
258
259#else /* SM_CONF_SHM */
260# define FILE_SYS(i)	FileSys[i]
261#endif /* SM_CONF_SHM */
262
263/* access to the various components of file system data */
264#define FILE_SYS_NAME(i)	FSPath[i]
265#define FILE_SYS_AVAIL(i)	FILE_SYS(i).fs_avail
266#define FILE_SYS_BLKSIZE(i)	FILE_SYS(i).fs_blksize
267#define FILE_SYS_DEV(i)	FILE_SYS(i).fs_dev
268
269
270/*
271**  Current qf file field assignments:
272**
273**	A	AUTH= parameter
274**	B	body type
275**	C	controlling user
276**	D	data file name
277**	d	data file directory name (added in 8.12)
278**	E	error recipient
279**	F	flag bits
280**	G	queue delay algorithm (_FFR_QUEUEDELAY)
281**	H	header
282**	I	data file's inode number
283**	K	time of last delivery attempt
284**	L	Solaris Content-Length: header (obsolete)
285**	M	message
286**	N	number of delivery attempts
287**	P	message priority
288**	q	quarantine reason (_FFR_QUARANTINE)
289**	Q	original recipient (ORCPT=)
290**	r	final recipient (Final-Recipient: DSN field)
291**	R	recipient
292**	S	sender
293**	T	init time
294**	V	queue file version
295**	X	free (was: character set if _FFR_SAVE_CHARSET)
296**	Y	current delay (_FFR_QUEUEDELAY)
297**	Z	original envelope id from ESMTP
298**	!	deliver by (added in 8.12)
299**	$	define macro
300**	.	terminate file
301*/
302
303/*
304**  QUEUEUP -- queue a message up for future transmission.
305**
306**	Parameters:
307**		e -- the envelope to queue up.
308**		announce -- if true, tell when you are queueing up.
309**		msync -- if true, then fsync() if SuperSafe interactive mode.
310**
311**	Returns:
312**		none.
313**
314**	Side Effects:
315**		The current request is saved in a control file.
316**		The queue file is left locked.
317*/
318
319void
320queueup(e, announce, msync)
321	register ENVELOPE *e;
322	bool announce;
323	bool msync;
324{
325	register SM_FILE_T *tfp;
326	register HDR *h;
327	register ADDRESS *q;
328	int tfd = -1;
329	int i;
330	bool newid;
331	register char *p;
332	MAILER nullmailer;
333	MCI mcibuf;
334	char qf[MAXPATHLEN];
335	char tf[MAXPATHLEN];
336	char df[MAXPATHLEN];
337	char buf[MAXLINE];
338
339	/*
340	**  Create control file.
341	*/
342
343	newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
344	(void) sm_strlcpy(tf, queuename(e, NEWQFL_LETTER), sizeof tf);
345	tfp = e->e_lockfp;
346	if (tfp == NULL)
347		newid = false;
348
349	/* if newid, write the queue file directly (instead of temp file) */
350	if (!newid)
351	{
352		const int flags = O_CREAT|O_WRONLY|O_EXCL;
353
354		/* get a locked tf file */
355		for (i = 0; i < 128; i++)
356		{
357			if (tfd < 0)
358			{
359				MODE_T oldumask = 0;
360
361				if (bitset(S_IWGRP, QueueFileMode))
362					oldumask = umask(002);
363				tfd = open(tf, flags, QueueFileMode);
364				if (bitset(S_IWGRP, QueueFileMode))
365					(void) umask(oldumask);
366
367				if (tfd < 0)
368				{
369					if (errno != EEXIST)
370						break;
371					if (LogLevel > 0 && (i % 32) == 0)
372						sm_syslog(LOG_ALERT, e->e_id,
373							  "queueup: cannot create %s, uid=%d: %s",
374							  tf, (int) geteuid(),
375							  sm_errstring(errno));
376				}
377			}
378			if (tfd >= 0)
379			{
380				if (lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB))
381					break;
382				else if (LogLevel > 0 && (i % 32) == 0)
383					sm_syslog(LOG_ALERT, e->e_id,
384						  "queueup: cannot lock %s: %s",
385						  tf, sm_errstring(errno));
386				if ((i % 32) == 31)
387				{
388					(void) close(tfd);
389					tfd = -1;
390				}
391			}
392
393			if ((i % 32) == 31)
394			{
395				/* save the old temp file away */
396				(void) rename(tf, queuename(e, TEMPQF_LETTER));
397			}
398			else
399				(void) sleep(i % 32);
400		}
401		if (tfd < 0 || (tfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
402						 (void *) &tfd, SM_IO_WRONLY,
403						 NULL)) == NULL)
404		{
405			int save_errno = errno;
406
407			printopenfds(true);
408			errno = save_errno;
409			syserr("!queueup: cannot create queue temp file %s, uid=%d",
410				tf, (int) geteuid());
411		}
412	}
413
414	if (tTd(40, 1))
415		sm_dprintf("\n>>>>> queueing %s/%s%s >>>>>\n",
416			   qid_printqueue(e->e_qgrp, e->e_qdir),
417			   queuename(e, ANYQFL_LETTER),
418			   newid ? " (new id)" : "");
419	if (tTd(40, 3))
420	{
421		sm_dprintf("  e_flags=");
422		printenvflags(e);
423	}
424	if (tTd(40, 32))
425	{
426		sm_dprintf("  sendq=");
427		printaddr(e->e_sendqueue, true);
428	}
429	if (tTd(40, 9))
430	{
431		sm_dprintf("  tfp=");
432		dumpfd(sm_io_getinfo(tfp, SM_IO_WHAT_FD, NULL), true, false);
433		sm_dprintf("  lockfp=");
434		if (e->e_lockfp == NULL)
435			sm_dprintf("NULL\n");
436		else
437			dumpfd(sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL),
438			       true, false);
439	}
440
441	/*
442	**  If there is no data file yet, create one.
443	*/
444
445	(void) sm_strlcpy(df, queuename(e, DATAFL_LETTER), sizeof df);
446	if (bitset(EF_HAS_DF, e->e_flags))
447	{
448		if (e->e_dfp != NULL &&
449		    SuperSafe != SAFE_REALLY &&
450		    sm_io_setinfo(e->e_dfp, SM_BF_COMMIT, NULL) < 0 &&
451		    errno != EINVAL)
452		{
453			syserr("!queueup: cannot commit data file %s, uid=%d",
454			       queuename(e, DATAFL_LETTER), (int) geteuid());
455		}
456		if (e->e_dfp != NULL &&
457		    SuperSafe == SAFE_INTERACTIVE && msync)
458		{
459			if (tTd(40,32))
460				sm_syslog(LOG_INFO, e->e_id,
461					  "queueup: fsync(e->e_dfp)");
462
463			if (fsync(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD,
464						NULL)) < 0)
465			{
466				if (newid)
467					syserr("!552 Error writing data file %s",
468					       df);
469				else
470					syserr("!452 Error writing data file %s",
471					       df);
472			}
473		}
474	}
475	else
476	{
477		int dfd;
478		MODE_T oldumask = 0;
479		register SM_FILE_T *dfp = NULL;
480		struct stat stbuf;
481
482		if (e->e_dfp != NULL &&
483		    sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE))
484			syserr("committing over bf file");
485
486		if (bitset(S_IWGRP, QueueFileMode))
487			oldumask = umask(002);
488		dfd = open(df, O_WRONLY|O_CREAT|O_TRUNC, QueueFileMode);
489		if (bitset(S_IWGRP, QueueFileMode))
490			(void) umask(oldumask);
491		if (dfd < 0 || (dfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
492						 (void *) &dfd, SM_IO_WRONLY,
493						 NULL)) == NULL)
494			syserr("!queueup: cannot create data temp file %s, uid=%d",
495				df, (int) geteuid());
496		if (fstat(dfd, &stbuf) < 0)
497			e->e_dfino = -1;
498		else
499		{
500			e->e_dfdev = stbuf.st_dev;
501			e->e_dfino = ST_INODE(stbuf);
502		}
503		e->e_flags |= EF_HAS_DF;
504		memset(&mcibuf, '\0', sizeof mcibuf);
505		mcibuf.mci_out = dfp;
506		mcibuf.mci_mailer = FileMailer;
507		(*e->e_putbody)(&mcibuf, e, NULL);
508
509		if (SuperSafe == SAFE_REALLY ||
510		    (SuperSafe == SAFE_INTERACTIVE && msync))
511		{
512			if (tTd(40,32))
513				sm_syslog(LOG_INFO, e->e_id,
514					  "queueup: fsync(dfp)");
515
516			if (fsync(sm_io_getinfo(dfp, SM_IO_WHAT_FD, NULL)) < 0)
517			{
518				if (newid)
519					syserr("!552 Error writing data file %s",
520					       df);
521				else
522					syserr("!452 Error writing data file %s",
523					       df);
524			}
525		}
526
527		if (sm_io_close(dfp, SM_TIME_DEFAULT) < 0)
528			syserr("!queueup: cannot save data temp file %s, uid=%d",
529				df, (int) geteuid());
530		e->e_putbody = putbody;
531	}
532
533	/*
534	**  Output future work requests.
535	**	Priority and creation time should be first, since
536	**	they are required by gatherq.
537	*/
538
539	/* output queue version number (must be first!) */
540	(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "V%d\n", QF_VERSION);
541
542	/* output creation time */
543	(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "T%ld\n", (long) e->e_ctime);
544
545	/* output last delivery time */
546#if _FFR_QUEUEDELAY
547	(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "K%ld\n", (long) e->e_dtime);
548	(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "G%d\n", e->e_queuealg);
549	(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Y%ld\n", (long) e->e_queuedelay);
550	if (tTd(40, 64))
551		sm_syslog(LOG_INFO, e->e_id,
552			"queue alg: %d delay %ld next: %ld (now: %ld)\n",
553			e->e_queuealg, e->e_queuedelay, e->e_dtime, curtime());
554#else /* _FFR_QUEUEDELAY */
555	(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "K%ld\n", (long) e->e_dtime);
556#endif /* _FFR_QUEUEDELAY */
557
558	/* output number of delivery attempts */
559	(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "N%d\n", e->e_ntries);
560
561	/* output message priority */
562	(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "P%ld\n", e->e_msgpriority);
563
564	/*
565	**  If data file is in a different directory than the queue file,
566	**  output a "d" record naming the directory of the data file.
567	*/
568
569	if (e->e_dfqgrp != e->e_qgrp)
570	{
571		(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "d%s\n",
572			Queue[e->e_dfqgrp]->qg_qpaths[e->e_dfqdir].qp_name);
573	}
574
575	/* output inode number of data file */
576	/* XXX should probably include device major/minor too */
577	if (e->e_dfino != -1)
578	{
579		(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "I%ld/%ld/%llu\n",
580				     (long) major(e->e_dfdev),
581				     (long) minor(e->e_dfdev),
582				     (ULONGLONG_T) e->e_dfino);
583	}
584
585	/* output body type */
586	if (e->e_bodytype != NULL)
587		(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "B%s\n",
588				     denlstring(e->e_bodytype, true, false));
589
590#if _FFR_QUARANTINE
591	/* quarantine reason */
592	if (e->e_quarmsg != NULL)
593		(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "q%s\n",
594				     denlstring(e->e_quarmsg, true, false));
595#endif /* _FFR_QUARANTINE */
596
597	/* message from envelope, if it exists */
598	if (e->e_message != NULL)
599		(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "M%s\n",
600				     denlstring(e->e_message, true, false));
601
602	/* send various flag bits through */
603	p = buf;
604	if (bitset(EF_WARNING, e->e_flags))
605		*p++ = 'w';
606	if (bitset(EF_RESPONSE, e->e_flags))
607		*p++ = 'r';
608	if (bitset(EF_HAS8BIT, e->e_flags))
609		*p++ = '8';
610	if (bitset(EF_DELETE_BCC, e->e_flags))
611		*p++ = 'b';
612	if (bitset(EF_RET_PARAM, e->e_flags))
613		*p++ = 'd';
614	if (bitset(EF_NO_BODY_RETN, e->e_flags))
615		*p++ = 'n';
616	if (bitset(EF_SPLIT, e->e_flags))
617		*p++ = 's';
618	*p++ = '\0';
619	if (buf[0] != '\0')
620		(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "F%s\n", buf);
621
622	/* save $={persistentMacros} macro values */
623	queueup_macros(macid("{persistentMacros}"), tfp, e);
624
625	/* output name of sender */
626	if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
627		p = e->e_sender;
628	else
629		p = e->e_from.q_paddr;
630	(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "S%s\n",
631			     denlstring(p, true, false));
632
633	/* output ESMTP-supplied "original" information */
634	if (e->e_envid != NULL)
635		(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Z%s\n",
636				     denlstring(e->e_envid, true, false));
637
638	/* output AUTH= parameter */
639	if (e->e_auth_param != NULL)
640		(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "A%s\n",
641				     denlstring(e->e_auth_param, true, false));
642	if (e->e_dlvr_flag != 0)
643		(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "!%c %ld\n",
644				     (char) e->e_dlvr_flag, e->e_deliver_by);
645
646	/* output list of recipient addresses */
647	printctladdr(NULL, NULL);
648	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
649	{
650		if (!QS_IS_UNDELIVERED(q->q_state))
651			continue;
652
653		/* message for this recipient, if it exists */
654		if (q->q_message != NULL)
655			(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "M%s\n",
656					     denlstring(q->q_message, true,
657							false));
658
659		printctladdr(q, tfp);
660		if (q->q_orcpt != NULL)
661			(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Q%s\n",
662					     denlstring(q->q_orcpt, true,
663							false));
664		if (q->q_finalrcpt != NULL)
665			(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "r%s\n",
666					     denlstring(q->q_finalrcpt, true,
667							false));
668		(void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'R');
669		if (bitset(QPRIMARY, q->q_flags))
670			(void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'P');
671		if (bitset(QHASNOTIFY, q->q_flags))
672			(void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'N');
673		if (bitset(QPINGONSUCCESS, q->q_flags))
674			(void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'S');
675		if (bitset(QPINGONFAILURE, q->q_flags))
676			(void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'F');
677		if (bitset(QPINGONDELAY, q->q_flags))
678			(void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'D');
679		if (q->q_alias != NULL &&
680		    bitset(QALIAS, q->q_alias->q_flags))
681			(void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'A');
682		(void) sm_io_putc(tfp, SM_TIME_DEFAULT, ':');
683		(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s\n",
684				     denlstring(q->q_paddr, true, false));
685		if (announce)
686		{
687			char *tag = "queued";
688
689#if _FFR_QUARANTINE
690			if (e->e_quarmsg != NULL)
691				tag = "quarantined";
692#endif /* _FFR_QUARANTINE */
693
694			e->e_to = q->q_paddr;
695			message(tag);
696			if (LogLevel > 8)
697				logdelivery(q->q_mailer, NULL, q->q_status,
698					    tag, NULL, (time_t) 0, e);
699			e->e_to = NULL;
700		}
701		if (tTd(40, 1))
702		{
703			sm_dprintf("queueing ");
704			printaddr(q, false);
705		}
706	}
707
708	/*
709	**  Output headers for this message.
710	**	Expand macros completely here.  Queue run will deal with
711	**	everything as absolute headers.
712	**		All headers that must be relative to the recipient
713	**		can be cracked later.
714	**	We set up a "null mailer" -- i.e., a mailer that will have
715	**	no effect on the addresses as they are output.
716	*/
717
718	memset((char *) &nullmailer, '\0', sizeof nullmailer);
719	nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
720			nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
721	nullmailer.m_eol = "\n";
722	memset(&mcibuf, '\0', sizeof mcibuf);
723	mcibuf.mci_mailer = &nullmailer;
724	mcibuf.mci_out = tfp;
725
726	macdefine(&e->e_macro, A_PERM, 'g', "\201f");
727	for (h = e->e_header; h != NULL; h = h->h_link)
728	{
729		if (h->h_value == NULL)
730			continue;
731
732		/* don't output resent headers on non-resent messages */
733		if (bitset(H_RESENT, h->h_flags) &&
734		    !bitset(EF_RESENT, e->e_flags))
735			continue;
736
737		/* expand macros; if null, don't output header at all */
738		if (bitset(H_DEFAULT, h->h_flags))
739		{
740			(void) expand(h->h_value, buf, sizeof buf, e);
741			if (buf[0] == '\0')
742				continue;
743		}
744
745		/* output this header */
746		(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "H?");
747
748		/* output conditional macro if present */
749		if (h->h_macro != '\0')
750		{
751			if (bitset(0200, h->h_macro))
752				(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT,
753						     "${%s}",
754						      macname(bitidx(h->h_macro)));
755			else
756				(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT,
757						     "$%c", h->h_macro);
758		}
759		else if (!bitzerop(h->h_mflags) &&
760			 bitset(H_CHECK|H_ACHECK, h->h_flags))
761		{
762			int j;
763
764			/* if conditional, output the set of conditions */
765			for (j = '\0'; j <= '\177'; j++)
766				if (bitnset(j, h->h_mflags))
767					(void) sm_io_putc(tfp, SM_TIME_DEFAULT,
768							  j);
769		}
770		(void) sm_io_putc(tfp, SM_TIME_DEFAULT, '?');
771
772		/* output the header: expand macros, convert addresses */
773		if (bitset(H_DEFAULT, h->h_flags) &&
774		    !bitset(H_BINDLATE, h->h_flags))
775		{
776			(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s: %s\n",
777					     h->h_field,
778					     denlstring(buf, false, true));
779		}
780		else if (bitset(H_FROM|H_RCPT, h->h_flags) &&
781			 !bitset(H_BINDLATE, h->h_flags))
782		{
783			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
784			SM_FILE_T *savetrace = TrafficLogFile;
785
786			TrafficLogFile = NULL;
787
788			if (bitset(H_FROM, h->h_flags))
789				oldstyle = false;
790
791			commaize(h, h->h_value, oldstyle, &mcibuf, e);
792
793			TrafficLogFile = savetrace;
794		}
795		else
796		{
797			(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s: %s\n",
798					     h->h_field,
799					     denlstring(h->h_value, false,
800							true));
801		}
802	}
803
804	/*
805	**  Clean up.
806	**
807	**	Write a terminator record -- this is to prevent
808	**	scurrilous crackers from appending any data.
809	*/
810
811	(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, ".\n");
812
813	if (sm_io_flush(tfp, SM_TIME_DEFAULT) != 0 ||
814	    ((SuperSafe == SAFE_REALLY ||
815	      (SuperSafe == SAFE_INTERACTIVE && msync)) &&
816	     fsync(sm_io_getinfo(tfp, SM_IO_WHAT_FD, NULL)) < 0) ||
817	    sm_io_error(tfp))
818	{
819		if (newid)
820			syserr("!552 Error writing control file %s", tf);
821		else
822			syserr("!452 Error writing control file %s", tf);
823	}
824
825	if (!newid)
826	{
827#if _FFR_QUARANTINE
828		char new = queue_letter(e, ANYQFL_LETTER);
829#endif /* _FFR_QUARANTINE */
830
831		/* rename (locked) tf to be (locked) [qh]f */
832		(void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER),
833				  sizeof qf);
834		if (rename(tf, qf) < 0)
835			syserr("cannot rename(%s, %s), uid=%d",
836				tf, qf, (int) geteuid());
837# if _FFR_QUARANTINE
838		else
839		{
840			/*
841			**  Check if type has changed and only
842			**  remove the old item if the rename above
843			**  succeeded.
844			*/
845
846			if (e->e_qfletter != '\0' &&
847			    e->e_qfletter != new)
848			{
849				if (tTd(40, 5))
850				{
851					sm_dprintf("type changed from %c to %c\n",
852						   e->e_qfletter, new);
853				}
854
855				if (unlink(queuename(e, e->e_qfletter)) < 0)
856				{
857					/* XXX: something more drastic? */
858					if (LogLevel > 0)
859						sm_syslog(LOG_ERR, e->e_id,
860							  "queueup: unlink(%s) failed: %s",
861							  queuename(e, e->e_qfletter),
862							  sm_errstring(errno));
863				}
864			}
865		}
866		e->e_qfletter = new;
867# endif /* _FFR_QUARANTINE */
868
869		/*
870		**  fsync() after renaming to make sure metadata is
871		**  written to disk on filesystems in which renames are
872		**  not guaranteed.
873		*/
874
875		if (SuperSafe != SAFE_NO)
876		{
877			/* for softupdates */
878			if (tfd >= 0 && fsync(tfd) < 0)
879			{
880				syserr("!queueup: cannot fsync queue temp file %s",
881				       tf);
882			}
883			SYNC_DIR(qf, true);
884		}
885
886		/* close and unlock old (locked) queue file */
887		if (e->e_lockfp != NULL)
888			(void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT);
889		e->e_lockfp = tfp;
890
891		/* save log info */
892		if (LogLevel > 79)
893			sm_syslog(LOG_DEBUG, e->e_id, "queueup %s", qf);
894	}
895	else
896	{
897		/* save log info */
898		if (LogLevel > 79)
899			sm_syslog(LOG_DEBUG, e->e_id, "queueup %s", tf);
900
901#if _FFR_QUARANTINE
902		e->e_qfletter = queue_letter(e, ANYQFL_LETTER);
903#endif /* _FFR_QUARANTINE */
904	}
905
906	errno = 0;
907	e->e_flags |= EF_INQUEUE;
908
909	if (tTd(40, 1))
910		sm_dprintf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
911	return;
912}
913
914/*
915**  PRINTCTLADDR -- print control address to file.
916**
917**	Parameters:
918**		a -- address.
919**		tfp -- file pointer.
920**
921**	Returns:
922**		none.
923**
924**	Side Effects:
925**		The control address (if changed) is printed to the file.
926**		The last control address and uid are saved.
927*/
928
929static void
930printctladdr(a, tfp)
931	register ADDRESS *a;
932	SM_FILE_T *tfp;
933{
934	char *user;
935	register ADDRESS *q;
936	uid_t uid;
937	gid_t gid;
938	static ADDRESS *lastctladdr = NULL;
939	static uid_t lastuid;
940
941	/* initialization */
942	if (a == NULL || a->q_alias == NULL || tfp == NULL)
943	{
944		if (lastctladdr != NULL && tfp != NULL)
945			(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C\n");
946		lastctladdr = NULL;
947		lastuid = 0;
948		return;
949	}
950
951	/* find the active uid */
952	q = getctladdr(a);
953	if (q == NULL)
954	{
955		user = NULL;
956		uid = 0;
957		gid = 0;
958	}
959	else
960	{
961		user = q->q_ruser != NULL ? q->q_ruser : q->q_user;
962		uid = q->q_uid;
963		gid = q->q_gid;
964	}
965	a = a->q_alias;
966
967	/* check to see if this is the same as last time */
968	if (lastctladdr != NULL && uid == lastuid &&
969	    strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
970		return;
971	lastuid = uid;
972	lastctladdr = a;
973
974	if (uid == 0 || user == NULL || user[0] == '\0')
975		(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C");
976	else
977		(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C%s:%ld:%ld",
978				     denlstring(user, true, false), (long) uid,
979				     (long) gid);
980	(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, ":%s\n",
981			     denlstring(a->q_paddr, true, false));
982}
983
984/*
985**  RUNNERS_SIGTERM -- propagate a SIGTERM to queue runner process
986**
987**	This propagates the signal to the child processes that are queue
988**	runners. This is for a queue runner "cleanup". After all of the
989**	child queue runner processes are signaled (it should be SIGTERM
990**	being the sig) then the old signal handler (Oldsh) is called
991**	to handle any cleanup set for this process (provided it is not
992**	SIG_DFL or SIG_IGN). The signal may not be handled immediately
993**	if the BlockOldsh flag is set. If the current process doesn't
994**	have a parent then handle the signal immediately, regardless of
995**	BlockOldsh.
996**
997**	Parameters:
998**		sig -- the signal number being sent
999**
1000**	Returns:
1001**		none.
1002**
1003**	Side Effects:
1004**		Sets the NoMoreRunners boolean to true to stop more runners
1005**		from being started in runqueue().
1006**
1007**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
1008**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
1009**		DOING.
1010*/
1011
1012static bool		volatile NoMoreRunners = false;
1013static sigfunc_t	Oldsh_term = SIG_DFL;
1014static sigfunc_t	Oldsh_hup = SIG_DFL;
1015static sigfunc_t	volatile Oldsh = SIG_DFL;
1016static bool		BlockOldsh = false;
1017static int		volatile Oldsig = 0;
1018static SIGFUNC_DECL	runners_sigterm __P((int));
1019static SIGFUNC_DECL	runners_sighup __P((int));
1020
1021static SIGFUNC_DECL
1022runners_sigterm(sig)
1023	int sig;
1024{
1025	int save_errno = errno;
1026
1027	FIX_SYSV_SIGNAL(sig, runners_sigterm);
1028	errno = save_errno;
1029	CHECK_CRITICAL(sig);
1030	NoMoreRunners = true;
1031	Oldsh = Oldsh_term;
1032	Oldsig = sig;
1033	proc_list_signal(PROC_QUEUE, sig);
1034
1035	if (!BlockOldsh || getppid() <= 1)
1036	{
1037		/* Check that a valid 'old signal handler' is callable */
1038		if (Oldsh_term != SIG_DFL && Oldsh_term != SIG_IGN &&
1039		    Oldsh_term != runners_sigterm)
1040			(*Oldsh_term)(sig);
1041	}
1042	errno = save_errno;
1043	return SIGFUNC_RETURN;
1044}
1045/*
1046**  RUNNERS_SIGHUP -- propagate a SIGHUP to queue runner process
1047**
1048**	This propagates the signal to the child processes that are queue
1049**	runners. This is for a queue runner "cleanup". After all of the
1050**	child queue runner processes are signaled (it should be SIGHUP
1051**	being the sig) then the old signal handler (Oldsh) is called to
1052**	handle any cleanup set for this process (provided it is not SIG_DFL
1053**	or SIG_IGN). The signal may not be handled immediately if the
1054**	BlockOldsh flag is set. If the current process doesn't have
1055**	a parent then handle the signal immediately, regardless of
1056**	BlockOldsh.
1057**
1058**	Parameters:
1059**		sig -- the signal number being sent
1060**
1061**	Returns:
1062**		none.
1063**
1064**	Side Effects:
1065**		Sets the NoMoreRunners boolean to true to stop more runners
1066**		from being started in runqueue().
1067**
1068**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
1069**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
1070**		DOING.
1071*/
1072
1073static SIGFUNC_DECL
1074runners_sighup(sig)
1075	int sig;
1076{
1077	int save_errno = errno;
1078
1079	FIX_SYSV_SIGNAL(sig, runners_sighup);
1080	errno = save_errno;
1081	CHECK_CRITICAL(sig);
1082	NoMoreRunners = true;
1083	Oldsh = Oldsh_hup;
1084	Oldsig = sig;
1085	proc_list_signal(PROC_QUEUE, sig);
1086
1087	if (!BlockOldsh || getppid() <= 1)
1088	{
1089		/* Check that a valid 'old signal handler' is callable */
1090		if (Oldsh_hup != SIG_DFL && Oldsh_hup != SIG_IGN &&
1091		    Oldsh_hup != runners_sighup)
1092			(*Oldsh_hup)(sig);
1093	}
1094	errno = save_errno;
1095	return SIGFUNC_RETURN;
1096}
1097/*
1098**  MARK_WORK_GROUP_RESTART -- mark a work group as needing a restart
1099**
1100**  Sets a workgroup for restarting.
1101**
1102**	Parameters:
1103**		wgrp -- the work group id to restart.
1104**		reason -- why (signal?), -1 to turn off restart
1105**
1106**	Returns:
1107**		none.
1108**
1109**	Side effects:
1110**		May set global RestartWorkGroup to true.
1111**
1112**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
1113**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
1114**		DOING.
1115*/
1116
1117void
1118mark_work_group_restart(wgrp, reason)
1119	int wgrp;
1120	int reason;
1121{
1122	if (wgrp < 0 || wgrp > NumWorkGroups)
1123		return;
1124
1125	WorkGrp[wgrp].wg_restart = reason;
1126	if (reason >= 0)
1127		RestartWorkGroup = true;
1128}
1129/*
1130**  RESTART_MARKED_WORK_GROUPS -- restart work groups marked as needing restart
1131**
1132**  Restart any workgroup marked as needing a restart provided more
1133**  runners are allowed.
1134**
1135**	Parameters:
1136**		none.
1137**
1138**	Returns:
1139**		none.
1140**
1141**	Side effects:
1142**		Sets global RestartWorkGroup to false.
1143*/
1144
1145void
1146restart_marked_work_groups()
1147{
1148	int i;
1149	int wasblocked;
1150
1151	if (NoMoreRunners)
1152		return;
1153
1154	/* Block SIGCHLD so reapchild() doesn't mess with us */
1155	wasblocked = sm_blocksignal(SIGCHLD);
1156
1157	for (i = 0; i < NumWorkGroups; i++)
1158	{
1159		if (WorkGrp[i].wg_restart >= 0)
1160		{
1161			if (LogLevel > 8)
1162				sm_syslog(LOG_ERR, NOQID,
1163					  "restart queue runner=%d due to signal 0x%x",
1164					  i, WorkGrp[i].wg_restart);
1165			restart_work_group(i);
1166		}
1167	}
1168	RestartWorkGroup = false;
1169
1170	if (wasblocked == 0)
1171		(void) sm_releasesignal(SIGCHLD);
1172}
1173/*
1174**  RESTART_WORK_GROUP -- restart a specific work group
1175**
1176**  Restart a specific workgroup provided more runners are allowed.
1177**  If the requested work group has been restarted too many times log
1178**  this and refuse to restart.
1179**
1180**	Parameters:
1181**		wgrp -- the work group id to restart
1182**
1183**	Returns:
1184**		none.
1185**
1186**	Side Effects:
1187**		starts another process doing the work of wgrp
1188*/
1189
1190#define MAX_PERSIST_RESTART	10	/* max allowed number of restarts */
1191
1192static void
1193restart_work_group(wgrp)
1194	int wgrp;
1195{
1196	if (NoMoreRunners ||
1197	    wgrp < 0 || wgrp > NumWorkGroups)
1198		return;
1199
1200	WorkGrp[wgrp].wg_restart = -1;
1201	if (WorkGrp[wgrp].wg_restartcnt < MAX_PERSIST_RESTART)
1202	{
1203		/* avoid overflow; increment here */
1204		WorkGrp[wgrp].wg_restartcnt++;
1205		(void) run_work_group(wgrp, RWG_FORK|RWG_PERSISTENT|RWG_RUNALL);
1206	}
1207	else
1208	{
1209		sm_syslog(LOG_ERR, NOQID,
1210			  "ERROR: persistent queue runner=%d restarted too many times, queue runner lost",
1211			  wgrp);
1212	}
1213}
1214/*
1215**  SCHEDULE_QUEUE_RUNS -- schedule the next queue run for a work group.
1216**
1217**	Parameters:
1218**		runall -- schedule even if individual bit is not set.
1219**		wgrp -- the work group id to schedule.
1220**		didit -- the queue run was performed for this work group.
1221**
1222**	Returns:
1223**		nothing
1224*/
1225
1226#define INCR_MOD(v, m)	if (++v >= m)	\
1227				v = 0;	\
1228			else
1229
1230static void
1231schedule_queue_runs(runall, wgrp, didit)
1232	bool runall;
1233	int wgrp;
1234	bool didit;
1235{
1236	int qgrp, cgrp, endgrp;
1237#if _FFR_QUEUE_SCHED_DBG
1238	time_t lastsched;
1239	bool sched;
1240#endif /* _FFR_QUEUE_SCHED_DBG */
1241	time_t now;
1242	time_t minqintvl;
1243
1244	/*
1245	**  This is a bit ugly since we have to duplicate the
1246	**  code that "walks" through a work queue group.
1247	*/
1248
1249	now = curtime();
1250	minqintvl = 0;
1251	cgrp = endgrp = WorkGrp[wgrp].wg_curqgrp;
1252	do
1253	{
1254		time_t qintvl;
1255
1256#if _FFR_QUEUE_SCHED_DBG
1257		lastsched = 0;
1258		sched = false;
1259#endif /* _FFR_QUEUE_SCHED_DBG */
1260		qgrp = WorkGrp[wgrp].wg_qgs[cgrp]->qg_index;
1261		if (Queue[qgrp]->qg_queueintvl > 0)
1262			qintvl = Queue[qgrp]->qg_queueintvl;
1263		else if (QueueIntvl > 0)
1264			qintvl = QueueIntvl;
1265		else
1266			qintvl = (time_t) 0;
1267#if _FFR_QUEUE_SCHED_DBG
1268		lastsched = Queue[qgrp]->qg_nextrun;
1269#endif /* _FFR_QUEUE_SCHED_DBG */
1270		if ((runall || Queue[qgrp]->qg_nextrun <= now) && qintvl > 0)
1271		{
1272#if _FFR_QUEUE_SCHED_DBG
1273			sched = true;
1274#endif /* _FFR_QUEUE_SCHED_DBG */
1275			if (minqintvl == 0 || qintvl < minqintvl)
1276				minqintvl = qintvl;
1277
1278			/*
1279			**  Only set a new time if a queue run was performed
1280			**  for this queue group.  If the queue was not run,
1281			**  we could starve it by setting a new time on each
1282			**  call.
1283			*/
1284
1285			if (didit)
1286				Queue[qgrp]->qg_nextrun += qintvl;
1287		}
1288#if _FFR_QUEUE_SCHED_DBG
1289		if (tTd(69, 10))
1290			sm_syslog(LOG_INFO, NOQID,
1291				"sqr: wgrp=%d, cgrp=%d, qgrp=%d, intvl=%ld, QI=%ld, runall=%d, lastrun=%ld, nextrun=%ld, sched=%d",
1292				wgrp, cgrp, qgrp, Queue[qgrp]->qg_queueintvl,
1293				QueueIntvl, runall, lastsched,
1294				Queue[qgrp]->qg_nextrun, sched);
1295#endif /* _FFR_QUEUE_SCHED_DBG */
1296		INCR_MOD(cgrp, WorkGrp[wgrp].wg_numqgrp);
1297	} while (endgrp != cgrp);
1298	if (minqintvl > 0)
1299		(void) sm_setevent(minqintvl, runqueueevent, 0);
1300}
1301
1302#if _FFR_QUEUE_RUN_PARANOIA
1303/*
1304**  CHECKQUEUERUNNER -- check whether a queue group hasn't been run.
1305**
1306**	Use this if events may get lost and hence queue runners may not
1307**	be started and mail will pile up in a queue.
1308**
1309**	Parameters:
1310**		none.
1311**
1312**	Returns:
1313**		true if a queue run is necessary.
1314**
1315**	Side Effects:
1316**		may schedule a queue run.
1317*/
1318
1319bool
1320checkqueuerunner()
1321{
1322	int qgrp;
1323	time_t now, minqintvl;
1324
1325	now = curtime();
1326	minqintvl = 0;
1327	for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++)
1328	{
1329		time_t qintvl;
1330
1331		if (Queue[qgrp]->qg_queueintvl > 0)
1332			qintvl = Queue[qgrp]->qg_queueintvl;
1333		else if (QueueIntvl > 0)
1334			qintvl = QueueIntvl;
1335		else
1336			qintvl = (time_t) 0;
1337		if (Queue[qgrp]->qg_nextrun <= now - qintvl)
1338		{
1339			if (minqintvl == 0 || qintvl < minqintvl)
1340				minqintvl = qintvl;
1341			if (LogLevel > 1)
1342				sm_syslog(LOG_WARNING, NOQID,
1343					"checkqueuerunner: queue %d should have been run at %s, queue interval %ld",
1344					qgrp,
1345					arpadate(ctime(&Queue[qgrp]->qg_nextrun)),
1346					qintvl);
1347		}
1348	}
1349	if (minqintvl > 0)
1350	{
1351		(void) sm_setevent(minqintvl, runqueueevent, 0);
1352		return true;
1353	}
1354	return false;
1355}
1356#endif /* _FFR_QUEUE_RUN_PARANOIA */
1357
1358/*
1359**  RUNQUEUE -- run the jobs in the queue.
1360**
1361**	Gets the stuff out of the queue in some presumably logical
1362**	order and processes them.
1363**
1364**	Parameters:
1365**		forkflag -- true if the queue scanning should be done in
1366**			a child process.  We double-fork so it is not our
1367**			child and we don't have to clean up after it.
1368**			false can be ignored if we have multiple queues.
1369**		verbose -- if true, print out status information.
1370**		persistent -- persistent queue runner?
1371**		runall -- run all groups or only a subset (DoQueueRun)?
1372**
1373**	Returns:
1374**		true if the queue run successfully began.
1375**
1376**	Side Effects:
1377**		runs things in the mail queue using run_work_group().
1378**		maybe schedules next queue run.
1379*/
1380
1381static ENVELOPE	QueueEnvelope;		/* the queue run envelope */
1382static time_t	LastQueueTime = 0;	/* last time a queue ID assigned */
1383static pid_t	LastQueuePid = -1;	/* last PID which had a queue ID */
1384
1385/* values for qp_supdirs */
1386#define QP_NOSUB	0x0000	/* No subdirectories */
1387#define QP_SUBDF	0x0001	/* "df" subdirectory */
1388#define QP_SUBQF	0x0002	/* "qf" subdirectory */
1389#define QP_SUBXF	0x0004	/* "xf" subdirectory */
1390
1391bool
1392runqueue(forkflag, verbose, persistent, runall)
1393	bool forkflag;
1394	bool verbose;
1395	bool persistent;
1396	bool runall;
1397{
1398	int i;
1399	bool ret = true;
1400	static int curnum = 0;
1401	sigfunc_t cursh;
1402#if SM_HEAP_CHECK
1403	SM_NONVOLATILE int oldgroup = 0;
1404
1405	if (sm_debug_active(&DebugLeakQ, 1))
1406	{
1407		oldgroup = sm_heap_group();
1408		sm_heap_newgroup();
1409		sm_dprintf("runqueue() heap group #%d\n", sm_heap_group());
1410	}
1411#endif /* SM_HEAP_CHECK */
1412
1413	/* queue run has been started, don't do any more this time */
1414	DoQueueRun = false;
1415
1416	/* more than one queue or more than one directory per queue */
1417	if (!forkflag && !verbose &&
1418	    (WorkGrp[0].wg_qgs[0]->qg_numqueues > 1 || NumWorkGroups > 1 ||
1419	     WorkGrp[0].wg_numqgrp > 1))
1420		forkflag = true;
1421
1422	/*
1423	**  For controlling queue runners via signals sent to this process.
1424	**  Oldsh* will get called too by runners_sig* (if it is not SIG_IGN
1425	**  or SIG_DFL) to preserve cleanup behavior. Now that this process
1426	**  will have children (and perhaps grandchildren) this handler will
1427	**  be left in place. This is because this process, once it has
1428	**  finished spinning off queue runners, may go back to doing something
1429	**  else (like being a daemon). And we still want on a SIG{TERM,HUP} to
1430	**  clean up the child queue runners. Only install 'runners_sig*' once
1431	**  else we'll get stuck looping forever.
1432	*/
1433
1434	cursh = sm_signal(SIGTERM, runners_sigterm);
1435	if (cursh != runners_sigterm)
1436		Oldsh_term = cursh;
1437	cursh = sm_signal(SIGHUP, runners_sighup);
1438	if (cursh != runners_sighup)
1439		Oldsh_hup = cursh;
1440
1441	for (i = 0; i < NumWorkGroups && !NoMoreRunners; i++)
1442	{
1443		int rwgflags = RWG_NONE;
1444
1445		/*
1446		**  If MaxQueueChildren active then test whether the start
1447		**  of the next queue group's additional queue runners (maximum)
1448		**  will result in MaxQueueChildren being exceeded.
1449		**
1450		**  Note: do not use continue; even though another workgroup
1451		**	may have fewer queue runners, this would be "unfair",
1452		**	i.e., this work group might "starve" then.
1453		*/
1454
1455#if _FFR_QUEUE_SCHED_DBG
1456		if (tTd(69, 10))
1457			sm_syslog(LOG_INFO, NOQID,
1458				"rq: curnum=%d, MaxQueueChildren=%d, CurRunners=%d, WorkGrp[curnum].wg_maxact=%d",
1459				curnum, MaxQueueChildren, CurRunners,
1460				WorkGrp[curnum].wg_maxact);
1461#endif /* _FFR_QUEUE_SCHED_DBG */
1462		if (MaxQueueChildren > 0 &&
1463		    CurRunners + WorkGrp[curnum].wg_maxact > MaxQueueChildren)
1464			break;
1465
1466		/*
1467		**  Pick up where we left off (curnum), in case we
1468		**  used up all the children last time without finishing.
1469		**  This give a round-robin fairness to queue runs.
1470		**
1471		**  Increment CurRunners before calling run_work_group()
1472		**  to avoid a "race condition" with proc_list_drop() which
1473		**  decrements CurRunners if the queue runners terminate.
1474		**  This actually doesn't cause any harm, but CurRunners
1475		**  might become negative which is at least confusing.
1476		**
1477		**  Notice: CurRunners is an upper limit, in some cases
1478		**  (too few jobs in the queue) this value is larger than
1479		**  the actual number of queue runners. The discrepancy can
1480		**  increase if some queue runners "hang" for a long time.
1481		*/
1482
1483		CurRunners += WorkGrp[curnum].wg_maxact;
1484		if (forkflag)
1485			rwgflags |= RWG_FORK;
1486		if (verbose)
1487			rwgflags |= RWG_VERBOSE;
1488		if (persistent)
1489			rwgflags |= RWG_PERSISTENT;
1490		if (runall)
1491			rwgflags |= RWG_RUNALL;
1492		ret = run_work_group(curnum, rwgflags);
1493
1494		/*
1495		**  Failure means a message was printed for ETRN
1496		**  and subsequent queues are likely to fail as well.
1497		**  Decrement CurRunners in that case because
1498		**  none have been started.
1499		*/
1500
1501		if (!ret)
1502		{
1503			CurRunners -= WorkGrp[curnum].wg_maxact;
1504			break;
1505		}
1506
1507		if (!persistent)
1508			schedule_queue_runs(runall, curnum, true);
1509		INCR_MOD(curnum, NumWorkGroups);
1510	}
1511
1512	/* schedule left over queue runs */
1513	if (i < NumWorkGroups && !NoMoreRunners && !persistent)
1514	{
1515		int h;
1516
1517		for (h = curnum; i < NumWorkGroups; i++)
1518		{
1519			schedule_queue_runs(runall, h, false);
1520			INCR_MOD(h, NumWorkGroups);
1521		}
1522	}
1523
1524
1525#if SM_HEAP_CHECK
1526	if (sm_debug_active(&DebugLeakQ, 1))
1527		sm_heap_setgroup(oldgroup);
1528#endif /* SM_HEAP_CHECK */
1529	return ret;
1530}
1531/*
1532**  RUNNER_WORK -- have a queue runner do its work
1533**
1534**  Have a queue runner do its work a list of entries.
1535**  When work isn't directly being done then this process can take a signal
1536**  and terminate immediately (in a clean fashion of course).
1537**  When work is directly being done, it's not to be interrupted
1538**  immediately: the work should be allowed to finish at a clean point
1539**  before termination (in a clean fashion of course).
1540**
1541**	Parameters:
1542**		e -- envelope.
1543**		sequenceno -- 'th process to run WorkQ.
1544**		didfork -- did the calling process fork()?
1545**		skip -- process only each skip'th item.
1546**		njobs -- number of jobs in WorkQ.
1547**
1548**	Returns:
1549**		none.
1550**
1551**	Side Effects:
1552**		runs things in the mail queue.
1553*/
1554
1555/* Get new load average every 30 seconds. */
1556#define GET_NEW_LA_TIME	30
1557
1558static void
1559runner_work(e, sequenceno, didfork, skip, njobs)
1560	register ENVELOPE *e;
1561	int sequenceno;
1562	bool didfork;
1563	int skip;
1564	int njobs;
1565{
1566	int n;
1567	WORK *w;
1568	time_t current_la_time, now;
1569
1570	current_la_time = curtime();
1571
1572	/*
1573	**  Here we temporarily block the second calling of the handlers.
1574	**  This allows us to handle the signal without terminating in the
1575	**  middle of direct work. If a signal does come, the test for
1576	**  NoMoreRunners will find it.
1577	*/
1578
1579	BlockOldsh = true;
1580
1581	/* process them once at a time */
1582	while (WorkQ != NULL)
1583	{
1584#if SM_HEAP_CHECK
1585		SM_NONVOLATILE int oldgroup = 0;
1586
1587		if (sm_debug_active(&DebugLeakQ, 1))
1588		{
1589			oldgroup = sm_heap_group();
1590			sm_heap_newgroup();
1591			sm_dprintf("run_queue_group() heap group #%d\n",
1592				sm_heap_group());
1593		}
1594#endif /* SM_HEAP_CHECK */
1595
1596		/* do no more work */
1597		if (NoMoreRunners)
1598		{
1599			/* Check that a valid signal handler is callable */
1600			if (Oldsh != SIG_DFL && Oldsh != SIG_IGN &&
1601			    Oldsh != runners_sighup &&
1602			    Oldsh != runners_sigterm)
1603				(*Oldsh)(Oldsig);
1604			break;
1605		}
1606
1607		w = WorkQ; /* assign current work item */
1608
1609		/*
1610		**  Set the head of the WorkQ to the next work item.
1611		**  It is set 'skip' ahead (the number of parallel queue
1612		**  runners working on WorkQ together) since each runner
1613		**  works on every 'skip'th (N-th) item.
1614		*/
1615
1616		for (n = 0; n < skip && WorkQ != NULL; n++)
1617			WorkQ = WorkQ->w_next;
1618		e->e_to = NULL;
1619
1620		/*
1621		**  Ignore jobs that are too expensive for the moment.
1622		**
1623		**	Get new load average every GET_NEW_LA_TIME seconds.
1624		*/
1625
1626		now = curtime();
1627		if (current_la_time < now - GET_NEW_LA_TIME)
1628		{
1629			sm_getla();
1630			current_la_time = now;
1631		}
1632		if (shouldqueue(WkRecipFact, current_la_time))
1633		{
1634			char *msg = "Aborting queue run: load average too high";
1635
1636			if (Verbose)
1637				message("%s", msg);
1638			if (LogLevel > 8)
1639				sm_syslog(LOG_INFO, NOQID, "runqueue: %s", msg);
1640			break;
1641		}
1642		if (shouldqueue(w->w_pri, w->w_ctime))
1643		{
1644			if (Verbose)
1645				message(EmptyString);
1646			if (QueueSortOrder == QSO_BYPRIORITY)
1647			{
1648				if (Verbose)
1649					message("Skipping %s/%s (sequence %d of %d) and flushing rest of queue",
1650						qid_printqueue(w->w_qgrp,
1651							       w->w_qdir),
1652						w->w_name + 2, sequenceno,
1653						njobs);
1654				if (LogLevel > 8)
1655					sm_syslog(LOG_INFO, NOQID,
1656						  "runqueue: Flushing queue from %s/%s (pri %ld, LA %d, %d of %d)",
1657						  qid_printqueue(w->w_qgrp,
1658								 w->w_qdir),
1659						  w->w_name + 2, w->w_pri,
1660						  CurrentLA, sequenceno,
1661						  njobs);
1662				break;
1663			}
1664			else if (Verbose)
1665				message("Skipping %s/%s (sequence %d of %d)",
1666					qid_printqueue(w->w_qgrp, w->w_qdir),
1667					w->w_name + 2, sequenceno, njobs);
1668		}
1669		else
1670		{
1671			if (Verbose)
1672			{
1673				message(EmptyString);
1674				message("Running %s/%s (sequence %d of %d)",
1675					qid_printqueue(w->w_qgrp, w->w_qdir),
1676					w->w_name + 2, sequenceno, njobs);
1677			}
1678			if (didfork && MaxQueueChildren > 0)
1679			{
1680				sm_blocksignal(SIGCHLD);
1681				(void) sm_signal(SIGCHLD, reapchild);
1682			}
1683			if (tTd(63, 100))
1684				sm_syslog(LOG_DEBUG, NOQID,
1685					  "runqueue %s dowork(%s)",
1686					  qid_printqueue(w->w_qgrp, w->w_qdir),
1687					  w->w_name + 2);
1688
1689			(void) dowork(w->w_qgrp, w->w_qdir, w->w_name + 2,
1690				      ForkQueueRuns, false, e);
1691			errno = 0;
1692		}
1693		sm_free(w->w_name); /* XXX */
1694		if (w->w_host != NULL)
1695			sm_free(w->w_host); /* XXX */
1696		sm_free((char *) w); /* XXX */
1697		sequenceno += skip; /* next sequence number */
1698#if SM_HEAP_CHECK
1699		if (sm_debug_active(&DebugLeakQ, 1))
1700			sm_heap_setgroup(oldgroup);
1701#endif /* SM_HEAP_CHECK */
1702	}
1703
1704	BlockOldsh = false;
1705
1706	/* check the signals didn't happen during the revert */
1707	if (NoMoreRunners)
1708	{
1709		/* Check that a valid signal handler is callable */
1710		if (Oldsh != SIG_DFL && Oldsh != SIG_IGN &&
1711		    Oldsh != runners_sighup && Oldsh != runners_sigterm)
1712			(*Oldsh)(Oldsig);
1713	}
1714
1715	Oldsh = SIG_DFL; /* after the NoMoreRunners check */
1716}
1717/*
1718**  RUN_WORK_GROUP -- run the jobs in a queue group from a work group.
1719**
1720**	Gets the stuff out of the queue in some presumably logical
1721**	order and processes them.
1722**
1723**	Parameters:
1724**		wgrp -- work group to process.
1725**		flags -- RWG_* flags
1726**
1727**	Returns:
1728**		true if the queue run successfully began.
1729**
1730**	Side Effects:
1731**		runs things in the mail queue.
1732*/
1733
1734/* Minimum sleep time for persistent queue runners */
1735#define MIN_SLEEP_TIME	5
1736
1737bool
1738run_work_group(wgrp, flags)
1739	int wgrp;
1740	int flags;
1741{
1742	register ENVELOPE *e;
1743	int njobs, qdir;
1744	int sequenceno = 1;
1745	int qgrp, endgrp, h, i;
1746	time_t current_la_time, now;
1747	bool full, more;
1748	SM_RPOOL_T *rpool;
1749	extern void rmexpstab __P((void));
1750	extern ENVELOPE BlankEnvelope;
1751	extern SIGFUNC_DECL reapchild __P((int));
1752
1753	if (wgrp < 0)
1754		return false;
1755
1756	/*
1757	**  If no work will ever be selected, don't even bother reading
1758	**  the queue.
1759	*/
1760
1761	sm_getla();	/* get load average */
1762	current_la_time = curtime();
1763
1764	if (!bitset(RWG_PERSISTENT, flags) &&
1765	    shouldqueue(WkRecipFact, current_la_time))
1766	{
1767		char *msg = "Skipping queue run -- load average too high";
1768
1769		if (bitset(RWG_VERBOSE, flags))
1770			message("458 %s\n", msg);
1771		if (LogLevel > 8)
1772			sm_syslog(LOG_INFO, NOQID, "runqueue: %s", msg);
1773		return false;
1774	}
1775
1776	/*
1777	**  See if we already have too many children.
1778	*/
1779
1780	if (bitset(RWG_FORK, flags) &&
1781	    WorkGrp[wgrp].wg_lowqintvl > 0 &&
1782	    !bitset(RWG_PERSISTENT, flags) &&
1783	    MaxChildren > 0 && CurChildren >= MaxChildren)
1784	{
1785		char *msg = "Skipping queue run -- too many children";
1786
1787		if (bitset(RWG_VERBOSE, flags))
1788			message("458 %s (%d)\n", msg, CurChildren);
1789		if (LogLevel > 8)
1790			sm_syslog(LOG_INFO, NOQID, "runqueue: %s (%d)",
1791				  msg, CurChildren);
1792		return false;
1793	}
1794
1795	/*
1796	**  See if we want to go off and do other useful work.
1797	*/
1798
1799	if (bitset(RWG_FORK, flags))
1800	{
1801		pid_t pid;
1802
1803		(void) sm_blocksignal(SIGCHLD);
1804		(void) sm_signal(SIGCHLD, reapchild);
1805
1806		pid = dofork();
1807		if (pid == -1)
1808		{
1809			const char *msg = "Skipping queue run -- fork() failed";
1810			const char *err = sm_errstring(errno);
1811
1812			if (bitset(RWG_VERBOSE, flags))
1813				message("458 %s: %s\n", msg, err);
1814			if (LogLevel > 8)
1815				sm_syslog(LOG_INFO, NOQID, "runqueue: %s: %s",
1816					  msg, err);
1817			(void) sm_releasesignal(SIGCHLD);
1818			return false;
1819		}
1820		if (pid != 0)
1821		{
1822			/* parent -- pick up intermediate zombie */
1823			(void) sm_blocksignal(SIGALRM);
1824
1825			/* wgrp only used when queue runners are persistent */
1826			proc_list_add(pid, "Queue runner", PROC_QUEUE,
1827				      WorkGrp[wgrp].wg_maxact,
1828				      bitset(RWG_PERSISTENT, flags) ? wgrp : -1);
1829			(void) sm_releasesignal(SIGALRM);
1830			(void) sm_releasesignal(SIGCHLD);
1831			return true;
1832		}
1833
1834		/* child -- clean up signals */
1835
1836		/* Reset global flags */
1837		RestartRequest = NULL;
1838		RestartWorkGroup = false;
1839		ShutdownRequest = NULL;
1840		PendingSignal = 0;
1841		CurrentPid = getpid();
1842
1843		/*
1844		**  Initialize exception stack and default exception
1845		**  handler for child process.
1846		*/
1847
1848		sm_exc_newthread(fatal_error);
1849		clrcontrol();
1850		proc_list_clear();
1851
1852		/* Add parent process as first child item */
1853		proc_list_add(CurrentPid, "Queue runner child process",
1854			      PROC_QUEUE_CHILD, 0, -1);
1855		(void) sm_releasesignal(SIGCHLD);
1856		(void) sm_signal(SIGCHLD, SIG_DFL);
1857		(void) sm_signal(SIGHUP, SIG_DFL);
1858		(void) sm_signal(SIGTERM, intsig);
1859	}
1860
1861	/*
1862	**  Release any resources used by the daemon code.
1863	*/
1864
1865	clrdaemon();
1866
1867	/* force it to run expensive jobs */
1868	NoConnect = false;
1869
1870	/* drop privileges */
1871	if (geteuid() == (uid_t) 0)
1872		(void) drop_privileges(false);
1873
1874	/*
1875	**  Create ourselves an envelope
1876	*/
1877
1878	CurEnv = &QueueEnvelope;
1879	rpool = sm_rpool_new_x(NULL);
1880	e = newenvelope(&QueueEnvelope, CurEnv, rpool);
1881	e->e_flags = BlankEnvelope.e_flags;
1882	e->e_parent = NULL;
1883
1884	/* make sure we have disconnected from parent */
1885	if (bitset(RWG_FORK, flags))
1886	{
1887		disconnect(1, e);
1888		QuickAbort = false;
1889	}
1890
1891	/*
1892	**  If we are running part of the queue, always ignore stored
1893	**  host status.
1894	*/
1895
1896	if (QueueLimitId != NULL || QueueLimitSender != NULL ||
1897#if _FFR_QUARANTINE
1898	    QueueLimitQuarantine != NULL ||
1899#endif /* _FFR_QUARANTINE */
1900	    QueueLimitRecipient != NULL)
1901	{
1902		IgnoreHostStatus = true;
1903		MinQueueAge = 0;
1904	}
1905
1906	/*
1907	**  Here is where we choose the queue group from the work group.
1908	**  The caller of the "domorework" label must setup a new envelope.
1909	*/
1910
1911	endgrp = WorkGrp[wgrp].wg_curqgrp; /* to not spin endlessly */
1912
1913  domorework:
1914
1915	/*
1916	**  Run a queue group if:
1917	**  RWG_RUNALL bit is set or the bit for this group is set.
1918	*/
1919
1920	now = curtime();
1921	for (;;)
1922	{
1923		/*
1924		**  Find the next queue group within the work group that
1925		**  has been marked as needing a run.
1926		*/
1927
1928		qgrp = WorkGrp[wgrp].wg_qgs[WorkGrp[wgrp].wg_curqgrp]->qg_index;
1929		WorkGrp[wgrp].wg_curqgrp++; /* advance */
1930		WorkGrp[wgrp].wg_curqgrp %= WorkGrp[wgrp].wg_numqgrp; /* wrap */
1931		if (bitset(RWG_RUNALL, flags) ||
1932		    (Queue[qgrp]->qg_nextrun <= now &&
1933		     Queue[qgrp]->qg_nextrun != (time_t) -1))
1934			break;
1935		if (endgrp == WorkGrp[wgrp].wg_curqgrp)
1936		{
1937			e->e_id = NULL;
1938			if (bitset(RWG_FORK, flags))
1939				finis(true, true, ExitStat);
1940			return true; /* we're done */
1941		}
1942	}
1943
1944	qdir = Queue[qgrp]->qg_curnum; /* round-robin init of queue position */
1945#if _FFR_QUEUE_SCHED_DBG
1946	if (tTd(69, 12))
1947		sm_syslog(LOG_INFO, NOQID,
1948			"rwg: wgrp=%d, qgrp=%d, qdir=%d, name=%s, curqgrp=%d, numgrps=%d",
1949			wgrp, qgrp, qdir, qid_printqueue(qgrp, qdir),
1950			WorkGrp[wgrp].wg_curqgrp, WorkGrp[wgrp].wg_numqgrp);
1951#endif /* _FFR_QUEUE_SCHED_DBG */
1952
1953#if HASNICE
1954	/* tweak niceness of queue runs */
1955	if (Queue[qgrp]->qg_nice > 0)
1956		(void) nice(Queue[qgrp]->qg_nice);
1957#endif /* HASNICE */
1958
1959	/* XXX running queue group... */
1960	sm_setproctitle(true, CurEnv, "running queue: %s",
1961			qid_printqueue(qgrp, qdir));
1962
1963	if (LogLevel > 69 || tTd(63, 99))
1964		sm_syslog(LOG_DEBUG, NOQID,
1965			  "runqueue %s, pid=%d, forkflag=%d",
1966			  qid_printqueue(qgrp, qdir), (int) CurrentPid,
1967			  bitset(RWG_FORK, flags));
1968
1969	/*
1970	**  Start making passes through the queue.
1971	**	First, read and sort the entire queue.
1972	**	Then, process the work in that order.
1973	**		But if you take too long, start over.
1974	*/
1975
1976	for (i = 0; i < Queue[qgrp]->qg_numqueues; i++)
1977	{
1978		h = gatherq(qgrp, qdir, false, &full, &more);
1979#if SM_CONF_SHM
1980		if (ShmId != SM_SHM_NO_ID)
1981			QSHM_ENTRIES(Queue[qgrp]->qg_qpaths[qdir].qp_idx) = h;
1982#endif /* SM_CONF_SHM */
1983		/* If there are no more items in this queue advance */
1984		if (!more)
1985		{
1986			/* A round-robin advance */
1987			qdir++;
1988			qdir %= Queue[qgrp]->qg_numqueues;
1989		}
1990
1991		/* Has the WorkList reached the limit? */
1992		if (full)
1993			break; /* don't try to gather more */
1994	}
1995
1996	/* order the existing work requests */
1997	njobs = sortq(Queue[qgrp]->qg_maxlist);
1998	Queue[qgrp]->qg_curnum = qdir; /* update */
1999
2000
2001	if (!Verbose && bitnset(QD_FORK, Queue[qgrp]->qg_flags))
2002	{
2003		int loop, maxrunners;
2004		pid_t pid;
2005
2006		/*
2007		**  For this WorkQ we want to fork off N children (maxrunners)
2008		**  at this point. Each child has a copy of WorkQ. Each child
2009		**  will process every N-th item. The parent will wait for all
2010		**  of the children to finish before moving on to the next
2011		**  queue group within the work group. This saves us forking
2012		**  a new runner-child for each work item.
2013		**  It's valid for qg_maxqrun == 0 since this may be an
2014		**  explicit "don't run this queue" setting.
2015		*/
2016
2017		maxrunners = Queue[qgrp]->qg_maxqrun;
2018
2019		/* No need to have more runners then there are jobs */
2020		if (maxrunners > njobs)
2021			maxrunners = njobs;
2022		for (loop = 0; loop < maxrunners; loop++)
2023		{
2024			/*
2025			**  Since the delivery may happen in a child and the
2026			**  parent does not wait, the parent may close the
2027			**  maps thereby removing any shared memory used by
2028			**  the map.  Therefore, close the maps now so the
2029			**  child will dynamically open them if necessary.
2030			*/
2031
2032			closemaps(false);
2033
2034			pid = fork();
2035			if (pid < 0)
2036			{
2037				syserr("run_work_group: cannot fork");
2038				return 0;
2039			}
2040			else if (pid > 0)
2041			{
2042				/* parent -- clean out connection cache */
2043				mci_flush(false, NULL);
2044				WorkQ = WorkQ->w_next; /* for the skip */
2045				sequenceno++;
2046				proc_list_add(pid, "Queue child runner process",
2047					      PROC_QUEUE_CHILD, 0, -1);
2048
2049				/* No additional work, no additional runners */
2050				if (WorkQ == NULL)
2051					break;
2052			}
2053			else
2054			{
2055				/* child -- Reset global flags */
2056				RestartRequest = NULL;
2057				RestartWorkGroup = false;
2058				ShutdownRequest = NULL;
2059				PendingSignal = 0;
2060				CurrentPid = getpid();
2061
2062				/*
2063				**  Initialize exception stack and default
2064				**  exception handler for child process.
2065				**  When fork()'d the child now has a private
2066				**  copy of WorkQ at its current position.
2067				*/
2068
2069				sm_exc_newthread(fatal_error);
2070
2071				/*
2072				**  SMTP processes (whether -bd or -bs) set
2073				**  SIGCHLD to reapchild to collect
2074				**  children status.  However, at delivery
2075				**  time, that status must be collected
2076				**  by sm_wait() to be dealt with properly
2077				**  (check success of delivery based
2078				**  on status code, etc).  Therefore, if we
2079				**  are an SMTP process, reset SIGCHLD
2080				**  back to the default so reapchild
2081				**  doesn't collect status before
2082				**  sm_wait().
2083				*/
2084
2085				if (OpMode == MD_SMTP ||
2086				    OpMode == MD_DAEMON ||
2087				    MaxQueueChildren > 0)
2088				{
2089					proc_list_clear();
2090					sm_releasesignal(SIGCHLD);
2091					(void) sm_signal(SIGCHLD, SIG_DFL);
2092				}
2093
2094				/* child -- error messages to the transcript */
2095				QuickAbort = OnlyOneError = false;
2096				runner_work(e, sequenceno, true,
2097					    maxrunners, njobs);
2098
2099				/* This child is done */
2100				finis(true, true, ExitStat);
2101				/* NOTREACHED */
2102			}
2103		}
2104
2105		sm_releasesignal(SIGCHLD);
2106
2107		/*
2108		**  Wait until all of the runners have completed before
2109		**  seeing if there is another queue group in the
2110		**  work group to process.
2111		**  XXX Future enhancement: don't wait() for all children
2112		**  here, just go ahead and make sure that overall the number
2113		**  of children is not exceeded.
2114		*/
2115
2116		while (CurChildren > 0)
2117		{
2118			int status;
2119			pid_t ret;
2120
2121			while ((ret = sm_wait(&status)) <= 0)
2122				continue;
2123			proc_list_drop(ret, status, NULL);
2124		}
2125	}
2126	else if (Queue[qgrp]->qg_maxqrun > 0 || bitset(RWG_FORCE, flags))
2127	{
2128		/*
2129		**  When current process will not fork children to do the work,
2130		**  it will do the work itself. The 'skip' will be 1 since
2131		**  there are no child runners to divide the work across.
2132		*/
2133
2134		runner_work(e, sequenceno, false, 1, njobs);
2135	}
2136
2137	/* free memory allocated by newenvelope() above */
2138	sm_rpool_free(rpool);
2139	QueueEnvelope.e_rpool = NULL;
2140
2141	/* Are there still more queues in the work group to process? */
2142	if (endgrp != WorkGrp[wgrp].wg_curqgrp)
2143	{
2144		rpool = sm_rpool_new_x(NULL);
2145		e = newenvelope(&QueueEnvelope, CurEnv, rpool);
2146		e->e_flags = BlankEnvelope.e_flags;
2147		goto domorework;
2148	}
2149
2150	/* No more queues in work group to process. Now check persistent. */
2151	if (bitset(RWG_PERSISTENT, flags))
2152	{
2153		sequenceno = 1;
2154		sm_setproctitle(true, CurEnv, "running queue: %s",
2155				qid_printqueue(qgrp, qdir));
2156
2157		/*
2158		**  close bogus maps, i.e., maps which caused a tempfail,
2159		**	so we get fresh map connections on the next lookup.
2160		**  closemaps() is also called when children are started.
2161		*/
2162
2163		closemaps(true);
2164
2165		/* Close any cached connections. */
2166		mci_flush(true, NULL);
2167
2168		/* Clean out expired related entries. */
2169		rmexpstab();
2170
2171#if NAMED_BIND
2172		/* Update MX records for FallBackMX. */
2173		if (FallBackMX != NULL)
2174			(void) getfallbackmxrr(FallBackMX);
2175#endif /* NAMED_BIND */
2176
2177#if USERDB
2178		/* close UserDatabase */
2179		_udbx_close();
2180#endif /* USERDB */
2181
2182#if SM_HEAP_CHECK
2183		if (sm_debug_active(&SmHeapCheck, 2)
2184		    && access("memdump", F_OK) == 0
2185		   )
2186		{
2187			SM_FILE_T *out;
2188
2189			remove("memdump");
2190			out = sm_io_open(SmFtStdio, SM_TIME_DEFAULT,
2191					 "memdump.out", SM_IO_APPEND, NULL);
2192			if (out != NULL)
2193			{
2194				(void) sm_io_fprintf(out, SM_TIME_DEFAULT, "----------------------\n");
2195				sm_heap_report(out,
2196					sm_debug_level(&SmHeapCheck) - 1);
2197				(void) sm_io_close(out, SM_TIME_DEFAULT);
2198			}
2199		}
2200#endif /* SM_HEAP_CHECK */
2201
2202		/* let me rest for a second to catch my breath */
2203		if (njobs == 0 && WorkGrp[wgrp].wg_lowqintvl < MIN_SLEEP_TIME)
2204			sleep(MIN_SLEEP_TIME);
2205		else if (WorkGrp[wgrp].wg_lowqintvl <= 0)
2206			sleep(QueueIntvl > 0 ? QueueIntvl : MIN_SLEEP_TIME);
2207		else
2208			sleep(WorkGrp[wgrp].wg_lowqintvl);
2209
2210		/*
2211		**  Get the LA outside the WorkQ loop if necessary.
2212		**  In a persistent queue runner the code is repeated over
2213		**  and over but gatherq() may ignore entries due to
2214		**  shouldqueue() (do we really have to do this twice?).
2215		**  Hence the queue runners would just idle around when once
2216		**  CurrentLA caused all entries in a queue to be ignored.
2217		*/
2218
2219		now = curtime();
2220		if (njobs == 0 && current_la_time < now - GET_NEW_LA_TIME)
2221		{
2222			sm_getla();
2223			current_la_time = now;
2224		}
2225		rpool = sm_rpool_new_x(NULL);
2226		e = newenvelope(&QueueEnvelope, CurEnv, rpool);
2227		e->e_flags = BlankEnvelope.e_flags;
2228		goto domorework;
2229	}
2230
2231	/* exit without the usual cleanup */
2232	e->e_id = NULL;
2233	if (bitset(RWG_FORK, flags))
2234		finis(true, true, ExitStat);
2235	/* NOTREACHED */
2236	return true;
2237}
2238
2239/*
2240**  DOQUEUERUN -- do a queue run?
2241*/
2242
2243bool
2244doqueuerun()
2245{
2246	return DoQueueRun;
2247}
2248
2249/*
2250**  RUNQUEUEEVENT -- Sets a flag to indicate that a queue run should be done.
2251**
2252**	Parameters:
2253**		none.
2254**
2255**	Returns:
2256**		none.
2257**
2258**	Side Effects:
2259**		The invocation of this function via an alarm may interrupt
2260**		a set of actions. Thus errno may be set in that context.
2261**		We need to restore errno at the end of this function to ensure
2262**		that any work done here that sets errno doesn't return a
2263**		misleading/false errno value. Errno may	be EINTR upon entry to
2264**		this function because of non-restartable/continuable system
2265**		API was active. Iff this is true we will override errno as
2266**		a timeout (as a more accurate error message).
2267**
2268**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
2269**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2270**		DOING.
2271*/
2272
2273void
2274runqueueevent()
2275{
2276	int save_errno = errno;
2277
2278	/*
2279	**  Set the general bit that we want a queue run,
2280	**  tested in doqueuerun()
2281	*/
2282
2283	DoQueueRun = true;
2284#if _FFR_QUEUE_SCHED_DBG
2285	if (tTd(69, 10))
2286		sm_syslog(LOG_INFO, NOQID, "rqe: done");
2287#endif /* _FFR_QUEUE_SCHED_DBG */
2288
2289	errno = save_errno;
2290	if (errno == EINTR)
2291		errno = ETIMEDOUT;
2292}
2293/*
2294**  GATHERQ -- gather messages from the message queue(s) the work queue.
2295**
2296**	Parameters:
2297**		qgrp -- the index of the queue group.
2298**		qdir -- the index of the queue directory.
2299**		doall -- if set, include everything in the queue (even
2300**			the jobs that cannot be run because the load
2301**			average is too high, or MaxQueueRun is reached).
2302**			Otherwise, exclude those jobs.
2303**		full -- (optional) to be set 'true' if WorkList is full
2304**		more -- (optional) to be set 'true' if there are still more
2305**			messages in this queue not added to WorkList
2306**
2307**	Returns:
2308**		The number of request in the queue (not necessarily
2309**		the number of requests in WorkList however).
2310**
2311**	Side Effects:
2312**		prepares available work into WorkList
2313*/
2314
2315#define NEED_P		0001	/* 'P': priority */
2316#define NEED_T		0002	/* 'T': time */
2317#define NEED_R		0004	/* 'R': recipient */
2318#define NEED_S		0010	/* 'S': sender */
2319#define NEED_H		0020	/* host */
2320#if _FFR_QUARANTINE
2321# define HAS_QUARANTINE		0040	/* has an unexpected 'q' line */
2322# define NEED_QUARANTINE	0100	/* 'q': reason */
2323#endif /* _FFR_QUARANTINE */
2324
2325static WORK	*WorkList = NULL;	/* list of unsort work */
2326static int	WorkListSize = 0;	/* current max size of WorkList */
2327static int	WorkListCount = 0;	/* # of work items in WorkList */
2328
2329static int
2330gatherq(qgrp, qdir, doall, full, more)
2331	int qgrp;
2332	int qdir;
2333	bool doall;
2334	bool *full;
2335	bool *more;
2336{
2337	register struct dirent *d;
2338	register WORK *w;
2339	register char *p;
2340	DIR *f;
2341	int i, num_ent;
2342	int wn;
2343	QUEUE_CHAR *check;
2344	char qd[MAXPATHLEN];
2345	char qf[MAXPATHLEN];
2346
2347	wn = WorkListCount - 1;
2348	num_ent = 0;
2349	if (qdir == NOQDIR)
2350		(void) sm_strlcpy(qd, ".", sizeof qd);
2351	else
2352		(void) sm_strlcpyn(qd, sizeof qd, 2,
2353			Queue[qgrp]->qg_qpaths[qdir].qp_name,
2354			(bitset(QP_SUBQF,
2355				Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
2356					? "/qf" : ""));
2357
2358	if (tTd(41, 1))
2359	{
2360		sm_dprintf("gatherq:\n");
2361
2362		check = QueueLimitId;
2363		while (check != NULL)
2364		{
2365			sm_dprintf("\tQueueLimitId = %s%s\n",
2366				check->queue_negate ? "!" : "",
2367				check->queue_match);
2368			check = check->queue_next;
2369		}
2370
2371		check = QueueLimitSender;
2372		while (check != NULL)
2373		{
2374			sm_dprintf("\tQueueLimitSender = %s%s\n",
2375				check->queue_negate ? "!" : "",
2376				check->queue_match);
2377			check = check->queue_next;
2378		}
2379
2380		check = QueueLimitRecipient;
2381		while (check != NULL)
2382		{
2383			sm_dprintf("\tQueueLimitRecipient = %s%s\n",
2384				check->queue_negate ? "!" : "",
2385				check->queue_match);
2386			check = check->queue_next;
2387		}
2388
2389#if _FFR_QUARANTINE
2390		if (QueueMode == QM_QUARANTINE)
2391		{
2392			check = QueueLimitQuarantine;
2393			while (check != NULL)
2394			{
2395				sm_dprintf("\tQueueLimitQuarantine = %s%s\n",
2396					   check->queue_negate ? "!" : "",
2397					   check->queue_match);
2398				check = check->queue_next;
2399			}
2400		}
2401#endif /* _FFR_QUARANTINE */
2402	}
2403
2404	/* open the queue directory */
2405	f = opendir(qd);
2406	if (f == NULL)
2407	{
2408		syserr("gatherq: cannot open \"%s\"",
2409			qid_printqueue(qgrp, qdir));
2410		if (full != NULL)
2411			*full = WorkListCount >= MaxQueueRun && MaxQueueRun > 0;
2412		if (more != NULL)
2413			*more = false;
2414		return 0;
2415	}
2416
2417	/*
2418	**  Read the work directory.
2419	*/
2420
2421	while ((d = readdir(f)) != NULL)
2422	{
2423		SM_FILE_T *cf;
2424		int qfver = 0;
2425		char lbuf[MAXNAME + 1];
2426		struct stat sbuf;
2427
2428		if (tTd(41, 50))
2429			sm_dprintf("gatherq: checking %s..", d->d_name);
2430
2431		/* is this an interesting entry? */
2432#if _FFR_QUARANTINE
2433		if (!(((QueueMode == QM_NORMAL &&
2434			d->d_name[0] == NORMQF_LETTER) ||
2435		       (QueueMode == QM_QUARANTINE &&
2436			d->d_name[0] == QUARQF_LETTER) ||
2437		       (QueueMode == QM_LOST &&
2438			d->d_name[0] == LOSEQF_LETTER)) &&
2439		      d->d_name[1] == 'f'))
2440#else /* _FFR_QUARANTINE */
2441		if (d->d_name[0] != NORMQF_LETTER || d->d_name[1] != 'f')
2442#endif /* _FFR_QUARANTINE */
2443		{
2444			if (tTd(41, 50))
2445				sm_dprintf("  skipping\n");
2446			continue;
2447		}
2448		if (tTd(41, 50))
2449			sm_dprintf("\n");
2450
2451		if (strlen(d->d_name) >= MAXQFNAME)
2452		{
2453			if (Verbose)
2454				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2455						     "gatherq: %s too long, %d max characters\n",
2456						     d->d_name, MAXQFNAME);
2457			if (LogLevel > 0)
2458				sm_syslog(LOG_ALERT, NOQID,
2459					  "gatherq: %s too long, %d max characters",
2460					  d->d_name, MAXQFNAME);
2461			continue;
2462		}
2463
2464		check = QueueLimitId;
2465		while (check != NULL)
2466		{
2467			if (strcontainedin(false, check->queue_match,
2468					   d->d_name) != check->queue_negate)
2469				break;
2470			else
2471				check = check->queue_next;
2472		}
2473		if (QueueLimitId != NULL && check == NULL)
2474			continue;
2475
2476		/* grow work list if necessary */
2477		if (++wn >= MaxQueueRun && MaxQueueRun > 0)
2478		{
2479			if (wn == MaxQueueRun && LogLevel > 0)
2480				sm_syslog(LOG_WARNING, NOQID,
2481					  "WorkList for %s maxed out at %d",
2482					  qid_printqueue(qgrp, qdir),
2483					  MaxQueueRun);
2484			if (doall)
2485				continue;	/* just count entries */
2486			break;
2487		}
2488		if (wn >= WorkListSize)
2489		{
2490			grow_wlist(qgrp, qdir);
2491			if (wn >= WorkListSize)
2492				continue;
2493		}
2494		SM_ASSERT(wn >= 0);
2495		w = &WorkList[wn];
2496
2497		(void) sm_strlcpyn(qf, sizeof qf, 3, qd, "/", d->d_name);
2498		if (stat(qf, &sbuf) < 0)
2499		{
2500			if (errno != ENOENT)
2501				sm_syslog(LOG_INFO, NOQID,
2502					  "gatherq: can't stat %s/%s",
2503					  qid_printqueue(qgrp, qdir),
2504					  d->d_name);
2505			wn--;
2506			continue;
2507		}
2508		if (!bitset(S_IFREG, sbuf.st_mode))
2509		{
2510			/* Yikes!  Skip it or we will hang on open! */
2511			if (!((d->d_name[0] == DATAFL_LETTER ||
2512			       d->d_name[0] == NORMQF_LETTER ||
2513#if _FFR_QUARANTINE
2514			       d->d_name[0] == QUARQF_LETTER ||
2515			       d->d_name[0] == LOSEQF_LETTER ||
2516#endif /* _FFR_QUARANTINE */
2517			       d->d_name[0] == XSCRPT_LETTER) &&
2518			      d->d_name[1] == 'f' && d->d_name[2] == '\0'))
2519				syserr("gatherq: %s/%s is not a regular file",
2520				       qid_printqueue(qgrp, qdir), d->d_name);
2521			wn--;
2522			continue;
2523		}
2524
2525		/* avoid work if possible */
2526		if ((QueueSortOrder == QSO_BYFILENAME ||
2527		     QueueSortOrder == QSO_BYMODTIME ||
2528		     QueueSortOrder == QSO_RANDOM) &&
2529#if _FFR_QUARANTINE
2530		    QueueLimitQuarantine == NULL &&
2531#endif /* _FFR_QUARANTINE */
2532		    QueueLimitSender == NULL &&
2533		    QueueLimitRecipient == NULL)
2534		{
2535			w->w_qgrp = qgrp;
2536			w->w_qdir = qdir;
2537			w->w_name = newstr(d->d_name);
2538			w->w_host = NULL;
2539			w->w_lock = w->w_tooyoung = false;
2540			w->w_pri = 0;
2541			w->w_ctime = 0;
2542			w->w_mtime = sbuf.st_mtime;
2543			++num_ent;
2544			continue;
2545		}
2546
2547		/* open control file */
2548		cf = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY,
2549				NULL);
2550		if (cf == NULL && OpMode != MD_PRINT)
2551		{
2552			/* this may be some random person sending hir msgs */
2553			if (tTd(41, 2))
2554				sm_dprintf("gatherq: cannot open %s: %s\n",
2555					d->d_name, sm_errstring(errno));
2556			errno = 0;
2557			wn--;
2558			continue;
2559		}
2560		w->w_qgrp = qgrp;
2561		w->w_qdir = qdir;
2562		w->w_name = newstr(d->d_name);
2563		w->w_host = NULL;
2564		if (cf != NULL)
2565		{
2566			w->w_lock = !lockfile(sm_io_getinfo(cf, SM_IO_WHAT_FD,
2567							    NULL),
2568					      w->w_name, NULL,
2569					      LOCK_SH|LOCK_NB);
2570		}
2571		w->w_tooyoung = false;
2572
2573		/* make sure jobs in creation don't clog queue */
2574		w->w_pri = 0x7fffffff;
2575		w->w_ctime = 0;
2576		w->w_mtime = sbuf.st_mtime;
2577
2578		/* extract useful information */
2579		i = NEED_P|NEED_T;
2580		if (QueueSortOrder == QSO_BYHOST
2581#if _FFR_RHS
2582		    || QueueSortOrder == QSO_BYSHUFFLE
2583#endif /* _FFR_RHS */
2584		   )
2585		{
2586			/* need w_host set for host sort order */
2587			i |= NEED_H;
2588		}
2589		if (QueueLimitSender != NULL)
2590			i |= NEED_S;
2591		if (QueueLimitRecipient != NULL)
2592			i |= NEED_R;
2593#if _FFR_QUARANTINE
2594		if (QueueLimitQuarantine != NULL)
2595			i |= NEED_QUARANTINE;
2596#endif /* _FFR_QUARANTINE */
2597		while (cf != NULL && i != 0 &&
2598		       sm_io_fgets(cf, SM_TIME_DEFAULT, lbuf,
2599				   sizeof lbuf) != NULL)
2600		{
2601			int c;
2602			time_t age;
2603
2604			p = strchr(lbuf, '\n');
2605			if (p != NULL)
2606				*p = '\0';
2607			else
2608			{
2609				/* flush rest of overly long line */
2610				while ((c = sm_io_getc(cf, SM_TIME_DEFAULT))
2611				       != SM_IO_EOF && c != '\n')
2612					continue;
2613			}
2614
2615			switch (lbuf[0])
2616			{
2617			  case 'V':
2618				qfver = atoi(&lbuf[1]);
2619				break;
2620
2621			  case 'P':
2622				w->w_pri = atol(&lbuf[1]);
2623				i &= ~NEED_P;
2624				break;
2625
2626			  case 'T':
2627				w->w_ctime = atol(&lbuf[1]);
2628				i &= ~NEED_T;
2629				break;
2630
2631#if _FFR_QUARANTINE
2632			  case 'q':
2633				if (QueueMode != QM_QUARANTINE &&
2634				    QueueMode != QM_LOST)
2635				{
2636					if (tTd(41, 49))
2637						sm_dprintf("%s not marked as quarantined but has a 'q' line\n",
2638							   w->w_name);
2639					i |= HAS_QUARANTINE;
2640				}
2641				else if (QueueMode == QM_QUARANTINE)
2642				{
2643					if (QueueLimitQuarantine == NULL)
2644					{
2645						i &= ~NEED_QUARANTINE;
2646						break;
2647					}
2648					p = &lbuf[1];
2649					check = QueueLimitQuarantine;
2650					while (check != NULL)
2651					{
2652						if (strcontainedin(false,
2653								   check->queue_match,
2654								   p) !=
2655						    check->queue_negate)
2656							break;
2657						else
2658							check = check->queue_next;
2659					}
2660					if (check != NULL)
2661						i &= ~NEED_QUARANTINE;
2662				}
2663				break;
2664#endif /* _FFR_QUARANTINE */
2665
2666			  case 'R':
2667				if (w->w_host == NULL &&
2668				    (p = strrchr(&lbuf[1], '@')) != NULL)
2669				{
2670#if _FFR_RHS
2671					if (QueueSortOrder == QSO_BYSHUFFLE)
2672						w->w_host = newstr(&p[1]);
2673					else
2674#endif /* _FFR_RHS */
2675						w->w_host = strrev(&p[1]);
2676					makelower(w->w_host);
2677					i &= ~NEED_H;
2678				}
2679				if (QueueLimitRecipient == NULL)
2680				{
2681					i &= ~NEED_R;
2682					break;
2683				}
2684				if (qfver > 0)
2685				{
2686					p = strchr(&lbuf[1], ':');
2687					if (p == NULL)
2688						p = &lbuf[1];
2689				}
2690				else
2691					p = &lbuf[1];
2692				check = QueueLimitRecipient;
2693				while (check != NULL)
2694				{
2695					if (strcontainedin(true,
2696							   check->queue_match,
2697							   p) !=
2698					    check->queue_negate)
2699						break;
2700					else
2701						check = check->queue_next;
2702				}
2703				if (check != NULL)
2704					i &= ~NEED_R;
2705				break;
2706
2707			  case 'S':
2708				check = QueueLimitSender;
2709				while (check != NULL)
2710				{
2711					if (strcontainedin(true,
2712							   check->queue_match,
2713							   &lbuf[1]) !=
2714					    check->queue_negate)
2715						break;
2716					else
2717						check = check->queue_next;
2718				}
2719				if (check != NULL)
2720					i &= ~NEED_S;
2721				break;
2722
2723			  case 'K':
2724				age = curtime() - (time_t) atol(&lbuf[1]);
2725				if (age >= 0 && MinQueueAge > 0 &&
2726				    age < MinQueueAge)
2727					w->w_tooyoung = true;
2728				break;
2729
2730			  case 'N':
2731				if (atol(&lbuf[1]) == 0)
2732					w->w_tooyoung = false;
2733				break;
2734
2735#if _FFR_QUEUEDELAY
2736/*
2737			  case 'G':
2738				queuealg = atoi(lbuf[1]);
2739				break;
2740			  case 'Y':
2741				queuedelay = (time_t) atol(&lbuf[1]);
2742				break;
2743*/
2744#endif /* _FFR_QUEUEDELAY */
2745			}
2746		}
2747		if (cf != NULL)
2748			(void) sm_io_close(cf, SM_TIME_DEFAULT);
2749
2750		if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
2751#if _FFR_QUARANTINE
2752		    bitset(HAS_QUARANTINE, i) ||
2753		    bitset(NEED_QUARANTINE, i) ||
2754#endif /* _FFR_QUARANTINE */
2755		    bitset(NEED_R|NEED_S, i))
2756		{
2757			/* don't even bother sorting this job in */
2758			if (tTd(41, 49))
2759				sm_dprintf("skipping %s (%x)\n", w->w_name, i);
2760			sm_free(w->w_name); /* XXX */
2761			if (w->w_host != NULL)
2762				sm_free(w->w_host); /* XXX */
2763			wn--;
2764		}
2765		else
2766			++num_ent;
2767	}
2768	(void) closedir(f);
2769	wn++;
2770
2771	i = wn - WorkListCount;
2772	WorkListCount += SM_MIN(num_ent, WorkListSize);
2773
2774	if (more != NULL)
2775		*more = WorkListCount < wn;
2776
2777	if (full != NULL)
2778		*full = (wn >= MaxQueueRun && MaxQueueRun > 0) ||
2779			(WorkList == NULL && wn > 0);
2780
2781	return i;
2782}
2783/*
2784**  SORTQ -- sort the work list
2785**
2786**	First the old WorkQ is cleared away. Then the WorkList is sorted
2787**	for all items so that important (higher sorting value) items are not
2788**	trunctated off. Then the most important items are moved from
2789**	WorkList to WorkQ. The lower count of 'max' or MaxListCount items
2790**	are moved.
2791**
2792**	Parameters:
2793**		max -- maximum number of items to be placed in WorkQ
2794**
2795**	Returns:
2796**		the number of items in WorkQ
2797**
2798**	Side Effects:
2799**		WorkQ gets released and filled with new work. WorkList
2800**		gets released. Work items get sorted in order.
2801*/
2802
2803static int
2804sortq(max)
2805	int max;
2806{
2807	register int i;			/* local counter */
2808	register WORK *w;		/* tmp item pointer */
2809	int wc = WorkListCount;		/* trim size for WorkQ */
2810
2811	if (WorkQ != NULL)
2812	{
2813		/* Clear out old WorkQ. */
2814		for (w = WorkQ; w != NULL; )
2815		{
2816			register WORK *nw = w->w_next;
2817
2818			WorkQ = nw;
2819			sm_free(w->w_name); /* XXX */
2820			if (w->w_host != NULL)
2821				sm_free(w->w_host); /* XXX */
2822			sm_free((char *) w); /* XXX */
2823			w = nw;
2824		}
2825		sm_free((char *) WorkQ);
2826		WorkQ = NULL;
2827	}
2828
2829	if (WorkList == NULL || wc <= 0)
2830		return 0;
2831
2832	/* Check if the per queue group item limit will be exceeded */
2833	if (wc > max && max > 0)
2834		wc = max;
2835
2836	/*
2837	**  The sort now takes place using all of the items in WorkList.
2838	**  The list gets trimmed to the most important items after the sort.
2839	**  If the trim were to happen before the sort then one or more
2840	**  important items might get truncated off -- not what we want.
2841	*/
2842
2843	if (QueueSortOrder == QSO_BYHOST)
2844	{
2845		/*
2846		**  Sort the work directory for the first time,
2847		**  based on host name, lock status, and priority.
2848		*/
2849
2850		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1);
2851
2852		/*
2853		**  If one message to host is locked, "lock" all messages
2854		**  to that host.
2855		*/
2856
2857		i = 0;
2858		while (i < wc)
2859		{
2860			if (!WorkList[i].w_lock)
2861			{
2862				i++;
2863				continue;
2864			}
2865			w = &WorkList[i];
2866			while (++i < wc)
2867			{
2868				if (WorkList[i].w_host == NULL &&
2869				    w->w_host == NULL)
2870					WorkList[i].w_lock = true;
2871				else if (WorkList[i].w_host != NULL &&
2872					 w->w_host != NULL &&
2873					 sm_strcasecmp(WorkList[i].w_host,
2874						       w->w_host) == 0)
2875					WorkList[i].w_lock = true;
2876				else
2877					break;
2878			}
2879		}
2880
2881		/*
2882		**  Sort the work directory for the second time,
2883		**  based on lock status, host name, and priority.
2884		*/
2885
2886		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2);
2887	}
2888	else if (QueueSortOrder == QSO_BYTIME)
2889	{
2890		/*
2891		**  Simple sort based on submission time only.
2892		*/
2893
2894		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf3);
2895	}
2896	else if (QueueSortOrder == QSO_BYFILENAME)
2897	{
2898		/*
2899		**  Sort based on queue filename.
2900		*/
2901
2902		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf4);
2903	}
2904	else if (QueueSortOrder == QSO_RANDOM)
2905	{
2906		/*
2907		**  Sort randomly.  To avoid problems with an instable sort,
2908		**  use a random index into the queue file name to start
2909		**  comparison.
2910		*/
2911
2912		randi = get_rand_mod(MAXQFNAME);
2913		if (randi < 2)
2914			randi = 3;
2915		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf5);
2916	}
2917	else if (QueueSortOrder == QSO_BYMODTIME)
2918	{
2919		/*
2920		**  Simple sort based on modification time of queue file.
2921		**  This puts the oldest items first.
2922		*/
2923
2924		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf6);
2925	}
2926#if _FFR_RHS
2927	else if (QueueSortOrder == QSO_BYSHUFFLE)
2928	{
2929		/*
2930		**  Simple sort based on shuffled host name.
2931		*/
2932
2933		init_shuffle_alphabet();
2934		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf7);
2935	}
2936#endif /* _FFR_RHS */
2937	else
2938	{
2939		/*
2940		**  Simple sort based on queue priority only.
2941		*/
2942
2943		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0);
2944	}
2945
2946	/*
2947	**  Convert the work list into canonical form.
2948	**	Should be turning it into a list of envelopes here perhaps.
2949	**  Only take the most important items up to the per queue group
2950	**  maximum.
2951	*/
2952
2953	for (i = wc; --i >= 0; )
2954	{
2955		w = (WORK *) xalloc(sizeof *w);
2956		w->w_qgrp = WorkList[i].w_qgrp;
2957		w->w_qdir = WorkList[i].w_qdir;
2958		w->w_name = WorkList[i].w_name;
2959		w->w_host = WorkList[i].w_host;
2960		w->w_lock = WorkList[i].w_lock;
2961		w->w_tooyoung = WorkList[i].w_tooyoung;
2962		w->w_pri = WorkList[i].w_pri;
2963		w->w_ctime = WorkList[i].w_ctime;
2964		w->w_mtime = WorkList[i].w_mtime;
2965		w->w_next = WorkQ;
2966		WorkQ = w;
2967	}
2968	if (WorkList != NULL)
2969		sm_free(WorkList); /* XXX */
2970	WorkList = NULL;
2971	WorkListSize = 0;
2972	WorkListCount = 0;
2973
2974	if (tTd(40, 1))
2975	{
2976		for (w = WorkQ; w != NULL; w = w->w_next)
2977		{
2978			if (w->w_host != NULL)
2979				sm_dprintf("%22s: pri=%ld %s\n",
2980					w->w_name, w->w_pri, w->w_host);
2981			else
2982				sm_dprintf("%32s: pri=%ld\n",
2983					w->w_name, w->w_pri);
2984		}
2985	}
2986
2987	return wc; /* return number of WorkQ items */
2988}
2989/*
2990**  GROW_WLIST -- make the work list larger
2991**
2992**	Parameters:
2993**		qgrp -- the index for the queue group.
2994**		qdir -- the index for the queue directory.
2995**
2996**	Returns:
2997**		none.
2998**
2999**	Side Effects:
3000**		Adds another QUEUESEGSIZE entries to WorkList if possible.
3001**		It can fail if there isn't enough memory, so WorkListSize
3002**		should be checked again upon return.
3003*/
3004
3005static void
3006grow_wlist(qgrp, qdir)
3007	int qgrp;
3008	int qdir;
3009{
3010	if (tTd(41, 1))
3011		sm_dprintf("grow_wlist: WorkListSize=%d\n", WorkListSize);
3012	if (WorkList == NULL)
3013	{
3014		WorkList = (WORK *) xalloc((sizeof *WorkList) *
3015					   (QUEUESEGSIZE + 1));
3016		WorkListSize = QUEUESEGSIZE;
3017	}
3018	else
3019	{
3020		int newsize = WorkListSize + QUEUESEGSIZE;
3021		WORK *newlist = (WORK *) sm_realloc((char *) WorkList,
3022					  (unsigned) sizeof(WORK) * (newsize + 1));
3023
3024		if (newlist != NULL)
3025		{
3026			WorkListSize = newsize;
3027			WorkList = newlist;
3028			if (LogLevel > 1)
3029			{
3030				sm_syslog(LOG_INFO, NOQID,
3031					  "grew WorkList for %s to %d",
3032					  qid_printqueue(qgrp, qdir),
3033					  WorkListSize);
3034			}
3035		}
3036		else if (LogLevel > 0)
3037		{
3038			sm_syslog(LOG_ALERT, NOQID,
3039				  "FAILED to grow WorkList for %s to %d",
3040				  qid_printqueue(qgrp, qdir), newsize);
3041		}
3042	}
3043	if (tTd(41, 1))
3044		sm_dprintf("grow_wlist: WorkListSize now %d\n", WorkListSize);
3045}
3046/*
3047**  WORKCMPF0 -- simple priority-only compare function.
3048**
3049**	Parameters:
3050**		a -- the first argument.
3051**		b -- the second argument.
3052**
3053**	Returns:
3054**		-1 if a < b
3055**		 0 if a == b
3056**		+1 if a > b
3057**
3058*/
3059
3060static int
3061workcmpf0(a, b)
3062	register WORK *a;
3063	register WORK *b;
3064{
3065	long pa = a->w_pri;
3066	long pb = b->w_pri;
3067
3068	if (pa == pb)
3069		return 0;
3070	else if (pa > pb)
3071		return 1;
3072	else
3073		return -1;
3074}
3075/*
3076**  WORKCMPF1 -- first compare function for ordering work based on host name.
3077**
3078**	Sorts on host name, lock status, and priority in that order.
3079**
3080**	Parameters:
3081**		a -- the first argument.
3082**		b -- the second argument.
3083**
3084**	Returns:
3085**		<0 if a < b
3086**		 0 if a == b
3087**		>0 if a > b
3088**
3089*/
3090
3091static int
3092workcmpf1(a, b)
3093	register WORK *a;
3094	register WORK *b;
3095{
3096	int i;
3097
3098	/* host name */
3099	if (a->w_host != NULL && b->w_host == NULL)
3100		return 1;
3101	else if (a->w_host == NULL && b->w_host != NULL)
3102		return -1;
3103	if (a->w_host != NULL && b->w_host != NULL &&
3104	    (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
3105		return i;
3106
3107	/* lock status */
3108	if (a->w_lock != b->w_lock)
3109		return b->w_lock - a->w_lock;
3110
3111	/* job priority */
3112	return workcmpf0(a, b);
3113}
3114/*
3115**  WORKCMPF2 -- second compare function for ordering work based on host name.
3116**
3117**	Sorts on lock status, host name, and priority in that order.
3118**
3119**	Parameters:
3120**		a -- the first argument.
3121**		b -- the second argument.
3122**
3123**	Returns:
3124**		<0 if a < b
3125**		 0 if a == b
3126**		>0 if a > b
3127**
3128*/
3129
3130static int
3131workcmpf2(a, b)
3132	register WORK *a;
3133	register WORK *b;
3134{
3135	int i;
3136
3137	/* lock status */
3138	if (a->w_lock != b->w_lock)
3139		return a->w_lock - b->w_lock;
3140
3141	/* host name */
3142	if (a->w_host != NULL && b->w_host == NULL)
3143		return 1;
3144	else if (a->w_host == NULL && b->w_host != NULL)
3145		return -1;
3146	if (a->w_host != NULL && b->w_host != NULL &&
3147	    (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
3148		return i;
3149
3150	/* job priority */
3151	return workcmpf0(a, b);
3152}
3153/*
3154**  WORKCMPF3 -- simple submission-time-only compare function.
3155**
3156**	Parameters:
3157**		a -- the first argument.
3158**		b -- the second argument.
3159**
3160**	Returns:
3161**		-1 if a < b
3162**		 0 if a == b
3163**		+1 if a > b
3164**
3165*/
3166
3167static int
3168workcmpf3(a, b)
3169	register WORK *a;
3170	register WORK *b;
3171{
3172	if (a->w_ctime > b->w_ctime)
3173		return 1;
3174	else if (a->w_ctime < b->w_ctime)
3175		return -1;
3176	else
3177		return 0;
3178}
3179/*
3180**  WORKCMPF4 -- compare based on file name
3181**
3182**	Parameters:
3183**		a -- the first argument.
3184**		b -- the second argument.
3185**
3186**	Returns:
3187**		-1 if a < b
3188**		 0 if a == b
3189**		+1 if a > b
3190**
3191*/
3192
3193static int
3194workcmpf4(a, b)
3195	register WORK *a;
3196	register WORK *b;
3197{
3198	return strcmp(a->w_name, b->w_name);
3199}
3200/*
3201**  WORKCMPF5 -- compare based on assigned random number
3202**
3203**	Parameters:
3204**		a -- the first argument (ignored).
3205**		b -- the second argument (ignored).
3206**
3207**	Returns:
3208**		randomly 1/-1
3209*/
3210
3211/* ARGSUSED0 */
3212static int
3213workcmpf5(a, b)
3214	register WORK *a;
3215	register WORK *b;
3216{
3217	if (strlen(a->w_name) < randi || strlen(b->w_name) < randi)
3218		return -1;
3219	return a->w_name[randi] - b->w_name[randi];
3220}
3221/*
3222**  WORKCMPF6 -- simple modification-time-only compare function.
3223**
3224**	Parameters:
3225**		a -- the first argument.
3226**		b -- the second argument.
3227**
3228**	Returns:
3229**		-1 if a < b
3230**		 0 if a == b
3231**		+1 if a > b
3232**
3233*/
3234
3235static int
3236workcmpf6(a, b)
3237	register WORK *a;
3238	register WORK *b;
3239{
3240	if (a->w_mtime > b->w_mtime)
3241		return 1;
3242	else if (a->w_mtime < b->w_mtime)
3243		return -1;
3244	else
3245		return 0;
3246}
3247#if _FFR_RHS
3248/*
3249**  WORKCMPF7 -- compare function for ordering work based on shuffled host name.
3250**
3251**	Sorts on lock status, host name, and priority in that order.
3252**
3253**	Parameters:
3254**		a -- the first argument.
3255**		b -- the second argument.
3256**
3257**	Returns:
3258**		<0 if a < b
3259**		 0 if a == b
3260**		>0 if a > b
3261**
3262*/
3263
3264static int
3265workcmpf7(a, b)
3266	register WORK *a;
3267	register WORK *b;
3268{
3269	int i;
3270
3271	/* lock status */
3272	if (a->w_lock != b->w_lock)
3273		return a->w_lock - b->w_lock;
3274
3275	/* host name */
3276	if (a->w_host != NULL && b->w_host == NULL)
3277		return 1;
3278	else if (a->w_host == NULL && b->w_host != NULL)
3279		return -1;
3280	if (a->w_host != NULL && b->w_host != NULL &&
3281	    (i = sm_strshufflecmp(a->w_host, b->w_host)) != 0)
3282		return i;
3283
3284	/* job priority */
3285	return workcmpf0(a, b);
3286}
3287#endif /* _FFR_RHS */
3288/*
3289**  STRREV -- reverse string
3290**
3291**	Returns a pointer to a new string that is the reverse of
3292**	the string pointed to by fwd.  The space for the new
3293**	string is obtained using xalloc().
3294**
3295**	Parameters:
3296**		fwd -- the string to reverse.
3297**
3298**	Returns:
3299**		the reversed string.
3300*/
3301
3302static char *
3303strrev(fwd)
3304	char *fwd;
3305{
3306	char *rev = NULL;
3307	int len, cnt;
3308
3309	len = strlen(fwd);
3310	rev = xalloc(len + 1);
3311	for (cnt = 0; cnt < len; ++cnt)
3312		rev[cnt] = fwd[len - cnt - 1];
3313	rev[len] = '\0';
3314	return rev;
3315}
3316
3317#if _FFR_RHS
3318
3319#define NASCII	128
3320#define NCHAR	256
3321
3322static unsigned char ShuffledAlphabet[NCHAR];
3323
3324void
3325init_shuffle_alphabet()
3326{
3327	static bool init = false;
3328	int i;
3329
3330	if (init)
3331		return;
3332
3333	/* fill the ShuffledAlphabet */
3334	for (i = 0; i < NCHAR; i++)
3335		ShuffledAlphabet[i] = i;
3336
3337	/* mix it */
3338	for (i = 1; i < NCHAR; i++)
3339	{
3340		register int j = get_random() % NCHAR;
3341		register int tmp;
3342
3343		tmp = ShuffledAlphabet[j];
3344		ShuffledAlphabet[j] = ShuffledAlphabet[i];
3345		ShuffledAlphabet[i] = tmp;
3346	}
3347
3348	/* make it case insensitive */
3349	for (i = 'A'; i <= 'Z'; i++)
3350		ShuffledAlphabet[i] = ShuffledAlphabet[i + 'a' - 'A'];
3351
3352	/* fill the upper part */
3353	for (i = 0; i < NCHAR; i++)
3354		ShuffledAlphabet[i + NCHAR] = ShuffledAlphabet[i];
3355	init = true;
3356}
3357
3358static int
3359sm_strshufflecmp(a, b)
3360	char *a;
3361	char *b;
3362{
3363	const unsigned char *us1 = (const unsigned char *) a;
3364	const unsigned char *us2 = (const unsigned char *) b;
3365
3366	while (ShuffledAlphabet[*us1] == ShuffledAlphabet[*us2++])
3367	{
3368		if (*us1++ == '\0')
3369			return 0;
3370	}
3371	return (ShuffledAlphabet[*us1] - ShuffledAlphabet[*--us2]);
3372}
3373#endif /* _FFR_RHS */
3374
3375/*
3376**  DOWORK -- do a work request.
3377**
3378**	Parameters:
3379**		qgrp -- the index of the queue group for the job.
3380**		qdir -- the index of the queue directory for the job.
3381**		id -- the ID of the job to run.
3382**		forkflag -- if set, run this in background.
3383**		requeueflag -- if set, reinstantiate the queue quickly.
3384**			This is used when expanding aliases in the queue.
3385**			If forkflag is also set, it doesn't wait for the
3386**			child.
3387**		e - the envelope in which to run it.
3388**
3389**	Returns:
3390**		process id of process that is running the queue job.
3391**
3392**	Side Effects:
3393**		The work request is satisfied if possible.
3394*/
3395
3396pid_t
3397dowork(qgrp, qdir, id, forkflag, requeueflag, e)
3398	int qgrp;
3399	int qdir;
3400	char *id;
3401	bool forkflag;
3402	bool requeueflag;
3403	register ENVELOPE *e;
3404{
3405	register pid_t pid;
3406	SM_RPOOL_T *rpool;
3407
3408	if (tTd(40, 1))
3409		sm_dprintf("dowork(%s/%s)\n", qid_printqueue(qgrp, qdir), id);
3410
3411	/*
3412	**  Fork for work.
3413	*/
3414
3415	if (forkflag)
3416	{
3417		/*
3418		**  Since the delivery may happen in a child and the
3419		**  parent does not wait, the parent may close the
3420		**  maps thereby removing any shared memory used by
3421		**  the map.  Therefore, close the maps now so the
3422		**  child will dynamically open them if necessary.
3423		*/
3424
3425		closemaps(false);
3426
3427		pid = fork();
3428		if (pid < 0)
3429		{
3430			syserr("dowork: cannot fork");
3431			return 0;
3432		}
3433		else if (pid > 0)
3434		{
3435			/* parent -- clean out connection cache */
3436			mci_flush(false, NULL);
3437		}
3438		else
3439		{
3440			/*
3441			**  Initialize exception stack and default exception
3442			**  handler for child process.
3443			*/
3444
3445			/* Reset global flags */
3446			RestartRequest = NULL;
3447			RestartWorkGroup = false;
3448			ShutdownRequest = NULL;
3449			PendingSignal = 0;
3450			CurrentPid = getpid();
3451			sm_exc_newthread(fatal_error);
3452
3453			/*
3454			**  See note above about SMTP processes and SIGCHLD.
3455			*/
3456
3457			if (OpMode == MD_SMTP ||
3458			    OpMode == MD_DAEMON ||
3459			    MaxQueueChildren > 0)
3460			{
3461				proc_list_clear();
3462				sm_releasesignal(SIGCHLD);
3463				(void) sm_signal(SIGCHLD, SIG_DFL);
3464			}
3465
3466			/* child -- error messages to the transcript */
3467			QuickAbort = OnlyOneError = false;
3468		}
3469	}
3470	else
3471	{
3472		pid = 0;
3473	}
3474
3475	if (pid == 0)
3476	{
3477		/*
3478		**  CHILD
3479		**	Lock the control file to avoid duplicate deliveries.
3480		**		Then run the file as though we had just read it.
3481		**	We save an idea of the temporary name so we
3482		**		can recover on interrupt.
3483		*/
3484
3485		if (forkflag)
3486		{
3487			/* Reset global flags */
3488			RestartRequest = NULL;
3489			RestartWorkGroup = false;
3490			ShutdownRequest = NULL;
3491			PendingSignal = 0;
3492		}
3493
3494		/* set basic modes, etc. */
3495		sm_clear_events();
3496		clearstats();
3497		rpool = sm_rpool_new_x(NULL);
3498		clearenvelope(e, false, rpool);
3499		e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
3500		set_delivery_mode(SM_DELIVER, e);
3501		e->e_errormode = EM_MAIL;
3502		e->e_id = id;
3503		e->e_qgrp = qgrp;
3504		e->e_qdir = qdir;
3505		GrabTo = UseErrorsTo = false;
3506		ExitStat = EX_OK;
3507		if (forkflag)
3508		{
3509			disconnect(1, e);
3510			set_op_mode(MD_QUEUERUN);
3511		}
3512		sm_setproctitle(true, e, "%s from queue", qid_printname(e));
3513		if (LogLevel > 76)
3514			sm_syslog(LOG_DEBUG, e->e_id, "dowork, pid=%d",
3515				  (int) CurrentPid);
3516
3517		/* don't use the headers from sendmail.cf... */
3518		e->e_header = NULL;
3519
3520		/* read the queue control file -- return if locked */
3521		if (!readqf(e, false))
3522		{
3523			if (tTd(40, 4) && e->e_id != NULL)
3524				sm_dprintf("readqf(%s) failed\n",
3525					qid_printname(e));
3526			e->e_id = NULL;
3527			if (forkflag)
3528				finis(false, true, EX_OK);
3529			else
3530			{
3531				/* adding this frees 8 bytes */
3532				clearenvelope(e, false, rpool);
3533
3534				/* adding this frees 12 bytes */
3535				sm_rpool_free(rpool);
3536				e->e_rpool = NULL;
3537				return 0;
3538			}
3539		}
3540
3541		e->e_flags |= EF_INQUEUE;
3542		eatheader(e, requeueflag, true);
3543
3544		if (requeueflag)
3545			queueup(e, false, false);
3546
3547		/* do the delivery */
3548		sendall(e, SM_DELIVER);
3549
3550		/* finish up and exit */
3551		if (forkflag)
3552			finis(true, true, ExitStat);
3553		else
3554		{
3555			dropenvelope(e, true, false);
3556			sm_rpool_free(rpool);
3557			e->e_rpool = NULL;
3558		}
3559	}
3560	e->e_id = NULL;
3561	return pid;
3562}
3563
3564/*
3565**  DOWORKLIST -- process a list of envelopes as work requests
3566**
3567**	Similar to dowork(), except that after forking, it processes an
3568**	envelope and its siblings, treating each envelope as a work request.
3569**
3570**	Parameters:
3571**		el -- envelope to be processed including its siblings.
3572**		forkflag -- if set, run this in background.
3573**		requeueflag -- if set, reinstantiate the queue quickly.
3574**			This is used when expanding aliases in the queue.
3575**			If forkflag is also set, it doesn't wait for the
3576**			child.
3577**
3578**	Returns:
3579**		process id of process that is running the queue job.
3580**
3581**	Side Effects:
3582**		The work request is satisfied if possible.
3583*/
3584
3585pid_t
3586doworklist(el, forkflag, requeueflag)
3587	ENVELOPE *el;
3588	bool forkflag;
3589	bool requeueflag;
3590{
3591	register pid_t pid;
3592	ENVELOPE *ei;
3593
3594	if (tTd(40, 1))
3595		sm_dprintf("doworklist()\n");
3596
3597	/*
3598	**  Fork for work.
3599	*/
3600
3601	if (forkflag)
3602	{
3603		/*
3604		**  Since the delivery may happen in a child and the
3605		**  parent does not wait, the parent may close the
3606		**  maps thereby removing any shared memory used by
3607		**  the map.  Therefore, close the maps now so the
3608		**  child will dynamically open them if necessary.
3609		*/
3610
3611		closemaps(false);
3612
3613		pid = fork();
3614		if (pid < 0)
3615		{
3616			syserr("doworklist: cannot fork");
3617			return 0;
3618		}
3619		else if (pid > 0)
3620		{
3621			/* parent -- clean out connection cache */
3622			mci_flush(false, NULL);
3623		}
3624		else
3625		{
3626			/*
3627			**  Initialize exception stack and default exception
3628			**  handler for child process.
3629			*/
3630
3631			/* Reset global flags */
3632			RestartRequest = NULL;
3633			RestartWorkGroup = false;
3634			ShutdownRequest = NULL;
3635			PendingSignal = 0;
3636			CurrentPid = getpid();
3637			sm_exc_newthread(fatal_error);
3638
3639			/*
3640			**  See note above about SMTP processes and SIGCHLD.
3641			*/
3642
3643			if (OpMode == MD_SMTP ||
3644			    OpMode == MD_DAEMON ||
3645			    MaxQueueChildren > 0)
3646			{
3647				proc_list_clear();
3648				sm_releasesignal(SIGCHLD);
3649				(void) sm_signal(SIGCHLD, SIG_DFL);
3650			}
3651
3652			/* child -- error messages to the transcript */
3653			QuickAbort = OnlyOneError = false;
3654		}
3655	}
3656	else
3657	{
3658		pid = 0;
3659	}
3660
3661	if (pid != 0)
3662		return pid;
3663
3664	/*
3665	**  IN CHILD
3666	**	Lock the control file to avoid duplicate deliveries.
3667	**		Then run the file as though we had just read it.
3668	**	We save an idea of the temporary name so we
3669	**		can recover on interrupt.
3670	*/
3671
3672	if (forkflag)
3673	{
3674		/* Reset global flags */
3675		RestartRequest = NULL;
3676		RestartWorkGroup = false;
3677		ShutdownRequest = NULL;
3678		PendingSignal = 0;
3679	}
3680
3681	/* set basic modes, etc. */
3682	sm_clear_events();
3683	clearstats();
3684	GrabTo = UseErrorsTo = false;
3685	ExitStat = EX_OK;
3686	if (forkflag)
3687	{
3688		disconnect(1, el);
3689		set_op_mode(MD_QUEUERUN);
3690	}
3691	if (LogLevel > 76)
3692		sm_syslog(LOG_DEBUG, el->e_id, "doworklist, pid=%d",
3693			  (int) CurrentPid);
3694
3695	for (ei = el; ei != NULL; ei = ei->e_sibling)
3696	{
3697		ENVELOPE e;
3698		SM_RPOOL_T *rpool;
3699
3700		if (WILL_BE_QUEUED(ei->e_sendmode))
3701			continue;
3702#if _FFR_QUARANTINE
3703		else if (QueueMode != QM_QUARANTINE &&
3704			 ei->e_quarmsg != NULL)
3705			continue;
3706#endif /* _FFR_QUARANTINE */
3707
3708		rpool = sm_rpool_new_x(NULL);
3709		clearenvelope(&e, true, rpool);
3710		e.e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
3711		set_delivery_mode(SM_DELIVER, &e);
3712		e.e_errormode = EM_MAIL;
3713		e.e_id = ei->e_id;
3714		e.e_qgrp = ei->e_qgrp;
3715		e.e_qdir = ei->e_qdir;
3716		openxscript(&e);
3717		sm_setproctitle(true, &e, "%s from queue", qid_printname(&e));
3718
3719		/* don't use the headers from sendmail.cf... */
3720		e.e_header = NULL;
3721		CurEnv = &e;
3722
3723		/* read the queue control file -- return if locked */
3724		if (readqf(&e, false))
3725		{
3726			e.e_flags |= EF_INQUEUE;
3727			eatheader(&e, requeueflag, true);
3728
3729			if (requeueflag)
3730				queueup(&e, false, false);
3731
3732			/* do the delivery */
3733			sendall(&e, SM_DELIVER);
3734			dropenvelope(&e, true, false);
3735		}
3736		else
3737		{
3738			if (tTd(40, 4) && e.e_id != NULL)
3739				sm_dprintf("readqf(%s) failed\n",
3740					qid_printname(&e));
3741		}
3742		sm_rpool_free(rpool);
3743		ei->e_id = NULL;
3744	}
3745
3746	/* restore CurEnv */
3747	CurEnv = el;
3748
3749	/* finish up and exit */
3750	if (forkflag)
3751		finis(true, true, ExitStat);
3752	return 0;
3753}
3754/*
3755**  READQF -- read queue file and set up environment.
3756**
3757**	Parameters:
3758**		e -- the envelope of the job to run.
3759**		openonly -- only open the qf (returned as e_lockfp)
3760**
3761**	Returns:
3762**		true if it successfully read the queue file.
3763**		false otherwise.
3764**
3765**	Side Effects:
3766**		The queue file is returned locked.
3767*/
3768
3769static bool
3770readqf(e, openonly)
3771	register ENVELOPE *e;
3772	bool openonly;
3773{
3774	register SM_FILE_T *qfp;
3775	ADDRESS *ctladdr;
3776	struct stat st, stf;
3777	char *bp;
3778	int qfver = 0;
3779	long hdrsize = 0;
3780	register char *p;
3781	char *frcpt = NULL;
3782	char *orcpt = NULL;
3783	bool nomore = false;
3784	bool bogus = false;
3785	MODE_T qsafe;
3786	char *err;
3787	char qf[MAXPATHLEN];
3788	char buf[MAXLINE];
3789
3790	/*
3791	**  Read and process the file.
3792	*/
3793
3794	(void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER), sizeof qf);
3795	qfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDWR, NULL);
3796	if (qfp == NULL)
3797	{
3798		int save_errno = errno;
3799
3800		if (tTd(40, 8))
3801			sm_dprintf("readqf(%s): sm_io_open failure (%s)\n",
3802				qf, sm_errstring(errno));
3803		errno = save_errno;
3804		if (errno != ENOENT
3805		    )
3806			syserr("readqf: no control file %s", qf);
3807		RELEASE_QUEUE;
3808		return false;
3809	}
3810
3811	if (!lockfile(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), qf, NULL,
3812		      LOCK_EX|LOCK_NB))
3813	{
3814		/* being processed by another queuer */
3815		if (Verbose)
3816			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3817					     "%s: locked\n", e->e_id);
3818		if (tTd(40, 8))
3819			sm_dprintf("%s: locked\n", e->e_id);
3820		if (LogLevel > 19)
3821			sm_syslog(LOG_DEBUG, e->e_id, "locked");
3822		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
3823		RELEASE_QUEUE;
3824		return false;
3825	}
3826
3827	/*
3828	**  Prevent locking race condition.
3829	**
3830	**  Process A: readqf(): qfp = fopen(qffile)
3831	**  Process B: queueup(): rename(tf, qf)
3832	**  Process B: unlocks(tf)
3833	**  Process A: lockfile(qf);
3834	**
3835	**  Process A (us) has the old qf file (before the rename deleted
3836	**  the directory entry) and will be delivering based on old data.
3837	**  This can lead to multiple deliveries of the same recipients.
3838	**
3839	**  Catch this by checking if the underlying qf file has changed
3840	**  *after* acquiring our lock and if so, act as though the file
3841	**  was still locked (i.e., just return like the lockfile() case
3842	**  above.
3843	*/
3844
3845	if (stat(qf, &stf) < 0 ||
3846	    fstat(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), &st) < 0)
3847	{
3848		/* must have been being processed by someone else */
3849		if (tTd(40, 8))
3850			sm_dprintf("readqf(%s): [f]stat failure (%s)\n",
3851				qf, sm_errstring(errno));
3852		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
3853		RELEASE_QUEUE;
3854		return false;
3855	}
3856
3857	if (st.st_nlink != stf.st_nlink ||
3858	    st.st_dev != stf.st_dev ||
3859	    ST_INODE(st) != ST_INODE(stf) ||
3860#if HAS_ST_GEN && 0		/* AFS returns garbage in st_gen */
3861	    st.st_gen != stf.st_gen ||
3862#endif /* HAS_ST_GEN && 0 */
3863	    st.st_uid != stf.st_uid ||
3864	    st.st_gid != stf.st_gid ||
3865	    st.st_size != stf.st_size)
3866	{
3867		/* changed after opened */
3868		if (Verbose)
3869			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3870					     "%s: changed\n", e->e_id);
3871		if (tTd(40, 8))
3872			sm_dprintf("%s: changed\n", e->e_id);
3873		if (LogLevel > 19)
3874			sm_syslog(LOG_DEBUG, e->e_id, "changed");
3875		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
3876		RELEASE_QUEUE;
3877		return false;
3878	}
3879
3880	/*
3881	**  Check the queue file for plausibility to avoid attacks.
3882	*/
3883
3884	qsafe = S_IWOTH|S_IWGRP;
3885	if (bitset(S_IWGRP, QueueFileMode))
3886		qsafe &= ~S_IWGRP;
3887
3888	bogus = st.st_uid != geteuid() &&
3889		st.st_uid != TrustedUid &&
3890		geteuid() != RealUid;
3891
3892	/*
3893	**  If this qf file results from a set-group-ID binary, then
3894	**  we check whether the directory is group-writable,
3895	**  the queue file mode contains the group-writable bit, and
3896	**  the groups are the same.
3897	**  Notice: this requires that the set-group-ID binary is used to
3898	**  run the queue!
3899	*/
3900
3901	if (bogus && st.st_gid == getegid() && UseMSP)
3902	{
3903		char delim;
3904		struct stat dst;
3905
3906		bp = SM_LAST_DIR_DELIM(qf);
3907		if (bp == NULL)
3908			delim = '\0';
3909		else
3910		{
3911			delim = *bp;
3912			*bp = '\0';
3913		}
3914		if (stat(delim == '\0' ? "." : qf, &dst) < 0)
3915			syserr("readqf: cannot stat directory %s",
3916				delim == '\0' ? "." : qf);
3917		else
3918		{
3919			bogus = !(bitset(S_IWGRP, QueueFileMode) &&
3920				  bitset(S_IWGRP, dst.st_mode) &&
3921				  dst.st_gid == st.st_gid);
3922		}
3923		if (delim != '\0')
3924			*bp = delim;
3925	}
3926	if (!bogus)
3927		bogus = bitset(qsafe, st.st_mode);
3928	if (bogus)
3929	{
3930		if (LogLevel > 0)
3931		{
3932			sm_syslog(LOG_ALERT, e->e_id,
3933				  "bogus queue file, uid=%d, gid=%d, mode=%o",
3934				  st.st_uid, st.st_gid, st.st_mode);
3935		}
3936		if (tTd(40, 8))
3937			sm_dprintf("readqf(%s): bogus file\n", qf);
3938		e->e_flags |= EF_INQUEUE;
3939		if (!openonly)
3940			loseqfile(e, "bogus file uid/gid in mqueue");
3941		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
3942		RELEASE_QUEUE;
3943		return false;
3944	}
3945
3946	if (st.st_size == 0)
3947	{
3948		/* must be a bogus file -- if also old, just remove it */
3949		if (!openonly && st.st_ctime + 10 * 60 < curtime())
3950		{
3951			(void) xunlink(queuename(e, DATAFL_LETTER));
3952			(void) xunlink(queuename(e, ANYQFL_LETTER));
3953		}
3954		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
3955		RELEASE_QUEUE;
3956		return false;
3957	}
3958
3959	if (st.st_nlink == 0)
3960	{
3961		/*
3962		**  Race condition -- we got a file just as it was being
3963		**  unlinked.  Just assume it is zero length.
3964		*/
3965
3966		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
3967		RELEASE_QUEUE;
3968		return false;
3969	}
3970
3971#if _FFR_TRUSTED_QF
3972	/*
3973	**  If we don't own the file mark it as unsafe.
3974	**  However, allow TrustedUser to own it as well
3975	**  in case TrustedUser manipulates the queue.
3976	*/
3977
3978	if (st.st_uid != geteuid() && st.st_uid != TrustedUid)
3979		e->e_flags |= EF_UNSAFE;
3980#else /* _FFR_TRUSTED_QF */
3981	/* If we don't own the file mark it as unsafe */
3982	if (st.st_uid != geteuid())
3983		e->e_flags |= EF_UNSAFE;
3984#endif /* _FFR_TRUSTED_QF */
3985
3986	/* good file -- save this lock */
3987	e->e_lockfp = qfp;
3988
3989	/* Just wanted the open file */
3990	if (openonly)
3991		return true;
3992
3993	/* do basic system initialization */
3994	initsys(e);
3995	macdefine(&e->e_macro, A_PERM, 'i', e->e_id);
3996
3997	LineNumber = 0;
3998	e->e_flags |= EF_GLOBALERRS;
3999	set_op_mode(MD_QUEUERUN);
4000	ctladdr = NULL;
4001#if _FFR_QUARANTINE
4002	e->e_qfletter = queue_letter(e, ANYQFL_LETTER);
4003#endif /* _FFR_QUARANTINE */
4004	e->e_dfqgrp = e->e_qgrp;
4005	e->e_dfqdir = e->e_qdir;
4006#if _FFR_QUEUE_MACRO
4007	macdefine(&e->e_macro, A_TEMP, macid("{queue}"),
4008		  qid_printqueue(e->e_qgrp, e->e_qdir));
4009#endif /* _FFR_QUEUE_MACRO */
4010	e->e_dfino = -1;
4011	e->e_msgsize = -1;
4012#if _FFR_QUEUEDELAY
4013	e->e_queuealg = QD_LINEAR;
4014	e->e_queuedelay = (time_t) 0;
4015#endif /* _FFR_QUEUEDELAY */
4016	while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
4017	{
4018		unsigned long qflags;
4019		ADDRESS *q;
4020		int r;
4021		time_t now;
4022		auto char *ep;
4023
4024		if (tTd(40, 4))
4025			sm_dprintf("+++++ %s\n", bp);
4026		if (nomore)
4027		{
4028			/* hack attack */
4029  hackattack:
4030			syserr("SECURITY ALERT: extra or bogus data in queue file: %s",
4031			       bp);
4032			err = "bogus queue line";
4033			goto fail;
4034		}
4035		switch (bp[0])
4036		{
4037		  case 'A':		/* AUTH= parameter */
4038			if (!xtextok(&bp[1]))
4039				goto hackattack;
4040			e->e_auth_param = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4041			break;
4042
4043		  case 'B':		/* body type */
4044			r = check_bodytype(&bp[1]);
4045			if (!BODYTYPE_VALID(r))
4046				goto hackattack;
4047			e->e_bodytype = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4048			break;
4049
4050		  case 'C':		/* specify controlling user */
4051			ctladdr = setctluser(&bp[1], qfver, e);
4052			break;
4053
4054		  case 'D':		/* data file name */
4055			/* obsolete -- ignore */
4056			break;
4057
4058		  case 'd':		/* data file directory name */
4059			{
4060				int qgrp, qdir;
4061
4062#if _FFR_MSP_PARANOIA
4063				/* forbid queue groups in MSP? */
4064				if (UseMSP)
4065					goto hackattack;
4066#endif /* _FFR_MSP_PARANOIA */
4067				for (qgrp = 0;
4068				     qgrp < NumQueue && Queue[qgrp] != NULL;
4069				     ++qgrp)
4070				{
4071					for (qdir = 0;
4072					     qdir < Queue[qgrp]->qg_numqueues;
4073					     ++qdir)
4074					{
4075						if (strcmp(&bp[1],
4076							   Queue[qgrp]->qg_qpaths[qdir].qp_name)
4077						    == 0)
4078						{
4079							e->e_dfqgrp = qgrp;
4080							e->e_dfqdir = qdir;
4081							goto done;
4082						}
4083					}
4084				}
4085				err = "bogus queue file directory";
4086				goto fail;
4087			  done:
4088				break;
4089			}
4090
4091		  case 'E':		/* specify error recipient */
4092			/* no longer used */
4093			break;
4094
4095		  case 'F':		/* flag bits */
4096			if (strncmp(bp, "From ", 5) == 0)
4097			{
4098				/* we are being spoofed! */
4099				syserr("SECURITY ALERT: bogus qf line %s", bp);
4100				err = "bogus queue line";
4101				goto fail;
4102			}
4103			for (p = &bp[1]; *p != '\0'; p++)
4104			{
4105				switch (*p)
4106				{
4107				  case '8':	/* has 8 bit data */
4108					e->e_flags |= EF_HAS8BIT;
4109					break;
4110
4111				  case 'b':	/* delete Bcc: header */
4112					e->e_flags |= EF_DELETE_BCC;
4113					break;
4114
4115				  case 'd':	/* envelope has DSN RET= */
4116					e->e_flags |= EF_RET_PARAM;
4117					break;
4118
4119				  case 'n':	/* don't return body */
4120					e->e_flags |= EF_NO_BODY_RETN;
4121					break;
4122
4123				  case 'r':	/* response */
4124					e->e_flags |= EF_RESPONSE;
4125					break;
4126
4127				  case 's':	/* split */
4128					e->e_flags |= EF_SPLIT;
4129					break;
4130
4131				  case 'w':	/* warning sent */
4132					e->e_flags |= EF_WARNING;
4133					break;
4134				}
4135			}
4136			break;
4137
4138#if _FFR_QUEUEDELAY
4139		  case 'G':		/* queue delay algorithm */
4140			e->e_queuealg = atoi(&buf[1]);
4141			break;
4142#endif /* _FFR_QUEUEDELAY */
4143
4144#if _FFR_QUARANTINE
4145		  case 'q':		/* quarantine reason */
4146			e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4147			macdefine(&e->e_macro, A_PERM,
4148				  macid("{quarantine}"), e->e_quarmsg);
4149			break;
4150#endif /* _FFR_QUARANTINE */
4151
4152		  case 'H':		/* header */
4153
4154			/*
4155			**  count size before chompheader() destroys the line.
4156			**  this isn't accurate due to macro expansion, but
4157			**  better than before. "+3" to skip H?? at least.
4158			*/
4159
4160			hdrsize += strlen(bp + 3);
4161			(void) chompheader(&bp[1], CHHDR_QUEUE, NULL, e);
4162			break;
4163
4164		  case 'I':		/* data file's inode number */
4165			/* regenerated below */
4166			break;
4167
4168		  case 'K':		/* time of last delivery attempt */
4169			e->e_dtime = atol(&buf[1]);
4170			break;
4171
4172		  case 'L':		/* Solaris Content-Length: */
4173		  case 'M':		/* message */
4174			/* ignore this; we want a new message next time */
4175			break;
4176
4177		  case 'N':		/* number of delivery attempts */
4178			e->e_ntries = atoi(&buf[1]);
4179
4180			/* if this has been tried recently, let it be */
4181			now = curtime();
4182			if (e->e_ntries > 0 && e->e_dtime <= now &&
4183			    now < e->e_dtime + queuedelay(e))
4184			{
4185				char *howlong;
4186
4187				howlong = pintvl(now - e->e_dtime, true);
4188				if (Verbose)
4189					(void) sm_io_fprintf(smioout,
4190							     SM_TIME_DEFAULT,
4191							     "%s: too young (%s)\n",
4192							     e->e_id, howlong);
4193				if (tTd(40, 8))
4194					sm_dprintf("%s: too young (%s)\n",
4195						e->e_id, howlong);
4196				if (LogLevel > 19)
4197					sm_syslog(LOG_DEBUG, e->e_id,
4198						  "too young (%s)",
4199						  howlong);
4200				e->e_id = NULL;
4201				unlockqueue(e);
4202				RELEASE_QUEUE;
4203				return false;
4204			}
4205			macdefine(&e->e_macro, A_TEMP,
4206				macid("{ntries}"), &buf[1]);
4207
4208#if NAMED_BIND
4209			/* adjust BIND parameters immediately */
4210			if (e->e_ntries == 0)
4211			{
4212				_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
4213				_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
4214			}
4215			else
4216			{
4217				_res.retry = TimeOuts.res_retry[RES_TO_NORMAL];
4218				_res.retrans = TimeOuts.res_retrans[RES_TO_NORMAL];
4219			}
4220#endif /* NAMED_BIND */
4221			break;
4222
4223		  case 'P':		/* message priority */
4224			e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
4225			break;
4226
4227		  case 'Q':		/* original recipient */
4228			orcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4229			break;
4230
4231		  case 'r':		/* final recipient */
4232			frcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4233			break;
4234
4235		  case 'R':		/* specify recipient */
4236			p = bp;
4237			qflags = 0;
4238			if (qfver >= 1)
4239			{
4240				/* get flag bits */
4241				while (*++p != '\0' && *p != ':')
4242				{
4243					switch (*p)
4244					{
4245					  case 'N':
4246						qflags |= QHASNOTIFY;
4247						break;
4248
4249					  case 'S':
4250						qflags |= QPINGONSUCCESS;
4251						break;
4252
4253					  case 'F':
4254						qflags |= QPINGONFAILURE;
4255						break;
4256
4257					  case 'D':
4258						qflags |= QPINGONDELAY;
4259						break;
4260
4261					  case 'P':
4262						qflags |= QPRIMARY;
4263						break;
4264
4265					  case 'A':
4266						if (ctladdr != NULL)
4267							ctladdr->q_flags |= QALIAS;
4268						break;
4269
4270					  default: /* ignore or complain? */
4271						break;
4272					}
4273				}
4274			}
4275			else
4276				qflags |= QPRIMARY;
4277			q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e,
4278				      true);
4279			if (q != NULL)
4280			{
4281				/* make sure we keep the current qgrp */
4282				if (ISVALIDQGRP(e->e_qgrp))
4283					q->q_qgrp = e->e_qgrp;
4284				q->q_alias = ctladdr;
4285				if (qfver >= 1)
4286					q->q_flags &= ~Q_PINGFLAGS;
4287				q->q_flags |= qflags;
4288				q->q_finalrcpt = frcpt;
4289				q->q_orcpt = orcpt;
4290				(void) recipient(q, &e->e_sendqueue, 0, e);
4291			}
4292			frcpt = NULL;
4293			orcpt = NULL;
4294			break;
4295
4296		  case 'S':		/* sender */
4297			setsender(sm_rpool_strdup_x(e->e_rpool, &bp[1]),
4298				  e, NULL, '\0', true);
4299			break;
4300
4301		  case 'T':		/* init time */
4302			e->e_ctime = atol(&bp[1]);
4303			break;
4304
4305		  case 'V':		/* queue file version number */
4306			qfver = atoi(&bp[1]);
4307			if (queuedelay_qfver_unsupported(qfver))
4308				syserr("queue file version %d not supported: %s",
4309				       qfver,
4310				       "sendmail not compiled with _FFR_QUEUEDELAY");
4311			if (qfver <= QF_VERSION)
4312				break;
4313			syserr("Version number in queue file (%d) greater than max (%d)",
4314				qfver, QF_VERSION);
4315			err = "unsupported queue file version";
4316			goto fail;
4317			/* NOTREACHED */
4318			break;
4319
4320#if _FFR_QUEUEDELAY
4321		  case 'Y':		/* current delay */
4322			e->e_queuedelay = (time_t) atol(&buf[1]);
4323			break;
4324#endif /* _FFR_QUEUEDELAY */
4325
4326		  case 'Z':		/* original envelope id from ESMTP */
4327			e->e_envid = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4328			macdefine(&e->e_macro, A_PERM,
4329				macid("{dsn_envid}"), e->e_envid);
4330			break;
4331
4332		  case '!':		/* deliver by */
4333
4334			/* format: flag (1 char) space long-integer */
4335			e->e_dlvr_flag = buf[1];
4336			e->e_deliver_by = strtol(&buf[3], NULL, 10);
4337
4338		  case '$':		/* define macro */
4339			{
4340				char *p;
4341
4342				/* XXX elimate p? */
4343				r = macid_parse(&bp[1], &ep);
4344				if (r == 0)
4345					break;
4346				p = sm_rpool_strdup_x(e->e_rpool, ep);
4347				macdefine(&e->e_macro, A_PERM, r, p);
4348			}
4349			break;
4350
4351		  case '.':		/* terminate file */
4352			nomore = true;
4353			break;
4354
4355		  default:
4356			syserr("readqf: %s: line %d: bad line \"%s\"",
4357				qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
4358			err = "unrecognized line";
4359			goto fail;
4360		}
4361
4362		if (bp != buf)
4363			sm_free(bp); /* XXX */
4364	}
4365
4366	/*
4367	**  If we haven't read any lines, this queue file is empty.
4368	**  Arrange to remove it without referencing any null pointers.
4369	*/
4370
4371	if (LineNumber == 0)
4372	{
4373		errno = 0;
4374		e->e_flags |= EF_CLRQUEUE|EF_FATALERRS|EF_RESPONSE;
4375		RELEASE_QUEUE;
4376		return true;
4377	}
4378
4379	/* Check to make sure we have a complete queue file read */
4380	if (!nomore)
4381	{
4382		syserr("readqf: %s: incomplete queue file read", qf);
4383		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
4384		RELEASE_QUEUE;
4385		return false;
4386	}
4387
4388	/* possibly set ${dsn_ret} macro */
4389	if (bitset(EF_RET_PARAM, e->e_flags))
4390	{
4391		if (bitset(EF_NO_BODY_RETN, e->e_flags))
4392			macdefine(&e->e_macro, A_PERM,
4393				macid("{dsn_ret}"), "hdrs");
4394		else
4395			macdefine(&e->e_macro, A_PERM,
4396				macid("{dsn_ret}"), "full");
4397	}
4398
4399	/*
4400	**  Arrange to read the data file.
4401	*/
4402
4403	p = queuename(e, DATAFL_LETTER);
4404	e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, p, SM_IO_RDONLY,
4405			      NULL);
4406	if (e->e_dfp == NULL)
4407	{
4408		syserr("readqf: cannot open %s", p);
4409	}
4410	else
4411	{
4412		e->e_flags |= EF_HAS_DF;
4413		if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &st)
4414		    >= 0)
4415		{
4416			e->e_msgsize = st.st_size + hdrsize;
4417			e->e_dfdev = st.st_dev;
4418			e->e_dfino = ST_INODE(st);
4419			(void) sm_snprintf(buf, sizeof buf, "%ld",
4420					   e->e_msgsize);
4421			macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"),
4422				  buf);
4423		}
4424	}
4425
4426	RELEASE_QUEUE;
4427	return true;
4428
4429  fail:
4430	/*
4431	**  There was some error reading the qf file (reason is in err var.)
4432	**  Cleanup:
4433	**	close file; clear e_lockfp since it is the same as qfp,
4434	**	hence it is invalid (as file) after qfp is closed;
4435	**	the qf file is on disk, so set the flag to avoid calling
4436	**	queueup() with bogus data.
4437	*/
4438
4439	if (qfp != NULL)
4440		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
4441	e->e_lockfp = NULL;
4442	e->e_flags |= EF_INQUEUE;
4443	loseqfile(e, err);
4444	RELEASE_QUEUE;
4445	return false;
4446}
4447/*
4448**  PRTSTR -- print a string, "unprintable" characters are shown as \oct
4449**
4450**	Parameters:
4451**		s -- string to print
4452**		ml -- maximum length of output
4453**
4454**	Returns:
4455**		number of entries
4456**
4457**	Side Effects:
4458**		Prints a string on stdout.
4459*/
4460
4461static void
4462prtstr(s, ml)
4463	char *s;
4464	int ml;
4465{
4466	int c;
4467
4468	if (s == NULL)
4469		return;
4470	while (ml-- > 0 && ((c = *s++) != '\0'))
4471	{
4472		if (c == '\\')
4473		{
4474			if (ml-- > 0)
4475			{
4476				(void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
4477				(void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
4478			}
4479		}
4480		else if (isascii(c) && isprint(c))
4481			(void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
4482		else
4483		{
4484			if ((ml -= 3) > 0)
4485				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4486						     "\\%03o", c & 0xFF);
4487		}
4488	}
4489}
4490/*
4491**  PRINTNQE -- print out number of entries in the mail queue
4492**
4493**	Parameters:
4494**		out -- output file pointer.
4495**		prefix -- string to output in front of each line.
4496**
4497**	Returns:
4498**		none.
4499*/
4500
4501void
4502printnqe(out, prefix)
4503	SM_FILE_T *out;
4504	char *prefix;
4505{
4506#if SM_CONF_SHM
4507	int i, k = 0, nrequests = 0;
4508	bool unknown = false;
4509
4510	if (ShmId == SM_SHM_NO_ID)
4511	{
4512		if (prefix == NULL)
4513			(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4514					"Data unavailable: shared memory not updated\n");
4515		else
4516			(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4517					"%sNOTCONFIGURED:-1\r\n", prefix);
4518		return;
4519	}
4520	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
4521	{
4522		int j;
4523
4524		k++;
4525		for (j = 0; j < Queue[i]->qg_numqueues; j++)
4526		{
4527			int n;
4528
4529			if (StopRequest)
4530				stop_sendmail();
4531
4532			n = QSHM_ENTRIES(Queue[i]->qg_qpaths[j].qp_idx);
4533			if (prefix != NULL)
4534				(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4535					"%s%s:%d\r\n",
4536					prefix, qid_printqueue(i, j), n);
4537			else if (n < 0)
4538			{
4539				(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4540					"%s: unknown number of entries\n",
4541					qid_printqueue(i, j));
4542				unknown = true;
4543			}
4544			else if (n == 0)
4545			{
4546				(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4547					"%s is empty\n",
4548					qid_printqueue(i, j));
4549			}
4550			else if (n > 0)
4551			{
4552				(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4553					"%s: entries=%d\n",
4554					qid_printqueue(i, j), n);
4555				nrequests += n;
4556				k++;
4557			}
4558		}
4559	}
4560	if (prefix == NULL && k > 1)
4561		(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4562				     "\t\tTotal requests: %d%s\n",
4563				     nrequests, unknown ? " (about)" : "");
4564#else /* SM_CONF_SHM */
4565	if (prefix == NULL)
4566		(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4567			     "Data unavailable without shared memory support\n");
4568	else
4569		(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4570			     "%sNOTAVAILABLE:-1\r\n", prefix);
4571#endif /* SM_CONF_SHM */
4572}
4573/*
4574**  PRINTQUEUE -- print out a representation of the mail queue
4575**
4576**	Parameters:
4577**		none.
4578**
4579**	Returns:
4580**		none.
4581**
4582**	Side Effects:
4583**		Prints a listing of the mail queue on the standard output.
4584*/
4585
4586void
4587printqueue()
4588{
4589	int i, k = 0, nrequests = 0;
4590
4591	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
4592	{
4593		int j;
4594
4595		k++;
4596		for (j = 0; j < Queue[i]->qg_numqueues; j++)
4597		{
4598			if (StopRequest)
4599				stop_sendmail();
4600			nrequests += print_single_queue(i, j);
4601			k++;
4602		}
4603	}
4604	if (k > 1)
4605		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4606				     "\t\tTotal requests: %d\n",
4607				     nrequests);
4608}
4609/*
4610**  PRINT_SINGLE_QUEUE -- print out a representation of a single mail queue
4611**
4612**	Parameters:
4613**		qgrp -- the index of the queue group.
4614**		qdir -- the queue directory.
4615**
4616**	Returns:
4617**		number of requests in mail queue.
4618**
4619**	Side Effects:
4620**		Prints a listing of the mail queue on the standard output.
4621*/
4622
4623int
4624print_single_queue(qgrp, qdir)
4625	int qgrp;
4626	int qdir;
4627{
4628	register WORK *w;
4629	SM_FILE_T *f;
4630	int nrequests;
4631	char qd[MAXPATHLEN];
4632	char qddf[MAXPATHLEN];
4633	char buf[MAXLINE];
4634
4635	if (qdir == NOQDIR)
4636	{
4637		(void) sm_strlcpy(qd, ".", sizeof qd);
4638		(void) sm_strlcpy(qddf, ".", sizeof qddf);
4639	}
4640	else
4641	{
4642		(void) sm_strlcpyn(qd, sizeof qd, 2,
4643			Queue[qgrp]->qg_qpaths[qdir].qp_name,
4644			(bitset(QP_SUBQF,
4645				Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
4646					? "/qf" : ""));
4647		(void) sm_strlcpyn(qddf, sizeof qddf, 2,
4648			Queue[qgrp]->qg_qpaths[qdir].qp_name,
4649			(bitset(QP_SUBDF,
4650				Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
4651					? "/df" : ""));
4652	}
4653
4654	/*
4655	**  Check for permission to print the queue
4656	*/
4657
4658	if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
4659	{
4660		struct stat st;
4661#ifdef NGROUPS_MAX
4662		int n;
4663		extern GIDSET_T InitialGidSet[NGROUPS_MAX];
4664#endif /* NGROUPS_MAX */
4665
4666		if (stat(qd, &st) < 0)
4667		{
4668			syserr("Cannot stat %s",
4669				qid_printqueue(qgrp, qdir));
4670			return 0;
4671		}
4672#ifdef NGROUPS_MAX
4673		n = NGROUPS_MAX;
4674		while (--n >= 0)
4675		{
4676			if (InitialGidSet[n] == st.st_gid)
4677				break;
4678		}
4679		if (n < 0 && RealGid != st.st_gid)
4680#else /* NGROUPS_MAX */
4681		if (RealGid != st.st_gid)
4682#endif /* NGROUPS_MAX */
4683		{
4684			usrerr("510 You are not permitted to see the queue");
4685			setstat(EX_NOPERM);
4686			return 0;
4687		}
4688	}
4689
4690	/*
4691	**  Read and order the queue.
4692	*/
4693
4694	nrequests = gatherq(qgrp, qdir, true, NULL, NULL);
4695	(void) sortq(Queue[qgrp]->qg_maxlist);
4696
4697	/*
4698	**  Print the work list that we have read.
4699	*/
4700
4701	/* first see if there is anything */
4702	if (nrequests <= 0)
4703	{
4704		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s is empty\n",
4705				     qid_printqueue(qgrp, qdir));
4706		return 0;
4707	}
4708
4709	sm_getla();	/* get load average */
4710
4711	(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\t\t%s (%d request%s",
4712			     qid_printqueue(qgrp, qdir),
4713			     nrequests, nrequests == 1 ? "" : "s");
4714	if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
4715		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4716				     ", only %d printed", MaxQueueRun);
4717	if (Verbose)
4718		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4719			")\n-----Q-ID----- --Size-- -Priority- ---Q-Time--- --------Sender/Recipient--------\n");
4720	else
4721		(void) sm_io_fprintf(smioout,  SM_TIME_DEFAULT,
4722			")\n-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------\n");
4723	for (w = WorkQ; w != NULL; w = w->w_next)
4724	{
4725		struct stat st;
4726		auto time_t submittime = 0;
4727		long dfsize;
4728		int flags = 0;
4729		int qfver;
4730#if _FFR_QUARANTINE
4731		char quarmsg[MAXLINE];
4732#endif /* _FFR_QUARANTINE */
4733		char statmsg[MAXLINE];
4734		char bodytype[MAXNAME + 1];
4735		char qf[MAXPATHLEN];
4736
4737		if (StopRequest)
4738			stop_sendmail();
4739
4740		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%13s",
4741				     w->w_name + 2);
4742		(void) sm_strlcpyn(qf, sizeof qf, 3, qd, "/", w->w_name);
4743		f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY,
4744			       NULL);
4745		if (f == NULL)
4746		{
4747			if (errno == EPERM)
4748				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4749						     " (permission denied)\n");
4750			else if (errno == ENOENT)
4751				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4752						     " (job completed)\n");
4753			else
4754				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4755						     " (%s)\n",
4756						     sm_errstring(errno));
4757			errno = 0;
4758			continue;
4759		}
4760		w->w_name[0] = DATAFL_LETTER;
4761		(void) sm_strlcpyn(qf, sizeof qf, 3, qddf, "/", w->w_name);
4762		if (stat(qf, &st) >= 0)
4763			dfsize = st.st_size;
4764		else
4765		{
4766			ENVELOPE e;
4767
4768			/*
4769			**  Maybe the df file can't be statted because
4770			**  it is in a different directory than the qf file.
4771			**  In order to find out, we must read the qf file.
4772			*/
4773
4774			newenvelope(&e, &BlankEnvelope, sm_rpool_new_x(NULL));
4775			e.e_id = w->w_name + 2;
4776			e.e_qgrp = qgrp;
4777			e.e_qdir = qdir;
4778			dfsize = -1;
4779			if (readqf(&e, false))
4780			{
4781				char *df = queuename(&e, DATAFL_LETTER);
4782				if (stat(df, &st) >= 0)
4783					dfsize = st.st_size;
4784			}
4785			if (e.e_lockfp != NULL)
4786			{
4787				(void) sm_io_close(e.e_lockfp, SM_TIME_DEFAULT);
4788				e.e_lockfp = NULL;
4789			}
4790			clearenvelope(&e, false, e.e_rpool);
4791			sm_rpool_free(e.e_rpool);
4792		}
4793		if (w->w_lock)
4794			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "*");
4795#if _FFR_QUARANTINE
4796		else if (QueueMode == QM_LOST)
4797			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "?");
4798#endif /* _FFR_QUARANTINE */
4799		else if (w->w_tooyoung)
4800			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "-");
4801		else if (shouldqueue(w->w_pri, w->w_ctime))
4802			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "X");
4803		else
4804			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " ");
4805
4806		errno = 0;
4807
4808#if _FFR_QUARANTINE
4809		quarmsg[0] = '\0';
4810#endif /* _FFR_QUARANTINE */
4811		statmsg[0] = bodytype[0] = '\0';
4812		qfver = 0;
4813		while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
4814		{
4815			register int i;
4816			register char *p;
4817
4818			if (StopRequest)
4819				stop_sendmail();
4820
4821			fixcrlf(buf, true);
4822			switch (buf[0])
4823			{
4824			  case 'V':	/* queue file version */
4825				qfver = atoi(&buf[1]);
4826				break;
4827
4828			  case 'M':	/* error message */
4829				if ((i = strlen(&buf[1])) >= sizeof statmsg)
4830					i = sizeof statmsg - 1;
4831				memmove(statmsg, &buf[1], i);
4832				statmsg[i] = '\0';
4833				break;
4834
4835#if _FFR_QUARANTINE
4836			  case 'q':	/* quarantine reason */
4837				if ((i = strlen(&buf[1])) >= sizeof quarmsg)
4838					i = sizeof quarmsg - 1;
4839				memmove(quarmsg, &buf[1], i);
4840				quarmsg[i] = '\0';
4841				break;
4842#endif /* _FFR_QUARANTINE */
4843
4844			  case 'B':	/* body type */
4845				if ((i = strlen(&buf[1])) >= sizeof bodytype)
4846					i = sizeof bodytype - 1;
4847				memmove(bodytype, &buf[1], i);
4848				bodytype[i] = '\0';
4849				break;
4850
4851			  case 'S':	/* sender name */
4852				if (Verbose)
4853				{
4854					(void) sm_io_fprintf(smioout,
4855						SM_TIME_DEFAULT,
4856						"%8ld %10ld%c%.12s ",
4857						dfsize,
4858						w->w_pri,
4859						bitset(EF_WARNING, flags)
4860							? '+' : ' ',
4861						ctime(&submittime) + 4);
4862					prtstr(&buf[1], 78);
4863				}
4864				else
4865				{
4866					(void) sm_io_fprintf(smioout,
4867						SM_TIME_DEFAULT,
4868						"%8ld %.16s ",
4869						dfsize,
4870						ctime(&submittime));
4871					prtstr(&buf[1], 39);
4872				}
4873#if _FFR_QUARANTINE
4874				if (quarmsg[0] != '\0')
4875				{
4876					(void) sm_io_fprintf(smioout,
4877							     SM_TIME_DEFAULT,
4878							     "\n     QUARANTINE: %.*s",
4879							     Verbose ? 100 : 60,
4880							     quarmsg);
4881					quarmsg[0] = '\0';
4882				}
4883#endif /* _FFR_QUARANTINE */
4884				if (statmsg[0] != '\0' || bodytype[0] != '\0')
4885				{
4886					(void) sm_io_fprintf(smioout,
4887						SM_TIME_DEFAULT,
4888						"\n    %10.10s",
4889						bodytype);
4890					if (statmsg[0] != '\0')
4891						(void) sm_io_fprintf(smioout,
4892							SM_TIME_DEFAULT,
4893							"   (%.*s)",
4894							Verbose ? 100 : 60,
4895							statmsg);
4896					statmsg[0] = '\0';
4897				}
4898				break;
4899
4900			  case 'C':	/* controlling user */
4901				if (Verbose)
4902					(void) sm_io_fprintf(smioout,
4903						SM_TIME_DEFAULT,
4904						"\n\t\t\t\t\t\t(---%.64s---)",
4905						&buf[1]);
4906				break;
4907
4908			  case 'R':	/* recipient name */
4909				p = &buf[1];
4910				if (qfver >= 1)
4911				{
4912					p = strchr(p, ':');
4913					if (p == NULL)
4914						break;
4915					p++;
4916				}
4917				if (Verbose)
4918				{
4919					(void) sm_io_fprintf(smioout,
4920							SM_TIME_DEFAULT,
4921							"\n\t\t\t\t\t\t");
4922					prtstr(p, 71);
4923				}
4924				else
4925				{
4926					(void) sm_io_fprintf(smioout,
4927							SM_TIME_DEFAULT,
4928							"\n\t\t\t\t\t ");
4929					prtstr(p, 38);
4930				}
4931				if (Verbose && statmsg[0] != '\0')
4932				{
4933					(void) sm_io_fprintf(smioout,
4934							SM_TIME_DEFAULT,
4935							"\n\t\t (%.100s)",
4936							statmsg);
4937					statmsg[0] = '\0';
4938				}
4939				break;
4940
4941			  case 'T':	/* creation time */
4942				submittime = atol(&buf[1]);
4943				break;
4944
4945			  case 'F':	/* flag bits */
4946				for (p = &buf[1]; *p != '\0'; p++)
4947				{
4948					switch (*p)
4949					{
4950					  case 'w':
4951						flags |= EF_WARNING;
4952						break;
4953					}
4954				}
4955			}
4956		}
4957		if (submittime == (time_t) 0)
4958			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4959					     " (no control file)");
4960		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n");
4961		(void) sm_io_close(f, SM_TIME_DEFAULT);
4962	}
4963	return nrequests;
4964}
4965
4966#if _FFR_QUARANTINE
4967/*
4968**  QUEUE_LETTER -- get the proper queue letter for the current QueueMode.
4969**
4970**	Parameters:
4971**		e -- envelope to build it in/from.
4972**		type -- the file type, used as the first character
4973**			of the file name.
4974**
4975**	Returns:
4976**		the letter to use
4977*/
4978
4979static char
4980queue_letter(e, type)
4981	ENVELOPE *e;
4982	int type;
4983{
4984	/* Change type according to QueueMode */
4985	if (type == ANYQFL_LETTER)
4986	{
4987		if (e->e_quarmsg != NULL)
4988			type = QUARQF_LETTER;
4989		else
4990		{
4991			switch (QueueMode)
4992			{
4993			  case QM_NORMAL:
4994				type = NORMQF_LETTER;
4995				break;
4996
4997			  case QM_QUARANTINE:
4998				type = QUARQF_LETTER;
4999				break;
5000
5001			  case QM_LOST:
5002				type = LOSEQF_LETTER;
5003				break;
5004
5005			  default:
5006				/* should never happen */
5007				abort();
5008				/* NOTREACHED */
5009			}
5010		}
5011	}
5012	return type;
5013}
5014#endif /* _FFR_QUARANTINE */
5015
5016/*
5017**  QUEUENAME -- build a file name in the queue directory for this envelope.
5018**
5019**	Parameters:
5020**		e -- envelope to build it in/from.
5021**		type -- the file type, used as the first character
5022**			of the file name.
5023**
5024**	Returns:
5025**		a pointer to the queue name (in a static buffer).
5026**
5027**	Side Effects:
5028**		If no id code is already assigned, queuename() will
5029**		assign an id code with assign_queueid().  If no queue
5030**		directory is assigned, one will be set with setnewqueue().
5031*/
5032
5033char *
5034queuename(e, type)
5035	register ENVELOPE *e;
5036	int type;
5037{
5038	int qd, qg;
5039	char *sub = "/";
5040	char pref[3];
5041	static char buf[MAXPATHLEN];
5042
5043	/* Assign an ID if needed */
5044	if (e->e_id == NULL)
5045		assign_queueid(e);
5046
5047#if _FFR_QUARANTINE
5048	type = queue_letter(e, type);
5049#endif /* _FFR_QUARANTINE */
5050
5051	/* begin of filename */
5052	pref[0] = (char) type;
5053	pref[1] = 'f';
5054	pref[2] = '\0';
5055
5056	/* Assign a queue group/directory if needed */
5057	if (type == XSCRPT_LETTER)
5058	{
5059		/*
5060		**  We don't want to call setnewqueue() if we are fetching
5061		**  the pathname of the transcript file, because setnewqueue
5062		**  chooses a queue, and sometimes we need to write to the
5063		**  transcript file before we have gathered enough information
5064		**  to choose a queue.
5065		*/
5066
5067		if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR)
5068		{
5069			if (e->e_qgrp != NOQGRP && e->e_qdir != NOQDIR)
5070			{
5071				e->e_xfqgrp = e->e_qgrp;
5072				e->e_xfqdir = e->e_qdir;
5073			}
5074			else
5075			{
5076				e->e_xfqgrp = 0;
5077				if (Queue[e->e_xfqgrp]->qg_numqueues <= 1)
5078					e->e_xfqdir = 0;
5079				else
5080				{
5081					e->e_xfqdir = get_rand_mod(
5082					      Queue[e->e_xfqgrp]->qg_numqueues);
5083				}
5084			}
5085		}
5086		qd = e->e_xfqdir;
5087		qg = e->e_xfqgrp;
5088	}
5089	else
5090	{
5091		if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR)
5092			setnewqueue(e);
5093		if (type ==  DATAFL_LETTER)
5094		{
5095			qd = e->e_dfqdir;
5096			qg = e->e_dfqgrp;
5097		}
5098		else
5099		{
5100			qd = e->e_qdir;
5101			qg = e->e_qgrp;
5102		}
5103	}
5104
5105	/* xf files always have a valid qd and qg picked above */
5106	if (e->e_qdir == NOQDIR && type != XSCRPT_LETTER)
5107		(void) sm_strlcpyn(buf, sizeof buf, 2, pref, e->e_id);
5108	else
5109	{
5110		switch (type)
5111		{
5112		  case DATAFL_LETTER:
5113			if (bitset(QP_SUBDF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
5114				sub = "/df/";
5115			break;
5116
5117#if _FFR_QUARANTINE
5118		  case QUARQF_LETTER:
5119#endif /* _FFR_QUARANTINE */
5120		  case TEMPQF_LETTER:
5121		  case NEWQFL_LETTER:
5122		  case LOSEQF_LETTER:
5123		  case NORMQF_LETTER:
5124			if (bitset(QP_SUBQF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
5125				sub = "/qf/";
5126			break;
5127
5128		  case XSCRPT_LETTER:
5129			if (bitset(QP_SUBXF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
5130				sub = "/xf/";
5131			break;
5132
5133		  default:
5134			sm_abort("queuename: bad queue file type %d", type);
5135		}
5136
5137		(void) sm_strlcpyn(buf, sizeof buf, 4,
5138				Queue[qg]->qg_qpaths[qd].qp_name,
5139				sub, pref, e->e_id);
5140	}
5141
5142	if (tTd(7, 2))
5143		sm_dprintf("queuename: %s\n", buf);
5144	return buf;
5145}
5146/*
5147**  ASSIGN_QUEUEID -- assign a queue ID for this envelope.
5148**
5149**	Assigns an id code if one does not already exist.
5150**	This code assumes that nothing will remain in the queue for
5151**	longer than 60 years.  It is critical that files with the given
5152**	name do not already exist in the queue.
5153**	[No longer initializes e_qdir to NOQDIR.]
5154**
5155**	Parameters:
5156**		e -- envelope to set it in.
5157**
5158**	Returns:
5159**		none.
5160*/
5161
5162static const char QueueIdChars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx";
5163# define QIC_LEN	60
5164# define queuenextid() CurrentPid
5165
5166
5167void
5168assign_queueid(e)
5169	register ENVELOPE *e;
5170{
5171	pid_t pid = queuenextid();
5172	static int cX = 0;
5173	static long random_offset;
5174	struct tm *tm;
5175	char idbuf[MAXQFNAME - 2];
5176	int seq;
5177
5178	if (e->e_id != NULL)
5179		return;
5180
5181	/* see if we need to get a new base time/pid */
5182	if (cX >= QIC_LEN * QIC_LEN || LastQueueTime == 0 ||
5183	    LastQueuePid != pid)
5184	{
5185		time_t then = LastQueueTime;
5186
5187		/* if the first time through, pick a random offset */
5188		if (LastQueueTime == 0)
5189			random_offset = get_random();
5190
5191		while ((LastQueueTime = curtime()) == then &&
5192		       LastQueuePid == pid)
5193		{
5194			(void) sleep(1);
5195		}
5196		LastQueuePid = queuenextid();
5197		cX = 0;
5198	}
5199
5200	/*
5201	**  Generate a new sequence number between 0 and QIC_LEN*QIC_LEN-1.
5202	**  This lets us generate up to QIC_LEN*QIC_LEN unique queue ids
5203	**  per second, per process.  With envelope splitting,
5204	**  a single message can consume many queue ids.
5205	*/
5206
5207	seq = (int)((cX + random_offset) % (QIC_LEN * QIC_LEN));
5208	++cX;
5209	if (tTd(7, 50))
5210		sm_dprintf("assign_queueid: random_offset = %ld (%d)\n",
5211			random_offset, seq);
5212
5213	tm = gmtime(&LastQueueTime);
5214	idbuf[0] = QueueIdChars[tm->tm_year % QIC_LEN];
5215	idbuf[1] = QueueIdChars[tm->tm_mon];
5216	idbuf[2] = QueueIdChars[tm->tm_mday];
5217	idbuf[3] = QueueIdChars[tm->tm_hour];
5218	idbuf[4] = QueueIdChars[tm->tm_min];
5219	idbuf[5] = QueueIdChars[tm->tm_sec];
5220	idbuf[6] = QueueIdChars[seq / QIC_LEN];
5221	idbuf[7] = QueueIdChars[seq % QIC_LEN];
5222	(void) sm_snprintf(&idbuf[8], sizeof idbuf - 8, "%06d",
5223			   (int) LastQueuePid);
5224	e->e_id = sm_rpool_strdup_x(e->e_rpool, idbuf);
5225	macdefine(&e->e_macro, A_PERM, 'i', e->e_id);
5226#if 0
5227	/* XXX: inherited from MainEnvelope */
5228	e->e_qgrp = NOQGRP;  /* too early to do anything else */
5229	e->e_qdir = NOQDIR;
5230	e->e_xfqgrp = NOQGRP;
5231#endif /* 0 */
5232#if _FFR_QUARANTINE
5233	/* New ID means it's not on disk yet */
5234	e->e_qfletter = '\0';
5235#endif /* _FFR_QUARANTINE */
5236	if (tTd(7, 1))
5237		sm_dprintf("assign_queueid: assigned id %s, e=%p\n",
5238			e->e_id, e);
5239	if (LogLevel > 93)
5240		sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
5241}
5242/*
5243**  SYNC_QUEUE_TIME -- Assure exclusive PID in any given second
5244**
5245**	Make sure one PID can't be used by two processes in any one second.
5246**
5247**		If the system rotates PIDs fast enough, may get the
5248**		same pid in the same second for two distinct processes.
5249**		This will interfere with the queue file naming system.
5250**
5251**	Parameters:
5252**		none
5253**
5254**	Returns:
5255**		none
5256*/
5257
5258void
5259sync_queue_time()
5260{
5261#if FAST_PID_RECYCLE
5262	if (OpMode != MD_TEST &&
5263	    OpMode != MD_VERIFY &&
5264	    LastQueueTime > 0 &&
5265	    LastQueuePid == CurrentPid &&
5266	    curtime() == LastQueueTime)
5267		(void) sleep(1);
5268#endif /* FAST_PID_RECYCLE */
5269}
5270/*
5271**  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
5272**
5273**	Parameters:
5274**		e -- the envelope to unlock.
5275**
5276**	Returns:
5277**		none
5278**
5279**	Side Effects:
5280**		unlocks the queue for `e'.
5281*/
5282
5283void
5284unlockqueue(e)
5285	ENVELOPE *e;
5286{
5287	if (tTd(51, 4))
5288		sm_dprintf("unlockqueue(%s)\n",
5289			e->e_id == NULL ? "NOQUEUE" : e->e_id);
5290
5291
5292	/* if there is a lock file in the envelope, close it */
5293	if (e->e_lockfp != NULL)
5294		(void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT);
5295	e->e_lockfp = NULL;
5296
5297	/* don't create a queue id if we don't already have one */
5298	if (e->e_id == NULL)
5299		return;
5300
5301	/* remove the transcript */
5302	if (LogLevel > 87)
5303		sm_syslog(LOG_DEBUG, e->e_id, "unlock");
5304	if (!tTd(51, 104))
5305		(void) xunlink(queuename(e, XSCRPT_LETTER));
5306}
5307/*
5308**  SETCTLUSER -- create a controlling address
5309**
5310**	Create a fake "address" given only a local login name; this is
5311**	used as a "controlling user" for future recipient addresses.
5312**
5313**	Parameters:
5314**		user -- the user name of the controlling user.
5315**		qfver -- the version stamp of this queue file.
5316**		e -- envelope
5317**
5318**	Returns:
5319**		An address descriptor for the controlling user,
5320**		using storage allocated from e->e_rpool.
5321**
5322*/
5323
5324static ADDRESS *
5325setctluser(user, qfver, e)
5326	char *user;
5327	int qfver;
5328	ENVELOPE *e;
5329{
5330	register ADDRESS *a;
5331	struct passwd *pw;
5332	char *p;
5333
5334	/*
5335	**  See if this clears our concept of controlling user.
5336	*/
5337
5338	if (user == NULL || *user == '\0')
5339		return NULL;
5340
5341	/*
5342	**  Set up addr fields for controlling user.
5343	*/
5344
5345	a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof *a);
5346	memset((char *) a, '\0', sizeof *a);
5347
5348	if (*user == ':')
5349	{
5350		p = &user[1];
5351		a->q_user = sm_rpool_strdup_x(e->e_rpool, p);
5352	}
5353	else
5354	{
5355		p = strtok(user, ":");
5356		a->q_user = sm_rpool_strdup_x(e->e_rpool, user);
5357		if (qfver >= 2)
5358		{
5359			if ((p = strtok(NULL, ":")) != NULL)
5360				a->q_uid = atoi(p);
5361			if ((p = strtok(NULL, ":")) != NULL)
5362				a->q_gid = atoi(p);
5363			if ((p = strtok(NULL, ":")) != NULL)
5364			{
5365				char *o;
5366
5367				a->q_flags |= QGOODUID;
5368
5369				/* if there is another ':': restore it */
5370				if ((o = strtok(NULL, ":")) != NULL && o > p)
5371					o[-1] = ':';
5372			}
5373		}
5374		else if ((pw = sm_getpwnam(user)) != NULL)
5375		{
5376			if (*pw->pw_dir == '\0')
5377				a->q_home = NULL;
5378			else if (strcmp(pw->pw_dir, "/") == 0)
5379				a->q_home = "";
5380			else
5381				a->q_home = sm_rpool_strdup_x(e->e_rpool, pw->pw_dir);
5382			a->q_uid = pw->pw_uid;
5383			a->q_gid = pw->pw_gid;
5384			a->q_flags |= QGOODUID;
5385		}
5386	}
5387
5388	a->q_flags |= QPRIMARY;		/* flag as a "ctladdr" */
5389	a->q_mailer = LocalMailer;
5390	if (p == NULL)
5391		a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user);
5392	else
5393		a->q_paddr = sm_rpool_strdup_x(e->e_rpool, p);
5394	return a;
5395}
5396/*
5397**  LOSEQFILE -- rename queue file with LOSEQF_LETTER & try to let someone know
5398**
5399**	Parameters:
5400**		e -- the envelope (e->e_id will be used).
5401**		why -- reported to whomever can hear.
5402**
5403**	Returns:
5404**		none.
5405*/
5406
5407void
5408loseqfile(e, why)
5409	register ENVELOPE *e;
5410	char *why;
5411{
5412	bool loseit = true;
5413	char *p;
5414	char buf[MAXPATHLEN];
5415
5416	if (e == NULL || e->e_id == NULL)
5417		return;
5418	p = queuename(e, ANYQFL_LETTER);
5419	if (sm_strlcpy(buf, p, sizeof buf) >= sizeof buf)
5420		return;
5421	if (!bitset(EF_INQUEUE, e->e_flags))
5422		queueup(e, false, true);
5423#if _FFR_QUARANTINE
5424	else if (QueueMode == QM_LOST)
5425		loseit = false;
5426#endif /* _FFR_QUARANTINE */
5427
5428	/* if already lost, no need to re-lose */
5429	if (loseit)
5430	{
5431		p = queuename(e, LOSEQF_LETTER);
5432		if (rename(buf, p) < 0)
5433			syserr("cannot rename(%s, %s), uid=%d",
5434			       buf, p, (int) geteuid());
5435		else if (LogLevel > 0)
5436			sm_syslog(LOG_ALERT, e->e_id,
5437				  "Losing %s: %s", buf, why);
5438	}
5439	if (e->e_dfp != NULL)
5440	{
5441		(void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
5442		e->e_dfp = NULL;
5443	}
5444	e->e_flags &= ~EF_HAS_DF;
5445}
5446/*
5447**  NAME2QID -- translate a queue group name to a queue group id
5448**
5449**	Parameters:
5450**		queuename -- name of queue group.
5451**
5452**	Returns:
5453**		queue group id if found.
5454**		NOQGRP otherwise.
5455*/
5456
5457int
5458name2qid(queuename)
5459	char *queuename;
5460{
5461	register STAB *s;
5462
5463	s = stab(queuename, ST_QUEUE, ST_FIND);
5464	if (s == NULL)
5465		return NOQGRP;
5466	return s->s_quegrp->qg_index;
5467}
5468/*
5469**  QID_PRINTNAME -- create externally printable version of queue id
5470**
5471**	Parameters:
5472**		e -- the envelope.
5473**
5474**	Returns:
5475**		a printable version
5476*/
5477
5478char *
5479qid_printname(e)
5480	ENVELOPE *e;
5481{
5482	char *id;
5483	static char idbuf[MAXQFNAME + 34];
5484
5485	if (e == NULL)
5486		return "";
5487
5488	if (e->e_id == NULL)
5489		id = "";
5490	else
5491		id = e->e_id;
5492
5493	if (e->e_qdir == NOQDIR)
5494		return id;
5495
5496	(void) sm_snprintf(idbuf, sizeof idbuf, "%.32s/%s",
5497			   Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_name,
5498			   id);
5499	return idbuf;
5500}
5501/*
5502**  QID_PRINTQUEUE -- create full version of queue directory for data files
5503**
5504**	Parameters:
5505**		qgrp -- index in queue group.
5506**		qdir -- the short version of the queue directory
5507**
5508**	Returns:
5509**		the full pathname to the queue (might point to a static var)
5510*/
5511
5512char *
5513qid_printqueue(qgrp, qdir)
5514	int qgrp;
5515	int qdir;
5516{
5517	char *subdir;
5518	static char dir[MAXPATHLEN];
5519
5520	if (qdir == NOQDIR)
5521		return Queue[qgrp]->qg_qdir;
5522
5523	if (strcmp(Queue[qgrp]->qg_qpaths[qdir].qp_name, ".") == 0)
5524		subdir = NULL;
5525	else
5526		subdir = Queue[qgrp]->qg_qpaths[qdir].qp_name;
5527
5528	(void) sm_strlcpyn(dir, sizeof dir, 4,
5529			Queue[qgrp]->qg_qdir,
5530			subdir == NULL ? "" : "/",
5531			subdir == NULL ? "" : subdir,
5532			(bitset(QP_SUBDF,
5533				Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
5534					? "/df" : ""));
5535	return dir;
5536}
5537
5538/*
5539**  PICKQDIR -- Pick a queue directory from a queue group
5540**
5541**	Parameters:
5542**		qg -- queue group
5543**		fsize -- file size in bytes
5544**		e -- envelope, or NULL
5545**
5546**	Result:
5547**		NOQDIR if no queue directory in qg has enough free space to
5548**		hold a file of size 'fsize', otherwise the index of
5549**		a randomly selected queue directory which resides on a
5550**		file system with enough disk space.
5551**		XXX This could be extended to select a queuedir with
5552**			a few (the fewest?) number of entries. That data
5553**			is available if shared memory is used.
5554**
5555**	Side Effects:
5556**		If the request fails and e != NULL then sm_syslog is called.
5557*/
5558
5559int
5560pickqdir(qg, fsize, e)
5561	QUEUEGRP *qg;
5562	long fsize;
5563	ENVELOPE *e;
5564{
5565	int qdir;
5566	int i;
5567	long avail = 0;
5568
5569	/* Pick a random directory, as a starting point. */
5570	if (qg->qg_numqueues <= 1)
5571		qdir = 0;
5572	else
5573		qdir = get_rand_mod(qg->qg_numqueues);
5574
5575	if (MinBlocksFree <= 0 && fsize <= 0)
5576		return qdir;
5577
5578	/*
5579	**  Now iterate over the queue directories,
5580	**  looking for a directory with enough space for this message.
5581	*/
5582
5583	i = qdir;
5584	do
5585	{
5586		QPATHS *qp = &qg->qg_qpaths[i];
5587		long needed = 0;
5588		long fsavail = 0;
5589
5590		if (fsize > 0)
5591			needed += fsize / FILE_SYS_BLKSIZE(qp->qp_fsysidx)
5592				  + ((fsize % FILE_SYS_BLKSIZE(qp->qp_fsysidx)
5593				      > 0) ? 1 : 0);
5594		if (MinBlocksFree > 0)
5595			needed += MinBlocksFree;
5596		fsavail = FILE_SYS_AVAIL(qp->qp_fsysidx);
5597#if SM_CONF_SHM
5598		if (fsavail <= 0)
5599		{
5600			long blksize;
5601
5602			/*
5603			**  might be not correctly updated,
5604			**  let's try to get the info directly.
5605			*/
5606
5607			fsavail = freediskspace(FILE_SYS_NAME(qp->qp_fsysidx),
5608						&blksize);
5609			if (fsavail < 0)
5610				fsavail = 0;
5611		}
5612#endif /* SM_CONF_SHM */
5613		if (needed <= fsavail)
5614			return i;
5615		if (avail < fsavail)
5616			avail = fsavail;
5617
5618		if (qg->qg_numqueues > 0)
5619			i = (i + 1) % qg->qg_numqueues;
5620	} while (i != qdir);
5621
5622	if (e != NULL && LogLevel > 0)
5623		sm_syslog(LOG_ALERT, e->e_id,
5624			"low on space (%s needs %ld bytes + %ld blocks in %s), max avail: %ld",
5625			CurHostName == NULL ? "SMTP-DAEMON" : CurHostName,
5626			fsize, MinBlocksFree,
5627			qg->qg_qdir, avail);
5628	return NOQDIR;
5629}
5630/*
5631**  SETNEWQUEUE -- Sets a new queue group and directory
5632**
5633**	Assign a queue group and directory to an envelope and store the
5634**	directory in e->e_qdir.
5635**
5636**	Parameters:
5637**		e -- envelope to assign a queue for.
5638**
5639**	Returns:
5640**		true if successful
5641**		false otherwise
5642**
5643**	Side Effects:
5644**		On success, e->e_qgrp and e->e_qdir are non-negative.
5645**		On failure (not enough disk space),
5646**		e->qgrp = NOQGRP, e->e_qdir = NOQDIR
5647**		and usrerr() is invoked (which could raise an exception).
5648*/
5649
5650bool
5651setnewqueue(e)
5652	ENVELOPE *e;
5653{
5654	if (tTd(41, 20))
5655		sm_dprintf("setnewqueue: called\n");
5656
5657	/* not set somewhere else */
5658	if (e->e_qgrp == NOQGRP)
5659	{
5660		ADDRESS *q;
5661
5662		/*
5663		**  Use the queue group of the "first" recipient, as set by
5664		**  the "queuegroup" rule set.  If that is not defined, then
5665		**  use the queue group of the mailer of the first recipient.
5666		**  If that is not defined either, then use the default
5667		**  queue group.
5668		**  Notice: "first" depends on the sorting of sendqueue
5669		**  in recipient().
5670		**  To avoid problems with "bad" recipients look
5671		**  for a valid address first.
5672		*/
5673
5674		q = e->e_sendqueue;
5675		while (q != NULL &&
5676		       (QS_IS_BADADDR(q->q_state) || QS_IS_DEAD(q->q_state)))
5677		{
5678			q = q->q_next;
5679		}
5680		if (q == NULL)
5681			e->e_qgrp = 0;
5682		else if (q->q_qgrp >= 0)
5683			e->e_qgrp = q->q_qgrp;
5684		else if (q->q_mailer != NULL &&
5685			 ISVALIDQGRP(q->q_mailer->m_qgrp))
5686			e->e_qgrp = q->q_mailer->m_qgrp;
5687		else
5688			e->e_qgrp = 0;
5689		e->e_dfqgrp = e->e_qgrp;
5690	}
5691
5692	if (ISVALIDQDIR(e->e_qdir) && ISVALIDQDIR(e->e_dfqdir))
5693	{
5694		if (tTd(41, 20))
5695			sm_dprintf("setnewqueue: e_qdir already assigned (%s)\n",
5696				qid_printqueue(e->e_qgrp, e->e_qdir));
5697		return true;
5698	}
5699
5700	filesys_update();
5701	e->e_qdir = pickqdir(Queue[e->e_qgrp], e->e_msgsize, e);
5702	if (e->e_qdir == NOQDIR)
5703	{
5704		e->e_qgrp = NOQGRP;
5705		if (!bitset(EF_FATALERRS, e->e_flags))
5706			usrerr("452 4.4.5 Insufficient disk space; try again later");
5707		e->e_flags |= EF_FATALERRS;
5708		return false;
5709	}
5710
5711	if (tTd(41, 3))
5712		sm_dprintf("setnewqueue: Assigned queue directory %s\n",
5713			qid_printqueue(e->e_qgrp, e->e_qdir));
5714
5715	if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR)
5716	{
5717		e->e_xfqgrp = e->e_qgrp;
5718		e->e_xfqdir = e->e_qdir;
5719	}
5720	e->e_dfqdir = e->e_qdir;
5721	return true;
5722}
5723/*
5724**  CHKQDIR -- check a queue directory
5725**
5726**	Parameters:
5727**		name -- name of queue directory
5728**		sff -- flags for safefile()
5729**
5730**	Returns:
5731**		is it a queue directory?
5732*/
5733
5734static bool
5735chkqdir(name, sff)
5736	char *name;
5737	long sff;
5738{
5739	struct stat statb;
5740	int i;
5741
5742	/* skip over . and .. directories */
5743	if (name[0] == '.' &&
5744	    (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
5745		return false;
5746#if HASLSTAT
5747	if (lstat(name, &statb) < 0)
5748#else /* HASLSTAT */
5749	if (stat(name, &statb) < 0)
5750#endif /* HASLSTAT */
5751	{
5752		if (tTd(41, 2))
5753			sm_dprintf("chkqdir: stat(\"%s\"): %s\n",
5754				   name, sm_errstring(errno));
5755		return false;
5756	}
5757#if HASLSTAT
5758	if (S_ISLNK(statb.st_mode))
5759	{
5760		/*
5761		**  For a symlink we need to make sure the
5762		**  target is a directory
5763		*/
5764
5765		if (stat(name, &statb) < 0)
5766		{
5767			if (tTd(41, 2))
5768				sm_dprintf("chkqdir: stat(\"%s\"): %s\n",
5769					   name, sm_errstring(errno));
5770			return false;
5771		}
5772	}
5773#endif /* HASLSTAT */
5774
5775	if (!S_ISDIR(statb.st_mode))
5776	{
5777		if (tTd(41, 2))
5778			sm_dprintf("chkqdir: \"%s\": Not a directory\n",
5779				name);
5780		return false;
5781	}
5782
5783	/* Print a warning if unsafe (but still use it) */
5784	/* XXX do this only if we want the warning? */
5785	i = safedirpath(name, RunAsUid, RunAsGid, NULL, sff, 0, 0);
5786	if (i != 0)
5787	{
5788		if (tTd(41, 2))
5789			sm_dprintf("chkqdir: \"%s\": Not safe: %s\n",
5790				   name, sm_errstring(i));
5791#if _FFR_CHK_QUEUE
5792		if (LogLevel > 8)
5793			sm_syslog(LOG_WARNING, NOQID,
5794				  "queue directory \"%s\": Not safe: %s",
5795				  name, sm_errstring(i));
5796#endif /* _FFR_CHK_QUEUE */
5797	}
5798	return true;
5799}
5800/*
5801**  MULTIQUEUE_CACHE -- cache a list of paths to queues.
5802**
5803**	Each potential queue is checked as the cache is built.
5804**	Thereafter, each is blindly trusted.
5805**	Note that we can be called again after a timeout to rebuild
5806**	(although code for that is not ready yet).
5807**
5808**	Parameters:
5809**		basedir -- base of all queue directories.
5810**		blen -- strlen(basedir).
5811**		qg -- queue group.
5812**		qn -- number of queue directories already cached.
5813**		phash -- pointer to hash value over queue dirs.
5814#if SM_CONF_SHM
5815**			only used if shared memory is active.
5816#endif * SM_CONF_SHM *
5817**
5818**	Returns:
5819**		new number of queue directories.
5820*/
5821
5822#define INITIAL_SLOTS	20
5823#define ADD_SLOTS	10
5824
5825static int
5826multiqueue_cache(basedir, blen, qg, qn, phash)
5827	char *basedir;
5828	int blen;
5829	QUEUEGRP *qg;
5830	int qn;
5831	unsigned int *phash;
5832{
5833	char *cp;
5834	int i, len;
5835	int slotsleft = 0;
5836	long sff = SFF_ANYFILE;
5837	char qpath[MAXPATHLEN];
5838	char subdir[MAXPATHLEN];
5839	char prefix[MAXPATHLEN];	/* dir relative to basedir */
5840
5841	if (tTd(41, 20))
5842		sm_dprintf("multiqueue_cache: called\n");
5843
5844	/* Initialize to current directory */
5845	prefix[0] = '.';
5846	prefix[1] = '\0';
5847	if (qg->qg_numqueues != 0 && qg->qg_qpaths != NULL)
5848	{
5849		for (i = 0; i < qg->qg_numqueues; i++)
5850		{
5851			if (qg->qg_qpaths[i].qp_name != NULL)
5852				(void) sm_free(qg->qg_qpaths[i].qp_name); /* XXX */
5853		}
5854		(void) sm_free((char *) qg->qg_qpaths); /* XXX */
5855		qg->qg_qpaths = NULL;
5856		qg->qg_numqueues = 0;
5857	}
5858
5859	/* If running as root, allow safedirpath() checks to use privs */
5860	if (RunAsUid == 0)
5861		sff |= SFF_ROOTOK;
5862#if _FFR_CHK_QUEUE
5863	sff |= SFF_SAFEDIRPATH|SFF_NOWWFILES;
5864	if (!UseMSP)
5865		sff |= SFF_NOGWFILES;
5866#endif /* _FFR_CHK_QUEUE */
5867
5868	if (!SM_IS_DIR_START(qg->qg_qdir))
5869	{
5870		/*
5871		**  XXX we could add basedir, but then we have to realloc()
5872		**  the string... Maybe another time.
5873		*/
5874
5875		syserr("QueuePath %s not absolute", qg->qg_qdir);
5876		ExitStat = EX_CONFIG;
5877		return qn;
5878	}
5879
5880	/* qpath: directory of current workgroup */
5881	len = sm_strlcpy(qpath, qg->qg_qdir, sizeof qpath);
5882	if (len >= sizeof qpath)
5883	{
5884		syserr("QueuePath %.256s too long (%d max)",
5885		       qg->qg_qdir, (int) sizeof qpath);
5886		ExitStat = EX_CONFIG;
5887		return qn;
5888	}
5889
5890	/* begin of qpath must be same as basedir */
5891	if (strncmp(basedir, qpath, blen) != 0 &&
5892	    (strncmp(basedir, qpath, blen - 1) != 0 || len != blen - 1))
5893	{
5894		syserr("QueuePath %s not subpath of QueueDirectory %s",
5895			qpath, basedir);
5896		ExitStat = EX_CONFIG;
5897		return qn;
5898	}
5899
5900	/* Do we have a nested subdirectory? */
5901	if (blen < len && SM_FIRST_DIR_DELIM(qg->qg_qdir + blen) != NULL)
5902	{
5903
5904		/* Copy subdirectory into prefix for later use */
5905		if (sm_strlcpy(prefix, qg->qg_qdir + blen, sizeof prefix) >=
5906		    sizeof prefix)
5907		{
5908			syserr("QueuePath %.256s too long (%d max)",
5909				qg->qg_qdir, (int) sizeof qpath);
5910			ExitStat = EX_CONFIG;
5911			return qn;
5912		}
5913		cp = SM_LAST_DIR_DELIM(prefix);
5914		SM_ASSERT(cp != NULL);
5915		*cp = '\0';	/* cut off trailing / */
5916	}
5917
5918	/* This is guaranteed by the basedir check above */
5919	SM_ASSERT(len >= blen - 1);
5920	cp = &qpath[len - 1];
5921	if (*cp == '*')
5922	{
5923		register DIR *dp;
5924		register struct dirent *d;
5925		int off;
5926		char *delim;
5927		char relpath[MAXPATHLEN];
5928
5929		*cp = '\0';	/* Overwrite wildcard */
5930		if ((cp = SM_LAST_DIR_DELIM(qpath)) == NULL)
5931		{
5932			syserr("QueueDirectory: can not wildcard relative path");
5933			if (tTd(41, 2))
5934				sm_dprintf("multiqueue_cache: \"%s*\": Can not wildcard relative path.\n",
5935					qpath);
5936			ExitStat = EX_CONFIG;
5937			return qn;
5938		}
5939		if (cp == qpath)
5940		{
5941			/*
5942			**  Special case of top level wildcard, like /foo*
5943			**	Change to //foo*
5944			*/
5945
5946			(void) sm_strlcpy(qpath + 1, qpath, sizeof qpath - 1);
5947			++cp;
5948		}
5949		delim = cp;
5950		*(cp++) = '\0';		/* Replace / with \0 */
5951		len = strlen(cp);	/* Last component of queue directory */
5952
5953		/*
5954		**  Path relative to basedir, with trailing /
5955		**  It will be modified below to specify the subdirectories
5956		**  so they can be opened without chdir().
5957		*/
5958
5959		off = sm_strlcpyn(relpath, sizeof relpath, 2, prefix, "/");
5960		SM_ASSERT(off < sizeof relpath);
5961
5962		if (tTd(41, 2))
5963			sm_dprintf("multiqueue_cache: prefix=\"%s%s\"\n",
5964				   relpath, cp);
5965
5966		/* It is always basedir: we don't need to store it per group */
5967		/* XXX: optimize this! -> one more global? */
5968		qg->qg_qdir = newstr(basedir);
5969		qg->qg_qdir[blen - 1] = '\0';	/* cut off trailing / */
5970
5971		/*
5972		**  XXX Should probably wrap this whole loop in a timeout
5973		**  in case some wag decides to NFS mount the queues.
5974		*/
5975
5976		/* Test path to get warning messages. */
5977		if (qn == 0)
5978		{
5979			/*  XXX qg_runasuid and qg_runasgid for specials? */
5980			i = safedirpath(basedir, RunAsUid, RunAsGid, NULL,
5981					sff, 0, 0);
5982			if (i != 0 && tTd(41, 2))
5983				sm_dprintf("multiqueue_cache: \"%s\": Not safe: %s\n",
5984					   basedir, sm_errstring(i));
5985		}
5986
5987		if ((dp = opendir(prefix)) == NULL)
5988		{
5989			syserr("can not opendir(%s/%s)", qg->qg_qdir, prefix);
5990			if (tTd(41, 2))
5991				sm_dprintf("multiqueue_cache: opendir(\"%s/%s\"): %s\n",
5992					   qg->qg_qdir, prefix,
5993					   sm_errstring(errno));
5994			ExitStat = EX_CONFIG;
5995			return qn;
5996		}
5997		while ((d = readdir(dp)) != NULL)
5998		{
5999			i = strlen(d->d_name);
6000			if (i < len || strncmp(d->d_name, cp, len) != 0)
6001			{
6002				if (tTd(41, 5))
6003					sm_dprintf("multiqueue_cache: \"%s\", skipped\n",
6004						d->d_name);
6005				continue;
6006			}
6007
6008			/* Create relative pathname: prefix + local directory */
6009			i = sizeof(relpath) - off;
6010			if (sm_strlcpy(relpath + off, d->d_name, i) >= i)
6011				continue;	/* way too long */
6012
6013			if (!chkqdir(relpath, sff))
6014				continue;
6015
6016			if (qg->qg_qpaths == NULL)
6017			{
6018				slotsleft = INITIAL_SLOTS;
6019				qg->qg_qpaths = (QPATHS *)xalloc((sizeof *qg->qg_qpaths) *
6020								slotsleft);
6021				qg->qg_numqueues = 0;
6022			}
6023			else if (slotsleft < 1)
6024			{
6025				qg->qg_qpaths = (QPATHS *)sm_realloc((char *)qg->qg_qpaths,
6026							  (sizeof *qg->qg_qpaths) *
6027							  (qg->qg_numqueues +
6028							   ADD_SLOTS));
6029				if (qg->qg_qpaths == NULL)
6030				{
6031					(void) closedir(dp);
6032					return qn;
6033				}
6034				slotsleft += ADD_SLOTS;
6035			}
6036
6037			/* check subdirs */
6038			qg->qg_qpaths[qg->qg_numqueues].qp_subdirs = QP_NOSUB;
6039
6040#define CHKRSUBDIR(name, flag)	\
6041	(void) sm_strlcpyn(subdir, sizeof subdir, 3, relpath, "/", name); \
6042	if (chkqdir(subdir, sff))	\
6043		qg->qg_qpaths[qg->qg_numqueues].qp_subdirs |= flag;	\
6044	else
6045
6046
6047			CHKRSUBDIR("qf", QP_SUBQF);
6048			CHKRSUBDIR("df", QP_SUBDF);
6049			CHKRSUBDIR("xf", QP_SUBXF);
6050
6051			/* assert(strlen(d->d_name) < MAXPATHLEN - 14) */
6052			/* maybe even - 17 (subdirs) */
6053
6054			if (prefix[0] != '.')
6055				qg->qg_qpaths[qg->qg_numqueues].qp_name =
6056					newstr(relpath);
6057			else
6058				qg->qg_qpaths[qg->qg_numqueues].qp_name =
6059					newstr(d->d_name);
6060
6061			if (tTd(41, 2))
6062				sm_dprintf("multiqueue_cache: %d: \"%s\" cached (%x).\n",
6063					qg->qg_numqueues, relpath,
6064					qg->qg_qpaths[qg->qg_numqueues].qp_subdirs);
6065#if SM_CONF_SHM
6066			qg->qg_qpaths[qg->qg_numqueues].qp_idx = qn;
6067			*phash = hash_q(relpath, *phash);
6068#endif /* SM_CONF_SHM */
6069			qg->qg_numqueues++;
6070			++qn;
6071			slotsleft--;
6072		}
6073		(void) closedir(dp);
6074
6075		/* undo damage */
6076		*delim = '/';
6077	}
6078	if (qg->qg_numqueues == 0)
6079	{
6080		qg->qg_qpaths = (QPATHS *) xalloc(sizeof *qg->qg_qpaths);
6081
6082		/* test path to get warning messages */
6083		i = safedirpath(qpath, RunAsUid, RunAsGid, NULL, sff, 0, 0);
6084		if (i == ENOENT)
6085		{
6086			syserr("can not opendir(%s)", qpath);
6087			if (tTd(41, 2))
6088				sm_dprintf("multiqueue_cache: opendir(\"%s\"): %s\n",
6089					   qpath, sm_errstring(i));
6090			ExitStat = EX_CONFIG;
6091			return qn;
6092		}
6093
6094		qg->qg_qpaths[0].qp_subdirs = QP_NOSUB;
6095		qg->qg_numqueues = 1;
6096
6097		/* check subdirs */
6098#define CHKSUBDIR(name, flag)	\
6099	(void) sm_strlcpyn(subdir, sizeof subdir, 3, qg->qg_qdir, "/", name); \
6100	if (chkqdir(subdir, sff))	\
6101		qg->qg_qpaths[0].qp_subdirs |= flag;	\
6102	else
6103
6104		CHKSUBDIR("qf", QP_SUBQF);
6105		CHKSUBDIR("df", QP_SUBDF);
6106		CHKSUBDIR("xf", QP_SUBXF);
6107
6108		if (qg->qg_qdir[blen - 1] != '\0' &&
6109		    qg->qg_qdir[blen] != '\0')
6110		{
6111			/*
6112			**  Copy the last component into qpaths and
6113			**  cut off qdir
6114			*/
6115
6116			qg->qg_qpaths[0].qp_name = newstr(qg->qg_qdir + blen);
6117			qg->qg_qdir[blen - 1] = '\0';
6118		}
6119		else
6120			qg->qg_qpaths[0].qp_name = newstr(".");
6121
6122#if SM_CONF_SHM
6123		qg->qg_qpaths[0].qp_idx = qn;
6124		*phash = hash_q(qg->qg_qpaths[0].qp_name, *phash);
6125#endif /* SM_CONF_SHM */
6126		++qn;
6127	}
6128	return qn;
6129}
6130
6131/*
6132**  FILESYS_FIND -- find entry in FileSys table, or add new one
6133**
6134**	Given the pathname of a directory, determine the file system
6135**	in which that directory resides, and return a pointer to the
6136**	entry in the FileSys table that describes the file system.
6137**	A new entry is added if necessary (and requested).
6138**	If the directory does not exist, -1 is returned.
6139**
6140**	Parameters:
6141**		path -- pathname of directory
6142**		add -- add to structure if not found.
6143**
6144**	Returns:
6145**		>=0: found: index in file system table
6146**		<0: some error, i.e.,
6147**		FSF_TOO_MANY: too many filesystems (-> syserr())
6148**		FSF_STAT_FAIL: can't stat() filesystem (-> syserr())
6149**		FSF_NOT_FOUND: not in list
6150*/
6151
6152static short filesys_find __P((char *, bool));
6153
6154#define FSF_NOT_FOUND	(-1)
6155#define FSF_STAT_FAIL	(-2)
6156#define FSF_TOO_MANY	(-3)
6157
6158static short
6159filesys_find(path, add)
6160	char *path;
6161	bool add;
6162{
6163	struct stat st;
6164	short i;
6165
6166	if (stat(path, &st) < 0)
6167	{
6168		syserr("cannot stat queue directory %s", path);
6169		return FSF_STAT_FAIL;
6170	}
6171	for (i = 0; i < NumFileSys; ++i)
6172	{
6173		if (FILE_SYS_DEV(i) == st.st_dev)
6174			return i;
6175	}
6176	if (i >= MAXFILESYS)
6177	{
6178		syserr("too many queue file systems (%d max)", MAXFILESYS);
6179		return FSF_TOO_MANY;
6180	}
6181	if (!add)
6182		return FSF_NOT_FOUND;
6183
6184	++NumFileSys;
6185	FILE_SYS_NAME(i) = path;
6186	FILE_SYS_DEV(i) = st.st_dev;
6187	FILE_SYS_AVAIL(i) = 0;
6188	FILE_SYS_BLKSIZE(i) = 1024; /* avoid divide by zero */
6189	return i;
6190}
6191
6192/*
6193**  FILESYS_SETUP -- set up mapping from queue directories to file systems
6194**
6195**	This data structure is used to efficiently check the amount of
6196**	free space available in a set of queue directories.
6197**
6198**	Parameters:
6199**		add -- initialize structure if necessary.
6200**
6201**	Returns:
6202**		0: success
6203**		<0: some error, i.e.,
6204**		FSF_NOT_FOUND: not in list
6205**		FSF_STAT_FAIL: can't stat() filesystem (-> syserr())
6206**		FSF_TOO_MANY: too many filesystems (-> syserr())
6207*/
6208
6209static int filesys_setup __P((bool));
6210
6211static int
6212filesys_setup(add)
6213	bool add;
6214{
6215	int i, j;
6216	short fs;
6217	int ret;
6218
6219	ret = 0;
6220	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
6221	{
6222		for (j = 0; j < Queue[i]->qg_numqueues; ++j)
6223		{
6224			QPATHS *qp = &Queue[i]->qg_qpaths[j];
6225
6226			fs = filesys_find(qp->qp_name, add);
6227			if (fs >= 0)
6228				qp->qp_fsysidx = fs;
6229			else
6230				qp->qp_fsysidx = 0;
6231			if (fs < ret)
6232				ret = fs;
6233		}
6234	}
6235	return ret;
6236}
6237
6238/*
6239**  FILESYS_UPDATE -- update amount of free space on all file systems
6240**
6241**	The FileSys table is used to cache the amount of free space
6242**	available on all queue directory file systems.
6243**	This function updates the cached information if it has expired.
6244**
6245**	Parameters:
6246**		none.
6247**
6248**	Returns:
6249**		none.
6250**
6251**	Side Effects:
6252**		Updates FileSys table.
6253*/
6254
6255void
6256filesys_update()
6257{
6258	int i;
6259	long avail, blksize;
6260	time_t now;
6261	static time_t nextupdate = 0;
6262
6263#if SM_CONF_SHM
6264	/* only the daemon updates this structure */
6265	if (ShmId != SM_SHM_NO_ID && DaemonPid != CurrentPid)
6266		return;
6267#endif /* SM_CONF_SHM */
6268	now = curtime();
6269	if (now < nextupdate)
6270		return;
6271	nextupdate = now + FILESYS_UPDATE_INTERVAL;
6272	for (i = 0; i < NumFileSys; ++i)
6273	{
6274		FILESYS *fs = &FILE_SYS(i);
6275
6276		avail = freediskspace(FILE_SYS_NAME(i), &blksize);
6277		if (avail < 0 || blksize <= 0)
6278		{
6279			if (LogLevel > 5)
6280				sm_syslog(LOG_ERR, NOQID,
6281					"filesys_update failed: %s, fs=%s, avail=%ld, blocksize=%ld",
6282					sm_errstring(errno),
6283					FILE_SYS_NAME(i), avail, blksize);
6284			fs->fs_avail = 0;
6285			fs->fs_blksize = 1024; /* avoid divide by zero */
6286			nextupdate = now + 2; /* let's do this soon again */
6287		}
6288		else
6289		{
6290			fs->fs_avail = avail;
6291			fs->fs_blksize = blksize;
6292		}
6293	}
6294}
6295
6296#if _FFR_ANY_FREE_FS
6297/*
6298**  FILESYS_FREE -- check whether there is at least one fs with enough space.
6299**
6300**	Parameters:
6301**		fsize -- file size in bytes
6302**
6303**	Returns:
6304**		true iff there is one fs with more than fsize bytes free.
6305*/
6306
6307bool
6308filesys_free(fsize)
6309	long fsize;
6310{
6311	int i;
6312
6313	if (fsize <= 0)
6314		return true;
6315	for (i = 0; i < NumFileSys; ++i)
6316	{
6317		long needed = 0;
6318
6319		if (FILE_SYS_AVAIL(i) < 0 || FILE_SYS_BLKSIZE(i) <= 0)
6320			continue;
6321		needed += fsize / FILE_SYS_BLKSIZE(i)
6322			  + ((fsize % FILE_SYS_BLKSIZE(i)
6323			      > 0) ? 1 : 0)
6324			  + MinBlocksFree;
6325		if (needed <= FILE_SYS_AVAIL(i))
6326			return true;
6327	}
6328	return false;
6329}
6330#endif /* _FFR_ANY_FREE_FS */
6331
6332#if _FFR_CONTROL_MSTAT
6333/*
6334**  DISK_STATUS -- show amount of free space in queue directories
6335**
6336**	Parameters:
6337**		out -- output file pointer.
6338**		prefix -- string to output in front of each line.
6339**
6340**	Returns:
6341**		none.
6342*/
6343
6344void
6345disk_status(out, prefix)
6346	SM_FILE_T *out;
6347	char *prefix;
6348{
6349	int i;
6350	long avail, blksize;
6351	long free;
6352
6353	for (i = 0; i < NumFileSys; ++i)
6354	{
6355		avail = freediskspace(FILE_SYS_NAME(i), &blksize);
6356		if (avail >= 0 && blksize > 0)
6357		{
6358			free = (long)((double) avail *
6359				((double) blksize / 1024));
6360		}
6361		else
6362			free = -1;
6363		(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
6364				"%s%d/%s/%ld\r\n",
6365				prefix, i,
6366				FILE_SYS_NAME(i),
6367					free);
6368	}
6369}
6370#endif /* _FFR_CONTROL_MSTAT */
6371
6372#if SM_CONF_SHM
6373/*
6374**  UPD_QS -- update information about queue when adding/deleting an entry
6375**
6376**	Parameters:
6377**		e -- envelope.
6378**		delete -- delete/add entry.
6379**		avail -- update the space available as well.
6380**
6381**	Returns:
6382**		none.
6383**
6384**	Side Effects:
6385**		Modifies available space in filesystem.
6386**		Changes number of entries in queue directory.
6387*/
6388
6389void
6390upd_qs(e, delete, avail)
6391	ENVELOPE *e;
6392	bool delete;
6393	bool avail;
6394{
6395	short fidx;
6396	int idx;
6397	long s;
6398
6399	if (ShmId == SM_SHM_NO_ID || e == NULL)
6400		return;
6401	if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR)
6402		return;
6403	idx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_idx;
6404
6405	/* XXX in theory this needs to be protected with a mutex */
6406	if (QSHM_ENTRIES(idx) >= 0)
6407	{
6408		if (delete)
6409			--QSHM_ENTRIES(idx);
6410		else
6411			++QSHM_ENTRIES(idx);
6412	}
6413
6414	fidx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_fsysidx;
6415	if (fidx < 0)
6416		return;
6417
6418	/* update available space also?  (might be loseqfile) */
6419	if (!avail)
6420		return;
6421
6422	/* convert size to blocks; this causes rounding errors */
6423	s = e->e_msgsize / FILE_SYS_BLKSIZE(fidx);
6424	if (s == 0)
6425		return;
6426
6427	/* XXX in theory this needs to be protected with a mutex */
6428	if (delete)
6429		FILE_SYS_AVAIL(fidx) += s;
6430	else
6431		FILE_SYS_AVAIL(fidx) -= s;
6432
6433}
6434
6435#if _FFR_SELECT_SHM
6436
6437static bool write_key_file __P((char *, long));
6438static long read_key_file __P((char *, long));
6439
6440/*
6441**  WRITE_KEY_FILE -- record some key into a file.
6442**
6443**	Parameters:
6444**		keypath -- file name.
6445**		key -- key to write.
6446**
6447**	Returns:
6448**		true iff file could be written.
6449**
6450**	Side Effects:
6451**		writes file.
6452*/
6453
6454static bool
6455write_key_file(keypath, key)
6456	char *keypath;
6457	long key;
6458{
6459	bool ok;
6460	long sff;
6461	SM_FILE_T *keyf;
6462
6463	ok = false;
6464	if (keypath == NULL || *keypath == '\0')
6465		return ok;
6466	sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT;
6467	if (TrustedUid != 0 && RealUid == TrustedUid)
6468		sff |= SFF_OPENASROOT;
6469	keyf = safefopen(keypath, O_WRONLY|O_TRUNC, FileMode, sff);
6470	if (keyf == NULL)
6471	{
6472		sm_syslog(LOG_ERR, NOQID, "unable to write %s: %s",
6473			  keypath, sm_errstring(errno));
6474	}
6475	else
6476	{
6477		ok = sm_io_fprintf(keyf, SM_TIME_DEFAULT, "%ld\n", key) !=
6478		     SM_IO_EOF;
6479		ok = (sm_io_close(keyf, SM_TIME_DEFAULT) != SM_IO_EOF) && ok;
6480	}
6481	return ok;
6482}
6483
6484/*
6485**  READ_KEY_FILE -- read a key from a file.
6486**
6487**	Parameters:
6488**		keypath -- file name.
6489**		key -- default key.
6490**
6491**	Returns:
6492**		key.
6493*/
6494
6495static long
6496read_key_file(keypath, key)
6497	char *keypath;
6498	long key;
6499{
6500	int r;
6501	long sff, n;
6502	SM_FILE_T *keyf;
6503
6504	if (keypath == NULL || *keypath == '\0')
6505		return key;
6506	sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY;
6507	if (RealUid == 0 || (TrustedUid != 0 && RealUid == TrustedUid))
6508		sff |= SFF_OPENASROOT;
6509	keyf = safefopen(keypath, O_RDONLY, FileMode, sff);
6510	if (keyf == NULL)
6511	{
6512		sm_syslog(LOG_ERR, NOQID, "unable to read %s: %s",
6513			  keypath, sm_errstring(errno));
6514	}
6515	else
6516	{
6517		r = sm_io_fscanf(keyf, SM_TIME_DEFAULT, "%ld", &n);
6518		if (r == 1)
6519			key = n;
6520		(void) sm_io_close(keyf, SM_TIME_DEFAULT);
6521	}
6522	return key;
6523}
6524#endif /* _FFR_SELECT_SHM */
6525
6526/*
6527**  INIT_SHM -- initialize shared memory structure
6528**
6529**	Initialize or attach to shared memory segment.
6530**	Currently it is not a fatal error if this doesn't work.
6531**	However, it causes us to have a "fallback" storage location
6532**	for everything that is supposed to be in the shared memory,
6533**	which makes the code slightly ugly.
6534**
6535**	Parameters:
6536**		qn -- number of queue directories.
6537**		owner -- owner of shared memory.
6538**		hash -- identifies data that is stored in shared memory.
6539**
6540**	Returns:
6541**		none.
6542*/
6543
6544static void init_shm __P((int, bool, unsigned int));
6545
6546static void
6547init_shm(qn, owner, hash)
6548	int qn;
6549	bool owner;
6550	unsigned int hash;
6551{
6552	int i;
6553#if _FFR_SELECT_SHM
6554	bool keyselect;
6555#endif /* _FFR_SELECT_SHM */
6556
6557	PtrFileSys = &FileSys[0];
6558	PNumFileSys = &Numfilesys;
6559#if _FFR_SELECT_SHM
6560/* if this "key" is specified: select one yourself */
6561# define SEL_SHM_KEY	((key_t) -1)
6562# define FIRST_SHM_KEY	25
6563#endif /* _FFR_SELECT_SHM */
6564
6565	/* This allows us to disable shared memory at runtime. */
6566	if (ShmKey != 0)
6567	{
6568		int count;
6569		int save_errno;
6570
6571		count = 0;
6572		shms = SM_T_SIZE + qn * sizeof(QUEUE_SHM_T);
6573#if _FFR_SELECT_SHM
6574		keyselect = ShmKey == SEL_SHM_KEY;
6575		if (keyselect)
6576		{
6577			if (owner)
6578				ShmKey = FIRST_SHM_KEY;
6579			else
6580			{
6581				ShmKey = read_key_file(ShmKeyFile, ShmKey);
6582				keyselect = false;
6583				if (ShmKey == SEL_SHM_KEY)
6584					goto error;
6585			}
6586		}
6587#endif /* _FFR_SELECT_SHM */
6588		for (;;)
6589		{
6590			/* XXX: maybe allow read access for group? */
6591			Pshm = sm_shmstart(ShmKey, shms, SHM_R|SHM_W, &ShmId,
6592					   owner);
6593			save_errno = errno;
6594			if (Pshm != NULL || save_errno != EEXIST)
6595				break;
6596			if (++count >= 3)
6597			{
6598#if _FFR_SELECT_SHM
6599				if (keyselect)
6600				{
6601					++ShmKey;
6602
6603					/* back where we started? */
6604					if (ShmKey == SEL_SHM_KEY)
6605						break;
6606					continue;
6607				}
6608#endif /* _FFR_SELECT_SHM */
6609				break;
6610			}
6611#if _FFR_SELECT_SHM
6612			/* only sleep if we are at the first key */
6613			if (!keyselect || ShmKey == SEL_SHM_KEY)
6614#endif /* _FFR_SELECT_SHM */
6615			sleep(count);
6616		}
6617		if (Pshm != NULL)
6618		{
6619			int *p;
6620
6621#if _FFR_SELECT_SHM
6622			if (keyselect)
6623				(void) write_key_file(ShmKeyFile, (long) ShmKey);
6624#endif /* _FFR_SELECT_SHM */
6625			p = (int *) Pshm;
6626			if (owner)
6627			{
6628				*p = (int) shms;
6629				*((pid_t *) SHM_OFF_PID(Pshm)) = CurrentPid;
6630				p = (int *) SHM_OFF_TAG(Pshm);
6631				*p = hash;
6632			}
6633			else
6634			{
6635				if (*p != (int) shms)
6636				{
6637					save_errno = EINVAL;
6638					cleanup_shm(false);
6639					goto error;
6640				}
6641				p = (int *) SHM_OFF_TAG(Pshm);
6642				if (*p != (int) hash)
6643				{
6644					save_errno = EINVAL;
6645					cleanup_shm(false);
6646					goto error;
6647				}
6648
6649				/*
6650				**  XXX how to check the pid?
6651				**  Read it from the pid-file? That does
6652				**  not need to exist.
6653				**  We could disable shm if we can't confirm
6654				**  that it is the right one.
6655				*/
6656			}
6657
6658			PtrFileSys = (FILESYS *) OFF_FILE_SYS(Pshm);
6659			PNumFileSys = (int *) OFF_NUM_FILE_SYS(Pshm);
6660			QShm = (QUEUE_SHM_T *) OFF_QUEUE_SHM(Pshm);
6661			PRSATmpCnt = (int *) OFF_RSA_TMP_CNT(Pshm);
6662			*PRSATmpCnt = 0;
6663			if (owner)
6664			{
6665				/* initialize values in shared memory */
6666				NumFileSys = 0;
6667				for (i = 0; i < qn; i++)
6668					QShm[i].qs_entries = -1;
6669			}
6670			return;
6671		}
6672  error:
6673		if (LogLevel > (owner ? 8 : 11))
6674		{
6675			sm_syslog(owner ? LOG_ERR : LOG_NOTICE, NOQID,
6676				  "can't %s shared memory, key=%ld: %s",
6677				  owner ? "initialize" : "attach to",
6678				  (long) ShmKey, sm_errstring(save_errno));
6679		}
6680	}
6681}
6682#endif /* SM_CONF_SHM */
6683
6684/*
6685**  SETUP_QUEUES -- setup all queue groups
6686**
6687**	Parameters:
6688**		owner -- owner of shared memory.
6689**
6690**	Returns:
6691**		none.
6692**
6693#if SM_CONF_SHM
6694**	Side Effects:
6695**		attaches shared memory.
6696#endif * SM_CONF_SHM *
6697*/
6698
6699void
6700setup_queues(owner)
6701	bool owner;
6702{
6703	int i, qn, len;
6704	unsigned int hashval;
6705	time_t now;
6706	char basedir[MAXPATHLEN];
6707	struct stat st;
6708
6709	/*
6710	**  Determine basedir for all queue directories.
6711	**  All queue directories must be (first level) subdirectories
6712	**  of the basedir.  The basedir is the QueueDir
6713	**  without wildcards, but with trailing /
6714	*/
6715
6716	hashval = 0;
6717	errno = 0;
6718	len = sm_strlcpy(basedir, QueueDir, sizeof basedir);
6719
6720	/* Provide space for trailing '/' */
6721	if (len >= sizeof basedir - 1)
6722	{
6723		syserr("QueueDirectory: path too long: %d,  max %d",
6724			len, (int) sizeof basedir - 1);
6725		ExitStat = EX_CONFIG;
6726		return;
6727	}
6728	SM_ASSERT(len > 0);
6729	if (basedir[len - 1] == '*')
6730	{
6731		char *cp;
6732
6733		cp = SM_LAST_DIR_DELIM(basedir);
6734		if (cp == NULL)
6735		{
6736			syserr("QueueDirectory: can not wildcard relative path \"%s\"",
6737				QueueDir);
6738			if (tTd(41, 2))
6739				sm_dprintf("setup_queues: \"%s\": Can not wildcard relative path.\n",
6740					QueueDir);
6741			ExitStat = EX_CONFIG;
6742			return;
6743		}
6744
6745		/* cut off wildcard pattern */
6746		*++cp = '\0';
6747		len = cp - basedir;
6748	}
6749	else if (!SM_IS_DIR_DELIM(basedir[len - 1]))
6750	{
6751		/* append trailing slash since it is a directory */
6752		basedir[len] = '/';
6753		basedir[++len] = '\0';
6754	}
6755
6756	/* len counts up to the last directory delimiter */
6757	SM_ASSERT(basedir[len - 1] == '/');
6758
6759	if (chdir(basedir) < 0)
6760	{
6761		int save_errno = errno;
6762
6763		syserr("can not chdir(%s)", basedir);
6764		if (save_errno == EACCES)
6765			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
6766				"Program mode requires special privileges, e.g., root or TrustedUser.\n");
6767		if (tTd(41, 2))
6768			sm_dprintf("setup_queues: \"%s\": %s\n",
6769				   basedir, sm_errstring(errno));
6770		ExitStat = EX_CONFIG;
6771		return;
6772	}
6773#if SM_CONF_SHM
6774	hashval = hash_q(basedir, hashval);
6775#endif /* SM_CONF_SHM */
6776
6777	/* initialize for queue runs */
6778	DoQueueRun = false;
6779	now = curtime();
6780	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
6781		Queue[i]->qg_nextrun = now;
6782
6783
6784	if (UseMSP && OpMode != MD_TEST)
6785	{
6786		long sff = SFF_CREAT;
6787
6788		if (stat(".", &st) < 0)
6789		{
6790			syserr("can not stat(%s)", basedir);
6791			if (tTd(41, 2))
6792				sm_dprintf("setup_queues: \"%s\": %s\n",
6793					   basedir, sm_errstring(errno));
6794			ExitStat = EX_CONFIG;
6795			return;
6796		}
6797		if (RunAsUid == 0)
6798			sff |= SFF_ROOTOK;
6799
6800		/*
6801		**  Check queue directory permissions.
6802		**	Can we write to a group writable queue directory?
6803		*/
6804
6805		if (bitset(S_IWGRP, QueueFileMode) &&
6806		    bitset(S_IWGRP, st.st_mode) &&
6807		    safefile(" ", RunAsUid, RunAsGid, RunAsUserName, sff,
6808			     QueueFileMode, NULL) != 0)
6809		{
6810			syserr("can not write to queue directory %s (RunAsGid=%d, required=%d)",
6811				basedir, (int) RunAsGid, (int) st.st_gid);
6812		}
6813		if (bitset(S_IWOTH|S_IXOTH, st.st_mode))
6814		{
6815#if _FFR_MSP_PARANOIA
6816			syserr("dangerous permissions=%o on queue directory %s",
6817				(int) st.st_mode, basedir);
6818#else /* _FFR_MSP_PARANOIA */
6819			if (LogLevel > 0)
6820				sm_syslog(LOG_ERR, NOQID,
6821					  "dangerous permissions=%o on queue directory %s",
6822					  (int) st.st_mode, basedir);
6823#endif /* _FFR_MSP_PARANOIA */
6824		}
6825#if _FFR_MSP_PARANOIA
6826		if (NumQueue > 1)
6827			syserr("can not use multiple queues for MSP");
6828#endif /* _FFR_MSP_PARANOIA */
6829	}
6830
6831	/* initial number of queue directories */
6832	qn = 0;
6833	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
6834		qn = multiqueue_cache(basedir, len, Queue[i], qn, &hashval);
6835
6836#if SM_CONF_SHM
6837	init_shm(qn, owner, hashval);
6838	i = filesys_setup(owner || ShmId == SM_SHM_NO_ID);
6839	if (i == FSF_NOT_FOUND)
6840	{
6841		/*
6842		**  We didn't get the right filesystem data
6843		**  This may happen if we don't have the right shared memory.
6844		**  So let's do this without shared memory.
6845		*/
6846
6847		SM_ASSERT(!owner);
6848		cleanup_shm(false);	/* release shared memory */
6849		i = filesys_setup(false);
6850		if (i < 0)
6851			syserr("filesys_setup failed twice, result=%d", i);
6852		else if (LogLevel > 8)
6853			sm_syslog(LOG_WARNING, NOQID,
6854				  "shared memory does not contain expected data, ignored");
6855	}
6856#else /* SM_CONF_SHM */
6857	i = filesys_setup(true);
6858#endif /* SM_CONF_SHM */
6859	if (i < 0)
6860		ExitStat = EX_CONFIG;
6861}
6862
6863#if SM_CONF_SHM
6864/*
6865**  CLEANUP_SHM -- do some cleanup work for shared memory etc
6866**
6867**	Parameters:
6868**		owner -- owner of shared memory?
6869**
6870**	Returns:
6871**		none.
6872**
6873**	Side Effects:
6874**		detaches shared memory.
6875*/
6876
6877void
6878cleanup_shm(owner)
6879	bool owner;
6880{
6881	if (ShmId != SM_SHM_NO_ID)
6882	{
6883		if (sm_shmstop(Pshm, ShmId, owner) < 0 && LogLevel > 8)
6884			sm_syslog(LOG_INFO, NOQID, "sm_shmstop failed=%s",
6885				  sm_errstring(errno));
6886		Pshm = NULL;
6887		ShmId = SM_SHM_NO_ID;
6888	}
6889}
6890#endif /* SM_CONF_SHM */
6891
6892/*
6893**  CLEANUP_QUEUES -- do some cleanup work for queues
6894**
6895**	Parameters:
6896**		none.
6897**
6898**	Returns:
6899**		none.
6900**
6901*/
6902
6903void
6904cleanup_queues()
6905{
6906	sync_queue_time();
6907}
6908/*
6909**  SET_DEF_QUEUEVAL -- set default values for a queue group.
6910**
6911**	Parameters:
6912**		qg -- queue group
6913**		all -- set all values (true for default group)?
6914**
6915**	Returns:
6916**		none.
6917**
6918**	Side Effects:
6919**		sets default values for the queue group.
6920*/
6921
6922void
6923set_def_queueval(qg, all)
6924	QUEUEGRP *qg;
6925	bool all;
6926{
6927	if (bitnset(QD_DEFINED, qg->qg_flags))
6928		return;
6929	if (all)
6930		qg->qg_qdir = QueueDir;
6931#if _FFR_QUEUE_GROUP_SORTORDER
6932	qg->qg_sortorder = QueueSortOrder;
6933#endif /* _FFR_QUEUE_GROUP_SORTORDER */
6934	qg->qg_maxqrun = all ? MaxRunnersPerQueue : -1;
6935	qg->qg_nice = NiceQueueRun;
6936}
6937/*
6938**  MAKEQUEUE -- define a new queue.
6939**
6940**	Parameters:
6941**		line -- description of queue.  This is in labeled fields.
6942**			The fields are:
6943**			   F -- the flags associated with the queue
6944**			   I -- the interval between running the queue
6945**			   J -- the maximum # of jobs in work list
6946**			   [M -- the maximum # of jobs in a queue run]
6947**			   N -- the niceness at which to run
6948**			   P -- the path to the queue
6949**			   S -- the queue sorting order
6950**			   R -- number of parallel queue runners
6951**			   r -- max recipients per envelope
6952**			The first word is the canonical name of the queue.
6953**		qdef -- this is a 'Q' definition from .cf
6954**
6955**	Returns:
6956**		none.
6957**
6958**	Side Effects:
6959**		enters the queue into the queue table.
6960*/
6961
6962void
6963makequeue(line, qdef)
6964	char *line;
6965	bool qdef;
6966{
6967	register char *p;
6968	register QUEUEGRP *qg;
6969	register STAB *s;
6970	int i;
6971	char fcode;
6972
6973	/* allocate a queue and set up defaults */
6974	qg = (QUEUEGRP *) xalloc(sizeof *qg);
6975	memset((char *) qg, '\0', sizeof *qg);
6976
6977	if (line[0] == '\0')
6978	{
6979		syserr("name required for queue");
6980		return;
6981	}
6982
6983	/* collect the queue name */
6984	for (p = line;
6985	     *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p));
6986	     p++)
6987		continue;
6988	if (*p != '\0')
6989		*p++ = '\0';
6990	qg->qg_name = newstr(line);
6991
6992	/* set default values, can be overridden below */
6993	set_def_queueval(qg, false);
6994
6995	/* now scan through and assign info from the fields */
6996	while (*p != '\0')
6997	{
6998		auto char *delimptr;
6999
7000		while (*p != '\0' &&
7001		       (*p == ',' || (isascii(*p) && isspace(*p))))
7002			p++;
7003
7004		/* p now points to field code */
7005		fcode = *p;
7006		while (*p != '\0' && *p != '=' && *p != ',')
7007			p++;
7008		if (*p++ != '=')
7009		{
7010			syserr("queue %s: `=' expected", qg->qg_name);
7011			return;
7012		}
7013		while (isascii(*p) && isspace(*p))
7014			p++;
7015
7016		/* p now points to the field body */
7017		p = munchstring(p, &delimptr, ',');
7018
7019		/* install the field into the queue struct */
7020		switch (fcode)
7021		{
7022		  case 'P':		/* pathname */
7023			if (*p == '\0')
7024				syserr("queue %s: empty path name",
7025					qg->qg_name);
7026			else
7027				qg->qg_qdir = newstr(p);
7028			break;
7029
7030		  case 'F':		/* flags */
7031			for (; *p != '\0'; p++)
7032				if (!(isascii(*p) && isspace(*p)))
7033					setbitn(*p, qg->qg_flags);
7034			break;
7035
7036			/*
7037			**  Do we need two intervals here:
7038			**  One for persistent queue runners,
7039			**  one for "normal" queue runs?
7040			*/
7041
7042		  case 'I':	/* interval between running the queue */
7043			qg->qg_queueintvl = convtime(p, 'm');
7044			break;
7045
7046		  case 'N':		/* run niceness */
7047			qg->qg_nice = atoi(p);
7048			break;
7049
7050		  case 'R':		/* maximum # of runners for the group */
7051			i = atoi(p);
7052
7053			/* can't have more runners than allowed total */
7054			if (MaxQueueChildren > 0 && i > MaxQueueChildren)
7055			{
7056				qg->qg_maxqrun = MaxQueueChildren;
7057				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7058						     "Q=%s: R=%d exceeds MaxQueueChildren=%d, set to MaxQueueChildren\n",
7059						     qg->qg_name, i,
7060						     MaxQueueChildren);
7061			}
7062			else
7063				qg->qg_maxqrun = i;
7064			break;
7065
7066		  case 'J':		/* maximum # of jobs in work list */
7067			qg->qg_maxlist = atoi(p);
7068			break;
7069
7070		  case 'r':		/* max recipients per envelope */
7071			qg->qg_maxrcpt = atoi(p);
7072			break;
7073
7074#if _FFR_QUEUE_GROUP_SORTORDER
7075		  case 'S':		/* queue sorting order */
7076			switch (*p)
7077			{
7078			  case 'h':	/* Host first */
7079			  case 'H':
7080				qg->qg_sortorder = QSO_BYHOST;
7081				break;
7082
7083			  case 'p':	/* Priority order */
7084			  case 'P':
7085				qg->qg_sortorder = QSO_BYPRIORITY;
7086				break;
7087
7088			  case 't':	/* Submission time */
7089			  case 'T':
7090				qg->qg_sortorder = QSO_BYTIME;
7091				break;
7092
7093			  case 'f':	/* File name */
7094			  case 'F':
7095				qg->qg_sortorder = QSO_BYFILENAME;
7096				break;
7097
7098			  case 'm':	/* Modification time */
7099			  case 'M':
7100				qg->qg_sortorder = QSO_BYMODTIME;
7101				break;
7102
7103			  case 'r':	/* Random */
7104			  case 'R':
7105				qg->qg_sortorder = QSO_RANDOM;
7106				break;
7107
7108# if _FFR_RHS
7109			  case 's':	/* Shuffled host name */
7110			  case 'S':
7111				qg->qg_sortorder = QSO_BYSHUFFLE;
7112				break;
7113# endif /* _FFR_RHS */
7114
7115			  default:
7116				syserr("Invalid queue sort order \"%s\"", p);
7117			}
7118			break;
7119#endif /* _FFR_QUEUE_GROUP_SORTORDER */
7120
7121		  default:
7122			syserr("Q%s: unknown queue equate %c=",
7123			       qg->qg_name, fcode);
7124			break;
7125		}
7126
7127		p = delimptr;
7128	}
7129
7130#if !HASNICE
7131	if (qg->qg_nice != NiceQueueRun)
7132	{
7133		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7134				     "Q%s: Warning: N= set on system that doesn't support nice()\n",
7135				     qg->qg_name);
7136	}
7137#endif /* !HASNICE */
7138
7139	/* do some rationality checking */
7140	if (NumQueue >= MAXQUEUEGROUPS)
7141	{
7142		syserr("too many queue groups defined (%d max)",
7143			MAXQUEUEGROUPS);
7144		return;
7145	}
7146
7147	if (qg->qg_qdir == NULL)
7148	{
7149		if (QueueDir == NULL || *QueueDir == '\0')
7150		{
7151			syserr("QueueDir must be defined before queue groups");
7152			return;
7153		}
7154		qg->qg_qdir = newstr(QueueDir);
7155	}
7156
7157	if (qg->qg_maxqrun > 1 && !bitnset(QD_FORK, qg->qg_flags))
7158	{
7159		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7160				     "Warning: Q=%s: R=%d: multiple queue runners specified\n\tbut flag '%c' is not set\n",
7161				     qg->qg_name, qg->qg_maxqrun, QD_FORK);
7162	}
7163
7164	/* enter the queue into the symbol table */
7165	if (tTd(37, 8))
7166		sm_syslog(LOG_INFO, NOQID,
7167			  "Adding %s to stab, path: %s", qg->qg_name,
7168			  qg->qg_qdir);
7169	s = stab(qg->qg_name, ST_QUEUE, ST_ENTER);
7170	if (s->s_quegrp != NULL)
7171	{
7172		i = s->s_quegrp->qg_index;
7173
7174		/* XXX what about the pointers inside this struct? */
7175		sm_free(s->s_quegrp); /* XXX */
7176	}
7177	else
7178		i = NumQueue++;
7179	Queue[i] = s->s_quegrp = qg;
7180	qg->qg_index = i;
7181
7182	/* set default value for max queue runners */
7183	if (qg->qg_maxqrun < 0)
7184	{
7185		if (MaxRunnersPerQueue > 0)
7186			qg->qg_maxqrun = MaxRunnersPerQueue;
7187		else
7188			qg->qg_maxqrun = 1;
7189	}
7190	if (qdef)
7191		setbitn(QD_DEFINED, qg->qg_flags);
7192}
7193#if 0
7194/*
7195**  HASHFQN -- calculate a hash value for a fully qualified host name
7196**
7197**	Arguments:
7198**		fqn -- an all lower-case host.domain string
7199**		buckets -- the number of buckets (queue directories)
7200**
7201**	Returns:
7202**		a bucket number (signed integer)
7203**		-1 on error
7204**
7205**	Contributed by Exactis.com, Inc.
7206*/
7207
7208int
7209hashfqn(fqn, buckets)
7210	register char *fqn;
7211	int buckets;
7212{
7213	register char *p;
7214	register int h = 0, hash, cnt;
7215
7216	if (fqn == NULL)
7217		return -1;
7218
7219	/*
7220	**  A variation on the gdb hash
7221	**  This is the best as of Feb 19, 1996 --bcx
7222	*/
7223
7224	p = fqn;
7225	h = 0x238F13AF * strlen(p);
7226	for (cnt = 0; *p != 0; ++p, cnt++)
7227	{
7228		h = (h + (*p << (cnt * 5 % 24))) & 0x7FFFFFFF;
7229	}
7230	h = (1103515243 * h + 12345) & 0x7FFFFFFF;
7231	if (buckets < 2)
7232		hash = 0;
7233	else
7234		hash = (h % buckets);
7235
7236	return hash;
7237}
7238#endif /* 0 */
7239
7240#if _FFR_QUEUEDELAY
7241/*
7242**  QUEUEDELAY -- compute queue delay time
7243**
7244**	Parameters:
7245**		e -- the envelope to queue up.
7246**
7247**	Returns:
7248**		queue delay time
7249**
7250**	Side Effects:
7251**		may change e_queuedelay
7252*/
7253
7254static time_t
7255queuedelay(e)
7256	ENVELOPE *e;
7257{
7258	time_t qd;
7259
7260	if (e->e_queuealg == QD_EXP)
7261	{
7262		if (e->e_queuedelay == 0)
7263			e->e_queuedelay = QueueInitDelay;
7264		else
7265		{
7266			e->e_queuedelay *= 2;
7267			if (e->e_queuedelay > QueueMaxDelay)
7268				e->e_queuedelay = QueueMaxDelay;
7269		}
7270		qd = e->e_queuedelay;
7271	}
7272	else
7273		qd = MinQueueAge;
7274	return qd;
7275}
7276#endif /* _FFR_QUEUEDELAY */
7277
7278/*
7279**  A structure for sorting Queue according to maxqrun without
7280**	screwing up Queue itself.
7281*/
7282
7283struct sortqgrp
7284{
7285	int sg_idx;		/* original index */
7286	int sg_maxqrun;		/* max queue runners */
7287};
7288typedef struct sortqgrp	SORTQGRP_T;
7289static int cmpidx __P((const void *, const void *));
7290
7291static int
7292cmpidx(a, b)
7293	const void *a;
7294	const void *b;
7295{
7296	/* The sort is highest to lowest, so the comparison is reversed */
7297	if (((SORTQGRP_T *)a)->sg_maxqrun < ((SORTQGRP_T *)b)->sg_maxqrun)
7298		return 1;
7299	else if (((SORTQGRP_T *)a)->sg_maxqrun > ((SORTQGRP_T *)b)->sg_maxqrun)
7300		return -1;
7301	else
7302		return 0;
7303}
7304
7305/*
7306**  MAKEWORKGROUP -- balance queue groups into work groups per MaxQueueChildren
7307**
7308**  Take the now defined queue groups and assign them to work groups.
7309**  This is done to balance out the number of concurrently active
7310**  queue runners such that MaxQueueChildren is not exceeded. This may
7311**  result in more than one queue group per work group. In such a case
7312**  the number of running queue groups in that work group will have no
7313**  more than the work group maximum number of runners (a "fair" portion
7314**  of MaxQueueRunners). All queue groups within a work group will get a
7315**  chance at running.
7316**
7317**	Parameters:
7318**		none.
7319**
7320**	Returns:
7321**		nothing.
7322**
7323**	Side Effects:
7324**		Sets up WorkGrp structure.
7325*/
7326
7327void
7328makeworkgroups()
7329{
7330	int i, j, total_runners = 0;
7331	int dir;
7332	SORTQGRP_T si[MAXQUEUEGROUPS + 1];
7333
7334	if (NumQueue == 1 && strcmp(Queue[0]->qg_name, "mqueue") == 0)
7335	{
7336		/*
7337		**  There is only the "mqueue" queue group (a default)
7338		**  containing all of the queues. We want to provide to
7339		**  this queue group the maximum allowable queue runners.
7340		**  To match older behavior (8.10/8.11) we'll try for
7341		**  1 runner per queue capping it at MaxQueueChildren.
7342		**  So if there are N queues, then there will be N runners
7343		**  for the "mqueue" queue group (where N is kept less than
7344		**  MaxQueueChildren).
7345		*/
7346
7347		NumWorkGroups = 1;
7348		WorkGrp[0].wg_numqgrp = 1;
7349		WorkGrp[0].wg_qgs = (QUEUEGRP **) xalloc(sizeof(QUEUEGRP *));
7350		WorkGrp[0].wg_qgs[0] = Queue[0];
7351		if (MaxQueueChildren > 0 &&
7352		    Queue[0]->qg_numqueues > MaxQueueChildren)
7353			WorkGrp[0].wg_runners = MaxQueueChildren;
7354		else
7355			WorkGrp[0].wg_runners = Queue[0]->qg_numqueues;
7356
7357		Queue[0]->qg_wgrp = 0;
7358
7359		/* can't have more runners than allowed total */
7360		if (MaxQueueChildren > 0 &&
7361		    Queue[0]->qg_maxqrun > MaxQueueChildren)
7362			Queue[0]->qg_maxqrun = MaxQueueChildren;
7363		WorkGrp[0].wg_maxact = Queue[0]->qg_maxqrun;
7364		WorkGrp[0].wg_lowqintvl = Queue[0]->qg_queueintvl;
7365		return;
7366	}
7367
7368	for (i = 0; i < NumQueue; i++)
7369	{
7370		si[i].sg_maxqrun = Queue[i]->qg_maxqrun;
7371		si[i].sg_idx = i;
7372	}
7373	qsort(si, NumQueue, sizeof(si[0]), cmpidx);
7374
7375	NumWorkGroups = 0;
7376	for (i = 0; i < NumQueue; i++)
7377	{
7378		total_runners += si[i].sg_maxqrun;
7379		if (MaxQueueChildren <= 0 || total_runners <= MaxQueueChildren)
7380			NumWorkGroups++;
7381		else
7382			break;
7383	}
7384
7385	if (NumWorkGroups < 1)
7386		NumWorkGroups = 1; /* gotta have one at least */
7387	else if (NumWorkGroups > MAXWORKGROUPS)
7388		NumWorkGroups = MAXWORKGROUPS; /* the limit */
7389
7390	/*
7391	**  We now know the number of work groups to pack the queue groups
7392	**  into. The queue groups in 'Queue' are sorted from highest
7393	**  to lowest for the number of runners per queue group.
7394	**  We put the queue groups with the largest number of runners
7395	**  into work groups first. Then the smaller ones are fitted in
7396	**  where it looks best.
7397	*/
7398
7399	j = 0;
7400	dir = 1;
7401	for (i = 0; i < NumQueue; i++)
7402	{
7403		/* a to-and-fro packing scheme, continue from last position */
7404		if (j >= NumWorkGroups)
7405		{
7406			dir = -1;
7407			j = NumWorkGroups - 1;
7408		}
7409		else if (j < 0)
7410		{
7411			j = 0;
7412			dir = 1;
7413		}
7414
7415		if (WorkGrp[j].wg_qgs == NULL)
7416			WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_malloc(sizeof(QUEUEGRP *) *
7417							(WorkGrp[j].wg_numqgrp + 1));
7418		else
7419			WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_realloc(WorkGrp[j].wg_qgs,
7420							sizeof(QUEUEGRP *) *
7421							(WorkGrp[j].wg_numqgrp + 1));
7422		if (WorkGrp[j].wg_qgs == NULL)
7423		{
7424			syserr("!cannot allocate memory for work queues, need %d bytes",
7425			       (int) (sizeof(QUEUEGRP *) *
7426				      (WorkGrp[j].wg_numqgrp + 1)));
7427		}
7428
7429		WorkGrp[j].wg_qgs[WorkGrp[j].wg_numqgrp] = Queue[si[i].sg_idx];
7430		WorkGrp[j].wg_numqgrp++;
7431		WorkGrp[j].wg_runners += Queue[i]->qg_maxqrun;
7432		Queue[si[i].sg_idx]->qg_wgrp = j;
7433
7434		if (WorkGrp[j].wg_maxact == 0)
7435		{
7436			/* can't have more runners than allowed total */
7437			if (MaxQueueChildren > 0 &&
7438			    Queue[i]->qg_maxqrun > MaxQueueChildren)
7439				Queue[i]->qg_maxqrun = MaxQueueChildren;
7440			WorkGrp[j].wg_maxact = Queue[i]->qg_maxqrun;
7441		}
7442
7443		/*
7444		**  XXX: must wg_lowqintvl be the GCD?
7445		**  qg1: 2m, qg2: 3m, minimum: 2m, when do queue runs for
7446		**  qg2 occur?
7447		*/
7448
7449		/* keep track of the lowest interval for a persistent runner */
7450		if (Queue[si[i].sg_idx]->qg_queueintvl > 0 &&
7451		    WorkGrp[j].wg_lowqintvl < Queue[si[i].sg_idx]->qg_queueintvl)
7452			WorkGrp[j].wg_lowqintvl = Queue[si[i].sg_idx]->qg_queueintvl;
7453		j += dir;
7454	}
7455	if (tTd(41, 9))
7456	{
7457		for (i = 0; i < NumWorkGroups; i++)
7458		{
7459			sm_dprintf("Workgroup[%d]=", i);
7460			for (j = 0; j < WorkGrp[i].wg_numqgrp; j++)
7461			{
7462				sm_dprintf("%s, ",
7463					WorkGrp[i].wg_qgs[j]->qg_name);
7464			}
7465			sm_dprintf("\n");
7466		}
7467	}
7468}
7469
7470/*
7471**  DUP_DF -- duplicate envelope data file
7472**
7473**	Copy the data file from the 'old' envelope to the 'new' envelope
7474**	in the most efficient way possible.
7475**
7476**	Create a hard link from the 'old' data file to the 'new' data file.
7477**	If the old and new queue directories are on different file systems,
7478**	then the new data file link is created in the old queue directory,
7479**	and the new queue file will contain a 'd' record pointing to the
7480**	directory containing the new data file.
7481**
7482**	Parameters:
7483**		old -- old envelope.
7484**		new -- new envelope.
7485**
7486**	Results:
7487**		Returns true on success, false on failure.
7488**
7489**	Side Effects:
7490**		On success, the new data file is created.
7491**		On fatal failure, EF_FATALERRS is set in old->e_flags.
7492*/
7493
7494static bool	dup_df __P((ENVELOPE *, ENVELOPE *));
7495
7496static bool
7497dup_df(old, new)
7498	ENVELOPE *old;
7499	ENVELOPE *new;
7500{
7501	int ofs, nfs, r;
7502	char opath[MAXPATHLEN];
7503	char npath[MAXPATHLEN];
7504
7505	if (!bitset(EF_HAS_DF, old->e_flags))
7506	{
7507		/*
7508		**  this can happen if: SuperSafe != True
7509		**  and a bounce mail is sent that is split.
7510		*/
7511
7512		queueup(old, false, true);
7513	}
7514	SM_REQUIRE(ISVALIDQGRP(old->e_qgrp) && ISVALIDQDIR(old->e_qdir));
7515	SM_REQUIRE(ISVALIDQGRP(new->e_qgrp) && ISVALIDQDIR(new->e_qdir));
7516
7517	(void) sm_strlcpy(opath, queuename(old, DATAFL_LETTER), sizeof opath);
7518	(void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof npath);
7519
7520	if (old->e_dfp != NULL)
7521	{
7522		r = sm_io_setinfo(old->e_dfp, SM_BF_COMMIT, NULL);
7523		if (r < 0 && errno != EINVAL)
7524		{
7525			syserr("@can't commit %s", opath);
7526			old->e_flags |= EF_FATALERRS;
7527			return false;
7528		}
7529	}
7530
7531	/*
7532	**  Attempt to create a hard link, if we think both old and new
7533	**  are on the same file system, otherwise copy the file.
7534	**
7535	**  Don't waste time attempting a hard link unless old and new
7536	**  are on the same file system.
7537	*/
7538
7539	ofs = Queue[old->e_qgrp]->qg_qpaths[old->e_qdir].qp_fsysidx;
7540	nfs = Queue[new->e_qgrp]->qg_qpaths[new->e_qdir].qp_fsysidx;
7541	if (FILE_SYS_DEV(ofs) == FILE_SYS_DEV(nfs))
7542	{
7543		if (link(opath, npath) == 0)
7544		{
7545			new->e_flags |= EF_HAS_DF;
7546			SYNC_DIR(npath, true);
7547			return true;
7548		}
7549		goto error;
7550	}
7551
7552	/*
7553	**  Can't link across queue directories, so try to create a hard
7554	**  link in the same queue directory as the old df file.
7555	**  The qf file will refer to the new df file using a 'd' record.
7556	*/
7557
7558	new->e_dfqgrp = old->e_dfqgrp;
7559	new->e_dfqdir = old->e_dfqdir;
7560	(void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof npath);
7561	if (link(opath, npath) == 0)
7562	{
7563		new->e_flags |= EF_HAS_DF;
7564		SYNC_DIR(npath, true);
7565		return true;
7566	}
7567
7568  error:
7569	if (LogLevel > 0)
7570		sm_syslog(LOG_ERR, old->e_id,
7571			  "dup_df: can't link %s to %s, error=%s, envelope splitting failed",
7572			  opath, npath, sm_errstring(errno));
7573	return false;
7574}
7575
7576/*
7577**  SPLIT_ENV -- Allocate a new envelope based on a given envelope.
7578**
7579**	Parameters:
7580**		e -- envelope.
7581**		sendqueue -- sendqueue for new envelope.
7582**		qgrp -- index of queue group.
7583**		qdir -- queue directory.
7584**
7585**	Results:
7586**		new envelope.
7587**
7588*/
7589
7590static ENVELOPE	*split_env __P((ENVELOPE *, ADDRESS *, int, int));
7591
7592static ENVELOPE *
7593split_env(e, sendqueue, qgrp, qdir)
7594	ENVELOPE *e;
7595	ADDRESS *sendqueue;
7596	int qgrp;
7597	int qdir;
7598{
7599	ENVELOPE *ee;
7600
7601	ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool, sizeof *ee);
7602	STRUCTCOPY(*e, *ee);
7603	ee->e_message = NULL;	/* XXX use original message? */
7604	ee->e_id = NULL;
7605	assign_queueid(ee);
7606	ee->e_sendqueue = sendqueue;
7607	ee->e_flags &= ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS
7608			 |EF_SENDRECEIPT|EF_RET_PARAM|EF_HAS_DF);
7609	ee->e_flags |= EF_NORECEIPT;	/* XXX really? */
7610	ee->e_from.q_state = QS_SENDER;
7611	ee->e_dfp = NULL;
7612	ee->e_lockfp = NULL;
7613	if (e->e_xfp != NULL)
7614		ee->e_xfp = sm_io_dup(e->e_xfp);
7615
7616	/* failed to dup e->e_xfp, start a new transcript */
7617	if (ee->e_xfp == NULL)
7618		openxscript(ee);
7619
7620	ee->e_qgrp = ee->e_dfqgrp = qgrp;
7621	ee->e_qdir = ee->e_dfqdir = qdir;
7622	ee->e_errormode = EM_MAIL;
7623	ee->e_statmsg = NULL;
7624#if _FFR_QUARANTINE
7625	if (e->e_quarmsg != NULL)
7626		ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool,
7627						  e->e_quarmsg);
7628#endif /* _FFR_QUARANTINE */
7629
7630	/*
7631	**  XXX Not sure if this copying is necessary.
7632	**  sendall() does this copying, but I (dm) don't know if that is
7633	**  because of the storage management discipline we were using
7634	**  before rpools were introduced, or if it is because these lists
7635	**  can be modified later.
7636	*/
7637
7638	ee->e_header = copyheader(e->e_header, ee->e_rpool);
7639	ee->e_errorqueue = copyqueue(e->e_errorqueue, ee->e_rpool);
7640
7641	return ee;
7642}
7643
7644/* return values from split functions, check also below! */
7645#define SM_SPLIT_FAIL	(0)
7646#define SM_SPLIT_NONE	(1)
7647#define SM_SPLIT_NEW(n)	(1 + (n))
7648
7649/*
7650**  SPLIT_ACROSS_QUEUE_GROUPS
7651**
7652**	This function splits an envelope across multiple queue groups
7653**	based on the queue group of each recipient.
7654**
7655**	Parameters:
7656**		e -- envelope.
7657**
7658**	Results:
7659**		SM_SPLIT_FAIL on failure
7660**		SM_SPLIT_NONE if no splitting occurred,
7661**		or 1 + the number of additional envelopes created.
7662**
7663**	Side Effects:
7664**		On success, e->e_sibling points to a list of zero or more
7665**		additional envelopes, and the associated data files exist
7666**		on disk.  But the queue files are not created.
7667**
7668**		On failure, e->e_sibling is not changed.
7669**		The order of recipients in e->e_sendqueue is permuted.
7670**		Abandoned data files for additional envelopes that failed
7671**		to be created may exist on disk.
7672*/
7673
7674static int	q_qgrp_compare __P((const void *, const void *));
7675static int	e_filesys_compare __P((const void *, const void *));
7676
7677static int
7678q_qgrp_compare(p1, p2)
7679	const void *p1;
7680	const void *p2;
7681{
7682	ADDRESS **pq1 = (ADDRESS **) p1;
7683	ADDRESS **pq2 = (ADDRESS **) p2;
7684
7685	return (*pq1)->q_qgrp - (*pq2)->q_qgrp;
7686}
7687
7688static int
7689e_filesys_compare(p1, p2)
7690	const void *p1;
7691	const void *p2;
7692{
7693	ENVELOPE **pe1 = (ENVELOPE **) p1;
7694	ENVELOPE **pe2 = (ENVELOPE **) p2;
7695	int fs1, fs2;
7696
7697	fs1 = Queue[(*pe1)->e_qgrp]->qg_qpaths[(*pe1)->e_qdir].qp_fsysidx;
7698	fs2 = Queue[(*pe2)->e_qgrp]->qg_qpaths[(*pe2)->e_qdir].qp_fsysidx;
7699	if (FILE_SYS_DEV(fs1) < FILE_SYS_DEV(fs2))
7700		return -1;
7701	if (FILE_SYS_DEV(fs1) > FILE_SYS_DEV(fs2))
7702		return 1;
7703	return 0;
7704}
7705
7706static int
7707split_across_queue_groups(e)
7708	ENVELOPE *e;
7709{
7710	int naddrs, nsplits, i;
7711	bool changed;
7712	char **pvp;
7713	ADDRESS *q, **addrs;
7714	ENVELOPE *ee, *es;
7715	ENVELOPE *splits[MAXQUEUEGROUPS];
7716	char pvpbuf[PSBUFSIZE];
7717
7718	SM_REQUIRE(ISVALIDQGRP(e->e_qgrp));
7719
7720	/* Count addresses and assign queue groups. */
7721	naddrs = 0;
7722	changed = false;
7723	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
7724	{
7725		if (QS_IS_DEAD(q->q_state))
7726			continue;
7727		++naddrs;
7728
7729		/* bad addresses and those already sent stay put */
7730		if (QS_IS_BADADDR(q->q_state) ||
7731		    QS_IS_SENT(q->q_state))
7732			q->q_qgrp = e->e_qgrp;
7733		else if (!ISVALIDQGRP(q->q_qgrp))
7734		{
7735			/* call ruleset which should return a queue group */
7736			i = rscap(RS_QUEUEGROUP, q->q_user, NULL, e, &pvp,
7737				  pvpbuf, sizeof(pvpbuf));
7738			if (i == EX_OK &&
7739			    pvp != NULL && pvp[0] != NULL &&
7740			    (pvp[0][0] & 0377) == CANONNET &&
7741			    pvp[1] != NULL && pvp[1][0] != '\0')
7742			{
7743				i = name2qid(pvp[1]);
7744				if (ISVALIDQGRP(i))
7745				{
7746					q->q_qgrp = i;
7747					changed = true;
7748					if (tTd(20, 4))
7749						sm_syslog(LOG_INFO, NOQID,
7750							"queue group name %s -> %d",
7751							pvp[1], i);
7752					continue;
7753				}
7754				else if (LogLevel > 10)
7755					sm_syslog(LOG_INFO, NOQID,
7756						"can't find queue group name %s, selection ignored",
7757						pvp[1]);
7758			}
7759			if (q->q_mailer != NULL &&
7760			    ISVALIDQGRP(q->q_mailer->m_qgrp))
7761			{
7762				changed = true;
7763				q->q_qgrp = q->q_mailer->m_qgrp;
7764			}
7765			else if (ISVALIDQGRP(e->e_qgrp))
7766				q->q_qgrp = e->e_qgrp;
7767			else
7768				q->q_qgrp = 0;
7769		}
7770	}
7771
7772	/* only one address? nothing to split. */
7773	if (naddrs <= 1 && !changed)
7774		return SM_SPLIT_NONE;
7775
7776	/* sort the addresses by queue group */
7777	addrs = sm_rpool_malloc_x(e->e_rpool, naddrs * sizeof(ADDRESS *));
7778	for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next)
7779	{
7780		if (QS_IS_DEAD(q->q_state))
7781			continue;
7782		addrs[i++] = q;
7783	}
7784	qsort(addrs, naddrs, sizeof(ADDRESS *), q_qgrp_compare);
7785
7786	/* split into multiple envelopes, by queue group */
7787	nsplits = 0;
7788	es = NULL;
7789	e->e_sendqueue = NULL;
7790	for (i = 0; i < naddrs; ++i)
7791	{
7792		if (i == naddrs - 1 || addrs[i]->q_qgrp != addrs[i + 1]->q_qgrp)
7793			addrs[i]->q_next = NULL;
7794		else
7795			addrs[i]->q_next = addrs[i + 1];
7796
7797		/* same queue group as original envelope? */
7798		if (addrs[i]->q_qgrp == e->e_qgrp)
7799		{
7800			if (e->e_sendqueue == NULL)
7801				e->e_sendqueue = addrs[i];
7802			continue;
7803		}
7804
7805		/* different queue group than original envelope */
7806		if (es == NULL || addrs[i]->q_qgrp != es->e_qgrp)
7807		{
7808			ee = split_env(e, addrs[i], addrs[i]->q_qgrp, NOQDIR);
7809			es = ee;
7810			splits[nsplits++] = ee;
7811		}
7812	}
7813
7814	/* no splits? return right now. */
7815	if (nsplits <= 0)
7816		return SM_SPLIT_NONE;
7817
7818	/* assign a queue directory to each additional envelope */
7819	for (i = 0; i < nsplits; ++i)
7820	{
7821		es = splits[i];
7822#if 0
7823		es->e_qdir = pickqdir(Queue[es->e_qgrp], es->e_msgsize, es);
7824#endif /* 0 */
7825		if (!setnewqueue(es))
7826			goto failure;
7827	}
7828
7829	/* sort the additional envelopes by queue file system */
7830	qsort(splits, nsplits, sizeof(ENVELOPE *), e_filesys_compare);
7831
7832	/* create data files for each additional envelope */
7833	if (!dup_df(e, splits[0]))
7834	{
7835		i = 0;
7836		goto failure;
7837	}
7838	for (i = 1; i < nsplits; ++i)
7839	{
7840		/* copy or link to the previous data file */
7841		if (!dup_df(splits[i - 1], splits[i]))
7842			goto failure;
7843	}
7844
7845	/* success: prepend the new envelopes to the e->e_sibling list */
7846	for (i = 0; i < nsplits; ++i)
7847	{
7848		es = splits[i];
7849		es->e_sibling = e->e_sibling;
7850		e->e_sibling = es;
7851	}
7852	return SM_SPLIT_NEW(nsplits);
7853
7854	/* failure: clean up */
7855  failure:
7856	if (i > 0)
7857	{
7858		int j;
7859
7860		for (j = 0; j < i; j++)
7861			(void) unlink(queuename(splits[j], DATAFL_LETTER));
7862	}
7863	e->e_sendqueue = addrs[0];
7864	for (i = 0; i < naddrs - 1; ++i)
7865		addrs[i]->q_next = addrs[i + 1];
7866	addrs[naddrs - 1]->q_next = NULL;
7867	return SM_SPLIT_FAIL;
7868}
7869
7870/*
7871**  SPLIT_WITHIN_QUEUE
7872**
7873**	Split an envelope with multiple recipients into several
7874**	envelopes within the same queue directory, if the number of
7875**	recipients exceeds the limit for the queue group.
7876**
7877**	Parameters:
7878**		e -- envelope.
7879**
7880**	Results:
7881**		SM_SPLIT_FAIL on failure
7882**		SM_SPLIT_NONE if no splitting occurred,
7883**		or 1 + the number of additional envelopes created.
7884*/
7885
7886#define SPLIT_LOG_LEVEL	8
7887
7888static int	split_within_queue __P((ENVELOPE *));
7889
7890static int
7891split_within_queue(e)
7892	ENVELOPE *e;
7893{
7894	int maxrcpt, nrcpt, ndead, nsplit, i;
7895	int j, l;
7896	char *lsplits;
7897	ADDRESS *q, **addrs;
7898	ENVELOPE *ee, *firstsibling;
7899
7900	if (!ISVALIDQGRP(e->e_qgrp) || bitset(EF_SPLIT, e->e_flags))
7901		return SM_SPLIT_NONE;
7902
7903	/* don't bother if there is no recipient limit */
7904	maxrcpt = Queue[e->e_qgrp]->qg_maxrcpt;
7905	if (maxrcpt <= 0)
7906		return SM_SPLIT_NONE;
7907
7908	/* count recipients */
7909	nrcpt = 0;
7910	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
7911	{
7912		if (QS_IS_DEAD(q->q_state))
7913			continue;
7914		++nrcpt;
7915	}
7916	if (nrcpt <= maxrcpt)
7917		return SM_SPLIT_NONE;
7918
7919	/*
7920	**  Preserve the recipient list
7921	**  so that we can restore it in case of error.
7922	**  (But we discard dead addresses.)
7923	*/
7924
7925	addrs = sm_rpool_malloc_x(e->e_rpool, nrcpt * sizeof(ADDRESS *));
7926	for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next)
7927	{
7928		if (QS_IS_DEAD(q->q_state))
7929			continue;
7930		addrs[i++] = q;
7931	}
7932
7933	/*
7934	**  Partition the recipient list so that bad and sent addresses
7935	**  come first. These will go with the original envelope, and
7936	**  do not count towards the maxrcpt limit.
7937	**  addrs[] does not contain QS_IS_DEAD() addresses.
7938	*/
7939
7940	ndead = 0;
7941	for (i = 0; i < nrcpt; ++i)
7942	{
7943		if (QS_IS_BADADDR(addrs[i]->q_state) ||
7944		    QS_IS_SENT(addrs[i]->q_state) ||
7945		    QS_IS_DEAD(addrs[i]->q_state)) /* for paranoia's sake */
7946		{
7947			if (i > ndead)
7948			{
7949				ADDRESS *tmp = addrs[i];
7950
7951				addrs[i] = addrs[ndead];
7952				addrs[ndead] = tmp;
7953			}
7954			++ndead;
7955		}
7956	}
7957
7958	/* Check if no splitting required. */
7959	if (nrcpt - ndead <= maxrcpt)
7960		return SM_SPLIT_NONE;
7961
7962	/* fix links */
7963	for (i = 0; i < nrcpt - 1; ++i)
7964		addrs[i]->q_next = addrs[i + 1];
7965	addrs[nrcpt - 1]->q_next = NULL;
7966	e->e_sendqueue = addrs[0];
7967
7968	/* prepare buffer for logging */
7969	if (LogLevel > SPLIT_LOG_LEVEL)
7970	{
7971		l = MAXLINE;
7972		lsplits = sm_malloc(l);
7973		if (lsplits != NULL)
7974			*lsplits = '\0';
7975		j = 0;
7976	}
7977	else
7978	{
7979		/* get rid of stupid compiler warnings */
7980		lsplits = NULL;
7981		j = l = 0;
7982	}
7983
7984	/* split the envelope */
7985	firstsibling = e->e_sibling;
7986	i = maxrcpt + ndead;
7987	nsplit = 0;
7988	for (;;)
7989	{
7990		addrs[i - 1]->q_next = NULL;
7991		ee = split_env(e, addrs[i], e->e_qgrp, e->e_qdir);
7992		if (!dup_df(e, ee))
7993		{
7994
7995			ee = firstsibling;
7996			while (ee != NULL)
7997			{
7998				(void) unlink(queuename(ee, DATAFL_LETTER));
7999				ee = ee->e_sibling;
8000			}
8001
8002			/* Error.  Restore e's sibling & recipient lists. */
8003			e->e_sibling = firstsibling;
8004			for (i = 0; i < nrcpt - 1; ++i)
8005				addrs[i]->q_next = addrs[i + 1];
8006			if (lsplits != NULL)
8007				sm_free(lsplits);
8008			return SM_SPLIT_FAIL;
8009		}
8010
8011		/* prepend the new envelope to e->e_sibling */
8012		ee->e_sibling = e->e_sibling;
8013		e->e_sibling = ee;
8014		++nsplit;
8015		if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
8016		{
8017			if (j >= l - strlen(ee->e_id) - 3)
8018			{
8019				char *p;
8020
8021				l += MAXLINE;
8022				p = sm_realloc(lsplits, l);
8023				if (p == NULL)
8024				{
8025					/* let's try to get this done */
8026					sm_free(lsplits);
8027					lsplits = NULL;
8028				}
8029				else
8030					lsplits = p;
8031			}
8032			if (lsplits != NULL)
8033			{
8034				if (j == 0)
8035					j += sm_strlcat(lsplits + j,
8036							ee->e_id,
8037							l - j);
8038				else
8039					j += sm_strlcat2(lsplits + j,
8040							 "; ",
8041							 ee->e_id,
8042							 l - j);
8043				SM_ASSERT(j < l);
8044			}
8045		}
8046		if (nrcpt - i <= maxrcpt)
8047			break;
8048		i += maxrcpt;
8049	}
8050	if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
8051	{
8052		if (nsplit > 0)
8053		{
8054			sm_syslog(LOG_NOTICE, e->e_id,
8055				  "split: maxrcpts=%d, rcpts=%d, count=%d, id%s=%s",
8056				  maxrcpt, nrcpt - ndead, nsplit,
8057				  nsplit > 1 ? "s" : "", lsplits);
8058		}
8059		sm_free(lsplits);
8060	}
8061	return SM_SPLIT_NEW(nsplit);
8062}
8063/*
8064**  SPLIT_BY_RECIPIENT
8065**
8066**	Split an envelope with multiple recipients into multiple
8067**	envelopes as required by the sendmail configuration.
8068**
8069**	Parameters:
8070**		e -- envelope.
8071**
8072**	Results:
8073**		Returns true on success, false on failure.
8074**
8075**	Side Effects:
8076**		see split_across_queue_groups(), split_within_queue(e)
8077*/
8078
8079bool
8080split_by_recipient(e)
8081	ENVELOPE *e;
8082{
8083	int split, n, i, j, l;
8084	char *lsplits;
8085	ENVELOPE *ee, *next, *firstsibling;
8086
8087	if (OpMode == SM_VERIFY || !ISVALIDQGRP(e->e_qgrp) ||
8088	    bitset(EF_SPLIT, e->e_flags))
8089		return true;
8090	n = split_across_queue_groups(e);
8091	if (n == SM_SPLIT_FAIL)
8092		return false;
8093	firstsibling = ee = e->e_sibling;
8094	if (n > 1 && LogLevel > SPLIT_LOG_LEVEL)
8095	{
8096		l = MAXLINE;
8097		lsplits = sm_malloc(l);
8098		if (lsplits != NULL)
8099			*lsplits = '\0';
8100		j = 0;
8101	}
8102	else
8103	{
8104		/* get rid of stupid compiler warnings */
8105		lsplits = NULL;
8106		j = l = 0;
8107	}
8108	for (i = 1; i < n; ++i)
8109	{
8110		next = ee->e_sibling;
8111		if (split_within_queue(ee) == SM_SPLIT_FAIL)
8112		{
8113			e->e_sibling = firstsibling;
8114			return false;
8115		}
8116		ee->e_flags |= EF_SPLIT;
8117		if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
8118		{
8119			if (j >= l - strlen(ee->e_id) - 3)
8120			{
8121				char *p;
8122
8123				l += MAXLINE;
8124				p = sm_realloc(lsplits, l);
8125				if (p == NULL)
8126				{
8127					/* let's try to get this done */
8128					sm_free(lsplits);
8129					lsplits = NULL;
8130				}
8131				else
8132					lsplits = p;
8133			}
8134			if (lsplits != NULL)
8135			{
8136				if (j == 0)
8137					j += sm_strlcat(lsplits + j,
8138							ee->e_id, l - j);
8139				else
8140					j += sm_strlcat2(lsplits + j, "; ",
8141							 ee->e_id, l - j);
8142				SM_ASSERT(j < l);
8143			}
8144		}
8145		ee = next;
8146	}
8147	if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL && n > 1)
8148	{
8149		sm_syslog(LOG_NOTICE, e->e_id, "split: count=%d, id%s=%s",
8150			  n - 1, n > 2 ? "s" : "", lsplits);
8151		sm_free(lsplits);
8152	}
8153	split = split_within_queue(e) != SM_SPLIT_FAIL;
8154	if (split)
8155		e->e_flags |= EF_SPLIT;
8156	return split;
8157}
8158
8159#if _FFR_QUARANTINE
8160/*
8161**  QUARANTINE_QUEUE_ITEM -- {un,}quarantine a single envelope
8162**
8163**	Add/remove quarantine reason and requeue appropriately.
8164**
8165**	Parameters:
8166**		qgrp -- queue group for the item
8167**		qdir -- queue directory in the given queue group
8168**		e -- envelope information for the item
8169**		reason -- quarantine reason, NULL means unquarantine.
8170**
8171**	Results:
8172**		true if item changed, false otherwise
8173**
8174**	Side Effects:
8175**		Changes quarantine tag in queue file and renames it.
8176*/
8177
8178static bool
8179quarantine_queue_item(qgrp, qdir, e, reason)
8180	int qgrp;
8181	int qdir;
8182	ENVELOPE *e;
8183	char *reason;
8184{
8185	bool dirty = false;
8186	bool failing = false;
8187	bool foundq = false;
8188	bool finished = false;
8189	int fd;
8190	int flags;
8191	int oldtype;
8192	int newtype;
8193	int save_errno;
8194	MODE_T oldumask = 0;
8195	SM_FILE_T *oldqfp, *tempqfp;
8196	char *bp;
8197	char oldqf[MAXPATHLEN];
8198	char tempqf[MAXPATHLEN];
8199	char newqf[MAXPATHLEN];
8200	char buf[MAXLINE];
8201
8202	oldtype = queue_letter(e, ANYQFL_LETTER);
8203	(void) sm_strlcpy(oldqf, queuename(e, ANYQFL_LETTER), sizeof oldqf);
8204	(void) sm_strlcpy(tempqf, queuename(e, NEWQFL_LETTER), sizeof tempqf);
8205
8206	/*
8207	**  Instead of duplicating all the open
8208	**  and lock code here, tell readqf() to
8209	**  do that work and return the open
8210	**  file pointer in e_lockfp.  Note that
8211	**  we must release the locks properly when
8212	**  we are done.
8213	*/
8214
8215	if (!readqf(e, true))
8216	{
8217		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8218				     "Skipping %s\n", qid_printname(e));
8219		return false;
8220	}
8221	oldqfp = e->e_lockfp;
8222
8223	/* open the new queue file */
8224	flags = O_CREAT|O_WRONLY|O_EXCL;
8225	if (bitset(S_IWGRP, QueueFileMode))
8226		oldumask = umask(002);
8227	fd = open(tempqf, flags, QueueFileMode);
8228	if (bitset(S_IWGRP, QueueFileMode))
8229		(void) umask(oldumask);
8230	RELEASE_QUEUE;
8231
8232	if (fd < 0)
8233	{
8234		save_errno = errno;
8235		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8236				     "Skipping %s: Could not open %s: %s\n",
8237				     qid_printname(e), tempqf,
8238				     sm_errstring(save_errno));
8239		(void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8240		return false;
8241	}
8242	if (!lockfile(fd, tempqf, NULL, LOCK_EX|LOCK_NB))
8243	{
8244		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8245				     "Skipping %s: Could not lock %s\n",
8246				     qid_printname(e), tempqf);
8247		(void) close(fd);
8248		(void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8249		return false;
8250	}
8251
8252	tempqfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &fd,
8253			     SM_IO_WRONLY, NULL);
8254	if (tempqfp == NULL)
8255	{
8256		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8257				     "Skipping %s: Could not lock %s\n",
8258				     qid_printname(e), tempqf);
8259		(void) close(fd);
8260		(void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8261		return false;
8262	}
8263
8264	/* Copy the data over, changing the quarantine reason */
8265	while ((bp = fgetfolded(buf, sizeof buf, oldqfp)) != NULL)
8266	{
8267		if (tTd(40, 4))
8268			sm_dprintf("+++++ %s\n", bp);
8269		switch (bp[0])
8270		{
8271		  case 'q':		/* quarantine reason */
8272			foundq = true;
8273			if (reason == NULL)
8274			{
8275				if (Verbose)
8276				{
8277					(void) sm_io_fprintf(smioout,
8278							     SM_TIME_DEFAULT,
8279							     "%s: Removed quarantine of \"%s\"\n",
8280							     e->e_id, &bp[1]);
8281				}
8282				sm_syslog(LOG_INFO, e->e_id, "unquarantine");
8283				dirty = true;
8284				continue;
8285			}
8286			else if (strcmp(reason, &bp[1]) == 0)
8287			{
8288				if (Verbose)
8289				{
8290					(void) sm_io_fprintf(smioout,
8291							     SM_TIME_DEFAULT,
8292							     "%s: Already quarantined with \"%s\"\n",
8293							     e->e_id, reason);
8294				}
8295				(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8296						     "q%s\n", reason);
8297			}
8298			else
8299			{
8300				if (Verbose)
8301				{
8302					(void) sm_io_fprintf(smioout,
8303							     SM_TIME_DEFAULT,
8304							     "%s: Quarantine changed from \"%s\" to \"%s\"\n",
8305							     e->e_id, &bp[1],
8306							     reason);
8307				}
8308				(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8309						     "q%s\n", reason);
8310				sm_syslog(LOG_INFO, e->e_id, "quarantine=%s",
8311					  reason);
8312				dirty = true;
8313			}
8314			break;
8315
8316		  case 'S':
8317			/*
8318			**  If we are quarantining an unquarantined item,
8319			**  need to put in a new 'q' line before it's
8320			**  too late.
8321			*/
8322
8323			if (!foundq && reason != NULL)
8324			{
8325				if (Verbose)
8326				{
8327					(void) sm_io_fprintf(smioout,
8328							     SM_TIME_DEFAULT,
8329							     "%s: Quarantined with \"%s\"\n",
8330							     e->e_id, reason);
8331				}
8332				(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8333						     "q%s\n", reason);
8334				sm_syslog(LOG_INFO, e->e_id, "quarantine=%s",
8335					  reason);
8336				foundq = true;
8337				dirty = true;
8338			}
8339
8340			/* Copy the line to the new file */
8341			(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8342					     "%s\n", bp);
8343			break;
8344
8345		  case '.':
8346			finished = true;
8347			/* FALLTHROUGH */
8348
8349		  default:
8350			/* Copy the line to the new file */
8351			(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8352					     "%s\n", bp);
8353			break;
8354		}
8355	}
8356
8357	/* Make sure we read the whole old file */
8358	errno = sm_io_error(tempqfp);
8359	if (errno != 0 && errno != SM_IO_EOF)
8360	{
8361		save_errno = errno;
8362		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8363				     "Skipping %s: Error reading %s: %s\n",
8364				     qid_printname(e), oldqf,
8365				     sm_errstring(save_errno));
8366		failing = true;
8367	}
8368
8369	if (!failing && !finished)
8370	{
8371		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8372				     "Skipping %s: Incomplete file: %s\n",
8373				     qid_printname(e), oldqf);
8374		failing = true;
8375	}
8376
8377	/* Check if we actually changed anything or we can just bail now */
8378	if (!dirty)
8379	{
8380		/* pretend we failed, even though we technically didn't */
8381		failing = true;
8382	}
8383
8384	/* Make sure we wrote things out safely */
8385	if (!failing &&
8386	    (sm_io_flush(tempqfp, SM_TIME_DEFAULT) != 0 ||
8387	     ((SuperSafe == SAFE_REALLY || SuperSafe == SAFE_INTERACTIVE) &&
8388	      fsync(sm_io_getinfo(tempqfp, SM_IO_WHAT_FD, NULL)) < 0) ||
8389	     ((errno = sm_io_error(tempqfp)) != 0)))
8390	{
8391		save_errno = errno;
8392		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8393				     "Skipping %s: Error writing %s: %s\n",
8394				     qid_printname(e), tempqf,
8395				     sm_errstring(save_errno));
8396		failing = true;
8397	}
8398
8399
8400	/* Figure out the new filename */
8401	newtype = (reason == NULL ? NORMQF_LETTER : QUARQF_LETTER);
8402	if (oldtype == newtype)
8403	{
8404		/* going to rename tempqf to oldqf */
8405		(void) sm_strlcpy(newqf, oldqf, sizeof newqf);
8406	}
8407	else
8408	{
8409		/* going to rename tempqf to new name based on newtype */
8410		(void) sm_strlcpy(newqf, queuename(e, newtype), sizeof newqf);
8411	}
8412
8413	save_errno = 0;
8414
8415	/* rename tempqf to newqf */
8416	if (!failing &&
8417	    rename(tempqf, newqf) < 0)
8418		save_errno = (errno == 0) ? EINVAL : errno;
8419
8420	/* Check rename() success */
8421	if (!failing && save_errno != 0)
8422	{
8423		sm_syslog(LOG_DEBUG, e->e_id,
8424			  "quarantine_queue_item: rename(%s, %s): %s",
8425			  tempqf, newqf, sm_errstring(save_errno));
8426
8427		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8428				     "Error renaming %s to %s: %s\n",
8429				     tempqf, newqf,
8430				     sm_errstring(save_errno));
8431		if (oldtype == newtype)
8432		{
8433			/*
8434			**  Bail here since we don't know the state of
8435			**  the filesystem and may need to keep tempqf
8436			**  for the user to rescue us.
8437			*/
8438
8439			RELEASE_QUEUE;
8440			errno = save_errno;
8441			syserr("!452 Error renaming control file %s", tempqf);
8442			/* NOTREACHED */
8443		}
8444		else
8445		{
8446			/* remove new file (if rename() half completed) */
8447			if (xunlink(newqf) < 0)
8448			{
8449				save_errno = errno;
8450				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8451						     "Error removing %s: %s\n",
8452						     newqf,
8453						     sm_errstring(save_errno));
8454			}
8455
8456			/* tempqf removed below */
8457			failing = true;
8458		}
8459
8460	}
8461
8462	/* If changing file types, need to remove old type */
8463	if (!failing && oldtype != newtype)
8464	{
8465		if (xunlink(oldqf) < 0)
8466		{
8467			save_errno = errno;
8468			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8469					     "Error removing %s: %s\n",
8470					     oldqf, sm_errstring(save_errno));
8471		}
8472	}
8473
8474	/* see if anything above failed */
8475	if (failing)
8476	{
8477		/* Something failed: remove new file, old file still there */
8478		(void) xunlink(tempqf);
8479	}
8480
8481	/*
8482	**  fsync() after file operations to make sure metadata is
8483	**  written to disk on filesystems in which renames are
8484	**  not guaranteed.  It's ok if they fail, mail won't be lost.
8485	*/
8486
8487	if (SuperSafe != SAFE_NO)
8488	{
8489		/* for soft-updates */
8490		(void) fsync(sm_io_getinfo(tempqfp,
8491					   SM_IO_WHAT_FD, NULL));
8492
8493		if (!failing)
8494		{
8495			/* for soft-updates */
8496			(void) fsync(sm_io_getinfo(oldqfp,
8497						   SM_IO_WHAT_FD, NULL));
8498		}
8499
8500		/* for other odd filesystems */
8501		SYNC_DIR(tempqf, false);
8502	}
8503
8504	/* Close up shop */
8505	RELEASE_QUEUE;
8506	if (tempqfp != NULL)
8507		(void) sm_io_close(tempqfp, SM_TIME_DEFAULT);
8508	if (oldqfp != NULL)
8509		(void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8510
8511	/* All went well */
8512	return !failing;
8513}
8514
8515/*
8516**  QUARANTINE_QUEUE -- {un,}quarantine matching items in the queue
8517**
8518**	Read all matching queue items, add/remove quarantine
8519**	reason, and requeue appropriately.
8520**
8521**	Parameters:
8522**		reason -- quarantine reason, "." means unquarantine.
8523**		qgrplimit -- limit to single queue group unless NOQGRP
8524**
8525**	Results:
8526**		none.
8527**
8528**	Side Effects:
8529**		Lots of changes to the queue.
8530*/
8531
8532void
8533quarantine_queue(reason, qgrplimit)
8534	char *reason;
8535	int qgrplimit;
8536{
8537	int changed = 0;
8538	int qgrp;
8539
8540	/* Convert internal representation of unquarantine */
8541	if (reason != NULL && reason[0] == '.' && reason[1] == '\0')
8542		reason = NULL;
8543
8544	if (reason != NULL)
8545	{
8546		/* clean it */
8547		reason = newstr(denlstring(reason, true, true));
8548	}
8549
8550	for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++)
8551	{
8552		int qdir;
8553
8554		if (qgrplimit != NOQGRP && qgrplimit != qgrp)
8555			continue;
8556
8557		for (qdir = 0; qdir < Queue[qgrp]->qg_numqueues; qdir++)
8558		{
8559			int i;
8560			int nrequests;
8561
8562			if (StopRequest)
8563				stop_sendmail();
8564
8565			nrequests = gatherq(qgrp, qdir, true, NULL, NULL);
8566
8567			/* first see if there is anything */
8568			if (nrequests <= 0)
8569			{
8570				if (Verbose)
8571				{
8572					(void) sm_io_fprintf(smioout,
8573							     SM_TIME_DEFAULT, "%s: no matches\n",
8574							     qid_printqueue(qgrp, qdir));
8575				}
8576				continue;
8577			}
8578
8579			if (Verbose)
8580			{
8581				(void) sm_io_fprintf(smioout,
8582						     SM_TIME_DEFAULT, "Processing %s:\n",
8583						     qid_printqueue(qgrp, qdir));
8584			}
8585
8586			for (i = 0; i < WorkListCount; i++)
8587			{
8588				ENVELOPE e;
8589
8590				if (StopRequest)
8591					stop_sendmail();
8592
8593				/* setup envelope */
8594				clearenvelope(&e, true, sm_rpool_new_x(NULL));
8595				e.e_id = WorkList[i].w_name + 2;
8596				e.e_qgrp = qgrp;
8597				e.e_qdir = qdir;
8598
8599				if (tTd(70, 101))
8600				{
8601					sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8602						      "Would do %s\n", e.e_id);
8603					changed++;
8604				}
8605				else if (quarantine_queue_item(qgrp, qdir,
8606							       &e, reason))
8607					changed++;
8608
8609				/* clean up */
8610				sm_rpool_free(e.e_rpool);
8611				e.e_rpool = NULL;
8612			}
8613			if (WorkList != NULL)
8614				sm_free(WorkList); /* XXX */
8615			WorkList = NULL;
8616			WorkListSize = 0;
8617			WorkListCount = 0;
8618		}
8619	}
8620	if (Verbose)
8621	{
8622		if (changed == 0)
8623			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8624					     "No changes\n");
8625		else
8626			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8627					     "%d change%s\n",
8628					     changed,
8629					     changed == 1 ? "" : "s");
8630	}
8631}
8632#endif /* _FFR_QUARANTINE */
8633