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