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