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