queue.c revision 94334
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.857 2002/04/02 16:43:25 ca 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 (obsolete)
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, 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, 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), 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, 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, 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, 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':		/* original 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		}
4395	}
4396
4397	RELEASE_QUEUE;
4398	return true;
4399
4400  fail:
4401	/*
4402	**  There was some error reading the qf file (reason is in err var.)
4403	**  Cleanup:
4404	**	close file; clear e_lockfp since it is the same as qfp,
4405	**	hence it is invalid (as file) after qfp is closed;
4406	**	the qf file is on disk, so set the flag to avoid calling
4407	**	queueup() with bogus data.
4408	*/
4409
4410	if (qfp != NULL)
4411		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
4412	e->e_lockfp = NULL;
4413	e->e_flags |= EF_INQUEUE;
4414	loseqfile(e, err);
4415	RELEASE_QUEUE;
4416	return false;
4417}
4418/*
4419**  PRTSTR -- print a string, "unprintable" characters are shown as \oct
4420**
4421**	Parameters:
4422**		s -- string to print
4423**		ml -- maximum length of output
4424**
4425**	Returns:
4426**		number of entries
4427**
4428**	Side Effects:
4429**		Prints a string on stdout.
4430*/
4431
4432static void
4433prtstr(s, ml)
4434	char *s;
4435	int ml;
4436{
4437	int c;
4438
4439	if (s == NULL)
4440		return;
4441	while (ml-- > 0 && ((c = *s++) != '\0'))
4442	{
4443		if (c == '\\')
4444		{
4445			if (ml-- > 0)
4446			{
4447				(void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
4448				(void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
4449			}
4450		}
4451		else if (isascii(c) && isprint(c))
4452			(void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
4453		else
4454		{
4455			if ((ml -= 3) > 0)
4456				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4457						     "\\%03o", c & 0xFF);
4458		}
4459	}
4460}
4461/*
4462**  PRINTNQE -- print out number of entries in the mail queue
4463**
4464**	Parameters:
4465**		out -- output file pointer.
4466**		prefix -- string to output in front of each line.
4467**
4468**	Returns:
4469**		none.
4470*/
4471
4472void
4473printnqe(out, prefix)
4474	SM_FILE_T *out;
4475	char *prefix;
4476{
4477#if SM_CONF_SHM
4478	int i, k = 0, nrequests = 0;
4479	bool unknown = false;
4480
4481	if (ShmId == SM_SHM_NO_ID)
4482	{
4483		if (prefix == NULL)
4484			(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4485					"Data unavailable: shared memory not updated\n");
4486		else
4487			(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4488					"%sNOTCONFIGURED:-1\r\n", prefix);
4489		return;
4490	}
4491	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
4492	{
4493		int j;
4494
4495		k++;
4496		for (j = 0; j < Queue[i]->qg_numqueues; j++)
4497		{
4498			int n;
4499
4500			if (StopRequest)
4501				stop_sendmail();
4502
4503			n = QSHM_ENTRIES(Queue[i]->qg_qpaths[j].qp_idx);
4504			if (prefix != NULL)
4505				(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4506					"%s%s:%d\r\n",
4507					prefix, qid_printqueue(i, j), n);
4508			else if (n < 0)
4509			{
4510				(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4511					"%s: unknown number of entries\n",
4512					qid_printqueue(i, j));
4513				unknown = true;
4514			}
4515			else if (n == 0)
4516			{
4517				(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4518					"%s is empty\n",
4519					qid_printqueue(i, j));
4520			}
4521			else if (n > 0)
4522			{
4523				(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4524					"%s: entries=%d\n",
4525					qid_printqueue(i, j), n);
4526				nrequests += n;
4527				k++;
4528			}
4529		}
4530	}
4531	if (prefix == NULL && k > 1)
4532		(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4533				     "\t\tTotal requests: %d%s\n",
4534				     nrequests, unknown ? " (about)" : "");
4535#else /* SM_CONF_SHM */
4536	if (prefix == NULL)
4537		(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4538			     "Data unavailable without shared memory support\n");
4539	else
4540		(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
4541			     "%sNOTAVAILABLE:-1\r\n", prefix);
4542#endif /* SM_CONF_SHM */
4543}
4544/*
4545**  PRINTQUEUE -- print out a representation of the mail queue
4546**
4547**	Parameters:
4548**		none.
4549**
4550**	Returns:
4551**		none.
4552**
4553**	Side Effects:
4554**		Prints a listing of the mail queue on the standard output.
4555*/
4556
4557void
4558printqueue()
4559{
4560	int i, k = 0, nrequests = 0;
4561
4562	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
4563	{
4564		int j;
4565
4566		k++;
4567		for (j = 0; j < Queue[i]->qg_numqueues; j++)
4568		{
4569			if (StopRequest)
4570				stop_sendmail();
4571			nrequests += print_single_queue(i, j);
4572			k++;
4573		}
4574	}
4575	if (k > 1)
4576		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4577				     "\t\tTotal requests: %d\n",
4578				     nrequests);
4579}
4580/*
4581**  PRINT_SINGLE_QUEUE -- print out a representation of a single mail queue
4582**
4583**	Parameters:
4584**		qgrp -- the index of the queue group.
4585**		qdir -- the queue directory.
4586**
4587**	Returns:
4588**		number of requests in mail queue.
4589**
4590**	Side Effects:
4591**		Prints a listing of the mail queue on the standard output.
4592*/
4593
4594int
4595print_single_queue(qgrp, qdir)
4596	int qgrp;
4597	int qdir;
4598{
4599	register WORK *w;
4600	SM_FILE_T *f;
4601	int nrequests;
4602	char qd[MAXPATHLEN];
4603	char qddf[MAXPATHLEN];
4604	char buf[MAXLINE];
4605
4606	if (qdir == NOQDIR)
4607	{
4608		(void) sm_strlcpy(qd, ".", sizeof qd);
4609		(void) sm_strlcpy(qddf, ".", sizeof qddf);
4610	}
4611	else
4612	{
4613		(void) sm_strlcpyn(qd, sizeof qd, 2,
4614			Queue[qgrp]->qg_qpaths[qdir].qp_name,
4615			(bitset(QP_SUBQF,
4616				Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
4617					? "/qf" : ""));
4618		(void) sm_strlcpyn(qddf, sizeof qddf, 2,
4619			Queue[qgrp]->qg_qpaths[qdir].qp_name,
4620			(bitset(QP_SUBDF,
4621				Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
4622					? "/df" : ""));
4623	}
4624
4625	/*
4626	**  Check for permission to print the queue
4627	*/
4628
4629	if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
4630	{
4631		struct stat st;
4632#ifdef NGROUPS_MAX
4633		int n;
4634		extern GIDSET_T InitialGidSet[NGROUPS_MAX];
4635#endif /* NGROUPS_MAX */
4636
4637		if (stat(qd, &st) < 0)
4638		{
4639			syserr("Cannot stat %s",
4640				qid_printqueue(qgrp, qdir));
4641			return 0;
4642		}
4643#ifdef NGROUPS_MAX
4644		n = NGROUPS_MAX;
4645		while (--n >= 0)
4646		{
4647			if (InitialGidSet[n] == st.st_gid)
4648				break;
4649		}
4650		if (n < 0 && RealGid != st.st_gid)
4651#else /* NGROUPS_MAX */
4652		if (RealGid != st.st_gid)
4653#endif /* NGROUPS_MAX */
4654		{
4655			usrerr("510 You are not permitted to see the queue");
4656			setstat(EX_NOPERM);
4657			return 0;
4658		}
4659	}
4660
4661	/*
4662	**  Read and order the queue.
4663	*/
4664
4665	nrequests = gatherq(qgrp, qdir, true, NULL, NULL);
4666	(void) sortq(Queue[qgrp]->qg_maxlist);
4667
4668	/*
4669	**  Print the work list that we have read.
4670	*/
4671
4672	/* first see if there is anything */
4673	if (nrequests <= 0)
4674	{
4675		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s is empty\n",
4676				     qid_printqueue(qgrp, qdir));
4677		return 0;
4678	}
4679
4680	sm_getla();	/* get load average */
4681
4682	(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\t\t%s (%d request%s",
4683			     qid_printqueue(qgrp, qdir),
4684			     nrequests, nrequests == 1 ? "" : "s");
4685	if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
4686		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4687				     ", only %d printed", MaxQueueRun);
4688	if (Verbose)
4689		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4690			")\n-----Q-ID----- --Size-- -Priority- ---Q-Time--- --------Sender/Recipient--------\n");
4691	else
4692		(void) sm_io_fprintf(smioout,  SM_TIME_DEFAULT,
4693			")\n-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------\n");
4694	for (w = WorkQ; w != NULL; w = w->w_next)
4695	{
4696		struct stat st;
4697		auto time_t submittime = 0;
4698		long dfsize;
4699		int flags = 0;
4700		int qfver;
4701#if _FFR_QUARANTINE
4702		char quarmsg[MAXLINE];
4703#endif /* _FFR_QUARANTINE */
4704		char statmsg[MAXLINE];
4705		char bodytype[MAXNAME + 1];
4706		char qf[MAXPATHLEN];
4707
4708		if (StopRequest)
4709			stop_sendmail();
4710
4711		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%13s",
4712				     w->w_name + 2);
4713		(void) sm_strlcpyn(qf, sizeof qf, 3, qd, "/", w->w_name);
4714		f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY,
4715			       NULL);
4716		if (f == NULL)
4717		{
4718			if (errno == EPERM)
4719				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4720						     " (permission denied)\n");
4721			else if (errno == ENOENT)
4722				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4723						     " (job completed)\n");
4724			else
4725				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4726						     " (%s)\n",
4727						     sm_errstring(errno));
4728			errno = 0;
4729			continue;
4730		}
4731		w->w_name[0] = DATAFL_LETTER;
4732		(void) sm_strlcpyn(qf, sizeof qf, 3, qddf, "/", w->w_name);
4733		if (stat(qf, &st) >= 0)
4734			dfsize = st.st_size;
4735		else
4736		{
4737			ENVELOPE e;
4738
4739			/*
4740			**  Maybe the df file can't be statted because
4741			**  it is in a different directory than the qf file.
4742			**  In order to find out, we must read the qf file.
4743			*/
4744
4745			newenvelope(&e, &BlankEnvelope, sm_rpool_new_x(NULL));
4746			e.e_id = w->w_name + 2;
4747			e.e_qgrp = qgrp;
4748			e.e_qdir = qdir;
4749			dfsize = -1;
4750			if (readqf(&e, false))
4751			{
4752				char *df = queuename(&e, DATAFL_LETTER);
4753				if (stat(df, &st) >= 0)
4754					dfsize = st.st_size;
4755			}
4756			if (e.e_lockfp != NULL)
4757			{
4758				(void) sm_io_close(e.e_lockfp, SM_TIME_DEFAULT);
4759				e.e_lockfp = NULL;
4760			}
4761			clearenvelope(&e, false, e.e_rpool);
4762			sm_rpool_free(e.e_rpool);
4763		}
4764		if (w->w_lock)
4765			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "*");
4766#if _FFR_QUARANTINE
4767		else if (QueueMode == QM_LOST)
4768			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "?");
4769#endif /* _FFR_QUARANTINE */
4770		else if (w->w_tooyoung)
4771			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "-");
4772		else if (shouldqueue(w->w_pri, w->w_ctime))
4773			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "X");
4774		else
4775			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " ");
4776
4777		errno = 0;
4778
4779#if _FFR_QUARANTINE
4780		quarmsg[0] = '\0';
4781#endif /* _FFR_QUARANTINE */
4782		statmsg[0] = bodytype[0] = '\0';
4783		qfver = 0;
4784		while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
4785		{
4786			register int i;
4787			register char *p;
4788
4789			if (StopRequest)
4790				stop_sendmail();
4791
4792			fixcrlf(buf, true);
4793			switch (buf[0])
4794			{
4795			  case 'V':	/* queue file version */
4796				qfver = atoi(&buf[1]);
4797				break;
4798
4799			  case 'M':	/* error message */
4800				if ((i = strlen(&buf[1])) >= sizeof statmsg)
4801					i = sizeof statmsg - 1;
4802				memmove(statmsg, &buf[1], i);
4803				statmsg[i] = '\0';
4804				break;
4805
4806#if _FFR_QUARANTINE
4807			  case 'q':	/* quarantine reason */
4808				if ((i = strlen(&buf[1])) >= sizeof quarmsg)
4809					i = sizeof quarmsg - 1;
4810				memmove(quarmsg, &buf[1], i);
4811				quarmsg[i] = '\0';
4812				break;
4813#endif /* _FFR_QUARANTINE */
4814
4815			  case 'B':	/* body type */
4816				if ((i = strlen(&buf[1])) >= sizeof bodytype)
4817					i = sizeof bodytype - 1;
4818				memmove(bodytype, &buf[1], i);
4819				bodytype[i] = '\0';
4820				break;
4821
4822			  case 'S':	/* sender name */
4823				if (Verbose)
4824				{
4825					(void) sm_io_fprintf(smioout,
4826						SM_TIME_DEFAULT,
4827						"%8ld %10ld%c%.12s ",
4828						dfsize,
4829						w->w_pri,
4830						bitset(EF_WARNING, flags)
4831							? '+' : ' ',
4832						ctime(&submittime) + 4);
4833					prtstr(&buf[1], 78);
4834				}
4835				else
4836				{
4837					(void) sm_io_fprintf(smioout,
4838						SM_TIME_DEFAULT,
4839						"%8ld %.16s ",
4840						dfsize,
4841						ctime(&submittime));
4842					prtstr(&buf[1], 39);
4843				}
4844#if _FFR_QUARANTINE
4845				if (quarmsg[0] != '\0')
4846				{
4847					(void) sm_io_fprintf(smioout,
4848							     SM_TIME_DEFAULT,
4849							     "\n     QUARANTINE: %.*s",
4850							     Verbose ? 100 : 60,
4851							     quarmsg);
4852					quarmsg[0] = '\0';
4853				}
4854#endif /* _FFR_QUARANTINE */
4855				if (statmsg[0] != '\0' || bodytype[0] != '\0')
4856				{
4857					(void) sm_io_fprintf(smioout,
4858						SM_TIME_DEFAULT,
4859						"\n    %10.10s",
4860						bodytype);
4861					if (statmsg[0] != '\0')
4862						(void) sm_io_fprintf(smioout,
4863							SM_TIME_DEFAULT,
4864							"   (%.*s)",
4865							Verbose ? 100 : 60,
4866							statmsg);
4867					statmsg[0] = '\0';
4868				}
4869				break;
4870
4871			  case 'C':	/* controlling user */
4872				if (Verbose)
4873					(void) sm_io_fprintf(smioout,
4874						SM_TIME_DEFAULT,
4875						"\n\t\t\t\t\t\t(---%.64s---)",
4876						&buf[1]);
4877				break;
4878
4879			  case 'R':	/* recipient name */
4880				p = &buf[1];
4881				if (qfver >= 1)
4882				{
4883					p = strchr(p, ':');
4884					if (p == NULL)
4885						break;
4886					p++;
4887				}
4888				if (Verbose)
4889				{
4890					(void) sm_io_fprintf(smioout,
4891							SM_TIME_DEFAULT,
4892							"\n\t\t\t\t\t\t");
4893					prtstr(p, 71);
4894				}
4895				else
4896				{
4897					(void) sm_io_fprintf(smioout,
4898							SM_TIME_DEFAULT,
4899							"\n\t\t\t\t\t ");
4900					prtstr(p, 38);
4901				}
4902				if (Verbose && statmsg[0] != '\0')
4903				{
4904					(void) sm_io_fprintf(smioout,
4905							SM_TIME_DEFAULT,
4906							"\n\t\t (%.100s)",
4907							statmsg);
4908					statmsg[0] = '\0';
4909				}
4910				break;
4911
4912			  case 'T':	/* creation time */
4913				submittime = atol(&buf[1]);
4914				break;
4915
4916			  case 'F':	/* flag bits */
4917				for (p = &buf[1]; *p != '\0'; p++)
4918				{
4919					switch (*p)
4920					{
4921					  case 'w':
4922						flags |= EF_WARNING;
4923						break;
4924					}
4925				}
4926			}
4927		}
4928		if (submittime == (time_t) 0)
4929			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4930					     " (no control file)");
4931		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n");
4932		(void) sm_io_close(f, SM_TIME_DEFAULT);
4933	}
4934	return nrequests;
4935}
4936
4937#if _FFR_QUARANTINE
4938/*
4939**  QUEUE_LETTER -- get the proper queue letter for the current QueueMode.
4940**
4941**	Parameters:
4942**		e -- envelope to build it in/from.
4943**		type -- the file type, used as the first character
4944**			of the file name.
4945**
4946**	Returns:
4947**		the letter to use
4948*/
4949
4950static char
4951queue_letter(e, type)
4952	ENVELOPE *e;
4953	int type;
4954{
4955	/* Change type according to QueueMode */
4956	if (type == ANYQFL_LETTER)
4957	{
4958		if (e->e_quarmsg != NULL)
4959			type = QUARQF_LETTER;
4960		else
4961		{
4962			switch (QueueMode)
4963			{
4964			  case QM_NORMAL:
4965				type = NORMQF_LETTER;
4966				break;
4967
4968			  case QM_QUARANTINE:
4969				type = QUARQF_LETTER;
4970				break;
4971
4972			  case QM_LOST:
4973				type = LOSEQF_LETTER;
4974				break;
4975
4976			  default:
4977				/* should never happen */
4978				abort();
4979				/* NOTREACHED */
4980			}
4981		}
4982	}
4983	return type;
4984}
4985#endif /* _FFR_QUARANTINE */
4986
4987/*
4988**  QUEUENAME -- build a file name in the queue directory for this envelope.
4989**
4990**	Parameters:
4991**		e -- envelope to build it in/from.
4992**		type -- the file type, used as the first character
4993**			of the file name.
4994**
4995**	Returns:
4996**		a pointer to the queue name (in a static buffer).
4997**
4998**	Side Effects:
4999**		If no id code is already assigned, queuename() will
5000**		assign an id code with assign_queueid().  If no queue
5001**		directory is assigned, one will be set with setnewqueue().
5002*/
5003
5004char *
5005queuename(e, type)
5006	register ENVELOPE *e;
5007	int type;
5008{
5009	int qd, qg;
5010	char *sub = "/";
5011	char pref[3];
5012	static char buf[MAXPATHLEN];
5013
5014	/* Assign an ID if needed */
5015	if (e->e_id == NULL)
5016		assign_queueid(e);
5017
5018#if _FFR_QUARANTINE
5019	type = queue_letter(e, type);
5020#endif /* _FFR_QUARANTINE */
5021
5022	/* begin of filename */
5023	pref[0] = (char) type;
5024	pref[1] = 'f';
5025	pref[2] = '\0';
5026
5027	/* Assign a queue group/directory if needed */
5028	if (type == XSCRPT_LETTER)
5029	{
5030		/*
5031		**  We don't want to call setnewqueue() if we are fetching
5032		**  the pathname of the transcript file, because setnewqueue
5033		**  chooses a queue, and sometimes we need to write to the
5034		**  transcript file before we have gathered enough information
5035		**  to choose a queue.
5036		*/
5037
5038		if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR)
5039		{
5040			if (e->e_qgrp != NOQGRP && e->e_qdir != NOQDIR)
5041			{
5042				e->e_xfqgrp = e->e_qgrp;
5043				e->e_xfqdir = e->e_qdir;
5044			}
5045			else
5046			{
5047				e->e_xfqgrp = 0;
5048				if (Queue[e->e_xfqgrp]->qg_numqueues <= 1)
5049					e->e_xfqdir = 0;
5050				else
5051				{
5052					e->e_xfqdir = get_rand_mod(
5053					      Queue[e->e_xfqgrp]->qg_numqueues);
5054				}
5055			}
5056		}
5057		qd = e->e_xfqdir;
5058		qg = e->e_xfqgrp;
5059	}
5060	else
5061	{
5062		if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR)
5063			setnewqueue(e);
5064		if (type ==  DATAFL_LETTER)
5065		{
5066			qd = e->e_dfqdir;
5067			qg = e->e_dfqgrp;
5068		}
5069		else
5070		{
5071			qd = e->e_qdir;
5072			qg = e->e_qgrp;
5073		}
5074	}
5075
5076	/* xf files always have a valid qd and qg picked above */
5077	if (e->e_qdir == NOQDIR && type != XSCRPT_LETTER)
5078		(void) sm_strlcpyn(buf, sizeof buf, 2, pref, e->e_id);
5079	else
5080	{
5081		switch (type)
5082		{
5083		  case DATAFL_LETTER:
5084			if (bitset(QP_SUBDF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
5085				sub = "/df/";
5086			break;
5087
5088#if _FFR_QUARANTINE
5089		  case QUARQF_LETTER:
5090#endif /* _FFR_QUARANTINE */
5091		  case TEMPQF_LETTER:
5092		  case NEWQFL_LETTER:
5093		  case LOSEQF_LETTER:
5094		  case NORMQF_LETTER:
5095			if (bitset(QP_SUBQF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
5096				sub = "/qf/";
5097			break;
5098
5099		  case XSCRPT_LETTER:
5100			if (bitset(QP_SUBXF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
5101				sub = "/xf/";
5102			break;
5103
5104		  default:
5105			sm_abort("queuename: bad queue file type %d", type);
5106		}
5107
5108		(void) sm_strlcpyn(buf, sizeof buf, 4,
5109				Queue[qg]->qg_qpaths[qd].qp_name,
5110				sub, pref, e->e_id);
5111	}
5112
5113	if (tTd(7, 2))
5114		sm_dprintf("queuename: %s\n", buf);
5115	return buf;
5116}
5117/*
5118**  ASSIGN_QUEUEID -- assign a queue ID for this envelope.
5119**
5120**	Assigns an id code if one does not already exist.
5121**	This code assumes that nothing will remain in the queue for
5122**	longer than 60 years.  It is critical that files with the given
5123**	name do not already exist in the queue.
5124**	[No longer initializes e_qdir to NOQDIR.]
5125**
5126**	Parameters:
5127**		e -- envelope to set it in.
5128**
5129**	Returns:
5130**		none.
5131*/
5132
5133static const char QueueIdChars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx";
5134# define QIC_LEN	60
5135# define queuenextid() CurrentPid
5136
5137
5138void
5139assign_queueid(e)
5140	register ENVELOPE *e;
5141{
5142	pid_t pid = queuenextid();
5143	static int cX = 0;
5144	static long random_offset;
5145	struct tm *tm;
5146	char idbuf[MAXQFNAME - 2];
5147	int seq;
5148
5149	if (e->e_id != NULL)
5150		return;
5151
5152	/* see if we need to get a new base time/pid */
5153	if (cX >= QIC_LEN * QIC_LEN || LastQueueTime == 0 ||
5154	    LastQueuePid != pid)
5155	{
5156		time_t then = LastQueueTime;
5157
5158		/* if the first time through, pick a random offset */
5159		if (LastQueueTime == 0)
5160			random_offset = get_random();
5161
5162		while ((LastQueueTime = curtime()) == then &&
5163		       LastQueuePid == pid)
5164		{
5165			(void) sleep(1);
5166		}
5167		LastQueuePid = queuenextid();
5168		cX = 0;
5169	}
5170
5171	/*
5172	**  Generate a new sequence number between 0 and QIC_LEN*QIC_LEN-1.
5173	**  This lets us generate up to QIC_LEN*QIC_LEN unique queue ids
5174	**  per second, per process.  With envelope splitting,
5175	**  a single message can consume many queue ids.
5176	*/
5177
5178	seq = (int)((cX + random_offset) % (QIC_LEN * QIC_LEN));
5179	++cX;
5180	if (tTd(7, 50))
5181		sm_dprintf("assign_queueid: random_offset = %ld (%d)\n",
5182			random_offset, seq);
5183
5184	tm = gmtime(&LastQueueTime);
5185	idbuf[0] = QueueIdChars[tm->tm_year % QIC_LEN];
5186	idbuf[1] = QueueIdChars[tm->tm_mon];
5187	idbuf[2] = QueueIdChars[tm->tm_mday];
5188	idbuf[3] = QueueIdChars[tm->tm_hour];
5189	idbuf[4] = QueueIdChars[tm->tm_min];
5190	idbuf[5] = QueueIdChars[tm->tm_sec];
5191	idbuf[6] = QueueIdChars[seq / QIC_LEN];
5192	idbuf[7] = QueueIdChars[seq % QIC_LEN];
5193	(void) sm_snprintf(&idbuf[8], sizeof idbuf - 8, "%06d",
5194			   (int) LastQueuePid);
5195	e->e_id = sm_rpool_strdup_x(e->e_rpool, idbuf);
5196	macdefine(&e->e_macro, A_PERM, 'i', e->e_id);
5197#if 0
5198	/* XXX: inherited from MainEnvelope */
5199	e->e_qgrp = NOQGRP;  /* too early to do anything else */
5200	e->e_qdir = NOQDIR;
5201	e->e_xfqgrp = NOQGRP;
5202#endif /* 0 */
5203#if _FFR_QUARANTINE
5204	/* New ID means it's not on disk yet */
5205	e->e_qfletter = '\0';
5206#endif /* _FFR_QUARANTINE */
5207	if (tTd(7, 1))
5208		sm_dprintf("assign_queueid: assigned id %s, e=%p\n",
5209			e->e_id, e);
5210	if (LogLevel > 93)
5211		sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
5212}
5213/*
5214**  SYNC_QUEUE_TIME -- Assure exclusive PID in any given second
5215**
5216**	Make sure one PID can't be used by two processes in any one second.
5217**
5218**		If the system rotates PIDs fast enough, may get the
5219**		same pid in the same second for two distinct processes.
5220**		This will interfere with the queue file naming system.
5221**
5222**	Parameters:
5223**		none
5224**
5225**	Returns:
5226**		none
5227*/
5228
5229void
5230sync_queue_time()
5231{
5232#if FAST_PID_RECYCLE
5233	if (OpMode != MD_TEST &&
5234	    OpMode != MD_VERIFY &&
5235	    LastQueueTime > 0 &&
5236	    LastQueuePid == CurrentPid &&
5237	    curtime() == LastQueueTime)
5238		(void) sleep(1);
5239#endif /* FAST_PID_RECYCLE */
5240}
5241/*
5242**  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
5243**
5244**	Parameters:
5245**		e -- the envelope to unlock.
5246**
5247**	Returns:
5248**		none
5249**
5250**	Side Effects:
5251**		unlocks the queue for `e'.
5252*/
5253
5254void
5255unlockqueue(e)
5256	ENVELOPE *e;
5257{
5258	if (tTd(51, 4))
5259		sm_dprintf("unlockqueue(%s)\n",
5260			e->e_id == NULL ? "NOQUEUE" : e->e_id);
5261
5262
5263	/* if there is a lock file in the envelope, close it */
5264	if (e->e_lockfp != NULL)
5265		(void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT);
5266	e->e_lockfp = NULL;
5267
5268	/* don't create a queue id if we don't already have one */
5269	if (e->e_id == NULL)
5270		return;
5271
5272	/* remove the transcript */
5273	if (LogLevel > 87)
5274		sm_syslog(LOG_DEBUG, e->e_id, "unlock");
5275	if (!tTd(51, 104))
5276		(void) xunlink(queuename(e, XSCRPT_LETTER));
5277}
5278/*
5279**  SETCTLUSER -- create a controlling address
5280**
5281**	Create a fake "address" given only a local login name; this is
5282**	used as a "controlling user" for future recipient addresses.
5283**
5284**	Parameters:
5285**		user -- the user name of the controlling user.
5286**		qfver -- the version stamp of this queue file.
5287**		e -- envelope
5288**
5289**	Returns:
5290**		An address descriptor for the controlling user,
5291**		using storage allocated from e->e_rpool.
5292**
5293*/
5294
5295static ADDRESS *
5296setctluser(user, qfver, e)
5297	char *user;
5298	int qfver;
5299	ENVELOPE *e;
5300{
5301	register ADDRESS *a;
5302	struct passwd *pw;
5303	char *p;
5304
5305	/*
5306	**  See if this clears our concept of controlling user.
5307	*/
5308
5309	if (user == NULL || *user == '\0')
5310		return NULL;
5311
5312	/*
5313	**  Set up addr fields for controlling user.
5314	*/
5315
5316	a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof *a);
5317	memset((char *) a, '\0', sizeof *a);
5318
5319	if (*user == ':')
5320	{
5321		p = &user[1];
5322		a->q_user = sm_rpool_strdup_x(e->e_rpool, p);
5323	}
5324	else
5325	{
5326		p = strtok(user, ":");
5327		a->q_user = sm_rpool_strdup_x(e->e_rpool, user);
5328		if (qfver >= 2)
5329		{
5330			if ((p = strtok(NULL, ":")) != NULL)
5331				a->q_uid = atoi(p);
5332			if ((p = strtok(NULL, ":")) != NULL)
5333				a->q_gid = atoi(p);
5334			if ((p = strtok(NULL, ":")) != NULL)
5335			{
5336				char *o;
5337
5338				a->q_flags |= QGOODUID;
5339
5340				/* if there is another ':': restore it */
5341				if ((o = strtok(NULL, ":")) != NULL && o > p)
5342					o[-1] = ':';
5343			}
5344		}
5345		else if ((pw = sm_getpwnam(user)) != NULL)
5346		{
5347			if (*pw->pw_dir == '\0')
5348				a->q_home = NULL;
5349			else if (strcmp(pw->pw_dir, "/") == 0)
5350				a->q_home = "";
5351			else
5352				a->q_home = sm_rpool_strdup_x(e->e_rpool, pw->pw_dir);
5353			a->q_uid = pw->pw_uid;
5354			a->q_gid = pw->pw_gid;
5355			a->q_flags |= QGOODUID;
5356		}
5357	}
5358
5359	a->q_flags |= QPRIMARY;		/* flag as a "ctladdr" */
5360	a->q_mailer = LocalMailer;
5361	if (p == NULL)
5362		a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user);
5363	else
5364		a->q_paddr = sm_rpool_strdup_x(e->e_rpool, p);
5365	return a;
5366}
5367/*
5368**  LOSEQFILE -- rename queue file with LOSEQF_LETTER & try to let someone know
5369**
5370**	Parameters:
5371**		e -- the envelope (e->e_id will be used).
5372**		why -- reported to whomever can hear.
5373**
5374**	Returns:
5375**		none.
5376*/
5377
5378void
5379loseqfile(e, why)
5380	register ENVELOPE *e;
5381	char *why;
5382{
5383	bool loseit = true;
5384	char *p;
5385	char buf[MAXPATHLEN];
5386
5387	if (e == NULL || e->e_id == NULL)
5388		return;
5389	p = queuename(e, ANYQFL_LETTER);
5390	if (sm_strlcpy(buf, p, sizeof buf) >= sizeof buf)
5391		return;
5392	if (!bitset(EF_INQUEUE, e->e_flags))
5393		queueup(e, false, true);
5394#if _FFR_QUARANTINE
5395	else if (QueueMode == QM_LOST)
5396		loseit = false;
5397#endif /* _FFR_QUARANTINE */
5398
5399	/* if already lost, no need to re-lose */
5400	if (loseit)
5401	{
5402		p = queuename(e, LOSEQF_LETTER);
5403		if (rename(buf, p) < 0)
5404			syserr("cannot rename(%s, %s), uid=%d",
5405			       buf, p, geteuid());
5406		else if (LogLevel > 0)
5407			sm_syslog(LOG_ALERT, e->e_id,
5408				  "Losing %s: %s", buf, why);
5409	}
5410	if (e->e_dfp != NULL)
5411	{
5412		(void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
5413		e->e_dfp = NULL;
5414	}
5415	e->e_flags &= ~EF_HAS_DF;
5416}
5417/*
5418**  NAME2QID -- translate a queue group name to a queue group id
5419**
5420**	Parameters:
5421**		queuename -- name of queue group.
5422**
5423**	Returns:
5424**		queue group id if found.
5425**		NOQGRP otherwise.
5426*/
5427
5428int
5429name2qid(queuename)
5430	char *queuename;
5431{
5432	register STAB *s;
5433
5434	s = stab(queuename, ST_QUEUE, ST_FIND);
5435	if (s == NULL)
5436		return NOQGRP;
5437	return s->s_quegrp->qg_index;
5438}
5439/*
5440**  QID_PRINTNAME -- create externally printable version of queue id
5441**
5442**	Parameters:
5443**		e -- the envelope.
5444**
5445**	Returns:
5446**		a printable version
5447*/
5448
5449char *
5450qid_printname(e)
5451	ENVELOPE *e;
5452{
5453	char *id;
5454	static char idbuf[MAXQFNAME + 34];
5455
5456	if (e == NULL)
5457		return "";
5458
5459	if (e->e_id == NULL)
5460		id = "";
5461	else
5462		id = e->e_id;
5463
5464	if (e->e_qdir == NOQDIR)
5465		return id;
5466
5467	(void) sm_snprintf(idbuf, sizeof idbuf, "%.32s/%s",
5468			   Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_name,
5469			   id);
5470	return idbuf;
5471}
5472/*
5473**  QID_PRINTQUEUE -- create full version of queue directory for data files
5474**
5475**	Parameters:
5476**		qgrp -- index in queue group.
5477**		qdir -- the short version of the queue directory
5478**
5479**	Returns:
5480**		the full pathname to the queue (might point to a static var)
5481*/
5482
5483char *
5484qid_printqueue(qgrp, qdir)
5485	int qgrp;
5486	int qdir;
5487{
5488	char *subdir;
5489	static char dir[MAXPATHLEN];
5490
5491	if (qdir == NOQDIR)
5492		return Queue[qgrp]->qg_qdir;
5493
5494	if (strcmp(Queue[qgrp]->qg_qpaths[qdir].qp_name, ".") == 0)
5495		subdir = NULL;
5496	else
5497		subdir = Queue[qgrp]->qg_qpaths[qdir].qp_name;
5498
5499	(void) sm_strlcpyn(dir, sizeof dir, 4,
5500			Queue[qgrp]->qg_qdir,
5501			subdir == NULL ? "" : "/",
5502			subdir == NULL ? "" : subdir,
5503			(bitset(QP_SUBDF,
5504				Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
5505					? "/df" : ""));
5506	return dir;
5507}
5508
5509/*
5510**  PICKQDIR -- Pick a queue directory from a queue group
5511**
5512**	Parameters:
5513**		qg -- queue group
5514**		fsize -- file size in bytes
5515**		e -- envelope, or NULL
5516**
5517**	Result:
5518**		NOQDIR if no queue directory in qg has enough free space to
5519**		hold a file of size 'fsize', otherwise the index of
5520**		a randomly selected queue directory which resides on a
5521**		file system with enough disk space.
5522**		XXX This could be extended to select a queuedir with
5523**			a few (the fewest?) number of entries. That data
5524**			is available if shared memory is used.
5525**
5526**	Side Effects:
5527**		If the request fails and e != NULL then sm_syslog is called.
5528*/
5529
5530int
5531pickqdir(qg, fsize, e)
5532	QUEUEGRP *qg;
5533	long fsize;
5534	ENVELOPE *e;
5535{
5536	int qdir;
5537	int i;
5538	long avail = 0;
5539
5540	/* Pick a random directory, as a starting point. */
5541	if (qg->qg_numqueues <= 1)
5542		qdir = 0;
5543	else
5544		qdir = get_rand_mod(qg->qg_numqueues);
5545
5546	if (MinBlocksFree <= 0 && fsize <= 0)
5547		return qdir;
5548
5549	/*
5550	**  Now iterate over the queue directories,
5551	**  looking for a directory with enough space for this message.
5552	*/
5553
5554	i = qdir;
5555	do
5556	{
5557		QPATHS *qp = &qg->qg_qpaths[i];
5558		long needed = 0;
5559		long fsavail = 0;
5560
5561		if (fsize > 0)
5562			needed += fsize / FILE_SYS_BLKSIZE(qp->qp_fsysidx)
5563				  + ((fsize % FILE_SYS_BLKSIZE(qp->qp_fsysidx)
5564				      > 0) ? 1 : 0);
5565		if (MinBlocksFree > 0)
5566			needed += MinBlocksFree;
5567		fsavail = FILE_SYS_AVAIL(qp->qp_fsysidx);
5568#if SM_CONF_SHM
5569		if (fsavail <= 0)
5570		{
5571			long blksize;
5572
5573			/*
5574			**  might be not correctly updated,
5575			**  let's try to get the info directly.
5576			*/
5577
5578			fsavail = freediskspace(FILE_SYS_NAME(qp->qp_fsysidx),
5579						&blksize);
5580			if (fsavail < 0)
5581				fsavail = 0;
5582		}
5583#endif /* SM_CONF_SHM */
5584		if (needed <= fsavail)
5585			return i;
5586		if (avail < fsavail)
5587			avail = fsavail;
5588
5589		if (qg->qg_numqueues > 0)
5590			i = (i + 1) % qg->qg_numqueues;
5591	} while (i != qdir);
5592
5593	if (e != NULL && LogLevel > 0)
5594		sm_syslog(LOG_ALERT, e->e_id,
5595			"low on space (%s needs %ld bytes + %ld blocks in %s), max avail: %ld",
5596			CurHostName == NULL ? "SMTP-DAEMON" : CurHostName,
5597			fsize, MinBlocksFree,
5598			qg->qg_qdir, avail);
5599	return NOQDIR;
5600}
5601/*
5602**  SETNEWQUEUE -- Sets a new queue group and directory
5603**
5604**	Assign a queue group and directory to an envelope and store the
5605**	directory in e->e_qdir.
5606**
5607**	Parameters:
5608**		e -- envelope to assign a queue for.
5609**
5610**	Returns:
5611**		true if successful
5612**		false otherwise
5613**
5614**	Side Effects:
5615**		On success, e->e_qgrp and e->e_qdir are non-negative.
5616**		On failure (not enough disk space),
5617**		e->qgrp = NOQGRP, e->e_qdir = NOQDIR
5618**		and usrerr() is invoked (which could raise an exception).
5619*/
5620
5621bool
5622setnewqueue(e)
5623	ENVELOPE *e;
5624{
5625	if (tTd(41, 20))
5626		sm_dprintf("setnewqueue: called\n");
5627
5628	/* not set somewhere else */
5629	if (e->e_qgrp == NOQGRP)
5630	{
5631		/*
5632		**  Use the queue group of the first recipient, as set by
5633		**  the "queuegroup" rule set.  If that is not defined, then
5634		**  use the queue group of the mailer of the first recipient.
5635		**  If that is not defined either, then use the default
5636		**  queue group.
5637		*/
5638
5639		if (e->e_sendqueue == NULL)
5640			e->e_qgrp = 0;
5641		else if (e->e_sendqueue->q_qgrp >= 0)
5642			e->e_qgrp = e->e_sendqueue->q_qgrp;
5643		else if (e->e_sendqueue->q_mailer != NULL &&
5644			 ISVALIDQGRP(e->e_sendqueue->q_mailer->m_qgrp))
5645			e->e_qgrp = e->e_sendqueue->q_mailer->m_qgrp;
5646		else
5647			e->e_qgrp = 0;
5648		e->e_dfqgrp = e->e_qgrp;
5649	}
5650
5651	if (ISVALIDQDIR(e->e_qdir) && ISVALIDQDIR(e->e_dfqdir))
5652	{
5653		if (tTd(41, 20))
5654			sm_dprintf("setnewqueue: e_qdir already assigned (%s)\n",
5655				qid_printqueue(e->e_qgrp, e->e_qdir));
5656		return true;
5657	}
5658
5659	filesys_update();
5660	e->e_qdir = pickqdir(Queue[e->e_qgrp], e->e_msgsize, e);
5661	if (e->e_qdir == NOQDIR)
5662	{
5663		e->e_qgrp = NOQGRP;
5664		if (!bitset(EF_FATALERRS, e->e_flags))
5665			usrerr("452 4.4.5 Insufficient disk space; try again later");
5666		e->e_flags |= EF_FATALERRS;
5667		return false;
5668	}
5669
5670	if (tTd(41, 3))
5671		sm_dprintf("setnewqueue: Assigned queue directory %s\n",
5672			qid_printqueue(e->e_qgrp, e->e_qdir));
5673
5674	if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR)
5675	{
5676		e->e_xfqgrp = e->e_qgrp;
5677		e->e_xfqdir = e->e_qdir;
5678	}
5679	e->e_dfqdir = e->e_qdir;
5680	return true;
5681}
5682/*
5683**  CHKQDIR -- check a queue directory
5684**
5685**	Parameters:
5686**		name -- name of queue directory
5687**		sff -- flags for safefile()
5688**
5689**	Returns:
5690**		is it a queue directory?
5691*/
5692
5693static bool
5694chkqdir(name, sff)
5695	char *name;
5696	long sff;
5697{
5698	struct stat statb;
5699	int i;
5700
5701	/* skip over . and .. directories */
5702	if (name[0] == '.' &&
5703	    (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
5704		return false;
5705#if HASLSTAT
5706	if (lstat(name, &statb) < 0)
5707#else /* HASLSTAT */
5708	if (stat(name, &statb) < 0)
5709#endif /* HASLSTAT */
5710	{
5711		if (tTd(41, 2))
5712			sm_dprintf("chkqdir: stat(\"%s\"): %s\n",
5713				   name, sm_errstring(errno));
5714		return false;
5715	}
5716#if HASLSTAT
5717	if (S_ISLNK(statb.st_mode))
5718	{
5719		/*
5720		**  For a symlink we need to make sure the
5721		**  target is a directory
5722		*/
5723
5724		if (stat(name, &statb) < 0)
5725		{
5726			if (tTd(41, 2))
5727				sm_dprintf("chkqdir: stat(\"%s\"): %s\n",
5728					   name, sm_errstring(errno));
5729			return false;
5730		}
5731	}
5732#endif /* HASLSTAT */
5733
5734	if (!S_ISDIR(statb.st_mode))
5735	{
5736		if (tTd(41, 2))
5737			sm_dprintf("chkqdir: \"%s\": Not a directory\n",
5738				name);
5739		return false;
5740	}
5741
5742	/* Print a warning if unsafe (but still use it) */
5743	/* XXX do this only if we want the warning? */
5744	i = safedirpath(name, RunAsUid, RunAsGid, NULL, sff, 0, 0);
5745	if (i != 0 && tTd(41, 2))
5746		sm_dprintf("chkqdir: \"%s\": Not safe: %s\n",
5747			   name, sm_errstring(i));
5748	return true;
5749}
5750/*
5751**  MULTIQUEUE_CACHE -- cache a list of paths to queues.
5752**
5753**	Each potential queue is checked as the cache is built.
5754**	Thereafter, each is blindly trusted.
5755**	Note that we can be called again after a timeout to rebuild
5756**	(although code for that is not ready yet).
5757**
5758**	Parameters:
5759**		basedir -- base of all queue directories.
5760**		blen -- strlen(basedir).
5761**		qg -- queue group.
5762**		qn -- number of queue directories already cached.
5763**		phash -- pointer to hash value over queue dirs.
5764#if SM_CONF_SHM
5765**			only used if shared memory is active.
5766#endif * SM_CONF_SHM *
5767**
5768**	Returns:
5769**		new number of queue directories.
5770*/
5771
5772#define INITIAL_SLOTS	20
5773#define ADD_SLOTS	10
5774
5775static int
5776multiqueue_cache(basedir, blen, qg, qn, phash)
5777	char *basedir;
5778	int blen;
5779	QUEUEGRP *qg;
5780	int qn;
5781	unsigned int *phash;
5782{
5783	char *cp;
5784	int i, len;
5785	int slotsleft = 0;
5786	long sff = SFF_ANYFILE;
5787	char qpath[MAXPATHLEN];
5788	char subdir[MAXPATHLEN];
5789	char prefix[MAXPATHLEN];	/* dir relative to basedir */
5790
5791	if (tTd(41, 20))
5792		sm_dprintf("multiqueue_cache: called\n");
5793
5794	/* Initialize to current directory */
5795	prefix[0] = '.';
5796	prefix[1] = '\0';
5797	if (qg->qg_numqueues != 0 && qg->qg_qpaths != NULL)
5798	{
5799		for (i = 0; i < qg->qg_numqueues; i++)
5800		{
5801			if (qg->qg_qpaths[i].qp_name != NULL)
5802				(void) sm_free(qg->qg_qpaths[i].qp_name); /* XXX */
5803		}
5804		(void) sm_free((char *) qg->qg_qpaths); /* XXX */
5805		qg->qg_qpaths = NULL;
5806		qg->qg_numqueues = 0;
5807	}
5808
5809	/* If running as root, allow safedirpath() checks to use privs */
5810	if (RunAsUid == 0)
5811		sff |= SFF_ROOTOK;
5812
5813	if (!SM_IS_DIR_START(qg->qg_qdir))
5814	{
5815		/*
5816		**  XXX we could add basedir, but then we have to realloc()
5817		**  the string... Maybe another time.
5818		*/
5819
5820		syserr("QueuePath %s not absolute", qg->qg_qdir);
5821		ExitStat = EX_CONFIG;
5822		return qn;
5823	}
5824
5825	/* qpath: directory of current workgroup */
5826	len = sm_strlcpy(qpath, qg->qg_qdir, sizeof qpath);
5827	if (len >= sizeof qpath)
5828	{
5829		syserr("QueuePath %.256s too long (%d max)",
5830		       qg->qg_qdir, (int) sizeof qpath);
5831		ExitStat = EX_CONFIG;
5832		return qn;
5833	}
5834
5835	/* begin of qpath must be same as basedir */
5836	if (strncmp(basedir, qpath, blen) != 0 &&
5837	    (strncmp(basedir, qpath, blen - 1) != 0 || len != blen - 1))
5838	{
5839		syserr("QueuePath %s not subpath of QueueDirectory %s",
5840			qpath, basedir);
5841		ExitStat = EX_CONFIG;
5842		return qn;
5843	}
5844
5845	/* Do we have a nested subdirectory? */
5846	if (blen < len && SM_FIRST_DIR_DELIM(qg->qg_qdir + blen) != NULL)
5847	{
5848
5849		/* Copy subdirectory into prefix for later use */
5850		if (sm_strlcpy(prefix, qg->qg_qdir + blen, sizeof prefix) >=
5851		    sizeof prefix)
5852		{
5853			syserr("QueuePath %.256s too long (%d max)",
5854				qg->qg_qdir, (int) sizeof qpath);
5855			ExitStat = EX_CONFIG;
5856			return qn;
5857		}
5858		cp = SM_LAST_DIR_DELIM(prefix);
5859		SM_ASSERT(cp != NULL);
5860		*cp = '\0';	/* cut off trailing / */
5861	}
5862
5863	/* This is guaranteed by the basedir check above */
5864	SM_ASSERT(len >= blen - 1);
5865	cp = &qpath[len - 1];
5866	if (*cp == '*')
5867	{
5868		register DIR *dp;
5869		register struct dirent *d;
5870		int off;
5871		char *delim;
5872		char relpath[MAXPATHLEN];
5873
5874		*cp = '\0';	/* Overwrite wildcard */
5875		if ((cp = SM_LAST_DIR_DELIM(qpath)) == NULL)
5876		{
5877			syserr("QueueDirectory: can not wildcard relative path");
5878			if (tTd(41, 2))
5879				sm_dprintf("multiqueue_cache: \"%s*\": Can not wildcard relative path.\n",
5880					qpath);
5881			ExitStat = EX_CONFIG;
5882			return qn;
5883		}
5884		if (cp == qpath)
5885		{
5886			/*
5887			**  Special case of top level wildcard, like /foo*
5888			**	Change to //foo*
5889			*/
5890
5891			(void) sm_strlcpy(qpath + 1, qpath, sizeof qpath - 1);
5892			++cp;
5893		}
5894		delim = cp;
5895		*(cp++) = '\0';		/* Replace / with \0 */
5896		len = strlen(cp);	/* Last component of queue directory */
5897
5898		/*
5899		**  Path relative to basedir, with trailing /
5900		**  It will be modified below to specify the subdirectories
5901		**  so they can be opened without chdir().
5902		*/
5903
5904		off = sm_strlcpyn(relpath, sizeof relpath, 2, prefix, "/");
5905		SM_ASSERT(off < sizeof relpath);
5906
5907		if (tTd(41, 2))
5908			sm_dprintf("multiqueue_cache: prefix=\"%s%s\"\n",
5909				   relpath, cp);
5910
5911		/* It is always basedir: we don't need to store it per group */
5912		/* XXX: optimize this! -> one more global? */
5913		qg->qg_qdir = newstr(basedir);
5914		qg->qg_qdir[blen - 1] = '\0';	/* cut off trailing / */
5915
5916		/*
5917		**  XXX Should probably wrap this whole loop in a timeout
5918		**  in case some wag decides to NFS mount the queues.
5919		*/
5920
5921		/* Test path to get warning messages. */
5922		if (qn == 0)
5923		{
5924			/*  XXX qg_runasuid and qg_runasgid for specials? */
5925			i = safedirpath(basedir, RunAsUid, RunAsGid, NULL,
5926					sff, 0, 0);
5927			if (i != 0 && tTd(41, 2))
5928				sm_dprintf("multiqueue_cache: \"%s\": Not safe: %s\n",
5929					   basedir, sm_errstring(i));
5930		}
5931
5932		if ((dp = opendir(prefix)) == NULL)
5933		{
5934			syserr("can not opendir(%s/%s)", qg->qg_qdir, prefix);
5935			if (tTd(41, 2))
5936				sm_dprintf("multiqueue_cache: opendir(\"%s/%s\"): %s\n",
5937					   qg->qg_qdir, prefix,
5938					   sm_errstring(errno));
5939			ExitStat = EX_CONFIG;
5940			return qn;
5941		}
5942		while ((d = readdir(dp)) != NULL)
5943		{
5944			i = strlen(d->d_name);
5945			if (i < len || strncmp(d->d_name, cp, len) != 0)
5946			{
5947				if (tTd(41, 5))
5948					sm_dprintf("multiqueue_cache: \"%s\", skipped\n",
5949						d->d_name);
5950				continue;
5951			}
5952
5953			/* Create relative pathname: prefix + local directory */
5954			i = sizeof(relpath) - off;
5955			if (sm_strlcpy(relpath + off, d->d_name, i) >= i)
5956				continue;	/* way too long */
5957
5958			if (!chkqdir(relpath, sff))
5959				continue;
5960
5961			if (qg->qg_qpaths == NULL)
5962			{
5963				slotsleft = INITIAL_SLOTS;
5964				qg->qg_qpaths = (QPATHS *)xalloc((sizeof *qg->qg_qpaths) *
5965								slotsleft);
5966				qg->qg_numqueues = 0;
5967			}
5968			else if (slotsleft < 1)
5969			{
5970				qg->qg_qpaths = (QPATHS *)sm_realloc((char *)qg->qg_qpaths,
5971							  (sizeof *qg->qg_qpaths) *
5972							  (qg->qg_numqueues +
5973							   ADD_SLOTS));
5974				if (qg->qg_qpaths == NULL)
5975				{
5976					(void) closedir(dp);
5977					return qn;
5978				}
5979				slotsleft += ADD_SLOTS;
5980			}
5981
5982			/* check subdirs */
5983			qg->qg_qpaths[qg->qg_numqueues].qp_subdirs = QP_NOSUB;
5984
5985#define CHKRSUBDIR(name, flag)	\
5986	(void) sm_strlcpyn(subdir, sizeof subdir, 3, relpath, "/", name); \
5987	if (chkqdir(subdir, sff))	\
5988		qg->qg_qpaths[qg->qg_numqueues].qp_subdirs |= flag;	\
5989	else
5990
5991
5992			CHKRSUBDIR("qf", QP_SUBQF);
5993			CHKRSUBDIR("df", QP_SUBDF);
5994			CHKRSUBDIR("xf", QP_SUBXF);
5995
5996			/* assert(strlen(d->d_name) < MAXPATHLEN - 14) */
5997			/* maybe even - 17 (subdirs) */
5998
5999			if (prefix[0] != '.')
6000				qg->qg_qpaths[qg->qg_numqueues].qp_name =
6001					newstr(relpath);
6002			else
6003				qg->qg_qpaths[qg->qg_numqueues].qp_name =
6004					newstr(d->d_name);
6005
6006			if (tTd(41, 2))
6007				sm_dprintf("multiqueue_cache: %d: \"%s\" cached (%x).\n",
6008					qg->qg_numqueues, relpath,
6009					qg->qg_qpaths[qg->qg_numqueues].qp_subdirs);
6010#if SM_CONF_SHM
6011			qg->qg_qpaths[qg->qg_numqueues].qp_idx = qn;
6012			*phash = hash_q(relpath, *phash);
6013#endif /* SM_CONF_SHM */
6014			qg->qg_numqueues++;
6015			++qn;
6016			slotsleft--;
6017		}
6018		(void) closedir(dp);
6019
6020		/* undo damage */
6021		*delim = '/';
6022	}
6023	if (qg->qg_numqueues == 0)
6024	{
6025		qg->qg_qpaths = (QPATHS *) xalloc(sizeof *qg->qg_qpaths);
6026
6027		/* test path to get warning messages */
6028		i = safedirpath(qpath, RunAsUid, RunAsGid, NULL, sff, 0, 0);
6029		if (i == ENOENT)
6030		{
6031			syserr("can not opendir(%s)", qpath);
6032			if (tTd(41, 2))
6033				sm_dprintf("multiqueue_cache: opendir(\"%s\"): %s\n",
6034					   qpath, sm_errstring(i));
6035			ExitStat = EX_CONFIG;
6036			return qn;
6037		}
6038
6039		qg->qg_qpaths[0].qp_subdirs = QP_NOSUB;
6040		qg->qg_numqueues = 1;
6041
6042		/* check subdirs */
6043#define CHKSUBDIR(name, flag)	\
6044	(void) sm_strlcpyn(subdir, sizeof subdir, 3, qg->qg_qdir, "/", name); \
6045	if (chkqdir(subdir, sff))	\
6046		qg->qg_qpaths[0].qp_subdirs |= flag;	\
6047	else
6048
6049		CHKSUBDIR("qf", QP_SUBQF);
6050		CHKSUBDIR("df", QP_SUBDF);
6051		CHKSUBDIR("xf", QP_SUBXF);
6052
6053		if (qg->qg_qdir[blen - 1] != '\0' &&
6054		    qg->qg_qdir[blen] != '\0')
6055		{
6056			/*
6057			**  Copy the last component into qpaths and
6058			**  cut off qdir
6059			*/
6060
6061			qg->qg_qpaths[0].qp_name = newstr(qg->qg_qdir + blen);
6062			qg->qg_qdir[blen - 1] = '\0';
6063		}
6064		else
6065			qg->qg_qpaths[0].qp_name = newstr(".");
6066
6067#if SM_CONF_SHM
6068		qg->qg_qpaths[0].qp_idx = qn;
6069		*phash = hash_q(qg->qg_qpaths[0].qp_name, *phash);
6070#endif /* SM_CONF_SHM */
6071		++qn;
6072	}
6073	return qn;
6074}
6075
6076/*
6077**  FILESYS_FIND -- find entry in FileSys table, or add new one
6078**
6079**	Given the pathname of a directory, determine the file system
6080**	in which that directory resides, and return a pointer to the
6081**	entry in the FileSys table that describes the file system.
6082**	A new entry is added if necessary (and requested).
6083**	If the directory does not exist, -1 is returned.
6084**
6085**	Parameters:
6086**		path -- pathname of directory
6087**		add -- add to structure if not found.
6088**
6089**	Returns:
6090**		>=0: found: index in file system table
6091**		<0: some error, i.e.,
6092**		FSF_TOO_MANY: too many filesystems (-> syserr())
6093**		FSF_STAT_FAIL: can't stat() filesystem (-> syserr())
6094**		FSF_NOT_FOUND: not in list
6095*/
6096
6097static short filesys_find __P((char *, bool));
6098
6099#define FSF_NOT_FOUND	(-1)
6100#define FSF_STAT_FAIL	(-2)
6101#define FSF_TOO_MANY	(-3)
6102
6103static short
6104filesys_find(path, add)
6105	char *path;
6106	bool add;
6107{
6108	struct stat st;
6109	short i;
6110
6111	if (stat(path, &st) < 0)
6112	{
6113		syserr("cannot stat queue directory %s", path);
6114		return FSF_STAT_FAIL;
6115	}
6116	for (i = 0; i < NumFileSys; ++i)
6117	{
6118		if (FILE_SYS_DEV(i) == st.st_dev)
6119			return i;
6120	}
6121	if (i >= MAXFILESYS)
6122	{
6123		syserr("too many queue file systems (%d max)", MAXFILESYS);
6124		return FSF_TOO_MANY;
6125	}
6126	if (!add)
6127		return FSF_NOT_FOUND;
6128
6129	++NumFileSys;
6130	FILE_SYS_NAME(i) = path;
6131	FILE_SYS_DEV(i) = st.st_dev;
6132	FILE_SYS_AVAIL(i) = 0;
6133	FILE_SYS_BLKSIZE(i) = 1024; /* avoid divide by zero */
6134	return i;
6135}
6136
6137/*
6138**  FILESYS_SETUP -- set up mapping from queue directories to file systems
6139**
6140**	This data structure is used to efficiently check the amount of
6141**	free space available in a set of queue directories.
6142**
6143**	Parameters:
6144**		add -- initialize structure if necessary.
6145**
6146**	Returns:
6147**		0: success
6148**		<0: some error, i.e.,
6149**		FSF_NOT_FOUND: not in list
6150**		FSF_STAT_FAIL: can't stat() filesystem (-> syserr())
6151**		FSF_TOO_MANY: too many filesystems (-> syserr())
6152*/
6153
6154static int filesys_setup __P((bool));
6155
6156static int
6157filesys_setup(add)
6158	bool add;
6159{
6160	int i, j;
6161	short fs;
6162	int ret;
6163
6164	ret = 0;
6165	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
6166	{
6167		for (j = 0; j < Queue[i]->qg_numqueues; ++j)
6168		{
6169			QPATHS *qp = &Queue[i]->qg_qpaths[j];
6170
6171			fs = filesys_find(qp->qp_name, add);
6172			if (fs >= 0)
6173				qp->qp_fsysidx = fs;
6174			else
6175				qp->qp_fsysidx = 0;
6176			if (fs < ret)
6177				ret = fs;
6178		}
6179	}
6180	return ret;
6181}
6182
6183/*
6184**  FILESYS_UPDATE -- update amount of free space on all file systems
6185**
6186**	The FileSys table is used to cache the amount of free space
6187**	available on all queue directory file systems.
6188**	This function updates the cached information if it has expired.
6189**
6190**	Parameters:
6191**		none.
6192**
6193**	Returns:
6194**		none.
6195**
6196**	Side Effects:
6197**		Updates FileSys table.
6198*/
6199
6200void
6201filesys_update()
6202{
6203	int i;
6204	long avail, blksize;
6205	time_t now;
6206	static time_t nextupdate = 0;
6207
6208#if SM_CONF_SHM
6209	/* only the daemon updates this structure */
6210	if (ShmId != SM_SHM_NO_ID && DaemonPid != CurrentPid)
6211		return;
6212#endif /* SM_CONF_SHM */
6213	now = curtime();
6214	if (now < nextupdate)
6215		return;
6216	nextupdate = now + FILESYS_UPDATE_INTERVAL;
6217	for (i = 0; i < NumFileSys; ++i)
6218	{
6219		FILESYS *fs = &FILE_SYS(i);
6220
6221		avail = freediskspace(FILE_SYS_NAME(i), &blksize);
6222		if (avail < 0 || blksize <= 0)
6223		{
6224			if (LogLevel > 5)
6225				sm_syslog(LOG_ERR, NOQID,
6226					"filesys_update failed: %s, fs=%s, avail=%ld, blocksize=%ld",
6227					sm_errstring(errno),
6228					FILE_SYS_NAME(i), avail, blksize);
6229			fs->fs_avail = 0;
6230			fs->fs_blksize = 1024; /* avoid divide by zero */
6231			nextupdate = now + 2; /* let's do this soon again */
6232		}
6233		else
6234		{
6235			fs->fs_avail = avail;
6236			fs->fs_blksize = blksize;
6237		}
6238	}
6239}
6240
6241#if _FFR_ANY_FREE_FS
6242/*
6243**  FILESYS_FREE -- check whether there is at least one fs with enough space.
6244**
6245**	Parameters:
6246**		fsize -- file size in bytes
6247**
6248**	Returns:
6249**		true iff there is one fs with more than fsize bytes free.
6250*/
6251
6252bool
6253filesys_free(fsize)
6254	long fsize;
6255{
6256	int i;
6257
6258	if (fsize <= 0)
6259		return true;
6260	for (i = 0; i < NumFileSys; ++i)
6261	{
6262		long needed = 0;
6263
6264		if (FILE_SYS_AVAIL(i) < 0 || FILE_SYS_BLKSIZE(i) <= 0)
6265			continue;
6266		needed += fsize / FILE_SYS_BLKSIZE(i)
6267			  + ((fsize % FILE_SYS_BLKSIZE(i)
6268			      > 0) ? 1 : 0)
6269			  + MinBlocksFree;
6270		if (needed <= FILE_SYS_AVAIL(i))
6271			return true;
6272	}
6273	return false;
6274}
6275#endif /* _FFR_ANY_FREE_FS */
6276
6277#if _FFR_CONTROL_MSTAT
6278/*
6279**  DISK_STATUS -- show amount of free space in queue directories
6280**
6281**	Parameters:
6282**		out -- output file pointer.
6283**		prefix -- string to output in front of each line.
6284**
6285**	Returns:
6286**		none.
6287*/
6288
6289void
6290disk_status(out, prefix)
6291	SM_FILE_T *out;
6292	char *prefix;
6293{
6294	int i;
6295	long avail, blksize;
6296	long free;
6297
6298	for (i = 0; i < NumFileSys; ++i)
6299	{
6300		avail = freediskspace(FILE_SYS_NAME(i), &blksize);
6301		if (avail >= 0 && blksize > 0)
6302		{
6303			free = (long)((double) avail *
6304				((double) blksize / 1024));
6305		}
6306		else
6307			free = -1;
6308		(void) sm_io_fprintf(out, SM_TIME_DEFAULT,
6309				"%s%d/%s/%ld\r\n",
6310				prefix, i,
6311				FILE_SYS_NAME(i),
6312					free);
6313	}
6314}
6315#endif /* _FFR_CONTROL_MSTAT */
6316
6317#if SM_CONF_SHM
6318/*
6319**  UPD_QS -- update information about queue when adding/deleting an entry
6320**
6321**	Parameters:
6322**		e -- envelope.
6323**		delete -- delete/add entry.
6324**		avail -- update the space available as well.
6325**
6326**	Returns:
6327**		none.
6328**
6329**	Side Effects:
6330**		Modifies available space in filesystem.
6331**		Changes number of entries in queue directory.
6332*/
6333
6334void
6335upd_qs(e, delete, avail)
6336	ENVELOPE *e;
6337	bool delete;
6338	bool avail;
6339{
6340	short fidx;
6341	int idx;
6342	long s;
6343
6344	if (ShmId == SM_SHM_NO_ID || e == NULL)
6345		return;
6346	if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR)
6347		return;
6348	idx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_idx;
6349
6350	/* XXX in theory this needs to be protected with a mutex */
6351	if (QSHM_ENTRIES(idx) >= 0)
6352	{
6353		if (delete)
6354			--QSHM_ENTRIES(idx);
6355		else
6356			++QSHM_ENTRIES(idx);
6357	}
6358
6359	fidx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_fsysidx;
6360	if (fidx < 0)
6361		return;
6362
6363	/* update available space also?  (might be loseqfile) */
6364	if (!avail)
6365		return;
6366
6367	/* convert size to blocks; this causes rounding errors */
6368	s = e->e_msgsize / FILE_SYS_BLKSIZE(fidx);
6369	if (s == 0)
6370		return;
6371
6372	/* XXX in theory this needs to be protected with a mutex */
6373	if (delete)
6374		FILE_SYS_AVAIL(fidx) += s;
6375	else
6376		FILE_SYS_AVAIL(fidx) -= s;
6377
6378}
6379
6380#if _FFR_SELECT_SHM
6381
6382static bool write_key_file __P((char *, long));
6383static long read_key_file __P((char *, long));
6384
6385/*
6386**  WRITE_KEY_FILE -- record some key into a file.
6387**
6388**	Parameters:
6389**		keypath -- file name.
6390**		key -- key to write.
6391**
6392**	Returns:
6393**		true iff file could be written.
6394**
6395**	Side Effects:
6396**		writes file.
6397*/
6398
6399static bool
6400write_key_file(keypath, key)
6401	char *keypath;
6402	long key;
6403{
6404	bool ok;
6405	long sff;
6406	SM_FILE_T *keyf;
6407
6408	ok = false;
6409	if (keypath == NULL || *keypath == '\0')
6410		return ok;
6411	sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT;
6412	if (TrustedUid != 0 && RealUid == TrustedUid)
6413		sff |= SFF_OPENASROOT;
6414	keyf = safefopen(keypath, O_WRONLY|O_TRUNC, 0644, sff);
6415	if (keyf == NULL)
6416	{
6417		sm_syslog(LOG_ERR, NOQID, "unable to write %s: %s",
6418			  keypath, sm_errstring(errno));
6419	}
6420	else
6421	{
6422		ok = sm_io_fprintf(keyf, SM_TIME_DEFAULT, "%ld\n", key) !=
6423		     SM_IO_EOF;
6424		ok = ok && (sm_io_close(keyf, SM_TIME_DEFAULT) != SM_IO_EOF);
6425	}
6426	return ok;
6427}
6428
6429/*
6430**  READ_KEY_FILE -- read a key from a file.
6431**
6432**	Parameters:
6433**		keypath -- file name.
6434**		key -- default key.
6435**
6436**	Returns:
6437**		key.
6438*/
6439
6440static long
6441read_key_file(keypath, key)
6442	char *keypath;
6443	long key;
6444{
6445	int r;
6446	long sff, n;
6447	SM_FILE_T *keyf;
6448
6449	if (keypath == NULL || *keypath == '\0')
6450		return key;
6451	sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY;
6452	if (TrustedUid != 0 && RealUid == TrustedUid)
6453		sff |= SFF_OPENASROOT;
6454	keyf = safefopen(keypath, O_RDONLY, 0644, sff);
6455	if (keyf == NULL)
6456	{
6457		sm_syslog(LOG_ERR, NOQID, "unable to read %s: %s",
6458			  keypath, sm_errstring(errno));
6459	}
6460	else
6461	{
6462		r = sm_io_fscanf(keyf, SM_TIME_DEFAULT, "%ld", &n);
6463		if (r == 1)
6464			key = n;
6465		(void) sm_io_close(keyf, SM_TIME_DEFAULT);
6466	}
6467	return key;
6468}
6469#endif /* _FFR_SELECT_SHM */
6470
6471/*
6472**  INIT_SHM -- initialize shared memory structure
6473**
6474**	Initialize or attach to shared memory segment.
6475**	Currently it is not a fatal error if this doesn't work.
6476**	However, it causes us to have a "fallback" storage location
6477**	for everything that is supposed to be in the shared memory,
6478**	which makes the code slightly ugly.
6479**
6480**	Parameters:
6481**		qn -- number of queue directories.
6482**		owner -- owner of shared memory.
6483**		hash -- identifies data that is stored in shared memory.
6484**
6485**	Returns:
6486**		none.
6487*/
6488
6489static void init_shm __P((int, bool, unsigned int));
6490
6491static void
6492init_shm(qn, owner, hash)
6493	int qn;
6494	bool owner;
6495	unsigned int hash;
6496{
6497	int i;
6498#if _FFR_SELECT_SHM
6499	bool keyselect;
6500#endif /* _FFR_SELECT_SHM */
6501
6502	PtrFileSys = &FileSys[0];
6503	PNumFileSys = &Numfilesys;
6504#if _FFR_SELECT_SHM
6505/* if this "key" is specified: select one yourself */
6506# define SEL_SHM_KEY	((key_t) -1)
6507# define FIRST_SHM_KEY	25
6508#endif /* _FFR_SELECT_SHM */
6509
6510	/* This allows us to disable shared memory at runtime. */
6511	if (ShmKey != 0)
6512	{
6513		int count;
6514		int save_errno;
6515		size_t shms;
6516
6517		count = 0;
6518		shms = SM_T_SIZE + qn * sizeof(QUEUE_SHM_T);
6519#if _FFR_SELECT_SHM
6520		keyselect = ShmKey == SEL_SHM_KEY;
6521		if (keyselect)
6522		{
6523			if (owner)
6524				ShmKey = FIRST_SHM_KEY;
6525			else
6526			{
6527				ShmKey = read_key_file(ShmKeyFile, ShmKey);
6528				keyselect = false;
6529				if (ShmKey == SEL_SHM_KEY)
6530					goto error;
6531			}
6532		}
6533#endif /* _FFR_SELECT_SHM */
6534		for (;;)
6535		{
6536			/* XXX: maybe allow read access for group? */
6537			Pshm = sm_shmstart(ShmKey, shms, SHM_R|SHM_W, &ShmId,
6538					   owner);
6539			save_errno = errno;
6540			if (Pshm != NULL || save_errno != EEXIST)
6541				break;
6542			if (++count >= 3)
6543			{
6544#if _FFR_SELECT_SHM
6545				if (keyselect)
6546				{
6547					++ShmKey;
6548
6549					/* back where we started? */
6550					if (ShmKey == SEL_SHM_KEY)
6551						break;
6552					continue;
6553				}
6554#endif /* _FFR_SELECT_SHM */
6555				break;
6556			}
6557#if _FFR_SELECT_SHM
6558			/* only sleep if we are at the first key */
6559			if (!keyselect || ShmKey == SEL_SHM_KEY)
6560#endif /* _FFR_SELECT_SHM */
6561			sleep(count);
6562		}
6563		if (Pshm != NULL)
6564		{
6565			int *p;
6566
6567#if _FFR_SELECT_SHM
6568			if (keyselect)
6569				(void) write_key_file(ShmKeyFile, (long) ShmKey);
6570#endif /* _FFR_SELECT_SHM */
6571			p = (int *) Pshm;
6572			if (owner)
6573			{
6574				*p = (int) shms;
6575				*((pid_t *) SHM_OFF_PID(Pshm)) = CurrentPid;
6576				p = (int *) SHM_OFF_TAG(Pshm);
6577				*p = hash;
6578			}
6579			else
6580			{
6581				if (*p != (int) shms)
6582				{
6583					save_errno = EINVAL;
6584					cleanup_shm(false);
6585					goto error;
6586				}
6587				p = (int *) SHM_OFF_TAG(Pshm);
6588				if (*p != (int) hash)
6589				{
6590					save_errno = EINVAL;
6591					cleanup_shm(false);
6592					goto error;
6593				}
6594
6595				/*
6596				**  XXX how to check the pid?
6597				**  Read it from the pid-file? That does
6598				**  not need to exist.
6599				**  We could disable shm if we can't confirm
6600				**  that it is the right one.
6601				*/
6602			}
6603
6604			PtrFileSys = (FILESYS *) OFF_FILE_SYS(Pshm);
6605			PNumFileSys = (int *) OFF_NUM_FILE_SYS(Pshm);
6606			QShm = (QUEUE_SHM_T *) OFF_QUEUE_SHM(Pshm);
6607			PRSATmpCnt = (int *) OFF_RSA_TMP_CNT(Pshm);
6608			*PRSATmpCnt = 0;
6609			if (owner)
6610			{
6611				/* initialize values in shared memory */
6612				NumFileSys = 0;
6613				for (i = 0; i < qn; i++)
6614					QShm[i].qs_entries = -1;
6615			}
6616			return;
6617		}
6618  error:
6619		if (LogLevel > (owner ? 8 : 11))
6620		{
6621			sm_syslog(owner ? LOG_ERR : LOG_NOTICE, NOQID,
6622				  "can't %s shared memory, key=%ld: %s",
6623				  owner ? "initialize" : "attach to",
6624				  (long) ShmKey, sm_errstring(save_errno));
6625		}
6626	}
6627}
6628#endif /* SM_CONF_SHM */
6629
6630/*
6631**  SETUP_QUEUES -- setup all queue groups
6632**
6633**	Parameters:
6634**		owner -- owner of shared memory.
6635**
6636**	Returns:
6637**		none.
6638**
6639#if SM_CONF_SHM
6640**	Side Effects:
6641**		attaches shared memory.
6642#endif * SM_CONF_SHM *
6643*/
6644
6645void
6646setup_queues(owner)
6647	bool owner;
6648{
6649	int i, qn, len;
6650	unsigned int hashval;
6651	time_t now;
6652	char basedir[MAXPATHLEN];
6653	struct stat st;
6654
6655	/*
6656	**  Determine basedir for all queue directories.
6657	**  All queue directories must be (first level) subdirectories
6658	**  of the basedir.  The basedir is the QueueDir
6659	**  without wildcards, but with trailing /
6660	*/
6661
6662	hashval = 0;
6663	errno = 0;
6664	len = sm_strlcpy(basedir, QueueDir, sizeof basedir);
6665	if (len >= sizeof basedir)
6666	{
6667		syserr("QueueDirectory: path too long: %d,  max %d",
6668			len, (int) sizeof basedir);
6669		ExitStat = EX_CONFIG;
6670		return;
6671	}
6672	SM_ASSERT(len > 0);
6673	if (basedir[len - 1] == '*')
6674	{
6675		char *cp;
6676
6677		cp = SM_LAST_DIR_DELIM(basedir);
6678		if (cp == NULL)
6679		{
6680			syserr("QueueDirectory: can not wildcard relative path \"%s\"",
6681				QueueDir);
6682			if (tTd(41, 2))
6683				sm_dprintf("setup_queues: \"%s\": Can not wildcard relative path.\n",
6684					QueueDir);
6685			ExitStat = EX_CONFIG;
6686			return;
6687		}
6688
6689		/* cut off wildcard pattern */
6690		*++cp = '\0';
6691		len = cp - basedir;
6692	}
6693	else if (!SM_IS_DIR_DELIM(basedir[len - 1]))
6694	{
6695		/* append trailing slash since it is a directory */
6696		basedir[len] = '/';
6697		basedir[++len] = '\0';
6698	}
6699
6700	/* len counts up to the last directory delimiter */
6701	SM_ASSERT(basedir[len - 1] == '/');
6702
6703	if (chdir(basedir) < 0)
6704	{
6705		int save_errno = errno;
6706
6707		syserr("can not chdir(%s)", basedir);
6708		if (save_errno == EACCES)
6709			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
6710				"Program mode requires special privileges, e.g., root or TrustedUser.\n");
6711		if (tTd(41, 2))
6712			sm_dprintf("setup_queues: \"%s\": %s\n",
6713				   basedir, sm_errstring(errno));
6714		ExitStat = EX_CONFIG;
6715		return;
6716	}
6717#if SM_CONF_SHM
6718	hashval = hash_q(basedir, hashval);
6719#endif /* SM_CONF_SHM */
6720
6721	/* initialize for queue runs */
6722	DoQueueRun = false;
6723	now = curtime();
6724	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
6725		Queue[i]->qg_nextrun = now;
6726
6727
6728	if (UseMSP && OpMode != MD_TEST)
6729	{
6730		long sff = SFF_CREAT;
6731
6732		if (stat(".", &st) < 0)
6733		{
6734			syserr("can not stat(%s)", basedir);
6735			if (tTd(41, 2))
6736				sm_dprintf("setup_queues: \"%s\": %s\n",
6737					   basedir, sm_errstring(errno));
6738			ExitStat = EX_CONFIG;
6739			return;
6740		}
6741		if (RunAsUid == 0)
6742			sff |= SFF_ROOTOK;
6743
6744		/*
6745		**  Check queue directory permissions.
6746		**	Can we write to a group writable queue directory?
6747		*/
6748
6749		if (bitset(S_IWGRP, QueueFileMode) &&
6750		    bitset(S_IWGRP, st.st_mode) &&
6751		    safefile(" ", RunAsUid, RunAsGid, RunAsUserName, sff,
6752			     QueueFileMode, NULL) != 0)
6753		{
6754			syserr("can not write to queue directory %s (RunAsGid=%d, required=%d)",
6755				basedir, (int) RunAsGid, (int) st.st_gid);
6756		}
6757		if (bitset(S_IWOTH|S_IXOTH, st.st_mode))
6758		{
6759#if _FFR_MSP_PARANOIA
6760			syserr("dangerous permissions=%o on queue directory %s",
6761				(int) st.st_mode, basedir);
6762#else /* _FFR_MSP_PARANOIA */
6763			if (LogLevel > 0)
6764				sm_syslog(LOG_ERR, NOQID,
6765					  "dangerous permissions=%o on queue directory %s",
6766					  (int) st.st_mode, basedir);
6767#endif /* _FFR_MSP_PARANOIA */
6768		}
6769#if _FFR_MSP_PARANOIA
6770		if (NumQueue > 1)
6771			syserr("can not use multiple queues for MSP");
6772#endif /* _FFR_MSP_PARANOIA */
6773	}
6774
6775	/* initial number of queue directories */
6776	qn = 0;
6777	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
6778		qn = multiqueue_cache(basedir, len, Queue[i], qn, &hashval);
6779
6780#if SM_CONF_SHM
6781	init_shm(qn, owner, hashval);
6782	i = filesys_setup(owner || ShmId == SM_SHM_NO_ID);
6783	if (i == FSF_NOT_FOUND)
6784	{
6785		/*
6786		**  We didn't get the right filesystem data
6787		**  This may happen if we don't have the right shared memory.
6788		**  So let's do this without shared memory.
6789		*/
6790
6791		SM_ASSERT(!owner);
6792		cleanup_shm(false);	/* release shared memory */
6793		i = filesys_setup(false);
6794		if (i < 0)
6795			syserr("filesys_setup failed twice, result=%d", i);
6796		else if (LogLevel > 8)
6797			sm_syslog(LOG_WARNING, NOQID,
6798				  "shared memory does not contain expected data, ignored");
6799	}
6800#else /* SM_CONF_SHM */
6801	i = filesys_setup(true);
6802#endif /* SM_CONF_SHM */
6803	if (i < 0)
6804		ExitStat = EX_CONFIG;
6805}
6806
6807#if SM_CONF_SHM
6808/*
6809**  CLEANUP_SHM -- do some cleanup work for shared memory etc
6810**
6811**	Parameters:
6812**		owner -- owner of shared memory?
6813**
6814**	Returns:
6815**		none.
6816**
6817**	Side Effects:
6818**		detaches shared memory.
6819*/
6820
6821void
6822cleanup_shm(owner)
6823	bool owner;
6824{
6825	if (ShmId != SM_SHM_NO_ID)
6826	{
6827		if (sm_shmstop(Pshm, ShmId, owner) < 0 && LogLevel > 8)
6828			sm_syslog(LOG_INFO, NOQID, "sh_shmstop failed=%s",
6829				  sm_errstring(errno));
6830		Pshm = NULL;
6831		ShmId = SM_SHM_NO_ID;
6832	}
6833}
6834#endif /* SM_CONF_SHM */
6835
6836/*
6837**  CLEANUP_QUEUES -- do some cleanup work for queues
6838**
6839**	Parameters:
6840**		none.
6841**
6842**	Returns:
6843**		none.
6844**
6845*/
6846
6847void
6848cleanup_queues()
6849{
6850	sync_queue_time();
6851}
6852/*
6853**  SET_DEF_QUEUEVAL -- set default values for a queue group.
6854**
6855**	Parameters:
6856**		qg -- queue group
6857**		all -- set all values (true for default group)?
6858**
6859**	Returns:
6860**		none.
6861**
6862**	Side Effects:
6863**		sets default values for the queue group.
6864*/
6865
6866void
6867set_def_queueval(qg, all)
6868	QUEUEGRP *qg;
6869	bool all;
6870{
6871	if (bitnset(QD_DEFINED, qg->qg_flags))
6872		return;
6873	if (all)
6874		qg->qg_qdir = QueueDir;
6875#if _FFR_QUEUE_GROUP_SORTORDER
6876	qg->qg_sortorder = QueueSortOrder;
6877#endif /* _FFR_QUEUE_GROUP_SORTORDER */
6878	qg->qg_maxqrun = all ? MaxRunnersPerQueue : -1;
6879	qg->qg_nice = NiceQueueRun;
6880}
6881/*
6882**  MAKEQUEUE -- define a new queue.
6883**
6884**	Parameters:
6885**		line -- description of queue.  This is in labeled fields.
6886**			The fields are:
6887**			   F -- the flags associated with the queue
6888**			   I -- the interval between running the queue
6889**			   J -- the maximum # of jobs in work list
6890**			   [M -- the maximum # of jobs in a queue run]
6891**			   N -- the niceness at which to run
6892**			   P -- the path to the queue
6893**			   S -- the queue sorting order
6894**			   R -- number of parallel queue runners
6895**			   r -- max recipients per envelope
6896**			The first word is the canonical name of the queue.
6897**		qdef -- this is a 'Q' definition from .cf
6898**
6899**	Returns:
6900**		none.
6901**
6902**	Side Effects:
6903**		enters the queue into the queue table.
6904*/
6905
6906void
6907makequeue(line, qdef)
6908	char *line;
6909	bool qdef;
6910{
6911	register char *p;
6912	register QUEUEGRP *qg;
6913	register STAB *s;
6914	int i;
6915	char fcode;
6916
6917	/* allocate a queue and set up defaults */
6918	qg = (QUEUEGRP *) xalloc(sizeof *qg);
6919	memset((char *) qg, '\0', sizeof *qg);
6920
6921	if (line[0] == '\0')
6922	{
6923		syserr("name required for queue");
6924		return;
6925	}
6926
6927	/* collect the queue name */
6928	for (p = line;
6929	     *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p));
6930	     p++)
6931		continue;
6932	if (*p != '\0')
6933		*p++ = '\0';
6934	qg->qg_name = newstr(line);
6935
6936	/* set default values, can be overridden below */
6937	set_def_queueval(qg, false);
6938
6939	/* now scan through and assign info from the fields */
6940	while (*p != '\0')
6941	{
6942		auto char *delimptr;
6943
6944		while (*p != '\0' &&
6945		       (*p == ',' || (isascii(*p) && isspace(*p))))
6946			p++;
6947
6948		/* p now points to field code */
6949		fcode = *p;
6950		while (*p != '\0' && *p != '=' && *p != ',')
6951			p++;
6952		if (*p++ != '=')
6953		{
6954			syserr("queue %s: `=' expected", qg->qg_name);
6955			return;
6956		}
6957		while (isascii(*p) && isspace(*p))
6958			p++;
6959
6960		/* p now points to the field body */
6961		p = munchstring(p, &delimptr, ',');
6962
6963		/* install the field into the queue struct */
6964		switch (fcode)
6965		{
6966		  case 'P':		/* pathname */
6967			if (*p == '\0')
6968				syserr("queue %s: empty path name",
6969					qg->qg_name);
6970			else
6971				qg->qg_qdir = newstr(p);
6972			break;
6973
6974		  case 'F':		/* flags */
6975			for (; *p != '\0'; p++)
6976				if (!(isascii(*p) && isspace(*p)))
6977					setbitn(*p, qg->qg_flags);
6978			break;
6979
6980			/*
6981			**  Do we need two intervals here:
6982			**  One for persistent queue runners,
6983			**  one for "normal" queue runs?
6984			*/
6985
6986		  case 'I':	/* interval between running the queue */
6987			qg->qg_queueintvl = convtime(p, 'm');
6988			break;
6989
6990		  case 'N':		/* run niceness */
6991			qg->qg_nice = atoi(p);
6992			break;
6993
6994		  case 'R':		/* maximum # of runners for the group */
6995			i = atoi(p);
6996
6997			/* can't have more runners than allowed total */
6998			if (MaxQueueChildren > 0 && i > MaxQueueChildren)
6999			{
7000				qg->qg_maxqrun = MaxQueueChildren;
7001				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7002						     "Q=%s: R=%d exceeds MaxQueueChildren=%d, set to MaxQueueChildren\n",
7003						     qg->qg_name, i,
7004						     MaxQueueChildren);
7005			}
7006			else
7007				qg->qg_maxqrun = i;
7008			break;
7009
7010		  case 'J':		/* maximum # of jobs in work list */
7011			qg->qg_maxlist = atoi(p);
7012			break;
7013
7014		  case 'r':		/* max recipients per envelope */
7015			qg->qg_maxrcpt = atoi(p);
7016			break;
7017
7018#if _FFR_QUEUE_GROUP_SORTORDER
7019		  case 'S':		/* queue sorting order */
7020			switch (*p)
7021			{
7022			  case 'h':	/* Host first */
7023			  case 'H':
7024				qg->qg_sortorder = QSO_BYHOST;
7025				break;
7026
7027			  case 'p':	/* Priority order */
7028			  case 'P':
7029				qg->qg_sortorder = QSO_BYPRIORITY;
7030				break;
7031
7032			  case 't':	/* Submission time */
7033			  case 'T':
7034				qg->qg_sortorder = QSO_BYTIME;
7035				break;
7036
7037			  case 'f':	/* File name */
7038			  case 'F':
7039				qg->qg_sortorder = QSO_BYFILENAME;
7040				break;
7041
7042			  case 'm':	/* Modification time */
7043			  case 'M':
7044				qg->qg_sortorder = QSO_BYMODTIME;
7045				break;
7046
7047			  case 'r':	/* Random */
7048			  case 'R':
7049				qg->qg_sortorder = QSO_RANDOM;
7050				break;
7051
7052# if _FFR_RHS
7053			  case 's':	/* Shuffled host name */
7054			  case 'S':
7055				qg->qg_sortorder = QSO_BYSHUFFLE;
7056				break;
7057# endif /* _FFR_RHS */
7058
7059			  default:
7060				syserr("Invalid queue sort order \"%s\"", p);
7061			}
7062			break;
7063#endif /* _FFR_QUEUE_GROUP_SORTORDER */
7064
7065		  default:
7066			syserr("Q%s: unknown queue equate %c=",
7067			       qg->qg_name, fcode);
7068			break;
7069		}
7070
7071		p = delimptr;
7072	}
7073
7074#if !HASNICE
7075	if (qg->qg_nice != NiceQueueRun)
7076	{
7077		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7078				     "Q%s: Warning: N= set on system that doesn't support nice()\n",
7079				     qg->qg_name);
7080	}
7081#endif /* !HASNICE */
7082
7083	/* do some rationality checking */
7084	if (NumQueue >= MAXQUEUEGROUPS)
7085	{
7086		syserr("too many queue groups defined (%d max)",
7087			MAXQUEUEGROUPS);
7088		return;
7089	}
7090
7091	if (qg->qg_qdir == NULL)
7092	{
7093		if (QueueDir == NULL || *QueueDir == '\0')
7094		{
7095			syserr("QueueDir must be defined before queue groups");
7096			return;
7097		}
7098		qg->qg_qdir = newstr(QueueDir);
7099	}
7100
7101	if (qg->qg_maxqrun > 1 && !bitnset(QD_FORK, qg->qg_flags))
7102	{
7103		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
7104				     "Warning: Q=%s: R=%d: multiple queue runners specified\n\tbut flag '%c' is not set\n",
7105				     qg->qg_name, qg->qg_maxqrun, QD_FORK);
7106	}
7107
7108	/* enter the queue into the symbol table */
7109	if (tTd(37, 8))
7110		sm_syslog(LOG_INFO, NOQID,
7111			  "Adding %s to stab, path: %s", qg->qg_name,
7112			  qg->qg_qdir);
7113	s = stab(qg->qg_name, ST_QUEUE, ST_ENTER);
7114	if (s->s_quegrp != NULL)
7115	{
7116		i = s->s_quegrp->qg_index;
7117
7118		/* XXX what about the pointers inside this struct? */
7119		sm_free(s->s_quegrp); /* XXX */
7120	}
7121	else
7122		i = NumQueue++;
7123	Queue[i] = s->s_quegrp = qg;
7124	qg->qg_index = i;
7125
7126	/* set default value for max queue runners */
7127	if (qg->qg_maxqrun < 0)
7128	{
7129		if (MaxRunnersPerQueue > 0)
7130			qg->qg_maxqrun = MaxRunnersPerQueue;
7131		else
7132			qg->qg_maxqrun = 1;
7133	}
7134	if (qdef)
7135		setbitn(QD_DEFINED, qg->qg_flags);
7136}
7137#if 0
7138/*
7139**  HASHFQN -- calculate a hash value for a fully qualified host name
7140**
7141**	Arguments:
7142**		fqn -- an all lower-case host.domain string
7143**		buckets -- the number of buckets (queue directories)
7144**
7145**	Returns:
7146**		a bucket number (signed integer)
7147**		-1 on error
7148**
7149**	Contributed by Exactis.com, Inc.
7150*/
7151
7152int
7153hashfqn(fqn, buckets)
7154	register char *fqn;
7155	int buckets;
7156{
7157	register char *p;
7158	register int h = 0, hash, cnt;
7159
7160	if (fqn == NULL)
7161		return -1;
7162
7163	/*
7164	**  A variation on the gdb hash
7165	**  This is the best as of Feb 19, 1996 --bcx
7166	*/
7167
7168	p = fqn;
7169	h = 0x238F13AF * strlen(p);
7170	for (cnt = 0; *p != 0; ++p, cnt++)
7171	{
7172		h = (h + (*p << (cnt * 5 % 24))) & 0x7FFFFFFF;
7173	}
7174	h = (1103515243 * h + 12345) & 0x7FFFFFFF;
7175	if (buckets < 2)
7176		hash = 0;
7177	else
7178		hash = (h % buckets);
7179
7180	return hash;
7181}
7182#endif /* 0 */
7183
7184#if _FFR_QUEUEDELAY
7185/*
7186**  QUEUEDELAY -- compute queue delay time
7187**
7188**	Parameters:
7189**		e -- the envelope to queue up.
7190**
7191**	Returns:
7192**		queue delay time
7193**
7194**	Side Effects:
7195**		may change e_queuedelay
7196*/
7197
7198static time_t
7199queuedelay(e)
7200	ENVELOPE *e;
7201{
7202	time_t qd;
7203
7204	if (e->e_queuealg == QD_EXP)
7205	{
7206		if (e->e_queuedelay == 0)
7207			e->e_queuedelay = QueueInitDelay;
7208		else
7209		{
7210			e->e_queuedelay *= 2;
7211			if (e->e_queuedelay > QueueMaxDelay)
7212				e->e_queuedelay = QueueMaxDelay;
7213		}
7214		qd = e->e_queuedelay;
7215	}
7216	else
7217		qd = MinQueueAge;
7218	return qd;
7219}
7220#endif /* _FFR_QUEUEDELAY */
7221
7222/*
7223**  A structure for sorting Queue according to maxqrun without
7224**	screwing up Queue itself.
7225*/
7226
7227struct sortqgrp
7228{
7229	int sg_idx;		/* original index */
7230	int sg_maxqrun;		/* max queue runners */
7231};
7232typedef struct sortqgrp	SORTQGRP_T;
7233static int cmpidx __P((const void *, const void *));
7234
7235static int
7236cmpidx(a, b)
7237	const void *a;
7238	const void *b;
7239{
7240	/* The sort is highest to lowest, so the comparison is reversed */
7241	if (((SORTQGRP_T *)a)->sg_maxqrun < ((SORTQGRP_T *)b)->sg_maxqrun)
7242		return 1;
7243	else if (((SORTQGRP_T *)a)->sg_maxqrun > ((SORTQGRP_T *)b)->sg_maxqrun)
7244		return -1;
7245	else
7246		return 0;
7247}
7248
7249/*
7250**  MAKEWORKGROUP -- balance queue groups into work groups per MaxQueueChildren
7251**
7252**  Take the now defined queue groups and assign them to work groups.
7253**  This is done to balance out the number of concurrently active
7254**  queue runners such that MaxQueueChildren is not exceeded. This may
7255**  result in more than one queue group per work group. In such a case
7256**  the number of running queue groups in that work group will have no
7257**  more than the work group maximum number of runners (a "fair" portion
7258**  of MaxQueueRunners). All queue groups within a work group will get a
7259**  chance at running.
7260**
7261**	Parameters:
7262**		none.
7263**
7264**	Returns:
7265**		nothing.
7266**
7267**	Side Effects:
7268**		Sets up WorkGrp structure.
7269*/
7270
7271void
7272makeworkgroups()
7273{
7274	int i, j, total_runners = 0;
7275	int dir;
7276	SORTQGRP_T si[MAXQUEUEGROUPS + 1];
7277
7278	if (NumQueue == 1 && strcmp(Queue[0]->qg_name, "mqueue") == 0)
7279	{
7280		/*
7281		**  There is only the "mqueue" queue group (a default)
7282		**  containing all of the queues. We want to provide to
7283		**  this queue group the maximum allowable queue runners.
7284		**  To match older behavior (8.10/8.11) we'll try for
7285		**  1 runner per queue capping it at MaxQueueChildren.
7286		**  So if there are N queues, then there will be N runners
7287		**  for the "mqueue" queue group (where N is kept less than
7288		**  MaxQueueChildren).
7289		*/
7290
7291		NumWorkGroups = 1;
7292		WorkGrp[0].wg_numqgrp = 1;
7293		WorkGrp[0].wg_qgs = (QUEUEGRP **) xalloc(sizeof(QUEUEGRP *));
7294		WorkGrp[0].wg_qgs[0] = Queue[0];
7295		if (MaxQueueChildren > 0 &&
7296		    Queue[0]->qg_numqueues > MaxQueueChildren)
7297			WorkGrp[0].wg_runners = MaxQueueChildren;
7298		else
7299			WorkGrp[0].wg_runners = Queue[0]->qg_numqueues;
7300
7301		Queue[0]->qg_wgrp = 0;
7302
7303		/* can't have more runners than allowed total */
7304		if (MaxQueueChildren > 0 &&
7305		    Queue[0]->qg_maxqrun > MaxQueueChildren)
7306			Queue[0]->qg_maxqrun = MaxQueueChildren;
7307		WorkGrp[0].wg_maxact = Queue[0]->qg_maxqrun;
7308		WorkGrp[0].wg_lowqintvl = Queue[0]->qg_queueintvl;
7309		return;
7310	}
7311
7312	for (i = 0; i < NumQueue; i++)
7313	{
7314		si[i].sg_maxqrun = Queue[i]->qg_maxqrun;
7315		si[i].sg_idx = i;
7316	}
7317	qsort(si, NumQueue, sizeof(si[0]), cmpidx);
7318
7319	NumWorkGroups = 0;
7320	for (i = 0; i < NumQueue; i++)
7321	{
7322		total_runners += si[i].sg_maxqrun;
7323		if (MaxQueueChildren <= 0 || total_runners <= MaxQueueChildren)
7324			NumWorkGroups++;
7325		else
7326			break;
7327	}
7328
7329	if (NumWorkGroups < 1)
7330		NumWorkGroups = 1; /* gotta have one at least */
7331	else if (NumWorkGroups > MAXWORKGROUPS)
7332		NumWorkGroups = MAXWORKGROUPS; /* the limit */
7333
7334	/*
7335	**  We now know the number of work groups to pack the queue groups
7336	**  into. The queue groups in 'Queue' are sorted from highest
7337	**  to lowest for the number of runners per queue group.
7338	**  We put the queue groups with the largest number of runners
7339	**  into work groups first. Then the smaller ones are fitted in
7340	**  where it looks best.
7341	*/
7342
7343	j = 0;
7344	dir = 1;
7345	for (i = 0; i < NumQueue; i++)
7346	{
7347		/* a to-and-fro packing scheme, continue from last position */
7348		if (j >= NumWorkGroups)
7349		{
7350			dir = -1;
7351			j = NumWorkGroups - 1;
7352		}
7353		else if (j < 0)
7354		{
7355			j = 0;
7356			dir = 1;
7357		}
7358
7359		if (WorkGrp[j].wg_qgs == NULL)
7360			WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_malloc(sizeof(QUEUEGRP *) *
7361							(WorkGrp[j].wg_numqgrp + 1));
7362		else
7363			WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_realloc(WorkGrp[j].wg_qgs,
7364							sizeof(QUEUEGRP *) *
7365							(WorkGrp[j].wg_numqgrp + 1));
7366		if (WorkGrp[j].wg_qgs == NULL)
7367		{
7368			syserr("!cannot allocate memory for work queues, need %d bytes",
7369			       (int) (sizeof(QUEUEGRP *) *
7370				      (WorkGrp[j].wg_numqgrp + 1)));
7371		}
7372
7373		WorkGrp[j].wg_qgs[WorkGrp[j].wg_numqgrp] = Queue[si[i].sg_idx];
7374		WorkGrp[j].wg_numqgrp++;
7375		WorkGrp[j].wg_runners += Queue[i]->qg_maxqrun;
7376		Queue[si[i].sg_idx]->qg_wgrp = j;
7377
7378		if (WorkGrp[j].wg_maxact == 0)
7379		{
7380			/* can't have more runners than allowed total */
7381			if (MaxQueueChildren > 0 &&
7382			    Queue[i]->qg_maxqrun > MaxQueueChildren)
7383				Queue[i]->qg_maxqrun = MaxQueueChildren;
7384			WorkGrp[j].wg_maxact = Queue[i]->qg_maxqrun;
7385		}
7386
7387		/*
7388		**  XXX: must wg_lowqintvl be the GCD?
7389		**  qg1: 2m, qg2: 3m, minimum: 2m, when do queue runs for
7390		**  qg2 occur?
7391		*/
7392
7393		/* keep track of the lowest interval for a persistent runner */
7394		if (Queue[si[i].sg_idx]->qg_queueintvl > 0 &&
7395		    WorkGrp[j].wg_lowqintvl < Queue[si[i].sg_idx]->qg_queueintvl)
7396			WorkGrp[j].wg_lowqintvl = Queue[si[i].sg_idx]->qg_queueintvl;
7397		j += dir;
7398	}
7399	if (tTd(41, 9))
7400	{
7401		for (i = 0; i < NumWorkGroups; i++)
7402		{
7403			sm_dprintf("Workgroup[%d]=", i);
7404			for (j = 0; j < WorkGrp[i].wg_numqgrp; j++)
7405			{
7406				sm_dprintf("%s, ",
7407					WorkGrp[i].wg_qgs[j]->qg_name);
7408			}
7409			sm_dprintf("\n");
7410		}
7411	}
7412}
7413
7414/*
7415**  DUP_DF -- duplicate envelope data file
7416**
7417**	Copy the data file from the 'old' envelope to the 'new' envelope
7418**	in the most efficient way possible.
7419**
7420**	Create a hard link from the 'old' data file to the 'new' data file.
7421**	If the old and new queue directories are on different file systems,
7422**	then the new data file link is created in the old queue directory,
7423**	and the new queue file will contain a 'd' record pointing to the
7424**	directory containing the new data file.
7425**
7426**	Parameters:
7427**		old -- old envelope.
7428**		new -- new envelope.
7429**
7430**	Results:
7431**		Returns true on success, false on failure.
7432**
7433**	Side Effects:
7434**		On success, the new data file is created.
7435**		On fatal failure, EF_FATALERRS is set in old->e_flags.
7436*/
7437
7438static bool	dup_df __P((ENVELOPE *, ENVELOPE *));
7439
7440static bool
7441dup_df(old, new)
7442	ENVELOPE *old;
7443	ENVELOPE *new;
7444{
7445	int ofs, nfs, r;
7446	char opath[MAXPATHLEN];
7447	char npath[MAXPATHLEN];
7448
7449	if (!bitset(EF_HAS_DF, old->e_flags))
7450	{
7451		/*
7452		**  this can happen if: SuperSafe != True
7453		**  and a bounce mail is sent that is split.
7454		*/
7455
7456		queueup(old, false, true);
7457	}
7458	SM_REQUIRE(ISVALIDQGRP(old->e_qgrp) && ISVALIDQDIR(old->e_qdir));
7459	SM_REQUIRE(ISVALIDQGRP(new->e_qgrp) && ISVALIDQDIR(new->e_qdir));
7460
7461	(void) sm_strlcpy(opath, queuename(old, DATAFL_LETTER), sizeof opath);
7462	(void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof npath);
7463
7464	if (old->e_dfp != NULL)
7465	{
7466		r = sm_io_setinfo(old->e_dfp, SM_BF_COMMIT, NULL);
7467		if (r < 0 && errno != EINVAL)
7468		{
7469			syserr("@can't commit %s", opath);
7470			old->e_flags |= EF_FATALERRS;
7471			return false;
7472		}
7473	}
7474
7475	/*
7476	**  Attempt to create a hard link, if we think both old and new
7477	**  are on the same file system, otherwise copy the file.
7478	**
7479	**  Don't waste time attempting a hard link unless old and new
7480	**  are on the same file system.
7481	*/
7482
7483	ofs = Queue[old->e_qgrp]->qg_qpaths[old->e_qdir].qp_fsysidx;
7484	nfs = Queue[new->e_qgrp]->qg_qpaths[new->e_qdir].qp_fsysidx;
7485	if (FILE_SYS_DEV(ofs) == FILE_SYS_DEV(nfs))
7486	{
7487		if (link(opath, npath) == 0)
7488		{
7489			new->e_flags |= EF_HAS_DF;
7490			SYNC_DIR(npath, true);
7491			return true;
7492		}
7493		goto error;
7494	}
7495
7496	/*
7497	**  Can't link across queue directories, so try to create a hard
7498	**  link in the same queue directory as the old df file.
7499	**  The qf file will refer to the new df file using a 'd' record.
7500	*/
7501
7502	new->e_dfqgrp = old->e_dfqgrp;
7503	new->e_dfqdir = old->e_dfqdir;
7504	(void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof npath);
7505	if (link(opath, npath) == 0)
7506	{
7507		new->e_flags |= EF_HAS_DF;
7508		SYNC_DIR(npath, true);
7509		return true;
7510	}
7511
7512  error:
7513	if (LogLevel > 0)
7514		sm_syslog(LOG_ERR, old->e_id,
7515			  "dup_df: can't link %s to %s, error=%s, envelope splitting failed",
7516			  opath, npath, sm_errstring(errno));
7517	return false;
7518}
7519
7520/*
7521**  SPLIT_ENV -- Allocate a new envelope based on a given envelope.
7522**
7523**	Parameters:
7524**		e -- envelope.
7525**		sendqueue -- sendqueue for new envelope.
7526**		qgrp -- index of queue group.
7527**		qdir -- queue directory.
7528**
7529**	Results:
7530**		new envelope.
7531**
7532*/
7533
7534static ENVELOPE	*split_env __P((ENVELOPE *, ADDRESS *, int, int));
7535
7536static ENVELOPE *
7537split_env(e, sendqueue, qgrp, qdir)
7538	ENVELOPE *e;
7539	ADDRESS *sendqueue;
7540	int qgrp;
7541	int qdir;
7542{
7543	ENVELOPE *ee;
7544
7545	ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool, sizeof *ee);
7546	STRUCTCOPY(*e, *ee);
7547	ee->e_message = NULL;	/* XXX use original message? */
7548	ee->e_id = NULL;
7549	assign_queueid(ee);
7550	ee->e_sendqueue = sendqueue;
7551	ee->e_flags &= ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS
7552			 |EF_SENDRECEIPT|EF_RET_PARAM|EF_HAS_DF);
7553	ee->e_flags |= EF_NORECEIPT;	/* XXX really? */
7554	ee->e_from.q_state = QS_SENDER;
7555	ee->e_dfp = NULL;
7556	ee->e_lockfp = NULL;
7557	if (e->e_xfp != NULL)
7558		ee->e_xfp = sm_io_dup(e->e_xfp);
7559
7560	/* failed to dup e->e_xfp, start a new transcript */
7561	if (ee->e_xfp == NULL)
7562		openxscript(ee);
7563
7564	ee->e_qgrp = ee->e_dfqgrp = qgrp;
7565	ee->e_qdir = ee->e_dfqdir = qdir;
7566	ee->e_errormode = EM_MAIL;
7567	ee->e_statmsg = NULL;
7568#if _FFR_QUARANTINE
7569	if (e->e_quarmsg != NULL)
7570		ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool,
7571						  e->e_quarmsg);
7572#endif /* _FFR_QUARANTINE */
7573
7574	/*
7575	**  XXX Not sure if this copying is necessary.
7576	**  sendall() does this copying, but I (dm) don't know if that is
7577	**  because of the storage management discipline we were using
7578	**  before rpools were introduced, or if it is because these lists
7579	**  can be modified later.
7580	*/
7581
7582	ee->e_header = copyheader(e->e_header, ee->e_rpool);
7583	ee->e_errorqueue = copyqueue(e->e_errorqueue, ee->e_rpool);
7584
7585	return ee;
7586}
7587
7588/* return values from split functions, check also below! */
7589#define SM_SPLIT_FAIL	(0)
7590#define SM_SPLIT_NONE	(1)
7591#define SM_SPLIT_NEW(n)	(1 + (n))
7592
7593/*
7594**  SPLIT_ACROSS_QUEUE_GROUPS
7595**
7596**	This function splits an envelope across multiple queue groups
7597**	based on the queue group of each recipient.
7598**
7599**	Parameters:
7600**		e -- envelope.
7601**
7602**	Results:
7603**		SM_SPLIT_FAIL on failure
7604**		SM_SPLIT_NONE if no splitting occurred,
7605**		or 1 + the number of additional envelopes created.
7606**
7607**	Side Effects:
7608**		On success, e->e_sibling points to a list of zero or more
7609**		additional envelopes, and the associated data files exist
7610**		on disk.  But the queue files are not created.
7611**
7612**		On failure, e->e_sibling is not changed.
7613**		The order of recipients in e->e_sendqueue is permuted.
7614**		Abandoned data files for additional envelopes that failed
7615**		to be created may exist on disk.
7616*/
7617
7618static int	q_qgrp_compare __P((const void *, const void *));
7619static int	e_filesys_compare __P((const void *, const void *));
7620
7621static int
7622q_qgrp_compare(p1, p2)
7623	const void *p1;
7624	const void *p2;
7625{
7626	ADDRESS **pq1 = (ADDRESS **) p1;
7627	ADDRESS **pq2 = (ADDRESS **) p2;
7628
7629	return (*pq1)->q_qgrp - (*pq2)->q_qgrp;
7630}
7631
7632static int
7633e_filesys_compare(p1, p2)
7634	const void *p1;
7635	const void *p2;
7636{
7637	ENVELOPE **pe1 = (ENVELOPE **) p1;
7638	ENVELOPE **pe2 = (ENVELOPE **) p2;
7639	int fs1, fs2;
7640
7641	fs1 = Queue[(*pe1)->e_qgrp]->qg_qpaths[(*pe1)->e_qdir].qp_fsysidx;
7642	fs2 = Queue[(*pe2)->e_qgrp]->qg_qpaths[(*pe2)->e_qdir].qp_fsysidx;
7643	if (FILE_SYS_DEV(fs1) < FILE_SYS_DEV(fs2))
7644		return -1;
7645	if (FILE_SYS_DEV(fs1) > FILE_SYS_DEV(fs2))
7646		return 1;
7647	return 0;
7648}
7649
7650static int
7651split_across_queue_groups(e)
7652	ENVELOPE *e;
7653{
7654	int naddrs, nsplits, i;
7655	char **pvp;
7656	ADDRESS *q, **addrs;
7657	ENVELOPE *ee, *es;
7658	ENVELOPE *splits[MAXQUEUEGROUPS];
7659	char pvpbuf[PSBUFSIZE];
7660
7661	SM_REQUIRE(ISVALIDQGRP(e->e_qgrp));
7662
7663	/* Count addresses and assign queue groups. */
7664	naddrs = 0;
7665	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
7666	{
7667		if (QS_IS_DEAD(q->q_state))
7668			continue;
7669		++naddrs;
7670
7671		/* bad addresses and those already sent stay put */
7672		if (QS_IS_BADADDR(q->q_state) ||
7673		    QS_IS_SENT(q->q_state))
7674			q->q_qgrp = e->e_qgrp;
7675		else if (!ISVALIDQGRP(q->q_qgrp))
7676		{
7677			/* call ruleset which should return a queue group */
7678			i = rscap(RS_QUEUEGROUP, q->q_user, NULL, e, &pvp,
7679				  pvpbuf, sizeof(pvpbuf));
7680			if (i == EX_OK &&
7681			    pvp != NULL && pvp[0] != NULL &&
7682			    (pvp[0][0] & 0377) == CANONNET &&
7683			    pvp[1] != NULL && pvp[1][0] != '\0')
7684			{
7685				i = name2qid(pvp[1]);
7686				if (ISVALIDQGRP(i))
7687				{
7688					q->q_qgrp = i;
7689					if (tTd(20, 4))
7690						sm_syslog(LOG_INFO, NOQID,
7691							"queue group name %s -> %d",
7692							pvp[1], i);
7693					continue;
7694				}
7695				else if (LogLevel > 10)
7696					sm_syslog(LOG_INFO, NOQID,
7697						"can't find queue group name %s, selection ignored",
7698						pvp[1]);
7699			}
7700			if (q->q_mailer != NULL &&
7701			    ISVALIDQGRP(q->q_mailer->m_qgrp))
7702				q->q_qgrp = q->q_mailer->m_qgrp;
7703			else if (ISVALIDQGRP(e->e_qgrp))
7704				q->q_qgrp = e->e_qgrp;
7705			else
7706				q->q_qgrp = 0;
7707		}
7708	}
7709
7710	/* only one address? nothing to split. */
7711	if (naddrs <= 1)
7712		return SM_SPLIT_NONE;
7713
7714	/* sort the addresses by queue group */
7715	addrs = sm_rpool_malloc_x(e->e_rpool, naddrs * sizeof(ADDRESS *));
7716	for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next)
7717	{
7718		if (QS_IS_DEAD(q->q_state))
7719			continue;
7720		addrs[i++] = q;
7721	}
7722	qsort(addrs, naddrs, sizeof(ADDRESS *), q_qgrp_compare);
7723
7724	/* split into multiple envelopes, by queue group */
7725	nsplits = 0;
7726	es = NULL;
7727	e->e_sendqueue = NULL;
7728	for (i = 0; i < naddrs; ++i)
7729	{
7730		if (i == naddrs - 1 || addrs[i]->q_qgrp != addrs[i + 1]->q_qgrp)
7731			addrs[i]->q_next = NULL;
7732		else
7733			addrs[i]->q_next = addrs[i + 1];
7734
7735		/* same queue group as original envelope? */
7736		if (addrs[i]->q_qgrp == e->e_qgrp)
7737		{
7738			if (e->e_sendqueue == NULL)
7739				e->e_sendqueue = addrs[i];
7740			continue;
7741		}
7742
7743		/* different queue group than original envelope */
7744		if (es == NULL || addrs[i]->q_qgrp != es->e_qgrp)
7745		{
7746			ee = split_env(e, addrs[i], addrs[i]->q_qgrp, NOQDIR);
7747			es = ee;
7748			splits[nsplits++] = ee;
7749		}
7750	}
7751
7752	/* no splits? return right now. */
7753	if (nsplits <= 0)
7754		return SM_SPLIT_NONE;
7755
7756	/* assign a queue directory to each additional envelope */
7757	for (i = 0; i < nsplits; ++i)
7758	{
7759		es = splits[i];
7760#if 0
7761		es->e_qdir = pickqdir(Queue[es->e_qgrp], es->e_msgsize, es);
7762#endif /* 0 */
7763		if (!setnewqueue(es))
7764			goto failure;
7765	}
7766
7767	/* sort the additional envelopes by queue file system */
7768	qsort(splits, nsplits, sizeof(ENVELOPE *), e_filesys_compare);
7769
7770	/* create data files for each additional envelope */
7771	if (!dup_df(e, splits[0]))
7772	{
7773		i = 0;
7774		goto failure;
7775	}
7776	for (i = 1; i < nsplits; ++i)
7777	{
7778		/* copy or link to the previous data file */
7779		if (!dup_df(splits[i - 1], splits[i]))
7780			goto failure;
7781	}
7782
7783	/* success: prepend the new envelopes to the e->e_sibling list */
7784	for (i = 0; i < nsplits; ++i)
7785	{
7786		es = splits[i];
7787		es->e_sibling = e->e_sibling;
7788		e->e_sibling = es;
7789	}
7790	return SM_SPLIT_NEW(nsplits);
7791
7792	/* failure: clean up */
7793  failure:
7794	if (i > 0)
7795	{
7796		int j;
7797
7798		for (j = 0; j < i; j++)
7799			(void) unlink(queuename(splits[j], DATAFL_LETTER));
7800	}
7801	e->e_sendqueue = addrs[0];
7802	for (i = 0; i < naddrs - 1; ++i)
7803		addrs[i]->q_next = addrs[i + 1];
7804	addrs[naddrs - 1]->q_next = NULL;
7805	return SM_SPLIT_FAIL;
7806}
7807
7808/*
7809**  SPLIT_WITHIN_QUEUE
7810**
7811**	Split an envelope with multiple recipients into several
7812**	envelopes within the same queue directory, if the number of
7813**	recipients exceeds the limit for the queue group.
7814**
7815**	Parameters:
7816**		e -- envelope.
7817**
7818**	Results:
7819**		SM_SPLIT_FAIL on failure
7820**		SM_SPLIT_NONE if no splitting occurred,
7821**		or 1 + the number of additional envelopes created.
7822*/
7823
7824#define SPLIT_LOG_LEVEL	8
7825
7826static int	split_within_queue __P((ENVELOPE *));
7827
7828static int
7829split_within_queue(e)
7830	ENVELOPE *e;
7831{
7832	int maxrcpt, nrcpt, ndead, nsplit, i;
7833	int j, l;
7834	char *lsplits;
7835	ADDRESS *q, **addrs;
7836	ENVELOPE *ee, *firstsibling;
7837
7838	if (!ISVALIDQGRP(e->e_qgrp) || bitset(EF_SPLIT, e->e_flags))
7839		return SM_SPLIT_NONE;
7840
7841	/* don't bother if there is no recipient limit */
7842	maxrcpt = Queue[e->e_qgrp]->qg_maxrcpt;
7843	if (maxrcpt <= 0)
7844		return SM_SPLIT_NONE;
7845
7846	/* count recipients */
7847	nrcpt = 0;
7848	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
7849	{
7850		if (QS_IS_DEAD(q->q_state))
7851			continue;
7852		++nrcpt;
7853	}
7854	if (nrcpt <= maxrcpt)
7855		return SM_SPLIT_NONE;
7856
7857	/*
7858	**  Preserve the recipient list
7859	**  so that we can restore it in case of error.
7860	**  (But we discard dead addresses.)
7861	*/
7862
7863	addrs = sm_rpool_malloc_x(e->e_rpool, nrcpt * sizeof(ADDRESS *));
7864	for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next)
7865	{
7866		if (QS_IS_DEAD(q->q_state))
7867			continue;
7868		addrs[i++] = q;
7869	}
7870
7871	/*
7872	**  Partition the recipient list so that bad and sent addresses
7873	**  come first. These will go with the original envelope, and
7874	**  do not count towards the maxrcpt limit.
7875	**  addrs[] does not contain QS_IS_DEAD() addresses.
7876	*/
7877
7878	ndead = 0;
7879	for (i = 0; i < nrcpt; ++i)
7880	{
7881		if (QS_IS_BADADDR(addrs[i]->q_state) ||
7882		    QS_IS_SENT(addrs[i]->q_state) ||
7883		    QS_IS_DEAD(addrs[i]->q_state)) /* for paranoia's sake */
7884		{
7885			if (i > ndead)
7886			{
7887				ADDRESS *tmp = addrs[i];
7888
7889				addrs[i] = addrs[ndead];
7890				addrs[ndead] = tmp;
7891			}
7892			++ndead;
7893		}
7894	}
7895
7896	/* Check if no splitting required. */
7897	if (nrcpt - ndead <= maxrcpt)
7898		return SM_SPLIT_NONE;
7899
7900	/* fix links */
7901	for (i = 0; i < nrcpt - 1; ++i)
7902		addrs[i]->q_next = addrs[i + 1];
7903	addrs[nrcpt - 1]->q_next = NULL;
7904	e->e_sendqueue = addrs[0];
7905
7906	/* prepare buffer for logging */
7907	if (LogLevel > SPLIT_LOG_LEVEL)
7908	{
7909		l = MAXLINE;
7910		lsplits = sm_malloc(l);
7911		if (lsplits != NULL)
7912			*lsplits = '\0';
7913		j = 0;
7914	}
7915	else
7916	{
7917		/* get rid of stupid compiler warnings */
7918		lsplits = NULL;
7919		j = l = 0;
7920	}
7921
7922	/* split the envelope */
7923	firstsibling = e->e_sibling;
7924	i = maxrcpt + ndead;
7925	nsplit = 0;
7926	for (;;)
7927	{
7928		addrs[i - 1]->q_next = NULL;
7929		ee = split_env(e, addrs[i], e->e_qgrp, e->e_qdir);
7930		if (!dup_df(e, ee))
7931		{
7932
7933			ee = firstsibling;
7934			while (ee != NULL)
7935			{
7936				(void) unlink(queuename(ee, DATAFL_LETTER));
7937				ee = ee->e_sibling;
7938			}
7939
7940			/* Error.  Restore e's sibling & recipient lists. */
7941			e->e_sibling = firstsibling;
7942			for (i = 0; i < nrcpt - 1; ++i)
7943				addrs[i]->q_next = addrs[i + 1];
7944			return SM_SPLIT_FAIL;
7945		}
7946
7947		/* prepend the new envelope to e->e_sibling */
7948		ee->e_sibling = e->e_sibling;
7949		e->e_sibling = ee;
7950		++nsplit;
7951		if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
7952		{
7953			if (j >= l - strlen(ee->e_id) - 3)
7954			{
7955				char *p;
7956
7957				l += MAXLINE;
7958				p = sm_realloc(lsplits, l);
7959				if (p == NULL)
7960				{
7961					/* let's try to get this done */
7962					sm_free(lsplits);
7963					lsplits = NULL;
7964				}
7965				else
7966					lsplits = p;
7967			}
7968			if (lsplits != NULL)
7969			{
7970				if (j == 0)
7971					j += sm_strlcat(lsplits + j,
7972							ee->e_id,
7973							l - j);
7974				else
7975					j += sm_strlcat2(lsplits + j,
7976							 "; ",
7977							 ee->e_id,
7978							 l - j);
7979				SM_ASSERT(j < l);
7980			}
7981		}
7982		if (nrcpt - i <= maxrcpt)
7983			break;
7984		i += maxrcpt;
7985	}
7986	if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL && nsplit > 0)
7987	{
7988		sm_syslog(LOG_NOTICE, e->e_id,
7989			  "split: maxrcpts=%d, rcpts=%d, count=%d, id%s=%s",
7990			  maxrcpt, nrcpt - ndead, nsplit,
7991			  nsplit > 1 ? "s" : "", lsplits);
7992		sm_free(lsplits);
7993	}
7994	return SM_SPLIT_NEW(nsplit);
7995}
7996/*
7997**  SPLIT_BY_RECIPIENT
7998**
7999**	Split an envelope with multiple recipients into multiple
8000**	envelopes as required by the sendmail configuration.
8001**
8002**	Parameters:
8003**		e -- envelope.
8004**
8005**	Results:
8006**		Returns true on success, false on failure.
8007**
8008**	Side Effects:
8009**		see split_across_queue_groups(), split_within_queue(e)
8010*/
8011
8012bool
8013split_by_recipient(e)
8014	ENVELOPE *e;
8015{
8016	int split, n, i, j, l;
8017	char *lsplits;
8018	ENVELOPE *ee, *next, *firstsibling;
8019
8020	if (OpMode == SM_VERIFY || !ISVALIDQGRP(e->e_qgrp) ||
8021	    bitset(EF_SPLIT, e->e_flags))
8022		return true;
8023	n = split_across_queue_groups(e);
8024	if (n == SM_SPLIT_FAIL)
8025		return false;
8026	firstsibling = ee = e->e_sibling;
8027	if (n > 1 && LogLevel > SPLIT_LOG_LEVEL)
8028	{
8029		l = MAXLINE;
8030		lsplits = sm_malloc(l);
8031		if (lsplits != NULL)
8032			*lsplits = '\0';
8033		j = 0;
8034	}
8035	else
8036	{
8037		/* get rid of stupid compiler warnings */
8038		lsplits = NULL;
8039		j = l = 0;
8040	}
8041	for (i = 1; i < n; ++i)
8042	{
8043		next = ee->e_sibling;
8044		if (split_within_queue(ee) == SM_SPLIT_FAIL)
8045		{
8046			e->e_sibling = firstsibling;
8047			return false;
8048		}
8049		ee->e_flags |= EF_SPLIT;
8050		if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
8051		{
8052			if (j >= l - strlen(ee->e_id) - 3)
8053			{
8054				char *p;
8055
8056				l += MAXLINE;
8057				p = sm_realloc(lsplits, l);
8058				if (p == NULL)
8059				{
8060					/* let's try to get this done */
8061					sm_free(lsplits);
8062					lsplits = NULL;
8063				}
8064				else
8065					lsplits = p;
8066			}
8067			if (lsplits != NULL)
8068			{
8069				if (j == 0)
8070					j += sm_strlcat(lsplits + j,
8071							ee->e_id, l - j);
8072				else
8073					j += sm_strlcat2(lsplits + j, "; ",
8074							 ee->e_id, l - j);
8075				SM_ASSERT(j < l);
8076			}
8077		}
8078		ee = next;
8079	}
8080	if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL && n > 1)
8081	{
8082		sm_syslog(LOG_NOTICE, e->e_id, "split: count=%d, id%s=%s",
8083			  n - 1, n > 2 ? "s" : "", lsplits);
8084		sm_free(lsplits);
8085	}
8086	split = split_within_queue(e) != SM_SPLIT_FAIL;
8087	if (split)
8088		e->e_flags |= EF_SPLIT;
8089	return split;
8090}
8091
8092#if _FFR_QUARANTINE
8093/*
8094**  QUARANTINE_QUEUE_ITEM -- {un,}quarantine a single envelope
8095**
8096**	Add/remove quarantine reason and requeue appropriately.
8097**
8098**	Parameters:
8099**		qgrp -- queue group for the item
8100**		qdir -- queue directory in the given queue group
8101**		e -- envelope information for the item
8102**		reason -- quarantine reason, NULL means unquarantine.
8103**
8104**	Results:
8105**		true if item changed, false otherwise
8106**
8107**	Side Effects:
8108**		Changes quarantine tag in queue file and renames it.
8109*/
8110
8111static bool
8112quarantine_queue_item(qgrp, qdir, e, reason)
8113	int qgrp;
8114	int qdir;
8115	ENVELOPE *e;
8116	char *reason;
8117{
8118	bool dirty = false;
8119	bool failing = false;
8120	bool foundq = false;
8121	bool finished = false;
8122	int fd;
8123	int flags;
8124	int oldtype;
8125	int newtype;
8126	int save_errno;
8127	MODE_T oldumask = 0;
8128	SM_FILE_T *oldqfp, *tempqfp;
8129	char *bp;
8130	char oldqf[MAXPATHLEN];
8131	char tempqf[MAXPATHLEN];
8132	char newqf[MAXPATHLEN];
8133	char buf[MAXLINE];
8134
8135	oldtype = queue_letter(e, ANYQFL_LETTER);
8136	(void) sm_strlcpy(oldqf, queuename(e, ANYQFL_LETTER), sizeof oldqf);
8137	(void) sm_strlcpy(tempqf, queuename(e, NEWQFL_LETTER), sizeof tempqf);
8138
8139	/*
8140	**  Instead of duplicating all the open
8141	**  and lock code here, tell readqf() to
8142	**  do that work and return the open
8143	**  file pointer in e_lockfp.  Note that
8144	**  we must release the locks properly when
8145	**  we are done.
8146	*/
8147
8148	if (!readqf(e, true))
8149	{
8150		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8151				     "Skipping %s\n", qid_printname(e));
8152		return false;
8153	}
8154	oldqfp = e->e_lockfp;
8155
8156	/* open the new queue file */
8157	flags = O_CREAT|O_WRONLY|O_EXCL;
8158	if (bitset(S_IWGRP, QueueFileMode))
8159		oldumask = umask(002);
8160	fd = open(tempqf, flags, QueueFileMode);
8161	if (bitset(S_IWGRP, QueueFileMode))
8162		(void) umask(oldumask);
8163	RELEASE_QUEUE;
8164
8165	if (fd < 0)
8166	{
8167		save_errno = errno;
8168		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8169				     "Skipping %s: Could not open %s: %s\n",
8170				     qid_printname(e), tempqf,
8171				     sm_errstring(save_errno));
8172		(void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8173		return false;
8174	}
8175	if (!lockfile(fd, tempqf, NULL, LOCK_EX|LOCK_NB))
8176	{
8177		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8178				     "Skipping %s: Could not lock %s\n",
8179				     qid_printname(e), tempqf);
8180		(void) close(fd);
8181		(void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8182		return false;
8183	}
8184
8185	tempqfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &fd,
8186			     SM_IO_WRONLY, NULL);
8187	if (tempqfp == NULL)
8188	{
8189		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8190				     "Skipping %s: Could not lock %s\n",
8191				     qid_printname(e), tempqf);
8192		(void) close(fd);
8193		(void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8194		return false;
8195	}
8196
8197	/* Copy the data over, changing the quarantine reason */
8198	while ((bp = fgetfolded(buf, sizeof buf, oldqfp)) != NULL)
8199	{
8200		if (tTd(40, 4))
8201			sm_dprintf("+++++ %s\n", bp);
8202		switch (bp[0])
8203		{
8204		  case 'q':		/* quarantine reason */
8205			foundq = true;
8206			if (reason == NULL)
8207			{
8208				if (Verbose)
8209				{
8210					(void) sm_io_fprintf(smioout,
8211							     SM_TIME_DEFAULT,
8212							     "%s: Removed quarantine of \"%s\"\n",
8213							     e->e_id, &bp[1]);
8214				}
8215				sm_syslog(LOG_INFO, e->e_id, "unquarantine");
8216				dirty = true;
8217				continue;
8218			}
8219			else if (strcmp(reason, &bp[1]) == 0)
8220			{
8221				if (Verbose)
8222				{
8223					(void) sm_io_fprintf(smioout,
8224							     SM_TIME_DEFAULT,
8225							     "%s: Already quarantined with \"%s\"\n",
8226							     e->e_id, reason);
8227				}
8228				(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8229						     "q%s\n", reason);
8230			}
8231			else
8232			{
8233				if (Verbose)
8234				{
8235					(void) sm_io_fprintf(smioout,
8236							     SM_TIME_DEFAULT,
8237							     "%s: Quarantine changed from \"%s\" to \"%s\"\n",
8238							     e->e_id, &bp[1],
8239							     reason);
8240				}
8241				(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8242						     "q%s\n", reason);
8243				sm_syslog(LOG_INFO, e->e_id, "quarantine=%s",
8244					  reason);
8245				dirty = true;
8246			}
8247			break;
8248
8249		  case 'R':
8250			/*
8251			**  If we are quarantining an unquarantined item,
8252			**  need to put in a new 'q' line before it's
8253			**  too late.
8254			*/
8255
8256			if (!foundq && reason != NULL)
8257			{
8258				if (Verbose)
8259				{
8260					(void) sm_io_fprintf(smioout,
8261							     SM_TIME_DEFAULT,
8262							     "%s: Quarantined with \"%s\"\n",
8263							     e->e_id, reason);
8264				}
8265				(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8266						     "q%s\n", reason);
8267				sm_syslog(LOG_INFO, e->e_id, "quarantine=%s",
8268					  reason);
8269				foundq = true;
8270				dirty = true;
8271			}
8272
8273			/* Copy the line to the new file */
8274			(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8275					     "%s\n", bp);
8276			break;
8277
8278		  case '.':
8279			finished = true;
8280			/* FALLTHROUGH */
8281
8282		  default:
8283			/* Copy the line to the new file */
8284			(void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
8285					     "%s\n", bp);
8286			break;
8287		}
8288	}
8289
8290	/* Make sure we read the whole old file */
8291	errno = sm_io_error(tempqfp);
8292	if (errno != 0 && errno != SM_IO_EOF)
8293	{
8294		save_errno = errno;
8295		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8296				     "Skipping %s: Error reading %s: %s\n",
8297				     qid_printname(e), oldqf,
8298				     sm_errstring(save_errno));
8299		failing = true;
8300	}
8301
8302	if (!failing && !finished)
8303	{
8304		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8305				     "Skipping %s: Incomplete file: %s\n",
8306				     qid_printname(e), oldqf);
8307		failing = true;
8308	}
8309
8310	/* Check if we actually changed anything or we can just bail now */
8311	if (!dirty)
8312	{
8313		/* pretend we failed, even though we technically didn't */
8314		failing = true;
8315	}
8316
8317	/* Make sure we wrote things out safely */
8318	if (!failing &&
8319	    (sm_io_flush(tempqfp, SM_TIME_DEFAULT) != 0 ||
8320	     ((SuperSafe == SAFE_REALLY || SuperSafe == SAFE_INTERACTIVE) &&
8321	      fsync(sm_io_getinfo(tempqfp, SM_IO_WHAT_FD, NULL)) < 0) ||
8322	     ((errno = sm_io_error(tempqfp)) != 0)))
8323	{
8324		save_errno = errno;
8325		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8326				     "Skipping %s: Error writing %s: %s\n",
8327				     qid_printname(e), tempqf,
8328				     sm_errstring(save_errno));
8329		failing = true;
8330	}
8331
8332
8333	/* Figure out the new filename */
8334	newtype = (reason == NULL ? NORMQF_LETTER : QUARQF_LETTER);
8335	if (oldtype == newtype)
8336	{
8337		/* going to rename tempqf to oldqf */
8338		(void) sm_strlcpy(newqf, oldqf, sizeof newqf);
8339	}
8340	else
8341	{
8342		/* going to rename tempqf to new name based on newtype */
8343		(void) sm_strlcpy(newqf, queuename(e, newtype), sizeof newqf);
8344	}
8345
8346	save_errno = 0;
8347
8348	/* rename tempqf to newqf */
8349	if (!failing &&
8350	    rename(tempqf, newqf) < 0)
8351		save_errno = (errno == 0) ? EINVAL : errno;
8352
8353	/* Check rename() success */
8354	if (!failing && save_errno != 0)
8355	{
8356		sm_syslog(LOG_DEBUG, e->e_id,
8357			  "quarantine_queue_item: rename(%s, %s): %s",
8358			  tempqf, newqf, sm_errstring(save_errno));
8359
8360		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8361				     "Error renaming %s to %s: %s\n",
8362				     tempqf, newqf,
8363				     sm_errstring(save_errno));
8364		if (oldtype == newtype)
8365		{
8366			/*
8367			**  Bail here since we don't know the state of
8368			**  the filesystem and may need to keep tempqf
8369			**  for the user to rescue us.
8370			*/
8371
8372			RELEASE_QUEUE;
8373			errno = save_errno;
8374			syserr("!452 Error renaming control file %s", tempqf);
8375			/* NOTREACHED */
8376		}
8377		else
8378		{
8379			/* remove new file (if rename() half completed) */
8380			if (xunlink(newqf) < 0)
8381			{
8382				save_errno = errno;
8383				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8384						     "Error removing %s: %s\n",
8385						     newqf,
8386						     sm_errstring(save_errno));
8387			}
8388
8389			/* tempqf removed below */
8390			failing = true;
8391		}
8392
8393	}
8394
8395	/* If changing file types, need to remove old type */
8396	if (!failing && oldtype != newtype)
8397	{
8398		if (xunlink(oldqf) < 0)
8399		{
8400			save_errno = errno;
8401			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8402					     "Error removing %s: %s\n",
8403					     oldqf, sm_errstring(save_errno));
8404		}
8405	}
8406
8407	/* see if anything above failed */
8408	if (failing)
8409	{
8410		/* Something failed: remove new file, old file still there */
8411		(void) xunlink(tempqf);
8412	}
8413
8414	/*
8415	**  fsync() after file operations to make sure metadata is
8416	**  written to disk on filesystems in which renames are
8417	**  not guaranteed.  It's ok if they fail, mail won't be lost.
8418	*/
8419
8420	if (SuperSafe != SAFE_NO)
8421	{
8422		/* for soft-updates */
8423		(void) fsync(sm_io_getinfo(tempqfp,
8424					   SM_IO_WHAT_FD, NULL));
8425
8426		if (!failing)
8427		{
8428			/* for soft-updates */
8429			(void) fsync(sm_io_getinfo(oldqfp,
8430						   SM_IO_WHAT_FD, NULL));
8431		}
8432
8433		/* for other odd filesystems */
8434		SYNC_DIR(tempqf, false);
8435	}
8436
8437	/* Close up shop */
8438	RELEASE_QUEUE;
8439	if (tempqfp != NULL)
8440		(void) sm_io_close(tempqfp, SM_TIME_DEFAULT);
8441	if (oldqfp != NULL)
8442		(void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
8443
8444	/* All went well */
8445	return !failing;
8446}
8447
8448/*
8449**  QUARANTINE_QUEUE -- {un,}quarantine matching items in the queue
8450**
8451**	Read all matching queue items, add/remove quarantine
8452**	reason, and requeue appropriately.
8453**
8454**	Parameters:
8455**		reason -- quarantine reason, "." means unquarantine.
8456**		qgrplimit -- limit to single queue group unless NOQGRP
8457**
8458**	Results:
8459**		none.
8460**
8461**	Side Effects:
8462**		Lots of changes to the queue.
8463*/
8464
8465void
8466quarantine_queue(reason, qgrplimit)
8467	char *reason;
8468	int qgrplimit;
8469{
8470	int changed = 0;
8471	int qgrp;
8472
8473	/* Convert internal representation of unquarantine */
8474	if (reason != NULL && reason[0] == '.' && reason[1] == '\0')
8475		reason = NULL;
8476
8477	if (reason != NULL)
8478	{
8479		/* clean it */
8480		reason = newstr(denlstring(reason, true, true));
8481	}
8482
8483	for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++)
8484	{
8485		int qdir;
8486
8487		if (qgrplimit != NOQGRP && qgrplimit != qgrp)
8488			continue;
8489
8490		for (qdir = 0; qdir < Queue[qgrp]->qg_numqueues; qdir++)
8491		{
8492			int i;
8493			int nrequests;
8494
8495			if (StopRequest)
8496				stop_sendmail();
8497
8498			nrequests = gatherq(qgrp, qdir, true, NULL, NULL);
8499
8500			/* first see if there is anything */
8501			if (nrequests <= 0)
8502			{
8503				if (Verbose)
8504				{
8505					(void) sm_io_fprintf(smioout,
8506							     SM_TIME_DEFAULT, "%s: no matches\n",
8507							     qid_printqueue(qgrp, qdir));
8508				}
8509				continue;
8510			}
8511
8512			if (Verbose)
8513			{
8514				(void) sm_io_fprintf(smioout,
8515						     SM_TIME_DEFAULT, "Processing %s:\n",
8516						     qid_printqueue(qgrp, qdir));
8517			}
8518
8519			for (i = 0; i < WorkListCount; i++)
8520			{
8521				ENVELOPE e;
8522
8523				if (StopRequest)
8524					stop_sendmail();
8525
8526				/* setup envelope */
8527				clearenvelope(&e, true, sm_rpool_new_x(NULL));
8528				e.e_id = WorkList[i].w_name + 2;
8529				e.e_qgrp = qgrp;
8530				e.e_qdir = qdir;
8531
8532				if (tTd(70, 101))
8533				{
8534					sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8535						      "Would do %s\n", e.e_id);
8536					changed++;
8537				}
8538				else if (quarantine_queue_item(qgrp, qdir,
8539							       &e, reason))
8540					changed++;
8541
8542				/* clean up */
8543				sm_rpool_free(e.e_rpool);
8544				e.e_rpool = NULL;
8545			}
8546			if (WorkList != NULL)
8547				sm_free(WorkList); /* XXX */
8548			WorkList = NULL;
8549			WorkListSize = 0;
8550			WorkListCount = 0;
8551		}
8552	}
8553	if (Verbose)
8554	{
8555		if (changed == 0)
8556			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8557					     "No changes\n");
8558		else
8559			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
8560					     "%d change%s\n",
8561					     changed,
8562					     changed == 1 ? "" : "s");
8563	}
8564}
8565#endif /* _FFR_QUARANTINE */
8566