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