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