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