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