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