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