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