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