source: trunk/third/sendmail/sendmail/queue.c @ 19204

Revision 19204, 195.3 KB checked in by zacheiss, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19203, which included commits to RCS files with non-trunk default branches.
Line 
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
16SM_RCSID("@(#)$Id: queue.c,v 1.1.1.1 2003-04-08 15:09:15 zacheiss 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 */
34static 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
42static char     queue_letter __P((ENVELOPE *, int));
43static 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
52struct 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
66typedef struct work     WORK;
67
68static WORK     *WorkQ;         /* queue of things to be done */
69static 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
76static 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
87struct 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
99typedef struct workgrp WORKGRP;
100
101static WORKGRP  volatile WorkGrp[MAXWORKGROUPS + 1];    /* work groups */
102
103#if SM_HEAP_CHECK
104static 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
113static const char EmptyString[] = "";
114
115static void     grow_wlist __P((int, int));
116static int      multiqueue_cache __P((char *, int, QUEUEGRP *, int, unsigned int *));
117static int      gatherq __P((int, int, bool, bool *, bool *));
118static int      sortq __P((int));
119static void     printctladdr __P((ADDRESS *, SM_FILE_T *));
120static bool     readqf __P((ENVELOPE *, bool));
121static void     restart_work_group __P((int));
122static void     runner_work __P((ENVELOPE *, int, bool, int, int));
123static void     schedule_queue_runs __P((bool, int, bool));
124static char     *strrev __P((char *));
125static ADDRESS  *setctluser __P((char *, int, ENVELOPE *));
126#if _FFR_RHS
127static int      sm_strshufflecmp __P((char *, char *));
128static void     init_shuffle_alphabet __P(());
129#endif /* _FFR_RHS */
130static int      workcmpf0();
131static int      workcmpf1();
132static int      workcmpf2();
133static int      workcmpf3();
134static int      workcmpf4();
135static int      randi = 3;      /* index for workcmpf5() */
136static int      workcmpf5();
137static int      workcmpf6();
138#if _FFR_RHS
139static 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
154typedef struct filesys_shared   FILESYS;
155
156struct 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 */
164static FILESYS  FileSys[MAXFILESYS];    /* queue file systems */
165static 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
188typedef struct queue_shared     QUEUE_SHM_T;
189
190struct queue_shared
191{
192        int     qs_entries;     /* number of entries */
193        /* XXX more to follow? */
194};
195
196static void     *Pshm;          /* pointer to shared memory */
197static FILESYS  *PtrFileSys;    /* pointer to queue file system array */
198int             ShmId = SM_SHM_NO_ID;   /* shared memory id */
199static QUEUE_SHM_T      *QShm;          /* pointer to shared queue data */
200static 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))
217int     *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
227static 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
240static unsigned int
241hash_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
319void
320queueup(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
929static void
930printctladdr(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
1012static bool             volatile NoMoreRunners = false;
1013static sigfunc_t        Oldsh_term = SIG_DFL;
1014static sigfunc_t        Oldsh_hup = SIG_DFL;
1015static sigfunc_t        volatile Oldsh = SIG_DFL;
1016static bool             BlockOldsh = false;
1017static int              volatile Oldsig = 0;
1018static SIGFUNC_DECL     runners_sigterm __P((int));
1019static SIGFUNC_DECL     runners_sighup __P((int));
1020
1021static SIGFUNC_DECL
1022runners_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
1073static SIGFUNC_DECL
1074runners_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
1117void
1118mark_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
1145void
1146restart_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
1192static void
1193restart_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
1230static void
1231schedule_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
1319bool
1320checkqueuerunner()
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
1381static ENVELOPE QueueEnvelope;          /* the queue run envelope */
1382static time_t   LastQueueTime = 0;      /* last time a queue ID assigned */
1383static 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
1391bool
1392runqueue(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
1558static void
1559runner_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
1737bool
1738run_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
2243bool
2244doqueuerun()
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
2273void
2274runqueueevent()
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
2325static WORK     *WorkList = NULL;       /* list of unsort work */
2326static int      WorkListSize = 0;       /* current max size of WorkList */
2327static int      WorkListCount = 0;      /* # of work items in WorkList */
2328
2329static int
2330gatherq(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
2803static int
2804sortq(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
3005static void
3006grow_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
3060static int
3061workcmpf0(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
3091static int
3092workcmpf1(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
3130static int
3131workcmpf2(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
3167static int
3168workcmpf3(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
3193static int
3194workcmpf4(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 */
3212static int
3213workcmpf5(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
3235static int
3236workcmpf6(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
3264static int
3265workcmpf7(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
3302static char *
3303strrev(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
3322static unsigned char ShuffledAlphabet[NCHAR];
3323
3324void
3325init_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
3358static int
3359sm_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
3396pid_t
3397dowork(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
3585pid_t
3586doworklist(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
3769static bool
3770readqf(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
4461static void
4462prtstr(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
4501void
4502printnqe(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
4586void
4587printqueue()
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
4623int
4624print_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
4979static char
4980queue_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
5033char *
5034queuename(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
5162static const char QueueIdChars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx";
5163# define QIC_LEN        60
5164# define queuenextid() CurrentPid
5165
5166
5167void
5168assign_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
5258void
5259sync_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
5283void
5284unlockqueue(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
5324static ADDRESS *
5325setctluser(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
5407void
5408loseqfile(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
5457int
5458name2qid(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
5478char *
5479qid_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
5512char *
5513qid_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
5559int
5560pickqdir(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
5650bool
5651setnewqueue(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
5734static bool
5735chkqdir(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
5825static int
5826multiqueue_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
6152static 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
6158static short
6159filesys_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
6209static int filesys_setup __P((bool));
6210
6211static int
6212filesys_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
6255void
6256filesys_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
6307bool
6308filesys_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
6344void
6345disk_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
6389void
6390upd_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
6437static bool write_key_file __P((char *, long));
6438static 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
6454static bool
6455write_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
6495static long
6496read_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
6544static void init_shm __P((int, bool, unsigned int));
6545
6546static void
6547init_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
6699void
6700setup_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
6877void
6878cleanup_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
6903void
6904cleanup_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
6922void
6923set_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
6962void
6963makequeue(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
7208int
7209hashfqn(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
7254static time_t
7255queuedelay(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
7283struct sortqgrp
7284{
7285        int sg_idx;             /* original index */
7286        int sg_maxqrun;         /* max queue runners */
7287};
7288typedef struct sortqgrp SORTQGRP_T;
7289static int cmpidx __P((const void *, const void *));
7290
7291static int
7292cmpidx(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
7327void
7328makeworkgroups()
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
7494static bool     dup_df __P((ENVELOPE *, ENVELOPE *));
7495
7496static bool
7497dup_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
7590static ENVELOPE *split_env __P((ENVELOPE *, ADDRESS *, int, int));
7591
7592static ENVELOPE *
7593split_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
7674static int      q_qgrp_compare __P((const void *, const void *));
7675static int      e_filesys_compare __P((const void *, const void *));
7676
7677static int
7678q_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
7688static int
7689e_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
7706static int
7707split_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
7888static int      split_within_queue __P((ENVELOPE *));
7889
7890static int
7891split_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
8079bool
8080split_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
8178static bool
8179quarantine_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
8532void
8533quarantine_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 */
Note: See TracBrowser for help on using the repository browser.