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