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