queue.c revision 141858
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.939 2004/08/03 19:57:23 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(ignore)
2403	int ignore;
2404{
2405	int save_errno = errno;
2406
2407	/*
2408	**  Set the general bit that we want a queue run,
2409	**  tested in doqueuerun()
2410	*/
2411
2412	DoQueueRun = true;
2413#if _FFR_QUEUE_SCHED_DBG
2414	if (tTd(69, 10))
2415		sm_syslog(LOG_INFO, NOQID, "rqe: done");
2416#endif /* _FFR_QUEUE_SCHED_DBG */
2417
2418	errno = save_errno;
2419	if (errno == EINTR)
2420		errno = ETIMEDOUT;
2421}
2422/*
2423**  GATHERQ -- gather messages from the message queue(s) the work queue.
2424**
2425**	Parameters:
2426**		qgrp -- the index of the queue group.
2427**		qdir -- the index of the queue directory.
2428**		doall -- if set, include everything in the queue (even
2429**			the jobs that cannot be run because the load
2430**			average is too high, or MaxQueueRun is reached).
2431**			Otherwise, exclude those jobs.
2432**		full -- (optional) to be set 'true' if WorkList is full
2433**		more -- (optional) to be set 'true' if there are still more
2434**			messages in this queue not added to WorkList
2435**
2436**	Returns:
2437**		The number of request in the queue (not necessarily
2438**		the number of requests in WorkList however).
2439**
2440**	Side Effects:
2441**		prepares available work into WorkList
2442*/
2443
2444#define NEED_P		0001	/* 'P': priority */
2445#define NEED_T		0002	/* 'T': time */
2446#define NEED_R		0004	/* 'R': recipient */
2447#define NEED_S		0010	/* 'S': sender */
2448#define NEED_H		0020	/* host */
2449#define HAS_QUARANTINE	0040	/* has an unexpected 'q' line */
2450#define NEED_QUARANTINE	0100	/* 'q': reason */
2451
2452static WORK	*WorkList = NULL;	/* list of unsort work */
2453static int	WorkListSize = 0;	/* current max size of WorkList */
2454static int	WorkListCount = 0;	/* # of work items in WorkList */
2455
2456static int
2457gatherq(qgrp, qdir, doall, full, more)
2458	int qgrp;
2459	int qdir;
2460	bool doall;
2461	bool *full;
2462	bool *more;
2463{
2464	register struct dirent *d;
2465	register WORK *w;
2466	register char *p;
2467	DIR *f;
2468	int i, num_ent;
2469	int wn;
2470	QUEUE_CHAR *check;
2471	char qd[MAXPATHLEN];
2472	char qf[MAXPATHLEN];
2473
2474	wn = WorkListCount - 1;
2475	num_ent = 0;
2476	if (qdir == NOQDIR)
2477		(void) sm_strlcpy(qd, ".", sizeof qd);
2478	else
2479		(void) sm_strlcpyn(qd, sizeof qd, 2,
2480			Queue[qgrp]->qg_qpaths[qdir].qp_name,
2481			(bitset(QP_SUBQF,
2482				Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
2483					? "/qf" : ""));
2484
2485	if (tTd(41, 1))
2486	{
2487		sm_dprintf("gatherq:\n");
2488
2489		check = QueueLimitId;
2490		while (check != NULL)
2491		{
2492			sm_dprintf("\tQueueLimitId = %s%s\n",
2493				check->queue_negate ? "!" : "",
2494				check->queue_match);
2495			check = check->queue_next;
2496		}
2497
2498		check = QueueLimitSender;
2499		while (check != NULL)
2500		{
2501			sm_dprintf("\tQueueLimitSender = %s%s\n",
2502				check->queue_negate ? "!" : "",
2503				check->queue_match);
2504			check = check->queue_next;
2505		}
2506
2507		check = QueueLimitRecipient;
2508		while (check != NULL)
2509		{
2510			sm_dprintf("\tQueueLimitRecipient = %s%s\n",
2511				check->queue_negate ? "!" : "",
2512				check->queue_match);
2513			check = check->queue_next;
2514		}
2515
2516		if (QueueMode == QM_QUARANTINE)
2517		{
2518			check = QueueLimitQuarantine;
2519			while (check != NULL)
2520			{
2521				sm_dprintf("\tQueueLimitQuarantine = %s%s\n",
2522					   check->queue_negate ? "!" : "",
2523					   check->queue_match);
2524				check = check->queue_next;
2525			}
2526		}
2527	}
2528
2529	/* open the queue directory */
2530	f = opendir(qd);
2531	if (f == NULL)
2532	{
2533		syserr("gatherq: cannot open \"%s\"",
2534			qid_printqueue(qgrp, qdir));
2535		if (full != NULL)
2536			*full = WorkListCount >= MaxQueueRun && MaxQueueRun > 0;
2537		if (more != NULL)
2538			*more = false;
2539		return 0;
2540	}
2541
2542	/*
2543	**  Read the work directory.
2544	*/
2545
2546	while ((d = readdir(f)) != NULL)
2547	{
2548		SM_FILE_T *cf;
2549		int qfver = 0;
2550		char lbuf[MAXNAME + 1];
2551		struct stat sbuf;
2552
2553		if (tTd(41, 50))
2554			sm_dprintf("gatherq: checking %s..", d->d_name);
2555
2556		/* is this an interesting entry? */
2557		if (!(((QueueMode == QM_NORMAL &&
2558			d->d_name[0] == NORMQF_LETTER) ||
2559		       (QueueMode == QM_QUARANTINE &&
2560			d->d_name[0] == QUARQF_LETTER) ||
2561		       (QueueMode == QM_LOST &&
2562			d->d_name[0] == LOSEQF_LETTER)) &&
2563		      d->d_name[1] == 'f'))
2564		{
2565			if (tTd(41, 50))
2566				sm_dprintf("  skipping\n");
2567			continue;
2568		}
2569		if (tTd(41, 50))
2570			sm_dprintf("\n");
2571
2572		if (strlen(d->d_name) >= MAXQFNAME)
2573		{
2574			if (Verbose)
2575				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2576						     "gatherq: %s too long, %d max characters\n",
2577						     d->d_name, MAXQFNAME);
2578			if (LogLevel > 0)
2579				sm_syslog(LOG_ALERT, NOQID,
2580					  "gatherq: %s too long, %d max characters",
2581					  d->d_name, MAXQFNAME);
2582			continue;
2583		}
2584
2585		check = QueueLimitId;
2586		while (check != NULL)
2587		{
2588			if (strcontainedin(false, check->queue_match,
2589					   d->d_name) != check->queue_negate)
2590				break;
2591			else
2592				check = check->queue_next;
2593		}
2594		if (QueueLimitId != NULL && check == NULL)
2595			continue;
2596
2597		/* grow work list if necessary */
2598		if (++wn >= MaxQueueRun && MaxQueueRun > 0)
2599		{
2600			if (wn == MaxQueueRun && LogLevel > 0)
2601				sm_syslog(LOG_WARNING, NOQID,
2602					  "WorkList for %s maxed out at %d",
2603					  qid_printqueue(qgrp, qdir),
2604					  MaxQueueRun);
2605			if (doall)
2606				continue;	/* just count entries */
2607			break;
2608		}
2609		if (wn >= WorkListSize)
2610		{
2611			grow_wlist(qgrp, qdir);
2612			if (wn >= WorkListSize)
2613				continue;
2614		}
2615		SM_ASSERT(wn >= 0);
2616		w = &WorkList[wn];
2617
2618		(void) sm_strlcpyn(qf, sizeof qf, 3, qd, "/", d->d_name);
2619		if (stat(qf, &sbuf) < 0)
2620		{
2621			if (errno != ENOENT)
2622				sm_syslog(LOG_INFO, NOQID,
2623					  "gatherq: can't stat %s/%s",
2624					  qid_printqueue(qgrp, qdir),
2625					  d->d_name);
2626			wn--;
2627			continue;
2628		}
2629		if (!bitset(S_IFREG, sbuf.st_mode))
2630		{
2631			/* Yikes!  Skip it or we will hang on open! */
2632			if (!((d->d_name[0] == DATAFL_LETTER ||
2633			       d->d_name[0] == NORMQF_LETTER ||
2634			       d->d_name[0] == QUARQF_LETTER ||
2635			       d->d_name[0] == LOSEQF_LETTER ||
2636			       d->d_name[0] == XSCRPT_LETTER) &&
2637			      d->d_name[1] == 'f' && d->d_name[2] == '\0'))
2638				syserr("gatherq: %s/%s is not a regular file",
2639				       qid_printqueue(qgrp, qdir), d->d_name);
2640			wn--;
2641			continue;
2642		}
2643
2644		/* avoid work if possible */
2645		if ((QueueSortOrder == QSO_BYFILENAME ||
2646		     QueueSortOrder == QSO_BYMODTIME ||
2647		     QueueSortOrder == QSO_RANDOM) &&
2648		    QueueLimitQuarantine == NULL &&
2649		    QueueLimitSender == NULL &&
2650		    QueueLimitRecipient == NULL)
2651		{
2652			w->w_qgrp = qgrp;
2653			w->w_qdir = qdir;
2654			w->w_name = newstr(d->d_name);
2655			w->w_host = NULL;
2656			w->w_lock = w->w_tooyoung = false;
2657			w->w_pri = 0;
2658			w->w_ctime = 0;
2659			w->w_mtime = sbuf.st_mtime;
2660			++num_ent;
2661			continue;
2662		}
2663
2664		/* open control file */
2665		cf = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY_B,
2666				NULL);
2667		if (cf == NULL && OpMode != MD_PRINT)
2668		{
2669			/* this may be some random person sending hir msgs */
2670			if (tTd(41, 2))
2671				sm_dprintf("gatherq: cannot open %s: %s\n",
2672					d->d_name, sm_errstring(errno));
2673			errno = 0;
2674			wn--;
2675			continue;
2676		}
2677		w->w_qgrp = qgrp;
2678		w->w_qdir = qdir;
2679		w->w_name = newstr(d->d_name);
2680		w->w_host = NULL;
2681		if (cf != NULL)
2682		{
2683			w->w_lock = !lockfile(sm_io_getinfo(cf, SM_IO_WHAT_FD,
2684							    NULL),
2685					      w->w_name, NULL,
2686					      LOCK_SH|LOCK_NB);
2687		}
2688		w->w_tooyoung = false;
2689
2690		/* make sure jobs in creation don't clog queue */
2691		w->w_pri = 0x7fffffff;
2692		w->w_ctime = 0;
2693		w->w_mtime = sbuf.st_mtime;
2694
2695		/* extract useful information */
2696		i = NEED_P|NEED_T;
2697		if (QueueSortOrder == QSO_BYHOST
2698#if _FFR_RHS
2699		    || QueueSortOrder == QSO_BYSHUFFLE
2700#endif /* _FFR_RHS */
2701		   )
2702		{
2703			/* need w_host set for host sort order */
2704			i |= NEED_H;
2705		}
2706		if (QueueLimitSender != NULL)
2707			i |= NEED_S;
2708		if (QueueLimitRecipient != NULL)
2709			i |= NEED_R;
2710		if (QueueLimitQuarantine != NULL)
2711			i |= NEED_QUARANTINE;
2712		while (cf != NULL && i != 0 &&
2713		       sm_io_fgets(cf, SM_TIME_DEFAULT, lbuf,
2714				   sizeof lbuf) != NULL)
2715		{
2716			int c;
2717			time_t age;
2718
2719			p = strchr(lbuf, '\n');
2720			if (p != NULL)
2721				*p = '\0';
2722			else
2723			{
2724				/* flush rest of overly long line */
2725				while ((c = sm_io_getc(cf, SM_TIME_DEFAULT))
2726				       != SM_IO_EOF && c != '\n')
2727					continue;
2728			}
2729
2730			switch (lbuf[0])
2731			{
2732			  case 'V':
2733				qfver = atoi(&lbuf[1]);
2734				break;
2735
2736			  case 'P':
2737				w->w_pri = atol(&lbuf[1]);
2738				i &= ~NEED_P;
2739				break;
2740
2741			  case 'T':
2742				w->w_ctime = atol(&lbuf[1]);
2743				i &= ~NEED_T;
2744				break;
2745
2746			  case 'q':
2747				if (QueueMode != QM_QUARANTINE &&
2748				    QueueMode != QM_LOST)
2749				{
2750					if (tTd(41, 49))
2751						sm_dprintf("%s not marked as quarantined but has a 'q' line\n",
2752							   w->w_name);
2753					i |= HAS_QUARANTINE;
2754				}
2755				else if (QueueMode == QM_QUARANTINE)
2756				{
2757					if (QueueLimitQuarantine == NULL)
2758					{
2759						i &= ~NEED_QUARANTINE;
2760						break;
2761					}
2762					p = &lbuf[1];
2763					check = QueueLimitQuarantine;
2764					while (check != NULL)
2765					{
2766						if (strcontainedin(false,
2767								   check->queue_match,
2768								   p) !=
2769						    check->queue_negate)
2770							break;
2771						else
2772							check = check->queue_next;
2773					}
2774					if (check != NULL)
2775						i &= ~NEED_QUARANTINE;
2776				}
2777				break;
2778
2779			  case 'R':
2780				if (w->w_host == NULL &&
2781				    (p = strrchr(&lbuf[1], '@')) != NULL)
2782				{
2783#if _FFR_RHS
2784					if (QueueSortOrder == QSO_BYSHUFFLE)
2785						w->w_host = newstr(&p[1]);
2786					else
2787#endif /* _FFR_RHS */
2788						w->w_host = strrev(&p[1]);
2789					makelower(w->w_host);
2790					i &= ~NEED_H;
2791				}
2792				if (QueueLimitRecipient == NULL)
2793				{
2794					i &= ~NEED_R;
2795					break;
2796				}
2797				if (qfver > 0)
2798				{
2799					p = strchr(&lbuf[1], ':');
2800					if (p == NULL)
2801						p = &lbuf[1];
2802					else
2803						++p; /* skip over ':' */
2804				}
2805				else
2806					p = &lbuf[1];
2807				check = QueueLimitRecipient;
2808				while (check != NULL)
2809				{
2810					if (strcontainedin(true,
2811							   check->queue_match,
2812							   p) !=
2813					    check->queue_negate)
2814						break;
2815					else
2816						check = check->queue_next;
2817				}
2818				if (check != NULL)
2819					i &= ~NEED_R;
2820				break;
2821
2822			  case 'S':
2823				check = QueueLimitSender;
2824				while (check != NULL)
2825				{
2826					if (strcontainedin(true,
2827							   check->queue_match,
2828							   &lbuf[1]) !=
2829					    check->queue_negate)
2830						break;
2831					else
2832						check = check->queue_next;
2833				}
2834				if (check != NULL)
2835					i &= ~NEED_S;
2836				break;
2837
2838			  case 'K':
2839				age = curtime() - (time_t) atol(&lbuf[1]);
2840				if (age >= 0 && MinQueueAge > 0 &&
2841				    age < MinQueueAge)
2842					w->w_tooyoung = true;
2843				break;
2844
2845			  case 'N':
2846				if (atol(&lbuf[1]) == 0)
2847					w->w_tooyoung = false;
2848				break;
2849			}
2850		}
2851		if (cf != NULL)
2852			(void) sm_io_close(cf, SM_TIME_DEFAULT);
2853
2854		if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
2855		    bitset(HAS_QUARANTINE, i) ||
2856		    bitset(NEED_QUARANTINE, i) ||
2857		    bitset(NEED_R|NEED_S, i))
2858		{
2859			/* don't even bother sorting this job in */
2860			if (tTd(41, 49))
2861				sm_dprintf("skipping %s (%x)\n", w->w_name, i);
2862			sm_free(w->w_name); /* XXX */
2863			if (w->w_host != NULL)
2864				sm_free(w->w_host); /* XXX */
2865			wn--;
2866		}
2867		else
2868			++num_ent;
2869	}
2870	(void) closedir(f);
2871	wn++;
2872
2873	i = wn - WorkListCount;
2874	WorkListCount += SM_MIN(num_ent, WorkListSize);
2875
2876	if (more != NULL)
2877		*more = WorkListCount < wn;
2878
2879	if (full != NULL)
2880		*full = (wn >= MaxQueueRun && MaxQueueRun > 0) ||
2881			(WorkList == NULL && wn > 0);
2882
2883	return i;
2884}
2885/*
2886**  SORTQ -- sort the work list
2887**
2888**	First the old WorkQ is cleared away. Then the WorkList is sorted
2889**	for all items so that important (higher sorting value) items are not
2890**	trunctated off. Then the most important items are moved from
2891**	WorkList to WorkQ. The lower count of 'max' or MaxListCount items
2892**	are moved.
2893**
2894**	Parameters:
2895**		max -- maximum number of items to be placed in WorkQ
2896**
2897**	Returns:
2898**		the number of items in WorkQ
2899**
2900**	Side Effects:
2901**		WorkQ gets released and filled with new work. WorkList
2902**		gets released. Work items get sorted in order.
2903*/
2904
2905static int
2906sortq(max)
2907	int max;
2908{
2909	register int i;			/* local counter */
2910	register WORK *w;		/* tmp item pointer */
2911	int wc = WorkListCount;		/* trim size for WorkQ */
2912
2913	if (WorkQ != NULL)
2914	{
2915		WORK *nw;
2916
2917		/* Clear out old WorkQ. */
2918		for (w = WorkQ; w != NULL; w = nw)
2919		{
2920			nw = w->w_next;
2921			sm_free(w->w_name); /* XXX */
2922			if (w->w_host != NULL)
2923				sm_free(w->w_host); /* XXX */
2924			sm_free((char *) w); /* XXX */
2925		}
2926		WorkQ = NULL;
2927	}
2928
2929	if (WorkList == NULL || wc <= 0)
2930		return 0;
2931
2932	/* Check if the per queue group item limit will be exceeded */
2933	if (wc > max && max > 0)
2934		wc = max;
2935
2936	/*
2937	**  The sort now takes place using all of the items in WorkList.
2938	**  The list gets trimmed to the most important items after the sort.
2939	**  If the trim were to happen before the sort then one or more
2940	**  important items might get truncated off -- not what we want.
2941	*/
2942
2943	if (QueueSortOrder == QSO_BYHOST)
2944	{
2945		/*
2946		**  Sort the work directory for the first time,
2947		**  based on host name, lock status, and priority.
2948		*/
2949
2950		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1);
2951
2952		/*
2953		**  If one message to host is locked, "lock" all messages
2954		**  to that host.
2955		*/
2956
2957		i = 0;
2958		while (i < wc)
2959		{
2960			if (!WorkList[i].w_lock)
2961			{
2962				i++;
2963				continue;
2964			}
2965			w = &WorkList[i];
2966			while (++i < wc)
2967			{
2968				if (WorkList[i].w_host == NULL &&
2969				    w->w_host == NULL)
2970					WorkList[i].w_lock = true;
2971				else if (WorkList[i].w_host != NULL &&
2972					 w->w_host != NULL &&
2973					 sm_strcasecmp(WorkList[i].w_host,
2974						       w->w_host) == 0)
2975					WorkList[i].w_lock = true;
2976				else
2977					break;
2978			}
2979		}
2980
2981		/*
2982		**  Sort the work directory for the second time,
2983		**  based on lock status, host name, and priority.
2984		*/
2985
2986		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2);
2987	}
2988	else if (QueueSortOrder == QSO_BYTIME)
2989	{
2990		/*
2991		**  Simple sort based on submission time only.
2992		*/
2993
2994		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf3);
2995	}
2996	else if (QueueSortOrder == QSO_BYFILENAME)
2997	{
2998		/*
2999		**  Sort based on queue filename.
3000		*/
3001
3002		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf4);
3003	}
3004	else if (QueueSortOrder == QSO_RANDOM)
3005	{
3006		/*
3007		**  Sort randomly.  To avoid problems with an instable sort,
3008		**  use a random index into the queue file name to start
3009		**  comparison.
3010		*/
3011
3012		randi = get_rand_mod(MAXQFNAME);
3013		if (randi < 2)
3014			randi = 3;
3015		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf5);
3016	}
3017	else if (QueueSortOrder == QSO_BYMODTIME)
3018	{
3019		/*
3020		**  Simple sort based on modification time of queue file.
3021		**  This puts the oldest items first.
3022		*/
3023
3024		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf6);
3025	}
3026#if _FFR_RHS
3027	else if (QueueSortOrder == QSO_BYSHUFFLE)
3028	{
3029		/*
3030		**  Simple sort based on shuffled host name.
3031		*/
3032
3033		init_shuffle_alphabet();
3034		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf7);
3035	}
3036#endif /* _FFR_RHS */
3037	else if (QueueSortOrder == QSO_BYPRIORITY)
3038	{
3039		/*
3040		**  Simple sort based on queue priority only.
3041		*/
3042
3043		qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0);
3044	}
3045	/* else don't sort at all */
3046
3047	/*
3048	**  Convert the work list into canonical form.
3049	**	Should be turning it into a list of envelopes here perhaps.
3050	**  Only take the most important items up to the per queue group
3051	**  maximum.
3052	*/
3053
3054	for (i = wc; --i >= 0; )
3055	{
3056		w = (WORK *) xalloc(sizeof *w);
3057		w->w_qgrp = WorkList[i].w_qgrp;
3058		w->w_qdir = WorkList[i].w_qdir;
3059		w->w_name = WorkList[i].w_name;
3060		w->w_host = WorkList[i].w_host;
3061		w->w_lock = WorkList[i].w_lock;
3062		w->w_tooyoung = WorkList[i].w_tooyoung;
3063		w->w_pri = WorkList[i].w_pri;
3064		w->w_ctime = WorkList[i].w_ctime;
3065		w->w_mtime = WorkList[i].w_mtime;
3066		w->w_next = WorkQ;
3067		WorkQ = w;
3068	}
3069
3070	/* free the rest of the list */
3071	for (i = WorkListCount; --i >= wc; )
3072	{
3073		sm_free(WorkList[i].w_name);
3074		if (WorkList[i].w_host != NULL)
3075			sm_free(WorkList[i].w_host);
3076	}
3077
3078	if (WorkList != NULL)
3079		sm_free(WorkList); /* XXX */
3080	WorkList = NULL;
3081	WorkListSize = 0;
3082	WorkListCount = 0;
3083
3084	if (tTd(40, 1))
3085	{
3086		for (w = WorkQ; w != NULL; w = w->w_next)
3087		{
3088			if (w->w_host != NULL)
3089				sm_dprintf("%22s: pri=%ld %s\n",
3090					w->w_name, w->w_pri, w->w_host);
3091			else
3092				sm_dprintf("%32s: pri=%ld\n",
3093					w->w_name, w->w_pri);
3094		}
3095	}
3096
3097	return wc; /* return number of WorkQ items */
3098}
3099/*
3100**  GROW_WLIST -- make the work list larger
3101**
3102**	Parameters:
3103**		qgrp -- the index for the queue group.
3104**		qdir -- the index for the queue directory.
3105**
3106**	Returns:
3107**		none.
3108**
3109**	Side Effects:
3110**		Adds another QUEUESEGSIZE entries to WorkList if possible.
3111**		It can fail if there isn't enough memory, so WorkListSize
3112**		should be checked again upon return.
3113*/
3114
3115static void
3116grow_wlist(qgrp, qdir)
3117	int qgrp;
3118	int qdir;
3119{
3120	if (tTd(41, 1))
3121		sm_dprintf("grow_wlist: WorkListSize=%d\n", WorkListSize);
3122	if (WorkList == NULL)
3123	{
3124		WorkList = (WORK *) xalloc((sizeof *WorkList) *
3125					   (QUEUESEGSIZE + 1));
3126		WorkListSize = QUEUESEGSIZE;
3127	}
3128	else
3129	{
3130		int newsize = WorkListSize + QUEUESEGSIZE;
3131		WORK *newlist = (WORK *) sm_realloc((char *) WorkList,
3132					  (unsigned) sizeof(WORK) * (newsize + 1));
3133
3134		if (newlist != NULL)
3135		{
3136			WorkListSize = newsize;
3137			WorkList = newlist;
3138			if (LogLevel > 1)
3139			{
3140				sm_syslog(LOG_INFO, NOQID,
3141					  "grew WorkList for %s to %d",
3142					  qid_printqueue(qgrp, qdir),
3143					  WorkListSize);
3144			}
3145		}
3146		else if (LogLevel > 0)
3147		{
3148			sm_syslog(LOG_ALERT, NOQID,
3149				  "FAILED to grow WorkList for %s to %d",
3150				  qid_printqueue(qgrp, qdir), newsize);
3151		}
3152	}
3153	if (tTd(41, 1))
3154		sm_dprintf("grow_wlist: WorkListSize now %d\n", WorkListSize);
3155}
3156/*
3157**  WORKCMPF0 -- simple priority-only compare function.
3158**
3159**	Parameters:
3160**		a -- the first argument.
3161**		b -- the second argument.
3162**
3163**	Returns:
3164**		-1 if a < b
3165**		 0 if a == b
3166**		+1 if a > b
3167**
3168*/
3169
3170static int
3171workcmpf0(a, b)
3172	register WORK *a;
3173	register WORK *b;
3174{
3175	long pa = a->w_pri;
3176	long pb = b->w_pri;
3177
3178	if (pa == pb)
3179		return 0;
3180	else if (pa > pb)
3181		return 1;
3182	else
3183		return -1;
3184}
3185/*
3186**  WORKCMPF1 -- first compare function for ordering work based on host name.
3187**
3188**	Sorts on host name, lock status, and priority in that order.
3189**
3190**	Parameters:
3191**		a -- the first argument.
3192**		b -- the second argument.
3193**
3194**	Returns:
3195**		<0 if a < b
3196**		 0 if a == b
3197**		>0 if a > b
3198**
3199*/
3200
3201static int
3202workcmpf1(a, b)
3203	register WORK *a;
3204	register WORK *b;
3205{
3206	int i;
3207
3208	/* host name */
3209	if (a->w_host != NULL && b->w_host == NULL)
3210		return 1;
3211	else if (a->w_host == NULL && b->w_host != NULL)
3212		return -1;
3213	if (a->w_host != NULL && b->w_host != NULL &&
3214	    (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
3215		return i;
3216
3217	/* lock status */
3218	if (a->w_lock != b->w_lock)
3219		return b->w_lock - a->w_lock;
3220
3221	/* job priority */
3222	return workcmpf0(a, b);
3223}
3224/*
3225**  WORKCMPF2 -- second compare function for ordering work based on host name.
3226**
3227**	Sorts on lock status, host name, and priority in that order.
3228**
3229**	Parameters:
3230**		a -- the first argument.
3231**		b -- the second argument.
3232**
3233**	Returns:
3234**		<0 if a < b
3235**		 0 if a == b
3236**		>0 if a > b
3237**
3238*/
3239
3240static int
3241workcmpf2(a, b)
3242	register WORK *a;
3243	register WORK *b;
3244{
3245	int i;
3246
3247	/* lock status */
3248	if (a->w_lock != b->w_lock)
3249		return a->w_lock - b->w_lock;
3250
3251	/* host name */
3252	if (a->w_host != NULL && b->w_host == NULL)
3253		return 1;
3254	else if (a->w_host == NULL && b->w_host != NULL)
3255		return -1;
3256	if (a->w_host != NULL && b->w_host != NULL &&
3257	    (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
3258		return i;
3259
3260	/* job priority */
3261	return workcmpf0(a, b);
3262}
3263/*
3264**  WORKCMPF3 -- simple submission-time-only compare function.
3265**
3266**	Parameters:
3267**		a -- the first argument.
3268**		b -- the second argument.
3269**
3270**	Returns:
3271**		-1 if a < b
3272**		 0 if a == b
3273**		+1 if a > b
3274**
3275*/
3276
3277static int
3278workcmpf3(a, b)
3279	register WORK *a;
3280	register WORK *b;
3281{
3282	if (a->w_ctime > b->w_ctime)
3283		return 1;
3284	else if (a->w_ctime < b->w_ctime)
3285		return -1;
3286	else
3287		return 0;
3288}
3289/*
3290**  WORKCMPF4 -- compare based on file name
3291**
3292**	Parameters:
3293**		a -- the first argument.
3294**		b -- the second argument.
3295**
3296**	Returns:
3297**		-1 if a < b
3298**		 0 if a == b
3299**		+1 if a > b
3300**
3301*/
3302
3303static int
3304workcmpf4(a, b)
3305	register WORK *a;
3306	register WORK *b;
3307{
3308	return strcmp(a->w_name, b->w_name);
3309}
3310/*
3311**  WORKCMPF5 -- compare based on assigned random number
3312**
3313**	Parameters:
3314**		a -- the first argument (ignored).
3315**		b -- the second argument (ignored).
3316**
3317**	Returns:
3318**		randomly 1/-1
3319*/
3320
3321/* ARGSUSED0 */
3322static int
3323workcmpf5(a, b)
3324	register WORK *a;
3325	register WORK *b;
3326{
3327	if (strlen(a->w_name) < randi || strlen(b->w_name) < randi)
3328		return -1;
3329	return a->w_name[randi] - b->w_name[randi];
3330}
3331/*
3332**  WORKCMPF6 -- simple modification-time-only compare function.
3333**
3334**	Parameters:
3335**		a -- the first argument.
3336**		b -- the second argument.
3337**
3338**	Returns:
3339**		-1 if a < b
3340**		 0 if a == b
3341**		+1 if a > b
3342**
3343*/
3344
3345static int
3346workcmpf6(a, b)
3347	register WORK *a;
3348	register WORK *b;
3349{
3350	if (a->w_mtime > b->w_mtime)
3351		return 1;
3352	else if (a->w_mtime < b->w_mtime)
3353		return -1;
3354	else
3355		return 0;
3356}
3357#if _FFR_RHS
3358/*
3359**  WORKCMPF7 -- compare function for ordering work based on shuffled host name.
3360**
3361**	Sorts on lock status, host name, and priority in that order.
3362**
3363**	Parameters:
3364**		a -- the first argument.
3365**		b -- the second argument.
3366**
3367**	Returns:
3368**		<0 if a < b
3369**		 0 if a == b
3370**		>0 if a > b
3371**
3372*/
3373
3374static int
3375workcmpf7(a, b)
3376	register WORK *a;
3377	register WORK *b;
3378{
3379	int i;
3380
3381	/* lock status */
3382	if (a->w_lock != b->w_lock)
3383		return a->w_lock - b->w_lock;
3384
3385	/* host name */
3386	if (a->w_host != NULL && b->w_host == NULL)
3387		return 1;
3388	else if (a->w_host == NULL && b->w_host != NULL)
3389		return -1;
3390	if (a->w_host != NULL && b->w_host != NULL &&
3391	    (i = sm_strshufflecmp(a->w_host, b->w_host)) != 0)
3392		return i;
3393
3394	/* job priority */
3395	return workcmpf0(a, b);
3396}
3397#endif /* _FFR_RHS */
3398/*
3399**  STRREV -- reverse string
3400**
3401**	Returns a pointer to a new string that is the reverse of
3402**	the string pointed to by fwd.  The space for the new
3403**	string is obtained using xalloc().
3404**
3405**	Parameters:
3406**		fwd -- the string to reverse.
3407**
3408**	Returns:
3409**		the reversed string.
3410*/
3411
3412static char *
3413strrev(fwd)
3414	char *fwd;
3415{
3416	char *rev = NULL;
3417	int len, cnt;
3418
3419	len = strlen(fwd);
3420	rev = xalloc(len + 1);
3421	for (cnt = 0; cnt < len; ++cnt)
3422		rev[cnt] = fwd[len - cnt - 1];
3423	rev[len] = '\0';
3424	return rev;
3425}
3426
3427#if _FFR_RHS
3428
3429# define NASCII	128
3430# define NCHAR	256
3431
3432static unsigned char ShuffledAlphabet[NCHAR];
3433
3434void
3435init_shuffle_alphabet()
3436{
3437	static bool init = false;
3438	int i;
3439
3440	if (init)
3441		return;
3442
3443	/* fill the ShuffledAlphabet */
3444	for (i = 0; i < NCHAR; i++)
3445		ShuffledAlphabet[i] = i;
3446
3447	/* mix it */
3448	for (i = 1; i < NCHAR; i++)
3449	{
3450		register int j = get_random() % NCHAR;
3451		register int tmp;
3452
3453		tmp = ShuffledAlphabet[j];
3454		ShuffledAlphabet[j] = ShuffledAlphabet[i];
3455		ShuffledAlphabet[i] = tmp;
3456	}
3457
3458	/* make it case insensitive */
3459	for (i = 'A'; i <= 'Z'; i++)
3460		ShuffledAlphabet[i] = ShuffledAlphabet[i + 'a' - 'A'];
3461
3462	/* fill the upper part */
3463	for (i = 0; i < NCHAR; i++)
3464		ShuffledAlphabet[i + NCHAR] = ShuffledAlphabet[i];
3465	init = true;
3466}
3467
3468static int
3469sm_strshufflecmp(a, b)
3470	char *a;
3471	char *b;
3472{
3473	const unsigned char *us1 = (const unsigned char *) a;
3474	const unsigned char *us2 = (const unsigned char *) b;
3475
3476	while (ShuffledAlphabet[*us1] == ShuffledAlphabet[*us2++])
3477	{
3478		if (*us1++ == '\0')
3479			return 0;
3480	}
3481	return (ShuffledAlphabet[*us1] - ShuffledAlphabet[*--us2]);
3482}
3483#endif /* _FFR_RHS */
3484
3485/*
3486**  DOWORK -- do a work request.
3487**
3488**	Parameters:
3489**		qgrp -- the index of the queue group for the job.
3490**		qdir -- the index of the queue directory for the job.
3491**		id -- the ID of the job to run.
3492**		forkflag -- if set, run this in background.
3493**		requeueflag -- if set, reinstantiate the queue quickly.
3494**			This is used when expanding aliases in the queue.
3495**			If forkflag is also set, it doesn't wait for the
3496**			child.
3497**		e - the envelope in which to run it.
3498**
3499**	Returns:
3500**		process id of process that is running the queue job.
3501**
3502**	Side Effects:
3503**		The work request is satisfied if possible.
3504*/
3505
3506pid_t
3507dowork(qgrp, qdir, id, forkflag, requeueflag, e)
3508	int qgrp;
3509	int qdir;
3510	char *id;
3511	bool forkflag;
3512	bool requeueflag;
3513	register ENVELOPE *e;
3514{
3515	register pid_t pid;
3516	SM_RPOOL_T *rpool;
3517
3518	if (tTd(40, 1))
3519		sm_dprintf("dowork(%s/%s)\n", qid_printqueue(qgrp, qdir), id);
3520
3521	/*
3522	**  Fork for work.
3523	*/
3524
3525	if (forkflag)
3526	{
3527		/*
3528		**  Since the delivery may happen in a child and the
3529		**  parent does not wait, the parent may close the
3530		**  maps thereby removing any shared memory used by
3531		**  the map.  Therefore, close the maps now so the
3532		**  child will dynamically open them if necessary.
3533		*/
3534
3535		closemaps(false);
3536
3537		pid = fork();
3538		if (pid < 0)
3539		{
3540			syserr("dowork: cannot fork");
3541			return 0;
3542		}
3543		else if (pid > 0)
3544		{
3545			/* parent -- clean out connection cache */
3546			mci_flush(false, NULL);
3547		}
3548		else
3549		{
3550			/*
3551			**  Initialize exception stack and default exception
3552			**  handler for child process.
3553			*/
3554
3555			/* Reset global flags */
3556			RestartRequest = NULL;
3557			RestartWorkGroup = false;
3558			ShutdownRequest = NULL;
3559			PendingSignal = 0;
3560			CurrentPid = getpid();
3561			sm_exc_newthread(fatal_error);
3562
3563			/*
3564			**  See note above about SMTP processes and SIGCHLD.
3565			*/
3566
3567			if (OpMode == MD_SMTP ||
3568			    OpMode == MD_DAEMON ||
3569			    MaxQueueChildren > 0)
3570			{
3571				proc_list_clear();
3572				sm_releasesignal(SIGCHLD);
3573				(void) sm_signal(SIGCHLD, SIG_DFL);
3574			}
3575
3576			/* child -- error messages to the transcript */
3577			QuickAbort = OnlyOneError = false;
3578		}
3579	}
3580	else
3581	{
3582		pid = 0;
3583	}
3584
3585	if (pid == 0)
3586	{
3587		/*
3588		**  CHILD
3589		**	Lock the control file to avoid duplicate deliveries.
3590		**		Then run the file as though we had just read it.
3591		**	We save an idea of the temporary name so we
3592		**		can recover on interrupt.
3593		*/
3594
3595		if (forkflag)
3596		{
3597			/* Reset global flags */
3598			RestartRequest = NULL;
3599			RestartWorkGroup = false;
3600			ShutdownRequest = NULL;
3601			PendingSignal = 0;
3602		}
3603
3604		/* set basic modes, etc. */
3605		sm_clear_events();
3606		clearstats();
3607		rpool = sm_rpool_new_x(NULL);
3608		clearenvelope(e, false, rpool);
3609		e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
3610		set_delivery_mode(SM_DELIVER, e);
3611		e->e_errormode = EM_MAIL;
3612		e->e_id = id;
3613		e->e_qgrp = qgrp;
3614		e->e_qdir = qdir;
3615		GrabTo = UseErrorsTo = false;
3616		ExitStat = EX_OK;
3617		if (forkflag)
3618		{
3619			disconnect(1, e);
3620			set_op_mode(MD_QUEUERUN);
3621		}
3622		sm_setproctitle(true, e, "%s from queue", qid_printname(e));
3623		if (LogLevel > 76)
3624			sm_syslog(LOG_DEBUG, e->e_id, "dowork, pid=%d",
3625				  (int) CurrentPid);
3626
3627		/* don't use the headers from sendmail.cf... */
3628		e->e_header = NULL;
3629
3630		/* read the queue control file -- return if locked */
3631		if (!readqf(e, false))
3632		{
3633			if (tTd(40, 4) && e->e_id != NULL)
3634				sm_dprintf("readqf(%s) failed\n",
3635					qid_printname(e));
3636			e->e_id = NULL;
3637			if (forkflag)
3638				finis(false, true, EX_OK);
3639			else
3640			{
3641				/* adding this frees 8 bytes */
3642				clearenvelope(e, false, rpool);
3643
3644				/* adding this frees 12 bytes */
3645				sm_rpool_free(rpool);
3646				e->e_rpool = NULL;
3647				return 0;
3648			}
3649		}
3650
3651		e->e_flags |= EF_INQUEUE;
3652		eatheader(e, requeueflag, true);
3653
3654		if (requeueflag)
3655			queueup(e, false, false);
3656
3657		/* do the delivery */
3658		sendall(e, SM_DELIVER);
3659
3660		/* finish up and exit */
3661		if (forkflag)
3662			finis(true, true, ExitStat);
3663		else
3664		{
3665			dropenvelope(e, true, false);
3666			sm_rpool_free(rpool);
3667			e->e_rpool = NULL;
3668		}
3669	}
3670	e->e_id = NULL;
3671	return pid;
3672}
3673
3674/*
3675**  DOWORKLIST -- process a list of envelopes as work requests
3676**
3677**	Similar to dowork(), except that after forking, it processes an
3678**	envelope and its siblings, treating each envelope as a work request.
3679**
3680**	Parameters:
3681**		el -- envelope to be processed including its siblings.
3682**		forkflag -- if set, run this in background.
3683**		requeueflag -- if set, reinstantiate the queue quickly.
3684**			This is used when expanding aliases in the queue.
3685**			If forkflag is also set, it doesn't wait for the
3686**			child.
3687**
3688**	Returns:
3689**		process id of process that is running the queue job.
3690**
3691**	Side Effects:
3692**		The work request is satisfied if possible.
3693*/
3694
3695pid_t
3696doworklist(el, forkflag, requeueflag)
3697	ENVELOPE *el;
3698	bool forkflag;
3699	bool requeueflag;
3700{
3701	register pid_t pid;
3702	ENVELOPE *ei;
3703
3704	if (tTd(40, 1))
3705		sm_dprintf("doworklist()\n");
3706
3707	/*
3708	**  Fork for work.
3709	*/
3710
3711	if (forkflag)
3712	{
3713		/*
3714		**  Since the delivery may happen in a child and the
3715		**  parent does not wait, the parent may close the
3716		**  maps thereby removing any shared memory used by
3717		**  the map.  Therefore, close the maps now so the
3718		**  child will dynamically open them if necessary.
3719		*/
3720
3721		closemaps(false);
3722
3723		pid = fork();
3724		if (pid < 0)
3725		{
3726			syserr("doworklist: cannot fork");
3727			return 0;
3728		}
3729		else if (pid > 0)
3730		{
3731			/* parent -- clean out connection cache */
3732			mci_flush(false, NULL);
3733		}
3734		else
3735		{
3736			/*
3737			**  Initialize exception stack and default exception
3738			**  handler for child process.
3739			*/
3740
3741			/* Reset global flags */
3742			RestartRequest = NULL;
3743			RestartWorkGroup = false;
3744			ShutdownRequest = NULL;
3745			PendingSignal = 0;
3746			CurrentPid = getpid();
3747			sm_exc_newthread(fatal_error);
3748
3749			/*
3750			**  See note above about SMTP processes and SIGCHLD.
3751			*/
3752
3753			if (OpMode == MD_SMTP ||
3754			    OpMode == MD_DAEMON ||
3755			    MaxQueueChildren > 0)
3756			{
3757				proc_list_clear();
3758				sm_releasesignal(SIGCHLD);
3759				(void) sm_signal(SIGCHLD, SIG_DFL);
3760			}
3761
3762			/* child -- error messages to the transcript */
3763			QuickAbort = OnlyOneError = false;
3764		}
3765	}
3766	else
3767	{
3768		pid = 0;
3769	}
3770
3771	if (pid != 0)
3772		return pid;
3773
3774	/*
3775	**  IN CHILD
3776	**	Lock the control file to avoid duplicate deliveries.
3777	**		Then run the file as though we had just read it.
3778	**	We save an idea of the temporary name so we
3779	**		can recover on interrupt.
3780	*/
3781
3782	if (forkflag)
3783	{
3784		/* Reset global flags */
3785		RestartRequest = NULL;
3786		RestartWorkGroup = false;
3787		ShutdownRequest = NULL;
3788		PendingSignal = 0;
3789	}
3790
3791	/* set basic modes, etc. */
3792	sm_clear_events();
3793	clearstats();
3794	GrabTo = UseErrorsTo = false;
3795	ExitStat = EX_OK;
3796	if (forkflag)
3797	{
3798		disconnect(1, el);
3799		set_op_mode(MD_QUEUERUN);
3800	}
3801	if (LogLevel > 76)
3802		sm_syslog(LOG_DEBUG, el->e_id, "doworklist, pid=%d",
3803			  (int) CurrentPid);
3804
3805	for (ei = el; ei != NULL; ei = ei->e_sibling)
3806	{
3807		ENVELOPE e;
3808		SM_RPOOL_T *rpool;
3809
3810		if (WILL_BE_QUEUED(ei->e_sendmode))
3811			continue;
3812		else if (QueueMode != QM_QUARANTINE &&
3813			 ei->e_quarmsg != NULL)
3814			continue;
3815
3816		rpool = sm_rpool_new_x(NULL);
3817		clearenvelope(&e, true, rpool);
3818		e.e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
3819		set_delivery_mode(SM_DELIVER, &e);
3820		e.e_errormode = EM_MAIL;
3821		e.e_id = ei->e_id;
3822		e.e_qgrp = ei->e_qgrp;
3823		e.e_qdir = ei->e_qdir;
3824		openxscript(&e);
3825		sm_setproctitle(true, &e, "%s from queue", qid_printname(&e));
3826
3827		/* don't use the headers from sendmail.cf... */
3828		e.e_header = NULL;
3829		CurEnv = &e;
3830
3831		/* read the queue control file -- return if locked */
3832		if (readqf(&e, false))
3833		{
3834			e.e_flags |= EF_INQUEUE;
3835			eatheader(&e, requeueflag, true);
3836
3837			if (requeueflag)
3838				queueup(&e, false, false);
3839
3840			/* do the delivery */
3841			sendall(&e, SM_DELIVER);
3842			dropenvelope(&e, true, false);
3843		}
3844		else
3845		{
3846			if (tTd(40, 4) && e.e_id != NULL)
3847				sm_dprintf("readqf(%s) failed\n",
3848					qid_printname(&e));
3849		}
3850		sm_rpool_free(rpool);
3851		ei->e_id = NULL;
3852	}
3853
3854	/* restore CurEnv */
3855	CurEnv = el;
3856
3857	/* finish up and exit */
3858	if (forkflag)
3859		finis(true, true, ExitStat);
3860	return 0;
3861}
3862/*
3863**  READQF -- read queue file and set up environment.
3864**
3865**	Parameters:
3866**		e -- the envelope of the job to run.
3867**		openonly -- only open the qf (returned as e_lockfp)
3868**
3869**	Returns:
3870**		true if it successfully read the queue file.
3871**		false otherwise.
3872**
3873**	Side Effects:
3874**		The queue file is returned locked.
3875*/
3876
3877static bool
3878readqf(e, openonly)
3879	register ENVELOPE *e;
3880	bool openonly;
3881{
3882	register SM_FILE_T *qfp;
3883	ADDRESS *ctladdr;
3884	struct stat st, stf;
3885	char *bp;
3886	int qfver = 0;
3887	long hdrsize = 0;
3888	register char *p;
3889	char *frcpt = NULL;
3890	char *orcpt = NULL;
3891	bool nomore = false;
3892	bool bogus = false;
3893	MODE_T qsafe;
3894	char *err;
3895	char qf[MAXPATHLEN];
3896	char buf[MAXLINE];
3897
3898	/*
3899	**  Read and process the file.
3900	*/
3901
3902	(void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER), sizeof qf);
3903	qfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDWR_B, NULL);
3904	if (qfp == NULL)
3905	{
3906		int save_errno = errno;
3907
3908		if (tTd(40, 8))
3909			sm_dprintf("readqf(%s): sm_io_open failure (%s)\n",
3910				qf, sm_errstring(errno));
3911		errno = save_errno;
3912		if (errno != ENOENT
3913		    )
3914			syserr("readqf: no control file %s", qf);
3915		RELEASE_QUEUE;
3916		return false;
3917	}
3918
3919	if (!lockfile(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), qf, NULL,
3920		      LOCK_EX|LOCK_NB))
3921	{
3922		/* being processed by another queuer */
3923		if (Verbose)
3924			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3925					     "%s: locked\n", e->e_id);
3926		if (tTd(40, 8))
3927			sm_dprintf("%s: locked\n", e->e_id);
3928		if (LogLevel > 19)
3929			sm_syslog(LOG_DEBUG, e->e_id, "locked");
3930		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
3931		RELEASE_QUEUE;
3932		return false;
3933	}
3934
3935	RELEASE_QUEUE;
3936
3937	/*
3938	**  Prevent locking race condition.
3939	**
3940	**  Process A: readqf(): qfp = fopen(qffile)
3941	**  Process B: queueup(): rename(tf, qf)
3942	**  Process B: unlocks(tf)
3943	**  Process A: lockfile(qf);
3944	**
3945	**  Process A (us) has the old qf file (before the rename deleted
3946	**  the directory entry) and will be delivering based on old data.
3947	**  This can lead to multiple deliveries of the same recipients.
3948	**
3949	**  Catch this by checking if the underlying qf file has changed
3950	**  *after* acquiring our lock and if so, act as though the file
3951	**  was still locked (i.e., just return like the lockfile() case
3952	**  above.
3953	*/
3954
3955	if (stat(qf, &stf) < 0 ||
3956	    fstat(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), &st) < 0)
3957	{
3958		/* must have been being processed by someone else */
3959		if (tTd(40, 8))
3960			sm_dprintf("readqf(%s): [f]stat failure (%s)\n",
3961				qf, sm_errstring(errno));
3962		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
3963		return false;
3964	}
3965
3966	if (st.st_nlink != stf.st_nlink ||
3967	    st.st_dev != stf.st_dev ||
3968	    ST_INODE(st) != ST_INODE(stf) ||
3969#if HAS_ST_GEN && 0		/* AFS returns garbage in st_gen */
3970	    st.st_gen != stf.st_gen ||
3971#endif /* HAS_ST_GEN && 0 */
3972	    st.st_uid != stf.st_uid ||
3973	    st.st_gid != stf.st_gid ||
3974	    st.st_size != stf.st_size)
3975	{
3976		/* changed after opened */
3977		if (Verbose)
3978			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3979					     "%s: changed\n", e->e_id);
3980		if (tTd(40, 8))
3981			sm_dprintf("%s: changed\n", e->e_id);
3982		if (LogLevel > 19)
3983			sm_syslog(LOG_DEBUG, e->e_id, "changed");
3984		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
3985		return false;
3986	}
3987
3988	/*
3989	**  Check the queue file for plausibility to avoid attacks.
3990	*/
3991
3992	qsafe = S_IWOTH|S_IWGRP;
3993	if (bitset(S_IWGRP, QueueFileMode))
3994		qsafe &= ~S_IWGRP;
3995
3996	bogus = st.st_uid != geteuid() &&
3997		st.st_uid != TrustedUid &&
3998		geteuid() != RealUid;
3999
4000	/*
4001	**  If this qf file results from a set-group-ID binary, then
4002	**  we check whether the directory is group-writable,
4003	**  the queue file mode contains the group-writable bit, and
4004	**  the groups are the same.
4005	**  Notice: this requires that the set-group-ID binary is used to
4006	**  run the queue!
4007	*/
4008
4009	if (bogus && st.st_gid == getegid() && UseMSP)
4010	{
4011		char delim;
4012		struct stat dst;
4013
4014		bp = SM_LAST_DIR_DELIM(qf);
4015		if (bp == NULL)
4016			delim = '\0';
4017		else
4018		{
4019			delim = *bp;
4020			*bp = '\0';
4021		}
4022		if (stat(delim == '\0' ? "." : qf, &dst) < 0)
4023			syserr("readqf: cannot stat directory %s",
4024				delim == '\0' ? "." : qf);
4025		else
4026		{
4027			bogus = !(bitset(S_IWGRP, QueueFileMode) &&
4028				  bitset(S_IWGRP, dst.st_mode) &&
4029				  dst.st_gid == st.st_gid);
4030		}
4031		if (delim != '\0')
4032			*bp = delim;
4033	}
4034	if (!bogus)
4035		bogus = bitset(qsafe, st.st_mode);
4036	if (bogus)
4037	{
4038		if (LogLevel > 0)
4039		{
4040			sm_syslog(LOG_ALERT, e->e_id,
4041				  "bogus queue file, uid=%d, gid=%d, mode=%o",
4042				  st.st_uid, st.st_gid, st.st_mode);
4043		}
4044		if (tTd(40, 8))
4045			sm_dprintf("readqf(%s): bogus file\n", qf);
4046		e->e_flags |= EF_INQUEUE;
4047		if (!openonly)
4048			loseqfile(e, "bogus file uid/gid in mqueue");
4049		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
4050		return false;
4051	}
4052
4053	if (st.st_size == 0)
4054	{
4055		/* must be a bogus file -- if also old, just remove it */
4056		if (!openonly && st.st_ctime + 10 * 60 < curtime())
4057		{
4058			(void) xunlink(queuename(e, DATAFL_LETTER));
4059			(void) xunlink(queuename(e, ANYQFL_LETTER));
4060		}
4061		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
4062		return false;
4063	}
4064
4065	if (st.st_nlink == 0)
4066	{
4067		/*
4068		**  Race condition -- we got a file just as it was being
4069		**  unlinked.  Just assume it is zero length.
4070		*/
4071
4072		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
4073		return false;
4074	}
4075
4076#if _FFR_TRUSTED_QF
4077	/*
4078	**  If we don't own the file mark it as unsafe.
4079	**  However, allow TrustedUser to own it as well
4080	**  in case TrustedUser manipulates the queue.
4081	*/
4082
4083	if (st.st_uid != geteuid() && st.st_uid != TrustedUid)
4084		e->e_flags |= EF_UNSAFE;
4085#else /* _FFR_TRUSTED_QF */
4086	/* If we don't own the file mark it as unsafe */
4087	if (st.st_uid != geteuid())
4088		e->e_flags |= EF_UNSAFE;
4089#endif /* _FFR_TRUSTED_QF */
4090
4091	/* good file -- save this lock */
4092	e->e_lockfp = qfp;
4093
4094	/* Just wanted the open file */
4095	if (openonly)
4096		return true;
4097
4098	/* do basic system initialization */
4099	initsys(e);
4100	macdefine(&e->e_macro, A_PERM, 'i', e->e_id);
4101
4102	LineNumber = 0;
4103	e->e_flags |= EF_GLOBALERRS;
4104	set_op_mode(MD_QUEUERUN);
4105	ctladdr = NULL;
4106	e->e_qfletter = queue_letter(e, ANYQFL_LETTER);
4107	e->e_dfqgrp = e->e_qgrp;
4108	e->e_dfqdir = e->e_qdir;
4109#if _FFR_QUEUE_MACRO
4110	macdefine(&e->e_macro, A_TEMP, macid("{queue}"),
4111		  qid_printqueue(e->e_qgrp, e->e_qdir));
4112#endif /* _FFR_QUEUE_MACRO */
4113	e->e_dfino = -1;
4114	e->e_msgsize = -1;
4115	while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
4116	{
4117		unsigned long qflags;
4118		ADDRESS *q;
4119		int r;
4120		time_t now;
4121		auto char *ep;
4122
4123		if (tTd(40, 4))
4124			sm_dprintf("+++++ %s\n", bp);
4125		if (nomore)
4126		{
4127			/* hack attack */
4128  hackattack:
4129			syserr("SECURITY ALERT: extra or bogus data in queue file: %s",
4130			       bp);
4131			err = "bogus queue line";
4132			goto fail;
4133		}
4134		switch (bp[0])
4135		{
4136		  case 'A':		/* AUTH= parameter */
4137			if (!xtextok(&bp[1]))
4138				goto hackattack;
4139			e->e_auth_param = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4140			break;
4141
4142		  case 'B':		/* body type */
4143			r = check_bodytype(&bp[1]);
4144			if (!BODYTYPE_VALID(r))
4145				goto hackattack;
4146			e->e_bodytype = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4147			break;
4148
4149		  case 'C':		/* specify controlling user */
4150			ctladdr = setctluser(&bp[1], qfver, e);
4151			break;
4152
4153		  case 'D':		/* data file name */
4154			/* obsolete -- ignore */
4155			break;
4156
4157		  case 'd':		/* data file directory name */
4158			{
4159				int qgrp, qdir;
4160
4161#if _FFR_MSP_PARANOIA
4162				/* forbid queue groups in MSP? */
4163				if (UseMSP)
4164					goto hackattack;
4165#endif /* _FFR_MSP_PARANOIA */
4166				for (qgrp = 0;
4167				     qgrp < NumQueue && Queue[qgrp] != NULL;
4168				     ++qgrp)
4169				{
4170					for (qdir = 0;
4171					     qdir < Queue[qgrp]->qg_numqueues;
4172					     ++qdir)
4173					{
4174						if (strcmp(&bp[1],
4175							   Queue[qgrp]->qg_qpaths[qdir].qp_name)
4176						    == 0)
4177						{
4178							e->e_dfqgrp = qgrp;
4179							e->e_dfqdir = qdir;
4180							goto done;
4181						}
4182					}
4183				}
4184				err = "bogus queue file directory";
4185				goto fail;
4186			  done:
4187				break;
4188			}
4189
4190		  case 'E':		/* specify error recipient */
4191			/* no longer used */
4192			break;
4193
4194		  case 'F':		/* flag bits */
4195			if (strncmp(bp, "From ", 5) == 0)
4196			{
4197				/* we are being spoofed! */
4198				syserr("SECURITY ALERT: bogus qf line %s", bp);
4199				err = "bogus queue line";
4200				goto fail;
4201			}
4202			for (p = &bp[1]; *p != '\0'; p++)
4203			{
4204				switch (*p)
4205				{
4206				  case '8':	/* has 8 bit data */
4207					e->e_flags |= EF_HAS8BIT;
4208					break;
4209
4210				  case 'b':	/* delete Bcc: header */
4211					e->e_flags |= EF_DELETE_BCC;
4212					break;
4213
4214				  case 'd':	/* envelope has DSN RET= */
4215					e->e_flags |= EF_RET_PARAM;
4216					break;
4217
4218				  case 'n':	/* don't return body */
4219					e->e_flags |= EF_NO_BODY_RETN;
4220					break;
4221
4222				  case 'r':	/* response */
4223					e->e_flags |= EF_RESPONSE;
4224					break;
4225
4226				  case 's':	/* split */
4227					e->e_flags |= EF_SPLIT;
4228					break;
4229
4230				  case 'w':	/* warning sent */
4231					e->e_flags |= EF_WARNING;
4232					break;
4233				}
4234			}
4235			break;
4236
4237		  case 'q':		/* quarantine reason */
4238			e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4239			macdefine(&e->e_macro, A_PERM,
4240				  macid("{quarantine}"), e->e_quarmsg);
4241			break;
4242
4243		  case 'H':		/* header */
4244
4245			/*
4246			**  count size before chompheader() destroys the line.
4247			**  this isn't accurate due to macro expansion, but
4248			**  better than before. "-3" to skip H?? at least.
4249			*/
4250
4251			hdrsize += strlen(bp) - 3;
4252			(void) chompheader(&bp[1], CHHDR_QUEUE, NULL, e);
4253			break;
4254
4255		  case 'I':		/* data file's inode number */
4256			/* regenerated below */
4257			break;
4258
4259		  case 'K':		/* time of last delivery attempt */
4260			e->e_dtime = atol(&buf[1]);
4261			break;
4262
4263		  case 'L':		/* Solaris Content-Length: */
4264		  case 'M':		/* message */
4265			/* ignore this; we want a new message next time */
4266			break;
4267
4268		  case 'N':		/* number of delivery attempts */
4269			e->e_ntries = atoi(&buf[1]);
4270
4271			/* if this has been tried recently, let it be */
4272			now = curtime();
4273			if (e->e_ntries > 0 && e->e_dtime <= now &&
4274			    now < e->e_dtime + MinQueueAge)
4275			{
4276				char *howlong;
4277
4278				howlong = pintvl(now - e->e_dtime, true);
4279				if (Verbose)
4280					(void) sm_io_fprintf(smioout,
4281							     SM_TIME_DEFAULT,
4282							     "%s: too young (%s)\n",
4283							     e->e_id, howlong);
4284				if (tTd(40, 8))
4285					sm_dprintf("%s: too young (%s)\n",
4286						e->e_id, howlong);
4287				if (LogLevel > 19)
4288					sm_syslog(LOG_DEBUG, e->e_id,
4289						  "too young (%s)",
4290						  howlong);
4291				e->e_id = NULL;
4292				unlockqueue(e);
4293				return false;
4294			}
4295			macdefine(&e->e_macro, A_TEMP,
4296				macid("{ntries}"), &buf[1]);
4297
4298#if NAMED_BIND
4299			/* adjust BIND parameters immediately */
4300			if (e->e_ntries == 0)
4301			{
4302				_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
4303				_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
4304			}
4305			else
4306			{
4307				_res.retry = TimeOuts.res_retry[RES_TO_NORMAL];
4308				_res.retrans = TimeOuts.res_retrans[RES_TO_NORMAL];
4309			}
4310#endif /* NAMED_BIND */
4311			break;
4312
4313		  case 'P':		/* message priority */
4314			e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
4315			break;
4316
4317		  case 'Q':		/* original recipient */
4318			orcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4319			break;
4320
4321		  case 'r':		/* final recipient */
4322			frcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4323			break;
4324
4325		  case 'R':		/* specify recipient */
4326			p = bp;
4327			qflags = 0;
4328			if (qfver >= 1)
4329			{
4330				/* get flag bits */
4331				while (*++p != '\0' && *p != ':')
4332				{
4333					switch (*p)
4334					{
4335					  case 'N':
4336						qflags |= QHASNOTIFY;
4337						break;
4338
4339					  case 'S':
4340						qflags |= QPINGONSUCCESS;
4341						break;
4342
4343					  case 'F':
4344						qflags |= QPINGONFAILURE;
4345						break;
4346
4347					  case 'D':
4348						qflags |= QPINGONDELAY;
4349						break;
4350
4351					  case 'P':
4352						qflags |= QPRIMARY;
4353						break;
4354
4355					  case 'A':
4356						if (ctladdr != NULL)
4357							ctladdr->q_flags |= QALIAS;
4358						break;
4359
4360					  default: /* ignore or complain? */
4361						break;
4362					}
4363				}
4364			}
4365			else
4366				qflags |= QPRIMARY;
4367			macdefine(&e->e_macro, A_PERM, macid("{addr_type}"),
4368				"e r");
4369			if (*p != '\0')
4370				q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0',
4371						NULL, e, true);
4372			else
4373				q = NULL;
4374			if (q != NULL)
4375			{
4376				/* make sure we keep the current qgrp */
4377				if (ISVALIDQGRP(e->e_qgrp))
4378					q->q_qgrp = e->e_qgrp;
4379				q->q_alias = ctladdr;
4380				if (qfver >= 1)
4381					q->q_flags &= ~Q_PINGFLAGS;
4382				q->q_flags |= qflags;
4383				q->q_finalrcpt = frcpt;
4384				q->q_orcpt = orcpt;
4385				(void) recipient(q, &e->e_sendqueue, 0, e);
4386			}
4387			frcpt = NULL;
4388			orcpt = NULL;
4389			macdefine(&e->e_macro, A_PERM, macid("{addr_type}"),
4390				NULL);
4391			break;
4392
4393		  case 'S':		/* sender */
4394			setsender(sm_rpool_strdup_x(e->e_rpool, &bp[1]),
4395				  e, NULL, '\0', true);
4396			break;
4397
4398		  case 'T':		/* init time */
4399			e->e_ctime = atol(&bp[1]);
4400			break;
4401
4402		  case 'V':		/* queue file version number */
4403			qfver = atoi(&bp[1]);
4404			if (qfver <= QF_VERSION)
4405				break;
4406			syserr("Version number in queue file (%d) greater than max (%d)",
4407				qfver, QF_VERSION);
4408			err = "unsupported queue file version";
4409			goto fail;
4410			/* NOTREACHED */
4411			break;
4412
4413		  case 'Z':		/* original envelope id from ESMTP */
4414			e->e_envid = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
4415			macdefine(&e->e_macro, A_PERM,
4416				macid("{dsn_envid}"), e->e_envid);
4417			break;
4418
4419		  case '!':		/* deliver by */
4420
4421			/* format: flag (1 char) space long-integer */
4422			e->e_dlvr_flag = buf[1];
4423			e->e_deliver_by = strtol(&buf[3], NULL, 10);
4424
4425		  case '$':		/* define macro */
4426			{
4427				char *p;
4428
4429				/* XXX elimate p? */
4430				r = macid_parse(&bp[1], &ep);
4431				if (r == 0)
4432					break;
4433				p = sm_rpool_strdup_x(e->e_rpool, ep);
4434				macdefine(&e->e_macro, A_PERM, r, p);
4435			}
4436			break;
4437
4438		  case '.':		/* terminate file */
4439			nomore = true;
4440			break;
4441
4442#if _FFR_QUEUEDELAY
4443		  case 'G':
4444		  case 'Y':
4445
4446			/*
4447			**  Maintain backward compatibility for
4448			**  users who defined _FFR_QUEUEDELAY in
4449			**  previous releases.  Remove this
4450			**  code in 8.14 or 8.15.
4451			*/
4452
4453			if (qfver == 5 || qfver == 7)
4454				break;
4455
4456			/* If not qfver 5 or 7, then 'G' or 'Y' is invalid */
4457			/* FALLTHROUGH */
4458#endif /* _FFR_QUEUEDELAY */
4459
4460		  default:
4461			syserr("readqf: %s: line %d: bad line \"%s\"",
4462				qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
4463			err = "unrecognized line";
4464			goto fail;
4465		}
4466
4467		if (bp != buf)
4468			sm_free(bp); /* XXX */
4469	}
4470
4471	/*
4472	**  If we haven't read any lines, this queue file is empty.
4473	**  Arrange to remove it without referencing any null pointers.
4474	*/
4475
4476	if (LineNumber == 0)
4477	{
4478		errno = 0;
4479		e->e_flags |= EF_CLRQUEUE|EF_FATALERRS|EF_RESPONSE;
4480		return true;
4481	}
4482
4483	/* Check to make sure we have a complete queue file read */
4484	if (!nomore)
4485	{
4486		syserr("readqf: %s: incomplete queue file read", qf);
4487		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
4488		return false;
4489	}
4490
4491	/* possibly set ${dsn_ret} macro */
4492	if (bitset(EF_RET_PARAM, e->e_flags))
4493	{
4494		if (bitset(EF_NO_BODY_RETN, e->e_flags))
4495			macdefine(&e->e_macro, A_PERM,
4496				macid("{dsn_ret}"), "hdrs");
4497		else
4498			macdefine(&e->e_macro, A_PERM,
4499				macid("{dsn_ret}"), "full");
4500	}
4501
4502	/*
4503	**  Arrange to read the data file.
4504	*/
4505
4506	p = queuename(e, DATAFL_LETTER);
4507	e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, p, SM_IO_RDONLY_B,
4508			      NULL);
4509	if (e->e_dfp == NULL)
4510	{
4511		syserr("readqf: cannot open %s", p);
4512	}
4513	else
4514	{
4515		e->e_flags |= EF_HAS_DF;
4516		if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &st)
4517		    >= 0)
4518		{
4519			e->e_msgsize = st.st_size + hdrsize;
4520			e->e_dfdev = st.st_dev;
4521			e->e_dfino = ST_INODE(st);
4522			(void) sm_snprintf(buf, sizeof buf, "%ld",
4523					   e->e_msgsize);
4524			macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"),
4525				  buf);
4526		}
4527	}
4528
4529	return true;
4530
4531  fail:
4532	/*
4533	**  There was some error reading the qf file (reason is in err var.)
4534	**  Cleanup:
4535	**	close file; clear e_lockfp since it is the same as qfp,
4536	**	hence it is invalid (as file) after qfp is closed;
4537	**	the qf file is on disk, so set the flag to avoid calling
4538	**	queueup() with bogus data.
4539	*/
4540
4541	if (qfp != NULL)
4542		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
4543	e->e_lockfp = NULL;
4544	e->e_flags |= EF_INQUEUE;
4545	loseqfile(e, err);
4546	return false;
4547}
4548/*
4549**  PRTSTR -- print a string, "unprintable" characters are shown as \oct
4550**
4551**	Parameters:
4552**		s -- string to print
4553**		ml -- maximum length of output
4554**
4555**	Returns:
4556**		number of entries
4557**
4558**	Side Effects:
4559**		Prints a string on stdout.
4560*/
4561
4562static void
4563prtstr(s, ml)
4564	char *s;
4565	int ml;
4566{
4567	int c;
4568
4569	if (s == NULL)
4570		return;
4571	while (ml-- > 0 && ((c = *s++) != '\0'))
4572	{
4573		if (c == '\\')
4574		{
4575			if (ml-- > 0)
4576			{
4577				(void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
4578				(void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
4579			}
4580		}
4581		else if (isascii(c) && isprint(c))
4582			(void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
4583		else
4584		{
4585			if ((ml -= 3) > 0)
4586				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4587						     "\\%03o", c & 0xFF);
4588		}
4589	}
4590}
4591/*
4592**  PRINTNQE -- print out number of entries in the mail queue
4593**
4594**	Parameters:
4595**		out -- output file pointer.
4596**		prefix -- string to output in front of each line.
4597**
4598**	Returns:
4599**		none.
4600*/
4601
4602void
4603printnqe(out, prefix)
4604	SM_FILE_T *out;
4605	char *prefix;
4606{
4607#if SM_CONF_SHM
4608	int i, k = 0, nrequests = 0;
4609	bool unknown = false;
4610
4611	if (ShmId == SM_SHM_NO_ID)
4612	{
4613		if (prefix == NULL)
4614			(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4615					"Data unavailable: shared memory not updated\n");
4616		else
4617			(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4618					"%sNOTCONFIGURED:-1\r\n", prefix);
4619		return;
4620	}
4621	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
4622	{
4623		int j;
4624
4625		k++;
4626		for (j = 0; j < Queue[i]->qg_numqueues; j++)
4627		{
4628			int n;
4629
4630			if (StopRequest)
4631				stop_sendmail();
4632
4633			n = QSHM_ENTRIES(Queue[i]->qg_qpaths[j].qp_idx);
4634			if (prefix != NULL)
4635				(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4636					"%s%s:%d\r\n",
4637					prefix, qid_printqueue(i, j), n);
4638			else if (n < 0)
4639			{
4640				(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4641					"%s: unknown number of entries\n",
4642					qid_printqueue(i, j));
4643				unknown = true;
4644			}
4645			else if (n == 0)
4646			{
4647				(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4648					"%s is empty\n",
4649					qid_printqueue(i, j));
4650			}
4651			else if (n > 0)
4652			{
4653				(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4654					"%s: entries=%d\n",
4655					qid_printqueue(i, j), n);
4656				nrequests += n;
4657				k++;
4658			}
4659		}
4660	}
4661	if (prefix == NULL && k > 1)
4662		(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4663				     "\t\tTotal requests: %d%s\n",
4664				     nrequests, unknown ? " (about)" : "");
4665#else /* SM_CONF_SHM */
4666	if (prefix == NULL)
4667		(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4668			     "Data unavailable without shared memory support\n");
4669	else
4670		(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4671			     "%sNOTAVAILABLE:-1\r\n", prefix);
4672#endif /* SM_CONF_SHM */
4673}
4674/*
4675**  PRINTQUEUE -- print out a representation of the mail queue
4676**
4677**	Parameters:
4678**		none.
4679**
4680**	Returns:
4681**		none.
4682**
4683**	Side Effects:
4684**		Prints a listing of the mail queue on the standard output.
4685*/
4686
4687void
4688printqueue()
4689{
4690	int i, k = 0, nrequests = 0;
4691
4692	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
4693	{
4694		int j;
4695
4696		k++;
4697		for (j = 0; j < Queue[i]->qg_numqueues; j++)
4698		{
4699			if (StopRequest)
4700				stop_sendmail();
4701			nrequests += print_single_queue(i, j);
4702			k++;
4703		}
4704	}
4705	if (k > 1)
4706		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4707				     "\t\tTotal requests: %d\n",
4708				     nrequests);
4709}
4710/*
4711**  PRINT_SINGLE_QUEUE -- print out a representation of a single mail queue
4712**
4713**	Parameters:
4714**		qgrp -- the index of the queue group.
4715**		qdir -- the queue directory.
4716**
4717**	Returns:
4718**		number of requests in mail queue.
4719**
4720**	Side Effects:
4721**		Prints a listing of the mail queue on the standard output.
4722*/
4723
4724int
4725print_single_queue(qgrp, qdir)
4726	int qgrp;
4727	int qdir;
4728{
4729	register WORK *w;
4730	SM_FILE_T *f;
4731	int nrequests;
4732	char qd[MAXPATHLEN];
4733	char qddf[MAXPATHLEN];
4734	char buf[MAXLINE];
4735
4736	if (qdir == NOQDIR)
4737	{
4738		(void) sm_strlcpy(qd, ".", sizeof qd);
4739		(void) sm_strlcpy(qddf, ".", sizeof qddf);
4740	}
4741	else
4742	{
4743		(void) sm_strlcpyn(qd, sizeof qd, 2,
4744			Queue[qgrp]->qg_qpaths[qdir].qp_name,
4745			(bitset(QP_SUBQF,
4746				Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
4747					? "/qf" : ""));
4748		(void) sm_strlcpyn(qddf, sizeof qddf, 2,
4749			Queue[qgrp]->qg_qpaths[qdir].qp_name,
4750			(bitset(QP_SUBDF,
4751				Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
4752					? "/df" : ""));
4753	}
4754
4755	/*
4756	**  Check for permission to print the queue
4757	*/
4758
4759	if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
4760	{
4761		struct stat st;
4762#ifdef NGROUPS_MAX
4763		int n;
4764		extern GIDSET_T InitialGidSet[NGROUPS_MAX];
4765#endif /* NGROUPS_MAX */
4766
4767		if (stat(qd, &st) < 0)
4768		{
4769			syserr("Cannot stat %s",
4770				qid_printqueue(qgrp, qdir));
4771			return 0;
4772		}
4773#ifdef NGROUPS_MAX
4774		n = NGROUPS_MAX;
4775		while (--n >= 0)
4776		{
4777			if (InitialGidSet[n] == st.st_gid)
4778				break;
4779		}
4780		if (n < 0 && RealGid != st.st_gid)
4781#else /* NGROUPS_MAX */
4782		if (RealGid != st.st_gid)
4783#endif /* NGROUPS_MAX */
4784		{
4785			usrerr("510 You are not permitted to see the queue");
4786			setstat(EX_NOPERM);
4787			return 0;
4788		}
4789	}
4790
4791	/*
4792	**  Read and order the queue.
4793	*/
4794
4795	nrequests = gatherq(qgrp, qdir, true, NULL, NULL);
4796	(void) sortq(Queue[qgrp]->qg_maxlist);
4797
4798	/*
4799	**  Print the work list that we have read.
4800	*/
4801
4802	/* first see if there is anything */
4803	if (nrequests <= 0)
4804	{
4805		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s is empty\n",
4806				     qid_printqueue(qgrp, qdir));
4807		return 0;
4808	}
4809
4810	sm_getla();	/* get load average */
4811
4812	(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\t\t%s (%d request%s",
4813			     qid_printqueue(qgrp, qdir),
4814			     nrequests, nrequests == 1 ? "" : "s");
4815	if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
4816		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4817				     ", only %d printed", MaxQueueRun);
4818	if (Verbose)
4819		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4820			")\n-----Q-ID----- --Size-- -Priority- ---Q-Time--- --------Sender/Recipient--------\n");
4821	else
4822		(void) sm_io_fprintf(smioout,  SM_TIME_DEFAULT,
4823			")\n-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------\n");
4824	for (w = WorkQ; w != NULL; w = w->w_next)
4825	{
4826		struct stat st;
4827		auto time_t submittime = 0;
4828		long dfsize;
4829		int flags = 0;
4830		int qfver;
4831		char quarmsg[MAXLINE];
4832		char statmsg[MAXLINE];
4833		char bodytype[MAXNAME + 1];
4834		char qf[MAXPATHLEN];
4835
4836		if (StopRequest)
4837			stop_sendmail();
4838
4839		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%13s",
4840				     w->w_name + 2);
4841		(void) sm_strlcpyn(qf, sizeof qf, 3, qd, "/", w->w_name);
4842		f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY_B,
4843			       NULL);
4844		if (f == NULL)
4845		{
4846			if (errno == EPERM)
4847				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4848						     " (permission denied)\n");
4849			else if (errno == ENOENT)
4850				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4851						     " (job completed)\n");
4852			else
4853				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4854						     " (%s)\n",
4855						     sm_errstring(errno));
4856			errno = 0;
4857			continue;
4858		}
4859		w->w_name[0] = DATAFL_LETTER;
4860		(void) sm_strlcpyn(qf, sizeof qf, 3, qddf, "/", w->w_name);
4861		if (stat(qf, &st) >= 0)
4862			dfsize = st.st_size;
4863		else
4864		{
4865			ENVELOPE e;
4866
4867			/*
4868			**  Maybe the df file can't be statted because
4869			**  it is in a different directory than the qf file.
4870			**  In order to find out, we must read the qf file.
4871			*/
4872
4873			newenvelope(&e, &BlankEnvelope, sm_rpool_new_x(NULL));
4874			e.e_id = w->w_name + 2;
4875			e.e_qgrp = qgrp;
4876			e.e_qdir = qdir;
4877			dfsize = -1;
4878			if (readqf(&e, false))
4879			{
4880				char *df = queuename(&e, DATAFL_LETTER);
4881				if (stat(df, &st) >= 0)
4882					dfsize = st.st_size;
4883			}
4884			if (e.e_lockfp != NULL)
4885			{
4886				(void) sm_io_close(e.e_lockfp, SM_TIME_DEFAULT);
4887				e.e_lockfp = NULL;
4888			}
4889			clearenvelope(&e, false, e.e_rpool);
4890			sm_rpool_free(e.e_rpool);
4891		}
4892		if (w->w_lock)
4893			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "*");
4894		else if (QueueMode == QM_LOST)
4895			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "?");
4896		else if (w->w_tooyoung)
4897			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "-");
4898		else if (shouldqueue(w->w_pri, w->w_ctime))
4899			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "X");
4900		else
4901			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " ");
4902
4903		errno = 0;
4904
4905		quarmsg[0] = '\0';
4906		statmsg[0] = bodytype[0] = '\0';
4907		qfver = 0;
4908		while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
4909		{
4910			register int i;
4911			register char *p;
4912
4913			if (StopRequest)
4914				stop_sendmail();
4915
4916			fixcrlf(buf, true);
4917			switch (buf[0])
4918			{
4919			  case 'V':	/* queue file version */
4920				qfver = atoi(&buf[1]);
4921				break;
4922
4923			  case 'M':	/* error message */
4924				if ((i = strlen(&buf[1])) >= sizeof statmsg)
4925					i = sizeof statmsg - 1;
4926				memmove(statmsg, &buf[1], i);
4927				statmsg[i] = '\0';
4928				break;
4929
4930			  case 'q':	/* quarantine reason */
4931				if ((i = strlen(&buf[1])) >= sizeof quarmsg)
4932					i = sizeof quarmsg - 1;
4933				memmove(quarmsg, &buf[1], i);
4934				quarmsg[i] = '\0';
4935				break;
4936
4937			  case 'B':	/* body type */
4938				if ((i = strlen(&buf[1])) >= sizeof bodytype)
4939					i = sizeof bodytype - 1;
4940				memmove(bodytype, &buf[1], i);
4941				bodytype[i] = '\0';
4942				break;
4943
4944			  case 'S':	/* sender name */
4945				if (Verbose)
4946				{
4947					(void) sm_io_fprintf(smioout,
4948						SM_TIME_DEFAULT,
4949						"%8ld %10ld%c%.12s ",
4950						dfsize,
4951						w->w_pri,
4952						bitset(EF_WARNING, flags)
4953							? '+' : ' ',
4954						ctime(&submittime) + 4);
4955					prtstr(&buf[1], 78);
4956				}
4957				else
4958				{
4959					(void) sm_io_fprintf(smioout,
4960						SM_TIME_DEFAULT,
4961						"%8ld %.16s ",
4962						dfsize,
4963						ctime(&submittime));
4964					prtstr(&buf[1], 39);
4965				}
4966
4967				if (quarmsg[0] != '\0')
4968				{
4969					(void) sm_io_fprintf(smioout,
4970							     SM_TIME_DEFAULT,
4971							     "\n     QUARANTINE: %.*s",
4972							     Verbose ? 100 : 60,
4973							     quarmsg);
4974					quarmsg[0] = '\0';
4975				}
4976
4977				if (statmsg[0] != '\0' || bodytype[0] != '\0')
4978				{
4979					(void) sm_io_fprintf(smioout,
4980						SM_TIME_DEFAULT,
4981						"\n    %10.10s",
4982						bodytype);
4983					if (statmsg[0] != '\0')
4984						(void) sm_io_fprintf(smioout,
4985							SM_TIME_DEFAULT,
4986							"   (%.*s)",
4987							Verbose ? 100 : 60,
4988							statmsg);
4989					statmsg[0] = '\0';
4990				}
4991				break;
4992
4993			  case 'C':	/* controlling user */
4994				if (Verbose)
4995					(void) sm_io_fprintf(smioout,
4996						SM_TIME_DEFAULT,
4997						"\n\t\t\t\t\t\t(---%.64s---)",
4998						&buf[1]);
4999				break;
5000
5001			  case 'R':	/* recipient name */
5002				p = &buf[1];
5003				if (qfver >= 1)
5004				{
5005					p = strchr(p, ':');
5006					if (p == NULL)
5007						break;
5008					p++;
5009				}
5010				if (Verbose)
5011				{
5012					(void) sm_io_fprintf(smioout,
5013							SM_TIME_DEFAULT,
5014							"\n\t\t\t\t\t\t");
5015					prtstr(p, 71);
5016				}
5017				else
5018				{
5019					(void) sm_io_fprintf(smioout,
5020							SM_TIME_DEFAULT,
5021							"\n\t\t\t\t\t ");
5022					prtstr(p, 38);
5023				}
5024				if (Verbose && statmsg[0] != '\0')
5025				{
5026					(void) sm_io_fprintf(smioout,
5027							SM_TIME_DEFAULT,
5028							"\n\t\t (%.100s)",
5029							statmsg);
5030					statmsg[0] = '\0';
5031				}
5032				break;
5033
5034			  case 'T':	/* creation time */
5035				submittime = atol(&buf[1]);
5036				break;
5037
5038			  case 'F':	/* flag bits */
5039				for (p = &buf[1]; *p != '\0'; p++)
5040				{
5041					switch (*p)
5042					{
5043					  case 'w':
5044						flags |= EF_WARNING;
5045						break;
5046					}
5047				}
5048			}
5049		}
5050		if (submittime == (time_t) 0)
5051			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
5052					     " (no control file)");
5053		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n");
5054		(void) sm_io_close(f, SM_TIME_DEFAULT);
5055	}
5056	return nrequests;
5057}
5058
5059/*
5060**  QUEUE_LETTER -- get the proper queue letter for the current QueueMode.
5061**
5062**	Parameters:
5063**		e -- envelope to build it in/from.
5064**		type -- the file type, used as the first character
5065**			of the file name.
5066**
5067**	Returns:
5068**		the letter to use
5069*/
5070
5071static char
5072queue_letter(e, type)
5073	ENVELOPE *e;
5074	int type;
5075{
5076	/* Change type according to QueueMode */
5077	if (type == ANYQFL_LETTER)
5078	{
5079		if (e->e_quarmsg != NULL)
5080			type = QUARQF_LETTER;
5081		else
5082		{
5083			switch (QueueMode)
5084			{
5085			  case QM_NORMAL:
5086				type = NORMQF_LETTER;
5087				break;
5088
5089			  case QM_QUARANTINE:
5090				type = QUARQF_LETTER;
5091				break;
5092
5093			  case QM_LOST:
5094				type = LOSEQF_LETTER;
5095				break;
5096
5097			  default:
5098				/* should never happen */
5099				abort();
5100				/* NOTREACHED */
5101			}
5102		}
5103	}
5104	return type;
5105}
5106
5107/*
5108**  QUEUENAME -- build a file name in the queue directory for this envelope.
5109**
5110**	Parameters:
5111**		e -- envelope to build it in/from.
5112**		type -- the file type, used as the first character
5113**			of the file name.
5114**
5115**	Returns:
5116**		a pointer to the queue name (in a static buffer).
5117**
5118**	Side Effects:
5119**		If no id code is already assigned, queuename() will
5120**		assign an id code with assign_queueid().  If no queue
5121**		directory is assigned, one will be set with setnewqueue().
5122*/
5123
5124char *
5125queuename(e, type)
5126	register ENVELOPE *e;
5127	int type;
5128{
5129	int qd, qg;
5130	char *sub = "/";
5131	char pref[3];
5132	static char buf[MAXPATHLEN];
5133
5134	/* Assign an ID if needed */
5135	if (e->e_id == NULL)
5136		assign_queueid(e);
5137	type = queue_letter(e, type);
5138
5139	/* begin of filename */
5140	pref[0] = (char) type;
5141	pref[1] = 'f';
5142	pref[2] = '\0';
5143
5144	/* Assign a queue group/directory if needed */
5145	if (type == XSCRPT_LETTER)
5146	{
5147		/*
5148		**  We don't want to call setnewqueue() if we are fetching
5149		**  the pathname of the transcript file, because setnewqueue
5150		**  chooses a queue, and sometimes we need to write to the
5151		**  transcript file before we have gathered enough information
5152		**  to choose a queue.
5153		*/
5154
5155		if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR)
5156		{
5157			if (e->e_qgrp != NOQGRP && e->e_qdir != NOQDIR)
5158			{
5159				e->e_xfqgrp = e->e_qgrp;
5160				e->e_xfqdir = e->e_qdir;
5161			}
5162			else
5163			{
5164				e->e_xfqgrp = 0;
5165				if (Queue[e->e_xfqgrp]->qg_numqueues <= 1)
5166					e->e_xfqdir = 0;
5167				else
5168				{
5169					e->e_xfqdir = get_rand_mod(
5170					      Queue[e->e_xfqgrp]->qg_numqueues);
5171				}
5172			}
5173		}
5174		qd = e->e_xfqdir;
5175		qg = e->e_xfqgrp;
5176	}
5177	else
5178	{
5179		if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR)
5180			setnewqueue(e);
5181		if (type ==  DATAFL_LETTER)
5182		{
5183			qd = e->e_dfqdir;
5184			qg = e->e_dfqgrp;
5185		}
5186		else
5187		{
5188			qd = e->e_qdir;
5189			qg = e->e_qgrp;
5190		}
5191	}
5192
5193	/* xf files always have a valid qd and qg picked above */
5194	if (e->e_qdir == NOQDIR && type != XSCRPT_LETTER)
5195		(void) sm_strlcpyn(buf, sizeof buf, 2, pref, e->e_id);
5196	else
5197	{
5198		switch (type)
5199		{
5200		  case DATAFL_LETTER:
5201			if (bitset(QP_SUBDF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
5202				sub = "/df/";
5203			break;
5204
5205		  case QUARQF_LETTER:
5206		  case TEMPQF_LETTER:
5207		  case NEWQFL_LETTER:
5208		  case LOSEQF_LETTER:
5209		  case NORMQF_LETTER:
5210			if (bitset(QP_SUBQF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
5211				sub = "/qf/";
5212			break;
5213
5214		  case XSCRPT_LETTER:
5215			if (bitset(QP_SUBXF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
5216				sub = "/xf/";
5217			break;
5218
5219		  default:
5220			sm_abort("queuename: bad queue file type %d", type);
5221		}
5222
5223		(void) sm_strlcpyn(buf, sizeof buf, 4,
5224				Queue[qg]->qg_qpaths[qd].qp_name,
5225				sub, pref, e->e_id);
5226	}
5227
5228	if (tTd(7, 2))
5229		sm_dprintf("queuename: %s\n", buf);
5230	return buf;
5231}
5232
5233/*
5234**  INIT_QID_ALG -- Initialize the (static) parameters that are used to
5235**	generate a queue ID.
5236**
5237**	This function is called by the daemon to reset
5238**	LastQueueTime and LastQueuePid which are used by assign_queueid().
5239**	Otherwise the algorithm may cause problems because
5240**	LastQueueTime and LastQueuePid are set indirectly by main()
5241**	before the daemon process is started, hence LastQueuePid is not
5242**	the pid of the daemon and therefore a child of the daemon can
5243**	actually have the same pid as LastQueuePid which means the section
5244**	in  assign_queueid():
5245**	* see if we need to get a new base time/pid *
5246**	is NOT triggered which will cause the same queue id to be generated.
5247**
5248**	Parameters:
5249**		none
5250**
5251**	Returns:
5252**		none.
5253*/
5254
5255void
5256init_qid_alg()
5257{
5258	LastQueueTime = 0;
5259	LastQueuePid = -1;
5260}
5261
5262/*
5263**  ASSIGN_QUEUEID -- assign a queue ID for this envelope.
5264**
5265**	Assigns an id code if one does not already exist.
5266**	This code assumes that nothing will remain in the queue for
5267**	longer than 60 years.  It is critical that files with the given
5268**	name do not already exist in the queue.
5269**	[No longer initializes e_qdir to NOQDIR.]
5270**
5271**	Parameters:
5272**		e -- envelope to set it in.
5273**
5274**	Returns:
5275**		none.
5276*/
5277
5278static const char QueueIdChars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
5279# define QIC_LEN	60
5280# define QIC_LEN_R	62
5281
5282/*
5283**  Note: the length is "officially" 60 because minutes and seconds are
5284**	usually only 0-59.  However (Linux):
5285**       tm_sec The number of seconds after the minute, normally in
5286**		the range 0 to 59, but can be up to 61 to allow for
5287**		leap seconds.
5288**	Hence the real length of the string is 62 to take this into account.
5289**	Alternatively % QIC_LEN can (should) be used for access everywhere.
5290*/
5291
5292# define queuenextid() CurrentPid
5293
5294
5295void
5296assign_queueid(e)
5297	register ENVELOPE *e;
5298{
5299	pid_t pid = queuenextid();
5300	static int cX = 0;
5301	static long random_offset;
5302	struct tm *tm;
5303	char idbuf[MAXQFNAME - 2];
5304	int seq;
5305
5306	if (e->e_id != NULL)
5307		return;
5308
5309	/* see if we need to get a new base time/pid */
5310	if (cX >= QIC_LEN * QIC_LEN || LastQueueTime == 0 ||
5311	    LastQueuePid != pid)
5312	{
5313		time_t then = LastQueueTime;
5314
5315		/* if the first time through, pick a random offset */
5316		if (LastQueueTime == 0)
5317			random_offset = get_random();
5318
5319		while ((LastQueueTime = curtime()) == then &&
5320		       LastQueuePid == pid)
5321		{
5322			(void) sleep(1);
5323		}
5324		LastQueuePid = queuenextid();
5325		cX = 0;
5326	}
5327
5328	/*
5329	**  Generate a new sequence number between 0 and QIC_LEN*QIC_LEN-1.
5330	**  This lets us generate up to QIC_LEN*QIC_LEN unique queue ids
5331	**  per second, per process.  With envelope splitting,
5332	**  a single message can consume many queue ids.
5333	*/
5334
5335	seq = (int)((cX + random_offset) % (QIC_LEN * QIC_LEN));
5336	++cX;
5337	if (tTd(7, 50))
5338		sm_dprintf("assign_queueid: random_offset = %ld (%d)\n",
5339			random_offset, seq);
5340
5341	tm = gmtime(&LastQueueTime);
5342	idbuf[0] = QueueIdChars[tm->tm_year % QIC_LEN];
5343	idbuf[1] = QueueIdChars[tm->tm_mon];
5344	idbuf[2] = QueueIdChars[tm->tm_mday];
5345	idbuf[3] = QueueIdChars[tm->tm_hour];
5346	idbuf[4] = QueueIdChars[tm->tm_min % QIC_LEN_R];
5347	idbuf[5] = QueueIdChars[tm->tm_sec % QIC_LEN_R];
5348	idbuf[6] = QueueIdChars[seq / QIC_LEN];
5349	idbuf[7] = QueueIdChars[seq % QIC_LEN];
5350	(void) sm_snprintf(&idbuf[8], sizeof idbuf - 8, "%06d",
5351			   (int) LastQueuePid);
5352	e->e_id = sm_rpool_strdup_x(e->e_rpool, idbuf);
5353	macdefine(&e->e_macro, A_PERM, 'i', e->e_id);
5354#if 0
5355	/* XXX: inherited from MainEnvelope */
5356	e->e_qgrp = NOQGRP;  /* too early to do anything else */
5357	e->e_qdir = NOQDIR;
5358	e->e_xfqgrp = NOQGRP;
5359#endif /* 0 */
5360
5361	/* New ID means it's not on disk yet */
5362	e->e_qfletter = '\0';
5363
5364	if (tTd(7, 1))
5365		sm_dprintf("assign_queueid: assigned id %s, e=%p\n",
5366			e->e_id, e);
5367	if (LogLevel > 93)
5368		sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
5369}
5370/*
5371**  SYNC_QUEUE_TIME -- Assure exclusive PID in any given second
5372**
5373**	Make sure one PID can't be used by two processes in any one second.
5374**
5375**		If the system rotates PIDs fast enough, may get the
5376**		same pid in the same second for two distinct processes.
5377**		This will interfere with the queue file naming system.
5378**
5379**	Parameters:
5380**		none
5381**
5382**	Returns:
5383**		none
5384*/
5385
5386void
5387sync_queue_time()
5388{
5389#if FAST_PID_RECYCLE
5390	if (OpMode != MD_TEST &&
5391	    OpMode != MD_VERIFY &&
5392	    LastQueueTime > 0 &&
5393	    LastQueuePid == CurrentPid &&
5394	    curtime() == LastQueueTime)
5395		(void) sleep(1);
5396#endif /* FAST_PID_RECYCLE */
5397}
5398/*
5399**  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
5400**
5401**	Parameters:
5402**		e -- the envelope to unlock.
5403**
5404**	Returns:
5405**		none
5406**
5407**	Side Effects:
5408**		unlocks the queue for `e'.
5409*/
5410
5411void
5412unlockqueue(e)
5413	ENVELOPE *e;
5414{
5415	if (tTd(51, 4))
5416		sm_dprintf("unlockqueue(%s)\n",
5417			e->e_id == NULL ? "NOQUEUE" : e->e_id);
5418
5419
5420	/* if there is a lock file in the envelope, close it */
5421	if (e->e_lockfp != NULL)
5422		(void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT);
5423	e->e_lockfp = NULL;
5424
5425	/* don't create a queue id if we don't already have one */
5426	if (e->e_id == NULL)
5427		return;
5428
5429	/* remove the transcript */
5430	if (LogLevel > 87)
5431		sm_syslog(LOG_DEBUG, e->e_id, "unlock");
5432	if (!tTd(51, 104))
5433		(void) xunlink(queuename(e, XSCRPT_LETTER));
5434}
5435/*
5436**  SETCTLUSER -- create a controlling address
5437**
5438**	Create a fake "address" given only a local login name; this is
5439**	used as a "controlling user" for future recipient addresses.
5440**
5441**	Parameters:
5442**		user -- the user name of the controlling user.
5443**		qfver -- the version stamp of this queue file.
5444**		e -- envelope
5445**
5446**	Returns:
5447**		An address descriptor for the controlling user,
5448**		using storage allocated from e->e_rpool.
5449**
5450*/
5451
5452static ADDRESS *
5453setctluser(user, qfver, e)
5454	char *user;
5455	int qfver;
5456	ENVELOPE *e;
5457{
5458	register ADDRESS *a;
5459	struct passwd *pw;
5460	char *p;
5461
5462	/*
5463	**  See if this clears our concept of controlling user.
5464	*/
5465
5466	if (user == NULL || *user == '\0')
5467		return NULL;
5468
5469	/*
5470	**  Set up addr fields for controlling user.
5471	*/
5472
5473	a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof *a);
5474	memset((char *) a, '\0', sizeof *a);
5475
5476	if (*user == ':')
5477	{
5478		p = &user[1];
5479		a->q_user = sm_rpool_strdup_x(e->e_rpool, p);
5480	}
5481	else
5482	{
5483		p = strtok(user, ":");
5484		a->q_user = sm_rpool_strdup_x(e->e_rpool, user);
5485		if (qfver >= 2)
5486		{
5487			if ((p = strtok(NULL, ":")) != NULL)
5488				a->q_uid = atoi(p);
5489			if ((p = strtok(NULL, ":")) != NULL)
5490				a->q_gid = atoi(p);
5491			if ((p = strtok(NULL, ":")) != NULL)
5492			{
5493				char *o;
5494
5495				a->q_flags |= QGOODUID;
5496
5497				/* if there is another ':': restore it */
5498				if ((o = strtok(NULL, ":")) != NULL && o > p)
5499					o[-1] = ':';
5500			}
5501		}
5502		else if ((pw = sm_getpwnam(user)) != NULL)
5503		{
5504			if (*pw->pw_dir == '\0')
5505				a->q_home = NULL;
5506			else if (strcmp(pw->pw_dir, "/") == 0)
5507				a->q_home = "";
5508			else
5509				a->q_home = sm_rpool_strdup_x(e->e_rpool, pw->pw_dir);
5510			a->q_uid = pw->pw_uid;
5511			a->q_gid = pw->pw_gid;
5512			a->q_flags |= QGOODUID;
5513		}
5514	}
5515
5516	a->q_flags |= QPRIMARY;		/* flag as a "ctladdr" */
5517	a->q_mailer = LocalMailer;
5518	if (p == NULL)
5519		a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user);
5520	else
5521		a->q_paddr = sm_rpool_strdup_x(e->e_rpool, p);
5522	return a;
5523}
5524/*
5525**  LOSEQFILE -- rename queue file with LOSEQF_LETTER & try to let someone know
5526**
5527**	Parameters:
5528**		e -- the envelope (e->e_id will be used).
5529**		why -- reported to whomever can hear.
5530**
5531**	Returns:
5532**		none.
5533*/
5534
5535void
5536loseqfile(e, why)
5537	register ENVELOPE *e;
5538	char *why;
5539{
5540	bool loseit = true;
5541	char *p;
5542	char buf[MAXPATHLEN];
5543
5544	if (e == NULL || e->e_id == NULL)
5545		return;
5546	p = queuename(e, ANYQFL_LETTER);
5547	if (sm_strlcpy(buf, p, sizeof buf) >= sizeof buf)
5548		return;
5549	if (!bitset(EF_INQUEUE, e->e_flags))
5550		queueup(e, false, true);
5551	else if (QueueMode == QM_LOST)
5552		loseit = false;
5553
5554	/* if already lost, no need to re-lose */
5555	if (loseit)
5556	{
5557		p = queuename(e, LOSEQF_LETTER);
5558		if (rename(buf, p) < 0)
5559			syserr("cannot rename(%s, %s), uid=%d",
5560			       buf, p, (int) geteuid());
5561		else if (LogLevel > 0)
5562			sm_syslog(LOG_ALERT, e->e_id,
5563				  "Losing %s: %s", buf, why);
5564	}
5565	if (e->e_dfp != NULL)
5566	{
5567		(void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
5568		e->e_dfp = NULL;
5569	}
5570	e->e_flags &= ~EF_HAS_DF;
5571}
5572/*
5573**  NAME2QID -- translate a queue group name to a queue group id
5574**
5575**	Parameters:
5576**		queuename -- name of queue group.
5577**
5578**	Returns:
5579**		queue group id if found.
5580**		NOQGRP otherwise.
5581*/
5582
5583int
5584name2qid(queuename)
5585	char *queuename;
5586{
5587	register STAB *s;
5588
5589	s = stab(queuename, ST_QUEUE, ST_FIND);
5590	if (s == NULL)
5591		return NOQGRP;
5592	return s->s_quegrp->qg_index;
5593}
5594/*
5595**  QID_PRINTNAME -- create externally printable version of queue id
5596**
5597**	Parameters:
5598**		e -- the envelope.
5599**
5600**	Returns:
5601**		a printable version
5602*/
5603
5604char *
5605qid_printname(e)
5606	ENVELOPE *e;
5607{
5608	char *id;
5609	static char idbuf[MAXQFNAME + 34];
5610
5611	if (e == NULL)
5612		return "";
5613
5614	if (e->e_id == NULL)
5615		id = "";
5616	else
5617		id = e->e_id;
5618
5619	if (e->e_qdir == NOQDIR)
5620		return id;
5621
5622	(void) sm_snprintf(idbuf, sizeof idbuf, "%.32s/%s",
5623			   Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_name,
5624			   id);
5625	return idbuf;
5626}
5627/*
5628**  QID_PRINTQUEUE -- create full version of queue directory for data files
5629**
5630**	Parameters:
5631**		qgrp -- index in queue group.
5632**		qdir -- the short version of the queue directory
5633**
5634**	Returns:
5635**		the full pathname to the queue (might point to a static var)
5636*/
5637
5638char *
5639qid_printqueue(qgrp, qdir)
5640	int qgrp;
5641	int qdir;
5642{
5643	char *subdir;
5644	static char dir[MAXPATHLEN];
5645
5646	if (qdir == NOQDIR)
5647		return Queue[qgrp]->qg_qdir;
5648
5649	if (strcmp(Queue[qgrp]->qg_qpaths[qdir].qp_name, ".") == 0)
5650		subdir = NULL;
5651	else
5652		subdir = Queue[qgrp]->qg_qpaths[qdir].qp_name;
5653
5654	(void) sm_strlcpyn(dir, sizeof dir, 4,
5655			Queue[qgrp]->qg_qdir,
5656			subdir == NULL ? "" : "/",
5657			subdir == NULL ? "" : subdir,
5658			(bitset(QP_SUBDF,
5659				Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
5660					? "/df" : ""));
5661	return dir;
5662}
5663
5664/*
5665**  PICKQDIR -- Pick a queue directory from a queue group
5666**
5667**	Parameters:
5668**		qg -- queue group
5669**		fsize -- file size in bytes
5670**		e -- envelope, or NULL
5671**
5672**	Result:
5673**		NOQDIR if no queue directory in qg has enough free space to
5674**		hold a file of size 'fsize', otherwise the index of
5675**		a randomly selected queue directory which resides on a
5676**		file system with enough disk space.
5677**		XXX This could be extended to select a queuedir with
5678**			a few (the fewest?) number of entries. That data
5679**			is available if shared memory is used.
5680**
5681**	Side Effects:
5682**		If the request fails and e != NULL then sm_syslog is called.
5683*/
5684
5685int
5686pickqdir(qg, fsize, e)
5687	QUEUEGRP *qg;
5688	long fsize;
5689	ENVELOPE *e;
5690{
5691	int qdir;
5692	int i;
5693	long avail = 0;
5694
5695	/* Pick a random directory, as a starting point. */
5696	if (qg->qg_numqueues <= 1)
5697		qdir = 0;
5698	else
5699		qdir = get_rand_mod(qg->qg_numqueues);
5700
5701	if (MinBlocksFree <= 0 && fsize <= 0)
5702		return qdir;
5703
5704	/*
5705	**  Now iterate over the queue directories,
5706	**  looking for a directory with enough space for this message.
5707	*/
5708
5709	i = qdir;
5710	do
5711	{
5712		QPATHS *qp = &qg->qg_qpaths[i];
5713		long needed = 0;
5714		long fsavail = 0;
5715
5716		if (fsize > 0)
5717			needed += fsize / FILE_SYS_BLKSIZE(qp->qp_fsysidx)
5718				  + ((fsize % FILE_SYS_BLKSIZE(qp->qp_fsysidx)
5719				      > 0) ? 1 : 0);
5720		if (MinBlocksFree > 0)
5721			needed += MinBlocksFree;
5722		fsavail = FILE_SYS_AVAIL(qp->qp_fsysidx);
5723#if SM_CONF_SHM
5724		if (fsavail <= 0)
5725		{
5726			long blksize;
5727
5728			/*
5729			**  might be not correctly updated,
5730			**  let's try to get the info directly.
5731			*/
5732
5733			fsavail = freediskspace(FILE_SYS_NAME(qp->qp_fsysidx),
5734						&blksize);
5735			if (fsavail < 0)
5736				fsavail = 0;
5737		}
5738#endif /* SM_CONF_SHM */
5739		if (needed <= fsavail)
5740			return i;
5741		if (avail < fsavail)
5742			avail = fsavail;
5743
5744		if (qg->qg_numqueues > 0)
5745			i = (i + 1) % qg->qg_numqueues;
5746	} while (i != qdir);
5747
5748	if (e != NULL && LogLevel > 0)
5749		sm_syslog(LOG_ALERT, e->e_id,
5750			"low on space (%s needs %ld bytes + %ld blocks in %s), max avail: %ld",
5751			CurHostName == NULL ? "SMTP-DAEMON" : CurHostName,
5752			fsize, MinBlocksFree,
5753			qg->qg_qdir, avail);
5754	return NOQDIR;
5755}
5756/*
5757**  SETNEWQUEUE -- Sets a new queue group and directory
5758**
5759**	Assign a queue group and directory to an envelope and store the
5760**	directory in e->e_qdir.
5761**
5762**	Parameters:
5763**		e -- envelope to assign a queue for.
5764**
5765**	Returns:
5766**		true if successful
5767**		false otherwise
5768**
5769**	Side Effects:
5770**		On success, e->e_qgrp and e->e_qdir are non-negative.
5771**		On failure (not enough disk space),
5772**		e->qgrp = NOQGRP, e->e_qdir = NOQDIR
5773**		and usrerr() is invoked (which could raise an exception).
5774*/
5775
5776bool
5777setnewqueue(e)
5778	ENVELOPE *e;
5779{
5780	if (tTd(41, 20))
5781		sm_dprintf("setnewqueue: called\n");
5782
5783	/* not set somewhere else */
5784	if (e->e_qgrp == NOQGRP)
5785	{
5786		ADDRESS *q;
5787
5788		/*
5789		**  Use the queue group of the "first" recipient, as set by
5790		**  the "queuegroup" rule set.  If that is not defined, then
5791		**  use the queue group of the mailer of the first recipient.
5792		**  If that is not defined either, then use the default
5793		**  queue group.
5794		**  Notice: "first" depends on the sorting of sendqueue
5795		**  in recipient().
5796		**  To avoid problems with "bad" recipients look
5797		**  for a valid address first.
5798		*/
5799
5800		q = e->e_sendqueue;
5801		while (q != NULL &&
5802		       (QS_IS_BADADDR(q->q_state) || QS_IS_DEAD(q->q_state)))
5803		{
5804			q = q->q_next;
5805		}
5806		if (q == NULL)
5807			e->e_qgrp = 0;
5808		else if (q->q_qgrp >= 0)
5809			e->e_qgrp = q->q_qgrp;
5810		else if (q->q_mailer != NULL &&
5811			 ISVALIDQGRP(q->q_mailer->m_qgrp))
5812			e->e_qgrp = q->q_mailer->m_qgrp;
5813		else
5814			e->e_qgrp = 0;
5815		e->e_dfqgrp = e->e_qgrp;
5816	}
5817
5818	if (ISVALIDQDIR(e->e_qdir) && ISVALIDQDIR(e->e_dfqdir))
5819	{
5820		if (tTd(41, 20))
5821			sm_dprintf("setnewqueue: e_qdir already assigned (%s)\n",
5822				qid_printqueue(e->e_qgrp, e->e_qdir));
5823		return true;
5824	}
5825
5826	filesys_update();
5827	e->e_qdir = pickqdir(Queue[e->e_qgrp], e->e_msgsize, e);
5828	if (e->e_qdir == NOQDIR)
5829	{
5830		e->e_qgrp = NOQGRP;
5831		if (!bitset(EF_FATALERRS, e->e_flags))
5832			usrerr("452 4.4.5 Insufficient disk space; try again later");
5833		e->e_flags |= EF_FATALERRS;
5834		return false;
5835	}
5836
5837	if (tTd(41, 3))
5838		sm_dprintf("setnewqueue: Assigned queue directory %s\n",
5839			qid_printqueue(e->e_qgrp, e->e_qdir));
5840
5841	if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR)
5842	{
5843		e->e_xfqgrp = e->e_qgrp;
5844		e->e_xfqdir = e->e_qdir;
5845	}
5846	e->e_dfqdir = e->e_qdir;
5847	return true;
5848}
5849/*
5850**  CHKQDIR -- check a queue directory
5851**
5852**	Parameters:
5853**		name -- name of queue directory
5854**		sff -- flags for safefile()
5855**
5856**	Returns:
5857**		is it a queue directory?
5858*/
5859
5860static bool
5861chkqdir(name, sff)
5862	char *name;
5863	long sff;
5864{
5865	struct stat statb;
5866	int i;
5867
5868	/* skip over . and .. directories */
5869	if (name[0] == '.' &&
5870	    (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
5871		return false;
5872#if HASLSTAT
5873	if (lstat(name, &statb) < 0)
5874#else /* HASLSTAT */
5875	if (stat(name, &statb) < 0)
5876#endif /* HASLSTAT */
5877	{
5878		if (tTd(41, 2))
5879			sm_dprintf("chkqdir: stat(\"%s\"): %s\n",
5880				   name, sm_errstring(errno));
5881		return false;
5882	}
5883#if HASLSTAT
5884	if (S_ISLNK(statb.st_mode))
5885	{
5886		/*
5887		**  For a symlink we need to make sure the
5888		**  target is a directory
5889		*/
5890
5891		if (stat(name, &statb) < 0)
5892		{
5893			if (tTd(41, 2))
5894				sm_dprintf("chkqdir: stat(\"%s\"): %s\n",
5895					   name, sm_errstring(errno));
5896			return false;
5897		}
5898	}
5899#endif /* HASLSTAT */
5900
5901	if (!S_ISDIR(statb.st_mode))
5902	{
5903		if (tTd(41, 2))
5904			sm_dprintf("chkqdir: \"%s\": Not a directory\n",
5905				name);
5906		return false;
5907	}
5908
5909	/* Print a warning if unsafe (but still use it) */
5910	/* XXX do this only if we want the warning? */
5911	i = safedirpath(name, RunAsUid, RunAsGid, NULL, sff, 0, 0);
5912	if (i != 0)
5913	{
5914		if (tTd(41, 2))
5915			sm_dprintf("chkqdir: \"%s\": Not safe: %s\n",
5916				   name, sm_errstring(i));
5917#if _FFR_CHK_QUEUE
5918		if (LogLevel > 8)
5919			sm_syslog(LOG_WARNING, NOQID,
5920				  "queue directory \"%s\": Not safe: %s",
5921				  name, sm_errstring(i));
5922#endif /* _FFR_CHK_QUEUE */
5923	}
5924	return true;
5925}
5926/*
5927**  MULTIQUEUE_CACHE -- cache a list of paths to queues.
5928**
5929**	Each potential queue is checked as the cache is built.
5930**	Thereafter, each is blindly trusted.
5931**	Note that we can be called again after a timeout to rebuild
5932**	(although code for that is not ready yet).
5933**
5934**	Parameters:
5935**		basedir -- base of all queue directories.
5936**		blen -- strlen(basedir).
5937**		qg -- queue group.
5938**		qn -- number of queue directories already cached.
5939**		phash -- pointer to hash value over queue dirs.
5940#if SM_CONF_SHM
5941**			only used if shared memory is active.
5942#endif * SM_CONF_SHM *
5943**
5944**	Returns:
5945**		new number of queue directories.
5946*/
5947
5948#define INITIAL_SLOTS	20
5949#define ADD_SLOTS	10
5950
5951static int
5952multiqueue_cache(basedir, blen, qg, qn, phash)
5953	char *basedir;
5954	int blen;
5955	QUEUEGRP *qg;
5956	int qn;
5957	unsigned int *phash;
5958{
5959	char *cp;
5960	int i, len;
5961	int slotsleft = 0;
5962	long sff = SFF_ANYFILE;
5963	char qpath[MAXPATHLEN];
5964	char subdir[MAXPATHLEN];
5965	char prefix[MAXPATHLEN];	/* dir relative to basedir */
5966
5967	if (tTd(41, 20))
5968		sm_dprintf("multiqueue_cache: called\n");
5969
5970	/* Initialize to current directory */
5971	prefix[0] = '.';
5972	prefix[1] = '\0';
5973	if (qg->qg_numqueues != 0 && qg->qg_qpaths != NULL)
5974	{
5975		for (i = 0; i < qg->qg_numqueues; i++)
5976		{
5977			if (qg->qg_qpaths[i].qp_name != NULL)
5978				(void) sm_free(qg->qg_qpaths[i].qp_name); /* XXX */
5979		}
5980		(void) sm_free((char *) qg->qg_qpaths); /* XXX */
5981		qg->qg_qpaths = NULL;
5982		qg->qg_numqueues = 0;
5983	}
5984
5985	/* If running as root, allow safedirpath() checks to use privs */
5986	if (RunAsUid == 0)
5987		sff |= SFF_ROOTOK;
5988#if _FFR_CHK_QUEUE
5989	sff |= SFF_SAFEDIRPATH|SFF_NOWWFILES;
5990	if (!UseMSP)
5991		sff |= SFF_NOGWFILES;
5992#endif /* _FFR_CHK_QUEUE */
5993
5994	if (!SM_IS_DIR_START(qg->qg_qdir))
5995	{
5996		/*
5997		**  XXX we could add basedir, but then we have to realloc()
5998		**  the string... Maybe another time.
5999		*/
6000
6001		syserr("QueuePath %s not absolute", qg->qg_qdir);
6002		ExitStat = EX_CONFIG;
6003		return qn;
6004	}
6005
6006	/* qpath: directory of current workgroup */
6007	len = sm_strlcpy(qpath, qg->qg_qdir, sizeof qpath);
6008	if (len >= sizeof qpath)
6009	{
6010		syserr("QueuePath %.256s too long (%d max)",
6011		       qg->qg_qdir, (int) sizeof qpath);
6012		ExitStat = EX_CONFIG;
6013		return qn;
6014	}
6015
6016	/* begin of qpath must be same as basedir */
6017	if (strncmp(basedir, qpath, blen) != 0 &&
6018	    (strncmp(basedir, qpath, blen - 1) != 0 || len != blen - 1))
6019	{
6020		syserr("QueuePath %s not subpath of QueueDirectory %s",
6021			qpath, basedir);
6022		ExitStat = EX_CONFIG;
6023		return qn;
6024	}
6025
6026	/* Do we have a nested subdirectory? */
6027	if (blen < len && SM_FIRST_DIR_DELIM(qg->qg_qdir + blen) != NULL)
6028	{
6029
6030		/* Copy subdirectory into prefix for later use */
6031		if (sm_strlcpy(prefix, qg->qg_qdir + blen, sizeof prefix) >=
6032		    sizeof prefix)
6033		{
6034			syserr("QueuePath %.256s too long (%d max)",
6035				qg->qg_qdir, (int) sizeof qpath);
6036			ExitStat = EX_CONFIG;
6037			return qn;
6038		}
6039		cp = SM_LAST_DIR_DELIM(prefix);
6040		SM_ASSERT(cp != NULL);
6041		*cp = '\0';	/* cut off trailing / */
6042	}
6043
6044	/* This is guaranteed by the basedir check above */
6045	SM_ASSERT(len >= blen - 1);
6046	cp = &qpath[len - 1];
6047	if (*cp == '*')
6048	{
6049		register DIR *dp;
6050		register struct dirent *d;
6051		int off;
6052		char *delim;
6053		char relpath[MAXPATHLEN];
6054
6055		*cp = '\0';	/* Overwrite wildcard */
6056		if ((cp = SM_LAST_DIR_DELIM(qpath)) == NULL)
6057		{
6058			syserr("QueueDirectory: can not wildcard relative path");
6059			if (tTd(41, 2))
6060				sm_dprintf("multiqueue_cache: \"%s*\": Can not wildcard relative path.\n",
6061					qpath);
6062			ExitStat = EX_CONFIG;
6063			return qn;
6064		}
6065		if (cp == qpath)
6066		{
6067			/*
6068			**  Special case of top level wildcard, like /foo*
6069			**	Change to //foo*
6070			*/
6071
6072			(void) sm_strlcpy(qpath + 1, qpath, sizeof qpath - 1);
6073			++cp;
6074		}
6075		delim = cp;
6076		*(cp++) = '\0';		/* Replace / with \0 */
6077		len = strlen(cp);	/* Last component of queue directory */
6078
6079		/*
6080		**  Path relative to basedir, with trailing /
6081		**  It will be modified below to specify the subdirectories
6082		**  so they can be opened without chdir().
6083		*/
6084
6085		off = sm_strlcpyn(relpath, sizeof relpath, 2, prefix, "/");
6086		SM_ASSERT(off < sizeof relpath);
6087
6088		if (tTd(41, 2))
6089			sm_dprintf("multiqueue_cache: prefix=\"%s%s\"\n",
6090				   relpath, cp);
6091
6092		/* It is always basedir: we don't need to store it per group */
6093		/* XXX: optimize this! -> one more global? */
6094		qg->qg_qdir = newstr(basedir);
6095		qg->qg_qdir[blen - 1] = '\0';	/* cut off trailing / */
6096
6097		/*
6098		**  XXX Should probably wrap this whole loop in a timeout
6099		**  in case some wag decides to NFS mount the queues.
6100		*/
6101
6102		/* Test path to get warning messages. */
6103		if (qn == 0)
6104		{
6105			/*  XXX qg_runasuid and qg_runasgid for specials? */
6106			i = safedirpath(basedir, RunAsUid, RunAsGid, NULL,
6107					sff, 0, 0);
6108			if (i != 0 && tTd(41, 2))
6109				sm_dprintf("multiqueue_cache: \"%s\": Not safe: %s\n",
6110					   basedir, sm_errstring(i));
6111		}
6112
6113		if ((dp = opendir(prefix)) == NULL)
6114		{
6115			syserr("can not opendir(%s/%s)", qg->qg_qdir, prefix);
6116			if (tTd(41, 2))
6117				sm_dprintf("multiqueue_cache: opendir(\"%s/%s\"): %s\n",
6118					   qg->qg_qdir, prefix,
6119					   sm_errstring(errno));
6120			ExitStat = EX_CONFIG;
6121			return qn;
6122		}
6123		while ((d = readdir(dp)) != NULL)
6124		{
6125			i = strlen(d->d_name);
6126			if (i < len || strncmp(d->d_name, cp, len) != 0)
6127			{
6128				if (tTd(41, 5))
6129					sm_dprintf("multiqueue_cache: \"%s\", skipped\n",
6130						d->d_name);
6131				continue;
6132			}
6133
6134			/* Create relative pathname: prefix + local directory */
6135			i = sizeof(relpath) - off;
6136			if (sm_strlcpy(relpath + off, d->d_name, i) >= i)
6137				continue;	/* way too long */
6138
6139			if (!chkqdir(relpath, sff))
6140				continue;
6141
6142			if (qg->qg_qpaths == NULL)
6143			{
6144				slotsleft = INITIAL_SLOTS;
6145				qg->qg_qpaths = (QPATHS *)xalloc((sizeof *qg->qg_qpaths) *
6146								slotsleft);
6147				qg->qg_numqueues = 0;
6148			}
6149			else if (slotsleft < 1)
6150			{
6151				qg->qg_qpaths = (QPATHS *)sm_realloc((char *)qg->qg_qpaths,
6152							  (sizeof *qg->qg_qpaths) *
6153							  (qg->qg_numqueues +
6154							   ADD_SLOTS));
6155				if (qg->qg_qpaths == NULL)
6156				{
6157					(void) closedir(dp);
6158					return qn;
6159				}
6160				slotsleft += ADD_SLOTS;
6161			}
6162
6163			/* check subdirs */
6164			qg->qg_qpaths[qg->qg_numqueues].qp_subdirs = QP_NOSUB;
6165
6166#define CHKRSUBDIR(name, flag)	\
6167	(void) sm_strlcpyn(subdir, sizeof subdir, 3, relpath, "/", name); \
6168	if (chkqdir(subdir, sff))	\
6169		qg->qg_qpaths[qg->qg_numqueues].qp_subdirs |= flag;	\
6170	else
6171
6172
6173			CHKRSUBDIR("qf", QP_SUBQF);
6174			CHKRSUBDIR("df", QP_SUBDF);
6175			CHKRSUBDIR("xf", QP_SUBXF);
6176
6177			/* assert(strlen(d->d_name) < MAXPATHLEN - 14) */
6178			/* maybe even - 17 (subdirs) */
6179
6180			if (prefix[0] != '.')
6181				qg->qg_qpaths[qg->qg_numqueues].qp_name =
6182					newstr(relpath);
6183			else
6184				qg->qg_qpaths[qg->qg_numqueues].qp_name =
6185					newstr(d->d_name);
6186
6187			if (tTd(41, 2))
6188				sm_dprintf("multiqueue_cache: %d: \"%s\" cached (%x).\n",
6189					qg->qg_numqueues, relpath,
6190					qg->qg_qpaths[qg->qg_numqueues].qp_subdirs);
6191#if SM_CONF_SHM
6192			qg->qg_qpaths[qg->qg_numqueues].qp_idx = qn;
6193			*phash = hash_q(relpath, *phash);
6194#endif /* SM_CONF_SHM */
6195			qg->qg_numqueues++;
6196			++qn;
6197			slotsleft--;
6198		}
6199		(void) closedir(dp);
6200
6201		/* undo damage */
6202		*delim = '/';
6203	}
6204	if (qg->qg_numqueues == 0)
6205	{
6206		qg->qg_qpaths = (QPATHS *) xalloc(sizeof *qg->qg_qpaths);
6207
6208		/* test path to get warning messages */
6209		i = safedirpath(qpath, RunAsUid, RunAsGid, NULL, sff, 0, 0);
6210		if (i == ENOENT)
6211		{
6212			syserr("can not opendir(%s)", qpath);
6213			if (tTd(41, 2))
6214				sm_dprintf("multiqueue_cache: opendir(\"%s\"): %s\n",
6215					   qpath, sm_errstring(i));
6216			ExitStat = EX_CONFIG;
6217			return qn;
6218		}
6219
6220		qg->qg_qpaths[0].qp_subdirs = QP_NOSUB;
6221		qg->qg_numqueues = 1;
6222
6223		/* check subdirs */
6224#define CHKSUBDIR(name, flag)	\
6225	(void) sm_strlcpyn(subdir, sizeof subdir, 3, qg->qg_qdir, "/", name); \
6226	if (chkqdir(subdir, sff))	\
6227		qg->qg_qpaths[0].qp_subdirs |= flag;	\
6228	else
6229
6230		CHKSUBDIR("qf", QP_SUBQF);
6231		CHKSUBDIR("df", QP_SUBDF);
6232		CHKSUBDIR("xf", QP_SUBXF);
6233
6234		if (qg->qg_qdir[blen - 1] != '\0' &&
6235		    qg->qg_qdir[blen] != '\0')
6236		{
6237			/*
6238			**  Copy the last component into qpaths and
6239			**  cut off qdir
6240			*/
6241
6242			qg->qg_qpaths[0].qp_name = newstr(qg->qg_qdir + blen);
6243			qg->qg_qdir[blen - 1] = '\0';
6244		}
6245		else
6246			qg->qg_qpaths[0].qp_name = newstr(".");
6247
6248#if SM_CONF_SHM
6249		qg->qg_qpaths[0].qp_idx = qn;
6250		*phash = hash_q(qg->qg_qpaths[0].qp_name, *phash);
6251#endif /* SM_CONF_SHM */
6252		++qn;
6253	}
6254	return qn;
6255}
6256
6257/*
6258**  FILESYS_FIND -- find entry in FileSys table, or add new one
6259**
6260**	Given the pathname of a directory, determine the file system
6261**	in which that directory resides, and return a pointer to the
6262**	entry in the FileSys table that describes the file system.
6263**	A new entry is added if necessary (and requested).
6264**	If the directory does not exist, -1 is returned.
6265**
6266**	Parameters:
6267**		path -- pathname of directory
6268**		add -- add to structure if not found.
6269**
6270**	Returns:
6271**		>=0: found: index in file system table
6272**		<0: some error, i.e.,
6273**		FSF_TOO_MANY: too many filesystems (-> syserr())
6274**		FSF_STAT_FAIL: can't stat() filesystem (-> syserr())
6275**		FSF_NOT_FOUND: not in list
6276*/
6277
6278static short filesys_find __P((char *, bool));
6279
6280#define FSF_NOT_FOUND	(-1)
6281#define FSF_STAT_FAIL	(-2)
6282#define FSF_TOO_MANY	(-3)
6283
6284static short
6285filesys_find(path, add)
6286	char *path;
6287	bool add;
6288{
6289	struct stat st;
6290	short i;
6291
6292	if (stat(path, &st) < 0)
6293	{
6294		syserr("cannot stat queue directory %s", path);
6295		return FSF_STAT_FAIL;
6296	}
6297	for (i = 0; i < NumFileSys; ++i)
6298	{
6299		if (FILE_SYS_DEV(i) == st.st_dev)
6300			return i;
6301	}
6302	if (i >= MAXFILESYS)
6303	{
6304		syserr("too many queue file systems (%d max)", MAXFILESYS);
6305		return FSF_TOO_MANY;
6306	}
6307	if (!add)
6308		return FSF_NOT_FOUND;
6309
6310	++NumFileSys;
6311	FILE_SYS_NAME(i) = path;
6312	FILE_SYS_DEV(i) = st.st_dev;
6313	FILE_SYS_AVAIL(i) = 0;
6314	FILE_SYS_BLKSIZE(i) = 1024; /* avoid divide by zero */
6315	return i;
6316}
6317
6318/*
6319**  FILESYS_SETUP -- set up mapping from queue directories to file systems
6320**
6321**	This data structure is used to efficiently check the amount of
6322**	free space available in a set of queue directories.
6323**
6324**	Parameters:
6325**		add -- initialize structure if necessary.
6326**
6327**	Returns:
6328**		0: success
6329**		<0: some error, i.e.,
6330**		FSF_NOT_FOUND: not in list
6331**		FSF_STAT_FAIL: can't stat() filesystem (-> syserr())
6332**		FSF_TOO_MANY: too many filesystems (-> syserr())
6333*/
6334
6335static int filesys_setup __P((bool));
6336
6337static int
6338filesys_setup(add)
6339	bool add;
6340{
6341	int i, j;
6342	short fs;
6343	int ret;
6344
6345	ret = 0;
6346	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
6347	{
6348		for (j = 0; j < Queue[i]->qg_numqueues; ++j)
6349		{
6350			QPATHS *qp = &Queue[i]->qg_qpaths[j];
6351
6352			fs = filesys_find(qp->qp_name, add);
6353			if (fs >= 0)
6354				qp->qp_fsysidx = fs;
6355			else
6356				qp->qp_fsysidx = 0;
6357			if (fs < ret)
6358				ret = fs;
6359		}
6360	}
6361	return ret;
6362}
6363
6364/*
6365**  FILESYS_UPDATE -- update amount of free space on all file systems
6366**
6367**	The FileSys table is used to cache the amount of free space
6368**	available on all queue directory file systems.
6369**	This function updates the cached information if it has expired.
6370**
6371**	Parameters:
6372**		none.
6373**
6374**	Returns:
6375**		none.
6376**
6377**	Side Effects:
6378**		Updates FileSys table.
6379*/
6380
6381void
6382filesys_update()
6383{
6384	int i;
6385	long avail, blksize;
6386	time_t now;
6387	static time_t nextupdate = 0;
6388
6389#if SM_CONF_SHM
6390	/* only the daemon updates this structure */
6391	if (ShmId != SM_SHM_NO_ID && DaemonPid != CurrentPid)
6392		return;
6393#endif /* SM_CONF_SHM */
6394	now = curtime();
6395	if (now < nextupdate)
6396		return;
6397	nextupdate = now + FILESYS_UPDATE_INTERVAL;
6398	for (i = 0; i < NumFileSys; ++i)
6399	{
6400		FILESYS *fs = &FILE_SYS(i);
6401
6402		avail = freediskspace(FILE_SYS_NAME(i), &blksize);
6403		if (avail < 0 || blksize <= 0)
6404		{
6405			if (LogLevel > 5)
6406				sm_syslog(LOG_ERR, NOQID,
6407					"filesys_update failed: %s, fs=%s, avail=%ld, blocksize=%ld",
6408					sm_errstring(errno),
6409					FILE_SYS_NAME(i), avail, blksize);
6410			fs->fs_avail = 0;
6411			fs->fs_blksize = 1024; /* avoid divide by zero */
6412			nextupdate = now + 2; /* let's do this soon again */
6413		}
6414		else
6415		{
6416			fs->fs_avail = avail;
6417			fs->fs_blksize = blksize;
6418		}
6419	}
6420}
6421
6422#if _FFR_ANY_FREE_FS
6423/*
6424**  FILESYS_FREE -- check whether there is at least one fs with enough space.
6425**
6426**	Parameters:
6427**		fsize -- file size in bytes
6428**
6429**	Returns:
6430**		true iff there is one fs with more than fsize bytes free.
6431*/
6432
6433bool
6434filesys_free(fsize)
6435	long fsize;
6436{
6437	int i;
6438
6439	if (fsize <= 0)
6440		return true;
6441	for (i = 0; i < NumFileSys; ++i)
6442	{
6443		long needed = 0;
6444
6445		if (FILE_SYS_AVAIL(i) < 0 || FILE_SYS_BLKSIZE(i) <= 0)
6446			continue;
6447		needed += fsize / FILE_SYS_BLKSIZE(i)
6448			  + ((fsize % FILE_SYS_BLKSIZE(i)
6449			      > 0) ? 1 : 0)
6450			  + MinBlocksFree;
6451		if (needed <= FILE_SYS_AVAIL(i))
6452			return true;
6453	}
6454	return false;
6455}
6456#endif /* _FFR_ANY_FREE_FS */
6457
6458#if _FFR_CONTROL_MSTAT
6459/*
6460**  DISK_STATUS -- show amount of free space in queue directories
6461**
6462**	Parameters:
6463**		out -- output file pointer.
6464**		prefix -- string to output in front of each line.
6465**
6466**	Returns:
6467**		none.
6468*/
6469
6470void
6471disk_status(out, prefix)
6472	SM_FILE_T *out;
6473	char *prefix;
6474{
6475	int i;
6476	long avail, blksize;
6477	long free;
6478
6479	for (i = 0; i < NumFileSys; ++i)
6480	{
6481		avail = freediskspace(FILE_SYS_NAME(i), &blksize);
6482		if (avail >= 0 && blksize > 0)
6483		{
6484			free = (long)((double) avail *
6485				((double) blksize / 1024));
6486		}
6487		else
6488			free = -1;
6489		(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
6490				"%s%d/%s/%ld\r\n",
6491				prefix, i,
6492				FILE_SYS_NAME(i),
6493					free);
6494	}
6495}
6496#endif /* _FFR_CONTROL_MSTAT */
6497
6498#if SM_CONF_SHM
6499/*
6500**  UPD_QS -- update information about queue when adding/deleting an entry
6501**
6502**	Parameters:
6503**		e -- envelope.
6504**		delete -- delete/add entry.
6505**		avail -- update the space available as well.
6506**
6507**	Returns:
6508**		none.
6509**
6510**	Side Effects:
6511**		Modifies available space in filesystem.
6512**		Changes number of entries in queue directory.
6513*/
6514
6515void
6516upd_qs(e, delete, avail)
6517	ENVELOPE *e;
6518	bool delete;
6519	bool avail;
6520{
6521	short fidx;
6522	int idx;
6523	long s;
6524
6525	if (ShmId == SM_SHM_NO_ID || e == NULL)
6526		return;
6527	if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR)
6528		return;
6529	idx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_idx;
6530
6531	/* XXX in theory this needs to be protected with a mutex */
6532	if (QSHM_ENTRIES(idx) >= 0)
6533	{
6534		if (delete)
6535			--QSHM_ENTRIES(idx);
6536		else
6537			++QSHM_ENTRIES(idx);
6538	}
6539
6540	fidx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_fsysidx;
6541	if (fidx < 0)
6542		return;
6543
6544	/* update available space also?  (might be loseqfile) */
6545	if (!avail)
6546		return;
6547
6548	/* convert size to blocks; this causes rounding errors */
6549	s = e->e_msgsize / FILE_SYS_BLKSIZE(fidx);
6550	if (s == 0)
6551		return;
6552
6553	/* XXX in theory this needs to be protected with a mutex */
6554	if (delete)
6555		FILE_SYS_AVAIL(fidx) += s;
6556	else
6557		FILE_SYS_AVAIL(fidx) -= s;
6558
6559}
6560
6561#if _FFR_SELECT_SHM
6562
6563static bool write_key_file __P((char *, long));
6564static long read_key_file __P((char *, long));
6565
6566/*
6567**  WRITE_KEY_FILE -- record some key into a file.
6568**
6569**	Parameters:
6570**		keypath -- file name.
6571**		key -- key to write.
6572**
6573**	Returns:
6574**		true iff file could be written.
6575**
6576**	Side Effects:
6577**		writes file.
6578*/
6579
6580static bool
6581write_key_file(keypath, key)
6582	char *keypath;
6583	long key;
6584{
6585	bool ok;
6586	long sff;
6587	SM_FILE_T *keyf;
6588
6589	ok = false;
6590	if (keypath == NULL || *keypath == '\0')
6591		return ok;
6592	sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT;
6593	if (TrustedUid != 0 && RealUid == TrustedUid)
6594		sff |= SFF_OPENASROOT;
6595	keyf = safefopen(keypath, O_WRONLY|O_TRUNC, FileMode, sff);
6596	if (keyf == NULL)
6597	{
6598		sm_syslog(LOG_ERR, NOQID, "unable to write %s: %s",
6599			  keypath, sm_errstring(errno));
6600	}
6601	else
6602	{
6603		ok = sm_io_fprintf(keyf, SM_TIME_DEFAULT, "%ld\n", key) !=
6604		     SM_IO_EOF;
6605		ok = (sm_io_close(keyf, SM_TIME_DEFAULT) != SM_IO_EOF) && ok;
6606	}
6607	return ok;
6608}
6609
6610/*
6611**  READ_KEY_FILE -- read a key from a file.
6612**
6613**	Parameters:
6614**		keypath -- file name.
6615**		key -- default key.
6616**
6617**	Returns:
6618**		key.
6619*/
6620
6621static long
6622read_key_file(keypath, key)
6623	char *keypath;
6624	long key;
6625{
6626	int r;
6627	long sff, n;
6628	SM_FILE_T *keyf;
6629
6630	if (keypath == NULL || *keypath == '\0')
6631		return key;
6632	sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY;
6633	if (RealUid == 0 || (TrustedUid != 0 && RealUid == TrustedUid))
6634		sff |= SFF_OPENASROOT;
6635	keyf = safefopen(keypath, O_RDONLY, FileMode, sff);
6636	if (keyf == NULL)
6637	{
6638		sm_syslog(LOG_ERR, NOQID, "unable to read %s: %s",
6639			  keypath, sm_errstring(errno));
6640	}
6641	else
6642	{
6643		r = sm_io_fscanf(keyf, SM_TIME_DEFAULT, "%ld", &n);
6644		if (r == 1)
6645			key = n;
6646		(void) sm_io_close(keyf, SM_TIME_DEFAULT);
6647	}
6648	return key;
6649}
6650#endif /* _FFR_SELECT_SHM */
6651
6652/*
6653**  INIT_SHM -- initialize shared memory structure
6654**
6655**	Initialize or attach to shared memory segment.
6656**	Currently it is not a fatal error if this doesn't work.
6657**	However, it causes us to have a "fallback" storage location
6658**	for everything that is supposed to be in the shared memory,
6659**	which makes the code slightly ugly.
6660**
6661**	Parameters:
6662**		qn -- number of queue directories.
6663**		owner -- owner of shared memory.
6664**		hash -- identifies data that is stored in shared memory.
6665**
6666**	Returns:
6667**		none.
6668*/
6669
6670static void init_shm __P((int, bool, unsigned int));
6671
6672static void
6673init_shm(qn, owner, hash)
6674	int qn;
6675	bool owner;
6676	unsigned int hash;
6677{
6678	int i;
6679#if _FFR_SELECT_SHM
6680	bool keyselect;
6681#endif /* _FFR_SELECT_SHM */
6682
6683	PtrFileSys = &FileSys[0];
6684	PNumFileSys = &Numfilesys;
6685#if _FFR_SELECT_SHM
6686/* if this "key" is specified: select one yourself */
6687# define SEL_SHM_KEY	((key_t) -1)
6688# define FIRST_SHM_KEY	25
6689#endif /* _FFR_SELECT_SHM */
6690
6691	/* This allows us to disable shared memory at runtime. */
6692	if (ShmKey != 0)
6693	{
6694		int count;
6695		int save_errno;
6696
6697		count = 0;
6698		shms = SM_T_SIZE + qn * sizeof(QUEUE_SHM_T);
6699#if _FFR_SELECT_SHM
6700		keyselect = ShmKey == SEL_SHM_KEY;
6701		if (keyselect)
6702		{
6703			if (owner)
6704				ShmKey = FIRST_SHM_KEY;
6705			else
6706			{
6707				ShmKey = read_key_file(ShmKeyFile, ShmKey);
6708				keyselect = false;
6709				if (ShmKey == SEL_SHM_KEY)
6710					goto error;
6711			}
6712		}
6713#endif /* _FFR_SELECT_SHM */
6714		for (;;)
6715		{
6716			/* XXX: maybe allow read access for group? */
6717			Pshm = sm_shmstart(ShmKey, shms, SHM_R|SHM_W, &ShmId,
6718					   owner);
6719			save_errno = errno;
6720			if (Pshm != NULL || !sm_file_exists(save_errno))
6721				break;
6722			if (++count >= 3)
6723			{
6724#if _FFR_SELECT_SHM
6725				if (keyselect)
6726				{
6727					++ShmKey;
6728
6729					/* back where we started? */
6730					if (ShmKey == SEL_SHM_KEY)
6731						break;
6732					continue;
6733				}
6734#endif /* _FFR_SELECT_SHM */
6735				break;
6736			}
6737#if _FFR_SELECT_SHM
6738			/* only sleep if we are at the first key */
6739			if (!keyselect || ShmKey == SEL_SHM_KEY)
6740#endif /* _FFR_SELECT_SHM */
6741			sleep(count);
6742		}
6743		if (Pshm != NULL)
6744		{
6745			int *p;
6746
6747#if _FFR_SELECT_SHM
6748			if (keyselect)
6749				(void) write_key_file(ShmKeyFile, (long) ShmKey);
6750#endif /* _FFR_SELECT_SHM */
6751			p = (int *) Pshm;
6752			if (owner)
6753			{
6754				*p = (int) shms;
6755				*((pid_t *) SHM_OFF_PID(Pshm)) = CurrentPid;
6756				p = (int *) SHM_OFF_TAG(Pshm);
6757				*p = hash;
6758			}
6759			else
6760			{
6761				if (*p != (int) shms)
6762				{
6763					save_errno = EINVAL;
6764					cleanup_shm(false);
6765					goto error;
6766				}
6767				p = (int *) SHM_OFF_TAG(Pshm);
6768				if (*p != (int) hash)
6769				{
6770					save_errno = EINVAL;
6771					cleanup_shm(false);
6772					goto error;
6773				}
6774
6775				/*
6776				**  XXX how to check the pid?
6777				**  Read it from the pid-file? That does
6778				**  not need to exist.
6779				**  We could disable shm if we can't confirm
6780				**  that it is the right one.
6781				*/
6782			}
6783
6784			PtrFileSys = (FILESYS *) OFF_FILE_SYS(Pshm);
6785			PNumFileSys = (int *) OFF_NUM_FILE_SYS(Pshm);
6786			QShm = (QUEUE_SHM_T *) OFF_QUEUE_SHM(Pshm);
6787			PRSATmpCnt = (int *) OFF_RSA_TMP_CNT(Pshm);
6788			*PRSATmpCnt = 0;
6789			if (owner)
6790			{
6791				/* initialize values in shared memory */
6792				NumFileSys = 0;
6793				for (i = 0; i < qn; i++)
6794					QShm[i].qs_entries = -1;
6795			}
6796			return;
6797		}
6798  error:
6799		if (LogLevel > (owner ? 8 : 11))
6800		{
6801			sm_syslog(owner ? LOG_ERR : LOG_NOTICE, NOQID,
6802				  "can't %s shared memory, key=%ld: %s",
6803				  owner ? "initialize" : "attach to",
6804				  (long) ShmKey, sm_errstring(save_errno));
6805		}
6806	}
6807}
6808#endif /* SM_CONF_SHM */
6809
6810
6811/*
6812**  SETUP_QUEUES -- setup all queue groups
6813**
6814**	Parameters:
6815**		owner -- owner of shared memory.
6816**
6817**	Returns:
6818**		none.
6819**
6820#if SM_CONF_SHM
6821**	Side Effects:
6822**		attaches shared memory.
6823#endif * SM_CONF_SHM *
6824*/
6825
6826void
6827setup_queues(owner)
6828	bool owner;
6829{
6830	int i, qn, len;
6831	unsigned int hashval;
6832	time_t now;
6833	char basedir[MAXPATHLEN];
6834	struct stat st;
6835
6836	/*
6837	**  Determine basedir for all queue directories.
6838	**  All queue directories must be (first level) subdirectories
6839	**  of the basedir.  The basedir is the QueueDir
6840	**  without wildcards, but with trailing /
6841	*/
6842
6843	hashval = 0;
6844	errno = 0;
6845	len = sm_strlcpy(basedir, QueueDir, sizeof basedir);
6846
6847	/* Provide space for trailing '/' */
6848	if (len >= sizeof basedir - 1)
6849	{
6850		syserr("QueueDirectory: path too long: %d,  max %d",
6851			len, (int) sizeof basedir - 1);
6852		ExitStat = EX_CONFIG;
6853		return;
6854	}
6855	SM_ASSERT(len > 0);
6856	if (basedir[len - 1] == '*')
6857	{
6858		char *cp;
6859
6860		cp = SM_LAST_DIR_DELIM(basedir);
6861		if (cp == NULL)
6862		{
6863			syserr("QueueDirectory: can not wildcard relative path \"%s\"",
6864				QueueDir);
6865			if (tTd(41, 2))
6866				sm_dprintf("setup_queues: \"%s\": Can not wildcard relative path.\n",
6867					QueueDir);
6868			ExitStat = EX_CONFIG;
6869			return;
6870		}
6871
6872		/* cut off wildcard pattern */
6873		*++cp = '\0';
6874		len = cp - basedir;
6875	}
6876	else if (!SM_IS_DIR_DELIM(basedir[len - 1]))
6877	{
6878		/* append trailing slash since it is a directory */
6879		basedir[len] = '/';
6880		basedir[++len] = '\0';
6881	}
6882
6883	/* len counts up to the last directory delimiter */
6884	SM_ASSERT(basedir[len - 1] == '/');
6885
6886	if (chdir(basedir) < 0)
6887	{
6888		int save_errno = errno;
6889
6890		syserr("can not chdir(%s)", basedir);
6891		if (save_errno == EACCES)
6892			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
6893				"Program mode requires special privileges, e.g., root or TrustedUser.\n");
6894		if (tTd(41, 2))
6895			sm_dprintf("setup_queues: \"%s\": %s\n",
6896				   basedir, sm_errstring(errno));
6897		ExitStat = EX_CONFIG;
6898		return;
6899	}
6900#if SM_CONF_SHM
6901	hashval = hash_q(basedir, hashval);
6902#endif /* SM_CONF_SHM */
6903
6904	/* initialize for queue runs */
6905	DoQueueRun = false;
6906	now = curtime();
6907	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
6908		Queue[i]->qg_nextrun = now;
6909
6910
6911	if (UseMSP && OpMode != MD_TEST)
6912	{
6913		long sff = SFF_CREAT;
6914
6915		if (stat(".", &st) < 0)
6916		{
6917			syserr("can not stat(%s)", basedir);
6918			if (tTd(41, 2))
6919				sm_dprintf("setup_queues: \"%s\": %s\n",
6920					   basedir, sm_errstring(errno));
6921			ExitStat = EX_CONFIG;
6922			return;
6923		}
6924		if (RunAsUid == 0)
6925			sff |= SFF_ROOTOK;
6926
6927		/*
6928		**  Check queue directory permissions.
6929		**	Can we write to a group writable queue directory?
6930		*/
6931
6932		if (bitset(S_IWGRP, QueueFileMode) &&
6933		    bitset(S_IWGRP, st.st_mode) &&
6934		    safefile(" ", RunAsUid, RunAsGid, RunAsUserName, sff,
6935			     QueueFileMode, NULL) != 0)
6936		{
6937			syserr("can not write to queue directory %s (RunAsGid=%d, required=%d)",
6938				basedir, (int) RunAsGid, (int) st.st_gid);
6939		}
6940		if (bitset(S_IWOTH|S_IXOTH, st.st_mode))
6941		{
6942#if _FFR_MSP_PARANOIA
6943			syserr("dangerous permissions=%o on queue directory %s",
6944				(int) st.st_mode, basedir);
6945#else /* _FFR_MSP_PARANOIA */
6946			if (LogLevel > 0)
6947				sm_syslog(LOG_ERR, NOQID,
6948					  "dangerous permissions=%o on queue directory %s",
6949					  (int) st.st_mode, basedir);
6950#endif /* _FFR_MSP_PARANOIA */
6951		}
6952#if _FFR_MSP_PARANOIA
6953		if (NumQueue > 1)
6954			syserr("can not use multiple queues for MSP");
6955#endif /* _FFR_MSP_PARANOIA */
6956	}
6957
6958	/* initial number of queue directories */
6959	qn = 0;
6960	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
6961		qn = multiqueue_cache(basedir, len, Queue[i], qn, &hashval);
6962
6963#if SM_CONF_SHM
6964	init_shm(qn, owner, hashval);
6965	i = filesys_setup(owner || ShmId == SM_SHM_NO_ID);
6966	if (i == FSF_NOT_FOUND)
6967	{
6968		/*
6969		**  We didn't get the right filesystem data
6970		**  This may happen if we don't have the right shared memory.
6971		**  So let's do this without shared memory.
6972		*/
6973
6974		SM_ASSERT(!owner);
6975		cleanup_shm(false);	/* release shared memory */
6976		i = filesys_setup(false);
6977		if (i < 0)
6978			syserr("filesys_setup failed twice, result=%d", i);
6979		else if (LogLevel > 8)
6980			sm_syslog(LOG_WARNING, NOQID,
6981				  "shared memory does not contain expected data, ignored");
6982	}
6983#else /* SM_CONF_SHM */
6984	i = filesys_setup(true);
6985#endif /* SM_CONF_SHM */
6986	if (i < 0)
6987		ExitStat = EX_CONFIG;
6988}
6989
6990#if SM_CONF_SHM
6991/*
6992**  CLEANUP_SHM -- do some cleanup work for shared memory etc
6993**
6994**	Parameters:
6995**		owner -- owner of shared memory?
6996**
6997**	Returns:
6998**		none.
6999**
7000**	Side Effects:
7001**		detaches shared memory.
7002*/
7003
7004void
7005cleanup_shm(owner)
7006	bool owner;
7007{
7008	if (ShmId != SM_SHM_NO_ID)
7009	{
7010		if (sm_shmstop(Pshm, ShmId, owner) < 0 && LogLevel > 8)
7011			sm_syslog(LOG_INFO, NOQID, "sm_shmstop failed=%s",
7012				  sm_errstring(errno));
7013		Pshm = NULL;
7014		ShmId = SM_SHM_NO_ID;
7015	}
7016}
7017#endif /* SM_CONF_SHM */
7018
7019/*
7020**  CLEANUP_QUEUES -- do some cleanup work for queues
7021**
7022**	Parameters:
7023**		none.
7024**
7025**	Returns:
7026**		none.
7027**
7028*/
7029
7030void
7031cleanup_queues()
7032{
7033	sync_queue_time();
7034}
7035/*
7036**  SET_DEF_QUEUEVAL -- set default values for a queue group.
7037**
7038**	Parameters:
7039**		qg -- queue group
7040**		all -- set all values (true for default group)?
7041**
7042**	Returns:
7043**		none.
7044**
7045**	Side Effects:
7046**		sets default values for the queue group.
7047*/
7048
7049void
7050set_def_queueval(qg, all)
7051	QUEUEGRP *qg;
7052	bool all;
7053{
7054	if (bitnset(QD_DEFINED, qg->qg_flags))
7055		return;
7056	if (all)
7057		qg->qg_qdir = QueueDir;
7058#if _FFR_QUEUE_GROUP_SORTORDER
7059	qg->qg_sortorder = QueueSortOrder;
7060#endif /* _FFR_QUEUE_GROUP_SORTORDER */
7061	qg->qg_maxqrun = all ? MaxRunnersPerQueue : -1;
7062	qg->qg_nice = NiceQueueRun;
7063}
7064/*
7065**  MAKEQUEUE -- define a new queue.
7066**
7067**	Parameters:
7068**		line -- description of queue.  This is in labeled fields.
7069**			The fields are:
7070**			   F -- the flags associated with the queue
7071**			   I -- the interval between running the queue
7072**			   J -- the maximum # of jobs in work list
7073**			   [M -- the maximum # of jobs in a queue run]
7074**			   N -- the niceness at which to run
7075**			   P -- the path to the queue
7076**			   S -- the queue sorting order
7077**			   R -- number of parallel queue runners
7078**			   r -- max recipients per envelope
7079**			The first word is the canonical name of the queue.
7080**		qdef -- this is a 'Q' definition from .cf
7081**
7082**	Returns:
7083**		none.
7084**
7085**	Side Effects:
7086**		enters the queue into the queue table.
7087*/
7088
7089void
7090makequeue(line, qdef)
7091	char *line;
7092	bool qdef;
7093{
7094	register char *p;
7095	register QUEUEGRP *qg;
7096	register STAB *s;
7097	int i;
7098	char fcode;
7099
7100	/* allocate a queue and set up defaults */
7101	qg = (QUEUEGRP *) xalloc(sizeof *qg);
7102	memset((char *) qg, '\0', sizeof *qg);
7103
7104	if (line[0] == '\0')
7105	{
7106		syserr("name required for queue");
7107		return;
7108	}
7109
7110	/* collect the queue name */
7111	for (p = line;
7112	     *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p));
7113	     p++)
7114		continue;
7115	if (*p != '\0')
7116		*p++ = '\0';
7117	qg->qg_name = newstr(line);
7118
7119	/* set default values, can be overridden below */
7120	set_def_queueval(qg, false);
7121
7122	/* now scan through and assign info from the fields */
7123	while (*p != '\0')
7124	{
7125		auto char *delimptr;
7126
7127		while (*p != '\0' &&
7128		       (*p == ',' || (isascii(*p) && isspace(*p))))
7129			p++;
7130
7131		/* p now points to field code */
7132		fcode = *p;
7133		while (*p != '\0' && *p != '=' && *p != ',')
7134			p++;
7135		if (*p++ != '=')
7136		{
7137			syserr("queue %s: `=' expected", qg->qg_name);
7138			return;
7139		}
7140		while (isascii(*p) && isspace(*p))
7141			p++;
7142
7143		/* p now points to the field body */
7144		p = munchstring(p, &delimptr, ',');
7145
7146		/* install the field into the queue struct */
7147		switch (fcode)
7148		{
7149		  case 'P':		/* pathname */
7150			if (*p == '\0')
7151				syserr("queue %s: empty path name",
7152					qg->qg_name);
7153			else
7154				qg->qg_qdir = newstr(p);
7155			break;
7156
7157		  case 'F':		/* flags */
7158			for (; *p != '\0'; p++)
7159				if (!(isascii(*p) && isspace(*p)))
7160					setbitn(*p, qg->qg_flags);
7161			break;
7162
7163			/*
7164			**  Do we need two intervals here:
7165			**  One for persistent queue runners,
7166			**  one for "normal" queue runs?
7167			*/
7168
7169		  case 'I':	/* interval between running the queue */
7170			qg->qg_queueintvl = convtime(p, 'm');
7171			break;
7172
7173		  case 'N':		/* run niceness */
7174			qg->qg_nice = atoi(p);
7175			break;
7176
7177		  case 'R':		/* maximum # of runners for the group */
7178			i = atoi(p);
7179
7180			/* can't have more runners than allowed total */
7181			if (MaxQueueChildren > 0 && i > MaxQueueChildren)
7182			{
7183				qg->qg_maxqrun = MaxQueueChildren;
7184				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7185						     "Q=%s: R=%d exceeds MaxQueueChildren=%d, set to MaxQueueChildren\n",
7186						     qg->qg_name, i,
7187						     MaxQueueChildren);
7188			}
7189			else
7190				qg->qg_maxqrun = i;
7191			break;
7192
7193		  case 'J':		/* maximum # of jobs in work list */
7194			qg->qg_maxlist = atoi(p);
7195			break;
7196
7197		  case 'r':		/* max recipients per envelope */
7198			qg->qg_maxrcpt = atoi(p);
7199			break;
7200
7201#if _FFR_QUEUE_GROUP_SORTORDER
7202		  case 'S':		/* queue sorting order */
7203			switch (*p)
7204			{
7205			  case 'h':	/* Host first */
7206			  case 'H':
7207				qg->qg_sortorder = QSO_BYHOST;
7208				break;
7209
7210			  case 'p':	/* Priority order */
7211			  case 'P':
7212				qg->qg_sortorder = QSO_BYPRIORITY;
7213				break;
7214
7215			  case 't':	/* Submission time */
7216			  case 'T':
7217				qg->qg_sortorder = QSO_BYTIME;
7218				break;
7219
7220			  case 'f':	/* File name */
7221			  case 'F':
7222				qg->qg_sortorder = QSO_BYFILENAME;
7223				break;
7224
7225			  case 'm':	/* Modification time */
7226			  case 'M':
7227				qg->qg_sortorder = QSO_BYMODTIME;
7228				break;
7229
7230			  case 'r':	/* Random */
7231			  case 'R':
7232				qg->qg_sortorder = QSO_RANDOM;
7233				break;
7234
7235# if _FFR_RHS
7236			  case 's':	/* Shuffled host name */
7237			  case 'S':
7238				qg->qg_sortorder = QSO_BYSHUFFLE;
7239				break;
7240# endif /* _FFR_RHS */
7241
7242			  case 'n':	/* none */
7243			  case 'N':
7244				qg->qg_sortorder = QSO_NONE;
7245				break;
7246
7247			  default:
7248				syserr("Invalid queue sort order \"%s\"", p);
7249			}
7250			break;
7251#endif /* _FFR_QUEUE_GROUP_SORTORDER */
7252
7253		  default:
7254			syserr("Q%s: unknown queue equate %c=",
7255			       qg->qg_name, fcode);
7256			break;
7257		}
7258
7259		p = delimptr;
7260	}
7261
7262#if !HASNICE
7263	if (qg->qg_nice != NiceQueueRun)
7264	{
7265		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7266				     "Q%s: Warning: N= set on system that doesn't support nice()\n",
7267				     qg->qg_name);
7268	}
7269#endif /* !HASNICE */
7270
7271	/* do some rationality checking */
7272	if (NumQueue >= MAXQUEUEGROUPS)
7273	{
7274		syserr("too many queue groups defined (%d max)",
7275			MAXQUEUEGROUPS);
7276		return;
7277	}
7278
7279	if (qg->qg_qdir == NULL)
7280	{
7281		if (QueueDir == NULL || *QueueDir == '\0')
7282		{
7283			syserr("QueueDir must be defined before queue groups");
7284			return;
7285		}
7286		qg->qg_qdir = newstr(QueueDir);
7287	}
7288
7289	if (qg->qg_maxqrun > 1 && !bitnset(QD_FORK, qg->qg_flags))
7290	{
7291		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7292				     "Warning: Q=%s: R=%d: multiple queue runners specified\n\tbut flag '%c' is not set\n",
7293				     qg->qg_name, qg->qg_maxqrun, QD_FORK);
7294	}
7295
7296	/* enter the queue into the symbol table */
7297	if (tTd(37, 8))
7298		sm_syslog(LOG_INFO, NOQID,
7299			  "Adding %s to stab, path: %s", qg->qg_name,
7300			  qg->qg_qdir);
7301	s = stab(qg->qg_name, ST_QUEUE, ST_ENTER);
7302	if (s->s_quegrp != NULL)
7303	{
7304		i = s->s_quegrp->qg_index;
7305
7306		/* XXX what about the pointers inside this struct? */
7307		sm_free(s->s_quegrp); /* XXX */
7308	}
7309	else
7310		i = NumQueue++;
7311	Queue[i] = s->s_quegrp = qg;
7312	qg->qg_index = i;
7313
7314	/* set default value for max queue runners */
7315	if (qg->qg_maxqrun < 0)
7316	{
7317		if (MaxRunnersPerQueue > 0)
7318			qg->qg_maxqrun = MaxRunnersPerQueue;
7319		else
7320			qg->qg_maxqrun = 1;
7321	}
7322	if (qdef)
7323		setbitn(QD_DEFINED, qg->qg_flags);
7324}
7325#if 0
7326/*
7327**  HASHFQN -- calculate a hash value for a fully qualified host name
7328**
7329**	Arguments:
7330**		fqn -- an all lower-case host.domain string
7331**		buckets -- the number of buckets (queue directories)
7332**
7333**	Returns:
7334**		a bucket number (signed integer)
7335**		-1 on error
7336**
7337**	Contributed by Exactis.com, Inc.
7338*/
7339
7340int
7341hashfqn(fqn, buckets)
7342	register char *fqn;
7343	int buckets;
7344{
7345	register char *p;
7346	register int h = 0, hash, cnt;
7347
7348	if (fqn == NULL)
7349		return -1;
7350
7351	/*
7352	**  A variation on the gdb hash
7353	**  This is the best as of Feb 19, 1996 --bcx
7354	*/
7355
7356	p = fqn;
7357	h = 0x238F13AF * strlen(p);
7358	for (cnt = 0; *p != 0; ++p, cnt++)
7359	{
7360		h = (h + (*p << (cnt * 5 % 24))) & 0x7FFFFFFF;
7361	}
7362	h = (1103515243 * h + 12345) & 0x7FFFFFFF;
7363	if (buckets < 2)
7364		hash = 0;
7365	else
7366		hash = (h % buckets);
7367
7368	return hash;
7369}
7370#endif /* 0 */
7371
7372/*
7373**  A structure for sorting Queue according to maxqrun without
7374**	screwing up Queue itself.
7375*/
7376
7377struct sortqgrp
7378{
7379	int sg_idx;		/* original index */
7380	int sg_maxqrun;		/* max queue runners */
7381};
7382typedef struct sortqgrp	SORTQGRP_T;
7383static int cmpidx __P((const void *, const void *));
7384
7385static int
7386cmpidx(a, b)
7387	const void *a;
7388	const void *b;
7389{
7390	/* The sort is highest to lowest, so the comparison is reversed */
7391	if (((SORTQGRP_T *)a)->sg_maxqrun < ((SORTQGRP_T *)b)->sg_maxqrun)
7392		return 1;
7393	else if (((SORTQGRP_T *)a)->sg_maxqrun > ((SORTQGRP_T *)b)->sg_maxqrun)
7394		return -1;
7395	else
7396		return 0;
7397}
7398
7399/*
7400**  MAKEWORKGROUP -- balance queue groups into work groups per MaxQueueChildren
7401**
7402**  Take the now defined queue groups and assign them to work groups.
7403**  This is done to balance out the number of concurrently active
7404**  queue runners such that MaxQueueChildren is not exceeded. This may
7405**  result in more than one queue group per work group. In such a case
7406**  the number of running queue groups in that work group will have no
7407**  more than the work group maximum number of runners (a "fair" portion
7408**  of MaxQueueRunners). All queue groups within a work group will get a
7409**  chance at running.
7410**
7411**	Parameters:
7412**		none.
7413**
7414**	Returns:
7415**		nothing.
7416**
7417**	Side Effects:
7418**		Sets up WorkGrp structure.
7419*/
7420
7421void
7422makeworkgroups()
7423{
7424	int i, j, total_runners, dir, h;
7425	SORTQGRP_T si[MAXQUEUEGROUPS + 1];
7426
7427	total_runners = 0;
7428	if (NumQueue == 1 && strcmp(Queue[0]->qg_name, "mqueue") == 0)
7429	{
7430		/*
7431		**  There is only the "mqueue" queue group (a default)
7432		**  containing all of the queues. We want to provide to
7433		**  this queue group the maximum allowable queue runners.
7434		**  To match older behavior (8.10/8.11) we'll try for
7435		**  1 runner per queue capping it at MaxQueueChildren.
7436		**  So if there are N queues, then there will be N runners
7437		**  for the "mqueue" queue group (where N is kept less than
7438		**  MaxQueueChildren).
7439		*/
7440
7441		NumWorkGroups = 1;
7442		WorkGrp[0].wg_numqgrp = 1;
7443		WorkGrp[0].wg_qgs = (QUEUEGRP **) xalloc(sizeof(QUEUEGRP *));
7444		WorkGrp[0].wg_qgs[0] = Queue[0];
7445		if (MaxQueueChildren > 0 &&
7446		    Queue[0]->qg_numqueues > MaxQueueChildren)
7447			WorkGrp[0].wg_runners = MaxQueueChildren;
7448		else
7449			WorkGrp[0].wg_runners = Queue[0]->qg_numqueues;
7450
7451		Queue[0]->qg_wgrp = 0;
7452
7453		/* can't have more runners than allowed total */
7454		if (MaxQueueChildren > 0 &&
7455		    Queue[0]->qg_maxqrun > MaxQueueChildren)
7456			Queue[0]->qg_maxqrun = MaxQueueChildren;
7457		WorkGrp[0].wg_maxact = Queue[0]->qg_maxqrun;
7458		WorkGrp[0].wg_lowqintvl = Queue[0]->qg_queueintvl;
7459		return;
7460	}
7461
7462	for (i = 0; i < NumQueue; i++)
7463	{
7464		si[i].sg_maxqrun = Queue[i]->qg_maxqrun;
7465		si[i].sg_idx = i;
7466	}
7467	qsort(si, NumQueue, sizeof(si[0]), cmpidx);
7468
7469	NumWorkGroups = 0;
7470	for (i = 0; i < NumQueue; i++)
7471	{
7472		total_runners += si[i].sg_maxqrun;
7473		if (MaxQueueChildren <= 0 || total_runners <= MaxQueueChildren)
7474			NumWorkGroups++;
7475		else
7476			break;
7477	}
7478
7479	if (NumWorkGroups < 1)
7480		NumWorkGroups = 1; /* gotta have one at least */
7481	else if (NumWorkGroups > MAXWORKGROUPS)
7482		NumWorkGroups = MAXWORKGROUPS; /* the limit */
7483
7484	/*
7485	**  We now know the number of work groups to pack the queue groups
7486	**  into. The queue groups in 'Queue' are sorted from highest
7487	**  to lowest for the number of runners per queue group.
7488	**  We put the queue groups with the largest number of runners
7489	**  into work groups first. Then the smaller ones are fitted in
7490	**  where it looks best.
7491	*/
7492
7493	j = 0;
7494	dir = 1;
7495	for (i = 0; i < NumQueue; i++)
7496	{
7497		/* a to-and-fro packing scheme, continue from last position */
7498		if (j >= NumWorkGroups)
7499		{
7500			dir = -1;
7501			j = NumWorkGroups - 1;
7502		}
7503		else if (j < 0)
7504		{
7505			j = 0;
7506			dir = 1;
7507		}
7508
7509		if (WorkGrp[j].wg_qgs == NULL)
7510			WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_malloc(sizeof(QUEUEGRP *) *
7511							(WorkGrp[j].wg_numqgrp + 1));
7512		else
7513			WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_realloc(WorkGrp[j].wg_qgs,
7514							sizeof(QUEUEGRP *) *
7515							(WorkGrp[j].wg_numqgrp + 1));
7516		if (WorkGrp[j].wg_qgs == NULL)
7517		{
7518			syserr("!cannot allocate memory for work queues, need %d bytes",
7519			       (int) (sizeof(QUEUEGRP *) *
7520				      (WorkGrp[j].wg_numqgrp + 1)));
7521		}
7522
7523		h = si[i].sg_idx;
7524		WorkGrp[j].wg_qgs[WorkGrp[j].wg_numqgrp] = Queue[h];
7525		WorkGrp[j].wg_numqgrp++;
7526		WorkGrp[j].wg_runners += Queue[h]->qg_maxqrun;
7527		Queue[h]->qg_wgrp = j;
7528
7529		if (WorkGrp[j].wg_maxact == 0)
7530		{
7531			/* can't have more runners than allowed total */
7532			if (MaxQueueChildren > 0 &&
7533			    Queue[h]->qg_maxqrun > MaxQueueChildren)
7534				Queue[h]->qg_maxqrun = MaxQueueChildren;
7535			WorkGrp[j].wg_maxact = Queue[h]->qg_maxqrun;
7536		}
7537
7538		/*
7539		**  XXX: must wg_lowqintvl be the GCD?
7540		**  qg1: 2m, qg2: 3m, minimum: 2m, when do queue runs for
7541		**  qg2 occur?
7542		*/
7543
7544		/* keep track of the lowest interval for a persistent runner */
7545		if (Queue[h]->qg_queueintvl > 0 &&
7546		    WorkGrp[j].wg_lowqintvl < Queue[h]->qg_queueintvl)
7547			WorkGrp[j].wg_lowqintvl = Queue[h]->qg_queueintvl;
7548		j += dir;
7549	}
7550	if (tTd(41, 9))
7551	{
7552		for (i = 0; i < NumWorkGroups; i++)
7553		{
7554			sm_dprintf("Workgroup[%d]=", i);
7555			for (j = 0; j < WorkGrp[i].wg_numqgrp; j++)
7556			{
7557				sm_dprintf("%s, ",
7558					WorkGrp[i].wg_qgs[j]->qg_name);
7559			}
7560			sm_dprintf("\n");
7561		}
7562	}
7563}
7564
7565/*
7566**  DUP_DF -- duplicate envelope data file
7567**
7568**	Copy the data file from the 'old' envelope to the 'new' envelope
7569**	in the most efficient way possible.
7570**
7571**	Create a hard link from the 'old' data file to the 'new' data file.
7572**	If the old and new queue directories are on different file systems,
7573**	then the new data file link is created in the old queue directory,
7574**	and the new queue file will contain a 'd' record pointing to the
7575**	directory containing the new data file.
7576**
7577**	Parameters:
7578**		old -- old envelope.
7579**		new -- new envelope.
7580**
7581**	Results:
7582**		Returns true on success, false on failure.
7583**
7584**	Side Effects:
7585**		On success, the new data file is created.
7586**		On fatal failure, EF_FATALERRS is set in old->e_flags.
7587*/
7588
7589static bool	dup_df __P((ENVELOPE *, ENVELOPE *));
7590
7591static bool
7592dup_df(old, new)
7593	ENVELOPE *old;
7594	ENVELOPE *new;
7595{
7596	int ofs, nfs, r;
7597	char opath[MAXPATHLEN];
7598	char npath[MAXPATHLEN];
7599
7600	if (!bitset(EF_HAS_DF, old->e_flags))
7601	{
7602		/*
7603		**  this can happen if: SuperSafe != True
7604		**  and a bounce mail is sent that is split.
7605		*/
7606
7607		queueup(old, false, true);
7608	}
7609	SM_REQUIRE(ISVALIDQGRP(old->e_qgrp) && ISVALIDQDIR(old->e_qdir));
7610	SM_REQUIRE(ISVALIDQGRP(new->e_qgrp) && ISVALIDQDIR(new->e_qdir));
7611
7612	(void) sm_strlcpy(opath, queuename(old, DATAFL_LETTER), sizeof opath);
7613	(void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof npath);
7614
7615	if (old->e_dfp != NULL)
7616	{
7617		r = sm_io_setinfo(old->e_dfp, SM_BF_COMMIT, NULL);
7618		if (r < 0 && errno != EINVAL)
7619		{
7620			syserr("@can't commit %s", opath);
7621			old->e_flags |= EF_FATALERRS;
7622			return false;
7623		}
7624	}
7625
7626	/*
7627	**  Attempt to create a hard link, if we think both old and new
7628	**  are on the same file system, otherwise copy the file.
7629	**
7630	**  Don't waste time attempting a hard link unless old and new
7631	**  are on the same file system.
7632	*/
7633
7634	ofs = Queue[old->e_qgrp]->qg_qpaths[old->e_qdir].qp_fsysidx;
7635	nfs = Queue[new->e_qgrp]->qg_qpaths[new->e_qdir].qp_fsysidx;
7636	if (FILE_SYS_DEV(ofs) == FILE_SYS_DEV(nfs))
7637	{
7638		if (link(opath, npath) == 0)
7639		{
7640			new->e_flags |= EF_HAS_DF;
7641			SYNC_DIR(npath, true);
7642			return true;
7643		}
7644		goto error;
7645	}
7646
7647	/*
7648	**  Can't link across queue directories, so try to create a hard
7649	**  link in the same queue directory as the old df file.
7650	**  The qf file will refer to the new df file using a 'd' record.
7651	*/
7652
7653	new->e_dfqgrp = old->e_dfqgrp;
7654	new->e_dfqdir = old->e_dfqdir;
7655	(void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof npath);
7656	if (link(opath, npath) == 0)
7657	{
7658		new->e_flags |= EF_HAS_DF;
7659		SYNC_DIR(npath, true);
7660		return true;
7661	}
7662
7663  error:
7664	if (LogLevel > 0)
7665		sm_syslog(LOG_ERR, old->e_id,
7666			  "dup_df: can't link %s to %s, error=%s, envelope splitting failed",
7667			  opath, npath, sm_errstring(errno));
7668	return false;
7669}
7670
7671/*
7672**  SPLIT_ENV -- Allocate a new envelope based on a given envelope.
7673**
7674**	Parameters:
7675**		e -- envelope.
7676**		sendqueue -- sendqueue for new envelope.
7677**		qgrp -- index of queue group.
7678**		qdir -- queue directory.
7679**
7680**	Results:
7681**		new envelope.
7682**
7683*/
7684
7685static ENVELOPE	*split_env __P((ENVELOPE *, ADDRESS *, int, int));
7686
7687static ENVELOPE *
7688split_env(e, sendqueue, qgrp, qdir)
7689	ENVELOPE *e;
7690	ADDRESS *sendqueue;
7691	int qgrp;
7692	int qdir;
7693{
7694	ENVELOPE *ee;
7695
7696	ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool, sizeof *ee);
7697	STRUCTCOPY(*e, *ee);
7698	ee->e_message = NULL;	/* XXX use original message? */
7699	ee->e_id = NULL;
7700	assign_queueid(ee);
7701	ee->e_sendqueue = sendqueue;
7702	ee->e_flags &= ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS
7703			 |EF_SENDRECEIPT|EF_RET_PARAM|EF_HAS_DF);
7704	ee->e_flags |= EF_NORECEIPT;	/* XXX really? */
7705	ee->e_from.q_state = QS_SENDER;
7706	ee->e_dfp = NULL;
7707	ee->e_lockfp = NULL;
7708	if (e->e_xfp != NULL)
7709		ee->e_xfp = sm_io_dup(e->e_xfp);
7710
7711	/* failed to dup e->e_xfp, start a new transcript */
7712	if (ee->e_xfp == NULL)
7713		openxscript(ee);
7714
7715	ee->e_qgrp = ee->e_dfqgrp = qgrp;
7716	ee->e_qdir = ee->e_dfqdir = qdir;
7717	ee->e_errormode = EM_MAIL;
7718	ee->e_statmsg = NULL;
7719	if (e->e_quarmsg != NULL)
7720		ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool,
7721						  e->e_quarmsg);
7722
7723	/*
7724	**  XXX Not sure if this copying is necessary.
7725	**  sendall() does this copying, but I (dm) don't know if that is
7726	**  because of the storage management discipline we were using
7727	**  before rpools were introduced, or if it is because these lists
7728	**  can be modified later.
7729	*/
7730
7731	ee->e_header = copyheader(e->e_header, ee->e_rpool);
7732	ee->e_errorqueue = copyqueue(e->e_errorqueue, ee->e_rpool);
7733
7734	return ee;
7735}
7736
7737/* return values from split functions, check also below! */
7738#define SM_SPLIT_FAIL	(0)
7739#define SM_SPLIT_NONE	(1)
7740#define SM_SPLIT_NEW(n)	(1 + (n))
7741
7742/*
7743**  SPLIT_ACROSS_QUEUE_GROUPS
7744**
7745**	This function splits an envelope across multiple queue groups
7746**	based on the queue group of each recipient.
7747**
7748**	Parameters:
7749**		e -- envelope.
7750**
7751**	Results:
7752**		SM_SPLIT_FAIL on failure
7753**		SM_SPLIT_NONE if no splitting occurred,
7754**		or 1 + the number of additional envelopes created.
7755**
7756**	Side Effects:
7757**		On success, e->e_sibling points to a list of zero or more
7758**		additional envelopes, and the associated data files exist
7759**		on disk.  But the queue files are not created.
7760**
7761**		On failure, e->e_sibling is not changed.
7762**		The order of recipients in e->e_sendqueue is permuted.
7763**		Abandoned data files for additional envelopes that failed
7764**		to be created may exist on disk.
7765*/
7766
7767static int	q_qgrp_compare __P((const void *, const void *));
7768static int	e_filesys_compare __P((const void *, const void *));
7769
7770static int
7771q_qgrp_compare(p1, p2)
7772	const void *p1;
7773	const void *p2;
7774{
7775	ADDRESS **pq1 = (ADDRESS **) p1;
7776	ADDRESS **pq2 = (ADDRESS **) p2;
7777
7778	return (*pq1)->q_qgrp - (*pq2)->q_qgrp;
7779}
7780
7781static int
7782e_filesys_compare(p1, p2)
7783	const void *p1;
7784	const void *p2;
7785{
7786	ENVELOPE **pe1 = (ENVELOPE **) p1;
7787	ENVELOPE **pe2 = (ENVELOPE **) p2;
7788	int fs1, fs2;
7789
7790	fs1 = Queue[(*pe1)->e_qgrp]->qg_qpaths[(*pe1)->e_qdir].qp_fsysidx;
7791	fs2 = Queue[(*pe2)->e_qgrp]->qg_qpaths[(*pe2)->e_qdir].qp_fsysidx;
7792	if (FILE_SYS_DEV(fs1) < FILE_SYS_DEV(fs2))
7793		return -1;
7794	if (FILE_SYS_DEV(fs1) > FILE_SYS_DEV(fs2))
7795		return 1;
7796	return 0;
7797}
7798
7799static int
7800split_across_queue_groups(e)
7801	ENVELOPE *e;
7802{
7803	int naddrs, nsplits, i;
7804	bool changed;
7805	char **pvp;
7806	ADDRESS *q, **addrs;
7807	ENVELOPE *ee, *es;
7808	ENVELOPE *splits[MAXQUEUEGROUPS];
7809	char pvpbuf[PSBUFSIZE];
7810
7811	SM_REQUIRE(ISVALIDQGRP(e->e_qgrp));
7812
7813	/* Count addresses and assign queue groups. */
7814	naddrs = 0;
7815	changed = false;
7816	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
7817	{
7818		if (QS_IS_DEAD(q->q_state))
7819			continue;
7820		++naddrs;
7821
7822		/* bad addresses and those already sent stay put */
7823		if (QS_IS_BADADDR(q->q_state) ||
7824		    QS_IS_SENT(q->q_state))
7825			q->q_qgrp = e->e_qgrp;
7826		else if (!ISVALIDQGRP(q->q_qgrp))
7827		{
7828			/* call ruleset which should return a queue group */
7829			i = rscap(RS_QUEUEGROUP, q->q_user, NULL, e, &pvp,
7830				  pvpbuf, sizeof(pvpbuf));
7831			if (i == EX_OK &&
7832			    pvp != NULL && pvp[0] != NULL &&
7833			    (pvp[0][0] & 0377) == CANONNET &&
7834			    pvp[1] != NULL && pvp[1][0] != '\0')
7835			{
7836				i = name2qid(pvp[1]);
7837				if (ISVALIDQGRP(i))
7838				{
7839					q->q_qgrp = i;
7840					changed = true;
7841					if (tTd(20, 4))
7842						sm_syslog(LOG_INFO, NOQID,
7843							"queue group name %s -> %d",
7844							pvp[1], i);
7845					continue;
7846				}
7847				else if (LogLevel > 10)
7848					sm_syslog(LOG_INFO, NOQID,
7849						"can't find queue group name %s, selection ignored",
7850						pvp[1]);
7851			}
7852			if (q->q_mailer != NULL &&
7853			    ISVALIDQGRP(q->q_mailer->m_qgrp))
7854			{
7855				changed = true;
7856				q->q_qgrp = q->q_mailer->m_qgrp;
7857			}
7858			else if (ISVALIDQGRP(e->e_qgrp))
7859				q->q_qgrp = e->e_qgrp;
7860			else
7861				q->q_qgrp = 0;
7862		}
7863	}
7864
7865	/* only one address? nothing to split. */
7866	if (naddrs <= 1 && !changed)
7867		return SM_SPLIT_NONE;
7868
7869	/* sort the addresses by queue group */
7870	addrs = sm_rpool_malloc_x(e->e_rpool, naddrs * sizeof(ADDRESS *));
7871	for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next)
7872	{
7873		if (QS_IS_DEAD(q->q_state))
7874			continue;
7875		addrs[i++] = q;
7876	}
7877	qsort(addrs, naddrs, sizeof(ADDRESS *), q_qgrp_compare);
7878
7879	/* split into multiple envelopes, by queue group */
7880	nsplits = 0;
7881	es = NULL;
7882	e->e_sendqueue = NULL;
7883	for (i = 0; i < naddrs; ++i)
7884	{
7885		if (i == naddrs - 1 || addrs[i]->q_qgrp != addrs[i + 1]->q_qgrp)
7886			addrs[i]->q_next = NULL;
7887		else
7888			addrs[i]->q_next = addrs[i + 1];
7889
7890		/* same queue group as original envelope? */
7891		if (addrs[i]->q_qgrp == e->e_qgrp)
7892		{
7893			if (e->e_sendqueue == NULL)
7894				e->e_sendqueue = addrs[i];
7895			continue;
7896		}
7897
7898		/* different queue group than original envelope */
7899		if (es == NULL || addrs[i]->q_qgrp != es->e_qgrp)
7900		{
7901			ee = split_env(e, addrs[i], addrs[i]->q_qgrp, NOQDIR);
7902			es = ee;
7903			splits[nsplits++] = ee;
7904		}
7905	}
7906
7907	/* no splits? return right now. */
7908	if (nsplits <= 0)
7909		return SM_SPLIT_NONE;
7910
7911	/* assign a queue directory to each additional envelope */
7912	for (i = 0; i < nsplits; ++i)
7913	{
7914		es = splits[i];
7915#if 0
7916		es->e_qdir = pickqdir(Queue[es->e_qgrp], es->e_msgsize, es);
7917#endif /* 0 */
7918		if (!setnewqueue(es))
7919			goto failure;
7920	}
7921
7922	/* sort the additional envelopes by queue file system */
7923	qsort(splits, nsplits, sizeof(ENVELOPE *), e_filesys_compare);
7924
7925	/* create data files for each additional envelope */
7926	if (!dup_df(e, splits[0]))
7927	{
7928		i = 0;
7929		goto failure;
7930	}
7931	for (i = 1; i < nsplits; ++i)
7932	{
7933		/* copy or link to the previous data file */
7934		if (!dup_df(splits[i - 1], splits[i]))
7935			goto failure;
7936	}
7937
7938	/* success: prepend the new envelopes to the e->e_sibling list */
7939	for (i = 0; i < nsplits; ++i)
7940	{
7941		es = splits[i];
7942		es->e_sibling = e->e_sibling;
7943		e->e_sibling = es;
7944	}
7945	return SM_SPLIT_NEW(nsplits);
7946
7947	/* failure: clean up */
7948  failure:
7949	if (i > 0)
7950	{
7951		int j;
7952
7953		for (j = 0; j < i; j++)
7954			(void) unlink(queuename(splits[j], DATAFL_LETTER));
7955	}
7956	e->e_sendqueue = addrs[0];
7957	for (i = 0; i < naddrs - 1; ++i)
7958		addrs[i]->q_next = addrs[i + 1];
7959	addrs[naddrs - 1]->q_next = NULL;
7960	return SM_SPLIT_FAIL;
7961}
7962
7963/*
7964**  SPLIT_WITHIN_QUEUE
7965**
7966**	Split an envelope with multiple recipients into several
7967**	envelopes within the same queue directory, if the number of
7968**	recipients exceeds the limit for the queue group.
7969**
7970**	Parameters:
7971**		e -- envelope.
7972**
7973**	Results:
7974**		SM_SPLIT_FAIL on failure
7975**		SM_SPLIT_NONE if no splitting occurred,
7976**		or 1 + the number of additional envelopes created.
7977*/
7978
7979#define SPLIT_LOG_LEVEL	8
7980
7981static int	split_within_queue __P((ENVELOPE *));
7982
7983static int
7984split_within_queue(e)
7985	ENVELOPE *e;
7986{
7987	int maxrcpt, nrcpt, ndead, nsplit, i;
7988	int j, l;
7989	char *lsplits;
7990	ADDRESS *q, **addrs;
7991	ENVELOPE *ee, *firstsibling;
7992
7993	if (!ISVALIDQGRP(e->e_qgrp) || bitset(EF_SPLIT, e->e_flags))
7994		return SM_SPLIT_NONE;
7995
7996	/* don't bother if there is no recipient limit */
7997	maxrcpt = Queue[e->e_qgrp]->qg_maxrcpt;
7998	if (maxrcpt <= 0)
7999		return SM_SPLIT_NONE;
8000
8001	/* count recipients */
8002	nrcpt = 0;
8003	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
8004	{
8005		if (QS_IS_DEAD(q->q_state))
8006			continue;
8007		++nrcpt;
8008	}
8009	if (nrcpt <= maxrcpt)
8010		return SM_SPLIT_NONE;
8011
8012	/*
8013	**  Preserve the recipient list
8014	**  so that we can restore it in case of error.
8015	**  (But we discard dead addresses.)
8016	*/
8017
8018	addrs = sm_rpool_malloc_x(e->e_rpool, nrcpt * sizeof(ADDRESS *));
8019	for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next)
8020	{
8021		if (QS_IS_DEAD(q->q_state))
8022			continue;
8023		addrs[i++] = q;
8024	}
8025
8026	/*
8027	**  Partition the recipient list so that bad and sent addresses
8028	**  come first. These will go with the original envelope, and
8029	**  do not count towards the maxrcpt limit.
8030	**  addrs[] does not contain QS_IS_DEAD() addresses.
8031	*/
8032
8033	ndead = 0;
8034	for (i = 0; i < nrcpt; ++i)
8035	{
8036		if (QS_IS_BADADDR(addrs[i]->q_state) ||
8037		    QS_IS_SENT(addrs[i]->q_state) ||
8038		    QS_IS_DEAD(addrs[i]->q_state)) /* for paranoia's sake */
8039		{
8040			if (i > ndead)
8041			{
8042				ADDRESS *tmp = addrs[i];
8043
8044				addrs[i] = addrs[ndead];
8045				addrs[ndead] = tmp;
8046			}
8047			++ndead;
8048		}
8049	}
8050
8051	/* Check if no splitting required. */
8052	if (nrcpt - ndead <= maxrcpt)
8053		return SM_SPLIT_NONE;
8054
8055	/* fix links */
8056	for (i = 0; i < nrcpt - 1; ++i)
8057		addrs[i]->q_next = addrs[i + 1];
8058	addrs[nrcpt - 1]->q_next = NULL;
8059	e->e_sendqueue = addrs[0];
8060
8061	/* prepare buffer for logging */
8062	if (LogLevel > SPLIT_LOG_LEVEL)
8063	{
8064		l = MAXLINE;
8065		lsplits = sm_malloc(l);
8066		if (lsplits != NULL)
8067			*lsplits = '\0';
8068		j = 0;
8069	}
8070	else
8071	{
8072		/* get rid of stupid compiler warnings */
8073		lsplits = NULL;
8074		j = l = 0;
8075	}
8076
8077	/* split the envelope */
8078	firstsibling = e->e_sibling;
8079	i = maxrcpt + ndead;
8080	nsplit = 0;
8081	for (;;)
8082	{
8083		addrs[i - 1]->q_next = NULL;
8084		ee = split_env(e, addrs[i], e->e_qgrp, e->e_qdir);
8085		if (!dup_df(e, ee))
8086		{
8087
8088			ee = firstsibling;
8089			while (ee != NULL)
8090			{
8091				(void) unlink(queuename(ee, DATAFL_LETTER));
8092				ee = ee->e_sibling;
8093			}
8094
8095			/* Error.  Restore e's sibling & recipient lists. */
8096			e->e_sibling = firstsibling;
8097			for (i = 0; i < nrcpt - 1; ++i)
8098				addrs[i]->q_next = addrs[i + 1];
8099			if (lsplits != NULL)
8100				sm_free(lsplits);
8101			return SM_SPLIT_FAIL;
8102		}
8103
8104		/* prepend the new envelope to e->e_sibling */
8105		ee->e_sibling = e->e_sibling;
8106		e->e_sibling = ee;
8107		++nsplit;
8108		if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
8109		{
8110			if (j >= l - strlen(ee->e_id) - 3)
8111			{
8112				char *p;
8113
8114				l += MAXLINE;
8115				p = sm_realloc(lsplits, l);
8116				if (p == NULL)
8117				{
8118					/* let's try to get this done */
8119					sm_free(lsplits);
8120					lsplits = NULL;
8121				}
8122				else
8123					lsplits = p;
8124			}
8125			if (lsplits != NULL)
8126			{
8127				if (j == 0)
8128					j += sm_strlcat(lsplits + j,
8129							ee->e_id,
8130							l - j);
8131				else
8132					j += sm_strlcat2(lsplits + j,
8133							 "; ",
8134							 ee->e_id,
8135							 l - j);
8136				SM_ASSERT(j < l);
8137			}
8138		}
8139		if (nrcpt - i <= maxrcpt)
8140			break;
8141		i += maxrcpt;
8142	}
8143	if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
8144	{
8145		if (nsplit > 0)
8146		{
8147			sm_syslog(LOG_NOTICE, e->e_id,
8148				  "split: maxrcpts=%d, rcpts=%d, count=%d, id%s=%s",
8149				  maxrcpt, nrcpt - ndead, nsplit,
8150				  nsplit > 1 ? "s" : "", lsplits);
8151		}
8152		sm_free(lsplits);
8153	}
8154	return SM_SPLIT_NEW(nsplit);
8155}
8156/*
8157**  SPLIT_BY_RECIPIENT
8158**
8159**	Split an envelope with multiple recipients into multiple
8160**	envelopes as required by the sendmail configuration.
8161**
8162**	Parameters:
8163**		e -- envelope.
8164**
8165**	Results:
8166**		Returns true on success, false on failure.
8167**
8168**	Side Effects:
8169**		see split_across_queue_groups(), split_within_queue(e)
8170*/
8171
8172bool
8173split_by_recipient(e)
8174	ENVELOPE *e;
8175{
8176	int split, n, i, j, l;
8177	char *lsplits;
8178	ENVELOPE *ee, *next, *firstsibling;
8179
8180	if (OpMode == SM_VERIFY || !ISVALIDQGRP(e->e_qgrp) ||
8181	    bitset(EF_SPLIT, e->e_flags))
8182		return true;
8183	n = split_across_queue_groups(e);
8184	if (n == SM_SPLIT_FAIL)
8185		return false;
8186	firstsibling = ee = e->e_sibling;
8187	if (n > 1 && LogLevel > SPLIT_LOG_LEVEL)
8188	{
8189		l = MAXLINE;
8190		lsplits = sm_malloc(l);
8191		if (lsplits != NULL)
8192			*lsplits = '\0';
8193		j = 0;
8194	}
8195	else
8196	{
8197		/* get rid of stupid compiler warnings */
8198		lsplits = NULL;
8199		j = l = 0;
8200	}
8201	for (i = 1; i < n; ++i)
8202	{
8203		next = ee->e_sibling;
8204		if (split_within_queue(ee) == SM_SPLIT_FAIL)
8205		{
8206			e->e_sibling = firstsibling;
8207			return false;
8208		}
8209		ee->e_flags |= EF_SPLIT;
8210		if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
8211		{
8212			if (j >= l - strlen(ee->e_id) - 3)
8213			{
8214				char *p;
8215
8216				l += MAXLINE;
8217				p = sm_realloc(lsplits, l);
8218				if (p == NULL)
8219				{
8220					/* let's try to get this done */
8221					sm_free(lsplits);
8222					lsplits = NULL;
8223				}
8224				else
8225					lsplits = p;
8226			}
8227			if (lsplits != NULL)
8228			{
8229				if (j == 0)
8230					j += sm_strlcat(lsplits + j,
8231							ee->e_id, l - j);
8232				else
8233					j += sm_strlcat2(lsplits + j, "; ",
8234							 ee->e_id, l - j);
8235				SM_ASSERT(j < l);
8236			}
8237		}
8238		ee = next;
8239	}
8240	if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL && n > 1)
8241	{
8242		sm_syslog(LOG_NOTICE, e->e_id, "split: count=%d, id%s=%s",
8243			  n - 1, n > 2 ? "s" : "", lsplits);
8244		sm_free(lsplits);
8245	}
8246	split = split_within_queue(e) != SM_SPLIT_FAIL;
8247	if (split)
8248		e->e_flags |= EF_SPLIT;
8249	return split;
8250}
8251
8252/*
8253**  QUARANTINE_QUEUE_ITEM -- {un,}quarantine a single envelope
8254**
8255**	Add/remove quarantine reason and requeue appropriately.
8256**
8257**	Parameters:
8258**		qgrp -- queue group for the item
8259**		qdir -- queue directory in the given queue group
8260**		e -- envelope information for the item
8261**		reason -- quarantine reason, NULL means unquarantine.
8262**
8263**	Results:
8264**		true if item changed, false otherwise
8265**
8266**	Side Effects:
8267**		Changes quarantine tag in queue file and renames it.
8268*/
8269
8270static bool
8271quarantine_queue_item(qgrp, qdir, e, reason)
8272	int qgrp;
8273	int qdir;
8274	ENVELOPE *e;
8275	char *reason;
8276{
8277	bool dirty = false;
8278	bool failing = false;
8279	bool foundq = false;
8280	bool finished = false;
8281	int fd;
8282	int flags;
8283	int oldtype;
8284	int newtype;
8285	int save_errno;
8286	MODE_T oldumask = 0;
8287	SM_FILE_T *oldqfp, *tempqfp;
8288	char *bp;
8289	char oldqf[MAXPATHLEN];
8290	char tempqf[MAXPATHLEN];
8291	char newqf[MAXPATHLEN];
8292	char buf[MAXLINE];
8293
8294	oldtype = queue_letter(e, ANYQFL_LETTER);
8295	(void) sm_strlcpy(oldqf, queuename(e, ANYQFL_LETTER), sizeof oldqf);
8296	(void) sm_strlcpy(tempqf, queuename(e, NEWQFL_LETTER), sizeof tempqf);
8297
8298	/*
8299	**  Instead of duplicating all the open
8300	**  and lock code here, tell readqf() to
8301	**  do that work and return the open
8302	**  file pointer in e_lockfp.  Note that
8303	**  we must release the locks properly when
8304	**  we are done.
8305	*/
8306
8307	if (!readqf(e, true))
8308	{
8309		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8310				     "Skipping %s\n", qid_printname(e));
8311		return false;
8312	}
8313	oldqfp = e->e_lockfp;
8314
8315	/* open the new queue file */
8316	flags = O_CREAT|O_WRONLY|O_EXCL;
8317	if (bitset(S_IWGRP, QueueFileMode))
8318		oldumask = umask(002);
8319	fd = open(tempqf, flags, QueueFileMode);
8320	if (bitset(S_IWGRP, QueueFileMode))
8321		(void) umask(oldumask);
8322	RELEASE_QUEUE;
8323
8324	if (fd < 0)
8325	{
8326		save_errno = errno;
8327		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8328				     "Skipping %s: Could not open %s: %s\n",
8329				     qid_printname(e), tempqf,
8330				     sm_errstring(save_errno));
8331		(void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8332		return false;
8333	}
8334	if (!lockfile(fd, tempqf, NULL, LOCK_EX|LOCK_NB))
8335	{
8336		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8337				     "Skipping %s: Could not lock %s\n",
8338				     qid_printname(e), tempqf);
8339		(void) close(fd);
8340		(void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8341		return false;
8342	}
8343
8344	tempqfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &fd,
8345			     SM_IO_WRONLY_B, NULL);
8346	if (tempqfp == NULL)
8347	{
8348		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8349				     "Skipping %s: Could not lock %s\n",
8350				     qid_printname(e), tempqf);
8351		(void) close(fd);
8352		(void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8353		return false;
8354	}
8355
8356	/* Copy the data over, changing the quarantine reason */
8357	while ((bp = fgetfolded(buf, sizeof buf, oldqfp)) != NULL)
8358	{
8359		if (tTd(40, 4))
8360			sm_dprintf("+++++ %s\n", bp);
8361		switch (bp[0])
8362		{
8363		  case 'q':		/* quarantine reason */
8364			foundq = true;
8365			if (reason == NULL)
8366			{
8367				if (Verbose)
8368				{
8369					(void) sm_io_fprintf(smioout,
8370							     SM_TIME_DEFAULT,
8371							     "%s: Removed quarantine of \"%s\"\n",
8372							     e->e_id, &bp[1]);
8373				}
8374				sm_syslog(LOG_INFO, e->e_id, "unquarantine");
8375				dirty = true;
8376				continue;
8377			}
8378			else if (strcmp(reason, &bp[1]) == 0)
8379			{
8380				if (Verbose)
8381				{
8382					(void) sm_io_fprintf(smioout,
8383							     SM_TIME_DEFAULT,
8384							     "%s: Already quarantined with \"%s\"\n",
8385							     e->e_id, reason);
8386				}
8387				(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8388						     "q%s\n", reason);
8389			}
8390			else
8391			{
8392				if (Verbose)
8393				{
8394					(void) sm_io_fprintf(smioout,
8395							     SM_TIME_DEFAULT,
8396							     "%s: Quarantine changed from \"%s\" to \"%s\"\n",
8397							     e->e_id, &bp[1],
8398							     reason);
8399				}
8400				(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8401						     "q%s\n", reason);
8402				sm_syslog(LOG_INFO, e->e_id, "quarantine=%s",
8403					  reason);
8404				dirty = true;
8405			}
8406			break;
8407
8408		  case 'S':
8409			/*
8410			**  If we are quarantining an unquarantined item,
8411			**  need to put in a new 'q' line before it's
8412			**  too late.
8413			*/
8414
8415			if (!foundq && reason != NULL)
8416			{
8417				if (Verbose)
8418				{
8419					(void) sm_io_fprintf(smioout,
8420							     SM_TIME_DEFAULT,
8421							     "%s: Quarantined with \"%s\"\n",
8422							     e->e_id, reason);
8423				}
8424				(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8425						     "q%s\n", reason);
8426				sm_syslog(LOG_INFO, e->e_id, "quarantine=%s",
8427					  reason);
8428				foundq = true;
8429				dirty = true;
8430			}
8431
8432			/* Copy the line to the new file */
8433			(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8434					     "%s\n", bp);
8435			break;
8436
8437		  case '.':
8438			finished = true;
8439			/* FALLTHROUGH */
8440
8441		  default:
8442			/* Copy the line to the new file */
8443			(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8444					     "%s\n", bp);
8445			break;
8446		}
8447	}
8448
8449	/* Make sure we read the whole old file */
8450	errno = sm_io_error(tempqfp);
8451	if (errno != 0 && errno != SM_IO_EOF)
8452	{
8453		save_errno = errno;
8454		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8455				     "Skipping %s: Error reading %s: %s\n",
8456				     qid_printname(e), oldqf,
8457				     sm_errstring(save_errno));
8458		failing = true;
8459	}
8460
8461	if (!failing && !finished)
8462	{
8463		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8464				     "Skipping %s: Incomplete file: %s\n",
8465				     qid_printname(e), oldqf);
8466		failing = true;
8467	}
8468
8469	/* Check if we actually changed anything or we can just bail now */
8470	if (!dirty)
8471	{
8472		/* pretend we failed, even though we technically didn't */
8473		failing = true;
8474	}
8475
8476	/* Make sure we wrote things out safely */
8477	if (!failing &&
8478	    (sm_io_flush(tempqfp, SM_TIME_DEFAULT) != 0 ||
8479	     ((SuperSafe == SAFE_REALLY ||
8480	       SuperSafe == SAFE_REALLY_POSTMILTER ||
8481	       SuperSafe == SAFE_INTERACTIVE) &&
8482	      fsync(sm_io_getinfo(tempqfp, SM_IO_WHAT_FD, NULL)) < 0) ||
8483	     ((errno = sm_io_error(tempqfp)) != 0)))
8484	{
8485		save_errno = errno;
8486		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8487				     "Skipping %s: Error writing %s: %s\n",
8488				     qid_printname(e), tempqf,
8489				     sm_errstring(save_errno));
8490		failing = true;
8491	}
8492
8493
8494	/* Figure out the new filename */
8495	newtype = (reason == NULL ? NORMQF_LETTER : QUARQF_LETTER);
8496	if (oldtype == newtype)
8497	{
8498		/* going to rename tempqf to oldqf */
8499		(void) sm_strlcpy(newqf, oldqf, sizeof newqf);
8500	}
8501	else
8502	{
8503		/* going to rename tempqf to new name based on newtype */
8504		(void) sm_strlcpy(newqf, queuename(e, newtype), sizeof newqf);
8505	}
8506
8507	save_errno = 0;
8508
8509	/* rename tempqf to newqf */
8510	if (!failing &&
8511	    rename(tempqf, newqf) < 0)
8512		save_errno = (errno == 0) ? EINVAL : errno;
8513
8514	/* Check rename() success */
8515	if (!failing && save_errno != 0)
8516	{
8517		sm_syslog(LOG_DEBUG, e->e_id,
8518			  "quarantine_queue_item: rename(%s, %s): %s",
8519			  tempqf, newqf, sm_errstring(save_errno));
8520
8521		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8522				     "Error renaming %s to %s: %s\n",
8523				     tempqf, newqf,
8524				     sm_errstring(save_errno));
8525		if (oldtype == newtype)
8526		{
8527			/*
8528			**  Bail here since we don't know the state of
8529			**  the filesystem and may need to keep tempqf
8530			**  for the user to rescue us.
8531			*/
8532
8533			RELEASE_QUEUE;
8534			errno = save_errno;
8535			syserr("!452 Error renaming control file %s", tempqf);
8536			/* NOTREACHED */
8537		}
8538		else
8539		{
8540			/* remove new file (if rename() half completed) */
8541			if (xunlink(newqf) < 0)
8542			{
8543				save_errno = errno;
8544				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8545						     "Error removing %s: %s\n",
8546						     newqf,
8547						     sm_errstring(save_errno));
8548			}
8549
8550			/* tempqf removed below */
8551			failing = true;
8552		}
8553
8554	}
8555
8556	/* If changing file types, need to remove old type */
8557	if (!failing && oldtype != newtype)
8558	{
8559		if (xunlink(oldqf) < 0)
8560		{
8561			save_errno = errno;
8562			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8563					     "Error removing %s: %s\n",
8564					     oldqf, sm_errstring(save_errno));
8565		}
8566	}
8567
8568	/* see if anything above failed */
8569	if (failing)
8570	{
8571		/* Something failed: remove new file, old file still there */
8572		(void) xunlink(tempqf);
8573	}
8574
8575	/*
8576	**  fsync() after file operations to make sure metadata is
8577	**  written to disk on filesystems in which renames are
8578	**  not guaranteed.  It's ok if they fail, mail won't be lost.
8579	*/
8580
8581	if (SuperSafe != SAFE_NO)
8582	{
8583		/* for soft-updates */
8584		(void) fsync(sm_io_getinfo(tempqfp,
8585					   SM_IO_WHAT_FD, NULL));
8586
8587		if (!failing)
8588		{
8589			/* for soft-updates */
8590			(void) fsync(sm_io_getinfo(oldqfp,
8591						   SM_IO_WHAT_FD, NULL));
8592		}
8593
8594		/* for other odd filesystems */
8595		SYNC_DIR(tempqf, false);
8596	}
8597
8598	/* Close up shop */
8599	RELEASE_QUEUE;
8600	if (tempqfp != NULL)
8601		(void) sm_io_close(tempqfp, SM_TIME_DEFAULT);
8602	if (oldqfp != NULL)
8603		(void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8604
8605	/* All went well */
8606	return !failing;
8607}
8608
8609/*
8610**  QUARANTINE_QUEUE -- {un,}quarantine matching items in the queue
8611**
8612**	Read all matching queue items, add/remove quarantine
8613**	reason, and requeue appropriately.
8614**
8615**	Parameters:
8616**		reason -- quarantine reason, "." means unquarantine.
8617**		qgrplimit -- limit to single queue group unless NOQGRP
8618**
8619**	Results:
8620**		none.
8621**
8622**	Side Effects:
8623**		Lots of changes to the queue.
8624*/
8625
8626void
8627quarantine_queue(reason, qgrplimit)
8628	char *reason;
8629	int qgrplimit;
8630{
8631	int changed = 0;
8632	int qgrp;
8633
8634	/* Convert internal representation of unquarantine */
8635	if (reason != NULL && reason[0] == '.' && reason[1] == '\0')
8636		reason = NULL;
8637
8638	if (reason != NULL)
8639	{
8640		/* clean it */
8641		reason = newstr(denlstring(reason, true, true));
8642	}
8643
8644	for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++)
8645	{
8646		int qdir;
8647
8648		if (qgrplimit != NOQGRP && qgrplimit != qgrp)
8649			continue;
8650
8651		for (qdir = 0; qdir < Queue[qgrp]->qg_numqueues; qdir++)
8652		{
8653			int i;
8654			int nrequests;
8655
8656			if (StopRequest)
8657				stop_sendmail();
8658
8659			nrequests = gatherq(qgrp, qdir, true, NULL, NULL);
8660
8661			/* first see if there is anything */
8662			if (nrequests <= 0)
8663			{
8664				if (Verbose)
8665				{
8666					(void) sm_io_fprintf(smioout,
8667							     SM_TIME_DEFAULT, "%s: no matches\n",
8668							     qid_printqueue(qgrp, qdir));
8669				}
8670				continue;
8671			}
8672
8673			if (Verbose)
8674			{
8675				(void) sm_io_fprintf(smioout,
8676						     SM_TIME_DEFAULT, "Processing %s:\n",
8677						     qid_printqueue(qgrp, qdir));
8678			}
8679
8680			for (i = 0; i < WorkListCount; i++)
8681			{
8682				ENVELOPE e;
8683
8684				if (StopRequest)
8685					stop_sendmail();
8686
8687				/* setup envelope */
8688				clearenvelope(&e, true, sm_rpool_new_x(NULL));
8689				e.e_id = WorkList[i].w_name + 2;
8690				e.e_qgrp = qgrp;
8691				e.e_qdir = qdir;
8692
8693				if (tTd(70, 101))
8694				{
8695					sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8696						      "Would do %s\n", e.e_id);
8697					changed++;
8698				}
8699				else if (quarantine_queue_item(qgrp, qdir,
8700							       &e, reason))
8701					changed++;
8702
8703				/* clean up */
8704				sm_rpool_free(e.e_rpool);
8705				e.e_rpool = NULL;
8706			}
8707			if (WorkList != NULL)
8708				sm_free(WorkList); /* XXX */
8709			WorkList = NULL;
8710			WorkListSize = 0;
8711			WorkListCount = 0;
8712		}
8713	}
8714	if (Verbose)
8715	{
8716		if (changed == 0)
8717			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8718					     "No changes\n");
8719		else
8720			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8721					     "%d change%s\n",
8722					     changed,
8723					     changed == 1 ? "" : "s");
8724	}
8725}
8726