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