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