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