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