17c478bd9Sstevel@tonic-gate /*
2e9af4bc0SJohn Beck * Copyright (c) 1998-2009 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate * All rights reserved.
47c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
57c478bd9Sstevel@tonic-gate * Copyright (c) 1988, 1993
67c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set
97c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of
107c478bd9Sstevel@tonic-gate * the sendmail distribution.
117c478bd9Sstevel@tonic-gate *
127c478bd9Sstevel@tonic-gate */
137c478bd9Sstevel@tonic-gate
147c478bd9Sstevel@tonic-gate #include <sendmail.h>
157c478bd9Sstevel@tonic-gate #include <sm/sem.h>
167c478bd9Sstevel@tonic-gate
17e9af4bc0SJohn Beck SM_RCSID("@(#)$Id: queue.c,v 8.987 2009/12/18 17:08:01 ca Exp $")
187c478bd9Sstevel@tonic-gate
197c478bd9Sstevel@tonic-gate #include <dirent.h>
207c478bd9Sstevel@tonic-gate
217c478bd9Sstevel@tonic-gate # define RELEASE_QUEUE (void) 0
227c478bd9Sstevel@tonic-gate # define ST_INODE(st) (st).st_ino
237c478bd9Sstevel@tonic-gate
247c478bd9Sstevel@tonic-gate # define sm_file_exists(errno) ((errno) == EEXIST)
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate # if HASFLOCK && defined(O_EXLOCK)
277c478bd9Sstevel@tonic-gate # define SM_OPEN_EXLOCK 1
287c478bd9Sstevel@tonic-gate # define TF_OPEN_FLAGS (O_CREAT|O_WRONLY|O_EXCL|O_EXLOCK)
297c478bd9Sstevel@tonic-gate # else /* HASFLOCK && defined(O_EXLOCK) */
307c478bd9Sstevel@tonic-gate # define TF_OPEN_FLAGS (O_CREAT|O_WRONLY|O_EXCL)
317c478bd9Sstevel@tonic-gate # endif /* HASFLOCK && defined(O_EXLOCK) */
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate #ifndef SM_OPEN_EXLOCK
347c478bd9Sstevel@tonic-gate # define SM_OPEN_EXLOCK 0
357c478bd9Sstevel@tonic-gate #endif /* ! SM_OPEN_EXLOCK */
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate ** Historical notes:
397c478bd9Sstevel@tonic-gate ** QF_VERSION == 4 was sendmail 8.10/8.11 without _FFR_QUEUEDELAY
407c478bd9Sstevel@tonic-gate ** QF_VERSION == 5 was sendmail 8.10/8.11 with _FFR_QUEUEDELAY
417c478bd9Sstevel@tonic-gate ** QF_VERSION == 6 was sendmail 8.12 without _FFR_QUEUEDELAY
427c478bd9Sstevel@tonic-gate ** QF_VERSION == 7 was sendmail 8.12 with _FFR_QUEUEDELAY
437c478bd9Sstevel@tonic-gate ** QF_VERSION == 8 is sendmail 8.13
447c478bd9Sstevel@tonic-gate */
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate #define QF_VERSION 8 /* version number of this queue format */
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate static char queue_letter __P((ENVELOPE *, int));
497c478bd9Sstevel@tonic-gate static bool quarantine_queue_item __P((int, int, ENVELOPE *, char *));
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate /* Naming convention: qgrp: index of queue group, qg: QUEUEGROUP */
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate /*
547c478bd9Sstevel@tonic-gate ** Work queue.
557c478bd9Sstevel@tonic-gate */
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate struct work
587c478bd9Sstevel@tonic-gate {
597c478bd9Sstevel@tonic-gate char *w_name; /* name of control file */
607c478bd9Sstevel@tonic-gate char *w_host; /* name of recipient host */
617c478bd9Sstevel@tonic-gate bool w_lock; /* is message locked? */
627c478bd9Sstevel@tonic-gate bool w_tooyoung; /* is it too young to run? */
637c478bd9Sstevel@tonic-gate long w_pri; /* priority of message, see below */
647c478bd9Sstevel@tonic-gate time_t w_ctime; /* creation time */
657c478bd9Sstevel@tonic-gate time_t w_mtime; /* modification time */
667c478bd9Sstevel@tonic-gate int w_qgrp; /* queue group located in */
677c478bd9Sstevel@tonic-gate int w_qdir; /* queue directory located in */
687c478bd9Sstevel@tonic-gate struct work *w_next; /* next in queue */
697c478bd9Sstevel@tonic-gate };
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate typedef struct work WORK;
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate static WORK *WorkQ; /* queue of things to be done */
747c478bd9Sstevel@tonic-gate static int NumWorkGroups; /* number of work groups */
757c478bd9Sstevel@tonic-gate static time_t Current_LA_time = 0;
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate /* Get new load average every 30 seconds. */
787c478bd9Sstevel@tonic-gate #define GET_NEW_LA_TIME 30
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate #define SM_GET_LA(now) \
817c478bd9Sstevel@tonic-gate do \
827c478bd9Sstevel@tonic-gate { \
837c478bd9Sstevel@tonic-gate now = curtime(); \
847c478bd9Sstevel@tonic-gate if (Current_LA_time < now - GET_NEW_LA_TIME) \
857c478bd9Sstevel@tonic-gate { \
867c478bd9Sstevel@tonic-gate sm_getla(); \
877c478bd9Sstevel@tonic-gate Current_LA_time = now; \
887c478bd9Sstevel@tonic-gate } \
897c478bd9Sstevel@tonic-gate } while (0)
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate /*
927c478bd9Sstevel@tonic-gate ** DoQueueRun indicates that a queue run is needed.
937c478bd9Sstevel@tonic-gate ** Notice: DoQueueRun is modified in a signal handler!
947c478bd9Sstevel@tonic-gate */
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate static bool volatile DoQueueRun; /* non-interrupt time queue run needed */
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate ** Work group definition structure.
1007c478bd9Sstevel@tonic-gate ** Each work group contains one or more queue groups. This is done
1017c478bd9Sstevel@tonic-gate ** to manage the number of queue group runners active at the same time
1027c478bd9Sstevel@tonic-gate ** to be within the constraints of MaxQueueChildren (if it is set).
1037c478bd9Sstevel@tonic-gate ** The number of queue groups that can be run on the next work run
1047c478bd9Sstevel@tonic-gate ** is kept track of. The queue groups are run in a round robin.
1057c478bd9Sstevel@tonic-gate */
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate struct workgrp
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate int wg_numqgrp; /* number of queue groups in work grp */
1107c478bd9Sstevel@tonic-gate int wg_runners; /* total runners */
1117c478bd9Sstevel@tonic-gate int wg_curqgrp; /* current queue group */
1127c478bd9Sstevel@tonic-gate QUEUEGRP **wg_qgs; /* array of queue groups */
1137c478bd9Sstevel@tonic-gate int wg_maxact; /* max # of active runners */
1147c478bd9Sstevel@tonic-gate time_t wg_lowqintvl; /* lowest queue interval */
1157c478bd9Sstevel@tonic-gate int wg_restart; /* needs restarting? */
1167c478bd9Sstevel@tonic-gate int wg_restartcnt; /* count of times restarted */
1177c478bd9Sstevel@tonic-gate };
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate typedef struct workgrp WORKGRP;
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate static WORKGRP volatile WorkGrp[MAXWORKGROUPS + 1]; /* work groups */
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK
1247c478bd9Sstevel@tonic-gate static SM_DEBUG_T DebugLeakQ = SM_DEBUG_INITIALIZER("leak_q",
1257c478bd9Sstevel@tonic-gate "@(#)$Debug: leak_q - trace memory leaks during queue processing $");
1267c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate /*
1297c478bd9Sstevel@tonic-gate ** We use EmptyString instead of "" to avoid
1307c478bd9Sstevel@tonic-gate ** 'zero-length format string' warnings from gcc
1317c478bd9Sstevel@tonic-gate */
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate static const char EmptyString[] = "";
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate static void grow_wlist __P((int, int));
1367c478bd9Sstevel@tonic-gate static int multiqueue_cache __P((char *, int, QUEUEGRP *, int, unsigned int *));
137e9af4bc0SJohn Beck static int gatherq __P((int, int, bool, bool *, bool *, int *));
1387c478bd9Sstevel@tonic-gate static int sortq __P((int));
1397c478bd9Sstevel@tonic-gate static void printctladdr __P((ADDRESS *, SM_FILE_T *));
1407c478bd9Sstevel@tonic-gate static bool readqf __P((ENVELOPE *, bool));
1417c478bd9Sstevel@tonic-gate static void restart_work_group __P((int));
1427c478bd9Sstevel@tonic-gate static void runner_work __P((ENVELOPE *, int, bool, int, int));
1437c478bd9Sstevel@tonic-gate static void schedule_queue_runs __P((bool, int, bool));
1447c478bd9Sstevel@tonic-gate static char *strrev __P((char *));
1457c478bd9Sstevel@tonic-gate static ADDRESS *setctluser __P((char *, int, ENVELOPE *));
1467c478bd9Sstevel@tonic-gate #if _FFR_RHS
1477c478bd9Sstevel@tonic-gate static int sm_strshufflecmp __P((char *, char *));
1487c478bd9Sstevel@tonic-gate static void init_shuffle_alphabet __P(());
1497c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */
150058561cbSjbeck
151058561cbSjbeck /*
152058561cbSjbeck ** Note: workcmpf?() don't use a prototype because it will cause a conflict
153058561cbSjbeck ** with the qsort() call (which expects something like
154058561cbSjbeck ** int (*compar)(const void *, const void *), not (WORK *, WORK *))
155058561cbSjbeck */
156058561cbSjbeck
1577c478bd9Sstevel@tonic-gate static int workcmpf0();
1587c478bd9Sstevel@tonic-gate static int workcmpf1();
1597c478bd9Sstevel@tonic-gate static int workcmpf2();
1607c478bd9Sstevel@tonic-gate static int workcmpf3();
1617c478bd9Sstevel@tonic-gate static int workcmpf4();
1627c478bd9Sstevel@tonic-gate static int randi = 3; /* index for workcmpf5() */
1637c478bd9Sstevel@tonic-gate static int workcmpf5();
1647c478bd9Sstevel@tonic-gate static int workcmpf6();
1657c478bd9Sstevel@tonic-gate #if _FFR_RHS
1667c478bd9Sstevel@tonic-gate static int workcmpf7();
1677c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate #if RANDOMSHIFT
1707c478bd9Sstevel@tonic-gate # define get_rand_mod(m) ((get_random() >> RANDOMSHIFT) % (m))
1717c478bd9Sstevel@tonic-gate #else /* RANDOMSHIFT */
1727c478bd9Sstevel@tonic-gate # define get_rand_mod(m) (get_random() % (m))
1737c478bd9Sstevel@tonic-gate #endif /* RANDOMSHIFT */
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate /*
1767c478bd9Sstevel@tonic-gate ** File system definition.
1777c478bd9Sstevel@tonic-gate ** Used to keep track of how much free space is available
1787c478bd9Sstevel@tonic-gate ** on a file system in which one or more queue directories reside.
1797c478bd9Sstevel@tonic-gate */
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate typedef struct filesys_shared FILESYS;
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate struct filesys_shared
1847c478bd9Sstevel@tonic-gate {
1857c478bd9Sstevel@tonic-gate dev_t fs_dev; /* unique device id */
1867c478bd9Sstevel@tonic-gate long fs_avail; /* number of free blocks available */
1877c478bd9Sstevel@tonic-gate long fs_blksize; /* block size, in bytes */
1887c478bd9Sstevel@tonic-gate };
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate /* probably kept in shared memory */
1917c478bd9Sstevel@tonic-gate static FILESYS FileSys[MAXFILESYS]; /* queue file systems */
192058561cbSjbeck static const char *FSPath[MAXFILESYS]; /* pathnames for file systems */
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate #if SM_CONF_SHM
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate /*
1977c478bd9Sstevel@tonic-gate ** Shared memory data
1987c478bd9Sstevel@tonic-gate **
1997c478bd9Sstevel@tonic-gate ** Current layout:
2007c478bd9Sstevel@tonic-gate ** size -- size of shared memory segment
2017c478bd9Sstevel@tonic-gate ** pid -- pid of owner, should be a unique id to avoid misinterpretations
2027c478bd9Sstevel@tonic-gate ** by other processes.
2037c478bd9Sstevel@tonic-gate ** tag -- should be a unique id to avoid misinterpretations by others.
2047c478bd9Sstevel@tonic-gate ** idea: hash over configuration data that will be stored here.
2057c478bd9Sstevel@tonic-gate ** NumFileSys -- number of file systems.
2067c478bd9Sstevel@tonic-gate ** FileSys -- (arrary of) structure for used file systems.
2077c478bd9Sstevel@tonic-gate ** RSATmpCnt -- counter for number of uses of ephemeral RSA key.
2087c478bd9Sstevel@tonic-gate ** QShm -- (array of) structure for information about queue directories.
2097c478bd9Sstevel@tonic-gate */
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate /*
2127c478bd9Sstevel@tonic-gate ** Queue data in shared memory
2137c478bd9Sstevel@tonic-gate */
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate typedef struct queue_shared QUEUE_SHM_T;
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate struct queue_shared
2187c478bd9Sstevel@tonic-gate {
2197c478bd9Sstevel@tonic-gate int qs_entries; /* number of entries */
2207c478bd9Sstevel@tonic-gate /* XXX more to follow? */
2217c478bd9Sstevel@tonic-gate };
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate static void *Pshm; /* pointer to shared memory */
2247c478bd9Sstevel@tonic-gate static FILESYS *PtrFileSys; /* pointer to queue file system array */
2257c478bd9Sstevel@tonic-gate int ShmId = SM_SHM_NO_ID; /* shared memory id */
2267c478bd9Sstevel@tonic-gate static QUEUE_SHM_T *QShm; /* pointer to shared queue data */
2277c478bd9Sstevel@tonic-gate static size_t shms;
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate # define SHM_OFF_PID(p) (((char *) (p)) + sizeof(int))
2307c478bd9Sstevel@tonic-gate # define SHM_OFF_TAG(p) (((char *) (p)) + sizeof(pid_t) + sizeof(int))
2317c478bd9Sstevel@tonic-gate # define SHM_OFF_HEAD (sizeof(pid_t) + sizeof(int) * 2)
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate /* how to access FileSys */
2347c478bd9Sstevel@tonic-gate # define FILE_SYS(i) (PtrFileSys[i])
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate /* first entry is a tag, for now just the size */
2377c478bd9Sstevel@tonic-gate # define OFF_FILE_SYS(p) (((char *) (p)) + SHM_OFF_HEAD)
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate /* offset for PNumFileSys */
2407c478bd9Sstevel@tonic-gate # define OFF_NUM_FILE_SYS(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys))
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate /* offset for PRSATmpCnt */
2437c478bd9Sstevel@tonic-gate # define OFF_RSA_TMP_CNT(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int))
2447c478bd9Sstevel@tonic-gate int *PRSATmpCnt;
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gate /* offset for queue_shm */
2477c478bd9Sstevel@tonic-gate # define OFF_QUEUE_SHM(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2)
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate # define QSHM_ENTRIES(i) QShm[i].qs_entries
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate /* basic size of shared memory segment */
2527c478bd9Sstevel@tonic-gate # define SM_T_SIZE (SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2)
2537c478bd9Sstevel@tonic-gate
2547c478bd9Sstevel@tonic-gate static unsigned int hash_q __P((char *, unsigned int));
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate /*
2577c478bd9Sstevel@tonic-gate ** HASH_Q -- simple hash function
2587c478bd9Sstevel@tonic-gate **
2597c478bd9Sstevel@tonic-gate ** Parameters:
2607c478bd9Sstevel@tonic-gate ** p -- string to hash.
2617c478bd9Sstevel@tonic-gate ** h -- hash start value (from previous run).
2627c478bd9Sstevel@tonic-gate **
2637c478bd9Sstevel@tonic-gate ** Returns:
2647c478bd9Sstevel@tonic-gate ** hash value.
2657c478bd9Sstevel@tonic-gate */
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate static unsigned int
hash_q(p,h)2687c478bd9Sstevel@tonic-gate hash_q(p, h)
2697c478bd9Sstevel@tonic-gate char *p;
2707c478bd9Sstevel@tonic-gate unsigned int h;
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate int c, d;
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate while (*p != '\0')
2757c478bd9Sstevel@tonic-gate {
2767c478bd9Sstevel@tonic-gate d = *p++;
2777c478bd9Sstevel@tonic-gate c = d;
2787c478bd9Sstevel@tonic-gate c ^= c<<6;
2797c478bd9Sstevel@tonic-gate h += (c<<11) ^ (c>>1);
2807c478bd9Sstevel@tonic-gate h ^= (d<<14) + (d<<7) + (d<<4) + d;
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate return h;
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate #else /* SM_CONF_SHM */
2877c478bd9Sstevel@tonic-gate # define FILE_SYS(i) FileSys[i]
2887c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */
2897c478bd9Sstevel@tonic-gate
2907c478bd9Sstevel@tonic-gate /* access to the various components of file system data */
2917c478bd9Sstevel@tonic-gate #define FILE_SYS_NAME(i) FSPath[i]
2927c478bd9Sstevel@tonic-gate #define FILE_SYS_AVAIL(i) FILE_SYS(i).fs_avail
2937c478bd9Sstevel@tonic-gate #define FILE_SYS_BLKSIZE(i) FILE_SYS(i).fs_blksize
2947c478bd9Sstevel@tonic-gate #define FILE_SYS_DEV(i) FILE_SYS(i).fs_dev
2957c478bd9Sstevel@tonic-gate
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate /*
2987c478bd9Sstevel@tonic-gate ** Current qf file field assignments:
2997c478bd9Sstevel@tonic-gate **
3007c478bd9Sstevel@tonic-gate ** A AUTH= parameter
3017c478bd9Sstevel@tonic-gate ** B body type
3027c478bd9Sstevel@tonic-gate ** C controlling user
3037c478bd9Sstevel@tonic-gate ** D data file name
3047c478bd9Sstevel@tonic-gate ** d data file directory name (added in 8.12)
3057c478bd9Sstevel@tonic-gate ** E error recipient
3067c478bd9Sstevel@tonic-gate ** F flag bits
3077c478bd9Sstevel@tonic-gate ** G free (was: queue delay algorithm if _FFR_QUEUEDELAY)
3087c478bd9Sstevel@tonic-gate ** H header
3097c478bd9Sstevel@tonic-gate ** I data file's inode number
3107c478bd9Sstevel@tonic-gate ** K time of last delivery attempt
3117c478bd9Sstevel@tonic-gate ** L Solaris Content-Length: header (obsolete)
3127c478bd9Sstevel@tonic-gate ** M message
3137c478bd9Sstevel@tonic-gate ** N number of delivery attempts
3147c478bd9Sstevel@tonic-gate ** P message priority
3157c478bd9Sstevel@tonic-gate ** q quarantine reason
3167c478bd9Sstevel@tonic-gate ** Q original recipient (ORCPT=)
3177c478bd9Sstevel@tonic-gate ** r final recipient (Final-Recipient: DSN field)
3187c478bd9Sstevel@tonic-gate ** R recipient
3197c478bd9Sstevel@tonic-gate ** S sender
3207c478bd9Sstevel@tonic-gate ** T init time
3217c478bd9Sstevel@tonic-gate ** V queue file version
3227c478bd9Sstevel@tonic-gate ** X free (was: character set if _FFR_SAVE_CHARSET)
3237c478bd9Sstevel@tonic-gate ** Y free (was: current delay if _FFR_QUEUEDELAY)
3247c478bd9Sstevel@tonic-gate ** Z original envelope id from ESMTP
3257c478bd9Sstevel@tonic-gate ** ! deliver by (added in 8.12)
3267c478bd9Sstevel@tonic-gate ** $ define macro
3277c478bd9Sstevel@tonic-gate ** . terminate file
3287c478bd9Sstevel@tonic-gate */
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate ** QUEUEUP -- queue a message up for future transmission.
3327c478bd9Sstevel@tonic-gate **
3337c478bd9Sstevel@tonic-gate ** Parameters:
3347c478bd9Sstevel@tonic-gate ** e -- the envelope to queue up.
3357c478bd9Sstevel@tonic-gate ** announce -- if true, tell when you are queueing up.
3367c478bd9Sstevel@tonic-gate ** msync -- if true, then fsync() if SuperSafe interactive mode.
3377c478bd9Sstevel@tonic-gate **
3387c478bd9Sstevel@tonic-gate ** Returns:
3397c478bd9Sstevel@tonic-gate ** none.
3407c478bd9Sstevel@tonic-gate **
3417c478bd9Sstevel@tonic-gate ** Side Effects:
3427c478bd9Sstevel@tonic-gate ** The current request is saved in a control file.
3437c478bd9Sstevel@tonic-gate ** The queue file is left locked.
3447c478bd9Sstevel@tonic-gate */
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate void
queueup(e,announce,msync)3477c478bd9Sstevel@tonic-gate queueup(e, announce, msync)
3487c478bd9Sstevel@tonic-gate register ENVELOPE *e;
3497c478bd9Sstevel@tonic-gate bool announce;
3507c478bd9Sstevel@tonic-gate bool msync;
3517c478bd9Sstevel@tonic-gate {
3527c478bd9Sstevel@tonic-gate register SM_FILE_T *tfp;
3537c478bd9Sstevel@tonic-gate register HDR *h;
3547c478bd9Sstevel@tonic-gate register ADDRESS *q;
3557c478bd9Sstevel@tonic-gate int tfd = -1;
3567c478bd9Sstevel@tonic-gate int i;
3577c478bd9Sstevel@tonic-gate bool newid;
3587c478bd9Sstevel@tonic-gate register char *p;
3597c478bd9Sstevel@tonic-gate MAILER nullmailer;
3607c478bd9Sstevel@tonic-gate MCI mcibuf;
3617c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN];
3627c478bd9Sstevel@tonic-gate char tf[MAXPATHLEN];
3637c478bd9Sstevel@tonic-gate char df[MAXPATHLEN];
3647c478bd9Sstevel@tonic-gate char buf[MAXLINE];
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate ** Create control file.
3687c478bd9Sstevel@tonic-gate */
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate #define OPEN_TF do \
3717c478bd9Sstevel@tonic-gate { \
3727c478bd9Sstevel@tonic-gate MODE_T oldumask = 0; \
3737c478bd9Sstevel@tonic-gate \
3747c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) \
3757c478bd9Sstevel@tonic-gate oldumask = umask(002); \
3767c478bd9Sstevel@tonic-gate tfd = open(tf, TF_OPEN_FLAGS, QueueFileMode); \
3777c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) \
3787c478bd9Sstevel@tonic-gate (void) umask(oldumask); \
3797c478bd9Sstevel@tonic-gate } while (0)
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate
3827c478bd9Sstevel@tonic-gate newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
383058561cbSjbeck (void) sm_strlcpy(tf, queuename(e, NEWQFL_LETTER), sizeof(tf));
3847c478bd9Sstevel@tonic-gate tfp = e->e_lockfp;
3857c478bd9Sstevel@tonic-gate if (tfp == NULL && newid)
3867c478bd9Sstevel@tonic-gate {
3877c478bd9Sstevel@tonic-gate /*
3887c478bd9Sstevel@tonic-gate ** open qf file directly: this will give an error if the file
3897c478bd9Sstevel@tonic-gate ** already exists and hence prevent problems if a queue-id
3907c478bd9Sstevel@tonic-gate ** is reused (e.g., because the clock is set back).
3917c478bd9Sstevel@tonic-gate */
3927c478bd9Sstevel@tonic-gate
393058561cbSjbeck (void) sm_strlcpy(tf, queuename(e, ANYQFL_LETTER), sizeof(tf));
3947c478bd9Sstevel@tonic-gate OPEN_TF;
3957c478bd9Sstevel@tonic-gate if (tfd < 0 ||
3967c478bd9Sstevel@tonic-gate #if !SM_OPEN_EXLOCK
3977c478bd9Sstevel@tonic-gate !lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB) ||
3987c478bd9Sstevel@tonic-gate #endif /* !SM_OPEN_EXLOCK */
3997c478bd9Sstevel@tonic-gate (tfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
4007c478bd9Sstevel@tonic-gate (void *) &tfd, SM_IO_WRONLY,
4017c478bd9Sstevel@tonic-gate NULL)) == NULL)
4027c478bd9Sstevel@tonic-gate {
4037c478bd9Sstevel@tonic-gate int save_errno = errno;
4047c478bd9Sstevel@tonic-gate
4057c478bd9Sstevel@tonic-gate printopenfds(true);
4067c478bd9Sstevel@tonic-gate errno = save_errno;
4077c478bd9Sstevel@tonic-gate syserr("!queueup: cannot create queue file %s, euid=%d, fd=%d, fp=%p",
4087c478bd9Sstevel@tonic-gate tf, (int) geteuid(), tfd, tfp);
4097c478bd9Sstevel@tonic-gate /* NOTREACHED */
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate e->e_lockfp = tfp;
4127c478bd9Sstevel@tonic-gate upd_qs(e, 1, 0, "queueup");
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate /* if newid, write the queue file directly (instead of temp file) */
4167c478bd9Sstevel@tonic-gate if (!newid)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate /* get a locked tf file */
4197c478bd9Sstevel@tonic-gate for (i = 0; i < 128; i++)
4207c478bd9Sstevel@tonic-gate {
4217c478bd9Sstevel@tonic-gate if (tfd < 0)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate OPEN_TF;
4247c478bd9Sstevel@tonic-gate if (tfd < 0)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate if (errno != EEXIST)
4277c478bd9Sstevel@tonic-gate break;
4287c478bd9Sstevel@tonic-gate if (LogLevel > 0 && (i % 32) == 0)
4297c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id,
4307800901eSjbeck "queueup: cannot create %s, euid=%d: %s",
4317c478bd9Sstevel@tonic-gate tf, (int) geteuid(),
4327c478bd9Sstevel@tonic-gate sm_errstring(errno));
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate #if SM_OPEN_EXLOCK
4357c478bd9Sstevel@tonic-gate else
4367c478bd9Sstevel@tonic-gate break;
4377c478bd9Sstevel@tonic-gate #endif /* SM_OPEN_EXLOCK */
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate if (tfd >= 0)
4407c478bd9Sstevel@tonic-gate {
4417c478bd9Sstevel@tonic-gate #if SM_OPEN_EXLOCK
4427c478bd9Sstevel@tonic-gate /* file is locked by open() */
4437c478bd9Sstevel@tonic-gate break;
4447c478bd9Sstevel@tonic-gate #else /* SM_OPEN_EXLOCK */
4457c478bd9Sstevel@tonic-gate if (lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB))
4467c478bd9Sstevel@tonic-gate break;
4477c478bd9Sstevel@tonic-gate else
4487c478bd9Sstevel@tonic-gate #endif /* SM_OPEN_EXLOCK */
4497c478bd9Sstevel@tonic-gate if (LogLevel > 0 && (i % 32) == 0)
4507c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id,
4517c478bd9Sstevel@tonic-gate "queueup: cannot lock %s: %s",
4527c478bd9Sstevel@tonic-gate tf, sm_errstring(errno));
4537c478bd9Sstevel@tonic-gate if ((i % 32) == 31)
4547c478bd9Sstevel@tonic-gate {
4557c478bd9Sstevel@tonic-gate (void) close(tfd);
4567c478bd9Sstevel@tonic-gate tfd = -1;
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate
4607c478bd9Sstevel@tonic-gate if ((i % 32) == 31)
4617c478bd9Sstevel@tonic-gate {
4627c478bd9Sstevel@tonic-gate /* save the old temp file away */
4637c478bd9Sstevel@tonic-gate (void) rename(tf, queuename(e, TEMPQF_LETTER));
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate else
4667c478bd9Sstevel@tonic-gate (void) sleep(i % 32);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate if (tfd < 0 || (tfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
4697c478bd9Sstevel@tonic-gate (void *) &tfd, SM_IO_WRONLY_B,
4707c478bd9Sstevel@tonic-gate NULL)) == NULL)
4717c478bd9Sstevel@tonic-gate {
4727c478bd9Sstevel@tonic-gate int save_errno = errno;
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate printopenfds(true);
4757c478bd9Sstevel@tonic-gate errno = save_errno;
4767c478bd9Sstevel@tonic-gate syserr("!queueup: cannot create queue temp file %s, uid=%d",
4777c478bd9Sstevel@tonic-gate tf, (int) geteuid());
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate if (tTd(40, 1))
4827c478bd9Sstevel@tonic-gate sm_dprintf("\n>>>>> queueing %s/%s%s >>>>>\n",
4837c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir),
4847c478bd9Sstevel@tonic-gate queuename(e, ANYQFL_LETTER),
4857c478bd9Sstevel@tonic-gate newid ? " (new id)" : "");
4867c478bd9Sstevel@tonic-gate if (tTd(40, 3))
4877c478bd9Sstevel@tonic-gate {
4887c478bd9Sstevel@tonic-gate sm_dprintf(" e_flags=");
4897c478bd9Sstevel@tonic-gate printenvflags(e);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate if (tTd(40, 32))
4927c478bd9Sstevel@tonic-gate {
4937c478bd9Sstevel@tonic-gate sm_dprintf(" sendq=");
4947c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), e->e_sendqueue, true);
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate if (tTd(40, 9))
4977c478bd9Sstevel@tonic-gate {
4987c478bd9Sstevel@tonic-gate sm_dprintf(" tfp=");
4997c478bd9Sstevel@tonic-gate dumpfd(sm_io_getinfo(tfp, SM_IO_WHAT_FD, NULL), true, false);
5007c478bd9Sstevel@tonic-gate sm_dprintf(" lockfp=");
5017c478bd9Sstevel@tonic-gate if (e->e_lockfp == NULL)
5027c478bd9Sstevel@tonic-gate sm_dprintf("NULL\n");
5037c478bd9Sstevel@tonic-gate else
5047c478bd9Sstevel@tonic-gate dumpfd(sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL),
5057c478bd9Sstevel@tonic-gate true, false);
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate /*
5097c478bd9Sstevel@tonic-gate ** If there is no data file yet, create one.
5107c478bd9Sstevel@tonic-gate */
5117c478bd9Sstevel@tonic-gate
512058561cbSjbeck (void) sm_strlcpy(df, queuename(e, DATAFL_LETTER), sizeof(df));
5137c478bd9Sstevel@tonic-gate if (bitset(EF_HAS_DF, e->e_flags))
5147c478bd9Sstevel@tonic-gate {
5157c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL &&
5167c478bd9Sstevel@tonic-gate SuperSafe != SAFE_REALLY &&
5177c478bd9Sstevel@tonic-gate SuperSafe != SAFE_REALLY_POSTMILTER &&
5187c478bd9Sstevel@tonic-gate sm_io_setinfo(e->e_dfp, SM_BF_COMMIT, NULL) < 0 &&
5197c478bd9Sstevel@tonic-gate errno != EINVAL)
5207c478bd9Sstevel@tonic-gate {
5217c478bd9Sstevel@tonic-gate syserr("!queueup: cannot commit data file %s, uid=%d",
5227c478bd9Sstevel@tonic-gate queuename(e, DATAFL_LETTER), (int) geteuid());
5237c478bd9Sstevel@tonic-gate }
5247c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL &&
5257c478bd9Sstevel@tonic-gate SuperSafe == SAFE_INTERACTIVE && msync)
5267c478bd9Sstevel@tonic-gate {
5277c478bd9Sstevel@tonic-gate if (tTd(40,32))
5287c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
5297c478bd9Sstevel@tonic-gate "queueup: fsync(e->e_dfp)");
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate if (fsync(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD,
5327c478bd9Sstevel@tonic-gate NULL)) < 0)
5337c478bd9Sstevel@tonic-gate {
5347c478bd9Sstevel@tonic-gate if (newid)
5357c478bd9Sstevel@tonic-gate syserr("!552 Error writing data file %s",
5367c478bd9Sstevel@tonic-gate df);
5377c478bd9Sstevel@tonic-gate else
5387c478bd9Sstevel@tonic-gate syserr("!452 Error writing data file %s",
5397c478bd9Sstevel@tonic-gate df);
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate else
5447c478bd9Sstevel@tonic-gate {
5457c478bd9Sstevel@tonic-gate int dfd;
5467c478bd9Sstevel@tonic-gate MODE_T oldumask = 0;
5477c478bd9Sstevel@tonic-gate register SM_FILE_T *dfp = NULL;
5487c478bd9Sstevel@tonic-gate struct stat stbuf;
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL &&
5517c478bd9Sstevel@tonic-gate sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE))
5527c478bd9Sstevel@tonic-gate syserr("committing over bf file");
5537c478bd9Sstevel@tonic-gate
5547c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode))
5557c478bd9Sstevel@tonic-gate oldumask = umask(002);
5567c478bd9Sstevel@tonic-gate dfd = open(df, O_WRONLY|O_CREAT|O_TRUNC|QF_O_EXTRA,
5577c478bd9Sstevel@tonic-gate QueueFileMode);
5587c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode))
5597c478bd9Sstevel@tonic-gate (void) umask(oldumask);
5607c478bd9Sstevel@tonic-gate if (dfd < 0 || (dfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
5617c478bd9Sstevel@tonic-gate (void *) &dfd, SM_IO_WRONLY_B,
5627c478bd9Sstevel@tonic-gate NULL)) == NULL)
5637c478bd9Sstevel@tonic-gate syserr("!queueup: cannot create data temp file %s, uid=%d",
5647c478bd9Sstevel@tonic-gate df, (int) geteuid());
5657c478bd9Sstevel@tonic-gate if (fstat(dfd, &stbuf) < 0)
5667c478bd9Sstevel@tonic-gate e->e_dfino = -1;
5677c478bd9Sstevel@tonic-gate else
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate e->e_dfdev = stbuf.st_dev;
5707c478bd9Sstevel@tonic-gate e->e_dfino = ST_INODE(stbuf);
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS_DF;
573058561cbSjbeck memset(&mcibuf, '\0', sizeof(mcibuf));
5747c478bd9Sstevel@tonic-gate mcibuf.mci_out = dfp;
5757c478bd9Sstevel@tonic-gate mcibuf.mci_mailer = FileMailer;
5767c478bd9Sstevel@tonic-gate (*e->e_putbody)(&mcibuf, e, NULL);
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate if (SuperSafe == SAFE_REALLY ||
5797c478bd9Sstevel@tonic-gate SuperSafe == SAFE_REALLY_POSTMILTER ||
5807c478bd9Sstevel@tonic-gate (SuperSafe == SAFE_INTERACTIVE && msync))
5817c478bd9Sstevel@tonic-gate {
5827c478bd9Sstevel@tonic-gate if (tTd(40,32))
5837c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
5847c478bd9Sstevel@tonic-gate "queueup: fsync(dfp)");
5857c478bd9Sstevel@tonic-gate
5867c478bd9Sstevel@tonic-gate if (fsync(sm_io_getinfo(dfp, SM_IO_WHAT_FD, NULL)) < 0)
5877c478bd9Sstevel@tonic-gate {
5887c478bd9Sstevel@tonic-gate if (newid)
5897c478bd9Sstevel@tonic-gate syserr("!552 Error writing data file %s",
5907c478bd9Sstevel@tonic-gate df);
5917c478bd9Sstevel@tonic-gate else
5927c478bd9Sstevel@tonic-gate syserr("!452 Error writing data file %s",
5937c478bd9Sstevel@tonic-gate df);
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate }
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate if (sm_io_close(dfp, SM_TIME_DEFAULT) < 0)
5987c478bd9Sstevel@tonic-gate syserr("!queueup: cannot save data temp file %s, uid=%d",
5997c478bd9Sstevel@tonic-gate df, (int) geteuid());
6007c478bd9Sstevel@tonic-gate e->e_putbody = putbody;
6017c478bd9Sstevel@tonic-gate }
6027c478bd9Sstevel@tonic-gate
6037c478bd9Sstevel@tonic-gate /*
6047c478bd9Sstevel@tonic-gate ** Output future work requests.
6057c478bd9Sstevel@tonic-gate ** Priority and creation time should be first, since
6067c478bd9Sstevel@tonic-gate ** they are required by gatherq.
6077c478bd9Sstevel@tonic-gate */
6087c478bd9Sstevel@tonic-gate
6097c478bd9Sstevel@tonic-gate /* output queue version number (must be first!) */
6107c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "V%d\n", QF_VERSION);
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate /* output creation time */
6137c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "T%ld\n", (long) e->e_ctime);
6147c478bd9Sstevel@tonic-gate
6157c478bd9Sstevel@tonic-gate /* output last delivery time */
6167c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "K%ld\n", (long) e->e_dtime);
6177c478bd9Sstevel@tonic-gate
6187c478bd9Sstevel@tonic-gate /* output number of delivery attempts */
6197c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "N%d\n", e->e_ntries);
6207c478bd9Sstevel@tonic-gate
6217c478bd9Sstevel@tonic-gate /* output message priority */
6227c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "P%ld\n", e->e_msgpriority);
6237c478bd9Sstevel@tonic-gate
6247c478bd9Sstevel@tonic-gate /*
6257c478bd9Sstevel@tonic-gate ** If data file is in a different directory than the queue file,
6267c478bd9Sstevel@tonic-gate ** output a "d" record naming the directory of the data file.
6277c478bd9Sstevel@tonic-gate */
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate if (e->e_dfqgrp != e->e_qgrp)
6307c478bd9Sstevel@tonic-gate {
6317c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "d%s\n",
6327c478bd9Sstevel@tonic-gate Queue[e->e_dfqgrp]->qg_qpaths[e->e_dfqdir].qp_name);
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate /* output inode number of data file */
6367c478bd9Sstevel@tonic-gate /* XXX should probably include device major/minor too */
6377c478bd9Sstevel@tonic-gate if (e->e_dfino != -1)
6387c478bd9Sstevel@tonic-gate {
6397c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "I%ld/%ld/%llu\n",
6407c478bd9Sstevel@tonic-gate (long) major(e->e_dfdev),
6417c478bd9Sstevel@tonic-gate (long) minor(e->e_dfdev),
6427c478bd9Sstevel@tonic-gate (ULONGLONG_T) e->e_dfino);
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate
6457c478bd9Sstevel@tonic-gate /* output body type */
6467c478bd9Sstevel@tonic-gate if (e->e_bodytype != NULL)
6477c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "B%s\n",
6487c478bd9Sstevel@tonic-gate denlstring(e->e_bodytype, true, false));
6497c478bd9Sstevel@tonic-gate
6507c478bd9Sstevel@tonic-gate /* quarantine reason */
6517c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL)
6527c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "q%s\n",
6537c478bd9Sstevel@tonic-gate denlstring(e->e_quarmsg, true, false));
6547c478bd9Sstevel@tonic-gate
6557c478bd9Sstevel@tonic-gate /* message from envelope, if it exists */
6567c478bd9Sstevel@tonic-gate if (e->e_message != NULL)
6577c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "M%s\n",
6587c478bd9Sstevel@tonic-gate denlstring(e->e_message, true, false));
6597c478bd9Sstevel@tonic-gate
6607c478bd9Sstevel@tonic-gate /* send various flag bits through */
6617c478bd9Sstevel@tonic-gate p = buf;
6627c478bd9Sstevel@tonic-gate if (bitset(EF_WARNING, e->e_flags))
6637c478bd9Sstevel@tonic-gate *p++ = 'w';
6647c478bd9Sstevel@tonic-gate if (bitset(EF_RESPONSE, e->e_flags))
6657c478bd9Sstevel@tonic-gate *p++ = 'r';
6667c478bd9Sstevel@tonic-gate if (bitset(EF_HAS8BIT, e->e_flags))
6677c478bd9Sstevel@tonic-gate *p++ = '8';
6687c478bd9Sstevel@tonic-gate if (bitset(EF_DELETE_BCC, e->e_flags))
6697c478bd9Sstevel@tonic-gate *p++ = 'b';
6707c478bd9Sstevel@tonic-gate if (bitset(EF_RET_PARAM, e->e_flags))
6717c478bd9Sstevel@tonic-gate *p++ = 'd';
6727c478bd9Sstevel@tonic-gate if (bitset(EF_NO_BODY_RETN, e->e_flags))
6737c478bd9Sstevel@tonic-gate *p++ = 'n';
6747c478bd9Sstevel@tonic-gate if (bitset(EF_SPLIT, e->e_flags))
6757c478bd9Sstevel@tonic-gate *p++ = 's';
6767c478bd9Sstevel@tonic-gate *p++ = '\0';
6777c478bd9Sstevel@tonic-gate if (buf[0] != '\0')
6787c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "F%s\n", buf);
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate /* save $={persistentMacros} macro values */
6817c478bd9Sstevel@tonic-gate queueup_macros(macid("{persistentMacros}"), tfp, e);
6827c478bd9Sstevel@tonic-gate
6837c478bd9Sstevel@tonic-gate /* output name of sender */
6847c478bd9Sstevel@tonic-gate if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
6857c478bd9Sstevel@tonic-gate p = e->e_sender;
6867c478bd9Sstevel@tonic-gate else
6877c478bd9Sstevel@tonic-gate p = e->e_from.q_paddr;
6887c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "S%s\n",
6897c478bd9Sstevel@tonic-gate denlstring(p, true, false));
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate /* output ESMTP-supplied "original" information */
6927c478bd9Sstevel@tonic-gate if (e->e_envid != NULL)
6937c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Z%s\n",
6947c478bd9Sstevel@tonic-gate denlstring(e->e_envid, true, false));
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate /* output AUTH= parameter */
6977c478bd9Sstevel@tonic-gate if (e->e_auth_param != NULL)
6987c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "A%s\n",
6997c478bd9Sstevel@tonic-gate denlstring(e->e_auth_param, true, false));
7007c478bd9Sstevel@tonic-gate if (e->e_dlvr_flag != 0)
7017c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "!%c %ld\n",
7027c478bd9Sstevel@tonic-gate (char) e->e_dlvr_flag, e->e_deliver_by);
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate /* output list of recipient addresses */
7057c478bd9Sstevel@tonic-gate printctladdr(NULL, NULL);
7067c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next)
7077c478bd9Sstevel@tonic-gate {
7087c478bd9Sstevel@tonic-gate if (!QS_IS_UNDELIVERED(q->q_state))
7097c478bd9Sstevel@tonic-gate continue;
7107c478bd9Sstevel@tonic-gate
7117c478bd9Sstevel@tonic-gate /* message for this recipient, if it exists */
7127c478bd9Sstevel@tonic-gate if (q->q_message != NULL)
7137c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "M%s\n",
7147c478bd9Sstevel@tonic-gate denlstring(q->q_message, true,
7157c478bd9Sstevel@tonic-gate false));
7167c478bd9Sstevel@tonic-gate
7177c478bd9Sstevel@tonic-gate printctladdr(q, tfp);
7187c478bd9Sstevel@tonic-gate if (q->q_orcpt != NULL)
7197c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Q%s\n",
7207c478bd9Sstevel@tonic-gate denlstring(q->q_orcpt, true,
7217c478bd9Sstevel@tonic-gate false));
7227c478bd9Sstevel@tonic-gate if (q->q_finalrcpt != NULL)
7237c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "r%s\n",
7247c478bd9Sstevel@tonic-gate denlstring(q->q_finalrcpt, true,
7257c478bd9Sstevel@tonic-gate false));
7267c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'R');
7277c478bd9Sstevel@tonic-gate if (bitset(QPRIMARY, q->q_flags))
7287c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'P');
7297c478bd9Sstevel@tonic-gate if (bitset(QHASNOTIFY, q->q_flags))
7307c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'N');
7317c478bd9Sstevel@tonic-gate if (bitset(QPINGONSUCCESS, q->q_flags))
7327c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'S');
7337c478bd9Sstevel@tonic-gate if (bitset(QPINGONFAILURE, q->q_flags))
7347c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'F');
7357c478bd9Sstevel@tonic-gate if (bitset(QPINGONDELAY, q->q_flags))
7367c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'D');
7377c478bd9Sstevel@tonic-gate if (q->q_alias != NULL &&
7387c478bd9Sstevel@tonic-gate bitset(QALIAS, q->q_alias->q_flags))
7397c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'A');
7407c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, ':');
7417c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s\n",
7427c478bd9Sstevel@tonic-gate denlstring(q->q_paddr, true, false));
7437c478bd9Sstevel@tonic-gate if (announce)
7447c478bd9Sstevel@tonic-gate {
7457c478bd9Sstevel@tonic-gate char *tag = "queued";
7467c478bd9Sstevel@tonic-gate
7477c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL)
7487c478bd9Sstevel@tonic-gate tag = "quarantined";
7497c478bd9Sstevel@tonic-gate
7507c478bd9Sstevel@tonic-gate e->e_to = q->q_paddr;
7517c478bd9Sstevel@tonic-gate message(tag);
7527c478bd9Sstevel@tonic-gate if (LogLevel > 8)
7537c478bd9Sstevel@tonic-gate logdelivery(q->q_mailer, NULL, q->q_status,
7547c478bd9Sstevel@tonic-gate tag, NULL, (time_t) 0, e);
7557c478bd9Sstevel@tonic-gate e->e_to = NULL;
7567c478bd9Sstevel@tonic-gate }
7577c478bd9Sstevel@tonic-gate if (tTd(40, 1))
7587c478bd9Sstevel@tonic-gate {
7597c478bd9Sstevel@tonic-gate sm_dprintf("queueing ");
7607c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), q, false);
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate
7647c478bd9Sstevel@tonic-gate /*
7657c478bd9Sstevel@tonic-gate ** Output headers for this message.
7667c478bd9Sstevel@tonic-gate ** Expand macros completely here. Queue run will deal with
7677c478bd9Sstevel@tonic-gate ** everything as absolute headers.
7687c478bd9Sstevel@tonic-gate ** All headers that must be relative to the recipient
7697c478bd9Sstevel@tonic-gate ** can be cracked later.
7707c478bd9Sstevel@tonic-gate ** We set up a "null mailer" -- i.e., a mailer that will have
7717c478bd9Sstevel@tonic-gate ** no effect on the addresses as they are output.
7727c478bd9Sstevel@tonic-gate */
7737c478bd9Sstevel@tonic-gate
774058561cbSjbeck memset((char *) &nullmailer, '\0', sizeof(nullmailer));
7757c478bd9Sstevel@tonic-gate nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
7767c478bd9Sstevel@tonic-gate nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
7777c478bd9Sstevel@tonic-gate nullmailer.m_eol = "\n";
778058561cbSjbeck memset(&mcibuf, '\0', sizeof(mcibuf));
7797c478bd9Sstevel@tonic-gate mcibuf.mci_mailer = &nullmailer;
7807c478bd9Sstevel@tonic-gate mcibuf.mci_out = tfp;
7817c478bd9Sstevel@tonic-gate
7827c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'g', "\201f");
7837c478bd9Sstevel@tonic-gate for (h = e->e_header; h != NULL; h = h->h_link)
7847c478bd9Sstevel@tonic-gate {
7857c478bd9Sstevel@tonic-gate if (h->h_value == NULL)
7867c478bd9Sstevel@tonic-gate continue;
7877c478bd9Sstevel@tonic-gate
7887c478bd9Sstevel@tonic-gate /* don't output resent headers on non-resent messages */
7897c478bd9Sstevel@tonic-gate if (bitset(H_RESENT, h->h_flags) &&
7907c478bd9Sstevel@tonic-gate !bitset(EF_RESENT, e->e_flags))
7917c478bd9Sstevel@tonic-gate continue;
7927c478bd9Sstevel@tonic-gate
7937c478bd9Sstevel@tonic-gate /* expand macros; if null, don't output header at all */
7947c478bd9Sstevel@tonic-gate if (bitset(H_DEFAULT, h->h_flags))
7957c478bd9Sstevel@tonic-gate {
796058561cbSjbeck (void) expand(h->h_value, buf, sizeof(buf), e);
7977c478bd9Sstevel@tonic-gate if (buf[0] == '\0')
7987c478bd9Sstevel@tonic-gate continue;
7994aac33d3Sjbeck if (buf[0] == ' ' && buf[1] == '\0')
8004aac33d3Sjbeck continue;
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate
8037c478bd9Sstevel@tonic-gate /* output this header */
8047c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "H?");
8057c478bd9Sstevel@tonic-gate
8067c478bd9Sstevel@tonic-gate /* output conditional macro if present */
8077c478bd9Sstevel@tonic-gate if (h->h_macro != '\0')
8087c478bd9Sstevel@tonic-gate {
8097c478bd9Sstevel@tonic-gate if (bitset(0200, h->h_macro))
8107c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT,
8117c478bd9Sstevel@tonic-gate "${%s}",
8127c478bd9Sstevel@tonic-gate macname(bitidx(h->h_macro)));
8137c478bd9Sstevel@tonic-gate else
8147c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT,
8157c478bd9Sstevel@tonic-gate "$%c", h->h_macro);
8167c478bd9Sstevel@tonic-gate }
8177c478bd9Sstevel@tonic-gate else if (!bitzerop(h->h_mflags) &&
8187c478bd9Sstevel@tonic-gate bitset(H_CHECK|H_ACHECK, h->h_flags))
8197c478bd9Sstevel@tonic-gate {
8207c478bd9Sstevel@tonic-gate int j;
8217c478bd9Sstevel@tonic-gate
8227c478bd9Sstevel@tonic-gate /* if conditional, output the set of conditions */
8237c478bd9Sstevel@tonic-gate for (j = '\0'; j <= '\177'; j++)
8247c478bd9Sstevel@tonic-gate if (bitnset(j, h->h_mflags))
8257c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT,
8267c478bd9Sstevel@tonic-gate j);
8277c478bd9Sstevel@tonic-gate }
8287c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, '?');
8297c478bd9Sstevel@tonic-gate
8307c478bd9Sstevel@tonic-gate /* output the header: expand macros, convert addresses */
8317c478bd9Sstevel@tonic-gate if (bitset(H_DEFAULT, h->h_flags) &&
8327c478bd9Sstevel@tonic-gate !bitset(H_BINDLATE, h->h_flags))
8337c478bd9Sstevel@tonic-gate {
8347c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s:%s\n",
8357c478bd9Sstevel@tonic-gate h->h_field,
8367c478bd9Sstevel@tonic-gate denlstring(buf, false, true));
8377c478bd9Sstevel@tonic-gate }
8387c478bd9Sstevel@tonic-gate else if (bitset(H_FROM|H_RCPT, h->h_flags) &&
8397c478bd9Sstevel@tonic-gate !bitset(H_BINDLATE, h->h_flags))
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
8427c478bd9Sstevel@tonic-gate SM_FILE_T *savetrace = TrafficLogFile;
8437c478bd9Sstevel@tonic-gate
8447c478bd9Sstevel@tonic-gate TrafficLogFile = NULL;
8457c478bd9Sstevel@tonic-gate
8467c478bd9Sstevel@tonic-gate if (bitset(H_FROM, h->h_flags))
8477c478bd9Sstevel@tonic-gate oldstyle = false;
8487800901eSjbeck commaize(h, h->h_value, oldstyle, &mcibuf, e,
8497800901eSjbeck PXLF_HEADER);
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate TrafficLogFile = savetrace;
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate else
8547c478bd9Sstevel@tonic-gate {
8557c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s:%s\n",
8567c478bd9Sstevel@tonic-gate h->h_field,
8577c478bd9Sstevel@tonic-gate denlstring(h->h_value, false,
8587c478bd9Sstevel@tonic-gate true));
8597c478bd9Sstevel@tonic-gate }
8607c478bd9Sstevel@tonic-gate }
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate /*
8637c478bd9Sstevel@tonic-gate ** Clean up.
8647c478bd9Sstevel@tonic-gate **
8657c478bd9Sstevel@tonic-gate ** Write a terminator record -- this is to prevent
8667c478bd9Sstevel@tonic-gate ** scurrilous crackers from appending any data.
8677c478bd9Sstevel@tonic-gate */
8687c478bd9Sstevel@tonic-gate
8697c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, ".\n");
8707c478bd9Sstevel@tonic-gate
8717c478bd9Sstevel@tonic-gate if (sm_io_flush(tfp, SM_TIME_DEFAULT) != 0 ||
8727c478bd9Sstevel@tonic-gate ((SuperSafe == SAFE_REALLY ||
8737c478bd9Sstevel@tonic-gate SuperSafe == SAFE_REALLY_POSTMILTER ||
8747c478bd9Sstevel@tonic-gate (SuperSafe == SAFE_INTERACTIVE && msync)) &&
8757c478bd9Sstevel@tonic-gate fsync(sm_io_getinfo(tfp, SM_IO_WHAT_FD, NULL)) < 0) ||
8767c478bd9Sstevel@tonic-gate sm_io_error(tfp))
8777c478bd9Sstevel@tonic-gate {
8787c478bd9Sstevel@tonic-gate if (newid)
8797c478bd9Sstevel@tonic-gate syserr("!552 Error writing control file %s", tf);
8807c478bd9Sstevel@tonic-gate else
8817c478bd9Sstevel@tonic-gate syserr("!452 Error writing control file %s", tf);
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate
8847c478bd9Sstevel@tonic-gate if (!newid)
8857c478bd9Sstevel@tonic-gate {
8867c478bd9Sstevel@tonic-gate char new = queue_letter(e, ANYQFL_LETTER);
8877c478bd9Sstevel@tonic-gate
8887c478bd9Sstevel@tonic-gate /* rename (locked) tf to be (locked) [qh]f */
8897c478bd9Sstevel@tonic-gate (void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER),
890058561cbSjbeck sizeof(qf));
8917c478bd9Sstevel@tonic-gate if (rename(tf, qf) < 0)
8927c478bd9Sstevel@tonic-gate syserr("cannot rename(%s, %s), uid=%d",
8937c478bd9Sstevel@tonic-gate tf, qf, (int) geteuid());
8947c478bd9Sstevel@tonic-gate else
8957c478bd9Sstevel@tonic-gate {
8967c478bd9Sstevel@tonic-gate /*
8977c478bd9Sstevel@tonic-gate ** Check if type has changed and only
8987c478bd9Sstevel@tonic-gate ** remove the old item if the rename above
8997c478bd9Sstevel@tonic-gate ** succeeded.
9007c478bd9Sstevel@tonic-gate */
9017c478bd9Sstevel@tonic-gate
9027c478bd9Sstevel@tonic-gate if (e->e_qfletter != '\0' &&
9037c478bd9Sstevel@tonic-gate e->e_qfletter != new)
9047c478bd9Sstevel@tonic-gate {
9057c478bd9Sstevel@tonic-gate if (tTd(40, 5))
9067c478bd9Sstevel@tonic-gate {
9077c478bd9Sstevel@tonic-gate sm_dprintf("type changed from %c to %c\n",
9087c478bd9Sstevel@tonic-gate e->e_qfletter, new);
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate if (unlink(queuename(e, e->e_qfletter)) < 0)
9127c478bd9Sstevel@tonic-gate {
9137c478bd9Sstevel@tonic-gate /* XXX: something more drastic? */
9147c478bd9Sstevel@tonic-gate if (LogLevel > 0)
9157c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
9167c478bd9Sstevel@tonic-gate "queueup: unlink(%s) failed: %s",
9177c478bd9Sstevel@tonic-gate queuename(e, e->e_qfletter),
9187c478bd9Sstevel@tonic-gate sm_errstring(errno));
9197c478bd9Sstevel@tonic-gate }
9207c478bd9Sstevel@tonic-gate }
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate e->e_qfletter = new;
9237c478bd9Sstevel@tonic-gate
9247c478bd9Sstevel@tonic-gate /*
9257c478bd9Sstevel@tonic-gate ** fsync() after renaming to make sure metadata is
9267c478bd9Sstevel@tonic-gate ** written to disk on filesystems in which renames are
9277c478bd9Sstevel@tonic-gate ** not guaranteed.
9287c478bd9Sstevel@tonic-gate */
9297c478bd9Sstevel@tonic-gate
9307c478bd9Sstevel@tonic-gate if (SuperSafe != SAFE_NO)
9317c478bd9Sstevel@tonic-gate {
9327c478bd9Sstevel@tonic-gate /* for softupdates */
9337c478bd9Sstevel@tonic-gate if (tfd >= 0 && fsync(tfd) < 0)
9347c478bd9Sstevel@tonic-gate {
9357c478bd9Sstevel@tonic-gate syserr("!queueup: cannot fsync queue temp file %s",
9367c478bd9Sstevel@tonic-gate tf);
9377c478bd9Sstevel@tonic-gate }
9387c478bd9Sstevel@tonic-gate SYNC_DIR(qf, true);
9397c478bd9Sstevel@tonic-gate }
9407c478bd9Sstevel@tonic-gate
9417c478bd9Sstevel@tonic-gate /* close and unlock old (locked) queue file */
9427c478bd9Sstevel@tonic-gate if (e->e_lockfp != NULL)
9437c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT);
9447c478bd9Sstevel@tonic-gate e->e_lockfp = tfp;
9457c478bd9Sstevel@tonic-gate
9467c478bd9Sstevel@tonic-gate /* save log info */
9477c478bd9Sstevel@tonic-gate if (LogLevel > 79)
9487c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "queueup %s", qf);
9497c478bd9Sstevel@tonic-gate }
9507c478bd9Sstevel@tonic-gate else
9517c478bd9Sstevel@tonic-gate {
9527c478bd9Sstevel@tonic-gate /* save log info */
9537c478bd9Sstevel@tonic-gate if (LogLevel > 79)
9547c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "queueup %s", tf);
9557c478bd9Sstevel@tonic-gate
9567c478bd9Sstevel@tonic-gate e->e_qfletter = queue_letter(e, ANYQFL_LETTER);
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate
9597c478bd9Sstevel@tonic-gate errno = 0;
9607c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE;
9617c478bd9Sstevel@tonic-gate
9627c478bd9Sstevel@tonic-gate if (tTd(40, 1))
9637c478bd9Sstevel@tonic-gate sm_dprintf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
9647c478bd9Sstevel@tonic-gate return;
9657c478bd9Sstevel@tonic-gate }
9667c478bd9Sstevel@tonic-gate
9677c478bd9Sstevel@tonic-gate /*
9687c478bd9Sstevel@tonic-gate ** PRINTCTLADDR -- print control address to file.
9697c478bd9Sstevel@tonic-gate **
9707c478bd9Sstevel@tonic-gate ** Parameters:
9717c478bd9Sstevel@tonic-gate ** a -- address.
9727c478bd9Sstevel@tonic-gate ** tfp -- file pointer.
9737c478bd9Sstevel@tonic-gate **
9747c478bd9Sstevel@tonic-gate ** Returns:
9757c478bd9Sstevel@tonic-gate ** none.
9767c478bd9Sstevel@tonic-gate **
9777c478bd9Sstevel@tonic-gate ** Side Effects:
9787c478bd9Sstevel@tonic-gate ** The control address (if changed) is printed to the file.
9797c478bd9Sstevel@tonic-gate ** The last control address and uid are saved.
9807c478bd9Sstevel@tonic-gate */
9817c478bd9Sstevel@tonic-gate
9827c478bd9Sstevel@tonic-gate static void
printctladdr(a,tfp)9837c478bd9Sstevel@tonic-gate printctladdr(a, tfp)
9847c478bd9Sstevel@tonic-gate register ADDRESS *a;
9857c478bd9Sstevel@tonic-gate SM_FILE_T *tfp;
9867c478bd9Sstevel@tonic-gate {
9877c478bd9Sstevel@tonic-gate char *user;
9887c478bd9Sstevel@tonic-gate register ADDRESS *q;
9897c478bd9Sstevel@tonic-gate uid_t uid;
9907c478bd9Sstevel@tonic-gate gid_t gid;
9917c478bd9Sstevel@tonic-gate static ADDRESS *lastctladdr = NULL;
9927c478bd9Sstevel@tonic-gate static uid_t lastuid;
9937c478bd9Sstevel@tonic-gate
9947c478bd9Sstevel@tonic-gate /* initialization */
9957c478bd9Sstevel@tonic-gate if (a == NULL || a->q_alias == NULL || tfp == NULL)
9967c478bd9Sstevel@tonic-gate {
9977c478bd9Sstevel@tonic-gate if (lastctladdr != NULL && tfp != NULL)
9987c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C\n");
9997c478bd9Sstevel@tonic-gate lastctladdr = NULL;
10007c478bd9Sstevel@tonic-gate lastuid = 0;
10017c478bd9Sstevel@tonic-gate return;
10027c478bd9Sstevel@tonic-gate }
10037c478bd9Sstevel@tonic-gate
10047c478bd9Sstevel@tonic-gate /* find the active uid */
10057c478bd9Sstevel@tonic-gate q = getctladdr(a);
10067c478bd9Sstevel@tonic-gate if (q == NULL)
10077c478bd9Sstevel@tonic-gate {
10087c478bd9Sstevel@tonic-gate user = NULL;
10097c478bd9Sstevel@tonic-gate uid = 0;
10107c478bd9Sstevel@tonic-gate gid = 0;
10117c478bd9Sstevel@tonic-gate }
10127c478bd9Sstevel@tonic-gate else
10137c478bd9Sstevel@tonic-gate {
10147c478bd9Sstevel@tonic-gate user = q->q_ruser != NULL ? q->q_ruser : q->q_user;
10157c478bd9Sstevel@tonic-gate uid = q->q_uid;
10167c478bd9Sstevel@tonic-gate gid = q->q_gid;
10177c478bd9Sstevel@tonic-gate }
10187c478bd9Sstevel@tonic-gate a = a->q_alias;
10197c478bd9Sstevel@tonic-gate
10207c478bd9Sstevel@tonic-gate /* check to see if this is the same as last time */
10217c478bd9Sstevel@tonic-gate if (lastctladdr != NULL && uid == lastuid &&
10227c478bd9Sstevel@tonic-gate strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
10237c478bd9Sstevel@tonic-gate return;
10247c478bd9Sstevel@tonic-gate lastuid = uid;
10257c478bd9Sstevel@tonic-gate lastctladdr = a;
10267c478bd9Sstevel@tonic-gate
10277c478bd9Sstevel@tonic-gate if (uid == 0 || user == NULL || user[0] == '\0')
10287c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C");
10297c478bd9Sstevel@tonic-gate else
10307c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C%s:%ld:%ld",
10317c478bd9Sstevel@tonic-gate denlstring(user, true, false), (long) uid,
10327c478bd9Sstevel@tonic-gate (long) gid);
10337c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, ":%s\n",
10347c478bd9Sstevel@tonic-gate denlstring(a->q_paddr, true, false));
10357c478bd9Sstevel@tonic-gate }
10367c478bd9Sstevel@tonic-gate
10377c478bd9Sstevel@tonic-gate /*
10387c478bd9Sstevel@tonic-gate ** RUNNERS_SIGTERM -- propagate a SIGTERM to queue runner process
10397c478bd9Sstevel@tonic-gate **
10407c478bd9Sstevel@tonic-gate ** This propagates the signal to the child processes that are queue
10417c478bd9Sstevel@tonic-gate ** runners. This is for a queue runner "cleanup". After all of the
10427c478bd9Sstevel@tonic-gate ** child queue runner processes are signaled (it should be SIGTERM
10437c478bd9Sstevel@tonic-gate ** being the sig) then the old signal handler (Oldsh) is called
10447c478bd9Sstevel@tonic-gate ** to handle any cleanup set for this process (provided it is not
10457c478bd9Sstevel@tonic-gate ** SIG_DFL or SIG_IGN). The signal may not be handled immediately
10467c478bd9Sstevel@tonic-gate ** if the BlockOldsh flag is set. If the current process doesn't
10477c478bd9Sstevel@tonic-gate ** have a parent then handle the signal immediately, regardless of
10487c478bd9Sstevel@tonic-gate ** BlockOldsh.
10497c478bd9Sstevel@tonic-gate **
10507c478bd9Sstevel@tonic-gate ** Parameters:
10517c478bd9Sstevel@tonic-gate ** sig -- the signal number being sent
10527c478bd9Sstevel@tonic-gate **
10537c478bd9Sstevel@tonic-gate ** Returns:
10547c478bd9Sstevel@tonic-gate ** none.
10557c478bd9Sstevel@tonic-gate **
10567c478bd9Sstevel@tonic-gate ** Side Effects:
10577c478bd9Sstevel@tonic-gate ** Sets the NoMoreRunners boolean to true to stop more runners
10587c478bd9Sstevel@tonic-gate ** from being started in runqueue().
10597c478bd9Sstevel@tonic-gate **
10607c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
10617c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
10627c478bd9Sstevel@tonic-gate ** DOING.
10637c478bd9Sstevel@tonic-gate */
10647c478bd9Sstevel@tonic-gate
10657c478bd9Sstevel@tonic-gate static bool volatile NoMoreRunners = false;
10667c478bd9Sstevel@tonic-gate static sigfunc_t Oldsh_term = SIG_DFL;
10677c478bd9Sstevel@tonic-gate static sigfunc_t Oldsh_hup = SIG_DFL;
10687c478bd9Sstevel@tonic-gate static sigfunc_t volatile Oldsh = SIG_DFL;
10697c478bd9Sstevel@tonic-gate static bool BlockOldsh = false;
10707c478bd9Sstevel@tonic-gate static int volatile Oldsig = 0;
10717c478bd9Sstevel@tonic-gate static SIGFUNC_DECL runners_sigterm __P((int));
10727c478bd9Sstevel@tonic-gate static SIGFUNC_DECL runners_sighup __P((int));
10737c478bd9Sstevel@tonic-gate
10747c478bd9Sstevel@tonic-gate static SIGFUNC_DECL
runners_sigterm(sig)10757c478bd9Sstevel@tonic-gate runners_sigterm(sig)
10767c478bd9Sstevel@tonic-gate int sig;
10777c478bd9Sstevel@tonic-gate {
10787c478bd9Sstevel@tonic-gate int save_errno = errno;
10797c478bd9Sstevel@tonic-gate
10807c478bd9Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, runners_sigterm);
10817c478bd9Sstevel@tonic-gate errno = save_errno;
10827c478bd9Sstevel@tonic-gate CHECK_CRITICAL(sig);
10837c478bd9Sstevel@tonic-gate NoMoreRunners = true;
10847c478bd9Sstevel@tonic-gate Oldsh = Oldsh_term;
10857c478bd9Sstevel@tonic-gate Oldsig = sig;
10867c478bd9Sstevel@tonic-gate proc_list_signal(PROC_QUEUE, sig);
10877c478bd9Sstevel@tonic-gate
10887c478bd9Sstevel@tonic-gate if (!BlockOldsh || getppid() <= 1)
10897c478bd9Sstevel@tonic-gate {
10907c478bd9Sstevel@tonic-gate /* Check that a valid 'old signal handler' is callable */
10917c478bd9Sstevel@tonic-gate if (Oldsh_term != SIG_DFL && Oldsh_term != SIG_IGN &&
10927c478bd9Sstevel@tonic-gate Oldsh_term != runners_sigterm)
10937c478bd9Sstevel@tonic-gate (*Oldsh_term)(sig);
10947c478bd9Sstevel@tonic-gate }
10957c478bd9Sstevel@tonic-gate errno = save_errno;
10967c478bd9Sstevel@tonic-gate return SIGFUNC_RETURN;
10977c478bd9Sstevel@tonic-gate }
10987c478bd9Sstevel@tonic-gate /*
10997c478bd9Sstevel@tonic-gate ** RUNNERS_SIGHUP -- propagate a SIGHUP to queue runner process
11007c478bd9Sstevel@tonic-gate **
11017c478bd9Sstevel@tonic-gate ** This propagates the signal to the child processes that are queue
11027c478bd9Sstevel@tonic-gate ** runners. This is for a queue runner "cleanup". After all of the
11037c478bd9Sstevel@tonic-gate ** child queue runner processes are signaled (it should be SIGHUP
11047c478bd9Sstevel@tonic-gate ** being the sig) then the old signal handler (Oldsh) is called to
11057c478bd9Sstevel@tonic-gate ** handle any cleanup set for this process (provided it is not SIG_DFL
11067c478bd9Sstevel@tonic-gate ** or SIG_IGN). The signal may not be handled immediately if the
11077c478bd9Sstevel@tonic-gate ** BlockOldsh flag is set. If the current process doesn't have
11087c478bd9Sstevel@tonic-gate ** a parent then handle the signal immediately, regardless of
11097c478bd9Sstevel@tonic-gate ** BlockOldsh.
11107c478bd9Sstevel@tonic-gate **
11117c478bd9Sstevel@tonic-gate ** Parameters:
11127c478bd9Sstevel@tonic-gate ** sig -- the signal number being sent
11137c478bd9Sstevel@tonic-gate **
11147c478bd9Sstevel@tonic-gate ** Returns:
11157c478bd9Sstevel@tonic-gate ** none.
11167c478bd9Sstevel@tonic-gate **
11177c478bd9Sstevel@tonic-gate ** Side Effects:
11187c478bd9Sstevel@tonic-gate ** Sets the NoMoreRunners boolean to true to stop more runners
11197c478bd9Sstevel@tonic-gate ** from being started in runqueue().
11207c478bd9Sstevel@tonic-gate **
11217c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
11227c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
11237c478bd9Sstevel@tonic-gate ** DOING.
11247c478bd9Sstevel@tonic-gate */
11257c478bd9Sstevel@tonic-gate
11267c478bd9Sstevel@tonic-gate static SIGFUNC_DECL
runners_sighup(sig)11277c478bd9Sstevel@tonic-gate runners_sighup(sig)
11287c478bd9Sstevel@tonic-gate int sig;
11297c478bd9Sstevel@tonic-gate {
11307c478bd9Sstevel@tonic-gate int save_errno = errno;
11317c478bd9Sstevel@tonic-gate
11327c478bd9Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, runners_sighup);
11337c478bd9Sstevel@tonic-gate errno = save_errno;
11347c478bd9Sstevel@tonic-gate CHECK_CRITICAL(sig);
11357c478bd9Sstevel@tonic-gate NoMoreRunners = true;
11367c478bd9Sstevel@tonic-gate Oldsh = Oldsh_hup;
11377c478bd9Sstevel@tonic-gate Oldsig = sig;
11387c478bd9Sstevel@tonic-gate proc_list_signal(PROC_QUEUE, sig);
11397c478bd9Sstevel@tonic-gate
11407c478bd9Sstevel@tonic-gate if (!BlockOldsh || getppid() <= 1)
11417c478bd9Sstevel@tonic-gate {
11427c478bd9Sstevel@tonic-gate /* Check that a valid 'old signal handler' is callable */
11437c478bd9Sstevel@tonic-gate if (Oldsh_hup != SIG_DFL && Oldsh_hup != SIG_IGN &&
11447c478bd9Sstevel@tonic-gate Oldsh_hup != runners_sighup)
11457c478bd9Sstevel@tonic-gate (*Oldsh_hup)(sig);
11467c478bd9Sstevel@tonic-gate }
11477c478bd9Sstevel@tonic-gate errno = save_errno;
11487c478bd9Sstevel@tonic-gate return SIGFUNC_RETURN;
11497c478bd9Sstevel@tonic-gate }
11507c478bd9Sstevel@tonic-gate /*
11517c478bd9Sstevel@tonic-gate ** MARK_WORK_GROUP_RESTART -- mark a work group as needing a restart
11527c478bd9Sstevel@tonic-gate **
11537c478bd9Sstevel@tonic-gate ** Sets a workgroup for restarting.
11547c478bd9Sstevel@tonic-gate **
11557c478bd9Sstevel@tonic-gate ** Parameters:
11567c478bd9Sstevel@tonic-gate ** wgrp -- the work group id to restart.
11577c478bd9Sstevel@tonic-gate ** reason -- why (signal?), -1 to turn off restart
11587c478bd9Sstevel@tonic-gate **
11597c478bd9Sstevel@tonic-gate ** Returns:
11607c478bd9Sstevel@tonic-gate ** none.
11617c478bd9Sstevel@tonic-gate **
11627c478bd9Sstevel@tonic-gate ** Side effects:
11637c478bd9Sstevel@tonic-gate ** May set global RestartWorkGroup to true.
11647c478bd9Sstevel@tonic-gate **
11657c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
11667c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
11677c478bd9Sstevel@tonic-gate ** DOING.
11687c478bd9Sstevel@tonic-gate */
11697c478bd9Sstevel@tonic-gate
11707c478bd9Sstevel@tonic-gate void
mark_work_group_restart(wgrp,reason)11717c478bd9Sstevel@tonic-gate mark_work_group_restart(wgrp, reason)
11727c478bd9Sstevel@tonic-gate int wgrp;
11737c478bd9Sstevel@tonic-gate int reason;
11747c478bd9Sstevel@tonic-gate {
11757c478bd9Sstevel@tonic-gate if (wgrp < 0 || wgrp > NumWorkGroups)
11767c478bd9Sstevel@tonic-gate return;
11777c478bd9Sstevel@tonic-gate
11787c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_restart = reason;
11797c478bd9Sstevel@tonic-gate if (reason >= 0)
11807c478bd9Sstevel@tonic-gate RestartWorkGroup = true;
11817c478bd9Sstevel@tonic-gate }
11827c478bd9Sstevel@tonic-gate /*
11837c478bd9Sstevel@tonic-gate ** RESTART_MARKED_WORK_GROUPS -- restart work groups marked as needing restart
11847c478bd9Sstevel@tonic-gate **
11857c478bd9Sstevel@tonic-gate ** Restart any workgroup marked as needing a restart provided more
11867c478bd9Sstevel@tonic-gate ** runners are allowed.
11877c478bd9Sstevel@tonic-gate **
11887c478bd9Sstevel@tonic-gate ** Parameters:
11897c478bd9Sstevel@tonic-gate ** none.
11907c478bd9Sstevel@tonic-gate **
11917c478bd9Sstevel@tonic-gate ** Returns:
11927c478bd9Sstevel@tonic-gate ** none.
11937c478bd9Sstevel@tonic-gate **
11947c478bd9Sstevel@tonic-gate ** Side effects:
11957c478bd9Sstevel@tonic-gate ** Sets global RestartWorkGroup to false.
11967c478bd9Sstevel@tonic-gate */
11977c478bd9Sstevel@tonic-gate
11987c478bd9Sstevel@tonic-gate void
restart_marked_work_groups()11997c478bd9Sstevel@tonic-gate restart_marked_work_groups()
12007c478bd9Sstevel@tonic-gate {
12017c478bd9Sstevel@tonic-gate int i;
12027c478bd9Sstevel@tonic-gate int wasblocked;
12037c478bd9Sstevel@tonic-gate
12047c478bd9Sstevel@tonic-gate if (NoMoreRunners)
12057c478bd9Sstevel@tonic-gate return;
12067c478bd9Sstevel@tonic-gate
12077c478bd9Sstevel@tonic-gate /* Block SIGCHLD so reapchild() doesn't mess with us */
12087c478bd9Sstevel@tonic-gate wasblocked = sm_blocksignal(SIGCHLD);
12097c478bd9Sstevel@tonic-gate
12107c478bd9Sstevel@tonic-gate for (i = 0; i < NumWorkGroups; i++)
12117c478bd9Sstevel@tonic-gate {
12127c478bd9Sstevel@tonic-gate if (WorkGrp[i].wg_restart >= 0)
12137c478bd9Sstevel@tonic-gate {
12147c478bd9Sstevel@tonic-gate if (LogLevel > 8)
12157c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID,
12167c478bd9Sstevel@tonic-gate "restart queue runner=%d due to signal 0x%x",
12177c478bd9Sstevel@tonic-gate i, WorkGrp[i].wg_restart);
12187c478bd9Sstevel@tonic-gate restart_work_group(i);
12197c478bd9Sstevel@tonic-gate }
12207c478bd9Sstevel@tonic-gate }
12217c478bd9Sstevel@tonic-gate RestartWorkGroup = false;
12227c478bd9Sstevel@tonic-gate
12237c478bd9Sstevel@tonic-gate if (wasblocked == 0)
12247c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGCHLD);
12257c478bd9Sstevel@tonic-gate }
12267c478bd9Sstevel@tonic-gate /*
12277c478bd9Sstevel@tonic-gate ** RESTART_WORK_GROUP -- restart a specific work group
12287c478bd9Sstevel@tonic-gate **
12297c478bd9Sstevel@tonic-gate ** Restart a specific workgroup provided more runners are allowed.
12307c478bd9Sstevel@tonic-gate ** If the requested work group has been restarted too many times log
12317c478bd9Sstevel@tonic-gate ** this and refuse to restart.
12327c478bd9Sstevel@tonic-gate **
12337c478bd9Sstevel@tonic-gate ** Parameters:
12347c478bd9Sstevel@tonic-gate ** wgrp -- the work group id to restart
12357c478bd9Sstevel@tonic-gate **
12367c478bd9Sstevel@tonic-gate ** Returns:
12377c478bd9Sstevel@tonic-gate ** none.
12387c478bd9Sstevel@tonic-gate **
12397c478bd9Sstevel@tonic-gate ** Side Effects:
12407c478bd9Sstevel@tonic-gate ** starts another process doing the work of wgrp
12417c478bd9Sstevel@tonic-gate */
12427c478bd9Sstevel@tonic-gate
12437c478bd9Sstevel@tonic-gate #define MAX_PERSIST_RESTART 10 /* max allowed number of restarts */
12447c478bd9Sstevel@tonic-gate
12457c478bd9Sstevel@tonic-gate static void
restart_work_group(wgrp)12467c478bd9Sstevel@tonic-gate restart_work_group(wgrp)
12477c478bd9Sstevel@tonic-gate int wgrp;
12487c478bd9Sstevel@tonic-gate {
12497c478bd9Sstevel@tonic-gate if (NoMoreRunners ||
12507c478bd9Sstevel@tonic-gate wgrp < 0 || wgrp > NumWorkGroups)
12517c478bd9Sstevel@tonic-gate return;
12527c478bd9Sstevel@tonic-gate
12537c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_restart = -1;
12547c478bd9Sstevel@tonic-gate if (WorkGrp[wgrp].wg_restartcnt < MAX_PERSIST_RESTART)
12557c478bd9Sstevel@tonic-gate {
12567c478bd9Sstevel@tonic-gate /* avoid overflow; increment here */
12577c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_restartcnt++;
12587c478bd9Sstevel@tonic-gate (void) run_work_group(wgrp, RWG_FORK|RWG_PERSISTENT|RWG_RUNALL);
12597c478bd9Sstevel@tonic-gate }
12607c478bd9Sstevel@tonic-gate else
12617c478bd9Sstevel@tonic-gate {
12627c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID,
12637c478bd9Sstevel@tonic-gate "ERROR: persistent queue runner=%d restarted too many times, queue runner lost",
12647c478bd9Sstevel@tonic-gate wgrp);
12657c478bd9Sstevel@tonic-gate }
12667c478bd9Sstevel@tonic-gate }
12677c478bd9Sstevel@tonic-gate /*
12687c478bd9Sstevel@tonic-gate ** SCHEDULE_QUEUE_RUNS -- schedule the next queue run for a work group.
12697c478bd9Sstevel@tonic-gate **
12707c478bd9Sstevel@tonic-gate ** Parameters:
12717c478bd9Sstevel@tonic-gate ** runall -- schedule even if individual bit is not set.
12727c478bd9Sstevel@tonic-gate ** wgrp -- the work group id to schedule.
12737c478bd9Sstevel@tonic-gate ** didit -- the queue run was performed for this work group.
12747c478bd9Sstevel@tonic-gate **
12757c478bd9Sstevel@tonic-gate ** Returns:
12767c478bd9Sstevel@tonic-gate ** nothing
12777c478bd9Sstevel@tonic-gate */
12787c478bd9Sstevel@tonic-gate
12797c478bd9Sstevel@tonic-gate #define INCR_MOD(v, m) if (++v >= m) \
12807c478bd9Sstevel@tonic-gate v = 0; \
12817c478bd9Sstevel@tonic-gate else
12827c478bd9Sstevel@tonic-gate
12837c478bd9Sstevel@tonic-gate static void
schedule_queue_runs(runall,wgrp,didit)12847c478bd9Sstevel@tonic-gate schedule_queue_runs(runall, wgrp, didit)
12857c478bd9Sstevel@tonic-gate bool runall;
12867c478bd9Sstevel@tonic-gate int wgrp;
12877c478bd9Sstevel@tonic-gate bool didit;
12887c478bd9Sstevel@tonic-gate {
12897c478bd9Sstevel@tonic-gate int qgrp, cgrp, endgrp;
12907c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG
12917c478bd9Sstevel@tonic-gate time_t lastsched;
12927c478bd9Sstevel@tonic-gate bool sched;
12937c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */
12947c478bd9Sstevel@tonic-gate time_t now;
12957c478bd9Sstevel@tonic-gate time_t minqintvl;
12967c478bd9Sstevel@tonic-gate
12977c478bd9Sstevel@tonic-gate /*
12987c478bd9Sstevel@tonic-gate ** This is a bit ugly since we have to duplicate the
12997c478bd9Sstevel@tonic-gate ** code that "walks" through a work queue group.
13007c478bd9Sstevel@tonic-gate */
13017c478bd9Sstevel@tonic-gate
13027c478bd9Sstevel@tonic-gate now = curtime();
13037c478bd9Sstevel@tonic-gate minqintvl = 0;
13047c478bd9Sstevel@tonic-gate cgrp = endgrp = WorkGrp[wgrp].wg_curqgrp;
13057c478bd9Sstevel@tonic-gate do
13067c478bd9Sstevel@tonic-gate {
13077c478bd9Sstevel@tonic-gate time_t qintvl;
13087c478bd9Sstevel@tonic-gate
13097c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG
13107c478bd9Sstevel@tonic-gate lastsched = 0;
13117c478bd9Sstevel@tonic-gate sched = false;
13127c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */
13137c478bd9Sstevel@tonic-gate qgrp = WorkGrp[wgrp].wg_qgs[cgrp]->qg_index;
13147c478bd9Sstevel@tonic-gate if (Queue[qgrp]->qg_queueintvl > 0)
13157c478bd9Sstevel@tonic-gate qintvl = Queue[qgrp]->qg_queueintvl;
13167c478bd9Sstevel@tonic-gate else if (QueueIntvl > 0)
13177c478bd9Sstevel@tonic-gate qintvl = QueueIntvl;
13187c478bd9Sstevel@tonic-gate else
13197c478bd9Sstevel@tonic-gate qintvl = (time_t) 0;
13207c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG
13217c478bd9Sstevel@tonic-gate lastsched = Queue[qgrp]->qg_nextrun;
13227c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */
13237c478bd9Sstevel@tonic-gate if ((runall || Queue[qgrp]->qg_nextrun <= now) && qintvl > 0)
13247c478bd9Sstevel@tonic-gate {
13257c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG
13267c478bd9Sstevel@tonic-gate sched = true;
13277c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */
13287c478bd9Sstevel@tonic-gate if (minqintvl == 0 || qintvl < minqintvl)
13297c478bd9Sstevel@tonic-gate minqintvl = qintvl;
13307c478bd9Sstevel@tonic-gate
13317c478bd9Sstevel@tonic-gate /*
13327c478bd9Sstevel@tonic-gate ** Only set a new time if a queue run was performed
13337c478bd9Sstevel@tonic-gate ** for this queue group. If the queue was not run,
13347c478bd9Sstevel@tonic-gate ** we could starve it by setting a new time on each
13357c478bd9Sstevel@tonic-gate ** call.
13367c478bd9Sstevel@tonic-gate */
13377c478bd9Sstevel@tonic-gate
13387c478bd9Sstevel@tonic-gate if (didit)
13397c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_nextrun += qintvl;
13407c478bd9Sstevel@tonic-gate }
13417c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG
13427c478bd9Sstevel@tonic-gate if (tTd(69, 10))
13437c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
13447c478bd9Sstevel@tonic-gate "sqr: wgrp=%d, cgrp=%d, qgrp=%d, intvl=%ld, QI=%ld, runall=%d, lastrun=%ld, nextrun=%ld, sched=%d",
13457c478bd9Sstevel@tonic-gate wgrp, cgrp, qgrp, Queue[qgrp]->qg_queueintvl,
13467c478bd9Sstevel@tonic-gate QueueIntvl, runall, lastsched,
13477c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_nextrun, sched);
13487c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */
13497c478bd9Sstevel@tonic-gate INCR_MOD(cgrp, WorkGrp[wgrp].wg_numqgrp);
13507c478bd9Sstevel@tonic-gate } while (endgrp != cgrp);
13517c478bd9Sstevel@tonic-gate if (minqintvl > 0)
13527c478bd9Sstevel@tonic-gate (void) sm_setevent(minqintvl, runqueueevent, 0);
13537c478bd9Sstevel@tonic-gate }
13547c478bd9Sstevel@tonic-gate
13557c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_RUN_PARANOIA
13567c478bd9Sstevel@tonic-gate /*
13577c478bd9Sstevel@tonic-gate ** CHECKQUEUERUNNER -- check whether a queue group hasn't been run.
13587c478bd9Sstevel@tonic-gate **
13597c478bd9Sstevel@tonic-gate ** Use this if events may get lost and hence queue runners may not
13607c478bd9Sstevel@tonic-gate ** be started and mail will pile up in a queue.
13617c478bd9Sstevel@tonic-gate **
13627c478bd9Sstevel@tonic-gate ** Parameters:
13637c478bd9Sstevel@tonic-gate ** none.
13647c478bd9Sstevel@tonic-gate **
13657c478bd9Sstevel@tonic-gate ** Returns:
13667c478bd9Sstevel@tonic-gate ** true if a queue run is necessary.
13677c478bd9Sstevel@tonic-gate **
13687c478bd9Sstevel@tonic-gate ** Side Effects:
13697c478bd9Sstevel@tonic-gate ** may schedule a queue run.
13707c478bd9Sstevel@tonic-gate */
13717c478bd9Sstevel@tonic-gate
13727c478bd9Sstevel@tonic-gate bool
checkqueuerunner()13737c478bd9Sstevel@tonic-gate checkqueuerunner()
13747c478bd9Sstevel@tonic-gate {
13757c478bd9Sstevel@tonic-gate int qgrp;
13767c478bd9Sstevel@tonic-gate time_t now, minqintvl;
13777c478bd9Sstevel@tonic-gate
13787c478bd9Sstevel@tonic-gate now = curtime();
13797c478bd9Sstevel@tonic-gate minqintvl = 0;
13807c478bd9Sstevel@tonic-gate for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++)
13817c478bd9Sstevel@tonic-gate {
13827c478bd9Sstevel@tonic-gate time_t qintvl;
13837c478bd9Sstevel@tonic-gate
13847c478bd9Sstevel@tonic-gate if (Queue[qgrp]->qg_queueintvl > 0)
13857c478bd9Sstevel@tonic-gate qintvl = Queue[qgrp]->qg_queueintvl;
13867c478bd9Sstevel@tonic-gate else if (QueueIntvl > 0)
13877c478bd9Sstevel@tonic-gate qintvl = QueueIntvl;
13887c478bd9Sstevel@tonic-gate else
13897c478bd9Sstevel@tonic-gate qintvl = (time_t) 0;
13907c478bd9Sstevel@tonic-gate if (Queue[qgrp]->qg_nextrun <= now - qintvl)
13917c478bd9Sstevel@tonic-gate {
13927c478bd9Sstevel@tonic-gate if (minqintvl == 0 || qintvl < minqintvl)
13937c478bd9Sstevel@tonic-gate minqintvl = qintvl;
13947c478bd9Sstevel@tonic-gate if (LogLevel > 1)
13957c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID,
13967c478bd9Sstevel@tonic-gate "checkqueuerunner: queue %d should have been run at %s, queue interval %ld",
13977c478bd9Sstevel@tonic-gate qgrp,
13987c478bd9Sstevel@tonic-gate arpadate(ctime(&Queue[qgrp]->qg_nextrun)),
13997c478bd9Sstevel@tonic-gate qintvl);
14007c478bd9Sstevel@tonic-gate }
14017c478bd9Sstevel@tonic-gate }
14027c478bd9Sstevel@tonic-gate if (minqintvl > 0)
14037c478bd9Sstevel@tonic-gate {
14047c478bd9Sstevel@tonic-gate (void) sm_setevent(minqintvl, runqueueevent, 0);
14057c478bd9Sstevel@tonic-gate return true;
14067c478bd9Sstevel@tonic-gate }
14077c478bd9Sstevel@tonic-gate return false;
14087c478bd9Sstevel@tonic-gate }
14097c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_RUN_PARANOIA */
14107c478bd9Sstevel@tonic-gate
14117c478bd9Sstevel@tonic-gate /*
14127c478bd9Sstevel@tonic-gate ** RUNQUEUE -- run the jobs in the queue.
14137c478bd9Sstevel@tonic-gate **
14147c478bd9Sstevel@tonic-gate ** Gets the stuff out of the queue in some presumably logical
14157c478bd9Sstevel@tonic-gate ** order and processes them.
14167c478bd9Sstevel@tonic-gate **
14177c478bd9Sstevel@tonic-gate ** Parameters:
14187c478bd9Sstevel@tonic-gate ** forkflag -- true if the queue scanning should be done in
14197c478bd9Sstevel@tonic-gate ** a child process. We double-fork so it is not our
14207c478bd9Sstevel@tonic-gate ** child and we don't have to clean up after it.
14217c478bd9Sstevel@tonic-gate ** false can be ignored if we have multiple queues.
14227c478bd9Sstevel@tonic-gate ** verbose -- if true, print out status information.
14237c478bd9Sstevel@tonic-gate ** persistent -- persistent queue runner?
14247c478bd9Sstevel@tonic-gate ** runall -- run all groups or only a subset (DoQueueRun)?
14257c478bd9Sstevel@tonic-gate **
14267c478bd9Sstevel@tonic-gate ** Returns:
14277c478bd9Sstevel@tonic-gate ** true if the queue run successfully began.
14287c478bd9Sstevel@tonic-gate **
14297c478bd9Sstevel@tonic-gate ** Side Effects:
14307c478bd9Sstevel@tonic-gate ** runs things in the mail queue using run_work_group().
14317c478bd9Sstevel@tonic-gate ** maybe schedules next queue run.
14327c478bd9Sstevel@tonic-gate */
14337c478bd9Sstevel@tonic-gate
14347c478bd9Sstevel@tonic-gate static ENVELOPE QueueEnvelope; /* the queue run envelope */
14357c478bd9Sstevel@tonic-gate static time_t LastQueueTime = 0; /* last time a queue ID assigned */
14367c478bd9Sstevel@tonic-gate static pid_t LastQueuePid = -1; /* last PID which had a queue ID */
14377c478bd9Sstevel@tonic-gate
14387c478bd9Sstevel@tonic-gate /* values for qp_supdirs */
14397c478bd9Sstevel@tonic-gate #define QP_NOSUB 0x0000 /* No subdirectories */
14407c478bd9Sstevel@tonic-gate #define QP_SUBDF 0x0001 /* "df" subdirectory */
14417c478bd9Sstevel@tonic-gate #define QP_SUBQF 0x0002 /* "qf" subdirectory */
14427c478bd9Sstevel@tonic-gate #define QP_SUBXF 0x0004 /* "xf" subdirectory */
14437c478bd9Sstevel@tonic-gate
14447c478bd9Sstevel@tonic-gate bool
runqueue(forkflag,verbose,persistent,runall)14457c478bd9Sstevel@tonic-gate runqueue(forkflag, verbose, persistent, runall)
14467c478bd9Sstevel@tonic-gate bool forkflag;
14477c478bd9Sstevel@tonic-gate bool verbose;
14487c478bd9Sstevel@tonic-gate bool persistent;
14497c478bd9Sstevel@tonic-gate bool runall;
14507c478bd9Sstevel@tonic-gate {
14517c478bd9Sstevel@tonic-gate int i;
14527c478bd9Sstevel@tonic-gate bool ret = true;
14537c478bd9Sstevel@tonic-gate static int curnum = 0;
14547c478bd9Sstevel@tonic-gate sigfunc_t cursh;
14557c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK
14567c478bd9Sstevel@tonic-gate SM_NONVOLATILE int oldgroup = 0;
14577c478bd9Sstevel@tonic-gate
14587c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugLeakQ, 1))
14597c478bd9Sstevel@tonic-gate {
14607c478bd9Sstevel@tonic-gate oldgroup = sm_heap_group();
14617c478bd9Sstevel@tonic-gate sm_heap_newgroup();
14627c478bd9Sstevel@tonic-gate sm_dprintf("runqueue() heap group #%d\n", sm_heap_group());
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */
14657c478bd9Sstevel@tonic-gate
14667c478bd9Sstevel@tonic-gate /* queue run has been started, don't do any more this time */
14677c478bd9Sstevel@tonic-gate DoQueueRun = false;
14687c478bd9Sstevel@tonic-gate
14697c478bd9Sstevel@tonic-gate /* more than one queue or more than one directory per queue */
14707c478bd9Sstevel@tonic-gate if (!forkflag && !verbose &&
14717c478bd9Sstevel@tonic-gate (WorkGrp[0].wg_qgs[0]->qg_numqueues > 1 || NumWorkGroups > 1 ||
14727c478bd9Sstevel@tonic-gate WorkGrp[0].wg_numqgrp > 1))
14737c478bd9Sstevel@tonic-gate forkflag = true;
14747c478bd9Sstevel@tonic-gate
14757c478bd9Sstevel@tonic-gate /*
14767c478bd9Sstevel@tonic-gate ** For controlling queue runners via signals sent to this process.
14777c478bd9Sstevel@tonic-gate ** Oldsh* will get called too by runners_sig* (if it is not SIG_IGN
14787c478bd9Sstevel@tonic-gate ** or SIG_DFL) to preserve cleanup behavior. Now that this process
14797c478bd9Sstevel@tonic-gate ** will have children (and perhaps grandchildren) this handler will
14807c478bd9Sstevel@tonic-gate ** be left in place. This is because this process, once it has
14817c478bd9Sstevel@tonic-gate ** finished spinning off queue runners, may go back to doing something
14827c478bd9Sstevel@tonic-gate ** else (like being a daemon). And we still want on a SIG{TERM,HUP} to
14837c478bd9Sstevel@tonic-gate ** clean up the child queue runners. Only install 'runners_sig*' once
14847c478bd9Sstevel@tonic-gate ** else we'll get stuck looping forever.
14857c478bd9Sstevel@tonic-gate */
14867c478bd9Sstevel@tonic-gate
14877c478bd9Sstevel@tonic-gate cursh = sm_signal(SIGTERM, runners_sigterm);
14887c478bd9Sstevel@tonic-gate if (cursh != runners_sigterm)
14897c478bd9Sstevel@tonic-gate Oldsh_term = cursh;
14907c478bd9Sstevel@tonic-gate cursh = sm_signal(SIGHUP, runners_sighup);
14917c478bd9Sstevel@tonic-gate if (cursh != runners_sighup)
14927c478bd9Sstevel@tonic-gate Oldsh_hup = cursh;
14937c478bd9Sstevel@tonic-gate
14947c478bd9Sstevel@tonic-gate for (i = 0; i < NumWorkGroups && !NoMoreRunners; i++)
14957c478bd9Sstevel@tonic-gate {
14967c478bd9Sstevel@tonic-gate int rwgflags = RWG_NONE;
14977c478bd9Sstevel@tonic-gate
14987c478bd9Sstevel@tonic-gate /*
14997c478bd9Sstevel@tonic-gate ** If MaxQueueChildren active then test whether the start
15007c478bd9Sstevel@tonic-gate ** of the next queue group's additional queue runners (maximum)
15017c478bd9Sstevel@tonic-gate ** will result in MaxQueueChildren being exceeded.
15027c478bd9Sstevel@tonic-gate **
15037c478bd9Sstevel@tonic-gate ** Note: do not use continue; even though another workgroup
15047c478bd9Sstevel@tonic-gate ** may have fewer queue runners, this would be "unfair",
15057c478bd9Sstevel@tonic-gate ** i.e., this work group might "starve" then.
15067c478bd9Sstevel@tonic-gate */
15077c478bd9Sstevel@tonic-gate
15087c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG
15097c478bd9Sstevel@tonic-gate if (tTd(69, 10))
15107c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
15117c478bd9Sstevel@tonic-gate "rq: curnum=%d, MaxQueueChildren=%d, CurRunners=%d, WorkGrp[curnum].wg_maxact=%d",
15127c478bd9Sstevel@tonic-gate curnum, MaxQueueChildren, CurRunners,
15137c478bd9Sstevel@tonic-gate WorkGrp[curnum].wg_maxact);
15147c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */
15157c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 &&
15167c478bd9Sstevel@tonic-gate CurRunners + WorkGrp[curnum].wg_maxact > MaxQueueChildren)
15177c478bd9Sstevel@tonic-gate break;
15187c478bd9Sstevel@tonic-gate
15197c478bd9Sstevel@tonic-gate /*
15207c478bd9Sstevel@tonic-gate ** Pick up where we left off (curnum), in case we
15217c478bd9Sstevel@tonic-gate ** used up all the children last time without finishing.
15227c478bd9Sstevel@tonic-gate ** This give a round-robin fairness to queue runs.
15237c478bd9Sstevel@tonic-gate **
15247c478bd9Sstevel@tonic-gate ** Increment CurRunners before calling run_work_group()
15257c478bd9Sstevel@tonic-gate ** to avoid a "race condition" with proc_list_drop() which
15267c478bd9Sstevel@tonic-gate ** decrements CurRunners if the queue runners terminate.
15277c478bd9Sstevel@tonic-gate ** Notice: CurRunners is an upper limit, in some cases
15287c478bd9Sstevel@tonic-gate ** (too few jobs in the queue) this value is larger than
15297c478bd9Sstevel@tonic-gate ** the actual number of queue runners. The discrepancy can
15307c478bd9Sstevel@tonic-gate ** increase if some queue runners "hang" for a long time.
15317c478bd9Sstevel@tonic-gate */
15327c478bd9Sstevel@tonic-gate
15337c478bd9Sstevel@tonic-gate CurRunners += WorkGrp[curnum].wg_maxact;
15347c478bd9Sstevel@tonic-gate if (forkflag)
15357c478bd9Sstevel@tonic-gate rwgflags |= RWG_FORK;
15367c478bd9Sstevel@tonic-gate if (verbose)
15377c478bd9Sstevel@tonic-gate rwgflags |= RWG_VERBOSE;
15387c478bd9Sstevel@tonic-gate if (persistent)
15397c478bd9Sstevel@tonic-gate rwgflags |= RWG_PERSISTENT;
15407c478bd9Sstevel@tonic-gate if (runall)
15417c478bd9Sstevel@tonic-gate rwgflags |= RWG_RUNALL;
15427c478bd9Sstevel@tonic-gate ret = run_work_group(curnum, rwgflags);
15437c478bd9Sstevel@tonic-gate
15447c478bd9Sstevel@tonic-gate /*
15457c478bd9Sstevel@tonic-gate ** Failure means a message was printed for ETRN
15467c478bd9Sstevel@tonic-gate ** and subsequent queues are likely to fail as well.
15477c478bd9Sstevel@tonic-gate ** Decrement CurRunners in that case because
15487c478bd9Sstevel@tonic-gate ** none have been started.
15497c478bd9Sstevel@tonic-gate */
15507c478bd9Sstevel@tonic-gate
15517c478bd9Sstevel@tonic-gate if (!ret)
15527c478bd9Sstevel@tonic-gate {
15537c478bd9Sstevel@tonic-gate CurRunners -= WorkGrp[curnum].wg_maxact;
15547c478bd9Sstevel@tonic-gate break;
15557c478bd9Sstevel@tonic-gate }
15567c478bd9Sstevel@tonic-gate
15577c478bd9Sstevel@tonic-gate if (!persistent)
15587c478bd9Sstevel@tonic-gate schedule_queue_runs(runall, curnum, true);
15597c478bd9Sstevel@tonic-gate INCR_MOD(curnum, NumWorkGroups);
15607c478bd9Sstevel@tonic-gate }
15617c478bd9Sstevel@tonic-gate
15627c478bd9Sstevel@tonic-gate /* schedule left over queue runs */
15637c478bd9Sstevel@tonic-gate if (i < NumWorkGroups && !NoMoreRunners && !persistent)
15647c478bd9Sstevel@tonic-gate {
15657c478bd9Sstevel@tonic-gate int h;
15667c478bd9Sstevel@tonic-gate
15677c478bd9Sstevel@tonic-gate for (h = curnum; i < NumWorkGroups; i++)
15687c478bd9Sstevel@tonic-gate {
15697c478bd9Sstevel@tonic-gate schedule_queue_runs(runall, h, false);
15707c478bd9Sstevel@tonic-gate INCR_MOD(h, NumWorkGroups);
15717c478bd9Sstevel@tonic-gate }
15727c478bd9Sstevel@tonic-gate }
15737c478bd9Sstevel@tonic-gate
15747c478bd9Sstevel@tonic-gate
15757c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK
15767c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugLeakQ, 1))
15777c478bd9Sstevel@tonic-gate sm_heap_setgroup(oldgroup);
15787c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */
15797c478bd9Sstevel@tonic-gate return ret;
15807c478bd9Sstevel@tonic-gate }
15817c478bd9Sstevel@tonic-gate
15827c478bd9Sstevel@tonic-gate #if _FFR_SKIP_DOMAINS
15837c478bd9Sstevel@tonic-gate /*
15847c478bd9Sstevel@tonic-gate ** SKIP_DOMAINS -- Skip 'skip' number of domains in the WorkQ.
15857c478bd9Sstevel@tonic-gate **
15867c478bd9Sstevel@tonic-gate ** Added by Stephen Frost <sfrost@snowman.net> to support
15877c478bd9Sstevel@tonic-gate ** having each runner process every N'th domain instead of
15887c478bd9Sstevel@tonic-gate ** every N'th message.
15897c478bd9Sstevel@tonic-gate **
15907c478bd9Sstevel@tonic-gate ** Parameters:
15917c478bd9Sstevel@tonic-gate ** skip -- number of domains in WorkQ to skip.
15927c478bd9Sstevel@tonic-gate **
15937c478bd9Sstevel@tonic-gate ** Returns:
15947c478bd9Sstevel@tonic-gate ** total number of messages skipped.
15957c478bd9Sstevel@tonic-gate **
15967c478bd9Sstevel@tonic-gate ** Side Effects:
15977c478bd9Sstevel@tonic-gate ** may change WorkQ
15987c478bd9Sstevel@tonic-gate */
15997c478bd9Sstevel@tonic-gate
16007c478bd9Sstevel@tonic-gate static int
skip_domains(skip)16017c478bd9Sstevel@tonic-gate skip_domains(skip)
16027c478bd9Sstevel@tonic-gate int skip;
16037c478bd9Sstevel@tonic-gate {
16047c478bd9Sstevel@tonic-gate int n, seqjump;
16057c478bd9Sstevel@tonic-gate
16067c478bd9Sstevel@tonic-gate for (n = 0, seqjump = 0; n < skip && WorkQ != NULL; seqjump++)
16077c478bd9Sstevel@tonic-gate {
16087c478bd9Sstevel@tonic-gate if (WorkQ->w_next != NULL)
16097c478bd9Sstevel@tonic-gate {
16107c478bd9Sstevel@tonic-gate if (WorkQ->w_host != NULL &&
16117c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host != NULL)
16127c478bd9Sstevel@tonic-gate {
16137c478bd9Sstevel@tonic-gate if (sm_strcasecmp(WorkQ->w_host,
16147c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host) != 0)
16157c478bd9Sstevel@tonic-gate n++;
16167c478bd9Sstevel@tonic-gate }
16177c478bd9Sstevel@tonic-gate else
16187c478bd9Sstevel@tonic-gate {
16197c478bd9Sstevel@tonic-gate if ((WorkQ->w_host != NULL &&
16207c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host == NULL) ||
16217c478bd9Sstevel@tonic-gate (WorkQ->w_host == NULL &&
16227c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host != NULL))
16237c478bd9Sstevel@tonic-gate n++;
16247c478bd9Sstevel@tonic-gate }
16257c478bd9Sstevel@tonic-gate }
16267c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next;
16277c478bd9Sstevel@tonic-gate }
16287c478bd9Sstevel@tonic-gate return seqjump;
16297c478bd9Sstevel@tonic-gate }
16307c478bd9Sstevel@tonic-gate #endif /* _FFR_SKIP_DOMAINS */
16317c478bd9Sstevel@tonic-gate
16327c478bd9Sstevel@tonic-gate /*
16337c478bd9Sstevel@tonic-gate ** RUNNER_WORK -- have a queue runner do its work
16347c478bd9Sstevel@tonic-gate **
16357c478bd9Sstevel@tonic-gate ** Have a queue runner do its work a list of entries.
16367c478bd9Sstevel@tonic-gate ** When work isn't directly being done then this process can take a signal
16377c478bd9Sstevel@tonic-gate ** and terminate immediately (in a clean fashion of course).
16387c478bd9Sstevel@tonic-gate ** When work is directly being done, it's not to be interrupted
16397c478bd9Sstevel@tonic-gate ** immediately: the work should be allowed to finish at a clean point
16407c478bd9Sstevel@tonic-gate ** before termination (in a clean fashion of course).
16417c478bd9Sstevel@tonic-gate **
16427c478bd9Sstevel@tonic-gate ** Parameters:
16437c478bd9Sstevel@tonic-gate ** e -- envelope.
16447c478bd9Sstevel@tonic-gate ** sequenceno -- 'th process to run WorkQ.
16457c478bd9Sstevel@tonic-gate ** didfork -- did the calling process fork()?
16467c478bd9Sstevel@tonic-gate ** skip -- process only each skip'th item.
16477c478bd9Sstevel@tonic-gate ** njobs -- number of jobs in WorkQ.
16487c478bd9Sstevel@tonic-gate **
16497c478bd9Sstevel@tonic-gate ** Returns:
16507c478bd9Sstevel@tonic-gate ** none.
16517c478bd9Sstevel@tonic-gate **
16527c478bd9Sstevel@tonic-gate ** Side Effects:
16537c478bd9Sstevel@tonic-gate ** runs things in the mail queue.
16547c478bd9Sstevel@tonic-gate */
16557c478bd9Sstevel@tonic-gate
16567c478bd9Sstevel@tonic-gate static void
runner_work(e,sequenceno,didfork,skip,njobs)16577c478bd9Sstevel@tonic-gate runner_work(e, sequenceno, didfork, skip, njobs)
16587c478bd9Sstevel@tonic-gate register ENVELOPE *e;
16597c478bd9Sstevel@tonic-gate int sequenceno;
16607c478bd9Sstevel@tonic-gate bool didfork;
16617c478bd9Sstevel@tonic-gate int skip;
16627c478bd9Sstevel@tonic-gate int njobs;
16637c478bd9Sstevel@tonic-gate {
16647c478bd9Sstevel@tonic-gate int n, seqjump;
16657c478bd9Sstevel@tonic-gate WORK *w;
16667c478bd9Sstevel@tonic-gate time_t now;
16677c478bd9Sstevel@tonic-gate
16687c478bd9Sstevel@tonic-gate SM_GET_LA(now);
16697c478bd9Sstevel@tonic-gate
16707c478bd9Sstevel@tonic-gate /*
16717c478bd9Sstevel@tonic-gate ** Here we temporarily block the second calling of the handlers.
16727c478bd9Sstevel@tonic-gate ** This allows us to handle the signal without terminating in the
16737c478bd9Sstevel@tonic-gate ** middle of direct work. If a signal does come, the test for
16747c478bd9Sstevel@tonic-gate ** NoMoreRunners will find it.
16757c478bd9Sstevel@tonic-gate */
16767c478bd9Sstevel@tonic-gate
16777c478bd9Sstevel@tonic-gate BlockOldsh = true;
16787c478bd9Sstevel@tonic-gate seqjump = skip;
16797c478bd9Sstevel@tonic-gate
16807c478bd9Sstevel@tonic-gate /* process them once at a time */
16817c478bd9Sstevel@tonic-gate while (WorkQ != NULL)
16827c478bd9Sstevel@tonic-gate {
16837c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK
16847c478bd9Sstevel@tonic-gate SM_NONVOLATILE int oldgroup = 0;
16857c478bd9Sstevel@tonic-gate
16867c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugLeakQ, 1))
16877c478bd9Sstevel@tonic-gate {
16887c478bd9Sstevel@tonic-gate oldgroup = sm_heap_group();
16897c478bd9Sstevel@tonic-gate sm_heap_newgroup();
16907c478bd9Sstevel@tonic-gate sm_dprintf("run_queue_group() heap group #%d\n",
16917c478bd9Sstevel@tonic-gate sm_heap_group());
16927c478bd9Sstevel@tonic-gate }
16937c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */
16947c478bd9Sstevel@tonic-gate
16957c478bd9Sstevel@tonic-gate /* do no more work */
16967c478bd9Sstevel@tonic-gate if (NoMoreRunners)
16977c478bd9Sstevel@tonic-gate {
16987c478bd9Sstevel@tonic-gate /* Check that a valid signal handler is callable */
16997c478bd9Sstevel@tonic-gate if (Oldsh != SIG_DFL && Oldsh != SIG_IGN &&
17007c478bd9Sstevel@tonic-gate Oldsh != runners_sighup &&
17017c478bd9Sstevel@tonic-gate Oldsh != runners_sigterm)
17027c478bd9Sstevel@tonic-gate (*Oldsh)(Oldsig);
17037c478bd9Sstevel@tonic-gate break;
17047c478bd9Sstevel@tonic-gate }
17057c478bd9Sstevel@tonic-gate
17067c478bd9Sstevel@tonic-gate w = WorkQ; /* assign current work item */
17077c478bd9Sstevel@tonic-gate
17087c478bd9Sstevel@tonic-gate /*
17097c478bd9Sstevel@tonic-gate ** Set the head of the WorkQ to the next work item.
17107c478bd9Sstevel@tonic-gate ** It is set 'skip' ahead (the number of parallel queue
17117c478bd9Sstevel@tonic-gate ** runners working on WorkQ together) since each runner
17127c478bd9Sstevel@tonic-gate ** works on every 'skip'th (N-th) item.
17137c478bd9Sstevel@tonic-gate #if _FFR_SKIP_DOMAINS
17147c478bd9Sstevel@tonic-gate ** In the case of the BYHOST Queue Sort Order, the 'item'
17157c478bd9Sstevel@tonic-gate ** is a domain, so we work on every 'skip'th (N-th) domain.
17167c478bd9Sstevel@tonic-gate #endif * _FFR_SKIP_DOMAINS *
17177c478bd9Sstevel@tonic-gate */
17187c478bd9Sstevel@tonic-gate
17197c478bd9Sstevel@tonic-gate #if _FFR_SKIP_DOMAINS
17207c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST)
17217c478bd9Sstevel@tonic-gate {
17227c478bd9Sstevel@tonic-gate seqjump = 1;
17237c478bd9Sstevel@tonic-gate if (WorkQ->w_next != NULL)
17247c478bd9Sstevel@tonic-gate {
17257c478bd9Sstevel@tonic-gate if (WorkQ->w_host != NULL &&
17267c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host != NULL)
17277c478bd9Sstevel@tonic-gate {
17287c478bd9Sstevel@tonic-gate if (sm_strcasecmp(WorkQ->w_host,
17297c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host)
17307c478bd9Sstevel@tonic-gate != 0)
17317c478bd9Sstevel@tonic-gate seqjump = skip_domains(skip);
17327c478bd9Sstevel@tonic-gate else
17337c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next;
17347c478bd9Sstevel@tonic-gate }
17357c478bd9Sstevel@tonic-gate else
17367c478bd9Sstevel@tonic-gate {
17377c478bd9Sstevel@tonic-gate if ((WorkQ->w_host != NULL &&
17387c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host == NULL) ||
17397c478bd9Sstevel@tonic-gate (WorkQ->w_host == NULL &&
17407c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host != NULL))
17417c478bd9Sstevel@tonic-gate seqjump = skip_domains(skip);
17427c478bd9Sstevel@tonic-gate else
17437c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next;
17447c478bd9Sstevel@tonic-gate }
17457c478bd9Sstevel@tonic-gate }
17467c478bd9Sstevel@tonic-gate else
17477c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next;
17487c478bd9Sstevel@tonic-gate }
17497c478bd9Sstevel@tonic-gate else
17507c478bd9Sstevel@tonic-gate #endif /* _FFR_SKIP_DOMAINS */
17517c478bd9Sstevel@tonic-gate {
17527c478bd9Sstevel@tonic-gate for (n = 0; n < skip && WorkQ != NULL; n++)
17537c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next;
17547c478bd9Sstevel@tonic-gate }
17557c478bd9Sstevel@tonic-gate
17567c478bd9Sstevel@tonic-gate e->e_to = NULL;
17577c478bd9Sstevel@tonic-gate
17587c478bd9Sstevel@tonic-gate /*
17597c478bd9Sstevel@tonic-gate ** Ignore jobs that are too expensive for the moment.
17607c478bd9Sstevel@tonic-gate **
17617c478bd9Sstevel@tonic-gate ** Get new load average every GET_NEW_LA_TIME seconds.
17627c478bd9Sstevel@tonic-gate */
17637c478bd9Sstevel@tonic-gate
17647c478bd9Sstevel@tonic-gate SM_GET_LA(now);
17657c478bd9Sstevel@tonic-gate if (shouldqueue(WkRecipFact, Current_LA_time))
17667c478bd9Sstevel@tonic-gate {
17677c478bd9Sstevel@tonic-gate char *msg = "Aborting queue run: load average too high";
17687c478bd9Sstevel@tonic-gate
17697c478bd9Sstevel@tonic-gate if (Verbose)
17707c478bd9Sstevel@tonic-gate message("%s", msg);
17717c478bd9Sstevel@tonic-gate if (LogLevel > 8)
17727c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "runqueue: %s", msg);
17737c478bd9Sstevel@tonic-gate break;
17747c478bd9Sstevel@tonic-gate }
17757c478bd9Sstevel@tonic-gate if (shouldqueue(w->w_pri, w->w_ctime))
17767c478bd9Sstevel@tonic-gate {
17777c478bd9Sstevel@tonic-gate if (Verbose)
17787c478bd9Sstevel@tonic-gate message(EmptyString);
17797c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYPRIORITY)
17807c478bd9Sstevel@tonic-gate {
17817c478bd9Sstevel@tonic-gate if (Verbose)
17827c478bd9Sstevel@tonic-gate message("Skipping %s/%s (sequence %d of %d) and flushing rest of queue",
17837c478bd9Sstevel@tonic-gate qid_printqueue(w->w_qgrp,
17847c478bd9Sstevel@tonic-gate w->w_qdir),
17857c478bd9Sstevel@tonic-gate w->w_name + 2, sequenceno,
17867c478bd9Sstevel@tonic-gate njobs);
17877c478bd9Sstevel@tonic-gate if (LogLevel > 8)
17887c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
17897c478bd9Sstevel@tonic-gate "runqueue: Flushing queue from %s/%s (pri %ld, LA %d, %d of %d)",
17907c478bd9Sstevel@tonic-gate qid_printqueue(w->w_qgrp,
17917c478bd9Sstevel@tonic-gate w->w_qdir),
17927c478bd9Sstevel@tonic-gate w->w_name + 2, w->w_pri,
17937c478bd9Sstevel@tonic-gate CurrentLA, sequenceno,
17947c478bd9Sstevel@tonic-gate njobs);
17957c478bd9Sstevel@tonic-gate break;
17967c478bd9Sstevel@tonic-gate }
17977c478bd9Sstevel@tonic-gate else if (Verbose)
17987c478bd9Sstevel@tonic-gate message("Skipping %s/%s (sequence %d of %d)",
17997c478bd9Sstevel@tonic-gate qid_printqueue(w->w_qgrp, w->w_qdir),
18007c478bd9Sstevel@tonic-gate w->w_name + 2, sequenceno, njobs);
18017c478bd9Sstevel@tonic-gate }
18027c478bd9Sstevel@tonic-gate else
18037c478bd9Sstevel@tonic-gate {
18047c478bd9Sstevel@tonic-gate if (Verbose)
18057c478bd9Sstevel@tonic-gate {
18067c478bd9Sstevel@tonic-gate message(EmptyString);
18077c478bd9Sstevel@tonic-gate message("Running %s/%s (sequence %d of %d)",
18087c478bd9Sstevel@tonic-gate qid_printqueue(w->w_qgrp, w->w_qdir),
18097c478bd9Sstevel@tonic-gate w->w_name + 2, sequenceno, njobs);
18107c478bd9Sstevel@tonic-gate }
18117c478bd9Sstevel@tonic-gate if (didfork && MaxQueueChildren > 0)
18127c478bd9Sstevel@tonic-gate {
18137c478bd9Sstevel@tonic-gate sm_blocksignal(SIGCHLD);
18147c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, reapchild);
18157c478bd9Sstevel@tonic-gate }
18167c478bd9Sstevel@tonic-gate if (tTd(63, 100))
18177c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, NOQID,
18187c478bd9Sstevel@tonic-gate "runqueue %s dowork(%s)",
18197c478bd9Sstevel@tonic-gate qid_printqueue(w->w_qgrp, w->w_qdir),
18207c478bd9Sstevel@tonic-gate w->w_name + 2);
18217c478bd9Sstevel@tonic-gate
18227c478bd9Sstevel@tonic-gate (void) dowork(w->w_qgrp, w->w_qdir, w->w_name + 2,
18237c478bd9Sstevel@tonic-gate ForkQueueRuns, false, e);
18247c478bd9Sstevel@tonic-gate errno = 0;
18257c478bd9Sstevel@tonic-gate }
18267c478bd9Sstevel@tonic-gate sm_free(w->w_name); /* XXX */
18277c478bd9Sstevel@tonic-gate if (w->w_host != NULL)
18287c478bd9Sstevel@tonic-gate sm_free(w->w_host); /* XXX */
18297c478bd9Sstevel@tonic-gate sm_free((char *) w); /* XXX */
18307c478bd9Sstevel@tonic-gate sequenceno += seqjump; /* next sequence number */
18317c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK
18327c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugLeakQ, 1))
18337c478bd9Sstevel@tonic-gate sm_heap_setgroup(oldgroup);
18347c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */
18357c478bd9Sstevel@tonic-gate }
18367c478bd9Sstevel@tonic-gate
18377c478bd9Sstevel@tonic-gate BlockOldsh = false;
18387c478bd9Sstevel@tonic-gate
18397c478bd9Sstevel@tonic-gate /* check the signals didn't happen during the revert */
18407c478bd9Sstevel@tonic-gate if (NoMoreRunners)
18417c478bd9Sstevel@tonic-gate {
18427c478bd9Sstevel@tonic-gate /* Check that a valid signal handler is callable */
18437c478bd9Sstevel@tonic-gate if (Oldsh != SIG_DFL && Oldsh != SIG_IGN &&
18447c478bd9Sstevel@tonic-gate Oldsh != runners_sighup && Oldsh != runners_sigterm)
18457c478bd9Sstevel@tonic-gate (*Oldsh)(Oldsig);
18467c478bd9Sstevel@tonic-gate }
18477c478bd9Sstevel@tonic-gate
18487c478bd9Sstevel@tonic-gate Oldsh = SIG_DFL; /* after the NoMoreRunners check */
18497c478bd9Sstevel@tonic-gate }
18507c478bd9Sstevel@tonic-gate /*
18517c478bd9Sstevel@tonic-gate ** RUN_WORK_GROUP -- run the jobs in a queue group from a work group.
18527c478bd9Sstevel@tonic-gate **
18537c478bd9Sstevel@tonic-gate ** Gets the stuff out of the queue in some presumably logical
18547c478bd9Sstevel@tonic-gate ** order and processes them.
18557c478bd9Sstevel@tonic-gate **
18567c478bd9Sstevel@tonic-gate ** Parameters:
18577c478bd9Sstevel@tonic-gate ** wgrp -- work group to process.
18587c478bd9Sstevel@tonic-gate ** flags -- RWG_* flags
18597c478bd9Sstevel@tonic-gate **
18607c478bd9Sstevel@tonic-gate ** Returns:
18617c478bd9Sstevel@tonic-gate ** true if the queue run successfully began.
18627c478bd9Sstevel@tonic-gate **
18637c478bd9Sstevel@tonic-gate ** Side Effects:
18647c478bd9Sstevel@tonic-gate ** runs things in the mail queue.
18657c478bd9Sstevel@tonic-gate */
18667c478bd9Sstevel@tonic-gate
18677c478bd9Sstevel@tonic-gate /* Minimum sleep time for persistent queue runners */
18687c478bd9Sstevel@tonic-gate #define MIN_SLEEP_TIME 5
18697c478bd9Sstevel@tonic-gate
18707c478bd9Sstevel@tonic-gate bool
run_work_group(wgrp,flags)18717c478bd9Sstevel@tonic-gate run_work_group(wgrp, flags)
18727c478bd9Sstevel@tonic-gate int wgrp;
18737c478bd9Sstevel@tonic-gate int flags;
18747c478bd9Sstevel@tonic-gate {
18757c478bd9Sstevel@tonic-gate register ENVELOPE *e;
18767c478bd9Sstevel@tonic-gate int njobs, qdir;
18777c478bd9Sstevel@tonic-gate int sequenceno = 1;
18787c478bd9Sstevel@tonic-gate int qgrp, endgrp, h, i;
18797c478bd9Sstevel@tonic-gate time_t now;
18807c478bd9Sstevel@tonic-gate bool full, more;
18817c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool;
18827c478bd9Sstevel@tonic-gate extern ENVELOPE BlankEnvelope;
18837c478bd9Sstevel@tonic-gate extern SIGFUNC_DECL reapchild __P((int));
18847c478bd9Sstevel@tonic-gate
18857c478bd9Sstevel@tonic-gate if (wgrp < 0)
18867c478bd9Sstevel@tonic-gate return false;
18877c478bd9Sstevel@tonic-gate
18887c478bd9Sstevel@tonic-gate /*
18897c478bd9Sstevel@tonic-gate ** If no work will ever be selected, don't even bother reading
18907c478bd9Sstevel@tonic-gate ** the queue.
18917c478bd9Sstevel@tonic-gate */
18927c478bd9Sstevel@tonic-gate
18937c478bd9Sstevel@tonic-gate SM_GET_LA(now);
18947c478bd9Sstevel@tonic-gate
18957c478bd9Sstevel@tonic-gate if (!bitset(RWG_PERSISTENT, flags) &&
18967c478bd9Sstevel@tonic-gate shouldqueue(WkRecipFact, Current_LA_time))
18977c478bd9Sstevel@tonic-gate {
18987c478bd9Sstevel@tonic-gate char *msg = "Skipping queue run -- load average too high";
18997c478bd9Sstevel@tonic-gate
19007c478bd9Sstevel@tonic-gate if (bitset(RWG_VERBOSE, flags))
19017c478bd9Sstevel@tonic-gate message("458 %s\n", msg);
19027c478bd9Sstevel@tonic-gate if (LogLevel > 8)
19037c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "runqueue: %s", msg);
19047c478bd9Sstevel@tonic-gate return false;
19057c478bd9Sstevel@tonic-gate }
19067c478bd9Sstevel@tonic-gate
19077c478bd9Sstevel@tonic-gate /*
19087c478bd9Sstevel@tonic-gate ** See if we already have too many children.
19097c478bd9Sstevel@tonic-gate */
19107c478bd9Sstevel@tonic-gate
19117c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags) &&
19127c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_lowqintvl > 0 &&
19137c478bd9Sstevel@tonic-gate !bitset(RWG_PERSISTENT, flags) &&
19147c478bd9Sstevel@tonic-gate MaxChildren > 0 && CurChildren >= MaxChildren)
19157c478bd9Sstevel@tonic-gate {
19167c478bd9Sstevel@tonic-gate char *msg = "Skipping queue run -- too many children";
19177c478bd9Sstevel@tonic-gate
19187c478bd9Sstevel@tonic-gate if (bitset(RWG_VERBOSE, flags))
19197c478bd9Sstevel@tonic-gate message("458 %s (%d)\n", msg, CurChildren);
19207c478bd9Sstevel@tonic-gate if (LogLevel > 8)
19217c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "runqueue: %s (%d)",
19227c478bd9Sstevel@tonic-gate msg, CurChildren);
19237c478bd9Sstevel@tonic-gate return false;
19247c478bd9Sstevel@tonic-gate }
19257c478bd9Sstevel@tonic-gate
19267c478bd9Sstevel@tonic-gate /*
19277c478bd9Sstevel@tonic-gate ** See if we want to go off and do other useful work.
19287c478bd9Sstevel@tonic-gate */
19297c478bd9Sstevel@tonic-gate
19307c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags))
19317c478bd9Sstevel@tonic-gate {
19327c478bd9Sstevel@tonic-gate pid_t pid;
19337c478bd9Sstevel@tonic-gate
19347c478bd9Sstevel@tonic-gate (void) sm_blocksignal(SIGCHLD);
19357c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, reapchild);
19367c478bd9Sstevel@tonic-gate
19377c478bd9Sstevel@tonic-gate pid = dofork();
19387c478bd9Sstevel@tonic-gate if (pid == -1)
19397c478bd9Sstevel@tonic-gate {
19407c478bd9Sstevel@tonic-gate const char *msg = "Skipping queue run -- fork() failed";
19417c478bd9Sstevel@tonic-gate const char *err = sm_errstring(errno);
19427c478bd9Sstevel@tonic-gate
19437c478bd9Sstevel@tonic-gate if (bitset(RWG_VERBOSE, flags))
19447c478bd9Sstevel@tonic-gate message("458 %s: %s\n", msg, err);
19457c478bd9Sstevel@tonic-gate if (LogLevel > 8)
19467c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "runqueue: %s: %s",
19477c478bd9Sstevel@tonic-gate msg, err);
19487c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGCHLD);
19497c478bd9Sstevel@tonic-gate return false;
19507c478bd9Sstevel@tonic-gate }
19517c478bd9Sstevel@tonic-gate if (pid != 0)
19527c478bd9Sstevel@tonic-gate {
19537c478bd9Sstevel@tonic-gate /* parent -- pick up intermediate zombie */
19547c478bd9Sstevel@tonic-gate (void) sm_blocksignal(SIGALRM);
19557c478bd9Sstevel@tonic-gate
19567c478bd9Sstevel@tonic-gate /* wgrp only used when queue runners are persistent */
19577c478bd9Sstevel@tonic-gate proc_list_add(pid, "Queue runner", PROC_QUEUE,
19587c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_maxact,
19597c478bd9Sstevel@tonic-gate bitset(RWG_PERSISTENT, flags) ? wgrp : -1,
19607c478bd9Sstevel@tonic-gate NULL);
19617c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGALRM);
19627c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGCHLD);
19637c478bd9Sstevel@tonic-gate return true;
19647c478bd9Sstevel@tonic-gate }
19657c478bd9Sstevel@tonic-gate
19667c478bd9Sstevel@tonic-gate /* child -- clean up signals */
19677c478bd9Sstevel@tonic-gate
19687c478bd9Sstevel@tonic-gate /* Reset global flags */
19697c478bd9Sstevel@tonic-gate RestartRequest = NULL;
19707c478bd9Sstevel@tonic-gate RestartWorkGroup = false;
19717c478bd9Sstevel@tonic-gate ShutdownRequest = NULL;
19727c478bd9Sstevel@tonic-gate PendingSignal = 0;
19737c478bd9Sstevel@tonic-gate CurrentPid = getpid();
19747c478bd9Sstevel@tonic-gate close_sendmail_pid();
19757c478bd9Sstevel@tonic-gate
19767c478bd9Sstevel@tonic-gate /*
19777c478bd9Sstevel@tonic-gate ** Initialize exception stack and default exception
19787c478bd9Sstevel@tonic-gate ** handler for child process.
19797c478bd9Sstevel@tonic-gate */
19807c478bd9Sstevel@tonic-gate
19817c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error);
19827c478bd9Sstevel@tonic-gate clrcontrol();
19837c478bd9Sstevel@tonic-gate proc_list_clear();
19847c478bd9Sstevel@tonic-gate
19857c478bd9Sstevel@tonic-gate /* Add parent process as first child item */
19867c478bd9Sstevel@tonic-gate proc_list_add(CurrentPid, "Queue runner child process",
19877c478bd9Sstevel@tonic-gate PROC_QUEUE_CHILD, 0, -1, NULL);
19887c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGCHLD);
19897c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL);
19907c478bd9Sstevel@tonic-gate (void) sm_signal(SIGHUP, SIG_DFL);
19917c478bd9Sstevel@tonic-gate (void) sm_signal(SIGTERM, intsig);
19927c478bd9Sstevel@tonic-gate }
19937c478bd9Sstevel@tonic-gate
19947c478bd9Sstevel@tonic-gate /*
19957c478bd9Sstevel@tonic-gate ** Release any resources used by the daemon code.
19967c478bd9Sstevel@tonic-gate */
19977c478bd9Sstevel@tonic-gate
19987c478bd9Sstevel@tonic-gate clrdaemon();
19997c478bd9Sstevel@tonic-gate
20007c478bd9Sstevel@tonic-gate /* force it to run expensive jobs */
20017c478bd9Sstevel@tonic-gate NoConnect = false;
20027c478bd9Sstevel@tonic-gate
20037c478bd9Sstevel@tonic-gate /* drop privileges */
20047c478bd9Sstevel@tonic-gate if (geteuid() == (uid_t) 0)
20057c478bd9Sstevel@tonic-gate (void) drop_privileges(false);
20067c478bd9Sstevel@tonic-gate
20077c478bd9Sstevel@tonic-gate /*
20087c478bd9Sstevel@tonic-gate ** Create ourselves an envelope
20097c478bd9Sstevel@tonic-gate */
20107c478bd9Sstevel@tonic-gate
20117c478bd9Sstevel@tonic-gate CurEnv = &QueueEnvelope;
20127c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL);
20137c478bd9Sstevel@tonic-gate e = newenvelope(&QueueEnvelope, CurEnv, rpool);
20147c478bd9Sstevel@tonic-gate e->e_flags = BlankEnvelope.e_flags;
20157c478bd9Sstevel@tonic-gate e->e_parent = NULL;
20167c478bd9Sstevel@tonic-gate
20177c478bd9Sstevel@tonic-gate /* make sure we have disconnected from parent */
20187c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags))
20197c478bd9Sstevel@tonic-gate {
20207c478bd9Sstevel@tonic-gate disconnect(1, e);
20217c478bd9Sstevel@tonic-gate QuickAbort = false;
20227c478bd9Sstevel@tonic-gate }
20237c478bd9Sstevel@tonic-gate
20247c478bd9Sstevel@tonic-gate /*
20257c478bd9Sstevel@tonic-gate ** If we are running part of the queue, always ignore stored
20267c478bd9Sstevel@tonic-gate ** host status.
20277c478bd9Sstevel@tonic-gate */
20287c478bd9Sstevel@tonic-gate
20297c478bd9Sstevel@tonic-gate if (QueueLimitId != NULL || QueueLimitSender != NULL ||
20307c478bd9Sstevel@tonic-gate QueueLimitQuarantine != NULL ||
20317c478bd9Sstevel@tonic-gate QueueLimitRecipient != NULL)
20327c478bd9Sstevel@tonic-gate {
20337c478bd9Sstevel@tonic-gate IgnoreHostStatus = true;
20347c478bd9Sstevel@tonic-gate MinQueueAge = 0;
20357c478bd9Sstevel@tonic-gate }
20367c478bd9Sstevel@tonic-gate
20377c478bd9Sstevel@tonic-gate /*
20387c478bd9Sstevel@tonic-gate ** Here is where we choose the queue group from the work group.
20397c478bd9Sstevel@tonic-gate ** The caller of the "domorework" label must setup a new envelope.
20407c478bd9Sstevel@tonic-gate */
20417c478bd9Sstevel@tonic-gate
20427c478bd9Sstevel@tonic-gate endgrp = WorkGrp[wgrp].wg_curqgrp; /* to not spin endlessly */
20437c478bd9Sstevel@tonic-gate
20447c478bd9Sstevel@tonic-gate domorework:
20457c478bd9Sstevel@tonic-gate
20467c478bd9Sstevel@tonic-gate /*
20477c478bd9Sstevel@tonic-gate ** Run a queue group if:
20487c478bd9Sstevel@tonic-gate ** RWG_RUNALL bit is set or the bit for this group is set.
20497c478bd9Sstevel@tonic-gate */
20507c478bd9Sstevel@tonic-gate
20517c478bd9Sstevel@tonic-gate now = curtime();
20527c478bd9Sstevel@tonic-gate for (;;)
20537c478bd9Sstevel@tonic-gate {
20547c478bd9Sstevel@tonic-gate /*
20557c478bd9Sstevel@tonic-gate ** Find the next queue group within the work group that
20567c478bd9Sstevel@tonic-gate ** has been marked as needing a run.
20577c478bd9Sstevel@tonic-gate */
20587c478bd9Sstevel@tonic-gate
20597c478bd9Sstevel@tonic-gate qgrp = WorkGrp[wgrp].wg_qgs[WorkGrp[wgrp].wg_curqgrp]->qg_index;
20607c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_curqgrp++; /* advance */
20617c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_curqgrp %= WorkGrp[wgrp].wg_numqgrp; /* wrap */
20627c478bd9Sstevel@tonic-gate if (bitset(RWG_RUNALL, flags) ||
20637c478bd9Sstevel@tonic-gate (Queue[qgrp]->qg_nextrun <= now &&
20647c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_nextrun != (time_t) -1))
20657c478bd9Sstevel@tonic-gate break;
20667c478bd9Sstevel@tonic-gate if (endgrp == WorkGrp[wgrp].wg_curqgrp)
20677c478bd9Sstevel@tonic-gate {
20687c478bd9Sstevel@tonic-gate e->e_id = NULL;
20697c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags))
20707c478bd9Sstevel@tonic-gate finis(true, true, ExitStat);
20717c478bd9Sstevel@tonic-gate return true; /* we're done */
20727c478bd9Sstevel@tonic-gate }
20737c478bd9Sstevel@tonic-gate }
20747c478bd9Sstevel@tonic-gate
20757c478bd9Sstevel@tonic-gate qdir = Queue[qgrp]->qg_curnum; /* round-robin init of queue position */
20767c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG
20777c478bd9Sstevel@tonic-gate if (tTd(69, 12))
20787c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
20797c478bd9Sstevel@tonic-gate "rwg: wgrp=%d, qgrp=%d, qdir=%d, name=%s, curqgrp=%d, numgrps=%d",
20807c478bd9Sstevel@tonic-gate wgrp, qgrp, qdir, qid_printqueue(qgrp, qdir),
20817c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_curqgrp, WorkGrp[wgrp].wg_numqgrp);
20827c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */
20837c478bd9Sstevel@tonic-gate
20847c478bd9Sstevel@tonic-gate #if HASNICE
20857c478bd9Sstevel@tonic-gate /* tweak niceness of queue runs */
20867c478bd9Sstevel@tonic-gate if (Queue[qgrp]->qg_nice > 0)
20877c478bd9Sstevel@tonic-gate (void) nice(Queue[qgrp]->qg_nice);
20887c478bd9Sstevel@tonic-gate #endif /* HASNICE */
20897c478bd9Sstevel@tonic-gate
20907c478bd9Sstevel@tonic-gate /* XXX running queue group... */
20917c478bd9Sstevel@tonic-gate sm_setproctitle(true, CurEnv, "running queue: %s",
20927c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir));
20937c478bd9Sstevel@tonic-gate
20947c478bd9Sstevel@tonic-gate if (LogLevel > 69 || tTd(63, 99))
20957c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, NOQID,
20967c478bd9Sstevel@tonic-gate "runqueue %s, pid=%d, forkflag=%d",
20977c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), (int) CurrentPid,
20987c478bd9Sstevel@tonic-gate bitset(RWG_FORK, flags));
20997c478bd9Sstevel@tonic-gate
21007c478bd9Sstevel@tonic-gate /*
21017c478bd9Sstevel@tonic-gate ** Start making passes through the queue.
21027c478bd9Sstevel@tonic-gate ** First, read and sort the entire queue.
21037c478bd9Sstevel@tonic-gate ** Then, process the work in that order.
21047c478bd9Sstevel@tonic-gate ** But if you take too long, start over.
21057c478bd9Sstevel@tonic-gate */
21067c478bd9Sstevel@tonic-gate
21077c478bd9Sstevel@tonic-gate for (i = 0; i < Queue[qgrp]->qg_numqueues; i++)
21087c478bd9Sstevel@tonic-gate {
2109e9af4bc0SJohn Beck (void) gatherq(qgrp, qdir, false, &full, &more, &h);
21107c478bd9Sstevel@tonic-gate #if SM_CONF_SHM
21117c478bd9Sstevel@tonic-gate if (ShmId != SM_SHM_NO_ID)
21127c478bd9Sstevel@tonic-gate QSHM_ENTRIES(Queue[qgrp]->qg_qpaths[qdir].qp_idx) = h;
21137c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */
21147c478bd9Sstevel@tonic-gate /* If there are no more items in this queue advance */
21157c478bd9Sstevel@tonic-gate if (!more)
21167c478bd9Sstevel@tonic-gate {
21177c478bd9Sstevel@tonic-gate /* A round-robin advance */
21187c478bd9Sstevel@tonic-gate qdir++;
21197c478bd9Sstevel@tonic-gate qdir %= Queue[qgrp]->qg_numqueues;
21207c478bd9Sstevel@tonic-gate }
21217c478bd9Sstevel@tonic-gate
21227c478bd9Sstevel@tonic-gate /* Has the WorkList reached the limit? */
21237c478bd9Sstevel@tonic-gate if (full)
21247c478bd9Sstevel@tonic-gate break; /* don't try to gather more */
21257c478bd9Sstevel@tonic-gate }
21267c478bd9Sstevel@tonic-gate
21277c478bd9Sstevel@tonic-gate /* order the existing work requests */
21287c478bd9Sstevel@tonic-gate njobs = sortq(Queue[qgrp]->qg_maxlist);
21297c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_curnum = qdir; /* update */
21307c478bd9Sstevel@tonic-gate
21317c478bd9Sstevel@tonic-gate
21327c478bd9Sstevel@tonic-gate if (!Verbose && bitnset(QD_FORK, Queue[qgrp]->qg_flags))
21337c478bd9Sstevel@tonic-gate {
21347c478bd9Sstevel@tonic-gate int loop, maxrunners;
21357c478bd9Sstevel@tonic-gate pid_t pid;
21367c478bd9Sstevel@tonic-gate
21377c478bd9Sstevel@tonic-gate /*
21387c478bd9Sstevel@tonic-gate ** For this WorkQ we want to fork off N children (maxrunners)
21397c478bd9Sstevel@tonic-gate ** at this point. Each child has a copy of WorkQ. Each child
21407c478bd9Sstevel@tonic-gate ** will process every N-th item. The parent will wait for all
21417c478bd9Sstevel@tonic-gate ** of the children to finish before moving on to the next
21427c478bd9Sstevel@tonic-gate ** queue group within the work group. This saves us forking
21437c478bd9Sstevel@tonic-gate ** a new runner-child for each work item.
21447c478bd9Sstevel@tonic-gate ** It's valid for qg_maxqrun == 0 since this may be an
21457c478bd9Sstevel@tonic-gate ** explicit "don't run this queue" setting.
21467c478bd9Sstevel@tonic-gate */
21477c478bd9Sstevel@tonic-gate
21487c478bd9Sstevel@tonic-gate maxrunners = Queue[qgrp]->qg_maxqrun;
21497c478bd9Sstevel@tonic-gate
21507800901eSjbeck /*
21517800901eSjbeck ** If no runners are configured for this group but
21527800901eSjbeck ** the queue is "forced" then lets use 1 runner.
21537800901eSjbeck */
21547800901eSjbeck
21557800901eSjbeck if (maxrunners == 0 && bitset(RWG_FORCE, flags))
21567800901eSjbeck maxrunners = 1;
21577800901eSjbeck
21587c478bd9Sstevel@tonic-gate /* No need to have more runners then there are jobs */
21597c478bd9Sstevel@tonic-gate if (maxrunners > njobs)
21607c478bd9Sstevel@tonic-gate maxrunners = njobs;
21617c478bd9Sstevel@tonic-gate for (loop = 0; loop < maxrunners; loop++)
21627c478bd9Sstevel@tonic-gate {
21637c478bd9Sstevel@tonic-gate /*
21647c478bd9Sstevel@tonic-gate ** Since the delivery may happen in a child and the
21657c478bd9Sstevel@tonic-gate ** parent does not wait, the parent may close the
21667c478bd9Sstevel@tonic-gate ** maps thereby removing any shared memory used by
21677c478bd9Sstevel@tonic-gate ** the map. Therefore, close the maps now so the
21687c478bd9Sstevel@tonic-gate ** child will dynamically open them if necessary.
21697c478bd9Sstevel@tonic-gate */
21707c478bd9Sstevel@tonic-gate
21717c478bd9Sstevel@tonic-gate closemaps(false);
21727c478bd9Sstevel@tonic-gate
21737c478bd9Sstevel@tonic-gate pid = fork();
21747c478bd9Sstevel@tonic-gate if (pid < 0)
21757c478bd9Sstevel@tonic-gate {
21767c478bd9Sstevel@tonic-gate syserr("run_work_group: cannot fork");
21777c478bd9Sstevel@tonic-gate return false;
21787c478bd9Sstevel@tonic-gate }
21797c478bd9Sstevel@tonic-gate else if (pid > 0)
21807c478bd9Sstevel@tonic-gate {
21817c478bd9Sstevel@tonic-gate /* parent -- clean out connection cache */
21827c478bd9Sstevel@tonic-gate mci_flush(false, NULL);
21837c478bd9Sstevel@tonic-gate #if _FFR_SKIP_DOMAINS
21847c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST)
21857c478bd9Sstevel@tonic-gate {
21867c478bd9Sstevel@tonic-gate sequenceno += skip_domains(1);
21877c478bd9Sstevel@tonic-gate }
21887c478bd9Sstevel@tonic-gate else
21897c478bd9Sstevel@tonic-gate #endif /* _FFR_SKIP_DOMAINS */
21907c478bd9Sstevel@tonic-gate {
21917c478bd9Sstevel@tonic-gate /* for the skip */
21927c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next;
21937c478bd9Sstevel@tonic-gate sequenceno++;
21947c478bd9Sstevel@tonic-gate }
21957c478bd9Sstevel@tonic-gate proc_list_add(pid, "Queue child runner process",
21967c478bd9Sstevel@tonic-gate PROC_QUEUE_CHILD, 0, -1, NULL);
21977c478bd9Sstevel@tonic-gate
21987c478bd9Sstevel@tonic-gate /* No additional work, no additional runners */
21997c478bd9Sstevel@tonic-gate if (WorkQ == NULL)
22007c478bd9Sstevel@tonic-gate break;
22017c478bd9Sstevel@tonic-gate }
22027c478bd9Sstevel@tonic-gate else
22037c478bd9Sstevel@tonic-gate {
22047c478bd9Sstevel@tonic-gate /* child -- Reset global flags */
22057c478bd9Sstevel@tonic-gate RestartRequest = NULL;
22067c478bd9Sstevel@tonic-gate RestartWorkGroup = false;
22077c478bd9Sstevel@tonic-gate ShutdownRequest = NULL;
22087c478bd9Sstevel@tonic-gate PendingSignal = 0;
22097c478bd9Sstevel@tonic-gate CurrentPid = getpid();
22107c478bd9Sstevel@tonic-gate close_sendmail_pid();
22117c478bd9Sstevel@tonic-gate
22127c478bd9Sstevel@tonic-gate /*
22137c478bd9Sstevel@tonic-gate ** Initialize exception stack and default
22147c478bd9Sstevel@tonic-gate ** exception handler for child process.
22157c478bd9Sstevel@tonic-gate ** When fork()'d the child now has a private
22167c478bd9Sstevel@tonic-gate ** copy of WorkQ at its current position.
22177c478bd9Sstevel@tonic-gate */
22187c478bd9Sstevel@tonic-gate
22197c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error);
22207c478bd9Sstevel@tonic-gate
22217c478bd9Sstevel@tonic-gate /*
22227c478bd9Sstevel@tonic-gate ** SMTP processes (whether -bd or -bs) set
22237c478bd9Sstevel@tonic-gate ** SIGCHLD to reapchild to collect
22247c478bd9Sstevel@tonic-gate ** children status. However, at delivery
22257c478bd9Sstevel@tonic-gate ** time, that status must be collected
22267c478bd9Sstevel@tonic-gate ** by sm_wait() to be dealt with properly
22277c478bd9Sstevel@tonic-gate ** (check success of delivery based
22287c478bd9Sstevel@tonic-gate ** on status code, etc). Therefore, if we
22297c478bd9Sstevel@tonic-gate ** are an SMTP process, reset SIGCHLD
22307c478bd9Sstevel@tonic-gate ** back to the default so reapchild
22317c478bd9Sstevel@tonic-gate ** doesn't collect status before
22327c478bd9Sstevel@tonic-gate ** sm_wait().
22337c478bd9Sstevel@tonic-gate */
22347c478bd9Sstevel@tonic-gate
22357c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP ||
22367c478bd9Sstevel@tonic-gate OpMode == MD_DAEMON ||
22377c478bd9Sstevel@tonic-gate MaxQueueChildren > 0)
22387c478bd9Sstevel@tonic-gate {
22397c478bd9Sstevel@tonic-gate proc_list_clear();
22407c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD);
22417c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL);
22427c478bd9Sstevel@tonic-gate }
22437c478bd9Sstevel@tonic-gate
22447c478bd9Sstevel@tonic-gate /* child -- error messages to the transcript */
22457c478bd9Sstevel@tonic-gate QuickAbort = OnlyOneError = false;
22467c478bd9Sstevel@tonic-gate runner_work(e, sequenceno, true,
22477c478bd9Sstevel@tonic-gate maxrunners, njobs);
22487c478bd9Sstevel@tonic-gate
22497c478bd9Sstevel@tonic-gate /* This child is done */
22507c478bd9Sstevel@tonic-gate finis(true, true, ExitStat);
22517c478bd9Sstevel@tonic-gate /* NOTREACHED */
22527c478bd9Sstevel@tonic-gate }
22537c478bd9Sstevel@tonic-gate }
22547c478bd9Sstevel@tonic-gate
22557c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD);
22567c478bd9Sstevel@tonic-gate
22577c478bd9Sstevel@tonic-gate /*
22587c478bd9Sstevel@tonic-gate ** Wait until all of the runners have completed before
22597c478bd9Sstevel@tonic-gate ** seeing if there is another queue group in the
22607c478bd9Sstevel@tonic-gate ** work group to process.
22617c478bd9Sstevel@tonic-gate ** XXX Future enhancement: don't wait() for all children
22627c478bd9Sstevel@tonic-gate ** here, just go ahead and make sure that overall the number
22637c478bd9Sstevel@tonic-gate ** of children is not exceeded.
22647c478bd9Sstevel@tonic-gate */
22657c478bd9Sstevel@tonic-gate
22667c478bd9Sstevel@tonic-gate while (CurChildren > 0)
22677c478bd9Sstevel@tonic-gate {
22687c478bd9Sstevel@tonic-gate int status;
22697c478bd9Sstevel@tonic-gate pid_t ret;
22707c478bd9Sstevel@tonic-gate
22717c478bd9Sstevel@tonic-gate while ((ret = sm_wait(&status)) <= 0)
22727c478bd9Sstevel@tonic-gate continue;
22737c478bd9Sstevel@tonic-gate proc_list_drop(ret, status, NULL);
22747c478bd9Sstevel@tonic-gate }
22757c478bd9Sstevel@tonic-gate }
22767c478bd9Sstevel@tonic-gate else if (Queue[qgrp]->qg_maxqrun > 0 || bitset(RWG_FORCE, flags))
22777c478bd9Sstevel@tonic-gate {
22787c478bd9Sstevel@tonic-gate /*
22797c478bd9Sstevel@tonic-gate ** When current process will not fork children to do the work,
22807c478bd9Sstevel@tonic-gate ** it will do the work itself. The 'skip' will be 1 since
22817c478bd9Sstevel@tonic-gate ** there are no child runners to divide the work across.
22827c478bd9Sstevel@tonic-gate */
22837c478bd9Sstevel@tonic-gate
22847c478bd9Sstevel@tonic-gate runner_work(e, sequenceno, false, 1, njobs);
22857c478bd9Sstevel@tonic-gate }
22867c478bd9Sstevel@tonic-gate
22877c478bd9Sstevel@tonic-gate /* free memory allocated by newenvelope() above */
22887c478bd9Sstevel@tonic-gate sm_rpool_free(rpool);
22897c478bd9Sstevel@tonic-gate QueueEnvelope.e_rpool = NULL;
22907c478bd9Sstevel@tonic-gate
22917c478bd9Sstevel@tonic-gate /* Are there still more queues in the work group to process? */
22927c478bd9Sstevel@tonic-gate if (endgrp != WorkGrp[wgrp].wg_curqgrp)
22937c478bd9Sstevel@tonic-gate {
22947c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL);
22957c478bd9Sstevel@tonic-gate e = newenvelope(&QueueEnvelope, CurEnv, rpool);
22967c478bd9Sstevel@tonic-gate e->e_flags = BlankEnvelope.e_flags;
22977c478bd9Sstevel@tonic-gate goto domorework;
22987c478bd9Sstevel@tonic-gate }
22997c478bd9Sstevel@tonic-gate
23007c478bd9Sstevel@tonic-gate /* No more queues in work group to process. Now check persistent. */
23017c478bd9Sstevel@tonic-gate if (bitset(RWG_PERSISTENT, flags))
23027c478bd9Sstevel@tonic-gate {
23037c478bd9Sstevel@tonic-gate sequenceno = 1;
23047c478bd9Sstevel@tonic-gate sm_setproctitle(true, CurEnv, "running queue: %s",
23057c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir));
23067c478bd9Sstevel@tonic-gate
23077c478bd9Sstevel@tonic-gate /*
23087c478bd9Sstevel@tonic-gate ** close bogus maps, i.e., maps which caused a tempfail,
23097c478bd9Sstevel@tonic-gate ** so we get fresh map connections on the next lookup.
23107c478bd9Sstevel@tonic-gate ** closemaps() is also called when children are started.
23117c478bd9Sstevel@tonic-gate */
23127c478bd9Sstevel@tonic-gate
23137c478bd9Sstevel@tonic-gate closemaps(true);
23147c478bd9Sstevel@tonic-gate
23157c478bd9Sstevel@tonic-gate /* Close any cached connections. */
23167c478bd9Sstevel@tonic-gate mci_flush(true, NULL);
23177c478bd9Sstevel@tonic-gate
23187c478bd9Sstevel@tonic-gate /* Clean out expired related entries. */
23197c478bd9Sstevel@tonic-gate rmexpstab();
23207c478bd9Sstevel@tonic-gate
23217c478bd9Sstevel@tonic-gate #if NAMED_BIND
23227c478bd9Sstevel@tonic-gate /* Update MX records for FallbackMX. */
23237c478bd9Sstevel@tonic-gate if (FallbackMX != NULL)
23247c478bd9Sstevel@tonic-gate (void) getfallbackmxrr(FallbackMX);
23257c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */
23267c478bd9Sstevel@tonic-gate
23277c478bd9Sstevel@tonic-gate #if USERDB
23287c478bd9Sstevel@tonic-gate /* close UserDatabase */
23297c478bd9Sstevel@tonic-gate _udbx_close();
23307c478bd9Sstevel@tonic-gate #endif /* USERDB */
23317c478bd9Sstevel@tonic-gate
23327c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK
23337c478bd9Sstevel@tonic-gate if (sm_debug_active(&SmHeapCheck, 2)
23347c478bd9Sstevel@tonic-gate && access("memdump", F_OK) == 0
23357c478bd9Sstevel@tonic-gate )
23367c478bd9Sstevel@tonic-gate {
23377c478bd9Sstevel@tonic-gate SM_FILE_T *out;
23387c478bd9Sstevel@tonic-gate
23397c478bd9Sstevel@tonic-gate remove("memdump");
23407c478bd9Sstevel@tonic-gate out = sm_io_open(SmFtStdio, SM_TIME_DEFAULT,
23417c478bd9Sstevel@tonic-gate "memdump.out", SM_IO_APPEND, NULL);
23427c478bd9Sstevel@tonic-gate if (out != NULL)
23437c478bd9Sstevel@tonic-gate {
23447c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, "----------------------\n");
23457c478bd9Sstevel@tonic-gate sm_heap_report(out,
23467c478bd9Sstevel@tonic-gate sm_debug_level(&SmHeapCheck) - 1);
23477c478bd9Sstevel@tonic-gate (void) sm_io_close(out, SM_TIME_DEFAULT);
23487c478bd9Sstevel@tonic-gate }
23497c478bd9Sstevel@tonic-gate }
23507c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */
23517c478bd9Sstevel@tonic-gate
23527c478bd9Sstevel@tonic-gate /* let me rest for a second to catch my breath */
23537c478bd9Sstevel@tonic-gate if (njobs == 0 && WorkGrp[wgrp].wg_lowqintvl < MIN_SLEEP_TIME)
23547c478bd9Sstevel@tonic-gate sleep(MIN_SLEEP_TIME);
23557c478bd9Sstevel@tonic-gate else if (WorkGrp[wgrp].wg_lowqintvl <= 0)
23567c478bd9Sstevel@tonic-gate sleep(QueueIntvl > 0 ? QueueIntvl : MIN_SLEEP_TIME);
23577c478bd9Sstevel@tonic-gate else
23587c478bd9Sstevel@tonic-gate sleep(WorkGrp[wgrp].wg_lowqintvl);
23597c478bd9Sstevel@tonic-gate
23607c478bd9Sstevel@tonic-gate /*
23617c478bd9Sstevel@tonic-gate ** Get the LA outside the WorkQ loop if necessary.
23627c478bd9Sstevel@tonic-gate ** In a persistent queue runner the code is repeated over
23637c478bd9Sstevel@tonic-gate ** and over but gatherq() may ignore entries due to
23647c478bd9Sstevel@tonic-gate ** shouldqueue() (do we really have to do this twice?).
23657c478bd9Sstevel@tonic-gate ** Hence the queue runners would just idle around when once
23667c478bd9Sstevel@tonic-gate ** CurrentLA caused all entries in a queue to be ignored.
23677c478bd9Sstevel@tonic-gate */
23687c478bd9Sstevel@tonic-gate
23697c478bd9Sstevel@tonic-gate if (njobs == 0)
23707c478bd9Sstevel@tonic-gate SM_GET_LA(now);
23717c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL);
23727c478bd9Sstevel@tonic-gate e = newenvelope(&QueueEnvelope, CurEnv, rpool);
23737c478bd9Sstevel@tonic-gate e->e_flags = BlankEnvelope.e_flags;
23747c478bd9Sstevel@tonic-gate goto domorework;
23757c478bd9Sstevel@tonic-gate }
23767c478bd9Sstevel@tonic-gate
23777c478bd9Sstevel@tonic-gate /* exit without the usual cleanup */
23787c478bd9Sstevel@tonic-gate e->e_id = NULL;
23797c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags))
23807c478bd9Sstevel@tonic-gate finis(true, true, ExitStat);
23817c478bd9Sstevel@tonic-gate /* NOTREACHED */
23827c478bd9Sstevel@tonic-gate return true;
23837c478bd9Sstevel@tonic-gate }
23847c478bd9Sstevel@tonic-gate
23857c478bd9Sstevel@tonic-gate /*
23867c478bd9Sstevel@tonic-gate ** DOQUEUERUN -- do a queue run?
23877c478bd9Sstevel@tonic-gate */
23887c478bd9Sstevel@tonic-gate
23897c478bd9Sstevel@tonic-gate bool
doqueuerun()23907c478bd9Sstevel@tonic-gate doqueuerun()
23917c478bd9Sstevel@tonic-gate {
23927c478bd9Sstevel@tonic-gate return DoQueueRun;
23937c478bd9Sstevel@tonic-gate }
23947c478bd9Sstevel@tonic-gate
23957c478bd9Sstevel@tonic-gate /*
23967c478bd9Sstevel@tonic-gate ** RUNQUEUEEVENT -- Sets a flag to indicate that a queue run should be done.
23977c478bd9Sstevel@tonic-gate **
23987c478bd9Sstevel@tonic-gate ** Parameters:
23997c478bd9Sstevel@tonic-gate ** none.
24007c478bd9Sstevel@tonic-gate **
24017c478bd9Sstevel@tonic-gate ** Returns:
24027c478bd9Sstevel@tonic-gate ** none.
24037c478bd9Sstevel@tonic-gate **
24047c478bd9Sstevel@tonic-gate ** Side Effects:
24057c478bd9Sstevel@tonic-gate ** The invocation of this function via an alarm may interrupt
24067c478bd9Sstevel@tonic-gate ** a set of actions. Thus errno may be set in that context.
24077c478bd9Sstevel@tonic-gate ** We need to restore errno at the end of this function to ensure
24087c478bd9Sstevel@tonic-gate ** that any work done here that sets errno doesn't return a
24097c478bd9Sstevel@tonic-gate ** misleading/false errno value. Errno may be EINTR upon entry to
24107c478bd9Sstevel@tonic-gate ** this function because of non-restartable/continuable system
24117c478bd9Sstevel@tonic-gate ** API was active. Iff this is true we will override errno as
24127c478bd9Sstevel@tonic-gate ** a timeout (as a more accurate error message).
24137c478bd9Sstevel@tonic-gate **
24147c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
24157c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
24167c478bd9Sstevel@tonic-gate ** DOING.
24177c478bd9Sstevel@tonic-gate */
24187c478bd9Sstevel@tonic-gate
24197c478bd9Sstevel@tonic-gate void
runqueueevent(ignore)24207c478bd9Sstevel@tonic-gate runqueueevent(ignore)
24217c478bd9Sstevel@tonic-gate int ignore;
24227c478bd9Sstevel@tonic-gate {
24237c478bd9Sstevel@tonic-gate int save_errno = errno;
24247c478bd9Sstevel@tonic-gate
24257c478bd9Sstevel@tonic-gate /*
24267c478bd9Sstevel@tonic-gate ** Set the general bit that we want a queue run,
24277c478bd9Sstevel@tonic-gate ** tested in doqueuerun()
24287c478bd9Sstevel@tonic-gate */
24297c478bd9Sstevel@tonic-gate
24307c478bd9Sstevel@tonic-gate DoQueueRun = true;
24317c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG
24327c478bd9Sstevel@tonic-gate if (tTd(69, 10))
24337c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "rqe: done");
24347c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */
24357c478bd9Sstevel@tonic-gate
24367c478bd9Sstevel@tonic-gate errno = save_errno;
24377c478bd9Sstevel@tonic-gate if (errno == EINTR)
24387c478bd9Sstevel@tonic-gate errno = ETIMEDOUT;
24397c478bd9Sstevel@tonic-gate }
24407c478bd9Sstevel@tonic-gate /*
24417c478bd9Sstevel@tonic-gate ** GATHERQ -- gather messages from the message queue(s) the work queue.
24427c478bd9Sstevel@tonic-gate **
24437c478bd9Sstevel@tonic-gate ** Parameters:
24447c478bd9Sstevel@tonic-gate ** qgrp -- the index of the queue group.
24457c478bd9Sstevel@tonic-gate ** qdir -- the index of the queue directory.
24467c478bd9Sstevel@tonic-gate ** doall -- if set, include everything in the queue (even
24477c478bd9Sstevel@tonic-gate ** the jobs that cannot be run because the load
24487c478bd9Sstevel@tonic-gate ** average is too high, or MaxQueueRun is reached).
24497c478bd9Sstevel@tonic-gate ** Otherwise, exclude those jobs.
24507c478bd9Sstevel@tonic-gate ** full -- (optional) to be set 'true' if WorkList is full
24517c478bd9Sstevel@tonic-gate ** more -- (optional) to be set 'true' if there are still more
24527c478bd9Sstevel@tonic-gate ** messages in this queue not added to WorkList
2453e9af4bc0SJohn Beck ** pnentries -- (optional) total nuber of entries in queue
24547c478bd9Sstevel@tonic-gate **
24557c478bd9Sstevel@tonic-gate ** Returns:
24567c478bd9Sstevel@tonic-gate ** The number of request in the queue (not necessarily
24577c478bd9Sstevel@tonic-gate ** the number of requests in WorkList however).
24587c478bd9Sstevel@tonic-gate **
24597c478bd9Sstevel@tonic-gate ** Side Effects:
24607c478bd9Sstevel@tonic-gate ** prepares available work into WorkList
24617c478bd9Sstevel@tonic-gate */
24627c478bd9Sstevel@tonic-gate
24637c478bd9Sstevel@tonic-gate #define NEED_P 0001 /* 'P': priority */
24647c478bd9Sstevel@tonic-gate #define NEED_T 0002 /* 'T': time */
24657c478bd9Sstevel@tonic-gate #define NEED_R 0004 /* 'R': recipient */
24667c478bd9Sstevel@tonic-gate #define NEED_S 0010 /* 'S': sender */
24677c478bd9Sstevel@tonic-gate #define NEED_H 0020 /* host */
24687c478bd9Sstevel@tonic-gate #define HAS_QUARANTINE 0040 /* has an unexpected 'q' line */
24697c478bd9Sstevel@tonic-gate #define NEED_QUARANTINE 0100 /* 'q': reason */
24707c478bd9Sstevel@tonic-gate
24717c478bd9Sstevel@tonic-gate static WORK *WorkList = NULL; /* list of unsort work */
24727c478bd9Sstevel@tonic-gate static int WorkListSize = 0; /* current max size of WorkList */
24737c478bd9Sstevel@tonic-gate static int WorkListCount = 0; /* # of work items in WorkList */
24747c478bd9Sstevel@tonic-gate
24757c478bd9Sstevel@tonic-gate static int
gatherq(qgrp,qdir,doall,full,more,pnentries)2476e9af4bc0SJohn Beck gatherq(qgrp, qdir, doall, full, more, pnentries)
24777c478bd9Sstevel@tonic-gate int qgrp;
24787c478bd9Sstevel@tonic-gate int qdir;
24797c478bd9Sstevel@tonic-gate bool doall;
24807c478bd9Sstevel@tonic-gate bool *full;
24817c478bd9Sstevel@tonic-gate bool *more;
2482e9af4bc0SJohn Beck int *pnentries;
24837c478bd9Sstevel@tonic-gate {
24847c478bd9Sstevel@tonic-gate register struct dirent *d;
24857c478bd9Sstevel@tonic-gate register WORK *w;
24867c478bd9Sstevel@tonic-gate register char *p;
24877c478bd9Sstevel@tonic-gate DIR *f;
2488e9af4bc0SJohn Beck int i, num_ent, wn, nentries;
24897c478bd9Sstevel@tonic-gate QUEUE_CHAR *check;
24907c478bd9Sstevel@tonic-gate char qd[MAXPATHLEN];
24917c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN];
24927c478bd9Sstevel@tonic-gate
24937c478bd9Sstevel@tonic-gate wn = WorkListCount - 1;
24947c478bd9Sstevel@tonic-gate num_ent = 0;
2495e9af4bc0SJohn Beck nentries = 0;
24967c478bd9Sstevel@tonic-gate if (qdir == NOQDIR)
2497058561cbSjbeck (void) sm_strlcpy(qd, ".", sizeof(qd));
24987c478bd9Sstevel@tonic-gate else
2499058561cbSjbeck (void) sm_strlcpyn(qd, sizeof(qd), 2,
25007c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name,
25017c478bd9Sstevel@tonic-gate (bitset(QP_SUBQF,
25027c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
25037c478bd9Sstevel@tonic-gate ? "/qf" : ""));
25047c478bd9Sstevel@tonic-gate
25057c478bd9Sstevel@tonic-gate if (tTd(41, 1))
25067c478bd9Sstevel@tonic-gate {
25077c478bd9Sstevel@tonic-gate sm_dprintf("gatherq:\n");
25087c478bd9Sstevel@tonic-gate
25097c478bd9Sstevel@tonic-gate check = QueueLimitId;
25107c478bd9Sstevel@tonic-gate while (check != NULL)
25117c478bd9Sstevel@tonic-gate {
25127c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitId = %s%s\n",
25137c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "",
25147c478bd9Sstevel@tonic-gate check->queue_match);
25157c478bd9Sstevel@tonic-gate check = check->queue_next;
25167c478bd9Sstevel@tonic-gate }
25177c478bd9Sstevel@tonic-gate
25187c478bd9Sstevel@tonic-gate check = QueueLimitSender;
25197c478bd9Sstevel@tonic-gate while (check != NULL)
25207c478bd9Sstevel@tonic-gate {
25217c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitSender = %s%s\n",
25227c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "",
25237c478bd9Sstevel@tonic-gate check->queue_match);
25247c478bd9Sstevel@tonic-gate check = check->queue_next;
25257c478bd9Sstevel@tonic-gate }
25267c478bd9Sstevel@tonic-gate
25277c478bd9Sstevel@tonic-gate check = QueueLimitRecipient;
25287c478bd9Sstevel@tonic-gate while (check != NULL)
25297c478bd9Sstevel@tonic-gate {
25307c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitRecipient = %s%s\n",
25317c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "",
25327c478bd9Sstevel@tonic-gate check->queue_match);
25337c478bd9Sstevel@tonic-gate check = check->queue_next;
25347c478bd9Sstevel@tonic-gate }
25357c478bd9Sstevel@tonic-gate
25367c478bd9Sstevel@tonic-gate if (QueueMode == QM_QUARANTINE)
25377c478bd9Sstevel@tonic-gate {
25387c478bd9Sstevel@tonic-gate check = QueueLimitQuarantine;
25397c478bd9Sstevel@tonic-gate while (check != NULL)
25407c478bd9Sstevel@tonic-gate {
25417c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitQuarantine = %s%s\n",
25427c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "",
25437c478bd9Sstevel@tonic-gate check->queue_match);
25447c478bd9Sstevel@tonic-gate check = check->queue_next;
25457c478bd9Sstevel@tonic-gate }
25467c478bd9Sstevel@tonic-gate }
25477c478bd9Sstevel@tonic-gate }
25487c478bd9Sstevel@tonic-gate
25497c478bd9Sstevel@tonic-gate /* open the queue directory */
25507c478bd9Sstevel@tonic-gate f = opendir(qd);
25517c478bd9Sstevel@tonic-gate if (f == NULL)
25527c478bd9Sstevel@tonic-gate {
25537c478bd9Sstevel@tonic-gate syserr("gatherq: cannot open \"%s\"",
25547c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir));
25557c478bd9Sstevel@tonic-gate if (full != NULL)
25567c478bd9Sstevel@tonic-gate *full = WorkListCount >= MaxQueueRun && MaxQueueRun > 0;
25577c478bd9Sstevel@tonic-gate if (more != NULL)
25587c478bd9Sstevel@tonic-gate *more = false;
25597c478bd9Sstevel@tonic-gate return 0;
25607c478bd9Sstevel@tonic-gate }
25617c478bd9Sstevel@tonic-gate
25627c478bd9Sstevel@tonic-gate /*
25637c478bd9Sstevel@tonic-gate ** Read the work directory.
25647c478bd9Sstevel@tonic-gate */
25657c478bd9Sstevel@tonic-gate
25667c478bd9Sstevel@tonic-gate while ((d = readdir(f)) != NULL)
25677c478bd9Sstevel@tonic-gate {
25687c478bd9Sstevel@tonic-gate SM_FILE_T *cf;
25697c478bd9Sstevel@tonic-gate int qfver = 0;
25707c478bd9Sstevel@tonic-gate char lbuf[MAXNAME + 1];
25717c478bd9Sstevel@tonic-gate struct stat sbuf;
25727c478bd9Sstevel@tonic-gate
25737c478bd9Sstevel@tonic-gate if (tTd(41, 50))
25747c478bd9Sstevel@tonic-gate sm_dprintf("gatherq: checking %s..", d->d_name);
25757c478bd9Sstevel@tonic-gate
25767c478bd9Sstevel@tonic-gate /* is this an interesting entry? */
25777c478bd9Sstevel@tonic-gate if (!(((QueueMode == QM_NORMAL &&
25787c478bd9Sstevel@tonic-gate d->d_name[0] == NORMQF_LETTER) ||
25797c478bd9Sstevel@tonic-gate (QueueMode == QM_QUARANTINE &&
25807c478bd9Sstevel@tonic-gate d->d_name[0] == QUARQF_LETTER) ||
25817c478bd9Sstevel@tonic-gate (QueueMode == QM_LOST &&
25827c478bd9Sstevel@tonic-gate d->d_name[0] == LOSEQF_LETTER)) &&
25837c478bd9Sstevel@tonic-gate d->d_name[1] == 'f'))
25847c478bd9Sstevel@tonic-gate {
25857c478bd9Sstevel@tonic-gate if (tTd(41, 50))
25867c478bd9Sstevel@tonic-gate sm_dprintf(" skipping\n");
25877c478bd9Sstevel@tonic-gate continue;
25887c478bd9Sstevel@tonic-gate }
25897c478bd9Sstevel@tonic-gate if (tTd(41, 50))
25907c478bd9Sstevel@tonic-gate sm_dprintf("\n");
25917c478bd9Sstevel@tonic-gate
25927c478bd9Sstevel@tonic-gate if (strlen(d->d_name) >= MAXQFNAME)
25937c478bd9Sstevel@tonic-gate {
25947c478bd9Sstevel@tonic-gate if (Verbose)
25957c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
25967c478bd9Sstevel@tonic-gate "gatherq: %s too long, %d max characters\n",
25977c478bd9Sstevel@tonic-gate d->d_name, MAXQFNAME);
25987c478bd9Sstevel@tonic-gate if (LogLevel > 0)
25997c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, NOQID,
26007c478bd9Sstevel@tonic-gate "gatherq: %s too long, %d max characters",
26017c478bd9Sstevel@tonic-gate d->d_name, MAXQFNAME);
26027c478bd9Sstevel@tonic-gate continue;
26037c478bd9Sstevel@tonic-gate }
26047c478bd9Sstevel@tonic-gate
2605e9af4bc0SJohn Beck ++nentries;
26067c478bd9Sstevel@tonic-gate check = QueueLimitId;
26077c478bd9Sstevel@tonic-gate while (check != NULL)
26087c478bd9Sstevel@tonic-gate {
26097c478bd9Sstevel@tonic-gate if (strcontainedin(false, check->queue_match,
26107c478bd9Sstevel@tonic-gate d->d_name) != check->queue_negate)
26117c478bd9Sstevel@tonic-gate break;
26127c478bd9Sstevel@tonic-gate else
26137c478bd9Sstevel@tonic-gate check = check->queue_next;
26147c478bd9Sstevel@tonic-gate }
26157c478bd9Sstevel@tonic-gate if (QueueLimitId != NULL && check == NULL)
26167c478bd9Sstevel@tonic-gate continue;
26177c478bd9Sstevel@tonic-gate
26187c478bd9Sstevel@tonic-gate /* grow work list if necessary */
26197c478bd9Sstevel@tonic-gate if (++wn >= MaxQueueRun && MaxQueueRun > 0)
26207c478bd9Sstevel@tonic-gate {
26217c478bd9Sstevel@tonic-gate if (wn == MaxQueueRun && LogLevel > 0)
26227c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID,
26237c478bd9Sstevel@tonic-gate "WorkList for %s maxed out at %d",
26247c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir),
26257c478bd9Sstevel@tonic-gate MaxQueueRun);
26267c478bd9Sstevel@tonic-gate if (doall)
26277c478bd9Sstevel@tonic-gate continue; /* just count entries */
26287c478bd9Sstevel@tonic-gate break;
26297c478bd9Sstevel@tonic-gate }
26307c478bd9Sstevel@tonic-gate if (wn >= WorkListSize)
26317c478bd9Sstevel@tonic-gate {
26327c478bd9Sstevel@tonic-gate grow_wlist(qgrp, qdir);
26337c478bd9Sstevel@tonic-gate if (wn >= WorkListSize)
26347c478bd9Sstevel@tonic-gate continue;
26357c478bd9Sstevel@tonic-gate }
26367c478bd9Sstevel@tonic-gate SM_ASSERT(wn >= 0);
26377c478bd9Sstevel@tonic-gate w = &WorkList[wn];
26387c478bd9Sstevel@tonic-gate
2639058561cbSjbeck (void) sm_strlcpyn(qf, sizeof(qf), 3, qd, "/", d->d_name);
26407c478bd9Sstevel@tonic-gate if (stat(qf, &sbuf) < 0)
26417c478bd9Sstevel@tonic-gate {
26427c478bd9Sstevel@tonic-gate if (errno != ENOENT)
26437c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
26447c478bd9Sstevel@tonic-gate "gatherq: can't stat %s/%s",
26457c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir),
26467c478bd9Sstevel@tonic-gate d->d_name);
26477c478bd9Sstevel@tonic-gate wn--;
26487c478bd9Sstevel@tonic-gate continue;
26497c478bd9Sstevel@tonic-gate }
26507c478bd9Sstevel@tonic-gate if (!bitset(S_IFREG, sbuf.st_mode))
26517c478bd9Sstevel@tonic-gate {
26527c478bd9Sstevel@tonic-gate /* Yikes! Skip it or we will hang on open! */
26537c478bd9Sstevel@tonic-gate if (!((d->d_name[0] == DATAFL_LETTER ||
26547c478bd9Sstevel@tonic-gate d->d_name[0] == NORMQF_LETTER ||
26557c478bd9Sstevel@tonic-gate d->d_name[0] == QUARQF_LETTER ||
26567c478bd9Sstevel@tonic-gate d->d_name[0] == LOSEQF_LETTER ||
26577c478bd9Sstevel@tonic-gate d->d_name[0] == XSCRPT_LETTER) &&
26587c478bd9Sstevel@tonic-gate d->d_name[1] == 'f' && d->d_name[2] == '\0'))
26597c478bd9Sstevel@tonic-gate syserr("gatherq: %s/%s is not a regular file",
26607c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), d->d_name);
26617c478bd9Sstevel@tonic-gate wn--;
26627c478bd9Sstevel@tonic-gate continue;
26637c478bd9Sstevel@tonic-gate }
26647c478bd9Sstevel@tonic-gate
26657c478bd9Sstevel@tonic-gate /* avoid work if possible */
26667c478bd9Sstevel@tonic-gate if ((QueueSortOrder == QSO_BYFILENAME ||
26677c478bd9Sstevel@tonic-gate QueueSortOrder == QSO_BYMODTIME ||
26681daa5768Sjbeck QueueSortOrder == QSO_NONE ||
26697c478bd9Sstevel@tonic-gate QueueSortOrder == QSO_RANDOM) &&
26707c478bd9Sstevel@tonic-gate QueueLimitQuarantine == NULL &&
26717c478bd9Sstevel@tonic-gate QueueLimitSender == NULL &&
26727c478bd9Sstevel@tonic-gate QueueLimitRecipient == NULL)
26737c478bd9Sstevel@tonic-gate {
26747c478bd9Sstevel@tonic-gate w->w_qgrp = qgrp;
26757c478bd9Sstevel@tonic-gate w->w_qdir = qdir;
26767c478bd9Sstevel@tonic-gate w->w_name = newstr(d->d_name);
26777c478bd9Sstevel@tonic-gate w->w_host = NULL;
26787c478bd9Sstevel@tonic-gate w->w_lock = w->w_tooyoung = false;
26797c478bd9Sstevel@tonic-gate w->w_pri = 0;
26807c478bd9Sstevel@tonic-gate w->w_ctime = 0;
26817c478bd9Sstevel@tonic-gate w->w_mtime = sbuf.st_mtime;
26827c478bd9Sstevel@tonic-gate ++num_ent;
26837c478bd9Sstevel@tonic-gate continue;
26847c478bd9Sstevel@tonic-gate }
26857c478bd9Sstevel@tonic-gate
26867c478bd9Sstevel@tonic-gate /* open control file */
26877c478bd9Sstevel@tonic-gate cf = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY_B,
26887c478bd9Sstevel@tonic-gate NULL);
26897c478bd9Sstevel@tonic-gate if (cf == NULL && OpMode != MD_PRINT)
26907c478bd9Sstevel@tonic-gate {
26917c478bd9Sstevel@tonic-gate /* this may be some random person sending hir msgs */
26927c478bd9Sstevel@tonic-gate if (tTd(41, 2))
26937c478bd9Sstevel@tonic-gate sm_dprintf("gatherq: cannot open %s: %s\n",
26947c478bd9Sstevel@tonic-gate d->d_name, sm_errstring(errno));
26957c478bd9Sstevel@tonic-gate errno = 0;
26967c478bd9Sstevel@tonic-gate wn--;
26977c478bd9Sstevel@tonic-gate continue;
26987c478bd9Sstevel@tonic-gate }
26997c478bd9Sstevel@tonic-gate w->w_qgrp = qgrp;
27007c478bd9Sstevel@tonic-gate w->w_qdir = qdir;
27017c478bd9Sstevel@tonic-gate w->w_name = newstr(d->d_name);
27027c478bd9Sstevel@tonic-gate w->w_host = NULL;
27037c478bd9Sstevel@tonic-gate if (cf != NULL)
27047c478bd9Sstevel@tonic-gate {
27057c478bd9Sstevel@tonic-gate w->w_lock = !lockfile(sm_io_getinfo(cf, SM_IO_WHAT_FD,
27067c478bd9Sstevel@tonic-gate NULL),
27077c478bd9Sstevel@tonic-gate w->w_name, NULL,
27087c478bd9Sstevel@tonic-gate LOCK_SH|LOCK_NB);
27097c478bd9Sstevel@tonic-gate }
27107c478bd9Sstevel@tonic-gate w->w_tooyoung = false;
27117c478bd9Sstevel@tonic-gate
27127c478bd9Sstevel@tonic-gate /* make sure jobs in creation don't clog queue */
27137c478bd9Sstevel@tonic-gate w->w_pri = 0x7fffffff;
27147c478bd9Sstevel@tonic-gate w->w_ctime = 0;
27157c478bd9Sstevel@tonic-gate w->w_mtime = sbuf.st_mtime;
27167c478bd9Sstevel@tonic-gate
27177c478bd9Sstevel@tonic-gate /* extract useful information */
27187c478bd9Sstevel@tonic-gate i = NEED_P|NEED_T;
27197c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST
27207c478bd9Sstevel@tonic-gate #if _FFR_RHS
27217c478bd9Sstevel@tonic-gate || QueueSortOrder == QSO_BYSHUFFLE
27227c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */
27237c478bd9Sstevel@tonic-gate )
27247c478bd9Sstevel@tonic-gate {
27257c478bd9Sstevel@tonic-gate /* need w_host set for host sort order */
27267c478bd9Sstevel@tonic-gate i |= NEED_H;
27277c478bd9Sstevel@tonic-gate }
27287c478bd9Sstevel@tonic-gate if (QueueLimitSender != NULL)
27297c478bd9Sstevel@tonic-gate i |= NEED_S;
27307c478bd9Sstevel@tonic-gate if (QueueLimitRecipient != NULL)
27317c478bd9Sstevel@tonic-gate i |= NEED_R;
27327c478bd9Sstevel@tonic-gate if (QueueLimitQuarantine != NULL)
27337c478bd9Sstevel@tonic-gate i |= NEED_QUARANTINE;
27347c478bd9Sstevel@tonic-gate while (cf != NULL && i != 0 &&
27357c478bd9Sstevel@tonic-gate sm_io_fgets(cf, SM_TIME_DEFAULT, lbuf,
2736058561cbSjbeck sizeof(lbuf)) != NULL)
27377c478bd9Sstevel@tonic-gate {
27387c478bd9Sstevel@tonic-gate int c;
27397c478bd9Sstevel@tonic-gate time_t age;
27407c478bd9Sstevel@tonic-gate
27417c478bd9Sstevel@tonic-gate p = strchr(lbuf, '\n');
27427c478bd9Sstevel@tonic-gate if (p != NULL)
27437c478bd9Sstevel@tonic-gate *p = '\0';
27447c478bd9Sstevel@tonic-gate else
27457c478bd9Sstevel@tonic-gate {
27467c478bd9Sstevel@tonic-gate /* flush rest of overly long line */
27477c478bd9Sstevel@tonic-gate while ((c = sm_io_getc(cf, SM_TIME_DEFAULT))
27487c478bd9Sstevel@tonic-gate != SM_IO_EOF && c != '\n')
27497c478bd9Sstevel@tonic-gate continue;
27507c478bd9Sstevel@tonic-gate }
27517c478bd9Sstevel@tonic-gate
27527c478bd9Sstevel@tonic-gate switch (lbuf[0])
27537c478bd9Sstevel@tonic-gate {
27547c478bd9Sstevel@tonic-gate case 'V':
27557c478bd9Sstevel@tonic-gate qfver = atoi(&lbuf[1]);
27567c478bd9Sstevel@tonic-gate break;
27577c478bd9Sstevel@tonic-gate
27587c478bd9Sstevel@tonic-gate case 'P':
27597c478bd9Sstevel@tonic-gate w->w_pri = atol(&lbuf[1]);
27607c478bd9Sstevel@tonic-gate i &= ~NEED_P;
27617c478bd9Sstevel@tonic-gate break;
27627c478bd9Sstevel@tonic-gate
27637c478bd9Sstevel@tonic-gate case 'T':
27647c478bd9Sstevel@tonic-gate w->w_ctime = atol(&lbuf[1]);
27657c478bd9Sstevel@tonic-gate i &= ~NEED_T;
27667c478bd9Sstevel@tonic-gate break;
27677c478bd9Sstevel@tonic-gate
27687c478bd9Sstevel@tonic-gate case 'q':
27697c478bd9Sstevel@tonic-gate if (QueueMode != QM_QUARANTINE &&
27707c478bd9Sstevel@tonic-gate QueueMode != QM_LOST)
27717c478bd9Sstevel@tonic-gate {
27727c478bd9Sstevel@tonic-gate if (tTd(41, 49))
27737c478bd9Sstevel@tonic-gate sm_dprintf("%s not marked as quarantined but has a 'q' line\n",
27747c478bd9Sstevel@tonic-gate w->w_name);
27757c478bd9Sstevel@tonic-gate i |= HAS_QUARANTINE;
27767c478bd9Sstevel@tonic-gate }
27777c478bd9Sstevel@tonic-gate else if (QueueMode == QM_QUARANTINE)
27787c478bd9Sstevel@tonic-gate {
27797c478bd9Sstevel@tonic-gate if (QueueLimitQuarantine == NULL)
27807c478bd9Sstevel@tonic-gate {
27817c478bd9Sstevel@tonic-gate i &= ~NEED_QUARANTINE;
27827c478bd9Sstevel@tonic-gate break;
27837c478bd9Sstevel@tonic-gate }
27847c478bd9Sstevel@tonic-gate p = &lbuf[1];
27857c478bd9Sstevel@tonic-gate check = QueueLimitQuarantine;
27867c478bd9Sstevel@tonic-gate while (check != NULL)
27877c478bd9Sstevel@tonic-gate {
27887c478bd9Sstevel@tonic-gate if (strcontainedin(false,
27897c478bd9Sstevel@tonic-gate check->queue_match,
27907c478bd9Sstevel@tonic-gate p) !=
27917c478bd9Sstevel@tonic-gate check->queue_negate)
27927c478bd9Sstevel@tonic-gate break;
27937c478bd9Sstevel@tonic-gate else
27947c478bd9Sstevel@tonic-gate check = check->queue_next;
27957c478bd9Sstevel@tonic-gate }
27967c478bd9Sstevel@tonic-gate if (check != NULL)
27977c478bd9Sstevel@tonic-gate i &= ~NEED_QUARANTINE;
27987c478bd9Sstevel@tonic-gate }
27997c478bd9Sstevel@tonic-gate break;
28007c478bd9Sstevel@tonic-gate
28017c478bd9Sstevel@tonic-gate case 'R':
28027c478bd9Sstevel@tonic-gate if (w->w_host == NULL &&
28037c478bd9Sstevel@tonic-gate (p = strrchr(&lbuf[1], '@')) != NULL)
28047c478bd9Sstevel@tonic-gate {
28057c478bd9Sstevel@tonic-gate #if _FFR_RHS
28067c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYSHUFFLE)
28077c478bd9Sstevel@tonic-gate w->w_host = newstr(&p[1]);
28087c478bd9Sstevel@tonic-gate else
28097c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */
28107c478bd9Sstevel@tonic-gate w->w_host = strrev(&p[1]);
28117c478bd9Sstevel@tonic-gate makelower(w->w_host);
28127c478bd9Sstevel@tonic-gate i &= ~NEED_H;
28137c478bd9Sstevel@tonic-gate }
28147c478bd9Sstevel@tonic-gate if (QueueLimitRecipient == NULL)
28157c478bd9Sstevel@tonic-gate {
28167c478bd9Sstevel@tonic-gate i &= ~NEED_R;
28177c478bd9Sstevel@tonic-gate break;
28187c478bd9Sstevel@tonic-gate }
28197c478bd9Sstevel@tonic-gate if (qfver > 0)
28207c478bd9Sstevel@tonic-gate {
28217c478bd9Sstevel@tonic-gate p = strchr(&lbuf[1], ':');
28227c478bd9Sstevel@tonic-gate if (p == NULL)
28237c478bd9Sstevel@tonic-gate p = &lbuf[1];
28247c478bd9Sstevel@tonic-gate else
28257c478bd9Sstevel@tonic-gate ++p; /* skip over ':' */
28267c478bd9Sstevel@tonic-gate }
28277c478bd9Sstevel@tonic-gate else
28287c478bd9Sstevel@tonic-gate p = &lbuf[1];
28297c478bd9Sstevel@tonic-gate check = QueueLimitRecipient;
28307c478bd9Sstevel@tonic-gate while (check != NULL)
28317c478bd9Sstevel@tonic-gate {
28327c478bd9Sstevel@tonic-gate if (strcontainedin(true,
28337c478bd9Sstevel@tonic-gate check->queue_match,
28347c478bd9Sstevel@tonic-gate p) !=
28357c478bd9Sstevel@tonic-gate check->queue_negate)
28367c478bd9Sstevel@tonic-gate break;
28377c478bd9Sstevel@tonic-gate else
28387c478bd9Sstevel@tonic-gate check = check->queue_next;
28397c478bd9Sstevel@tonic-gate }
28407c478bd9Sstevel@tonic-gate if (check != NULL)
28417c478bd9Sstevel@tonic-gate i &= ~NEED_R;
28427c478bd9Sstevel@tonic-gate break;
28437c478bd9Sstevel@tonic-gate
28447c478bd9Sstevel@tonic-gate case 'S':
28457c478bd9Sstevel@tonic-gate check = QueueLimitSender;
28467c478bd9Sstevel@tonic-gate while (check != NULL)
28477c478bd9Sstevel@tonic-gate {
28487c478bd9Sstevel@tonic-gate if (strcontainedin(true,
28497c478bd9Sstevel@tonic-gate check->queue_match,
28507c478bd9Sstevel@tonic-gate &lbuf[1]) !=
28517c478bd9Sstevel@tonic-gate check->queue_negate)
28527c478bd9Sstevel@tonic-gate break;
28537c478bd9Sstevel@tonic-gate else
28547c478bd9Sstevel@tonic-gate check = check->queue_next;
28557c478bd9Sstevel@tonic-gate }
28567c478bd9Sstevel@tonic-gate if (check != NULL)
28577c478bd9Sstevel@tonic-gate i &= ~NEED_S;
28587c478bd9Sstevel@tonic-gate break;
28597c478bd9Sstevel@tonic-gate
28607c478bd9Sstevel@tonic-gate case 'K':
2861e9af4bc0SJohn Beck #if _FFR_EXPDELAY
2862e9af4bc0SJohn Beck if (MaxQueueAge > 0)
2863e9af4bc0SJohn Beck {
2864e9af4bc0SJohn Beck time_t lasttry, delay;
2865e9af4bc0SJohn Beck
2866e9af4bc0SJohn Beck lasttry = (time_t) atol(&lbuf[1]);
2867e9af4bc0SJohn Beck delay = MIN(lasttry - w->w_ctime,
2868e9af4bc0SJohn Beck MaxQueueAge);
2869e9af4bc0SJohn Beck age = curtime() - lasttry;
2870e9af4bc0SJohn Beck if (age < delay)
2871e9af4bc0SJohn Beck w->w_tooyoung = true;
2872e9af4bc0SJohn Beck break;
2873e9af4bc0SJohn Beck }
2874e9af4bc0SJohn Beck #endif /* _FFR_EXPDELAY */
2875e9af4bc0SJohn Beck
28767c478bd9Sstevel@tonic-gate age = curtime() - (time_t) atol(&lbuf[1]);
28777c478bd9Sstevel@tonic-gate if (age >= 0 && MinQueueAge > 0 &&
28787c478bd9Sstevel@tonic-gate age < MinQueueAge)
28797c478bd9Sstevel@tonic-gate w->w_tooyoung = true;
28807c478bd9Sstevel@tonic-gate break;
28817c478bd9Sstevel@tonic-gate
28827c478bd9Sstevel@tonic-gate case 'N':
28837c478bd9Sstevel@tonic-gate if (atol(&lbuf[1]) == 0)
28847c478bd9Sstevel@tonic-gate w->w_tooyoung = false;
28857c478bd9Sstevel@tonic-gate break;
28867c478bd9Sstevel@tonic-gate }
28877c478bd9Sstevel@tonic-gate }
28887c478bd9Sstevel@tonic-gate if (cf != NULL)
28897c478bd9Sstevel@tonic-gate (void) sm_io_close(cf, SM_TIME_DEFAULT);
28907c478bd9Sstevel@tonic-gate
2891445f2479Sjbeck if ((!doall && (shouldqueue(w->w_pri, w->w_ctime) ||
2892445f2479Sjbeck w->w_tooyoung)) ||
28937c478bd9Sstevel@tonic-gate bitset(HAS_QUARANTINE, i) ||
28947c478bd9Sstevel@tonic-gate bitset(NEED_QUARANTINE, i) ||
28957c478bd9Sstevel@tonic-gate bitset(NEED_R|NEED_S, i))
28967c478bd9Sstevel@tonic-gate {
28977c478bd9Sstevel@tonic-gate /* don't even bother sorting this job in */
28987c478bd9Sstevel@tonic-gate if (tTd(41, 49))
28997c478bd9Sstevel@tonic-gate sm_dprintf("skipping %s (%x)\n", w->w_name, i);
29007c478bd9Sstevel@tonic-gate sm_free(w->w_name); /* XXX */
29017c478bd9Sstevel@tonic-gate if (w->w_host != NULL)
29027c478bd9Sstevel@tonic-gate sm_free(w->w_host); /* XXX */
29037c478bd9Sstevel@tonic-gate wn--;
29047c478bd9Sstevel@tonic-gate }
29057c478bd9Sstevel@tonic-gate else
29067c478bd9Sstevel@tonic-gate ++num_ent;
29077c478bd9Sstevel@tonic-gate }
29087c478bd9Sstevel@tonic-gate (void) closedir(f);
29097c478bd9Sstevel@tonic-gate wn++;
29107c478bd9Sstevel@tonic-gate
29117c478bd9Sstevel@tonic-gate i = wn - WorkListCount;
29127c478bd9Sstevel@tonic-gate WorkListCount += SM_MIN(num_ent, WorkListSize);
29137c478bd9Sstevel@tonic-gate
29147c478bd9Sstevel@tonic-gate if (more != NULL)
29157c478bd9Sstevel@tonic-gate *more = WorkListCount < wn;
29167c478bd9Sstevel@tonic-gate
29177c478bd9Sstevel@tonic-gate if (full != NULL)
29187c478bd9Sstevel@tonic-gate *full = (wn >= MaxQueueRun && MaxQueueRun > 0) ||
29197c478bd9Sstevel@tonic-gate (WorkList == NULL && wn > 0);
29207c478bd9Sstevel@tonic-gate
2921e9af4bc0SJohn Beck if (pnentries != NULL)
2922e9af4bc0SJohn Beck *pnentries = nentries;
29237c478bd9Sstevel@tonic-gate return i;
29247c478bd9Sstevel@tonic-gate }
29257c478bd9Sstevel@tonic-gate /*
29267c478bd9Sstevel@tonic-gate ** SORTQ -- sort the work list
29277c478bd9Sstevel@tonic-gate **
29287c478bd9Sstevel@tonic-gate ** First the old WorkQ is cleared away. Then the WorkList is sorted
29297c478bd9Sstevel@tonic-gate ** for all items so that important (higher sorting value) items are not
29307c478bd9Sstevel@tonic-gate ** trunctated off. Then the most important items are moved from
29317c478bd9Sstevel@tonic-gate ** WorkList to WorkQ. The lower count of 'max' or MaxListCount items
29327c478bd9Sstevel@tonic-gate ** are moved.
29337c478bd9Sstevel@tonic-gate **
29347c478bd9Sstevel@tonic-gate ** Parameters:
29357c478bd9Sstevel@tonic-gate ** max -- maximum number of items to be placed in WorkQ
29367c478bd9Sstevel@tonic-gate **
29377c478bd9Sstevel@tonic-gate ** Returns:
29387c478bd9Sstevel@tonic-gate ** the number of items in WorkQ
29397c478bd9Sstevel@tonic-gate **
29407c478bd9Sstevel@tonic-gate ** Side Effects:
29417c478bd9Sstevel@tonic-gate ** WorkQ gets released and filled with new work. WorkList
29427c478bd9Sstevel@tonic-gate ** gets released. Work items get sorted in order.
29437c478bd9Sstevel@tonic-gate */
29447c478bd9Sstevel@tonic-gate
29457c478bd9Sstevel@tonic-gate static int
sortq(max)29467c478bd9Sstevel@tonic-gate sortq(max)
29477c478bd9Sstevel@tonic-gate int max;
29487c478bd9Sstevel@tonic-gate {
29497c478bd9Sstevel@tonic-gate register int i; /* local counter */
29507c478bd9Sstevel@tonic-gate register WORK *w; /* tmp item pointer */
29517c478bd9Sstevel@tonic-gate int wc = WorkListCount; /* trim size for WorkQ */
29527c478bd9Sstevel@tonic-gate
29537c478bd9Sstevel@tonic-gate if (WorkQ != NULL)
29547c478bd9Sstevel@tonic-gate {
29557c478bd9Sstevel@tonic-gate WORK *nw;
29567c478bd9Sstevel@tonic-gate
29577c478bd9Sstevel@tonic-gate /* Clear out old WorkQ. */
29587c478bd9Sstevel@tonic-gate for (w = WorkQ; w != NULL; w = nw)
29597c478bd9Sstevel@tonic-gate {
29607c478bd9Sstevel@tonic-gate nw = w->w_next;
29617c478bd9Sstevel@tonic-gate sm_free(w->w_name); /* XXX */
29627c478bd9Sstevel@tonic-gate if (w->w_host != NULL)
29637c478bd9Sstevel@tonic-gate sm_free(w->w_host); /* XXX */
29647c478bd9Sstevel@tonic-gate sm_free((char *) w); /* XXX */
29657c478bd9Sstevel@tonic-gate }
29667c478bd9Sstevel@tonic-gate WorkQ = NULL;
29677c478bd9Sstevel@tonic-gate }
29687c478bd9Sstevel@tonic-gate
29697c478bd9Sstevel@tonic-gate if (WorkList == NULL || wc <= 0)
29707c478bd9Sstevel@tonic-gate return 0;
29717c478bd9Sstevel@tonic-gate
29727c478bd9Sstevel@tonic-gate /*
29737c478bd9Sstevel@tonic-gate ** The sort now takes place using all of the items in WorkList.
29747c478bd9Sstevel@tonic-gate ** The list gets trimmed to the most important items after the sort.
29757c478bd9Sstevel@tonic-gate ** If the trim were to happen before the sort then one or more
29767c478bd9Sstevel@tonic-gate ** important items might get truncated off -- not what we want.
29777c478bd9Sstevel@tonic-gate */
29787c478bd9Sstevel@tonic-gate
29797c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST)
29807c478bd9Sstevel@tonic-gate {
29817c478bd9Sstevel@tonic-gate /*
29827c478bd9Sstevel@tonic-gate ** Sort the work directory for the first time,
29837c478bd9Sstevel@tonic-gate ** based on host name, lock status, and priority.
29847c478bd9Sstevel@tonic-gate */
29857c478bd9Sstevel@tonic-gate
2986058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf1);
29877c478bd9Sstevel@tonic-gate
29887c478bd9Sstevel@tonic-gate /*
29897c478bd9Sstevel@tonic-gate ** If one message to host is locked, "lock" all messages
29907c478bd9Sstevel@tonic-gate ** to that host.
29917c478bd9Sstevel@tonic-gate */
29927c478bd9Sstevel@tonic-gate
29937c478bd9Sstevel@tonic-gate i = 0;
29947c478bd9Sstevel@tonic-gate while (i < wc)
29957c478bd9Sstevel@tonic-gate {
29967c478bd9Sstevel@tonic-gate if (!WorkList[i].w_lock)
29977c478bd9Sstevel@tonic-gate {
29987c478bd9Sstevel@tonic-gate i++;
29997c478bd9Sstevel@tonic-gate continue;
30007c478bd9Sstevel@tonic-gate }
30017c478bd9Sstevel@tonic-gate w = &WorkList[i];
30027c478bd9Sstevel@tonic-gate while (++i < wc)
30037c478bd9Sstevel@tonic-gate {
30047c478bd9Sstevel@tonic-gate if (WorkList[i].w_host == NULL &&
30057c478bd9Sstevel@tonic-gate w->w_host == NULL)
30067c478bd9Sstevel@tonic-gate WorkList[i].w_lock = true;
30077c478bd9Sstevel@tonic-gate else if (WorkList[i].w_host != NULL &&
30087c478bd9Sstevel@tonic-gate w->w_host != NULL &&
30097c478bd9Sstevel@tonic-gate sm_strcasecmp(WorkList[i].w_host,
30107c478bd9Sstevel@tonic-gate w->w_host) == 0)
30117c478bd9Sstevel@tonic-gate WorkList[i].w_lock = true;
30127c478bd9Sstevel@tonic-gate else
30137c478bd9Sstevel@tonic-gate break;
30147c478bd9Sstevel@tonic-gate }
30157c478bd9Sstevel@tonic-gate }
30167c478bd9Sstevel@tonic-gate
30177c478bd9Sstevel@tonic-gate /*
30187c478bd9Sstevel@tonic-gate ** Sort the work directory for the second time,
30197c478bd9Sstevel@tonic-gate ** based on lock status, host name, and priority.
30207c478bd9Sstevel@tonic-gate */
30217c478bd9Sstevel@tonic-gate
3022058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf2);
30237c478bd9Sstevel@tonic-gate }
30247c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYTIME)
30257c478bd9Sstevel@tonic-gate {
30267c478bd9Sstevel@tonic-gate /*
30277c478bd9Sstevel@tonic-gate ** Simple sort based on submission time only.
30287c478bd9Sstevel@tonic-gate */
30297c478bd9Sstevel@tonic-gate
3030058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf3);
30317c478bd9Sstevel@tonic-gate }
30327c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYFILENAME)
30337c478bd9Sstevel@tonic-gate {
30347c478bd9Sstevel@tonic-gate /*
30357c478bd9Sstevel@tonic-gate ** Sort based on queue filename.
30367c478bd9Sstevel@tonic-gate */
30377c478bd9Sstevel@tonic-gate
3038058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf4);
30397c478bd9Sstevel@tonic-gate }
30407c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_RANDOM)
30417c478bd9Sstevel@tonic-gate {
30427c478bd9Sstevel@tonic-gate /*
30437c478bd9Sstevel@tonic-gate ** Sort randomly. To avoid problems with an instable sort,
30447c478bd9Sstevel@tonic-gate ** use a random index into the queue file name to start
30457c478bd9Sstevel@tonic-gate ** comparison.
30467c478bd9Sstevel@tonic-gate */
30477c478bd9Sstevel@tonic-gate
30487c478bd9Sstevel@tonic-gate randi = get_rand_mod(MAXQFNAME);
30497c478bd9Sstevel@tonic-gate if (randi < 2)
30507c478bd9Sstevel@tonic-gate randi = 3;
3051058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf5);
30527c478bd9Sstevel@tonic-gate }
30537c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYMODTIME)
30547c478bd9Sstevel@tonic-gate {
30557c478bd9Sstevel@tonic-gate /*
30567c478bd9Sstevel@tonic-gate ** Simple sort based on modification time of queue file.
30577c478bd9Sstevel@tonic-gate ** This puts the oldest items first.
30587c478bd9Sstevel@tonic-gate */
30597c478bd9Sstevel@tonic-gate
3060058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf6);
30617c478bd9Sstevel@tonic-gate }
30627c478bd9Sstevel@tonic-gate #if _FFR_RHS
30637c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYSHUFFLE)
30647c478bd9Sstevel@tonic-gate {
30657c478bd9Sstevel@tonic-gate /*
30667c478bd9Sstevel@tonic-gate ** Simple sort based on shuffled host name.
30677c478bd9Sstevel@tonic-gate */
30687c478bd9Sstevel@tonic-gate
30697c478bd9Sstevel@tonic-gate init_shuffle_alphabet();
3070058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf7);
30717c478bd9Sstevel@tonic-gate }
30727c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */
30737c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYPRIORITY)
30747c478bd9Sstevel@tonic-gate {
30757c478bd9Sstevel@tonic-gate /*
30767c478bd9Sstevel@tonic-gate ** Simple sort based on queue priority only.
30777c478bd9Sstevel@tonic-gate */
30787c478bd9Sstevel@tonic-gate
3079058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf0);
30807c478bd9Sstevel@tonic-gate }
30817c478bd9Sstevel@tonic-gate /* else don't sort at all */
30827c478bd9Sstevel@tonic-gate
308349218d4fSjbeck /* Check if the per queue group item limit will be exceeded */
308449218d4fSjbeck if (wc > max && max > 0)
308549218d4fSjbeck wc = max;
308649218d4fSjbeck
30877c478bd9Sstevel@tonic-gate /*
30887c478bd9Sstevel@tonic-gate ** Convert the work list into canonical form.
30897c478bd9Sstevel@tonic-gate ** Should be turning it into a list of envelopes here perhaps.
30907c478bd9Sstevel@tonic-gate ** Only take the most important items up to the per queue group
30917c478bd9Sstevel@tonic-gate ** maximum.
30927c478bd9Sstevel@tonic-gate */
30937c478bd9Sstevel@tonic-gate
30947c478bd9Sstevel@tonic-gate for (i = wc; --i >= 0; )
30957c478bd9Sstevel@tonic-gate {
3096058561cbSjbeck w = (WORK *) xalloc(sizeof(*w));
30977c478bd9Sstevel@tonic-gate w->w_qgrp = WorkList[i].w_qgrp;
30987c478bd9Sstevel@tonic-gate w->w_qdir = WorkList[i].w_qdir;
30997c478bd9Sstevel@tonic-gate w->w_name = WorkList[i].w_name;
31007c478bd9Sstevel@tonic-gate w->w_host = WorkList[i].w_host;
31017c478bd9Sstevel@tonic-gate w->w_lock = WorkList[i].w_lock;
31027c478bd9Sstevel@tonic-gate w->w_tooyoung = WorkList[i].w_tooyoung;
31037c478bd9Sstevel@tonic-gate w->w_pri = WorkList[i].w_pri;
31047c478bd9Sstevel@tonic-gate w->w_ctime = WorkList[i].w_ctime;
31057c478bd9Sstevel@tonic-gate w->w_mtime = WorkList[i].w_mtime;
31067c478bd9Sstevel@tonic-gate w->w_next = WorkQ;
31077c478bd9Sstevel@tonic-gate WorkQ = w;
31087c478bd9Sstevel@tonic-gate }
31097c478bd9Sstevel@tonic-gate
31107c478bd9Sstevel@tonic-gate /* free the rest of the list */
31117c478bd9Sstevel@tonic-gate for (i = WorkListCount; --i >= wc; )
31127c478bd9Sstevel@tonic-gate {
31137c478bd9Sstevel@tonic-gate sm_free(WorkList[i].w_name);
31147c478bd9Sstevel@tonic-gate if (WorkList[i].w_host != NULL)
31157c478bd9Sstevel@tonic-gate sm_free(WorkList[i].w_host);
31167c478bd9Sstevel@tonic-gate }
31177c478bd9Sstevel@tonic-gate
31187c478bd9Sstevel@tonic-gate if (WorkList != NULL)
31197c478bd9Sstevel@tonic-gate sm_free(WorkList); /* XXX */
31207c478bd9Sstevel@tonic-gate WorkList = NULL;
31217c478bd9Sstevel@tonic-gate WorkListSize = 0;
31227c478bd9Sstevel@tonic-gate WorkListCount = 0;
31237c478bd9Sstevel@tonic-gate
31247c478bd9Sstevel@tonic-gate if (tTd(40, 1))
31257c478bd9Sstevel@tonic-gate {
31267c478bd9Sstevel@tonic-gate for (w = WorkQ; w != NULL; w = w->w_next)
31277c478bd9Sstevel@tonic-gate {
31287c478bd9Sstevel@tonic-gate if (w->w_host != NULL)
31297c478bd9Sstevel@tonic-gate sm_dprintf("%22s: pri=%ld %s\n",
31307c478bd9Sstevel@tonic-gate w->w_name, w->w_pri, w->w_host);
31317c478bd9Sstevel@tonic-gate else
31327c478bd9Sstevel@tonic-gate sm_dprintf("%32s: pri=%ld\n",
31337c478bd9Sstevel@tonic-gate w->w_name, w->w_pri);
31347c478bd9Sstevel@tonic-gate }
31357c478bd9Sstevel@tonic-gate }
31367c478bd9Sstevel@tonic-gate
31377c478bd9Sstevel@tonic-gate return wc; /* return number of WorkQ items */
31387c478bd9Sstevel@tonic-gate }
31397c478bd9Sstevel@tonic-gate /*
31407c478bd9Sstevel@tonic-gate ** GROW_WLIST -- make the work list larger
31417c478bd9Sstevel@tonic-gate **
31427c478bd9Sstevel@tonic-gate ** Parameters:
31437c478bd9Sstevel@tonic-gate ** qgrp -- the index for the queue group.
31447c478bd9Sstevel@tonic-gate ** qdir -- the index for the queue directory.
31457c478bd9Sstevel@tonic-gate **
31467c478bd9Sstevel@tonic-gate ** Returns:
31477c478bd9Sstevel@tonic-gate ** none.
31487c478bd9Sstevel@tonic-gate **
31497c478bd9Sstevel@tonic-gate ** Side Effects:
31507c478bd9Sstevel@tonic-gate ** Adds another QUEUESEGSIZE entries to WorkList if possible.
31517c478bd9Sstevel@tonic-gate ** It can fail if there isn't enough memory, so WorkListSize
31527c478bd9Sstevel@tonic-gate ** should be checked again upon return.
31537c478bd9Sstevel@tonic-gate */
31547c478bd9Sstevel@tonic-gate
31557c478bd9Sstevel@tonic-gate static void
grow_wlist(qgrp,qdir)31567c478bd9Sstevel@tonic-gate grow_wlist(qgrp, qdir)
31577c478bd9Sstevel@tonic-gate int qgrp;
31587c478bd9Sstevel@tonic-gate int qdir;
31597c478bd9Sstevel@tonic-gate {
31607c478bd9Sstevel@tonic-gate if (tTd(41, 1))
31617c478bd9Sstevel@tonic-gate sm_dprintf("grow_wlist: WorkListSize=%d\n", WorkListSize);
31627c478bd9Sstevel@tonic-gate if (WorkList == NULL)
31637c478bd9Sstevel@tonic-gate {
3164058561cbSjbeck WorkList = (WORK *) xalloc((sizeof(*WorkList)) *
31657c478bd9Sstevel@tonic-gate (QUEUESEGSIZE + 1));
31667c478bd9Sstevel@tonic-gate WorkListSize = QUEUESEGSIZE;
31677c478bd9Sstevel@tonic-gate }
31687c478bd9Sstevel@tonic-gate else
31697c478bd9Sstevel@tonic-gate {
31707c478bd9Sstevel@tonic-gate int newsize = WorkListSize + QUEUESEGSIZE;
31717c478bd9Sstevel@tonic-gate WORK *newlist = (WORK *) sm_realloc((char *) WorkList,
31727c478bd9Sstevel@tonic-gate (unsigned) sizeof(WORK) * (newsize + 1));
31737c478bd9Sstevel@tonic-gate
31747c478bd9Sstevel@tonic-gate if (newlist != NULL)
31757c478bd9Sstevel@tonic-gate {
31767c478bd9Sstevel@tonic-gate WorkListSize = newsize;
31777c478bd9Sstevel@tonic-gate WorkList = newlist;
31787c478bd9Sstevel@tonic-gate if (LogLevel > 1)
31797c478bd9Sstevel@tonic-gate {
31807c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
31817c478bd9Sstevel@tonic-gate "grew WorkList for %s to %d",
31827c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir),
31837c478bd9Sstevel@tonic-gate WorkListSize);
31847c478bd9Sstevel@tonic-gate }
31857c478bd9Sstevel@tonic-gate }
31867c478bd9Sstevel@tonic-gate else if (LogLevel > 0)
31877c478bd9Sstevel@tonic-gate {
31887c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, NOQID,
31897c478bd9Sstevel@tonic-gate "FAILED to grow WorkList for %s to %d",
31907c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), newsize);
31917c478bd9Sstevel@tonic-gate }
31927c478bd9Sstevel@tonic-gate }
31937c478bd9Sstevel@tonic-gate if (tTd(41, 1))
31947c478bd9Sstevel@tonic-gate sm_dprintf("grow_wlist: WorkListSize now %d\n", WorkListSize);
31957c478bd9Sstevel@tonic-gate }
31967c478bd9Sstevel@tonic-gate /*
31977c478bd9Sstevel@tonic-gate ** WORKCMPF0 -- simple priority-only compare function.
31987c478bd9Sstevel@tonic-gate **
31997c478bd9Sstevel@tonic-gate ** Parameters:
32007c478bd9Sstevel@tonic-gate ** a -- the first argument.
32017c478bd9Sstevel@tonic-gate ** b -- the second argument.
32027c478bd9Sstevel@tonic-gate **
32037c478bd9Sstevel@tonic-gate ** Returns:
32047c478bd9Sstevel@tonic-gate ** -1 if a < b
32057c478bd9Sstevel@tonic-gate ** 0 if a == b
32067c478bd9Sstevel@tonic-gate ** +1 if a > b
32077c478bd9Sstevel@tonic-gate **
32087c478bd9Sstevel@tonic-gate */
32097c478bd9Sstevel@tonic-gate
32107c478bd9Sstevel@tonic-gate static int
workcmpf0(a,b)32117c478bd9Sstevel@tonic-gate workcmpf0(a, b)
32127c478bd9Sstevel@tonic-gate register WORK *a;
32137c478bd9Sstevel@tonic-gate register WORK *b;
32147c478bd9Sstevel@tonic-gate {
32157c478bd9Sstevel@tonic-gate long pa = a->w_pri;
32167c478bd9Sstevel@tonic-gate long pb = b->w_pri;
32177c478bd9Sstevel@tonic-gate
32187c478bd9Sstevel@tonic-gate if (pa == pb)
32197c478bd9Sstevel@tonic-gate return 0;
32207c478bd9Sstevel@tonic-gate else if (pa > pb)
32217c478bd9Sstevel@tonic-gate return 1;
32227c478bd9Sstevel@tonic-gate else
32237c478bd9Sstevel@tonic-gate return -1;
32247c478bd9Sstevel@tonic-gate }
32257c478bd9Sstevel@tonic-gate /*
32267c478bd9Sstevel@tonic-gate ** WORKCMPF1 -- first compare function for ordering work based on host name.
32277c478bd9Sstevel@tonic-gate **
32287c478bd9Sstevel@tonic-gate ** Sorts on host name, lock status, and priority in that order.
32297c478bd9Sstevel@tonic-gate **
32307c478bd9Sstevel@tonic-gate ** Parameters:
32317c478bd9Sstevel@tonic-gate ** a -- the first argument.
32327c478bd9Sstevel@tonic-gate ** b -- the second argument.
32337c478bd9Sstevel@tonic-gate **
32347c478bd9Sstevel@tonic-gate ** Returns:
32357c478bd9Sstevel@tonic-gate ** <0 if a < b
32367c478bd9Sstevel@tonic-gate ** 0 if a == b
32377c478bd9Sstevel@tonic-gate ** >0 if a > b
32387c478bd9Sstevel@tonic-gate **
32397c478bd9Sstevel@tonic-gate */
32407c478bd9Sstevel@tonic-gate
32417c478bd9Sstevel@tonic-gate static int
workcmpf1(a,b)32427c478bd9Sstevel@tonic-gate workcmpf1(a, b)
32437c478bd9Sstevel@tonic-gate register WORK *a;
32447c478bd9Sstevel@tonic-gate register WORK *b;
32457c478bd9Sstevel@tonic-gate {
32467c478bd9Sstevel@tonic-gate int i;
32477c478bd9Sstevel@tonic-gate
32487c478bd9Sstevel@tonic-gate /* host name */
32497c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host == NULL)
32507c478bd9Sstevel@tonic-gate return 1;
32517c478bd9Sstevel@tonic-gate else if (a->w_host == NULL && b->w_host != NULL)
32527c478bd9Sstevel@tonic-gate return -1;
32537c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host != NULL &&
32547c478bd9Sstevel@tonic-gate (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
32557c478bd9Sstevel@tonic-gate return i;
32567c478bd9Sstevel@tonic-gate
32577c478bd9Sstevel@tonic-gate /* lock status */
32587c478bd9Sstevel@tonic-gate if (a->w_lock != b->w_lock)
32597c478bd9Sstevel@tonic-gate return b->w_lock - a->w_lock;
32607c478bd9Sstevel@tonic-gate
32617c478bd9Sstevel@tonic-gate /* job priority */
32627c478bd9Sstevel@tonic-gate return workcmpf0(a, b);
32637c478bd9Sstevel@tonic-gate }
32647c478bd9Sstevel@tonic-gate /*
32657c478bd9Sstevel@tonic-gate ** WORKCMPF2 -- second compare function for ordering work based on host name.
32667c478bd9Sstevel@tonic-gate **
32677c478bd9Sstevel@tonic-gate ** Sorts on lock status, host name, and priority in that order.
32687c478bd9Sstevel@tonic-gate **
32697c478bd9Sstevel@tonic-gate ** Parameters:
32707c478bd9Sstevel@tonic-gate ** a -- the first argument.
32717c478bd9Sstevel@tonic-gate ** b -- the second argument.
32727c478bd9Sstevel@tonic-gate **
32737c478bd9Sstevel@tonic-gate ** Returns:
32747c478bd9Sstevel@tonic-gate ** <0 if a < b
32757c478bd9Sstevel@tonic-gate ** 0 if a == b
32767c478bd9Sstevel@tonic-gate ** >0 if a > b
32777c478bd9Sstevel@tonic-gate **
32787c478bd9Sstevel@tonic-gate */
32797c478bd9Sstevel@tonic-gate
32807c478bd9Sstevel@tonic-gate static int
workcmpf2(a,b)32817c478bd9Sstevel@tonic-gate workcmpf2(a, b)
32827c478bd9Sstevel@tonic-gate register WORK *a;
32837c478bd9Sstevel@tonic-gate register WORK *b;
32847c478bd9Sstevel@tonic-gate {
32857c478bd9Sstevel@tonic-gate int i;
32867c478bd9Sstevel@tonic-gate
32877c478bd9Sstevel@tonic-gate /* lock status */
32887c478bd9Sstevel@tonic-gate if (a->w_lock != b->w_lock)
32897c478bd9Sstevel@tonic-gate return a->w_lock - b->w_lock;
32907c478bd9Sstevel@tonic-gate
32917c478bd9Sstevel@tonic-gate /* host name */
32927c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host == NULL)
32937c478bd9Sstevel@tonic-gate return 1;
32947c478bd9Sstevel@tonic-gate else if (a->w_host == NULL && b->w_host != NULL)
32957c478bd9Sstevel@tonic-gate return -1;
32967c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host != NULL &&
32977c478bd9Sstevel@tonic-gate (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
32987c478bd9Sstevel@tonic-gate return i;
32997c478bd9Sstevel@tonic-gate
33007c478bd9Sstevel@tonic-gate /* job priority */
33017c478bd9Sstevel@tonic-gate return workcmpf0(a, b);
33027c478bd9Sstevel@tonic-gate }
33037c478bd9Sstevel@tonic-gate /*
33047c478bd9Sstevel@tonic-gate ** WORKCMPF3 -- simple submission-time-only compare function.
33057c478bd9Sstevel@tonic-gate **
33067c478bd9Sstevel@tonic-gate ** Parameters:
33077c478bd9Sstevel@tonic-gate ** a -- the first argument.
33087c478bd9Sstevel@tonic-gate ** b -- the second argument.
33097c478bd9Sstevel@tonic-gate **
33107c478bd9Sstevel@tonic-gate ** Returns:
33117c478bd9Sstevel@tonic-gate ** -1 if a < b
33127c478bd9Sstevel@tonic-gate ** 0 if a == b
33137c478bd9Sstevel@tonic-gate ** +1 if a > b
33147c478bd9Sstevel@tonic-gate **
33157c478bd9Sstevel@tonic-gate */
33167c478bd9Sstevel@tonic-gate
33177c478bd9Sstevel@tonic-gate static int
workcmpf3(a,b)33187c478bd9Sstevel@tonic-gate workcmpf3(a, b)
33197c478bd9Sstevel@tonic-gate register WORK *a;
33207c478bd9Sstevel@tonic-gate register WORK *b;
33217c478bd9Sstevel@tonic-gate {
33227c478bd9Sstevel@tonic-gate if (a->w_ctime > b->w_ctime)
33237c478bd9Sstevel@tonic-gate return 1;
33247c478bd9Sstevel@tonic-gate else if (a->w_ctime < b->w_ctime)
33257c478bd9Sstevel@tonic-gate return -1;
33267c478bd9Sstevel@tonic-gate else
33277c478bd9Sstevel@tonic-gate return 0;
33287c478bd9Sstevel@tonic-gate }
33297c478bd9Sstevel@tonic-gate /*
33307c478bd9Sstevel@tonic-gate ** WORKCMPF4 -- compare based on file name
33317c478bd9Sstevel@tonic-gate **
33327c478bd9Sstevel@tonic-gate ** Parameters:
33337c478bd9Sstevel@tonic-gate ** a -- the first argument.
33347c478bd9Sstevel@tonic-gate ** b -- the second argument.
33357c478bd9Sstevel@tonic-gate **
33367c478bd9Sstevel@tonic-gate ** Returns:
33377c478bd9Sstevel@tonic-gate ** -1 if a < b
33387c478bd9Sstevel@tonic-gate ** 0 if a == b
33397c478bd9Sstevel@tonic-gate ** +1 if a > b
33407c478bd9Sstevel@tonic-gate **
33417c478bd9Sstevel@tonic-gate */
33427c478bd9Sstevel@tonic-gate
33437c478bd9Sstevel@tonic-gate static int
workcmpf4(a,b)33447c478bd9Sstevel@tonic-gate workcmpf4(a, b)
33457c478bd9Sstevel@tonic-gate register WORK *a;
33467c478bd9Sstevel@tonic-gate register WORK *b;
33477c478bd9Sstevel@tonic-gate {
33487c478bd9Sstevel@tonic-gate return strcmp(a->w_name, b->w_name);
33497c478bd9Sstevel@tonic-gate }
33507c478bd9Sstevel@tonic-gate /*
33517c478bd9Sstevel@tonic-gate ** WORKCMPF5 -- compare based on assigned random number
33527c478bd9Sstevel@tonic-gate **
33537c478bd9Sstevel@tonic-gate ** Parameters:
3354e9af4bc0SJohn Beck ** a -- the first argument.
3355e9af4bc0SJohn Beck ** b -- the second argument.
33567c478bd9Sstevel@tonic-gate **
33577c478bd9Sstevel@tonic-gate ** Returns:
33587c478bd9Sstevel@tonic-gate ** randomly 1/-1
33597c478bd9Sstevel@tonic-gate */
33607c478bd9Sstevel@tonic-gate
33617c478bd9Sstevel@tonic-gate /* ARGSUSED0 */
33627c478bd9Sstevel@tonic-gate static int
workcmpf5(a,b)33637c478bd9Sstevel@tonic-gate workcmpf5(a, b)
33647c478bd9Sstevel@tonic-gate register WORK *a;
33657c478bd9Sstevel@tonic-gate register WORK *b;
33667c478bd9Sstevel@tonic-gate {
33677c478bd9Sstevel@tonic-gate if (strlen(a->w_name) < randi || strlen(b->w_name) < randi)
33687c478bd9Sstevel@tonic-gate return -1;
33697c478bd9Sstevel@tonic-gate return a->w_name[randi] - b->w_name[randi];
33707c478bd9Sstevel@tonic-gate }
33717c478bd9Sstevel@tonic-gate /*
33727c478bd9Sstevel@tonic-gate ** WORKCMPF6 -- simple modification-time-only compare function.
33737c478bd9Sstevel@tonic-gate **
33747c478bd9Sstevel@tonic-gate ** Parameters:
33757c478bd9Sstevel@tonic-gate ** a -- the first argument.
33767c478bd9Sstevel@tonic-gate ** b -- the second argument.
33777c478bd9Sstevel@tonic-gate **
33787c478bd9Sstevel@tonic-gate ** Returns:
33797c478bd9Sstevel@tonic-gate ** -1 if a < b
33807c478bd9Sstevel@tonic-gate ** 0 if a == b
33817c478bd9Sstevel@tonic-gate ** +1 if a > b
33827c478bd9Sstevel@tonic-gate **
33837c478bd9Sstevel@tonic-gate */
33847c478bd9Sstevel@tonic-gate
33857c478bd9Sstevel@tonic-gate static int
workcmpf6(a,b)33867c478bd9Sstevel@tonic-gate workcmpf6(a, b)
33877c478bd9Sstevel@tonic-gate register WORK *a;
33887c478bd9Sstevel@tonic-gate register WORK *b;
33897c478bd9Sstevel@tonic-gate {
33907c478bd9Sstevel@tonic-gate if (a->w_mtime > b->w_mtime)
33917c478bd9Sstevel@tonic-gate return 1;
33927c478bd9Sstevel@tonic-gate else if (a->w_mtime < b->w_mtime)
33937c478bd9Sstevel@tonic-gate return -1;
33947c478bd9Sstevel@tonic-gate else
33957c478bd9Sstevel@tonic-gate return 0;
33967c478bd9Sstevel@tonic-gate }
33977c478bd9Sstevel@tonic-gate #if _FFR_RHS
33987c478bd9Sstevel@tonic-gate /*
33997c478bd9Sstevel@tonic-gate ** WORKCMPF7 -- compare function for ordering work based on shuffled host name.
34007c478bd9Sstevel@tonic-gate **
34017c478bd9Sstevel@tonic-gate ** Sorts on lock status, host name, and priority in that order.
34027c478bd9Sstevel@tonic-gate **
34037c478bd9Sstevel@tonic-gate ** Parameters:
34047c478bd9Sstevel@tonic-gate ** a -- the first argument.
34057c478bd9Sstevel@tonic-gate ** b -- the second argument.
34067c478bd9Sstevel@tonic-gate **
34077c478bd9Sstevel@tonic-gate ** Returns:
34087c478bd9Sstevel@tonic-gate ** <0 if a < b
34097c478bd9Sstevel@tonic-gate ** 0 if a == b
34107c478bd9Sstevel@tonic-gate ** >0 if a > b
34117c478bd9Sstevel@tonic-gate **
34127c478bd9Sstevel@tonic-gate */
34137c478bd9Sstevel@tonic-gate
34147c478bd9Sstevel@tonic-gate static int
workcmpf7(a,b)34157c478bd9Sstevel@tonic-gate workcmpf7(a, b)
34167c478bd9Sstevel@tonic-gate register WORK *a;
34177c478bd9Sstevel@tonic-gate register WORK *b;
34187c478bd9Sstevel@tonic-gate {
34197c478bd9Sstevel@tonic-gate int i;
34207c478bd9Sstevel@tonic-gate
34217c478bd9Sstevel@tonic-gate /* lock status */
34227c478bd9Sstevel@tonic-gate if (a->w_lock != b->w_lock)
34237c478bd9Sstevel@tonic-gate return a->w_lock - b->w_lock;
34247c478bd9Sstevel@tonic-gate
34257c478bd9Sstevel@tonic-gate /* host name */
34267c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host == NULL)
34277c478bd9Sstevel@tonic-gate return 1;
34287c478bd9Sstevel@tonic-gate else if (a->w_host == NULL && b->w_host != NULL)
34297c478bd9Sstevel@tonic-gate return -1;
34307c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host != NULL &&
34317c478bd9Sstevel@tonic-gate (i = sm_strshufflecmp(a->w_host, b->w_host)) != 0)
34327c478bd9Sstevel@tonic-gate return i;
34337c478bd9Sstevel@tonic-gate
34347c478bd9Sstevel@tonic-gate /* job priority */
34357c478bd9Sstevel@tonic-gate return workcmpf0(a, b);
34367c478bd9Sstevel@tonic-gate }
34377c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */
34387c478bd9Sstevel@tonic-gate /*
34397c478bd9Sstevel@tonic-gate ** STRREV -- reverse string
34407c478bd9Sstevel@tonic-gate **
34417c478bd9Sstevel@tonic-gate ** Returns a pointer to a new string that is the reverse of
34427c478bd9Sstevel@tonic-gate ** the string pointed to by fwd. The space for the new
34437c478bd9Sstevel@tonic-gate ** string is obtained using xalloc().
34447c478bd9Sstevel@tonic-gate **
34457c478bd9Sstevel@tonic-gate ** Parameters:
34467c478bd9Sstevel@tonic-gate ** fwd -- the string to reverse.
34477c478bd9Sstevel@tonic-gate **
34487c478bd9Sstevel@tonic-gate ** Returns:
34497c478bd9Sstevel@tonic-gate ** the reversed string.
34507c478bd9Sstevel@tonic-gate */
34517c478bd9Sstevel@tonic-gate
34527c478bd9Sstevel@tonic-gate static char *
strrev(fwd)34537c478bd9Sstevel@tonic-gate strrev(fwd)
34547c478bd9Sstevel@tonic-gate char *fwd;
34557c478bd9Sstevel@tonic-gate {
34567c478bd9Sstevel@tonic-gate char *rev = NULL;
34577c478bd9Sstevel@tonic-gate int len, cnt;
34587c478bd9Sstevel@tonic-gate
34597c478bd9Sstevel@tonic-gate len = strlen(fwd);
34607c478bd9Sstevel@tonic-gate rev = xalloc(len + 1);
34617c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < len; ++cnt)
34627c478bd9Sstevel@tonic-gate rev[cnt] = fwd[len - cnt - 1];
34637c478bd9Sstevel@tonic-gate rev[len] = '\0';
34647c478bd9Sstevel@tonic-gate return rev;
34657c478bd9Sstevel@tonic-gate }
34667c478bd9Sstevel@tonic-gate
34677c478bd9Sstevel@tonic-gate #if _FFR_RHS
34687c478bd9Sstevel@tonic-gate
34697c478bd9Sstevel@tonic-gate # define NASCII 128
34707c478bd9Sstevel@tonic-gate # define NCHAR 256
34717c478bd9Sstevel@tonic-gate
34727c478bd9Sstevel@tonic-gate static unsigned char ShuffledAlphabet[NCHAR];
34737c478bd9Sstevel@tonic-gate
34747c478bd9Sstevel@tonic-gate void
init_shuffle_alphabet()34757c478bd9Sstevel@tonic-gate init_shuffle_alphabet()
34767c478bd9Sstevel@tonic-gate {
34777c478bd9Sstevel@tonic-gate static bool init = false;
34787c478bd9Sstevel@tonic-gate int i;
34797c478bd9Sstevel@tonic-gate
34807c478bd9Sstevel@tonic-gate if (init)
34817c478bd9Sstevel@tonic-gate return;
34827c478bd9Sstevel@tonic-gate
34837c478bd9Sstevel@tonic-gate /* fill the ShuffledAlphabet */
348449218d4fSjbeck for (i = 0; i < NASCII; i++)
34857c478bd9Sstevel@tonic-gate ShuffledAlphabet[i] = i;
34867c478bd9Sstevel@tonic-gate
34877c478bd9Sstevel@tonic-gate /* mix it */
348849218d4fSjbeck for (i = 1; i < NASCII; i++)
34897c478bd9Sstevel@tonic-gate {
349049218d4fSjbeck register int j = get_random() % NASCII;
34917c478bd9Sstevel@tonic-gate register int tmp;
34927c478bd9Sstevel@tonic-gate
34937c478bd9Sstevel@tonic-gate tmp = ShuffledAlphabet[j];
34947c478bd9Sstevel@tonic-gate ShuffledAlphabet[j] = ShuffledAlphabet[i];
34957c478bd9Sstevel@tonic-gate ShuffledAlphabet[i] = tmp;
34967c478bd9Sstevel@tonic-gate }
34977c478bd9Sstevel@tonic-gate
34987c478bd9Sstevel@tonic-gate /* make it case insensitive */
34997c478bd9Sstevel@tonic-gate for (i = 'A'; i <= 'Z'; i++)
35007c478bd9Sstevel@tonic-gate ShuffledAlphabet[i] = ShuffledAlphabet[i + 'a' - 'A'];
35017c478bd9Sstevel@tonic-gate
35027c478bd9Sstevel@tonic-gate /* fill the upper part */
350349218d4fSjbeck for (i = 0; i < NASCII; i++)
350449218d4fSjbeck ShuffledAlphabet[i + NASCII] = ShuffledAlphabet[i];
35057c478bd9Sstevel@tonic-gate init = true;
35067c478bd9Sstevel@tonic-gate }
35077c478bd9Sstevel@tonic-gate
35087c478bd9Sstevel@tonic-gate static int
sm_strshufflecmp(a,b)35097c478bd9Sstevel@tonic-gate sm_strshufflecmp(a, b)
35107c478bd9Sstevel@tonic-gate char *a;
35117c478bd9Sstevel@tonic-gate char *b;
35127c478bd9Sstevel@tonic-gate {
35137c478bd9Sstevel@tonic-gate const unsigned char *us1 = (const unsigned char *) a;
35147c478bd9Sstevel@tonic-gate const unsigned char *us2 = (const unsigned char *) b;
35157c478bd9Sstevel@tonic-gate
35167c478bd9Sstevel@tonic-gate while (ShuffledAlphabet[*us1] == ShuffledAlphabet[*us2++])
35177c478bd9Sstevel@tonic-gate {
35187c478bd9Sstevel@tonic-gate if (*us1++ == '\0')
35197c478bd9Sstevel@tonic-gate return 0;
35207c478bd9Sstevel@tonic-gate }
35217c478bd9Sstevel@tonic-gate return (ShuffledAlphabet[*us1] - ShuffledAlphabet[*--us2]);
35227c478bd9Sstevel@tonic-gate }
35237c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */
35247c478bd9Sstevel@tonic-gate
35257c478bd9Sstevel@tonic-gate /*
35267c478bd9Sstevel@tonic-gate ** DOWORK -- do a work request.
35277c478bd9Sstevel@tonic-gate **
35287c478bd9Sstevel@tonic-gate ** Parameters:
35297c478bd9Sstevel@tonic-gate ** qgrp -- the index of the queue group for the job.
35307c478bd9Sstevel@tonic-gate ** qdir -- the index of the queue directory for the job.
35317c478bd9Sstevel@tonic-gate ** id -- the ID of the job to run.
35327c478bd9Sstevel@tonic-gate ** forkflag -- if set, run this in background.
35337c478bd9Sstevel@tonic-gate ** requeueflag -- if set, reinstantiate the queue quickly.
35347c478bd9Sstevel@tonic-gate ** This is used when expanding aliases in the queue.
35357c478bd9Sstevel@tonic-gate ** If forkflag is also set, it doesn't wait for the
35367c478bd9Sstevel@tonic-gate ** child.
35377c478bd9Sstevel@tonic-gate ** e - the envelope in which to run it.
35387c478bd9Sstevel@tonic-gate **
35397c478bd9Sstevel@tonic-gate ** Returns:
35407c478bd9Sstevel@tonic-gate ** process id of process that is running the queue job.
35417c478bd9Sstevel@tonic-gate **
35427c478bd9Sstevel@tonic-gate ** Side Effects:
35437c478bd9Sstevel@tonic-gate ** The work request is satisfied if possible.
35447c478bd9Sstevel@tonic-gate */
35457c478bd9Sstevel@tonic-gate
35467c478bd9Sstevel@tonic-gate pid_t
dowork(qgrp,qdir,id,forkflag,requeueflag,e)35477c478bd9Sstevel@tonic-gate dowork(qgrp, qdir, id, forkflag, requeueflag, e)
35487c478bd9Sstevel@tonic-gate int qgrp;
35497c478bd9Sstevel@tonic-gate int qdir;
35507c478bd9Sstevel@tonic-gate char *id;
35517c478bd9Sstevel@tonic-gate bool forkflag;
35527c478bd9Sstevel@tonic-gate bool requeueflag;
35537c478bd9Sstevel@tonic-gate register ENVELOPE *e;
35547c478bd9Sstevel@tonic-gate {
35557c478bd9Sstevel@tonic-gate register pid_t pid;
35567c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool;
35577c478bd9Sstevel@tonic-gate
35587c478bd9Sstevel@tonic-gate if (tTd(40, 1))
35597c478bd9Sstevel@tonic-gate sm_dprintf("dowork(%s/%s)\n", qid_printqueue(qgrp, qdir), id);
35607c478bd9Sstevel@tonic-gate
35617c478bd9Sstevel@tonic-gate /*
35627c478bd9Sstevel@tonic-gate ** Fork for work.
35637c478bd9Sstevel@tonic-gate */
35647c478bd9Sstevel@tonic-gate
35657c478bd9Sstevel@tonic-gate if (forkflag)
35667c478bd9Sstevel@tonic-gate {
35677c478bd9Sstevel@tonic-gate /*
35687c478bd9Sstevel@tonic-gate ** Since the delivery may happen in a child and the
35697c478bd9Sstevel@tonic-gate ** parent does not wait, the parent may close the
35707c478bd9Sstevel@tonic-gate ** maps thereby removing any shared memory used by
35717c478bd9Sstevel@tonic-gate ** the map. Therefore, close the maps now so the
35727c478bd9Sstevel@tonic-gate ** child will dynamically open them if necessary.
35737c478bd9Sstevel@tonic-gate */
35747c478bd9Sstevel@tonic-gate
35757c478bd9Sstevel@tonic-gate closemaps(false);
35767c478bd9Sstevel@tonic-gate
35777c478bd9Sstevel@tonic-gate pid = fork();
35787c478bd9Sstevel@tonic-gate if (pid < 0)
35797c478bd9Sstevel@tonic-gate {
35807c478bd9Sstevel@tonic-gate syserr("dowork: cannot fork");
35817c478bd9Sstevel@tonic-gate return 0;
35827c478bd9Sstevel@tonic-gate }
35837c478bd9Sstevel@tonic-gate else if (pid > 0)
35847c478bd9Sstevel@tonic-gate {
35857c478bd9Sstevel@tonic-gate /* parent -- clean out connection cache */
35867c478bd9Sstevel@tonic-gate mci_flush(false, NULL);
35877c478bd9Sstevel@tonic-gate }
35887c478bd9Sstevel@tonic-gate else
35897c478bd9Sstevel@tonic-gate {
35907c478bd9Sstevel@tonic-gate /*
35917c478bd9Sstevel@tonic-gate ** Initialize exception stack and default exception
35927c478bd9Sstevel@tonic-gate ** handler for child process.
35937c478bd9Sstevel@tonic-gate */
35947c478bd9Sstevel@tonic-gate
35957c478bd9Sstevel@tonic-gate /* Reset global flags */
35967c478bd9Sstevel@tonic-gate RestartRequest = NULL;
35977c478bd9Sstevel@tonic-gate RestartWorkGroup = false;
35987c478bd9Sstevel@tonic-gate ShutdownRequest = NULL;
35997c478bd9Sstevel@tonic-gate PendingSignal = 0;
36007c478bd9Sstevel@tonic-gate CurrentPid = getpid();
36017c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error);
36027c478bd9Sstevel@tonic-gate
36037c478bd9Sstevel@tonic-gate /*
36047c478bd9Sstevel@tonic-gate ** See note above about SMTP processes and SIGCHLD.
36057c478bd9Sstevel@tonic-gate */
36067c478bd9Sstevel@tonic-gate
36077c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP ||
36087c478bd9Sstevel@tonic-gate OpMode == MD_DAEMON ||
36097c478bd9Sstevel@tonic-gate MaxQueueChildren > 0)
36107c478bd9Sstevel@tonic-gate {
36117c478bd9Sstevel@tonic-gate proc_list_clear();
36127c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD);
36137c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL);
36147c478bd9Sstevel@tonic-gate }
36157c478bd9Sstevel@tonic-gate
36167c478bd9Sstevel@tonic-gate /* child -- error messages to the transcript */
36177c478bd9Sstevel@tonic-gate QuickAbort = OnlyOneError = false;
36187c478bd9Sstevel@tonic-gate }
36197c478bd9Sstevel@tonic-gate }
36207c478bd9Sstevel@tonic-gate else
36217c478bd9Sstevel@tonic-gate {
36227c478bd9Sstevel@tonic-gate pid = 0;
36237c478bd9Sstevel@tonic-gate }
36247c478bd9Sstevel@tonic-gate
36257c478bd9Sstevel@tonic-gate if (pid == 0)
36267c478bd9Sstevel@tonic-gate {
36277c478bd9Sstevel@tonic-gate /*
36287c478bd9Sstevel@tonic-gate ** CHILD
36297c478bd9Sstevel@tonic-gate ** Lock the control file to avoid duplicate deliveries.
36307c478bd9Sstevel@tonic-gate ** Then run the file as though we had just read it.
36317c478bd9Sstevel@tonic-gate ** We save an idea of the temporary name so we
36327c478bd9Sstevel@tonic-gate ** can recover on interrupt.
36337c478bd9Sstevel@tonic-gate */
36347c478bd9Sstevel@tonic-gate
36357c478bd9Sstevel@tonic-gate if (forkflag)
36367c478bd9Sstevel@tonic-gate {
36377c478bd9Sstevel@tonic-gate /* Reset global flags */
36387c478bd9Sstevel@tonic-gate RestartRequest = NULL;
36397c478bd9Sstevel@tonic-gate RestartWorkGroup = false;
36407c478bd9Sstevel@tonic-gate ShutdownRequest = NULL;
36417c478bd9Sstevel@tonic-gate PendingSignal = 0;
36427c478bd9Sstevel@tonic-gate }
36437c478bd9Sstevel@tonic-gate
36447c478bd9Sstevel@tonic-gate /* set basic modes, etc. */
36457c478bd9Sstevel@tonic-gate sm_clear_events();
36467c478bd9Sstevel@tonic-gate clearstats();
36477c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL);
36487c478bd9Sstevel@tonic-gate clearenvelope(e, false, rpool);
36497c478bd9Sstevel@tonic-gate e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
36507c478bd9Sstevel@tonic-gate set_delivery_mode(SM_DELIVER, e);
36517c478bd9Sstevel@tonic-gate e->e_errormode = EM_MAIL;
36527c478bd9Sstevel@tonic-gate e->e_id = id;
36537c478bd9Sstevel@tonic-gate e->e_qgrp = qgrp;
36547c478bd9Sstevel@tonic-gate e->e_qdir = qdir;
36557c478bd9Sstevel@tonic-gate GrabTo = UseErrorsTo = false;
36567c478bd9Sstevel@tonic-gate ExitStat = EX_OK;
36577c478bd9Sstevel@tonic-gate if (forkflag)
36587c478bd9Sstevel@tonic-gate {
36597c478bd9Sstevel@tonic-gate disconnect(1, e);
36607c478bd9Sstevel@tonic-gate set_op_mode(MD_QUEUERUN);
36617c478bd9Sstevel@tonic-gate }
36627c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s from queue", qid_printname(e));
36637c478bd9Sstevel@tonic-gate if (LogLevel > 76)
36647c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "dowork, pid=%d",
36657c478bd9Sstevel@tonic-gate (int) CurrentPid);
36667c478bd9Sstevel@tonic-gate
36677c478bd9Sstevel@tonic-gate /* don't use the headers from sendmail.cf... */
36687c478bd9Sstevel@tonic-gate e->e_header = NULL;
36697c478bd9Sstevel@tonic-gate
36707c478bd9Sstevel@tonic-gate /* read the queue control file -- return if locked */
36717c478bd9Sstevel@tonic-gate if (!readqf(e, false))
36727c478bd9Sstevel@tonic-gate {
36737c478bd9Sstevel@tonic-gate if (tTd(40, 4) && e->e_id != NULL)
36747c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s) failed\n",
36757c478bd9Sstevel@tonic-gate qid_printname(e));
36767c478bd9Sstevel@tonic-gate e->e_id = NULL;
36777c478bd9Sstevel@tonic-gate if (forkflag)
36787c478bd9Sstevel@tonic-gate finis(false, true, EX_OK);
36797c478bd9Sstevel@tonic-gate else
36807c478bd9Sstevel@tonic-gate {
36817c478bd9Sstevel@tonic-gate /* adding this frees 8 bytes */
36827c478bd9Sstevel@tonic-gate clearenvelope(e, false, rpool);
36837c478bd9Sstevel@tonic-gate
36847c478bd9Sstevel@tonic-gate /* adding this frees 12 bytes */
36857c478bd9Sstevel@tonic-gate sm_rpool_free(rpool);
36867c478bd9Sstevel@tonic-gate e->e_rpool = NULL;
36877c478bd9Sstevel@tonic-gate return 0;
36887c478bd9Sstevel@tonic-gate }
36897c478bd9Sstevel@tonic-gate }
36907c478bd9Sstevel@tonic-gate
36917c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE;
36927c478bd9Sstevel@tonic-gate eatheader(e, requeueflag, true);
36937c478bd9Sstevel@tonic-gate
36947c478bd9Sstevel@tonic-gate if (requeueflag)
36957c478bd9Sstevel@tonic-gate queueup(e, false, false);
36967c478bd9Sstevel@tonic-gate
36977c478bd9Sstevel@tonic-gate /* do the delivery */
36987c478bd9Sstevel@tonic-gate sendall(e, SM_DELIVER);
36997c478bd9Sstevel@tonic-gate
37007c478bd9Sstevel@tonic-gate /* finish up and exit */
37017c478bd9Sstevel@tonic-gate if (forkflag)
37027c478bd9Sstevel@tonic-gate finis(true, true, ExitStat);
37037c478bd9Sstevel@tonic-gate else
37047c478bd9Sstevel@tonic-gate {
3705e9af4bc0SJohn Beck (void) dropenvelope(e, true, false);
37067c478bd9Sstevel@tonic-gate sm_rpool_free(rpool);
37077c478bd9Sstevel@tonic-gate e->e_rpool = NULL;
37087c478bd9Sstevel@tonic-gate }
37097c478bd9Sstevel@tonic-gate }
37107c478bd9Sstevel@tonic-gate e->e_id = NULL;
37117c478bd9Sstevel@tonic-gate return pid;
37127c478bd9Sstevel@tonic-gate }
37137c478bd9Sstevel@tonic-gate
37147c478bd9Sstevel@tonic-gate /*
37157c478bd9Sstevel@tonic-gate ** DOWORKLIST -- process a list of envelopes as work requests
37167c478bd9Sstevel@tonic-gate **
37177c478bd9Sstevel@tonic-gate ** Similar to dowork(), except that after forking, it processes an
37187c478bd9Sstevel@tonic-gate ** envelope and its siblings, treating each envelope as a work request.
37197c478bd9Sstevel@tonic-gate **
37207c478bd9Sstevel@tonic-gate ** Parameters:
37217c478bd9Sstevel@tonic-gate ** el -- envelope to be processed including its siblings.
37227c478bd9Sstevel@tonic-gate ** forkflag -- if set, run this in background.
37237c478bd9Sstevel@tonic-gate ** requeueflag -- if set, reinstantiate the queue quickly.
37247c478bd9Sstevel@tonic-gate ** This is used when expanding aliases in the queue.
37257c478bd9Sstevel@tonic-gate ** If forkflag is also set, it doesn't wait for the
37267c478bd9Sstevel@tonic-gate ** child.
37277c478bd9Sstevel@tonic-gate **
37287c478bd9Sstevel@tonic-gate ** Returns:
37297c478bd9Sstevel@tonic-gate ** process id of process that is running the queue job.
37307c478bd9Sstevel@tonic-gate **
37317c478bd9Sstevel@tonic-gate ** Side Effects:
37327c478bd9Sstevel@tonic-gate ** The work request is satisfied if possible.
37337c478bd9Sstevel@tonic-gate */
37347c478bd9Sstevel@tonic-gate
37357c478bd9Sstevel@tonic-gate pid_t
doworklist(el,forkflag,requeueflag)37367c478bd9Sstevel@tonic-gate doworklist(el, forkflag, requeueflag)
37377c478bd9Sstevel@tonic-gate ENVELOPE *el;
37387c478bd9Sstevel@tonic-gate bool forkflag;
37397c478bd9Sstevel@tonic-gate bool requeueflag;
37407c478bd9Sstevel@tonic-gate {
37417c478bd9Sstevel@tonic-gate register pid_t pid;
37427c478bd9Sstevel@tonic-gate ENVELOPE *ei;
37437c478bd9Sstevel@tonic-gate
37447c478bd9Sstevel@tonic-gate if (tTd(40, 1))
37457c478bd9Sstevel@tonic-gate sm_dprintf("doworklist()\n");
37467c478bd9Sstevel@tonic-gate
37477c478bd9Sstevel@tonic-gate /*
37487c478bd9Sstevel@tonic-gate ** Fork for work.
37497c478bd9Sstevel@tonic-gate */
37507c478bd9Sstevel@tonic-gate
37517c478bd9Sstevel@tonic-gate if (forkflag)
37527c478bd9Sstevel@tonic-gate {
37537c478bd9Sstevel@tonic-gate /*
37547c478bd9Sstevel@tonic-gate ** Since the delivery may happen in a child and the
37557c478bd9Sstevel@tonic-gate ** parent does not wait, the parent may close the
37567c478bd9Sstevel@tonic-gate ** maps thereby removing any shared memory used by
37577c478bd9Sstevel@tonic-gate ** the map. Therefore, close the maps now so the
37587c478bd9Sstevel@tonic-gate ** child will dynamically open them if necessary.
37597c478bd9Sstevel@tonic-gate */
37607c478bd9Sstevel@tonic-gate
37617c478bd9Sstevel@tonic-gate closemaps(false);
37627c478bd9Sstevel@tonic-gate
37637c478bd9Sstevel@tonic-gate pid = fork();
37647c478bd9Sstevel@tonic-gate if (pid < 0)
37657c478bd9Sstevel@tonic-gate {
37667c478bd9Sstevel@tonic-gate syserr("doworklist: cannot fork");
37677c478bd9Sstevel@tonic-gate return 0;
37687c478bd9Sstevel@tonic-gate }
37697c478bd9Sstevel@tonic-gate else if (pid > 0)
37707c478bd9Sstevel@tonic-gate {
37717c478bd9Sstevel@tonic-gate /* parent -- clean out connection cache */
37727c478bd9Sstevel@tonic-gate mci_flush(false, NULL);
37737c478bd9Sstevel@tonic-gate }
37747c478bd9Sstevel@tonic-gate else
37757c478bd9Sstevel@tonic-gate {
37767c478bd9Sstevel@tonic-gate /*
37777c478bd9Sstevel@tonic-gate ** Initialize exception stack and default exception
37787c478bd9Sstevel@tonic-gate ** handler for child process.
37797c478bd9Sstevel@tonic-gate */
37807c478bd9Sstevel@tonic-gate
37817c478bd9Sstevel@tonic-gate /* Reset global flags */
37827c478bd9Sstevel@tonic-gate RestartRequest = NULL;
37837c478bd9Sstevel@tonic-gate RestartWorkGroup = false;
37847c478bd9Sstevel@tonic-gate ShutdownRequest = NULL;
37857c478bd9Sstevel@tonic-gate PendingSignal = 0;
37867c478bd9Sstevel@tonic-gate CurrentPid = getpid();
37877c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error);
37887c478bd9Sstevel@tonic-gate
37897c478bd9Sstevel@tonic-gate /*
37907c478bd9Sstevel@tonic-gate ** See note above about SMTP processes and SIGCHLD.
37917c478bd9Sstevel@tonic-gate */
37927c478bd9Sstevel@tonic-gate
37937c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP ||
37947c478bd9Sstevel@tonic-gate OpMode == MD_DAEMON ||
37957c478bd9Sstevel@tonic-gate MaxQueueChildren > 0)
37967c478bd9Sstevel@tonic-gate {
37977c478bd9Sstevel@tonic-gate proc_list_clear();
37987c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD);
37997c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL);
38007c478bd9Sstevel@tonic-gate }
38017c478bd9Sstevel@tonic-gate
38027c478bd9Sstevel@tonic-gate /* child -- error messages to the transcript */
38037c478bd9Sstevel@tonic-gate QuickAbort = OnlyOneError = false;
38047c478bd9Sstevel@tonic-gate }
38057c478bd9Sstevel@tonic-gate }
38067c478bd9Sstevel@tonic-gate else
38077c478bd9Sstevel@tonic-gate {
38087c478bd9Sstevel@tonic-gate pid = 0;
38097c478bd9Sstevel@tonic-gate }
38107c478bd9Sstevel@tonic-gate
38117c478bd9Sstevel@tonic-gate if (pid != 0)
38127c478bd9Sstevel@tonic-gate return pid;
38137c478bd9Sstevel@tonic-gate
38147c478bd9Sstevel@tonic-gate /*
38157c478bd9Sstevel@tonic-gate ** IN CHILD
38167c478bd9Sstevel@tonic-gate ** Lock the control file to avoid duplicate deliveries.
38177c478bd9Sstevel@tonic-gate ** Then run the file as though we had just read it.
38187c478bd9Sstevel@tonic-gate ** We save an idea of the temporary name so we
38197c478bd9Sstevel@tonic-gate ** can recover on interrupt.
38207c478bd9Sstevel@tonic-gate */
38217c478bd9Sstevel@tonic-gate
38227c478bd9Sstevel@tonic-gate if (forkflag)
38237c478bd9Sstevel@tonic-gate {
38247c478bd9Sstevel@tonic-gate /* Reset global flags */
38257c478bd9Sstevel@tonic-gate RestartRequest = NULL;
38267c478bd9Sstevel@tonic-gate RestartWorkGroup = false;
38277c478bd9Sstevel@tonic-gate ShutdownRequest = NULL;
38287c478bd9Sstevel@tonic-gate PendingSignal = 0;
38297c478bd9Sstevel@tonic-gate }
38307c478bd9Sstevel@tonic-gate
38317c478bd9Sstevel@tonic-gate /* set basic modes, etc. */
38327c478bd9Sstevel@tonic-gate sm_clear_events();
38337c478bd9Sstevel@tonic-gate clearstats();
38347c478bd9Sstevel@tonic-gate GrabTo = UseErrorsTo = false;
38357c478bd9Sstevel@tonic-gate ExitStat = EX_OK;
38367c478bd9Sstevel@tonic-gate if (forkflag)
38377c478bd9Sstevel@tonic-gate {
38387c478bd9Sstevel@tonic-gate disconnect(1, el);
38397c478bd9Sstevel@tonic-gate set_op_mode(MD_QUEUERUN);
38407c478bd9Sstevel@tonic-gate }
38417c478bd9Sstevel@tonic-gate if (LogLevel > 76)
38427c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, el->e_id, "doworklist, pid=%d",
38437c478bd9Sstevel@tonic-gate (int) CurrentPid);
38447c478bd9Sstevel@tonic-gate
38457c478bd9Sstevel@tonic-gate for (ei = el; ei != NULL; ei = ei->e_sibling)
38467c478bd9Sstevel@tonic-gate {
38477c478bd9Sstevel@tonic-gate ENVELOPE e;
38487c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool;
38497c478bd9Sstevel@tonic-gate
38507c478bd9Sstevel@tonic-gate if (WILL_BE_QUEUED(ei->e_sendmode))
38517c478bd9Sstevel@tonic-gate continue;
38527c478bd9Sstevel@tonic-gate else if (QueueMode != QM_QUARANTINE &&
38537c478bd9Sstevel@tonic-gate ei->e_quarmsg != NULL)
38547c478bd9Sstevel@tonic-gate continue;
38557c478bd9Sstevel@tonic-gate
38567c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL);
38577c478bd9Sstevel@tonic-gate clearenvelope(&e, true, rpool);
38587c478bd9Sstevel@tonic-gate e.e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
38597c478bd9Sstevel@tonic-gate set_delivery_mode(SM_DELIVER, &e);
38607c478bd9Sstevel@tonic-gate e.e_errormode = EM_MAIL;
38617c478bd9Sstevel@tonic-gate e.e_id = ei->e_id;
38627c478bd9Sstevel@tonic-gate e.e_qgrp = ei->e_qgrp;
38637c478bd9Sstevel@tonic-gate e.e_qdir = ei->e_qdir;
38647c478bd9Sstevel@tonic-gate openxscript(&e);
38657c478bd9Sstevel@tonic-gate sm_setproctitle(true, &e, "%s from queue", qid_printname(&e));
38667c478bd9Sstevel@tonic-gate
38677c478bd9Sstevel@tonic-gate /* don't use the headers from sendmail.cf... */
38687c478bd9Sstevel@tonic-gate e.e_header = NULL;
38697c478bd9Sstevel@tonic-gate CurEnv = &e;
38707c478bd9Sstevel@tonic-gate
38717c478bd9Sstevel@tonic-gate /* read the queue control file -- return if locked */
38727c478bd9Sstevel@tonic-gate if (readqf(&e, false))
38737c478bd9Sstevel@tonic-gate {
38747c478bd9Sstevel@tonic-gate e.e_flags |= EF_INQUEUE;
38757c478bd9Sstevel@tonic-gate eatheader(&e, requeueflag, true);
38767c478bd9Sstevel@tonic-gate
38777c478bd9Sstevel@tonic-gate if (requeueflag)
38787c478bd9Sstevel@tonic-gate queueup(&e, false, false);
38797c478bd9Sstevel@tonic-gate
38807c478bd9Sstevel@tonic-gate /* do the delivery */
38817c478bd9Sstevel@tonic-gate sendall(&e, SM_DELIVER);
3882e9af4bc0SJohn Beck (void) dropenvelope(&e, true, false);
38837c478bd9Sstevel@tonic-gate }
38847c478bd9Sstevel@tonic-gate else
38857c478bd9Sstevel@tonic-gate {
38867c478bd9Sstevel@tonic-gate if (tTd(40, 4) && e.e_id != NULL)
38877c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s) failed\n",
38887c478bd9Sstevel@tonic-gate qid_printname(&e));
38897c478bd9Sstevel@tonic-gate }
38907c478bd9Sstevel@tonic-gate sm_rpool_free(rpool);
38917c478bd9Sstevel@tonic-gate ei->e_id = NULL;
38927c478bd9Sstevel@tonic-gate }
38937c478bd9Sstevel@tonic-gate
38947c478bd9Sstevel@tonic-gate /* restore CurEnv */
38957c478bd9Sstevel@tonic-gate CurEnv = el;
38967c478bd9Sstevel@tonic-gate
38977c478bd9Sstevel@tonic-gate /* finish up and exit */
38987c478bd9Sstevel@tonic-gate if (forkflag)
38997c478bd9Sstevel@tonic-gate finis(true, true, ExitStat);
39007c478bd9Sstevel@tonic-gate return 0;
39017c478bd9Sstevel@tonic-gate }
39027c478bd9Sstevel@tonic-gate /*
39037c478bd9Sstevel@tonic-gate ** READQF -- read queue file and set up environment.
39047c478bd9Sstevel@tonic-gate **
39057c478bd9Sstevel@tonic-gate ** Parameters:
39067c478bd9Sstevel@tonic-gate ** e -- the envelope of the job to run.
39077c478bd9Sstevel@tonic-gate ** openonly -- only open the qf (returned as e_lockfp)
39087c478bd9Sstevel@tonic-gate **
39097c478bd9Sstevel@tonic-gate ** Returns:
39107c478bd9Sstevel@tonic-gate ** true if it successfully read the queue file.
39117c478bd9Sstevel@tonic-gate ** false otherwise.
39127c478bd9Sstevel@tonic-gate **
39137c478bd9Sstevel@tonic-gate ** Side Effects:
39147c478bd9Sstevel@tonic-gate ** The queue file is returned locked.
39157c478bd9Sstevel@tonic-gate */
39167c478bd9Sstevel@tonic-gate
39177c478bd9Sstevel@tonic-gate static bool
readqf(e,openonly)39187c478bd9Sstevel@tonic-gate readqf(e, openonly)
39197c478bd9Sstevel@tonic-gate register ENVELOPE *e;
39207c478bd9Sstevel@tonic-gate bool openonly;
39217c478bd9Sstevel@tonic-gate {
39227c478bd9Sstevel@tonic-gate register SM_FILE_T *qfp;
39237c478bd9Sstevel@tonic-gate ADDRESS *ctladdr;
39247c478bd9Sstevel@tonic-gate struct stat st, stf;
39257c478bd9Sstevel@tonic-gate char *bp;
39267c478bd9Sstevel@tonic-gate int qfver = 0;
39277c478bd9Sstevel@tonic-gate long hdrsize = 0;
39287c478bd9Sstevel@tonic-gate register char *p;
39297c478bd9Sstevel@tonic-gate char *frcpt = NULL;
39307c478bd9Sstevel@tonic-gate char *orcpt = NULL;
39317c478bd9Sstevel@tonic-gate bool nomore = false;
39327c478bd9Sstevel@tonic-gate bool bogus = false;
39337c478bd9Sstevel@tonic-gate MODE_T qsafe;
39347c478bd9Sstevel@tonic-gate char *err;
39357c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN];
39367c478bd9Sstevel@tonic-gate char buf[MAXLINE];
3937058561cbSjbeck int bufsize;
39387c478bd9Sstevel@tonic-gate
39397c478bd9Sstevel@tonic-gate /*
39407c478bd9Sstevel@tonic-gate ** Read and process the file.
39417c478bd9Sstevel@tonic-gate */
39427c478bd9Sstevel@tonic-gate
39434aac33d3Sjbeck SM_REQUIRE(e != NULL);
39443ee0e492Sjbeck bp = NULL;
3945058561cbSjbeck (void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER), sizeof(qf));
39467c478bd9Sstevel@tonic-gate qfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDWR_B, NULL);
39477c478bd9Sstevel@tonic-gate if (qfp == NULL)
39487c478bd9Sstevel@tonic-gate {
39497c478bd9Sstevel@tonic-gate int save_errno = errno;
39507c478bd9Sstevel@tonic-gate
39517c478bd9Sstevel@tonic-gate if (tTd(40, 8))
39527c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s): sm_io_open failure (%s)\n",
39537c478bd9Sstevel@tonic-gate qf, sm_errstring(errno));
39547c478bd9Sstevel@tonic-gate errno = save_errno;
39557c478bd9Sstevel@tonic-gate if (errno != ENOENT
39567c478bd9Sstevel@tonic-gate )
39577c478bd9Sstevel@tonic-gate syserr("readqf: no control file %s", qf);
39587c478bd9Sstevel@tonic-gate RELEASE_QUEUE;
39597c478bd9Sstevel@tonic-gate return false;
39607c478bd9Sstevel@tonic-gate }
39617c478bd9Sstevel@tonic-gate
39627c478bd9Sstevel@tonic-gate if (!lockfile(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), qf, NULL,
39637c478bd9Sstevel@tonic-gate LOCK_EX|LOCK_NB))
39647c478bd9Sstevel@tonic-gate {
39657c478bd9Sstevel@tonic-gate /* being processed by another queuer */
39667c478bd9Sstevel@tonic-gate if (Verbose)
39677c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
39687c478bd9Sstevel@tonic-gate "%s: locked\n", e->e_id);
39697c478bd9Sstevel@tonic-gate if (tTd(40, 8))
39707c478bd9Sstevel@tonic-gate sm_dprintf("%s: locked\n", e->e_id);
39717c478bd9Sstevel@tonic-gate if (LogLevel > 19)
39727c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "locked");
39737c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT);
39747c478bd9Sstevel@tonic-gate RELEASE_QUEUE;
39757c478bd9Sstevel@tonic-gate return false;
39767c478bd9Sstevel@tonic-gate }
39777c478bd9Sstevel@tonic-gate
39787c478bd9Sstevel@tonic-gate RELEASE_QUEUE;
39797c478bd9Sstevel@tonic-gate
39807c478bd9Sstevel@tonic-gate /*
39817c478bd9Sstevel@tonic-gate ** Prevent locking race condition.
39827c478bd9Sstevel@tonic-gate **
39837c478bd9Sstevel@tonic-gate ** Process A: readqf(): qfp = fopen(qffile)
39847c478bd9Sstevel@tonic-gate ** Process B: queueup(): rename(tf, qf)
39857c478bd9Sstevel@tonic-gate ** Process B: unlocks(tf)
39867c478bd9Sstevel@tonic-gate ** Process A: lockfile(qf);
39877c478bd9Sstevel@tonic-gate **
39887c478bd9Sstevel@tonic-gate ** Process A (us) has the old qf file (before the rename deleted
39897c478bd9Sstevel@tonic-gate ** the directory entry) and will be delivering based on old data.
39907c478bd9Sstevel@tonic-gate ** This can lead to multiple deliveries of the same recipients.
39917c478bd9Sstevel@tonic-gate **
39927c478bd9Sstevel@tonic-gate ** Catch this by checking if the underlying qf file has changed
39937c478bd9Sstevel@tonic-gate ** *after* acquiring our lock and if so, act as though the file
39947c478bd9Sstevel@tonic-gate ** was still locked (i.e., just return like the lockfile() case
39957c478bd9Sstevel@tonic-gate ** above.
39967c478bd9Sstevel@tonic-gate */
39977c478bd9Sstevel@tonic-gate
39987c478bd9Sstevel@tonic-gate if (stat(qf, &stf) < 0 ||
39997c478bd9Sstevel@tonic-gate fstat(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), &st) < 0)
40007c478bd9Sstevel@tonic-gate {
40017c478bd9Sstevel@tonic-gate /* must have been being processed by someone else */
40027c478bd9Sstevel@tonic-gate if (tTd(40, 8))
40037c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s): [f]stat failure (%s)\n",
40047c478bd9Sstevel@tonic-gate qf, sm_errstring(errno));
40057c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT);
40067c478bd9Sstevel@tonic-gate return false;
40077c478bd9Sstevel@tonic-gate }
40087c478bd9Sstevel@tonic-gate
40097c478bd9Sstevel@tonic-gate if (st.st_nlink != stf.st_nlink ||
40107c478bd9Sstevel@tonic-gate st.st_dev != stf.st_dev ||
40117c478bd9Sstevel@tonic-gate ST_INODE(st) != ST_INODE(stf) ||
40127c478bd9Sstevel@tonic-gate #if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */
40137c478bd9Sstevel@tonic-gate st.st_gen != stf.st_gen ||
40147c478bd9Sstevel@tonic-gate #endif /* HAS_ST_GEN && 0 */
40157c478bd9Sstevel@tonic-gate st.st_uid != stf.st_uid ||
40167c478bd9Sstevel@tonic-gate st.st_gid != stf.st_gid ||
40177c478bd9Sstevel@tonic-gate st.st_size != stf.st_size)
40187c478bd9Sstevel@tonic-gate {
40197c478bd9Sstevel@tonic-gate /* changed after opened */
40207c478bd9Sstevel@tonic-gate if (Verbose)
40217c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
40227c478bd9Sstevel@tonic-gate "%s: changed\n", e->e_id);
40237c478bd9Sstevel@tonic-gate if (tTd(40, 8))
40247c478bd9Sstevel@tonic-gate sm_dprintf("%s: changed\n", e->e_id);
40257c478bd9Sstevel@tonic-gate if (LogLevel > 19)
40267c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "changed");
40277c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT);
40287c478bd9Sstevel@tonic-gate return false;
40297c478bd9Sstevel@tonic-gate }
40307c478bd9Sstevel@tonic-gate
40317c478bd9Sstevel@tonic-gate /*
40327c478bd9Sstevel@tonic-gate ** Check the queue file for plausibility to avoid attacks.
40337c478bd9Sstevel@tonic-gate */
40347c478bd9Sstevel@tonic-gate
40357c478bd9Sstevel@tonic-gate qsafe = S_IWOTH|S_IWGRP;
40367c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode))
40377c478bd9Sstevel@tonic-gate qsafe &= ~S_IWGRP;
40387c478bd9Sstevel@tonic-gate
40397c478bd9Sstevel@tonic-gate bogus = st.st_uid != geteuid() &&
40407c478bd9Sstevel@tonic-gate st.st_uid != TrustedUid &&
40417c478bd9Sstevel@tonic-gate geteuid() != RealUid;
40427c478bd9Sstevel@tonic-gate
40437c478bd9Sstevel@tonic-gate /*
40447c478bd9Sstevel@tonic-gate ** If this qf file results from a set-group-ID binary, then
40457c478bd9Sstevel@tonic-gate ** we check whether the directory is group-writable,
40467c478bd9Sstevel@tonic-gate ** the queue file mode contains the group-writable bit, and
40477c478bd9Sstevel@tonic-gate ** the groups are the same.
40487c478bd9Sstevel@tonic-gate ** Notice: this requires that the set-group-ID binary is used to
40497c478bd9Sstevel@tonic-gate ** run the queue!
40507c478bd9Sstevel@tonic-gate */
40517c478bd9Sstevel@tonic-gate
40527c478bd9Sstevel@tonic-gate if (bogus && st.st_gid == getegid() && UseMSP)
40537c478bd9Sstevel@tonic-gate {
40547c478bd9Sstevel@tonic-gate char delim;
40557c478bd9Sstevel@tonic-gate struct stat dst;
40567c478bd9Sstevel@tonic-gate
40577c478bd9Sstevel@tonic-gate bp = SM_LAST_DIR_DELIM(qf);
40587c478bd9Sstevel@tonic-gate if (bp == NULL)
40597c478bd9Sstevel@tonic-gate delim = '\0';
40607c478bd9Sstevel@tonic-gate else
40617c478bd9Sstevel@tonic-gate {
40627c478bd9Sstevel@tonic-gate delim = *bp;
40637c478bd9Sstevel@tonic-gate *bp = '\0';
40647c478bd9Sstevel@tonic-gate }
40657c478bd9Sstevel@tonic-gate if (stat(delim == '\0' ? "." : qf, &dst) < 0)
40667c478bd9Sstevel@tonic-gate syserr("readqf: cannot stat directory %s",
40677c478bd9Sstevel@tonic-gate delim == '\0' ? "." : qf);
40687c478bd9Sstevel@tonic-gate else
40697c478bd9Sstevel@tonic-gate {
40707c478bd9Sstevel@tonic-gate bogus = !(bitset(S_IWGRP, QueueFileMode) &&
40717c478bd9Sstevel@tonic-gate bitset(S_IWGRP, dst.st_mode) &&
40727c478bd9Sstevel@tonic-gate dst.st_gid == st.st_gid);
40737c478bd9Sstevel@tonic-gate }
40747c478bd9Sstevel@tonic-gate if (delim != '\0')
40757c478bd9Sstevel@tonic-gate *bp = delim;
40763ee0e492Sjbeck bp = NULL;
40777c478bd9Sstevel@tonic-gate }
40787c478bd9Sstevel@tonic-gate if (!bogus)
40797c478bd9Sstevel@tonic-gate bogus = bitset(qsafe, st.st_mode);
40807c478bd9Sstevel@tonic-gate if (bogus)
40817c478bd9Sstevel@tonic-gate {
40827c478bd9Sstevel@tonic-gate if (LogLevel > 0)
40837c478bd9Sstevel@tonic-gate {
40847c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id,
40857c478bd9Sstevel@tonic-gate "bogus queue file, uid=%d, gid=%d, mode=%o",
40867c478bd9Sstevel@tonic-gate st.st_uid, st.st_gid, st.st_mode);
40877c478bd9Sstevel@tonic-gate }
40887c478bd9Sstevel@tonic-gate if (tTd(40, 8))
40897c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s): bogus file\n", qf);
40907c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE;
40917c478bd9Sstevel@tonic-gate if (!openonly)
40927c478bd9Sstevel@tonic-gate loseqfile(e, "bogus file uid/gid in mqueue");
40937c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT);
40947c478bd9Sstevel@tonic-gate return false;
40957c478bd9Sstevel@tonic-gate }
40967c478bd9Sstevel@tonic-gate
40977c478bd9Sstevel@tonic-gate if (st.st_size == 0)
40987c478bd9Sstevel@tonic-gate {
40997c478bd9Sstevel@tonic-gate /* must be a bogus file -- if also old, just remove it */
41007c478bd9Sstevel@tonic-gate if (!openonly && st.st_ctime + 10 * 60 < curtime())
41017c478bd9Sstevel@tonic-gate {
41027c478bd9Sstevel@tonic-gate (void) xunlink(queuename(e, DATAFL_LETTER));
41037c478bd9Sstevel@tonic-gate (void) xunlink(queuename(e, ANYQFL_LETTER));
41047c478bd9Sstevel@tonic-gate }
41057c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT);
41067c478bd9Sstevel@tonic-gate return false;
41077c478bd9Sstevel@tonic-gate }
41087c478bd9Sstevel@tonic-gate
41097c478bd9Sstevel@tonic-gate if (st.st_nlink == 0)
41107c478bd9Sstevel@tonic-gate {
41117c478bd9Sstevel@tonic-gate /*
41127c478bd9Sstevel@tonic-gate ** Race condition -- we got a file just as it was being
41137c478bd9Sstevel@tonic-gate ** unlinked. Just assume it is zero length.
41147c478bd9Sstevel@tonic-gate */
41157c478bd9Sstevel@tonic-gate
41167c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT);
41177c478bd9Sstevel@tonic-gate return false;
41187c478bd9Sstevel@tonic-gate }
41197c478bd9Sstevel@tonic-gate
41207c478bd9Sstevel@tonic-gate #if _FFR_TRUSTED_QF
41217c478bd9Sstevel@tonic-gate /*
41227c478bd9Sstevel@tonic-gate ** If we don't own the file mark it as unsafe.
41237c478bd9Sstevel@tonic-gate ** However, allow TrustedUser to own it as well
41247c478bd9Sstevel@tonic-gate ** in case TrustedUser manipulates the queue.
41257c478bd9Sstevel@tonic-gate */
41267c478bd9Sstevel@tonic-gate
41277c478bd9Sstevel@tonic-gate if (st.st_uid != geteuid() && st.st_uid != TrustedUid)
41287c478bd9Sstevel@tonic-gate e->e_flags |= EF_UNSAFE;
41297c478bd9Sstevel@tonic-gate #else /* _FFR_TRUSTED_QF */
41307c478bd9Sstevel@tonic-gate /* If we don't own the file mark it as unsafe */
41317c478bd9Sstevel@tonic-gate if (st.st_uid != geteuid())
41327c478bd9Sstevel@tonic-gate e->e_flags |= EF_UNSAFE;
41337c478bd9Sstevel@tonic-gate #endif /* _FFR_TRUSTED_QF */
41347c478bd9Sstevel@tonic-gate
41357c478bd9Sstevel@tonic-gate /* good file -- save this lock */
41367c478bd9Sstevel@tonic-gate e->e_lockfp = qfp;
41377c478bd9Sstevel@tonic-gate
41387c478bd9Sstevel@tonic-gate /* Just wanted the open file */
41397c478bd9Sstevel@tonic-gate if (openonly)
41407c478bd9Sstevel@tonic-gate return true;
41417c478bd9Sstevel@tonic-gate
41427c478bd9Sstevel@tonic-gate /* do basic system initialization */
41437c478bd9Sstevel@tonic-gate initsys(e);
41447c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'i', e->e_id);
41457c478bd9Sstevel@tonic-gate
41467c478bd9Sstevel@tonic-gate LineNumber = 0;
41477c478bd9Sstevel@tonic-gate e->e_flags |= EF_GLOBALERRS;
41487c478bd9Sstevel@tonic-gate set_op_mode(MD_QUEUERUN);
41497c478bd9Sstevel@tonic-gate ctladdr = NULL;
41507c478bd9Sstevel@tonic-gate e->e_qfletter = queue_letter(e, ANYQFL_LETTER);
41517c478bd9Sstevel@tonic-gate e->e_dfqgrp = e->e_qgrp;
41527c478bd9Sstevel@tonic-gate e->e_dfqdir = e->e_qdir;
41537c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_MACRO
41547c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{queue}"),
41557c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir));
41567c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_MACRO */
41577c478bd9Sstevel@tonic-gate e->e_dfino = -1;
41587c478bd9Sstevel@tonic-gate e->e_msgsize = -1;
4159058561cbSjbeck while (bufsize = sizeof(buf),
4160058561cbSjbeck (bp = fgetfolded(buf, &bufsize, qfp)) != NULL)
41617c478bd9Sstevel@tonic-gate {
41627c478bd9Sstevel@tonic-gate unsigned long qflags;
41637c478bd9Sstevel@tonic-gate ADDRESS *q;
41647c478bd9Sstevel@tonic-gate int r;
41657c478bd9Sstevel@tonic-gate time_t now;
41667c478bd9Sstevel@tonic-gate auto char *ep;
41677c478bd9Sstevel@tonic-gate
41687c478bd9Sstevel@tonic-gate if (tTd(40, 4))
41697c478bd9Sstevel@tonic-gate sm_dprintf("+++++ %s\n", bp);
41707c478bd9Sstevel@tonic-gate if (nomore)
41717c478bd9Sstevel@tonic-gate {
41727c478bd9Sstevel@tonic-gate /* hack attack */
41737c478bd9Sstevel@tonic-gate hackattack:
41747c478bd9Sstevel@tonic-gate syserr("SECURITY ALERT: extra or bogus data in queue file: %s",
41757c478bd9Sstevel@tonic-gate bp);
41767c478bd9Sstevel@tonic-gate err = "bogus queue line";
41777c478bd9Sstevel@tonic-gate goto fail;
41787c478bd9Sstevel@tonic-gate }
41797c478bd9Sstevel@tonic-gate switch (bp[0])
41807c478bd9Sstevel@tonic-gate {
41817c478bd9Sstevel@tonic-gate case 'A': /* AUTH= parameter */
41827c478bd9Sstevel@tonic-gate if (!xtextok(&bp[1]))
41837c478bd9Sstevel@tonic-gate goto hackattack;
41847c478bd9Sstevel@tonic-gate e->e_auth_param = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
41857c478bd9Sstevel@tonic-gate break;
41867c478bd9Sstevel@tonic-gate
41877c478bd9Sstevel@tonic-gate case 'B': /* body type */
41887c478bd9Sstevel@tonic-gate r = check_bodytype(&bp[1]);
41897c478bd9Sstevel@tonic-gate if (!BODYTYPE_VALID(r))
41907c478bd9Sstevel@tonic-gate goto hackattack;
41917c478bd9Sstevel@tonic-gate e->e_bodytype = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
41927c478bd9Sstevel@tonic-gate break;
41937c478bd9Sstevel@tonic-gate
41947c478bd9Sstevel@tonic-gate case 'C': /* specify controlling user */
41957c478bd9Sstevel@tonic-gate ctladdr = setctluser(&bp[1], qfver, e);
41967c478bd9Sstevel@tonic-gate break;
41977c478bd9Sstevel@tonic-gate
41987c478bd9Sstevel@tonic-gate case 'D': /* data file name */
41997c478bd9Sstevel@tonic-gate /* obsolete -- ignore */
42007c478bd9Sstevel@tonic-gate break;
42017c478bd9Sstevel@tonic-gate
42027c478bd9Sstevel@tonic-gate case 'd': /* data file directory name */
42037c478bd9Sstevel@tonic-gate {
42047c478bd9Sstevel@tonic-gate int qgrp, qdir;
42057c478bd9Sstevel@tonic-gate
42067c478bd9Sstevel@tonic-gate #if _FFR_MSP_PARANOIA
42077c478bd9Sstevel@tonic-gate /* forbid queue groups in MSP? */
42087c478bd9Sstevel@tonic-gate if (UseMSP)
42097c478bd9Sstevel@tonic-gate goto hackattack;
42107c478bd9Sstevel@tonic-gate #endif /* _FFR_MSP_PARANOIA */
42117c478bd9Sstevel@tonic-gate for (qgrp = 0;
42127c478bd9Sstevel@tonic-gate qgrp < NumQueue && Queue[qgrp] != NULL;
42137c478bd9Sstevel@tonic-gate ++qgrp)
42147c478bd9Sstevel@tonic-gate {
42157c478bd9Sstevel@tonic-gate for (qdir = 0;
42167c478bd9Sstevel@tonic-gate qdir < Queue[qgrp]->qg_numqueues;
42177c478bd9Sstevel@tonic-gate ++qdir)
42187c478bd9Sstevel@tonic-gate {
42197c478bd9Sstevel@tonic-gate if (strcmp(&bp[1],
42207c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name)
42217c478bd9Sstevel@tonic-gate == 0)
42227c478bd9Sstevel@tonic-gate {
42237c478bd9Sstevel@tonic-gate e->e_dfqgrp = qgrp;
42247c478bd9Sstevel@tonic-gate e->e_dfqdir = qdir;
42257c478bd9Sstevel@tonic-gate goto done;
42267c478bd9Sstevel@tonic-gate }
42277c478bd9Sstevel@tonic-gate }
42287c478bd9Sstevel@tonic-gate }
42297c478bd9Sstevel@tonic-gate err = "bogus queue file directory";
42307c478bd9Sstevel@tonic-gate goto fail;
42317c478bd9Sstevel@tonic-gate done:
42327c478bd9Sstevel@tonic-gate break;
42337c478bd9Sstevel@tonic-gate }
42347c478bd9Sstevel@tonic-gate
42357c478bd9Sstevel@tonic-gate case 'E': /* specify error recipient */
42367c478bd9Sstevel@tonic-gate /* no longer used */
42377c478bd9Sstevel@tonic-gate break;
42387c478bd9Sstevel@tonic-gate
42397c478bd9Sstevel@tonic-gate case 'F': /* flag bits */
42407c478bd9Sstevel@tonic-gate if (strncmp(bp, "From ", 5) == 0)
42417c478bd9Sstevel@tonic-gate {
42427c478bd9Sstevel@tonic-gate /* we are being spoofed! */
42437c478bd9Sstevel@tonic-gate syserr("SECURITY ALERT: bogus qf line %s", bp);
42447c478bd9Sstevel@tonic-gate err = "bogus queue line";
42457c478bd9Sstevel@tonic-gate goto fail;
42467c478bd9Sstevel@tonic-gate }
42477c478bd9Sstevel@tonic-gate for (p = &bp[1]; *p != '\0'; p++)
42487c478bd9Sstevel@tonic-gate {
42497c478bd9Sstevel@tonic-gate switch (*p)
42507c478bd9Sstevel@tonic-gate {
42517c478bd9Sstevel@tonic-gate case '8': /* has 8 bit data */
42527c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS8BIT;
42537c478bd9Sstevel@tonic-gate break;
42547c478bd9Sstevel@tonic-gate
42557c478bd9Sstevel@tonic-gate case 'b': /* delete Bcc: header */
42567c478bd9Sstevel@tonic-gate e->e_flags |= EF_DELETE_BCC;
42577c478bd9Sstevel@tonic-gate break;
42587c478bd9Sstevel@tonic-gate
42597c478bd9Sstevel@tonic-gate case 'd': /* envelope has DSN RET= */
42607c478bd9Sstevel@tonic-gate e->e_flags |= EF_RET_PARAM;
42617c478bd9Sstevel@tonic-gate break;
42627c478bd9Sstevel@tonic-gate
42637c478bd9Sstevel@tonic-gate case 'n': /* don't return body */
42647c478bd9Sstevel@tonic-gate e->e_flags |= EF_NO_BODY_RETN;
42657c478bd9Sstevel@tonic-gate break;
42667c478bd9Sstevel@tonic-gate
42677c478bd9Sstevel@tonic-gate case 'r': /* response */
42687c478bd9Sstevel@tonic-gate e->e_flags |= EF_RESPONSE;
42697c478bd9Sstevel@tonic-gate break;
42707c478bd9Sstevel@tonic-gate
42717c478bd9Sstevel@tonic-gate case 's': /* split */
42727c478bd9Sstevel@tonic-gate e->e_flags |= EF_SPLIT;
42737c478bd9Sstevel@tonic-gate break;
42747c478bd9Sstevel@tonic-gate
42757c478bd9Sstevel@tonic-gate case 'w': /* warning sent */
42767c478bd9Sstevel@tonic-gate e->e_flags |= EF_WARNING;
42777c478bd9Sstevel@tonic-gate break;
42787c478bd9Sstevel@tonic-gate }
42797c478bd9Sstevel@tonic-gate }
42807c478bd9Sstevel@tonic-gate break;
42817c478bd9Sstevel@tonic-gate
42827c478bd9Sstevel@tonic-gate case 'q': /* quarantine reason */
42837c478bd9Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
42847c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM,
42857c478bd9Sstevel@tonic-gate macid("{quarantine}"), e->e_quarmsg);
42867c478bd9Sstevel@tonic-gate break;
42877c478bd9Sstevel@tonic-gate
42887c478bd9Sstevel@tonic-gate case 'H': /* header */
42897c478bd9Sstevel@tonic-gate
42907c478bd9Sstevel@tonic-gate /*
42917c478bd9Sstevel@tonic-gate ** count size before chompheader() destroys the line.
42927c478bd9Sstevel@tonic-gate ** this isn't accurate due to macro expansion, but
42937c478bd9Sstevel@tonic-gate ** better than before. "-3" to skip H?? at least.
42947c478bd9Sstevel@tonic-gate */
42957c478bd9Sstevel@tonic-gate
42967c478bd9Sstevel@tonic-gate hdrsize += strlen(bp) - 3;
42977c478bd9Sstevel@tonic-gate (void) chompheader(&bp[1], CHHDR_QUEUE, NULL, e);
42987c478bd9Sstevel@tonic-gate break;
42997c478bd9Sstevel@tonic-gate
43007c478bd9Sstevel@tonic-gate case 'I': /* data file's inode number */
43017c478bd9Sstevel@tonic-gate /* regenerated below */
43027c478bd9Sstevel@tonic-gate break;
43037c478bd9Sstevel@tonic-gate
43047c478bd9Sstevel@tonic-gate case 'K': /* time of last delivery attempt */
43057c478bd9Sstevel@tonic-gate e->e_dtime = atol(&buf[1]);
43067c478bd9Sstevel@tonic-gate break;
43077c478bd9Sstevel@tonic-gate
43087c478bd9Sstevel@tonic-gate case 'L': /* Solaris Content-Length: */
43097c478bd9Sstevel@tonic-gate case 'M': /* message */
43107c478bd9Sstevel@tonic-gate /* ignore this; we want a new message next time */
43117c478bd9Sstevel@tonic-gate break;
43127c478bd9Sstevel@tonic-gate
43137c478bd9Sstevel@tonic-gate case 'N': /* number of delivery attempts */
43147c478bd9Sstevel@tonic-gate e->e_ntries = atoi(&buf[1]);
43157c478bd9Sstevel@tonic-gate
43167c478bd9Sstevel@tonic-gate /* if this has been tried recently, let it be */
43177c478bd9Sstevel@tonic-gate now = curtime();
43187c478bd9Sstevel@tonic-gate if (e->e_ntries > 0 && e->e_dtime <= now &&
43197c478bd9Sstevel@tonic-gate now < e->e_dtime + MinQueueAge)
43207c478bd9Sstevel@tonic-gate {
43217c478bd9Sstevel@tonic-gate char *howlong;
43227c478bd9Sstevel@tonic-gate
43237c478bd9Sstevel@tonic-gate howlong = pintvl(now - e->e_dtime, true);
43247c478bd9Sstevel@tonic-gate if (Verbose)
43257c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
43267c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
43277c478bd9Sstevel@tonic-gate "%s: too young (%s)\n",
43287c478bd9Sstevel@tonic-gate e->e_id, howlong);
43297c478bd9Sstevel@tonic-gate if (tTd(40, 8))
43307c478bd9Sstevel@tonic-gate sm_dprintf("%s: too young (%s)\n",
43317c478bd9Sstevel@tonic-gate e->e_id, howlong);
43327c478bd9Sstevel@tonic-gate if (LogLevel > 19)
43337c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id,
43347c478bd9Sstevel@tonic-gate "too young (%s)",
43357c478bd9Sstevel@tonic-gate howlong);
43367c478bd9Sstevel@tonic-gate e->e_id = NULL;
43377c478bd9Sstevel@tonic-gate unlockqueue(e);
4338058561cbSjbeck if (bp != buf)
4339058561cbSjbeck sm_free(bp);
43407c478bd9Sstevel@tonic-gate return false;
43417c478bd9Sstevel@tonic-gate }
43427c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP,
43437c478bd9Sstevel@tonic-gate macid("{ntries}"), &buf[1]);
43447c478bd9Sstevel@tonic-gate
43457c478bd9Sstevel@tonic-gate #if NAMED_BIND
43467c478bd9Sstevel@tonic-gate /* adjust BIND parameters immediately */
43477c478bd9Sstevel@tonic-gate if (e->e_ntries == 0)
43487c478bd9Sstevel@tonic-gate {
43497c478bd9Sstevel@tonic-gate _res.retry = TimeOuts.res_retry[RES_TO_FIRST];
43507c478bd9Sstevel@tonic-gate _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
43517c478bd9Sstevel@tonic-gate }
43527c478bd9Sstevel@tonic-gate else
43537c478bd9Sstevel@tonic-gate {
43547c478bd9Sstevel@tonic-gate _res.retry = TimeOuts.res_retry[RES_TO_NORMAL];
43557c478bd9Sstevel@tonic-gate _res.retrans = TimeOuts.res_retrans[RES_TO_NORMAL];
43567c478bd9Sstevel@tonic-gate }
43577c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */
43587c478bd9Sstevel@tonic-gate break;
43597c478bd9Sstevel@tonic-gate
43607c478bd9Sstevel@tonic-gate case 'P': /* message priority */
43617c478bd9Sstevel@tonic-gate e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
43627c478bd9Sstevel@tonic-gate break;
43637c478bd9Sstevel@tonic-gate
43647c478bd9Sstevel@tonic-gate case 'Q': /* original recipient */
43657c478bd9Sstevel@tonic-gate orcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
43667c478bd9Sstevel@tonic-gate break;
43677c478bd9Sstevel@tonic-gate
43687c478bd9Sstevel@tonic-gate case 'r': /* final recipient */
43697c478bd9Sstevel@tonic-gate frcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
43707c478bd9Sstevel@tonic-gate break;
43717c478bd9Sstevel@tonic-gate
43727c478bd9Sstevel@tonic-gate case 'R': /* specify recipient */
43737c478bd9Sstevel@tonic-gate p = bp;
43747c478bd9Sstevel@tonic-gate qflags = 0;
43757c478bd9Sstevel@tonic-gate if (qfver >= 1)
43767c478bd9Sstevel@tonic-gate {
43777c478bd9Sstevel@tonic-gate /* get flag bits */
43787c478bd9Sstevel@tonic-gate while (*++p != '\0' && *p != ':')
43797c478bd9Sstevel@tonic-gate {
43807c478bd9Sstevel@tonic-gate switch (*p)
43817c478bd9Sstevel@tonic-gate {
43827c478bd9Sstevel@tonic-gate case 'N':
43837c478bd9Sstevel@tonic-gate qflags |= QHASNOTIFY;
43847c478bd9Sstevel@tonic-gate break;
43857c478bd9Sstevel@tonic-gate
43867c478bd9Sstevel@tonic-gate case 'S':
43877c478bd9Sstevel@tonic-gate qflags |= QPINGONSUCCESS;
43887c478bd9Sstevel@tonic-gate break;
43897c478bd9Sstevel@tonic-gate
43907c478bd9Sstevel@tonic-gate case 'F':
43917c478bd9Sstevel@tonic-gate qflags |= QPINGONFAILURE;
43927c478bd9Sstevel@tonic-gate break;
43937c478bd9Sstevel@tonic-gate
43947c478bd9Sstevel@tonic-gate case 'D':
43957c478bd9Sstevel@tonic-gate qflags |= QPINGONDELAY;
43967c478bd9Sstevel@tonic-gate break;
43977c478bd9Sstevel@tonic-gate
43987c478bd9Sstevel@tonic-gate case 'P':
43997c478bd9Sstevel@tonic-gate qflags |= QPRIMARY;
44007c478bd9Sstevel@tonic-gate break;
44017c478bd9Sstevel@tonic-gate
44027c478bd9Sstevel@tonic-gate case 'A':
44037c478bd9Sstevel@tonic-gate if (ctladdr != NULL)
44047c478bd9Sstevel@tonic-gate ctladdr->q_flags |= QALIAS;
44057c478bd9Sstevel@tonic-gate break;
44067c478bd9Sstevel@tonic-gate
44077c478bd9Sstevel@tonic-gate default: /* ignore or complain? */
44087c478bd9Sstevel@tonic-gate break;
44097c478bd9Sstevel@tonic-gate }
44107c478bd9Sstevel@tonic-gate }
44117c478bd9Sstevel@tonic-gate }
44127c478bd9Sstevel@tonic-gate else
44137c478bd9Sstevel@tonic-gate qflags |= QPRIMARY;
44147c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{addr_type}"),
44157c478bd9Sstevel@tonic-gate "e r");
44167c478bd9Sstevel@tonic-gate if (*p != '\0')
44177c478bd9Sstevel@tonic-gate q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0',
44187c478bd9Sstevel@tonic-gate NULL, e, true);
44197c478bd9Sstevel@tonic-gate else
44207c478bd9Sstevel@tonic-gate q = NULL;
44217c478bd9Sstevel@tonic-gate if (q != NULL)
44227c478bd9Sstevel@tonic-gate {
44237c478bd9Sstevel@tonic-gate /* make sure we keep the current qgrp */
44247c478bd9Sstevel@tonic-gate if (ISVALIDQGRP(e->e_qgrp))
44257c478bd9Sstevel@tonic-gate q->q_qgrp = e->e_qgrp;
44267c478bd9Sstevel@tonic-gate q->q_alias = ctladdr;
44277c478bd9Sstevel@tonic-gate if (qfver >= 1)
44287c478bd9Sstevel@tonic-gate q->q_flags &= ~Q_PINGFLAGS;
44297c478bd9Sstevel@tonic-gate q->q_flags |= qflags;
44307c478bd9Sstevel@tonic-gate q->q_finalrcpt = frcpt;
44317c478bd9Sstevel@tonic-gate q->q_orcpt = orcpt;
44327c478bd9Sstevel@tonic-gate (void) recipient(q, &e->e_sendqueue, 0, e);
44337c478bd9Sstevel@tonic-gate }
44347c478bd9Sstevel@tonic-gate frcpt = NULL;
44357c478bd9Sstevel@tonic-gate orcpt = NULL;
44367c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{addr_type}"),
44377c478bd9Sstevel@tonic-gate NULL);
44387c478bd9Sstevel@tonic-gate break;
44397c478bd9Sstevel@tonic-gate
44407c478bd9Sstevel@tonic-gate case 'S': /* sender */
44417c478bd9Sstevel@tonic-gate setsender(sm_rpool_strdup_x(e->e_rpool, &bp[1]),
44427c478bd9Sstevel@tonic-gate e, NULL, '\0', true);
44437c478bd9Sstevel@tonic-gate break;
44447c478bd9Sstevel@tonic-gate
44457c478bd9Sstevel@tonic-gate case 'T': /* init time */
44467c478bd9Sstevel@tonic-gate e->e_ctime = atol(&bp[1]);
44477c478bd9Sstevel@tonic-gate break;
44487c478bd9Sstevel@tonic-gate
44497c478bd9Sstevel@tonic-gate case 'V': /* queue file version number */
44507c478bd9Sstevel@tonic-gate qfver = atoi(&bp[1]);
44517c478bd9Sstevel@tonic-gate if (qfver <= QF_VERSION)
44527c478bd9Sstevel@tonic-gate break;
44537c478bd9Sstevel@tonic-gate syserr("Version number in queue file (%d) greater than max (%d)",
44547c478bd9Sstevel@tonic-gate qfver, QF_VERSION);
44557c478bd9Sstevel@tonic-gate err = "unsupported queue file version";
44567c478bd9Sstevel@tonic-gate goto fail;
44577c478bd9Sstevel@tonic-gate /* NOTREACHED */
44587c478bd9Sstevel@tonic-gate break;
44597c478bd9Sstevel@tonic-gate
44607c478bd9Sstevel@tonic-gate case 'Z': /* original envelope id from ESMTP */
44617c478bd9Sstevel@tonic-gate e->e_envid = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
44627c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM,
44637c478bd9Sstevel@tonic-gate macid("{dsn_envid}"), e->e_envid);
44647c478bd9Sstevel@tonic-gate break;
44657c478bd9Sstevel@tonic-gate
44667c478bd9Sstevel@tonic-gate case '!': /* deliver by */
44677c478bd9Sstevel@tonic-gate
44687c478bd9Sstevel@tonic-gate /* format: flag (1 char) space long-integer */
44697c478bd9Sstevel@tonic-gate e->e_dlvr_flag = buf[1];
44707c478bd9Sstevel@tonic-gate e->e_deliver_by = strtol(&buf[3], NULL, 10);
4471*fec46055SToomas Soome /* FALLTHROUGH */
44727c478bd9Sstevel@tonic-gate
44737c478bd9Sstevel@tonic-gate case '$': /* define macro */
44747c478bd9Sstevel@tonic-gate {
44757c478bd9Sstevel@tonic-gate char *p;
44767c478bd9Sstevel@tonic-gate
44777c478bd9Sstevel@tonic-gate /* XXX elimate p? */
44787c478bd9Sstevel@tonic-gate r = macid_parse(&bp[1], &ep);
44797c478bd9Sstevel@tonic-gate if (r == 0)
44807c478bd9Sstevel@tonic-gate break;
44817c478bd9Sstevel@tonic-gate p = sm_rpool_strdup_x(e->e_rpool, ep);
44827c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, r, p);
44837c478bd9Sstevel@tonic-gate }
44847c478bd9Sstevel@tonic-gate break;
44857c478bd9Sstevel@tonic-gate
44867c478bd9Sstevel@tonic-gate case '.': /* terminate file */
44877c478bd9Sstevel@tonic-gate nomore = true;
44887c478bd9Sstevel@tonic-gate break;
44897c478bd9Sstevel@tonic-gate
44907c478bd9Sstevel@tonic-gate #if _FFR_QUEUEDELAY
44917c478bd9Sstevel@tonic-gate case 'G':
44927c478bd9Sstevel@tonic-gate case 'Y':
44937c478bd9Sstevel@tonic-gate
44947c478bd9Sstevel@tonic-gate /*
44957c478bd9Sstevel@tonic-gate ** Maintain backward compatibility for
44967c478bd9Sstevel@tonic-gate ** users who defined _FFR_QUEUEDELAY in
44977c478bd9Sstevel@tonic-gate ** previous releases. Remove this
44987c478bd9Sstevel@tonic-gate ** code in 8.14 or 8.15.
44997c478bd9Sstevel@tonic-gate */
45007c478bd9Sstevel@tonic-gate
45017c478bd9Sstevel@tonic-gate if (qfver == 5 || qfver == 7)
45027c478bd9Sstevel@tonic-gate break;
45037c478bd9Sstevel@tonic-gate
45047c478bd9Sstevel@tonic-gate /* If not qfver 5 or 7, then 'G' or 'Y' is invalid */
45057c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
45067c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUEDELAY */
45077c478bd9Sstevel@tonic-gate
45087c478bd9Sstevel@tonic-gate default:
45097c478bd9Sstevel@tonic-gate syserr("readqf: %s: line %d: bad line \"%s\"",
45107c478bd9Sstevel@tonic-gate qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
45117c478bd9Sstevel@tonic-gate err = "unrecognized line";
45127c478bd9Sstevel@tonic-gate goto fail;
45137c478bd9Sstevel@tonic-gate }
45147c478bd9Sstevel@tonic-gate
45157c478bd9Sstevel@tonic-gate if (bp != buf)
4516058561cbSjbeck SM_FREE(bp);
45177c478bd9Sstevel@tonic-gate }
45187c478bd9Sstevel@tonic-gate
45197c478bd9Sstevel@tonic-gate /*
45207c478bd9Sstevel@tonic-gate ** If we haven't read any lines, this queue file is empty.
45217c478bd9Sstevel@tonic-gate ** Arrange to remove it without referencing any null pointers.
45227c478bd9Sstevel@tonic-gate */
45237c478bd9Sstevel@tonic-gate
45247c478bd9Sstevel@tonic-gate if (LineNumber == 0)
45257c478bd9Sstevel@tonic-gate {
45267c478bd9Sstevel@tonic-gate errno = 0;
45277c478bd9Sstevel@tonic-gate e->e_flags |= EF_CLRQUEUE|EF_FATALERRS|EF_RESPONSE;
45287c478bd9Sstevel@tonic-gate return true;
45297c478bd9Sstevel@tonic-gate }
45307c478bd9Sstevel@tonic-gate
45317c478bd9Sstevel@tonic-gate /* Check to make sure we have a complete queue file read */
45327c478bd9Sstevel@tonic-gate if (!nomore)
45337c478bd9Sstevel@tonic-gate {
45347c478bd9Sstevel@tonic-gate syserr("readqf: %s: incomplete queue file read", qf);
45357c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT);
45367c478bd9Sstevel@tonic-gate return false;
45377c478bd9Sstevel@tonic-gate }
45387c478bd9Sstevel@tonic-gate
45394aac33d3Sjbeck #if _FFR_QF_PARANOIA
45404aac33d3Sjbeck /* Check to make sure key fields were read */
45414aac33d3Sjbeck if (e->e_from.q_mailer == NULL)
45424aac33d3Sjbeck {
45434aac33d3Sjbeck syserr("readqf: %s: sender not specified in queue file", qf);
45444aac33d3Sjbeck (void) sm_io_close(qfp, SM_TIME_DEFAULT);
45454aac33d3Sjbeck return false;
45464aac33d3Sjbeck }
45474aac33d3Sjbeck /* other checks? */
45484aac33d3Sjbeck #endif /* _FFR_QF_PARANOIA */
45494aac33d3Sjbeck
45507c478bd9Sstevel@tonic-gate /* possibly set ${dsn_ret} macro */
45517c478bd9Sstevel@tonic-gate if (bitset(EF_RET_PARAM, e->e_flags))
45527c478bd9Sstevel@tonic-gate {
45537c478bd9Sstevel@tonic-gate if (bitset(EF_NO_BODY_RETN, e->e_flags))
45547c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM,
45557c478bd9Sstevel@tonic-gate macid("{dsn_ret}"), "hdrs");
45567c478bd9Sstevel@tonic-gate else
45577c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM,
45587c478bd9Sstevel@tonic-gate macid("{dsn_ret}"), "full");
45597c478bd9Sstevel@tonic-gate }
45607c478bd9Sstevel@tonic-gate
45617c478bd9Sstevel@tonic-gate /*
45627c478bd9Sstevel@tonic-gate ** Arrange to read the data file.
45637c478bd9Sstevel@tonic-gate */
45647c478bd9Sstevel@tonic-gate
45657c478bd9Sstevel@tonic-gate p = queuename(e, DATAFL_LETTER);
45667c478bd9Sstevel@tonic-gate e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, p, SM_IO_RDONLY_B,
45677c478bd9Sstevel@tonic-gate NULL);
45687c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL)
45697c478bd9Sstevel@tonic-gate {
45707c478bd9Sstevel@tonic-gate syserr("readqf: cannot open %s", p);
45717c478bd9Sstevel@tonic-gate }
45727c478bd9Sstevel@tonic-gate else
45737c478bd9Sstevel@tonic-gate {
45747c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS_DF;
45757c478bd9Sstevel@tonic-gate if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &st)
45767c478bd9Sstevel@tonic-gate >= 0)
45777c478bd9Sstevel@tonic-gate {
45787c478bd9Sstevel@tonic-gate e->e_msgsize = st.st_size + hdrsize;
45797c478bd9Sstevel@tonic-gate e->e_dfdev = st.st_dev;
45807c478bd9Sstevel@tonic-gate e->e_dfino = ST_INODE(st);
4581058561cbSjbeck (void) sm_snprintf(buf, sizeof(buf), "%ld",
45827c478bd9Sstevel@tonic-gate e->e_msgsize);
45837c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"),
45847c478bd9Sstevel@tonic-gate buf);
45857c478bd9Sstevel@tonic-gate }
45867c478bd9Sstevel@tonic-gate }
45877c478bd9Sstevel@tonic-gate
45887c478bd9Sstevel@tonic-gate return true;
45897c478bd9Sstevel@tonic-gate
45907c478bd9Sstevel@tonic-gate fail:
45917c478bd9Sstevel@tonic-gate /*
45927c478bd9Sstevel@tonic-gate ** There was some error reading the qf file (reason is in err var.)
45937c478bd9Sstevel@tonic-gate ** Cleanup:
45947c478bd9Sstevel@tonic-gate ** close file; clear e_lockfp since it is the same as qfp,
45957c478bd9Sstevel@tonic-gate ** hence it is invalid (as file) after qfp is closed;
45967c478bd9Sstevel@tonic-gate ** the qf file is on disk, so set the flag to avoid calling
45977c478bd9Sstevel@tonic-gate ** queueup() with bogus data.
45987c478bd9Sstevel@tonic-gate */
45997c478bd9Sstevel@tonic-gate
4600058561cbSjbeck if (bp != buf)
4601058561cbSjbeck SM_FREE(bp);
46027c478bd9Sstevel@tonic-gate if (qfp != NULL)
46037c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT);
46047c478bd9Sstevel@tonic-gate e->e_lockfp = NULL;
46057c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE;
46067c478bd9Sstevel@tonic-gate loseqfile(e, err);
46077c478bd9Sstevel@tonic-gate return false;
46087c478bd9Sstevel@tonic-gate }
46097c478bd9Sstevel@tonic-gate /*
46107c478bd9Sstevel@tonic-gate ** PRTSTR -- print a string, "unprintable" characters are shown as \oct
46117c478bd9Sstevel@tonic-gate **
46127c478bd9Sstevel@tonic-gate ** Parameters:
46137c478bd9Sstevel@tonic-gate ** s -- string to print
46147c478bd9Sstevel@tonic-gate ** ml -- maximum length of output
46157c478bd9Sstevel@tonic-gate **
46167c478bd9Sstevel@tonic-gate ** Returns:
46177c478bd9Sstevel@tonic-gate ** number of entries
46187c478bd9Sstevel@tonic-gate **
46197c478bd9Sstevel@tonic-gate ** Side Effects:
46207c478bd9Sstevel@tonic-gate ** Prints a string on stdout.
46217c478bd9Sstevel@tonic-gate */
46227c478bd9Sstevel@tonic-gate
4623058561cbSjbeck static void prtstr __P((char *, int));
4624058561cbSjbeck
46257c478bd9Sstevel@tonic-gate static void
prtstr(s,ml)46267c478bd9Sstevel@tonic-gate prtstr(s, ml)
46277c478bd9Sstevel@tonic-gate char *s;
46287c478bd9Sstevel@tonic-gate int ml;
46297c478bd9Sstevel@tonic-gate {
46307c478bd9Sstevel@tonic-gate int c;
46317c478bd9Sstevel@tonic-gate
46327c478bd9Sstevel@tonic-gate if (s == NULL)
46337c478bd9Sstevel@tonic-gate return;
46347c478bd9Sstevel@tonic-gate while (ml-- > 0 && ((c = *s++) != '\0'))
46357c478bd9Sstevel@tonic-gate {
46367c478bd9Sstevel@tonic-gate if (c == '\\')
46377c478bd9Sstevel@tonic-gate {
46387c478bd9Sstevel@tonic-gate if (ml-- > 0)
46397c478bd9Sstevel@tonic-gate {
46407c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
46417c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
46427c478bd9Sstevel@tonic-gate }
46437c478bd9Sstevel@tonic-gate }
46447c478bd9Sstevel@tonic-gate else if (isascii(c) && isprint(c))
46457c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
46467c478bd9Sstevel@tonic-gate else
46477c478bd9Sstevel@tonic-gate {
46487c478bd9Sstevel@tonic-gate if ((ml -= 3) > 0)
46497c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
46507c478bd9Sstevel@tonic-gate "\\%03o", c & 0xFF);
46517c478bd9Sstevel@tonic-gate }
46527c478bd9Sstevel@tonic-gate }
46537c478bd9Sstevel@tonic-gate }
46547c478bd9Sstevel@tonic-gate /*
46557c478bd9Sstevel@tonic-gate ** PRINTNQE -- print out number of entries in the mail queue
46567c478bd9Sstevel@tonic-gate **
46577c478bd9Sstevel@tonic-gate ** Parameters:
46587c478bd9Sstevel@tonic-gate ** out -- output file pointer.
46597c478bd9Sstevel@tonic-gate ** prefix -- string to output in front of each line.
46607c478bd9Sstevel@tonic-gate **
46617c478bd9Sstevel@tonic-gate ** Returns:
46627c478bd9Sstevel@tonic-gate ** none.
46637c478bd9Sstevel@tonic-gate */
46647c478bd9Sstevel@tonic-gate
46657c478bd9Sstevel@tonic-gate void
printnqe(out,prefix)46667c478bd9Sstevel@tonic-gate printnqe(out, prefix)
46677c478bd9Sstevel@tonic-gate SM_FILE_T *out;
46687c478bd9Sstevel@tonic-gate char *prefix;
46697c478bd9Sstevel@tonic-gate {
46707c478bd9Sstevel@tonic-gate #if SM_CONF_SHM
46717c478bd9Sstevel@tonic-gate int i, k = 0, nrequests = 0;
46727c478bd9Sstevel@tonic-gate bool unknown = false;
46737c478bd9Sstevel@tonic-gate
46747c478bd9Sstevel@tonic-gate if (ShmId == SM_SHM_NO_ID)
46757c478bd9Sstevel@tonic-gate {
46767c478bd9Sstevel@tonic-gate if (prefix == NULL)
46777c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
46787c478bd9Sstevel@tonic-gate "Data unavailable: shared memory not updated\n");
46797c478bd9Sstevel@tonic-gate else
46807c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
46817c478bd9Sstevel@tonic-gate "%sNOTCONFIGURED:-1\r\n", prefix);
46827c478bd9Sstevel@tonic-gate return;
46837c478bd9Sstevel@tonic-gate }
46847c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
46857c478bd9Sstevel@tonic-gate {
46867c478bd9Sstevel@tonic-gate int j;
46877c478bd9Sstevel@tonic-gate
46887c478bd9Sstevel@tonic-gate k++;
46897c478bd9Sstevel@tonic-gate for (j = 0; j < Queue[i]->qg_numqueues; j++)
46907c478bd9Sstevel@tonic-gate {
46917c478bd9Sstevel@tonic-gate int n;
46927c478bd9Sstevel@tonic-gate
46937c478bd9Sstevel@tonic-gate if (StopRequest)
46947c478bd9Sstevel@tonic-gate stop_sendmail();
46957c478bd9Sstevel@tonic-gate
46967c478bd9Sstevel@tonic-gate n = QSHM_ENTRIES(Queue[i]->qg_qpaths[j].qp_idx);
46977c478bd9Sstevel@tonic-gate if (prefix != NULL)
46987c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
46997c478bd9Sstevel@tonic-gate "%s%s:%d\r\n",
47007c478bd9Sstevel@tonic-gate prefix, qid_printqueue(i, j), n);
47017c478bd9Sstevel@tonic-gate else if (n < 0)
47027c478bd9Sstevel@tonic-gate {
47037c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
47047c478bd9Sstevel@tonic-gate "%s: unknown number of entries\n",
47057c478bd9Sstevel@tonic-gate qid_printqueue(i, j));
47067c478bd9Sstevel@tonic-gate unknown = true;
47077c478bd9Sstevel@tonic-gate }
47087c478bd9Sstevel@tonic-gate else if (n == 0)
47097c478bd9Sstevel@tonic-gate {
47107c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
47117c478bd9Sstevel@tonic-gate "%s is empty\n",
47127c478bd9Sstevel@tonic-gate qid_printqueue(i, j));
47137c478bd9Sstevel@tonic-gate }
47147c478bd9Sstevel@tonic-gate else if (n > 0)
47157c478bd9Sstevel@tonic-gate {
47167c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
47177c478bd9Sstevel@tonic-gate "%s: entries=%d\n",
47187c478bd9Sstevel@tonic-gate qid_printqueue(i, j), n);
47197c478bd9Sstevel@tonic-gate nrequests += n;
47207c478bd9Sstevel@tonic-gate k++;
47217c478bd9Sstevel@tonic-gate }
47227c478bd9Sstevel@tonic-gate }
47237c478bd9Sstevel@tonic-gate }
47247c478bd9Sstevel@tonic-gate if (prefix == NULL && k > 1)
47257c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
47267c478bd9Sstevel@tonic-gate "\t\tTotal requests: %d%s\n",
47277c478bd9Sstevel@tonic-gate nrequests, unknown ? " (about)" : "");
47287c478bd9Sstevel@tonic-gate #else /* SM_CONF_SHM */
47297c478bd9Sstevel@tonic-gate if (prefix == NULL)
47307c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
47317c478bd9Sstevel@tonic-gate "Data unavailable without shared memory support\n");
47327c478bd9Sstevel@tonic-gate else
47337c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
47347c478bd9Sstevel@tonic-gate "%sNOTAVAILABLE:-1\r\n", prefix);
47357c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */
47367c478bd9Sstevel@tonic-gate }
47377c478bd9Sstevel@tonic-gate /*
47387c478bd9Sstevel@tonic-gate ** PRINTQUEUE -- print out a representation of the mail queue
47397c478bd9Sstevel@tonic-gate **
47407c478bd9Sstevel@tonic-gate ** Parameters:
47417c478bd9Sstevel@tonic-gate ** none.
47427c478bd9Sstevel@tonic-gate **
47437c478bd9Sstevel@tonic-gate ** Returns:
47447c478bd9Sstevel@tonic-gate ** none.
47457c478bd9Sstevel@tonic-gate **
47467c478bd9Sstevel@tonic-gate ** Side Effects:
47477c478bd9Sstevel@tonic-gate ** Prints a listing of the mail queue on the standard output.
47487c478bd9Sstevel@tonic-gate */
47497c478bd9Sstevel@tonic-gate
47507c478bd9Sstevel@tonic-gate void
printqueue()47517c478bd9Sstevel@tonic-gate printqueue()
47527c478bd9Sstevel@tonic-gate {
47537c478bd9Sstevel@tonic-gate int i, k = 0, nrequests = 0;
47547c478bd9Sstevel@tonic-gate
47557c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
47567c478bd9Sstevel@tonic-gate {
47577c478bd9Sstevel@tonic-gate int j;
47587c478bd9Sstevel@tonic-gate
47597c478bd9Sstevel@tonic-gate k++;
47607c478bd9Sstevel@tonic-gate for (j = 0; j < Queue[i]->qg_numqueues; j++)
47617c478bd9Sstevel@tonic-gate {
47627c478bd9Sstevel@tonic-gate if (StopRequest)
47637c478bd9Sstevel@tonic-gate stop_sendmail();
47647c478bd9Sstevel@tonic-gate nrequests += print_single_queue(i, j);
47657c478bd9Sstevel@tonic-gate k++;
47667c478bd9Sstevel@tonic-gate }
47677c478bd9Sstevel@tonic-gate }
47687c478bd9Sstevel@tonic-gate if (k > 1)
47697c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
47707c478bd9Sstevel@tonic-gate "\t\tTotal requests: %d\n",
47717c478bd9Sstevel@tonic-gate nrequests);
47727c478bd9Sstevel@tonic-gate }
47737c478bd9Sstevel@tonic-gate /*
47747c478bd9Sstevel@tonic-gate ** PRINT_SINGLE_QUEUE -- print out a representation of a single mail queue
47757c478bd9Sstevel@tonic-gate **
47767c478bd9Sstevel@tonic-gate ** Parameters:
47777c478bd9Sstevel@tonic-gate ** qgrp -- the index of the queue group.
47787c478bd9Sstevel@tonic-gate ** qdir -- the queue directory.
47797c478bd9Sstevel@tonic-gate **
47807c478bd9Sstevel@tonic-gate ** Returns:
47817c478bd9Sstevel@tonic-gate ** number of requests in mail queue.
47827c478bd9Sstevel@tonic-gate **
47837c478bd9Sstevel@tonic-gate ** Side Effects:
47847c478bd9Sstevel@tonic-gate ** Prints a listing of the mail queue on the standard output.
47857c478bd9Sstevel@tonic-gate */
47867c478bd9Sstevel@tonic-gate
47877c478bd9Sstevel@tonic-gate int
print_single_queue(qgrp,qdir)47887c478bd9Sstevel@tonic-gate print_single_queue(qgrp, qdir)
47897c478bd9Sstevel@tonic-gate int qgrp;
47907c478bd9Sstevel@tonic-gate int qdir;
47917c478bd9Sstevel@tonic-gate {
47927c478bd9Sstevel@tonic-gate register WORK *w;
47937c478bd9Sstevel@tonic-gate SM_FILE_T *f;
47947c478bd9Sstevel@tonic-gate int nrequests;
47957c478bd9Sstevel@tonic-gate char qd[MAXPATHLEN];
47967c478bd9Sstevel@tonic-gate char qddf[MAXPATHLEN];
47977c478bd9Sstevel@tonic-gate char buf[MAXLINE];
47987c478bd9Sstevel@tonic-gate
47997c478bd9Sstevel@tonic-gate if (qdir == NOQDIR)
48007c478bd9Sstevel@tonic-gate {
4801058561cbSjbeck (void) sm_strlcpy(qd, ".", sizeof(qd));
4802058561cbSjbeck (void) sm_strlcpy(qddf, ".", sizeof(qddf));
48037c478bd9Sstevel@tonic-gate }
48047c478bd9Sstevel@tonic-gate else
48057c478bd9Sstevel@tonic-gate {
4806058561cbSjbeck (void) sm_strlcpyn(qd, sizeof(qd), 2,
48077c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name,
48087c478bd9Sstevel@tonic-gate (bitset(QP_SUBQF,
48097c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
48107c478bd9Sstevel@tonic-gate ? "/qf" : ""));
4811058561cbSjbeck (void) sm_strlcpyn(qddf, sizeof(qddf), 2,
48127c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name,
48137c478bd9Sstevel@tonic-gate (bitset(QP_SUBDF,
48147c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
48157c478bd9Sstevel@tonic-gate ? "/df" : ""));
48167c478bd9Sstevel@tonic-gate }
48177c478bd9Sstevel@tonic-gate
48187c478bd9Sstevel@tonic-gate /*
48197c478bd9Sstevel@tonic-gate ** Check for permission to print the queue
48207c478bd9Sstevel@tonic-gate */
48217c478bd9Sstevel@tonic-gate
48227c478bd9Sstevel@tonic-gate if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
48237c478bd9Sstevel@tonic-gate {
48247c478bd9Sstevel@tonic-gate struct stat st;
48257c478bd9Sstevel@tonic-gate #ifdef NGROUPS_MAX
48267c478bd9Sstevel@tonic-gate int n;
48277c478bd9Sstevel@tonic-gate extern GIDSET_T InitialGidSet[NGROUPS_MAX];
48287c478bd9Sstevel@tonic-gate #endif /* NGROUPS_MAX */
48297c478bd9Sstevel@tonic-gate
48307c478bd9Sstevel@tonic-gate if (stat(qd, &st) < 0)
48317c478bd9Sstevel@tonic-gate {
48327c478bd9Sstevel@tonic-gate syserr("Cannot stat %s",
48337c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir));
48347c478bd9Sstevel@tonic-gate return 0;
48357c478bd9Sstevel@tonic-gate }
48367c478bd9Sstevel@tonic-gate #ifdef NGROUPS_MAX
48377c478bd9Sstevel@tonic-gate n = NGROUPS_MAX;
48387c478bd9Sstevel@tonic-gate while (--n >= 0)
48397c478bd9Sstevel@tonic-gate {
48407c478bd9Sstevel@tonic-gate if (InitialGidSet[n] == st.st_gid)
48417c478bd9Sstevel@tonic-gate break;
48427c478bd9Sstevel@tonic-gate }
48437c478bd9Sstevel@tonic-gate if (n < 0 && RealGid != st.st_gid)
48447c478bd9Sstevel@tonic-gate #else /* NGROUPS_MAX */
48457c478bd9Sstevel@tonic-gate if (RealGid != st.st_gid)
48467c478bd9Sstevel@tonic-gate #endif /* NGROUPS_MAX */
48477c478bd9Sstevel@tonic-gate {
48487c478bd9Sstevel@tonic-gate usrerr("510 You are not permitted to see the queue");
48497c478bd9Sstevel@tonic-gate setstat(EX_NOPERM);
48507c478bd9Sstevel@tonic-gate return 0;
48517c478bd9Sstevel@tonic-gate }
48527c478bd9Sstevel@tonic-gate }
48537c478bd9Sstevel@tonic-gate
48547c478bd9Sstevel@tonic-gate /*
48557c478bd9Sstevel@tonic-gate ** Read and order the queue.
48567c478bd9Sstevel@tonic-gate */
48577c478bd9Sstevel@tonic-gate
4858e9af4bc0SJohn Beck nrequests = gatherq(qgrp, qdir, true, NULL, NULL, NULL);
48597c478bd9Sstevel@tonic-gate (void) sortq(Queue[qgrp]->qg_maxlist);
48607c478bd9Sstevel@tonic-gate
48617c478bd9Sstevel@tonic-gate /*
48627c478bd9Sstevel@tonic-gate ** Print the work list that we have read.
48637c478bd9Sstevel@tonic-gate */
48647c478bd9Sstevel@tonic-gate
48657c478bd9Sstevel@tonic-gate /* first see if there is anything */
48667c478bd9Sstevel@tonic-gate if (nrequests <= 0)
48677c478bd9Sstevel@tonic-gate {
48687c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s is empty\n",
48697c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir));
48707c478bd9Sstevel@tonic-gate return 0;
48717c478bd9Sstevel@tonic-gate }
48727c478bd9Sstevel@tonic-gate
48737c478bd9Sstevel@tonic-gate sm_getla(); /* get load average */
48747c478bd9Sstevel@tonic-gate
48757c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\t\t%s (%d request%s",
48767c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir),
48777c478bd9Sstevel@tonic-gate nrequests, nrequests == 1 ? "" : "s");
48787c478bd9Sstevel@tonic-gate if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
48797c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
48807c478bd9Sstevel@tonic-gate ", only %d printed", MaxQueueRun);
48817c478bd9Sstevel@tonic-gate if (Verbose)
48827c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
48837c478bd9Sstevel@tonic-gate ")\n-----Q-ID----- --Size-- -Priority- ---Q-Time--- --------Sender/Recipient--------\n");
48847c478bd9Sstevel@tonic-gate else
48857c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
48867c478bd9Sstevel@tonic-gate ")\n-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------\n");
48877c478bd9Sstevel@tonic-gate for (w = WorkQ; w != NULL; w = w->w_next)
48887c478bd9Sstevel@tonic-gate {
48897c478bd9Sstevel@tonic-gate struct stat st;
48907c478bd9Sstevel@tonic-gate auto time_t submittime = 0;
48917c478bd9Sstevel@tonic-gate long dfsize;
48927c478bd9Sstevel@tonic-gate int flags = 0;
48937c478bd9Sstevel@tonic-gate int qfver;
48947c478bd9Sstevel@tonic-gate char quarmsg[MAXLINE];
48957c478bd9Sstevel@tonic-gate char statmsg[MAXLINE];
48967c478bd9Sstevel@tonic-gate char bodytype[MAXNAME + 1];
48977c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN];
48987c478bd9Sstevel@tonic-gate
48997c478bd9Sstevel@tonic-gate if (StopRequest)
49007c478bd9Sstevel@tonic-gate stop_sendmail();
49017c478bd9Sstevel@tonic-gate
49027c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%13s",
49037c478bd9Sstevel@tonic-gate w->w_name + 2);
4904058561cbSjbeck (void) sm_strlcpyn(qf, sizeof(qf), 3, qd, "/", w->w_name);
49057c478bd9Sstevel@tonic-gate f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY_B,
49067c478bd9Sstevel@tonic-gate NULL);
49077c478bd9Sstevel@tonic-gate if (f == NULL)
49087c478bd9Sstevel@tonic-gate {
49097c478bd9Sstevel@tonic-gate if (errno == EPERM)
49107c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
49117c478bd9Sstevel@tonic-gate " (permission denied)\n");
49127c478bd9Sstevel@tonic-gate else if (errno == ENOENT)
49137c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
49147c478bd9Sstevel@tonic-gate " (job completed)\n");
49157c478bd9Sstevel@tonic-gate else
49167c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
49177c478bd9Sstevel@tonic-gate " (%s)\n",
49187c478bd9Sstevel@tonic-gate sm_errstring(errno));
49197c478bd9Sstevel@tonic-gate errno = 0;
49207c478bd9Sstevel@tonic-gate continue;
49217c478bd9Sstevel@tonic-gate }
49227c478bd9Sstevel@tonic-gate w->w_name[0] = DATAFL_LETTER;
4923058561cbSjbeck (void) sm_strlcpyn(qf, sizeof(qf), 3, qddf, "/", w->w_name);
49247c478bd9Sstevel@tonic-gate if (stat(qf, &st) >= 0)
49257c478bd9Sstevel@tonic-gate dfsize = st.st_size;
49267c478bd9Sstevel@tonic-gate else
49277c478bd9Sstevel@tonic-gate {
49287c478bd9Sstevel@tonic-gate ENVELOPE e;
49297c478bd9Sstevel@tonic-gate
49307c478bd9Sstevel@tonic-gate /*
49317c478bd9Sstevel@tonic-gate ** Maybe the df file can't be statted because
49327c478bd9Sstevel@tonic-gate ** it is in a different directory than the qf file.
49337c478bd9Sstevel@tonic-gate ** In order to find out, we must read the qf file.
49347c478bd9Sstevel@tonic-gate */
49357c478bd9Sstevel@tonic-gate
49367c478bd9Sstevel@tonic-gate newenvelope(&e, &BlankEnvelope, sm_rpool_new_x(NULL));
49377c478bd9Sstevel@tonic-gate e.e_id = w->w_name + 2;
49387c478bd9Sstevel@tonic-gate e.e_qgrp = qgrp;
49397c478bd9Sstevel@tonic-gate e.e_qdir = qdir;
49407c478bd9Sstevel@tonic-gate dfsize = -1;
49417c478bd9Sstevel@tonic-gate if (readqf(&e, false))
49427c478bd9Sstevel@tonic-gate {
49437c478bd9Sstevel@tonic-gate char *df = queuename(&e, DATAFL_LETTER);
49447c478bd9Sstevel@tonic-gate if (stat(df, &st) >= 0)
49457c478bd9Sstevel@tonic-gate dfsize = st.st_size;
49467c478bd9Sstevel@tonic-gate }
49477c478bd9Sstevel@tonic-gate if (e.e_lockfp != NULL)
49487c478bd9Sstevel@tonic-gate {
49497c478bd9Sstevel@tonic-gate (void) sm_io_close(e.e_lockfp, SM_TIME_DEFAULT);
49507c478bd9Sstevel@tonic-gate e.e_lockfp = NULL;
49517c478bd9Sstevel@tonic-gate }
49527c478bd9Sstevel@tonic-gate clearenvelope(&e, false, e.e_rpool);
49537c478bd9Sstevel@tonic-gate sm_rpool_free(e.e_rpool);
49547c478bd9Sstevel@tonic-gate }
49557c478bd9Sstevel@tonic-gate if (w->w_lock)
49567c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "*");
49577c478bd9Sstevel@tonic-gate else if (QueueMode == QM_LOST)
49587c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "?");
49597c478bd9Sstevel@tonic-gate else if (w->w_tooyoung)
49607c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "-");
49617c478bd9Sstevel@tonic-gate else if (shouldqueue(w->w_pri, w->w_ctime))
49627c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "X");
49637c478bd9Sstevel@tonic-gate else
49647c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " ");
49657c478bd9Sstevel@tonic-gate
49667c478bd9Sstevel@tonic-gate errno = 0;
49677c478bd9Sstevel@tonic-gate
49687c478bd9Sstevel@tonic-gate quarmsg[0] = '\0';
49697c478bd9Sstevel@tonic-gate statmsg[0] = bodytype[0] = '\0';
49707c478bd9Sstevel@tonic-gate qfver = 0;
4971058561cbSjbeck while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
49727c478bd9Sstevel@tonic-gate {
49737c478bd9Sstevel@tonic-gate register int i;
49747c478bd9Sstevel@tonic-gate register char *p;
49757c478bd9Sstevel@tonic-gate
49767c478bd9Sstevel@tonic-gate if (StopRequest)
49777c478bd9Sstevel@tonic-gate stop_sendmail();
49787c478bd9Sstevel@tonic-gate
49797c478bd9Sstevel@tonic-gate fixcrlf(buf, true);
49807c478bd9Sstevel@tonic-gate switch (buf[0])
49817c478bd9Sstevel@tonic-gate {
49827c478bd9Sstevel@tonic-gate case 'V': /* queue file version */
49837c478bd9Sstevel@tonic-gate qfver = atoi(&buf[1]);
49847c478bd9Sstevel@tonic-gate break;
49857c478bd9Sstevel@tonic-gate
49867c478bd9Sstevel@tonic-gate case 'M': /* error message */
4987058561cbSjbeck if ((i = strlen(&buf[1])) >= sizeof(statmsg))
4988058561cbSjbeck i = sizeof(statmsg) - 1;
49897c478bd9Sstevel@tonic-gate memmove(statmsg, &buf[1], i);
49907c478bd9Sstevel@tonic-gate statmsg[i] = '\0';
49917c478bd9Sstevel@tonic-gate break;
49927c478bd9Sstevel@tonic-gate
49937c478bd9Sstevel@tonic-gate case 'q': /* quarantine reason */
4994058561cbSjbeck if ((i = strlen(&buf[1])) >= sizeof(quarmsg))
4995058561cbSjbeck i = sizeof(quarmsg) - 1;
49967c478bd9Sstevel@tonic-gate memmove(quarmsg, &buf[1], i);
49977c478bd9Sstevel@tonic-gate quarmsg[i] = '\0';
49987c478bd9Sstevel@tonic-gate break;
49997c478bd9Sstevel@tonic-gate
50007c478bd9Sstevel@tonic-gate case 'B': /* body type */
5001058561cbSjbeck if ((i = strlen(&buf[1])) >= sizeof(bodytype))
5002058561cbSjbeck i = sizeof(bodytype) - 1;
50037c478bd9Sstevel@tonic-gate memmove(bodytype, &buf[1], i);
50047c478bd9Sstevel@tonic-gate bodytype[i] = '\0';
50057c478bd9Sstevel@tonic-gate break;
50067c478bd9Sstevel@tonic-gate
50077c478bd9Sstevel@tonic-gate case 'S': /* sender name */
50087c478bd9Sstevel@tonic-gate if (Verbose)
50097c478bd9Sstevel@tonic-gate {
50107c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
50117c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
50127c478bd9Sstevel@tonic-gate "%8ld %10ld%c%.12s ",
50137c478bd9Sstevel@tonic-gate dfsize,
50147c478bd9Sstevel@tonic-gate w->w_pri,
50157c478bd9Sstevel@tonic-gate bitset(EF_WARNING, flags)
50167c478bd9Sstevel@tonic-gate ? '+' : ' ',
50177c478bd9Sstevel@tonic-gate ctime(&submittime) + 4);
50187c478bd9Sstevel@tonic-gate prtstr(&buf[1], 78);
50197c478bd9Sstevel@tonic-gate }
50207c478bd9Sstevel@tonic-gate else
50217c478bd9Sstevel@tonic-gate {
50227c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
50237c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
50247c478bd9Sstevel@tonic-gate "%8ld %.16s ",
50257c478bd9Sstevel@tonic-gate dfsize,
50267c478bd9Sstevel@tonic-gate ctime(&submittime));
50277c478bd9Sstevel@tonic-gate prtstr(&buf[1], 39);
50287c478bd9Sstevel@tonic-gate }
50297c478bd9Sstevel@tonic-gate
50307c478bd9Sstevel@tonic-gate if (quarmsg[0] != '\0')
50317c478bd9Sstevel@tonic-gate {
50327c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
50337c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
50347c478bd9Sstevel@tonic-gate "\n QUARANTINE: %.*s",
50357c478bd9Sstevel@tonic-gate Verbose ? 100 : 60,
50367c478bd9Sstevel@tonic-gate quarmsg);
50377c478bd9Sstevel@tonic-gate quarmsg[0] = '\0';
50387c478bd9Sstevel@tonic-gate }
50397c478bd9Sstevel@tonic-gate
50407c478bd9Sstevel@tonic-gate if (statmsg[0] != '\0' || bodytype[0] != '\0')
50417c478bd9Sstevel@tonic-gate {
50427c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
50437c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
50447c478bd9Sstevel@tonic-gate "\n %10.10s",
50457c478bd9Sstevel@tonic-gate bodytype);
50467c478bd9Sstevel@tonic-gate if (statmsg[0] != '\0')
50477c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
50487c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
50497c478bd9Sstevel@tonic-gate " (%.*s)",
50507c478bd9Sstevel@tonic-gate Verbose ? 100 : 60,
50517c478bd9Sstevel@tonic-gate statmsg);
50527c478bd9Sstevel@tonic-gate statmsg[0] = '\0';
50537c478bd9Sstevel@tonic-gate }
50547c478bd9Sstevel@tonic-gate break;
50557c478bd9Sstevel@tonic-gate
50567c478bd9Sstevel@tonic-gate case 'C': /* controlling user */
50577c478bd9Sstevel@tonic-gate if (Verbose)
50587c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
50597c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
50607c478bd9Sstevel@tonic-gate "\n\t\t\t\t\t\t(---%.64s---)",
50617c478bd9Sstevel@tonic-gate &buf[1]);
50627c478bd9Sstevel@tonic-gate break;
50637c478bd9Sstevel@tonic-gate
50647c478bd9Sstevel@tonic-gate case 'R': /* recipient name */
50657c478bd9Sstevel@tonic-gate p = &buf[1];
50667c478bd9Sstevel@tonic-gate if (qfver >= 1)
50677c478bd9Sstevel@tonic-gate {
50687c478bd9Sstevel@tonic-gate p = strchr(p, ':');
50697c478bd9Sstevel@tonic-gate if (p == NULL)
50707c478bd9Sstevel@tonic-gate break;
50717c478bd9Sstevel@tonic-gate p++;
50727c478bd9Sstevel@tonic-gate }
50737c478bd9Sstevel@tonic-gate if (Verbose)
50747c478bd9Sstevel@tonic-gate {
50757c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
50767c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
50777c478bd9Sstevel@tonic-gate "\n\t\t\t\t\t\t");
50787c478bd9Sstevel@tonic-gate prtstr(p, 71);
50797c478bd9Sstevel@tonic-gate }
50807c478bd9Sstevel@tonic-gate else
50817c478bd9Sstevel@tonic-gate {
50827c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
50837c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
50847c478bd9Sstevel@tonic-gate "\n\t\t\t\t\t ");
50857c478bd9Sstevel@tonic-gate prtstr(p, 38);
50867c478bd9Sstevel@tonic-gate }
50877c478bd9Sstevel@tonic-gate if (Verbose && statmsg[0] != '\0')
50887c478bd9Sstevel@tonic-gate {
50897c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
50907c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
50917c478bd9Sstevel@tonic-gate "\n\t\t (%.100s)",
50927c478bd9Sstevel@tonic-gate statmsg);
50937c478bd9Sstevel@tonic-gate statmsg[0] = '\0';
50947c478bd9Sstevel@tonic-gate }
50957c478bd9Sstevel@tonic-gate break;
50967c478bd9Sstevel@tonic-gate
50977c478bd9Sstevel@tonic-gate case 'T': /* creation time */
50987c478bd9Sstevel@tonic-gate submittime = atol(&buf[1]);
50997c478bd9Sstevel@tonic-gate break;
51007c478bd9Sstevel@tonic-gate
51017c478bd9Sstevel@tonic-gate case 'F': /* flag bits */
51027c478bd9Sstevel@tonic-gate for (p = &buf[1]; *p != '\0'; p++)
51037c478bd9Sstevel@tonic-gate {
51047c478bd9Sstevel@tonic-gate switch (*p)
51057c478bd9Sstevel@tonic-gate {
51067c478bd9Sstevel@tonic-gate case 'w':
51077c478bd9Sstevel@tonic-gate flags |= EF_WARNING;
51087c478bd9Sstevel@tonic-gate break;
51097c478bd9Sstevel@tonic-gate }
51107c478bd9Sstevel@tonic-gate }
51117c478bd9Sstevel@tonic-gate }
51127c478bd9Sstevel@tonic-gate }
51137c478bd9Sstevel@tonic-gate if (submittime == (time_t) 0)
51147c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
51157c478bd9Sstevel@tonic-gate " (no control file)");
51167c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n");
51177c478bd9Sstevel@tonic-gate (void) sm_io_close(f, SM_TIME_DEFAULT);
51187c478bd9Sstevel@tonic-gate }
51197c478bd9Sstevel@tonic-gate return nrequests;
51207c478bd9Sstevel@tonic-gate }
51217c478bd9Sstevel@tonic-gate
51227c478bd9Sstevel@tonic-gate /*
51237c478bd9Sstevel@tonic-gate ** QUEUE_LETTER -- get the proper queue letter for the current QueueMode.
51247c478bd9Sstevel@tonic-gate **
51257c478bd9Sstevel@tonic-gate ** Parameters:
51267c478bd9Sstevel@tonic-gate ** e -- envelope to build it in/from.
51277c478bd9Sstevel@tonic-gate ** type -- the file type, used as the first character
51287c478bd9Sstevel@tonic-gate ** of the file name.
51297c478bd9Sstevel@tonic-gate **
51307c478bd9Sstevel@tonic-gate ** Returns:
51317c478bd9Sstevel@tonic-gate ** the letter to use
51327c478bd9Sstevel@tonic-gate */
51337c478bd9Sstevel@tonic-gate
51347c478bd9Sstevel@tonic-gate static char
queue_letter(e,type)51357c478bd9Sstevel@tonic-gate queue_letter(e, type)
51367c478bd9Sstevel@tonic-gate ENVELOPE *e;
51377c478bd9Sstevel@tonic-gate int type;
51387c478bd9Sstevel@tonic-gate {
51397c478bd9Sstevel@tonic-gate /* Change type according to QueueMode */
51407c478bd9Sstevel@tonic-gate if (type == ANYQFL_LETTER)
51417c478bd9Sstevel@tonic-gate {
51427c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL)
51437c478bd9Sstevel@tonic-gate type = QUARQF_LETTER;
51447c478bd9Sstevel@tonic-gate else
51457c478bd9Sstevel@tonic-gate {
51467c478bd9Sstevel@tonic-gate switch (QueueMode)
51477c478bd9Sstevel@tonic-gate {
51487c478bd9Sstevel@tonic-gate case QM_NORMAL:
51497c478bd9Sstevel@tonic-gate type = NORMQF_LETTER;
51507c478bd9Sstevel@tonic-gate break;
51517c478bd9Sstevel@tonic-gate
51527c478bd9Sstevel@tonic-gate case QM_QUARANTINE:
51537c478bd9Sstevel@tonic-gate type = QUARQF_LETTER;
51547c478bd9Sstevel@tonic-gate break;
51557c478bd9Sstevel@tonic-gate
51567c478bd9Sstevel@tonic-gate case QM_LOST:
51577c478bd9Sstevel@tonic-gate type = LOSEQF_LETTER;
51587c478bd9Sstevel@tonic-gate break;
51597c478bd9Sstevel@tonic-gate
51607c478bd9Sstevel@tonic-gate default:
51617c478bd9Sstevel@tonic-gate /* should never happen */
51627c478bd9Sstevel@tonic-gate abort();
51637c478bd9Sstevel@tonic-gate /* NOTREACHED */
51647c478bd9Sstevel@tonic-gate }
51657c478bd9Sstevel@tonic-gate }
51667c478bd9Sstevel@tonic-gate }
51677c478bd9Sstevel@tonic-gate return type;
51687c478bd9Sstevel@tonic-gate }
51697c478bd9Sstevel@tonic-gate
51707c478bd9Sstevel@tonic-gate /*
51717c478bd9Sstevel@tonic-gate ** QUEUENAME -- build a file name in the queue directory for this envelope.
51727c478bd9Sstevel@tonic-gate **
51737c478bd9Sstevel@tonic-gate ** Parameters:
51747c478bd9Sstevel@tonic-gate ** e -- envelope to build it in/from.
51757c478bd9Sstevel@tonic-gate ** type -- the file type, used as the first character
51767c478bd9Sstevel@tonic-gate ** of the file name.
51777c478bd9Sstevel@tonic-gate **
51787c478bd9Sstevel@tonic-gate ** Returns:
51797c478bd9Sstevel@tonic-gate ** a pointer to the queue name (in a static buffer).
51807c478bd9Sstevel@tonic-gate **
51817c478bd9Sstevel@tonic-gate ** Side Effects:
51827c478bd9Sstevel@tonic-gate ** If no id code is already assigned, queuename() will
51837c478bd9Sstevel@tonic-gate ** assign an id code with assign_queueid(). If no queue
51847c478bd9Sstevel@tonic-gate ** directory is assigned, one will be set with setnewqueue().
51857c478bd9Sstevel@tonic-gate */
51867c478bd9Sstevel@tonic-gate
51877c478bd9Sstevel@tonic-gate char *
queuename(e,type)51887c478bd9Sstevel@tonic-gate queuename(e, type)
51897c478bd9Sstevel@tonic-gate register ENVELOPE *e;
51907c478bd9Sstevel@tonic-gate int type;
51917c478bd9Sstevel@tonic-gate {
51927c478bd9Sstevel@tonic-gate int qd, qg;
51937c478bd9Sstevel@tonic-gate char *sub = "/";
51947c478bd9Sstevel@tonic-gate char pref[3];
51957c478bd9Sstevel@tonic-gate static char buf[MAXPATHLEN];
51967c478bd9Sstevel@tonic-gate
51977c478bd9Sstevel@tonic-gate /* Assign an ID if needed */
51987c478bd9Sstevel@tonic-gate if (e->e_id == NULL)
51997c478bd9Sstevel@tonic-gate assign_queueid(e);
52007c478bd9Sstevel@tonic-gate type = queue_letter(e, type);
52017c478bd9Sstevel@tonic-gate
52027c478bd9Sstevel@tonic-gate /* begin of filename */
52037c478bd9Sstevel@tonic-gate pref[0] = (char) type;
52047c478bd9Sstevel@tonic-gate pref[1] = 'f';
52057c478bd9Sstevel@tonic-gate pref[2] = '\0';
52067c478bd9Sstevel@tonic-gate
52077c478bd9Sstevel@tonic-gate /* Assign a queue group/directory if needed */
52087c478bd9Sstevel@tonic-gate if (type == XSCRPT_LETTER)
52097c478bd9Sstevel@tonic-gate {
52107c478bd9Sstevel@tonic-gate /*
52117c478bd9Sstevel@tonic-gate ** We don't want to call setnewqueue() if we are fetching
52127c478bd9Sstevel@tonic-gate ** the pathname of the transcript file, because setnewqueue
52137c478bd9Sstevel@tonic-gate ** chooses a queue, and sometimes we need to write to the
52147c478bd9Sstevel@tonic-gate ** transcript file before we have gathered enough information
52157c478bd9Sstevel@tonic-gate ** to choose a queue.
52167c478bd9Sstevel@tonic-gate */
52177c478bd9Sstevel@tonic-gate
52187c478bd9Sstevel@tonic-gate if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR)
52197c478bd9Sstevel@tonic-gate {
52207c478bd9Sstevel@tonic-gate if (e->e_qgrp != NOQGRP && e->e_qdir != NOQDIR)
52217c478bd9Sstevel@tonic-gate {
52227c478bd9Sstevel@tonic-gate e->e_xfqgrp = e->e_qgrp;
52237c478bd9Sstevel@tonic-gate e->e_xfqdir = e->e_qdir;
52247c478bd9Sstevel@tonic-gate }
52257c478bd9Sstevel@tonic-gate else
52267c478bd9Sstevel@tonic-gate {
52277c478bd9Sstevel@tonic-gate e->e_xfqgrp = 0;
52287c478bd9Sstevel@tonic-gate if (Queue[e->e_xfqgrp]->qg_numqueues <= 1)
52297c478bd9Sstevel@tonic-gate e->e_xfqdir = 0;
52307c478bd9Sstevel@tonic-gate else
52317c478bd9Sstevel@tonic-gate {
52327c478bd9Sstevel@tonic-gate e->e_xfqdir = get_rand_mod(
52337c478bd9Sstevel@tonic-gate Queue[e->e_xfqgrp]->qg_numqueues);
52347c478bd9Sstevel@tonic-gate }
52357c478bd9Sstevel@tonic-gate }
52367c478bd9Sstevel@tonic-gate }
52377c478bd9Sstevel@tonic-gate qd = e->e_xfqdir;
52387c478bd9Sstevel@tonic-gate qg = e->e_xfqgrp;
52397c478bd9Sstevel@tonic-gate }
52407c478bd9Sstevel@tonic-gate else
52417c478bd9Sstevel@tonic-gate {
52427c478bd9Sstevel@tonic-gate if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR)
52433ee0e492Sjbeck (void) setnewqueue(e);
52447c478bd9Sstevel@tonic-gate if (type == DATAFL_LETTER)
52457c478bd9Sstevel@tonic-gate {
52467c478bd9Sstevel@tonic-gate qd = e->e_dfqdir;
52477c478bd9Sstevel@tonic-gate qg = e->e_dfqgrp;
52487c478bd9Sstevel@tonic-gate }
52497c478bd9Sstevel@tonic-gate else
52507c478bd9Sstevel@tonic-gate {
52517c478bd9Sstevel@tonic-gate qd = e->e_qdir;
52527c478bd9Sstevel@tonic-gate qg = e->e_qgrp;
52537c478bd9Sstevel@tonic-gate }
52547c478bd9Sstevel@tonic-gate }
52557c478bd9Sstevel@tonic-gate
52567c478bd9Sstevel@tonic-gate /* xf files always have a valid qd and qg picked above */
52573ee0e492Sjbeck if ((qd == NOQDIR || qg == NOQGRP) && type != XSCRPT_LETTER)
5258058561cbSjbeck (void) sm_strlcpyn(buf, sizeof(buf), 2, pref, e->e_id);
52597c478bd9Sstevel@tonic-gate else
52607c478bd9Sstevel@tonic-gate {
52617c478bd9Sstevel@tonic-gate switch (type)
52627c478bd9Sstevel@tonic-gate {
52637c478bd9Sstevel@tonic-gate case DATAFL_LETTER:
52647c478bd9Sstevel@tonic-gate if (bitset(QP_SUBDF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
52657c478bd9Sstevel@tonic-gate sub = "/df/";
52667c478bd9Sstevel@tonic-gate break;
52677c478bd9Sstevel@tonic-gate
52687c478bd9Sstevel@tonic-gate case QUARQF_LETTER:
52697c478bd9Sstevel@tonic-gate case TEMPQF_LETTER:
52707c478bd9Sstevel@tonic-gate case NEWQFL_LETTER:
52717c478bd9Sstevel@tonic-gate case LOSEQF_LETTER:
52727c478bd9Sstevel@tonic-gate case NORMQF_LETTER:
52737c478bd9Sstevel@tonic-gate if (bitset(QP_SUBQF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
52747c478bd9Sstevel@tonic-gate sub = "/qf/";
52757c478bd9Sstevel@tonic-gate break;
52767c478bd9Sstevel@tonic-gate
52777c478bd9Sstevel@tonic-gate case XSCRPT_LETTER:
52787c478bd9Sstevel@tonic-gate if (bitset(QP_SUBXF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
52797c478bd9Sstevel@tonic-gate sub = "/xf/";
52807c478bd9Sstevel@tonic-gate break;
52817c478bd9Sstevel@tonic-gate
52827c478bd9Sstevel@tonic-gate default:
52837c478bd9Sstevel@tonic-gate sm_abort("queuename: bad queue file type %d", type);
52847c478bd9Sstevel@tonic-gate }
52857c478bd9Sstevel@tonic-gate
5286058561cbSjbeck (void) sm_strlcpyn(buf, sizeof(buf), 4,
52877c478bd9Sstevel@tonic-gate Queue[qg]->qg_qpaths[qd].qp_name,
52887c478bd9Sstevel@tonic-gate sub, pref, e->e_id);
52897c478bd9Sstevel@tonic-gate }
52907c478bd9Sstevel@tonic-gate
52917c478bd9Sstevel@tonic-gate if (tTd(7, 2))
52927c478bd9Sstevel@tonic-gate sm_dprintf("queuename: %s\n", buf);
52937c478bd9Sstevel@tonic-gate return buf;
52947c478bd9Sstevel@tonic-gate }
52957c478bd9Sstevel@tonic-gate
52967c478bd9Sstevel@tonic-gate /*
52977c478bd9Sstevel@tonic-gate ** INIT_QID_ALG -- Initialize the (static) parameters that are used to
52987c478bd9Sstevel@tonic-gate ** generate a queue ID.
52997c478bd9Sstevel@tonic-gate **
53007c478bd9Sstevel@tonic-gate ** This function is called by the daemon to reset
53017c478bd9Sstevel@tonic-gate ** LastQueueTime and LastQueuePid which are used by assign_queueid().
53027c478bd9Sstevel@tonic-gate ** Otherwise the algorithm may cause problems because
53037c478bd9Sstevel@tonic-gate ** LastQueueTime and LastQueuePid are set indirectly by main()
53047c478bd9Sstevel@tonic-gate ** before the daemon process is started, hence LastQueuePid is not
53057c478bd9Sstevel@tonic-gate ** the pid of the daemon and therefore a child of the daemon can
53067c478bd9Sstevel@tonic-gate ** actually have the same pid as LastQueuePid which means the section
53077c478bd9Sstevel@tonic-gate ** in assign_queueid():
53087c478bd9Sstevel@tonic-gate ** * see if we need to get a new base time/pid *
53097c478bd9Sstevel@tonic-gate ** is NOT triggered which will cause the same queue id to be generated.
53107c478bd9Sstevel@tonic-gate **
53117c478bd9Sstevel@tonic-gate ** Parameters:
53127c478bd9Sstevel@tonic-gate ** none
53137c478bd9Sstevel@tonic-gate **
53147c478bd9Sstevel@tonic-gate ** Returns:
53157c478bd9Sstevel@tonic-gate ** none.
53167c478bd9Sstevel@tonic-gate */
53177c478bd9Sstevel@tonic-gate
53187c478bd9Sstevel@tonic-gate void
init_qid_alg()53197c478bd9Sstevel@tonic-gate init_qid_alg()
53207c478bd9Sstevel@tonic-gate {
53217c478bd9Sstevel@tonic-gate LastQueueTime = 0;
53227c478bd9Sstevel@tonic-gate LastQueuePid = -1;
53237c478bd9Sstevel@tonic-gate }
53247c478bd9Sstevel@tonic-gate
53257c478bd9Sstevel@tonic-gate /*
53267c478bd9Sstevel@tonic-gate ** ASSIGN_QUEUEID -- assign a queue ID for this envelope.
53277c478bd9Sstevel@tonic-gate **
53287c478bd9Sstevel@tonic-gate ** Assigns an id code if one does not already exist.
53297c478bd9Sstevel@tonic-gate ** This code assumes that nothing will remain in the queue for
53307c478bd9Sstevel@tonic-gate ** longer than 60 years. It is critical that files with the given
53317c478bd9Sstevel@tonic-gate ** name do not already exist in the queue.
53327c478bd9Sstevel@tonic-gate ** [No longer initializes e_qdir to NOQDIR.]
53337c478bd9Sstevel@tonic-gate **
53347c478bd9Sstevel@tonic-gate ** Parameters:
53357c478bd9Sstevel@tonic-gate ** e -- envelope to set it in.
53367c478bd9Sstevel@tonic-gate **
53377c478bd9Sstevel@tonic-gate ** Returns:
53387c478bd9Sstevel@tonic-gate ** none.
53397c478bd9Sstevel@tonic-gate */
53407c478bd9Sstevel@tonic-gate
53417c478bd9Sstevel@tonic-gate static const char QueueIdChars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
53427c478bd9Sstevel@tonic-gate # define QIC_LEN 60
53437c478bd9Sstevel@tonic-gate # define QIC_LEN_R 62
53447c478bd9Sstevel@tonic-gate
53457c478bd9Sstevel@tonic-gate /*
53467c478bd9Sstevel@tonic-gate ** Note: the length is "officially" 60 because minutes and seconds are
53477c478bd9Sstevel@tonic-gate ** usually only 0-59. However (Linux):
53487c478bd9Sstevel@tonic-gate ** tm_sec The number of seconds after the minute, normally in
53497c478bd9Sstevel@tonic-gate ** the range 0 to 59, but can be up to 61 to allow for
53507c478bd9Sstevel@tonic-gate ** leap seconds.
53517c478bd9Sstevel@tonic-gate ** Hence the real length of the string is 62 to take this into account.
53527c478bd9Sstevel@tonic-gate ** Alternatively % QIC_LEN can (should) be used for access everywhere.
53537c478bd9Sstevel@tonic-gate */
53547c478bd9Sstevel@tonic-gate
53557c478bd9Sstevel@tonic-gate # define queuenextid() CurrentPid
5356e9af4bc0SJohn Beck #define QIC_LEN_SQR (QIC_LEN * QIC_LEN)
53577c478bd9Sstevel@tonic-gate
53587c478bd9Sstevel@tonic-gate void
assign_queueid(e)53597c478bd9Sstevel@tonic-gate assign_queueid(e)
53607c478bd9Sstevel@tonic-gate register ENVELOPE *e;
53617c478bd9Sstevel@tonic-gate {
53627c478bd9Sstevel@tonic-gate pid_t pid = queuenextid();
5363e9af4bc0SJohn Beck static unsigned int cX = 0;
5364e9af4bc0SJohn Beck static unsigned int random_offset;
53657c478bd9Sstevel@tonic-gate struct tm *tm;
53667c478bd9Sstevel@tonic-gate char idbuf[MAXQFNAME - 2];
5367e9af4bc0SJohn Beck unsigned int seq;
53687c478bd9Sstevel@tonic-gate
53697c478bd9Sstevel@tonic-gate if (e->e_id != NULL)
53707c478bd9Sstevel@tonic-gate return;
53717c478bd9Sstevel@tonic-gate
53727c478bd9Sstevel@tonic-gate /* see if we need to get a new base time/pid */
5373e9af4bc0SJohn Beck if (cX >= QIC_LEN_SQR || LastQueueTime == 0 || LastQueuePid != pid)
53747c478bd9Sstevel@tonic-gate {
53757c478bd9Sstevel@tonic-gate time_t then = LastQueueTime;
53767c478bd9Sstevel@tonic-gate
53777c478bd9Sstevel@tonic-gate /* if the first time through, pick a random offset */
53787c478bd9Sstevel@tonic-gate if (LastQueueTime == 0)
5379e9af4bc0SJohn Beck random_offset = ((unsigned int)get_random())
5380e9af4bc0SJohn Beck % QIC_LEN_SQR;
53817c478bd9Sstevel@tonic-gate
53827c478bd9Sstevel@tonic-gate while ((LastQueueTime = curtime()) == then &&
53837c478bd9Sstevel@tonic-gate LastQueuePid == pid)
53847c478bd9Sstevel@tonic-gate {
53857c478bd9Sstevel@tonic-gate (void) sleep(1);
53867c478bd9Sstevel@tonic-gate }
53877c478bd9Sstevel@tonic-gate LastQueuePid = queuenextid();
53887c478bd9Sstevel@tonic-gate cX = 0;
53897c478bd9Sstevel@tonic-gate }
53907c478bd9Sstevel@tonic-gate
53917c478bd9Sstevel@tonic-gate /*
5392e9af4bc0SJohn Beck ** Generate a new sequence number between 0 and QIC_LEN_SQR-1.
5393e9af4bc0SJohn Beck ** This lets us generate up to QIC_LEN_SQR unique queue ids
53947c478bd9Sstevel@tonic-gate ** per second, per process. With envelope splitting,
53957c478bd9Sstevel@tonic-gate ** a single message can consume many queue ids.
53967c478bd9Sstevel@tonic-gate */
53977c478bd9Sstevel@tonic-gate
5398e9af4bc0SJohn Beck seq = (cX + random_offset) % QIC_LEN_SQR;
53997c478bd9Sstevel@tonic-gate ++cX;
54007c478bd9Sstevel@tonic-gate if (tTd(7, 50))
5401e9af4bc0SJohn Beck sm_dprintf("assign_queueid: random_offset=%u (%u)\n",
54027c478bd9Sstevel@tonic-gate random_offset, seq);
54037c478bd9Sstevel@tonic-gate
54047c478bd9Sstevel@tonic-gate tm = gmtime(&LastQueueTime);
54057c478bd9Sstevel@tonic-gate idbuf[0] = QueueIdChars[tm->tm_year % QIC_LEN];
54067c478bd9Sstevel@tonic-gate idbuf[1] = QueueIdChars[tm->tm_mon];
54077c478bd9Sstevel@tonic-gate idbuf[2] = QueueIdChars[tm->tm_mday];
54087c478bd9Sstevel@tonic-gate idbuf[3] = QueueIdChars[tm->tm_hour];
54097c478bd9Sstevel@tonic-gate idbuf[4] = QueueIdChars[tm->tm_min % QIC_LEN_R];
54107c478bd9Sstevel@tonic-gate idbuf[5] = QueueIdChars[tm->tm_sec % QIC_LEN_R];
54117c478bd9Sstevel@tonic-gate idbuf[6] = QueueIdChars[seq / QIC_LEN];
54127c478bd9Sstevel@tonic-gate idbuf[7] = QueueIdChars[seq % QIC_LEN];
5413058561cbSjbeck (void) sm_snprintf(&idbuf[8], sizeof(idbuf) - 8, "%06d",
54147c478bd9Sstevel@tonic-gate (int) LastQueuePid);
54157c478bd9Sstevel@tonic-gate e->e_id = sm_rpool_strdup_x(e->e_rpool, idbuf);
54167c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'i', e->e_id);
54177c478bd9Sstevel@tonic-gate #if 0
54187c478bd9Sstevel@tonic-gate /* XXX: inherited from MainEnvelope */
54197c478bd9Sstevel@tonic-gate e->e_qgrp = NOQGRP; /* too early to do anything else */
54207c478bd9Sstevel@tonic-gate e->e_qdir = NOQDIR;
54217c478bd9Sstevel@tonic-gate e->e_xfqgrp = NOQGRP;
54227c478bd9Sstevel@tonic-gate #endif /* 0 */
54237c478bd9Sstevel@tonic-gate
54247c478bd9Sstevel@tonic-gate /* New ID means it's not on disk yet */
54257c478bd9Sstevel@tonic-gate e->e_qfletter = '\0';
54267c478bd9Sstevel@tonic-gate
54277c478bd9Sstevel@tonic-gate if (tTd(7, 1))
54287c478bd9Sstevel@tonic-gate sm_dprintf("assign_queueid: assigned id %s, e=%p\n",
54297c478bd9Sstevel@tonic-gate e->e_id, e);
54307c478bd9Sstevel@tonic-gate if (LogLevel > 93)
54317c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
54327c478bd9Sstevel@tonic-gate }
54337c478bd9Sstevel@tonic-gate /*
54347c478bd9Sstevel@tonic-gate ** SYNC_QUEUE_TIME -- Assure exclusive PID in any given second
54357c478bd9Sstevel@tonic-gate **
54367c478bd9Sstevel@tonic-gate ** Make sure one PID can't be used by two processes in any one second.
54377c478bd9Sstevel@tonic-gate **
54387c478bd9Sstevel@tonic-gate ** If the system rotates PIDs fast enough, may get the
54397c478bd9Sstevel@tonic-gate ** same pid in the same second for two distinct processes.
54407c478bd9Sstevel@tonic-gate ** This will interfere with the queue file naming system.
54417c478bd9Sstevel@tonic-gate **
54427c478bd9Sstevel@tonic-gate ** Parameters:
54437c478bd9Sstevel@tonic-gate ** none
54447c478bd9Sstevel@tonic-gate **
54457c478bd9Sstevel@tonic-gate ** Returns:
54467c478bd9Sstevel@tonic-gate ** none
54477c478bd9Sstevel@tonic-gate */
54487c478bd9Sstevel@tonic-gate
54497c478bd9Sstevel@tonic-gate void
sync_queue_time()54507c478bd9Sstevel@tonic-gate sync_queue_time()
54517c478bd9Sstevel@tonic-gate {
54527c478bd9Sstevel@tonic-gate #if FAST_PID_RECYCLE
54537c478bd9Sstevel@tonic-gate if (OpMode != MD_TEST &&
5454e9af4bc0SJohn Beck OpMode != MD_CHECKCONFIG &&
54557c478bd9Sstevel@tonic-gate OpMode != MD_VERIFY &&
54567c478bd9Sstevel@tonic-gate LastQueueTime > 0 &&
54577c478bd9Sstevel@tonic-gate LastQueuePid == CurrentPid &&
54587c478bd9Sstevel@tonic-gate curtime() == LastQueueTime)
54597c478bd9Sstevel@tonic-gate (void) sleep(1);
54607c478bd9Sstevel@tonic-gate #endif /* FAST_PID_RECYCLE */
54617c478bd9Sstevel@tonic-gate }
54627c478bd9Sstevel@tonic-gate /*
54637c478bd9Sstevel@tonic-gate ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope
54647c478bd9Sstevel@tonic-gate **
54657c478bd9Sstevel@tonic-gate ** Parameters:
54667c478bd9Sstevel@tonic-gate ** e -- the envelope to unlock.
54677c478bd9Sstevel@tonic-gate **
54687c478bd9Sstevel@tonic-gate ** Returns:
54697c478bd9Sstevel@tonic-gate ** none
54707c478bd9Sstevel@tonic-gate **
54717c478bd9Sstevel@tonic-gate ** Side Effects:
54727c478bd9Sstevel@tonic-gate ** unlocks the queue for `e'.
54737c478bd9Sstevel@tonic-gate */
54747c478bd9Sstevel@tonic-gate
54757c478bd9Sstevel@tonic-gate void
unlockqueue(e)54767c478bd9Sstevel@tonic-gate unlockqueue(e)
54777c478bd9Sstevel@tonic-gate ENVELOPE *e;
54787c478bd9Sstevel@tonic-gate {
54797c478bd9Sstevel@tonic-gate if (tTd(51, 4))
54807c478bd9Sstevel@tonic-gate sm_dprintf("unlockqueue(%s)\n",
54817c478bd9Sstevel@tonic-gate e->e_id == NULL ? "NOQUEUE" : e->e_id);
54827c478bd9Sstevel@tonic-gate
54837c478bd9Sstevel@tonic-gate
54847c478bd9Sstevel@tonic-gate /* if there is a lock file in the envelope, close it */
54857c478bd9Sstevel@tonic-gate if (e->e_lockfp != NULL)
54867c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT);
54877c478bd9Sstevel@tonic-gate e->e_lockfp = NULL;
54887c478bd9Sstevel@tonic-gate
54897c478bd9Sstevel@tonic-gate /* don't create a queue id if we don't already have one */
54907c478bd9Sstevel@tonic-gate if (e->e_id == NULL)
54917c478bd9Sstevel@tonic-gate return;
54927c478bd9Sstevel@tonic-gate
54937c478bd9Sstevel@tonic-gate /* remove the transcript */
54947c478bd9Sstevel@tonic-gate if (LogLevel > 87)
54957c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "unlock");
54967c478bd9Sstevel@tonic-gate if (!tTd(51, 104))
54977c478bd9Sstevel@tonic-gate (void) xunlink(queuename(e, XSCRPT_LETTER));
54987c478bd9Sstevel@tonic-gate }
54997c478bd9Sstevel@tonic-gate /*
55007c478bd9Sstevel@tonic-gate ** SETCTLUSER -- create a controlling address
55017c478bd9Sstevel@tonic-gate **
55027c478bd9Sstevel@tonic-gate ** Create a fake "address" given only a local login name; this is
55037c478bd9Sstevel@tonic-gate ** used as a "controlling user" for future recipient addresses.
55047c478bd9Sstevel@tonic-gate **
55057c478bd9Sstevel@tonic-gate ** Parameters:
55067c478bd9Sstevel@tonic-gate ** user -- the user name of the controlling user.
55077c478bd9Sstevel@tonic-gate ** qfver -- the version stamp of this queue file.
55087c478bd9Sstevel@tonic-gate ** e -- envelope
55097c478bd9Sstevel@tonic-gate **
55107c478bd9Sstevel@tonic-gate ** Returns:
55117c478bd9Sstevel@tonic-gate ** An address descriptor for the controlling user,
55127c478bd9Sstevel@tonic-gate ** using storage allocated from e->e_rpool.
55137c478bd9Sstevel@tonic-gate **
55147c478bd9Sstevel@tonic-gate */
55157c478bd9Sstevel@tonic-gate
55167c478bd9Sstevel@tonic-gate static ADDRESS *
setctluser(user,qfver,e)55177c478bd9Sstevel@tonic-gate setctluser(user, qfver, e)
55187c478bd9Sstevel@tonic-gate char *user;
55197c478bd9Sstevel@tonic-gate int qfver;
55207c478bd9Sstevel@tonic-gate ENVELOPE *e;
55217c478bd9Sstevel@tonic-gate {
55227c478bd9Sstevel@tonic-gate register ADDRESS *a;
55237c478bd9Sstevel@tonic-gate struct passwd *pw;
55247c478bd9Sstevel@tonic-gate char *p;
55257c478bd9Sstevel@tonic-gate
55267c478bd9Sstevel@tonic-gate /*
55277c478bd9Sstevel@tonic-gate ** See if this clears our concept of controlling user.
55287c478bd9Sstevel@tonic-gate */
55297c478bd9Sstevel@tonic-gate
55307c478bd9Sstevel@tonic-gate if (user == NULL || *user == '\0')
55317c478bd9Sstevel@tonic-gate return NULL;
55327c478bd9Sstevel@tonic-gate
55337c478bd9Sstevel@tonic-gate /*
55347c478bd9Sstevel@tonic-gate ** Set up addr fields for controlling user.
55357c478bd9Sstevel@tonic-gate */
55367c478bd9Sstevel@tonic-gate
5537058561cbSjbeck a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof(*a));
5538058561cbSjbeck memset((char *) a, '\0', sizeof(*a));
55397c478bd9Sstevel@tonic-gate
55407c478bd9Sstevel@tonic-gate if (*user == ':')
55417c478bd9Sstevel@tonic-gate {
55427c478bd9Sstevel@tonic-gate p = &user[1];
55437c478bd9Sstevel@tonic-gate a->q_user = sm_rpool_strdup_x(e->e_rpool, p);
55447c478bd9Sstevel@tonic-gate }
55457c478bd9Sstevel@tonic-gate else
55467c478bd9Sstevel@tonic-gate {
55477c478bd9Sstevel@tonic-gate p = strtok(user, ":");
55487c478bd9Sstevel@tonic-gate a->q_user = sm_rpool_strdup_x(e->e_rpool, user);
55497c478bd9Sstevel@tonic-gate if (qfver >= 2)
55507c478bd9Sstevel@tonic-gate {
55517c478bd9Sstevel@tonic-gate if ((p = strtok(NULL, ":")) != NULL)
55527c478bd9Sstevel@tonic-gate a->q_uid = atoi(p);
55537c478bd9Sstevel@tonic-gate if ((p = strtok(NULL, ":")) != NULL)
55547c478bd9Sstevel@tonic-gate a->q_gid = atoi(p);
55557c478bd9Sstevel@tonic-gate if ((p = strtok(NULL, ":")) != NULL)
55567c478bd9Sstevel@tonic-gate {
55577c478bd9Sstevel@tonic-gate char *o;
55587c478bd9Sstevel@tonic-gate
55597c478bd9Sstevel@tonic-gate a->q_flags |= QGOODUID;
55607c478bd9Sstevel@tonic-gate
55617c478bd9Sstevel@tonic-gate /* if there is another ':': restore it */
55627c478bd9Sstevel@tonic-gate if ((o = strtok(NULL, ":")) != NULL && o > p)
55637c478bd9Sstevel@tonic-gate o[-1] = ':';
55647c478bd9Sstevel@tonic-gate }
55657c478bd9Sstevel@tonic-gate }
55667c478bd9Sstevel@tonic-gate else if ((pw = sm_getpwnam(user)) != NULL)
55677c478bd9Sstevel@tonic-gate {
55687c478bd9Sstevel@tonic-gate if (*pw->pw_dir == '\0')
55697c478bd9Sstevel@tonic-gate a->q_home = NULL;
55707c478bd9Sstevel@tonic-gate else if (strcmp(pw->pw_dir, "/") == 0)
55717c478bd9Sstevel@tonic-gate a->q_home = "";
55727c478bd9Sstevel@tonic-gate else
55737c478bd9Sstevel@tonic-gate a->q_home = sm_rpool_strdup_x(e->e_rpool, pw->pw_dir);
55747c478bd9Sstevel@tonic-gate a->q_uid = pw->pw_uid;
55757c478bd9Sstevel@tonic-gate a->q_gid = pw->pw_gid;
55767c478bd9Sstevel@tonic-gate a->q_flags |= QGOODUID;
55777c478bd9Sstevel@tonic-gate }
55787c478bd9Sstevel@tonic-gate }
55797c478bd9Sstevel@tonic-gate
55807c478bd9Sstevel@tonic-gate a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */
55817c478bd9Sstevel@tonic-gate a->q_mailer = LocalMailer;
55827c478bd9Sstevel@tonic-gate if (p == NULL)
55837c478bd9Sstevel@tonic-gate a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user);
55847c478bd9Sstevel@tonic-gate else
55857c478bd9Sstevel@tonic-gate a->q_paddr = sm_rpool_strdup_x(e->e_rpool, p);
55867c478bd9Sstevel@tonic-gate return a;
55877c478bd9Sstevel@tonic-gate }
55887c478bd9Sstevel@tonic-gate /*
55897c478bd9Sstevel@tonic-gate ** LOSEQFILE -- rename queue file with LOSEQF_LETTER & try to let someone know
55907c478bd9Sstevel@tonic-gate **
55917c478bd9Sstevel@tonic-gate ** Parameters:
55927c478bd9Sstevel@tonic-gate ** e -- the envelope (e->e_id will be used).
55937c478bd9Sstevel@tonic-gate ** why -- reported to whomever can hear.
55947c478bd9Sstevel@tonic-gate **
55957c478bd9Sstevel@tonic-gate ** Returns:
55967c478bd9Sstevel@tonic-gate ** none.
55977c478bd9Sstevel@tonic-gate */
55987c478bd9Sstevel@tonic-gate
55997c478bd9Sstevel@tonic-gate void
loseqfile(e,why)56007c478bd9Sstevel@tonic-gate loseqfile(e, why)
56017c478bd9Sstevel@tonic-gate register ENVELOPE *e;
56027c478bd9Sstevel@tonic-gate char *why;
56037c478bd9Sstevel@tonic-gate {
56047c478bd9Sstevel@tonic-gate bool loseit = true;
56057c478bd9Sstevel@tonic-gate char *p;
56067c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN];
56077c478bd9Sstevel@tonic-gate
56087c478bd9Sstevel@tonic-gate if (e == NULL || e->e_id == NULL)
56097c478bd9Sstevel@tonic-gate return;
56107c478bd9Sstevel@tonic-gate p = queuename(e, ANYQFL_LETTER);
5611058561cbSjbeck if (sm_strlcpy(buf, p, sizeof(buf)) >= sizeof(buf))
56127c478bd9Sstevel@tonic-gate return;
56137c478bd9Sstevel@tonic-gate if (!bitset(EF_INQUEUE, e->e_flags))
56147c478bd9Sstevel@tonic-gate queueup(e, false, true);
56157c478bd9Sstevel@tonic-gate else if (QueueMode == QM_LOST)
56167c478bd9Sstevel@tonic-gate loseit = false;
56177c478bd9Sstevel@tonic-gate
56187c478bd9Sstevel@tonic-gate /* if already lost, no need to re-lose */
56197c478bd9Sstevel@tonic-gate if (loseit)
56207c478bd9Sstevel@tonic-gate {
56217c478bd9Sstevel@tonic-gate p = queuename(e, LOSEQF_LETTER);
56227c478bd9Sstevel@tonic-gate if (rename(buf, p) < 0)
56237c478bd9Sstevel@tonic-gate syserr("cannot rename(%s, %s), uid=%d",
56247c478bd9Sstevel@tonic-gate buf, p, (int) geteuid());
56257c478bd9Sstevel@tonic-gate else if (LogLevel > 0)
56267c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id,
56277c478bd9Sstevel@tonic-gate "Losing %s: %s", buf, why);
56287c478bd9Sstevel@tonic-gate }
56297c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL)
56307c478bd9Sstevel@tonic-gate {
56317c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
56327c478bd9Sstevel@tonic-gate e->e_dfp = NULL;
56337c478bd9Sstevel@tonic-gate }
56347c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_HAS_DF;
56357c478bd9Sstevel@tonic-gate }
56367c478bd9Sstevel@tonic-gate /*
56377c478bd9Sstevel@tonic-gate ** NAME2QID -- translate a queue group name to a queue group id
56387c478bd9Sstevel@tonic-gate **
56397c478bd9Sstevel@tonic-gate ** Parameters:
56407c478bd9Sstevel@tonic-gate ** queuename -- name of queue group.
56417c478bd9Sstevel@tonic-gate **
56427c478bd9Sstevel@tonic-gate ** Returns:
56437c478bd9Sstevel@tonic-gate ** queue group id if found.
56447c478bd9Sstevel@tonic-gate ** NOQGRP otherwise.
56457c478bd9Sstevel@tonic-gate */
56467c478bd9Sstevel@tonic-gate
56477c478bd9Sstevel@tonic-gate int
name2qid(queuename)56487c478bd9Sstevel@tonic-gate name2qid(queuename)
56497c478bd9Sstevel@tonic-gate char *queuename;
56507c478bd9Sstevel@tonic-gate {
56517c478bd9Sstevel@tonic-gate register STAB *s;
56527c478bd9Sstevel@tonic-gate
56537c478bd9Sstevel@tonic-gate s = stab(queuename, ST_QUEUE, ST_FIND);
56547c478bd9Sstevel@tonic-gate if (s == NULL)
56557c478bd9Sstevel@tonic-gate return NOQGRP;
56567c478bd9Sstevel@tonic-gate return s->s_quegrp->qg_index;
56577c478bd9Sstevel@tonic-gate }
56587c478bd9Sstevel@tonic-gate /*
56597c478bd9Sstevel@tonic-gate ** QID_PRINTNAME -- create externally printable version of queue id
56607c478bd9Sstevel@tonic-gate **
56617c478bd9Sstevel@tonic-gate ** Parameters:
56627c478bd9Sstevel@tonic-gate ** e -- the envelope.
56637c478bd9Sstevel@tonic-gate **
56647c478bd9Sstevel@tonic-gate ** Returns:
56657c478bd9Sstevel@tonic-gate ** a printable version
56667c478bd9Sstevel@tonic-gate */
56677c478bd9Sstevel@tonic-gate
56687c478bd9Sstevel@tonic-gate char *
qid_printname(e)56697c478bd9Sstevel@tonic-gate qid_printname(e)
56707c478bd9Sstevel@tonic-gate ENVELOPE *e;
56717c478bd9Sstevel@tonic-gate {
56727c478bd9Sstevel@tonic-gate char *id;
56737c478bd9Sstevel@tonic-gate static char idbuf[MAXQFNAME + 34];
56747c478bd9Sstevel@tonic-gate
56757c478bd9Sstevel@tonic-gate if (e == NULL)
56767c478bd9Sstevel@tonic-gate return "";
56777c478bd9Sstevel@tonic-gate
56787c478bd9Sstevel@tonic-gate if (e->e_id == NULL)
56797c478bd9Sstevel@tonic-gate id = "";
56807c478bd9Sstevel@tonic-gate else
56817c478bd9Sstevel@tonic-gate id = e->e_id;
56827c478bd9Sstevel@tonic-gate
56837c478bd9Sstevel@tonic-gate if (e->e_qdir == NOQDIR)
56847c478bd9Sstevel@tonic-gate return id;
56857c478bd9Sstevel@tonic-gate
5686058561cbSjbeck (void) sm_snprintf(idbuf, sizeof(idbuf), "%.32s/%s",
56877c478bd9Sstevel@tonic-gate Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_name,
56887c478bd9Sstevel@tonic-gate id);
56897c478bd9Sstevel@tonic-gate return idbuf;
56907c478bd9Sstevel@tonic-gate }
56917c478bd9Sstevel@tonic-gate /*
56927c478bd9Sstevel@tonic-gate ** QID_PRINTQUEUE -- create full version of queue directory for data files
56937c478bd9Sstevel@tonic-gate **
56947c478bd9Sstevel@tonic-gate ** Parameters:
56957c478bd9Sstevel@tonic-gate ** qgrp -- index in queue group.
56967c478bd9Sstevel@tonic-gate ** qdir -- the short version of the queue directory
56977c478bd9Sstevel@tonic-gate **
56987c478bd9Sstevel@tonic-gate ** Returns:
56997c478bd9Sstevel@tonic-gate ** the full pathname to the queue (might point to a static var)
57007c478bd9Sstevel@tonic-gate */
57017c478bd9Sstevel@tonic-gate
57027c478bd9Sstevel@tonic-gate char *
qid_printqueue(qgrp,qdir)57037c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)
57047c478bd9Sstevel@tonic-gate int qgrp;
57057c478bd9Sstevel@tonic-gate int qdir;
57067c478bd9Sstevel@tonic-gate {
57077c478bd9Sstevel@tonic-gate char *subdir;
57087c478bd9Sstevel@tonic-gate static char dir[MAXPATHLEN];
57097c478bd9Sstevel@tonic-gate
57107c478bd9Sstevel@tonic-gate if (qdir == NOQDIR)
57117c478bd9Sstevel@tonic-gate return Queue[qgrp]->qg_qdir;
57127c478bd9Sstevel@tonic-gate
57137c478bd9Sstevel@tonic-gate if (strcmp(Queue[qgrp]->qg_qpaths[qdir].qp_name, ".") == 0)
57147c478bd9Sstevel@tonic-gate subdir = NULL;
57157c478bd9Sstevel@tonic-gate else
57167c478bd9Sstevel@tonic-gate subdir = Queue[qgrp]->qg_qpaths[qdir].qp_name;
57177c478bd9Sstevel@tonic-gate
5718058561cbSjbeck (void) sm_strlcpyn(dir, sizeof(dir), 4,
57197c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qdir,
57207c478bd9Sstevel@tonic-gate subdir == NULL ? "" : "/",
57217c478bd9Sstevel@tonic-gate subdir == NULL ? "" : subdir,
57227c478bd9Sstevel@tonic-gate (bitset(QP_SUBDF,
57237c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
57247c478bd9Sstevel@tonic-gate ? "/df" : ""));
57257c478bd9Sstevel@tonic-gate return dir;
57267c478bd9Sstevel@tonic-gate }
57277c478bd9Sstevel@tonic-gate
57287c478bd9Sstevel@tonic-gate /*
57297c478bd9Sstevel@tonic-gate ** PICKQDIR -- Pick a queue directory from a queue group
57307c478bd9Sstevel@tonic-gate **
57317c478bd9Sstevel@tonic-gate ** Parameters:
57327c478bd9Sstevel@tonic-gate ** qg -- queue group
57337c478bd9Sstevel@tonic-gate ** fsize -- file size in bytes
57347c478bd9Sstevel@tonic-gate ** e -- envelope, or NULL
57357c478bd9Sstevel@tonic-gate **
57367c478bd9Sstevel@tonic-gate ** Result:
57377c478bd9Sstevel@tonic-gate ** NOQDIR if no queue directory in qg has enough free space to
57387c478bd9Sstevel@tonic-gate ** hold a file of size 'fsize', otherwise the index of
57397c478bd9Sstevel@tonic-gate ** a randomly selected queue directory which resides on a
57407c478bd9Sstevel@tonic-gate ** file system with enough disk space.
57417c478bd9Sstevel@tonic-gate ** XXX This could be extended to select a queuedir with
57427c478bd9Sstevel@tonic-gate ** a few (the fewest?) number of entries. That data
57437c478bd9Sstevel@tonic-gate ** is available if shared memory is used.
57447c478bd9Sstevel@tonic-gate **
57457c478bd9Sstevel@tonic-gate ** Side Effects:
57467c478bd9Sstevel@tonic-gate ** If the request fails and e != NULL then sm_syslog is called.
57477c478bd9Sstevel@tonic-gate */
57487c478bd9Sstevel@tonic-gate
57497c478bd9Sstevel@tonic-gate int
pickqdir(qg,fsize,e)57507c478bd9Sstevel@tonic-gate pickqdir(qg, fsize, e)
57517c478bd9Sstevel@tonic-gate QUEUEGRP *qg;
57527c478bd9Sstevel@tonic-gate long fsize;
57537c478bd9Sstevel@tonic-gate ENVELOPE *e;
57547c478bd9Sstevel@tonic-gate {
57557c478bd9Sstevel@tonic-gate int qdir;
57567c478bd9Sstevel@tonic-gate int i;
57577c478bd9Sstevel@tonic-gate long avail = 0;
57587c478bd9Sstevel@tonic-gate
57597c478bd9Sstevel@tonic-gate /* Pick a random directory, as a starting point. */
57607c478bd9Sstevel@tonic-gate if (qg->qg_numqueues <= 1)
57617c478bd9Sstevel@tonic-gate qdir = 0;
57627c478bd9Sstevel@tonic-gate else
57637c478bd9Sstevel@tonic-gate qdir = get_rand_mod(qg->qg_numqueues);
57647c478bd9Sstevel@tonic-gate
5765e9af4bc0SJohn Beck #if _FFR_TESTS
5766e9af4bc0SJohn Beck if (tTd(4, 101))
5767e9af4bc0SJohn Beck return NOQDIR;
5768e9af4bc0SJohn Beck #endif /* _FFR_TESTS */
57697c478bd9Sstevel@tonic-gate if (MinBlocksFree <= 0 && fsize <= 0)
57707c478bd9Sstevel@tonic-gate return qdir;
57717c478bd9Sstevel@tonic-gate
57727c478bd9Sstevel@tonic-gate /*
57737c478bd9Sstevel@tonic-gate ** Now iterate over the queue directories,
57747c478bd9Sstevel@tonic-gate ** looking for a directory with enough space for this message.
57757c478bd9Sstevel@tonic-gate */
57767c478bd9Sstevel@tonic-gate
57777c478bd9Sstevel@tonic-gate i = qdir;
57787c478bd9Sstevel@tonic-gate do
57797c478bd9Sstevel@tonic-gate {
57807c478bd9Sstevel@tonic-gate QPATHS *qp = &qg->qg_qpaths[i];
57817c478bd9Sstevel@tonic-gate long needed = 0;
57827c478bd9Sstevel@tonic-gate long fsavail = 0;
57837c478bd9Sstevel@tonic-gate
57847c478bd9Sstevel@tonic-gate if (fsize > 0)
57857c478bd9Sstevel@tonic-gate needed += fsize / FILE_SYS_BLKSIZE(qp->qp_fsysidx)
57867c478bd9Sstevel@tonic-gate + ((fsize % FILE_SYS_BLKSIZE(qp->qp_fsysidx)
57877c478bd9Sstevel@tonic-gate > 0) ? 1 : 0);
57887c478bd9Sstevel@tonic-gate if (MinBlocksFree > 0)
57897c478bd9Sstevel@tonic-gate needed += MinBlocksFree;
57907c478bd9Sstevel@tonic-gate fsavail = FILE_SYS_AVAIL(qp->qp_fsysidx);
57917c478bd9Sstevel@tonic-gate #if SM_CONF_SHM
57927c478bd9Sstevel@tonic-gate if (fsavail <= 0)
57937c478bd9Sstevel@tonic-gate {
57947c478bd9Sstevel@tonic-gate long blksize;
57957c478bd9Sstevel@tonic-gate
57967c478bd9Sstevel@tonic-gate /*
57977c478bd9Sstevel@tonic-gate ** might be not correctly updated,
57987c478bd9Sstevel@tonic-gate ** let's try to get the info directly.
57997c478bd9Sstevel@tonic-gate */
58007c478bd9Sstevel@tonic-gate
58017c478bd9Sstevel@tonic-gate fsavail = freediskspace(FILE_SYS_NAME(qp->qp_fsysidx),
58027c478bd9Sstevel@tonic-gate &blksize);
58037c478bd9Sstevel@tonic-gate if (fsavail < 0)
58047c478bd9Sstevel@tonic-gate fsavail = 0;
58057c478bd9Sstevel@tonic-gate }
58067c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */
58077c478bd9Sstevel@tonic-gate if (needed <= fsavail)
58087c478bd9Sstevel@tonic-gate return i;
58097c478bd9Sstevel@tonic-gate if (avail < fsavail)
58107c478bd9Sstevel@tonic-gate avail = fsavail;
58117c478bd9Sstevel@tonic-gate
58127c478bd9Sstevel@tonic-gate if (qg->qg_numqueues > 0)
58137c478bd9Sstevel@tonic-gate i = (i + 1) % qg->qg_numqueues;
58147c478bd9Sstevel@tonic-gate } while (i != qdir);
58157c478bd9Sstevel@tonic-gate
58167c478bd9Sstevel@tonic-gate if (e != NULL && LogLevel > 0)
58177c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id,
58187c478bd9Sstevel@tonic-gate "low on space (%s needs %ld bytes + %ld blocks in %s), max avail: %ld",
58197c478bd9Sstevel@tonic-gate CurHostName == NULL ? "SMTP-DAEMON" : CurHostName,
58207c478bd9Sstevel@tonic-gate fsize, MinBlocksFree,
58217c478bd9Sstevel@tonic-gate qg->qg_qdir, avail);
58227c478bd9Sstevel@tonic-gate return NOQDIR;
58237c478bd9Sstevel@tonic-gate }
58247c478bd9Sstevel@tonic-gate /*
58257c478bd9Sstevel@tonic-gate ** SETNEWQUEUE -- Sets a new queue group and directory
58267c478bd9Sstevel@tonic-gate **
58277c478bd9Sstevel@tonic-gate ** Assign a queue group and directory to an envelope and store the
58287c478bd9Sstevel@tonic-gate ** directory in e->e_qdir.
58297c478bd9Sstevel@tonic-gate **
58307c478bd9Sstevel@tonic-gate ** Parameters:
58317c478bd9Sstevel@tonic-gate ** e -- envelope to assign a queue for.
58327c478bd9Sstevel@tonic-gate **
58337c478bd9Sstevel@tonic-gate ** Returns:
58347c478bd9Sstevel@tonic-gate ** true if successful
58357c478bd9Sstevel@tonic-gate ** false otherwise
58367c478bd9Sstevel@tonic-gate **
58377c478bd9Sstevel@tonic-gate ** Side Effects:
58387c478bd9Sstevel@tonic-gate ** On success, e->e_qgrp and e->e_qdir are non-negative.
58397c478bd9Sstevel@tonic-gate ** On failure (not enough disk space),
58407c478bd9Sstevel@tonic-gate ** e->qgrp = NOQGRP, e->e_qdir = NOQDIR
58417c478bd9Sstevel@tonic-gate ** and usrerr() is invoked (which could raise an exception).
58427c478bd9Sstevel@tonic-gate */
58437c478bd9Sstevel@tonic-gate
58447c478bd9Sstevel@tonic-gate bool
setnewqueue(e)58457c478bd9Sstevel@tonic-gate setnewqueue(e)
58467c478bd9Sstevel@tonic-gate ENVELOPE *e;
58477c478bd9Sstevel@tonic-gate {
58487c478bd9Sstevel@tonic-gate if (tTd(41, 20))
58497c478bd9Sstevel@tonic-gate sm_dprintf("setnewqueue: called\n");
58507c478bd9Sstevel@tonic-gate
58517c478bd9Sstevel@tonic-gate /* not set somewhere else */
58527c478bd9Sstevel@tonic-gate if (e->e_qgrp == NOQGRP)
58537c478bd9Sstevel@tonic-gate {
58547c478bd9Sstevel@tonic-gate ADDRESS *q;
58557c478bd9Sstevel@tonic-gate
58567c478bd9Sstevel@tonic-gate /*
58577c478bd9Sstevel@tonic-gate ** Use the queue group of the "first" recipient, as set by
58587c478bd9Sstevel@tonic-gate ** the "queuegroup" rule set. If that is not defined, then
58597c478bd9Sstevel@tonic-gate ** use the queue group of the mailer of the first recipient.
58607c478bd9Sstevel@tonic-gate ** If that is not defined either, then use the default
58617c478bd9Sstevel@tonic-gate ** queue group.
58627c478bd9Sstevel@tonic-gate ** Notice: "first" depends on the sorting of sendqueue
58637c478bd9Sstevel@tonic-gate ** in recipient().
58647c478bd9Sstevel@tonic-gate ** To avoid problems with "bad" recipients look
58657c478bd9Sstevel@tonic-gate ** for a valid address first.
58667c478bd9Sstevel@tonic-gate */
58677c478bd9Sstevel@tonic-gate
58687c478bd9Sstevel@tonic-gate q = e->e_sendqueue;
58697c478bd9Sstevel@tonic-gate while (q != NULL &&
58707c478bd9Sstevel@tonic-gate (QS_IS_BADADDR(q->q_state) || QS_IS_DEAD(q->q_state)))
58717c478bd9Sstevel@tonic-gate {
58727c478bd9Sstevel@tonic-gate q = q->q_next;
58737c478bd9Sstevel@tonic-gate }
58747c478bd9Sstevel@tonic-gate if (q == NULL)
58757c478bd9Sstevel@tonic-gate e->e_qgrp = 0;
58767c478bd9Sstevel@tonic-gate else if (q->q_qgrp >= 0)
58777c478bd9Sstevel@tonic-gate e->e_qgrp = q->q_qgrp;
58787c478bd9Sstevel@tonic-gate else if (q->q_mailer != NULL &&
58797c478bd9Sstevel@tonic-gate ISVALIDQGRP(q->q_mailer->m_qgrp))
58807c478bd9Sstevel@tonic-gate e->e_qgrp = q->q_mailer->m_qgrp;
58817c478bd9Sstevel@tonic-gate else
58827c478bd9Sstevel@tonic-gate e->e_qgrp = 0;
58837c478bd9Sstevel@tonic-gate e->e_dfqgrp = e->e_qgrp;
58847c478bd9Sstevel@tonic-gate }
58857c478bd9Sstevel@tonic-gate
58867c478bd9Sstevel@tonic-gate if (ISVALIDQDIR(e->e_qdir) && ISVALIDQDIR(e->e_dfqdir))
58877c478bd9Sstevel@tonic-gate {
58887c478bd9Sstevel@tonic-gate if (tTd(41, 20))
58897c478bd9Sstevel@tonic-gate sm_dprintf("setnewqueue: e_qdir already assigned (%s)\n",
58907c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir));
58917c478bd9Sstevel@tonic-gate return true;
58927c478bd9Sstevel@tonic-gate }
58937c478bd9Sstevel@tonic-gate
58947c478bd9Sstevel@tonic-gate filesys_update();
58957c478bd9Sstevel@tonic-gate e->e_qdir = pickqdir(Queue[e->e_qgrp], e->e_msgsize, e);
58967c478bd9Sstevel@tonic-gate if (e->e_qdir == NOQDIR)
58977c478bd9Sstevel@tonic-gate {
58987c478bd9Sstevel@tonic-gate e->e_qgrp = NOQGRP;
58997c478bd9Sstevel@tonic-gate if (!bitset(EF_FATALERRS, e->e_flags))
59007c478bd9Sstevel@tonic-gate usrerr("452 4.4.5 Insufficient disk space; try again later");
59017c478bd9Sstevel@tonic-gate e->e_flags |= EF_FATALERRS;
59027c478bd9Sstevel@tonic-gate return false;
59037c478bd9Sstevel@tonic-gate }
59047c478bd9Sstevel@tonic-gate
59057c478bd9Sstevel@tonic-gate if (tTd(41, 3))
59067c478bd9Sstevel@tonic-gate sm_dprintf("setnewqueue: Assigned queue directory %s\n",
59077c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir));
59087c478bd9Sstevel@tonic-gate
59097c478bd9Sstevel@tonic-gate if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR)
59107c478bd9Sstevel@tonic-gate {
59117c478bd9Sstevel@tonic-gate e->e_xfqgrp = e->e_qgrp;
59127c478bd9Sstevel@tonic-gate e->e_xfqdir = e->e_qdir;
59137c478bd9Sstevel@tonic-gate }
59147c478bd9Sstevel@tonic-gate e->e_dfqdir = e->e_qdir;
59157c478bd9Sstevel@tonic-gate return true;
59167c478bd9Sstevel@tonic-gate }
59177c478bd9Sstevel@tonic-gate /*
59187c478bd9Sstevel@tonic-gate ** CHKQDIR -- check a queue directory
59197c478bd9Sstevel@tonic-gate **
59207c478bd9Sstevel@tonic-gate ** Parameters:
59217c478bd9Sstevel@tonic-gate ** name -- name of queue directory
59227c478bd9Sstevel@tonic-gate ** sff -- flags for safefile()
59237c478bd9Sstevel@tonic-gate **
59247c478bd9Sstevel@tonic-gate ** Returns:
59257c478bd9Sstevel@tonic-gate ** is it a queue directory?
59267c478bd9Sstevel@tonic-gate */
59277c478bd9Sstevel@tonic-gate
5928058561cbSjbeck static bool chkqdir __P((char *, long));
5929058561cbSjbeck
59307c478bd9Sstevel@tonic-gate static bool
chkqdir(name,sff)59317c478bd9Sstevel@tonic-gate chkqdir(name, sff)
59327c478bd9Sstevel@tonic-gate char *name;
59337c478bd9Sstevel@tonic-gate long sff;
59347c478bd9Sstevel@tonic-gate {
59357c478bd9Sstevel@tonic-gate struct stat statb;
59367c478bd9Sstevel@tonic-gate int i;
59377c478bd9Sstevel@tonic-gate
59387c478bd9Sstevel@tonic-gate /* skip over . and .. directories */
59397c478bd9Sstevel@tonic-gate if (name[0] == '.' &&
59407c478bd9Sstevel@tonic-gate (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
59417c478bd9Sstevel@tonic-gate return false;
59427c478bd9Sstevel@tonic-gate #if HASLSTAT
59437c478bd9Sstevel@tonic-gate if (lstat(name, &statb) < 0)
59447c478bd9Sstevel@tonic-gate #else /* HASLSTAT */
59457c478bd9Sstevel@tonic-gate if (stat(name, &statb) < 0)
59467c478bd9Sstevel@tonic-gate #endif /* HASLSTAT */
59477c478bd9Sstevel@tonic-gate {
59487c478bd9Sstevel@tonic-gate if (tTd(41, 2))
59497c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: stat(\"%s\"): %s\n",
59507c478bd9Sstevel@tonic-gate name, sm_errstring(errno));
59517c478bd9Sstevel@tonic-gate return false;
59527c478bd9Sstevel@tonic-gate }
59537c478bd9Sstevel@tonic-gate #if HASLSTAT
59547c478bd9Sstevel@tonic-gate if (S_ISLNK(statb.st_mode))
59557c478bd9Sstevel@tonic-gate {
59567c478bd9Sstevel@tonic-gate /*
59577c478bd9Sstevel@tonic-gate ** For a symlink we need to make sure the
59587c478bd9Sstevel@tonic-gate ** target is a directory
59597c478bd9Sstevel@tonic-gate */
59607c478bd9Sstevel@tonic-gate
59617c478bd9Sstevel@tonic-gate if (stat(name, &statb) < 0)
59627c478bd9Sstevel@tonic-gate {
59637c478bd9Sstevel@tonic-gate if (tTd(41, 2))
59647c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: stat(\"%s\"): %s\n",
59657c478bd9Sstevel@tonic-gate name, sm_errstring(errno));
59667c478bd9Sstevel@tonic-gate return false;
59677c478bd9Sstevel@tonic-gate }
59687c478bd9Sstevel@tonic-gate }
59697c478bd9Sstevel@tonic-gate #endif /* HASLSTAT */
59707c478bd9Sstevel@tonic-gate
59717c478bd9Sstevel@tonic-gate if (!S_ISDIR(statb.st_mode))
59727c478bd9Sstevel@tonic-gate {
59737c478bd9Sstevel@tonic-gate if (tTd(41, 2))
59747c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: \"%s\": Not a directory\n",
59757c478bd9Sstevel@tonic-gate name);
59767c478bd9Sstevel@tonic-gate return false;
59777c478bd9Sstevel@tonic-gate }
59787c478bd9Sstevel@tonic-gate
59797c478bd9Sstevel@tonic-gate /* Print a warning if unsafe (but still use it) */
59807c478bd9Sstevel@tonic-gate /* XXX do this only if we want the warning? */
59817c478bd9Sstevel@tonic-gate i = safedirpath(name, RunAsUid, RunAsGid, NULL, sff, 0, 0);
59827c478bd9Sstevel@tonic-gate if (i != 0)
59837c478bd9Sstevel@tonic-gate {
59847c478bd9Sstevel@tonic-gate if (tTd(41, 2))
59857c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: \"%s\": Not safe: %s\n",
59867c478bd9Sstevel@tonic-gate name, sm_errstring(i));
59877c478bd9Sstevel@tonic-gate #if _FFR_CHK_QUEUE
59887c478bd9Sstevel@tonic-gate if (LogLevel > 8)
59897c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID,
59907c478bd9Sstevel@tonic-gate "queue directory \"%s\": Not safe: %s",
59917c478bd9Sstevel@tonic-gate name, sm_errstring(i));
59927c478bd9Sstevel@tonic-gate #endif /* _FFR_CHK_QUEUE */
59937c478bd9Sstevel@tonic-gate }
59947c478bd9Sstevel@tonic-gate return true;
59957c478bd9Sstevel@tonic-gate }
59967c478bd9Sstevel@tonic-gate /*
59977c478bd9Sstevel@tonic-gate ** MULTIQUEUE_CACHE -- cache a list of paths to queues.
59987c478bd9Sstevel@tonic-gate **
59997c478bd9Sstevel@tonic-gate ** Each potential queue is checked as the cache is built.
60007c478bd9Sstevel@tonic-gate ** Thereafter, each is blindly trusted.
60017c478bd9Sstevel@tonic-gate ** Note that we can be called again after a timeout to rebuild
60027c478bd9Sstevel@tonic-gate ** (although code for that is not ready yet).
60037c478bd9Sstevel@tonic-gate **
60047c478bd9Sstevel@tonic-gate ** Parameters:
60057c478bd9Sstevel@tonic-gate ** basedir -- base of all queue directories.
60067c478bd9Sstevel@tonic-gate ** blen -- strlen(basedir).
60077c478bd9Sstevel@tonic-gate ** qg -- queue group.
60087c478bd9Sstevel@tonic-gate ** qn -- number of queue directories already cached.
60097c478bd9Sstevel@tonic-gate ** phash -- pointer to hash value over queue dirs.
60107c478bd9Sstevel@tonic-gate #if SM_CONF_SHM
60117c478bd9Sstevel@tonic-gate ** only used if shared memory is active.
60127c478bd9Sstevel@tonic-gate #endif * SM_CONF_SHM *
60137c478bd9Sstevel@tonic-gate **
60147c478bd9Sstevel@tonic-gate ** Returns:
60157c478bd9Sstevel@tonic-gate ** new number of queue directories.
60167c478bd9Sstevel@tonic-gate */
60177c478bd9Sstevel@tonic-gate
60187c478bd9Sstevel@tonic-gate #define INITIAL_SLOTS 20
60197c478bd9Sstevel@tonic-gate #define ADD_SLOTS 10
60207c478bd9Sstevel@tonic-gate
60217c478bd9Sstevel@tonic-gate static int
multiqueue_cache(basedir,blen,qg,qn,phash)60227c478bd9Sstevel@tonic-gate multiqueue_cache(basedir, blen, qg, qn, phash)
60237c478bd9Sstevel@tonic-gate char *basedir;
60247c478bd9Sstevel@tonic-gate int blen;
60257c478bd9Sstevel@tonic-gate QUEUEGRP *qg;
60267c478bd9Sstevel@tonic-gate int qn;
60277c478bd9Sstevel@tonic-gate unsigned int *phash;
60287c478bd9Sstevel@tonic-gate {
60297c478bd9Sstevel@tonic-gate char *cp;
60307c478bd9Sstevel@tonic-gate int i, len;
60317c478bd9Sstevel@tonic-gate int slotsleft = 0;
60327c478bd9Sstevel@tonic-gate long sff = SFF_ANYFILE;
60337c478bd9Sstevel@tonic-gate char qpath[MAXPATHLEN];
60347c478bd9Sstevel@tonic-gate char subdir[MAXPATHLEN];
60357c478bd9Sstevel@tonic-gate char prefix[MAXPATHLEN]; /* dir relative to basedir */
60367c478bd9Sstevel@tonic-gate
60377c478bd9Sstevel@tonic-gate if (tTd(41, 20))
60387c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: called\n");
60397c478bd9Sstevel@tonic-gate
60407c478bd9Sstevel@tonic-gate /* Initialize to current directory */
60417c478bd9Sstevel@tonic-gate prefix[0] = '.';
60427c478bd9Sstevel@tonic-gate prefix[1] = '\0';
60437c478bd9Sstevel@tonic-gate if (qg->qg_numqueues != 0 && qg->qg_qpaths != NULL)
60447c478bd9Sstevel@tonic-gate {
60457c478bd9Sstevel@tonic-gate for (i = 0; i < qg->qg_numqueues; i++)
60467c478bd9Sstevel@tonic-gate {
60477c478bd9Sstevel@tonic-gate if (qg->qg_qpaths[i].qp_name != NULL)
60487c478bd9Sstevel@tonic-gate (void) sm_free(qg->qg_qpaths[i].qp_name); /* XXX */
60497c478bd9Sstevel@tonic-gate }
60507c478bd9Sstevel@tonic-gate (void) sm_free((char *) qg->qg_qpaths); /* XXX */
60517c478bd9Sstevel@tonic-gate qg->qg_qpaths = NULL;
60527c478bd9Sstevel@tonic-gate qg->qg_numqueues = 0;
60537c478bd9Sstevel@tonic-gate }
60547c478bd9Sstevel@tonic-gate
60557c478bd9Sstevel@tonic-gate /* If running as root, allow safedirpath() checks to use privs */
60567c478bd9Sstevel@tonic-gate if (RunAsUid == 0)
60577c478bd9Sstevel@tonic-gate sff |= SFF_ROOTOK;
60587c478bd9Sstevel@tonic-gate #if _FFR_CHK_QUEUE
60597c478bd9Sstevel@tonic-gate sff |= SFF_SAFEDIRPATH|SFF_NOWWFILES;
60607c478bd9Sstevel@tonic-gate if (!UseMSP)
60617c478bd9Sstevel@tonic-gate sff |= SFF_NOGWFILES;
60627c478bd9Sstevel@tonic-gate #endif /* _FFR_CHK_QUEUE */
60637c478bd9Sstevel@tonic-gate
60647c478bd9Sstevel@tonic-gate if (!SM_IS_DIR_START(qg->qg_qdir))
60657c478bd9Sstevel@tonic-gate {
60667c478bd9Sstevel@tonic-gate /*
60677c478bd9Sstevel@tonic-gate ** XXX we could add basedir, but then we have to realloc()
60687c478bd9Sstevel@tonic-gate ** the string... Maybe another time.
60697c478bd9Sstevel@tonic-gate */
60707c478bd9Sstevel@tonic-gate
60717c478bd9Sstevel@tonic-gate syserr("QueuePath %s not absolute", qg->qg_qdir);
60727c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG;
60737c478bd9Sstevel@tonic-gate return qn;
60747c478bd9Sstevel@tonic-gate }
60757c478bd9Sstevel@tonic-gate
60767c478bd9Sstevel@tonic-gate /* qpath: directory of current workgroup */
6077058561cbSjbeck len = sm_strlcpy(qpath, qg->qg_qdir, sizeof(qpath));
6078058561cbSjbeck if (len >= sizeof(qpath))
60797c478bd9Sstevel@tonic-gate {
60807c478bd9Sstevel@tonic-gate syserr("QueuePath %.256s too long (%d max)",
6081058561cbSjbeck qg->qg_qdir, (int) sizeof(qpath));
60827c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG;
60837c478bd9Sstevel@tonic-gate return qn;
60847c478bd9Sstevel@tonic-gate }
60857c478bd9Sstevel@tonic-gate
60867c478bd9Sstevel@tonic-gate /* begin of qpath must be same as basedir */
60877c478bd9Sstevel@tonic-gate if (strncmp(basedir, qpath, blen) != 0 &&
60887c478bd9Sstevel@tonic-gate (strncmp(basedir, qpath, blen - 1) != 0 || len != blen - 1))
60897c478bd9Sstevel@tonic-gate {
60907c478bd9Sstevel@tonic-gate syserr("QueuePath %s not subpath of QueueDirectory %s",
60917c478bd9Sstevel@tonic-gate qpath, basedir);
60927c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG;
60937c478bd9Sstevel@tonic-gate return qn;
60947c478bd9Sstevel@tonic-gate }
60957c478bd9Sstevel@tonic-gate
60967c478bd9Sstevel@tonic-gate /* Do we have a nested subdirectory? */
60977c478bd9Sstevel@tonic-gate if (blen < len && SM_FIRST_DIR_DELIM(qg->qg_qdir + blen) != NULL)
60987c478bd9Sstevel@tonic-gate {
60997c478bd9Sstevel@tonic-gate
61007c478bd9Sstevel@tonic-gate /* Copy subdirectory into prefix for later use */
6101058561cbSjbeck if (sm_strlcpy(prefix, qg->qg_qdir + blen, sizeof(prefix)) >=
6102058561cbSjbeck sizeof(prefix))
61037c478bd9Sstevel@tonic-gate {
61047c478bd9Sstevel@tonic-gate syserr("QueuePath %.256s too long (%d max)",
6105058561cbSjbeck qg->qg_qdir, (int) sizeof(qpath));
61067c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG;
61077c478bd9Sstevel@tonic-gate return qn;
61087c478bd9Sstevel@tonic-gate }
61097c478bd9Sstevel@tonic-gate cp = SM_LAST_DIR_DELIM(prefix);
61107c478bd9Sstevel@tonic-gate SM_ASSERT(cp != NULL);
61117c478bd9Sstevel@tonic-gate *cp = '\0'; /* cut off trailing / */
61127c478bd9Sstevel@tonic-gate }
61137c478bd9Sstevel@tonic-gate
61147c478bd9Sstevel@tonic-gate /* This is guaranteed by the basedir check above */
61157c478bd9Sstevel@tonic-gate SM_ASSERT(len >= blen - 1);
61167c478bd9Sstevel@tonic-gate cp = &qpath[len - 1];
61177c478bd9Sstevel@tonic-gate if (*cp == '*')
61187c478bd9Sstevel@tonic-gate {
61197c478bd9Sstevel@tonic-gate register DIR *dp;
61207c478bd9Sstevel@tonic-gate register struct dirent *d;
61217c478bd9Sstevel@tonic-gate int off;
61227c478bd9Sstevel@tonic-gate char *delim;
61237c478bd9Sstevel@tonic-gate char relpath[MAXPATHLEN];
61247c478bd9Sstevel@tonic-gate
61257c478bd9Sstevel@tonic-gate *cp = '\0'; /* Overwrite wildcard */
61267c478bd9Sstevel@tonic-gate if ((cp = SM_LAST_DIR_DELIM(qpath)) == NULL)
61277c478bd9Sstevel@tonic-gate {
61287c478bd9Sstevel@tonic-gate syserr("QueueDirectory: can not wildcard relative path");
61297c478bd9Sstevel@tonic-gate if (tTd(41, 2))
61307c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: \"%s*\": Can not wildcard relative path.\n",
61317c478bd9Sstevel@tonic-gate qpath);
61327c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG;
61337c478bd9Sstevel@tonic-gate return qn;
61347c478bd9Sstevel@tonic-gate }
61357c478bd9Sstevel@tonic-gate if (cp == qpath)
61367c478bd9Sstevel@tonic-gate {
61377c478bd9Sstevel@tonic-gate /*
61387c478bd9Sstevel@tonic-gate ** Special case of top level wildcard, like /foo*
61397c478bd9Sstevel@tonic-gate ** Change to //foo*
61407c478bd9Sstevel@tonic-gate */
61417c478bd9Sstevel@tonic-gate
6142058561cbSjbeck (void) sm_strlcpy(qpath + 1, qpath, sizeof(qpath) - 1);
61437c478bd9Sstevel@tonic-gate ++cp;
61447c478bd9Sstevel@tonic-gate }
61457c478bd9Sstevel@tonic-gate delim = cp;
61467c478bd9Sstevel@tonic-gate *(cp++) = '\0'; /* Replace / with \0 */
61477c478bd9Sstevel@tonic-gate len = strlen(cp); /* Last component of queue directory */
61487c478bd9Sstevel@tonic-gate
61497c478bd9Sstevel@tonic-gate /*
61507c478bd9Sstevel@tonic-gate ** Path relative to basedir, with trailing /
61517c478bd9Sstevel@tonic-gate ** It will be modified below to specify the subdirectories
61527c478bd9Sstevel@tonic-gate ** so they can be opened without chdir().
61537c478bd9Sstevel@tonic-gate */
61547c478bd9Sstevel@tonic-gate
6155058561cbSjbeck off = sm_strlcpyn(relpath, sizeof(relpath), 2, prefix, "/");
6156058561cbSjbeck SM_ASSERT(off < sizeof(relpath));
61577c478bd9Sstevel@tonic-gate
61587c478bd9Sstevel@tonic-gate if (tTd(41, 2))
61597c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: prefix=\"%s%s\"\n",
61607c478bd9Sstevel@tonic-gate relpath, cp);
61617c478bd9Sstevel@tonic-gate
61627c478bd9Sstevel@tonic-gate /* It is always basedir: we don't need to store it per group */
61637c478bd9Sstevel@tonic-gate /* XXX: optimize this! -> one more global? */
61647c478bd9Sstevel@tonic-gate qg->qg_qdir = newstr(basedir);
61657c478bd9Sstevel@tonic-gate qg->qg_qdir[blen - 1] = '\0'; /* cut off trailing / */
61667c478bd9Sstevel@tonic-gate
61677c478bd9Sstevel@tonic-gate /*
61687c478bd9Sstevel@tonic-gate ** XXX Should probably wrap this whole loop in a timeout
61697c478bd9Sstevel@tonic-gate ** in case some wag decides to NFS mount the queues.
61707c478bd9Sstevel@tonic-gate */
61717c478bd9Sstevel@tonic-gate
61727c478bd9Sstevel@tonic-gate /* Test path to get warning messages. */
61737c478bd9Sstevel@tonic-gate if (qn == 0)
61747c478bd9Sstevel@tonic-gate {
61757c478bd9Sstevel@tonic-gate /* XXX qg_runasuid and qg_runasgid for specials? */
61767c478bd9Sstevel@tonic-gate i = safedirpath(basedir, RunAsUid, RunAsGid, NULL,
61777c478bd9Sstevel@tonic-gate sff, 0, 0);
61787c478bd9Sstevel@tonic-gate if (i != 0 && tTd(41, 2))
61797c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: \"%s\": Not safe: %s\n",
61807c478bd9Sstevel@tonic-gate basedir, sm_errstring(i));
61817c478bd9Sstevel@tonic-gate }
61827c478bd9Sstevel@tonic-gate
61837c478bd9Sstevel@tonic-gate if ((dp = opendir(prefix)) == NULL)
61847c478bd9Sstevel@tonic-gate {
61857c478bd9Sstevel@tonic-gate syserr("can not opendir(%s/%s)", qg->qg_qdir, prefix);
61867c478bd9Sstevel@tonic-gate if (tTd(41, 2))
61877c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: opendir(\"%s/%s\"): %s\n",
61887c478bd9Sstevel@tonic-gate qg->qg_qdir, prefix,
61897c478bd9Sstevel@tonic-gate sm_errstring(errno));
61907c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG;
61917c478bd9Sstevel@tonic-gate return qn;
61927c478bd9Sstevel@tonic-gate }
61937c478bd9Sstevel@tonic-gate while ((d = readdir(dp)) != NULL)
61947c478bd9Sstevel@tonic-gate {
6195058561cbSjbeck /* Skip . and .. directories */
6196058561cbSjbeck if (strcmp(d->d_name, ".") == 0 ||
6197058561cbSjbeck strcmp(d->d_name, "..") == 0)
6198058561cbSjbeck continue;
6199058561cbSjbeck
62007c478bd9Sstevel@tonic-gate i = strlen(d->d_name);
62017c478bd9Sstevel@tonic-gate if (i < len || strncmp(d->d_name, cp, len) != 0)
62027c478bd9Sstevel@tonic-gate {
62037c478bd9Sstevel@tonic-gate if (tTd(41, 5))
62047c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: \"%s\", skipped\n",
62057c478bd9Sstevel@tonic-gate d->d_name);
62067c478bd9Sstevel@tonic-gate continue;
62077c478bd9Sstevel@tonic-gate }
62087c478bd9Sstevel@tonic-gate
62097c478bd9Sstevel@tonic-gate /* Create relative pathname: prefix + local directory */
62107c478bd9Sstevel@tonic-gate i = sizeof(relpath) - off;
62117c478bd9Sstevel@tonic-gate if (sm_strlcpy(relpath + off, d->d_name, i) >= i)
62127c478bd9Sstevel@tonic-gate continue; /* way too long */
62137c478bd9Sstevel@tonic-gate
62147c478bd9Sstevel@tonic-gate if (!chkqdir(relpath, sff))
62157c478bd9Sstevel@tonic-gate continue;
62167c478bd9Sstevel@tonic-gate
62177c478bd9Sstevel@tonic-gate if (qg->qg_qpaths == NULL)
62187c478bd9Sstevel@tonic-gate {
62197c478bd9Sstevel@tonic-gate slotsleft = INITIAL_SLOTS;
6220058561cbSjbeck qg->qg_qpaths = (QPATHS *)xalloc((sizeof(*qg->qg_qpaths)) *
62217c478bd9Sstevel@tonic-gate slotsleft);
62227c478bd9Sstevel@tonic-gate qg->qg_numqueues = 0;
62237c478bd9Sstevel@tonic-gate }
62247c478bd9Sstevel@tonic-gate else if (slotsleft < 1)
62257c478bd9Sstevel@tonic-gate {
62267c478bd9Sstevel@tonic-gate qg->qg_qpaths = (QPATHS *)sm_realloc((char *)qg->qg_qpaths,
6227058561cbSjbeck (sizeof(*qg->qg_qpaths)) *
62287c478bd9Sstevel@tonic-gate (qg->qg_numqueues +
62297c478bd9Sstevel@tonic-gate ADD_SLOTS));
62307c478bd9Sstevel@tonic-gate if (qg->qg_qpaths == NULL)
62317c478bd9Sstevel@tonic-gate {
62327c478bd9Sstevel@tonic-gate (void) closedir(dp);
62337c478bd9Sstevel@tonic-gate return qn;
62347c478bd9Sstevel@tonic-gate }
62357c478bd9Sstevel@tonic-gate slotsleft += ADD_SLOTS;
62367c478bd9Sstevel@tonic-gate }
62377c478bd9Sstevel@tonic-gate
62387c478bd9Sstevel@tonic-gate /* check subdirs */
62397c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_subdirs = QP_NOSUB;
62407c478bd9Sstevel@tonic-gate
62417c478bd9Sstevel@tonic-gate #define CHKRSUBDIR(name, flag) \
6242058561cbSjbeck (void) sm_strlcpyn(subdir, sizeof(subdir), 3, relpath, "/", name); \
62437c478bd9Sstevel@tonic-gate if (chkqdir(subdir, sff)) \
62447c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_subdirs |= flag; \
62457c478bd9Sstevel@tonic-gate else
62467c478bd9Sstevel@tonic-gate
62477c478bd9Sstevel@tonic-gate
62487c478bd9Sstevel@tonic-gate CHKRSUBDIR("qf", QP_SUBQF);
62497c478bd9Sstevel@tonic-gate CHKRSUBDIR("df", QP_SUBDF);
62507c478bd9Sstevel@tonic-gate CHKRSUBDIR("xf", QP_SUBXF);
62517c478bd9Sstevel@tonic-gate
62527c478bd9Sstevel@tonic-gate /* assert(strlen(d->d_name) < MAXPATHLEN - 14) */
62537c478bd9Sstevel@tonic-gate /* maybe even - 17 (subdirs) */
62547c478bd9Sstevel@tonic-gate
62557c478bd9Sstevel@tonic-gate if (prefix[0] != '.')
62567c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_name =
62577c478bd9Sstevel@tonic-gate newstr(relpath);
62587c478bd9Sstevel@tonic-gate else
62597c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_name =
62607c478bd9Sstevel@tonic-gate newstr(d->d_name);
62617c478bd9Sstevel@tonic-gate
62627c478bd9Sstevel@tonic-gate if (tTd(41, 2))
62637c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: %d: \"%s\" cached (%x).\n",
62647c478bd9Sstevel@tonic-gate qg->qg_numqueues, relpath,
62657c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_subdirs);
62667c478bd9Sstevel@tonic-gate #if SM_CONF_SHM
62677c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_idx = qn;
62687c478bd9Sstevel@tonic-gate *phash = hash_q(relpath, *phash);
62697c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */
62707c478bd9Sstevel@tonic-gate qg->qg_numqueues++;
62717c478bd9Sstevel@tonic-gate ++qn;
62727c478bd9Sstevel@tonic-gate slotsleft--;
62737c478bd9Sstevel@tonic-gate }
62747c478bd9Sstevel@tonic-gate (void) closedir(dp);
62757c478bd9Sstevel@tonic-gate
62767c478bd9Sstevel@tonic-gate /* undo damage */
62777c478bd9Sstevel@tonic-gate *delim = '/';
62787c478bd9Sstevel@tonic-gate }
62797c478bd9Sstevel@tonic-gate if (qg->qg_numqueues == 0)
62807c478bd9Sstevel@tonic-gate {
6281058561cbSjbeck qg->qg_qpaths = (QPATHS *) xalloc(sizeof(*qg->qg_qpaths));
62827c478bd9Sstevel@tonic-gate
62837c478bd9Sstevel@tonic-gate /* test path to get warning messages */
62847c478bd9Sstevel@tonic-gate i = safedirpath(qpath, RunAsUid, RunAsGid, NULL, sff, 0, 0);
62857c478bd9Sstevel@tonic-gate if (i == ENOENT)
62867c478bd9Sstevel@tonic-gate {
62877c478bd9Sstevel@tonic-gate syserr("can not opendir(%s)", qpath);
62887c478bd9Sstevel@tonic-gate if (tTd(41, 2))
62897c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: opendir(\"%s\"): %s\n",
62907c478bd9Sstevel@tonic-gate qpath, sm_errstring(i));
62917c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG;
62927c478bd9Sstevel@tonic-gate return qn;
62937c478bd9Sstevel@tonic-gate }
62947c478bd9Sstevel@tonic-gate
62957c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_subdirs = QP_NOSUB;
62967c478bd9Sstevel@tonic-gate qg->qg_numqueues = 1;
62977c478bd9Sstevel@tonic-gate
62987c478bd9Sstevel@tonic-gate /* check subdirs */
62997c478bd9Sstevel@tonic-gate #define CHKSUBDIR(name, flag) \
6300058561cbSjbeck (void) sm_strlcpyn(subdir, sizeof(subdir), 3, qg->qg_qdir, "/", name); \
63017c478bd9Sstevel@tonic-gate if (chkqdir(subdir, sff)) \
63027c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_subdirs |= flag; \
63037c478bd9Sstevel@tonic-gate else
63047c478bd9Sstevel@tonic-gate
63057c478bd9Sstevel@tonic-gate CHKSUBDIR("qf", QP_SUBQF);
63067c478bd9Sstevel@tonic-gate CHKSUBDIR("df", QP_SUBDF);
63077c478bd9Sstevel@tonic-gate CHKSUBDIR("xf", QP_SUBXF);
63087c478bd9Sstevel@tonic-gate
63097c478bd9Sstevel@tonic-gate if (qg->qg_qdir[blen - 1] != '\0' &&
63107c478bd9Sstevel@tonic-gate qg->qg_qdir[blen] != '\0')
63117c478bd9Sstevel@tonic-gate {
63127c478bd9Sstevel@tonic-gate /*
63137c478bd9Sstevel@tonic-gate ** Copy the last component into qpaths and
63147c478bd9Sstevel@tonic-gate ** cut off qdir
63157c478bd9Sstevel@tonic-gate */
63167c478bd9Sstevel@tonic-gate
63177c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_name = newstr(qg->qg_qdir + blen);
63187c478bd9Sstevel@tonic-gate qg->qg_qdir[blen - 1] = '\0';
63197c478bd9Sstevel@tonic-gate }
63207c478bd9Sstevel@tonic-gate else
63217c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_name = newstr(".");
63227c478bd9Sstevel@tonic-gate
63237c478bd9Sstevel@tonic-gate #if SM_CONF_SHM
63247c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_idx = qn;
63257c478bd9Sstevel@tonic-gate *phash = hash_q(qg->qg_qpaths[0].qp_name, *phash);
63267c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */
63277c478bd9Sstevel@tonic-gate ++qn;
63287c478bd9Sstevel@tonic-gate }
63297c478bd9Sstevel@tonic-gate return qn;
63307c478bd9Sstevel@tonic-gate }
63317c478bd9Sstevel@tonic-gate
63327c478bd9Sstevel@tonic-gate /*
63337c478bd9Sstevel@tonic-gate ** FILESYS_FIND -- find entry in FileSys table, or add new one
63347c478bd9Sstevel@tonic-gate **
63357c478bd9Sstevel@tonic-gate ** Given the pathname of a directory, determine the file system
63367c478bd9Sstevel@tonic-gate ** in which that directory resides, and return a pointer to the
63377c478bd9Sstevel@tonic-gate ** entry in the FileSys table that describes the file system.
63387c478bd9Sstevel@tonic-gate ** A new entry is added if necessary (and requested).
63397c478bd9Sstevel@tonic-gate ** If the directory does not exist, -1 is returned.
63407c478bd9Sstevel@tonic-gate **
63417c478bd9Sstevel@tonic-gate ** Parameters:
634249218d4fSjbeck ** name -- name of directory (must be persistent!)
634349218d4fSjbeck ** path -- pathname of directory (name plus maybe "/df")
63447c478bd9Sstevel@tonic-gate ** add -- add to structure if not found.
63457c478bd9Sstevel@tonic-gate **
63467c478bd9Sstevel@tonic-gate ** Returns:
63477c478bd9Sstevel@tonic-gate ** >=0: found: index in file system table
63487c478bd9Sstevel@tonic-gate ** <0: some error, i.e.,
63497c478bd9Sstevel@tonic-gate ** FSF_TOO_MANY: too many filesystems (-> syserr())
63507c478bd9Sstevel@tonic-gate ** FSF_STAT_FAIL: can't stat() filesystem (-> syserr())
63517c478bd9Sstevel@tonic-gate ** FSF_NOT_FOUND: not in list
63527c478bd9Sstevel@tonic-gate */
63537c478bd9Sstevel@tonic-gate
6354058561cbSjbeck static short filesys_find __P((const char *, const char *, bool));
63557c478bd9Sstevel@tonic-gate
63567c478bd9Sstevel@tonic-gate #define FSF_NOT_FOUND (-1)
63577c478bd9Sstevel@tonic-gate #define FSF_STAT_FAIL (-2)
63587c478bd9Sstevel@tonic-gate #define FSF_TOO_MANY (-3)
63597c478bd9Sstevel@tonic-gate
63607c478bd9Sstevel@tonic-gate static short
filesys_find(name,path,add)636149218d4fSjbeck filesys_find(name, path, add)
6362058561cbSjbeck const char *name;
6363058561cbSjbeck const char *path;
63647c478bd9Sstevel@tonic-gate bool add;
63657c478bd9Sstevel@tonic-gate {
63667c478bd9Sstevel@tonic-gate struct stat st;
63677c478bd9Sstevel@tonic-gate short i;
63687c478bd9Sstevel@tonic-gate
63697c478bd9Sstevel@tonic-gate if (stat(path, &st) < 0)
63707c478bd9Sstevel@tonic-gate {
63717c478bd9Sstevel@tonic-gate syserr("cannot stat queue directory %s", path);
63727c478bd9Sstevel@tonic-gate return FSF_STAT_FAIL;
63737c478bd9Sstevel@tonic-gate }
63747c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i)
63757c478bd9Sstevel@tonic-gate {
63767c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(i) == st.st_dev)
63771daa5768Sjbeck {
63781daa5768Sjbeck /*
63791daa5768Sjbeck ** Make sure the file system (FS) name is set:
63801daa5768Sjbeck ** even though the source code indicates that
63811daa5768Sjbeck ** FILE_SYS_DEV() is only set below, it could be
63821daa5768Sjbeck ** set via shared memory, hence we need to perform
63831daa5768Sjbeck ** this check/assignment here.
63841daa5768Sjbeck */
63851daa5768Sjbeck
63861daa5768Sjbeck if (NULL == FILE_SYS_NAME(i))
63871daa5768Sjbeck FILE_SYS_NAME(i) = name;
63887c478bd9Sstevel@tonic-gate return i;
63897c478bd9Sstevel@tonic-gate }
63901daa5768Sjbeck }
63917c478bd9Sstevel@tonic-gate if (i >= MAXFILESYS)
63927c478bd9Sstevel@tonic-gate {
63937c478bd9Sstevel@tonic-gate syserr("too many queue file systems (%d max)", MAXFILESYS);
63947c478bd9Sstevel@tonic-gate return FSF_TOO_MANY;
63957c478bd9Sstevel@tonic-gate }
63967c478bd9Sstevel@tonic-gate if (!add)
63977c478bd9Sstevel@tonic-gate return FSF_NOT_FOUND;
63987c478bd9Sstevel@tonic-gate
63997c478bd9Sstevel@tonic-gate ++NumFileSys;
640049218d4fSjbeck FILE_SYS_NAME(i) = name;
64017c478bd9Sstevel@tonic-gate FILE_SYS_DEV(i) = st.st_dev;
64027c478bd9Sstevel@tonic-gate FILE_SYS_AVAIL(i) = 0;
64037c478bd9Sstevel@tonic-gate FILE_SYS_BLKSIZE(i) = 1024; /* avoid divide by zero */
64047c478bd9Sstevel@tonic-gate return i;
64057c478bd9Sstevel@tonic-gate }
64067c478bd9Sstevel@tonic-gate
64077c478bd9Sstevel@tonic-gate /*
64087c478bd9Sstevel@tonic-gate ** FILESYS_SETUP -- set up mapping from queue directories to file systems
64097c478bd9Sstevel@tonic-gate **
64107c478bd9Sstevel@tonic-gate ** This data structure is used to efficiently check the amount of
64117c478bd9Sstevel@tonic-gate ** free space available in a set of queue directories.
64127c478bd9Sstevel@tonic-gate **
64137c478bd9Sstevel@tonic-gate ** Parameters:
64147c478bd9Sstevel@tonic-gate ** add -- initialize structure if necessary.
64157c478bd9Sstevel@tonic-gate **
64167c478bd9Sstevel@tonic-gate ** Returns:
64177c478bd9Sstevel@tonic-gate ** 0: success
64187c478bd9Sstevel@tonic-gate ** <0: some error, i.e.,
64197c478bd9Sstevel@tonic-gate ** FSF_NOT_FOUND: not in list
64207c478bd9Sstevel@tonic-gate ** FSF_STAT_FAIL: can't stat() filesystem (-> syserr())
64217c478bd9Sstevel@tonic-gate ** FSF_TOO_MANY: too many filesystems (-> syserr())
64227c478bd9Sstevel@tonic-gate */
64237c478bd9Sstevel@tonic-gate
64247c478bd9Sstevel@tonic-gate static int filesys_setup __P((bool));
64257c478bd9Sstevel@tonic-gate
64267c478bd9Sstevel@tonic-gate static int
filesys_setup(add)64277c478bd9Sstevel@tonic-gate filesys_setup(add)
64287c478bd9Sstevel@tonic-gate bool add;
64297c478bd9Sstevel@tonic-gate {
64307c478bd9Sstevel@tonic-gate int i, j;
64317c478bd9Sstevel@tonic-gate short fs;
64327c478bd9Sstevel@tonic-gate int ret;
64337c478bd9Sstevel@tonic-gate
64347c478bd9Sstevel@tonic-gate ret = 0;
64357c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
64367c478bd9Sstevel@tonic-gate {
64377c478bd9Sstevel@tonic-gate for (j = 0; j < Queue[i]->qg_numqueues; ++j)
64387c478bd9Sstevel@tonic-gate {
64397c478bd9Sstevel@tonic-gate QPATHS *qp = &Queue[i]->qg_qpaths[j];
644049218d4fSjbeck char qddf[MAXPATHLEN];
64417c478bd9Sstevel@tonic-gate
6442058561cbSjbeck (void) sm_strlcpyn(qddf, sizeof(qddf), 2, qp->qp_name,
644349218d4fSjbeck (bitset(QP_SUBDF, qp->qp_subdirs)
644449218d4fSjbeck ? "/df" : ""));
644549218d4fSjbeck fs = filesys_find(qp->qp_name, qddf, add);
64467c478bd9Sstevel@tonic-gate if (fs >= 0)
64477c478bd9Sstevel@tonic-gate qp->qp_fsysidx = fs;
64487c478bd9Sstevel@tonic-gate else
64497c478bd9Sstevel@tonic-gate qp->qp_fsysidx = 0;
64507c478bd9Sstevel@tonic-gate if (fs < ret)
64517c478bd9Sstevel@tonic-gate ret = fs;
64527c478bd9Sstevel@tonic-gate }
64537c478bd9Sstevel@tonic-gate }
64547c478bd9Sstevel@tonic-gate return ret;
64557c478bd9Sstevel@tonic-gate }
64567c478bd9Sstevel@tonic-gate
64577c478bd9Sstevel@tonic-gate /*
64587c478bd9Sstevel@tonic-gate ** FILESYS_UPDATE -- update amount of free space on all file systems
64597c478bd9Sstevel@tonic-gate **
64607c478bd9Sstevel@tonic-gate ** The FileSys table is used to cache the amount of free space
64617c478bd9Sstevel@tonic-gate ** available on all queue directory file systems.
64627c478bd9Sstevel@tonic-gate ** This function updates the cached information if it has expired.
64637c478bd9Sstevel@tonic-gate **
64647c478bd9Sstevel@tonic-gate ** Parameters:
64657c478bd9Sstevel@tonic-gate ** none.
64667c478bd9Sstevel@tonic-gate **
64677c478bd9Sstevel@tonic-gate ** Returns:
64687c478bd9Sstevel@tonic-gate ** none.
64697c478bd9Sstevel@tonic-gate **
64707c478bd9Sstevel@tonic-gate ** Side Effects:
64717c478bd9Sstevel@tonic-gate ** Updates FileSys table.
64727c478bd9Sstevel@tonic-gate */
64737c478bd9Sstevel@tonic-gate
64747c478bd9Sstevel@tonic-gate void
filesys_update()64757c478bd9Sstevel@tonic-gate filesys_update()
64767c478bd9Sstevel@tonic-gate {
64777c478bd9Sstevel@tonic-gate int i;
64787c478bd9Sstevel@tonic-gate long avail, blksize;
64797c478bd9Sstevel@tonic-gate time_t now;
64807c478bd9Sstevel@tonic-gate static time_t nextupdate = 0;
64817c478bd9Sstevel@tonic-gate
64827c478bd9Sstevel@tonic-gate #if SM_CONF_SHM
6483058561cbSjbeck /*
6484058561cbSjbeck ** Only the daemon updates the shared memory, i.e.,
6485058561cbSjbeck ** if shared memory is available but the pid is not the
6486058561cbSjbeck ** one of the daemon, then don't do anything.
6487058561cbSjbeck */
6488058561cbSjbeck
64891daa5768Sjbeck if (ShmId != SM_SHM_NO_ID && DaemonPid != CurrentPid)
64907c478bd9Sstevel@tonic-gate return;
64917c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */
64927c478bd9Sstevel@tonic-gate now = curtime();
64937c478bd9Sstevel@tonic-gate if (now < nextupdate)
64947c478bd9Sstevel@tonic-gate return;
64957c478bd9Sstevel@tonic-gate nextupdate = now + FILESYS_UPDATE_INTERVAL;
64967c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i)
64977c478bd9Sstevel@tonic-gate {
64987c478bd9Sstevel@tonic-gate FILESYS *fs = &FILE_SYS(i);
64997c478bd9Sstevel@tonic-gate
65007c478bd9Sstevel@tonic-gate avail = freediskspace(FILE_SYS_NAME(i), &blksize);
65017c478bd9Sstevel@tonic-gate if (avail < 0 || blksize <= 0)
65027c478bd9Sstevel@tonic-gate {
65037c478bd9Sstevel@tonic-gate if (LogLevel > 5)
65047c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID,
65057c478bd9Sstevel@tonic-gate "filesys_update failed: %s, fs=%s, avail=%ld, blocksize=%ld",
65067c478bd9Sstevel@tonic-gate sm_errstring(errno),
65077c478bd9Sstevel@tonic-gate FILE_SYS_NAME(i), avail, blksize);
65087c478bd9Sstevel@tonic-gate fs->fs_avail = 0;
65097c478bd9Sstevel@tonic-gate fs->fs_blksize = 1024; /* avoid divide by zero */
65107c478bd9Sstevel@tonic-gate nextupdate = now + 2; /* let's do this soon again */
65117c478bd9Sstevel@tonic-gate }
65127c478bd9Sstevel@tonic-gate else
65137c478bd9Sstevel@tonic-gate {
65147c478bd9Sstevel@tonic-gate fs->fs_avail = avail;
65157c478bd9Sstevel@tonic-gate fs->fs_blksize = blksize;
65167c478bd9Sstevel@tonic-gate }
65177c478bd9Sstevel@tonic-gate }
65187c478bd9Sstevel@tonic-gate }
65197c478bd9Sstevel@tonic-gate
65207c478bd9Sstevel@tonic-gate #if _FFR_ANY_FREE_FS
65217c478bd9Sstevel@tonic-gate /*
65227c478bd9Sstevel@tonic-gate ** FILESYS_FREE -- check whether there is at least one fs with enough space.
65237c478bd9Sstevel@tonic-gate **
65247c478bd9Sstevel@tonic-gate ** Parameters:
65257c478bd9Sstevel@tonic-gate ** fsize -- file size in bytes
65267c478bd9Sstevel@tonic-gate **
65277c478bd9Sstevel@tonic-gate ** Returns:
65287c478bd9Sstevel@tonic-gate ** true iff there is one fs with more than fsize bytes free.
65297c478bd9Sstevel@tonic-gate */
65307c478bd9Sstevel@tonic-gate
65317c478bd9Sstevel@tonic-gate bool
filesys_free(fsize)65327c478bd9Sstevel@tonic-gate filesys_free(fsize)
65337c478bd9Sstevel@tonic-gate long fsize;
65347c478bd9Sstevel@tonic-gate {
65357c478bd9Sstevel@tonic-gate int i;
65367c478bd9Sstevel@tonic-gate
65377c478bd9Sstevel@tonic-gate if (fsize <= 0)
65387c478bd9Sstevel@tonic-gate return true;
65397c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i)
65407c478bd9Sstevel@tonic-gate {
65417c478bd9Sstevel@tonic-gate long needed = 0;
65427c478bd9Sstevel@tonic-gate
65437c478bd9Sstevel@tonic-gate if (FILE_SYS_AVAIL(i) < 0 || FILE_SYS_BLKSIZE(i) <= 0)
65447c478bd9Sstevel@tonic-gate continue;
65457c478bd9Sstevel@tonic-gate needed += fsize / FILE_SYS_BLKSIZE(i)
65467c478bd9Sstevel@tonic-gate + ((fsize % FILE_SYS_BLKSIZE(i)
65477c478bd9Sstevel@tonic-gate > 0) ? 1 : 0)
65487c478bd9Sstevel@tonic-gate + MinBlocksFree;
65497c478bd9Sstevel@tonic-gate if (needed <= FILE_SYS_AVAIL(i))
65507c478bd9Sstevel@tonic-gate return true;
65517c478bd9Sstevel@tonic-gate }
65527c478bd9Sstevel@tonic-gate return false;
65537c478bd9Sstevel@tonic-gate }
65547c478bd9Sstevel@tonic-gate #endif /* _FFR_ANY_FREE_FS */
65557c478bd9Sstevel@tonic-gate
65567c478bd9Sstevel@tonic-gate /*
65577c478bd9Sstevel@tonic-gate ** DISK_STATUS -- show amount of free space in queue directories
65587c478bd9Sstevel@tonic-gate **
65597c478bd9Sstevel@tonic-gate ** Parameters:
65607c478bd9Sstevel@tonic-gate ** out -- output file pointer.
65617c478bd9Sstevel@tonic-gate ** prefix -- string to output in front of each line.
65627c478bd9Sstevel@tonic-gate **
65637c478bd9Sstevel@tonic-gate ** Returns:
65647c478bd9Sstevel@tonic-gate ** none.
65657c478bd9Sstevel@tonic-gate */
65667c478bd9Sstevel@tonic-gate
65677c478bd9Sstevel@tonic-gate void
disk_status(out,prefix)65687c478bd9Sstevel@tonic-gate disk_status(out, prefix)
65697c478bd9Sstevel@tonic-gate SM_FILE_T *out;
65707c478bd9Sstevel@tonic-gate char *prefix;
65717c478bd9Sstevel@tonic-gate {
65727c478bd9Sstevel@tonic-gate int i;
65737c478bd9Sstevel@tonic-gate long avail, blksize;
65747c478bd9Sstevel@tonic-gate long free;
65757c478bd9Sstevel@tonic-gate
65767c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i)
65777c478bd9Sstevel@tonic-gate {
65787c478bd9Sstevel@tonic-gate avail = freediskspace(FILE_SYS_NAME(i), &blksize);
65797c478bd9Sstevel@tonic-gate if (avail >= 0 && blksize > 0)
65807c478bd9Sstevel@tonic-gate {
65817c478bd9Sstevel@tonic-gate free = (long)((double) avail *
65827c478bd9Sstevel@tonic-gate ((double) blksize / 1024));
65837c478bd9Sstevel@tonic-gate }
65847c478bd9Sstevel@tonic-gate else
65857c478bd9Sstevel@tonic-gate free = -1;
65867c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
65877c478bd9Sstevel@tonic-gate "%s%d/%s/%ld\r\n",
65887c478bd9Sstevel@tonic-gate prefix, i,
65897c478bd9Sstevel@tonic-gate FILE_SYS_NAME(i),
65907c478bd9Sstevel@tonic-gate free);
65917c478bd9Sstevel@tonic-gate }
65927c478bd9Sstevel@tonic-gate }
65937c478bd9Sstevel@tonic-gate
65947c478bd9Sstevel@tonic-gate #if SM_CONF_SHM
65957c478bd9Sstevel@tonic-gate
65967c478bd9Sstevel@tonic-gate /*
65977c478bd9Sstevel@tonic-gate ** INIT_SEM -- initialize semaphore system
65987c478bd9Sstevel@tonic-gate **
65997c478bd9Sstevel@tonic-gate ** Parameters:
66007c478bd9Sstevel@tonic-gate ** owner -- is this the owner of semaphores?
66017c478bd9Sstevel@tonic-gate **
66027c478bd9Sstevel@tonic-gate ** Returns:
66037c478bd9Sstevel@tonic-gate ** none.
66047c478bd9Sstevel@tonic-gate */
66057c478bd9Sstevel@tonic-gate
66067c478bd9Sstevel@tonic-gate #if _FFR_USE_SEM_LOCKING
66077c478bd9Sstevel@tonic-gate #if SM_CONF_SEM
66087c478bd9Sstevel@tonic-gate static int SemId = -1; /* Semaphore Id */
66097c478bd9Sstevel@tonic-gate int SemKey = SM_SEM_KEY;
66107c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SEM */
66117c478bd9Sstevel@tonic-gate #endif /* _FFR_USE_SEM_LOCKING */
66127c478bd9Sstevel@tonic-gate
66137c478bd9Sstevel@tonic-gate static void init_sem __P((bool));
66147c478bd9Sstevel@tonic-gate
66157c478bd9Sstevel@tonic-gate static void
init_sem(owner)66167c478bd9Sstevel@tonic-gate init_sem(owner)
66177c478bd9Sstevel@tonic-gate bool owner;
66187c478bd9Sstevel@tonic-gate {
66197c478bd9Sstevel@tonic-gate #if _FFR_USE_SEM_LOCKING
66207c478bd9Sstevel@tonic-gate #if SM_CONF_SEM
66217c478bd9Sstevel@tonic-gate SemId = sm_sem_start(SemKey, 1, 0, owner);
66227c478bd9Sstevel@tonic-gate if (SemId < 0)
66237c478bd9Sstevel@tonic-gate {
66247c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID,
6625d4660949Sjbeck "func=init_sem, sem_key=%ld, sm_sem_start=%d, error=%s",
6626d4660949Sjbeck (long) SemKey, SemId, sm_errstring(-SemId));
66277c478bd9Sstevel@tonic-gate return;
66287c478bd9Sstevel@tonic-gate }
6629e9af4bc0SJohn Beck if (owner && RunAsUid != 0)
6630e9af4bc0SJohn Beck {
6631e9af4bc0SJohn Beck int r;
6632e9af4bc0SJohn Beck
6633e9af4bc0SJohn Beck r = sm_semsetowner(SemId, RunAsUid, RunAsGid, 0660);
6634e9af4bc0SJohn Beck if (r != 0)
6635e9af4bc0SJohn Beck sm_syslog(LOG_ERR, NOQID,
6636e9af4bc0SJohn Beck "key=%ld, sm_semsetowner=%d, RunAsUid=%d, RunAsGid=%d",
6637e9af4bc0SJohn Beck (long) SemKey, r, RunAsUid, RunAsGid);
6638e9af4bc0SJohn Beck }
66397c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SEM */
66407c478bd9Sstevel@tonic-gate #endif /* _FFR_USE_SEM_LOCKING */
66417c478bd9Sstevel@tonic-gate return;
66427c478bd9Sstevel@tonic-gate }
66437c478bd9Sstevel@tonic-gate
66447c478bd9Sstevel@tonic-gate /*
66457c478bd9Sstevel@tonic-gate ** STOP_SEM -- stop semaphore system
66467c478bd9Sstevel@tonic-gate **
66477c478bd9Sstevel@tonic-gate ** Parameters:
66487c478bd9Sstevel@tonic-gate ** owner -- is this the owner of semaphores?
66497c478bd9Sstevel@tonic-gate **
66507c478bd9Sstevel@tonic-gate ** Returns:
66517c478bd9Sstevel@tonic-gate ** none.
66527c478bd9Sstevel@tonic-gate */
66537c478bd9Sstevel@tonic-gate
66547c478bd9Sstevel@tonic-gate static void stop_sem __P((bool));
66557c478bd9Sstevel@tonic-gate
66567c478bd9Sstevel@tonic-gate static void
stop_sem(owner)66577c478bd9Sstevel@tonic-gate stop_sem(owner)
66587c478bd9Sstevel@tonic-gate bool owner;
66597c478bd9Sstevel@tonic-gate {
66607c478bd9Sstevel@tonic-gate #if _FFR_USE_SEM_LOCKING
66617c478bd9Sstevel@tonic-gate #if SM_CONF_SEM
66627c478bd9Sstevel@tonic-gate if (owner && SemId >= 0)
66637c478bd9Sstevel@tonic-gate sm_sem_stop(SemId);
66647c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SEM */
66657c478bd9Sstevel@tonic-gate #endif /* _FFR_USE_SEM_LOCKING */
66667c478bd9Sstevel@tonic-gate return;
66677c478bd9Sstevel@tonic-gate }
66687c478bd9Sstevel@tonic-gate
66697c478bd9Sstevel@tonic-gate /*
66707c478bd9Sstevel@tonic-gate ** UPD_QS -- update information about queue when adding/deleting an entry
66717c478bd9Sstevel@tonic-gate **
66727c478bd9Sstevel@tonic-gate ** Parameters:
66737c478bd9Sstevel@tonic-gate ** e -- envelope.
66747c478bd9Sstevel@tonic-gate ** count -- add/remove entry (+1/0/-1: add/no change/remove)
66757c478bd9Sstevel@tonic-gate ** space -- update the space available as well.
66767c478bd9Sstevel@tonic-gate ** (>0/0/<0: add/no change/remove)
66777c478bd9Sstevel@tonic-gate ** where -- caller (for logging)
66787c478bd9Sstevel@tonic-gate **
66797c478bd9Sstevel@tonic-gate ** Returns:
66807c478bd9Sstevel@tonic-gate ** none.
66817c478bd9Sstevel@tonic-gate **
66827c478bd9Sstevel@tonic-gate ** Side Effects:
66837c478bd9Sstevel@tonic-gate ** Modifies available space in filesystem.
66847c478bd9Sstevel@tonic-gate ** Changes number of entries in queue directory.
66857c478bd9Sstevel@tonic-gate */
66867c478bd9Sstevel@tonic-gate
66877c478bd9Sstevel@tonic-gate void
upd_qs(e,count,space,where)66887c478bd9Sstevel@tonic-gate upd_qs(e, count, space, where)
66897c478bd9Sstevel@tonic-gate ENVELOPE *e;
66907c478bd9Sstevel@tonic-gate int count;
66917c478bd9Sstevel@tonic-gate int space;
66927c478bd9Sstevel@tonic-gate char *where;
66937c478bd9Sstevel@tonic-gate {
66947c478bd9Sstevel@tonic-gate short fidx;
66957c478bd9Sstevel@tonic-gate int idx;
66967c478bd9Sstevel@tonic-gate # if _FFR_USE_SEM_LOCKING
66977c478bd9Sstevel@tonic-gate int r;
66987c478bd9Sstevel@tonic-gate # endif /* _FFR_USE_SEM_LOCKING */
66997c478bd9Sstevel@tonic-gate long s;
67007c478bd9Sstevel@tonic-gate
67017c478bd9Sstevel@tonic-gate if (ShmId == SM_SHM_NO_ID || e == NULL)
67027c478bd9Sstevel@tonic-gate return;
67037c478bd9Sstevel@tonic-gate if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR)
67047c478bd9Sstevel@tonic-gate return;
67057c478bd9Sstevel@tonic-gate idx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_idx;
67067c478bd9Sstevel@tonic-gate if (tTd(73,2))
67077c478bd9Sstevel@tonic-gate sm_dprintf("func=upd_qs, count=%d, space=%d, where=%s, idx=%d, entries=%d\n",
67087c478bd9Sstevel@tonic-gate count, space, where, idx, QSHM_ENTRIES(idx));
67097c478bd9Sstevel@tonic-gate
67107c478bd9Sstevel@tonic-gate /* XXX in theory this needs to be protected with a mutex */
67117c478bd9Sstevel@tonic-gate if (QSHM_ENTRIES(idx) >= 0 && count != 0)
67127c478bd9Sstevel@tonic-gate {
67137c478bd9Sstevel@tonic-gate # if _FFR_USE_SEM_LOCKING
67147c478bd9Sstevel@tonic-gate r = sm_sem_acq(SemId, 0, 1);
67157c478bd9Sstevel@tonic-gate # endif /* _FFR_USE_SEM_LOCKING */
67167c478bd9Sstevel@tonic-gate QSHM_ENTRIES(idx) += count;
67177c478bd9Sstevel@tonic-gate # if _FFR_USE_SEM_LOCKING
67187c478bd9Sstevel@tonic-gate if (r >= 0)
67197c478bd9Sstevel@tonic-gate r = sm_sem_rel(SemId, 0, 1);
67207c478bd9Sstevel@tonic-gate # endif /* _FFR_USE_SEM_LOCKING */
67217c478bd9Sstevel@tonic-gate }
67227c478bd9Sstevel@tonic-gate
67237c478bd9Sstevel@tonic-gate fidx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_fsysidx;
67247c478bd9Sstevel@tonic-gate if (fidx < 0)
67257c478bd9Sstevel@tonic-gate return;
67267c478bd9Sstevel@tonic-gate
67277c478bd9Sstevel@tonic-gate /* update available space also? (might be loseqfile) */
67287c478bd9Sstevel@tonic-gate if (space == 0)
67297c478bd9Sstevel@tonic-gate return;
67307c478bd9Sstevel@tonic-gate
67317c478bd9Sstevel@tonic-gate /* convert size to blocks; this causes rounding errors */
67327c478bd9Sstevel@tonic-gate s = e->e_msgsize / FILE_SYS_BLKSIZE(fidx);
67337c478bd9Sstevel@tonic-gate if (s == 0)
67347c478bd9Sstevel@tonic-gate return;
67357c478bd9Sstevel@tonic-gate
67367c478bd9Sstevel@tonic-gate /* XXX in theory this needs to be protected with a mutex */
67377c478bd9Sstevel@tonic-gate if (space > 0)
67387c478bd9Sstevel@tonic-gate FILE_SYS_AVAIL(fidx) += s;
67397c478bd9Sstevel@tonic-gate else
67407c478bd9Sstevel@tonic-gate FILE_SYS_AVAIL(fidx) -= s;
67417c478bd9Sstevel@tonic-gate
67427c478bd9Sstevel@tonic-gate }
67437c478bd9Sstevel@tonic-gate
67447c478bd9Sstevel@tonic-gate static bool write_key_file __P((char *, long));
67457c478bd9Sstevel@tonic-gate static long read_key_file __P((char *, long));
67467c478bd9Sstevel@tonic-gate
67477c478bd9Sstevel@tonic-gate /*
67487c478bd9Sstevel@tonic-gate ** WRITE_KEY_FILE -- record some key into a file.
67497c478bd9Sstevel@tonic-gate **
67507c478bd9Sstevel@tonic-gate ** Parameters:
67517c478bd9Sstevel@tonic-gate ** keypath -- file name.
67527c478bd9Sstevel@tonic-gate ** key -- key to write.
67537c478bd9Sstevel@tonic-gate **
67547c478bd9Sstevel@tonic-gate ** Returns:
67557c478bd9Sstevel@tonic-gate ** true iff file could be written.
67567c478bd9Sstevel@tonic-gate **
67577c478bd9Sstevel@tonic-gate ** Side Effects:
67587c478bd9Sstevel@tonic-gate ** writes file.
67597c478bd9Sstevel@tonic-gate */
67607c478bd9Sstevel@tonic-gate
67617c478bd9Sstevel@tonic-gate static bool
write_key_file(keypath,key)67627c478bd9Sstevel@tonic-gate write_key_file(keypath, key)
67637c478bd9Sstevel@tonic-gate char *keypath;
67647c478bd9Sstevel@tonic-gate long key;
67657c478bd9Sstevel@tonic-gate {
67667c478bd9Sstevel@tonic-gate bool ok;
67677c478bd9Sstevel@tonic-gate long sff;
67687c478bd9Sstevel@tonic-gate SM_FILE_T *keyf;
67697c478bd9Sstevel@tonic-gate
67707c478bd9Sstevel@tonic-gate ok = false;
67717c478bd9Sstevel@tonic-gate if (keypath == NULL || *keypath == '\0')
67727c478bd9Sstevel@tonic-gate return ok;
67737c478bd9Sstevel@tonic-gate sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT;
67747c478bd9Sstevel@tonic-gate if (TrustedUid != 0 && RealUid == TrustedUid)
67757c478bd9Sstevel@tonic-gate sff |= SFF_OPENASROOT;
67767c478bd9Sstevel@tonic-gate keyf = safefopen(keypath, O_WRONLY|O_TRUNC, FileMode, sff);
67777c478bd9Sstevel@tonic-gate if (keyf == NULL)
67787c478bd9Sstevel@tonic-gate {
67797c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, "unable to write %s: %s",
67807c478bd9Sstevel@tonic-gate keypath, sm_errstring(errno));
67817c478bd9Sstevel@tonic-gate }
67827c478bd9Sstevel@tonic-gate else
67837c478bd9Sstevel@tonic-gate {
678449218d4fSjbeck if (geteuid() == 0 && RunAsUid != 0)
678549218d4fSjbeck {
678649218d4fSjbeck # if HASFCHOWN
678749218d4fSjbeck int fd;
678849218d4fSjbeck
678949218d4fSjbeck fd = keyf->f_file;
679049218d4fSjbeck if (fd >= 0 && fchown(fd, RunAsUid, -1) < 0)
679149218d4fSjbeck {
679249218d4fSjbeck int err = errno;
679349218d4fSjbeck
679449218d4fSjbeck sm_syslog(LOG_ALERT, NOQID,
679549218d4fSjbeck "ownership change on %s to %d failed: %s",
679649218d4fSjbeck keypath, RunAsUid, sm_errstring(err));
679749218d4fSjbeck }
679849218d4fSjbeck # endif /* HASFCHOWN */
679949218d4fSjbeck }
68007c478bd9Sstevel@tonic-gate ok = sm_io_fprintf(keyf, SM_TIME_DEFAULT, "%ld\n", key) !=
68017c478bd9Sstevel@tonic-gate SM_IO_EOF;
68027c478bd9Sstevel@tonic-gate ok = (sm_io_close(keyf, SM_TIME_DEFAULT) != SM_IO_EOF) && ok;
68037c478bd9Sstevel@tonic-gate }
68047c478bd9Sstevel@tonic-gate return ok;
68057c478bd9Sstevel@tonic-gate }
68067c478bd9Sstevel@tonic-gate
68077c478bd9Sstevel@tonic-gate /*
68087c478bd9Sstevel@tonic-gate ** READ_KEY_FILE -- read a key from a file.
68097c478bd9Sstevel@tonic-gate **
68107c478bd9Sstevel@tonic-gate ** Parameters:
68117c478bd9Sstevel@tonic-gate ** keypath -- file name.
68127c478bd9Sstevel@tonic-gate ** key -- default key.
68137c478bd9Sstevel@tonic-gate **
68147c478bd9Sstevel@tonic-gate ** Returns:
68157c478bd9Sstevel@tonic-gate ** key.
68167c478bd9Sstevel@tonic-gate */
68177c478bd9Sstevel@tonic-gate
68187c478bd9Sstevel@tonic-gate static long
read_key_file(keypath,key)68197c478bd9Sstevel@tonic-gate read_key_file(keypath, key)
68207c478bd9Sstevel@tonic-gate char *keypath;
68217c478bd9Sstevel@tonic-gate long key;
68227c478bd9Sstevel@tonic-gate {
68237c478bd9Sstevel@tonic-gate int r;
68247c478bd9Sstevel@tonic-gate long sff, n;
68257c478bd9Sstevel@tonic-gate SM_FILE_T *keyf;
68267c478bd9Sstevel@tonic-gate
68277c478bd9Sstevel@tonic-gate if (keypath == NULL || *keypath == '\0')
68287c478bd9Sstevel@tonic-gate return key;
68297c478bd9Sstevel@tonic-gate sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY;
68307c478bd9Sstevel@tonic-gate if (RealUid == 0 || (TrustedUid != 0 && RealUid == TrustedUid))
68317c478bd9Sstevel@tonic-gate sff |= SFF_OPENASROOT;
68327c478bd9Sstevel@tonic-gate keyf = safefopen(keypath, O_RDONLY, FileMode, sff);
68337c478bd9Sstevel@tonic-gate if (keyf == NULL)
68347c478bd9Sstevel@tonic-gate {
68357c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, "unable to read %s: %s",
68367c478bd9Sstevel@tonic-gate keypath, sm_errstring(errno));
68377c478bd9Sstevel@tonic-gate }
68387c478bd9Sstevel@tonic-gate else
68397c478bd9Sstevel@tonic-gate {
68407c478bd9Sstevel@tonic-gate r = sm_io_fscanf(keyf, SM_TIME_DEFAULT, "%ld", &n);
68417c478bd9Sstevel@tonic-gate if (r == 1)
68427c478bd9Sstevel@tonic-gate key = n;
68437c478bd9Sstevel@tonic-gate (void) sm_io_close(keyf, SM_TIME_DEFAULT);
68447c478bd9Sstevel@tonic-gate }
68457c478bd9Sstevel@tonic-gate return key;
68467c478bd9Sstevel@tonic-gate }
68477c478bd9Sstevel@tonic-gate
68487c478bd9Sstevel@tonic-gate /*
68497c478bd9Sstevel@tonic-gate ** INIT_SHM -- initialize shared memory structure
68507c478bd9Sstevel@tonic-gate **
68517c478bd9Sstevel@tonic-gate ** Initialize or attach to shared memory segment.
68527c478bd9Sstevel@tonic-gate ** Currently it is not a fatal error if this doesn't work.
68537c478bd9Sstevel@tonic-gate ** However, it causes us to have a "fallback" storage location
68547c478bd9Sstevel@tonic-gate ** for everything that is supposed to be in the shared memory,
68557c478bd9Sstevel@tonic-gate ** which makes the code slightly ugly.
68567c478bd9Sstevel@tonic-gate **
68577c478bd9Sstevel@tonic-gate ** Parameters:
68587c478bd9Sstevel@tonic-gate ** qn -- number of queue directories.
68597c478bd9Sstevel@tonic-gate ** owner -- owner of shared memory.
68607c478bd9Sstevel@tonic-gate ** hash -- identifies data that is stored in shared memory.
68617c478bd9Sstevel@tonic-gate **
68627c478bd9Sstevel@tonic-gate ** Returns:
68637c478bd9Sstevel@tonic-gate ** none.
68647c478bd9Sstevel@tonic-gate */
68657c478bd9Sstevel@tonic-gate
68667c478bd9Sstevel@tonic-gate static void init_shm __P((int, bool, unsigned int));
68677c478bd9Sstevel@tonic-gate
68687c478bd9Sstevel@tonic-gate static void
init_shm(qn,owner,hash)68697c478bd9Sstevel@tonic-gate init_shm(qn, owner, hash)
68707c478bd9Sstevel@tonic-gate int qn;
68717c478bd9Sstevel@tonic-gate bool owner;
68727c478bd9Sstevel@tonic-gate unsigned int hash;
68737c478bd9Sstevel@tonic-gate {
68747c478bd9Sstevel@tonic-gate int i;
68757c478bd9Sstevel@tonic-gate int count;
68767c478bd9Sstevel@tonic-gate int save_errno;
68777c478bd9Sstevel@tonic-gate bool keyselect;
68787c478bd9Sstevel@tonic-gate
68797c478bd9Sstevel@tonic-gate PtrFileSys = &FileSys[0];
68807c478bd9Sstevel@tonic-gate PNumFileSys = &Numfilesys;
68817c478bd9Sstevel@tonic-gate /* if this "key" is specified: select one yourself */
68827c478bd9Sstevel@tonic-gate #define SEL_SHM_KEY ((key_t) -1)
68837c478bd9Sstevel@tonic-gate #define FIRST_SHM_KEY 25
68847c478bd9Sstevel@tonic-gate
68857c478bd9Sstevel@tonic-gate /* This allows us to disable shared memory at runtime. */
68867c478bd9Sstevel@tonic-gate if (ShmKey == 0)
68877c478bd9Sstevel@tonic-gate return;
68887c478bd9Sstevel@tonic-gate
68897c478bd9Sstevel@tonic-gate count = 0;
68907c478bd9Sstevel@tonic-gate shms = SM_T_SIZE + qn * sizeof(QUEUE_SHM_T);
68917c478bd9Sstevel@tonic-gate keyselect = ShmKey == SEL_SHM_KEY;
68927c478bd9Sstevel@tonic-gate if (keyselect)
68937c478bd9Sstevel@tonic-gate {
68947c478bd9Sstevel@tonic-gate if (owner)
68957c478bd9Sstevel@tonic-gate ShmKey = FIRST_SHM_KEY;
68967c478bd9Sstevel@tonic-gate else
68977c478bd9Sstevel@tonic-gate {
6898058561cbSjbeck errno = 0;
68997c478bd9Sstevel@tonic-gate ShmKey = read_key_file(ShmKeyFile, ShmKey);
69007c478bd9Sstevel@tonic-gate keyselect = false;
69017c478bd9Sstevel@tonic-gate if (ShmKey == SEL_SHM_KEY)
6902058561cbSjbeck {
6903058561cbSjbeck save_errno = (errno != 0) ? errno : EINVAL;
69047c478bd9Sstevel@tonic-gate goto error;
69057c478bd9Sstevel@tonic-gate }
69067c478bd9Sstevel@tonic-gate }
6907058561cbSjbeck }
69087c478bd9Sstevel@tonic-gate for (;;)
69097c478bd9Sstevel@tonic-gate {
69107c478bd9Sstevel@tonic-gate /* allow read/write access for group? */
69117c478bd9Sstevel@tonic-gate Pshm = sm_shmstart(ShmKey, shms,
69127c478bd9Sstevel@tonic-gate SHM_R|SHM_W|(SHM_R>>3)|(SHM_W>>3),
69137c478bd9Sstevel@tonic-gate &ShmId, owner);
69147c478bd9Sstevel@tonic-gate save_errno = errno;
69157c478bd9Sstevel@tonic-gate if (Pshm != NULL || !sm_file_exists(save_errno))
69167c478bd9Sstevel@tonic-gate break;
69177c478bd9Sstevel@tonic-gate if (++count >= 3)
69187c478bd9Sstevel@tonic-gate {
69197c478bd9Sstevel@tonic-gate if (keyselect)
69207c478bd9Sstevel@tonic-gate {
69217c478bd9Sstevel@tonic-gate ++ShmKey;
69227c478bd9Sstevel@tonic-gate
69237c478bd9Sstevel@tonic-gate /* back where we started? */
69247c478bd9Sstevel@tonic-gate if (ShmKey == SEL_SHM_KEY)
69257c478bd9Sstevel@tonic-gate break;
69267c478bd9Sstevel@tonic-gate continue;
69277c478bd9Sstevel@tonic-gate }
69287c478bd9Sstevel@tonic-gate break;
69297c478bd9Sstevel@tonic-gate }
6930058561cbSjbeck
69317c478bd9Sstevel@tonic-gate /* only sleep if we are at the first key */
69327c478bd9Sstevel@tonic-gate if (!keyselect || ShmKey == SEL_SHM_KEY)
69337c478bd9Sstevel@tonic-gate sleep(count);
69347c478bd9Sstevel@tonic-gate }
69357c478bd9Sstevel@tonic-gate if (Pshm != NULL)
69367c478bd9Sstevel@tonic-gate {
69377c478bd9Sstevel@tonic-gate int *p;
69387c478bd9Sstevel@tonic-gate
69397c478bd9Sstevel@tonic-gate if (keyselect)
69407c478bd9Sstevel@tonic-gate (void) write_key_file(ShmKeyFile, (long) ShmKey);
69417c478bd9Sstevel@tonic-gate if (owner && RunAsUid != 0)
69427c478bd9Sstevel@tonic-gate {
6943445f2479Sjbeck i = sm_shmsetowner(ShmId, RunAsUid, RunAsGid, 0660);
69447c478bd9Sstevel@tonic-gate if (i != 0)
69457c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID,
69467c478bd9Sstevel@tonic-gate "key=%ld, sm_shmsetowner=%d, RunAsUid=%d, RunAsGid=%d",
6947445f2479Sjbeck (long) ShmKey, i, RunAsUid, RunAsGid);
69487c478bd9Sstevel@tonic-gate }
69497c478bd9Sstevel@tonic-gate p = (int *) Pshm;
69507c478bd9Sstevel@tonic-gate if (owner)
69517c478bd9Sstevel@tonic-gate {
69527c478bd9Sstevel@tonic-gate *p = (int) shms;
69537c478bd9Sstevel@tonic-gate *((pid_t *) SHM_OFF_PID(Pshm)) = CurrentPid;
69547c478bd9Sstevel@tonic-gate p = (int *) SHM_OFF_TAG(Pshm);
69557c478bd9Sstevel@tonic-gate *p = hash;
69567c478bd9Sstevel@tonic-gate }
69577c478bd9Sstevel@tonic-gate else
69587c478bd9Sstevel@tonic-gate {
69597c478bd9Sstevel@tonic-gate if (*p != (int) shms)
69607c478bd9Sstevel@tonic-gate {
69617c478bd9Sstevel@tonic-gate save_errno = EINVAL;
69627c478bd9Sstevel@tonic-gate cleanup_shm(false);
69637c478bd9Sstevel@tonic-gate goto error;
69647c478bd9Sstevel@tonic-gate }
69657c478bd9Sstevel@tonic-gate p = (int *) SHM_OFF_TAG(Pshm);
69667c478bd9Sstevel@tonic-gate if (*p != (int) hash)
69677c478bd9Sstevel@tonic-gate {
69687c478bd9Sstevel@tonic-gate save_errno = EINVAL;
69697c478bd9Sstevel@tonic-gate cleanup_shm(false);
69707c478bd9Sstevel@tonic-gate goto error;
69717c478bd9Sstevel@tonic-gate }
69727c478bd9Sstevel@tonic-gate
69737c478bd9Sstevel@tonic-gate /*
69747c478bd9Sstevel@tonic-gate ** XXX how to check the pid?
69757c478bd9Sstevel@tonic-gate ** Read it from the pid-file? That does
69767c478bd9Sstevel@tonic-gate ** not need to exist.
69777c478bd9Sstevel@tonic-gate ** We could disable shm if we can't confirm
69787c478bd9Sstevel@tonic-gate ** that it is the right one.
69797c478bd9Sstevel@tonic-gate */
69807c478bd9Sstevel@tonic-gate }
69817c478bd9Sstevel@tonic-gate
69827c478bd9Sstevel@tonic-gate PtrFileSys = (FILESYS *) OFF_FILE_SYS(Pshm);
69837c478bd9Sstevel@tonic-gate PNumFileSys = (int *) OFF_NUM_FILE_SYS(Pshm);
69847c478bd9Sstevel@tonic-gate QShm = (QUEUE_SHM_T *) OFF_QUEUE_SHM(Pshm);
69857c478bd9Sstevel@tonic-gate PRSATmpCnt = (int *) OFF_RSA_TMP_CNT(Pshm);
69867c478bd9Sstevel@tonic-gate *PRSATmpCnt = 0;
69877c478bd9Sstevel@tonic-gate if (owner)
69887c478bd9Sstevel@tonic-gate {
69897c478bd9Sstevel@tonic-gate /* initialize values in shared memory */
69907c478bd9Sstevel@tonic-gate NumFileSys = 0;
69917c478bd9Sstevel@tonic-gate for (i = 0; i < qn; i++)
69927c478bd9Sstevel@tonic-gate QShm[i].qs_entries = -1;
69937c478bd9Sstevel@tonic-gate }
69947c478bd9Sstevel@tonic-gate init_sem(owner);
69957c478bd9Sstevel@tonic-gate return;
69967c478bd9Sstevel@tonic-gate }
69977c478bd9Sstevel@tonic-gate error:
69987c478bd9Sstevel@tonic-gate if (LogLevel > (owner ? 8 : 11))
69997c478bd9Sstevel@tonic-gate {
70007c478bd9Sstevel@tonic-gate sm_syslog(owner ? LOG_ERR : LOG_NOTICE, NOQID,
70017c478bd9Sstevel@tonic-gate "can't %s shared memory, key=%ld: %s",
70027c478bd9Sstevel@tonic-gate owner ? "initialize" : "attach to",
70037c478bd9Sstevel@tonic-gate (long) ShmKey, sm_errstring(save_errno));
70047c478bd9Sstevel@tonic-gate }
70057c478bd9Sstevel@tonic-gate }
70067c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */
70077c478bd9Sstevel@tonic-gate
70087c478bd9Sstevel@tonic-gate
70097c478bd9Sstevel@tonic-gate /*
70107c478bd9Sstevel@tonic-gate ** SETUP_QUEUES -- set up all queue groups
70117c478bd9Sstevel@tonic-gate **
70127c478bd9Sstevel@tonic-gate ** Parameters:
7013058561cbSjbeck ** owner -- owner of shared memory?
70147c478bd9Sstevel@tonic-gate **
70157c478bd9Sstevel@tonic-gate ** Returns:
70167c478bd9Sstevel@tonic-gate ** none.
70177c478bd9Sstevel@tonic-gate **
70187c478bd9Sstevel@tonic-gate #if SM_CONF_SHM
70197c478bd9Sstevel@tonic-gate ** Side Effects:
70207c478bd9Sstevel@tonic-gate ** attaches shared memory.
70217c478bd9Sstevel@tonic-gate #endif * SM_CONF_SHM *
70227c478bd9Sstevel@tonic-gate */
70237c478bd9Sstevel@tonic-gate
70247c478bd9Sstevel@tonic-gate void
setup_queues(owner)70257c478bd9Sstevel@tonic-gate setup_queues(owner)
70267c478bd9Sstevel@tonic-gate bool owner;
70277c478bd9Sstevel@tonic-gate {
70287c478bd9Sstevel@tonic-gate int i, qn, len;
70297c478bd9Sstevel@tonic-gate unsigned int hashval;
70307c478bd9Sstevel@tonic-gate time_t now;
70317c478bd9Sstevel@tonic-gate char basedir[MAXPATHLEN];
70327c478bd9Sstevel@tonic-gate struct stat st;
70337c478bd9Sstevel@tonic-gate
70347c478bd9Sstevel@tonic-gate /*
70357c478bd9Sstevel@tonic-gate ** Determine basedir for all queue directories.
70367c478bd9Sstevel@tonic-gate ** All queue directories must be (first level) subdirectories
70377c478bd9Sstevel@tonic-gate ** of the basedir. The basedir is the QueueDir
70387c478bd9Sstevel@tonic-gate ** without wildcards, but with trailing /
70397c478bd9Sstevel@tonic-gate */
70407c478bd9Sstevel@tonic-gate
70417c478bd9Sstevel@tonic-gate hashval = 0;
70427c478bd9Sstevel@tonic-gate errno = 0;
7043058561cbSjbeck len = sm_strlcpy(basedir, QueueDir, sizeof(basedir));
70447c478bd9Sstevel@tonic-gate
70457c478bd9Sstevel@tonic-gate /* Provide space for trailing '/' */
7046058561cbSjbeck if (len >= sizeof(basedir) - 1)
70477c478bd9Sstevel@tonic-gate {
70487c478bd9Sstevel@tonic-gate syserr("QueueDirectory: path too long: %d, max %d",
7049058561cbSjbeck len, (int) sizeof(basedir) - 1);
70507c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG;
70517c478bd9Sstevel@tonic-gate return;
70527c478bd9Sstevel@tonic-gate }
70537c478bd9Sstevel@tonic-gate SM_ASSERT(len > 0);
70547c478bd9Sstevel@tonic-gate if (basedir[len - 1] == '*')
70557c478bd9Sstevel@tonic-gate {
70567c478bd9Sstevel@tonic-gate char *cp;
70577c478bd9Sstevel@tonic-gate
70587c478bd9Sstevel@tonic-gate cp = SM_LAST_DIR_DELIM(basedir);
70597c478bd9Sstevel@tonic-gate if (cp == NULL)
70607c478bd9Sstevel@tonic-gate {
70617c478bd9Sstevel@tonic-gate syserr("QueueDirectory: can not wildcard relative path \"%s\"",
70627c478bd9Sstevel@tonic-gate QueueDir);
70637c478bd9Sstevel@tonic-gate if (tTd(41, 2))
70647c478bd9Sstevel@tonic-gate sm_dprintf("setup_queues: \"%s\": Can not wildcard relative path.\n",
70657c478bd9Sstevel@tonic-gate QueueDir);
70667c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG;
70677c478bd9Sstevel@tonic-gate return;
70687c478bd9Sstevel@tonic-gate }
70697c478bd9Sstevel@tonic-gate
70707c478bd9Sstevel@tonic-gate /* cut off wildcard pattern */
70717c478bd9Sstevel@tonic-gate *++cp = '\0';
70727c478bd9Sstevel@tonic-gate len = cp - basedir;
70737c478bd9Sstevel@tonic-gate }
70747c478bd9Sstevel@tonic-gate else if (!SM_IS_DIR_DELIM(basedir[len - 1]))
70757c478bd9Sstevel@tonic-gate {
70767c478bd9Sstevel@tonic-gate /* append trailing slash since it is a directory */
70777c478bd9Sstevel@tonic-gate basedir[len] = '/';
70787c478bd9Sstevel@tonic-gate basedir[++len] = '\0';
70797c478bd9Sstevel@tonic-gate }
70807c478bd9Sstevel@tonic-gate
70817c478bd9Sstevel@tonic-gate /* len counts up to the last directory delimiter */
70827c478bd9Sstevel@tonic-gate SM_ASSERT(basedir[len - 1] == '/');
70837c478bd9Sstevel@tonic-gate
70847c478bd9Sstevel@tonic-gate if (chdir(basedir) < 0)
70857c478bd9Sstevel@tonic-gate {
70867c478bd9Sstevel@tonic-gate int save_errno = errno;
70877c478bd9Sstevel@tonic-gate
70887c478bd9Sstevel@tonic-gate syserr("can not chdir(%s)", basedir);
70897c478bd9Sstevel@tonic-gate if (save_errno == EACCES)
70907c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
70917c478bd9Sstevel@tonic-gate "Program mode requires special privileges, e.g., root or TrustedUser.\n");
70927c478bd9Sstevel@tonic-gate if (tTd(41, 2))
70937c478bd9Sstevel@tonic-gate sm_dprintf("setup_queues: \"%s\": %s\n",
70947c478bd9Sstevel@tonic-gate basedir, sm_errstring(errno));
70957c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG;
70967c478bd9Sstevel@tonic-gate return;
70977c478bd9Sstevel@tonic-gate }
70987c478bd9Sstevel@tonic-gate #if SM_CONF_SHM
70997c478bd9Sstevel@tonic-gate hashval = hash_q(basedir, hashval);
71007c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */
71017c478bd9Sstevel@tonic-gate
71027c478bd9Sstevel@tonic-gate /* initialize for queue runs */
71037c478bd9Sstevel@tonic-gate DoQueueRun = false;
71047c478bd9Sstevel@tonic-gate now = curtime();
71057c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
71067c478bd9Sstevel@tonic-gate Queue[i]->qg_nextrun = now;
71077c478bd9Sstevel@tonic-gate
71087c478bd9Sstevel@tonic-gate
71097c478bd9Sstevel@tonic-gate if (UseMSP && OpMode != MD_TEST)
71107c478bd9Sstevel@tonic-gate {
71117c478bd9Sstevel@tonic-gate long sff = SFF_CREAT;
71127c478bd9Sstevel@tonic-gate
71137c478bd9Sstevel@tonic-gate if (stat(".", &st) < 0)
71147c478bd9Sstevel@tonic-gate {
71157c478bd9Sstevel@tonic-gate syserr("can not stat(%s)", basedir);
71167c478bd9Sstevel@tonic-gate if (tTd(41, 2))
71177c478bd9Sstevel@tonic-gate sm_dprintf("setup_queues: \"%s\": %s\n",
71187c478bd9Sstevel@tonic-gate basedir, sm_errstring(errno));
71197c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG;
71207c478bd9Sstevel@tonic-gate return;
71217c478bd9Sstevel@tonic-gate }
71227c478bd9Sstevel@tonic-gate if (RunAsUid == 0)
71237c478bd9Sstevel@tonic-gate sff |= SFF_ROOTOK;
71247c478bd9Sstevel@tonic-gate
71257c478bd9Sstevel@tonic-gate /*
71267c478bd9Sstevel@tonic-gate ** Check queue directory permissions.
71277c478bd9Sstevel@tonic-gate ** Can we write to a group writable queue directory?
71287c478bd9Sstevel@tonic-gate */
71297c478bd9Sstevel@tonic-gate
71307c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode) &&
71317c478bd9Sstevel@tonic-gate bitset(S_IWGRP, st.st_mode) &&
71327c478bd9Sstevel@tonic-gate safefile(" ", RunAsUid, RunAsGid, RunAsUserName, sff,
71337c478bd9Sstevel@tonic-gate QueueFileMode, NULL) != 0)
71347c478bd9Sstevel@tonic-gate {
71357c478bd9Sstevel@tonic-gate syserr("can not write to queue directory %s (RunAsGid=%d, required=%d)",
71367c478bd9Sstevel@tonic-gate basedir, (int) RunAsGid, (int) st.st_gid);
71377c478bd9Sstevel@tonic-gate }
71387c478bd9Sstevel@tonic-gate if (bitset(S_IWOTH|S_IXOTH, st.st_mode))
71397c478bd9Sstevel@tonic-gate {
71407c478bd9Sstevel@tonic-gate #if _FFR_MSP_PARANOIA
71417c478bd9Sstevel@tonic-gate syserr("dangerous permissions=%o on queue directory %s",
71427c478bd9Sstevel@tonic-gate (int) st.st_mode, basedir);
71437c478bd9Sstevel@tonic-gate #else /* _FFR_MSP_PARANOIA */
71447c478bd9Sstevel@tonic-gate if (LogLevel > 0)
71457c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID,
71467c478bd9Sstevel@tonic-gate "dangerous permissions=%o on queue directory %s",
71477c478bd9Sstevel@tonic-gate (int) st.st_mode, basedir);
71487c478bd9Sstevel@tonic-gate #endif /* _FFR_MSP_PARANOIA */
71497c478bd9Sstevel@tonic-gate }
71507c478bd9Sstevel@tonic-gate #if _FFR_MSP_PARANOIA
71517c478bd9Sstevel@tonic-gate if (NumQueue > 1)
71527c478bd9Sstevel@tonic-gate syserr("can not use multiple queues for MSP");
71537c478bd9Sstevel@tonic-gate #endif /* _FFR_MSP_PARANOIA */
71547c478bd9Sstevel@tonic-gate }
71557c478bd9Sstevel@tonic-gate
71567c478bd9Sstevel@tonic-gate /* initial number of queue directories */
71577c478bd9Sstevel@tonic-gate qn = 0;
71587c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
71597c478bd9Sstevel@tonic-gate qn = multiqueue_cache(basedir, len, Queue[i], qn, &hashval);
71607c478bd9Sstevel@tonic-gate
71617c478bd9Sstevel@tonic-gate #if SM_CONF_SHM
71627c478bd9Sstevel@tonic-gate init_shm(qn, owner, hashval);
71637c478bd9Sstevel@tonic-gate i = filesys_setup(owner || ShmId == SM_SHM_NO_ID);
71647c478bd9Sstevel@tonic-gate if (i == FSF_NOT_FOUND)
71657c478bd9Sstevel@tonic-gate {
71667c478bd9Sstevel@tonic-gate /*
71677c478bd9Sstevel@tonic-gate ** We didn't get the right filesystem data
71687c478bd9Sstevel@tonic-gate ** This may happen if we don't have the right shared memory.
71697c478bd9Sstevel@tonic-gate ** So let's do this without shared memory.
71707c478bd9Sstevel@tonic-gate */
71717c478bd9Sstevel@tonic-gate
71727c478bd9Sstevel@tonic-gate SM_ASSERT(!owner);
71737c478bd9Sstevel@tonic-gate cleanup_shm(false); /* release shared memory */
71747c478bd9Sstevel@tonic-gate i = filesys_setup(false);
71757c478bd9Sstevel@tonic-gate if (i < 0)
71767c478bd9Sstevel@tonic-gate syserr("filesys_setup failed twice, result=%d", i);
71777c478bd9Sstevel@tonic-gate else if (LogLevel > 8)
71787c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID,
71797c478bd9Sstevel@tonic-gate "shared memory does not contain expected data, ignored");
71807c478bd9Sstevel@tonic-gate }
71817c478bd9Sstevel@tonic-gate #else /* SM_CONF_SHM */
71827c478bd9Sstevel@tonic-gate i = filesys_setup(true);
71837c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */
71847c478bd9Sstevel@tonic-gate if (i < 0)
71857c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG;
71867c478bd9Sstevel@tonic-gate }
71877c478bd9Sstevel@tonic-gate
71887c478bd9Sstevel@tonic-gate #if SM_CONF_SHM
71897c478bd9Sstevel@tonic-gate /*
71907c478bd9Sstevel@tonic-gate ** CLEANUP_SHM -- do some cleanup work for shared memory etc
71917c478bd9Sstevel@tonic-gate **
71927c478bd9Sstevel@tonic-gate ** Parameters:
71937c478bd9Sstevel@tonic-gate ** owner -- owner of shared memory?
71947c478bd9Sstevel@tonic-gate **
71957c478bd9Sstevel@tonic-gate ** Returns:
71967c478bd9Sstevel@tonic-gate ** none.
71977c478bd9Sstevel@tonic-gate **
71987c478bd9Sstevel@tonic-gate ** Side Effects:
71997c478bd9Sstevel@tonic-gate ** detaches shared memory.
72007c478bd9Sstevel@tonic-gate */
72017c478bd9Sstevel@tonic-gate
72027c478bd9Sstevel@tonic-gate void
cleanup_shm(owner)72037c478bd9Sstevel@tonic-gate cleanup_shm(owner)
72047c478bd9Sstevel@tonic-gate bool owner;
72057c478bd9Sstevel@tonic-gate {
72067c478bd9Sstevel@tonic-gate if (ShmId != SM_SHM_NO_ID)
72077c478bd9Sstevel@tonic-gate {
72087c478bd9Sstevel@tonic-gate if (sm_shmstop(Pshm, ShmId, owner) < 0 && LogLevel > 8)
72097c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "sm_shmstop failed=%s",
72107c478bd9Sstevel@tonic-gate sm_errstring(errno));
72117c478bd9Sstevel@tonic-gate Pshm = NULL;
72127c478bd9Sstevel@tonic-gate ShmId = SM_SHM_NO_ID;
72137c478bd9Sstevel@tonic-gate }
72147c478bd9Sstevel@tonic-gate stop_sem(owner);
72157c478bd9Sstevel@tonic-gate }
72167c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */
72177c478bd9Sstevel@tonic-gate
72187c478bd9Sstevel@tonic-gate /*
72197c478bd9Sstevel@tonic-gate ** CLEANUP_QUEUES -- do some cleanup work for queues
72207c478bd9Sstevel@tonic-gate **
72217c478bd9Sstevel@tonic-gate ** Parameters:
72227c478bd9Sstevel@tonic-gate ** none.
72237c478bd9Sstevel@tonic-gate **
72247c478bd9Sstevel@tonic-gate ** Returns:
72257c478bd9Sstevel@tonic-gate ** none.
72267c478bd9Sstevel@tonic-gate **
72277c478bd9Sstevel@tonic-gate */
72287c478bd9Sstevel@tonic-gate
72297c478bd9Sstevel@tonic-gate void
cleanup_queues()72307c478bd9Sstevel@tonic-gate cleanup_queues()
72317c478bd9Sstevel@tonic-gate {
72327c478bd9Sstevel@tonic-gate sync_queue_time();
72337c478bd9Sstevel@tonic-gate }
72347c478bd9Sstevel@tonic-gate /*
72357c478bd9Sstevel@tonic-gate ** SET_DEF_QUEUEVAL -- set default values for a queue group.
72367c478bd9Sstevel@tonic-gate **
72377c478bd9Sstevel@tonic-gate ** Parameters:
72387c478bd9Sstevel@tonic-gate ** qg -- queue group
72397c478bd9Sstevel@tonic-gate ** all -- set all values (true for default group)?
72407c478bd9Sstevel@tonic-gate **
72417c478bd9Sstevel@tonic-gate ** Returns:
72427c478bd9Sstevel@tonic-gate ** none.
72437c478bd9Sstevel@tonic-gate **
72447c478bd9Sstevel@tonic-gate ** Side Effects:
72457c478bd9Sstevel@tonic-gate ** sets default values for the queue group.
72467c478bd9Sstevel@tonic-gate */
72477c478bd9Sstevel@tonic-gate
72487c478bd9Sstevel@tonic-gate void
set_def_queueval(qg,all)72497c478bd9Sstevel@tonic-gate set_def_queueval(qg, all)
72507c478bd9Sstevel@tonic-gate QUEUEGRP *qg;
72517c478bd9Sstevel@tonic-gate bool all;
72527c478bd9Sstevel@tonic-gate {
72537c478bd9Sstevel@tonic-gate if (bitnset(QD_DEFINED, qg->qg_flags))
72547c478bd9Sstevel@tonic-gate return;
72557c478bd9Sstevel@tonic-gate if (all)
72567c478bd9Sstevel@tonic-gate qg->qg_qdir = QueueDir;
72577c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_GROUP_SORTORDER
72587c478bd9Sstevel@tonic-gate qg->qg_sortorder = QueueSortOrder;
72597c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_GROUP_SORTORDER */
72607c478bd9Sstevel@tonic-gate qg->qg_maxqrun = all ? MaxRunnersPerQueue : -1;
72617c478bd9Sstevel@tonic-gate qg->qg_nice = NiceQueueRun;
72627c478bd9Sstevel@tonic-gate }
72637c478bd9Sstevel@tonic-gate /*
72647c478bd9Sstevel@tonic-gate ** MAKEQUEUE -- define a new queue.
72657c478bd9Sstevel@tonic-gate **
72667c478bd9Sstevel@tonic-gate ** Parameters:
72677c478bd9Sstevel@tonic-gate ** line -- description of queue. This is in labeled fields.
72687c478bd9Sstevel@tonic-gate ** The fields are:
72697c478bd9Sstevel@tonic-gate ** F -- the flags associated with the queue
72707c478bd9Sstevel@tonic-gate ** I -- the interval between running the queue
72717c478bd9Sstevel@tonic-gate ** J -- the maximum # of jobs in work list
72727c478bd9Sstevel@tonic-gate ** [M -- the maximum # of jobs in a queue run]
72737c478bd9Sstevel@tonic-gate ** N -- the niceness at which to run
72747c478bd9Sstevel@tonic-gate ** P -- the path to the queue
72757c478bd9Sstevel@tonic-gate ** S -- the queue sorting order
72767c478bd9Sstevel@tonic-gate ** R -- number of parallel queue runners
72777c478bd9Sstevel@tonic-gate ** r -- max recipients per envelope
72787c478bd9Sstevel@tonic-gate ** The first word is the canonical name of the queue.
72797c478bd9Sstevel@tonic-gate ** qdef -- this is a 'Q' definition from .cf
72807c478bd9Sstevel@tonic-gate **
72817c478bd9Sstevel@tonic-gate ** Returns:
72827c478bd9Sstevel@tonic-gate ** none.
72837c478bd9Sstevel@tonic-gate **
72847c478bd9Sstevel@tonic-gate ** Side Effects:
72857c478bd9Sstevel@tonic-gate ** enters the queue into the queue table.
72867c478bd9Sstevel@tonic-gate */
72877c478bd9Sstevel@tonic-gate
72887c478bd9Sstevel@tonic-gate void
makequeue(line,qdef)72897c478bd9Sstevel@tonic-gate makequeue(line, qdef)
72907c478bd9Sstevel@tonic-gate char *line;
72917c478bd9Sstevel@tonic-gate bool qdef;
72927c478bd9Sstevel@tonic-gate {
72937c478bd9Sstevel@tonic-gate register char *p;
72947c478bd9Sstevel@tonic-gate register QUEUEGRP *qg;
72957c478bd9Sstevel@tonic-gate register STAB *s;
72967c478bd9Sstevel@tonic-gate int i;
72977c478bd9Sstevel@tonic-gate char fcode;
72987c478bd9Sstevel@tonic-gate
72997c478bd9Sstevel@tonic-gate /* allocate a queue and set up defaults */
7300058561cbSjbeck qg = (QUEUEGRP *) xalloc(sizeof(*qg));
7301058561cbSjbeck memset((char *) qg, '\0', sizeof(*qg));
73027c478bd9Sstevel@tonic-gate
73037c478bd9Sstevel@tonic-gate if (line[0] == '\0')
73047c478bd9Sstevel@tonic-gate {
73057c478bd9Sstevel@tonic-gate syserr("name required for queue");
73067c478bd9Sstevel@tonic-gate return;
73077c478bd9Sstevel@tonic-gate }
73087c478bd9Sstevel@tonic-gate
73097c478bd9Sstevel@tonic-gate /* collect the queue name */
73107c478bd9Sstevel@tonic-gate for (p = line;
73117c478bd9Sstevel@tonic-gate *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p));
73127c478bd9Sstevel@tonic-gate p++)
73137c478bd9Sstevel@tonic-gate continue;
73147c478bd9Sstevel@tonic-gate if (*p != '\0')
73157c478bd9Sstevel@tonic-gate *p++ = '\0';
73167c478bd9Sstevel@tonic-gate qg->qg_name = newstr(line);
73177c478bd9Sstevel@tonic-gate
73187c478bd9Sstevel@tonic-gate /* set default values, can be overridden below */
73197c478bd9Sstevel@tonic-gate set_def_queueval(qg, false);
73207c478bd9Sstevel@tonic-gate
73217c478bd9Sstevel@tonic-gate /* now scan through and assign info from the fields */
73227c478bd9Sstevel@tonic-gate while (*p != '\0')
73237c478bd9Sstevel@tonic-gate {
73247c478bd9Sstevel@tonic-gate auto char *delimptr;
73257c478bd9Sstevel@tonic-gate
73267c478bd9Sstevel@tonic-gate while (*p != '\0' &&
73277c478bd9Sstevel@tonic-gate (*p == ',' || (isascii(*p) && isspace(*p))))
73287c478bd9Sstevel@tonic-gate p++;
73297c478bd9Sstevel@tonic-gate
73307c478bd9Sstevel@tonic-gate /* p now points to field code */
73317c478bd9Sstevel@tonic-gate fcode = *p;
73327c478bd9Sstevel@tonic-gate while (*p != '\0' && *p != '=' && *p != ',')
73337c478bd9Sstevel@tonic-gate p++;
73347c478bd9Sstevel@tonic-gate if (*p++ != '=')
73357c478bd9Sstevel@tonic-gate {
73367c478bd9Sstevel@tonic-gate syserr("queue %s: `=' expected", qg->qg_name);
73377c478bd9Sstevel@tonic-gate return;
73387c478bd9Sstevel@tonic-gate }
73397c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p))
73407c478bd9Sstevel@tonic-gate p++;
73417c478bd9Sstevel@tonic-gate
73427c478bd9Sstevel@tonic-gate /* p now points to the field body */
73437c478bd9Sstevel@tonic-gate p = munchstring(p, &delimptr, ',');
73447c478bd9Sstevel@tonic-gate
73457c478bd9Sstevel@tonic-gate /* install the field into the queue struct */
73467c478bd9Sstevel@tonic-gate switch (fcode)
73477c478bd9Sstevel@tonic-gate {
73487c478bd9Sstevel@tonic-gate case 'P': /* pathname */
73497c478bd9Sstevel@tonic-gate if (*p == '\0')
73507c478bd9Sstevel@tonic-gate syserr("queue %s: empty path name",
73517c478bd9Sstevel@tonic-gate qg->qg_name);
73527c478bd9Sstevel@tonic-gate else
73537c478bd9Sstevel@tonic-gate qg->qg_qdir = newstr(p);
73547c478bd9Sstevel@tonic-gate break;
73557c478bd9Sstevel@tonic-gate
73567c478bd9Sstevel@tonic-gate case 'F': /* flags */
73577c478bd9Sstevel@tonic-gate for (; *p != '\0'; p++)
73587c478bd9Sstevel@tonic-gate if (!(isascii(*p) && isspace(*p)))
73597c478bd9Sstevel@tonic-gate setbitn(*p, qg->qg_flags);
73607c478bd9Sstevel@tonic-gate break;
73617c478bd9Sstevel@tonic-gate
73627c478bd9Sstevel@tonic-gate /*
73637c478bd9Sstevel@tonic-gate ** Do we need two intervals here:
73647c478bd9Sstevel@tonic-gate ** One for persistent queue runners,
73657c478bd9Sstevel@tonic-gate ** one for "normal" queue runs?
73667c478bd9Sstevel@tonic-gate */
73677c478bd9Sstevel@tonic-gate
73687c478bd9Sstevel@tonic-gate case 'I': /* interval between running the queue */
73697c478bd9Sstevel@tonic-gate qg->qg_queueintvl = convtime(p, 'm');
73707c478bd9Sstevel@tonic-gate break;
73717c478bd9Sstevel@tonic-gate
73727c478bd9Sstevel@tonic-gate case 'N': /* run niceness */
73737c478bd9Sstevel@tonic-gate qg->qg_nice = atoi(p);
73747c478bd9Sstevel@tonic-gate break;
73757c478bd9Sstevel@tonic-gate
73767c478bd9Sstevel@tonic-gate case 'R': /* maximum # of runners for the group */
73777c478bd9Sstevel@tonic-gate i = atoi(p);
73787c478bd9Sstevel@tonic-gate
73797c478bd9Sstevel@tonic-gate /* can't have more runners than allowed total */
73807c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && i > MaxQueueChildren)
73817c478bd9Sstevel@tonic-gate {
73827c478bd9Sstevel@tonic-gate qg->qg_maxqrun = MaxQueueChildren;
73837c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
73847c478bd9Sstevel@tonic-gate "Q=%s: R=%d exceeds MaxQueueChildren=%d, set to MaxQueueChildren\n",
73857c478bd9Sstevel@tonic-gate qg->qg_name, i,
73867c478bd9Sstevel@tonic-gate MaxQueueChildren);
73877c478bd9Sstevel@tonic-gate }
73887c478bd9Sstevel@tonic-gate else
73897c478bd9Sstevel@tonic-gate qg->qg_maxqrun = i;
73907c478bd9Sstevel@tonic-gate break;
73917c478bd9Sstevel@tonic-gate
73927c478bd9Sstevel@tonic-gate case 'J': /* maximum # of jobs in work list */
73937c478bd9Sstevel@tonic-gate qg->qg_maxlist = atoi(p);
73947c478bd9Sstevel@tonic-gate break;
73957c478bd9Sstevel@tonic-gate
73967c478bd9Sstevel@tonic-gate case 'r': /* max recipients per envelope */
73977c478bd9Sstevel@tonic-gate qg->qg_maxrcpt = atoi(p);
73987c478bd9Sstevel@tonic-gate break;
73997c478bd9Sstevel@tonic-gate
74007c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_GROUP_SORTORDER
74017c478bd9Sstevel@tonic-gate case 'S': /* queue sorting order */
74027c478bd9Sstevel@tonic-gate switch (*p)
74037c478bd9Sstevel@tonic-gate {
74047c478bd9Sstevel@tonic-gate case 'h': /* Host first */
74057c478bd9Sstevel@tonic-gate case 'H':
74067c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYHOST;
74077c478bd9Sstevel@tonic-gate break;
74087c478bd9Sstevel@tonic-gate
74097c478bd9Sstevel@tonic-gate case 'p': /* Priority order */
74107c478bd9Sstevel@tonic-gate case 'P':
74117c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYPRIORITY;
74127c478bd9Sstevel@tonic-gate break;
74137c478bd9Sstevel@tonic-gate
74147c478bd9Sstevel@tonic-gate case 't': /* Submission time */
74157c478bd9Sstevel@tonic-gate case 'T':
74167c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYTIME;
74177c478bd9Sstevel@tonic-gate break;
74187c478bd9Sstevel@tonic-gate
74197c478bd9Sstevel@tonic-gate case 'f': /* File name */
74207c478bd9Sstevel@tonic-gate case 'F':
74217c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYFILENAME;
74227c478bd9Sstevel@tonic-gate break;
74237c478bd9Sstevel@tonic-gate
74247c478bd9Sstevel@tonic-gate case 'm': /* Modification time */
74257c478bd9Sstevel@tonic-gate case 'M':
74267c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYMODTIME;
74277c478bd9Sstevel@tonic-gate break;
74287c478bd9Sstevel@tonic-gate
74297c478bd9Sstevel@tonic-gate case 'r': /* Random */
74307c478bd9Sstevel@tonic-gate case 'R':
74317c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_RANDOM;
74327c478bd9Sstevel@tonic-gate break;
74337c478bd9Sstevel@tonic-gate
74347c478bd9Sstevel@tonic-gate # if _FFR_RHS
74357c478bd9Sstevel@tonic-gate case 's': /* Shuffled host name */
74367c478bd9Sstevel@tonic-gate case 'S':
74377c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYSHUFFLE;
74387c478bd9Sstevel@tonic-gate break;
74397c478bd9Sstevel@tonic-gate # endif /* _FFR_RHS */
74407c478bd9Sstevel@tonic-gate
74417c478bd9Sstevel@tonic-gate case 'n': /* none */
74427c478bd9Sstevel@tonic-gate case 'N':
74437c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_NONE;
74447c478bd9Sstevel@tonic-gate break;
74457c478bd9Sstevel@tonic-gate
74467c478bd9Sstevel@tonic-gate default:
74477c478bd9Sstevel@tonic-gate syserr("Invalid queue sort order \"%s\"", p);
74487c478bd9Sstevel@tonic-gate }
74497c478bd9Sstevel@tonic-gate break;
74507c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_GROUP_SORTORDER */
74517c478bd9Sstevel@tonic-gate
74527c478bd9Sstevel@tonic-gate default:
74537c478bd9Sstevel@tonic-gate syserr("Q%s: unknown queue equate %c=",
74547c478bd9Sstevel@tonic-gate qg->qg_name, fcode);
74557c478bd9Sstevel@tonic-gate break;
74567c478bd9Sstevel@tonic-gate }
74577c478bd9Sstevel@tonic-gate
74587c478bd9Sstevel@tonic-gate p = delimptr;
74597c478bd9Sstevel@tonic-gate }
74607c478bd9Sstevel@tonic-gate
74617c478bd9Sstevel@tonic-gate #if !HASNICE
74627c478bd9Sstevel@tonic-gate if (qg->qg_nice != NiceQueueRun)
74637c478bd9Sstevel@tonic-gate {
74647c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
74657c478bd9Sstevel@tonic-gate "Q%s: Warning: N= set on system that doesn't support nice()\n",
74667c478bd9Sstevel@tonic-gate qg->qg_name);
74677c478bd9Sstevel@tonic-gate }
74687c478bd9Sstevel@tonic-gate #endif /* !HASNICE */
74697c478bd9Sstevel@tonic-gate
74707c478bd9Sstevel@tonic-gate /* do some rationality checking */
74717c478bd9Sstevel@tonic-gate if (NumQueue >= MAXQUEUEGROUPS)
74727c478bd9Sstevel@tonic-gate {
74737c478bd9Sstevel@tonic-gate syserr("too many queue groups defined (%d max)",
74747c478bd9Sstevel@tonic-gate MAXQUEUEGROUPS);
74757c478bd9Sstevel@tonic-gate return;
74767c478bd9Sstevel@tonic-gate }
74777c478bd9Sstevel@tonic-gate
74787c478bd9Sstevel@tonic-gate if (qg->qg_qdir == NULL)
74797c478bd9Sstevel@tonic-gate {
74807c478bd9Sstevel@tonic-gate if (QueueDir == NULL || *QueueDir == '\0')
74817c478bd9Sstevel@tonic-gate {
74827c478bd9Sstevel@tonic-gate syserr("QueueDir must be defined before queue groups");
74837c478bd9Sstevel@tonic-gate return;
74847c478bd9Sstevel@tonic-gate }
74857c478bd9Sstevel@tonic-gate qg->qg_qdir = newstr(QueueDir);
74867c478bd9Sstevel@tonic-gate }
74877c478bd9Sstevel@tonic-gate
74887c478bd9Sstevel@tonic-gate if (qg->qg_maxqrun > 1 && !bitnset(QD_FORK, qg->qg_flags))
74897c478bd9Sstevel@tonic-gate {
74907c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
74917c478bd9Sstevel@tonic-gate "Warning: Q=%s: R=%d: multiple queue runners specified\n\tbut flag '%c' is not set\n",
74927c478bd9Sstevel@tonic-gate qg->qg_name, qg->qg_maxqrun, QD_FORK);
74937c478bd9Sstevel@tonic-gate }
74947c478bd9Sstevel@tonic-gate
74957c478bd9Sstevel@tonic-gate /* enter the queue into the symbol table */
74967c478bd9Sstevel@tonic-gate if (tTd(37, 8))
74977c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
74987c478bd9Sstevel@tonic-gate "Adding %s to stab, path: %s", qg->qg_name,
74997c478bd9Sstevel@tonic-gate qg->qg_qdir);
75007c478bd9Sstevel@tonic-gate s = stab(qg->qg_name, ST_QUEUE, ST_ENTER);
75017c478bd9Sstevel@tonic-gate if (s->s_quegrp != NULL)
75027c478bd9Sstevel@tonic-gate {
75037c478bd9Sstevel@tonic-gate i = s->s_quegrp->qg_index;
75047c478bd9Sstevel@tonic-gate
75057c478bd9Sstevel@tonic-gate /* XXX what about the pointers inside this struct? */
75067c478bd9Sstevel@tonic-gate sm_free(s->s_quegrp); /* XXX */
75077c478bd9Sstevel@tonic-gate }
75087c478bd9Sstevel@tonic-gate else
75097c478bd9Sstevel@tonic-gate i = NumQueue++;
75107c478bd9Sstevel@tonic-gate Queue[i] = s->s_quegrp = qg;
75117c478bd9Sstevel@tonic-gate qg->qg_index = i;
75127c478bd9Sstevel@tonic-gate
75137c478bd9Sstevel@tonic-gate /* set default value for max queue runners */
75147c478bd9Sstevel@tonic-gate if (qg->qg_maxqrun < 0)
75157c478bd9Sstevel@tonic-gate {
75167c478bd9Sstevel@tonic-gate if (MaxRunnersPerQueue > 0)
75177c478bd9Sstevel@tonic-gate qg->qg_maxqrun = MaxRunnersPerQueue;
75187c478bd9Sstevel@tonic-gate else
75197c478bd9Sstevel@tonic-gate qg->qg_maxqrun = 1;
75207c478bd9Sstevel@tonic-gate }
75217c478bd9Sstevel@tonic-gate if (qdef)
75227c478bd9Sstevel@tonic-gate setbitn(QD_DEFINED, qg->qg_flags);
75237c478bd9Sstevel@tonic-gate }
75247c478bd9Sstevel@tonic-gate #if 0
75257c478bd9Sstevel@tonic-gate /*
75267c478bd9Sstevel@tonic-gate ** HASHFQN -- calculate a hash value for a fully qualified host name
75277c478bd9Sstevel@tonic-gate **
75287c478bd9Sstevel@tonic-gate ** Arguments:
75297c478bd9Sstevel@tonic-gate ** fqn -- an all lower-case host.domain string
75307c478bd9Sstevel@tonic-gate ** buckets -- the number of buckets (queue directories)
75317c478bd9Sstevel@tonic-gate **
75327c478bd9Sstevel@tonic-gate ** Returns:
75337c478bd9Sstevel@tonic-gate ** a bucket number (signed integer)
75347c478bd9Sstevel@tonic-gate ** -1 on error
75357c478bd9Sstevel@tonic-gate **
75367c478bd9Sstevel@tonic-gate ** Contributed by Exactis.com, Inc.
75377c478bd9Sstevel@tonic-gate */
75387c478bd9Sstevel@tonic-gate
75397c478bd9Sstevel@tonic-gate int
75407c478bd9Sstevel@tonic-gate hashfqn(fqn, buckets)
75417c478bd9Sstevel@tonic-gate register char *fqn;
75427c478bd9Sstevel@tonic-gate int buckets;
75437c478bd9Sstevel@tonic-gate {
75447c478bd9Sstevel@tonic-gate register char *p;
75457c478bd9Sstevel@tonic-gate register int h = 0, hash, cnt;
75467c478bd9Sstevel@tonic-gate
75477c478bd9Sstevel@tonic-gate if (fqn == NULL)
75487c478bd9Sstevel@tonic-gate return -1;
75497c478bd9Sstevel@tonic-gate
75507c478bd9Sstevel@tonic-gate /*
75517c478bd9Sstevel@tonic-gate ** A variation on the gdb hash
75527c478bd9Sstevel@tonic-gate ** This is the best as of Feb 19, 1996 --bcx
75537c478bd9Sstevel@tonic-gate */
75547c478bd9Sstevel@tonic-gate
75557c478bd9Sstevel@tonic-gate p = fqn;
75567c478bd9Sstevel@tonic-gate h = 0x238F13AF * strlen(p);
75577c478bd9Sstevel@tonic-gate for (cnt = 0; *p != 0; ++p, cnt++)
75587c478bd9Sstevel@tonic-gate {
75597c478bd9Sstevel@tonic-gate h = (h + (*p << (cnt * 5 % 24))) & 0x7FFFFFFF;
75607c478bd9Sstevel@tonic-gate }
75617c478bd9Sstevel@tonic-gate h = (1103515243 * h + 12345) & 0x7FFFFFFF;
75627c478bd9Sstevel@tonic-gate if (buckets < 2)
75637c478bd9Sstevel@tonic-gate hash = 0;
75647c478bd9Sstevel@tonic-gate else
75657c478bd9Sstevel@tonic-gate hash = (h % buckets);
75667c478bd9Sstevel@tonic-gate
75677c478bd9Sstevel@tonic-gate return hash;
75687c478bd9Sstevel@tonic-gate }
75697c478bd9Sstevel@tonic-gate #endif /* 0 */
75707c478bd9Sstevel@tonic-gate
75717c478bd9Sstevel@tonic-gate /*
75727c478bd9Sstevel@tonic-gate ** A structure for sorting Queue according to maxqrun without
75737c478bd9Sstevel@tonic-gate ** screwing up Queue itself.
75747c478bd9Sstevel@tonic-gate */
75757c478bd9Sstevel@tonic-gate
75767c478bd9Sstevel@tonic-gate struct sortqgrp
75777c478bd9Sstevel@tonic-gate {
75787c478bd9Sstevel@tonic-gate int sg_idx; /* original index */
75797c478bd9Sstevel@tonic-gate int sg_maxqrun; /* max queue runners */
75807c478bd9Sstevel@tonic-gate };
75817c478bd9Sstevel@tonic-gate typedef struct sortqgrp SORTQGRP_T;
75827c478bd9Sstevel@tonic-gate static int cmpidx __P((const void *, const void *));
75837c478bd9Sstevel@tonic-gate
75847c478bd9Sstevel@tonic-gate static int
cmpidx(a,b)75857c478bd9Sstevel@tonic-gate cmpidx(a, b)
75867c478bd9Sstevel@tonic-gate const void *a;
75877c478bd9Sstevel@tonic-gate const void *b;
75887c478bd9Sstevel@tonic-gate {
75897c478bd9Sstevel@tonic-gate /* The sort is highest to lowest, so the comparison is reversed */
75907c478bd9Sstevel@tonic-gate if (((SORTQGRP_T *)a)->sg_maxqrun < ((SORTQGRP_T *)b)->sg_maxqrun)
75917c478bd9Sstevel@tonic-gate return 1;
75927c478bd9Sstevel@tonic-gate else if (((SORTQGRP_T *)a)->sg_maxqrun > ((SORTQGRP_T *)b)->sg_maxqrun)
75937c478bd9Sstevel@tonic-gate return -1;
75947c478bd9Sstevel@tonic-gate else
75957c478bd9Sstevel@tonic-gate return 0;
75967c478bd9Sstevel@tonic-gate }
75977c478bd9Sstevel@tonic-gate
75987c478bd9Sstevel@tonic-gate /*
75997c478bd9Sstevel@tonic-gate ** MAKEWORKGROUP -- balance queue groups into work groups per MaxQueueChildren
76007c478bd9Sstevel@tonic-gate **
76017c478bd9Sstevel@tonic-gate ** Take the now defined queue groups and assign them to work groups.
76027c478bd9Sstevel@tonic-gate ** This is done to balance out the number of concurrently active
76037c478bd9Sstevel@tonic-gate ** queue runners such that MaxQueueChildren is not exceeded. This may
76047c478bd9Sstevel@tonic-gate ** result in more than one queue group per work group. In such a case
76057c478bd9Sstevel@tonic-gate ** the number of running queue groups in that work group will have no
76067c478bd9Sstevel@tonic-gate ** more than the work group maximum number of runners (a "fair" portion
76077c478bd9Sstevel@tonic-gate ** of MaxQueueRunners). All queue groups within a work group will get a
76087c478bd9Sstevel@tonic-gate ** chance at running.
76097c478bd9Sstevel@tonic-gate **
76107c478bd9Sstevel@tonic-gate ** Parameters:
76117c478bd9Sstevel@tonic-gate ** none.
76127c478bd9Sstevel@tonic-gate **
76137c478bd9Sstevel@tonic-gate ** Returns:
76147c478bd9Sstevel@tonic-gate ** nothing.
76157c478bd9Sstevel@tonic-gate **
76167c478bd9Sstevel@tonic-gate ** Side Effects:
76177c478bd9Sstevel@tonic-gate ** Sets up WorkGrp structure.
76187c478bd9Sstevel@tonic-gate */
76197c478bd9Sstevel@tonic-gate
76207c478bd9Sstevel@tonic-gate void
makeworkgroups()76217c478bd9Sstevel@tonic-gate makeworkgroups()
76227c478bd9Sstevel@tonic-gate {
76237c478bd9Sstevel@tonic-gate int i, j, total_runners, dir, h;
76247c478bd9Sstevel@tonic-gate SORTQGRP_T si[MAXQUEUEGROUPS + 1];
76257c478bd9Sstevel@tonic-gate
76267c478bd9Sstevel@tonic-gate total_runners = 0;
76277c478bd9Sstevel@tonic-gate if (NumQueue == 1 && strcmp(Queue[0]->qg_name, "mqueue") == 0)
76287c478bd9Sstevel@tonic-gate {
76297c478bd9Sstevel@tonic-gate /*
76307c478bd9Sstevel@tonic-gate ** There is only the "mqueue" queue group (a default)
76317c478bd9Sstevel@tonic-gate ** containing all of the queues. We want to provide to
76327c478bd9Sstevel@tonic-gate ** this queue group the maximum allowable queue runners.
76337c478bd9Sstevel@tonic-gate ** To match older behavior (8.10/8.11) we'll try for
76347c478bd9Sstevel@tonic-gate ** 1 runner per queue capping it at MaxQueueChildren.
76357c478bd9Sstevel@tonic-gate ** So if there are N queues, then there will be N runners
76367c478bd9Sstevel@tonic-gate ** for the "mqueue" queue group (where N is kept less than
76377c478bd9Sstevel@tonic-gate ** MaxQueueChildren).
76387c478bd9Sstevel@tonic-gate */
76397c478bd9Sstevel@tonic-gate
76407c478bd9Sstevel@tonic-gate NumWorkGroups = 1;
76417c478bd9Sstevel@tonic-gate WorkGrp[0].wg_numqgrp = 1;
76427c478bd9Sstevel@tonic-gate WorkGrp[0].wg_qgs = (QUEUEGRP **) xalloc(sizeof(QUEUEGRP *));
76437c478bd9Sstevel@tonic-gate WorkGrp[0].wg_qgs[0] = Queue[0];
76447c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 &&
76457c478bd9Sstevel@tonic-gate Queue[0]->qg_numqueues > MaxQueueChildren)
76467c478bd9Sstevel@tonic-gate WorkGrp[0].wg_runners = MaxQueueChildren;
76477c478bd9Sstevel@tonic-gate else
76487c478bd9Sstevel@tonic-gate WorkGrp[0].wg_runners = Queue[0]->qg_numqueues;
76497c478bd9Sstevel@tonic-gate
76507c478bd9Sstevel@tonic-gate Queue[0]->qg_wgrp = 0;
76517c478bd9Sstevel@tonic-gate
76527c478bd9Sstevel@tonic-gate /* can't have more runners than allowed total */
76537c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 &&
76547c478bd9Sstevel@tonic-gate Queue[0]->qg_maxqrun > MaxQueueChildren)
76557c478bd9Sstevel@tonic-gate Queue[0]->qg_maxqrun = MaxQueueChildren;
76567c478bd9Sstevel@tonic-gate WorkGrp[0].wg_maxact = Queue[0]->qg_maxqrun;
76577c478bd9Sstevel@tonic-gate WorkGrp[0].wg_lowqintvl = Queue[0]->qg_queueintvl;
76587c478bd9Sstevel@tonic-gate return;
76597c478bd9Sstevel@tonic-gate }
76607c478bd9Sstevel@tonic-gate
76617c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue; i++)
76627c478bd9Sstevel@tonic-gate {
76637c478bd9Sstevel@tonic-gate si[i].sg_maxqrun = Queue[i]->qg_maxqrun;
76647c478bd9Sstevel@tonic-gate si[i].sg_idx = i;
76657c478bd9Sstevel@tonic-gate }
76667c478bd9Sstevel@tonic-gate qsort(si, NumQueue, sizeof(si[0]), cmpidx);
76677c478bd9Sstevel@tonic-gate
76687c478bd9Sstevel@tonic-gate NumWorkGroups = 0;
76697c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue; i++)
76707c478bd9Sstevel@tonic-gate {
76717c478bd9Sstevel@tonic-gate total_runners += si[i].sg_maxqrun;
76727c478bd9Sstevel@tonic-gate if (MaxQueueChildren <= 0 || total_runners <= MaxQueueChildren)
76737c478bd9Sstevel@tonic-gate NumWorkGroups++;
76747c478bd9Sstevel@tonic-gate else
76757c478bd9Sstevel@tonic-gate break;
76767c478bd9Sstevel@tonic-gate }
76777c478bd9Sstevel@tonic-gate
76787c478bd9Sstevel@tonic-gate if (NumWorkGroups < 1)
76797c478bd9Sstevel@tonic-gate NumWorkGroups = 1; /* gotta have one at least */
76807c478bd9Sstevel@tonic-gate else if (NumWorkGroups > MAXWORKGROUPS)
76817c478bd9Sstevel@tonic-gate NumWorkGroups = MAXWORKGROUPS; /* the limit */
76827c478bd9Sstevel@tonic-gate
76837c478bd9Sstevel@tonic-gate /*
76847c478bd9Sstevel@tonic-gate ** We now know the number of work groups to pack the queue groups
76857c478bd9Sstevel@tonic-gate ** into. The queue groups in 'Queue' are sorted from highest
76867c478bd9Sstevel@tonic-gate ** to lowest for the number of runners per queue group.
76877c478bd9Sstevel@tonic-gate ** We put the queue groups with the largest number of runners
76887c478bd9Sstevel@tonic-gate ** into work groups first. Then the smaller ones are fitted in
76897c478bd9Sstevel@tonic-gate ** where it looks best.
76907c478bd9Sstevel@tonic-gate */
76917c478bd9Sstevel@tonic-gate
76927c478bd9Sstevel@tonic-gate j = 0;
76937c478bd9Sstevel@tonic-gate dir = 1;
76947c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue; i++)
76957c478bd9Sstevel@tonic-gate {
76967c478bd9Sstevel@tonic-gate /* a to-and-fro packing scheme, continue from last position */
76977c478bd9Sstevel@tonic-gate if (j >= NumWorkGroups)
76987c478bd9Sstevel@tonic-gate {
76997c478bd9Sstevel@tonic-gate dir = -1;
77007c478bd9Sstevel@tonic-gate j = NumWorkGroups - 1;
77017c478bd9Sstevel@tonic-gate }
77027c478bd9Sstevel@tonic-gate else if (j < 0)
77037c478bd9Sstevel@tonic-gate {
77047c478bd9Sstevel@tonic-gate j = 0;
77057c478bd9Sstevel@tonic-gate dir = 1;
77067c478bd9Sstevel@tonic-gate }
77077c478bd9Sstevel@tonic-gate
77087c478bd9Sstevel@tonic-gate if (WorkGrp[j].wg_qgs == NULL)
77097c478bd9Sstevel@tonic-gate WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_malloc(sizeof(QUEUEGRP *) *
77107c478bd9Sstevel@tonic-gate (WorkGrp[j].wg_numqgrp + 1));
77117c478bd9Sstevel@tonic-gate else
77127c478bd9Sstevel@tonic-gate WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_realloc(WorkGrp[j].wg_qgs,
77137c478bd9Sstevel@tonic-gate sizeof(QUEUEGRP *) *
77147c478bd9Sstevel@tonic-gate (WorkGrp[j].wg_numqgrp + 1));
77157c478bd9Sstevel@tonic-gate if (WorkGrp[j].wg_qgs == NULL)
77167c478bd9Sstevel@tonic-gate {
77177c478bd9Sstevel@tonic-gate syserr("!cannot allocate memory for work queues, need %d bytes",
77187c478bd9Sstevel@tonic-gate (int) (sizeof(QUEUEGRP *) *
77197c478bd9Sstevel@tonic-gate (WorkGrp[j].wg_numqgrp + 1)));
77207c478bd9Sstevel@tonic-gate }
77217c478bd9Sstevel@tonic-gate
77227c478bd9Sstevel@tonic-gate h = si[i].sg_idx;
77237c478bd9Sstevel@tonic-gate WorkGrp[j].wg_qgs[WorkGrp[j].wg_numqgrp] = Queue[h];
77247c478bd9Sstevel@tonic-gate WorkGrp[j].wg_numqgrp++;
77257c478bd9Sstevel@tonic-gate WorkGrp[j].wg_runners += Queue[h]->qg_maxqrun;
77267c478bd9Sstevel@tonic-gate Queue[h]->qg_wgrp = j;
77277c478bd9Sstevel@tonic-gate
77287c478bd9Sstevel@tonic-gate if (WorkGrp[j].wg_maxact == 0)
77297c478bd9Sstevel@tonic-gate {
77307c478bd9Sstevel@tonic-gate /* can't have more runners than allowed total */
77317c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 &&
77327c478bd9Sstevel@tonic-gate Queue[h]->qg_maxqrun > MaxQueueChildren)
77337c478bd9Sstevel@tonic-gate Queue[h]->qg_maxqrun = MaxQueueChildren;
77347c478bd9Sstevel@tonic-gate WorkGrp[j].wg_maxact = Queue[h]->qg_maxqrun;
77357c478bd9Sstevel@tonic-gate }
77367c478bd9Sstevel@tonic-gate
77377c478bd9Sstevel@tonic-gate /*
77387c478bd9Sstevel@tonic-gate ** XXX: must wg_lowqintvl be the GCD?
77397c478bd9Sstevel@tonic-gate ** qg1: 2m, qg2: 3m, minimum: 2m, when do queue runs for
77407c478bd9Sstevel@tonic-gate ** qg2 occur?
77417c478bd9Sstevel@tonic-gate */
77427c478bd9Sstevel@tonic-gate
77437c478bd9Sstevel@tonic-gate /* keep track of the lowest interval for a persistent runner */
77447c478bd9Sstevel@tonic-gate if (Queue[h]->qg_queueintvl > 0 &&
77457c478bd9Sstevel@tonic-gate WorkGrp[j].wg_lowqintvl < Queue[h]->qg_queueintvl)
77467c478bd9Sstevel@tonic-gate WorkGrp[j].wg_lowqintvl = Queue[h]->qg_queueintvl;
77477c478bd9Sstevel@tonic-gate j += dir;
77487c478bd9Sstevel@tonic-gate }
77497c478bd9Sstevel@tonic-gate if (tTd(41, 9))
77507c478bd9Sstevel@tonic-gate {
77517c478bd9Sstevel@tonic-gate for (i = 0; i < NumWorkGroups; i++)
77527c478bd9Sstevel@tonic-gate {
77537c478bd9Sstevel@tonic-gate sm_dprintf("Workgroup[%d]=", i);
77547c478bd9Sstevel@tonic-gate for (j = 0; j < WorkGrp[i].wg_numqgrp; j++)
77557c478bd9Sstevel@tonic-gate {
77567c478bd9Sstevel@tonic-gate sm_dprintf("%s, ",
77577c478bd9Sstevel@tonic-gate WorkGrp[i].wg_qgs[j]->qg_name);
77587c478bd9Sstevel@tonic-gate }
77597c478bd9Sstevel@tonic-gate sm_dprintf("\n");
77607c478bd9Sstevel@tonic-gate }
77617c478bd9Sstevel@tonic-gate }
77627c478bd9Sstevel@tonic-gate }
77637c478bd9Sstevel@tonic-gate
77647c478bd9Sstevel@tonic-gate /*
77657c478bd9Sstevel@tonic-gate ** DUP_DF -- duplicate envelope data file
77667c478bd9Sstevel@tonic-gate **
77677c478bd9Sstevel@tonic-gate ** Copy the data file from the 'old' envelope to the 'new' envelope
77687c478bd9Sstevel@tonic-gate ** in the most efficient way possible.
77697c478bd9Sstevel@tonic-gate **
77707c478bd9Sstevel@tonic-gate ** Create a hard link from the 'old' data file to the 'new' data file.
77717c478bd9Sstevel@tonic-gate ** If the old and new queue directories are on different file systems,
77727c478bd9Sstevel@tonic-gate ** then the new data file link is created in the old queue directory,
77737c478bd9Sstevel@tonic-gate ** and the new queue file will contain a 'd' record pointing to the
77747c478bd9Sstevel@tonic-gate ** directory containing the new data file.
77757c478bd9Sstevel@tonic-gate **
77767c478bd9Sstevel@tonic-gate ** Parameters:
77777c478bd9Sstevel@tonic-gate ** old -- old envelope.
77787c478bd9Sstevel@tonic-gate ** new -- new envelope.
77797c478bd9Sstevel@tonic-gate **
77807c478bd9Sstevel@tonic-gate ** Results:
77817c478bd9Sstevel@tonic-gate ** Returns true on success, false on failure.
77827c478bd9Sstevel@tonic-gate **
77837c478bd9Sstevel@tonic-gate ** Side Effects:
77847c478bd9Sstevel@tonic-gate ** On success, the new data file is created.
77857c478bd9Sstevel@tonic-gate ** On fatal failure, EF_FATALERRS is set in old->e_flags.
77867c478bd9Sstevel@tonic-gate */
77877c478bd9Sstevel@tonic-gate
77887c478bd9Sstevel@tonic-gate static bool dup_df __P((ENVELOPE *, ENVELOPE *));
77897c478bd9Sstevel@tonic-gate
77907c478bd9Sstevel@tonic-gate static bool
dup_df(old,new)77917c478bd9Sstevel@tonic-gate dup_df(old, new)
77927c478bd9Sstevel@tonic-gate ENVELOPE *old;
77937c478bd9Sstevel@tonic-gate ENVELOPE *new;
77947c478bd9Sstevel@tonic-gate {
77957c478bd9Sstevel@tonic-gate int ofs, nfs, r;
77967c478bd9Sstevel@tonic-gate char opath[MAXPATHLEN];
77977c478bd9Sstevel@tonic-gate char npath[MAXPATHLEN];
77987c478bd9Sstevel@tonic-gate
77997c478bd9Sstevel@tonic-gate if (!bitset(EF_HAS_DF, old->e_flags))
78007c478bd9Sstevel@tonic-gate {
78017c478bd9Sstevel@tonic-gate /*
78027c478bd9Sstevel@tonic-gate ** this can happen if: SuperSafe != True
78037c478bd9Sstevel@tonic-gate ** and a bounce mail is sent that is split.
78047c478bd9Sstevel@tonic-gate */
78057c478bd9Sstevel@tonic-gate
78067c478bd9Sstevel@tonic-gate queueup(old, false, true);
78077c478bd9Sstevel@tonic-gate }
78087c478bd9Sstevel@tonic-gate SM_REQUIRE(ISVALIDQGRP(old->e_qgrp) && ISVALIDQDIR(old->e_qdir));
78097c478bd9Sstevel@tonic-gate SM_REQUIRE(ISVALIDQGRP(new->e_qgrp) && ISVALIDQDIR(new->e_qdir));
78107c478bd9Sstevel@tonic-gate
7811058561cbSjbeck (void) sm_strlcpy(opath, queuename(old, DATAFL_LETTER), sizeof(opath));
7812058561cbSjbeck (void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof(npath));
78137c478bd9Sstevel@tonic-gate
78147c478bd9Sstevel@tonic-gate if (old->e_dfp != NULL)
78157c478bd9Sstevel@tonic-gate {
78167c478bd9Sstevel@tonic-gate r = sm_io_setinfo(old->e_dfp, SM_BF_COMMIT, NULL);
78177c478bd9Sstevel@tonic-gate if (r < 0 && errno != EINVAL)
78187c478bd9Sstevel@tonic-gate {
78197c478bd9Sstevel@tonic-gate syserr("@can't commit %s", opath);
78207c478bd9Sstevel@tonic-gate old->e_flags |= EF_FATALERRS;
78217c478bd9Sstevel@tonic-gate return false;
78227c478bd9Sstevel@tonic-gate }
78237c478bd9Sstevel@tonic-gate }
78247c478bd9Sstevel@tonic-gate
78257c478bd9Sstevel@tonic-gate /*
78267c478bd9Sstevel@tonic-gate ** Attempt to create a hard link, if we think both old and new
78277c478bd9Sstevel@tonic-gate ** are on the same file system, otherwise copy the file.
78287c478bd9Sstevel@tonic-gate **
78297c478bd9Sstevel@tonic-gate ** Don't waste time attempting a hard link unless old and new
78307c478bd9Sstevel@tonic-gate ** are on the same file system.
78317c478bd9Sstevel@tonic-gate */
78327c478bd9Sstevel@tonic-gate
783349218d4fSjbeck SM_REQUIRE(ISVALIDQGRP(old->e_dfqgrp) && ISVALIDQDIR(old->e_dfqdir));
783449218d4fSjbeck SM_REQUIRE(ISVALIDQGRP(new->e_dfqgrp) && ISVALIDQDIR(new->e_dfqdir));
783549218d4fSjbeck
783649218d4fSjbeck ofs = Queue[old->e_dfqgrp]->qg_qpaths[old->e_dfqdir].qp_fsysidx;
783749218d4fSjbeck nfs = Queue[new->e_dfqgrp]->qg_qpaths[new->e_dfqdir].qp_fsysidx;
78387c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(ofs) == FILE_SYS_DEV(nfs))
78397c478bd9Sstevel@tonic-gate {
78407c478bd9Sstevel@tonic-gate if (link(opath, npath) == 0)
78417c478bd9Sstevel@tonic-gate {
78427c478bd9Sstevel@tonic-gate new->e_flags |= EF_HAS_DF;
78437c478bd9Sstevel@tonic-gate SYNC_DIR(npath, true);
78447c478bd9Sstevel@tonic-gate return true;
78457c478bd9Sstevel@tonic-gate }
78467c478bd9Sstevel@tonic-gate goto error;
78477c478bd9Sstevel@tonic-gate }
78487c478bd9Sstevel@tonic-gate
78497c478bd9Sstevel@tonic-gate /*
78507c478bd9Sstevel@tonic-gate ** Can't link across queue directories, so try to create a hard
78517c478bd9Sstevel@tonic-gate ** link in the same queue directory as the old df file.
78527c478bd9Sstevel@tonic-gate ** The qf file will refer to the new df file using a 'd' record.
78537c478bd9Sstevel@tonic-gate */
78547c478bd9Sstevel@tonic-gate
78557c478bd9Sstevel@tonic-gate new->e_dfqgrp = old->e_dfqgrp;
78567c478bd9Sstevel@tonic-gate new->e_dfqdir = old->e_dfqdir;
7857058561cbSjbeck (void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof(npath));
78587c478bd9Sstevel@tonic-gate if (link(opath, npath) == 0)
78597c478bd9Sstevel@tonic-gate {
78607c478bd9Sstevel@tonic-gate new->e_flags |= EF_HAS_DF;
78617c478bd9Sstevel@tonic-gate SYNC_DIR(npath, true);
78627c478bd9Sstevel@tonic-gate return true;
78637c478bd9Sstevel@tonic-gate }
78647c478bd9Sstevel@tonic-gate
78657c478bd9Sstevel@tonic-gate error:
78667c478bd9Sstevel@tonic-gate if (LogLevel > 0)
78677c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, old->e_id,
78687c478bd9Sstevel@tonic-gate "dup_df: can't link %s to %s, error=%s, envelope splitting failed",
78697c478bd9Sstevel@tonic-gate opath, npath, sm_errstring(errno));
78707c478bd9Sstevel@tonic-gate return false;
78717c478bd9Sstevel@tonic-gate }
78727c478bd9Sstevel@tonic-gate
78737c478bd9Sstevel@tonic-gate /*
78747c478bd9Sstevel@tonic-gate ** SPLIT_ENV -- Allocate a new envelope based on a given envelope.
78757c478bd9Sstevel@tonic-gate **
78767c478bd9Sstevel@tonic-gate ** Parameters:
78777c478bd9Sstevel@tonic-gate ** e -- envelope.
78787c478bd9Sstevel@tonic-gate ** sendqueue -- sendqueue for new envelope.
78797c478bd9Sstevel@tonic-gate ** qgrp -- index of queue group.
78807c478bd9Sstevel@tonic-gate ** qdir -- queue directory.
78817c478bd9Sstevel@tonic-gate **
78827c478bd9Sstevel@tonic-gate ** Results:
78837c478bd9Sstevel@tonic-gate ** new envelope.
78847c478bd9Sstevel@tonic-gate **
78857c478bd9Sstevel@tonic-gate */
78867c478bd9Sstevel@tonic-gate
78877c478bd9Sstevel@tonic-gate static ENVELOPE *split_env __P((ENVELOPE *, ADDRESS *, int, int));
78887c478bd9Sstevel@tonic-gate
78897c478bd9Sstevel@tonic-gate static ENVELOPE *
split_env(e,sendqueue,qgrp,qdir)78907c478bd9Sstevel@tonic-gate split_env(e, sendqueue, qgrp, qdir)
78917c478bd9Sstevel@tonic-gate ENVELOPE *e;
78927c478bd9Sstevel@tonic-gate ADDRESS *sendqueue;
78937c478bd9Sstevel@tonic-gate int qgrp;
78947c478bd9Sstevel@tonic-gate int qdir;
78957c478bd9Sstevel@tonic-gate {
78967c478bd9Sstevel@tonic-gate ENVELOPE *ee;
78977c478bd9Sstevel@tonic-gate
7898058561cbSjbeck ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool, sizeof(*ee));
78997c478bd9Sstevel@tonic-gate STRUCTCOPY(*e, *ee);
79007c478bd9Sstevel@tonic-gate ee->e_message = NULL; /* XXX use original message? */
79017c478bd9Sstevel@tonic-gate ee->e_id = NULL;
79027c478bd9Sstevel@tonic-gate assign_queueid(ee);
79037c478bd9Sstevel@tonic-gate ee->e_sendqueue = sendqueue;
79047c478bd9Sstevel@tonic-gate ee->e_flags &= ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS
79057c478bd9Sstevel@tonic-gate |EF_SENDRECEIPT|EF_RET_PARAM|EF_HAS_DF);
79067c478bd9Sstevel@tonic-gate ee->e_flags |= EF_NORECEIPT; /* XXX really? */
79077c478bd9Sstevel@tonic-gate ee->e_from.q_state = QS_SENDER;
79087c478bd9Sstevel@tonic-gate ee->e_dfp = NULL;
79097c478bd9Sstevel@tonic-gate ee->e_lockfp = NULL;
79107c478bd9Sstevel@tonic-gate if (e->e_xfp != NULL)
79117c478bd9Sstevel@tonic-gate ee->e_xfp = sm_io_dup(e->e_xfp);
79127c478bd9Sstevel@tonic-gate
79137c478bd9Sstevel@tonic-gate /* failed to dup e->e_xfp, start a new transcript */
79147c478bd9Sstevel@tonic-gate if (ee->e_xfp == NULL)
79157c478bd9Sstevel@tonic-gate openxscript(ee);
79167c478bd9Sstevel@tonic-gate
79177c478bd9Sstevel@tonic-gate ee->e_qgrp = ee->e_dfqgrp = qgrp;
79187c478bd9Sstevel@tonic-gate ee->e_qdir = ee->e_dfqdir = qdir;
79197c478bd9Sstevel@tonic-gate ee->e_errormode = EM_MAIL;
79207c478bd9Sstevel@tonic-gate ee->e_statmsg = NULL;
79217c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL)
79227c478bd9Sstevel@tonic-gate ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool,
79237c478bd9Sstevel@tonic-gate e->e_quarmsg);
79247c478bd9Sstevel@tonic-gate
79257c478bd9Sstevel@tonic-gate /*
79267c478bd9Sstevel@tonic-gate ** XXX Not sure if this copying is necessary.
79277c478bd9Sstevel@tonic-gate ** sendall() does this copying, but I (dm) don't know if that is
79287c478bd9Sstevel@tonic-gate ** because of the storage management discipline we were using
79297c478bd9Sstevel@tonic-gate ** before rpools were introduced, or if it is because these lists
79307c478bd9Sstevel@tonic-gate ** can be modified later.
79317c478bd9Sstevel@tonic-gate */
79327c478bd9Sstevel@tonic-gate
79337c478bd9Sstevel@tonic-gate ee->e_header = copyheader(e->e_header, ee->e_rpool);
79347c478bd9Sstevel@tonic-gate ee->e_errorqueue = copyqueue(e->e_errorqueue, ee->e_rpool);
79357c478bd9Sstevel@tonic-gate
79367c478bd9Sstevel@tonic-gate return ee;
79377c478bd9Sstevel@tonic-gate }
79387c478bd9Sstevel@tonic-gate
79397c478bd9Sstevel@tonic-gate /* return values from split functions, check also below! */
79407c478bd9Sstevel@tonic-gate #define SM_SPLIT_FAIL (0)
79417c478bd9Sstevel@tonic-gate #define SM_SPLIT_NONE (1)
79427c478bd9Sstevel@tonic-gate #define SM_SPLIT_NEW(n) (1 + (n))
79437c478bd9Sstevel@tonic-gate
79447c478bd9Sstevel@tonic-gate /*
79457c478bd9Sstevel@tonic-gate ** SPLIT_ACROSS_QUEUE_GROUPS
79467c478bd9Sstevel@tonic-gate **
79477c478bd9Sstevel@tonic-gate ** This function splits an envelope across multiple queue groups
79487c478bd9Sstevel@tonic-gate ** based on the queue group of each recipient.
79497c478bd9Sstevel@tonic-gate **
79507c478bd9Sstevel@tonic-gate ** Parameters:
79517c478bd9Sstevel@tonic-gate ** e -- envelope.
79527c478bd9Sstevel@tonic-gate **
79537c478bd9Sstevel@tonic-gate ** Results:
79547c478bd9Sstevel@tonic-gate ** SM_SPLIT_FAIL on failure
79557c478bd9Sstevel@tonic-gate ** SM_SPLIT_NONE if no splitting occurred,
79567c478bd9Sstevel@tonic-gate ** or 1 + the number of additional envelopes created.
79577c478bd9Sstevel@tonic-gate **
79587c478bd9Sstevel@tonic-gate ** Side Effects:
79597c478bd9Sstevel@tonic-gate ** On success, e->e_sibling points to a list of zero or more
79607c478bd9Sstevel@tonic-gate ** additional envelopes, and the associated data files exist
79617c478bd9Sstevel@tonic-gate ** on disk. But the queue files are not created.
79627c478bd9Sstevel@tonic-gate **
79637c478bd9Sstevel@tonic-gate ** On failure, e->e_sibling is not changed.
79647c478bd9Sstevel@tonic-gate ** The order of recipients in e->e_sendqueue is permuted.
79657c478bd9Sstevel@tonic-gate ** Abandoned data files for additional envelopes that failed
79667c478bd9Sstevel@tonic-gate ** to be created may exist on disk.
79677c478bd9Sstevel@tonic-gate */
79687c478bd9Sstevel@tonic-gate
79697c478bd9Sstevel@tonic-gate static int q_qgrp_compare __P((const void *, const void *));
79707c478bd9Sstevel@tonic-gate static int e_filesys_compare __P((const void *, const void *));
79717c478bd9Sstevel@tonic-gate
79727c478bd9Sstevel@tonic-gate static int
q_qgrp_compare(p1,p2)79737c478bd9Sstevel@tonic-gate q_qgrp_compare(p1, p2)
79747c478bd9Sstevel@tonic-gate const void *p1;
79757c478bd9Sstevel@tonic-gate const void *p2;
79767c478bd9Sstevel@tonic-gate {
79777c478bd9Sstevel@tonic-gate ADDRESS **pq1 = (ADDRESS **) p1;
79787c478bd9Sstevel@tonic-gate ADDRESS **pq2 = (ADDRESS **) p2;
79797c478bd9Sstevel@tonic-gate
79807c478bd9Sstevel@tonic-gate return (*pq1)->q_qgrp - (*pq2)->q_qgrp;
79817c478bd9Sstevel@tonic-gate }
79827c478bd9Sstevel@tonic-gate
79837c478bd9Sstevel@tonic-gate static int
e_filesys_compare(p1,p2)79847c478bd9Sstevel@tonic-gate e_filesys_compare(p1, p2)
79857c478bd9Sstevel@tonic-gate const void *p1;
79867c478bd9Sstevel@tonic-gate const void *p2;
79877c478bd9Sstevel@tonic-gate {
79887c478bd9Sstevel@tonic-gate ENVELOPE **pe1 = (ENVELOPE **) p1;
79897c478bd9Sstevel@tonic-gate ENVELOPE **pe2 = (ENVELOPE **) p2;
79907c478bd9Sstevel@tonic-gate int fs1, fs2;
79917c478bd9Sstevel@tonic-gate
79927c478bd9Sstevel@tonic-gate fs1 = Queue[(*pe1)->e_qgrp]->qg_qpaths[(*pe1)->e_qdir].qp_fsysidx;
79937c478bd9Sstevel@tonic-gate fs2 = Queue[(*pe2)->e_qgrp]->qg_qpaths[(*pe2)->e_qdir].qp_fsysidx;
79947c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(fs1) < FILE_SYS_DEV(fs2))
79957c478bd9Sstevel@tonic-gate return -1;
79967c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(fs1) > FILE_SYS_DEV(fs2))
79977c478bd9Sstevel@tonic-gate return 1;
79987c478bd9Sstevel@tonic-gate return 0;
79997c478bd9Sstevel@tonic-gate }
80007c478bd9Sstevel@tonic-gate
8001058561cbSjbeck static int split_across_queue_groups __P((ENVELOPE *));
80027c478bd9Sstevel@tonic-gate static int
split_across_queue_groups(e)80037c478bd9Sstevel@tonic-gate split_across_queue_groups(e)
80047c478bd9Sstevel@tonic-gate ENVELOPE *e;
80057c478bd9Sstevel@tonic-gate {
80067c478bd9Sstevel@tonic-gate int naddrs, nsplits, i;
80077c478bd9Sstevel@tonic-gate bool changed;
80087c478bd9Sstevel@tonic-gate char **pvp;
80097c478bd9Sstevel@tonic-gate ADDRESS *q, **addrs;
80107c478bd9Sstevel@tonic-gate ENVELOPE *ee, *es;
80117c478bd9Sstevel@tonic-gate ENVELOPE *splits[MAXQUEUEGROUPS];
80127c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE];
80137c478bd9Sstevel@tonic-gate
80147c478bd9Sstevel@tonic-gate SM_REQUIRE(ISVALIDQGRP(e->e_qgrp));
80157c478bd9Sstevel@tonic-gate
80167c478bd9Sstevel@tonic-gate /* Count addresses and assign queue groups. */
80177c478bd9Sstevel@tonic-gate naddrs = 0;
80187c478bd9Sstevel@tonic-gate changed = false;
80197c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next)
80207c478bd9Sstevel@tonic-gate {
80217c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state))
80227c478bd9Sstevel@tonic-gate continue;
80237c478bd9Sstevel@tonic-gate ++naddrs;
80247c478bd9Sstevel@tonic-gate
80257c478bd9Sstevel@tonic-gate /* bad addresses and those already sent stay put */
80267c478bd9Sstevel@tonic-gate if (QS_IS_BADADDR(q->q_state) ||
80277c478bd9Sstevel@tonic-gate QS_IS_SENT(q->q_state))
80287c478bd9Sstevel@tonic-gate q->q_qgrp = e->e_qgrp;
80297c478bd9Sstevel@tonic-gate else if (!ISVALIDQGRP(q->q_qgrp))
80307c478bd9Sstevel@tonic-gate {
80317c478bd9Sstevel@tonic-gate /* call ruleset which should return a queue group */
80327c478bd9Sstevel@tonic-gate i = rscap(RS_QUEUEGROUP, q->q_user, NULL, e, &pvp,
80337c478bd9Sstevel@tonic-gate pvpbuf, sizeof(pvpbuf));
80347c478bd9Sstevel@tonic-gate if (i == EX_OK &&
80357c478bd9Sstevel@tonic-gate pvp != NULL && pvp[0] != NULL &&
80367c478bd9Sstevel@tonic-gate (pvp[0][0] & 0377) == CANONNET &&
80377c478bd9Sstevel@tonic-gate pvp[1] != NULL && pvp[1][0] != '\0')
80387c478bd9Sstevel@tonic-gate {
80397c478bd9Sstevel@tonic-gate i = name2qid(pvp[1]);
80407c478bd9Sstevel@tonic-gate if (ISVALIDQGRP(i))
80417c478bd9Sstevel@tonic-gate {
80427c478bd9Sstevel@tonic-gate q->q_qgrp = i;
80437c478bd9Sstevel@tonic-gate changed = true;
80447c478bd9Sstevel@tonic-gate if (tTd(20, 4))
80457c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
80467c478bd9Sstevel@tonic-gate "queue group name %s -> %d",
80477c478bd9Sstevel@tonic-gate pvp[1], i);
80487c478bd9Sstevel@tonic-gate continue;
80497c478bd9Sstevel@tonic-gate }
80507c478bd9Sstevel@tonic-gate else if (LogLevel > 10)
80517c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
80527c478bd9Sstevel@tonic-gate "can't find queue group name %s, selection ignored",
80537c478bd9Sstevel@tonic-gate pvp[1]);
80547c478bd9Sstevel@tonic-gate }
80557c478bd9Sstevel@tonic-gate if (q->q_mailer != NULL &&
80567c478bd9Sstevel@tonic-gate ISVALIDQGRP(q->q_mailer->m_qgrp))
80577c478bd9Sstevel@tonic-gate {
80587c478bd9Sstevel@tonic-gate changed = true;
80597c478bd9Sstevel@tonic-gate q->q_qgrp = q->q_mailer->m_qgrp;
80607c478bd9Sstevel@tonic-gate }
80617c478bd9Sstevel@tonic-gate else if (ISVALIDQGRP(e->e_qgrp))
80627c478bd9Sstevel@tonic-gate q->q_qgrp = e->e_qgrp;
80637c478bd9Sstevel@tonic-gate else
80647c478bd9Sstevel@tonic-gate q->q_qgrp = 0;
80657c478bd9Sstevel@tonic-gate }
80667c478bd9Sstevel@tonic-gate }
80677c478bd9Sstevel@tonic-gate
80687c478bd9Sstevel@tonic-gate /* only one address? nothing to split. */
80697c478bd9Sstevel@tonic-gate if (naddrs <= 1 && !changed)
80707c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE;
80717c478bd9Sstevel@tonic-gate
80727c478bd9Sstevel@tonic-gate /* sort the addresses by queue group */
80737c478bd9Sstevel@tonic-gate addrs = sm_rpool_malloc_x(e->e_rpool, naddrs * sizeof(ADDRESS *));
80747c478bd9Sstevel@tonic-gate for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next)
80757c478bd9Sstevel@tonic-gate {
80767c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state))
80777c478bd9Sstevel@tonic-gate continue;
80787c478bd9Sstevel@tonic-gate addrs[i++] = q;
80797c478bd9Sstevel@tonic-gate }
80807c478bd9Sstevel@tonic-gate qsort(addrs, naddrs, sizeof(ADDRESS *), q_qgrp_compare);
80817c478bd9Sstevel@tonic-gate
80827c478bd9Sstevel@tonic-gate /* split into multiple envelopes, by queue group */
80837c478bd9Sstevel@tonic-gate nsplits = 0;
80847c478bd9Sstevel@tonic-gate es = NULL;
80857c478bd9Sstevel@tonic-gate e->e_sendqueue = NULL;
80867c478bd9Sstevel@tonic-gate for (i = 0; i < naddrs; ++i)
80877c478bd9Sstevel@tonic-gate {
80887c478bd9Sstevel@tonic-gate if (i == naddrs - 1 || addrs[i]->q_qgrp != addrs[i + 1]->q_qgrp)
80897c478bd9Sstevel@tonic-gate addrs[i]->q_next = NULL;
80907c478bd9Sstevel@tonic-gate else
80917c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1];
80927c478bd9Sstevel@tonic-gate
80937c478bd9Sstevel@tonic-gate /* same queue group as original envelope? */
80947c478bd9Sstevel@tonic-gate if (addrs[i]->q_qgrp == e->e_qgrp)
80957c478bd9Sstevel@tonic-gate {
80967c478bd9Sstevel@tonic-gate if (e->e_sendqueue == NULL)
80977c478bd9Sstevel@tonic-gate e->e_sendqueue = addrs[i];
80987c478bd9Sstevel@tonic-gate continue;
80997c478bd9Sstevel@tonic-gate }
81007c478bd9Sstevel@tonic-gate
81017c478bd9Sstevel@tonic-gate /* different queue group than original envelope */
81027c478bd9Sstevel@tonic-gate if (es == NULL || addrs[i]->q_qgrp != es->e_qgrp)
81037c478bd9Sstevel@tonic-gate {
81047c478bd9Sstevel@tonic-gate ee = split_env(e, addrs[i], addrs[i]->q_qgrp, NOQDIR);
81057c478bd9Sstevel@tonic-gate es = ee;
81067c478bd9Sstevel@tonic-gate splits[nsplits++] = ee;
81077c478bd9Sstevel@tonic-gate }
81087c478bd9Sstevel@tonic-gate }
81097c478bd9Sstevel@tonic-gate
81107c478bd9Sstevel@tonic-gate /* no splits? return right now. */
81117c478bd9Sstevel@tonic-gate if (nsplits <= 0)
81127c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE;
81137c478bd9Sstevel@tonic-gate
81147c478bd9Sstevel@tonic-gate /* assign a queue directory to each additional envelope */
81157c478bd9Sstevel@tonic-gate for (i = 0; i < nsplits; ++i)
81167c478bd9Sstevel@tonic-gate {
81177c478bd9Sstevel@tonic-gate es = splits[i];
81187c478bd9Sstevel@tonic-gate #if 0
81197c478bd9Sstevel@tonic-gate es->e_qdir = pickqdir(Queue[es->e_qgrp], es->e_msgsize, es);
81207c478bd9Sstevel@tonic-gate #endif /* 0 */
81217c478bd9Sstevel@tonic-gate if (!setnewqueue(es))
81227c478bd9Sstevel@tonic-gate goto failure;
81237c478bd9Sstevel@tonic-gate }
81247c478bd9Sstevel@tonic-gate
81257c478bd9Sstevel@tonic-gate /* sort the additional envelopes by queue file system */
81267c478bd9Sstevel@tonic-gate qsort(splits, nsplits, sizeof(ENVELOPE *), e_filesys_compare);
81277c478bd9Sstevel@tonic-gate
81287c478bd9Sstevel@tonic-gate /* create data files for each additional envelope */
81297c478bd9Sstevel@tonic-gate if (!dup_df(e, splits[0]))
81307c478bd9Sstevel@tonic-gate {
81317c478bd9Sstevel@tonic-gate i = 0;
81327c478bd9Sstevel@tonic-gate goto failure;
81337c478bd9Sstevel@tonic-gate }
81347c478bd9Sstevel@tonic-gate for (i = 1; i < nsplits; ++i)
81357c478bd9Sstevel@tonic-gate {
81367c478bd9Sstevel@tonic-gate /* copy or link to the previous data file */
81377c478bd9Sstevel@tonic-gate if (!dup_df(splits[i - 1], splits[i]))
81387c478bd9Sstevel@tonic-gate goto failure;
81397c478bd9Sstevel@tonic-gate }
81407c478bd9Sstevel@tonic-gate
81417c478bd9Sstevel@tonic-gate /* success: prepend the new envelopes to the e->e_sibling list */
81427c478bd9Sstevel@tonic-gate for (i = 0; i < nsplits; ++i)
81437c478bd9Sstevel@tonic-gate {
81447c478bd9Sstevel@tonic-gate es = splits[i];
81457c478bd9Sstevel@tonic-gate es->e_sibling = e->e_sibling;
81467c478bd9Sstevel@tonic-gate e->e_sibling = es;
81477c478bd9Sstevel@tonic-gate }
81487c478bd9Sstevel@tonic-gate return SM_SPLIT_NEW(nsplits);
81497c478bd9Sstevel@tonic-gate
81507c478bd9Sstevel@tonic-gate /* failure: clean up */
81517c478bd9Sstevel@tonic-gate failure:
81527c478bd9Sstevel@tonic-gate if (i > 0)
81537c478bd9Sstevel@tonic-gate {
81547c478bd9Sstevel@tonic-gate int j;
81557c478bd9Sstevel@tonic-gate
81567c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++)
81577c478bd9Sstevel@tonic-gate (void) unlink(queuename(splits[j], DATAFL_LETTER));
81587c478bd9Sstevel@tonic-gate }
81597c478bd9Sstevel@tonic-gate e->e_sendqueue = addrs[0];
81607c478bd9Sstevel@tonic-gate for (i = 0; i < naddrs - 1; ++i)
81617c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1];
81627c478bd9Sstevel@tonic-gate addrs[naddrs - 1]->q_next = NULL;
81637c478bd9Sstevel@tonic-gate return SM_SPLIT_FAIL;
81647c478bd9Sstevel@tonic-gate }
81657c478bd9Sstevel@tonic-gate
81667c478bd9Sstevel@tonic-gate /*
81677c478bd9Sstevel@tonic-gate ** SPLIT_WITHIN_QUEUE
81687c478bd9Sstevel@tonic-gate **
81697c478bd9Sstevel@tonic-gate ** Split an envelope with multiple recipients into several
81707c478bd9Sstevel@tonic-gate ** envelopes within the same queue directory, if the number of
81717c478bd9Sstevel@tonic-gate ** recipients exceeds the limit for the queue group.
81727c478bd9Sstevel@tonic-gate **
81737c478bd9Sstevel@tonic-gate ** Parameters:
81747c478bd9Sstevel@tonic-gate ** e -- envelope.
81757c478bd9Sstevel@tonic-gate **
81767c478bd9Sstevel@tonic-gate ** Results:
81777c478bd9Sstevel@tonic-gate ** SM_SPLIT_FAIL on failure
81787c478bd9Sstevel@tonic-gate ** SM_SPLIT_NONE if no splitting occurred,
81797c478bd9Sstevel@tonic-gate ** or 1 + the number of additional envelopes created.
81807c478bd9Sstevel@tonic-gate */
81817c478bd9Sstevel@tonic-gate
81827c478bd9Sstevel@tonic-gate #define SPLIT_LOG_LEVEL 8
81837c478bd9Sstevel@tonic-gate
81847c478bd9Sstevel@tonic-gate static int split_within_queue __P((ENVELOPE *));
81857c478bd9Sstevel@tonic-gate
81867c478bd9Sstevel@tonic-gate static int
split_within_queue(e)81877c478bd9Sstevel@tonic-gate split_within_queue(e)
81887c478bd9Sstevel@tonic-gate ENVELOPE *e;
81897c478bd9Sstevel@tonic-gate {
81907c478bd9Sstevel@tonic-gate int maxrcpt, nrcpt, ndead, nsplit, i;
81917c478bd9Sstevel@tonic-gate int j, l;
81927c478bd9Sstevel@tonic-gate char *lsplits;
81937c478bd9Sstevel@tonic-gate ADDRESS *q, **addrs;
81947c478bd9Sstevel@tonic-gate ENVELOPE *ee, *firstsibling;
81957c478bd9Sstevel@tonic-gate
81967c478bd9Sstevel@tonic-gate if (!ISVALIDQGRP(e->e_qgrp) || bitset(EF_SPLIT, e->e_flags))
81977c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE;
81987c478bd9Sstevel@tonic-gate
81997c478bd9Sstevel@tonic-gate /* don't bother if there is no recipient limit */
82007c478bd9Sstevel@tonic-gate maxrcpt = Queue[e->e_qgrp]->qg_maxrcpt;
82017c478bd9Sstevel@tonic-gate if (maxrcpt <= 0)
82027c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE;
82037c478bd9Sstevel@tonic-gate
82047c478bd9Sstevel@tonic-gate /* count recipients */
82057c478bd9Sstevel@tonic-gate nrcpt = 0;
82067c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next)
82077c478bd9Sstevel@tonic-gate {
82087c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state))
82097c478bd9Sstevel@tonic-gate continue;
82107c478bd9Sstevel@tonic-gate ++nrcpt;
82117c478bd9Sstevel@tonic-gate }
82127c478bd9Sstevel@tonic-gate if (nrcpt <= maxrcpt)
82137c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE;
82147c478bd9Sstevel@tonic-gate
82157c478bd9Sstevel@tonic-gate /*
82167c478bd9Sstevel@tonic-gate ** Preserve the recipient list
82177c478bd9Sstevel@tonic-gate ** so that we can restore it in case of error.
82187c478bd9Sstevel@tonic-gate ** (But we discard dead addresses.)
82197c478bd9Sstevel@tonic-gate */
82207c478bd9Sstevel@tonic-gate
82217c478bd9Sstevel@tonic-gate addrs = sm_rpool_malloc_x(e->e_rpool, nrcpt * sizeof(ADDRESS *));
82227c478bd9Sstevel@tonic-gate for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next)
82237c478bd9Sstevel@tonic-gate {
82247c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state))
82257c478bd9Sstevel@tonic-gate continue;
82267c478bd9Sstevel@tonic-gate addrs[i++] = q;
82277c478bd9Sstevel@tonic-gate }
82287c478bd9Sstevel@tonic-gate
82297c478bd9Sstevel@tonic-gate /*
82307c478bd9Sstevel@tonic-gate ** Partition the recipient list so that bad and sent addresses
82317c478bd9Sstevel@tonic-gate ** come first. These will go with the original envelope, and
82327c478bd9Sstevel@tonic-gate ** do not count towards the maxrcpt limit.
82337c478bd9Sstevel@tonic-gate ** addrs[] does not contain QS_IS_DEAD() addresses.
82347c478bd9Sstevel@tonic-gate */
82357c478bd9Sstevel@tonic-gate
82367c478bd9Sstevel@tonic-gate ndead = 0;
82377c478bd9Sstevel@tonic-gate for (i = 0; i < nrcpt; ++i)
82387c478bd9Sstevel@tonic-gate {
82397c478bd9Sstevel@tonic-gate if (QS_IS_BADADDR(addrs[i]->q_state) ||
82407c478bd9Sstevel@tonic-gate QS_IS_SENT(addrs[i]->q_state) ||
82417c478bd9Sstevel@tonic-gate QS_IS_DEAD(addrs[i]->q_state)) /* for paranoia's sake */
82427c478bd9Sstevel@tonic-gate {
82437c478bd9Sstevel@tonic-gate if (i > ndead)
82447c478bd9Sstevel@tonic-gate {
82457c478bd9Sstevel@tonic-gate ADDRESS *tmp = addrs[i];
82467c478bd9Sstevel@tonic-gate
82477c478bd9Sstevel@tonic-gate addrs[i] = addrs[ndead];
82487c478bd9Sstevel@tonic-gate addrs[ndead] = tmp;
82497c478bd9Sstevel@tonic-gate }
82507c478bd9Sstevel@tonic-gate ++ndead;
82517c478bd9Sstevel@tonic-gate }
82527c478bd9Sstevel@tonic-gate }
82537c478bd9Sstevel@tonic-gate
82547c478bd9Sstevel@tonic-gate /* Check if no splitting required. */
82557c478bd9Sstevel@tonic-gate if (nrcpt - ndead <= maxrcpt)
82567c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE;
82577c478bd9Sstevel@tonic-gate
82587c478bd9Sstevel@tonic-gate /* fix links */
82597c478bd9Sstevel@tonic-gate for (i = 0; i < nrcpt - 1; ++i)
82607c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1];
82617c478bd9Sstevel@tonic-gate addrs[nrcpt - 1]->q_next = NULL;
82627c478bd9Sstevel@tonic-gate e->e_sendqueue = addrs[0];
82637c478bd9Sstevel@tonic-gate
82647c478bd9Sstevel@tonic-gate /* prepare buffer for logging */
82657c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL)
82667c478bd9Sstevel@tonic-gate {
82677c478bd9Sstevel@tonic-gate l = MAXLINE;
82687c478bd9Sstevel@tonic-gate lsplits = sm_malloc(l);
82697c478bd9Sstevel@tonic-gate if (lsplits != NULL)
82707c478bd9Sstevel@tonic-gate *lsplits = '\0';
82717c478bd9Sstevel@tonic-gate j = 0;
82727c478bd9Sstevel@tonic-gate }
82737c478bd9Sstevel@tonic-gate else
82747c478bd9Sstevel@tonic-gate {
82757c478bd9Sstevel@tonic-gate /* get rid of stupid compiler warnings */
82767c478bd9Sstevel@tonic-gate lsplits = NULL;
82777c478bd9Sstevel@tonic-gate j = l = 0;
82787c478bd9Sstevel@tonic-gate }
82797c478bd9Sstevel@tonic-gate
82807c478bd9Sstevel@tonic-gate /* split the envelope */
82817c478bd9Sstevel@tonic-gate firstsibling = e->e_sibling;
82827c478bd9Sstevel@tonic-gate i = maxrcpt + ndead;
82837c478bd9Sstevel@tonic-gate nsplit = 0;
82847c478bd9Sstevel@tonic-gate for (;;)
82857c478bd9Sstevel@tonic-gate {
82867c478bd9Sstevel@tonic-gate addrs[i - 1]->q_next = NULL;
82877c478bd9Sstevel@tonic-gate ee = split_env(e, addrs[i], e->e_qgrp, e->e_qdir);
82887c478bd9Sstevel@tonic-gate if (!dup_df(e, ee))
82897c478bd9Sstevel@tonic-gate {
82907c478bd9Sstevel@tonic-gate
82917c478bd9Sstevel@tonic-gate ee = firstsibling;
82927c478bd9Sstevel@tonic-gate while (ee != NULL)
82937c478bd9Sstevel@tonic-gate {
82947c478bd9Sstevel@tonic-gate (void) unlink(queuename(ee, DATAFL_LETTER));
82957c478bd9Sstevel@tonic-gate ee = ee->e_sibling;
82967c478bd9Sstevel@tonic-gate }
82977c478bd9Sstevel@tonic-gate
82987c478bd9Sstevel@tonic-gate /* Error. Restore e's sibling & recipient lists. */
82997c478bd9Sstevel@tonic-gate e->e_sibling = firstsibling;
83007c478bd9Sstevel@tonic-gate for (i = 0; i < nrcpt - 1; ++i)
83017c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1];
83027c478bd9Sstevel@tonic-gate if (lsplits != NULL)
83037c478bd9Sstevel@tonic-gate sm_free(lsplits);
83047c478bd9Sstevel@tonic-gate return SM_SPLIT_FAIL;
83057c478bd9Sstevel@tonic-gate }
83067c478bd9Sstevel@tonic-gate
83077c478bd9Sstevel@tonic-gate /* prepend the new envelope to e->e_sibling */
83087c478bd9Sstevel@tonic-gate ee->e_sibling = e->e_sibling;
83097c478bd9Sstevel@tonic-gate e->e_sibling = ee;
83107c478bd9Sstevel@tonic-gate ++nsplit;
83117c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
83127c478bd9Sstevel@tonic-gate {
83137c478bd9Sstevel@tonic-gate if (j >= l - strlen(ee->e_id) - 3)
83147c478bd9Sstevel@tonic-gate {
83157c478bd9Sstevel@tonic-gate char *p;
83167c478bd9Sstevel@tonic-gate
83177c478bd9Sstevel@tonic-gate l += MAXLINE;
83187c478bd9Sstevel@tonic-gate p = sm_realloc(lsplits, l);
83197c478bd9Sstevel@tonic-gate if (p == NULL)
83207c478bd9Sstevel@tonic-gate {
83217c478bd9Sstevel@tonic-gate /* let's try to get this done */
83227c478bd9Sstevel@tonic-gate sm_free(lsplits);
83237c478bd9Sstevel@tonic-gate lsplits = NULL;
83247c478bd9Sstevel@tonic-gate }
83257c478bd9Sstevel@tonic-gate else
83267c478bd9Sstevel@tonic-gate lsplits = p;
83277c478bd9Sstevel@tonic-gate }
83287c478bd9Sstevel@tonic-gate if (lsplits != NULL)
83297c478bd9Sstevel@tonic-gate {
83307c478bd9Sstevel@tonic-gate if (j == 0)
83317c478bd9Sstevel@tonic-gate j += sm_strlcat(lsplits + j,
83327c478bd9Sstevel@tonic-gate ee->e_id,
83337c478bd9Sstevel@tonic-gate l - j);
83347c478bd9Sstevel@tonic-gate else
83357c478bd9Sstevel@tonic-gate j += sm_strlcat2(lsplits + j,
83367c478bd9Sstevel@tonic-gate "; ",
83377c478bd9Sstevel@tonic-gate ee->e_id,
83387c478bd9Sstevel@tonic-gate l - j);
83397c478bd9Sstevel@tonic-gate SM_ASSERT(j < l);
83407c478bd9Sstevel@tonic-gate }
83417c478bd9Sstevel@tonic-gate }
83427c478bd9Sstevel@tonic-gate if (nrcpt - i <= maxrcpt)
83437c478bd9Sstevel@tonic-gate break;
83447c478bd9Sstevel@tonic-gate i += maxrcpt;
83457c478bd9Sstevel@tonic-gate }
83467c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
83477c478bd9Sstevel@tonic-gate {
83487c478bd9Sstevel@tonic-gate if (nsplit > 0)
83497c478bd9Sstevel@tonic-gate {
83507c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id,
83517c478bd9Sstevel@tonic-gate "split: maxrcpts=%d, rcpts=%d, count=%d, id%s=%s",
83527c478bd9Sstevel@tonic-gate maxrcpt, nrcpt - ndead, nsplit,
83537c478bd9Sstevel@tonic-gate nsplit > 1 ? "s" : "", lsplits);
83547c478bd9Sstevel@tonic-gate }
83557c478bd9Sstevel@tonic-gate sm_free(lsplits);
83567c478bd9Sstevel@tonic-gate }
83577c478bd9Sstevel@tonic-gate return SM_SPLIT_NEW(nsplit);
83587c478bd9Sstevel@tonic-gate }
83597c478bd9Sstevel@tonic-gate /*
83607c478bd9Sstevel@tonic-gate ** SPLIT_BY_RECIPIENT
83617c478bd9Sstevel@tonic-gate **
83627c478bd9Sstevel@tonic-gate ** Split an envelope with multiple recipients into multiple
83637c478bd9Sstevel@tonic-gate ** envelopes as required by the sendmail configuration.
83647c478bd9Sstevel@tonic-gate **
83657c478bd9Sstevel@tonic-gate ** Parameters:
83667c478bd9Sstevel@tonic-gate ** e -- envelope.
83677c478bd9Sstevel@tonic-gate **
83687c478bd9Sstevel@tonic-gate ** Results:
83697c478bd9Sstevel@tonic-gate ** Returns true on success, false on failure.
83707c478bd9Sstevel@tonic-gate **
83717c478bd9Sstevel@tonic-gate ** Side Effects:
83727c478bd9Sstevel@tonic-gate ** see split_across_queue_groups(), split_within_queue(e)
83737c478bd9Sstevel@tonic-gate */
83747c478bd9Sstevel@tonic-gate
83757c478bd9Sstevel@tonic-gate bool
split_by_recipient(e)83767c478bd9Sstevel@tonic-gate split_by_recipient(e)
83777c478bd9Sstevel@tonic-gate ENVELOPE *e;
83787c478bd9Sstevel@tonic-gate {
83797c478bd9Sstevel@tonic-gate int split, n, i, j, l;
83807c478bd9Sstevel@tonic-gate char *lsplits;
83817c478bd9Sstevel@tonic-gate ENVELOPE *ee, *next, *firstsibling;
83827c478bd9Sstevel@tonic-gate
83837c478bd9Sstevel@tonic-gate if (OpMode == SM_VERIFY || !ISVALIDQGRP(e->e_qgrp) ||
83847c478bd9Sstevel@tonic-gate bitset(EF_SPLIT, e->e_flags))
83857c478bd9Sstevel@tonic-gate return true;
83867c478bd9Sstevel@tonic-gate n = split_across_queue_groups(e);
83877c478bd9Sstevel@tonic-gate if (n == SM_SPLIT_FAIL)
83887c478bd9Sstevel@tonic-gate return false;
83897c478bd9Sstevel@tonic-gate firstsibling = ee = e->e_sibling;
83907c478bd9Sstevel@tonic-gate if (n > 1 && LogLevel > SPLIT_LOG_LEVEL)
83917c478bd9Sstevel@tonic-gate {
83927c478bd9Sstevel@tonic-gate l = MAXLINE;
83937c478bd9Sstevel@tonic-gate lsplits = sm_malloc(l);
83947c478bd9Sstevel@tonic-gate if (lsplits != NULL)
83957c478bd9Sstevel@tonic-gate *lsplits = '\0';
83967c478bd9Sstevel@tonic-gate j = 0;
83977c478bd9Sstevel@tonic-gate }
83987c478bd9Sstevel@tonic-gate else
83997c478bd9Sstevel@tonic-gate {
84007c478bd9Sstevel@tonic-gate /* get rid of stupid compiler warnings */
84017c478bd9Sstevel@tonic-gate lsplits = NULL;
84027c478bd9Sstevel@tonic-gate j = l = 0;
84037c478bd9Sstevel@tonic-gate }
84047c478bd9Sstevel@tonic-gate for (i = 1; i < n; ++i)
84057c478bd9Sstevel@tonic-gate {
84067c478bd9Sstevel@tonic-gate next = ee->e_sibling;
84077c478bd9Sstevel@tonic-gate if (split_within_queue(ee) == SM_SPLIT_FAIL)
84087c478bd9Sstevel@tonic-gate {
84097c478bd9Sstevel@tonic-gate e->e_sibling = firstsibling;
84107c478bd9Sstevel@tonic-gate return false;
84117c478bd9Sstevel@tonic-gate }
84127c478bd9Sstevel@tonic-gate ee->e_flags |= EF_SPLIT;
84137c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
84147c478bd9Sstevel@tonic-gate {
84157c478bd9Sstevel@tonic-gate if (j >= l - strlen(ee->e_id) - 3)
84167c478bd9Sstevel@tonic-gate {
84177c478bd9Sstevel@tonic-gate char *p;
84187c478bd9Sstevel@tonic-gate
84197c478bd9Sstevel@tonic-gate l += MAXLINE;
84207c478bd9Sstevel@tonic-gate p = sm_realloc(lsplits, l);
84217c478bd9Sstevel@tonic-gate if (p == NULL)
84227c478bd9Sstevel@tonic-gate {
84237c478bd9Sstevel@tonic-gate /* let's try to get this done */
84247c478bd9Sstevel@tonic-gate sm_free(lsplits);
84257c478bd9Sstevel@tonic-gate lsplits = NULL;
84267c478bd9Sstevel@tonic-gate }
84277c478bd9Sstevel@tonic-gate else
84287c478bd9Sstevel@tonic-gate lsplits = p;
84297c478bd9Sstevel@tonic-gate }
84307c478bd9Sstevel@tonic-gate if (lsplits != NULL)
84317c478bd9Sstevel@tonic-gate {
84327c478bd9Sstevel@tonic-gate if (j == 0)
84337c478bd9Sstevel@tonic-gate j += sm_strlcat(lsplits + j,
84347c478bd9Sstevel@tonic-gate ee->e_id, l - j);
84357c478bd9Sstevel@tonic-gate else
84367c478bd9Sstevel@tonic-gate j += sm_strlcat2(lsplits + j, "; ",
84377c478bd9Sstevel@tonic-gate ee->e_id, l - j);
84387c478bd9Sstevel@tonic-gate SM_ASSERT(j < l);
84397c478bd9Sstevel@tonic-gate }
84407c478bd9Sstevel@tonic-gate }
84417c478bd9Sstevel@tonic-gate ee = next;
84427c478bd9Sstevel@tonic-gate }
84437c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL && n > 1)
84447c478bd9Sstevel@tonic-gate {
84457c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id, "split: count=%d, id%s=%s",
84467c478bd9Sstevel@tonic-gate n - 1, n > 2 ? "s" : "", lsplits);
84477c478bd9Sstevel@tonic-gate sm_free(lsplits);
84487c478bd9Sstevel@tonic-gate }
84497c478bd9Sstevel@tonic-gate split = split_within_queue(e) != SM_SPLIT_FAIL;
84507c478bd9Sstevel@tonic-gate if (split)
84517c478bd9Sstevel@tonic-gate e->e_flags |= EF_SPLIT;
84527c478bd9Sstevel@tonic-gate return split;
84537c478bd9Sstevel@tonic-gate }
84547c478bd9Sstevel@tonic-gate
84557c478bd9Sstevel@tonic-gate /*
84567c478bd9Sstevel@tonic-gate ** QUARANTINE_QUEUE_ITEM -- {un,}quarantine a single envelope
84577c478bd9Sstevel@tonic-gate **
84587c478bd9Sstevel@tonic-gate ** Add/remove quarantine reason and requeue appropriately.
84597c478bd9Sstevel@tonic-gate **
84607c478bd9Sstevel@tonic-gate ** Parameters:
84617c478bd9Sstevel@tonic-gate ** qgrp -- queue group for the item
84627c478bd9Sstevel@tonic-gate ** qdir -- queue directory in the given queue group
84637c478bd9Sstevel@tonic-gate ** e -- envelope information for the item
84647c478bd9Sstevel@tonic-gate ** reason -- quarantine reason, NULL means unquarantine.
84657c478bd9Sstevel@tonic-gate **
84667c478bd9Sstevel@tonic-gate ** Results:
84677c478bd9Sstevel@tonic-gate ** true if item changed, false otherwise
84687c478bd9Sstevel@tonic-gate **
84697c478bd9Sstevel@tonic-gate ** Side Effects:
84707c478bd9Sstevel@tonic-gate ** Changes quarantine tag in queue file and renames it.
84717c478bd9Sstevel@tonic-gate */
84727c478bd9Sstevel@tonic-gate
84737c478bd9Sstevel@tonic-gate static bool
quarantine_queue_item(qgrp,qdir,e,reason)84747c478bd9Sstevel@tonic-gate quarantine_queue_item(qgrp, qdir, e, reason)
84757c478bd9Sstevel@tonic-gate int qgrp;
84767c478bd9Sstevel@tonic-gate int qdir;
84777c478bd9Sstevel@tonic-gate ENVELOPE *e;
84787c478bd9Sstevel@tonic-gate char *reason;
84797c478bd9Sstevel@tonic-gate {
84807c478bd9Sstevel@tonic-gate bool dirty = false;
84817c478bd9Sstevel@tonic-gate bool failing = false;
84827c478bd9Sstevel@tonic-gate bool foundq = false;
84837c478bd9Sstevel@tonic-gate bool finished = false;
84847c478bd9Sstevel@tonic-gate int fd;
84857c478bd9Sstevel@tonic-gate int flags;
84867c478bd9Sstevel@tonic-gate int oldtype;
84877c478bd9Sstevel@tonic-gate int newtype;
84887c478bd9Sstevel@tonic-gate int save_errno;
84897c478bd9Sstevel@tonic-gate MODE_T oldumask = 0;
84907c478bd9Sstevel@tonic-gate SM_FILE_T *oldqfp, *tempqfp;
84917c478bd9Sstevel@tonic-gate char *bp;
8492058561cbSjbeck int bufsize;
84937c478bd9Sstevel@tonic-gate char oldqf[MAXPATHLEN];
84947c478bd9Sstevel@tonic-gate char tempqf[MAXPATHLEN];
84957c478bd9Sstevel@tonic-gate char newqf[MAXPATHLEN];
84967c478bd9Sstevel@tonic-gate char buf[MAXLINE];
84977c478bd9Sstevel@tonic-gate
84987c478bd9Sstevel@tonic-gate oldtype = queue_letter(e, ANYQFL_LETTER);
8499058561cbSjbeck (void) sm_strlcpy(oldqf, queuename(e, ANYQFL_LETTER), sizeof(oldqf));
8500058561cbSjbeck (void) sm_strlcpy(tempqf, queuename(e, NEWQFL_LETTER), sizeof(tempqf));
85017c478bd9Sstevel@tonic-gate
85027c478bd9Sstevel@tonic-gate /*
85037c478bd9Sstevel@tonic-gate ** Instead of duplicating all the open
85047c478bd9Sstevel@tonic-gate ** and lock code here, tell readqf() to
85057c478bd9Sstevel@tonic-gate ** do that work and return the open
85067c478bd9Sstevel@tonic-gate ** file pointer in e_lockfp. Note that
85077c478bd9Sstevel@tonic-gate ** we must release the locks properly when
85087c478bd9Sstevel@tonic-gate ** we are done.
85097c478bd9Sstevel@tonic-gate */
85107c478bd9Sstevel@tonic-gate
85117c478bd9Sstevel@tonic-gate if (!readqf(e, true))
85127c478bd9Sstevel@tonic-gate {
85137c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
85147c478bd9Sstevel@tonic-gate "Skipping %s\n", qid_printname(e));
85157c478bd9Sstevel@tonic-gate return false;
85167c478bd9Sstevel@tonic-gate }
85177c478bd9Sstevel@tonic-gate oldqfp = e->e_lockfp;
85187c478bd9Sstevel@tonic-gate
85197c478bd9Sstevel@tonic-gate /* open the new queue file */
85207c478bd9Sstevel@tonic-gate flags = O_CREAT|O_WRONLY|O_EXCL;
85217c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode))
85227c478bd9Sstevel@tonic-gate oldumask = umask(002);
85237c478bd9Sstevel@tonic-gate fd = open(tempqf, flags, QueueFileMode);
85247c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode))
85257c478bd9Sstevel@tonic-gate (void) umask(oldumask);
85267c478bd9Sstevel@tonic-gate RELEASE_QUEUE;
85277c478bd9Sstevel@tonic-gate
85287c478bd9Sstevel@tonic-gate if (fd < 0)
85297c478bd9Sstevel@tonic-gate {
85307c478bd9Sstevel@tonic-gate save_errno = errno;
85317c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
85327c478bd9Sstevel@tonic-gate "Skipping %s: Could not open %s: %s\n",
85337c478bd9Sstevel@tonic-gate qid_printname(e), tempqf,
85347c478bd9Sstevel@tonic-gate sm_errstring(save_errno));
85357c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
85367c478bd9Sstevel@tonic-gate return false;
85377c478bd9Sstevel@tonic-gate }
85387c478bd9Sstevel@tonic-gate if (!lockfile(fd, tempqf, NULL, LOCK_EX|LOCK_NB))
85397c478bd9Sstevel@tonic-gate {
85407c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
85417c478bd9Sstevel@tonic-gate "Skipping %s: Could not lock %s\n",
85427c478bd9Sstevel@tonic-gate qid_printname(e), tempqf);
85437c478bd9Sstevel@tonic-gate (void) close(fd);
85447c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
85457c478bd9Sstevel@tonic-gate return false;
85467c478bd9Sstevel@tonic-gate }
85477c478bd9Sstevel@tonic-gate
85487c478bd9Sstevel@tonic-gate tempqfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &fd,
85497c478bd9Sstevel@tonic-gate SM_IO_WRONLY_B, NULL);
85507c478bd9Sstevel@tonic-gate if (tempqfp == NULL)
85517c478bd9Sstevel@tonic-gate {
85527c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
85537c478bd9Sstevel@tonic-gate "Skipping %s: Could not lock %s\n",
85547c478bd9Sstevel@tonic-gate qid_printname(e), tempqf);
85557c478bd9Sstevel@tonic-gate (void) close(fd);
85567c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
85577c478bd9Sstevel@tonic-gate return false;
85587c478bd9Sstevel@tonic-gate }
85597c478bd9Sstevel@tonic-gate
85607c478bd9Sstevel@tonic-gate /* Copy the data over, changing the quarantine reason */
8561058561cbSjbeck while (bufsize = sizeof(buf),
8562058561cbSjbeck (bp = fgetfolded(buf, &bufsize, oldqfp)) != NULL)
85637c478bd9Sstevel@tonic-gate {
85647c478bd9Sstevel@tonic-gate if (tTd(40, 4))
85657c478bd9Sstevel@tonic-gate sm_dprintf("+++++ %s\n", bp);
85667c478bd9Sstevel@tonic-gate switch (bp[0])
85677c478bd9Sstevel@tonic-gate {
85687c478bd9Sstevel@tonic-gate case 'q': /* quarantine reason */
85697c478bd9Sstevel@tonic-gate foundq = true;
85707c478bd9Sstevel@tonic-gate if (reason == NULL)
85717c478bd9Sstevel@tonic-gate {
85727c478bd9Sstevel@tonic-gate if (Verbose)
85737c478bd9Sstevel@tonic-gate {
85747c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
85757c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
85767c478bd9Sstevel@tonic-gate "%s: Removed quarantine of \"%s\"\n",
85777c478bd9Sstevel@tonic-gate e->e_id, &bp[1]);
85787c478bd9Sstevel@tonic-gate }
85797c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "unquarantine");
85807c478bd9Sstevel@tonic-gate dirty = true;
85817c478bd9Sstevel@tonic-gate }
85827c478bd9Sstevel@tonic-gate else if (strcmp(reason, &bp[1]) == 0)
85837c478bd9Sstevel@tonic-gate {
85847c478bd9Sstevel@tonic-gate if (Verbose)
85857c478bd9Sstevel@tonic-gate {
85867c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
85877c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
85887c478bd9Sstevel@tonic-gate "%s: Already quarantined with \"%s\"\n",
85897c478bd9Sstevel@tonic-gate e->e_id, reason);
85907c478bd9Sstevel@tonic-gate }
85917c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
85927c478bd9Sstevel@tonic-gate "q%s\n", reason);
85937c478bd9Sstevel@tonic-gate }
85947c478bd9Sstevel@tonic-gate else
85957c478bd9Sstevel@tonic-gate {
85967c478bd9Sstevel@tonic-gate if (Verbose)
85977c478bd9Sstevel@tonic-gate {
85987c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
85997c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
86007c478bd9Sstevel@tonic-gate "%s: Quarantine changed from \"%s\" to \"%s\"\n",
86017c478bd9Sstevel@tonic-gate e->e_id, &bp[1],
86027c478bd9Sstevel@tonic-gate reason);
86037c478bd9Sstevel@tonic-gate }
86047c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
86057c478bd9Sstevel@tonic-gate "q%s\n", reason);
86067c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "quarantine=%s",
86077c478bd9Sstevel@tonic-gate reason);
86087c478bd9Sstevel@tonic-gate dirty = true;
86097c478bd9Sstevel@tonic-gate }
86107c478bd9Sstevel@tonic-gate break;
86117c478bd9Sstevel@tonic-gate
86127c478bd9Sstevel@tonic-gate case 'S':
86137c478bd9Sstevel@tonic-gate /*
86147c478bd9Sstevel@tonic-gate ** If we are quarantining an unquarantined item,
86157c478bd9Sstevel@tonic-gate ** need to put in a new 'q' line before it's
86167c478bd9Sstevel@tonic-gate ** too late.
86177c478bd9Sstevel@tonic-gate */
86187c478bd9Sstevel@tonic-gate
86197c478bd9Sstevel@tonic-gate if (!foundq && reason != NULL)
86207c478bd9Sstevel@tonic-gate {
86217c478bd9Sstevel@tonic-gate if (Verbose)
86227c478bd9Sstevel@tonic-gate {
86237c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
86247c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
86257c478bd9Sstevel@tonic-gate "%s: Quarantined with \"%s\"\n",
86267c478bd9Sstevel@tonic-gate e->e_id, reason);
86277c478bd9Sstevel@tonic-gate }
86287c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
86297c478bd9Sstevel@tonic-gate "q%s\n", reason);
86307c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "quarantine=%s",
86317c478bd9Sstevel@tonic-gate reason);
86327c478bd9Sstevel@tonic-gate foundq = true;
86337c478bd9Sstevel@tonic-gate dirty = true;
86347c478bd9Sstevel@tonic-gate }
86357c478bd9Sstevel@tonic-gate
86367c478bd9Sstevel@tonic-gate /* Copy the line to the new file */
86377c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
86387c478bd9Sstevel@tonic-gate "%s\n", bp);
86397c478bd9Sstevel@tonic-gate break;
86407c478bd9Sstevel@tonic-gate
86417c478bd9Sstevel@tonic-gate case '.':
86427c478bd9Sstevel@tonic-gate finished = true;
86437c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
86447c478bd9Sstevel@tonic-gate
86457c478bd9Sstevel@tonic-gate default:
86467c478bd9Sstevel@tonic-gate /* Copy the line to the new file */
86477c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
86487c478bd9Sstevel@tonic-gate "%s\n", bp);
86497c478bd9Sstevel@tonic-gate break;
86507c478bd9Sstevel@tonic-gate }
8651058561cbSjbeck if (bp != buf)
8652058561cbSjbeck sm_free(bp);
86537c478bd9Sstevel@tonic-gate }
86547c478bd9Sstevel@tonic-gate
86557c478bd9Sstevel@tonic-gate /* Make sure we read the whole old file */
86567c478bd9Sstevel@tonic-gate errno = sm_io_error(tempqfp);
86577c478bd9Sstevel@tonic-gate if (errno != 0 && errno != SM_IO_EOF)
86587c478bd9Sstevel@tonic-gate {
86597c478bd9Sstevel@tonic-gate save_errno = errno;
86607c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
86617c478bd9Sstevel@tonic-gate "Skipping %s: Error reading %s: %s\n",
86627c478bd9Sstevel@tonic-gate qid_printname(e), oldqf,
86637c478bd9Sstevel@tonic-gate sm_errstring(save_errno));
86647c478bd9Sstevel@tonic-gate failing = true;
86657c478bd9Sstevel@tonic-gate }
86667c478bd9Sstevel@tonic-gate
86677c478bd9Sstevel@tonic-gate if (!failing && !finished)
86687c478bd9Sstevel@tonic-gate {
86697c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
86707c478bd9Sstevel@tonic-gate "Skipping %s: Incomplete file: %s\n",
86717c478bd9Sstevel@tonic-gate qid_printname(e), oldqf);
86727c478bd9Sstevel@tonic-gate failing = true;
86737c478bd9Sstevel@tonic-gate }
86747c478bd9Sstevel@tonic-gate
86757c478bd9Sstevel@tonic-gate /* Check if we actually changed anything or we can just bail now */
86767c478bd9Sstevel@tonic-gate if (!dirty)
86777c478bd9Sstevel@tonic-gate {
86787c478bd9Sstevel@tonic-gate /* pretend we failed, even though we technically didn't */
86797c478bd9Sstevel@tonic-gate failing = true;
86807c478bd9Sstevel@tonic-gate }
86817c478bd9Sstevel@tonic-gate
86827c478bd9Sstevel@tonic-gate /* Make sure we wrote things out safely */
86837c478bd9Sstevel@tonic-gate if (!failing &&
86847c478bd9Sstevel@tonic-gate (sm_io_flush(tempqfp, SM_TIME_DEFAULT) != 0 ||
86857c478bd9Sstevel@tonic-gate ((SuperSafe == SAFE_REALLY ||
86867c478bd9Sstevel@tonic-gate SuperSafe == SAFE_REALLY_POSTMILTER ||
86877c478bd9Sstevel@tonic-gate SuperSafe == SAFE_INTERACTIVE) &&
86887c478bd9Sstevel@tonic-gate fsync(sm_io_getinfo(tempqfp, SM_IO_WHAT_FD, NULL)) < 0) ||
86897c478bd9Sstevel@tonic-gate ((errno = sm_io_error(tempqfp)) != 0)))
86907c478bd9Sstevel@tonic-gate {
86917c478bd9Sstevel@tonic-gate save_errno = errno;
86927c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
86937c478bd9Sstevel@tonic-gate "Skipping %s: Error writing %s: %s\n",
86947c478bd9Sstevel@tonic-gate qid_printname(e), tempqf,
86957c478bd9Sstevel@tonic-gate sm_errstring(save_errno));
86967c478bd9Sstevel@tonic-gate failing = true;
86977c478bd9Sstevel@tonic-gate }
86987c478bd9Sstevel@tonic-gate
86997c478bd9Sstevel@tonic-gate
87007c478bd9Sstevel@tonic-gate /* Figure out the new filename */
87017c478bd9Sstevel@tonic-gate newtype = (reason == NULL ? NORMQF_LETTER : QUARQF_LETTER);
87027c478bd9Sstevel@tonic-gate if (oldtype == newtype)
87037c478bd9Sstevel@tonic-gate {
87047c478bd9Sstevel@tonic-gate /* going to rename tempqf to oldqf */
8705058561cbSjbeck (void) sm_strlcpy(newqf, oldqf, sizeof(newqf));
87067c478bd9Sstevel@tonic-gate }
87077c478bd9Sstevel@tonic-gate else
87087c478bd9Sstevel@tonic-gate {
87097c478bd9Sstevel@tonic-gate /* going to rename tempqf to new name based on newtype */
8710058561cbSjbeck (void) sm_strlcpy(newqf, queuename(e, newtype), sizeof(newqf));
87117c478bd9Sstevel@tonic-gate }
87127c478bd9Sstevel@tonic-gate
87137c478bd9Sstevel@tonic-gate save_errno = 0;
87147c478bd9Sstevel@tonic-gate
87157c478bd9Sstevel@tonic-gate /* rename tempqf to newqf */
87167c478bd9Sstevel@tonic-gate if (!failing &&
87177c478bd9Sstevel@tonic-gate rename(tempqf, newqf) < 0)
87187c478bd9Sstevel@tonic-gate save_errno = (errno == 0) ? EINVAL : errno;
87197c478bd9Sstevel@tonic-gate
87207c478bd9Sstevel@tonic-gate /* Check rename() success */
87217c478bd9Sstevel@tonic-gate if (!failing && save_errno != 0)
87227c478bd9Sstevel@tonic-gate {
87237c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id,
87247c478bd9Sstevel@tonic-gate "quarantine_queue_item: rename(%s, %s): %s",
87257c478bd9Sstevel@tonic-gate tempqf, newqf, sm_errstring(save_errno));
87267c478bd9Sstevel@tonic-gate
87277c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
87287c478bd9Sstevel@tonic-gate "Error renaming %s to %s: %s\n",
87297c478bd9Sstevel@tonic-gate tempqf, newqf,
87307c478bd9Sstevel@tonic-gate sm_errstring(save_errno));
87317c478bd9Sstevel@tonic-gate if (oldtype == newtype)
87327c478bd9Sstevel@tonic-gate {
87337c478bd9Sstevel@tonic-gate /*
87347c478bd9Sstevel@tonic-gate ** Bail here since we don't know the state of
87357c478bd9Sstevel@tonic-gate ** the filesystem and may need to keep tempqf
87367c478bd9Sstevel@tonic-gate ** for the user to rescue us.
87377c478bd9Sstevel@tonic-gate */
87387c478bd9Sstevel@tonic-gate
87397c478bd9Sstevel@tonic-gate RELEASE_QUEUE;
87407c478bd9Sstevel@tonic-gate errno = save_errno;
87417c478bd9Sstevel@tonic-gate syserr("!452 Error renaming control file %s", tempqf);
87427c478bd9Sstevel@tonic-gate /* NOTREACHED */
87437c478bd9Sstevel@tonic-gate }
87447c478bd9Sstevel@tonic-gate else
87457c478bd9Sstevel@tonic-gate {
87467c478bd9Sstevel@tonic-gate /* remove new file (if rename() half completed) */
87477c478bd9Sstevel@tonic-gate if (xunlink(newqf) < 0)
87487c478bd9Sstevel@tonic-gate {
87497c478bd9Sstevel@tonic-gate save_errno = errno;
87507c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
87517c478bd9Sstevel@tonic-gate "Error removing %s: %s\n",
87527c478bd9Sstevel@tonic-gate newqf,
87537c478bd9Sstevel@tonic-gate sm_errstring(save_errno));
87547c478bd9Sstevel@tonic-gate }
87557c478bd9Sstevel@tonic-gate
87567c478bd9Sstevel@tonic-gate /* tempqf removed below */
87577c478bd9Sstevel@tonic-gate failing = true;
87587c478bd9Sstevel@tonic-gate }
87597c478bd9Sstevel@tonic-gate
87607c478bd9Sstevel@tonic-gate }
87617c478bd9Sstevel@tonic-gate
87627c478bd9Sstevel@tonic-gate /* If changing file types, need to remove old type */
87637c478bd9Sstevel@tonic-gate if (!failing && oldtype != newtype)
87647c478bd9Sstevel@tonic-gate {
87657c478bd9Sstevel@tonic-gate if (xunlink(oldqf) < 0)
87667c478bd9Sstevel@tonic-gate {
87677c478bd9Sstevel@tonic-gate save_errno = errno;
87687c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
87697c478bd9Sstevel@tonic-gate "Error removing %s: %s\n",
87707c478bd9Sstevel@tonic-gate oldqf, sm_errstring(save_errno));
87717c478bd9Sstevel@tonic-gate }
87727c478bd9Sstevel@tonic-gate }
87737c478bd9Sstevel@tonic-gate
87747c478bd9Sstevel@tonic-gate /* see if anything above failed */
87757c478bd9Sstevel@tonic-gate if (failing)
87767c478bd9Sstevel@tonic-gate {
87777c478bd9Sstevel@tonic-gate /* Something failed: remove new file, old file still there */
87787c478bd9Sstevel@tonic-gate (void) xunlink(tempqf);
87797c478bd9Sstevel@tonic-gate }
87807c478bd9Sstevel@tonic-gate
87817c478bd9Sstevel@tonic-gate /*
87827c478bd9Sstevel@tonic-gate ** fsync() after file operations to make sure metadata is
87837c478bd9Sstevel@tonic-gate ** written to disk on filesystems in which renames are
87847c478bd9Sstevel@tonic-gate ** not guaranteed. It's ok if they fail, mail won't be lost.
87857c478bd9Sstevel@tonic-gate */
87867c478bd9Sstevel@tonic-gate
87877c478bd9Sstevel@tonic-gate if (SuperSafe != SAFE_NO)
87887c478bd9Sstevel@tonic-gate {
87897c478bd9Sstevel@tonic-gate /* for soft-updates */
87907c478bd9Sstevel@tonic-gate (void) fsync(sm_io_getinfo(tempqfp,
87917c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, NULL));
87927c478bd9Sstevel@tonic-gate
87937c478bd9Sstevel@tonic-gate if (!failing)
87947c478bd9Sstevel@tonic-gate {
87957c478bd9Sstevel@tonic-gate /* for soft-updates */
87967c478bd9Sstevel@tonic-gate (void) fsync(sm_io_getinfo(oldqfp,
87977c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, NULL));
87987c478bd9Sstevel@tonic-gate }
87997c478bd9Sstevel@tonic-gate
88007c478bd9Sstevel@tonic-gate /* for other odd filesystems */
88017c478bd9Sstevel@tonic-gate SYNC_DIR(tempqf, false);
88027c478bd9Sstevel@tonic-gate }
88037c478bd9Sstevel@tonic-gate
88047c478bd9Sstevel@tonic-gate /* Close up shop */
88057c478bd9Sstevel@tonic-gate RELEASE_QUEUE;
88067c478bd9Sstevel@tonic-gate if (tempqfp != NULL)
88077c478bd9Sstevel@tonic-gate (void) sm_io_close(tempqfp, SM_TIME_DEFAULT);
88087c478bd9Sstevel@tonic-gate if (oldqfp != NULL)
88097c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
88107c478bd9Sstevel@tonic-gate
88117c478bd9Sstevel@tonic-gate /* All went well */
88127c478bd9Sstevel@tonic-gate return !failing;
88137c478bd9Sstevel@tonic-gate }
88147c478bd9Sstevel@tonic-gate
88157c478bd9Sstevel@tonic-gate /*
88167c478bd9Sstevel@tonic-gate ** QUARANTINE_QUEUE -- {un,}quarantine matching items in the queue
88177c478bd9Sstevel@tonic-gate **
88187c478bd9Sstevel@tonic-gate ** Read all matching queue items, add/remove quarantine
88197c478bd9Sstevel@tonic-gate ** reason, and requeue appropriately.
88207c478bd9Sstevel@tonic-gate **
88217c478bd9Sstevel@tonic-gate ** Parameters:
88227c478bd9Sstevel@tonic-gate ** reason -- quarantine reason, "." means unquarantine.
88237c478bd9Sstevel@tonic-gate ** qgrplimit -- limit to single queue group unless NOQGRP
88247c478bd9Sstevel@tonic-gate **
88257c478bd9Sstevel@tonic-gate ** Results:
88267c478bd9Sstevel@tonic-gate ** none.
88277c478bd9Sstevel@tonic-gate **
88287c478bd9Sstevel@tonic-gate ** Side Effects:
88297c478bd9Sstevel@tonic-gate ** Lots of changes to the queue.
88307c478bd9Sstevel@tonic-gate */
88317c478bd9Sstevel@tonic-gate
88327c478bd9Sstevel@tonic-gate void
quarantine_queue(reason,qgrplimit)88337c478bd9Sstevel@tonic-gate quarantine_queue(reason, qgrplimit)
88347c478bd9Sstevel@tonic-gate char *reason;
88357c478bd9Sstevel@tonic-gate int qgrplimit;
88367c478bd9Sstevel@tonic-gate {
88377c478bd9Sstevel@tonic-gate int changed = 0;
88387c478bd9Sstevel@tonic-gate int qgrp;
88397c478bd9Sstevel@tonic-gate
88407c478bd9Sstevel@tonic-gate /* Convert internal representation of unquarantine */
88417c478bd9Sstevel@tonic-gate if (reason != NULL && reason[0] == '.' && reason[1] == '\0')
88427c478bd9Sstevel@tonic-gate reason = NULL;
88437c478bd9Sstevel@tonic-gate
88447c478bd9Sstevel@tonic-gate if (reason != NULL)
88457c478bd9Sstevel@tonic-gate {
88467c478bd9Sstevel@tonic-gate /* clean it */
88477c478bd9Sstevel@tonic-gate reason = newstr(denlstring(reason, true, true));
88487c478bd9Sstevel@tonic-gate }
88497c478bd9Sstevel@tonic-gate
88507c478bd9Sstevel@tonic-gate for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++)
88517c478bd9Sstevel@tonic-gate {
88527c478bd9Sstevel@tonic-gate int qdir;
88537c478bd9Sstevel@tonic-gate
88547c478bd9Sstevel@tonic-gate if (qgrplimit != NOQGRP && qgrplimit != qgrp)
88557c478bd9Sstevel@tonic-gate continue;
88567c478bd9Sstevel@tonic-gate
88577c478bd9Sstevel@tonic-gate for (qdir = 0; qdir < Queue[qgrp]->qg_numqueues; qdir++)
88587c478bd9Sstevel@tonic-gate {
88597c478bd9Sstevel@tonic-gate int i;
88607c478bd9Sstevel@tonic-gate int nrequests;
88617c478bd9Sstevel@tonic-gate
88627c478bd9Sstevel@tonic-gate if (StopRequest)
88637c478bd9Sstevel@tonic-gate stop_sendmail();
88647c478bd9Sstevel@tonic-gate
8865e9af4bc0SJohn Beck nrequests = gatherq(qgrp, qdir, true, NULL, NULL, NULL);
88667c478bd9Sstevel@tonic-gate
88677c478bd9Sstevel@tonic-gate /* first see if there is anything */
88687c478bd9Sstevel@tonic-gate if (nrequests <= 0)
88697c478bd9Sstevel@tonic-gate {
88707c478bd9Sstevel@tonic-gate if (Verbose)
88717c478bd9Sstevel@tonic-gate {
88727c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
88737c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, "%s: no matches\n",
88747c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir));
88757c478bd9Sstevel@tonic-gate }
88767c478bd9Sstevel@tonic-gate continue;
88777c478bd9Sstevel@tonic-gate }
88787c478bd9Sstevel@tonic-gate
88797c478bd9Sstevel@tonic-gate if (Verbose)
88807c478bd9Sstevel@tonic-gate {
88817c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout,
88827c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, "Processing %s:\n",
88837c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir));
88847c478bd9Sstevel@tonic-gate }
88857c478bd9Sstevel@tonic-gate
88867c478bd9Sstevel@tonic-gate for (i = 0; i < WorkListCount; i++)
88877c478bd9Sstevel@tonic-gate {
88887c478bd9Sstevel@tonic-gate ENVELOPE e;
88897c478bd9Sstevel@tonic-gate
88907c478bd9Sstevel@tonic-gate if (StopRequest)
88917c478bd9Sstevel@tonic-gate stop_sendmail();
88927c478bd9Sstevel@tonic-gate
88937c478bd9Sstevel@tonic-gate /* setup envelope */
88947c478bd9Sstevel@tonic-gate clearenvelope(&e, true, sm_rpool_new_x(NULL));
88957c478bd9Sstevel@tonic-gate e.e_id = WorkList[i].w_name + 2;
88967c478bd9Sstevel@tonic-gate e.e_qgrp = qgrp;
88977c478bd9Sstevel@tonic-gate e.e_qdir = qdir;
88987c478bd9Sstevel@tonic-gate
88997c478bd9Sstevel@tonic-gate if (tTd(70, 101))
89007c478bd9Sstevel@tonic-gate {
89017c478bd9Sstevel@tonic-gate sm_io_fprintf(smioout, SM_TIME_DEFAULT,
89027c478bd9Sstevel@tonic-gate "Would do %s\n", e.e_id);
89037c478bd9Sstevel@tonic-gate changed++;
89047c478bd9Sstevel@tonic-gate }
89057c478bd9Sstevel@tonic-gate else if (quarantine_queue_item(qgrp, qdir,
89067c478bd9Sstevel@tonic-gate &e, reason))
89077c478bd9Sstevel@tonic-gate changed++;
89087c478bd9Sstevel@tonic-gate
89097c478bd9Sstevel@tonic-gate /* clean up */
89107c478bd9Sstevel@tonic-gate sm_rpool_free(e.e_rpool);
89117c478bd9Sstevel@tonic-gate e.e_rpool = NULL;
89127c478bd9Sstevel@tonic-gate }
89137c478bd9Sstevel@tonic-gate if (WorkList != NULL)
89147c478bd9Sstevel@tonic-gate sm_free(WorkList); /* XXX */
89157c478bd9Sstevel@tonic-gate WorkList = NULL;
89167c478bd9Sstevel@tonic-gate WorkListSize = 0;
89177c478bd9Sstevel@tonic-gate WorkListCount = 0;
89187c478bd9Sstevel@tonic-gate }
89197c478bd9Sstevel@tonic-gate }
89207c478bd9Sstevel@tonic-gate if (Verbose)
89217c478bd9Sstevel@tonic-gate {
89227c478bd9Sstevel@tonic-gate if (changed == 0)
89237c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
89247c478bd9Sstevel@tonic-gate "No changes\n");
89257c478bd9Sstevel@tonic-gate else
89267c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
89277c478bd9Sstevel@tonic-gate "%d change%s\n",
89287c478bd9Sstevel@tonic-gate changed,
89297c478bd9Sstevel@tonic-gate changed == 1 ? "" : "s");
89307c478bd9Sstevel@tonic-gate }
89317c478bd9Sstevel@tonic-gate }
8932