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