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