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