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