17c478bd9Sstevel@tonic-gate /* 23ee0e492Sjbeck * Copyright (c) 1998-2006 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 #pragma ident "%Z%%M% %I% %E% SMI" 157c478bd9Sstevel@tonic-gate 167c478bd9Sstevel@tonic-gate #include <sendmail.h> 177c478bd9Sstevel@tonic-gate #include <sm/sem.h> 187c478bd9Sstevel@tonic-gate 19*058561cbSjbeck SM_RCSID("@(#)$Id: queue.c,v 8.970 2006/12/19 01:15:07 ca Exp $") 207c478bd9Sstevel@tonic-gate 217c478bd9Sstevel@tonic-gate #include <dirent.h> 227c478bd9Sstevel@tonic-gate 237c478bd9Sstevel@tonic-gate # define RELEASE_QUEUE (void) 0 247c478bd9Sstevel@tonic-gate # define ST_INODE(st) (st).st_ino 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate # define sm_file_exists(errno) ((errno) == EEXIST) 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate # if HASFLOCK && defined(O_EXLOCK) 297c478bd9Sstevel@tonic-gate # define SM_OPEN_EXLOCK 1 307c478bd9Sstevel@tonic-gate # define TF_OPEN_FLAGS (O_CREAT|O_WRONLY|O_EXCL|O_EXLOCK) 317c478bd9Sstevel@tonic-gate # else /* HASFLOCK && defined(O_EXLOCK) */ 327c478bd9Sstevel@tonic-gate # define TF_OPEN_FLAGS (O_CREAT|O_WRONLY|O_EXCL) 337c478bd9Sstevel@tonic-gate # endif /* HASFLOCK && defined(O_EXLOCK) */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #ifndef SM_OPEN_EXLOCK 367c478bd9Sstevel@tonic-gate # define SM_OPEN_EXLOCK 0 377c478bd9Sstevel@tonic-gate #endif /* ! SM_OPEN_EXLOCK */ 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate /* 407c478bd9Sstevel@tonic-gate ** Historical notes: 417c478bd9Sstevel@tonic-gate ** QF_VERSION == 4 was sendmail 8.10/8.11 without _FFR_QUEUEDELAY 427c478bd9Sstevel@tonic-gate ** QF_VERSION == 5 was sendmail 8.10/8.11 with _FFR_QUEUEDELAY 437c478bd9Sstevel@tonic-gate ** QF_VERSION == 6 was sendmail 8.12 without _FFR_QUEUEDELAY 447c478bd9Sstevel@tonic-gate ** QF_VERSION == 7 was sendmail 8.12 with _FFR_QUEUEDELAY 457c478bd9Sstevel@tonic-gate ** QF_VERSION == 8 is sendmail 8.13 467c478bd9Sstevel@tonic-gate */ 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #define QF_VERSION 8 /* version number of this queue format */ 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate static char queue_letter __P((ENVELOPE *, int)); 517c478bd9Sstevel@tonic-gate static bool quarantine_queue_item __P((int, int, ENVELOPE *, char *)); 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate /* Naming convention: qgrp: index of queue group, qg: QUEUEGROUP */ 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate /* 567c478bd9Sstevel@tonic-gate ** Work queue. 577c478bd9Sstevel@tonic-gate */ 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate struct work 607c478bd9Sstevel@tonic-gate { 617c478bd9Sstevel@tonic-gate char *w_name; /* name of control file */ 627c478bd9Sstevel@tonic-gate char *w_host; /* name of recipient host */ 637c478bd9Sstevel@tonic-gate bool w_lock; /* is message locked? */ 647c478bd9Sstevel@tonic-gate bool w_tooyoung; /* is it too young to run? */ 657c478bd9Sstevel@tonic-gate long w_pri; /* priority of message, see below */ 667c478bd9Sstevel@tonic-gate time_t w_ctime; /* creation time */ 677c478bd9Sstevel@tonic-gate time_t w_mtime; /* modification time */ 687c478bd9Sstevel@tonic-gate int w_qgrp; /* queue group located in */ 697c478bd9Sstevel@tonic-gate int w_qdir; /* queue directory located in */ 707c478bd9Sstevel@tonic-gate struct work *w_next; /* next in queue */ 717c478bd9Sstevel@tonic-gate }; 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate typedef struct work WORK; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate static WORK *WorkQ; /* queue of things to be done */ 767c478bd9Sstevel@tonic-gate static int NumWorkGroups; /* number of work groups */ 777c478bd9Sstevel@tonic-gate static time_t Current_LA_time = 0; 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate /* Get new load average every 30 seconds. */ 807c478bd9Sstevel@tonic-gate #define GET_NEW_LA_TIME 30 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate #define SM_GET_LA(now) \ 837c478bd9Sstevel@tonic-gate do \ 847c478bd9Sstevel@tonic-gate { \ 857c478bd9Sstevel@tonic-gate now = curtime(); \ 867c478bd9Sstevel@tonic-gate if (Current_LA_time < now - GET_NEW_LA_TIME) \ 877c478bd9Sstevel@tonic-gate { \ 887c478bd9Sstevel@tonic-gate sm_getla(); \ 897c478bd9Sstevel@tonic-gate Current_LA_time = now; \ 907c478bd9Sstevel@tonic-gate } \ 917c478bd9Sstevel@tonic-gate } while (0) 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate /* 947c478bd9Sstevel@tonic-gate ** DoQueueRun indicates that a queue run is needed. 957c478bd9Sstevel@tonic-gate ** Notice: DoQueueRun is modified in a signal handler! 967c478bd9Sstevel@tonic-gate */ 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate static bool volatile DoQueueRun; /* non-interrupt time queue run needed */ 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* 1017c478bd9Sstevel@tonic-gate ** Work group definition structure. 1027c478bd9Sstevel@tonic-gate ** Each work group contains one or more queue groups. This is done 1037c478bd9Sstevel@tonic-gate ** to manage the number of queue group runners active at the same time 1047c478bd9Sstevel@tonic-gate ** to be within the constraints of MaxQueueChildren (if it is set). 1057c478bd9Sstevel@tonic-gate ** The number of queue groups that can be run on the next work run 1067c478bd9Sstevel@tonic-gate ** is kept track of. The queue groups are run in a round robin. 1077c478bd9Sstevel@tonic-gate */ 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate struct workgrp 1107c478bd9Sstevel@tonic-gate { 1117c478bd9Sstevel@tonic-gate int wg_numqgrp; /* number of queue groups in work grp */ 1127c478bd9Sstevel@tonic-gate int wg_runners; /* total runners */ 1137c478bd9Sstevel@tonic-gate int wg_curqgrp; /* current queue group */ 1147c478bd9Sstevel@tonic-gate QUEUEGRP **wg_qgs; /* array of queue groups */ 1157c478bd9Sstevel@tonic-gate int wg_maxact; /* max # of active runners */ 1167c478bd9Sstevel@tonic-gate time_t wg_lowqintvl; /* lowest queue interval */ 1177c478bd9Sstevel@tonic-gate int wg_restart; /* needs restarting? */ 1187c478bd9Sstevel@tonic-gate int wg_restartcnt; /* count of times restarted */ 1197c478bd9Sstevel@tonic-gate }; 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate typedef struct workgrp WORKGRP; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate static WORKGRP volatile WorkGrp[MAXWORKGROUPS + 1]; /* work groups */ 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 1267c478bd9Sstevel@tonic-gate static SM_DEBUG_T DebugLeakQ = SM_DEBUG_INITIALIZER("leak_q", 1277c478bd9Sstevel@tonic-gate "@(#)$Debug: leak_q - trace memory leaks during queue processing $"); 1287c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* 1317c478bd9Sstevel@tonic-gate ** We use EmptyString instead of "" to avoid 1327c478bd9Sstevel@tonic-gate ** 'zero-length format string' warnings from gcc 1337c478bd9Sstevel@tonic-gate */ 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate static const char EmptyString[] = ""; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate static void grow_wlist __P((int, int)); 1387c478bd9Sstevel@tonic-gate static int multiqueue_cache __P((char *, int, QUEUEGRP *, int, unsigned int *)); 1397c478bd9Sstevel@tonic-gate static int gatherq __P((int, int, bool, bool *, bool *)); 1407c478bd9Sstevel@tonic-gate static int sortq __P((int)); 1417c478bd9Sstevel@tonic-gate static void printctladdr __P((ADDRESS *, SM_FILE_T *)); 1427c478bd9Sstevel@tonic-gate static bool readqf __P((ENVELOPE *, bool)); 1437c478bd9Sstevel@tonic-gate static void restart_work_group __P((int)); 1447c478bd9Sstevel@tonic-gate static void runner_work __P((ENVELOPE *, int, bool, int, int)); 1457c478bd9Sstevel@tonic-gate static void schedule_queue_runs __P((bool, int, bool)); 1467c478bd9Sstevel@tonic-gate static char *strrev __P((char *)); 1477c478bd9Sstevel@tonic-gate static ADDRESS *setctluser __P((char *, int, ENVELOPE *)); 1487c478bd9Sstevel@tonic-gate #if _FFR_RHS 1497c478bd9Sstevel@tonic-gate static int sm_strshufflecmp __P((char *, char *)); 1507c478bd9Sstevel@tonic-gate static void init_shuffle_alphabet __P(()); 1517c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 152*058561cbSjbeck 153*058561cbSjbeck /* 154*058561cbSjbeck ** Note: workcmpf?() don't use a prototype because it will cause a conflict 155*058561cbSjbeck ** with the qsort() call (which expects something like 156*058561cbSjbeck ** int (*compar)(const void *, const void *), not (WORK *, WORK *)) 157*058561cbSjbeck */ 158*058561cbSjbeck 1597c478bd9Sstevel@tonic-gate static int workcmpf0(); 1607c478bd9Sstevel@tonic-gate static int workcmpf1(); 1617c478bd9Sstevel@tonic-gate static int workcmpf2(); 1627c478bd9Sstevel@tonic-gate static int workcmpf3(); 1637c478bd9Sstevel@tonic-gate static int workcmpf4(); 1647c478bd9Sstevel@tonic-gate static int randi = 3; /* index for workcmpf5() */ 1657c478bd9Sstevel@tonic-gate static int workcmpf5(); 1667c478bd9Sstevel@tonic-gate static int workcmpf6(); 1677c478bd9Sstevel@tonic-gate #if _FFR_RHS 1687c478bd9Sstevel@tonic-gate static int workcmpf7(); 1697c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate #if RANDOMSHIFT 1727c478bd9Sstevel@tonic-gate # define get_rand_mod(m) ((get_random() >> RANDOMSHIFT) % (m)) 1737c478bd9Sstevel@tonic-gate #else /* RANDOMSHIFT */ 1747c478bd9Sstevel@tonic-gate # define get_rand_mod(m) (get_random() % (m)) 1757c478bd9Sstevel@tonic-gate #endif /* RANDOMSHIFT */ 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate /* 1787c478bd9Sstevel@tonic-gate ** File system definition. 1797c478bd9Sstevel@tonic-gate ** Used to keep track of how much free space is available 1807c478bd9Sstevel@tonic-gate ** on a file system in which one or more queue directories reside. 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate typedef struct filesys_shared FILESYS; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate struct filesys_shared 1867c478bd9Sstevel@tonic-gate { 1877c478bd9Sstevel@tonic-gate dev_t fs_dev; /* unique device id */ 1887c478bd9Sstevel@tonic-gate long fs_avail; /* number of free blocks available */ 1897c478bd9Sstevel@tonic-gate long fs_blksize; /* block size, in bytes */ 1907c478bd9Sstevel@tonic-gate }; 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate /* probably kept in shared memory */ 1937c478bd9Sstevel@tonic-gate static FILESYS FileSys[MAXFILESYS]; /* queue file systems */ 194*058561cbSjbeck static const char *FSPath[MAXFILESYS]; /* pathnames for file systems */ 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate ** Shared memory data 2007c478bd9Sstevel@tonic-gate ** 2017c478bd9Sstevel@tonic-gate ** Current layout: 2027c478bd9Sstevel@tonic-gate ** size -- size of shared memory segment 2037c478bd9Sstevel@tonic-gate ** pid -- pid of owner, should be a unique id to avoid misinterpretations 2047c478bd9Sstevel@tonic-gate ** by other processes. 2057c478bd9Sstevel@tonic-gate ** tag -- should be a unique id to avoid misinterpretations by others. 2067c478bd9Sstevel@tonic-gate ** idea: hash over configuration data that will be stored here. 2077c478bd9Sstevel@tonic-gate ** NumFileSys -- number of file systems. 2087c478bd9Sstevel@tonic-gate ** FileSys -- (arrary of) structure for used file systems. 2097c478bd9Sstevel@tonic-gate ** RSATmpCnt -- counter for number of uses of ephemeral RSA key. 2107c478bd9Sstevel@tonic-gate ** QShm -- (array of) structure for information about queue directories. 2117c478bd9Sstevel@tonic-gate */ 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate ** Queue data in shared memory 2157c478bd9Sstevel@tonic-gate */ 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate typedef struct queue_shared QUEUE_SHM_T; 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate struct queue_shared 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate int qs_entries; /* number of entries */ 2227c478bd9Sstevel@tonic-gate /* XXX more to follow? */ 2237c478bd9Sstevel@tonic-gate }; 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate static void *Pshm; /* pointer to shared memory */ 2267c478bd9Sstevel@tonic-gate static FILESYS *PtrFileSys; /* pointer to queue file system array */ 2277c478bd9Sstevel@tonic-gate int ShmId = SM_SHM_NO_ID; /* shared memory id */ 2287c478bd9Sstevel@tonic-gate static QUEUE_SHM_T *QShm; /* pointer to shared queue data */ 2297c478bd9Sstevel@tonic-gate static size_t shms; 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate # define SHM_OFF_PID(p) (((char *) (p)) + sizeof(int)) 2327c478bd9Sstevel@tonic-gate # define SHM_OFF_TAG(p) (((char *) (p)) + sizeof(pid_t) + sizeof(int)) 2337c478bd9Sstevel@tonic-gate # define SHM_OFF_HEAD (sizeof(pid_t) + sizeof(int) * 2) 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* how to access FileSys */ 2367c478bd9Sstevel@tonic-gate # define FILE_SYS(i) (PtrFileSys[i]) 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* first entry is a tag, for now just the size */ 2397c478bd9Sstevel@tonic-gate # define OFF_FILE_SYS(p) (((char *) (p)) + SHM_OFF_HEAD) 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate /* offset for PNumFileSys */ 2427c478bd9Sstevel@tonic-gate # define OFF_NUM_FILE_SYS(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys)) 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate /* offset for PRSATmpCnt */ 2457c478bd9Sstevel@tonic-gate # define OFF_RSA_TMP_CNT(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int)) 2467c478bd9Sstevel@tonic-gate int *PRSATmpCnt; 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate /* offset for queue_shm */ 2497c478bd9Sstevel@tonic-gate # define OFF_QUEUE_SHM(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2) 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate # define QSHM_ENTRIES(i) QShm[i].qs_entries 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate /* basic size of shared memory segment */ 2547c478bd9Sstevel@tonic-gate # define SM_T_SIZE (SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2) 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate static unsigned int hash_q __P((char *, unsigned int)); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* 2597c478bd9Sstevel@tonic-gate ** HASH_Q -- simple hash function 2607c478bd9Sstevel@tonic-gate ** 2617c478bd9Sstevel@tonic-gate ** Parameters: 2627c478bd9Sstevel@tonic-gate ** p -- string to hash. 2637c478bd9Sstevel@tonic-gate ** h -- hash start value (from previous run). 2647c478bd9Sstevel@tonic-gate ** 2657c478bd9Sstevel@tonic-gate ** Returns: 2667c478bd9Sstevel@tonic-gate ** hash value. 2677c478bd9Sstevel@tonic-gate */ 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate static unsigned int 2707c478bd9Sstevel@tonic-gate hash_q(p, h) 2717c478bd9Sstevel@tonic-gate char *p; 2727c478bd9Sstevel@tonic-gate unsigned int h; 2737c478bd9Sstevel@tonic-gate { 2747c478bd9Sstevel@tonic-gate int c, d; 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate while (*p != '\0') 2777c478bd9Sstevel@tonic-gate { 2787c478bd9Sstevel@tonic-gate d = *p++; 2797c478bd9Sstevel@tonic-gate c = d; 2807c478bd9Sstevel@tonic-gate c ^= c<<6; 2817c478bd9Sstevel@tonic-gate h += (c<<11) ^ (c>>1); 2827c478bd9Sstevel@tonic-gate h ^= (d<<14) + (d<<7) + (d<<4) + d; 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate return h; 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate #else /* SM_CONF_SHM */ 2897c478bd9Sstevel@tonic-gate # define FILE_SYS(i) FileSys[i] 2907c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate /* access to the various components of file system data */ 2937c478bd9Sstevel@tonic-gate #define FILE_SYS_NAME(i) FSPath[i] 2947c478bd9Sstevel@tonic-gate #define FILE_SYS_AVAIL(i) FILE_SYS(i).fs_avail 2957c478bd9Sstevel@tonic-gate #define FILE_SYS_BLKSIZE(i) FILE_SYS(i).fs_blksize 2967c478bd9Sstevel@tonic-gate #define FILE_SYS_DEV(i) FILE_SYS(i).fs_dev 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate /* 3007c478bd9Sstevel@tonic-gate ** Current qf file field assignments: 3017c478bd9Sstevel@tonic-gate ** 3027c478bd9Sstevel@tonic-gate ** A AUTH= parameter 3037c478bd9Sstevel@tonic-gate ** B body type 3047c478bd9Sstevel@tonic-gate ** C controlling user 3057c478bd9Sstevel@tonic-gate ** D data file name 3067c478bd9Sstevel@tonic-gate ** d data file directory name (added in 8.12) 3077c478bd9Sstevel@tonic-gate ** E error recipient 3087c478bd9Sstevel@tonic-gate ** F flag bits 3097c478bd9Sstevel@tonic-gate ** G free (was: queue delay algorithm if _FFR_QUEUEDELAY) 3107c478bd9Sstevel@tonic-gate ** H header 3117c478bd9Sstevel@tonic-gate ** I data file's inode number 3127c478bd9Sstevel@tonic-gate ** K time of last delivery attempt 3137c478bd9Sstevel@tonic-gate ** L Solaris Content-Length: header (obsolete) 3147c478bd9Sstevel@tonic-gate ** M message 3157c478bd9Sstevel@tonic-gate ** N number of delivery attempts 3167c478bd9Sstevel@tonic-gate ** P message priority 3177c478bd9Sstevel@tonic-gate ** q quarantine reason 3187c478bd9Sstevel@tonic-gate ** Q original recipient (ORCPT=) 3197c478bd9Sstevel@tonic-gate ** r final recipient (Final-Recipient: DSN field) 3207c478bd9Sstevel@tonic-gate ** R recipient 3217c478bd9Sstevel@tonic-gate ** S sender 3227c478bd9Sstevel@tonic-gate ** T init time 3237c478bd9Sstevel@tonic-gate ** V queue file version 3247c478bd9Sstevel@tonic-gate ** X free (was: character set if _FFR_SAVE_CHARSET) 3257c478bd9Sstevel@tonic-gate ** Y free (was: current delay if _FFR_QUEUEDELAY) 3267c478bd9Sstevel@tonic-gate ** Z original envelope id from ESMTP 3277c478bd9Sstevel@tonic-gate ** ! deliver by (added in 8.12) 3287c478bd9Sstevel@tonic-gate ** $ define macro 3297c478bd9Sstevel@tonic-gate ** . terminate file 3307c478bd9Sstevel@tonic-gate */ 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate ** QUEUEUP -- queue a message up for future transmission. 3347c478bd9Sstevel@tonic-gate ** 3357c478bd9Sstevel@tonic-gate ** Parameters: 3367c478bd9Sstevel@tonic-gate ** e -- the envelope to queue up. 3377c478bd9Sstevel@tonic-gate ** announce -- if true, tell when you are queueing up. 3387c478bd9Sstevel@tonic-gate ** msync -- if true, then fsync() if SuperSafe interactive mode. 3397c478bd9Sstevel@tonic-gate ** 3407c478bd9Sstevel@tonic-gate ** Returns: 3417c478bd9Sstevel@tonic-gate ** none. 3427c478bd9Sstevel@tonic-gate ** 3437c478bd9Sstevel@tonic-gate ** Side Effects: 3447c478bd9Sstevel@tonic-gate ** The current request is saved in a control file. 3457c478bd9Sstevel@tonic-gate ** The queue file is left locked. 3467c478bd9Sstevel@tonic-gate */ 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate void 3497c478bd9Sstevel@tonic-gate queueup(e, announce, msync) 3507c478bd9Sstevel@tonic-gate register ENVELOPE *e; 3517c478bd9Sstevel@tonic-gate bool announce; 3527c478bd9Sstevel@tonic-gate bool msync; 3537c478bd9Sstevel@tonic-gate { 3547c478bd9Sstevel@tonic-gate register SM_FILE_T *tfp; 3557c478bd9Sstevel@tonic-gate register HDR *h; 3567c478bd9Sstevel@tonic-gate register ADDRESS *q; 3577c478bd9Sstevel@tonic-gate int tfd = -1; 3587c478bd9Sstevel@tonic-gate int i; 3597c478bd9Sstevel@tonic-gate bool newid; 3607c478bd9Sstevel@tonic-gate register char *p; 3617c478bd9Sstevel@tonic-gate MAILER nullmailer; 3627c478bd9Sstevel@tonic-gate MCI mcibuf; 3637c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN]; 3647c478bd9Sstevel@tonic-gate char tf[MAXPATHLEN]; 3657c478bd9Sstevel@tonic-gate char df[MAXPATHLEN]; 3667c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate ** Create control file. 3707c478bd9Sstevel@tonic-gate */ 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate #define OPEN_TF do \ 3737c478bd9Sstevel@tonic-gate { \ 3747c478bd9Sstevel@tonic-gate MODE_T oldumask = 0; \ 3757c478bd9Sstevel@tonic-gate \ 3767c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) \ 3777c478bd9Sstevel@tonic-gate oldumask = umask(002); \ 3787c478bd9Sstevel@tonic-gate tfd = open(tf, TF_OPEN_FLAGS, QueueFileMode); \ 3797c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) \ 3807c478bd9Sstevel@tonic-gate (void) umask(oldumask); \ 3817c478bd9Sstevel@tonic-gate } while (0) 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags); 385*058561cbSjbeck (void) sm_strlcpy(tf, queuename(e, NEWQFL_LETTER), sizeof(tf)); 3867c478bd9Sstevel@tonic-gate tfp = e->e_lockfp; 3877c478bd9Sstevel@tonic-gate if (tfp == NULL && newid) 3887c478bd9Sstevel@tonic-gate { 3897c478bd9Sstevel@tonic-gate /* 3907c478bd9Sstevel@tonic-gate ** open qf file directly: this will give an error if the file 3917c478bd9Sstevel@tonic-gate ** already exists and hence prevent problems if a queue-id 3927c478bd9Sstevel@tonic-gate ** is reused (e.g., because the clock is set back). 3937c478bd9Sstevel@tonic-gate */ 3947c478bd9Sstevel@tonic-gate 395*058561cbSjbeck (void) sm_strlcpy(tf, queuename(e, ANYQFL_LETTER), sizeof(tf)); 3967c478bd9Sstevel@tonic-gate OPEN_TF; 3977c478bd9Sstevel@tonic-gate if (tfd < 0 || 3987c478bd9Sstevel@tonic-gate #if !SM_OPEN_EXLOCK 3997c478bd9Sstevel@tonic-gate !lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB) || 4007c478bd9Sstevel@tonic-gate #endif /* !SM_OPEN_EXLOCK */ 4017c478bd9Sstevel@tonic-gate (tfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 4027c478bd9Sstevel@tonic-gate (void *) &tfd, SM_IO_WRONLY, 4037c478bd9Sstevel@tonic-gate NULL)) == NULL) 4047c478bd9Sstevel@tonic-gate { 4057c478bd9Sstevel@tonic-gate int save_errno = errno; 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate printopenfds(true); 4087c478bd9Sstevel@tonic-gate errno = save_errno; 4097c478bd9Sstevel@tonic-gate syserr("!queueup: cannot create queue file %s, euid=%d, fd=%d, fp=%p", 4107c478bd9Sstevel@tonic-gate tf, (int) geteuid(), tfd, tfp); 4117c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate e->e_lockfp = tfp; 4147c478bd9Sstevel@tonic-gate upd_qs(e, 1, 0, "queueup"); 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* if newid, write the queue file directly (instead of temp file) */ 4187c478bd9Sstevel@tonic-gate if (!newid) 4197c478bd9Sstevel@tonic-gate { 4207c478bd9Sstevel@tonic-gate /* get a locked tf file */ 4217c478bd9Sstevel@tonic-gate for (i = 0; i < 128; i++) 4227c478bd9Sstevel@tonic-gate { 4237c478bd9Sstevel@tonic-gate if (tfd < 0) 4247c478bd9Sstevel@tonic-gate { 4257c478bd9Sstevel@tonic-gate OPEN_TF; 4267c478bd9Sstevel@tonic-gate if (tfd < 0) 4277c478bd9Sstevel@tonic-gate { 4287c478bd9Sstevel@tonic-gate if (errno != EEXIST) 4297c478bd9Sstevel@tonic-gate break; 4307c478bd9Sstevel@tonic-gate if (LogLevel > 0 && (i % 32) == 0) 4317c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 4327c478bd9Sstevel@tonic-gate "queueup: cannot create %s, uid=%d: %s", 4337c478bd9Sstevel@tonic-gate tf, (int) geteuid(), 4347c478bd9Sstevel@tonic-gate sm_errstring(errno)); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate #if SM_OPEN_EXLOCK 4377c478bd9Sstevel@tonic-gate else 4387c478bd9Sstevel@tonic-gate break; 4397c478bd9Sstevel@tonic-gate #endif /* SM_OPEN_EXLOCK */ 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate if (tfd >= 0) 4427c478bd9Sstevel@tonic-gate { 4437c478bd9Sstevel@tonic-gate #if SM_OPEN_EXLOCK 4447c478bd9Sstevel@tonic-gate /* file is locked by open() */ 4457c478bd9Sstevel@tonic-gate break; 4467c478bd9Sstevel@tonic-gate #else /* SM_OPEN_EXLOCK */ 4477c478bd9Sstevel@tonic-gate if (lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB)) 4487c478bd9Sstevel@tonic-gate break; 4497c478bd9Sstevel@tonic-gate else 4507c478bd9Sstevel@tonic-gate #endif /* SM_OPEN_EXLOCK */ 4517c478bd9Sstevel@tonic-gate if (LogLevel > 0 && (i % 32) == 0) 4527c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 4537c478bd9Sstevel@tonic-gate "queueup: cannot lock %s: %s", 4547c478bd9Sstevel@tonic-gate tf, sm_errstring(errno)); 4557c478bd9Sstevel@tonic-gate if ((i % 32) == 31) 4567c478bd9Sstevel@tonic-gate { 4577c478bd9Sstevel@tonic-gate (void) close(tfd); 4587c478bd9Sstevel@tonic-gate tfd = -1; 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate if ((i % 32) == 31) 4637c478bd9Sstevel@tonic-gate { 4647c478bd9Sstevel@tonic-gate /* save the old temp file away */ 4657c478bd9Sstevel@tonic-gate (void) rename(tf, queuename(e, TEMPQF_LETTER)); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate else 4687c478bd9Sstevel@tonic-gate (void) sleep(i % 32); 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate if (tfd < 0 || (tfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 4717c478bd9Sstevel@tonic-gate (void *) &tfd, SM_IO_WRONLY_B, 4727c478bd9Sstevel@tonic-gate NULL)) == NULL) 4737c478bd9Sstevel@tonic-gate { 4747c478bd9Sstevel@tonic-gate int save_errno = errno; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate printopenfds(true); 4777c478bd9Sstevel@tonic-gate errno = save_errno; 4787c478bd9Sstevel@tonic-gate syserr("!queueup: cannot create queue temp file %s, uid=%d", 4797c478bd9Sstevel@tonic-gate tf, (int) geteuid()); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 4847c478bd9Sstevel@tonic-gate sm_dprintf("\n>>>>> queueing %s/%s%s >>>>>\n", 4857c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir), 4867c478bd9Sstevel@tonic-gate queuename(e, ANYQFL_LETTER), 4877c478bd9Sstevel@tonic-gate newid ? " (new id)" : ""); 4887c478bd9Sstevel@tonic-gate if (tTd(40, 3)) 4897c478bd9Sstevel@tonic-gate { 4907c478bd9Sstevel@tonic-gate sm_dprintf(" e_flags="); 4917c478bd9Sstevel@tonic-gate printenvflags(e); 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate if (tTd(40, 32)) 4947c478bd9Sstevel@tonic-gate { 4957c478bd9Sstevel@tonic-gate sm_dprintf(" sendq="); 4967c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), e->e_sendqueue, true); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate if (tTd(40, 9)) 4997c478bd9Sstevel@tonic-gate { 5007c478bd9Sstevel@tonic-gate sm_dprintf(" tfp="); 5017c478bd9Sstevel@tonic-gate dumpfd(sm_io_getinfo(tfp, SM_IO_WHAT_FD, NULL), true, false); 5027c478bd9Sstevel@tonic-gate sm_dprintf(" lockfp="); 5037c478bd9Sstevel@tonic-gate if (e->e_lockfp == NULL) 5047c478bd9Sstevel@tonic-gate sm_dprintf("NULL\n"); 5057c478bd9Sstevel@tonic-gate else 5067c478bd9Sstevel@tonic-gate dumpfd(sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL), 5077c478bd9Sstevel@tonic-gate true, false); 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* 5117c478bd9Sstevel@tonic-gate ** If there is no data file yet, create one. 5127c478bd9Sstevel@tonic-gate */ 5137c478bd9Sstevel@tonic-gate 514*058561cbSjbeck (void) sm_strlcpy(df, queuename(e, DATAFL_LETTER), sizeof(df)); 5157c478bd9Sstevel@tonic-gate if (bitset(EF_HAS_DF, e->e_flags)) 5167c478bd9Sstevel@tonic-gate { 5177c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL && 5187c478bd9Sstevel@tonic-gate SuperSafe != SAFE_REALLY && 5197c478bd9Sstevel@tonic-gate SuperSafe != SAFE_REALLY_POSTMILTER && 5207c478bd9Sstevel@tonic-gate sm_io_setinfo(e->e_dfp, SM_BF_COMMIT, NULL) < 0 && 5217c478bd9Sstevel@tonic-gate errno != EINVAL) 5227c478bd9Sstevel@tonic-gate { 5237c478bd9Sstevel@tonic-gate syserr("!queueup: cannot commit data file %s, uid=%d", 5247c478bd9Sstevel@tonic-gate queuename(e, DATAFL_LETTER), (int) geteuid()); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL && 5277c478bd9Sstevel@tonic-gate SuperSafe == SAFE_INTERACTIVE && msync) 5287c478bd9Sstevel@tonic-gate { 5297c478bd9Sstevel@tonic-gate if (tTd(40,32)) 5307c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 5317c478bd9Sstevel@tonic-gate "queueup: fsync(e->e_dfp)"); 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate if (fsync(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, 5347c478bd9Sstevel@tonic-gate NULL)) < 0) 5357c478bd9Sstevel@tonic-gate { 5367c478bd9Sstevel@tonic-gate if (newid) 5377c478bd9Sstevel@tonic-gate syserr("!552 Error writing data file %s", 5387c478bd9Sstevel@tonic-gate df); 5397c478bd9Sstevel@tonic-gate else 5407c478bd9Sstevel@tonic-gate syserr("!452 Error writing data file %s", 5417c478bd9Sstevel@tonic-gate df); 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate else 5467c478bd9Sstevel@tonic-gate { 5477c478bd9Sstevel@tonic-gate int dfd; 5487c478bd9Sstevel@tonic-gate MODE_T oldumask = 0; 5497c478bd9Sstevel@tonic-gate register SM_FILE_T *dfp = NULL; 5507c478bd9Sstevel@tonic-gate struct stat stbuf; 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL && 5537c478bd9Sstevel@tonic-gate sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE)) 5547c478bd9Sstevel@tonic-gate syserr("committing over bf file"); 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 5577c478bd9Sstevel@tonic-gate oldumask = umask(002); 5587c478bd9Sstevel@tonic-gate dfd = open(df, O_WRONLY|O_CREAT|O_TRUNC|QF_O_EXTRA, 5597c478bd9Sstevel@tonic-gate QueueFileMode); 5607c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 5617c478bd9Sstevel@tonic-gate (void) umask(oldumask); 5627c478bd9Sstevel@tonic-gate if (dfd < 0 || (dfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 5637c478bd9Sstevel@tonic-gate (void *) &dfd, SM_IO_WRONLY_B, 5647c478bd9Sstevel@tonic-gate NULL)) == NULL) 5657c478bd9Sstevel@tonic-gate syserr("!queueup: cannot create data temp file %s, uid=%d", 5667c478bd9Sstevel@tonic-gate df, (int) geteuid()); 5677c478bd9Sstevel@tonic-gate if (fstat(dfd, &stbuf) < 0) 5687c478bd9Sstevel@tonic-gate e->e_dfino = -1; 5697c478bd9Sstevel@tonic-gate else 5707c478bd9Sstevel@tonic-gate { 5717c478bd9Sstevel@tonic-gate e->e_dfdev = stbuf.st_dev; 5727c478bd9Sstevel@tonic-gate e->e_dfino = ST_INODE(stbuf); 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS_DF; 575*058561cbSjbeck memset(&mcibuf, '\0', sizeof(mcibuf)); 5767c478bd9Sstevel@tonic-gate mcibuf.mci_out = dfp; 5777c478bd9Sstevel@tonic-gate mcibuf.mci_mailer = FileMailer; 5787c478bd9Sstevel@tonic-gate (*e->e_putbody)(&mcibuf, e, NULL); 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate if (SuperSafe == SAFE_REALLY || 5817c478bd9Sstevel@tonic-gate SuperSafe == SAFE_REALLY_POSTMILTER || 5827c478bd9Sstevel@tonic-gate (SuperSafe == SAFE_INTERACTIVE && msync)) 5837c478bd9Sstevel@tonic-gate { 5847c478bd9Sstevel@tonic-gate if (tTd(40,32)) 5857c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 5867c478bd9Sstevel@tonic-gate "queueup: fsync(dfp)"); 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate if (fsync(sm_io_getinfo(dfp, SM_IO_WHAT_FD, NULL)) < 0) 5897c478bd9Sstevel@tonic-gate { 5907c478bd9Sstevel@tonic-gate if (newid) 5917c478bd9Sstevel@tonic-gate syserr("!552 Error writing data file %s", 5927c478bd9Sstevel@tonic-gate df); 5937c478bd9Sstevel@tonic-gate else 5947c478bd9Sstevel@tonic-gate syserr("!452 Error writing data file %s", 5957c478bd9Sstevel@tonic-gate df); 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate if (sm_io_close(dfp, SM_TIME_DEFAULT) < 0) 6007c478bd9Sstevel@tonic-gate syserr("!queueup: cannot save data temp file %s, uid=%d", 6017c478bd9Sstevel@tonic-gate df, (int) geteuid()); 6027c478bd9Sstevel@tonic-gate e->e_putbody = putbody; 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate /* 6067c478bd9Sstevel@tonic-gate ** Output future work requests. 6077c478bd9Sstevel@tonic-gate ** Priority and creation time should be first, since 6087c478bd9Sstevel@tonic-gate ** they are required by gatherq. 6097c478bd9Sstevel@tonic-gate */ 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate /* output queue version number (must be first!) */ 6127c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "V%d\n", QF_VERSION); 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate /* output creation time */ 6157c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "T%ld\n", (long) e->e_ctime); 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate /* output last delivery time */ 6187c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "K%ld\n", (long) e->e_dtime); 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate /* output number of delivery attempts */ 6217c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "N%d\n", e->e_ntries); 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate /* output message priority */ 6247c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "P%ld\n", e->e_msgpriority); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate /* 6277c478bd9Sstevel@tonic-gate ** If data file is in a different directory than the queue file, 6287c478bd9Sstevel@tonic-gate ** output a "d" record naming the directory of the data file. 6297c478bd9Sstevel@tonic-gate */ 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate if (e->e_dfqgrp != e->e_qgrp) 6327c478bd9Sstevel@tonic-gate { 6337c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "d%s\n", 6347c478bd9Sstevel@tonic-gate Queue[e->e_dfqgrp]->qg_qpaths[e->e_dfqdir].qp_name); 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate /* output inode number of data file */ 6387c478bd9Sstevel@tonic-gate /* XXX should probably include device major/minor too */ 6397c478bd9Sstevel@tonic-gate if (e->e_dfino != -1) 6407c478bd9Sstevel@tonic-gate { 6417c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "I%ld/%ld/%llu\n", 6427c478bd9Sstevel@tonic-gate (long) major(e->e_dfdev), 6437c478bd9Sstevel@tonic-gate (long) minor(e->e_dfdev), 6447c478bd9Sstevel@tonic-gate (ULONGLONG_T) e->e_dfino); 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate /* output body type */ 6487c478bd9Sstevel@tonic-gate if (e->e_bodytype != NULL) 6497c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "B%s\n", 6507c478bd9Sstevel@tonic-gate denlstring(e->e_bodytype, true, false)); 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate /* quarantine reason */ 6537c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 6547c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "q%s\n", 6557c478bd9Sstevel@tonic-gate denlstring(e->e_quarmsg, true, false)); 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate /* message from envelope, if it exists */ 6587c478bd9Sstevel@tonic-gate if (e->e_message != NULL) 6597c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "M%s\n", 6607c478bd9Sstevel@tonic-gate denlstring(e->e_message, true, false)); 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate /* send various flag bits through */ 6637c478bd9Sstevel@tonic-gate p = buf; 6647c478bd9Sstevel@tonic-gate if (bitset(EF_WARNING, e->e_flags)) 6657c478bd9Sstevel@tonic-gate *p++ = 'w'; 6667c478bd9Sstevel@tonic-gate if (bitset(EF_RESPONSE, e->e_flags)) 6677c478bd9Sstevel@tonic-gate *p++ = 'r'; 6687c478bd9Sstevel@tonic-gate if (bitset(EF_HAS8BIT, e->e_flags)) 6697c478bd9Sstevel@tonic-gate *p++ = '8'; 6707c478bd9Sstevel@tonic-gate if (bitset(EF_DELETE_BCC, e->e_flags)) 6717c478bd9Sstevel@tonic-gate *p++ = 'b'; 6727c478bd9Sstevel@tonic-gate if (bitset(EF_RET_PARAM, e->e_flags)) 6737c478bd9Sstevel@tonic-gate *p++ = 'd'; 6747c478bd9Sstevel@tonic-gate if (bitset(EF_NO_BODY_RETN, e->e_flags)) 6757c478bd9Sstevel@tonic-gate *p++ = 'n'; 6767c478bd9Sstevel@tonic-gate if (bitset(EF_SPLIT, e->e_flags)) 6777c478bd9Sstevel@tonic-gate *p++ = 's'; 6787c478bd9Sstevel@tonic-gate *p++ = '\0'; 6797c478bd9Sstevel@tonic-gate if (buf[0] != '\0') 6807c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "F%s\n", buf); 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate /* save $={persistentMacros} macro values */ 6837c478bd9Sstevel@tonic-gate queueup_macros(macid("{persistentMacros}"), tfp, e); 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate /* output name of sender */ 6867c478bd9Sstevel@tonic-gate if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 6877c478bd9Sstevel@tonic-gate p = e->e_sender; 6887c478bd9Sstevel@tonic-gate else 6897c478bd9Sstevel@tonic-gate p = e->e_from.q_paddr; 6907c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "S%s\n", 6917c478bd9Sstevel@tonic-gate denlstring(p, true, false)); 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate /* output ESMTP-supplied "original" information */ 6947c478bd9Sstevel@tonic-gate if (e->e_envid != NULL) 6957c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Z%s\n", 6967c478bd9Sstevel@tonic-gate denlstring(e->e_envid, true, false)); 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate /* output AUTH= parameter */ 6997c478bd9Sstevel@tonic-gate if (e->e_auth_param != NULL) 7007c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "A%s\n", 7017c478bd9Sstevel@tonic-gate denlstring(e->e_auth_param, true, false)); 7027c478bd9Sstevel@tonic-gate if (e->e_dlvr_flag != 0) 7037c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "!%c %ld\n", 7047c478bd9Sstevel@tonic-gate (char) e->e_dlvr_flag, e->e_deliver_by); 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate /* output list of recipient addresses */ 7077c478bd9Sstevel@tonic-gate printctladdr(NULL, NULL); 7087c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 7097c478bd9Sstevel@tonic-gate { 7107c478bd9Sstevel@tonic-gate if (!QS_IS_UNDELIVERED(q->q_state)) 7117c478bd9Sstevel@tonic-gate continue; 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate /* message for this recipient, if it exists */ 7147c478bd9Sstevel@tonic-gate if (q->q_message != NULL) 7157c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "M%s\n", 7167c478bd9Sstevel@tonic-gate denlstring(q->q_message, true, 7177c478bd9Sstevel@tonic-gate false)); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate printctladdr(q, tfp); 7207c478bd9Sstevel@tonic-gate if (q->q_orcpt != NULL) 7217c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Q%s\n", 7227c478bd9Sstevel@tonic-gate denlstring(q->q_orcpt, true, 7237c478bd9Sstevel@tonic-gate false)); 7247c478bd9Sstevel@tonic-gate if (q->q_finalrcpt != NULL) 7257c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "r%s\n", 7267c478bd9Sstevel@tonic-gate denlstring(q->q_finalrcpt, true, 7277c478bd9Sstevel@tonic-gate false)); 7287c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'R'); 7297c478bd9Sstevel@tonic-gate if (bitset(QPRIMARY, q->q_flags)) 7307c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'P'); 7317c478bd9Sstevel@tonic-gate if (bitset(QHASNOTIFY, q->q_flags)) 7327c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'N'); 7337c478bd9Sstevel@tonic-gate if (bitset(QPINGONSUCCESS, q->q_flags)) 7347c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'S'); 7357c478bd9Sstevel@tonic-gate if (bitset(QPINGONFAILURE, q->q_flags)) 7367c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'F'); 7377c478bd9Sstevel@tonic-gate if (bitset(QPINGONDELAY, q->q_flags)) 7387c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'D'); 7397c478bd9Sstevel@tonic-gate if (q->q_alias != NULL && 7407c478bd9Sstevel@tonic-gate bitset(QALIAS, q->q_alias->q_flags)) 7417c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'A'); 7427c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, ':'); 7437c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s\n", 7447c478bd9Sstevel@tonic-gate denlstring(q->q_paddr, true, false)); 7457c478bd9Sstevel@tonic-gate if (announce) 7467c478bd9Sstevel@tonic-gate { 7477c478bd9Sstevel@tonic-gate char *tag = "queued"; 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 7507c478bd9Sstevel@tonic-gate tag = "quarantined"; 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate e->e_to = q->q_paddr; 7537c478bd9Sstevel@tonic-gate message(tag); 7547c478bd9Sstevel@tonic-gate if (LogLevel > 8) 7557c478bd9Sstevel@tonic-gate logdelivery(q->q_mailer, NULL, q->q_status, 7567c478bd9Sstevel@tonic-gate tag, NULL, (time_t) 0, e); 7577c478bd9Sstevel@tonic-gate e->e_to = NULL; 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 7607c478bd9Sstevel@tonic-gate { 7617c478bd9Sstevel@tonic-gate sm_dprintf("queueing "); 7627c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), q, false); 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate /* 7677c478bd9Sstevel@tonic-gate ** Output headers for this message. 7687c478bd9Sstevel@tonic-gate ** Expand macros completely here. Queue run will deal with 7697c478bd9Sstevel@tonic-gate ** everything as absolute headers. 7707c478bd9Sstevel@tonic-gate ** All headers that must be relative to the recipient 7717c478bd9Sstevel@tonic-gate ** can be cracked later. 7727c478bd9Sstevel@tonic-gate ** We set up a "null mailer" -- i.e., a mailer that will have 7737c478bd9Sstevel@tonic-gate ** no effect on the addresses as they are output. 7747c478bd9Sstevel@tonic-gate */ 7757c478bd9Sstevel@tonic-gate 776*058561cbSjbeck memset((char *) &nullmailer, '\0', sizeof(nullmailer)); 7777c478bd9Sstevel@tonic-gate nullmailer.m_re_rwset = nullmailer.m_rh_rwset = 7787c478bd9Sstevel@tonic-gate nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1; 7797c478bd9Sstevel@tonic-gate nullmailer.m_eol = "\n"; 780*058561cbSjbeck memset(&mcibuf, '\0', sizeof(mcibuf)); 7817c478bd9Sstevel@tonic-gate mcibuf.mci_mailer = &nullmailer; 7827c478bd9Sstevel@tonic-gate mcibuf.mci_out = tfp; 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'g', "\201f"); 7857c478bd9Sstevel@tonic-gate for (h = e->e_header; h != NULL; h = h->h_link) 7867c478bd9Sstevel@tonic-gate { 7877c478bd9Sstevel@tonic-gate if (h->h_value == NULL) 7887c478bd9Sstevel@tonic-gate continue; 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate /* don't output resent headers on non-resent messages */ 7917c478bd9Sstevel@tonic-gate if (bitset(H_RESENT, h->h_flags) && 7927c478bd9Sstevel@tonic-gate !bitset(EF_RESENT, e->e_flags)) 7937c478bd9Sstevel@tonic-gate continue; 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate /* expand macros; if null, don't output header at all */ 7967c478bd9Sstevel@tonic-gate if (bitset(H_DEFAULT, h->h_flags)) 7977c478bd9Sstevel@tonic-gate { 798*058561cbSjbeck (void) expand(h->h_value, buf, sizeof(buf), e); 7997c478bd9Sstevel@tonic-gate if (buf[0] == '\0') 8007c478bd9Sstevel@tonic-gate 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 { 834*058561cbSjbeck (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; 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate commaize(h, h->h_value, oldstyle, &mcibuf, e); 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate TrafficLogFile = savetrace; 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate else 8547c478bd9Sstevel@tonic-gate { 855*058561cbSjbeck (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), 890*058561cbSjbeck 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 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 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 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 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 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 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 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 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 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 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 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 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 { 21097c478bd9Sstevel@tonic-gate h = gatherq(qgrp, qdir, false, &full, &more); 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 21507c478bd9Sstevel@tonic-gate /* No need to have more runners then there are jobs */ 21517c478bd9Sstevel@tonic-gate if (maxrunners > njobs) 21527c478bd9Sstevel@tonic-gate maxrunners = njobs; 21537c478bd9Sstevel@tonic-gate for (loop = 0; loop < maxrunners; loop++) 21547c478bd9Sstevel@tonic-gate { 21557c478bd9Sstevel@tonic-gate /* 21567c478bd9Sstevel@tonic-gate ** Since the delivery may happen in a child and the 21577c478bd9Sstevel@tonic-gate ** parent does not wait, the parent may close the 21587c478bd9Sstevel@tonic-gate ** maps thereby removing any shared memory used by 21597c478bd9Sstevel@tonic-gate ** the map. Therefore, close the maps now so the 21607c478bd9Sstevel@tonic-gate ** child will dynamically open them if necessary. 21617c478bd9Sstevel@tonic-gate */ 21627c478bd9Sstevel@tonic-gate 21637c478bd9Sstevel@tonic-gate closemaps(false); 21647c478bd9Sstevel@tonic-gate 21657c478bd9Sstevel@tonic-gate pid = fork(); 21667c478bd9Sstevel@tonic-gate if (pid < 0) 21677c478bd9Sstevel@tonic-gate { 21687c478bd9Sstevel@tonic-gate syserr("run_work_group: cannot fork"); 21697c478bd9Sstevel@tonic-gate return false; 21707c478bd9Sstevel@tonic-gate } 21717c478bd9Sstevel@tonic-gate else if (pid > 0) 21727c478bd9Sstevel@tonic-gate { 21737c478bd9Sstevel@tonic-gate /* parent -- clean out connection cache */ 21747c478bd9Sstevel@tonic-gate mci_flush(false, NULL); 21757c478bd9Sstevel@tonic-gate #if _FFR_SKIP_DOMAINS 21767c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST) 21777c478bd9Sstevel@tonic-gate { 21787c478bd9Sstevel@tonic-gate sequenceno += skip_domains(1); 21797c478bd9Sstevel@tonic-gate } 21807c478bd9Sstevel@tonic-gate else 21817c478bd9Sstevel@tonic-gate #endif /* _FFR_SKIP_DOMAINS */ 21827c478bd9Sstevel@tonic-gate { 21837c478bd9Sstevel@tonic-gate /* for the skip */ 21847c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next; 21857c478bd9Sstevel@tonic-gate sequenceno++; 21867c478bd9Sstevel@tonic-gate } 21877c478bd9Sstevel@tonic-gate proc_list_add(pid, "Queue child runner process", 21887c478bd9Sstevel@tonic-gate PROC_QUEUE_CHILD, 0, -1, NULL); 21897c478bd9Sstevel@tonic-gate 21907c478bd9Sstevel@tonic-gate /* No additional work, no additional runners */ 21917c478bd9Sstevel@tonic-gate if (WorkQ == NULL) 21927c478bd9Sstevel@tonic-gate break; 21937c478bd9Sstevel@tonic-gate } 21947c478bd9Sstevel@tonic-gate else 21957c478bd9Sstevel@tonic-gate { 21967c478bd9Sstevel@tonic-gate /* child -- Reset global flags */ 21977c478bd9Sstevel@tonic-gate RestartRequest = NULL; 21987c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 21997c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 22007c478bd9Sstevel@tonic-gate PendingSignal = 0; 22017c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 22027c478bd9Sstevel@tonic-gate close_sendmail_pid(); 22037c478bd9Sstevel@tonic-gate 22047c478bd9Sstevel@tonic-gate /* 22057c478bd9Sstevel@tonic-gate ** Initialize exception stack and default 22067c478bd9Sstevel@tonic-gate ** exception handler for child process. 22077c478bd9Sstevel@tonic-gate ** When fork()'d the child now has a private 22087c478bd9Sstevel@tonic-gate ** copy of WorkQ at its current position. 22097c478bd9Sstevel@tonic-gate */ 22107c478bd9Sstevel@tonic-gate 22117c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error); 22127c478bd9Sstevel@tonic-gate 22137c478bd9Sstevel@tonic-gate /* 22147c478bd9Sstevel@tonic-gate ** SMTP processes (whether -bd or -bs) set 22157c478bd9Sstevel@tonic-gate ** SIGCHLD to reapchild to collect 22167c478bd9Sstevel@tonic-gate ** children status. However, at delivery 22177c478bd9Sstevel@tonic-gate ** time, that status must be collected 22187c478bd9Sstevel@tonic-gate ** by sm_wait() to be dealt with properly 22197c478bd9Sstevel@tonic-gate ** (check success of delivery based 22207c478bd9Sstevel@tonic-gate ** on status code, etc). Therefore, if we 22217c478bd9Sstevel@tonic-gate ** are an SMTP process, reset SIGCHLD 22227c478bd9Sstevel@tonic-gate ** back to the default so reapchild 22237c478bd9Sstevel@tonic-gate ** doesn't collect status before 22247c478bd9Sstevel@tonic-gate ** sm_wait(). 22257c478bd9Sstevel@tonic-gate */ 22267c478bd9Sstevel@tonic-gate 22277c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP || 22287c478bd9Sstevel@tonic-gate OpMode == MD_DAEMON || 22297c478bd9Sstevel@tonic-gate MaxQueueChildren > 0) 22307c478bd9Sstevel@tonic-gate { 22317c478bd9Sstevel@tonic-gate proc_list_clear(); 22327c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD); 22337c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 22347c478bd9Sstevel@tonic-gate } 22357c478bd9Sstevel@tonic-gate 22367c478bd9Sstevel@tonic-gate /* child -- error messages to the transcript */ 22377c478bd9Sstevel@tonic-gate QuickAbort = OnlyOneError = false; 22387c478bd9Sstevel@tonic-gate runner_work(e, sequenceno, true, 22397c478bd9Sstevel@tonic-gate maxrunners, njobs); 22407c478bd9Sstevel@tonic-gate 22417c478bd9Sstevel@tonic-gate /* This child is done */ 22427c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 22437c478bd9Sstevel@tonic-gate /* NOTREACHED */ 22447c478bd9Sstevel@tonic-gate } 22457c478bd9Sstevel@tonic-gate } 22467c478bd9Sstevel@tonic-gate 22477c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD); 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate /* 22507c478bd9Sstevel@tonic-gate ** Wait until all of the runners have completed before 22517c478bd9Sstevel@tonic-gate ** seeing if there is another queue group in the 22527c478bd9Sstevel@tonic-gate ** work group to process. 22537c478bd9Sstevel@tonic-gate ** XXX Future enhancement: don't wait() for all children 22547c478bd9Sstevel@tonic-gate ** here, just go ahead and make sure that overall the number 22557c478bd9Sstevel@tonic-gate ** of children is not exceeded. 22567c478bd9Sstevel@tonic-gate */ 22577c478bd9Sstevel@tonic-gate 22587c478bd9Sstevel@tonic-gate while (CurChildren > 0) 22597c478bd9Sstevel@tonic-gate { 22607c478bd9Sstevel@tonic-gate int status; 22617c478bd9Sstevel@tonic-gate pid_t ret; 22627c478bd9Sstevel@tonic-gate 22637c478bd9Sstevel@tonic-gate while ((ret = sm_wait(&status)) <= 0) 22647c478bd9Sstevel@tonic-gate continue; 22657c478bd9Sstevel@tonic-gate proc_list_drop(ret, status, NULL); 22667c478bd9Sstevel@tonic-gate } 22677c478bd9Sstevel@tonic-gate } 22687c478bd9Sstevel@tonic-gate else if (Queue[qgrp]->qg_maxqrun > 0 || bitset(RWG_FORCE, flags)) 22697c478bd9Sstevel@tonic-gate { 22707c478bd9Sstevel@tonic-gate /* 22717c478bd9Sstevel@tonic-gate ** When current process will not fork children to do the work, 22727c478bd9Sstevel@tonic-gate ** it will do the work itself. The 'skip' will be 1 since 22737c478bd9Sstevel@tonic-gate ** there are no child runners to divide the work across. 22747c478bd9Sstevel@tonic-gate */ 22757c478bd9Sstevel@tonic-gate 22767c478bd9Sstevel@tonic-gate runner_work(e, sequenceno, false, 1, njobs); 22777c478bd9Sstevel@tonic-gate } 22787c478bd9Sstevel@tonic-gate 22797c478bd9Sstevel@tonic-gate /* free memory allocated by newenvelope() above */ 22807c478bd9Sstevel@tonic-gate sm_rpool_free(rpool); 22817c478bd9Sstevel@tonic-gate QueueEnvelope.e_rpool = NULL; 22827c478bd9Sstevel@tonic-gate 22837c478bd9Sstevel@tonic-gate /* Are there still more queues in the work group to process? */ 22847c478bd9Sstevel@tonic-gate if (endgrp != WorkGrp[wgrp].wg_curqgrp) 22857c478bd9Sstevel@tonic-gate { 22867c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL); 22877c478bd9Sstevel@tonic-gate e = newenvelope(&QueueEnvelope, CurEnv, rpool); 22887c478bd9Sstevel@tonic-gate e->e_flags = BlankEnvelope.e_flags; 22897c478bd9Sstevel@tonic-gate goto domorework; 22907c478bd9Sstevel@tonic-gate } 22917c478bd9Sstevel@tonic-gate 22927c478bd9Sstevel@tonic-gate /* No more queues in work group to process. Now check persistent. */ 22937c478bd9Sstevel@tonic-gate if (bitset(RWG_PERSISTENT, flags)) 22947c478bd9Sstevel@tonic-gate { 22957c478bd9Sstevel@tonic-gate sequenceno = 1; 22967c478bd9Sstevel@tonic-gate sm_setproctitle(true, CurEnv, "running queue: %s", 22977c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 22987c478bd9Sstevel@tonic-gate 22997c478bd9Sstevel@tonic-gate /* 23007c478bd9Sstevel@tonic-gate ** close bogus maps, i.e., maps which caused a tempfail, 23017c478bd9Sstevel@tonic-gate ** so we get fresh map connections on the next lookup. 23027c478bd9Sstevel@tonic-gate ** closemaps() is also called when children are started. 23037c478bd9Sstevel@tonic-gate */ 23047c478bd9Sstevel@tonic-gate 23057c478bd9Sstevel@tonic-gate closemaps(true); 23067c478bd9Sstevel@tonic-gate 23077c478bd9Sstevel@tonic-gate /* Close any cached connections. */ 23087c478bd9Sstevel@tonic-gate mci_flush(true, NULL); 23097c478bd9Sstevel@tonic-gate 23107c478bd9Sstevel@tonic-gate /* Clean out expired related entries. */ 23117c478bd9Sstevel@tonic-gate rmexpstab(); 23127c478bd9Sstevel@tonic-gate 23137c478bd9Sstevel@tonic-gate #if NAMED_BIND 23147c478bd9Sstevel@tonic-gate /* Update MX records for FallbackMX. */ 23157c478bd9Sstevel@tonic-gate if (FallbackMX != NULL) 23167c478bd9Sstevel@tonic-gate (void) getfallbackmxrr(FallbackMX); 23177c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 23187c478bd9Sstevel@tonic-gate 23197c478bd9Sstevel@tonic-gate #if USERDB 23207c478bd9Sstevel@tonic-gate /* close UserDatabase */ 23217c478bd9Sstevel@tonic-gate _udbx_close(); 23227c478bd9Sstevel@tonic-gate #endif /* USERDB */ 23237c478bd9Sstevel@tonic-gate 23247c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 23257c478bd9Sstevel@tonic-gate if (sm_debug_active(&SmHeapCheck, 2) 23267c478bd9Sstevel@tonic-gate && access("memdump", F_OK) == 0 23277c478bd9Sstevel@tonic-gate ) 23287c478bd9Sstevel@tonic-gate { 23297c478bd9Sstevel@tonic-gate SM_FILE_T *out; 23307c478bd9Sstevel@tonic-gate 23317c478bd9Sstevel@tonic-gate remove("memdump"); 23327c478bd9Sstevel@tonic-gate out = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, 23337c478bd9Sstevel@tonic-gate "memdump.out", SM_IO_APPEND, NULL); 23347c478bd9Sstevel@tonic-gate if (out != NULL) 23357c478bd9Sstevel@tonic-gate { 23367c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, "----------------------\n"); 23377c478bd9Sstevel@tonic-gate sm_heap_report(out, 23387c478bd9Sstevel@tonic-gate sm_debug_level(&SmHeapCheck) - 1); 23397c478bd9Sstevel@tonic-gate (void) sm_io_close(out, SM_TIME_DEFAULT); 23407c478bd9Sstevel@tonic-gate } 23417c478bd9Sstevel@tonic-gate } 23427c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 23437c478bd9Sstevel@tonic-gate 23447c478bd9Sstevel@tonic-gate /* let me rest for a second to catch my breath */ 23457c478bd9Sstevel@tonic-gate if (njobs == 0 && WorkGrp[wgrp].wg_lowqintvl < MIN_SLEEP_TIME) 23467c478bd9Sstevel@tonic-gate sleep(MIN_SLEEP_TIME); 23477c478bd9Sstevel@tonic-gate else if (WorkGrp[wgrp].wg_lowqintvl <= 0) 23487c478bd9Sstevel@tonic-gate sleep(QueueIntvl > 0 ? QueueIntvl : MIN_SLEEP_TIME); 23497c478bd9Sstevel@tonic-gate else 23507c478bd9Sstevel@tonic-gate sleep(WorkGrp[wgrp].wg_lowqintvl); 23517c478bd9Sstevel@tonic-gate 23527c478bd9Sstevel@tonic-gate /* 23537c478bd9Sstevel@tonic-gate ** Get the LA outside the WorkQ loop if necessary. 23547c478bd9Sstevel@tonic-gate ** In a persistent queue runner the code is repeated over 23557c478bd9Sstevel@tonic-gate ** and over but gatherq() may ignore entries due to 23567c478bd9Sstevel@tonic-gate ** shouldqueue() (do we really have to do this twice?). 23577c478bd9Sstevel@tonic-gate ** Hence the queue runners would just idle around when once 23587c478bd9Sstevel@tonic-gate ** CurrentLA caused all entries in a queue to be ignored. 23597c478bd9Sstevel@tonic-gate */ 23607c478bd9Sstevel@tonic-gate 23617c478bd9Sstevel@tonic-gate if (njobs == 0) 23627c478bd9Sstevel@tonic-gate SM_GET_LA(now); 23637c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL); 23647c478bd9Sstevel@tonic-gate e = newenvelope(&QueueEnvelope, CurEnv, rpool); 23657c478bd9Sstevel@tonic-gate e->e_flags = BlankEnvelope.e_flags; 23667c478bd9Sstevel@tonic-gate goto domorework; 23677c478bd9Sstevel@tonic-gate } 23687c478bd9Sstevel@tonic-gate 23697c478bd9Sstevel@tonic-gate /* exit without the usual cleanup */ 23707c478bd9Sstevel@tonic-gate e->e_id = NULL; 23717c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags)) 23727c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 23737c478bd9Sstevel@tonic-gate /* NOTREACHED */ 23747c478bd9Sstevel@tonic-gate return true; 23757c478bd9Sstevel@tonic-gate } 23767c478bd9Sstevel@tonic-gate 23777c478bd9Sstevel@tonic-gate /* 23787c478bd9Sstevel@tonic-gate ** DOQUEUERUN -- do a queue run? 23797c478bd9Sstevel@tonic-gate */ 23807c478bd9Sstevel@tonic-gate 23817c478bd9Sstevel@tonic-gate bool 23827c478bd9Sstevel@tonic-gate doqueuerun() 23837c478bd9Sstevel@tonic-gate { 23847c478bd9Sstevel@tonic-gate return DoQueueRun; 23857c478bd9Sstevel@tonic-gate } 23867c478bd9Sstevel@tonic-gate 23877c478bd9Sstevel@tonic-gate /* 23887c478bd9Sstevel@tonic-gate ** RUNQUEUEEVENT -- Sets a flag to indicate that a queue run should be done. 23897c478bd9Sstevel@tonic-gate ** 23907c478bd9Sstevel@tonic-gate ** Parameters: 23917c478bd9Sstevel@tonic-gate ** none. 23927c478bd9Sstevel@tonic-gate ** 23937c478bd9Sstevel@tonic-gate ** Returns: 23947c478bd9Sstevel@tonic-gate ** none. 23957c478bd9Sstevel@tonic-gate ** 23967c478bd9Sstevel@tonic-gate ** Side Effects: 23977c478bd9Sstevel@tonic-gate ** The invocation of this function via an alarm may interrupt 23987c478bd9Sstevel@tonic-gate ** a set of actions. Thus errno may be set in that context. 23997c478bd9Sstevel@tonic-gate ** We need to restore errno at the end of this function to ensure 24007c478bd9Sstevel@tonic-gate ** that any work done here that sets errno doesn't return a 24017c478bd9Sstevel@tonic-gate ** misleading/false errno value. Errno may be EINTR upon entry to 24027c478bd9Sstevel@tonic-gate ** this function because of non-restartable/continuable system 24037c478bd9Sstevel@tonic-gate ** API was active. Iff this is true we will override errno as 24047c478bd9Sstevel@tonic-gate ** a timeout (as a more accurate error message). 24057c478bd9Sstevel@tonic-gate ** 24067c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 24077c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 24087c478bd9Sstevel@tonic-gate ** DOING. 24097c478bd9Sstevel@tonic-gate */ 24107c478bd9Sstevel@tonic-gate 24117c478bd9Sstevel@tonic-gate void 24127c478bd9Sstevel@tonic-gate runqueueevent(ignore) 24137c478bd9Sstevel@tonic-gate int ignore; 24147c478bd9Sstevel@tonic-gate { 24157c478bd9Sstevel@tonic-gate int save_errno = errno; 24167c478bd9Sstevel@tonic-gate 24177c478bd9Sstevel@tonic-gate /* 24187c478bd9Sstevel@tonic-gate ** Set the general bit that we want a queue run, 24197c478bd9Sstevel@tonic-gate ** tested in doqueuerun() 24207c478bd9Sstevel@tonic-gate */ 24217c478bd9Sstevel@tonic-gate 24227c478bd9Sstevel@tonic-gate DoQueueRun = true; 24237c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 24247c478bd9Sstevel@tonic-gate if (tTd(69, 10)) 24257c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "rqe: done"); 24267c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 24277c478bd9Sstevel@tonic-gate 24287c478bd9Sstevel@tonic-gate errno = save_errno; 24297c478bd9Sstevel@tonic-gate if (errno == EINTR) 24307c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 24317c478bd9Sstevel@tonic-gate } 24327c478bd9Sstevel@tonic-gate /* 24337c478bd9Sstevel@tonic-gate ** GATHERQ -- gather messages from the message queue(s) the work queue. 24347c478bd9Sstevel@tonic-gate ** 24357c478bd9Sstevel@tonic-gate ** Parameters: 24367c478bd9Sstevel@tonic-gate ** qgrp -- the index of the queue group. 24377c478bd9Sstevel@tonic-gate ** qdir -- the index of the queue directory. 24387c478bd9Sstevel@tonic-gate ** doall -- if set, include everything in the queue (even 24397c478bd9Sstevel@tonic-gate ** the jobs that cannot be run because the load 24407c478bd9Sstevel@tonic-gate ** average is too high, or MaxQueueRun is reached). 24417c478bd9Sstevel@tonic-gate ** Otherwise, exclude those jobs. 24427c478bd9Sstevel@tonic-gate ** full -- (optional) to be set 'true' if WorkList is full 24437c478bd9Sstevel@tonic-gate ** more -- (optional) to be set 'true' if there are still more 24447c478bd9Sstevel@tonic-gate ** messages in this queue not added to WorkList 24457c478bd9Sstevel@tonic-gate ** 24467c478bd9Sstevel@tonic-gate ** Returns: 24477c478bd9Sstevel@tonic-gate ** The number of request in the queue (not necessarily 24487c478bd9Sstevel@tonic-gate ** the number of requests in WorkList however). 24497c478bd9Sstevel@tonic-gate ** 24507c478bd9Sstevel@tonic-gate ** Side Effects: 24517c478bd9Sstevel@tonic-gate ** prepares available work into WorkList 24527c478bd9Sstevel@tonic-gate */ 24537c478bd9Sstevel@tonic-gate 24547c478bd9Sstevel@tonic-gate #define NEED_P 0001 /* 'P': priority */ 24557c478bd9Sstevel@tonic-gate #define NEED_T 0002 /* 'T': time */ 24567c478bd9Sstevel@tonic-gate #define NEED_R 0004 /* 'R': recipient */ 24577c478bd9Sstevel@tonic-gate #define NEED_S 0010 /* 'S': sender */ 24587c478bd9Sstevel@tonic-gate #define NEED_H 0020 /* host */ 24597c478bd9Sstevel@tonic-gate #define HAS_QUARANTINE 0040 /* has an unexpected 'q' line */ 24607c478bd9Sstevel@tonic-gate #define NEED_QUARANTINE 0100 /* 'q': reason */ 24617c478bd9Sstevel@tonic-gate 24627c478bd9Sstevel@tonic-gate static WORK *WorkList = NULL; /* list of unsort work */ 24637c478bd9Sstevel@tonic-gate static int WorkListSize = 0; /* current max size of WorkList */ 24647c478bd9Sstevel@tonic-gate static int WorkListCount = 0; /* # of work items in WorkList */ 24657c478bd9Sstevel@tonic-gate 24667c478bd9Sstevel@tonic-gate static int 24677c478bd9Sstevel@tonic-gate gatherq(qgrp, qdir, doall, full, more) 24687c478bd9Sstevel@tonic-gate int qgrp; 24697c478bd9Sstevel@tonic-gate int qdir; 24707c478bd9Sstevel@tonic-gate bool doall; 24717c478bd9Sstevel@tonic-gate bool *full; 24727c478bd9Sstevel@tonic-gate bool *more; 24737c478bd9Sstevel@tonic-gate { 24747c478bd9Sstevel@tonic-gate register struct dirent *d; 24757c478bd9Sstevel@tonic-gate register WORK *w; 24767c478bd9Sstevel@tonic-gate register char *p; 24777c478bd9Sstevel@tonic-gate DIR *f; 24787c478bd9Sstevel@tonic-gate int i, num_ent; 24797c478bd9Sstevel@tonic-gate int wn; 24807c478bd9Sstevel@tonic-gate QUEUE_CHAR *check; 24817c478bd9Sstevel@tonic-gate char qd[MAXPATHLEN]; 24827c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN]; 24837c478bd9Sstevel@tonic-gate 24847c478bd9Sstevel@tonic-gate wn = WorkListCount - 1; 24857c478bd9Sstevel@tonic-gate num_ent = 0; 24867c478bd9Sstevel@tonic-gate if (qdir == NOQDIR) 2487*058561cbSjbeck (void) sm_strlcpy(qd, ".", sizeof(qd)); 24887c478bd9Sstevel@tonic-gate else 2489*058561cbSjbeck (void) sm_strlcpyn(qd, sizeof(qd), 2, 24907c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name, 24917c478bd9Sstevel@tonic-gate (bitset(QP_SUBQF, 24927c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs) 24937c478bd9Sstevel@tonic-gate ? "/qf" : "")); 24947c478bd9Sstevel@tonic-gate 24957c478bd9Sstevel@tonic-gate if (tTd(41, 1)) 24967c478bd9Sstevel@tonic-gate { 24977c478bd9Sstevel@tonic-gate sm_dprintf("gatherq:\n"); 24987c478bd9Sstevel@tonic-gate 24997c478bd9Sstevel@tonic-gate check = QueueLimitId; 25007c478bd9Sstevel@tonic-gate while (check != NULL) 25017c478bd9Sstevel@tonic-gate { 25027c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitId = %s%s\n", 25037c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "", 25047c478bd9Sstevel@tonic-gate check->queue_match); 25057c478bd9Sstevel@tonic-gate check = check->queue_next; 25067c478bd9Sstevel@tonic-gate } 25077c478bd9Sstevel@tonic-gate 25087c478bd9Sstevel@tonic-gate check = QueueLimitSender; 25097c478bd9Sstevel@tonic-gate while (check != NULL) 25107c478bd9Sstevel@tonic-gate { 25117c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitSender = %s%s\n", 25127c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "", 25137c478bd9Sstevel@tonic-gate check->queue_match); 25147c478bd9Sstevel@tonic-gate check = check->queue_next; 25157c478bd9Sstevel@tonic-gate } 25167c478bd9Sstevel@tonic-gate 25177c478bd9Sstevel@tonic-gate check = QueueLimitRecipient; 25187c478bd9Sstevel@tonic-gate while (check != NULL) 25197c478bd9Sstevel@tonic-gate { 25207c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitRecipient = %s%s\n", 25217c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "", 25227c478bd9Sstevel@tonic-gate check->queue_match); 25237c478bd9Sstevel@tonic-gate check = check->queue_next; 25247c478bd9Sstevel@tonic-gate } 25257c478bd9Sstevel@tonic-gate 25267c478bd9Sstevel@tonic-gate if (QueueMode == QM_QUARANTINE) 25277c478bd9Sstevel@tonic-gate { 25287c478bd9Sstevel@tonic-gate check = QueueLimitQuarantine; 25297c478bd9Sstevel@tonic-gate while (check != NULL) 25307c478bd9Sstevel@tonic-gate { 25317c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitQuarantine = %s%s\n", 25327c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "", 25337c478bd9Sstevel@tonic-gate check->queue_match); 25347c478bd9Sstevel@tonic-gate check = check->queue_next; 25357c478bd9Sstevel@tonic-gate } 25367c478bd9Sstevel@tonic-gate } 25377c478bd9Sstevel@tonic-gate } 25387c478bd9Sstevel@tonic-gate 25397c478bd9Sstevel@tonic-gate /* open the queue directory */ 25407c478bd9Sstevel@tonic-gate f = opendir(qd); 25417c478bd9Sstevel@tonic-gate if (f == NULL) 25427c478bd9Sstevel@tonic-gate { 25437c478bd9Sstevel@tonic-gate syserr("gatherq: cannot open \"%s\"", 25447c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 25457c478bd9Sstevel@tonic-gate if (full != NULL) 25467c478bd9Sstevel@tonic-gate *full = WorkListCount >= MaxQueueRun && MaxQueueRun > 0; 25477c478bd9Sstevel@tonic-gate if (more != NULL) 25487c478bd9Sstevel@tonic-gate *more = false; 25497c478bd9Sstevel@tonic-gate return 0; 25507c478bd9Sstevel@tonic-gate } 25517c478bd9Sstevel@tonic-gate 25527c478bd9Sstevel@tonic-gate /* 25537c478bd9Sstevel@tonic-gate ** Read the work directory. 25547c478bd9Sstevel@tonic-gate */ 25557c478bd9Sstevel@tonic-gate 25567c478bd9Sstevel@tonic-gate while ((d = readdir(f)) != NULL) 25577c478bd9Sstevel@tonic-gate { 25587c478bd9Sstevel@tonic-gate SM_FILE_T *cf; 25597c478bd9Sstevel@tonic-gate int qfver = 0; 25607c478bd9Sstevel@tonic-gate char lbuf[MAXNAME + 1]; 25617c478bd9Sstevel@tonic-gate struct stat sbuf; 25627c478bd9Sstevel@tonic-gate 25637c478bd9Sstevel@tonic-gate if (tTd(41, 50)) 25647c478bd9Sstevel@tonic-gate sm_dprintf("gatherq: checking %s..", d->d_name); 25657c478bd9Sstevel@tonic-gate 25667c478bd9Sstevel@tonic-gate /* is this an interesting entry? */ 25677c478bd9Sstevel@tonic-gate if (!(((QueueMode == QM_NORMAL && 25687c478bd9Sstevel@tonic-gate d->d_name[0] == NORMQF_LETTER) || 25697c478bd9Sstevel@tonic-gate (QueueMode == QM_QUARANTINE && 25707c478bd9Sstevel@tonic-gate d->d_name[0] == QUARQF_LETTER) || 25717c478bd9Sstevel@tonic-gate (QueueMode == QM_LOST && 25727c478bd9Sstevel@tonic-gate d->d_name[0] == LOSEQF_LETTER)) && 25737c478bd9Sstevel@tonic-gate d->d_name[1] == 'f')) 25747c478bd9Sstevel@tonic-gate { 25757c478bd9Sstevel@tonic-gate if (tTd(41, 50)) 25767c478bd9Sstevel@tonic-gate sm_dprintf(" skipping\n"); 25777c478bd9Sstevel@tonic-gate continue; 25787c478bd9Sstevel@tonic-gate } 25797c478bd9Sstevel@tonic-gate if (tTd(41, 50)) 25807c478bd9Sstevel@tonic-gate sm_dprintf("\n"); 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate if (strlen(d->d_name) >= MAXQFNAME) 25837c478bd9Sstevel@tonic-gate { 25847c478bd9Sstevel@tonic-gate if (Verbose) 25857c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 25867c478bd9Sstevel@tonic-gate "gatherq: %s too long, %d max characters\n", 25877c478bd9Sstevel@tonic-gate d->d_name, MAXQFNAME); 25887c478bd9Sstevel@tonic-gate if (LogLevel > 0) 25897c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, NOQID, 25907c478bd9Sstevel@tonic-gate "gatherq: %s too long, %d max characters", 25917c478bd9Sstevel@tonic-gate d->d_name, MAXQFNAME); 25927c478bd9Sstevel@tonic-gate continue; 25937c478bd9Sstevel@tonic-gate } 25947c478bd9Sstevel@tonic-gate 25957c478bd9Sstevel@tonic-gate check = QueueLimitId; 25967c478bd9Sstevel@tonic-gate while (check != NULL) 25977c478bd9Sstevel@tonic-gate { 25987c478bd9Sstevel@tonic-gate if (strcontainedin(false, check->queue_match, 25997c478bd9Sstevel@tonic-gate d->d_name) != check->queue_negate) 26007c478bd9Sstevel@tonic-gate break; 26017c478bd9Sstevel@tonic-gate else 26027c478bd9Sstevel@tonic-gate check = check->queue_next; 26037c478bd9Sstevel@tonic-gate } 26047c478bd9Sstevel@tonic-gate if (QueueLimitId != NULL && check == NULL) 26057c478bd9Sstevel@tonic-gate continue; 26067c478bd9Sstevel@tonic-gate 26077c478bd9Sstevel@tonic-gate /* grow work list if necessary */ 26087c478bd9Sstevel@tonic-gate if (++wn >= MaxQueueRun && MaxQueueRun > 0) 26097c478bd9Sstevel@tonic-gate { 26107c478bd9Sstevel@tonic-gate if (wn == MaxQueueRun && LogLevel > 0) 26117c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 26127c478bd9Sstevel@tonic-gate "WorkList for %s maxed out at %d", 26137c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), 26147c478bd9Sstevel@tonic-gate MaxQueueRun); 26157c478bd9Sstevel@tonic-gate if (doall) 26167c478bd9Sstevel@tonic-gate continue; /* just count entries */ 26177c478bd9Sstevel@tonic-gate break; 26187c478bd9Sstevel@tonic-gate } 26197c478bd9Sstevel@tonic-gate if (wn >= WorkListSize) 26207c478bd9Sstevel@tonic-gate { 26217c478bd9Sstevel@tonic-gate grow_wlist(qgrp, qdir); 26227c478bd9Sstevel@tonic-gate if (wn >= WorkListSize) 26237c478bd9Sstevel@tonic-gate continue; 26247c478bd9Sstevel@tonic-gate } 26257c478bd9Sstevel@tonic-gate SM_ASSERT(wn >= 0); 26267c478bd9Sstevel@tonic-gate w = &WorkList[wn]; 26277c478bd9Sstevel@tonic-gate 2628*058561cbSjbeck (void) sm_strlcpyn(qf, sizeof(qf), 3, qd, "/", d->d_name); 26297c478bd9Sstevel@tonic-gate if (stat(qf, &sbuf) < 0) 26307c478bd9Sstevel@tonic-gate { 26317c478bd9Sstevel@tonic-gate if (errno != ENOENT) 26327c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 26337c478bd9Sstevel@tonic-gate "gatherq: can't stat %s/%s", 26347c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), 26357c478bd9Sstevel@tonic-gate d->d_name); 26367c478bd9Sstevel@tonic-gate wn--; 26377c478bd9Sstevel@tonic-gate continue; 26387c478bd9Sstevel@tonic-gate } 26397c478bd9Sstevel@tonic-gate if (!bitset(S_IFREG, sbuf.st_mode)) 26407c478bd9Sstevel@tonic-gate { 26417c478bd9Sstevel@tonic-gate /* Yikes! Skip it or we will hang on open! */ 26427c478bd9Sstevel@tonic-gate if (!((d->d_name[0] == DATAFL_LETTER || 26437c478bd9Sstevel@tonic-gate d->d_name[0] == NORMQF_LETTER || 26447c478bd9Sstevel@tonic-gate d->d_name[0] == QUARQF_LETTER || 26457c478bd9Sstevel@tonic-gate d->d_name[0] == LOSEQF_LETTER || 26467c478bd9Sstevel@tonic-gate d->d_name[0] == XSCRPT_LETTER) && 26477c478bd9Sstevel@tonic-gate d->d_name[1] == 'f' && d->d_name[2] == '\0')) 26487c478bd9Sstevel@tonic-gate syserr("gatherq: %s/%s is not a regular file", 26497c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), d->d_name); 26507c478bd9Sstevel@tonic-gate wn--; 26517c478bd9Sstevel@tonic-gate continue; 26527c478bd9Sstevel@tonic-gate } 26537c478bd9Sstevel@tonic-gate 26547c478bd9Sstevel@tonic-gate /* avoid work if possible */ 26557c478bd9Sstevel@tonic-gate if ((QueueSortOrder == QSO_BYFILENAME || 26567c478bd9Sstevel@tonic-gate QueueSortOrder == QSO_BYMODTIME || 26571daa5768Sjbeck QueueSortOrder == QSO_NONE || 26587c478bd9Sstevel@tonic-gate QueueSortOrder == QSO_RANDOM) && 26597c478bd9Sstevel@tonic-gate QueueLimitQuarantine == NULL && 26607c478bd9Sstevel@tonic-gate QueueLimitSender == NULL && 26617c478bd9Sstevel@tonic-gate QueueLimitRecipient == NULL) 26627c478bd9Sstevel@tonic-gate { 26637c478bd9Sstevel@tonic-gate w->w_qgrp = qgrp; 26647c478bd9Sstevel@tonic-gate w->w_qdir = qdir; 26657c478bd9Sstevel@tonic-gate w->w_name = newstr(d->d_name); 26667c478bd9Sstevel@tonic-gate w->w_host = NULL; 26677c478bd9Sstevel@tonic-gate w->w_lock = w->w_tooyoung = false; 26687c478bd9Sstevel@tonic-gate w->w_pri = 0; 26697c478bd9Sstevel@tonic-gate w->w_ctime = 0; 26707c478bd9Sstevel@tonic-gate w->w_mtime = sbuf.st_mtime; 26717c478bd9Sstevel@tonic-gate ++num_ent; 26727c478bd9Sstevel@tonic-gate continue; 26737c478bd9Sstevel@tonic-gate } 26747c478bd9Sstevel@tonic-gate 26757c478bd9Sstevel@tonic-gate /* open control file */ 26767c478bd9Sstevel@tonic-gate cf = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY_B, 26777c478bd9Sstevel@tonic-gate NULL); 26787c478bd9Sstevel@tonic-gate if (cf == NULL && OpMode != MD_PRINT) 26797c478bd9Sstevel@tonic-gate { 26807c478bd9Sstevel@tonic-gate /* this may be some random person sending hir msgs */ 26817c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 26827c478bd9Sstevel@tonic-gate sm_dprintf("gatherq: cannot open %s: %s\n", 26837c478bd9Sstevel@tonic-gate d->d_name, sm_errstring(errno)); 26847c478bd9Sstevel@tonic-gate errno = 0; 26857c478bd9Sstevel@tonic-gate wn--; 26867c478bd9Sstevel@tonic-gate continue; 26877c478bd9Sstevel@tonic-gate } 26887c478bd9Sstevel@tonic-gate w->w_qgrp = qgrp; 26897c478bd9Sstevel@tonic-gate w->w_qdir = qdir; 26907c478bd9Sstevel@tonic-gate w->w_name = newstr(d->d_name); 26917c478bd9Sstevel@tonic-gate w->w_host = NULL; 26927c478bd9Sstevel@tonic-gate if (cf != NULL) 26937c478bd9Sstevel@tonic-gate { 26947c478bd9Sstevel@tonic-gate w->w_lock = !lockfile(sm_io_getinfo(cf, SM_IO_WHAT_FD, 26957c478bd9Sstevel@tonic-gate NULL), 26967c478bd9Sstevel@tonic-gate w->w_name, NULL, 26977c478bd9Sstevel@tonic-gate LOCK_SH|LOCK_NB); 26987c478bd9Sstevel@tonic-gate } 26997c478bd9Sstevel@tonic-gate w->w_tooyoung = false; 27007c478bd9Sstevel@tonic-gate 27017c478bd9Sstevel@tonic-gate /* make sure jobs in creation don't clog queue */ 27027c478bd9Sstevel@tonic-gate w->w_pri = 0x7fffffff; 27037c478bd9Sstevel@tonic-gate w->w_ctime = 0; 27047c478bd9Sstevel@tonic-gate w->w_mtime = sbuf.st_mtime; 27057c478bd9Sstevel@tonic-gate 27067c478bd9Sstevel@tonic-gate /* extract useful information */ 27077c478bd9Sstevel@tonic-gate i = NEED_P|NEED_T; 27087c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST 27097c478bd9Sstevel@tonic-gate #if _FFR_RHS 27107c478bd9Sstevel@tonic-gate || QueueSortOrder == QSO_BYSHUFFLE 27117c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 27127c478bd9Sstevel@tonic-gate ) 27137c478bd9Sstevel@tonic-gate { 27147c478bd9Sstevel@tonic-gate /* need w_host set for host sort order */ 27157c478bd9Sstevel@tonic-gate i |= NEED_H; 27167c478bd9Sstevel@tonic-gate } 27177c478bd9Sstevel@tonic-gate if (QueueLimitSender != NULL) 27187c478bd9Sstevel@tonic-gate i |= NEED_S; 27197c478bd9Sstevel@tonic-gate if (QueueLimitRecipient != NULL) 27207c478bd9Sstevel@tonic-gate i |= NEED_R; 27217c478bd9Sstevel@tonic-gate if (QueueLimitQuarantine != NULL) 27227c478bd9Sstevel@tonic-gate i |= NEED_QUARANTINE; 27237c478bd9Sstevel@tonic-gate while (cf != NULL && i != 0 && 27247c478bd9Sstevel@tonic-gate sm_io_fgets(cf, SM_TIME_DEFAULT, lbuf, 2725*058561cbSjbeck sizeof(lbuf)) != NULL) 27267c478bd9Sstevel@tonic-gate { 27277c478bd9Sstevel@tonic-gate int c; 27287c478bd9Sstevel@tonic-gate time_t age; 27297c478bd9Sstevel@tonic-gate 27307c478bd9Sstevel@tonic-gate p = strchr(lbuf, '\n'); 27317c478bd9Sstevel@tonic-gate if (p != NULL) 27327c478bd9Sstevel@tonic-gate *p = '\0'; 27337c478bd9Sstevel@tonic-gate else 27347c478bd9Sstevel@tonic-gate { 27357c478bd9Sstevel@tonic-gate /* flush rest of overly long line */ 27367c478bd9Sstevel@tonic-gate while ((c = sm_io_getc(cf, SM_TIME_DEFAULT)) 27377c478bd9Sstevel@tonic-gate != SM_IO_EOF && c != '\n') 27387c478bd9Sstevel@tonic-gate continue; 27397c478bd9Sstevel@tonic-gate } 27407c478bd9Sstevel@tonic-gate 27417c478bd9Sstevel@tonic-gate switch (lbuf[0]) 27427c478bd9Sstevel@tonic-gate { 27437c478bd9Sstevel@tonic-gate case 'V': 27447c478bd9Sstevel@tonic-gate qfver = atoi(&lbuf[1]); 27457c478bd9Sstevel@tonic-gate break; 27467c478bd9Sstevel@tonic-gate 27477c478bd9Sstevel@tonic-gate case 'P': 27487c478bd9Sstevel@tonic-gate w->w_pri = atol(&lbuf[1]); 27497c478bd9Sstevel@tonic-gate i &= ~NEED_P; 27507c478bd9Sstevel@tonic-gate break; 27517c478bd9Sstevel@tonic-gate 27527c478bd9Sstevel@tonic-gate case 'T': 27537c478bd9Sstevel@tonic-gate w->w_ctime = atol(&lbuf[1]); 27547c478bd9Sstevel@tonic-gate i &= ~NEED_T; 27557c478bd9Sstevel@tonic-gate break; 27567c478bd9Sstevel@tonic-gate 27577c478bd9Sstevel@tonic-gate case 'q': 27587c478bd9Sstevel@tonic-gate if (QueueMode != QM_QUARANTINE && 27597c478bd9Sstevel@tonic-gate QueueMode != QM_LOST) 27607c478bd9Sstevel@tonic-gate { 27617c478bd9Sstevel@tonic-gate if (tTd(41, 49)) 27627c478bd9Sstevel@tonic-gate sm_dprintf("%s not marked as quarantined but has a 'q' line\n", 27637c478bd9Sstevel@tonic-gate w->w_name); 27647c478bd9Sstevel@tonic-gate i |= HAS_QUARANTINE; 27657c478bd9Sstevel@tonic-gate } 27667c478bd9Sstevel@tonic-gate else if (QueueMode == QM_QUARANTINE) 27677c478bd9Sstevel@tonic-gate { 27687c478bd9Sstevel@tonic-gate if (QueueLimitQuarantine == NULL) 27697c478bd9Sstevel@tonic-gate { 27707c478bd9Sstevel@tonic-gate i &= ~NEED_QUARANTINE; 27717c478bd9Sstevel@tonic-gate break; 27727c478bd9Sstevel@tonic-gate } 27737c478bd9Sstevel@tonic-gate p = &lbuf[1]; 27747c478bd9Sstevel@tonic-gate check = QueueLimitQuarantine; 27757c478bd9Sstevel@tonic-gate while (check != NULL) 27767c478bd9Sstevel@tonic-gate { 27777c478bd9Sstevel@tonic-gate if (strcontainedin(false, 27787c478bd9Sstevel@tonic-gate check->queue_match, 27797c478bd9Sstevel@tonic-gate p) != 27807c478bd9Sstevel@tonic-gate check->queue_negate) 27817c478bd9Sstevel@tonic-gate break; 27827c478bd9Sstevel@tonic-gate else 27837c478bd9Sstevel@tonic-gate check = check->queue_next; 27847c478bd9Sstevel@tonic-gate } 27857c478bd9Sstevel@tonic-gate if (check != NULL) 27867c478bd9Sstevel@tonic-gate i &= ~NEED_QUARANTINE; 27877c478bd9Sstevel@tonic-gate } 27887c478bd9Sstevel@tonic-gate break; 27897c478bd9Sstevel@tonic-gate 27907c478bd9Sstevel@tonic-gate case 'R': 27917c478bd9Sstevel@tonic-gate if (w->w_host == NULL && 27927c478bd9Sstevel@tonic-gate (p = strrchr(&lbuf[1], '@')) != NULL) 27937c478bd9Sstevel@tonic-gate { 27947c478bd9Sstevel@tonic-gate #if _FFR_RHS 27957c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYSHUFFLE) 27967c478bd9Sstevel@tonic-gate w->w_host = newstr(&p[1]); 27977c478bd9Sstevel@tonic-gate else 27987c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 27997c478bd9Sstevel@tonic-gate w->w_host = strrev(&p[1]); 28007c478bd9Sstevel@tonic-gate makelower(w->w_host); 28017c478bd9Sstevel@tonic-gate i &= ~NEED_H; 28027c478bd9Sstevel@tonic-gate } 28037c478bd9Sstevel@tonic-gate if (QueueLimitRecipient == NULL) 28047c478bd9Sstevel@tonic-gate { 28057c478bd9Sstevel@tonic-gate i &= ~NEED_R; 28067c478bd9Sstevel@tonic-gate break; 28077c478bd9Sstevel@tonic-gate } 28087c478bd9Sstevel@tonic-gate if (qfver > 0) 28097c478bd9Sstevel@tonic-gate { 28107c478bd9Sstevel@tonic-gate p = strchr(&lbuf[1], ':'); 28117c478bd9Sstevel@tonic-gate if (p == NULL) 28127c478bd9Sstevel@tonic-gate p = &lbuf[1]; 28137c478bd9Sstevel@tonic-gate else 28147c478bd9Sstevel@tonic-gate ++p; /* skip over ':' */ 28157c478bd9Sstevel@tonic-gate } 28167c478bd9Sstevel@tonic-gate else 28177c478bd9Sstevel@tonic-gate p = &lbuf[1]; 28187c478bd9Sstevel@tonic-gate check = QueueLimitRecipient; 28197c478bd9Sstevel@tonic-gate while (check != NULL) 28207c478bd9Sstevel@tonic-gate { 28217c478bd9Sstevel@tonic-gate if (strcontainedin(true, 28227c478bd9Sstevel@tonic-gate check->queue_match, 28237c478bd9Sstevel@tonic-gate p) != 28247c478bd9Sstevel@tonic-gate check->queue_negate) 28257c478bd9Sstevel@tonic-gate break; 28267c478bd9Sstevel@tonic-gate else 28277c478bd9Sstevel@tonic-gate check = check->queue_next; 28287c478bd9Sstevel@tonic-gate } 28297c478bd9Sstevel@tonic-gate if (check != NULL) 28307c478bd9Sstevel@tonic-gate i &= ~NEED_R; 28317c478bd9Sstevel@tonic-gate break; 28327c478bd9Sstevel@tonic-gate 28337c478bd9Sstevel@tonic-gate case 'S': 28347c478bd9Sstevel@tonic-gate check = QueueLimitSender; 28357c478bd9Sstevel@tonic-gate while (check != NULL) 28367c478bd9Sstevel@tonic-gate { 28377c478bd9Sstevel@tonic-gate if (strcontainedin(true, 28387c478bd9Sstevel@tonic-gate check->queue_match, 28397c478bd9Sstevel@tonic-gate &lbuf[1]) != 28407c478bd9Sstevel@tonic-gate check->queue_negate) 28417c478bd9Sstevel@tonic-gate break; 28427c478bd9Sstevel@tonic-gate else 28437c478bd9Sstevel@tonic-gate check = check->queue_next; 28447c478bd9Sstevel@tonic-gate } 28457c478bd9Sstevel@tonic-gate if (check != NULL) 28467c478bd9Sstevel@tonic-gate i &= ~NEED_S; 28477c478bd9Sstevel@tonic-gate break; 28487c478bd9Sstevel@tonic-gate 28497c478bd9Sstevel@tonic-gate case 'K': 28507c478bd9Sstevel@tonic-gate age = curtime() - (time_t) atol(&lbuf[1]); 28517c478bd9Sstevel@tonic-gate if (age >= 0 && MinQueueAge > 0 && 28527c478bd9Sstevel@tonic-gate age < MinQueueAge) 28537c478bd9Sstevel@tonic-gate w->w_tooyoung = true; 28547c478bd9Sstevel@tonic-gate break; 28557c478bd9Sstevel@tonic-gate 28567c478bd9Sstevel@tonic-gate case 'N': 28577c478bd9Sstevel@tonic-gate if (atol(&lbuf[1]) == 0) 28587c478bd9Sstevel@tonic-gate w->w_tooyoung = false; 28597c478bd9Sstevel@tonic-gate break; 28607c478bd9Sstevel@tonic-gate } 28617c478bd9Sstevel@tonic-gate } 28627c478bd9Sstevel@tonic-gate if (cf != NULL) 28637c478bd9Sstevel@tonic-gate (void) sm_io_close(cf, SM_TIME_DEFAULT); 28647c478bd9Sstevel@tonic-gate 2865445f2479Sjbeck if ((!doall && (shouldqueue(w->w_pri, w->w_ctime) || 2866445f2479Sjbeck w->w_tooyoung)) || 28677c478bd9Sstevel@tonic-gate bitset(HAS_QUARANTINE, i) || 28687c478bd9Sstevel@tonic-gate bitset(NEED_QUARANTINE, i) || 28697c478bd9Sstevel@tonic-gate bitset(NEED_R|NEED_S, i)) 28707c478bd9Sstevel@tonic-gate { 28717c478bd9Sstevel@tonic-gate /* don't even bother sorting this job in */ 28727c478bd9Sstevel@tonic-gate if (tTd(41, 49)) 28737c478bd9Sstevel@tonic-gate sm_dprintf("skipping %s (%x)\n", w->w_name, i); 28747c478bd9Sstevel@tonic-gate sm_free(w->w_name); /* XXX */ 28757c478bd9Sstevel@tonic-gate if (w->w_host != NULL) 28767c478bd9Sstevel@tonic-gate sm_free(w->w_host); /* XXX */ 28777c478bd9Sstevel@tonic-gate wn--; 28787c478bd9Sstevel@tonic-gate } 28797c478bd9Sstevel@tonic-gate else 28807c478bd9Sstevel@tonic-gate ++num_ent; 28817c478bd9Sstevel@tonic-gate } 28827c478bd9Sstevel@tonic-gate (void) closedir(f); 28837c478bd9Sstevel@tonic-gate wn++; 28847c478bd9Sstevel@tonic-gate 28857c478bd9Sstevel@tonic-gate i = wn - WorkListCount; 28867c478bd9Sstevel@tonic-gate WorkListCount += SM_MIN(num_ent, WorkListSize); 28877c478bd9Sstevel@tonic-gate 28887c478bd9Sstevel@tonic-gate if (more != NULL) 28897c478bd9Sstevel@tonic-gate *more = WorkListCount < wn; 28907c478bd9Sstevel@tonic-gate 28917c478bd9Sstevel@tonic-gate if (full != NULL) 28927c478bd9Sstevel@tonic-gate *full = (wn >= MaxQueueRun && MaxQueueRun > 0) || 28937c478bd9Sstevel@tonic-gate (WorkList == NULL && wn > 0); 28947c478bd9Sstevel@tonic-gate 28957c478bd9Sstevel@tonic-gate return i; 28967c478bd9Sstevel@tonic-gate } 28977c478bd9Sstevel@tonic-gate /* 28987c478bd9Sstevel@tonic-gate ** SORTQ -- sort the work list 28997c478bd9Sstevel@tonic-gate ** 29007c478bd9Sstevel@tonic-gate ** First the old WorkQ is cleared away. Then the WorkList is sorted 29017c478bd9Sstevel@tonic-gate ** for all items so that important (higher sorting value) items are not 29027c478bd9Sstevel@tonic-gate ** trunctated off. Then the most important items are moved from 29037c478bd9Sstevel@tonic-gate ** WorkList to WorkQ. The lower count of 'max' or MaxListCount items 29047c478bd9Sstevel@tonic-gate ** are moved. 29057c478bd9Sstevel@tonic-gate ** 29067c478bd9Sstevel@tonic-gate ** Parameters: 29077c478bd9Sstevel@tonic-gate ** max -- maximum number of items to be placed in WorkQ 29087c478bd9Sstevel@tonic-gate ** 29097c478bd9Sstevel@tonic-gate ** Returns: 29107c478bd9Sstevel@tonic-gate ** the number of items in WorkQ 29117c478bd9Sstevel@tonic-gate ** 29127c478bd9Sstevel@tonic-gate ** Side Effects: 29137c478bd9Sstevel@tonic-gate ** WorkQ gets released and filled with new work. WorkList 29147c478bd9Sstevel@tonic-gate ** gets released. Work items get sorted in order. 29157c478bd9Sstevel@tonic-gate */ 29167c478bd9Sstevel@tonic-gate 29177c478bd9Sstevel@tonic-gate static int 29187c478bd9Sstevel@tonic-gate sortq(max) 29197c478bd9Sstevel@tonic-gate int max; 29207c478bd9Sstevel@tonic-gate { 29217c478bd9Sstevel@tonic-gate register int i; /* local counter */ 29227c478bd9Sstevel@tonic-gate register WORK *w; /* tmp item pointer */ 29237c478bd9Sstevel@tonic-gate int wc = WorkListCount; /* trim size for WorkQ */ 29247c478bd9Sstevel@tonic-gate 29257c478bd9Sstevel@tonic-gate if (WorkQ != NULL) 29267c478bd9Sstevel@tonic-gate { 29277c478bd9Sstevel@tonic-gate WORK *nw; 29287c478bd9Sstevel@tonic-gate 29297c478bd9Sstevel@tonic-gate /* Clear out old WorkQ. */ 29307c478bd9Sstevel@tonic-gate for (w = WorkQ; w != NULL; w = nw) 29317c478bd9Sstevel@tonic-gate { 29327c478bd9Sstevel@tonic-gate nw = w->w_next; 29337c478bd9Sstevel@tonic-gate sm_free(w->w_name); /* XXX */ 29347c478bd9Sstevel@tonic-gate if (w->w_host != NULL) 29357c478bd9Sstevel@tonic-gate sm_free(w->w_host); /* XXX */ 29367c478bd9Sstevel@tonic-gate sm_free((char *) w); /* XXX */ 29377c478bd9Sstevel@tonic-gate } 29387c478bd9Sstevel@tonic-gate WorkQ = NULL; 29397c478bd9Sstevel@tonic-gate } 29407c478bd9Sstevel@tonic-gate 29417c478bd9Sstevel@tonic-gate if (WorkList == NULL || wc <= 0) 29427c478bd9Sstevel@tonic-gate return 0; 29437c478bd9Sstevel@tonic-gate 29447c478bd9Sstevel@tonic-gate /* 29457c478bd9Sstevel@tonic-gate ** The sort now takes place using all of the items in WorkList. 29467c478bd9Sstevel@tonic-gate ** The list gets trimmed to the most important items after the sort. 29477c478bd9Sstevel@tonic-gate ** If the trim were to happen before the sort then one or more 29487c478bd9Sstevel@tonic-gate ** important items might get truncated off -- not what we want. 29497c478bd9Sstevel@tonic-gate */ 29507c478bd9Sstevel@tonic-gate 29517c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST) 29527c478bd9Sstevel@tonic-gate { 29537c478bd9Sstevel@tonic-gate /* 29547c478bd9Sstevel@tonic-gate ** Sort the work directory for the first time, 29557c478bd9Sstevel@tonic-gate ** based on host name, lock status, and priority. 29567c478bd9Sstevel@tonic-gate */ 29577c478bd9Sstevel@tonic-gate 2958*058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf1); 29597c478bd9Sstevel@tonic-gate 29607c478bd9Sstevel@tonic-gate /* 29617c478bd9Sstevel@tonic-gate ** If one message to host is locked, "lock" all messages 29627c478bd9Sstevel@tonic-gate ** to that host. 29637c478bd9Sstevel@tonic-gate */ 29647c478bd9Sstevel@tonic-gate 29657c478bd9Sstevel@tonic-gate i = 0; 29667c478bd9Sstevel@tonic-gate while (i < wc) 29677c478bd9Sstevel@tonic-gate { 29687c478bd9Sstevel@tonic-gate if (!WorkList[i].w_lock) 29697c478bd9Sstevel@tonic-gate { 29707c478bd9Sstevel@tonic-gate i++; 29717c478bd9Sstevel@tonic-gate continue; 29727c478bd9Sstevel@tonic-gate } 29737c478bd9Sstevel@tonic-gate w = &WorkList[i]; 29747c478bd9Sstevel@tonic-gate while (++i < wc) 29757c478bd9Sstevel@tonic-gate { 29767c478bd9Sstevel@tonic-gate if (WorkList[i].w_host == NULL && 29777c478bd9Sstevel@tonic-gate w->w_host == NULL) 29787c478bd9Sstevel@tonic-gate WorkList[i].w_lock = true; 29797c478bd9Sstevel@tonic-gate else if (WorkList[i].w_host != NULL && 29807c478bd9Sstevel@tonic-gate w->w_host != NULL && 29817c478bd9Sstevel@tonic-gate sm_strcasecmp(WorkList[i].w_host, 29827c478bd9Sstevel@tonic-gate w->w_host) == 0) 29837c478bd9Sstevel@tonic-gate WorkList[i].w_lock = true; 29847c478bd9Sstevel@tonic-gate else 29857c478bd9Sstevel@tonic-gate break; 29867c478bd9Sstevel@tonic-gate } 29877c478bd9Sstevel@tonic-gate } 29887c478bd9Sstevel@tonic-gate 29897c478bd9Sstevel@tonic-gate /* 29907c478bd9Sstevel@tonic-gate ** Sort the work directory for the second time, 29917c478bd9Sstevel@tonic-gate ** based on lock status, host name, and priority. 29927c478bd9Sstevel@tonic-gate */ 29937c478bd9Sstevel@tonic-gate 2994*058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf2); 29957c478bd9Sstevel@tonic-gate } 29967c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYTIME) 29977c478bd9Sstevel@tonic-gate { 29987c478bd9Sstevel@tonic-gate /* 29997c478bd9Sstevel@tonic-gate ** Simple sort based on submission time only. 30007c478bd9Sstevel@tonic-gate */ 30017c478bd9Sstevel@tonic-gate 3002*058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf3); 30037c478bd9Sstevel@tonic-gate } 30047c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYFILENAME) 30057c478bd9Sstevel@tonic-gate { 30067c478bd9Sstevel@tonic-gate /* 30077c478bd9Sstevel@tonic-gate ** Sort based on queue filename. 30087c478bd9Sstevel@tonic-gate */ 30097c478bd9Sstevel@tonic-gate 3010*058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf4); 30117c478bd9Sstevel@tonic-gate } 30127c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_RANDOM) 30137c478bd9Sstevel@tonic-gate { 30147c478bd9Sstevel@tonic-gate /* 30157c478bd9Sstevel@tonic-gate ** Sort randomly. To avoid problems with an instable sort, 30167c478bd9Sstevel@tonic-gate ** use a random index into the queue file name to start 30177c478bd9Sstevel@tonic-gate ** comparison. 30187c478bd9Sstevel@tonic-gate */ 30197c478bd9Sstevel@tonic-gate 30207c478bd9Sstevel@tonic-gate randi = get_rand_mod(MAXQFNAME); 30217c478bd9Sstevel@tonic-gate if (randi < 2) 30227c478bd9Sstevel@tonic-gate randi = 3; 3023*058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf5); 30247c478bd9Sstevel@tonic-gate } 30257c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYMODTIME) 30267c478bd9Sstevel@tonic-gate { 30277c478bd9Sstevel@tonic-gate /* 30287c478bd9Sstevel@tonic-gate ** Simple sort based on modification time of queue file. 30297c478bd9Sstevel@tonic-gate ** This puts the oldest items first. 30307c478bd9Sstevel@tonic-gate */ 30317c478bd9Sstevel@tonic-gate 3032*058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf6); 30337c478bd9Sstevel@tonic-gate } 30347c478bd9Sstevel@tonic-gate #if _FFR_RHS 30357c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYSHUFFLE) 30367c478bd9Sstevel@tonic-gate { 30377c478bd9Sstevel@tonic-gate /* 30387c478bd9Sstevel@tonic-gate ** Simple sort based on shuffled host name. 30397c478bd9Sstevel@tonic-gate */ 30407c478bd9Sstevel@tonic-gate 30417c478bd9Sstevel@tonic-gate init_shuffle_alphabet(); 3042*058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf7); 30437c478bd9Sstevel@tonic-gate } 30447c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 30457c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYPRIORITY) 30467c478bd9Sstevel@tonic-gate { 30477c478bd9Sstevel@tonic-gate /* 30487c478bd9Sstevel@tonic-gate ** Simple sort based on queue priority only. 30497c478bd9Sstevel@tonic-gate */ 30507c478bd9Sstevel@tonic-gate 3051*058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf0); 30527c478bd9Sstevel@tonic-gate } 30537c478bd9Sstevel@tonic-gate /* else don't sort at all */ 30547c478bd9Sstevel@tonic-gate 305549218d4fSjbeck /* Check if the per queue group item limit will be exceeded */ 305649218d4fSjbeck if (wc > max && max > 0) 305749218d4fSjbeck wc = max; 305849218d4fSjbeck 30597c478bd9Sstevel@tonic-gate /* 30607c478bd9Sstevel@tonic-gate ** Convert the work list into canonical form. 30617c478bd9Sstevel@tonic-gate ** Should be turning it into a list of envelopes here perhaps. 30627c478bd9Sstevel@tonic-gate ** Only take the most important items up to the per queue group 30637c478bd9Sstevel@tonic-gate ** maximum. 30647c478bd9Sstevel@tonic-gate */ 30657c478bd9Sstevel@tonic-gate 30667c478bd9Sstevel@tonic-gate for (i = wc; --i >= 0; ) 30677c478bd9Sstevel@tonic-gate { 3068*058561cbSjbeck w = (WORK *) xalloc(sizeof(*w)); 30697c478bd9Sstevel@tonic-gate w->w_qgrp = WorkList[i].w_qgrp; 30707c478bd9Sstevel@tonic-gate w->w_qdir = WorkList[i].w_qdir; 30717c478bd9Sstevel@tonic-gate w->w_name = WorkList[i].w_name; 30727c478bd9Sstevel@tonic-gate w->w_host = WorkList[i].w_host; 30737c478bd9Sstevel@tonic-gate w->w_lock = WorkList[i].w_lock; 30747c478bd9Sstevel@tonic-gate w->w_tooyoung = WorkList[i].w_tooyoung; 30757c478bd9Sstevel@tonic-gate w->w_pri = WorkList[i].w_pri; 30767c478bd9Sstevel@tonic-gate w->w_ctime = WorkList[i].w_ctime; 30777c478bd9Sstevel@tonic-gate w->w_mtime = WorkList[i].w_mtime; 30787c478bd9Sstevel@tonic-gate w->w_next = WorkQ; 30797c478bd9Sstevel@tonic-gate WorkQ = w; 30807c478bd9Sstevel@tonic-gate } 30817c478bd9Sstevel@tonic-gate 30827c478bd9Sstevel@tonic-gate /* free the rest of the list */ 30837c478bd9Sstevel@tonic-gate for (i = WorkListCount; --i >= wc; ) 30847c478bd9Sstevel@tonic-gate { 30857c478bd9Sstevel@tonic-gate sm_free(WorkList[i].w_name); 30867c478bd9Sstevel@tonic-gate if (WorkList[i].w_host != NULL) 30877c478bd9Sstevel@tonic-gate sm_free(WorkList[i].w_host); 30887c478bd9Sstevel@tonic-gate } 30897c478bd9Sstevel@tonic-gate 30907c478bd9Sstevel@tonic-gate if (WorkList != NULL) 30917c478bd9Sstevel@tonic-gate sm_free(WorkList); /* XXX */ 30927c478bd9Sstevel@tonic-gate WorkList = NULL; 30937c478bd9Sstevel@tonic-gate WorkListSize = 0; 30947c478bd9Sstevel@tonic-gate WorkListCount = 0; 30957c478bd9Sstevel@tonic-gate 30967c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 30977c478bd9Sstevel@tonic-gate { 30987c478bd9Sstevel@tonic-gate for (w = WorkQ; w != NULL; w = w->w_next) 30997c478bd9Sstevel@tonic-gate { 31007c478bd9Sstevel@tonic-gate if (w->w_host != NULL) 31017c478bd9Sstevel@tonic-gate sm_dprintf("%22s: pri=%ld %s\n", 31027c478bd9Sstevel@tonic-gate w->w_name, w->w_pri, w->w_host); 31037c478bd9Sstevel@tonic-gate else 31047c478bd9Sstevel@tonic-gate sm_dprintf("%32s: pri=%ld\n", 31057c478bd9Sstevel@tonic-gate w->w_name, w->w_pri); 31067c478bd9Sstevel@tonic-gate } 31077c478bd9Sstevel@tonic-gate } 31087c478bd9Sstevel@tonic-gate 31097c478bd9Sstevel@tonic-gate return wc; /* return number of WorkQ items */ 31107c478bd9Sstevel@tonic-gate } 31117c478bd9Sstevel@tonic-gate /* 31127c478bd9Sstevel@tonic-gate ** GROW_WLIST -- make the work list larger 31137c478bd9Sstevel@tonic-gate ** 31147c478bd9Sstevel@tonic-gate ** Parameters: 31157c478bd9Sstevel@tonic-gate ** qgrp -- the index for the queue group. 31167c478bd9Sstevel@tonic-gate ** qdir -- the index for the queue directory. 31177c478bd9Sstevel@tonic-gate ** 31187c478bd9Sstevel@tonic-gate ** Returns: 31197c478bd9Sstevel@tonic-gate ** none. 31207c478bd9Sstevel@tonic-gate ** 31217c478bd9Sstevel@tonic-gate ** Side Effects: 31227c478bd9Sstevel@tonic-gate ** Adds another QUEUESEGSIZE entries to WorkList if possible. 31237c478bd9Sstevel@tonic-gate ** It can fail if there isn't enough memory, so WorkListSize 31247c478bd9Sstevel@tonic-gate ** should be checked again upon return. 31257c478bd9Sstevel@tonic-gate */ 31267c478bd9Sstevel@tonic-gate 31277c478bd9Sstevel@tonic-gate static void 31287c478bd9Sstevel@tonic-gate grow_wlist(qgrp, qdir) 31297c478bd9Sstevel@tonic-gate int qgrp; 31307c478bd9Sstevel@tonic-gate int qdir; 31317c478bd9Sstevel@tonic-gate { 31327c478bd9Sstevel@tonic-gate if (tTd(41, 1)) 31337c478bd9Sstevel@tonic-gate sm_dprintf("grow_wlist: WorkListSize=%d\n", WorkListSize); 31347c478bd9Sstevel@tonic-gate if (WorkList == NULL) 31357c478bd9Sstevel@tonic-gate { 3136*058561cbSjbeck WorkList = (WORK *) xalloc((sizeof(*WorkList)) * 31377c478bd9Sstevel@tonic-gate (QUEUESEGSIZE + 1)); 31387c478bd9Sstevel@tonic-gate WorkListSize = QUEUESEGSIZE; 31397c478bd9Sstevel@tonic-gate } 31407c478bd9Sstevel@tonic-gate else 31417c478bd9Sstevel@tonic-gate { 31427c478bd9Sstevel@tonic-gate int newsize = WorkListSize + QUEUESEGSIZE; 31437c478bd9Sstevel@tonic-gate WORK *newlist = (WORK *) sm_realloc((char *) WorkList, 31447c478bd9Sstevel@tonic-gate (unsigned) sizeof(WORK) * (newsize + 1)); 31457c478bd9Sstevel@tonic-gate 31467c478bd9Sstevel@tonic-gate if (newlist != NULL) 31477c478bd9Sstevel@tonic-gate { 31487c478bd9Sstevel@tonic-gate WorkListSize = newsize; 31497c478bd9Sstevel@tonic-gate WorkList = newlist; 31507c478bd9Sstevel@tonic-gate if (LogLevel > 1) 31517c478bd9Sstevel@tonic-gate { 31527c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 31537c478bd9Sstevel@tonic-gate "grew WorkList for %s to %d", 31547c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), 31557c478bd9Sstevel@tonic-gate WorkListSize); 31567c478bd9Sstevel@tonic-gate } 31577c478bd9Sstevel@tonic-gate } 31587c478bd9Sstevel@tonic-gate else if (LogLevel > 0) 31597c478bd9Sstevel@tonic-gate { 31607c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, NOQID, 31617c478bd9Sstevel@tonic-gate "FAILED to grow WorkList for %s to %d", 31627c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), newsize); 31637c478bd9Sstevel@tonic-gate } 31647c478bd9Sstevel@tonic-gate } 31657c478bd9Sstevel@tonic-gate if (tTd(41, 1)) 31667c478bd9Sstevel@tonic-gate sm_dprintf("grow_wlist: WorkListSize now %d\n", WorkListSize); 31677c478bd9Sstevel@tonic-gate } 31687c478bd9Sstevel@tonic-gate /* 31697c478bd9Sstevel@tonic-gate ** WORKCMPF0 -- simple priority-only compare function. 31707c478bd9Sstevel@tonic-gate ** 31717c478bd9Sstevel@tonic-gate ** Parameters: 31727c478bd9Sstevel@tonic-gate ** a -- the first argument. 31737c478bd9Sstevel@tonic-gate ** b -- the second argument. 31747c478bd9Sstevel@tonic-gate ** 31757c478bd9Sstevel@tonic-gate ** Returns: 31767c478bd9Sstevel@tonic-gate ** -1 if a < b 31777c478bd9Sstevel@tonic-gate ** 0 if a == b 31787c478bd9Sstevel@tonic-gate ** +1 if a > b 31797c478bd9Sstevel@tonic-gate ** 31807c478bd9Sstevel@tonic-gate */ 31817c478bd9Sstevel@tonic-gate 31827c478bd9Sstevel@tonic-gate static int 31837c478bd9Sstevel@tonic-gate workcmpf0(a, b) 31847c478bd9Sstevel@tonic-gate register WORK *a; 31857c478bd9Sstevel@tonic-gate register WORK *b; 31867c478bd9Sstevel@tonic-gate { 31877c478bd9Sstevel@tonic-gate long pa = a->w_pri; 31887c478bd9Sstevel@tonic-gate long pb = b->w_pri; 31897c478bd9Sstevel@tonic-gate 31907c478bd9Sstevel@tonic-gate if (pa == pb) 31917c478bd9Sstevel@tonic-gate return 0; 31927c478bd9Sstevel@tonic-gate else if (pa > pb) 31937c478bd9Sstevel@tonic-gate return 1; 31947c478bd9Sstevel@tonic-gate else 31957c478bd9Sstevel@tonic-gate return -1; 31967c478bd9Sstevel@tonic-gate } 31977c478bd9Sstevel@tonic-gate /* 31987c478bd9Sstevel@tonic-gate ** WORKCMPF1 -- first compare function for ordering work based on host name. 31997c478bd9Sstevel@tonic-gate ** 32007c478bd9Sstevel@tonic-gate ** Sorts on host name, lock status, and priority in that order. 32017c478bd9Sstevel@tonic-gate ** 32027c478bd9Sstevel@tonic-gate ** Parameters: 32037c478bd9Sstevel@tonic-gate ** a -- the first argument. 32047c478bd9Sstevel@tonic-gate ** b -- the second argument. 32057c478bd9Sstevel@tonic-gate ** 32067c478bd9Sstevel@tonic-gate ** Returns: 32077c478bd9Sstevel@tonic-gate ** <0 if a < b 32087c478bd9Sstevel@tonic-gate ** 0 if a == b 32097c478bd9Sstevel@tonic-gate ** >0 if a > b 32107c478bd9Sstevel@tonic-gate ** 32117c478bd9Sstevel@tonic-gate */ 32127c478bd9Sstevel@tonic-gate 32137c478bd9Sstevel@tonic-gate static int 32147c478bd9Sstevel@tonic-gate workcmpf1(a, b) 32157c478bd9Sstevel@tonic-gate register WORK *a; 32167c478bd9Sstevel@tonic-gate register WORK *b; 32177c478bd9Sstevel@tonic-gate { 32187c478bd9Sstevel@tonic-gate int i; 32197c478bd9Sstevel@tonic-gate 32207c478bd9Sstevel@tonic-gate /* host name */ 32217c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host == NULL) 32227c478bd9Sstevel@tonic-gate return 1; 32237c478bd9Sstevel@tonic-gate else if (a->w_host == NULL && b->w_host != NULL) 32247c478bd9Sstevel@tonic-gate return -1; 32257c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host != NULL && 32267c478bd9Sstevel@tonic-gate (i = sm_strcasecmp(a->w_host, b->w_host)) != 0) 32277c478bd9Sstevel@tonic-gate return i; 32287c478bd9Sstevel@tonic-gate 32297c478bd9Sstevel@tonic-gate /* lock status */ 32307c478bd9Sstevel@tonic-gate if (a->w_lock != b->w_lock) 32317c478bd9Sstevel@tonic-gate return b->w_lock - a->w_lock; 32327c478bd9Sstevel@tonic-gate 32337c478bd9Sstevel@tonic-gate /* job priority */ 32347c478bd9Sstevel@tonic-gate return workcmpf0(a, b); 32357c478bd9Sstevel@tonic-gate } 32367c478bd9Sstevel@tonic-gate /* 32377c478bd9Sstevel@tonic-gate ** WORKCMPF2 -- second compare function for ordering work based on host name. 32387c478bd9Sstevel@tonic-gate ** 32397c478bd9Sstevel@tonic-gate ** Sorts on lock status, host name, and priority in that order. 32407c478bd9Sstevel@tonic-gate ** 32417c478bd9Sstevel@tonic-gate ** Parameters: 32427c478bd9Sstevel@tonic-gate ** a -- the first argument. 32437c478bd9Sstevel@tonic-gate ** b -- the second argument. 32447c478bd9Sstevel@tonic-gate ** 32457c478bd9Sstevel@tonic-gate ** Returns: 32467c478bd9Sstevel@tonic-gate ** <0 if a < b 32477c478bd9Sstevel@tonic-gate ** 0 if a == b 32487c478bd9Sstevel@tonic-gate ** >0 if a > b 32497c478bd9Sstevel@tonic-gate ** 32507c478bd9Sstevel@tonic-gate */ 32517c478bd9Sstevel@tonic-gate 32527c478bd9Sstevel@tonic-gate static int 32537c478bd9Sstevel@tonic-gate workcmpf2(a, b) 32547c478bd9Sstevel@tonic-gate register WORK *a; 32557c478bd9Sstevel@tonic-gate register WORK *b; 32567c478bd9Sstevel@tonic-gate { 32577c478bd9Sstevel@tonic-gate int i; 32587c478bd9Sstevel@tonic-gate 32597c478bd9Sstevel@tonic-gate /* lock status */ 32607c478bd9Sstevel@tonic-gate if (a->w_lock != b->w_lock) 32617c478bd9Sstevel@tonic-gate return a->w_lock - b->w_lock; 32627c478bd9Sstevel@tonic-gate 32637c478bd9Sstevel@tonic-gate /* host name */ 32647c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host == NULL) 32657c478bd9Sstevel@tonic-gate return 1; 32667c478bd9Sstevel@tonic-gate else if (a->w_host == NULL && b->w_host != NULL) 32677c478bd9Sstevel@tonic-gate return -1; 32687c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host != NULL && 32697c478bd9Sstevel@tonic-gate (i = sm_strcasecmp(a->w_host, b->w_host)) != 0) 32707c478bd9Sstevel@tonic-gate return i; 32717c478bd9Sstevel@tonic-gate 32727c478bd9Sstevel@tonic-gate /* job priority */ 32737c478bd9Sstevel@tonic-gate return workcmpf0(a, b); 32747c478bd9Sstevel@tonic-gate } 32757c478bd9Sstevel@tonic-gate /* 32767c478bd9Sstevel@tonic-gate ** WORKCMPF3 -- simple submission-time-only compare function. 32777c478bd9Sstevel@tonic-gate ** 32787c478bd9Sstevel@tonic-gate ** Parameters: 32797c478bd9Sstevel@tonic-gate ** a -- the first argument. 32807c478bd9Sstevel@tonic-gate ** b -- the second argument. 32817c478bd9Sstevel@tonic-gate ** 32827c478bd9Sstevel@tonic-gate ** Returns: 32837c478bd9Sstevel@tonic-gate ** -1 if a < b 32847c478bd9Sstevel@tonic-gate ** 0 if a == b 32857c478bd9Sstevel@tonic-gate ** +1 if a > b 32867c478bd9Sstevel@tonic-gate ** 32877c478bd9Sstevel@tonic-gate */ 32887c478bd9Sstevel@tonic-gate 32897c478bd9Sstevel@tonic-gate static int 32907c478bd9Sstevel@tonic-gate workcmpf3(a, b) 32917c478bd9Sstevel@tonic-gate register WORK *a; 32927c478bd9Sstevel@tonic-gate register WORK *b; 32937c478bd9Sstevel@tonic-gate { 32947c478bd9Sstevel@tonic-gate if (a->w_ctime > b->w_ctime) 32957c478bd9Sstevel@tonic-gate return 1; 32967c478bd9Sstevel@tonic-gate else if (a->w_ctime < b->w_ctime) 32977c478bd9Sstevel@tonic-gate return -1; 32987c478bd9Sstevel@tonic-gate else 32997c478bd9Sstevel@tonic-gate return 0; 33007c478bd9Sstevel@tonic-gate } 33017c478bd9Sstevel@tonic-gate /* 33027c478bd9Sstevel@tonic-gate ** WORKCMPF4 -- compare based on file name 33037c478bd9Sstevel@tonic-gate ** 33047c478bd9Sstevel@tonic-gate ** Parameters: 33057c478bd9Sstevel@tonic-gate ** a -- the first argument. 33067c478bd9Sstevel@tonic-gate ** b -- the second argument. 33077c478bd9Sstevel@tonic-gate ** 33087c478bd9Sstevel@tonic-gate ** Returns: 33097c478bd9Sstevel@tonic-gate ** -1 if a < b 33107c478bd9Sstevel@tonic-gate ** 0 if a == b 33117c478bd9Sstevel@tonic-gate ** +1 if a > b 33127c478bd9Sstevel@tonic-gate ** 33137c478bd9Sstevel@tonic-gate */ 33147c478bd9Sstevel@tonic-gate 33157c478bd9Sstevel@tonic-gate static int 33167c478bd9Sstevel@tonic-gate workcmpf4(a, b) 33177c478bd9Sstevel@tonic-gate register WORK *a; 33187c478bd9Sstevel@tonic-gate register WORK *b; 33197c478bd9Sstevel@tonic-gate { 33207c478bd9Sstevel@tonic-gate return strcmp(a->w_name, b->w_name); 33217c478bd9Sstevel@tonic-gate } 33227c478bd9Sstevel@tonic-gate /* 33237c478bd9Sstevel@tonic-gate ** WORKCMPF5 -- compare based on assigned random number 33247c478bd9Sstevel@tonic-gate ** 33257c478bd9Sstevel@tonic-gate ** Parameters: 33267c478bd9Sstevel@tonic-gate ** a -- the first argument (ignored). 33277c478bd9Sstevel@tonic-gate ** b -- the second argument (ignored). 33287c478bd9Sstevel@tonic-gate ** 33297c478bd9Sstevel@tonic-gate ** Returns: 33307c478bd9Sstevel@tonic-gate ** randomly 1/-1 33317c478bd9Sstevel@tonic-gate */ 33327c478bd9Sstevel@tonic-gate 33337c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 33347c478bd9Sstevel@tonic-gate static int 33357c478bd9Sstevel@tonic-gate workcmpf5(a, b) 33367c478bd9Sstevel@tonic-gate register WORK *a; 33377c478bd9Sstevel@tonic-gate register WORK *b; 33387c478bd9Sstevel@tonic-gate { 33397c478bd9Sstevel@tonic-gate if (strlen(a->w_name) < randi || strlen(b->w_name) < randi) 33407c478bd9Sstevel@tonic-gate return -1; 33417c478bd9Sstevel@tonic-gate return a->w_name[randi] - b->w_name[randi]; 33427c478bd9Sstevel@tonic-gate } 33437c478bd9Sstevel@tonic-gate /* 33447c478bd9Sstevel@tonic-gate ** WORKCMPF6 -- simple modification-time-only compare function. 33457c478bd9Sstevel@tonic-gate ** 33467c478bd9Sstevel@tonic-gate ** Parameters: 33477c478bd9Sstevel@tonic-gate ** a -- the first argument. 33487c478bd9Sstevel@tonic-gate ** b -- the second argument. 33497c478bd9Sstevel@tonic-gate ** 33507c478bd9Sstevel@tonic-gate ** Returns: 33517c478bd9Sstevel@tonic-gate ** -1 if a < b 33527c478bd9Sstevel@tonic-gate ** 0 if a == b 33537c478bd9Sstevel@tonic-gate ** +1 if a > b 33547c478bd9Sstevel@tonic-gate ** 33557c478bd9Sstevel@tonic-gate */ 33567c478bd9Sstevel@tonic-gate 33577c478bd9Sstevel@tonic-gate static int 33587c478bd9Sstevel@tonic-gate workcmpf6(a, b) 33597c478bd9Sstevel@tonic-gate register WORK *a; 33607c478bd9Sstevel@tonic-gate register WORK *b; 33617c478bd9Sstevel@tonic-gate { 33627c478bd9Sstevel@tonic-gate if (a->w_mtime > b->w_mtime) 33637c478bd9Sstevel@tonic-gate return 1; 33647c478bd9Sstevel@tonic-gate else if (a->w_mtime < b->w_mtime) 33657c478bd9Sstevel@tonic-gate return -1; 33667c478bd9Sstevel@tonic-gate else 33677c478bd9Sstevel@tonic-gate return 0; 33687c478bd9Sstevel@tonic-gate } 33697c478bd9Sstevel@tonic-gate #if _FFR_RHS 33707c478bd9Sstevel@tonic-gate /* 33717c478bd9Sstevel@tonic-gate ** WORKCMPF7 -- compare function for ordering work based on shuffled host name. 33727c478bd9Sstevel@tonic-gate ** 33737c478bd9Sstevel@tonic-gate ** Sorts on lock status, host name, and priority in that order. 33747c478bd9Sstevel@tonic-gate ** 33757c478bd9Sstevel@tonic-gate ** Parameters: 33767c478bd9Sstevel@tonic-gate ** a -- the first argument. 33777c478bd9Sstevel@tonic-gate ** b -- the second argument. 33787c478bd9Sstevel@tonic-gate ** 33797c478bd9Sstevel@tonic-gate ** Returns: 33807c478bd9Sstevel@tonic-gate ** <0 if a < b 33817c478bd9Sstevel@tonic-gate ** 0 if a == b 33827c478bd9Sstevel@tonic-gate ** >0 if a > b 33837c478bd9Sstevel@tonic-gate ** 33847c478bd9Sstevel@tonic-gate */ 33857c478bd9Sstevel@tonic-gate 33867c478bd9Sstevel@tonic-gate static int 33877c478bd9Sstevel@tonic-gate workcmpf7(a, b) 33887c478bd9Sstevel@tonic-gate register WORK *a; 33897c478bd9Sstevel@tonic-gate register WORK *b; 33907c478bd9Sstevel@tonic-gate { 33917c478bd9Sstevel@tonic-gate int i; 33927c478bd9Sstevel@tonic-gate 33937c478bd9Sstevel@tonic-gate /* lock status */ 33947c478bd9Sstevel@tonic-gate if (a->w_lock != b->w_lock) 33957c478bd9Sstevel@tonic-gate return a->w_lock - b->w_lock; 33967c478bd9Sstevel@tonic-gate 33977c478bd9Sstevel@tonic-gate /* host name */ 33987c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host == NULL) 33997c478bd9Sstevel@tonic-gate return 1; 34007c478bd9Sstevel@tonic-gate else if (a->w_host == NULL && b->w_host != NULL) 34017c478bd9Sstevel@tonic-gate return -1; 34027c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host != NULL && 34037c478bd9Sstevel@tonic-gate (i = sm_strshufflecmp(a->w_host, b->w_host)) != 0) 34047c478bd9Sstevel@tonic-gate return i; 34057c478bd9Sstevel@tonic-gate 34067c478bd9Sstevel@tonic-gate /* job priority */ 34077c478bd9Sstevel@tonic-gate return workcmpf0(a, b); 34087c478bd9Sstevel@tonic-gate } 34097c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 34107c478bd9Sstevel@tonic-gate /* 34117c478bd9Sstevel@tonic-gate ** STRREV -- reverse string 34127c478bd9Sstevel@tonic-gate ** 34137c478bd9Sstevel@tonic-gate ** Returns a pointer to a new string that is the reverse of 34147c478bd9Sstevel@tonic-gate ** the string pointed to by fwd. The space for the new 34157c478bd9Sstevel@tonic-gate ** string is obtained using xalloc(). 34167c478bd9Sstevel@tonic-gate ** 34177c478bd9Sstevel@tonic-gate ** Parameters: 34187c478bd9Sstevel@tonic-gate ** fwd -- the string to reverse. 34197c478bd9Sstevel@tonic-gate ** 34207c478bd9Sstevel@tonic-gate ** Returns: 34217c478bd9Sstevel@tonic-gate ** the reversed string. 34227c478bd9Sstevel@tonic-gate */ 34237c478bd9Sstevel@tonic-gate 34247c478bd9Sstevel@tonic-gate static char * 34257c478bd9Sstevel@tonic-gate strrev(fwd) 34267c478bd9Sstevel@tonic-gate char *fwd; 34277c478bd9Sstevel@tonic-gate { 34287c478bd9Sstevel@tonic-gate char *rev = NULL; 34297c478bd9Sstevel@tonic-gate int len, cnt; 34307c478bd9Sstevel@tonic-gate 34317c478bd9Sstevel@tonic-gate len = strlen(fwd); 34327c478bd9Sstevel@tonic-gate rev = xalloc(len + 1); 34337c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < len; ++cnt) 34347c478bd9Sstevel@tonic-gate rev[cnt] = fwd[len - cnt - 1]; 34357c478bd9Sstevel@tonic-gate rev[len] = '\0'; 34367c478bd9Sstevel@tonic-gate return rev; 34377c478bd9Sstevel@tonic-gate } 34387c478bd9Sstevel@tonic-gate 34397c478bd9Sstevel@tonic-gate #if _FFR_RHS 34407c478bd9Sstevel@tonic-gate 34417c478bd9Sstevel@tonic-gate # define NASCII 128 34427c478bd9Sstevel@tonic-gate # define NCHAR 256 34437c478bd9Sstevel@tonic-gate 34447c478bd9Sstevel@tonic-gate static unsigned char ShuffledAlphabet[NCHAR]; 34457c478bd9Sstevel@tonic-gate 34467c478bd9Sstevel@tonic-gate void 34477c478bd9Sstevel@tonic-gate init_shuffle_alphabet() 34487c478bd9Sstevel@tonic-gate { 34497c478bd9Sstevel@tonic-gate static bool init = false; 34507c478bd9Sstevel@tonic-gate int i; 34517c478bd9Sstevel@tonic-gate 34527c478bd9Sstevel@tonic-gate if (init) 34537c478bd9Sstevel@tonic-gate return; 34547c478bd9Sstevel@tonic-gate 34557c478bd9Sstevel@tonic-gate /* fill the ShuffledAlphabet */ 345649218d4fSjbeck for (i = 0; i < NASCII; i++) 34577c478bd9Sstevel@tonic-gate ShuffledAlphabet[i] = i; 34587c478bd9Sstevel@tonic-gate 34597c478bd9Sstevel@tonic-gate /* mix it */ 346049218d4fSjbeck for (i = 1; i < NASCII; i++) 34617c478bd9Sstevel@tonic-gate { 346249218d4fSjbeck register int j = get_random() % NASCII; 34637c478bd9Sstevel@tonic-gate register int tmp; 34647c478bd9Sstevel@tonic-gate 34657c478bd9Sstevel@tonic-gate tmp = ShuffledAlphabet[j]; 34667c478bd9Sstevel@tonic-gate ShuffledAlphabet[j] = ShuffledAlphabet[i]; 34677c478bd9Sstevel@tonic-gate ShuffledAlphabet[i] = tmp; 34687c478bd9Sstevel@tonic-gate } 34697c478bd9Sstevel@tonic-gate 34707c478bd9Sstevel@tonic-gate /* make it case insensitive */ 34717c478bd9Sstevel@tonic-gate for (i = 'A'; i <= 'Z'; i++) 34727c478bd9Sstevel@tonic-gate ShuffledAlphabet[i] = ShuffledAlphabet[i + 'a' - 'A']; 34737c478bd9Sstevel@tonic-gate 34747c478bd9Sstevel@tonic-gate /* fill the upper part */ 347549218d4fSjbeck for (i = 0; i < NASCII; i++) 347649218d4fSjbeck ShuffledAlphabet[i + NASCII] = ShuffledAlphabet[i]; 34777c478bd9Sstevel@tonic-gate init = true; 34787c478bd9Sstevel@tonic-gate } 34797c478bd9Sstevel@tonic-gate 34807c478bd9Sstevel@tonic-gate static int 34817c478bd9Sstevel@tonic-gate sm_strshufflecmp(a, b) 34827c478bd9Sstevel@tonic-gate char *a; 34837c478bd9Sstevel@tonic-gate char *b; 34847c478bd9Sstevel@tonic-gate { 34857c478bd9Sstevel@tonic-gate const unsigned char *us1 = (const unsigned char *) a; 34867c478bd9Sstevel@tonic-gate const unsigned char *us2 = (const unsigned char *) b; 34877c478bd9Sstevel@tonic-gate 34887c478bd9Sstevel@tonic-gate while (ShuffledAlphabet[*us1] == ShuffledAlphabet[*us2++]) 34897c478bd9Sstevel@tonic-gate { 34907c478bd9Sstevel@tonic-gate if (*us1++ == '\0') 34917c478bd9Sstevel@tonic-gate return 0; 34927c478bd9Sstevel@tonic-gate } 34937c478bd9Sstevel@tonic-gate return (ShuffledAlphabet[*us1] - ShuffledAlphabet[*--us2]); 34947c478bd9Sstevel@tonic-gate } 34957c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 34967c478bd9Sstevel@tonic-gate 34977c478bd9Sstevel@tonic-gate /* 34987c478bd9Sstevel@tonic-gate ** DOWORK -- do a work request. 34997c478bd9Sstevel@tonic-gate ** 35007c478bd9Sstevel@tonic-gate ** Parameters: 35017c478bd9Sstevel@tonic-gate ** qgrp -- the index of the queue group for the job. 35027c478bd9Sstevel@tonic-gate ** qdir -- the index of the queue directory for the job. 35037c478bd9Sstevel@tonic-gate ** id -- the ID of the job to run. 35047c478bd9Sstevel@tonic-gate ** forkflag -- if set, run this in background. 35057c478bd9Sstevel@tonic-gate ** requeueflag -- if set, reinstantiate the queue quickly. 35067c478bd9Sstevel@tonic-gate ** This is used when expanding aliases in the queue. 35077c478bd9Sstevel@tonic-gate ** If forkflag is also set, it doesn't wait for the 35087c478bd9Sstevel@tonic-gate ** child. 35097c478bd9Sstevel@tonic-gate ** e - the envelope in which to run it. 35107c478bd9Sstevel@tonic-gate ** 35117c478bd9Sstevel@tonic-gate ** Returns: 35127c478bd9Sstevel@tonic-gate ** process id of process that is running the queue job. 35137c478bd9Sstevel@tonic-gate ** 35147c478bd9Sstevel@tonic-gate ** Side Effects: 35157c478bd9Sstevel@tonic-gate ** The work request is satisfied if possible. 35167c478bd9Sstevel@tonic-gate */ 35177c478bd9Sstevel@tonic-gate 35187c478bd9Sstevel@tonic-gate pid_t 35197c478bd9Sstevel@tonic-gate dowork(qgrp, qdir, id, forkflag, requeueflag, e) 35207c478bd9Sstevel@tonic-gate int qgrp; 35217c478bd9Sstevel@tonic-gate int qdir; 35227c478bd9Sstevel@tonic-gate char *id; 35237c478bd9Sstevel@tonic-gate bool forkflag; 35247c478bd9Sstevel@tonic-gate bool requeueflag; 35257c478bd9Sstevel@tonic-gate register ENVELOPE *e; 35267c478bd9Sstevel@tonic-gate { 35277c478bd9Sstevel@tonic-gate register pid_t pid; 35287c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool; 35297c478bd9Sstevel@tonic-gate 35307c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 35317c478bd9Sstevel@tonic-gate sm_dprintf("dowork(%s/%s)\n", qid_printqueue(qgrp, qdir), id); 35327c478bd9Sstevel@tonic-gate 35337c478bd9Sstevel@tonic-gate /* 35347c478bd9Sstevel@tonic-gate ** Fork for work. 35357c478bd9Sstevel@tonic-gate */ 35367c478bd9Sstevel@tonic-gate 35377c478bd9Sstevel@tonic-gate if (forkflag) 35387c478bd9Sstevel@tonic-gate { 35397c478bd9Sstevel@tonic-gate /* 35407c478bd9Sstevel@tonic-gate ** Since the delivery may happen in a child and the 35417c478bd9Sstevel@tonic-gate ** parent does not wait, the parent may close the 35427c478bd9Sstevel@tonic-gate ** maps thereby removing any shared memory used by 35437c478bd9Sstevel@tonic-gate ** the map. Therefore, close the maps now so the 35447c478bd9Sstevel@tonic-gate ** child will dynamically open them if necessary. 35457c478bd9Sstevel@tonic-gate */ 35467c478bd9Sstevel@tonic-gate 35477c478bd9Sstevel@tonic-gate closemaps(false); 35487c478bd9Sstevel@tonic-gate 35497c478bd9Sstevel@tonic-gate pid = fork(); 35507c478bd9Sstevel@tonic-gate if (pid < 0) 35517c478bd9Sstevel@tonic-gate { 35527c478bd9Sstevel@tonic-gate syserr("dowork: cannot fork"); 35537c478bd9Sstevel@tonic-gate return 0; 35547c478bd9Sstevel@tonic-gate } 35557c478bd9Sstevel@tonic-gate else if (pid > 0) 35567c478bd9Sstevel@tonic-gate { 35577c478bd9Sstevel@tonic-gate /* parent -- clean out connection cache */ 35587c478bd9Sstevel@tonic-gate mci_flush(false, NULL); 35597c478bd9Sstevel@tonic-gate } 35607c478bd9Sstevel@tonic-gate else 35617c478bd9Sstevel@tonic-gate { 35627c478bd9Sstevel@tonic-gate /* 35637c478bd9Sstevel@tonic-gate ** Initialize exception stack and default exception 35647c478bd9Sstevel@tonic-gate ** handler for child process. 35657c478bd9Sstevel@tonic-gate */ 35667c478bd9Sstevel@tonic-gate 35677c478bd9Sstevel@tonic-gate /* Reset global flags */ 35687c478bd9Sstevel@tonic-gate RestartRequest = NULL; 35697c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 35707c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 35717c478bd9Sstevel@tonic-gate PendingSignal = 0; 35727c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 35737c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error); 35747c478bd9Sstevel@tonic-gate 35757c478bd9Sstevel@tonic-gate /* 35767c478bd9Sstevel@tonic-gate ** See note above about SMTP processes and SIGCHLD. 35777c478bd9Sstevel@tonic-gate */ 35787c478bd9Sstevel@tonic-gate 35797c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP || 35807c478bd9Sstevel@tonic-gate OpMode == MD_DAEMON || 35817c478bd9Sstevel@tonic-gate MaxQueueChildren > 0) 35827c478bd9Sstevel@tonic-gate { 35837c478bd9Sstevel@tonic-gate proc_list_clear(); 35847c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD); 35857c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 35867c478bd9Sstevel@tonic-gate } 35877c478bd9Sstevel@tonic-gate 35887c478bd9Sstevel@tonic-gate /* child -- error messages to the transcript */ 35897c478bd9Sstevel@tonic-gate QuickAbort = OnlyOneError = false; 35907c478bd9Sstevel@tonic-gate } 35917c478bd9Sstevel@tonic-gate } 35927c478bd9Sstevel@tonic-gate else 35937c478bd9Sstevel@tonic-gate { 35947c478bd9Sstevel@tonic-gate pid = 0; 35957c478bd9Sstevel@tonic-gate } 35967c478bd9Sstevel@tonic-gate 35977c478bd9Sstevel@tonic-gate if (pid == 0) 35987c478bd9Sstevel@tonic-gate { 35997c478bd9Sstevel@tonic-gate /* 36007c478bd9Sstevel@tonic-gate ** CHILD 36017c478bd9Sstevel@tonic-gate ** Lock the control file to avoid duplicate deliveries. 36027c478bd9Sstevel@tonic-gate ** Then run the file as though we had just read it. 36037c478bd9Sstevel@tonic-gate ** We save an idea of the temporary name so we 36047c478bd9Sstevel@tonic-gate ** can recover on interrupt. 36057c478bd9Sstevel@tonic-gate */ 36067c478bd9Sstevel@tonic-gate 36077c478bd9Sstevel@tonic-gate if (forkflag) 36087c478bd9Sstevel@tonic-gate { 36097c478bd9Sstevel@tonic-gate /* Reset global flags */ 36107c478bd9Sstevel@tonic-gate RestartRequest = NULL; 36117c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 36127c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 36137c478bd9Sstevel@tonic-gate PendingSignal = 0; 36147c478bd9Sstevel@tonic-gate } 36157c478bd9Sstevel@tonic-gate 36167c478bd9Sstevel@tonic-gate /* set basic modes, etc. */ 36177c478bd9Sstevel@tonic-gate sm_clear_events(); 36187c478bd9Sstevel@tonic-gate clearstats(); 36197c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL); 36207c478bd9Sstevel@tonic-gate clearenvelope(e, false, rpool); 36217c478bd9Sstevel@tonic-gate e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS; 36227c478bd9Sstevel@tonic-gate set_delivery_mode(SM_DELIVER, e); 36237c478bd9Sstevel@tonic-gate e->e_errormode = EM_MAIL; 36247c478bd9Sstevel@tonic-gate e->e_id = id; 36257c478bd9Sstevel@tonic-gate e->e_qgrp = qgrp; 36267c478bd9Sstevel@tonic-gate e->e_qdir = qdir; 36277c478bd9Sstevel@tonic-gate GrabTo = UseErrorsTo = false; 36287c478bd9Sstevel@tonic-gate ExitStat = EX_OK; 36297c478bd9Sstevel@tonic-gate if (forkflag) 36307c478bd9Sstevel@tonic-gate { 36317c478bd9Sstevel@tonic-gate disconnect(1, e); 36327c478bd9Sstevel@tonic-gate set_op_mode(MD_QUEUERUN); 36337c478bd9Sstevel@tonic-gate } 36347c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s from queue", qid_printname(e)); 36357c478bd9Sstevel@tonic-gate if (LogLevel > 76) 36367c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "dowork, pid=%d", 36377c478bd9Sstevel@tonic-gate (int) CurrentPid); 36387c478bd9Sstevel@tonic-gate 36397c478bd9Sstevel@tonic-gate /* don't use the headers from sendmail.cf... */ 36407c478bd9Sstevel@tonic-gate e->e_header = NULL; 36417c478bd9Sstevel@tonic-gate 36427c478bd9Sstevel@tonic-gate /* read the queue control file -- return if locked */ 36437c478bd9Sstevel@tonic-gate if (!readqf(e, false)) 36447c478bd9Sstevel@tonic-gate { 36457c478bd9Sstevel@tonic-gate if (tTd(40, 4) && e->e_id != NULL) 36467c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s) failed\n", 36477c478bd9Sstevel@tonic-gate qid_printname(e)); 36487c478bd9Sstevel@tonic-gate e->e_id = NULL; 36497c478bd9Sstevel@tonic-gate if (forkflag) 36507c478bd9Sstevel@tonic-gate finis(false, true, EX_OK); 36517c478bd9Sstevel@tonic-gate else 36527c478bd9Sstevel@tonic-gate { 36537c478bd9Sstevel@tonic-gate /* adding this frees 8 bytes */ 36547c478bd9Sstevel@tonic-gate clearenvelope(e, false, rpool); 36557c478bd9Sstevel@tonic-gate 36567c478bd9Sstevel@tonic-gate /* adding this frees 12 bytes */ 36577c478bd9Sstevel@tonic-gate sm_rpool_free(rpool); 36587c478bd9Sstevel@tonic-gate e->e_rpool = NULL; 36597c478bd9Sstevel@tonic-gate return 0; 36607c478bd9Sstevel@tonic-gate } 36617c478bd9Sstevel@tonic-gate } 36627c478bd9Sstevel@tonic-gate 36637c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE; 36647c478bd9Sstevel@tonic-gate eatheader(e, requeueflag, true); 36657c478bd9Sstevel@tonic-gate 36667c478bd9Sstevel@tonic-gate if (requeueflag) 36677c478bd9Sstevel@tonic-gate queueup(e, false, false); 36687c478bd9Sstevel@tonic-gate 36697c478bd9Sstevel@tonic-gate /* do the delivery */ 36707c478bd9Sstevel@tonic-gate sendall(e, SM_DELIVER); 36717c478bd9Sstevel@tonic-gate 36727c478bd9Sstevel@tonic-gate /* finish up and exit */ 36737c478bd9Sstevel@tonic-gate if (forkflag) 36747c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 36757c478bd9Sstevel@tonic-gate else 36767c478bd9Sstevel@tonic-gate { 36777c478bd9Sstevel@tonic-gate dropenvelope(e, true, false); 36787c478bd9Sstevel@tonic-gate sm_rpool_free(rpool); 36797c478bd9Sstevel@tonic-gate e->e_rpool = NULL; 36807c478bd9Sstevel@tonic-gate } 36817c478bd9Sstevel@tonic-gate } 36827c478bd9Sstevel@tonic-gate e->e_id = NULL; 36837c478bd9Sstevel@tonic-gate return pid; 36847c478bd9Sstevel@tonic-gate } 36857c478bd9Sstevel@tonic-gate 36867c478bd9Sstevel@tonic-gate /* 36877c478bd9Sstevel@tonic-gate ** DOWORKLIST -- process a list of envelopes as work requests 36887c478bd9Sstevel@tonic-gate ** 36897c478bd9Sstevel@tonic-gate ** Similar to dowork(), except that after forking, it processes an 36907c478bd9Sstevel@tonic-gate ** envelope and its siblings, treating each envelope as a work request. 36917c478bd9Sstevel@tonic-gate ** 36927c478bd9Sstevel@tonic-gate ** Parameters: 36937c478bd9Sstevel@tonic-gate ** el -- envelope to be processed including its siblings. 36947c478bd9Sstevel@tonic-gate ** forkflag -- if set, run this in background. 36957c478bd9Sstevel@tonic-gate ** requeueflag -- if set, reinstantiate the queue quickly. 36967c478bd9Sstevel@tonic-gate ** This is used when expanding aliases in the queue. 36977c478bd9Sstevel@tonic-gate ** If forkflag is also set, it doesn't wait for the 36987c478bd9Sstevel@tonic-gate ** child. 36997c478bd9Sstevel@tonic-gate ** 37007c478bd9Sstevel@tonic-gate ** Returns: 37017c478bd9Sstevel@tonic-gate ** process id of process that is running the queue job. 37027c478bd9Sstevel@tonic-gate ** 37037c478bd9Sstevel@tonic-gate ** Side Effects: 37047c478bd9Sstevel@tonic-gate ** The work request is satisfied if possible. 37057c478bd9Sstevel@tonic-gate */ 37067c478bd9Sstevel@tonic-gate 37077c478bd9Sstevel@tonic-gate pid_t 37087c478bd9Sstevel@tonic-gate doworklist(el, forkflag, requeueflag) 37097c478bd9Sstevel@tonic-gate ENVELOPE *el; 37107c478bd9Sstevel@tonic-gate bool forkflag; 37117c478bd9Sstevel@tonic-gate bool requeueflag; 37127c478bd9Sstevel@tonic-gate { 37137c478bd9Sstevel@tonic-gate register pid_t pid; 37147c478bd9Sstevel@tonic-gate ENVELOPE *ei; 37157c478bd9Sstevel@tonic-gate 37167c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 37177c478bd9Sstevel@tonic-gate sm_dprintf("doworklist()\n"); 37187c478bd9Sstevel@tonic-gate 37197c478bd9Sstevel@tonic-gate /* 37207c478bd9Sstevel@tonic-gate ** Fork for work. 37217c478bd9Sstevel@tonic-gate */ 37227c478bd9Sstevel@tonic-gate 37237c478bd9Sstevel@tonic-gate if (forkflag) 37247c478bd9Sstevel@tonic-gate { 37257c478bd9Sstevel@tonic-gate /* 37267c478bd9Sstevel@tonic-gate ** Since the delivery may happen in a child and the 37277c478bd9Sstevel@tonic-gate ** parent does not wait, the parent may close the 37287c478bd9Sstevel@tonic-gate ** maps thereby removing any shared memory used by 37297c478bd9Sstevel@tonic-gate ** the map. Therefore, close the maps now so the 37307c478bd9Sstevel@tonic-gate ** child will dynamically open them if necessary. 37317c478bd9Sstevel@tonic-gate */ 37327c478bd9Sstevel@tonic-gate 37337c478bd9Sstevel@tonic-gate closemaps(false); 37347c478bd9Sstevel@tonic-gate 37357c478bd9Sstevel@tonic-gate pid = fork(); 37367c478bd9Sstevel@tonic-gate if (pid < 0) 37377c478bd9Sstevel@tonic-gate { 37387c478bd9Sstevel@tonic-gate syserr("doworklist: cannot fork"); 37397c478bd9Sstevel@tonic-gate return 0; 37407c478bd9Sstevel@tonic-gate } 37417c478bd9Sstevel@tonic-gate else if (pid > 0) 37427c478bd9Sstevel@tonic-gate { 37437c478bd9Sstevel@tonic-gate /* parent -- clean out connection cache */ 37447c478bd9Sstevel@tonic-gate mci_flush(false, NULL); 37457c478bd9Sstevel@tonic-gate } 37467c478bd9Sstevel@tonic-gate else 37477c478bd9Sstevel@tonic-gate { 37487c478bd9Sstevel@tonic-gate /* 37497c478bd9Sstevel@tonic-gate ** Initialize exception stack and default exception 37507c478bd9Sstevel@tonic-gate ** handler for child process. 37517c478bd9Sstevel@tonic-gate */ 37527c478bd9Sstevel@tonic-gate 37537c478bd9Sstevel@tonic-gate /* Reset global flags */ 37547c478bd9Sstevel@tonic-gate RestartRequest = NULL; 37557c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 37567c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 37577c478bd9Sstevel@tonic-gate PendingSignal = 0; 37587c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 37597c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error); 37607c478bd9Sstevel@tonic-gate 37617c478bd9Sstevel@tonic-gate /* 37627c478bd9Sstevel@tonic-gate ** See note above about SMTP processes and SIGCHLD. 37637c478bd9Sstevel@tonic-gate */ 37647c478bd9Sstevel@tonic-gate 37657c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP || 37667c478bd9Sstevel@tonic-gate OpMode == MD_DAEMON || 37677c478bd9Sstevel@tonic-gate MaxQueueChildren > 0) 37687c478bd9Sstevel@tonic-gate { 37697c478bd9Sstevel@tonic-gate proc_list_clear(); 37707c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD); 37717c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 37727c478bd9Sstevel@tonic-gate } 37737c478bd9Sstevel@tonic-gate 37747c478bd9Sstevel@tonic-gate /* child -- error messages to the transcript */ 37757c478bd9Sstevel@tonic-gate QuickAbort = OnlyOneError = false; 37767c478bd9Sstevel@tonic-gate } 37777c478bd9Sstevel@tonic-gate } 37787c478bd9Sstevel@tonic-gate else 37797c478bd9Sstevel@tonic-gate { 37807c478bd9Sstevel@tonic-gate pid = 0; 37817c478bd9Sstevel@tonic-gate } 37827c478bd9Sstevel@tonic-gate 37837c478bd9Sstevel@tonic-gate if (pid != 0) 37847c478bd9Sstevel@tonic-gate return pid; 37857c478bd9Sstevel@tonic-gate 37867c478bd9Sstevel@tonic-gate /* 37877c478bd9Sstevel@tonic-gate ** IN CHILD 37887c478bd9Sstevel@tonic-gate ** Lock the control file to avoid duplicate deliveries. 37897c478bd9Sstevel@tonic-gate ** Then run the file as though we had just read it. 37907c478bd9Sstevel@tonic-gate ** We save an idea of the temporary name so we 37917c478bd9Sstevel@tonic-gate ** can recover on interrupt. 37927c478bd9Sstevel@tonic-gate */ 37937c478bd9Sstevel@tonic-gate 37947c478bd9Sstevel@tonic-gate if (forkflag) 37957c478bd9Sstevel@tonic-gate { 37967c478bd9Sstevel@tonic-gate /* Reset global flags */ 37977c478bd9Sstevel@tonic-gate RestartRequest = NULL; 37987c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 37997c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 38007c478bd9Sstevel@tonic-gate PendingSignal = 0; 38017c478bd9Sstevel@tonic-gate } 38027c478bd9Sstevel@tonic-gate 38037c478bd9Sstevel@tonic-gate /* set basic modes, etc. */ 38047c478bd9Sstevel@tonic-gate sm_clear_events(); 38057c478bd9Sstevel@tonic-gate clearstats(); 38067c478bd9Sstevel@tonic-gate GrabTo = UseErrorsTo = false; 38077c478bd9Sstevel@tonic-gate ExitStat = EX_OK; 38087c478bd9Sstevel@tonic-gate if (forkflag) 38097c478bd9Sstevel@tonic-gate { 38107c478bd9Sstevel@tonic-gate disconnect(1, el); 38117c478bd9Sstevel@tonic-gate set_op_mode(MD_QUEUERUN); 38127c478bd9Sstevel@tonic-gate } 38137c478bd9Sstevel@tonic-gate if (LogLevel > 76) 38147c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, el->e_id, "doworklist, pid=%d", 38157c478bd9Sstevel@tonic-gate (int) CurrentPid); 38167c478bd9Sstevel@tonic-gate 38177c478bd9Sstevel@tonic-gate for (ei = el; ei != NULL; ei = ei->e_sibling) 38187c478bd9Sstevel@tonic-gate { 38197c478bd9Sstevel@tonic-gate ENVELOPE e; 38207c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool; 38217c478bd9Sstevel@tonic-gate 38227c478bd9Sstevel@tonic-gate if (WILL_BE_QUEUED(ei->e_sendmode)) 38237c478bd9Sstevel@tonic-gate continue; 38247c478bd9Sstevel@tonic-gate else if (QueueMode != QM_QUARANTINE && 38257c478bd9Sstevel@tonic-gate ei->e_quarmsg != NULL) 38267c478bd9Sstevel@tonic-gate continue; 38277c478bd9Sstevel@tonic-gate 38287c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL); 38297c478bd9Sstevel@tonic-gate clearenvelope(&e, true, rpool); 38307c478bd9Sstevel@tonic-gate e.e_flags |= EF_QUEUERUN|EF_GLOBALERRS; 38317c478bd9Sstevel@tonic-gate set_delivery_mode(SM_DELIVER, &e); 38327c478bd9Sstevel@tonic-gate e.e_errormode = EM_MAIL; 38337c478bd9Sstevel@tonic-gate e.e_id = ei->e_id; 38347c478bd9Sstevel@tonic-gate e.e_qgrp = ei->e_qgrp; 38357c478bd9Sstevel@tonic-gate e.e_qdir = ei->e_qdir; 38367c478bd9Sstevel@tonic-gate openxscript(&e); 38377c478bd9Sstevel@tonic-gate sm_setproctitle(true, &e, "%s from queue", qid_printname(&e)); 38387c478bd9Sstevel@tonic-gate 38397c478bd9Sstevel@tonic-gate /* don't use the headers from sendmail.cf... */ 38407c478bd9Sstevel@tonic-gate e.e_header = NULL; 38417c478bd9Sstevel@tonic-gate CurEnv = &e; 38427c478bd9Sstevel@tonic-gate 38437c478bd9Sstevel@tonic-gate /* read the queue control file -- return if locked */ 38447c478bd9Sstevel@tonic-gate if (readqf(&e, false)) 38457c478bd9Sstevel@tonic-gate { 38467c478bd9Sstevel@tonic-gate e.e_flags |= EF_INQUEUE; 38477c478bd9Sstevel@tonic-gate eatheader(&e, requeueflag, true); 38487c478bd9Sstevel@tonic-gate 38497c478bd9Sstevel@tonic-gate if (requeueflag) 38507c478bd9Sstevel@tonic-gate queueup(&e, false, false); 38517c478bd9Sstevel@tonic-gate 38527c478bd9Sstevel@tonic-gate /* do the delivery */ 38537c478bd9Sstevel@tonic-gate sendall(&e, SM_DELIVER); 38547c478bd9Sstevel@tonic-gate dropenvelope(&e, true, false); 38557c478bd9Sstevel@tonic-gate } 38567c478bd9Sstevel@tonic-gate else 38577c478bd9Sstevel@tonic-gate { 38587c478bd9Sstevel@tonic-gate if (tTd(40, 4) && e.e_id != NULL) 38597c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s) failed\n", 38607c478bd9Sstevel@tonic-gate qid_printname(&e)); 38617c478bd9Sstevel@tonic-gate } 38627c478bd9Sstevel@tonic-gate sm_rpool_free(rpool); 38637c478bd9Sstevel@tonic-gate ei->e_id = NULL; 38647c478bd9Sstevel@tonic-gate } 38657c478bd9Sstevel@tonic-gate 38667c478bd9Sstevel@tonic-gate /* restore CurEnv */ 38677c478bd9Sstevel@tonic-gate CurEnv = el; 38687c478bd9Sstevel@tonic-gate 38697c478bd9Sstevel@tonic-gate /* finish up and exit */ 38707c478bd9Sstevel@tonic-gate if (forkflag) 38717c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 38727c478bd9Sstevel@tonic-gate return 0; 38737c478bd9Sstevel@tonic-gate } 38747c478bd9Sstevel@tonic-gate /* 38757c478bd9Sstevel@tonic-gate ** READQF -- read queue file and set up environment. 38767c478bd9Sstevel@tonic-gate ** 38777c478bd9Sstevel@tonic-gate ** Parameters: 38787c478bd9Sstevel@tonic-gate ** e -- the envelope of the job to run. 38797c478bd9Sstevel@tonic-gate ** openonly -- only open the qf (returned as e_lockfp) 38807c478bd9Sstevel@tonic-gate ** 38817c478bd9Sstevel@tonic-gate ** Returns: 38827c478bd9Sstevel@tonic-gate ** true if it successfully read the queue file. 38837c478bd9Sstevel@tonic-gate ** false otherwise. 38847c478bd9Sstevel@tonic-gate ** 38857c478bd9Sstevel@tonic-gate ** Side Effects: 38867c478bd9Sstevel@tonic-gate ** The queue file is returned locked. 38877c478bd9Sstevel@tonic-gate */ 38887c478bd9Sstevel@tonic-gate 38897c478bd9Sstevel@tonic-gate static bool 38907c478bd9Sstevel@tonic-gate readqf(e, openonly) 38917c478bd9Sstevel@tonic-gate register ENVELOPE *e; 38927c478bd9Sstevel@tonic-gate bool openonly; 38937c478bd9Sstevel@tonic-gate { 38947c478bd9Sstevel@tonic-gate register SM_FILE_T *qfp; 38957c478bd9Sstevel@tonic-gate ADDRESS *ctladdr; 38967c478bd9Sstevel@tonic-gate struct stat st, stf; 38977c478bd9Sstevel@tonic-gate char *bp; 38987c478bd9Sstevel@tonic-gate int qfver = 0; 38997c478bd9Sstevel@tonic-gate long hdrsize = 0; 39007c478bd9Sstevel@tonic-gate register char *p; 39017c478bd9Sstevel@tonic-gate char *frcpt = NULL; 39027c478bd9Sstevel@tonic-gate char *orcpt = NULL; 39037c478bd9Sstevel@tonic-gate bool nomore = false; 39047c478bd9Sstevel@tonic-gate bool bogus = false; 39057c478bd9Sstevel@tonic-gate MODE_T qsafe; 39067c478bd9Sstevel@tonic-gate char *err; 39077c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN]; 39087c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 3909*058561cbSjbeck int bufsize; 39107c478bd9Sstevel@tonic-gate 39117c478bd9Sstevel@tonic-gate /* 39127c478bd9Sstevel@tonic-gate ** Read and process the file. 39137c478bd9Sstevel@tonic-gate */ 39147c478bd9Sstevel@tonic-gate 39153ee0e492Sjbeck bp = NULL; 3916*058561cbSjbeck (void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER), sizeof(qf)); 39177c478bd9Sstevel@tonic-gate qfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDWR_B, NULL); 39187c478bd9Sstevel@tonic-gate if (qfp == NULL) 39197c478bd9Sstevel@tonic-gate { 39207c478bd9Sstevel@tonic-gate int save_errno = errno; 39217c478bd9Sstevel@tonic-gate 39227c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 39237c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s): sm_io_open failure (%s)\n", 39247c478bd9Sstevel@tonic-gate qf, sm_errstring(errno)); 39257c478bd9Sstevel@tonic-gate errno = save_errno; 39267c478bd9Sstevel@tonic-gate if (errno != ENOENT 39277c478bd9Sstevel@tonic-gate ) 39287c478bd9Sstevel@tonic-gate syserr("readqf: no control file %s", qf); 39297c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 39307c478bd9Sstevel@tonic-gate return false; 39317c478bd9Sstevel@tonic-gate } 39327c478bd9Sstevel@tonic-gate 39337c478bd9Sstevel@tonic-gate if (!lockfile(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), qf, NULL, 39347c478bd9Sstevel@tonic-gate LOCK_EX|LOCK_NB)) 39357c478bd9Sstevel@tonic-gate { 39367c478bd9Sstevel@tonic-gate /* being processed by another queuer */ 39377c478bd9Sstevel@tonic-gate if (Verbose) 39387c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 39397c478bd9Sstevel@tonic-gate "%s: locked\n", e->e_id); 39407c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 39417c478bd9Sstevel@tonic-gate sm_dprintf("%s: locked\n", e->e_id); 39427c478bd9Sstevel@tonic-gate if (LogLevel > 19) 39437c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "locked"); 39447c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 39457c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 39467c478bd9Sstevel@tonic-gate return false; 39477c478bd9Sstevel@tonic-gate } 39487c478bd9Sstevel@tonic-gate 39497c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 39507c478bd9Sstevel@tonic-gate 39517c478bd9Sstevel@tonic-gate /* 39527c478bd9Sstevel@tonic-gate ** Prevent locking race condition. 39537c478bd9Sstevel@tonic-gate ** 39547c478bd9Sstevel@tonic-gate ** Process A: readqf(): qfp = fopen(qffile) 39557c478bd9Sstevel@tonic-gate ** Process B: queueup(): rename(tf, qf) 39567c478bd9Sstevel@tonic-gate ** Process B: unlocks(tf) 39577c478bd9Sstevel@tonic-gate ** Process A: lockfile(qf); 39587c478bd9Sstevel@tonic-gate ** 39597c478bd9Sstevel@tonic-gate ** Process A (us) has the old qf file (before the rename deleted 39607c478bd9Sstevel@tonic-gate ** the directory entry) and will be delivering based on old data. 39617c478bd9Sstevel@tonic-gate ** This can lead to multiple deliveries of the same recipients. 39627c478bd9Sstevel@tonic-gate ** 39637c478bd9Sstevel@tonic-gate ** Catch this by checking if the underlying qf file has changed 39647c478bd9Sstevel@tonic-gate ** *after* acquiring our lock and if so, act as though the file 39657c478bd9Sstevel@tonic-gate ** was still locked (i.e., just return like the lockfile() case 39667c478bd9Sstevel@tonic-gate ** above. 39677c478bd9Sstevel@tonic-gate */ 39687c478bd9Sstevel@tonic-gate 39697c478bd9Sstevel@tonic-gate if (stat(qf, &stf) < 0 || 39707c478bd9Sstevel@tonic-gate fstat(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), &st) < 0) 39717c478bd9Sstevel@tonic-gate { 39727c478bd9Sstevel@tonic-gate /* must have been being processed by someone else */ 39737c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 39747c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s): [f]stat failure (%s)\n", 39757c478bd9Sstevel@tonic-gate qf, sm_errstring(errno)); 39767c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 39777c478bd9Sstevel@tonic-gate return false; 39787c478bd9Sstevel@tonic-gate } 39797c478bd9Sstevel@tonic-gate 39807c478bd9Sstevel@tonic-gate if (st.st_nlink != stf.st_nlink || 39817c478bd9Sstevel@tonic-gate st.st_dev != stf.st_dev || 39827c478bd9Sstevel@tonic-gate ST_INODE(st) != ST_INODE(stf) || 39837c478bd9Sstevel@tonic-gate #if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */ 39847c478bd9Sstevel@tonic-gate st.st_gen != stf.st_gen || 39857c478bd9Sstevel@tonic-gate #endif /* HAS_ST_GEN && 0 */ 39867c478bd9Sstevel@tonic-gate st.st_uid != stf.st_uid || 39877c478bd9Sstevel@tonic-gate st.st_gid != stf.st_gid || 39887c478bd9Sstevel@tonic-gate st.st_size != stf.st_size) 39897c478bd9Sstevel@tonic-gate { 39907c478bd9Sstevel@tonic-gate /* changed after opened */ 39917c478bd9Sstevel@tonic-gate if (Verbose) 39927c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 39937c478bd9Sstevel@tonic-gate "%s: changed\n", e->e_id); 39947c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 39957c478bd9Sstevel@tonic-gate sm_dprintf("%s: changed\n", e->e_id); 39967c478bd9Sstevel@tonic-gate if (LogLevel > 19) 39977c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "changed"); 39987c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 39997c478bd9Sstevel@tonic-gate return false; 40007c478bd9Sstevel@tonic-gate } 40017c478bd9Sstevel@tonic-gate 40027c478bd9Sstevel@tonic-gate /* 40037c478bd9Sstevel@tonic-gate ** Check the queue file for plausibility to avoid attacks. 40047c478bd9Sstevel@tonic-gate */ 40057c478bd9Sstevel@tonic-gate 40067c478bd9Sstevel@tonic-gate qsafe = S_IWOTH|S_IWGRP; 40077c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 40087c478bd9Sstevel@tonic-gate qsafe &= ~S_IWGRP; 40097c478bd9Sstevel@tonic-gate 40107c478bd9Sstevel@tonic-gate bogus = st.st_uid != geteuid() && 40117c478bd9Sstevel@tonic-gate st.st_uid != TrustedUid && 40127c478bd9Sstevel@tonic-gate geteuid() != RealUid; 40137c478bd9Sstevel@tonic-gate 40147c478bd9Sstevel@tonic-gate /* 40157c478bd9Sstevel@tonic-gate ** If this qf file results from a set-group-ID binary, then 40167c478bd9Sstevel@tonic-gate ** we check whether the directory is group-writable, 40177c478bd9Sstevel@tonic-gate ** the queue file mode contains the group-writable bit, and 40187c478bd9Sstevel@tonic-gate ** the groups are the same. 40197c478bd9Sstevel@tonic-gate ** Notice: this requires that the set-group-ID binary is used to 40207c478bd9Sstevel@tonic-gate ** run the queue! 40217c478bd9Sstevel@tonic-gate */ 40227c478bd9Sstevel@tonic-gate 40237c478bd9Sstevel@tonic-gate if (bogus && st.st_gid == getegid() && UseMSP) 40247c478bd9Sstevel@tonic-gate { 40257c478bd9Sstevel@tonic-gate char delim; 40267c478bd9Sstevel@tonic-gate struct stat dst; 40277c478bd9Sstevel@tonic-gate 40287c478bd9Sstevel@tonic-gate bp = SM_LAST_DIR_DELIM(qf); 40297c478bd9Sstevel@tonic-gate if (bp == NULL) 40307c478bd9Sstevel@tonic-gate delim = '\0'; 40317c478bd9Sstevel@tonic-gate else 40327c478bd9Sstevel@tonic-gate { 40337c478bd9Sstevel@tonic-gate delim = *bp; 40347c478bd9Sstevel@tonic-gate *bp = '\0'; 40357c478bd9Sstevel@tonic-gate } 40367c478bd9Sstevel@tonic-gate if (stat(delim == '\0' ? "." : qf, &dst) < 0) 40377c478bd9Sstevel@tonic-gate syserr("readqf: cannot stat directory %s", 40387c478bd9Sstevel@tonic-gate delim == '\0' ? "." : qf); 40397c478bd9Sstevel@tonic-gate else 40407c478bd9Sstevel@tonic-gate { 40417c478bd9Sstevel@tonic-gate bogus = !(bitset(S_IWGRP, QueueFileMode) && 40427c478bd9Sstevel@tonic-gate bitset(S_IWGRP, dst.st_mode) && 40437c478bd9Sstevel@tonic-gate dst.st_gid == st.st_gid); 40447c478bd9Sstevel@tonic-gate } 40457c478bd9Sstevel@tonic-gate if (delim != '\0') 40467c478bd9Sstevel@tonic-gate *bp = delim; 40473ee0e492Sjbeck bp = NULL; 40487c478bd9Sstevel@tonic-gate } 40497c478bd9Sstevel@tonic-gate if (!bogus) 40507c478bd9Sstevel@tonic-gate bogus = bitset(qsafe, st.st_mode); 40517c478bd9Sstevel@tonic-gate if (bogus) 40527c478bd9Sstevel@tonic-gate { 40537c478bd9Sstevel@tonic-gate if (LogLevel > 0) 40547c478bd9Sstevel@tonic-gate { 40557c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 40567c478bd9Sstevel@tonic-gate "bogus queue file, uid=%d, gid=%d, mode=%o", 40577c478bd9Sstevel@tonic-gate st.st_uid, st.st_gid, st.st_mode); 40587c478bd9Sstevel@tonic-gate } 40597c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 40607c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s): bogus file\n", qf); 40617c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE; 40627c478bd9Sstevel@tonic-gate if (!openonly) 40637c478bd9Sstevel@tonic-gate loseqfile(e, "bogus file uid/gid in mqueue"); 40647c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 40657c478bd9Sstevel@tonic-gate return false; 40667c478bd9Sstevel@tonic-gate } 40677c478bd9Sstevel@tonic-gate 40687c478bd9Sstevel@tonic-gate if (st.st_size == 0) 40697c478bd9Sstevel@tonic-gate { 40707c478bd9Sstevel@tonic-gate /* must be a bogus file -- if also old, just remove it */ 40717c478bd9Sstevel@tonic-gate if (!openonly && st.st_ctime + 10 * 60 < curtime()) 40727c478bd9Sstevel@tonic-gate { 40737c478bd9Sstevel@tonic-gate (void) xunlink(queuename(e, DATAFL_LETTER)); 40747c478bd9Sstevel@tonic-gate (void) xunlink(queuename(e, ANYQFL_LETTER)); 40757c478bd9Sstevel@tonic-gate } 40767c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 40777c478bd9Sstevel@tonic-gate return false; 40787c478bd9Sstevel@tonic-gate } 40797c478bd9Sstevel@tonic-gate 40807c478bd9Sstevel@tonic-gate if (st.st_nlink == 0) 40817c478bd9Sstevel@tonic-gate { 40827c478bd9Sstevel@tonic-gate /* 40837c478bd9Sstevel@tonic-gate ** Race condition -- we got a file just as it was being 40847c478bd9Sstevel@tonic-gate ** unlinked. Just assume it is zero length. 40857c478bd9Sstevel@tonic-gate */ 40867c478bd9Sstevel@tonic-gate 40877c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 40887c478bd9Sstevel@tonic-gate return false; 40897c478bd9Sstevel@tonic-gate } 40907c478bd9Sstevel@tonic-gate 40917c478bd9Sstevel@tonic-gate #if _FFR_TRUSTED_QF 40927c478bd9Sstevel@tonic-gate /* 40937c478bd9Sstevel@tonic-gate ** If we don't own the file mark it as unsafe. 40947c478bd9Sstevel@tonic-gate ** However, allow TrustedUser to own it as well 40957c478bd9Sstevel@tonic-gate ** in case TrustedUser manipulates the queue. 40967c478bd9Sstevel@tonic-gate */ 40977c478bd9Sstevel@tonic-gate 40987c478bd9Sstevel@tonic-gate if (st.st_uid != geteuid() && st.st_uid != TrustedUid) 40997c478bd9Sstevel@tonic-gate e->e_flags |= EF_UNSAFE; 41007c478bd9Sstevel@tonic-gate #else /* _FFR_TRUSTED_QF */ 41017c478bd9Sstevel@tonic-gate /* If we don't own the file mark it as unsafe */ 41027c478bd9Sstevel@tonic-gate if (st.st_uid != geteuid()) 41037c478bd9Sstevel@tonic-gate e->e_flags |= EF_UNSAFE; 41047c478bd9Sstevel@tonic-gate #endif /* _FFR_TRUSTED_QF */ 41057c478bd9Sstevel@tonic-gate 41067c478bd9Sstevel@tonic-gate /* good file -- save this lock */ 41077c478bd9Sstevel@tonic-gate e->e_lockfp = qfp; 41087c478bd9Sstevel@tonic-gate 41097c478bd9Sstevel@tonic-gate /* Just wanted the open file */ 41107c478bd9Sstevel@tonic-gate if (openonly) 41117c478bd9Sstevel@tonic-gate return true; 41127c478bd9Sstevel@tonic-gate 41137c478bd9Sstevel@tonic-gate /* do basic system initialization */ 41147c478bd9Sstevel@tonic-gate initsys(e); 41157c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'i', e->e_id); 41167c478bd9Sstevel@tonic-gate 41177c478bd9Sstevel@tonic-gate LineNumber = 0; 41187c478bd9Sstevel@tonic-gate e->e_flags |= EF_GLOBALERRS; 41197c478bd9Sstevel@tonic-gate set_op_mode(MD_QUEUERUN); 41207c478bd9Sstevel@tonic-gate ctladdr = NULL; 41217c478bd9Sstevel@tonic-gate e->e_qfletter = queue_letter(e, ANYQFL_LETTER); 41227c478bd9Sstevel@tonic-gate e->e_dfqgrp = e->e_qgrp; 41237c478bd9Sstevel@tonic-gate e->e_dfqdir = e->e_qdir; 41247c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_MACRO 41257c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{queue}"), 41267c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir)); 41277c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_MACRO */ 41287c478bd9Sstevel@tonic-gate e->e_dfino = -1; 41297c478bd9Sstevel@tonic-gate e->e_msgsize = -1; 4130*058561cbSjbeck while (bufsize = sizeof(buf), 4131*058561cbSjbeck (bp = fgetfolded(buf, &bufsize, qfp)) != NULL) 41327c478bd9Sstevel@tonic-gate { 41337c478bd9Sstevel@tonic-gate unsigned long qflags; 41347c478bd9Sstevel@tonic-gate ADDRESS *q; 41357c478bd9Sstevel@tonic-gate int r; 41367c478bd9Sstevel@tonic-gate time_t now; 41377c478bd9Sstevel@tonic-gate auto char *ep; 41387c478bd9Sstevel@tonic-gate 41397c478bd9Sstevel@tonic-gate if (tTd(40, 4)) 41407c478bd9Sstevel@tonic-gate sm_dprintf("+++++ %s\n", bp); 41417c478bd9Sstevel@tonic-gate if (nomore) 41427c478bd9Sstevel@tonic-gate { 41437c478bd9Sstevel@tonic-gate /* hack attack */ 41447c478bd9Sstevel@tonic-gate hackattack: 41457c478bd9Sstevel@tonic-gate syserr("SECURITY ALERT: extra or bogus data in queue file: %s", 41467c478bd9Sstevel@tonic-gate bp); 41477c478bd9Sstevel@tonic-gate err = "bogus queue line"; 41487c478bd9Sstevel@tonic-gate goto fail; 41497c478bd9Sstevel@tonic-gate } 41507c478bd9Sstevel@tonic-gate switch (bp[0]) 41517c478bd9Sstevel@tonic-gate { 41527c478bd9Sstevel@tonic-gate case 'A': /* AUTH= parameter */ 41537c478bd9Sstevel@tonic-gate if (!xtextok(&bp[1])) 41547c478bd9Sstevel@tonic-gate goto hackattack; 41557c478bd9Sstevel@tonic-gate e->e_auth_param = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 41567c478bd9Sstevel@tonic-gate break; 41577c478bd9Sstevel@tonic-gate 41587c478bd9Sstevel@tonic-gate case 'B': /* body type */ 41597c478bd9Sstevel@tonic-gate r = check_bodytype(&bp[1]); 41607c478bd9Sstevel@tonic-gate if (!BODYTYPE_VALID(r)) 41617c478bd9Sstevel@tonic-gate goto hackattack; 41627c478bd9Sstevel@tonic-gate e->e_bodytype = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 41637c478bd9Sstevel@tonic-gate break; 41647c478bd9Sstevel@tonic-gate 41657c478bd9Sstevel@tonic-gate case 'C': /* specify controlling user */ 41667c478bd9Sstevel@tonic-gate ctladdr = setctluser(&bp[1], qfver, e); 41677c478bd9Sstevel@tonic-gate break; 41687c478bd9Sstevel@tonic-gate 41697c478bd9Sstevel@tonic-gate case 'D': /* data file name */ 41707c478bd9Sstevel@tonic-gate /* obsolete -- ignore */ 41717c478bd9Sstevel@tonic-gate break; 41727c478bd9Sstevel@tonic-gate 41737c478bd9Sstevel@tonic-gate case 'd': /* data file directory name */ 41747c478bd9Sstevel@tonic-gate { 41757c478bd9Sstevel@tonic-gate int qgrp, qdir; 41767c478bd9Sstevel@tonic-gate 41777c478bd9Sstevel@tonic-gate #if _FFR_MSP_PARANOIA 41787c478bd9Sstevel@tonic-gate /* forbid queue groups in MSP? */ 41797c478bd9Sstevel@tonic-gate if (UseMSP) 41807c478bd9Sstevel@tonic-gate goto hackattack; 41817c478bd9Sstevel@tonic-gate #endif /* _FFR_MSP_PARANOIA */ 41827c478bd9Sstevel@tonic-gate for (qgrp = 0; 41837c478bd9Sstevel@tonic-gate qgrp < NumQueue && Queue[qgrp] != NULL; 41847c478bd9Sstevel@tonic-gate ++qgrp) 41857c478bd9Sstevel@tonic-gate { 41867c478bd9Sstevel@tonic-gate for (qdir = 0; 41877c478bd9Sstevel@tonic-gate qdir < Queue[qgrp]->qg_numqueues; 41887c478bd9Sstevel@tonic-gate ++qdir) 41897c478bd9Sstevel@tonic-gate { 41907c478bd9Sstevel@tonic-gate if (strcmp(&bp[1], 41917c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name) 41927c478bd9Sstevel@tonic-gate == 0) 41937c478bd9Sstevel@tonic-gate { 41947c478bd9Sstevel@tonic-gate e->e_dfqgrp = qgrp; 41957c478bd9Sstevel@tonic-gate e->e_dfqdir = qdir; 41967c478bd9Sstevel@tonic-gate goto done; 41977c478bd9Sstevel@tonic-gate } 41987c478bd9Sstevel@tonic-gate } 41997c478bd9Sstevel@tonic-gate } 42007c478bd9Sstevel@tonic-gate err = "bogus queue file directory"; 42017c478bd9Sstevel@tonic-gate goto fail; 42027c478bd9Sstevel@tonic-gate done: 42037c478bd9Sstevel@tonic-gate break; 42047c478bd9Sstevel@tonic-gate } 42057c478bd9Sstevel@tonic-gate 42067c478bd9Sstevel@tonic-gate case 'E': /* specify error recipient */ 42077c478bd9Sstevel@tonic-gate /* no longer used */ 42087c478bd9Sstevel@tonic-gate break; 42097c478bd9Sstevel@tonic-gate 42107c478bd9Sstevel@tonic-gate case 'F': /* flag bits */ 42117c478bd9Sstevel@tonic-gate if (strncmp(bp, "From ", 5) == 0) 42127c478bd9Sstevel@tonic-gate { 42137c478bd9Sstevel@tonic-gate /* we are being spoofed! */ 42147c478bd9Sstevel@tonic-gate syserr("SECURITY ALERT: bogus qf line %s", bp); 42157c478bd9Sstevel@tonic-gate err = "bogus queue line"; 42167c478bd9Sstevel@tonic-gate goto fail; 42177c478bd9Sstevel@tonic-gate } 42187c478bd9Sstevel@tonic-gate for (p = &bp[1]; *p != '\0'; p++) 42197c478bd9Sstevel@tonic-gate { 42207c478bd9Sstevel@tonic-gate switch (*p) 42217c478bd9Sstevel@tonic-gate { 42227c478bd9Sstevel@tonic-gate case '8': /* has 8 bit data */ 42237c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS8BIT; 42247c478bd9Sstevel@tonic-gate break; 42257c478bd9Sstevel@tonic-gate 42267c478bd9Sstevel@tonic-gate case 'b': /* delete Bcc: header */ 42277c478bd9Sstevel@tonic-gate e->e_flags |= EF_DELETE_BCC; 42287c478bd9Sstevel@tonic-gate break; 42297c478bd9Sstevel@tonic-gate 42307c478bd9Sstevel@tonic-gate case 'd': /* envelope has DSN RET= */ 42317c478bd9Sstevel@tonic-gate e->e_flags |= EF_RET_PARAM; 42327c478bd9Sstevel@tonic-gate break; 42337c478bd9Sstevel@tonic-gate 42347c478bd9Sstevel@tonic-gate case 'n': /* don't return body */ 42357c478bd9Sstevel@tonic-gate e->e_flags |= EF_NO_BODY_RETN; 42367c478bd9Sstevel@tonic-gate break; 42377c478bd9Sstevel@tonic-gate 42387c478bd9Sstevel@tonic-gate case 'r': /* response */ 42397c478bd9Sstevel@tonic-gate e->e_flags |= EF_RESPONSE; 42407c478bd9Sstevel@tonic-gate break; 42417c478bd9Sstevel@tonic-gate 42427c478bd9Sstevel@tonic-gate case 's': /* split */ 42437c478bd9Sstevel@tonic-gate e->e_flags |= EF_SPLIT; 42447c478bd9Sstevel@tonic-gate break; 42457c478bd9Sstevel@tonic-gate 42467c478bd9Sstevel@tonic-gate case 'w': /* warning sent */ 42477c478bd9Sstevel@tonic-gate e->e_flags |= EF_WARNING; 42487c478bd9Sstevel@tonic-gate break; 42497c478bd9Sstevel@tonic-gate } 42507c478bd9Sstevel@tonic-gate } 42517c478bd9Sstevel@tonic-gate break; 42527c478bd9Sstevel@tonic-gate 42537c478bd9Sstevel@tonic-gate case 'q': /* quarantine reason */ 42547c478bd9Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 42557c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 42567c478bd9Sstevel@tonic-gate macid("{quarantine}"), e->e_quarmsg); 42577c478bd9Sstevel@tonic-gate break; 42587c478bd9Sstevel@tonic-gate 42597c478bd9Sstevel@tonic-gate case 'H': /* header */ 42607c478bd9Sstevel@tonic-gate 42617c478bd9Sstevel@tonic-gate /* 42627c478bd9Sstevel@tonic-gate ** count size before chompheader() destroys the line. 42637c478bd9Sstevel@tonic-gate ** this isn't accurate due to macro expansion, but 42647c478bd9Sstevel@tonic-gate ** better than before. "-3" to skip H?? at least. 42657c478bd9Sstevel@tonic-gate */ 42667c478bd9Sstevel@tonic-gate 42677c478bd9Sstevel@tonic-gate hdrsize += strlen(bp) - 3; 42687c478bd9Sstevel@tonic-gate (void) chompheader(&bp[1], CHHDR_QUEUE, NULL, e); 42697c478bd9Sstevel@tonic-gate break; 42707c478bd9Sstevel@tonic-gate 42717c478bd9Sstevel@tonic-gate case 'I': /* data file's inode number */ 42727c478bd9Sstevel@tonic-gate /* regenerated below */ 42737c478bd9Sstevel@tonic-gate break; 42747c478bd9Sstevel@tonic-gate 42757c478bd9Sstevel@tonic-gate case 'K': /* time of last delivery attempt */ 42767c478bd9Sstevel@tonic-gate e->e_dtime = atol(&buf[1]); 42777c478bd9Sstevel@tonic-gate break; 42787c478bd9Sstevel@tonic-gate 42797c478bd9Sstevel@tonic-gate case 'L': /* Solaris Content-Length: */ 42807c478bd9Sstevel@tonic-gate case 'M': /* message */ 42817c478bd9Sstevel@tonic-gate /* ignore this; we want a new message next time */ 42827c478bd9Sstevel@tonic-gate break; 42837c478bd9Sstevel@tonic-gate 42847c478bd9Sstevel@tonic-gate case 'N': /* number of delivery attempts */ 42857c478bd9Sstevel@tonic-gate e->e_ntries = atoi(&buf[1]); 42867c478bd9Sstevel@tonic-gate 42877c478bd9Sstevel@tonic-gate /* if this has been tried recently, let it be */ 42887c478bd9Sstevel@tonic-gate now = curtime(); 42897c478bd9Sstevel@tonic-gate if (e->e_ntries > 0 && e->e_dtime <= now && 42907c478bd9Sstevel@tonic-gate now < e->e_dtime + MinQueueAge) 42917c478bd9Sstevel@tonic-gate { 42927c478bd9Sstevel@tonic-gate char *howlong; 42937c478bd9Sstevel@tonic-gate 42947c478bd9Sstevel@tonic-gate howlong = pintvl(now - e->e_dtime, true); 42957c478bd9Sstevel@tonic-gate if (Verbose) 42967c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 42977c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 42987c478bd9Sstevel@tonic-gate "%s: too young (%s)\n", 42997c478bd9Sstevel@tonic-gate e->e_id, howlong); 43007c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 43017c478bd9Sstevel@tonic-gate sm_dprintf("%s: too young (%s)\n", 43027c478bd9Sstevel@tonic-gate e->e_id, howlong); 43037c478bd9Sstevel@tonic-gate if (LogLevel > 19) 43047c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, 43057c478bd9Sstevel@tonic-gate "too young (%s)", 43067c478bd9Sstevel@tonic-gate howlong); 43077c478bd9Sstevel@tonic-gate e->e_id = NULL; 43087c478bd9Sstevel@tonic-gate unlockqueue(e); 4309*058561cbSjbeck if (bp != buf) 4310*058561cbSjbeck sm_free(bp); 43117c478bd9Sstevel@tonic-gate return false; 43127c478bd9Sstevel@tonic-gate } 43137c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, 43147c478bd9Sstevel@tonic-gate macid("{ntries}"), &buf[1]); 43157c478bd9Sstevel@tonic-gate 43167c478bd9Sstevel@tonic-gate #if NAMED_BIND 43177c478bd9Sstevel@tonic-gate /* adjust BIND parameters immediately */ 43187c478bd9Sstevel@tonic-gate if (e->e_ntries == 0) 43197c478bd9Sstevel@tonic-gate { 43207c478bd9Sstevel@tonic-gate _res.retry = TimeOuts.res_retry[RES_TO_FIRST]; 43217c478bd9Sstevel@tonic-gate _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; 43227c478bd9Sstevel@tonic-gate } 43237c478bd9Sstevel@tonic-gate else 43247c478bd9Sstevel@tonic-gate { 43257c478bd9Sstevel@tonic-gate _res.retry = TimeOuts.res_retry[RES_TO_NORMAL]; 43267c478bd9Sstevel@tonic-gate _res.retrans = TimeOuts.res_retrans[RES_TO_NORMAL]; 43277c478bd9Sstevel@tonic-gate } 43287c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 43297c478bd9Sstevel@tonic-gate break; 43307c478bd9Sstevel@tonic-gate 43317c478bd9Sstevel@tonic-gate case 'P': /* message priority */ 43327c478bd9Sstevel@tonic-gate e->e_msgpriority = atol(&bp[1]) + WkTimeFact; 43337c478bd9Sstevel@tonic-gate break; 43347c478bd9Sstevel@tonic-gate 43357c478bd9Sstevel@tonic-gate case 'Q': /* original recipient */ 43367c478bd9Sstevel@tonic-gate orcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 43377c478bd9Sstevel@tonic-gate break; 43387c478bd9Sstevel@tonic-gate 43397c478bd9Sstevel@tonic-gate case 'r': /* final recipient */ 43407c478bd9Sstevel@tonic-gate frcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 43417c478bd9Sstevel@tonic-gate break; 43427c478bd9Sstevel@tonic-gate 43437c478bd9Sstevel@tonic-gate case 'R': /* specify recipient */ 43447c478bd9Sstevel@tonic-gate p = bp; 43457c478bd9Sstevel@tonic-gate qflags = 0; 43467c478bd9Sstevel@tonic-gate if (qfver >= 1) 43477c478bd9Sstevel@tonic-gate { 43487c478bd9Sstevel@tonic-gate /* get flag bits */ 43497c478bd9Sstevel@tonic-gate while (*++p != '\0' && *p != ':') 43507c478bd9Sstevel@tonic-gate { 43517c478bd9Sstevel@tonic-gate switch (*p) 43527c478bd9Sstevel@tonic-gate { 43537c478bd9Sstevel@tonic-gate case 'N': 43547c478bd9Sstevel@tonic-gate qflags |= QHASNOTIFY; 43557c478bd9Sstevel@tonic-gate break; 43567c478bd9Sstevel@tonic-gate 43577c478bd9Sstevel@tonic-gate case 'S': 43587c478bd9Sstevel@tonic-gate qflags |= QPINGONSUCCESS; 43597c478bd9Sstevel@tonic-gate break; 43607c478bd9Sstevel@tonic-gate 43617c478bd9Sstevel@tonic-gate case 'F': 43627c478bd9Sstevel@tonic-gate qflags |= QPINGONFAILURE; 43637c478bd9Sstevel@tonic-gate break; 43647c478bd9Sstevel@tonic-gate 43657c478bd9Sstevel@tonic-gate case 'D': 43667c478bd9Sstevel@tonic-gate qflags |= QPINGONDELAY; 43677c478bd9Sstevel@tonic-gate break; 43687c478bd9Sstevel@tonic-gate 43697c478bd9Sstevel@tonic-gate case 'P': 43707c478bd9Sstevel@tonic-gate qflags |= QPRIMARY; 43717c478bd9Sstevel@tonic-gate break; 43727c478bd9Sstevel@tonic-gate 43737c478bd9Sstevel@tonic-gate case 'A': 43747c478bd9Sstevel@tonic-gate if (ctladdr != NULL) 43757c478bd9Sstevel@tonic-gate ctladdr->q_flags |= QALIAS; 43767c478bd9Sstevel@tonic-gate break; 43777c478bd9Sstevel@tonic-gate 43787c478bd9Sstevel@tonic-gate default: /* ignore or complain? */ 43797c478bd9Sstevel@tonic-gate break; 43807c478bd9Sstevel@tonic-gate } 43817c478bd9Sstevel@tonic-gate } 43827c478bd9Sstevel@tonic-gate } 43837c478bd9Sstevel@tonic-gate else 43847c478bd9Sstevel@tonic-gate qflags |= QPRIMARY; 43857c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), 43867c478bd9Sstevel@tonic-gate "e r"); 43877c478bd9Sstevel@tonic-gate if (*p != '\0') 43887c478bd9Sstevel@tonic-gate q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', 43897c478bd9Sstevel@tonic-gate NULL, e, true); 43907c478bd9Sstevel@tonic-gate else 43917c478bd9Sstevel@tonic-gate q = NULL; 43927c478bd9Sstevel@tonic-gate if (q != NULL) 43937c478bd9Sstevel@tonic-gate { 43947c478bd9Sstevel@tonic-gate /* make sure we keep the current qgrp */ 43957c478bd9Sstevel@tonic-gate if (ISVALIDQGRP(e->e_qgrp)) 43967c478bd9Sstevel@tonic-gate q->q_qgrp = e->e_qgrp; 43977c478bd9Sstevel@tonic-gate q->q_alias = ctladdr; 43987c478bd9Sstevel@tonic-gate if (qfver >= 1) 43997c478bd9Sstevel@tonic-gate q->q_flags &= ~Q_PINGFLAGS; 44007c478bd9Sstevel@tonic-gate q->q_flags |= qflags; 44017c478bd9Sstevel@tonic-gate q->q_finalrcpt = frcpt; 44027c478bd9Sstevel@tonic-gate q->q_orcpt = orcpt; 44037c478bd9Sstevel@tonic-gate (void) recipient(q, &e->e_sendqueue, 0, e); 44047c478bd9Sstevel@tonic-gate } 44057c478bd9Sstevel@tonic-gate frcpt = NULL; 44067c478bd9Sstevel@tonic-gate orcpt = NULL; 44077c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), 44087c478bd9Sstevel@tonic-gate NULL); 44097c478bd9Sstevel@tonic-gate break; 44107c478bd9Sstevel@tonic-gate 44117c478bd9Sstevel@tonic-gate case 'S': /* sender */ 44127c478bd9Sstevel@tonic-gate setsender(sm_rpool_strdup_x(e->e_rpool, &bp[1]), 44137c478bd9Sstevel@tonic-gate e, NULL, '\0', true); 44147c478bd9Sstevel@tonic-gate break; 44157c478bd9Sstevel@tonic-gate 44167c478bd9Sstevel@tonic-gate case 'T': /* init time */ 44177c478bd9Sstevel@tonic-gate e->e_ctime = atol(&bp[1]); 44187c478bd9Sstevel@tonic-gate break; 44197c478bd9Sstevel@tonic-gate 44207c478bd9Sstevel@tonic-gate case 'V': /* queue file version number */ 44217c478bd9Sstevel@tonic-gate qfver = atoi(&bp[1]); 44227c478bd9Sstevel@tonic-gate if (qfver <= QF_VERSION) 44237c478bd9Sstevel@tonic-gate break; 44247c478bd9Sstevel@tonic-gate syserr("Version number in queue file (%d) greater than max (%d)", 44257c478bd9Sstevel@tonic-gate qfver, QF_VERSION); 44267c478bd9Sstevel@tonic-gate err = "unsupported queue file version"; 44277c478bd9Sstevel@tonic-gate goto fail; 44287c478bd9Sstevel@tonic-gate /* NOTREACHED */ 44297c478bd9Sstevel@tonic-gate break; 44307c478bd9Sstevel@tonic-gate 44317c478bd9Sstevel@tonic-gate case 'Z': /* original envelope id from ESMTP */ 44327c478bd9Sstevel@tonic-gate e->e_envid = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 44337c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 44347c478bd9Sstevel@tonic-gate macid("{dsn_envid}"), e->e_envid); 44357c478bd9Sstevel@tonic-gate break; 44367c478bd9Sstevel@tonic-gate 44377c478bd9Sstevel@tonic-gate case '!': /* deliver by */ 44387c478bd9Sstevel@tonic-gate 44397c478bd9Sstevel@tonic-gate /* format: flag (1 char) space long-integer */ 44407c478bd9Sstevel@tonic-gate e->e_dlvr_flag = buf[1]; 44417c478bd9Sstevel@tonic-gate e->e_deliver_by = strtol(&buf[3], NULL, 10); 44427c478bd9Sstevel@tonic-gate 44437c478bd9Sstevel@tonic-gate case '$': /* define macro */ 44447c478bd9Sstevel@tonic-gate { 44457c478bd9Sstevel@tonic-gate char *p; 44467c478bd9Sstevel@tonic-gate 44477c478bd9Sstevel@tonic-gate /* XXX elimate p? */ 44487c478bd9Sstevel@tonic-gate r = macid_parse(&bp[1], &ep); 44497c478bd9Sstevel@tonic-gate if (r == 0) 44507c478bd9Sstevel@tonic-gate break; 44517c478bd9Sstevel@tonic-gate p = sm_rpool_strdup_x(e->e_rpool, ep); 44527c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, r, p); 44537c478bd9Sstevel@tonic-gate } 44547c478bd9Sstevel@tonic-gate break; 44557c478bd9Sstevel@tonic-gate 44567c478bd9Sstevel@tonic-gate case '.': /* terminate file */ 44577c478bd9Sstevel@tonic-gate nomore = true; 44587c478bd9Sstevel@tonic-gate break; 44597c478bd9Sstevel@tonic-gate 44607c478bd9Sstevel@tonic-gate #if _FFR_QUEUEDELAY 44617c478bd9Sstevel@tonic-gate case 'G': 44627c478bd9Sstevel@tonic-gate case 'Y': 44637c478bd9Sstevel@tonic-gate 44647c478bd9Sstevel@tonic-gate /* 44657c478bd9Sstevel@tonic-gate ** Maintain backward compatibility for 44667c478bd9Sstevel@tonic-gate ** users who defined _FFR_QUEUEDELAY in 44677c478bd9Sstevel@tonic-gate ** previous releases. Remove this 44687c478bd9Sstevel@tonic-gate ** code in 8.14 or 8.15. 44697c478bd9Sstevel@tonic-gate */ 44707c478bd9Sstevel@tonic-gate 44717c478bd9Sstevel@tonic-gate if (qfver == 5 || qfver == 7) 44727c478bd9Sstevel@tonic-gate break; 44737c478bd9Sstevel@tonic-gate 44747c478bd9Sstevel@tonic-gate /* If not qfver 5 or 7, then 'G' or 'Y' is invalid */ 44757c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 44767c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUEDELAY */ 44777c478bd9Sstevel@tonic-gate 44787c478bd9Sstevel@tonic-gate default: 44797c478bd9Sstevel@tonic-gate syserr("readqf: %s: line %d: bad line \"%s\"", 44807c478bd9Sstevel@tonic-gate qf, LineNumber, shortenstring(bp, MAXSHORTSTR)); 44817c478bd9Sstevel@tonic-gate err = "unrecognized line"; 44827c478bd9Sstevel@tonic-gate goto fail; 44837c478bd9Sstevel@tonic-gate } 44847c478bd9Sstevel@tonic-gate 44857c478bd9Sstevel@tonic-gate if (bp != buf) 4486*058561cbSjbeck SM_FREE(bp); 44877c478bd9Sstevel@tonic-gate } 44887c478bd9Sstevel@tonic-gate 44897c478bd9Sstevel@tonic-gate /* 44907c478bd9Sstevel@tonic-gate ** If we haven't read any lines, this queue file is empty. 44917c478bd9Sstevel@tonic-gate ** Arrange to remove it without referencing any null pointers. 44927c478bd9Sstevel@tonic-gate */ 44937c478bd9Sstevel@tonic-gate 44947c478bd9Sstevel@tonic-gate if (LineNumber == 0) 44957c478bd9Sstevel@tonic-gate { 44967c478bd9Sstevel@tonic-gate errno = 0; 44977c478bd9Sstevel@tonic-gate e->e_flags |= EF_CLRQUEUE|EF_FATALERRS|EF_RESPONSE; 44987c478bd9Sstevel@tonic-gate return true; 44997c478bd9Sstevel@tonic-gate } 45007c478bd9Sstevel@tonic-gate 45017c478bd9Sstevel@tonic-gate /* Check to make sure we have a complete queue file read */ 45027c478bd9Sstevel@tonic-gate if (!nomore) 45037c478bd9Sstevel@tonic-gate { 45047c478bd9Sstevel@tonic-gate syserr("readqf: %s: incomplete queue file read", qf); 45057c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 45067c478bd9Sstevel@tonic-gate return false; 45077c478bd9Sstevel@tonic-gate } 45087c478bd9Sstevel@tonic-gate 45097c478bd9Sstevel@tonic-gate /* possibly set ${dsn_ret} macro */ 45107c478bd9Sstevel@tonic-gate if (bitset(EF_RET_PARAM, e->e_flags)) 45117c478bd9Sstevel@tonic-gate { 45127c478bd9Sstevel@tonic-gate if (bitset(EF_NO_BODY_RETN, e->e_flags)) 45137c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 45147c478bd9Sstevel@tonic-gate macid("{dsn_ret}"), "hdrs"); 45157c478bd9Sstevel@tonic-gate else 45167c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 45177c478bd9Sstevel@tonic-gate macid("{dsn_ret}"), "full"); 45187c478bd9Sstevel@tonic-gate } 45197c478bd9Sstevel@tonic-gate 45207c478bd9Sstevel@tonic-gate /* 45217c478bd9Sstevel@tonic-gate ** Arrange to read the data file. 45227c478bd9Sstevel@tonic-gate */ 45237c478bd9Sstevel@tonic-gate 45247c478bd9Sstevel@tonic-gate p = queuename(e, DATAFL_LETTER); 45257c478bd9Sstevel@tonic-gate e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, p, SM_IO_RDONLY_B, 45267c478bd9Sstevel@tonic-gate NULL); 45277c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL) 45287c478bd9Sstevel@tonic-gate { 45297c478bd9Sstevel@tonic-gate syserr("readqf: cannot open %s", p); 45307c478bd9Sstevel@tonic-gate } 45317c478bd9Sstevel@tonic-gate else 45327c478bd9Sstevel@tonic-gate { 45337c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS_DF; 45347c478bd9Sstevel@tonic-gate if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &st) 45357c478bd9Sstevel@tonic-gate >= 0) 45367c478bd9Sstevel@tonic-gate { 45377c478bd9Sstevel@tonic-gate e->e_msgsize = st.st_size + hdrsize; 45387c478bd9Sstevel@tonic-gate e->e_dfdev = st.st_dev; 45397c478bd9Sstevel@tonic-gate e->e_dfino = ST_INODE(st); 4540*058561cbSjbeck (void) sm_snprintf(buf, sizeof(buf), "%ld", 45417c478bd9Sstevel@tonic-gate e->e_msgsize); 45427c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), 45437c478bd9Sstevel@tonic-gate buf); 45447c478bd9Sstevel@tonic-gate } 45457c478bd9Sstevel@tonic-gate } 45467c478bd9Sstevel@tonic-gate 45477c478bd9Sstevel@tonic-gate return true; 45487c478bd9Sstevel@tonic-gate 45497c478bd9Sstevel@tonic-gate fail: 45507c478bd9Sstevel@tonic-gate /* 45517c478bd9Sstevel@tonic-gate ** There was some error reading the qf file (reason is in err var.) 45527c478bd9Sstevel@tonic-gate ** Cleanup: 45537c478bd9Sstevel@tonic-gate ** close file; clear e_lockfp since it is the same as qfp, 45547c478bd9Sstevel@tonic-gate ** hence it is invalid (as file) after qfp is closed; 45557c478bd9Sstevel@tonic-gate ** the qf file is on disk, so set the flag to avoid calling 45567c478bd9Sstevel@tonic-gate ** queueup() with bogus data. 45577c478bd9Sstevel@tonic-gate */ 45587c478bd9Sstevel@tonic-gate 4559*058561cbSjbeck if (bp != buf) 4560*058561cbSjbeck SM_FREE(bp); 45617c478bd9Sstevel@tonic-gate if (qfp != NULL) 45627c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 45637c478bd9Sstevel@tonic-gate e->e_lockfp = NULL; 45647c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE; 45657c478bd9Sstevel@tonic-gate loseqfile(e, err); 45667c478bd9Sstevel@tonic-gate return false; 45677c478bd9Sstevel@tonic-gate } 45687c478bd9Sstevel@tonic-gate /* 45697c478bd9Sstevel@tonic-gate ** PRTSTR -- print a string, "unprintable" characters are shown as \oct 45707c478bd9Sstevel@tonic-gate ** 45717c478bd9Sstevel@tonic-gate ** Parameters: 45727c478bd9Sstevel@tonic-gate ** s -- string to print 45737c478bd9Sstevel@tonic-gate ** ml -- maximum length of output 45747c478bd9Sstevel@tonic-gate ** 45757c478bd9Sstevel@tonic-gate ** Returns: 45767c478bd9Sstevel@tonic-gate ** number of entries 45777c478bd9Sstevel@tonic-gate ** 45787c478bd9Sstevel@tonic-gate ** Side Effects: 45797c478bd9Sstevel@tonic-gate ** Prints a string on stdout. 45807c478bd9Sstevel@tonic-gate */ 45817c478bd9Sstevel@tonic-gate 4582*058561cbSjbeck static void prtstr __P((char *, int)); 4583*058561cbSjbeck 45847c478bd9Sstevel@tonic-gate static void 45857c478bd9Sstevel@tonic-gate prtstr(s, ml) 45867c478bd9Sstevel@tonic-gate char *s; 45877c478bd9Sstevel@tonic-gate int ml; 45887c478bd9Sstevel@tonic-gate { 45897c478bd9Sstevel@tonic-gate int c; 45907c478bd9Sstevel@tonic-gate 45917c478bd9Sstevel@tonic-gate if (s == NULL) 45927c478bd9Sstevel@tonic-gate return; 45937c478bd9Sstevel@tonic-gate while (ml-- > 0 && ((c = *s++) != '\0')) 45947c478bd9Sstevel@tonic-gate { 45957c478bd9Sstevel@tonic-gate if (c == '\\') 45967c478bd9Sstevel@tonic-gate { 45977c478bd9Sstevel@tonic-gate if (ml-- > 0) 45987c478bd9Sstevel@tonic-gate { 45997c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c); 46007c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c); 46017c478bd9Sstevel@tonic-gate } 46027c478bd9Sstevel@tonic-gate } 46037c478bd9Sstevel@tonic-gate else if (isascii(c) && isprint(c)) 46047c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c); 46057c478bd9Sstevel@tonic-gate else 46067c478bd9Sstevel@tonic-gate { 46077c478bd9Sstevel@tonic-gate if ((ml -= 3) > 0) 46087c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 46097c478bd9Sstevel@tonic-gate "\\%03o", c & 0xFF); 46107c478bd9Sstevel@tonic-gate } 46117c478bd9Sstevel@tonic-gate } 46127c478bd9Sstevel@tonic-gate } 46137c478bd9Sstevel@tonic-gate /* 46147c478bd9Sstevel@tonic-gate ** PRINTNQE -- print out number of entries in the mail queue 46157c478bd9Sstevel@tonic-gate ** 46167c478bd9Sstevel@tonic-gate ** Parameters: 46177c478bd9Sstevel@tonic-gate ** out -- output file pointer. 46187c478bd9Sstevel@tonic-gate ** prefix -- string to output in front of each line. 46197c478bd9Sstevel@tonic-gate ** 46207c478bd9Sstevel@tonic-gate ** Returns: 46217c478bd9Sstevel@tonic-gate ** none. 46227c478bd9Sstevel@tonic-gate */ 46237c478bd9Sstevel@tonic-gate 46247c478bd9Sstevel@tonic-gate void 46257c478bd9Sstevel@tonic-gate printnqe(out, prefix) 46267c478bd9Sstevel@tonic-gate SM_FILE_T *out; 46277c478bd9Sstevel@tonic-gate char *prefix; 46287c478bd9Sstevel@tonic-gate { 46297c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 46307c478bd9Sstevel@tonic-gate int i, k = 0, nrequests = 0; 46317c478bd9Sstevel@tonic-gate bool unknown = false; 46327c478bd9Sstevel@tonic-gate 46337c478bd9Sstevel@tonic-gate if (ShmId == SM_SHM_NO_ID) 46347c478bd9Sstevel@tonic-gate { 46357c478bd9Sstevel@tonic-gate if (prefix == NULL) 46367c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46377c478bd9Sstevel@tonic-gate "Data unavailable: shared memory not updated\n"); 46387c478bd9Sstevel@tonic-gate else 46397c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46407c478bd9Sstevel@tonic-gate "%sNOTCONFIGURED:-1\r\n", prefix); 46417c478bd9Sstevel@tonic-gate return; 46427c478bd9Sstevel@tonic-gate } 46437c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 46447c478bd9Sstevel@tonic-gate { 46457c478bd9Sstevel@tonic-gate int j; 46467c478bd9Sstevel@tonic-gate 46477c478bd9Sstevel@tonic-gate k++; 46487c478bd9Sstevel@tonic-gate for (j = 0; j < Queue[i]->qg_numqueues; j++) 46497c478bd9Sstevel@tonic-gate { 46507c478bd9Sstevel@tonic-gate int n; 46517c478bd9Sstevel@tonic-gate 46527c478bd9Sstevel@tonic-gate if (StopRequest) 46537c478bd9Sstevel@tonic-gate stop_sendmail(); 46547c478bd9Sstevel@tonic-gate 46557c478bd9Sstevel@tonic-gate n = QSHM_ENTRIES(Queue[i]->qg_qpaths[j].qp_idx); 46567c478bd9Sstevel@tonic-gate if (prefix != NULL) 46577c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46587c478bd9Sstevel@tonic-gate "%s%s:%d\r\n", 46597c478bd9Sstevel@tonic-gate prefix, qid_printqueue(i, j), n); 46607c478bd9Sstevel@tonic-gate else if (n < 0) 46617c478bd9Sstevel@tonic-gate { 46627c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46637c478bd9Sstevel@tonic-gate "%s: unknown number of entries\n", 46647c478bd9Sstevel@tonic-gate qid_printqueue(i, j)); 46657c478bd9Sstevel@tonic-gate unknown = true; 46667c478bd9Sstevel@tonic-gate } 46677c478bd9Sstevel@tonic-gate else if (n == 0) 46687c478bd9Sstevel@tonic-gate { 46697c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46707c478bd9Sstevel@tonic-gate "%s is empty\n", 46717c478bd9Sstevel@tonic-gate qid_printqueue(i, j)); 46727c478bd9Sstevel@tonic-gate } 46737c478bd9Sstevel@tonic-gate else if (n > 0) 46747c478bd9Sstevel@tonic-gate { 46757c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46767c478bd9Sstevel@tonic-gate "%s: entries=%d\n", 46777c478bd9Sstevel@tonic-gate qid_printqueue(i, j), n); 46787c478bd9Sstevel@tonic-gate nrequests += n; 46797c478bd9Sstevel@tonic-gate k++; 46807c478bd9Sstevel@tonic-gate } 46817c478bd9Sstevel@tonic-gate } 46827c478bd9Sstevel@tonic-gate } 46837c478bd9Sstevel@tonic-gate if (prefix == NULL && k > 1) 46847c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46857c478bd9Sstevel@tonic-gate "\t\tTotal requests: %d%s\n", 46867c478bd9Sstevel@tonic-gate nrequests, unknown ? " (about)" : ""); 46877c478bd9Sstevel@tonic-gate #else /* SM_CONF_SHM */ 46887c478bd9Sstevel@tonic-gate if (prefix == NULL) 46897c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46907c478bd9Sstevel@tonic-gate "Data unavailable without shared memory support\n"); 46917c478bd9Sstevel@tonic-gate else 46927c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46937c478bd9Sstevel@tonic-gate "%sNOTAVAILABLE:-1\r\n", prefix); 46947c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 46957c478bd9Sstevel@tonic-gate } 46967c478bd9Sstevel@tonic-gate /* 46977c478bd9Sstevel@tonic-gate ** PRINTQUEUE -- print out a representation of the mail queue 46987c478bd9Sstevel@tonic-gate ** 46997c478bd9Sstevel@tonic-gate ** Parameters: 47007c478bd9Sstevel@tonic-gate ** none. 47017c478bd9Sstevel@tonic-gate ** 47027c478bd9Sstevel@tonic-gate ** Returns: 47037c478bd9Sstevel@tonic-gate ** none. 47047c478bd9Sstevel@tonic-gate ** 47057c478bd9Sstevel@tonic-gate ** Side Effects: 47067c478bd9Sstevel@tonic-gate ** Prints a listing of the mail queue on the standard output. 47077c478bd9Sstevel@tonic-gate */ 47087c478bd9Sstevel@tonic-gate 47097c478bd9Sstevel@tonic-gate void 47107c478bd9Sstevel@tonic-gate printqueue() 47117c478bd9Sstevel@tonic-gate { 47127c478bd9Sstevel@tonic-gate int i, k = 0, nrequests = 0; 47137c478bd9Sstevel@tonic-gate 47147c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 47157c478bd9Sstevel@tonic-gate { 47167c478bd9Sstevel@tonic-gate int j; 47177c478bd9Sstevel@tonic-gate 47187c478bd9Sstevel@tonic-gate k++; 47197c478bd9Sstevel@tonic-gate for (j = 0; j < Queue[i]->qg_numqueues; j++) 47207c478bd9Sstevel@tonic-gate { 47217c478bd9Sstevel@tonic-gate if (StopRequest) 47227c478bd9Sstevel@tonic-gate stop_sendmail(); 47237c478bd9Sstevel@tonic-gate nrequests += print_single_queue(i, j); 47247c478bd9Sstevel@tonic-gate k++; 47257c478bd9Sstevel@tonic-gate } 47267c478bd9Sstevel@tonic-gate } 47277c478bd9Sstevel@tonic-gate if (k > 1) 47287c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 47297c478bd9Sstevel@tonic-gate "\t\tTotal requests: %d\n", 47307c478bd9Sstevel@tonic-gate nrequests); 47317c478bd9Sstevel@tonic-gate } 47327c478bd9Sstevel@tonic-gate /* 47337c478bd9Sstevel@tonic-gate ** PRINT_SINGLE_QUEUE -- print out a representation of a single mail queue 47347c478bd9Sstevel@tonic-gate ** 47357c478bd9Sstevel@tonic-gate ** Parameters: 47367c478bd9Sstevel@tonic-gate ** qgrp -- the index of the queue group. 47377c478bd9Sstevel@tonic-gate ** qdir -- the queue directory. 47387c478bd9Sstevel@tonic-gate ** 47397c478bd9Sstevel@tonic-gate ** Returns: 47407c478bd9Sstevel@tonic-gate ** number of requests in mail queue. 47417c478bd9Sstevel@tonic-gate ** 47427c478bd9Sstevel@tonic-gate ** Side Effects: 47437c478bd9Sstevel@tonic-gate ** Prints a listing of the mail queue on the standard output. 47447c478bd9Sstevel@tonic-gate */ 47457c478bd9Sstevel@tonic-gate 47467c478bd9Sstevel@tonic-gate int 47477c478bd9Sstevel@tonic-gate print_single_queue(qgrp, qdir) 47487c478bd9Sstevel@tonic-gate int qgrp; 47497c478bd9Sstevel@tonic-gate int qdir; 47507c478bd9Sstevel@tonic-gate { 47517c478bd9Sstevel@tonic-gate register WORK *w; 47527c478bd9Sstevel@tonic-gate SM_FILE_T *f; 47537c478bd9Sstevel@tonic-gate int nrequests; 47547c478bd9Sstevel@tonic-gate char qd[MAXPATHLEN]; 47557c478bd9Sstevel@tonic-gate char qddf[MAXPATHLEN]; 47567c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 47577c478bd9Sstevel@tonic-gate 47587c478bd9Sstevel@tonic-gate if (qdir == NOQDIR) 47597c478bd9Sstevel@tonic-gate { 4760*058561cbSjbeck (void) sm_strlcpy(qd, ".", sizeof(qd)); 4761*058561cbSjbeck (void) sm_strlcpy(qddf, ".", sizeof(qddf)); 47627c478bd9Sstevel@tonic-gate } 47637c478bd9Sstevel@tonic-gate else 47647c478bd9Sstevel@tonic-gate { 4765*058561cbSjbeck (void) sm_strlcpyn(qd, sizeof(qd), 2, 47667c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name, 47677c478bd9Sstevel@tonic-gate (bitset(QP_SUBQF, 47687c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs) 47697c478bd9Sstevel@tonic-gate ? "/qf" : "")); 4770*058561cbSjbeck (void) sm_strlcpyn(qddf, sizeof(qddf), 2, 47717c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name, 47727c478bd9Sstevel@tonic-gate (bitset(QP_SUBDF, 47737c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs) 47747c478bd9Sstevel@tonic-gate ? "/df" : "")); 47757c478bd9Sstevel@tonic-gate } 47767c478bd9Sstevel@tonic-gate 47777c478bd9Sstevel@tonic-gate /* 47787c478bd9Sstevel@tonic-gate ** Check for permission to print the queue 47797c478bd9Sstevel@tonic-gate */ 47807c478bd9Sstevel@tonic-gate 47817c478bd9Sstevel@tonic-gate if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0) 47827c478bd9Sstevel@tonic-gate { 47837c478bd9Sstevel@tonic-gate struct stat st; 47847c478bd9Sstevel@tonic-gate #ifdef NGROUPS_MAX 47857c478bd9Sstevel@tonic-gate int n; 47867c478bd9Sstevel@tonic-gate extern GIDSET_T InitialGidSet[NGROUPS_MAX]; 47877c478bd9Sstevel@tonic-gate #endif /* NGROUPS_MAX */ 47887c478bd9Sstevel@tonic-gate 47897c478bd9Sstevel@tonic-gate if (stat(qd, &st) < 0) 47907c478bd9Sstevel@tonic-gate { 47917c478bd9Sstevel@tonic-gate syserr("Cannot stat %s", 47927c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 47937c478bd9Sstevel@tonic-gate return 0; 47947c478bd9Sstevel@tonic-gate } 47957c478bd9Sstevel@tonic-gate #ifdef NGROUPS_MAX 47967c478bd9Sstevel@tonic-gate n = NGROUPS_MAX; 47977c478bd9Sstevel@tonic-gate while (--n >= 0) 47987c478bd9Sstevel@tonic-gate { 47997c478bd9Sstevel@tonic-gate if (InitialGidSet[n] == st.st_gid) 48007c478bd9Sstevel@tonic-gate break; 48017c478bd9Sstevel@tonic-gate } 48027c478bd9Sstevel@tonic-gate if (n < 0 && RealGid != st.st_gid) 48037c478bd9Sstevel@tonic-gate #else /* NGROUPS_MAX */ 48047c478bd9Sstevel@tonic-gate if (RealGid != st.st_gid) 48057c478bd9Sstevel@tonic-gate #endif /* NGROUPS_MAX */ 48067c478bd9Sstevel@tonic-gate { 48077c478bd9Sstevel@tonic-gate usrerr("510 You are not permitted to see the queue"); 48087c478bd9Sstevel@tonic-gate setstat(EX_NOPERM); 48097c478bd9Sstevel@tonic-gate return 0; 48107c478bd9Sstevel@tonic-gate } 48117c478bd9Sstevel@tonic-gate } 48127c478bd9Sstevel@tonic-gate 48137c478bd9Sstevel@tonic-gate /* 48147c478bd9Sstevel@tonic-gate ** Read and order the queue. 48157c478bd9Sstevel@tonic-gate */ 48167c478bd9Sstevel@tonic-gate 48177c478bd9Sstevel@tonic-gate nrequests = gatherq(qgrp, qdir, true, NULL, NULL); 48187c478bd9Sstevel@tonic-gate (void) sortq(Queue[qgrp]->qg_maxlist); 48197c478bd9Sstevel@tonic-gate 48207c478bd9Sstevel@tonic-gate /* 48217c478bd9Sstevel@tonic-gate ** Print the work list that we have read. 48227c478bd9Sstevel@tonic-gate */ 48237c478bd9Sstevel@tonic-gate 48247c478bd9Sstevel@tonic-gate /* first see if there is anything */ 48257c478bd9Sstevel@tonic-gate if (nrequests <= 0) 48267c478bd9Sstevel@tonic-gate { 48277c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s is empty\n", 48287c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 48297c478bd9Sstevel@tonic-gate return 0; 48307c478bd9Sstevel@tonic-gate } 48317c478bd9Sstevel@tonic-gate 48327c478bd9Sstevel@tonic-gate sm_getla(); /* get load average */ 48337c478bd9Sstevel@tonic-gate 48347c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\t\t%s (%d request%s", 48357c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), 48367c478bd9Sstevel@tonic-gate nrequests, nrequests == 1 ? "" : "s"); 48377c478bd9Sstevel@tonic-gate if (MaxQueueRun > 0 && nrequests > MaxQueueRun) 48387c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48397c478bd9Sstevel@tonic-gate ", only %d printed", MaxQueueRun); 48407c478bd9Sstevel@tonic-gate if (Verbose) 48417c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48427c478bd9Sstevel@tonic-gate ")\n-----Q-ID----- --Size-- -Priority- ---Q-Time--- --------Sender/Recipient--------\n"); 48437c478bd9Sstevel@tonic-gate else 48447c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48457c478bd9Sstevel@tonic-gate ")\n-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------\n"); 48467c478bd9Sstevel@tonic-gate for (w = WorkQ; w != NULL; w = w->w_next) 48477c478bd9Sstevel@tonic-gate { 48487c478bd9Sstevel@tonic-gate struct stat st; 48497c478bd9Sstevel@tonic-gate auto time_t submittime = 0; 48507c478bd9Sstevel@tonic-gate long dfsize; 48517c478bd9Sstevel@tonic-gate int flags = 0; 48527c478bd9Sstevel@tonic-gate int qfver; 48537c478bd9Sstevel@tonic-gate char quarmsg[MAXLINE]; 48547c478bd9Sstevel@tonic-gate char statmsg[MAXLINE]; 48557c478bd9Sstevel@tonic-gate char bodytype[MAXNAME + 1]; 48567c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN]; 48577c478bd9Sstevel@tonic-gate 48587c478bd9Sstevel@tonic-gate if (StopRequest) 48597c478bd9Sstevel@tonic-gate stop_sendmail(); 48607c478bd9Sstevel@tonic-gate 48617c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%13s", 48627c478bd9Sstevel@tonic-gate w->w_name + 2); 4863*058561cbSjbeck (void) sm_strlcpyn(qf, sizeof(qf), 3, qd, "/", w->w_name); 48647c478bd9Sstevel@tonic-gate f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY_B, 48657c478bd9Sstevel@tonic-gate NULL); 48667c478bd9Sstevel@tonic-gate if (f == NULL) 48677c478bd9Sstevel@tonic-gate { 48687c478bd9Sstevel@tonic-gate if (errno == EPERM) 48697c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48707c478bd9Sstevel@tonic-gate " (permission denied)\n"); 48717c478bd9Sstevel@tonic-gate else if (errno == ENOENT) 48727c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48737c478bd9Sstevel@tonic-gate " (job completed)\n"); 48747c478bd9Sstevel@tonic-gate else 48757c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48767c478bd9Sstevel@tonic-gate " (%s)\n", 48777c478bd9Sstevel@tonic-gate sm_errstring(errno)); 48787c478bd9Sstevel@tonic-gate errno = 0; 48797c478bd9Sstevel@tonic-gate continue; 48807c478bd9Sstevel@tonic-gate } 48817c478bd9Sstevel@tonic-gate w->w_name[0] = DATAFL_LETTER; 4882*058561cbSjbeck (void) sm_strlcpyn(qf, sizeof(qf), 3, qddf, "/", w->w_name); 48837c478bd9Sstevel@tonic-gate if (stat(qf, &st) >= 0) 48847c478bd9Sstevel@tonic-gate dfsize = st.st_size; 48857c478bd9Sstevel@tonic-gate else 48867c478bd9Sstevel@tonic-gate { 48877c478bd9Sstevel@tonic-gate ENVELOPE e; 48887c478bd9Sstevel@tonic-gate 48897c478bd9Sstevel@tonic-gate /* 48907c478bd9Sstevel@tonic-gate ** Maybe the df file can't be statted because 48917c478bd9Sstevel@tonic-gate ** it is in a different directory than the qf file. 48927c478bd9Sstevel@tonic-gate ** In order to find out, we must read the qf file. 48937c478bd9Sstevel@tonic-gate */ 48947c478bd9Sstevel@tonic-gate 48957c478bd9Sstevel@tonic-gate newenvelope(&e, &BlankEnvelope, sm_rpool_new_x(NULL)); 48967c478bd9Sstevel@tonic-gate e.e_id = w->w_name + 2; 48977c478bd9Sstevel@tonic-gate e.e_qgrp = qgrp; 48987c478bd9Sstevel@tonic-gate e.e_qdir = qdir; 48997c478bd9Sstevel@tonic-gate dfsize = -1; 49007c478bd9Sstevel@tonic-gate if (readqf(&e, false)) 49017c478bd9Sstevel@tonic-gate { 49027c478bd9Sstevel@tonic-gate char *df = queuename(&e, DATAFL_LETTER); 49037c478bd9Sstevel@tonic-gate if (stat(df, &st) >= 0) 49047c478bd9Sstevel@tonic-gate dfsize = st.st_size; 49057c478bd9Sstevel@tonic-gate } 49067c478bd9Sstevel@tonic-gate if (e.e_lockfp != NULL) 49077c478bd9Sstevel@tonic-gate { 49087c478bd9Sstevel@tonic-gate (void) sm_io_close(e.e_lockfp, SM_TIME_DEFAULT); 49097c478bd9Sstevel@tonic-gate e.e_lockfp = NULL; 49107c478bd9Sstevel@tonic-gate } 49117c478bd9Sstevel@tonic-gate clearenvelope(&e, false, e.e_rpool); 49127c478bd9Sstevel@tonic-gate sm_rpool_free(e.e_rpool); 49137c478bd9Sstevel@tonic-gate } 49147c478bd9Sstevel@tonic-gate if (w->w_lock) 49157c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "*"); 49167c478bd9Sstevel@tonic-gate else if (QueueMode == QM_LOST) 49177c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "?"); 49187c478bd9Sstevel@tonic-gate else if (w->w_tooyoung) 49197c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "-"); 49207c478bd9Sstevel@tonic-gate else if (shouldqueue(w->w_pri, w->w_ctime)) 49217c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "X"); 49227c478bd9Sstevel@tonic-gate else 49237c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " "); 49247c478bd9Sstevel@tonic-gate 49257c478bd9Sstevel@tonic-gate errno = 0; 49267c478bd9Sstevel@tonic-gate 49277c478bd9Sstevel@tonic-gate quarmsg[0] = '\0'; 49287c478bd9Sstevel@tonic-gate statmsg[0] = bodytype[0] = '\0'; 49297c478bd9Sstevel@tonic-gate qfver = 0; 4930*058561cbSjbeck while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL) 49317c478bd9Sstevel@tonic-gate { 49327c478bd9Sstevel@tonic-gate register int i; 49337c478bd9Sstevel@tonic-gate register char *p; 49347c478bd9Sstevel@tonic-gate 49357c478bd9Sstevel@tonic-gate if (StopRequest) 49367c478bd9Sstevel@tonic-gate stop_sendmail(); 49377c478bd9Sstevel@tonic-gate 49387c478bd9Sstevel@tonic-gate fixcrlf(buf, true); 49397c478bd9Sstevel@tonic-gate switch (buf[0]) 49407c478bd9Sstevel@tonic-gate { 49417c478bd9Sstevel@tonic-gate case 'V': /* queue file version */ 49427c478bd9Sstevel@tonic-gate qfver = atoi(&buf[1]); 49437c478bd9Sstevel@tonic-gate break; 49447c478bd9Sstevel@tonic-gate 49457c478bd9Sstevel@tonic-gate case 'M': /* error message */ 4946*058561cbSjbeck if ((i = strlen(&buf[1])) >= sizeof(statmsg)) 4947*058561cbSjbeck i = sizeof(statmsg) - 1; 49487c478bd9Sstevel@tonic-gate memmove(statmsg, &buf[1], i); 49497c478bd9Sstevel@tonic-gate statmsg[i] = '\0'; 49507c478bd9Sstevel@tonic-gate break; 49517c478bd9Sstevel@tonic-gate 49527c478bd9Sstevel@tonic-gate case 'q': /* quarantine reason */ 4953*058561cbSjbeck if ((i = strlen(&buf[1])) >= sizeof(quarmsg)) 4954*058561cbSjbeck i = sizeof(quarmsg) - 1; 49557c478bd9Sstevel@tonic-gate memmove(quarmsg, &buf[1], i); 49567c478bd9Sstevel@tonic-gate quarmsg[i] = '\0'; 49577c478bd9Sstevel@tonic-gate break; 49587c478bd9Sstevel@tonic-gate 49597c478bd9Sstevel@tonic-gate case 'B': /* body type */ 4960*058561cbSjbeck if ((i = strlen(&buf[1])) >= sizeof(bodytype)) 4961*058561cbSjbeck i = sizeof(bodytype) - 1; 49627c478bd9Sstevel@tonic-gate memmove(bodytype, &buf[1], i); 49637c478bd9Sstevel@tonic-gate bodytype[i] = '\0'; 49647c478bd9Sstevel@tonic-gate break; 49657c478bd9Sstevel@tonic-gate 49667c478bd9Sstevel@tonic-gate case 'S': /* sender name */ 49677c478bd9Sstevel@tonic-gate if (Verbose) 49687c478bd9Sstevel@tonic-gate { 49697c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 49707c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49717c478bd9Sstevel@tonic-gate "%8ld %10ld%c%.12s ", 49727c478bd9Sstevel@tonic-gate dfsize, 49737c478bd9Sstevel@tonic-gate w->w_pri, 49747c478bd9Sstevel@tonic-gate bitset(EF_WARNING, flags) 49757c478bd9Sstevel@tonic-gate ? '+' : ' ', 49767c478bd9Sstevel@tonic-gate ctime(&submittime) + 4); 49777c478bd9Sstevel@tonic-gate prtstr(&buf[1], 78); 49787c478bd9Sstevel@tonic-gate } 49797c478bd9Sstevel@tonic-gate else 49807c478bd9Sstevel@tonic-gate { 49817c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 49827c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49837c478bd9Sstevel@tonic-gate "%8ld %.16s ", 49847c478bd9Sstevel@tonic-gate dfsize, 49857c478bd9Sstevel@tonic-gate ctime(&submittime)); 49867c478bd9Sstevel@tonic-gate prtstr(&buf[1], 39); 49877c478bd9Sstevel@tonic-gate } 49887c478bd9Sstevel@tonic-gate 49897c478bd9Sstevel@tonic-gate if (quarmsg[0] != '\0') 49907c478bd9Sstevel@tonic-gate { 49917c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 49927c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49937c478bd9Sstevel@tonic-gate "\n QUARANTINE: %.*s", 49947c478bd9Sstevel@tonic-gate Verbose ? 100 : 60, 49957c478bd9Sstevel@tonic-gate quarmsg); 49967c478bd9Sstevel@tonic-gate quarmsg[0] = '\0'; 49977c478bd9Sstevel@tonic-gate } 49987c478bd9Sstevel@tonic-gate 49997c478bd9Sstevel@tonic-gate if (statmsg[0] != '\0' || bodytype[0] != '\0') 50007c478bd9Sstevel@tonic-gate { 50017c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50027c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50037c478bd9Sstevel@tonic-gate "\n %10.10s", 50047c478bd9Sstevel@tonic-gate bodytype); 50057c478bd9Sstevel@tonic-gate if (statmsg[0] != '\0') 50067c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50077c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50087c478bd9Sstevel@tonic-gate " (%.*s)", 50097c478bd9Sstevel@tonic-gate Verbose ? 100 : 60, 50107c478bd9Sstevel@tonic-gate statmsg); 50117c478bd9Sstevel@tonic-gate statmsg[0] = '\0'; 50127c478bd9Sstevel@tonic-gate } 50137c478bd9Sstevel@tonic-gate break; 50147c478bd9Sstevel@tonic-gate 50157c478bd9Sstevel@tonic-gate case 'C': /* controlling user */ 50167c478bd9Sstevel@tonic-gate if (Verbose) 50177c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50187c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50197c478bd9Sstevel@tonic-gate "\n\t\t\t\t\t\t(---%.64s---)", 50207c478bd9Sstevel@tonic-gate &buf[1]); 50217c478bd9Sstevel@tonic-gate break; 50227c478bd9Sstevel@tonic-gate 50237c478bd9Sstevel@tonic-gate case 'R': /* recipient name */ 50247c478bd9Sstevel@tonic-gate p = &buf[1]; 50257c478bd9Sstevel@tonic-gate if (qfver >= 1) 50267c478bd9Sstevel@tonic-gate { 50277c478bd9Sstevel@tonic-gate p = strchr(p, ':'); 50287c478bd9Sstevel@tonic-gate if (p == NULL) 50297c478bd9Sstevel@tonic-gate break; 50307c478bd9Sstevel@tonic-gate p++; 50317c478bd9Sstevel@tonic-gate } 50327c478bd9Sstevel@tonic-gate if (Verbose) 50337c478bd9Sstevel@tonic-gate { 50347c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50357c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50367c478bd9Sstevel@tonic-gate "\n\t\t\t\t\t\t"); 50377c478bd9Sstevel@tonic-gate prtstr(p, 71); 50387c478bd9Sstevel@tonic-gate } 50397c478bd9Sstevel@tonic-gate else 50407c478bd9Sstevel@tonic-gate { 50417c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50427c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50437c478bd9Sstevel@tonic-gate "\n\t\t\t\t\t "); 50447c478bd9Sstevel@tonic-gate prtstr(p, 38); 50457c478bd9Sstevel@tonic-gate } 50467c478bd9Sstevel@tonic-gate if (Verbose && statmsg[0] != '\0') 50477c478bd9Sstevel@tonic-gate { 50487c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50497c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50507c478bd9Sstevel@tonic-gate "\n\t\t (%.100s)", 50517c478bd9Sstevel@tonic-gate statmsg); 50527c478bd9Sstevel@tonic-gate statmsg[0] = '\0'; 50537c478bd9Sstevel@tonic-gate } 50547c478bd9Sstevel@tonic-gate break; 50557c478bd9Sstevel@tonic-gate 50567c478bd9Sstevel@tonic-gate case 'T': /* creation time */ 50577c478bd9Sstevel@tonic-gate submittime = atol(&buf[1]); 50587c478bd9Sstevel@tonic-gate break; 50597c478bd9Sstevel@tonic-gate 50607c478bd9Sstevel@tonic-gate case 'F': /* flag bits */ 50617c478bd9Sstevel@tonic-gate for (p = &buf[1]; *p != '\0'; p++) 50627c478bd9Sstevel@tonic-gate { 50637c478bd9Sstevel@tonic-gate switch (*p) 50647c478bd9Sstevel@tonic-gate { 50657c478bd9Sstevel@tonic-gate case 'w': 50667c478bd9Sstevel@tonic-gate flags |= EF_WARNING; 50677c478bd9Sstevel@tonic-gate break; 50687c478bd9Sstevel@tonic-gate } 50697c478bd9Sstevel@tonic-gate } 50707c478bd9Sstevel@tonic-gate } 50717c478bd9Sstevel@tonic-gate } 50727c478bd9Sstevel@tonic-gate if (submittime == (time_t) 0) 50737c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 50747c478bd9Sstevel@tonic-gate " (no control file)"); 50757c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); 50767c478bd9Sstevel@tonic-gate (void) sm_io_close(f, SM_TIME_DEFAULT); 50777c478bd9Sstevel@tonic-gate } 50787c478bd9Sstevel@tonic-gate return nrequests; 50797c478bd9Sstevel@tonic-gate } 50807c478bd9Sstevel@tonic-gate 50817c478bd9Sstevel@tonic-gate /* 50827c478bd9Sstevel@tonic-gate ** QUEUE_LETTER -- get the proper queue letter for the current QueueMode. 50837c478bd9Sstevel@tonic-gate ** 50847c478bd9Sstevel@tonic-gate ** Parameters: 50857c478bd9Sstevel@tonic-gate ** e -- envelope to build it in/from. 50867c478bd9Sstevel@tonic-gate ** type -- the file type, used as the first character 50877c478bd9Sstevel@tonic-gate ** of the file name. 50887c478bd9Sstevel@tonic-gate ** 50897c478bd9Sstevel@tonic-gate ** Returns: 50907c478bd9Sstevel@tonic-gate ** the letter to use 50917c478bd9Sstevel@tonic-gate */ 50927c478bd9Sstevel@tonic-gate 50937c478bd9Sstevel@tonic-gate static char 50947c478bd9Sstevel@tonic-gate queue_letter(e, type) 50957c478bd9Sstevel@tonic-gate ENVELOPE *e; 50967c478bd9Sstevel@tonic-gate int type; 50977c478bd9Sstevel@tonic-gate { 50987c478bd9Sstevel@tonic-gate /* Change type according to QueueMode */ 50997c478bd9Sstevel@tonic-gate if (type == ANYQFL_LETTER) 51007c478bd9Sstevel@tonic-gate { 51017c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 51027c478bd9Sstevel@tonic-gate type = QUARQF_LETTER; 51037c478bd9Sstevel@tonic-gate else 51047c478bd9Sstevel@tonic-gate { 51057c478bd9Sstevel@tonic-gate switch (QueueMode) 51067c478bd9Sstevel@tonic-gate { 51077c478bd9Sstevel@tonic-gate case QM_NORMAL: 51087c478bd9Sstevel@tonic-gate type = NORMQF_LETTER; 51097c478bd9Sstevel@tonic-gate break; 51107c478bd9Sstevel@tonic-gate 51117c478bd9Sstevel@tonic-gate case QM_QUARANTINE: 51127c478bd9Sstevel@tonic-gate type = QUARQF_LETTER; 51137c478bd9Sstevel@tonic-gate break; 51147c478bd9Sstevel@tonic-gate 51157c478bd9Sstevel@tonic-gate case QM_LOST: 51167c478bd9Sstevel@tonic-gate type = LOSEQF_LETTER; 51177c478bd9Sstevel@tonic-gate break; 51187c478bd9Sstevel@tonic-gate 51197c478bd9Sstevel@tonic-gate default: 51207c478bd9Sstevel@tonic-gate /* should never happen */ 51217c478bd9Sstevel@tonic-gate abort(); 51227c478bd9Sstevel@tonic-gate /* NOTREACHED */ 51237c478bd9Sstevel@tonic-gate } 51247c478bd9Sstevel@tonic-gate } 51257c478bd9Sstevel@tonic-gate } 51267c478bd9Sstevel@tonic-gate return type; 51277c478bd9Sstevel@tonic-gate } 51287c478bd9Sstevel@tonic-gate 51297c478bd9Sstevel@tonic-gate /* 51307c478bd9Sstevel@tonic-gate ** QUEUENAME -- build a file name in the queue directory for this envelope. 51317c478bd9Sstevel@tonic-gate ** 51327c478bd9Sstevel@tonic-gate ** Parameters: 51337c478bd9Sstevel@tonic-gate ** e -- envelope to build it in/from. 51347c478bd9Sstevel@tonic-gate ** type -- the file type, used as the first character 51357c478bd9Sstevel@tonic-gate ** of the file name. 51367c478bd9Sstevel@tonic-gate ** 51377c478bd9Sstevel@tonic-gate ** Returns: 51387c478bd9Sstevel@tonic-gate ** a pointer to the queue name (in a static buffer). 51397c478bd9Sstevel@tonic-gate ** 51407c478bd9Sstevel@tonic-gate ** Side Effects: 51417c478bd9Sstevel@tonic-gate ** If no id code is already assigned, queuename() will 51427c478bd9Sstevel@tonic-gate ** assign an id code with assign_queueid(). If no queue 51437c478bd9Sstevel@tonic-gate ** directory is assigned, one will be set with setnewqueue(). 51447c478bd9Sstevel@tonic-gate */ 51457c478bd9Sstevel@tonic-gate 51467c478bd9Sstevel@tonic-gate char * 51477c478bd9Sstevel@tonic-gate queuename(e, type) 51487c478bd9Sstevel@tonic-gate register ENVELOPE *e; 51497c478bd9Sstevel@tonic-gate int type; 51507c478bd9Sstevel@tonic-gate { 51517c478bd9Sstevel@tonic-gate int qd, qg; 51527c478bd9Sstevel@tonic-gate char *sub = "/"; 51537c478bd9Sstevel@tonic-gate char pref[3]; 51547c478bd9Sstevel@tonic-gate static char buf[MAXPATHLEN]; 51557c478bd9Sstevel@tonic-gate 51567c478bd9Sstevel@tonic-gate /* Assign an ID if needed */ 51577c478bd9Sstevel@tonic-gate if (e->e_id == NULL) 51587c478bd9Sstevel@tonic-gate assign_queueid(e); 51597c478bd9Sstevel@tonic-gate type = queue_letter(e, type); 51607c478bd9Sstevel@tonic-gate 51617c478bd9Sstevel@tonic-gate /* begin of filename */ 51627c478bd9Sstevel@tonic-gate pref[0] = (char) type; 51637c478bd9Sstevel@tonic-gate pref[1] = 'f'; 51647c478bd9Sstevel@tonic-gate pref[2] = '\0'; 51657c478bd9Sstevel@tonic-gate 51667c478bd9Sstevel@tonic-gate /* Assign a queue group/directory if needed */ 51677c478bd9Sstevel@tonic-gate if (type == XSCRPT_LETTER) 51687c478bd9Sstevel@tonic-gate { 51697c478bd9Sstevel@tonic-gate /* 51707c478bd9Sstevel@tonic-gate ** We don't want to call setnewqueue() if we are fetching 51717c478bd9Sstevel@tonic-gate ** the pathname of the transcript file, because setnewqueue 51727c478bd9Sstevel@tonic-gate ** chooses a queue, and sometimes we need to write to the 51737c478bd9Sstevel@tonic-gate ** transcript file before we have gathered enough information 51747c478bd9Sstevel@tonic-gate ** to choose a queue. 51757c478bd9Sstevel@tonic-gate */ 51767c478bd9Sstevel@tonic-gate 51777c478bd9Sstevel@tonic-gate if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR) 51787c478bd9Sstevel@tonic-gate { 51797c478bd9Sstevel@tonic-gate if (e->e_qgrp != NOQGRP && e->e_qdir != NOQDIR) 51807c478bd9Sstevel@tonic-gate { 51817c478bd9Sstevel@tonic-gate e->e_xfqgrp = e->e_qgrp; 51827c478bd9Sstevel@tonic-gate e->e_xfqdir = e->e_qdir; 51837c478bd9Sstevel@tonic-gate } 51847c478bd9Sstevel@tonic-gate else 51857c478bd9Sstevel@tonic-gate { 51867c478bd9Sstevel@tonic-gate e->e_xfqgrp = 0; 51877c478bd9Sstevel@tonic-gate if (Queue[e->e_xfqgrp]->qg_numqueues <= 1) 51887c478bd9Sstevel@tonic-gate e->e_xfqdir = 0; 51897c478bd9Sstevel@tonic-gate else 51907c478bd9Sstevel@tonic-gate { 51917c478bd9Sstevel@tonic-gate e->e_xfqdir = get_rand_mod( 51927c478bd9Sstevel@tonic-gate Queue[e->e_xfqgrp]->qg_numqueues); 51937c478bd9Sstevel@tonic-gate } 51947c478bd9Sstevel@tonic-gate } 51957c478bd9Sstevel@tonic-gate } 51967c478bd9Sstevel@tonic-gate qd = e->e_xfqdir; 51977c478bd9Sstevel@tonic-gate qg = e->e_xfqgrp; 51987c478bd9Sstevel@tonic-gate } 51997c478bd9Sstevel@tonic-gate else 52007c478bd9Sstevel@tonic-gate { 52017c478bd9Sstevel@tonic-gate if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR) 52023ee0e492Sjbeck (void) setnewqueue(e); 52037c478bd9Sstevel@tonic-gate if (type == DATAFL_LETTER) 52047c478bd9Sstevel@tonic-gate { 52057c478bd9Sstevel@tonic-gate qd = e->e_dfqdir; 52067c478bd9Sstevel@tonic-gate qg = e->e_dfqgrp; 52077c478bd9Sstevel@tonic-gate } 52087c478bd9Sstevel@tonic-gate else 52097c478bd9Sstevel@tonic-gate { 52107c478bd9Sstevel@tonic-gate qd = e->e_qdir; 52117c478bd9Sstevel@tonic-gate qg = e->e_qgrp; 52127c478bd9Sstevel@tonic-gate } 52137c478bd9Sstevel@tonic-gate } 52147c478bd9Sstevel@tonic-gate 52157c478bd9Sstevel@tonic-gate /* xf files always have a valid qd and qg picked above */ 52163ee0e492Sjbeck if ((qd == NOQDIR || qg == NOQGRP) && type != XSCRPT_LETTER) 5217*058561cbSjbeck (void) sm_strlcpyn(buf, sizeof(buf), 2, pref, e->e_id); 52187c478bd9Sstevel@tonic-gate else 52197c478bd9Sstevel@tonic-gate { 52207c478bd9Sstevel@tonic-gate switch (type) 52217c478bd9Sstevel@tonic-gate { 52227c478bd9Sstevel@tonic-gate case DATAFL_LETTER: 52237c478bd9Sstevel@tonic-gate if (bitset(QP_SUBDF, Queue[qg]->qg_qpaths[qd].qp_subdirs)) 52247c478bd9Sstevel@tonic-gate sub = "/df/"; 52257c478bd9Sstevel@tonic-gate break; 52267c478bd9Sstevel@tonic-gate 52277c478bd9Sstevel@tonic-gate case QUARQF_LETTER: 52287c478bd9Sstevel@tonic-gate case TEMPQF_LETTER: 52297c478bd9Sstevel@tonic-gate case NEWQFL_LETTER: 52307c478bd9Sstevel@tonic-gate case LOSEQF_LETTER: 52317c478bd9Sstevel@tonic-gate case NORMQF_LETTER: 52327c478bd9Sstevel@tonic-gate if (bitset(QP_SUBQF, Queue[qg]->qg_qpaths[qd].qp_subdirs)) 52337c478bd9Sstevel@tonic-gate sub = "/qf/"; 52347c478bd9Sstevel@tonic-gate break; 52357c478bd9Sstevel@tonic-gate 52367c478bd9Sstevel@tonic-gate case XSCRPT_LETTER: 52377c478bd9Sstevel@tonic-gate if (bitset(QP_SUBXF, Queue[qg]->qg_qpaths[qd].qp_subdirs)) 52387c478bd9Sstevel@tonic-gate sub = "/xf/"; 52397c478bd9Sstevel@tonic-gate break; 52407c478bd9Sstevel@tonic-gate 52417c478bd9Sstevel@tonic-gate default: 52427c478bd9Sstevel@tonic-gate sm_abort("queuename: bad queue file type %d", type); 52437c478bd9Sstevel@tonic-gate } 52447c478bd9Sstevel@tonic-gate 5245*058561cbSjbeck (void) sm_strlcpyn(buf, sizeof(buf), 4, 52467c478bd9Sstevel@tonic-gate Queue[qg]->qg_qpaths[qd].qp_name, 52477c478bd9Sstevel@tonic-gate sub, pref, e->e_id); 52487c478bd9Sstevel@tonic-gate } 52497c478bd9Sstevel@tonic-gate 52507c478bd9Sstevel@tonic-gate if (tTd(7, 2)) 52517c478bd9Sstevel@tonic-gate sm_dprintf("queuename: %s\n", buf); 52527c478bd9Sstevel@tonic-gate return buf; 52537c478bd9Sstevel@tonic-gate } 52547c478bd9Sstevel@tonic-gate 52557c478bd9Sstevel@tonic-gate /* 52567c478bd9Sstevel@tonic-gate ** INIT_QID_ALG -- Initialize the (static) parameters that are used to 52577c478bd9Sstevel@tonic-gate ** generate a queue ID. 52587c478bd9Sstevel@tonic-gate ** 52597c478bd9Sstevel@tonic-gate ** This function is called by the daemon to reset 52607c478bd9Sstevel@tonic-gate ** LastQueueTime and LastQueuePid which are used by assign_queueid(). 52617c478bd9Sstevel@tonic-gate ** Otherwise the algorithm may cause problems because 52627c478bd9Sstevel@tonic-gate ** LastQueueTime and LastQueuePid are set indirectly by main() 52637c478bd9Sstevel@tonic-gate ** before the daemon process is started, hence LastQueuePid is not 52647c478bd9Sstevel@tonic-gate ** the pid of the daemon and therefore a child of the daemon can 52657c478bd9Sstevel@tonic-gate ** actually have the same pid as LastQueuePid which means the section 52667c478bd9Sstevel@tonic-gate ** in assign_queueid(): 52677c478bd9Sstevel@tonic-gate ** * see if we need to get a new base time/pid * 52687c478bd9Sstevel@tonic-gate ** is NOT triggered which will cause the same queue id to be generated. 52697c478bd9Sstevel@tonic-gate ** 52707c478bd9Sstevel@tonic-gate ** Parameters: 52717c478bd9Sstevel@tonic-gate ** none 52727c478bd9Sstevel@tonic-gate ** 52737c478bd9Sstevel@tonic-gate ** Returns: 52747c478bd9Sstevel@tonic-gate ** none. 52757c478bd9Sstevel@tonic-gate */ 52767c478bd9Sstevel@tonic-gate 52777c478bd9Sstevel@tonic-gate void 52787c478bd9Sstevel@tonic-gate init_qid_alg() 52797c478bd9Sstevel@tonic-gate { 52807c478bd9Sstevel@tonic-gate LastQueueTime = 0; 52817c478bd9Sstevel@tonic-gate LastQueuePid = -1; 52827c478bd9Sstevel@tonic-gate } 52837c478bd9Sstevel@tonic-gate 52847c478bd9Sstevel@tonic-gate /* 52857c478bd9Sstevel@tonic-gate ** ASSIGN_QUEUEID -- assign a queue ID for this envelope. 52867c478bd9Sstevel@tonic-gate ** 52877c478bd9Sstevel@tonic-gate ** Assigns an id code if one does not already exist. 52887c478bd9Sstevel@tonic-gate ** This code assumes that nothing will remain in the queue for 52897c478bd9Sstevel@tonic-gate ** longer than 60 years. It is critical that files with the given 52907c478bd9Sstevel@tonic-gate ** name do not already exist in the queue. 52917c478bd9Sstevel@tonic-gate ** [No longer initializes e_qdir to NOQDIR.] 52927c478bd9Sstevel@tonic-gate ** 52937c478bd9Sstevel@tonic-gate ** Parameters: 52947c478bd9Sstevel@tonic-gate ** e -- envelope to set it in. 52957c478bd9Sstevel@tonic-gate ** 52967c478bd9Sstevel@tonic-gate ** Returns: 52977c478bd9Sstevel@tonic-gate ** none. 52987c478bd9Sstevel@tonic-gate */ 52997c478bd9Sstevel@tonic-gate 53007c478bd9Sstevel@tonic-gate static const char QueueIdChars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 53017c478bd9Sstevel@tonic-gate # define QIC_LEN 60 53027c478bd9Sstevel@tonic-gate # define QIC_LEN_R 62 53037c478bd9Sstevel@tonic-gate 53047c478bd9Sstevel@tonic-gate /* 53057c478bd9Sstevel@tonic-gate ** Note: the length is "officially" 60 because minutes and seconds are 53067c478bd9Sstevel@tonic-gate ** usually only 0-59. However (Linux): 53077c478bd9Sstevel@tonic-gate ** tm_sec The number of seconds after the minute, normally in 53087c478bd9Sstevel@tonic-gate ** the range 0 to 59, but can be up to 61 to allow for 53097c478bd9Sstevel@tonic-gate ** leap seconds. 53107c478bd9Sstevel@tonic-gate ** Hence the real length of the string is 62 to take this into account. 53117c478bd9Sstevel@tonic-gate ** Alternatively % QIC_LEN can (should) be used for access everywhere. 53127c478bd9Sstevel@tonic-gate */ 53137c478bd9Sstevel@tonic-gate 53147c478bd9Sstevel@tonic-gate # define queuenextid() CurrentPid 53157c478bd9Sstevel@tonic-gate 53167c478bd9Sstevel@tonic-gate 53177c478bd9Sstevel@tonic-gate void 53187c478bd9Sstevel@tonic-gate assign_queueid(e) 53197c478bd9Sstevel@tonic-gate register ENVELOPE *e; 53207c478bd9Sstevel@tonic-gate { 53217c478bd9Sstevel@tonic-gate pid_t pid = queuenextid(); 53227c478bd9Sstevel@tonic-gate static int cX = 0; 53237c478bd9Sstevel@tonic-gate static long random_offset; 53247c478bd9Sstevel@tonic-gate struct tm *tm; 53257c478bd9Sstevel@tonic-gate char idbuf[MAXQFNAME - 2]; 53267c478bd9Sstevel@tonic-gate int seq; 53277c478bd9Sstevel@tonic-gate 53287c478bd9Sstevel@tonic-gate if (e->e_id != NULL) 53297c478bd9Sstevel@tonic-gate return; 53307c478bd9Sstevel@tonic-gate 53317c478bd9Sstevel@tonic-gate /* see if we need to get a new base time/pid */ 53327c478bd9Sstevel@tonic-gate if (cX >= QIC_LEN * QIC_LEN || LastQueueTime == 0 || 53337c478bd9Sstevel@tonic-gate LastQueuePid != pid) 53347c478bd9Sstevel@tonic-gate { 53357c478bd9Sstevel@tonic-gate time_t then = LastQueueTime; 53367c478bd9Sstevel@tonic-gate 53377c478bd9Sstevel@tonic-gate /* if the first time through, pick a random offset */ 53387c478bd9Sstevel@tonic-gate if (LastQueueTime == 0) 53397c478bd9Sstevel@tonic-gate random_offset = get_random(); 53407c478bd9Sstevel@tonic-gate 53417c478bd9Sstevel@tonic-gate while ((LastQueueTime = curtime()) == then && 53427c478bd9Sstevel@tonic-gate LastQueuePid == pid) 53437c478bd9Sstevel@tonic-gate { 53447c478bd9Sstevel@tonic-gate (void) sleep(1); 53457c478bd9Sstevel@tonic-gate } 53467c478bd9Sstevel@tonic-gate LastQueuePid = queuenextid(); 53477c478bd9Sstevel@tonic-gate cX = 0; 53487c478bd9Sstevel@tonic-gate } 53497c478bd9Sstevel@tonic-gate 53507c478bd9Sstevel@tonic-gate /* 53517c478bd9Sstevel@tonic-gate ** Generate a new sequence number between 0 and QIC_LEN*QIC_LEN-1. 53527c478bd9Sstevel@tonic-gate ** This lets us generate up to QIC_LEN*QIC_LEN unique queue ids 53537c478bd9Sstevel@tonic-gate ** per second, per process. With envelope splitting, 53547c478bd9Sstevel@tonic-gate ** a single message can consume many queue ids. 53557c478bd9Sstevel@tonic-gate */ 53567c478bd9Sstevel@tonic-gate 53577c478bd9Sstevel@tonic-gate seq = (int)((cX + random_offset) % (QIC_LEN * QIC_LEN)); 53587c478bd9Sstevel@tonic-gate ++cX; 53597c478bd9Sstevel@tonic-gate if (tTd(7, 50)) 53607c478bd9Sstevel@tonic-gate sm_dprintf("assign_queueid: random_offset = %ld (%d)\n", 53617c478bd9Sstevel@tonic-gate random_offset, seq); 53627c478bd9Sstevel@tonic-gate 53637c478bd9Sstevel@tonic-gate tm = gmtime(&LastQueueTime); 53647c478bd9Sstevel@tonic-gate idbuf[0] = QueueIdChars[tm->tm_year % QIC_LEN]; 53657c478bd9Sstevel@tonic-gate idbuf[1] = QueueIdChars[tm->tm_mon]; 53667c478bd9Sstevel@tonic-gate idbuf[2] = QueueIdChars[tm->tm_mday]; 53677c478bd9Sstevel@tonic-gate idbuf[3] = QueueIdChars[tm->tm_hour]; 53687c478bd9Sstevel@tonic-gate idbuf[4] = QueueIdChars[tm->tm_min % QIC_LEN_R]; 53697c478bd9Sstevel@tonic-gate idbuf[5] = QueueIdChars[tm->tm_sec % QIC_LEN_R]; 53707c478bd9Sstevel@tonic-gate idbuf[6] = QueueIdChars[seq / QIC_LEN]; 53717c478bd9Sstevel@tonic-gate idbuf[7] = QueueIdChars[seq % QIC_LEN]; 5372*058561cbSjbeck (void) sm_snprintf(&idbuf[8], sizeof(idbuf) - 8, "%06d", 53737c478bd9Sstevel@tonic-gate (int) LastQueuePid); 53747c478bd9Sstevel@tonic-gate e->e_id = sm_rpool_strdup_x(e->e_rpool, idbuf); 53757c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'i', e->e_id); 53767c478bd9Sstevel@tonic-gate #if 0 53777c478bd9Sstevel@tonic-gate /* XXX: inherited from MainEnvelope */ 53787c478bd9Sstevel@tonic-gate e->e_qgrp = NOQGRP; /* too early to do anything else */ 53797c478bd9Sstevel@tonic-gate e->e_qdir = NOQDIR; 53807c478bd9Sstevel@tonic-gate e->e_xfqgrp = NOQGRP; 53817c478bd9Sstevel@tonic-gate #endif /* 0 */ 53827c478bd9Sstevel@tonic-gate 53837c478bd9Sstevel@tonic-gate /* New ID means it's not on disk yet */ 53847c478bd9Sstevel@tonic-gate e->e_qfletter = '\0'; 53857c478bd9Sstevel@tonic-gate 53867c478bd9Sstevel@tonic-gate if (tTd(7, 1)) 53877c478bd9Sstevel@tonic-gate sm_dprintf("assign_queueid: assigned id %s, e=%p\n", 53887c478bd9Sstevel@tonic-gate e->e_id, e); 53897c478bd9Sstevel@tonic-gate if (LogLevel > 93) 53907c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "assigned id"); 53917c478bd9Sstevel@tonic-gate } 53927c478bd9Sstevel@tonic-gate /* 53937c478bd9Sstevel@tonic-gate ** SYNC_QUEUE_TIME -- Assure exclusive PID in any given second 53947c478bd9Sstevel@tonic-gate ** 53957c478bd9Sstevel@tonic-gate ** Make sure one PID can't be used by two processes in any one second. 53967c478bd9Sstevel@tonic-gate ** 53977c478bd9Sstevel@tonic-gate ** If the system rotates PIDs fast enough, may get the 53987c478bd9Sstevel@tonic-gate ** same pid in the same second for two distinct processes. 53997c478bd9Sstevel@tonic-gate ** This will interfere with the queue file naming system. 54007c478bd9Sstevel@tonic-gate ** 54017c478bd9Sstevel@tonic-gate ** Parameters: 54027c478bd9Sstevel@tonic-gate ** none 54037c478bd9Sstevel@tonic-gate ** 54047c478bd9Sstevel@tonic-gate ** Returns: 54057c478bd9Sstevel@tonic-gate ** none 54067c478bd9Sstevel@tonic-gate */ 54077c478bd9Sstevel@tonic-gate 54087c478bd9Sstevel@tonic-gate void 54097c478bd9Sstevel@tonic-gate sync_queue_time() 54107c478bd9Sstevel@tonic-gate { 54117c478bd9Sstevel@tonic-gate #if FAST_PID_RECYCLE 54127c478bd9Sstevel@tonic-gate if (OpMode != MD_TEST && 54137c478bd9Sstevel@tonic-gate OpMode != MD_VERIFY && 54147c478bd9Sstevel@tonic-gate LastQueueTime > 0 && 54157c478bd9Sstevel@tonic-gate LastQueuePid == CurrentPid && 54167c478bd9Sstevel@tonic-gate curtime() == LastQueueTime) 54177c478bd9Sstevel@tonic-gate (void) sleep(1); 54187c478bd9Sstevel@tonic-gate #endif /* FAST_PID_RECYCLE */ 54197c478bd9Sstevel@tonic-gate } 54207c478bd9Sstevel@tonic-gate /* 54217c478bd9Sstevel@tonic-gate ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 54227c478bd9Sstevel@tonic-gate ** 54237c478bd9Sstevel@tonic-gate ** Parameters: 54247c478bd9Sstevel@tonic-gate ** e -- the envelope to unlock. 54257c478bd9Sstevel@tonic-gate ** 54267c478bd9Sstevel@tonic-gate ** Returns: 54277c478bd9Sstevel@tonic-gate ** none 54287c478bd9Sstevel@tonic-gate ** 54297c478bd9Sstevel@tonic-gate ** Side Effects: 54307c478bd9Sstevel@tonic-gate ** unlocks the queue for `e'. 54317c478bd9Sstevel@tonic-gate */ 54327c478bd9Sstevel@tonic-gate 54337c478bd9Sstevel@tonic-gate void 54347c478bd9Sstevel@tonic-gate unlockqueue(e) 54357c478bd9Sstevel@tonic-gate ENVELOPE *e; 54367c478bd9Sstevel@tonic-gate { 54377c478bd9Sstevel@tonic-gate if (tTd(51, 4)) 54387c478bd9Sstevel@tonic-gate sm_dprintf("unlockqueue(%s)\n", 54397c478bd9Sstevel@tonic-gate e->e_id == NULL ? "NOQUEUE" : e->e_id); 54407c478bd9Sstevel@tonic-gate 54417c478bd9Sstevel@tonic-gate 54427c478bd9Sstevel@tonic-gate /* if there is a lock file in the envelope, close it */ 54437c478bd9Sstevel@tonic-gate if (e->e_lockfp != NULL) 54447c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT); 54457c478bd9Sstevel@tonic-gate e->e_lockfp = NULL; 54467c478bd9Sstevel@tonic-gate 54477c478bd9Sstevel@tonic-gate /* don't create a queue id if we don't already have one */ 54487c478bd9Sstevel@tonic-gate if (e->e_id == NULL) 54497c478bd9Sstevel@tonic-gate return; 54507c478bd9Sstevel@tonic-gate 54517c478bd9Sstevel@tonic-gate /* remove the transcript */ 54527c478bd9Sstevel@tonic-gate if (LogLevel > 87) 54537c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "unlock"); 54547c478bd9Sstevel@tonic-gate if (!tTd(51, 104)) 54557c478bd9Sstevel@tonic-gate (void) xunlink(queuename(e, XSCRPT_LETTER)); 54567c478bd9Sstevel@tonic-gate } 54577c478bd9Sstevel@tonic-gate /* 54587c478bd9Sstevel@tonic-gate ** SETCTLUSER -- create a controlling address 54597c478bd9Sstevel@tonic-gate ** 54607c478bd9Sstevel@tonic-gate ** Create a fake "address" given only a local login name; this is 54617c478bd9Sstevel@tonic-gate ** used as a "controlling user" for future recipient addresses. 54627c478bd9Sstevel@tonic-gate ** 54637c478bd9Sstevel@tonic-gate ** Parameters: 54647c478bd9Sstevel@tonic-gate ** user -- the user name of the controlling user. 54657c478bd9Sstevel@tonic-gate ** qfver -- the version stamp of this queue file. 54667c478bd9Sstevel@tonic-gate ** e -- envelope 54677c478bd9Sstevel@tonic-gate ** 54687c478bd9Sstevel@tonic-gate ** Returns: 54697c478bd9Sstevel@tonic-gate ** An address descriptor for the controlling user, 54707c478bd9Sstevel@tonic-gate ** using storage allocated from e->e_rpool. 54717c478bd9Sstevel@tonic-gate ** 54727c478bd9Sstevel@tonic-gate */ 54737c478bd9Sstevel@tonic-gate 54747c478bd9Sstevel@tonic-gate static ADDRESS * 54757c478bd9Sstevel@tonic-gate setctluser(user, qfver, e) 54767c478bd9Sstevel@tonic-gate char *user; 54777c478bd9Sstevel@tonic-gate int qfver; 54787c478bd9Sstevel@tonic-gate ENVELOPE *e; 54797c478bd9Sstevel@tonic-gate { 54807c478bd9Sstevel@tonic-gate register ADDRESS *a; 54817c478bd9Sstevel@tonic-gate struct passwd *pw; 54827c478bd9Sstevel@tonic-gate char *p; 54837c478bd9Sstevel@tonic-gate 54847c478bd9Sstevel@tonic-gate /* 54857c478bd9Sstevel@tonic-gate ** See if this clears our concept of controlling user. 54867c478bd9Sstevel@tonic-gate */ 54877c478bd9Sstevel@tonic-gate 54887c478bd9Sstevel@tonic-gate if (user == NULL || *user == '\0') 54897c478bd9Sstevel@tonic-gate return NULL; 54907c478bd9Sstevel@tonic-gate 54917c478bd9Sstevel@tonic-gate /* 54927c478bd9Sstevel@tonic-gate ** Set up addr fields for controlling user. 54937c478bd9Sstevel@tonic-gate */ 54947c478bd9Sstevel@tonic-gate 5495*058561cbSjbeck a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof(*a)); 5496*058561cbSjbeck memset((char *) a, '\0', sizeof(*a)); 54977c478bd9Sstevel@tonic-gate 54987c478bd9Sstevel@tonic-gate if (*user == ':') 54997c478bd9Sstevel@tonic-gate { 55007c478bd9Sstevel@tonic-gate p = &user[1]; 55017c478bd9Sstevel@tonic-gate a->q_user = sm_rpool_strdup_x(e->e_rpool, p); 55027c478bd9Sstevel@tonic-gate } 55037c478bd9Sstevel@tonic-gate else 55047c478bd9Sstevel@tonic-gate { 55057c478bd9Sstevel@tonic-gate p = strtok(user, ":"); 55067c478bd9Sstevel@tonic-gate a->q_user = sm_rpool_strdup_x(e->e_rpool, user); 55077c478bd9Sstevel@tonic-gate if (qfver >= 2) 55087c478bd9Sstevel@tonic-gate { 55097c478bd9Sstevel@tonic-gate if ((p = strtok(NULL, ":")) != NULL) 55107c478bd9Sstevel@tonic-gate a->q_uid = atoi(p); 55117c478bd9Sstevel@tonic-gate if ((p = strtok(NULL, ":")) != NULL) 55127c478bd9Sstevel@tonic-gate a->q_gid = atoi(p); 55137c478bd9Sstevel@tonic-gate if ((p = strtok(NULL, ":")) != NULL) 55147c478bd9Sstevel@tonic-gate { 55157c478bd9Sstevel@tonic-gate char *o; 55167c478bd9Sstevel@tonic-gate 55177c478bd9Sstevel@tonic-gate a->q_flags |= QGOODUID; 55187c478bd9Sstevel@tonic-gate 55197c478bd9Sstevel@tonic-gate /* if there is another ':': restore it */ 55207c478bd9Sstevel@tonic-gate if ((o = strtok(NULL, ":")) != NULL && o > p) 55217c478bd9Sstevel@tonic-gate o[-1] = ':'; 55227c478bd9Sstevel@tonic-gate } 55237c478bd9Sstevel@tonic-gate } 55247c478bd9Sstevel@tonic-gate else if ((pw = sm_getpwnam(user)) != NULL) 55257c478bd9Sstevel@tonic-gate { 55267c478bd9Sstevel@tonic-gate if (*pw->pw_dir == '\0') 55277c478bd9Sstevel@tonic-gate a->q_home = NULL; 55287c478bd9Sstevel@tonic-gate else if (strcmp(pw->pw_dir, "/") == 0) 55297c478bd9Sstevel@tonic-gate a->q_home = ""; 55307c478bd9Sstevel@tonic-gate else 55317c478bd9Sstevel@tonic-gate a->q_home = sm_rpool_strdup_x(e->e_rpool, pw->pw_dir); 55327c478bd9Sstevel@tonic-gate a->q_uid = pw->pw_uid; 55337c478bd9Sstevel@tonic-gate a->q_gid = pw->pw_gid; 55347c478bd9Sstevel@tonic-gate a->q_flags |= QGOODUID; 55357c478bd9Sstevel@tonic-gate } 55367c478bd9Sstevel@tonic-gate } 55377c478bd9Sstevel@tonic-gate 55387c478bd9Sstevel@tonic-gate a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */ 55397c478bd9Sstevel@tonic-gate a->q_mailer = LocalMailer; 55407c478bd9Sstevel@tonic-gate if (p == NULL) 55417c478bd9Sstevel@tonic-gate a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user); 55427c478bd9Sstevel@tonic-gate else 55437c478bd9Sstevel@tonic-gate a->q_paddr = sm_rpool_strdup_x(e->e_rpool, p); 55447c478bd9Sstevel@tonic-gate return a; 55457c478bd9Sstevel@tonic-gate } 55467c478bd9Sstevel@tonic-gate /* 55477c478bd9Sstevel@tonic-gate ** LOSEQFILE -- rename queue file with LOSEQF_LETTER & try to let someone know 55487c478bd9Sstevel@tonic-gate ** 55497c478bd9Sstevel@tonic-gate ** Parameters: 55507c478bd9Sstevel@tonic-gate ** e -- the envelope (e->e_id will be used). 55517c478bd9Sstevel@tonic-gate ** why -- reported to whomever can hear. 55527c478bd9Sstevel@tonic-gate ** 55537c478bd9Sstevel@tonic-gate ** Returns: 55547c478bd9Sstevel@tonic-gate ** none. 55557c478bd9Sstevel@tonic-gate */ 55567c478bd9Sstevel@tonic-gate 55577c478bd9Sstevel@tonic-gate void 55587c478bd9Sstevel@tonic-gate loseqfile(e, why) 55597c478bd9Sstevel@tonic-gate register ENVELOPE *e; 55607c478bd9Sstevel@tonic-gate char *why; 55617c478bd9Sstevel@tonic-gate { 55627c478bd9Sstevel@tonic-gate bool loseit = true; 55637c478bd9Sstevel@tonic-gate char *p; 55647c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN]; 55657c478bd9Sstevel@tonic-gate 55667c478bd9Sstevel@tonic-gate if (e == NULL || e->e_id == NULL) 55677c478bd9Sstevel@tonic-gate return; 55687c478bd9Sstevel@tonic-gate p = queuename(e, ANYQFL_LETTER); 5569*058561cbSjbeck if (sm_strlcpy(buf, p, sizeof(buf)) >= sizeof(buf)) 55707c478bd9Sstevel@tonic-gate return; 55717c478bd9Sstevel@tonic-gate if (!bitset(EF_INQUEUE, e->e_flags)) 55727c478bd9Sstevel@tonic-gate queueup(e, false, true); 55737c478bd9Sstevel@tonic-gate else if (QueueMode == QM_LOST) 55747c478bd9Sstevel@tonic-gate loseit = false; 55757c478bd9Sstevel@tonic-gate 55767c478bd9Sstevel@tonic-gate /* if already lost, no need to re-lose */ 55777c478bd9Sstevel@tonic-gate if (loseit) 55787c478bd9Sstevel@tonic-gate { 55797c478bd9Sstevel@tonic-gate p = queuename(e, LOSEQF_LETTER); 55807c478bd9Sstevel@tonic-gate if (rename(buf, p) < 0) 55817c478bd9Sstevel@tonic-gate syserr("cannot rename(%s, %s), uid=%d", 55827c478bd9Sstevel@tonic-gate buf, p, (int) geteuid()); 55837c478bd9Sstevel@tonic-gate else if (LogLevel > 0) 55847c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 55857c478bd9Sstevel@tonic-gate "Losing %s: %s", buf, why); 55867c478bd9Sstevel@tonic-gate } 55877c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL) 55887c478bd9Sstevel@tonic-gate { 55897c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); 55907c478bd9Sstevel@tonic-gate e->e_dfp = NULL; 55917c478bd9Sstevel@tonic-gate } 55927c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_HAS_DF; 55937c478bd9Sstevel@tonic-gate } 55947c478bd9Sstevel@tonic-gate /* 55957c478bd9Sstevel@tonic-gate ** NAME2QID -- translate a queue group name to a queue group id 55967c478bd9Sstevel@tonic-gate ** 55977c478bd9Sstevel@tonic-gate ** Parameters: 55987c478bd9Sstevel@tonic-gate ** queuename -- name of queue group. 55997c478bd9Sstevel@tonic-gate ** 56007c478bd9Sstevel@tonic-gate ** Returns: 56017c478bd9Sstevel@tonic-gate ** queue group id if found. 56027c478bd9Sstevel@tonic-gate ** NOQGRP otherwise. 56037c478bd9Sstevel@tonic-gate */ 56047c478bd9Sstevel@tonic-gate 56057c478bd9Sstevel@tonic-gate int 56067c478bd9Sstevel@tonic-gate name2qid(queuename) 56077c478bd9Sstevel@tonic-gate char *queuename; 56087c478bd9Sstevel@tonic-gate { 56097c478bd9Sstevel@tonic-gate register STAB *s; 56107c478bd9Sstevel@tonic-gate 56117c478bd9Sstevel@tonic-gate s = stab(queuename, ST_QUEUE, ST_FIND); 56127c478bd9Sstevel@tonic-gate if (s == NULL) 56137c478bd9Sstevel@tonic-gate return NOQGRP; 56147c478bd9Sstevel@tonic-gate return s->s_quegrp->qg_index; 56157c478bd9Sstevel@tonic-gate } 56167c478bd9Sstevel@tonic-gate /* 56177c478bd9Sstevel@tonic-gate ** QID_PRINTNAME -- create externally printable version of queue id 56187c478bd9Sstevel@tonic-gate ** 56197c478bd9Sstevel@tonic-gate ** Parameters: 56207c478bd9Sstevel@tonic-gate ** e -- the envelope. 56217c478bd9Sstevel@tonic-gate ** 56227c478bd9Sstevel@tonic-gate ** Returns: 56237c478bd9Sstevel@tonic-gate ** a printable version 56247c478bd9Sstevel@tonic-gate */ 56257c478bd9Sstevel@tonic-gate 56267c478bd9Sstevel@tonic-gate char * 56277c478bd9Sstevel@tonic-gate qid_printname(e) 56287c478bd9Sstevel@tonic-gate ENVELOPE *e; 56297c478bd9Sstevel@tonic-gate { 56307c478bd9Sstevel@tonic-gate char *id; 56317c478bd9Sstevel@tonic-gate static char idbuf[MAXQFNAME + 34]; 56327c478bd9Sstevel@tonic-gate 56337c478bd9Sstevel@tonic-gate if (e == NULL) 56347c478bd9Sstevel@tonic-gate return ""; 56357c478bd9Sstevel@tonic-gate 56367c478bd9Sstevel@tonic-gate if (e->e_id == NULL) 56377c478bd9Sstevel@tonic-gate id = ""; 56387c478bd9Sstevel@tonic-gate else 56397c478bd9Sstevel@tonic-gate id = e->e_id; 56407c478bd9Sstevel@tonic-gate 56417c478bd9Sstevel@tonic-gate if (e->e_qdir == NOQDIR) 56427c478bd9Sstevel@tonic-gate return id; 56437c478bd9Sstevel@tonic-gate 5644*058561cbSjbeck (void) sm_snprintf(idbuf, sizeof(idbuf), "%.32s/%s", 56457c478bd9Sstevel@tonic-gate Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_name, 56467c478bd9Sstevel@tonic-gate id); 56477c478bd9Sstevel@tonic-gate return idbuf; 56487c478bd9Sstevel@tonic-gate } 56497c478bd9Sstevel@tonic-gate /* 56507c478bd9Sstevel@tonic-gate ** QID_PRINTQUEUE -- create full version of queue directory for data files 56517c478bd9Sstevel@tonic-gate ** 56527c478bd9Sstevel@tonic-gate ** Parameters: 56537c478bd9Sstevel@tonic-gate ** qgrp -- index in queue group. 56547c478bd9Sstevel@tonic-gate ** qdir -- the short version of the queue directory 56557c478bd9Sstevel@tonic-gate ** 56567c478bd9Sstevel@tonic-gate ** Returns: 56577c478bd9Sstevel@tonic-gate ** the full pathname to the queue (might point to a static var) 56587c478bd9Sstevel@tonic-gate */ 56597c478bd9Sstevel@tonic-gate 56607c478bd9Sstevel@tonic-gate char * 56617c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir) 56627c478bd9Sstevel@tonic-gate int qgrp; 56637c478bd9Sstevel@tonic-gate int qdir; 56647c478bd9Sstevel@tonic-gate { 56657c478bd9Sstevel@tonic-gate char *subdir; 56667c478bd9Sstevel@tonic-gate static char dir[MAXPATHLEN]; 56677c478bd9Sstevel@tonic-gate 56687c478bd9Sstevel@tonic-gate if (qdir == NOQDIR) 56697c478bd9Sstevel@tonic-gate return Queue[qgrp]->qg_qdir; 56707c478bd9Sstevel@tonic-gate 56717c478bd9Sstevel@tonic-gate if (strcmp(Queue[qgrp]->qg_qpaths[qdir].qp_name, ".") == 0) 56727c478bd9Sstevel@tonic-gate subdir = NULL; 56737c478bd9Sstevel@tonic-gate else 56747c478bd9Sstevel@tonic-gate subdir = Queue[qgrp]->qg_qpaths[qdir].qp_name; 56757c478bd9Sstevel@tonic-gate 5676*058561cbSjbeck (void) sm_strlcpyn(dir, sizeof(dir), 4, 56777c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qdir, 56787c478bd9Sstevel@tonic-gate subdir == NULL ? "" : "/", 56797c478bd9Sstevel@tonic-gate subdir == NULL ? "" : subdir, 56807c478bd9Sstevel@tonic-gate (bitset(QP_SUBDF, 56817c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs) 56827c478bd9Sstevel@tonic-gate ? "/df" : "")); 56837c478bd9Sstevel@tonic-gate return dir; 56847c478bd9Sstevel@tonic-gate } 56857c478bd9Sstevel@tonic-gate 56867c478bd9Sstevel@tonic-gate /* 56877c478bd9Sstevel@tonic-gate ** PICKQDIR -- Pick a queue directory from a queue group 56887c478bd9Sstevel@tonic-gate ** 56897c478bd9Sstevel@tonic-gate ** Parameters: 56907c478bd9Sstevel@tonic-gate ** qg -- queue group 56917c478bd9Sstevel@tonic-gate ** fsize -- file size in bytes 56927c478bd9Sstevel@tonic-gate ** e -- envelope, or NULL 56937c478bd9Sstevel@tonic-gate ** 56947c478bd9Sstevel@tonic-gate ** Result: 56957c478bd9Sstevel@tonic-gate ** NOQDIR if no queue directory in qg has enough free space to 56967c478bd9Sstevel@tonic-gate ** hold a file of size 'fsize', otherwise the index of 56977c478bd9Sstevel@tonic-gate ** a randomly selected queue directory which resides on a 56987c478bd9Sstevel@tonic-gate ** file system with enough disk space. 56997c478bd9Sstevel@tonic-gate ** XXX This could be extended to select a queuedir with 57007c478bd9Sstevel@tonic-gate ** a few (the fewest?) number of entries. That data 57017c478bd9Sstevel@tonic-gate ** is available if shared memory is used. 57027c478bd9Sstevel@tonic-gate ** 57037c478bd9Sstevel@tonic-gate ** Side Effects: 57047c478bd9Sstevel@tonic-gate ** If the request fails and e != NULL then sm_syslog is called. 57057c478bd9Sstevel@tonic-gate */ 57067c478bd9Sstevel@tonic-gate 57077c478bd9Sstevel@tonic-gate int 57087c478bd9Sstevel@tonic-gate pickqdir(qg, fsize, e) 57097c478bd9Sstevel@tonic-gate QUEUEGRP *qg; 57107c478bd9Sstevel@tonic-gate long fsize; 57117c478bd9Sstevel@tonic-gate ENVELOPE *e; 57127c478bd9Sstevel@tonic-gate { 57137c478bd9Sstevel@tonic-gate int qdir; 57147c478bd9Sstevel@tonic-gate int i; 57157c478bd9Sstevel@tonic-gate long avail = 0; 57167c478bd9Sstevel@tonic-gate 57177c478bd9Sstevel@tonic-gate /* Pick a random directory, as a starting point. */ 57187c478bd9Sstevel@tonic-gate if (qg->qg_numqueues <= 1) 57197c478bd9Sstevel@tonic-gate qdir = 0; 57207c478bd9Sstevel@tonic-gate else 57217c478bd9Sstevel@tonic-gate qdir = get_rand_mod(qg->qg_numqueues); 57227c478bd9Sstevel@tonic-gate 57237c478bd9Sstevel@tonic-gate if (MinBlocksFree <= 0 && fsize <= 0) 57247c478bd9Sstevel@tonic-gate return qdir; 57257c478bd9Sstevel@tonic-gate 57267c478bd9Sstevel@tonic-gate /* 57277c478bd9Sstevel@tonic-gate ** Now iterate over the queue directories, 57287c478bd9Sstevel@tonic-gate ** looking for a directory with enough space for this message. 57297c478bd9Sstevel@tonic-gate */ 57307c478bd9Sstevel@tonic-gate 57317c478bd9Sstevel@tonic-gate i = qdir; 57327c478bd9Sstevel@tonic-gate do 57337c478bd9Sstevel@tonic-gate { 57347c478bd9Sstevel@tonic-gate QPATHS *qp = &qg->qg_qpaths[i]; 57357c478bd9Sstevel@tonic-gate long needed = 0; 57367c478bd9Sstevel@tonic-gate long fsavail = 0; 57377c478bd9Sstevel@tonic-gate 57387c478bd9Sstevel@tonic-gate if (fsize > 0) 57397c478bd9Sstevel@tonic-gate needed += fsize / FILE_SYS_BLKSIZE(qp->qp_fsysidx) 57407c478bd9Sstevel@tonic-gate + ((fsize % FILE_SYS_BLKSIZE(qp->qp_fsysidx) 57417c478bd9Sstevel@tonic-gate > 0) ? 1 : 0); 57427c478bd9Sstevel@tonic-gate if (MinBlocksFree > 0) 57437c478bd9Sstevel@tonic-gate needed += MinBlocksFree; 57447c478bd9Sstevel@tonic-gate fsavail = FILE_SYS_AVAIL(qp->qp_fsysidx); 57457c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 57467c478bd9Sstevel@tonic-gate if (fsavail <= 0) 57477c478bd9Sstevel@tonic-gate { 57487c478bd9Sstevel@tonic-gate long blksize; 57497c478bd9Sstevel@tonic-gate 57507c478bd9Sstevel@tonic-gate /* 57517c478bd9Sstevel@tonic-gate ** might be not correctly updated, 57527c478bd9Sstevel@tonic-gate ** let's try to get the info directly. 57537c478bd9Sstevel@tonic-gate */ 57547c478bd9Sstevel@tonic-gate 57557c478bd9Sstevel@tonic-gate fsavail = freediskspace(FILE_SYS_NAME(qp->qp_fsysidx), 57567c478bd9Sstevel@tonic-gate &blksize); 57577c478bd9Sstevel@tonic-gate if (fsavail < 0) 57587c478bd9Sstevel@tonic-gate fsavail = 0; 57597c478bd9Sstevel@tonic-gate } 57607c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 57617c478bd9Sstevel@tonic-gate if (needed <= fsavail) 57627c478bd9Sstevel@tonic-gate return i; 57637c478bd9Sstevel@tonic-gate if (avail < fsavail) 57647c478bd9Sstevel@tonic-gate avail = fsavail; 57657c478bd9Sstevel@tonic-gate 57667c478bd9Sstevel@tonic-gate if (qg->qg_numqueues > 0) 57677c478bd9Sstevel@tonic-gate i = (i + 1) % qg->qg_numqueues; 57687c478bd9Sstevel@tonic-gate } while (i != qdir); 57697c478bd9Sstevel@tonic-gate 57707c478bd9Sstevel@tonic-gate if (e != NULL && LogLevel > 0) 57717c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 57727c478bd9Sstevel@tonic-gate "low on space (%s needs %ld bytes + %ld blocks in %s), max avail: %ld", 57737c478bd9Sstevel@tonic-gate CurHostName == NULL ? "SMTP-DAEMON" : CurHostName, 57747c478bd9Sstevel@tonic-gate fsize, MinBlocksFree, 57757c478bd9Sstevel@tonic-gate qg->qg_qdir, avail); 57767c478bd9Sstevel@tonic-gate return NOQDIR; 57777c478bd9Sstevel@tonic-gate } 57787c478bd9Sstevel@tonic-gate /* 57797c478bd9Sstevel@tonic-gate ** SETNEWQUEUE -- Sets a new queue group and directory 57807c478bd9Sstevel@tonic-gate ** 57817c478bd9Sstevel@tonic-gate ** Assign a queue group and directory to an envelope and store the 57827c478bd9Sstevel@tonic-gate ** directory in e->e_qdir. 57837c478bd9Sstevel@tonic-gate ** 57847c478bd9Sstevel@tonic-gate ** Parameters: 57857c478bd9Sstevel@tonic-gate ** e -- envelope to assign a queue for. 57867c478bd9Sstevel@tonic-gate ** 57877c478bd9Sstevel@tonic-gate ** Returns: 57887c478bd9Sstevel@tonic-gate ** true if successful 57897c478bd9Sstevel@tonic-gate ** false otherwise 57907c478bd9Sstevel@tonic-gate ** 57917c478bd9Sstevel@tonic-gate ** Side Effects: 57927c478bd9Sstevel@tonic-gate ** On success, e->e_qgrp and e->e_qdir are non-negative. 57937c478bd9Sstevel@tonic-gate ** On failure (not enough disk space), 57947c478bd9Sstevel@tonic-gate ** e->qgrp = NOQGRP, e->e_qdir = NOQDIR 57957c478bd9Sstevel@tonic-gate ** and usrerr() is invoked (which could raise an exception). 57967c478bd9Sstevel@tonic-gate */ 57977c478bd9Sstevel@tonic-gate 57987c478bd9Sstevel@tonic-gate bool 57997c478bd9Sstevel@tonic-gate setnewqueue(e) 58007c478bd9Sstevel@tonic-gate ENVELOPE *e; 58017c478bd9Sstevel@tonic-gate { 58027c478bd9Sstevel@tonic-gate if (tTd(41, 20)) 58037c478bd9Sstevel@tonic-gate sm_dprintf("setnewqueue: called\n"); 58047c478bd9Sstevel@tonic-gate 58057c478bd9Sstevel@tonic-gate /* not set somewhere else */ 58067c478bd9Sstevel@tonic-gate if (e->e_qgrp == NOQGRP) 58077c478bd9Sstevel@tonic-gate { 58087c478bd9Sstevel@tonic-gate ADDRESS *q; 58097c478bd9Sstevel@tonic-gate 58107c478bd9Sstevel@tonic-gate /* 58117c478bd9Sstevel@tonic-gate ** Use the queue group of the "first" recipient, as set by 58127c478bd9Sstevel@tonic-gate ** the "queuegroup" rule set. If that is not defined, then 58137c478bd9Sstevel@tonic-gate ** use the queue group of the mailer of the first recipient. 58147c478bd9Sstevel@tonic-gate ** If that is not defined either, then use the default 58157c478bd9Sstevel@tonic-gate ** queue group. 58167c478bd9Sstevel@tonic-gate ** Notice: "first" depends on the sorting of sendqueue 58177c478bd9Sstevel@tonic-gate ** in recipient(). 58187c478bd9Sstevel@tonic-gate ** To avoid problems with "bad" recipients look 58197c478bd9Sstevel@tonic-gate ** for a valid address first. 58207c478bd9Sstevel@tonic-gate */ 58217c478bd9Sstevel@tonic-gate 58227c478bd9Sstevel@tonic-gate q = e->e_sendqueue; 58237c478bd9Sstevel@tonic-gate while (q != NULL && 58247c478bd9Sstevel@tonic-gate (QS_IS_BADADDR(q->q_state) || QS_IS_DEAD(q->q_state))) 58257c478bd9Sstevel@tonic-gate { 58267c478bd9Sstevel@tonic-gate q = q->q_next; 58277c478bd9Sstevel@tonic-gate } 58287c478bd9Sstevel@tonic-gate if (q == NULL) 58297c478bd9Sstevel@tonic-gate e->e_qgrp = 0; 58307c478bd9Sstevel@tonic-gate else if (q->q_qgrp >= 0) 58317c478bd9Sstevel@tonic-gate e->e_qgrp = q->q_qgrp; 58327c478bd9Sstevel@tonic-gate else if (q->q_mailer != NULL && 58337c478bd9Sstevel@tonic-gate ISVALIDQGRP(q->q_mailer->m_qgrp)) 58347c478bd9Sstevel@tonic-gate e->e_qgrp = q->q_mailer->m_qgrp; 58357c478bd9Sstevel@tonic-gate else 58367c478bd9Sstevel@tonic-gate e->e_qgrp = 0; 58377c478bd9Sstevel@tonic-gate e->e_dfqgrp = e->e_qgrp; 58387c478bd9Sstevel@tonic-gate } 58397c478bd9Sstevel@tonic-gate 58407c478bd9Sstevel@tonic-gate if (ISVALIDQDIR(e->e_qdir) && ISVALIDQDIR(e->e_dfqdir)) 58417c478bd9Sstevel@tonic-gate { 58427c478bd9Sstevel@tonic-gate if (tTd(41, 20)) 58437c478bd9Sstevel@tonic-gate sm_dprintf("setnewqueue: e_qdir already assigned (%s)\n", 58447c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir)); 58457c478bd9Sstevel@tonic-gate return true; 58467c478bd9Sstevel@tonic-gate } 58477c478bd9Sstevel@tonic-gate 58487c478bd9Sstevel@tonic-gate filesys_update(); 58497c478bd9Sstevel@tonic-gate e->e_qdir = pickqdir(Queue[e->e_qgrp], e->e_msgsize, e); 58507c478bd9Sstevel@tonic-gate if (e->e_qdir == NOQDIR) 58517c478bd9Sstevel@tonic-gate { 58527c478bd9Sstevel@tonic-gate e->e_qgrp = NOQGRP; 58537c478bd9Sstevel@tonic-gate if (!bitset(EF_FATALERRS, e->e_flags)) 58547c478bd9Sstevel@tonic-gate usrerr("452 4.4.5 Insufficient disk space; try again later"); 58557c478bd9Sstevel@tonic-gate e->e_flags |= EF_FATALERRS; 58567c478bd9Sstevel@tonic-gate return false; 58577c478bd9Sstevel@tonic-gate } 58587c478bd9Sstevel@tonic-gate 58597c478bd9Sstevel@tonic-gate if (tTd(41, 3)) 58607c478bd9Sstevel@tonic-gate sm_dprintf("setnewqueue: Assigned queue directory %s\n", 58617c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir)); 58627c478bd9Sstevel@tonic-gate 58637c478bd9Sstevel@tonic-gate if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR) 58647c478bd9Sstevel@tonic-gate { 58657c478bd9Sstevel@tonic-gate e->e_xfqgrp = e->e_qgrp; 58667c478bd9Sstevel@tonic-gate e->e_xfqdir = e->e_qdir; 58677c478bd9Sstevel@tonic-gate } 58687c478bd9Sstevel@tonic-gate e->e_dfqdir = e->e_qdir; 58697c478bd9Sstevel@tonic-gate return true; 58707c478bd9Sstevel@tonic-gate } 58717c478bd9Sstevel@tonic-gate /* 58727c478bd9Sstevel@tonic-gate ** CHKQDIR -- check a queue directory 58737c478bd9Sstevel@tonic-gate ** 58747c478bd9Sstevel@tonic-gate ** Parameters: 58757c478bd9Sstevel@tonic-gate ** name -- name of queue directory 58767c478bd9Sstevel@tonic-gate ** sff -- flags for safefile() 58777c478bd9Sstevel@tonic-gate ** 58787c478bd9Sstevel@tonic-gate ** Returns: 58797c478bd9Sstevel@tonic-gate ** is it a queue directory? 58807c478bd9Sstevel@tonic-gate */ 58817c478bd9Sstevel@tonic-gate 5882*058561cbSjbeck static bool chkqdir __P((char *, long)); 5883*058561cbSjbeck 58847c478bd9Sstevel@tonic-gate static bool 58857c478bd9Sstevel@tonic-gate chkqdir(name, sff) 58867c478bd9Sstevel@tonic-gate char *name; 58877c478bd9Sstevel@tonic-gate long sff; 58887c478bd9Sstevel@tonic-gate { 58897c478bd9Sstevel@tonic-gate struct stat statb; 58907c478bd9Sstevel@tonic-gate int i; 58917c478bd9Sstevel@tonic-gate 58927c478bd9Sstevel@tonic-gate /* skip over . and .. directories */ 58937c478bd9Sstevel@tonic-gate if (name[0] == '.' && 58947c478bd9Sstevel@tonic-gate (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) 58957c478bd9Sstevel@tonic-gate return false; 58967c478bd9Sstevel@tonic-gate #if HASLSTAT 58977c478bd9Sstevel@tonic-gate if (lstat(name, &statb) < 0) 58987c478bd9Sstevel@tonic-gate #else /* HASLSTAT */ 58997c478bd9Sstevel@tonic-gate if (stat(name, &statb) < 0) 59007c478bd9Sstevel@tonic-gate #endif /* HASLSTAT */ 59017c478bd9Sstevel@tonic-gate { 59027c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 59037c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: stat(\"%s\"): %s\n", 59047c478bd9Sstevel@tonic-gate name, sm_errstring(errno)); 59057c478bd9Sstevel@tonic-gate return false; 59067c478bd9Sstevel@tonic-gate } 59077c478bd9Sstevel@tonic-gate #if HASLSTAT 59087c478bd9Sstevel@tonic-gate if (S_ISLNK(statb.st_mode)) 59097c478bd9Sstevel@tonic-gate { 59107c478bd9Sstevel@tonic-gate /* 59117c478bd9Sstevel@tonic-gate ** For a symlink we need to make sure the 59127c478bd9Sstevel@tonic-gate ** target is a directory 59137c478bd9Sstevel@tonic-gate */ 59147c478bd9Sstevel@tonic-gate 59157c478bd9Sstevel@tonic-gate if (stat(name, &statb) < 0) 59167c478bd9Sstevel@tonic-gate { 59177c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 59187c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: stat(\"%s\"): %s\n", 59197c478bd9Sstevel@tonic-gate name, sm_errstring(errno)); 59207c478bd9Sstevel@tonic-gate return false; 59217c478bd9Sstevel@tonic-gate } 59227c478bd9Sstevel@tonic-gate } 59237c478bd9Sstevel@tonic-gate #endif /* HASLSTAT */ 59247c478bd9Sstevel@tonic-gate 59257c478bd9Sstevel@tonic-gate if (!S_ISDIR(statb.st_mode)) 59267c478bd9Sstevel@tonic-gate { 59277c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 59287c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: \"%s\": Not a directory\n", 59297c478bd9Sstevel@tonic-gate name); 59307c478bd9Sstevel@tonic-gate return false; 59317c478bd9Sstevel@tonic-gate } 59327c478bd9Sstevel@tonic-gate 59337c478bd9Sstevel@tonic-gate /* Print a warning if unsafe (but still use it) */ 59347c478bd9Sstevel@tonic-gate /* XXX do this only if we want the warning? */ 59357c478bd9Sstevel@tonic-gate i = safedirpath(name, RunAsUid, RunAsGid, NULL, sff, 0, 0); 59367c478bd9Sstevel@tonic-gate if (i != 0) 59377c478bd9Sstevel@tonic-gate { 59387c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 59397c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: \"%s\": Not safe: %s\n", 59407c478bd9Sstevel@tonic-gate name, sm_errstring(i)); 59417c478bd9Sstevel@tonic-gate #if _FFR_CHK_QUEUE 59427c478bd9Sstevel@tonic-gate if (LogLevel > 8) 59437c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 59447c478bd9Sstevel@tonic-gate "queue directory \"%s\": Not safe: %s", 59457c478bd9Sstevel@tonic-gate name, sm_errstring(i)); 59467c478bd9Sstevel@tonic-gate #endif /* _FFR_CHK_QUEUE */ 59477c478bd9Sstevel@tonic-gate } 59487c478bd9Sstevel@tonic-gate return true; 59497c478bd9Sstevel@tonic-gate } 59507c478bd9Sstevel@tonic-gate /* 59517c478bd9Sstevel@tonic-gate ** MULTIQUEUE_CACHE -- cache a list of paths to queues. 59527c478bd9Sstevel@tonic-gate ** 59537c478bd9Sstevel@tonic-gate ** Each potential queue is checked as the cache is built. 59547c478bd9Sstevel@tonic-gate ** Thereafter, each is blindly trusted. 59557c478bd9Sstevel@tonic-gate ** Note that we can be called again after a timeout to rebuild 59567c478bd9Sstevel@tonic-gate ** (although code for that is not ready yet). 59577c478bd9Sstevel@tonic-gate ** 59587c478bd9Sstevel@tonic-gate ** Parameters: 59597c478bd9Sstevel@tonic-gate ** basedir -- base of all queue directories. 59607c478bd9Sstevel@tonic-gate ** blen -- strlen(basedir). 59617c478bd9Sstevel@tonic-gate ** qg -- queue group. 59627c478bd9Sstevel@tonic-gate ** qn -- number of queue directories already cached. 59637c478bd9Sstevel@tonic-gate ** phash -- pointer to hash value over queue dirs. 59647c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 59657c478bd9Sstevel@tonic-gate ** only used if shared memory is active. 59667c478bd9Sstevel@tonic-gate #endif * SM_CONF_SHM * 59677c478bd9Sstevel@tonic-gate ** 59687c478bd9Sstevel@tonic-gate ** Returns: 59697c478bd9Sstevel@tonic-gate ** new number of queue directories. 59707c478bd9Sstevel@tonic-gate */ 59717c478bd9Sstevel@tonic-gate 59727c478bd9Sstevel@tonic-gate #define INITIAL_SLOTS 20 59737c478bd9Sstevel@tonic-gate #define ADD_SLOTS 10 59747c478bd9Sstevel@tonic-gate 59757c478bd9Sstevel@tonic-gate static int 59767c478bd9Sstevel@tonic-gate multiqueue_cache(basedir, blen, qg, qn, phash) 59777c478bd9Sstevel@tonic-gate char *basedir; 59787c478bd9Sstevel@tonic-gate int blen; 59797c478bd9Sstevel@tonic-gate QUEUEGRP *qg; 59807c478bd9Sstevel@tonic-gate int qn; 59817c478bd9Sstevel@tonic-gate unsigned int *phash; 59827c478bd9Sstevel@tonic-gate { 59837c478bd9Sstevel@tonic-gate char *cp; 59847c478bd9Sstevel@tonic-gate int i, len; 59857c478bd9Sstevel@tonic-gate int slotsleft = 0; 59867c478bd9Sstevel@tonic-gate long sff = SFF_ANYFILE; 59877c478bd9Sstevel@tonic-gate char qpath[MAXPATHLEN]; 59887c478bd9Sstevel@tonic-gate char subdir[MAXPATHLEN]; 59897c478bd9Sstevel@tonic-gate char prefix[MAXPATHLEN]; /* dir relative to basedir */ 59907c478bd9Sstevel@tonic-gate 59917c478bd9Sstevel@tonic-gate if (tTd(41, 20)) 59927c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: called\n"); 59937c478bd9Sstevel@tonic-gate 59947c478bd9Sstevel@tonic-gate /* Initialize to current directory */ 59957c478bd9Sstevel@tonic-gate prefix[0] = '.'; 59967c478bd9Sstevel@tonic-gate prefix[1] = '\0'; 59977c478bd9Sstevel@tonic-gate if (qg->qg_numqueues != 0 && qg->qg_qpaths != NULL) 59987c478bd9Sstevel@tonic-gate { 59997c478bd9Sstevel@tonic-gate for (i = 0; i < qg->qg_numqueues; i++) 60007c478bd9Sstevel@tonic-gate { 60017c478bd9Sstevel@tonic-gate if (qg->qg_qpaths[i].qp_name != NULL) 60027c478bd9Sstevel@tonic-gate (void) sm_free(qg->qg_qpaths[i].qp_name); /* XXX */ 60037c478bd9Sstevel@tonic-gate } 60047c478bd9Sstevel@tonic-gate (void) sm_free((char *) qg->qg_qpaths); /* XXX */ 60057c478bd9Sstevel@tonic-gate qg->qg_qpaths = NULL; 60067c478bd9Sstevel@tonic-gate qg->qg_numqueues = 0; 60077c478bd9Sstevel@tonic-gate } 60087c478bd9Sstevel@tonic-gate 60097c478bd9Sstevel@tonic-gate /* If running as root, allow safedirpath() checks to use privs */ 60107c478bd9Sstevel@tonic-gate if (RunAsUid == 0) 60117c478bd9Sstevel@tonic-gate sff |= SFF_ROOTOK; 60127c478bd9Sstevel@tonic-gate #if _FFR_CHK_QUEUE 60137c478bd9Sstevel@tonic-gate sff |= SFF_SAFEDIRPATH|SFF_NOWWFILES; 60147c478bd9Sstevel@tonic-gate if (!UseMSP) 60157c478bd9Sstevel@tonic-gate sff |= SFF_NOGWFILES; 60167c478bd9Sstevel@tonic-gate #endif /* _FFR_CHK_QUEUE */ 60177c478bd9Sstevel@tonic-gate 60187c478bd9Sstevel@tonic-gate if (!SM_IS_DIR_START(qg->qg_qdir)) 60197c478bd9Sstevel@tonic-gate { 60207c478bd9Sstevel@tonic-gate /* 60217c478bd9Sstevel@tonic-gate ** XXX we could add basedir, but then we have to realloc() 60227c478bd9Sstevel@tonic-gate ** the string... Maybe another time. 60237c478bd9Sstevel@tonic-gate */ 60247c478bd9Sstevel@tonic-gate 60257c478bd9Sstevel@tonic-gate syserr("QueuePath %s not absolute", qg->qg_qdir); 60267c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 60277c478bd9Sstevel@tonic-gate return qn; 60287c478bd9Sstevel@tonic-gate } 60297c478bd9Sstevel@tonic-gate 60307c478bd9Sstevel@tonic-gate /* qpath: directory of current workgroup */ 6031*058561cbSjbeck len = sm_strlcpy(qpath, qg->qg_qdir, sizeof(qpath)); 6032*058561cbSjbeck if (len >= sizeof(qpath)) 60337c478bd9Sstevel@tonic-gate { 60347c478bd9Sstevel@tonic-gate syserr("QueuePath %.256s too long (%d max)", 6035*058561cbSjbeck qg->qg_qdir, (int) sizeof(qpath)); 60367c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 60377c478bd9Sstevel@tonic-gate return qn; 60387c478bd9Sstevel@tonic-gate } 60397c478bd9Sstevel@tonic-gate 60407c478bd9Sstevel@tonic-gate /* begin of qpath must be same as basedir */ 60417c478bd9Sstevel@tonic-gate if (strncmp(basedir, qpath, blen) != 0 && 60427c478bd9Sstevel@tonic-gate (strncmp(basedir, qpath, blen - 1) != 0 || len != blen - 1)) 60437c478bd9Sstevel@tonic-gate { 60447c478bd9Sstevel@tonic-gate syserr("QueuePath %s not subpath of QueueDirectory %s", 60457c478bd9Sstevel@tonic-gate qpath, basedir); 60467c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 60477c478bd9Sstevel@tonic-gate return qn; 60487c478bd9Sstevel@tonic-gate } 60497c478bd9Sstevel@tonic-gate 60507c478bd9Sstevel@tonic-gate /* Do we have a nested subdirectory? */ 60517c478bd9Sstevel@tonic-gate if (blen < len && SM_FIRST_DIR_DELIM(qg->qg_qdir + blen) != NULL) 60527c478bd9Sstevel@tonic-gate { 60537c478bd9Sstevel@tonic-gate 60547c478bd9Sstevel@tonic-gate /* Copy subdirectory into prefix for later use */ 6055*058561cbSjbeck if (sm_strlcpy(prefix, qg->qg_qdir + blen, sizeof(prefix)) >= 6056*058561cbSjbeck sizeof(prefix)) 60577c478bd9Sstevel@tonic-gate { 60587c478bd9Sstevel@tonic-gate syserr("QueuePath %.256s too long (%d max)", 6059*058561cbSjbeck qg->qg_qdir, (int) sizeof(qpath)); 60607c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 60617c478bd9Sstevel@tonic-gate return qn; 60627c478bd9Sstevel@tonic-gate } 60637c478bd9Sstevel@tonic-gate cp = SM_LAST_DIR_DELIM(prefix); 60647c478bd9Sstevel@tonic-gate SM_ASSERT(cp != NULL); 60657c478bd9Sstevel@tonic-gate *cp = '\0'; /* cut off trailing / */ 60667c478bd9Sstevel@tonic-gate } 60677c478bd9Sstevel@tonic-gate 60687c478bd9Sstevel@tonic-gate /* This is guaranteed by the basedir check above */ 60697c478bd9Sstevel@tonic-gate SM_ASSERT(len >= blen - 1); 60707c478bd9Sstevel@tonic-gate cp = &qpath[len - 1]; 60717c478bd9Sstevel@tonic-gate if (*cp == '*') 60727c478bd9Sstevel@tonic-gate { 60737c478bd9Sstevel@tonic-gate register DIR *dp; 60747c478bd9Sstevel@tonic-gate register struct dirent *d; 60757c478bd9Sstevel@tonic-gate int off; 60767c478bd9Sstevel@tonic-gate char *delim; 60777c478bd9Sstevel@tonic-gate char relpath[MAXPATHLEN]; 60787c478bd9Sstevel@tonic-gate 60797c478bd9Sstevel@tonic-gate *cp = '\0'; /* Overwrite wildcard */ 60807c478bd9Sstevel@tonic-gate if ((cp = SM_LAST_DIR_DELIM(qpath)) == NULL) 60817c478bd9Sstevel@tonic-gate { 60827c478bd9Sstevel@tonic-gate syserr("QueueDirectory: can not wildcard relative path"); 60837c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 60847c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: \"%s*\": Can not wildcard relative path.\n", 60857c478bd9Sstevel@tonic-gate qpath); 60867c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 60877c478bd9Sstevel@tonic-gate return qn; 60887c478bd9Sstevel@tonic-gate } 60897c478bd9Sstevel@tonic-gate if (cp == qpath) 60907c478bd9Sstevel@tonic-gate { 60917c478bd9Sstevel@tonic-gate /* 60927c478bd9Sstevel@tonic-gate ** Special case of top level wildcard, like /foo* 60937c478bd9Sstevel@tonic-gate ** Change to //foo* 60947c478bd9Sstevel@tonic-gate */ 60957c478bd9Sstevel@tonic-gate 6096*058561cbSjbeck (void) sm_strlcpy(qpath + 1, qpath, sizeof(qpath) - 1); 60977c478bd9Sstevel@tonic-gate ++cp; 60987c478bd9Sstevel@tonic-gate } 60997c478bd9Sstevel@tonic-gate delim = cp; 61007c478bd9Sstevel@tonic-gate *(cp++) = '\0'; /* Replace / with \0 */ 61017c478bd9Sstevel@tonic-gate len = strlen(cp); /* Last component of queue directory */ 61027c478bd9Sstevel@tonic-gate 61037c478bd9Sstevel@tonic-gate /* 61047c478bd9Sstevel@tonic-gate ** Path relative to basedir, with trailing / 61057c478bd9Sstevel@tonic-gate ** It will be modified below to specify the subdirectories 61067c478bd9Sstevel@tonic-gate ** so they can be opened without chdir(). 61077c478bd9Sstevel@tonic-gate */ 61087c478bd9Sstevel@tonic-gate 6109*058561cbSjbeck off = sm_strlcpyn(relpath, sizeof(relpath), 2, prefix, "/"); 6110*058561cbSjbeck SM_ASSERT(off < sizeof(relpath)); 61117c478bd9Sstevel@tonic-gate 61127c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 61137c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: prefix=\"%s%s\"\n", 61147c478bd9Sstevel@tonic-gate relpath, cp); 61157c478bd9Sstevel@tonic-gate 61167c478bd9Sstevel@tonic-gate /* It is always basedir: we don't need to store it per group */ 61177c478bd9Sstevel@tonic-gate /* XXX: optimize this! -> one more global? */ 61187c478bd9Sstevel@tonic-gate qg->qg_qdir = newstr(basedir); 61197c478bd9Sstevel@tonic-gate qg->qg_qdir[blen - 1] = '\0'; /* cut off trailing / */ 61207c478bd9Sstevel@tonic-gate 61217c478bd9Sstevel@tonic-gate /* 61227c478bd9Sstevel@tonic-gate ** XXX Should probably wrap this whole loop in a timeout 61237c478bd9Sstevel@tonic-gate ** in case some wag decides to NFS mount the queues. 61247c478bd9Sstevel@tonic-gate */ 61257c478bd9Sstevel@tonic-gate 61267c478bd9Sstevel@tonic-gate /* Test path to get warning messages. */ 61277c478bd9Sstevel@tonic-gate if (qn == 0) 61287c478bd9Sstevel@tonic-gate { 61297c478bd9Sstevel@tonic-gate /* XXX qg_runasuid and qg_runasgid for specials? */ 61307c478bd9Sstevel@tonic-gate i = safedirpath(basedir, RunAsUid, RunAsGid, NULL, 61317c478bd9Sstevel@tonic-gate sff, 0, 0); 61327c478bd9Sstevel@tonic-gate if (i != 0 && tTd(41, 2)) 61337c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: \"%s\": Not safe: %s\n", 61347c478bd9Sstevel@tonic-gate basedir, sm_errstring(i)); 61357c478bd9Sstevel@tonic-gate } 61367c478bd9Sstevel@tonic-gate 61377c478bd9Sstevel@tonic-gate if ((dp = opendir(prefix)) == NULL) 61387c478bd9Sstevel@tonic-gate { 61397c478bd9Sstevel@tonic-gate syserr("can not opendir(%s/%s)", qg->qg_qdir, prefix); 61407c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 61417c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: opendir(\"%s/%s\"): %s\n", 61427c478bd9Sstevel@tonic-gate qg->qg_qdir, prefix, 61437c478bd9Sstevel@tonic-gate sm_errstring(errno)); 61447c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 61457c478bd9Sstevel@tonic-gate return qn; 61467c478bd9Sstevel@tonic-gate } 61477c478bd9Sstevel@tonic-gate while ((d = readdir(dp)) != NULL) 61487c478bd9Sstevel@tonic-gate { 6149*058561cbSjbeck /* Skip . and .. directories */ 6150*058561cbSjbeck if (strcmp(d->d_name, ".") == 0 || 6151*058561cbSjbeck strcmp(d->d_name, "..") == 0) 6152*058561cbSjbeck continue; 6153*058561cbSjbeck 61547c478bd9Sstevel@tonic-gate i = strlen(d->d_name); 61557c478bd9Sstevel@tonic-gate if (i < len || strncmp(d->d_name, cp, len) != 0) 61567c478bd9Sstevel@tonic-gate { 61577c478bd9Sstevel@tonic-gate if (tTd(41, 5)) 61587c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: \"%s\", skipped\n", 61597c478bd9Sstevel@tonic-gate d->d_name); 61607c478bd9Sstevel@tonic-gate continue; 61617c478bd9Sstevel@tonic-gate } 61627c478bd9Sstevel@tonic-gate 61637c478bd9Sstevel@tonic-gate /* Create relative pathname: prefix + local directory */ 61647c478bd9Sstevel@tonic-gate i = sizeof(relpath) - off; 61657c478bd9Sstevel@tonic-gate if (sm_strlcpy(relpath + off, d->d_name, i) >= i) 61667c478bd9Sstevel@tonic-gate continue; /* way too long */ 61677c478bd9Sstevel@tonic-gate 61687c478bd9Sstevel@tonic-gate if (!chkqdir(relpath, sff)) 61697c478bd9Sstevel@tonic-gate continue; 61707c478bd9Sstevel@tonic-gate 61717c478bd9Sstevel@tonic-gate if (qg->qg_qpaths == NULL) 61727c478bd9Sstevel@tonic-gate { 61737c478bd9Sstevel@tonic-gate slotsleft = INITIAL_SLOTS; 6174*058561cbSjbeck qg->qg_qpaths = (QPATHS *)xalloc((sizeof(*qg->qg_qpaths)) * 61757c478bd9Sstevel@tonic-gate slotsleft); 61767c478bd9Sstevel@tonic-gate qg->qg_numqueues = 0; 61777c478bd9Sstevel@tonic-gate } 61787c478bd9Sstevel@tonic-gate else if (slotsleft < 1) 61797c478bd9Sstevel@tonic-gate { 61807c478bd9Sstevel@tonic-gate qg->qg_qpaths = (QPATHS *)sm_realloc((char *)qg->qg_qpaths, 6181*058561cbSjbeck (sizeof(*qg->qg_qpaths)) * 61827c478bd9Sstevel@tonic-gate (qg->qg_numqueues + 61837c478bd9Sstevel@tonic-gate ADD_SLOTS)); 61847c478bd9Sstevel@tonic-gate if (qg->qg_qpaths == NULL) 61857c478bd9Sstevel@tonic-gate { 61867c478bd9Sstevel@tonic-gate (void) closedir(dp); 61877c478bd9Sstevel@tonic-gate return qn; 61887c478bd9Sstevel@tonic-gate } 61897c478bd9Sstevel@tonic-gate slotsleft += ADD_SLOTS; 61907c478bd9Sstevel@tonic-gate } 61917c478bd9Sstevel@tonic-gate 61927c478bd9Sstevel@tonic-gate /* check subdirs */ 61937c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_subdirs = QP_NOSUB; 61947c478bd9Sstevel@tonic-gate 61957c478bd9Sstevel@tonic-gate #define CHKRSUBDIR(name, flag) \ 6196*058561cbSjbeck (void) sm_strlcpyn(subdir, sizeof(subdir), 3, relpath, "/", name); \ 61977c478bd9Sstevel@tonic-gate if (chkqdir(subdir, sff)) \ 61987c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_subdirs |= flag; \ 61997c478bd9Sstevel@tonic-gate else 62007c478bd9Sstevel@tonic-gate 62017c478bd9Sstevel@tonic-gate 62027c478bd9Sstevel@tonic-gate CHKRSUBDIR("qf", QP_SUBQF); 62037c478bd9Sstevel@tonic-gate CHKRSUBDIR("df", QP_SUBDF); 62047c478bd9Sstevel@tonic-gate CHKRSUBDIR("xf", QP_SUBXF); 62057c478bd9Sstevel@tonic-gate 62067c478bd9Sstevel@tonic-gate /* assert(strlen(d->d_name) < MAXPATHLEN - 14) */ 62077c478bd9Sstevel@tonic-gate /* maybe even - 17 (subdirs) */ 62087c478bd9Sstevel@tonic-gate 62097c478bd9Sstevel@tonic-gate if (prefix[0] != '.') 62107c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_name = 62117c478bd9Sstevel@tonic-gate newstr(relpath); 62127c478bd9Sstevel@tonic-gate else 62137c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_name = 62147c478bd9Sstevel@tonic-gate newstr(d->d_name); 62157c478bd9Sstevel@tonic-gate 62167c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 62177c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: %d: \"%s\" cached (%x).\n", 62187c478bd9Sstevel@tonic-gate qg->qg_numqueues, relpath, 62197c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_subdirs); 62207c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 62217c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_idx = qn; 62227c478bd9Sstevel@tonic-gate *phash = hash_q(relpath, *phash); 62237c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 62247c478bd9Sstevel@tonic-gate qg->qg_numqueues++; 62257c478bd9Sstevel@tonic-gate ++qn; 62267c478bd9Sstevel@tonic-gate slotsleft--; 62277c478bd9Sstevel@tonic-gate } 62287c478bd9Sstevel@tonic-gate (void) closedir(dp); 62297c478bd9Sstevel@tonic-gate 62307c478bd9Sstevel@tonic-gate /* undo damage */ 62317c478bd9Sstevel@tonic-gate *delim = '/'; 62327c478bd9Sstevel@tonic-gate } 62337c478bd9Sstevel@tonic-gate if (qg->qg_numqueues == 0) 62347c478bd9Sstevel@tonic-gate { 6235*058561cbSjbeck qg->qg_qpaths = (QPATHS *) xalloc(sizeof(*qg->qg_qpaths)); 62367c478bd9Sstevel@tonic-gate 62377c478bd9Sstevel@tonic-gate /* test path to get warning messages */ 62387c478bd9Sstevel@tonic-gate i = safedirpath(qpath, RunAsUid, RunAsGid, NULL, sff, 0, 0); 62397c478bd9Sstevel@tonic-gate if (i == ENOENT) 62407c478bd9Sstevel@tonic-gate { 62417c478bd9Sstevel@tonic-gate syserr("can not opendir(%s)", qpath); 62427c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 62437c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: opendir(\"%s\"): %s\n", 62447c478bd9Sstevel@tonic-gate qpath, sm_errstring(i)); 62457c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 62467c478bd9Sstevel@tonic-gate return qn; 62477c478bd9Sstevel@tonic-gate } 62487c478bd9Sstevel@tonic-gate 62497c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_subdirs = QP_NOSUB; 62507c478bd9Sstevel@tonic-gate qg->qg_numqueues = 1; 62517c478bd9Sstevel@tonic-gate 62527c478bd9Sstevel@tonic-gate /* check subdirs */ 62537c478bd9Sstevel@tonic-gate #define CHKSUBDIR(name, flag) \ 6254*058561cbSjbeck (void) sm_strlcpyn(subdir, sizeof(subdir), 3, qg->qg_qdir, "/", name); \ 62557c478bd9Sstevel@tonic-gate if (chkqdir(subdir, sff)) \ 62567c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_subdirs |= flag; \ 62577c478bd9Sstevel@tonic-gate else 62587c478bd9Sstevel@tonic-gate 62597c478bd9Sstevel@tonic-gate CHKSUBDIR("qf", QP_SUBQF); 62607c478bd9Sstevel@tonic-gate CHKSUBDIR("df", QP_SUBDF); 62617c478bd9Sstevel@tonic-gate CHKSUBDIR("xf", QP_SUBXF); 62627c478bd9Sstevel@tonic-gate 62637c478bd9Sstevel@tonic-gate if (qg->qg_qdir[blen - 1] != '\0' && 62647c478bd9Sstevel@tonic-gate qg->qg_qdir[blen] != '\0') 62657c478bd9Sstevel@tonic-gate { 62667c478bd9Sstevel@tonic-gate /* 62677c478bd9Sstevel@tonic-gate ** Copy the last component into qpaths and 62687c478bd9Sstevel@tonic-gate ** cut off qdir 62697c478bd9Sstevel@tonic-gate */ 62707c478bd9Sstevel@tonic-gate 62717c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_name = newstr(qg->qg_qdir + blen); 62727c478bd9Sstevel@tonic-gate qg->qg_qdir[blen - 1] = '\0'; 62737c478bd9Sstevel@tonic-gate } 62747c478bd9Sstevel@tonic-gate else 62757c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_name = newstr("."); 62767c478bd9Sstevel@tonic-gate 62777c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 62787c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_idx = qn; 62797c478bd9Sstevel@tonic-gate *phash = hash_q(qg->qg_qpaths[0].qp_name, *phash); 62807c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 62817c478bd9Sstevel@tonic-gate ++qn; 62827c478bd9Sstevel@tonic-gate } 62837c478bd9Sstevel@tonic-gate return qn; 62847c478bd9Sstevel@tonic-gate } 62857c478bd9Sstevel@tonic-gate 62867c478bd9Sstevel@tonic-gate /* 62877c478bd9Sstevel@tonic-gate ** FILESYS_FIND -- find entry in FileSys table, or add new one 62887c478bd9Sstevel@tonic-gate ** 62897c478bd9Sstevel@tonic-gate ** Given the pathname of a directory, determine the file system 62907c478bd9Sstevel@tonic-gate ** in which that directory resides, and return a pointer to the 62917c478bd9Sstevel@tonic-gate ** entry in the FileSys table that describes the file system. 62927c478bd9Sstevel@tonic-gate ** A new entry is added if necessary (and requested). 62937c478bd9Sstevel@tonic-gate ** If the directory does not exist, -1 is returned. 62947c478bd9Sstevel@tonic-gate ** 62957c478bd9Sstevel@tonic-gate ** Parameters: 629649218d4fSjbeck ** name -- name of directory (must be persistent!) 629749218d4fSjbeck ** path -- pathname of directory (name plus maybe "/df") 62987c478bd9Sstevel@tonic-gate ** add -- add to structure if not found. 62997c478bd9Sstevel@tonic-gate ** 63007c478bd9Sstevel@tonic-gate ** Returns: 63017c478bd9Sstevel@tonic-gate ** >=0: found: index in file system table 63027c478bd9Sstevel@tonic-gate ** <0: some error, i.e., 63037c478bd9Sstevel@tonic-gate ** FSF_TOO_MANY: too many filesystems (-> syserr()) 63047c478bd9Sstevel@tonic-gate ** FSF_STAT_FAIL: can't stat() filesystem (-> syserr()) 63057c478bd9Sstevel@tonic-gate ** FSF_NOT_FOUND: not in list 63067c478bd9Sstevel@tonic-gate */ 63077c478bd9Sstevel@tonic-gate 6308*058561cbSjbeck static short filesys_find __P((const char *, const char *, bool)); 63097c478bd9Sstevel@tonic-gate 63107c478bd9Sstevel@tonic-gate #define FSF_NOT_FOUND (-1) 63117c478bd9Sstevel@tonic-gate #define FSF_STAT_FAIL (-2) 63127c478bd9Sstevel@tonic-gate #define FSF_TOO_MANY (-3) 63137c478bd9Sstevel@tonic-gate 63147c478bd9Sstevel@tonic-gate static short 631549218d4fSjbeck filesys_find(name, path, add) 6316*058561cbSjbeck const char *name; 6317*058561cbSjbeck const char *path; 63187c478bd9Sstevel@tonic-gate bool add; 63197c478bd9Sstevel@tonic-gate { 63207c478bd9Sstevel@tonic-gate struct stat st; 63217c478bd9Sstevel@tonic-gate short i; 63227c478bd9Sstevel@tonic-gate 63237c478bd9Sstevel@tonic-gate if (stat(path, &st) < 0) 63247c478bd9Sstevel@tonic-gate { 63257c478bd9Sstevel@tonic-gate syserr("cannot stat queue directory %s", path); 63267c478bd9Sstevel@tonic-gate return FSF_STAT_FAIL; 63277c478bd9Sstevel@tonic-gate } 63287c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i) 63297c478bd9Sstevel@tonic-gate { 63307c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(i) == st.st_dev) 63311daa5768Sjbeck { 63321daa5768Sjbeck /* 63331daa5768Sjbeck ** Make sure the file system (FS) name is set: 63341daa5768Sjbeck ** even though the source code indicates that 63351daa5768Sjbeck ** FILE_SYS_DEV() is only set below, it could be 63361daa5768Sjbeck ** set via shared memory, hence we need to perform 63371daa5768Sjbeck ** this check/assignment here. 63381daa5768Sjbeck */ 63391daa5768Sjbeck 63401daa5768Sjbeck if (NULL == FILE_SYS_NAME(i)) 63411daa5768Sjbeck FILE_SYS_NAME(i) = name; 63427c478bd9Sstevel@tonic-gate return i; 63431daa5768Sjbeck } 63447c478bd9Sstevel@tonic-gate } 63457c478bd9Sstevel@tonic-gate if (i >= MAXFILESYS) 63467c478bd9Sstevel@tonic-gate { 63477c478bd9Sstevel@tonic-gate syserr("too many queue file systems (%d max)", MAXFILESYS); 63487c478bd9Sstevel@tonic-gate return FSF_TOO_MANY; 63497c478bd9Sstevel@tonic-gate } 63507c478bd9Sstevel@tonic-gate if (!add) 63517c478bd9Sstevel@tonic-gate return FSF_NOT_FOUND; 63527c478bd9Sstevel@tonic-gate 63537c478bd9Sstevel@tonic-gate ++NumFileSys; 635449218d4fSjbeck FILE_SYS_NAME(i) = name; 63557c478bd9Sstevel@tonic-gate FILE_SYS_DEV(i) = st.st_dev; 63567c478bd9Sstevel@tonic-gate FILE_SYS_AVAIL(i) = 0; 63577c478bd9Sstevel@tonic-gate FILE_SYS_BLKSIZE(i) = 1024; /* avoid divide by zero */ 63587c478bd9Sstevel@tonic-gate return i; 63597c478bd9Sstevel@tonic-gate } 63607c478bd9Sstevel@tonic-gate 63617c478bd9Sstevel@tonic-gate /* 63627c478bd9Sstevel@tonic-gate ** FILESYS_SETUP -- set up mapping from queue directories to file systems 63637c478bd9Sstevel@tonic-gate ** 63647c478bd9Sstevel@tonic-gate ** This data structure is used to efficiently check the amount of 63657c478bd9Sstevel@tonic-gate ** free space available in a set of queue directories. 63667c478bd9Sstevel@tonic-gate ** 63677c478bd9Sstevel@tonic-gate ** Parameters: 63687c478bd9Sstevel@tonic-gate ** add -- initialize structure if necessary. 63697c478bd9Sstevel@tonic-gate ** 63707c478bd9Sstevel@tonic-gate ** Returns: 63717c478bd9Sstevel@tonic-gate ** 0: success 63727c478bd9Sstevel@tonic-gate ** <0: some error, i.e., 63737c478bd9Sstevel@tonic-gate ** FSF_NOT_FOUND: not in list 63747c478bd9Sstevel@tonic-gate ** FSF_STAT_FAIL: can't stat() filesystem (-> syserr()) 63757c478bd9Sstevel@tonic-gate ** FSF_TOO_MANY: too many filesystems (-> syserr()) 63767c478bd9Sstevel@tonic-gate */ 63777c478bd9Sstevel@tonic-gate 63787c478bd9Sstevel@tonic-gate static int filesys_setup __P((bool)); 63797c478bd9Sstevel@tonic-gate 63807c478bd9Sstevel@tonic-gate static int 63817c478bd9Sstevel@tonic-gate filesys_setup(add) 63827c478bd9Sstevel@tonic-gate bool add; 63837c478bd9Sstevel@tonic-gate { 63847c478bd9Sstevel@tonic-gate int i, j; 63857c478bd9Sstevel@tonic-gate short fs; 63867c478bd9Sstevel@tonic-gate int ret; 63877c478bd9Sstevel@tonic-gate 63887c478bd9Sstevel@tonic-gate ret = 0; 63897c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 63907c478bd9Sstevel@tonic-gate { 63917c478bd9Sstevel@tonic-gate for (j = 0; j < Queue[i]->qg_numqueues; ++j) 63927c478bd9Sstevel@tonic-gate { 63937c478bd9Sstevel@tonic-gate QPATHS *qp = &Queue[i]->qg_qpaths[j]; 639449218d4fSjbeck char qddf[MAXPATHLEN]; 63957c478bd9Sstevel@tonic-gate 6396*058561cbSjbeck (void) sm_strlcpyn(qddf, sizeof(qddf), 2, qp->qp_name, 639749218d4fSjbeck (bitset(QP_SUBDF, qp->qp_subdirs) 639849218d4fSjbeck ? "/df" : "")); 639949218d4fSjbeck fs = filesys_find(qp->qp_name, qddf, add); 64007c478bd9Sstevel@tonic-gate if (fs >= 0) 64017c478bd9Sstevel@tonic-gate qp->qp_fsysidx = fs; 64027c478bd9Sstevel@tonic-gate else 64037c478bd9Sstevel@tonic-gate qp->qp_fsysidx = 0; 64047c478bd9Sstevel@tonic-gate if (fs < ret) 64057c478bd9Sstevel@tonic-gate ret = fs; 64067c478bd9Sstevel@tonic-gate } 64077c478bd9Sstevel@tonic-gate } 64087c478bd9Sstevel@tonic-gate return ret; 64097c478bd9Sstevel@tonic-gate } 64107c478bd9Sstevel@tonic-gate 64117c478bd9Sstevel@tonic-gate /* 64127c478bd9Sstevel@tonic-gate ** FILESYS_UPDATE -- update amount of free space on all file systems 64137c478bd9Sstevel@tonic-gate ** 64147c478bd9Sstevel@tonic-gate ** The FileSys table is used to cache the amount of free space 64157c478bd9Sstevel@tonic-gate ** available on all queue directory file systems. 64167c478bd9Sstevel@tonic-gate ** This function updates the cached information if it has expired. 64177c478bd9Sstevel@tonic-gate ** 64187c478bd9Sstevel@tonic-gate ** Parameters: 64197c478bd9Sstevel@tonic-gate ** none. 64207c478bd9Sstevel@tonic-gate ** 64217c478bd9Sstevel@tonic-gate ** Returns: 64227c478bd9Sstevel@tonic-gate ** none. 64237c478bd9Sstevel@tonic-gate ** 64247c478bd9Sstevel@tonic-gate ** Side Effects: 64257c478bd9Sstevel@tonic-gate ** Updates FileSys table. 64267c478bd9Sstevel@tonic-gate */ 64277c478bd9Sstevel@tonic-gate 64287c478bd9Sstevel@tonic-gate void 64297c478bd9Sstevel@tonic-gate filesys_update() 64307c478bd9Sstevel@tonic-gate { 64317c478bd9Sstevel@tonic-gate int i; 64327c478bd9Sstevel@tonic-gate long avail, blksize; 64337c478bd9Sstevel@tonic-gate time_t now; 64347c478bd9Sstevel@tonic-gate static time_t nextupdate = 0; 64357c478bd9Sstevel@tonic-gate 64367c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 6437*058561cbSjbeck /* 6438*058561cbSjbeck ** Only the daemon updates the shared memory, i.e., 6439*058561cbSjbeck ** if shared memory is available but the pid is not the 6440*058561cbSjbeck ** one of the daemon, then don't do anything. 6441*058561cbSjbeck */ 6442*058561cbSjbeck 64431daa5768Sjbeck if (ShmId != SM_SHM_NO_ID && DaemonPid != CurrentPid) 64447c478bd9Sstevel@tonic-gate return; 64457c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 64467c478bd9Sstevel@tonic-gate now = curtime(); 64477c478bd9Sstevel@tonic-gate if (now < nextupdate) 64487c478bd9Sstevel@tonic-gate return; 64497c478bd9Sstevel@tonic-gate nextupdate = now + FILESYS_UPDATE_INTERVAL; 64507c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i) 64517c478bd9Sstevel@tonic-gate { 64527c478bd9Sstevel@tonic-gate FILESYS *fs = &FILE_SYS(i); 64537c478bd9Sstevel@tonic-gate 64547c478bd9Sstevel@tonic-gate avail = freediskspace(FILE_SYS_NAME(i), &blksize); 64557c478bd9Sstevel@tonic-gate if (avail < 0 || blksize <= 0) 64567c478bd9Sstevel@tonic-gate { 64577c478bd9Sstevel@tonic-gate if (LogLevel > 5) 64587c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 64597c478bd9Sstevel@tonic-gate "filesys_update failed: %s, fs=%s, avail=%ld, blocksize=%ld", 64607c478bd9Sstevel@tonic-gate sm_errstring(errno), 64617c478bd9Sstevel@tonic-gate FILE_SYS_NAME(i), avail, blksize); 64627c478bd9Sstevel@tonic-gate fs->fs_avail = 0; 64637c478bd9Sstevel@tonic-gate fs->fs_blksize = 1024; /* avoid divide by zero */ 64647c478bd9Sstevel@tonic-gate nextupdate = now + 2; /* let's do this soon again */ 64657c478bd9Sstevel@tonic-gate } 64667c478bd9Sstevel@tonic-gate else 64677c478bd9Sstevel@tonic-gate { 64687c478bd9Sstevel@tonic-gate fs->fs_avail = avail; 64697c478bd9Sstevel@tonic-gate fs->fs_blksize = blksize; 64707c478bd9Sstevel@tonic-gate } 64717c478bd9Sstevel@tonic-gate } 64727c478bd9Sstevel@tonic-gate } 64737c478bd9Sstevel@tonic-gate 64747c478bd9Sstevel@tonic-gate #if _FFR_ANY_FREE_FS 64757c478bd9Sstevel@tonic-gate /* 64767c478bd9Sstevel@tonic-gate ** FILESYS_FREE -- check whether there is at least one fs with enough space. 64777c478bd9Sstevel@tonic-gate ** 64787c478bd9Sstevel@tonic-gate ** Parameters: 64797c478bd9Sstevel@tonic-gate ** fsize -- file size in bytes 64807c478bd9Sstevel@tonic-gate ** 64817c478bd9Sstevel@tonic-gate ** Returns: 64827c478bd9Sstevel@tonic-gate ** true iff there is one fs with more than fsize bytes free. 64837c478bd9Sstevel@tonic-gate */ 64847c478bd9Sstevel@tonic-gate 64857c478bd9Sstevel@tonic-gate bool 64867c478bd9Sstevel@tonic-gate filesys_free(fsize) 64877c478bd9Sstevel@tonic-gate long fsize; 64887c478bd9Sstevel@tonic-gate { 64897c478bd9Sstevel@tonic-gate int i; 64907c478bd9Sstevel@tonic-gate 64917c478bd9Sstevel@tonic-gate if (fsize <= 0) 64927c478bd9Sstevel@tonic-gate return true; 64937c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i) 64947c478bd9Sstevel@tonic-gate { 64957c478bd9Sstevel@tonic-gate long needed = 0; 64967c478bd9Sstevel@tonic-gate 64977c478bd9Sstevel@tonic-gate if (FILE_SYS_AVAIL(i) < 0 || FILE_SYS_BLKSIZE(i) <= 0) 64987c478bd9Sstevel@tonic-gate continue; 64997c478bd9Sstevel@tonic-gate needed += fsize / FILE_SYS_BLKSIZE(i) 65007c478bd9Sstevel@tonic-gate + ((fsize % FILE_SYS_BLKSIZE(i) 65017c478bd9Sstevel@tonic-gate > 0) ? 1 : 0) 65027c478bd9Sstevel@tonic-gate + MinBlocksFree; 65037c478bd9Sstevel@tonic-gate if (needed <= FILE_SYS_AVAIL(i)) 65047c478bd9Sstevel@tonic-gate return true; 65057c478bd9Sstevel@tonic-gate } 65067c478bd9Sstevel@tonic-gate return false; 65077c478bd9Sstevel@tonic-gate } 65087c478bd9Sstevel@tonic-gate #endif /* _FFR_ANY_FREE_FS */ 65097c478bd9Sstevel@tonic-gate 65107c478bd9Sstevel@tonic-gate /* 65117c478bd9Sstevel@tonic-gate ** DISK_STATUS -- show amount of free space in queue directories 65127c478bd9Sstevel@tonic-gate ** 65137c478bd9Sstevel@tonic-gate ** Parameters: 65147c478bd9Sstevel@tonic-gate ** out -- output file pointer. 65157c478bd9Sstevel@tonic-gate ** prefix -- string to output in front of each line. 65167c478bd9Sstevel@tonic-gate ** 65177c478bd9Sstevel@tonic-gate ** Returns: 65187c478bd9Sstevel@tonic-gate ** none. 65197c478bd9Sstevel@tonic-gate */ 65207c478bd9Sstevel@tonic-gate 65217c478bd9Sstevel@tonic-gate void 65227c478bd9Sstevel@tonic-gate disk_status(out, prefix) 65237c478bd9Sstevel@tonic-gate SM_FILE_T *out; 65247c478bd9Sstevel@tonic-gate char *prefix; 65257c478bd9Sstevel@tonic-gate { 65267c478bd9Sstevel@tonic-gate int i; 65277c478bd9Sstevel@tonic-gate long avail, blksize; 65287c478bd9Sstevel@tonic-gate long free; 65297c478bd9Sstevel@tonic-gate 65307c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i) 65317c478bd9Sstevel@tonic-gate { 65327c478bd9Sstevel@tonic-gate avail = freediskspace(FILE_SYS_NAME(i), &blksize); 65337c478bd9Sstevel@tonic-gate if (avail >= 0 && blksize > 0) 65347c478bd9Sstevel@tonic-gate { 65357c478bd9Sstevel@tonic-gate free = (long)((double) avail * 65367c478bd9Sstevel@tonic-gate ((double) blksize / 1024)); 65377c478bd9Sstevel@tonic-gate } 65387c478bd9Sstevel@tonic-gate else 65397c478bd9Sstevel@tonic-gate free = -1; 65407c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 65417c478bd9Sstevel@tonic-gate "%s%d/%s/%ld\r\n", 65427c478bd9Sstevel@tonic-gate prefix, i, 65437c478bd9Sstevel@tonic-gate FILE_SYS_NAME(i), 65447c478bd9Sstevel@tonic-gate free); 65457c478bd9Sstevel@tonic-gate } 65467c478bd9Sstevel@tonic-gate } 65477c478bd9Sstevel@tonic-gate 65487c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 65497c478bd9Sstevel@tonic-gate 65507c478bd9Sstevel@tonic-gate /* 65517c478bd9Sstevel@tonic-gate ** INIT_SEM -- initialize semaphore system 65527c478bd9Sstevel@tonic-gate ** 65537c478bd9Sstevel@tonic-gate ** Parameters: 65547c478bd9Sstevel@tonic-gate ** owner -- is this the owner of semaphores? 65557c478bd9Sstevel@tonic-gate ** 65567c478bd9Sstevel@tonic-gate ** Returns: 65577c478bd9Sstevel@tonic-gate ** none. 65587c478bd9Sstevel@tonic-gate */ 65597c478bd9Sstevel@tonic-gate 65607c478bd9Sstevel@tonic-gate #if _FFR_USE_SEM_LOCKING 65617c478bd9Sstevel@tonic-gate #if SM_CONF_SEM 65627c478bd9Sstevel@tonic-gate static int SemId = -1; /* Semaphore Id */ 65637c478bd9Sstevel@tonic-gate int SemKey = SM_SEM_KEY; 65647c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SEM */ 65657c478bd9Sstevel@tonic-gate #endif /* _FFR_USE_SEM_LOCKING */ 65667c478bd9Sstevel@tonic-gate 65677c478bd9Sstevel@tonic-gate static void init_sem __P((bool)); 65687c478bd9Sstevel@tonic-gate 65697c478bd9Sstevel@tonic-gate static void 65707c478bd9Sstevel@tonic-gate init_sem(owner) 65717c478bd9Sstevel@tonic-gate bool owner; 65727c478bd9Sstevel@tonic-gate { 65737c478bd9Sstevel@tonic-gate #if _FFR_USE_SEM_LOCKING 65747c478bd9Sstevel@tonic-gate #if SM_CONF_SEM 65757c478bd9Sstevel@tonic-gate SemId = sm_sem_start(SemKey, 1, 0, owner); 65767c478bd9Sstevel@tonic-gate if (SemId < 0) 65777c478bd9Sstevel@tonic-gate { 65787c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 65797c478bd9Sstevel@tonic-gate "func=init_sem, sem_key=%ld, sm_sem_start=%d", 65807c478bd9Sstevel@tonic-gate (long) SemKey, SemId); 65817c478bd9Sstevel@tonic-gate return; 65827c478bd9Sstevel@tonic-gate } 65837c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SEM */ 65847c478bd9Sstevel@tonic-gate #endif /* _FFR_USE_SEM_LOCKING */ 65857c478bd9Sstevel@tonic-gate return; 65867c478bd9Sstevel@tonic-gate } 65877c478bd9Sstevel@tonic-gate 65887c478bd9Sstevel@tonic-gate /* 65897c478bd9Sstevel@tonic-gate ** STOP_SEM -- stop semaphore system 65907c478bd9Sstevel@tonic-gate ** 65917c478bd9Sstevel@tonic-gate ** Parameters: 65927c478bd9Sstevel@tonic-gate ** owner -- is this the owner of semaphores? 65937c478bd9Sstevel@tonic-gate ** 65947c478bd9Sstevel@tonic-gate ** Returns: 65957c478bd9Sstevel@tonic-gate ** none. 65967c478bd9Sstevel@tonic-gate */ 65977c478bd9Sstevel@tonic-gate 65987c478bd9Sstevel@tonic-gate static void stop_sem __P((bool)); 65997c478bd9Sstevel@tonic-gate 66007c478bd9Sstevel@tonic-gate static void 66017c478bd9Sstevel@tonic-gate stop_sem(owner) 66027c478bd9Sstevel@tonic-gate bool owner; 66037c478bd9Sstevel@tonic-gate { 66047c478bd9Sstevel@tonic-gate #if _FFR_USE_SEM_LOCKING 66057c478bd9Sstevel@tonic-gate #if SM_CONF_SEM 66067c478bd9Sstevel@tonic-gate if (owner && SemId >= 0) 66077c478bd9Sstevel@tonic-gate sm_sem_stop(SemId); 66087c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SEM */ 66097c478bd9Sstevel@tonic-gate #endif /* _FFR_USE_SEM_LOCKING */ 66107c478bd9Sstevel@tonic-gate return; 66117c478bd9Sstevel@tonic-gate } 66127c478bd9Sstevel@tonic-gate 66137c478bd9Sstevel@tonic-gate /* 66147c478bd9Sstevel@tonic-gate ** UPD_QS -- update information about queue when adding/deleting an entry 66157c478bd9Sstevel@tonic-gate ** 66167c478bd9Sstevel@tonic-gate ** Parameters: 66177c478bd9Sstevel@tonic-gate ** e -- envelope. 66187c478bd9Sstevel@tonic-gate ** count -- add/remove entry (+1/0/-1: add/no change/remove) 66197c478bd9Sstevel@tonic-gate ** space -- update the space available as well. 66207c478bd9Sstevel@tonic-gate ** (>0/0/<0: add/no change/remove) 66217c478bd9Sstevel@tonic-gate ** where -- caller (for logging) 66227c478bd9Sstevel@tonic-gate ** 66237c478bd9Sstevel@tonic-gate ** Returns: 66247c478bd9Sstevel@tonic-gate ** none. 66257c478bd9Sstevel@tonic-gate ** 66267c478bd9Sstevel@tonic-gate ** Side Effects: 66277c478bd9Sstevel@tonic-gate ** Modifies available space in filesystem. 66287c478bd9Sstevel@tonic-gate ** Changes number of entries in queue directory. 66297c478bd9Sstevel@tonic-gate */ 66307c478bd9Sstevel@tonic-gate 66317c478bd9Sstevel@tonic-gate void 66327c478bd9Sstevel@tonic-gate upd_qs(e, count, space, where) 66337c478bd9Sstevel@tonic-gate ENVELOPE *e; 66347c478bd9Sstevel@tonic-gate int count; 66357c478bd9Sstevel@tonic-gate int space; 66367c478bd9Sstevel@tonic-gate char *where; 66377c478bd9Sstevel@tonic-gate { 66387c478bd9Sstevel@tonic-gate short fidx; 66397c478bd9Sstevel@tonic-gate int idx; 66407c478bd9Sstevel@tonic-gate # if _FFR_USE_SEM_LOCKING 66417c478bd9Sstevel@tonic-gate int r; 66427c478bd9Sstevel@tonic-gate # endif /* _FFR_USE_SEM_LOCKING */ 66437c478bd9Sstevel@tonic-gate long s; 66447c478bd9Sstevel@tonic-gate 66457c478bd9Sstevel@tonic-gate if (ShmId == SM_SHM_NO_ID || e == NULL) 66467c478bd9Sstevel@tonic-gate return; 66477c478bd9Sstevel@tonic-gate if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR) 66487c478bd9Sstevel@tonic-gate return; 66497c478bd9Sstevel@tonic-gate idx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_idx; 66507c478bd9Sstevel@tonic-gate if (tTd(73,2)) 66517c478bd9Sstevel@tonic-gate sm_dprintf("func=upd_qs, count=%d, space=%d, where=%s, idx=%d, entries=%d\n", 66527c478bd9Sstevel@tonic-gate count, space, where, idx, QSHM_ENTRIES(idx)); 66537c478bd9Sstevel@tonic-gate 66547c478bd9Sstevel@tonic-gate /* XXX in theory this needs to be protected with a mutex */ 66557c478bd9Sstevel@tonic-gate if (QSHM_ENTRIES(idx) >= 0 && count != 0) 66567c478bd9Sstevel@tonic-gate { 66577c478bd9Sstevel@tonic-gate # if _FFR_USE_SEM_LOCKING 66587c478bd9Sstevel@tonic-gate r = sm_sem_acq(SemId, 0, 1); 66597c478bd9Sstevel@tonic-gate # endif /* _FFR_USE_SEM_LOCKING */ 66607c478bd9Sstevel@tonic-gate QSHM_ENTRIES(idx) += count; 66617c478bd9Sstevel@tonic-gate # if _FFR_USE_SEM_LOCKING 66627c478bd9Sstevel@tonic-gate if (r >= 0) 66637c478bd9Sstevel@tonic-gate r = sm_sem_rel(SemId, 0, 1); 66647c478bd9Sstevel@tonic-gate # endif /* _FFR_USE_SEM_LOCKING */ 66657c478bd9Sstevel@tonic-gate } 66667c478bd9Sstevel@tonic-gate 66677c478bd9Sstevel@tonic-gate fidx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_fsysidx; 66687c478bd9Sstevel@tonic-gate if (fidx < 0) 66697c478bd9Sstevel@tonic-gate return; 66707c478bd9Sstevel@tonic-gate 66717c478bd9Sstevel@tonic-gate /* update available space also? (might be loseqfile) */ 66727c478bd9Sstevel@tonic-gate if (space == 0) 66737c478bd9Sstevel@tonic-gate return; 66747c478bd9Sstevel@tonic-gate 66757c478bd9Sstevel@tonic-gate /* convert size to blocks; this causes rounding errors */ 66767c478bd9Sstevel@tonic-gate s = e->e_msgsize / FILE_SYS_BLKSIZE(fidx); 66777c478bd9Sstevel@tonic-gate if (s == 0) 66787c478bd9Sstevel@tonic-gate return; 66797c478bd9Sstevel@tonic-gate 66807c478bd9Sstevel@tonic-gate /* XXX in theory this needs to be protected with a mutex */ 66817c478bd9Sstevel@tonic-gate if (space > 0) 66827c478bd9Sstevel@tonic-gate FILE_SYS_AVAIL(fidx) += s; 66837c478bd9Sstevel@tonic-gate else 66847c478bd9Sstevel@tonic-gate FILE_SYS_AVAIL(fidx) -= s; 66857c478bd9Sstevel@tonic-gate 66867c478bd9Sstevel@tonic-gate } 66877c478bd9Sstevel@tonic-gate 66887c478bd9Sstevel@tonic-gate static bool write_key_file __P((char *, long)); 66897c478bd9Sstevel@tonic-gate static long read_key_file __P((char *, long)); 66907c478bd9Sstevel@tonic-gate 66917c478bd9Sstevel@tonic-gate /* 66927c478bd9Sstevel@tonic-gate ** WRITE_KEY_FILE -- record some key into a file. 66937c478bd9Sstevel@tonic-gate ** 66947c478bd9Sstevel@tonic-gate ** Parameters: 66957c478bd9Sstevel@tonic-gate ** keypath -- file name. 66967c478bd9Sstevel@tonic-gate ** key -- key to write. 66977c478bd9Sstevel@tonic-gate ** 66987c478bd9Sstevel@tonic-gate ** Returns: 66997c478bd9Sstevel@tonic-gate ** true iff file could be written. 67007c478bd9Sstevel@tonic-gate ** 67017c478bd9Sstevel@tonic-gate ** Side Effects: 67027c478bd9Sstevel@tonic-gate ** writes file. 67037c478bd9Sstevel@tonic-gate */ 67047c478bd9Sstevel@tonic-gate 67057c478bd9Sstevel@tonic-gate static bool 67067c478bd9Sstevel@tonic-gate write_key_file(keypath, key) 67077c478bd9Sstevel@tonic-gate char *keypath; 67087c478bd9Sstevel@tonic-gate long key; 67097c478bd9Sstevel@tonic-gate { 67107c478bd9Sstevel@tonic-gate bool ok; 67117c478bd9Sstevel@tonic-gate long sff; 67127c478bd9Sstevel@tonic-gate SM_FILE_T *keyf; 67137c478bd9Sstevel@tonic-gate 67147c478bd9Sstevel@tonic-gate ok = false; 67157c478bd9Sstevel@tonic-gate if (keypath == NULL || *keypath == '\0') 67167c478bd9Sstevel@tonic-gate return ok; 67177c478bd9Sstevel@tonic-gate sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT; 67187c478bd9Sstevel@tonic-gate if (TrustedUid != 0 && RealUid == TrustedUid) 67197c478bd9Sstevel@tonic-gate sff |= SFF_OPENASROOT; 67207c478bd9Sstevel@tonic-gate keyf = safefopen(keypath, O_WRONLY|O_TRUNC, FileMode, sff); 67217c478bd9Sstevel@tonic-gate if (keyf == NULL) 67227c478bd9Sstevel@tonic-gate { 67237c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, "unable to write %s: %s", 67247c478bd9Sstevel@tonic-gate keypath, sm_errstring(errno)); 67257c478bd9Sstevel@tonic-gate } 67267c478bd9Sstevel@tonic-gate else 67277c478bd9Sstevel@tonic-gate { 672849218d4fSjbeck if (geteuid() == 0 && RunAsUid != 0) 672949218d4fSjbeck { 673049218d4fSjbeck # if HASFCHOWN 673149218d4fSjbeck int fd; 673249218d4fSjbeck 673349218d4fSjbeck fd = keyf->f_file; 673449218d4fSjbeck if (fd >= 0 && fchown(fd, RunAsUid, -1) < 0) 673549218d4fSjbeck { 673649218d4fSjbeck int err = errno; 673749218d4fSjbeck 673849218d4fSjbeck sm_syslog(LOG_ALERT, NOQID, 673949218d4fSjbeck "ownership change on %s to %d failed: %s", 674049218d4fSjbeck keypath, RunAsUid, sm_errstring(err)); 674149218d4fSjbeck } 674249218d4fSjbeck # endif /* HASFCHOWN */ 674349218d4fSjbeck } 67447c478bd9Sstevel@tonic-gate ok = sm_io_fprintf(keyf, SM_TIME_DEFAULT, "%ld\n", key) != 67457c478bd9Sstevel@tonic-gate SM_IO_EOF; 67467c478bd9Sstevel@tonic-gate ok = (sm_io_close(keyf, SM_TIME_DEFAULT) != SM_IO_EOF) && ok; 67477c478bd9Sstevel@tonic-gate } 67487c478bd9Sstevel@tonic-gate return ok; 67497c478bd9Sstevel@tonic-gate } 67507c478bd9Sstevel@tonic-gate 67517c478bd9Sstevel@tonic-gate /* 67527c478bd9Sstevel@tonic-gate ** READ_KEY_FILE -- read a key from a file. 67537c478bd9Sstevel@tonic-gate ** 67547c478bd9Sstevel@tonic-gate ** Parameters: 67557c478bd9Sstevel@tonic-gate ** keypath -- file name. 67567c478bd9Sstevel@tonic-gate ** key -- default key. 67577c478bd9Sstevel@tonic-gate ** 67587c478bd9Sstevel@tonic-gate ** Returns: 67597c478bd9Sstevel@tonic-gate ** key. 67607c478bd9Sstevel@tonic-gate */ 67617c478bd9Sstevel@tonic-gate 67627c478bd9Sstevel@tonic-gate static long 67637c478bd9Sstevel@tonic-gate read_key_file(keypath, key) 67647c478bd9Sstevel@tonic-gate char *keypath; 67657c478bd9Sstevel@tonic-gate long key; 67667c478bd9Sstevel@tonic-gate { 67677c478bd9Sstevel@tonic-gate int r; 67687c478bd9Sstevel@tonic-gate long sff, n; 67697c478bd9Sstevel@tonic-gate SM_FILE_T *keyf; 67707c478bd9Sstevel@tonic-gate 67717c478bd9Sstevel@tonic-gate if (keypath == NULL || *keypath == '\0') 67727c478bd9Sstevel@tonic-gate return key; 67737c478bd9Sstevel@tonic-gate sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY; 67747c478bd9Sstevel@tonic-gate if (RealUid == 0 || (TrustedUid != 0 && RealUid == TrustedUid)) 67757c478bd9Sstevel@tonic-gate sff |= SFF_OPENASROOT; 67767c478bd9Sstevel@tonic-gate keyf = safefopen(keypath, O_RDONLY, FileMode, sff); 67777c478bd9Sstevel@tonic-gate if (keyf == NULL) 67787c478bd9Sstevel@tonic-gate { 67797c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, "unable to read %s: %s", 67807c478bd9Sstevel@tonic-gate keypath, sm_errstring(errno)); 67817c478bd9Sstevel@tonic-gate } 67827c478bd9Sstevel@tonic-gate else 67837c478bd9Sstevel@tonic-gate { 67847c478bd9Sstevel@tonic-gate r = sm_io_fscanf(keyf, SM_TIME_DEFAULT, "%ld", &n); 67857c478bd9Sstevel@tonic-gate if (r == 1) 67867c478bd9Sstevel@tonic-gate key = n; 67877c478bd9Sstevel@tonic-gate (void) sm_io_close(keyf, SM_TIME_DEFAULT); 67887c478bd9Sstevel@tonic-gate } 67897c478bd9Sstevel@tonic-gate return key; 67907c478bd9Sstevel@tonic-gate } 67917c478bd9Sstevel@tonic-gate 67927c478bd9Sstevel@tonic-gate /* 67937c478bd9Sstevel@tonic-gate ** INIT_SHM -- initialize shared memory structure 67947c478bd9Sstevel@tonic-gate ** 67957c478bd9Sstevel@tonic-gate ** Initialize or attach to shared memory segment. 67967c478bd9Sstevel@tonic-gate ** Currently it is not a fatal error if this doesn't work. 67977c478bd9Sstevel@tonic-gate ** However, it causes us to have a "fallback" storage location 67987c478bd9Sstevel@tonic-gate ** for everything that is supposed to be in the shared memory, 67997c478bd9Sstevel@tonic-gate ** which makes the code slightly ugly. 68007c478bd9Sstevel@tonic-gate ** 68017c478bd9Sstevel@tonic-gate ** Parameters: 68027c478bd9Sstevel@tonic-gate ** qn -- number of queue directories. 68037c478bd9Sstevel@tonic-gate ** owner -- owner of shared memory. 68047c478bd9Sstevel@tonic-gate ** hash -- identifies data that is stored in shared memory. 68057c478bd9Sstevel@tonic-gate ** 68067c478bd9Sstevel@tonic-gate ** Returns: 68077c478bd9Sstevel@tonic-gate ** none. 68087c478bd9Sstevel@tonic-gate */ 68097c478bd9Sstevel@tonic-gate 68107c478bd9Sstevel@tonic-gate static void init_shm __P((int, bool, unsigned int)); 68117c478bd9Sstevel@tonic-gate 68127c478bd9Sstevel@tonic-gate static void 68137c478bd9Sstevel@tonic-gate init_shm(qn, owner, hash) 68147c478bd9Sstevel@tonic-gate int qn; 68157c478bd9Sstevel@tonic-gate bool owner; 68167c478bd9Sstevel@tonic-gate unsigned int hash; 68177c478bd9Sstevel@tonic-gate { 68187c478bd9Sstevel@tonic-gate int i; 68197c478bd9Sstevel@tonic-gate int count; 68207c478bd9Sstevel@tonic-gate int save_errno; 68217c478bd9Sstevel@tonic-gate bool keyselect; 68227c478bd9Sstevel@tonic-gate 68237c478bd9Sstevel@tonic-gate PtrFileSys = &FileSys[0]; 68247c478bd9Sstevel@tonic-gate PNumFileSys = &Numfilesys; 68257c478bd9Sstevel@tonic-gate /* if this "key" is specified: select one yourself */ 6826*058561cbSjbeck #define SEL_SHM_KEY ((key_t) -1) 6827*058561cbSjbeck #define FIRST_SHM_KEY 25 68287c478bd9Sstevel@tonic-gate 68297c478bd9Sstevel@tonic-gate /* This allows us to disable shared memory at runtime. */ 68307c478bd9Sstevel@tonic-gate if (ShmKey == 0) 68317c478bd9Sstevel@tonic-gate return; 68327c478bd9Sstevel@tonic-gate 68337c478bd9Sstevel@tonic-gate count = 0; 68347c478bd9Sstevel@tonic-gate shms = SM_T_SIZE + qn * sizeof(QUEUE_SHM_T); 68357c478bd9Sstevel@tonic-gate keyselect = ShmKey == SEL_SHM_KEY; 68367c478bd9Sstevel@tonic-gate if (keyselect) 68377c478bd9Sstevel@tonic-gate { 68387c478bd9Sstevel@tonic-gate if (owner) 68397c478bd9Sstevel@tonic-gate ShmKey = FIRST_SHM_KEY; 68407c478bd9Sstevel@tonic-gate else 68417c478bd9Sstevel@tonic-gate { 6842*058561cbSjbeck errno = 0; 68437c478bd9Sstevel@tonic-gate ShmKey = read_key_file(ShmKeyFile, ShmKey); 68447c478bd9Sstevel@tonic-gate keyselect = false; 68457c478bd9Sstevel@tonic-gate if (ShmKey == SEL_SHM_KEY) 6846*058561cbSjbeck { 6847*058561cbSjbeck save_errno = (errno != 0) ? errno : EINVAL; 68487c478bd9Sstevel@tonic-gate goto error; 6849*058561cbSjbeck } 68507c478bd9Sstevel@tonic-gate } 68517c478bd9Sstevel@tonic-gate } 68527c478bd9Sstevel@tonic-gate for (;;) 68537c478bd9Sstevel@tonic-gate { 68547c478bd9Sstevel@tonic-gate /* allow read/write access for group? */ 68557c478bd9Sstevel@tonic-gate Pshm = sm_shmstart(ShmKey, shms, 68567c478bd9Sstevel@tonic-gate SHM_R|SHM_W|(SHM_R>>3)|(SHM_W>>3), 68577c478bd9Sstevel@tonic-gate &ShmId, owner); 68587c478bd9Sstevel@tonic-gate save_errno = errno; 68597c478bd9Sstevel@tonic-gate if (Pshm != NULL || !sm_file_exists(save_errno)) 68607c478bd9Sstevel@tonic-gate break; 68617c478bd9Sstevel@tonic-gate if (++count >= 3) 68627c478bd9Sstevel@tonic-gate { 68637c478bd9Sstevel@tonic-gate if (keyselect) 68647c478bd9Sstevel@tonic-gate { 68657c478bd9Sstevel@tonic-gate ++ShmKey; 68667c478bd9Sstevel@tonic-gate 68677c478bd9Sstevel@tonic-gate /* back where we started? */ 68687c478bd9Sstevel@tonic-gate if (ShmKey == SEL_SHM_KEY) 68697c478bd9Sstevel@tonic-gate break; 68707c478bd9Sstevel@tonic-gate continue; 68717c478bd9Sstevel@tonic-gate } 68727c478bd9Sstevel@tonic-gate break; 68737c478bd9Sstevel@tonic-gate } 6874*058561cbSjbeck 68757c478bd9Sstevel@tonic-gate /* only sleep if we are at the first key */ 68767c478bd9Sstevel@tonic-gate if (!keyselect || ShmKey == SEL_SHM_KEY) 6877*058561cbSjbeck sleep(count); 68787c478bd9Sstevel@tonic-gate } 68797c478bd9Sstevel@tonic-gate if (Pshm != NULL) 68807c478bd9Sstevel@tonic-gate { 68817c478bd9Sstevel@tonic-gate int *p; 68827c478bd9Sstevel@tonic-gate 68837c478bd9Sstevel@tonic-gate if (keyselect) 68847c478bd9Sstevel@tonic-gate (void) write_key_file(ShmKeyFile, (long) ShmKey); 68857c478bd9Sstevel@tonic-gate if (owner && RunAsUid != 0) 68867c478bd9Sstevel@tonic-gate { 6887445f2479Sjbeck i = sm_shmsetowner(ShmId, RunAsUid, RunAsGid, 0660); 68887c478bd9Sstevel@tonic-gate if (i != 0) 68897c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 6890445f2479Sjbeck "key=%ld, sm_shmsetowner=%d, RunAsUid=%d, RunAsGid=%d", 6891445f2479Sjbeck (long) ShmKey, i, RunAsUid, RunAsGid); 68927c478bd9Sstevel@tonic-gate } 68937c478bd9Sstevel@tonic-gate p = (int *) Pshm; 68947c478bd9Sstevel@tonic-gate if (owner) 68957c478bd9Sstevel@tonic-gate { 68967c478bd9Sstevel@tonic-gate *p = (int) shms; 68977c478bd9Sstevel@tonic-gate *((pid_t *) SHM_OFF_PID(Pshm)) = CurrentPid; 68987c478bd9Sstevel@tonic-gate p = (int *) SHM_OFF_TAG(Pshm); 68997c478bd9Sstevel@tonic-gate *p = hash; 69007c478bd9Sstevel@tonic-gate } 69017c478bd9Sstevel@tonic-gate else 69027c478bd9Sstevel@tonic-gate { 69037c478bd9Sstevel@tonic-gate if (*p != (int) shms) 69047c478bd9Sstevel@tonic-gate { 69057c478bd9Sstevel@tonic-gate save_errno = EINVAL; 69067c478bd9Sstevel@tonic-gate cleanup_shm(false); 69077c478bd9Sstevel@tonic-gate goto error; 69087c478bd9Sstevel@tonic-gate } 69097c478bd9Sstevel@tonic-gate p = (int *) SHM_OFF_TAG(Pshm); 69107c478bd9Sstevel@tonic-gate if (*p != (int) hash) 69117c478bd9Sstevel@tonic-gate { 69127c478bd9Sstevel@tonic-gate save_errno = EINVAL; 69137c478bd9Sstevel@tonic-gate cleanup_shm(false); 69147c478bd9Sstevel@tonic-gate goto error; 69157c478bd9Sstevel@tonic-gate } 69167c478bd9Sstevel@tonic-gate 69177c478bd9Sstevel@tonic-gate /* 69187c478bd9Sstevel@tonic-gate ** XXX how to check the pid? 69197c478bd9Sstevel@tonic-gate ** Read it from the pid-file? That does 69207c478bd9Sstevel@tonic-gate ** not need to exist. 69217c478bd9Sstevel@tonic-gate ** We could disable shm if we can't confirm 69227c478bd9Sstevel@tonic-gate ** that it is the right one. 69237c478bd9Sstevel@tonic-gate */ 69247c478bd9Sstevel@tonic-gate } 69257c478bd9Sstevel@tonic-gate 69267c478bd9Sstevel@tonic-gate PtrFileSys = (FILESYS *) OFF_FILE_SYS(Pshm); 69277c478bd9Sstevel@tonic-gate PNumFileSys = (int *) OFF_NUM_FILE_SYS(Pshm); 69287c478bd9Sstevel@tonic-gate QShm = (QUEUE_SHM_T *) OFF_QUEUE_SHM(Pshm); 69297c478bd9Sstevel@tonic-gate PRSATmpCnt = (int *) OFF_RSA_TMP_CNT(Pshm); 69307c478bd9Sstevel@tonic-gate *PRSATmpCnt = 0; 69317c478bd9Sstevel@tonic-gate if (owner) 69327c478bd9Sstevel@tonic-gate { 69337c478bd9Sstevel@tonic-gate /* initialize values in shared memory */ 69347c478bd9Sstevel@tonic-gate NumFileSys = 0; 69357c478bd9Sstevel@tonic-gate for (i = 0; i < qn; i++) 69367c478bd9Sstevel@tonic-gate QShm[i].qs_entries = -1; 69377c478bd9Sstevel@tonic-gate } 69387c478bd9Sstevel@tonic-gate init_sem(owner); 69397c478bd9Sstevel@tonic-gate return; 69407c478bd9Sstevel@tonic-gate } 69417c478bd9Sstevel@tonic-gate error: 69427c478bd9Sstevel@tonic-gate if (LogLevel > (owner ? 8 : 11)) 69437c478bd9Sstevel@tonic-gate { 69447c478bd9Sstevel@tonic-gate sm_syslog(owner ? LOG_ERR : LOG_NOTICE, NOQID, 69457c478bd9Sstevel@tonic-gate "can't %s shared memory, key=%ld: %s", 69467c478bd9Sstevel@tonic-gate owner ? "initialize" : "attach to", 69477c478bd9Sstevel@tonic-gate (long) ShmKey, sm_errstring(save_errno)); 69487c478bd9Sstevel@tonic-gate } 69497c478bd9Sstevel@tonic-gate } 69507c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 69517c478bd9Sstevel@tonic-gate 69527c478bd9Sstevel@tonic-gate 69537c478bd9Sstevel@tonic-gate /* 6954*058561cbSjbeck ** SETUP_QUEUES -- set up all queue groups 69557c478bd9Sstevel@tonic-gate ** 69567c478bd9Sstevel@tonic-gate ** Parameters: 6957*058561cbSjbeck ** owner -- owner of shared memory? 69587c478bd9Sstevel@tonic-gate ** 69597c478bd9Sstevel@tonic-gate ** Returns: 69607c478bd9Sstevel@tonic-gate ** none. 69617c478bd9Sstevel@tonic-gate ** 69627c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 69637c478bd9Sstevel@tonic-gate ** Side Effects: 69647c478bd9Sstevel@tonic-gate ** attaches shared memory. 69657c478bd9Sstevel@tonic-gate #endif * SM_CONF_SHM * 69667c478bd9Sstevel@tonic-gate */ 69677c478bd9Sstevel@tonic-gate 69687c478bd9Sstevel@tonic-gate void 69697c478bd9Sstevel@tonic-gate setup_queues(owner) 69707c478bd9Sstevel@tonic-gate bool owner; 69717c478bd9Sstevel@tonic-gate { 69727c478bd9Sstevel@tonic-gate int i, qn, len; 69737c478bd9Sstevel@tonic-gate unsigned int hashval; 69747c478bd9Sstevel@tonic-gate time_t now; 69757c478bd9Sstevel@tonic-gate char basedir[MAXPATHLEN]; 69767c478bd9Sstevel@tonic-gate struct stat st; 69777c478bd9Sstevel@tonic-gate 69787c478bd9Sstevel@tonic-gate /* 69797c478bd9Sstevel@tonic-gate ** Determine basedir for all queue directories. 69807c478bd9Sstevel@tonic-gate ** All queue directories must be (first level) subdirectories 69817c478bd9Sstevel@tonic-gate ** of the basedir. The basedir is the QueueDir 69827c478bd9Sstevel@tonic-gate ** without wildcards, but with trailing / 69837c478bd9Sstevel@tonic-gate */ 69847c478bd9Sstevel@tonic-gate 69857c478bd9Sstevel@tonic-gate hashval = 0; 69867c478bd9Sstevel@tonic-gate errno = 0; 6987*058561cbSjbeck len = sm_strlcpy(basedir, QueueDir, sizeof(basedir)); 69887c478bd9Sstevel@tonic-gate 69897c478bd9Sstevel@tonic-gate /* Provide space for trailing '/' */ 6990*058561cbSjbeck if (len >= sizeof(basedir) - 1) 69917c478bd9Sstevel@tonic-gate { 69927c478bd9Sstevel@tonic-gate syserr("QueueDirectory: path too long: %d, max %d", 6993*058561cbSjbeck len, (int) sizeof(basedir) - 1); 69947c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 69957c478bd9Sstevel@tonic-gate return; 69967c478bd9Sstevel@tonic-gate } 69977c478bd9Sstevel@tonic-gate SM_ASSERT(len > 0); 69987c478bd9Sstevel@tonic-gate if (basedir[len - 1] == '*') 69997c478bd9Sstevel@tonic-gate { 70007c478bd9Sstevel@tonic-gate char *cp; 70017c478bd9Sstevel@tonic-gate 70027c478bd9Sstevel@tonic-gate cp = SM_LAST_DIR_DELIM(basedir); 70037c478bd9Sstevel@tonic-gate if (cp == NULL) 70047c478bd9Sstevel@tonic-gate { 70057c478bd9Sstevel@tonic-gate syserr("QueueDirectory: can not wildcard relative path \"%s\"", 70067c478bd9Sstevel@tonic-gate QueueDir); 70077c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 70087c478bd9Sstevel@tonic-gate sm_dprintf("setup_queues: \"%s\": Can not wildcard relative path.\n", 70097c478bd9Sstevel@tonic-gate QueueDir); 70107c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 70117c478bd9Sstevel@tonic-gate return; 70127c478bd9Sstevel@tonic-gate } 70137c478bd9Sstevel@tonic-gate 70147c478bd9Sstevel@tonic-gate /* cut off wildcard pattern */ 70157c478bd9Sstevel@tonic-gate *++cp = '\0'; 70167c478bd9Sstevel@tonic-gate len = cp - basedir; 70177c478bd9Sstevel@tonic-gate } 70187c478bd9Sstevel@tonic-gate else if (!SM_IS_DIR_DELIM(basedir[len - 1])) 70197c478bd9Sstevel@tonic-gate { 70207c478bd9Sstevel@tonic-gate /* append trailing slash since it is a directory */ 70217c478bd9Sstevel@tonic-gate basedir[len] = '/'; 70227c478bd9Sstevel@tonic-gate basedir[++len] = '\0'; 70237c478bd9Sstevel@tonic-gate } 70247c478bd9Sstevel@tonic-gate 70257c478bd9Sstevel@tonic-gate /* len counts up to the last directory delimiter */ 70267c478bd9Sstevel@tonic-gate SM_ASSERT(basedir[len - 1] == '/'); 70277c478bd9Sstevel@tonic-gate 70287c478bd9Sstevel@tonic-gate if (chdir(basedir) < 0) 70297c478bd9Sstevel@tonic-gate { 70307c478bd9Sstevel@tonic-gate int save_errno = errno; 70317c478bd9Sstevel@tonic-gate 70327c478bd9Sstevel@tonic-gate syserr("can not chdir(%s)", basedir); 70337c478bd9Sstevel@tonic-gate if (save_errno == EACCES) 70347c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 70357c478bd9Sstevel@tonic-gate "Program mode requires special privileges, e.g., root or TrustedUser.\n"); 70367c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 70377c478bd9Sstevel@tonic-gate sm_dprintf("setup_queues: \"%s\": %s\n", 70387c478bd9Sstevel@tonic-gate basedir, sm_errstring(errno)); 70397c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 70407c478bd9Sstevel@tonic-gate return; 70417c478bd9Sstevel@tonic-gate } 70427c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 70437c478bd9Sstevel@tonic-gate hashval = hash_q(basedir, hashval); 70447c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 70457c478bd9Sstevel@tonic-gate 70467c478bd9Sstevel@tonic-gate /* initialize for queue runs */ 70477c478bd9Sstevel@tonic-gate DoQueueRun = false; 70487c478bd9Sstevel@tonic-gate now = curtime(); 70497c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 70507c478bd9Sstevel@tonic-gate Queue[i]->qg_nextrun = now; 70517c478bd9Sstevel@tonic-gate 70527c478bd9Sstevel@tonic-gate 70537c478bd9Sstevel@tonic-gate if (UseMSP && OpMode != MD_TEST) 70547c478bd9Sstevel@tonic-gate { 70557c478bd9Sstevel@tonic-gate long sff = SFF_CREAT; 70567c478bd9Sstevel@tonic-gate 70577c478bd9Sstevel@tonic-gate if (stat(".", &st) < 0) 70587c478bd9Sstevel@tonic-gate { 70597c478bd9Sstevel@tonic-gate syserr("can not stat(%s)", basedir); 70607c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 70617c478bd9Sstevel@tonic-gate sm_dprintf("setup_queues: \"%s\": %s\n", 70627c478bd9Sstevel@tonic-gate basedir, sm_errstring(errno)); 70637c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 70647c478bd9Sstevel@tonic-gate return; 70657c478bd9Sstevel@tonic-gate } 70667c478bd9Sstevel@tonic-gate if (RunAsUid == 0) 70677c478bd9Sstevel@tonic-gate sff |= SFF_ROOTOK; 70687c478bd9Sstevel@tonic-gate 70697c478bd9Sstevel@tonic-gate /* 70707c478bd9Sstevel@tonic-gate ** Check queue directory permissions. 70717c478bd9Sstevel@tonic-gate ** Can we write to a group writable queue directory? 70727c478bd9Sstevel@tonic-gate */ 70737c478bd9Sstevel@tonic-gate 70747c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode) && 70757c478bd9Sstevel@tonic-gate bitset(S_IWGRP, st.st_mode) && 70767c478bd9Sstevel@tonic-gate safefile(" ", RunAsUid, RunAsGid, RunAsUserName, sff, 70777c478bd9Sstevel@tonic-gate QueueFileMode, NULL) != 0) 70787c478bd9Sstevel@tonic-gate { 70797c478bd9Sstevel@tonic-gate syserr("can not write to queue directory %s (RunAsGid=%d, required=%d)", 70807c478bd9Sstevel@tonic-gate basedir, (int) RunAsGid, (int) st.st_gid); 70817c478bd9Sstevel@tonic-gate } 70827c478bd9Sstevel@tonic-gate if (bitset(S_IWOTH|S_IXOTH, st.st_mode)) 70837c478bd9Sstevel@tonic-gate { 70847c478bd9Sstevel@tonic-gate #if _FFR_MSP_PARANOIA 70857c478bd9Sstevel@tonic-gate syserr("dangerous permissions=%o on queue directory %s", 70867c478bd9Sstevel@tonic-gate (int) st.st_mode, basedir); 70877c478bd9Sstevel@tonic-gate #else /* _FFR_MSP_PARANOIA */ 70887c478bd9Sstevel@tonic-gate if (LogLevel > 0) 70897c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 70907c478bd9Sstevel@tonic-gate "dangerous permissions=%o on queue directory %s", 70917c478bd9Sstevel@tonic-gate (int) st.st_mode, basedir); 70927c478bd9Sstevel@tonic-gate #endif /* _FFR_MSP_PARANOIA */ 70937c478bd9Sstevel@tonic-gate } 70947c478bd9Sstevel@tonic-gate #if _FFR_MSP_PARANOIA 70957c478bd9Sstevel@tonic-gate if (NumQueue > 1) 70967c478bd9Sstevel@tonic-gate syserr("can not use multiple queues for MSP"); 70977c478bd9Sstevel@tonic-gate #endif /* _FFR_MSP_PARANOIA */ 70987c478bd9Sstevel@tonic-gate } 70997c478bd9Sstevel@tonic-gate 71007c478bd9Sstevel@tonic-gate /* initial number of queue directories */ 71017c478bd9Sstevel@tonic-gate qn = 0; 71027c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 71037c478bd9Sstevel@tonic-gate qn = multiqueue_cache(basedir, len, Queue[i], qn, &hashval); 71047c478bd9Sstevel@tonic-gate 71057c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 71067c478bd9Sstevel@tonic-gate init_shm(qn, owner, hashval); 71077c478bd9Sstevel@tonic-gate i = filesys_setup(owner || ShmId == SM_SHM_NO_ID); 71087c478bd9Sstevel@tonic-gate if (i == FSF_NOT_FOUND) 71097c478bd9Sstevel@tonic-gate { 71107c478bd9Sstevel@tonic-gate /* 71117c478bd9Sstevel@tonic-gate ** We didn't get the right filesystem data 71127c478bd9Sstevel@tonic-gate ** This may happen if we don't have the right shared memory. 71137c478bd9Sstevel@tonic-gate ** So let's do this without shared memory. 71147c478bd9Sstevel@tonic-gate */ 71157c478bd9Sstevel@tonic-gate 71167c478bd9Sstevel@tonic-gate SM_ASSERT(!owner); 71177c478bd9Sstevel@tonic-gate cleanup_shm(false); /* release shared memory */ 71187c478bd9Sstevel@tonic-gate i = filesys_setup(false); 71197c478bd9Sstevel@tonic-gate if (i < 0) 71207c478bd9Sstevel@tonic-gate syserr("filesys_setup failed twice, result=%d", i); 71217c478bd9Sstevel@tonic-gate else if (LogLevel > 8) 71227c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 71237c478bd9Sstevel@tonic-gate "shared memory does not contain expected data, ignored"); 71247c478bd9Sstevel@tonic-gate } 71257c478bd9Sstevel@tonic-gate #else /* SM_CONF_SHM */ 71267c478bd9Sstevel@tonic-gate i = filesys_setup(true); 71277c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 71287c478bd9Sstevel@tonic-gate if (i < 0) 71297c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 71307c478bd9Sstevel@tonic-gate } 71317c478bd9Sstevel@tonic-gate 71327c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 71337c478bd9Sstevel@tonic-gate /* 71347c478bd9Sstevel@tonic-gate ** CLEANUP_SHM -- do some cleanup work for shared memory etc 71357c478bd9Sstevel@tonic-gate ** 71367c478bd9Sstevel@tonic-gate ** Parameters: 71377c478bd9Sstevel@tonic-gate ** owner -- owner of shared memory? 71387c478bd9Sstevel@tonic-gate ** 71397c478bd9Sstevel@tonic-gate ** Returns: 71407c478bd9Sstevel@tonic-gate ** none. 71417c478bd9Sstevel@tonic-gate ** 71427c478bd9Sstevel@tonic-gate ** Side Effects: 71437c478bd9Sstevel@tonic-gate ** detaches shared memory. 71447c478bd9Sstevel@tonic-gate */ 71457c478bd9Sstevel@tonic-gate 71467c478bd9Sstevel@tonic-gate void 71477c478bd9Sstevel@tonic-gate cleanup_shm(owner) 71487c478bd9Sstevel@tonic-gate bool owner; 71497c478bd9Sstevel@tonic-gate { 71507c478bd9Sstevel@tonic-gate if (ShmId != SM_SHM_NO_ID) 71517c478bd9Sstevel@tonic-gate { 71527c478bd9Sstevel@tonic-gate if (sm_shmstop(Pshm, ShmId, owner) < 0 && LogLevel > 8) 71537c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "sm_shmstop failed=%s", 71547c478bd9Sstevel@tonic-gate sm_errstring(errno)); 71557c478bd9Sstevel@tonic-gate Pshm = NULL; 71567c478bd9Sstevel@tonic-gate ShmId = SM_SHM_NO_ID; 71577c478bd9Sstevel@tonic-gate } 71587c478bd9Sstevel@tonic-gate stop_sem(owner); 71597c478bd9Sstevel@tonic-gate } 71607c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 71617c478bd9Sstevel@tonic-gate 71627c478bd9Sstevel@tonic-gate /* 71637c478bd9Sstevel@tonic-gate ** CLEANUP_QUEUES -- do some cleanup work for queues 71647c478bd9Sstevel@tonic-gate ** 71657c478bd9Sstevel@tonic-gate ** Parameters: 71667c478bd9Sstevel@tonic-gate ** none. 71677c478bd9Sstevel@tonic-gate ** 71687c478bd9Sstevel@tonic-gate ** Returns: 71697c478bd9Sstevel@tonic-gate ** none. 71707c478bd9Sstevel@tonic-gate ** 71717c478bd9Sstevel@tonic-gate */ 71727c478bd9Sstevel@tonic-gate 71737c478bd9Sstevel@tonic-gate void 71747c478bd9Sstevel@tonic-gate cleanup_queues() 71757c478bd9Sstevel@tonic-gate { 71767c478bd9Sstevel@tonic-gate sync_queue_time(); 71777c478bd9Sstevel@tonic-gate } 71787c478bd9Sstevel@tonic-gate /* 71797c478bd9Sstevel@tonic-gate ** SET_DEF_QUEUEVAL -- set default values for a queue group. 71807c478bd9Sstevel@tonic-gate ** 71817c478bd9Sstevel@tonic-gate ** Parameters: 71827c478bd9Sstevel@tonic-gate ** qg -- queue group 71837c478bd9Sstevel@tonic-gate ** all -- set all values (true for default group)? 71847c478bd9Sstevel@tonic-gate ** 71857c478bd9Sstevel@tonic-gate ** Returns: 71867c478bd9Sstevel@tonic-gate ** none. 71877c478bd9Sstevel@tonic-gate ** 71887c478bd9Sstevel@tonic-gate ** Side Effects: 71897c478bd9Sstevel@tonic-gate ** sets default values for the queue group. 71907c478bd9Sstevel@tonic-gate */ 71917c478bd9Sstevel@tonic-gate 71927c478bd9Sstevel@tonic-gate void 71937c478bd9Sstevel@tonic-gate set_def_queueval(qg, all) 71947c478bd9Sstevel@tonic-gate QUEUEGRP *qg; 71957c478bd9Sstevel@tonic-gate bool all; 71967c478bd9Sstevel@tonic-gate { 71977c478bd9Sstevel@tonic-gate if (bitnset(QD_DEFINED, qg->qg_flags)) 71987c478bd9Sstevel@tonic-gate return; 71997c478bd9Sstevel@tonic-gate if (all) 72007c478bd9Sstevel@tonic-gate qg->qg_qdir = QueueDir; 72017c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_GROUP_SORTORDER 72027c478bd9Sstevel@tonic-gate qg->qg_sortorder = QueueSortOrder; 72037c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_GROUP_SORTORDER */ 72047c478bd9Sstevel@tonic-gate qg->qg_maxqrun = all ? MaxRunnersPerQueue : -1; 72057c478bd9Sstevel@tonic-gate qg->qg_nice = NiceQueueRun; 72067c478bd9Sstevel@tonic-gate } 72077c478bd9Sstevel@tonic-gate /* 72087c478bd9Sstevel@tonic-gate ** MAKEQUEUE -- define a new queue. 72097c478bd9Sstevel@tonic-gate ** 72107c478bd9Sstevel@tonic-gate ** Parameters: 72117c478bd9Sstevel@tonic-gate ** line -- description of queue. This is in labeled fields. 72127c478bd9Sstevel@tonic-gate ** The fields are: 72137c478bd9Sstevel@tonic-gate ** F -- the flags associated with the queue 72147c478bd9Sstevel@tonic-gate ** I -- the interval between running the queue 72157c478bd9Sstevel@tonic-gate ** J -- the maximum # of jobs in work list 72167c478bd9Sstevel@tonic-gate ** [M -- the maximum # of jobs in a queue run] 72177c478bd9Sstevel@tonic-gate ** N -- the niceness at which to run 72187c478bd9Sstevel@tonic-gate ** P -- the path to the queue 72197c478bd9Sstevel@tonic-gate ** S -- the queue sorting order 72207c478bd9Sstevel@tonic-gate ** R -- number of parallel queue runners 72217c478bd9Sstevel@tonic-gate ** r -- max recipients per envelope 72227c478bd9Sstevel@tonic-gate ** The first word is the canonical name of the queue. 72237c478bd9Sstevel@tonic-gate ** qdef -- this is a 'Q' definition from .cf 72247c478bd9Sstevel@tonic-gate ** 72257c478bd9Sstevel@tonic-gate ** Returns: 72267c478bd9Sstevel@tonic-gate ** none. 72277c478bd9Sstevel@tonic-gate ** 72287c478bd9Sstevel@tonic-gate ** Side Effects: 72297c478bd9Sstevel@tonic-gate ** enters the queue into the queue table. 72307c478bd9Sstevel@tonic-gate */ 72317c478bd9Sstevel@tonic-gate 72327c478bd9Sstevel@tonic-gate void 72337c478bd9Sstevel@tonic-gate makequeue(line, qdef) 72347c478bd9Sstevel@tonic-gate char *line; 72357c478bd9Sstevel@tonic-gate bool qdef; 72367c478bd9Sstevel@tonic-gate { 72377c478bd9Sstevel@tonic-gate register char *p; 72387c478bd9Sstevel@tonic-gate register QUEUEGRP *qg; 72397c478bd9Sstevel@tonic-gate register STAB *s; 72407c478bd9Sstevel@tonic-gate int i; 72417c478bd9Sstevel@tonic-gate char fcode; 72427c478bd9Sstevel@tonic-gate 72437c478bd9Sstevel@tonic-gate /* allocate a queue and set up defaults */ 7244*058561cbSjbeck qg = (QUEUEGRP *) xalloc(sizeof(*qg)); 7245*058561cbSjbeck memset((char *) qg, '\0', sizeof(*qg)); 72467c478bd9Sstevel@tonic-gate 72477c478bd9Sstevel@tonic-gate if (line[0] == '\0') 72487c478bd9Sstevel@tonic-gate { 72497c478bd9Sstevel@tonic-gate syserr("name required for queue"); 72507c478bd9Sstevel@tonic-gate return; 72517c478bd9Sstevel@tonic-gate } 72527c478bd9Sstevel@tonic-gate 72537c478bd9Sstevel@tonic-gate /* collect the queue name */ 72547c478bd9Sstevel@tonic-gate for (p = line; 72557c478bd9Sstevel@tonic-gate *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); 72567c478bd9Sstevel@tonic-gate p++) 72577c478bd9Sstevel@tonic-gate continue; 72587c478bd9Sstevel@tonic-gate if (*p != '\0') 72597c478bd9Sstevel@tonic-gate *p++ = '\0'; 72607c478bd9Sstevel@tonic-gate qg->qg_name = newstr(line); 72617c478bd9Sstevel@tonic-gate 72627c478bd9Sstevel@tonic-gate /* set default values, can be overridden below */ 72637c478bd9Sstevel@tonic-gate set_def_queueval(qg, false); 72647c478bd9Sstevel@tonic-gate 72657c478bd9Sstevel@tonic-gate /* now scan through and assign info from the fields */ 72667c478bd9Sstevel@tonic-gate while (*p != '\0') 72677c478bd9Sstevel@tonic-gate { 72687c478bd9Sstevel@tonic-gate auto char *delimptr; 72697c478bd9Sstevel@tonic-gate 72707c478bd9Sstevel@tonic-gate while (*p != '\0' && 72717c478bd9Sstevel@tonic-gate (*p == ',' || (isascii(*p) && isspace(*p)))) 72727c478bd9Sstevel@tonic-gate p++; 72737c478bd9Sstevel@tonic-gate 72747c478bd9Sstevel@tonic-gate /* p now points to field code */ 72757c478bd9Sstevel@tonic-gate fcode = *p; 72767c478bd9Sstevel@tonic-gate while (*p != '\0' && *p != '=' && *p != ',') 72777c478bd9Sstevel@tonic-gate p++; 72787c478bd9Sstevel@tonic-gate if (*p++ != '=') 72797c478bd9Sstevel@tonic-gate { 72807c478bd9Sstevel@tonic-gate syserr("queue %s: `=' expected", qg->qg_name); 72817c478bd9Sstevel@tonic-gate return; 72827c478bd9Sstevel@tonic-gate } 72837c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p)) 72847c478bd9Sstevel@tonic-gate p++; 72857c478bd9Sstevel@tonic-gate 72867c478bd9Sstevel@tonic-gate /* p now points to the field body */ 72877c478bd9Sstevel@tonic-gate p = munchstring(p, &delimptr, ','); 72887c478bd9Sstevel@tonic-gate 72897c478bd9Sstevel@tonic-gate /* install the field into the queue struct */ 72907c478bd9Sstevel@tonic-gate switch (fcode) 72917c478bd9Sstevel@tonic-gate { 72927c478bd9Sstevel@tonic-gate case 'P': /* pathname */ 72937c478bd9Sstevel@tonic-gate if (*p == '\0') 72947c478bd9Sstevel@tonic-gate syserr("queue %s: empty path name", 72957c478bd9Sstevel@tonic-gate qg->qg_name); 72967c478bd9Sstevel@tonic-gate else 72977c478bd9Sstevel@tonic-gate qg->qg_qdir = newstr(p); 72987c478bd9Sstevel@tonic-gate break; 72997c478bd9Sstevel@tonic-gate 73007c478bd9Sstevel@tonic-gate case 'F': /* flags */ 73017c478bd9Sstevel@tonic-gate for (; *p != '\0'; p++) 73027c478bd9Sstevel@tonic-gate if (!(isascii(*p) && isspace(*p))) 73037c478bd9Sstevel@tonic-gate setbitn(*p, qg->qg_flags); 73047c478bd9Sstevel@tonic-gate break; 73057c478bd9Sstevel@tonic-gate 73067c478bd9Sstevel@tonic-gate /* 73077c478bd9Sstevel@tonic-gate ** Do we need two intervals here: 73087c478bd9Sstevel@tonic-gate ** One for persistent queue runners, 73097c478bd9Sstevel@tonic-gate ** one for "normal" queue runs? 73107c478bd9Sstevel@tonic-gate */ 73117c478bd9Sstevel@tonic-gate 73127c478bd9Sstevel@tonic-gate case 'I': /* interval between running the queue */ 73137c478bd9Sstevel@tonic-gate qg->qg_queueintvl = convtime(p, 'm'); 73147c478bd9Sstevel@tonic-gate break; 73157c478bd9Sstevel@tonic-gate 73167c478bd9Sstevel@tonic-gate case 'N': /* run niceness */ 73177c478bd9Sstevel@tonic-gate qg->qg_nice = atoi(p); 73187c478bd9Sstevel@tonic-gate break; 73197c478bd9Sstevel@tonic-gate 73207c478bd9Sstevel@tonic-gate case 'R': /* maximum # of runners for the group */ 73217c478bd9Sstevel@tonic-gate i = atoi(p); 73227c478bd9Sstevel@tonic-gate 73237c478bd9Sstevel@tonic-gate /* can't have more runners than allowed total */ 73247c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && i > MaxQueueChildren) 73257c478bd9Sstevel@tonic-gate { 73267c478bd9Sstevel@tonic-gate qg->qg_maxqrun = MaxQueueChildren; 73277c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 73287c478bd9Sstevel@tonic-gate "Q=%s: R=%d exceeds MaxQueueChildren=%d, set to MaxQueueChildren\n", 73297c478bd9Sstevel@tonic-gate qg->qg_name, i, 73307c478bd9Sstevel@tonic-gate MaxQueueChildren); 73317c478bd9Sstevel@tonic-gate } 73327c478bd9Sstevel@tonic-gate else 73337c478bd9Sstevel@tonic-gate qg->qg_maxqrun = i; 73347c478bd9Sstevel@tonic-gate break; 73357c478bd9Sstevel@tonic-gate 73367c478bd9Sstevel@tonic-gate case 'J': /* maximum # of jobs in work list */ 73377c478bd9Sstevel@tonic-gate qg->qg_maxlist = atoi(p); 73387c478bd9Sstevel@tonic-gate break; 73397c478bd9Sstevel@tonic-gate 73407c478bd9Sstevel@tonic-gate case 'r': /* max recipients per envelope */ 73417c478bd9Sstevel@tonic-gate qg->qg_maxrcpt = atoi(p); 73427c478bd9Sstevel@tonic-gate break; 73437c478bd9Sstevel@tonic-gate 73447c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_GROUP_SORTORDER 73457c478bd9Sstevel@tonic-gate case 'S': /* queue sorting order */ 73467c478bd9Sstevel@tonic-gate switch (*p) 73477c478bd9Sstevel@tonic-gate { 73487c478bd9Sstevel@tonic-gate case 'h': /* Host first */ 73497c478bd9Sstevel@tonic-gate case 'H': 73507c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYHOST; 73517c478bd9Sstevel@tonic-gate break; 73527c478bd9Sstevel@tonic-gate 73537c478bd9Sstevel@tonic-gate case 'p': /* Priority order */ 73547c478bd9Sstevel@tonic-gate case 'P': 73557c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYPRIORITY; 73567c478bd9Sstevel@tonic-gate break; 73577c478bd9Sstevel@tonic-gate 73587c478bd9Sstevel@tonic-gate case 't': /* Submission time */ 73597c478bd9Sstevel@tonic-gate case 'T': 73607c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYTIME; 73617c478bd9Sstevel@tonic-gate break; 73627c478bd9Sstevel@tonic-gate 73637c478bd9Sstevel@tonic-gate case 'f': /* File name */ 73647c478bd9Sstevel@tonic-gate case 'F': 73657c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYFILENAME; 73667c478bd9Sstevel@tonic-gate break; 73677c478bd9Sstevel@tonic-gate 73687c478bd9Sstevel@tonic-gate case 'm': /* Modification time */ 73697c478bd9Sstevel@tonic-gate case 'M': 73707c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYMODTIME; 73717c478bd9Sstevel@tonic-gate break; 73727c478bd9Sstevel@tonic-gate 73737c478bd9Sstevel@tonic-gate case 'r': /* Random */ 73747c478bd9Sstevel@tonic-gate case 'R': 73757c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_RANDOM; 73767c478bd9Sstevel@tonic-gate break; 73777c478bd9Sstevel@tonic-gate 73787c478bd9Sstevel@tonic-gate # if _FFR_RHS 73797c478bd9Sstevel@tonic-gate case 's': /* Shuffled host name */ 73807c478bd9Sstevel@tonic-gate case 'S': 73817c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYSHUFFLE; 73827c478bd9Sstevel@tonic-gate break; 73837c478bd9Sstevel@tonic-gate # endif /* _FFR_RHS */ 73847c478bd9Sstevel@tonic-gate 73857c478bd9Sstevel@tonic-gate case 'n': /* none */ 73867c478bd9Sstevel@tonic-gate case 'N': 73877c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_NONE; 73887c478bd9Sstevel@tonic-gate break; 73897c478bd9Sstevel@tonic-gate 73907c478bd9Sstevel@tonic-gate default: 73917c478bd9Sstevel@tonic-gate syserr("Invalid queue sort order \"%s\"", p); 73927c478bd9Sstevel@tonic-gate } 73937c478bd9Sstevel@tonic-gate break; 73947c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_GROUP_SORTORDER */ 73957c478bd9Sstevel@tonic-gate 73967c478bd9Sstevel@tonic-gate default: 73977c478bd9Sstevel@tonic-gate syserr("Q%s: unknown queue equate %c=", 73987c478bd9Sstevel@tonic-gate qg->qg_name, fcode); 73997c478bd9Sstevel@tonic-gate break; 74007c478bd9Sstevel@tonic-gate } 74017c478bd9Sstevel@tonic-gate 74027c478bd9Sstevel@tonic-gate p = delimptr; 74037c478bd9Sstevel@tonic-gate } 74047c478bd9Sstevel@tonic-gate 74057c478bd9Sstevel@tonic-gate #if !HASNICE 74067c478bd9Sstevel@tonic-gate if (qg->qg_nice != NiceQueueRun) 74077c478bd9Sstevel@tonic-gate { 74087c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 74097c478bd9Sstevel@tonic-gate "Q%s: Warning: N= set on system that doesn't support nice()\n", 74107c478bd9Sstevel@tonic-gate qg->qg_name); 74117c478bd9Sstevel@tonic-gate } 74127c478bd9Sstevel@tonic-gate #endif /* !HASNICE */ 74137c478bd9Sstevel@tonic-gate 74147c478bd9Sstevel@tonic-gate /* do some rationality checking */ 74157c478bd9Sstevel@tonic-gate if (NumQueue >= MAXQUEUEGROUPS) 74167c478bd9Sstevel@tonic-gate { 74177c478bd9Sstevel@tonic-gate syserr("too many queue groups defined (%d max)", 74187c478bd9Sstevel@tonic-gate MAXQUEUEGROUPS); 74197c478bd9Sstevel@tonic-gate return; 74207c478bd9Sstevel@tonic-gate } 74217c478bd9Sstevel@tonic-gate 74227c478bd9Sstevel@tonic-gate if (qg->qg_qdir == NULL) 74237c478bd9Sstevel@tonic-gate { 74247c478bd9Sstevel@tonic-gate if (QueueDir == NULL || *QueueDir == '\0') 74257c478bd9Sstevel@tonic-gate { 74267c478bd9Sstevel@tonic-gate syserr("QueueDir must be defined before queue groups"); 74277c478bd9Sstevel@tonic-gate return; 74287c478bd9Sstevel@tonic-gate } 74297c478bd9Sstevel@tonic-gate qg->qg_qdir = newstr(QueueDir); 74307c478bd9Sstevel@tonic-gate } 74317c478bd9Sstevel@tonic-gate 74327c478bd9Sstevel@tonic-gate if (qg->qg_maxqrun > 1 && !bitnset(QD_FORK, qg->qg_flags)) 74337c478bd9Sstevel@tonic-gate { 74347c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 74357c478bd9Sstevel@tonic-gate "Warning: Q=%s: R=%d: multiple queue runners specified\n\tbut flag '%c' is not set\n", 74367c478bd9Sstevel@tonic-gate qg->qg_name, qg->qg_maxqrun, QD_FORK); 74377c478bd9Sstevel@tonic-gate } 74387c478bd9Sstevel@tonic-gate 74397c478bd9Sstevel@tonic-gate /* enter the queue into the symbol table */ 74407c478bd9Sstevel@tonic-gate if (tTd(37, 8)) 74417c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 74427c478bd9Sstevel@tonic-gate "Adding %s to stab, path: %s", qg->qg_name, 74437c478bd9Sstevel@tonic-gate qg->qg_qdir); 74447c478bd9Sstevel@tonic-gate s = stab(qg->qg_name, ST_QUEUE, ST_ENTER); 74457c478bd9Sstevel@tonic-gate if (s->s_quegrp != NULL) 74467c478bd9Sstevel@tonic-gate { 74477c478bd9Sstevel@tonic-gate i = s->s_quegrp->qg_index; 74487c478bd9Sstevel@tonic-gate 74497c478bd9Sstevel@tonic-gate /* XXX what about the pointers inside this struct? */ 74507c478bd9Sstevel@tonic-gate sm_free(s->s_quegrp); /* XXX */ 74517c478bd9Sstevel@tonic-gate } 74527c478bd9Sstevel@tonic-gate else 74537c478bd9Sstevel@tonic-gate i = NumQueue++; 74547c478bd9Sstevel@tonic-gate Queue[i] = s->s_quegrp = qg; 74557c478bd9Sstevel@tonic-gate qg->qg_index = i; 74567c478bd9Sstevel@tonic-gate 74577c478bd9Sstevel@tonic-gate /* set default value for max queue runners */ 74587c478bd9Sstevel@tonic-gate if (qg->qg_maxqrun < 0) 74597c478bd9Sstevel@tonic-gate { 74607c478bd9Sstevel@tonic-gate if (MaxRunnersPerQueue > 0) 74617c478bd9Sstevel@tonic-gate qg->qg_maxqrun = MaxRunnersPerQueue; 74627c478bd9Sstevel@tonic-gate else 74637c478bd9Sstevel@tonic-gate qg->qg_maxqrun = 1; 74647c478bd9Sstevel@tonic-gate } 74657c478bd9Sstevel@tonic-gate if (qdef) 74667c478bd9Sstevel@tonic-gate setbitn(QD_DEFINED, qg->qg_flags); 74677c478bd9Sstevel@tonic-gate } 74687c478bd9Sstevel@tonic-gate #if 0 74697c478bd9Sstevel@tonic-gate /* 74707c478bd9Sstevel@tonic-gate ** HASHFQN -- calculate a hash value for a fully qualified host name 74717c478bd9Sstevel@tonic-gate ** 74727c478bd9Sstevel@tonic-gate ** Arguments: 74737c478bd9Sstevel@tonic-gate ** fqn -- an all lower-case host.domain string 74747c478bd9Sstevel@tonic-gate ** buckets -- the number of buckets (queue directories) 74757c478bd9Sstevel@tonic-gate ** 74767c478bd9Sstevel@tonic-gate ** Returns: 74777c478bd9Sstevel@tonic-gate ** a bucket number (signed integer) 74787c478bd9Sstevel@tonic-gate ** -1 on error 74797c478bd9Sstevel@tonic-gate ** 74807c478bd9Sstevel@tonic-gate ** Contributed by Exactis.com, Inc. 74817c478bd9Sstevel@tonic-gate */ 74827c478bd9Sstevel@tonic-gate 74837c478bd9Sstevel@tonic-gate int 74847c478bd9Sstevel@tonic-gate hashfqn(fqn, buckets) 74857c478bd9Sstevel@tonic-gate register char *fqn; 74867c478bd9Sstevel@tonic-gate int buckets; 74877c478bd9Sstevel@tonic-gate { 74887c478bd9Sstevel@tonic-gate register char *p; 74897c478bd9Sstevel@tonic-gate register int h = 0, hash, cnt; 74907c478bd9Sstevel@tonic-gate 74917c478bd9Sstevel@tonic-gate if (fqn == NULL) 74927c478bd9Sstevel@tonic-gate return -1; 74937c478bd9Sstevel@tonic-gate 74947c478bd9Sstevel@tonic-gate /* 74957c478bd9Sstevel@tonic-gate ** A variation on the gdb hash 74967c478bd9Sstevel@tonic-gate ** This is the best as of Feb 19, 1996 --bcx 74977c478bd9Sstevel@tonic-gate */ 74987c478bd9Sstevel@tonic-gate 74997c478bd9Sstevel@tonic-gate p = fqn; 75007c478bd9Sstevel@tonic-gate h = 0x238F13AF * strlen(p); 75017c478bd9Sstevel@tonic-gate for (cnt = 0; *p != 0; ++p, cnt++) 75027c478bd9Sstevel@tonic-gate { 75037c478bd9Sstevel@tonic-gate h = (h + (*p << (cnt * 5 % 24))) & 0x7FFFFFFF; 75047c478bd9Sstevel@tonic-gate } 75057c478bd9Sstevel@tonic-gate h = (1103515243 * h + 12345) & 0x7FFFFFFF; 75067c478bd9Sstevel@tonic-gate if (buckets < 2) 75077c478bd9Sstevel@tonic-gate hash = 0; 75087c478bd9Sstevel@tonic-gate else 75097c478bd9Sstevel@tonic-gate hash = (h % buckets); 75107c478bd9Sstevel@tonic-gate 75117c478bd9Sstevel@tonic-gate return hash; 75127c478bd9Sstevel@tonic-gate } 75137c478bd9Sstevel@tonic-gate #endif /* 0 */ 75147c478bd9Sstevel@tonic-gate 75157c478bd9Sstevel@tonic-gate /* 75167c478bd9Sstevel@tonic-gate ** A structure for sorting Queue according to maxqrun without 75177c478bd9Sstevel@tonic-gate ** screwing up Queue itself. 75187c478bd9Sstevel@tonic-gate */ 75197c478bd9Sstevel@tonic-gate 75207c478bd9Sstevel@tonic-gate struct sortqgrp 75217c478bd9Sstevel@tonic-gate { 75227c478bd9Sstevel@tonic-gate int sg_idx; /* original index */ 75237c478bd9Sstevel@tonic-gate int sg_maxqrun; /* max queue runners */ 75247c478bd9Sstevel@tonic-gate }; 75257c478bd9Sstevel@tonic-gate typedef struct sortqgrp SORTQGRP_T; 75267c478bd9Sstevel@tonic-gate static int cmpidx __P((const void *, const void *)); 75277c478bd9Sstevel@tonic-gate 75287c478bd9Sstevel@tonic-gate static int 75297c478bd9Sstevel@tonic-gate cmpidx(a, b) 75307c478bd9Sstevel@tonic-gate const void *a; 75317c478bd9Sstevel@tonic-gate const void *b; 75327c478bd9Sstevel@tonic-gate { 75337c478bd9Sstevel@tonic-gate /* The sort is highest to lowest, so the comparison is reversed */ 75347c478bd9Sstevel@tonic-gate if (((SORTQGRP_T *)a)->sg_maxqrun < ((SORTQGRP_T *)b)->sg_maxqrun) 75357c478bd9Sstevel@tonic-gate return 1; 75367c478bd9Sstevel@tonic-gate else if (((SORTQGRP_T *)a)->sg_maxqrun > ((SORTQGRP_T *)b)->sg_maxqrun) 75377c478bd9Sstevel@tonic-gate return -1; 75387c478bd9Sstevel@tonic-gate else 75397c478bd9Sstevel@tonic-gate return 0; 75407c478bd9Sstevel@tonic-gate } 75417c478bd9Sstevel@tonic-gate 75427c478bd9Sstevel@tonic-gate /* 75437c478bd9Sstevel@tonic-gate ** MAKEWORKGROUP -- balance queue groups into work groups per MaxQueueChildren 75447c478bd9Sstevel@tonic-gate ** 75457c478bd9Sstevel@tonic-gate ** Take the now defined queue groups and assign them to work groups. 75467c478bd9Sstevel@tonic-gate ** This is done to balance out the number of concurrently active 75477c478bd9Sstevel@tonic-gate ** queue runners such that MaxQueueChildren is not exceeded. This may 75487c478bd9Sstevel@tonic-gate ** result in more than one queue group per work group. In such a case 75497c478bd9Sstevel@tonic-gate ** the number of running queue groups in that work group will have no 75507c478bd9Sstevel@tonic-gate ** more than the work group maximum number of runners (a "fair" portion 75517c478bd9Sstevel@tonic-gate ** of MaxQueueRunners). All queue groups within a work group will get a 75527c478bd9Sstevel@tonic-gate ** chance at running. 75537c478bd9Sstevel@tonic-gate ** 75547c478bd9Sstevel@tonic-gate ** Parameters: 75557c478bd9Sstevel@tonic-gate ** none. 75567c478bd9Sstevel@tonic-gate ** 75577c478bd9Sstevel@tonic-gate ** Returns: 75587c478bd9Sstevel@tonic-gate ** nothing. 75597c478bd9Sstevel@tonic-gate ** 75607c478bd9Sstevel@tonic-gate ** Side Effects: 75617c478bd9Sstevel@tonic-gate ** Sets up WorkGrp structure. 75627c478bd9Sstevel@tonic-gate */ 75637c478bd9Sstevel@tonic-gate 75647c478bd9Sstevel@tonic-gate void 75657c478bd9Sstevel@tonic-gate makeworkgroups() 75667c478bd9Sstevel@tonic-gate { 75677c478bd9Sstevel@tonic-gate int i, j, total_runners, dir, h; 75687c478bd9Sstevel@tonic-gate SORTQGRP_T si[MAXQUEUEGROUPS + 1]; 75697c478bd9Sstevel@tonic-gate 75707c478bd9Sstevel@tonic-gate total_runners = 0; 75717c478bd9Sstevel@tonic-gate if (NumQueue == 1 && strcmp(Queue[0]->qg_name, "mqueue") == 0) 75727c478bd9Sstevel@tonic-gate { 75737c478bd9Sstevel@tonic-gate /* 75747c478bd9Sstevel@tonic-gate ** There is only the "mqueue" queue group (a default) 75757c478bd9Sstevel@tonic-gate ** containing all of the queues. We want to provide to 75767c478bd9Sstevel@tonic-gate ** this queue group the maximum allowable queue runners. 75777c478bd9Sstevel@tonic-gate ** To match older behavior (8.10/8.11) we'll try for 75787c478bd9Sstevel@tonic-gate ** 1 runner per queue capping it at MaxQueueChildren. 75797c478bd9Sstevel@tonic-gate ** So if there are N queues, then there will be N runners 75807c478bd9Sstevel@tonic-gate ** for the "mqueue" queue group (where N is kept less than 75817c478bd9Sstevel@tonic-gate ** MaxQueueChildren). 75827c478bd9Sstevel@tonic-gate */ 75837c478bd9Sstevel@tonic-gate 75847c478bd9Sstevel@tonic-gate NumWorkGroups = 1; 75857c478bd9Sstevel@tonic-gate WorkGrp[0].wg_numqgrp = 1; 75867c478bd9Sstevel@tonic-gate WorkGrp[0].wg_qgs = (QUEUEGRP **) xalloc(sizeof(QUEUEGRP *)); 75877c478bd9Sstevel@tonic-gate WorkGrp[0].wg_qgs[0] = Queue[0]; 75887c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && 75897c478bd9Sstevel@tonic-gate Queue[0]->qg_numqueues > MaxQueueChildren) 75907c478bd9Sstevel@tonic-gate WorkGrp[0].wg_runners = MaxQueueChildren; 75917c478bd9Sstevel@tonic-gate else 75927c478bd9Sstevel@tonic-gate WorkGrp[0].wg_runners = Queue[0]->qg_numqueues; 75937c478bd9Sstevel@tonic-gate 75947c478bd9Sstevel@tonic-gate Queue[0]->qg_wgrp = 0; 75957c478bd9Sstevel@tonic-gate 75967c478bd9Sstevel@tonic-gate /* can't have more runners than allowed total */ 75977c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && 75987c478bd9Sstevel@tonic-gate Queue[0]->qg_maxqrun > MaxQueueChildren) 75997c478bd9Sstevel@tonic-gate Queue[0]->qg_maxqrun = MaxQueueChildren; 76007c478bd9Sstevel@tonic-gate WorkGrp[0].wg_maxact = Queue[0]->qg_maxqrun; 76017c478bd9Sstevel@tonic-gate WorkGrp[0].wg_lowqintvl = Queue[0]->qg_queueintvl; 76027c478bd9Sstevel@tonic-gate return; 76037c478bd9Sstevel@tonic-gate } 76047c478bd9Sstevel@tonic-gate 76057c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue; i++) 76067c478bd9Sstevel@tonic-gate { 76077c478bd9Sstevel@tonic-gate si[i].sg_maxqrun = Queue[i]->qg_maxqrun; 76087c478bd9Sstevel@tonic-gate si[i].sg_idx = i; 76097c478bd9Sstevel@tonic-gate } 76107c478bd9Sstevel@tonic-gate qsort(si, NumQueue, sizeof(si[0]), cmpidx); 76117c478bd9Sstevel@tonic-gate 76127c478bd9Sstevel@tonic-gate NumWorkGroups = 0; 76137c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue; i++) 76147c478bd9Sstevel@tonic-gate { 76157c478bd9Sstevel@tonic-gate total_runners += si[i].sg_maxqrun; 76167c478bd9Sstevel@tonic-gate if (MaxQueueChildren <= 0 || total_runners <= MaxQueueChildren) 76177c478bd9Sstevel@tonic-gate NumWorkGroups++; 76187c478bd9Sstevel@tonic-gate else 76197c478bd9Sstevel@tonic-gate break; 76207c478bd9Sstevel@tonic-gate } 76217c478bd9Sstevel@tonic-gate 76227c478bd9Sstevel@tonic-gate if (NumWorkGroups < 1) 76237c478bd9Sstevel@tonic-gate NumWorkGroups = 1; /* gotta have one at least */ 76247c478bd9Sstevel@tonic-gate else if (NumWorkGroups > MAXWORKGROUPS) 76257c478bd9Sstevel@tonic-gate NumWorkGroups = MAXWORKGROUPS; /* the limit */ 76267c478bd9Sstevel@tonic-gate 76277c478bd9Sstevel@tonic-gate /* 76287c478bd9Sstevel@tonic-gate ** We now know the number of work groups to pack the queue groups 76297c478bd9Sstevel@tonic-gate ** into. The queue groups in 'Queue' are sorted from highest 76307c478bd9Sstevel@tonic-gate ** to lowest for the number of runners per queue group. 76317c478bd9Sstevel@tonic-gate ** We put the queue groups with the largest number of runners 76327c478bd9Sstevel@tonic-gate ** into work groups first. Then the smaller ones are fitted in 76337c478bd9Sstevel@tonic-gate ** where it looks best. 76347c478bd9Sstevel@tonic-gate */ 76357c478bd9Sstevel@tonic-gate 76367c478bd9Sstevel@tonic-gate j = 0; 76377c478bd9Sstevel@tonic-gate dir = 1; 76387c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue; i++) 76397c478bd9Sstevel@tonic-gate { 76407c478bd9Sstevel@tonic-gate /* a to-and-fro packing scheme, continue from last position */ 76417c478bd9Sstevel@tonic-gate if (j >= NumWorkGroups) 76427c478bd9Sstevel@tonic-gate { 76437c478bd9Sstevel@tonic-gate dir = -1; 76447c478bd9Sstevel@tonic-gate j = NumWorkGroups - 1; 76457c478bd9Sstevel@tonic-gate } 76467c478bd9Sstevel@tonic-gate else if (j < 0) 76477c478bd9Sstevel@tonic-gate { 76487c478bd9Sstevel@tonic-gate j = 0; 76497c478bd9Sstevel@tonic-gate dir = 1; 76507c478bd9Sstevel@tonic-gate } 76517c478bd9Sstevel@tonic-gate 76527c478bd9Sstevel@tonic-gate if (WorkGrp[j].wg_qgs == NULL) 76537c478bd9Sstevel@tonic-gate WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_malloc(sizeof(QUEUEGRP *) * 76547c478bd9Sstevel@tonic-gate (WorkGrp[j].wg_numqgrp + 1)); 76557c478bd9Sstevel@tonic-gate else 76567c478bd9Sstevel@tonic-gate WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_realloc(WorkGrp[j].wg_qgs, 76577c478bd9Sstevel@tonic-gate sizeof(QUEUEGRP *) * 76587c478bd9Sstevel@tonic-gate (WorkGrp[j].wg_numqgrp + 1)); 76597c478bd9Sstevel@tonic-gate if (WorkGrp[j].wg_qgs == NULL) 76607c478bd9Sstevel@tonic-gate { 76617c478bd9Sstevel@tonic-gate syserr("!cannot allocate memory for work queues, need %d bytes", 76627c478bd9Sstevel@tonic-gate (int) (sizeof(QUEUEGRP *) * 76637c478bd9Sstevel@tonic-gate (WorkGrp[j].wg_numqgrp + 1))); 76647c478bd9Sstevel@tonic-gate } 76657c478bd9Sstevel@tonic-gate 76667c478bd9Sstevel@tonic-gate h = si[i].sg_idx; 76677c478bd9Sstevel@tonic-gate WorkGrp[j].wg_qgs[WorkGrp[j].wg_numqgrp] = Queue[h]; 76687c478bd9Sstevel@tonic-gate WorkGrp[j].wg_numqgrp++; 76697c478bd9Sstevel@tonic-gate WorkGrp[j].wg_runners += Queue[h]->qg_maxqrun; 76707c478bd9Sstevel@tonic-gate Queue[h]->qg_wgrp = j; 76717c478bd9Sstevel@tonic-gate 76727c478bd9Sstevel@tonic-gate if (WorkGrp[j].wg_maxact == 0) 76737c478bd9Sstevel@tonic-gate { 76747c478bd9Sstevel@tonic-gate /* can't have more runners than allowed total */ 76757c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && 76767c478bd9Sstevel@tonic-gate Queue[h]->qg_maxqrun > MaxQueueChildren) 76777c478bd9Sstevel@tonic-gate Queue[h]->qg_maxqrun = MaxQueueChildren; 76787c478bd9Sstevel@tonic-gate WorkGrp[j].wg_maxact = Queue[h]->qg_maxqrun; 76797c478bd9Sstevel@tonic-gate } 76807c478bd9Sstevel@tonic-gate 76817c478bd9Sstevel@tonic-gate /* 76827c478bd9Sstevel@tonic-gate ** XXX: must wg_lowqintvl be the GCD? 76837c478bd9Sstevel@tonic-gate ** qg1: 2m, qg2: 3m, minimum: 2m, when do queue runs for 76847c478bd9Sstevel@tonic-gate ** qg2 occur? 76857c478bd9Sstevel@tonic-gate */ 76867c478bd9Sstevel@tonic-gate 76877c478bd9Sstevel@tonic-gate /* keep track of the lowest interval for a persistent runner */ 76887c478bd9Sstevel@tonic-gate if (Queue[h]->qg_queueintvl > 0 && 76897c478bd9Sstevel@tonic-gate WorkGrp[j].wg_lowqintvl < Queue[h]->qg_queueintvl) 76907c478bd9Sstevel@tonic-gate WorkGrp[j].wg_lowqintvl = Queue[h]->qg_queueintvl; 76917c478bd9Sstevel@tonic-gate j += dir; 76927c478bd9Sstevel@tonic-gate } 76937c478bd9Sstevel@tonic-gate if (tTd(41, 9)) 76947c478bd9Sstevel@tonic-gate { 76957c478bd9Sstevel@tonic-gate for (i = 0; i < NumWorkGroups; i++) 76967c478bd9Sstevel@tonic-gate { 76977c478bd9Sstevel@tonic-gate sm_dprintf("Workgroup[%d]=", i); 76987c478bd9Sstevel@tonic-gate for (j = 0; j < WorkGrp[i].wg_numqgrp; j++) 76997c478bd9Sstevel@tonic-gate { 77007c478bd9Sstevel@tonic-gate sm_dprintf("%s, ", 77017c478bd9Sstevel@tonic-gate WorkGrp[i].wg_qgs[j]->qg_name); 77027c478bd9Sstevel@tonic-gate } 77037c478bd9Sstevel@tonic-gate sm_dprintf("\n"); 77047c478bd9Sstevel@tonic-gate } 77057c478bd9Sstevel@tonic-gate } 77067c478bd9Sstevel@tonic-gate } 77077c478bd9Sstevel@tonic-gate 77087c478bd9Sstevel@tonic-gate /* 77097c478bd9Sstevel@tonic-gate ** DUP_DF -- duplicate envelope data file 77107c478bd9Sstevel@tonic-gate ** 77117c478bd9Sstevel@tonic-gate ** Copy the data file from the 'old' envelope to the 'new' envelope 77127c478bd9Sstevel@tonic-gate ** in the most efficient way possible. 77137c478bd9Sstevel@tonic-gate ** 77147c478bd9Sstevel@tonic-gate ** Create a hard link from the 'old' data file to the 'new' data file. 77157c478bd9Sstevel@tonic-gate ** If the old and new queue directories are on different file systems, 77167c478bd9Sstevel@tonic-gate ** then the new data file link is created in the old queue directory, 77177c478bd9Sstevel@tonic-gate ** and the new queue file will contain a 'd' record pointing to the 77187c478bd9Sstevel@tonic-gate ** directory containing the new data file. 77197c478bd9Sstevel@tonic-gate ** 77207c478bd9Sstevel@tonic-gate ** Parameters: 77217c478bd9Sstevel@tonic-gate ** old -- old envelope. 77227c478bd9Sstevel@tonic-gate ** new -- new envelope. 77237c478bd9Sstevel@tonic-gate ** 77247c478bd9Sstevel@tonic-gate ** Results: 77257c478bd9Sstevel@tonic-gate ** Returns true on success, false on failure. 77267c478bd9Sstevel@tonic-gate ** 77277c478bd9Sstevel@tonic-gate ** Side Effects: 77287c478bd9Sstevel@tonic-gate ** On success, the new data file is created. 77297c478bd9Sstevel@tonic-gate ** On fatal failure, EF_FATALERRS is set in old->e_flags. 77307c478bd9Sstevel@tonic-gate */ 77317c478bd9Sstevel@tonic-gate 77327c478bd9Sstevel@tonic-gate static bool dup_df __P((ENVELOPE *, ENVELOPE *)); 77337c478bd9Sstevel@tonic-gate 77347c478bd9Sstevel@tonic-gate static bool 77357c478bd9Sstevel@tonic-gate dup_df(old, new) 77367c478bd9Sstevel@tonic-gate ENVELOPE *old; 77377c478bd9Sstevel@tonic-gate ENVELOPE *new; 77387c478bd9Sstevel@tonic-gate { 77397c478bd9Sstevel@tonic-gate int ofs, nfs, r; 77407c478bd9Sstevel@tonic-gate char opath[MAXPATHLEN]; 77417c478bd9Sstevel@tonic-gate char npath[MAXPATHLEN]; 77427c478bd9Sstevel@tonic-gate 77437c478bd9Sstevel@tonic-gate if (!bitset(EF_HAS_DF, old->e_flags)) 77447c478bd9Sstevel@tonic-gate { 77457c478bd9Sstevel@tonic-gate /* 77467c478bd9Sstevel@tonic-gate ** this can happen if: SuperSafe != True 77477c478bd9Sstevel@tonic-gate ** and a bounce mail is sent that is split. 77487c478bd9Sstevel@tonic-gate */ 77497c478bd9Sstevel@tonic-gate 77507c478bd9Sstevel@tonic-gate queueup(old, false, true); 77517c478bd9Sstevel@tonic-gate } 77527c478bd9Sstevel@tonic-gate SM_REQUIRE(ISVALIDQGRP(old->e_qgrp) && ISVALIDQDIR(old->e_qdir)); 77537c478bd9Sstevel@tonic-gate SM_REQUIRE(ISVALIDQGRP(new->e_qgrp) && ISVALIDQDIR(new->e_qdir)); 77547c478bd9Sstevel@tonic-gate 7755*058561cbSjbeck (void) sm_strlcpy(opath, queuename(old, DATAFL_LETTER), sizeof(opath)); 7756*058561cbSjbeck (void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof(npath)); 77577c478bd9Sstevel@tonic-gate 77587c478bd9Sstevel@tonic-gate if (old->e_dfp != NULL) 77597c478bd9Sstevel@tonic-gate { 77607c478bd9Sstevel@tonic-gate r = sm_io_setinfo(old->e_dfp, SM_BF_COMMIT, NULL); 77617c478bd9Sstevel@tonic-gate if (r < 0 && errno != EINVAL) 77627c478bd9Sstevel@tonic-gate { 77637c478bd9Sstevel@tonic-gate syserr("@can't commit %s", opath); 77647c478bd9Sstevel@tonic-gate old->e_flags |= EF_FATALERRS; 77657c478bd9Sstevel@tonic-gate return false; 77667c478bd9Sstevel@tonic-gate } 77677c478bd9Sstevel@tonic-gate } 77687c478bd9Sstevel@tonic-gate 77697c478bd9Sstevel@tonic-gate /* 77707c478bd9Sstevel@tonic-gate ** Attempt to create a hard link, if we think both old and new 77717c478bd9Sstevel@tonic-gate ** are on the same file system, otherwise copy the file. 77727c478bd9Sstevel@tonic-gate ** 77737c478bd9Sstevel@tonic-gate ** Don't waste time attempting a hard link unless old and new 77747c478bd9Sstevel@tonic-gate ** are on the same file system. 77757c478bd9Sstevel@tonic-gate */ 77767c478bd9Sstevel@tonic-gate 777749218d4fSjbeck SM_REQUIRE(ISVALIDQGRP(old->e_dfqgrp) && ISVALIDQDIR(old->e_dfqdir)); 777849218d4fSjbeck SM_REQUIRE(ISVALIDQGRP(new->e_dfqgrp) && ISVALIDQDIR(new->e_dfqdir)); 777949218d4fSjbeck 778049218d4fSjbeck ofs = Queue[old->e_dfqgrp]->qg_qpaths[old->e_dfqdir].qp_fsysidx; 778149218d4fSjbeck nfs = Queue[new->e_dfqgrp]->qg_qpaths[new->e_dfqdir].qp_fsysidx; 77827c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(ofs) == FILE_SYS_DEV(nfs)) 77837c478bd9Sstevel@tonic-gate { 77847c478bd9Sstevel@tonic-gate if (link(opath, npath) == 0) 77857c478bd9Sstevel@tonic-gate { 77867c478bd9Sstevel@tonic-gate new->e_flags |= EF_HAS_DF; 77877c478bd9Sstevel@tonic-gate SYNC_DIR(npath, true); 77887c478bd9Sstevel@tonic-gate return true; 77897c478bd9Sstevel@tonic-gate } 77907c478bd9Sstevel@tonic-gate goto error; 77917c478bd9Sstevel@tonic-gate } 77927c478bd9Sstevel@tonic-gate 77937c478bd9Sstevel@tonic-gate /* 77947c478bd9Sstevel@tonic-gate ** Can't link across queue directories, so try to create a hard 77957c478bd9Sstevel@tonic-gate ** link in the same queue directory as the old df file. 77967c478bd9Sstevel@tonic-gate ** The qf file will refer to the new df file using a 'd' record. 77977c478bd9Sstevel@tonic-gate */ 77987c478bd9Sstevel@tonic-gate 77997c478bd9Sstevel@tonic-gate new->e_dfqgrp = old->e_dfqgrp; 78007c478bd9Sstevel@tonic-gate new->e_dfqdir = old->e_dfqdir; 7801*058561cbSjbeck (void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof(npath)); 78027c478bd9Sstevel@tonic-gate if (link(opath, npath) == 0) 78037c478bd9Sstevel@tonic-gate { 78047c478bd9Sstevel@tonic-gate new->e_flags |= EF_HAS_DF; 78057c478bd9Sstevel@tonic-gate SYNC_DIR(npath, true); 78067c478bd9Sstevel@tonic-gate return true; 78077c478bd9Sstevel@tonic-gate } 78087c478bd9Sstevel@tonic-gate 78097c478bd9Sstevel@tonic-gate error: 78107c478bd9Sstevel@tonic-gate if (LogLevel > 0) 78117c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, old->e_id, 78127c478bd9Sstevel@tonic-gate "dup_df: can't link %s to %s, error=%s, envelope splitting failed", 78137c478bd9Sstevel@tonic-gate opath, npath, sm_errstring(errno)); 78147c478bd9Sstevel@tonic-gate return false; 78157c478bd9Sstevel@tonic-gate } 78167c478bd9Sstevel@tonic-gate 78177c478bd9Sstevel@tonic-gate /* 78187c478bd9Sstevel@tonic-gate ** SPLIT_ENV -- Allocate a new envelope based on a given envelope. 78197c478bd9Sstevel@tonic-gate ** 78207c478bd9Sstevel@tonic-gate ** Parameters: 78217c478bd9Sstevel@tonic-gate ** e -- envelope. 78227c478bd9Sstevel@tonic-gate ** sendqueue -- sendqueue for new envelope. 78237c478bd9Sstevel@tonic-gate ** qgrp -- index of queue group. 78247c478bd9Sstevel@tonic-gate ** qdir -- queue directory. 78257c478bd9Sstevel@tonic-gate ** 78267c478bd9Sstevel@tonic-gate ** Results: 78277c478bd9Sstevel@tonic-gate ** new envelope. 78287c478bd9Sstevel@tonic-gate ** 78297c478bd9Sstevel@tonic-gate */ 78307c478bd9Sstevel@tonic-gate 78317c478bd9Sstevel@tonic-gate static ENVELOPE *split_env __P((ENVELOPE *, ADDRESS *, int, int)); 78327c478bd9Sstevel@tonic-gate 78337c478bd9Sstevel@tonic-gate static ENVELOPE * 78347c478bd9Sstevel@tonic-gate split_env(e, sendqueue, qgrp, qdir) 78357c478bd9Sstevel@tonic-gate ENVELOPE *e; 78367c478bd9Sstevel@tonic-gate ADDRESS *sendqueue; 78377c478bd9Sstevel@tonic-gate int qgrp; 78387c478bd9Sstevel@tonic-gate int qdir; 78397c478bd9Sstevel@tonic-gate { 78407c478bd9Sstevel@tonic-gate ENVELOPE *ee; 78417c478bd9Sstevel@tonic-gate 7842*058561cbSjbeck ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool, sizeof(*ee)); 78437c478bd9Sstevel@tonic-gate STRUCTCOPY(*e, *ee); 78447c478bd9Sstevel@tonic-gate ee->e_message = NULL; /* XXX use original message? */ 78457c478bd9Sstevel@tonic-gate ee->e_id = NULL; 78467c478bd9Sstevel@tonic-gate assign_queueid(ee); 78477c478bd9Sstevel@tonic-gate ee->e_sendqueue = sendqueue; 78487c478bd9Sstevel@tonic-gate ee->e_flags &= ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS 78497c478bd9Sstevel@tonic-gate |EF_SENDRECEIPT|EF_RET_PARAM|EF_HAS_DF); 78507c478bd9Sstevel@tonic-gate ee->e_flags |= EF_NORECEIPT; /* XXX really? */ 78517c478bd9Sstevel@tonic-gate ee->e_from.q_state = QS_SENDER; 78527c478bd9Sstevel@tonic-gate ee->e_dfp = NULL; 78537c478bd9Sstevel@tonic-gate ee->e_lockfp = NULL; 78547c478bd9Sstevel@tonic-gate if (e->e_xfp != NULL) 78557c478bd9Sstevel@tonic-gate ee->e_xfp = sm_io_dup(e->e_xfp); 78567c478bd9Sstevel@tonic-gate 78577c478bd9Sstevel@tonic-gate /* failed to dup e->e_xfp, start a new transcript */ 78587c478bd9Sstevel@tonic-gate if (ee->e_xfp == NULL) 78597c478bd9Sstevel@tonic-gate openxscript(ee); 78607c478bd9Sstevel@tonic-gate 78617c478bd9Sstevel@tonic-gate ee->e_qgrp = ee->e_dfqgrp = qgrp; 78627c478bd9Sstevel@tonic-gate ee->e_qdir = ee->e_dfqdir = qdir; 78637c478bd9Sstevel@tonic-gate ee->e_errormode = EM_MAIL; 78647c478bd9Sstevel@tonic-gate ee->e_statmsg = NULL; 78657c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 78667c478bd9Sstevel@tonic-gate ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool, 78677c478bd9Sstevel@tonic-gate e->e_quarmsg); 78687c478bd9Sstevel@tonic-gate 78697c478bd9Sstevel@tonic-gate /* 78707c478bd9Sstevel@tonic-gate ** XXX Not sure if this copying is necessary. 78717c478bd9Sstevel@tonic-gate ** sendall() does this copying, but I (dm) don't know if that is 78727c478bd9Sstevel@tonic-gate ** because of the storage management discipline we were using 78737c478bd9Sstevel@tonic-gate ** before rpools were introduced, or if it is because these lists 78747c478bd9Sstevel@tonic-gate ** can be modified later. 78757c478bd9Sstevel@tonic-gate */ 78767c478bd9Sstevel@tonic-gate 78777c478bd9Sstevel@tonic-gate ee->e_header = copyheader(e->e_header, ee->e_rpool); 78787c478bd9Sstevel@tonic-gate ee->e_errorqueue = copyqueue(e->e_errorqueue, ee->e_rpool); 78797c478bd9Sstevel@tonic-gate 78807c478bd9Sstevel@tonic-gate return ee; 78817c478bd9Sstevel@tonic-gate } 78827c478bd9Sstevel@tonic-gate 78837c478bd9Sstevel@tonic-gate /* return values from split functions, check also below! */ 78847c478bd9Sstevel@tonic-gate #define SM_SPLIT_FAIL (0) 78857c478bd9Sstevel@tonic-gate #define SM_SPLIT_NONE (1) 78867c478bd9Sstevel@tonic-gate #define SM_SPLIT_NEW(n) (1 + (n)) 78877c478bd9Sstevel@tonic-gate 78887c478bd9Sstevel@tonic-gate /* 78897c478bd9Sstevel@tonic-gate ** SPLIT_ACROSS_QUEUE_GROUPS 78907c478bd9Sstevel@tonic-gate ** 78917c478bd9Sstevel@tonic-gate ** This function splits an envelope across multiple queue groups 78927c478bd9Sstevel@tonic-gate ** based on the queue group of each recipient. 78937c478bd9Sstevel@tonic-gate ** 78947c478bd9Sstevel@tonic-gate ** Parameters: 78957c478bd9Sstevel@tonic-gate ** e -- envelope. 78967c478bd9Sstevel@tonic-gate ** 78977c478bd9Sstevel@tonic-gate ** Results: 78987c478bd9Sstevel@tonic-gate ** SM_SPLIT_FAIL on failure 78997c478bd9Sstevel@tonic-gate ** SM_SPLIT_NONE if no splitting occurred, 79007c478bd9Sstevel@tonic-gate ** or 1 + the number of additional envelopes created. 79017c478bd9Sstevel@tonic-gate ** 79027c478bd9Sstevel@tonic-gate ** Side Effects: 79037c478bd9Sstevel@tonic-gate ** On success, e->e_sibling points to a list of zero or more 79047c478bd9Sstevel@tonic-gate ** additional envelopes, and the associated data files exist 79057c478bd9Sstevel@tonic-gate ** on disk. But the queue files are not created. 79067c478bd9Sstevel@tonic-gate ** 79077c478bd9Sstevel@tonic-gate ** On failure, e->e_sibling is not changed. 79087c478bd9Sstevel@tonic-gate ** The order of recipients in e->e_sendqueue is permuted. 79097c478bd9Sstevel@tonic-gate ** Abandoned data files for additional envelopes that failed 79107c478bd9Sstevel@tonic-gate ** to be created may exist on disk. 79117c478bd9Sstevel@tonic-gate */ 79127c478bd9Sstevel@tonic-gate 79137c478bd9Sstevel@tonic-gate static int q_qgrp_compare __P((const void *, const void *)); 79147c478bd9Sstevel@tonic-gate static int e_filesys_compare __P((const void *, const void *)); 79157c478bd9Sstevel@tonic-gate 79167c478bd9Sstevel@tonic-gate static int 79177c478bd9Sstevel@tonic-gate q_qgrp_compare(p1, p2) 79187c478bd9Sstevel@tonic-gate const void *p1; 79197c478bd9Sstevel@tonic-gate const void *p2; 79207c478bd9Sstevel@tonic-gate { 79217c478bd9Sstevel@tonic-gate ADDRESS **pq1 = (ADDRESS **) p1; 79227c478bd9Sstevel@tonic-gate ADDRESS **pq2 = (ADDRESS **) p2; 79237c478bd9Sstevel@tonic-gate 79247c478bd9Sstevel@tonic-gate return (*pq1)->q_qgrp - (*pq2)->q_qgrp; 79257c478bd9Sstevel@tonic-gate } 79267c478bd9Sstevel@tonic-gate 79277c478bd9Sstevel@tonic-gate static int 79287c478bd9Sstevel@tonic-gate e_filesys_compare(p1, p2) 79297c478bd9Sstevel@tonic-gate const void *p1; 79307c478bd9Sstevel@tonic-gate const void *p2; 79317c478bd9Sstevel@tonic-gate { 79327c478bd9Sstevel@tonic-gate ENVELOPE **pe1 = (ENVELOPE **) p1; 79337c478bd9Sstevel@tonic-gate ENVELOPE **pe2 = (ENVELOPE **) p2; 79347c478bd9Sstevel@tonic-gate int fs1, fs2; 79357c478bd9Sstevel@tonic-gate 79367c478bd9Sstevel@tonic-gate fs1 = Queue[(*pe1)->e_qgrp]->qg_qpaths[(*pe1)->e_qdir].qp_fsysidx; 79377c478bd9Sstevel@tonic-gate fs2 = Queue[(*pe2)->e_qgrp]->qg_qpaths[(*pe2)->e_qdir].qp_fsysidx; 79387c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(fs1) < FILE_SYS_DEV(fs2)) 79397c478bd9Sstevel@tonic-gate return -1; 79407c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(fs1) > FILE_SYS_DEV(fs2)) 79417c478bd9Sstevel@tonic-gate return 1; 79427c478bd9Sstevel@tonic-gate return 0; 79437c478bd9Sstevel@tonic-gate } 79447c478bd9Sstevel@tonic-gate 7945*058561cbSjbeck static int split_across_queue_groups __P((ENVELOPE *)); 79467c478bd9Sstevel@tonic-gate static int 79477c478bd9Sstevel@tonic-gate split_across_queue_groups(e) 79487c478bd9Sstevel@tonic-gate ENVELOPE *e; 79497c478bd9Sstevel@tonic-gate { 79507c478bd9Sstevel@tonic-gate int naddrs, nsplits, i; 79517c478bd9Sstevel@tonic-gate bool changed; 79527c478bd9Sstevel@tonic-gate char **pvp; 79537c478bd9Sstevel@tonic-gate ADDRESS *q, **addrs; 79547c478bd9Sstevel@tonic-gate ENVELOPE *ee, *es; 79557c478bd9Sstevel@tonic-gate ENVELOPE *splits[MAXQUEUEGROUPS]; 79567c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE]; 79577c478bd9Sstevel@tonic-gate 79587c478bd9Sstevel@tonic-gate SM_REQUIRE(ISVALIDQGRP(e->e_qgrp)); 79597c478bd9Sstevel@tonic-gate 79607c478bd9Sstevel@tonic-gate /* Count addresses and assign queue groups. */ 79617c478bd9Sstevel@tonic-gate naddrs = 0; 79627c478bd9Sstevel@tonic-gate changed = false; 79637c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 79647c478bd9Sstevel@tonic-gate { 79657c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 79667c478bd9Sstevel@tonic-gate continue; 79677c478bd9Sstevel@tonic-gate ++naddrs; 79687c478bd9Sstevel@tonic-gate 79697c478bd9Sstevel@tonic-gate /* bad addresses and those already sent stay put */ 79707c478bd9Sstevel@tonic-gate if (QS_IS_BADADDR(q->q_state) || 79717c478bd9Sstevel@tonic-gate QS_IS_SENT(q->q_state)) 79727c478bd9Sstevel@tonic-gate q->q_qgrp = e->e_qgrp; 79737c478bd9Sstevel@tonic-gate else if (!ISVALIDQGRP(q->q_qgrp)) 79747c478bd9Sstevel@tonic-gate { 79757c478bd9Sstevel@tonic-gate /* call ruleset which should return a queue group */ 79767c478bd9Sstevel@tonic-gate i = rscap(RS_QUEUEGROUP, q->q_user, NULL, e, &pvp, 79777c478bd9Sstevel@tonic-gate pvpbuf, sizeof(pvpbuf)); 79787c478bd9Sstevel@tonic-gate if (i == EX_OK && 79797c478bd9Sstevel@tonic-gate pvp != NULL && pvp[0] != NULL && 79807c478bd9Sstevel@tonic-gate (pvp[0][0] & 0377) == CANONNET && 79817c478bd9Sstevel@tonic-gate pvp[1] != NULL && pvp[1][0] != '\0') 79827c478bd9Sstevel@tonic-gate { 79837c478bd9Sstevel@tonic-gate i = name2qid(pvp[1]); 79847c478bd9Sstevel@tonic-gate if (ISVALIDQGRP(i)) 79857c478bd9Sstevel@tonic-gate { 79867c478bd9Sstevel@tonic-gate q->q_qgrp = i; 79877c478bd9Sstevel@tonic-gate changed = true; 79887c478bd9Sstevel@tonic-gate if (tTd(20, 4)) 79897c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 79907c478bd9Sstevel@tonic-gate "queue group name %s -> %d", 79917c478bd9Sstevel@tonic-gate pvp[1], i); 79927c478bd9Sstevel@tonic-gate continue; 79937c478bd9Sstevel@tonic-gate } 79947c478bd9Sstevel@tonic-gate else if (LogLevel > 10) 79957c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 79967c478bd9Sstevel@tonic-gate "can't find queue group name %s, selection ignored", 79977c478bd9Sstevel@tonic-gate pvp[1]); 79987c478bd9Sstevel@tonic-gate } 79997c478bd9Sstevel@tonic-gate if (q->q_mailer != NULL && 80007c478bd9Sstevel@tonic-gate ISVALIDQGRP(q->q_mailer->m_qgrp)) 80017c478bd9Sstevel@tonic-gate { 80027c478bd9Sstevel@tonic-gate changed = true; 80037c478bd9Sstevel@tonic-gate q->q_qgrp = q->q_mailer->m_qgrp; 80047c478bd9Sstevel@tonic-gate } 80057c478bd9Sstevel@tonic-gate else if (ISVALIDQGRP(e->e_qgrp)) 80067c478bd9Sstevel@tonic-gate q->q_qgrp = e->e_qgrp; 80077c478bd9Sstevel@tonic-gate else 80087c478bd9Sstevel@tonic-gate q->q_qgrp = 0; 80097c478bd9Sstevel@tonic-gate } 80107c478bd9Sstevel@tonic-gate } 80117c478bd9Sstevel@tonic-gate 80127c478bd9Sstevel@tonic-gate /* only one address? nothing to split. */ 80137c478bd9Sstevel@tonic-gate if (naddrs <= 1 && !changed) 80147c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 80157c478bd9Sstevel@tonic-gate 80167c478bd9Sstevel@tonic-gate /* sort the addresses by queue group */ 80177c478bd9Sstevel@tonic-gate addrs = sm_rpool_malloc_x(e->e_rpool, naddrs * sizeof(ADDRESS *)); 80187c478bd9Sstevel@tonic-gate for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next) 80197c478bd9Sstevel@tonic-gate { 80207c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 80217c478bd9Sstevel@tonic-gate continue; 80227c478bd9Sstevel@tonic-gate addrs[i++] = q; 80237c478bd9Sstevel@tonic-gate } 80247c478bd9Sstevel@tonic-gate qsort(addrs, naddrs, sizeof(ADDRESS *), q_qgrp_compare); 80257c478bd9Sstevel@tonic-gate 80267c478bd9Sstevel@tonic-gate /* split into multiple envelopes, by queue group */ 80277c478bd9Sstevel@tonic-gate nsplits = 0; 80287c478bd9Sstevel@tonic-gate es = NULL; 80297c478bd9Sstevel@tonic-gate e->e_sendqueue = NULL; 80307c478bd9Sstevel@tonic-gate for (i = 0; i < naddrs; ++i) 80317c478bd9Sstevel@tonic-gate { 80327c478bd9Sstevel@tonic-gate if (i == naddrs - 1 || addrs[i]->q_qgrp != addrs[i + 1]->q_qgrp) 80337c478bd9Sstevel@tonic-gate addrs[i]->q_next = NULL; 80347c478bd9Sstevel@tonic-gate else 80357c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1]; 80367c478bd9Sstevel@tonic-gate 80377c478bd9Sstevel@tonic-gate /* same queue group as original envelope? */ 80387c478bd9Sstevel@tonic-gate if (addrs[i]->q_qgrp == e->e_qgrp) 80397c478bd9Sstevel@tonic-gate { 80407c478bd9Sstevel@tonic-gate if (e->e_sendqueue == NULL) 80417c478bd9Sstevel@tonic-gate e->e_sendqueue = addrs[i]; 80427c478bd9Sstevel@tonic-gate continue; 80437c478bd9Sstevel@tonic-gate } 80447c478bd9Sstevel@tonic-gate 80457c478bd9Sstevel@tonic-gate /* different queue group than original envelope */ 80467c478bd9Sstevel@tonic-gate if (es == NULL || addrs[i]->q_qgrp != es->e_qgrp) 80477c478bd9Sstevel@tonic-gate { 80487c478bd9Sstevel@tonic-gate ee = split_env(e, addrs[i], addrs[i]->q_qgrp, NOQDIR); 80497c478bd9Sstevel@tonic-gate es = ee; 80507c478bd9Sstevel@tonic-gate splits[nsplits++] = ee; 80517c478bd9Sstevel@tonic-gate } 80527c478bd9Sstevel@tonic-gate } 80537c478bd9Sstevel@tonic-gate 80547c478bd9Sstevel@tonic-gate /* no splits? return right now. */ 80557c478bd9Sstevel@tonic-gate if (nsplits <= 0) 80567c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 80577c478bd9Sstevel@tonic-gate 80587c478bd9Sstevel@tonic-gate /* assign a queue directory to each additional envelope */ 80597c478bd9Sstevel@tonic-gate for (i = 0; i < nsplits; ++i) 80607c478bd9Sstevel@tonic-gate { 80617c478bd9Sstevel@tonic-gate es = splits[i]; 80627c478bd9Sstevel@tonic-gate #if 0 80637c478bd9Sstevel@tonic-gate es->e_qdir = pickqdir(Queue[es->e_qgrp], es->e_msgsize, es); 80647c478bd9Sstevel@tonic-gate #endif /* 0 */ 80657c478bd9Sstevel@tonic-gate if (!setnewqueue(es)) 80667c478bd9Sstevel@tonic-gate goto failure; 80677c478bd9Sstevel@tonic-gate } 80687c478bd9Sstevel@tonic-gate 80697c478bd9Sstevel@tonic-gate /* sort the additional envelopes by queue file system */ 80707c478bd9Sstevel@tonic-gate qsort(splits, nsplits, sizeof(ENVELOPE *), e_filesys_compare); 80717c478bd9Sstevel@tonic-gate 80727c478bd9Sstevel@tonic-gate /* create data files for each additional envelope */ 80737c478bd9Sstevel@tonic-gate if (!dup_df(e, splits[0])) 80747c478bd9Sstevel@tonic-gate { 80757c478bd9Sstevel@tonic-gate i = 0; 80767c478bd9Sstevel@tonic-gate goto failure; 80777c478bd9Sstevel@tonic-gate } 80787c478bd9Sstevel@tonic-gate for (i = 1; i < nsplits; ++i) 80797c478bd9Sstevel@tonic-gate { 80807c478bd9Sstevel@tonic-gate /* copy or link to the previous data file */ 80817c478bd9Sstevel@tonic-gate if (!dup_df(splits[i - 1], splits[i])) 80827c478bd9Sstevel@tonic-gate goto failure; 80837c478bd9Sstevel@tonic-gate } 80847c478bd9Sstevel@tonic-gate 80857c478bd9Sstevel@tonic-gate /* success: prepend the new envelopes to the e->e_sibling list */ 80867c478bd9Sstevel@tonic-gate for (i = 0; i < nsplits; ++i) 80877c478bd9Sstevel@tonic-gate { 80887c478bd9Sstevel@tonic-gate es = splits[i]; 80897c478bd9Sstevel@tonic-gate es->e_sibling = e->e_sibling; 80907c478bd9Sstevel@tonic-gate e->e_sibling = es; 80917c478bd9Sstevel@tonic-gate } 80927c478bd9Sstevel@tonic-gate return SM_SPLIT_NEW(nsplits); 80937c478bd9Sstevel@tonic-gate 80947c478bd9Sstevel@tonic-gate /* failure: clean up */ 80957c478bd9Sstevel@tonic-gate failure: 80967c478bd9Sstevel@tonic-gate if (i > 0) 80977c478bd9Sstevel@tonic-gate { 80987c478bd9Sstevel@tonic-gate int j; 80997c478bd9Sstevel@tonic-gate 81007c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++) 81017c478bd9Sstevel@tonic-gate (void) unlink(queuename(splits[j], DATAFL_LETTER)); 81027c478bd9Sstevel@tonic-gate } 81037c478bd9Sstevel@tonic-gate e->e_sendqueue = addrs[0]; 81047c478bd9Sstevel@tonic-gate for (i = 0; i < naddrs - 1; ++i) 81057c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1]; 81067c478bd9Sstevel@tonic-gate addrs[naddrs - 1]->q_next = NULL; 81077c478bd9Sstevel@tonic-gate return SM_SPLIT_FAIL; 81087c478bd9Sstevel@tonic-gate } 81097c478bd9Sstevel@tonic-gate 81107c478bd9Sstevel@tonic-gate /* 81117c478bd9Sstevel@tonic-gate ** SPLIT_WITHIN_QUEUE 81127c478bd9Sstevel@tonic-gate ** 81137c478bd9Sstevel@tonic-gate ** Split an envelope with multiple recipients into several 81147c478bd9Sstevel@tonic-gate ** envelopes within the same queue directory, if the number of 81157c478bd9Sstevel@tonic-gate ** recipients exceeds the limit for the queue group. 81167c478bd9Sstevel@tonic-gate ** 81177c478bd9Sstevel@tonic-gate ** Parameters: 81187c478bd9Sstevel@tonic-gate ** e -- envelope. 81197c478bd9Sstevel@tonic-gate ** 81207c478bd9Sstevel@tonic-gate ** Results: 81217c478bd9Sstevel@tonic-gate ** SM_SPLIT_FAIL on failure 81227c478bd9Sstevel@tonic-gate ** SM_SPLIT_NONE if no splitting occurred, 81237c478bd9Sstevel@tonic-gate ** or 1 + the number of additional envelopes created. 81247c478bd9Sstevel@tonic-gate */ 81257c478bd9Sstevel@tonic-gate 81267c478bd9Sstevel@tonic-gate #define SPLIT_LOG_LEVEL 8 81277c478bd9Sstevel@tonic-gate 81287c478bd9Sstevel@tonic-gate static int split_within_queue __P((ENVELOPE *)); 81297c478bd9Sstevel@tonic-gate 81307c478bd9Sstevel@tonic-gate static int 81317c478bd9Sstevel@tonic-gate split_within_queue(e) 81327c478bd9Sstevel@tonic-gate ENVELOPE *e; 81337c478bd9Sstevel@tonic-gate { 81347c478bd9Sstevel@tonic-gate int maxrcpt, nrcpt, ndead, nsplit, i; 81357c478bd9Sstevel@tonic-gate int j, l; 81367c478bd9Sstevel@tonic-gate char *lsplits; 81377c478bd9Sstevel@tonic-gate ADDRESS *q, **addrs; 81387c478bd9Sstevel@tonic-gate ENVELOPE *ee, *firstsibling; 81397c478bd9Sstevel@tonic-gate 81407c478bd9Sstevel@tonic-gate if (!ISVALIDQGRP(e->e_qgrp) || bitset(EF_SPLIT, e->e_flags)) 81417c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 81427c478bd9Sstevel@tonic-gate 81437c478bd9Sstevel@tonic-gate /* don't bother if there is no recipient limit */ 81447c478bd9Sstevel@tonic-gate maxrcpt = Queue[e->e_qgrp]->qg_maxrcpt; 81457c478bd9Sstevel@tonic-gate if (maxrcpt <= 0) 81467c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 81477c478bd9Sstevel@tonic-gate 81487c478bd9Sstevel@tonic-gate /* count recipients */ 81497c478bd9Sstevel@tonic-gate nrcpt = 0; 81507c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 81517c478bd9Sstevel@tonic-gate { 81527c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 81537c478bd9Sstevel@tonic-gate continue; 81547c478bd9Sstevel@tonic-gate ++nrcpt; 81557c478bd9Sstevel@tonic-gate } 81567c478bd9Sstevel@tonic-gate if (nrcpt <= maxrcpt) 81577c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 81587c478bd9Sstevel@tonic-gate 81597c478bd9Sstevel@tonic-gate /* 81607c478bd9Sstevel@tonic-gate ** Preserve the recipient list 81617c478bd9Sstevel@tonic-gate ** so that we can restore it in case of error. 81627c478bd9Sstevel@tonic-gate ** (But we discard dead addresses.) 81637c478bd9Sstevel@tonic-gate */ 81647c478bd9Sstevel@tonic-gate 81657c478bd9Sstevel@tonic-gate addrs = sm_rpool_malloc_x(e->e_rpool, nrcpt * sizeof(ADDRESS *)); 81667c478bd9Sstevel@tonic-gate for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next) 81677c478bd9Sstevel@tonic-gate { 81687c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 81697c478bd9Sstevel@tonic-gate continue; 81707c478bd9Sstevel@tonic-gate addrs[i++] = q; 81717c478bd9Sstevel@tonic-gate } 81727c478bd9Sstevel@tonic-gate 81737c478bd9Sstevel@tonic-gate /* 81747c478bd9Sstevel@tonic-gate ** Partition the recipient list so that bad and sent addresses 81757c478bd9Sstevel@tonic-gate ** come first. These will go with the original envelope, and 81767c478bd9Sstevel@tonic-gate ** do not count towards the maxrcpt limit. 81777c478bd9Sstevel@tonic-gate ** addrs[] does not contain QS_IS_DEAD() addresses. 81787c478bd9Sstevel@tonic-gate */ 81797c478bd9Sstevel@tonic-gate 81807c478bd9Sstevel@tonic-gate ndead = 0; 81817c478bd9Sstevel@tonic-gate for (i = 0; i < nrcpt; ++i) 81827c478bd9Sstevel@tonic-gate { 81837c478bd9Sstevel@tonic-gate if (QS_IS_BADADDR(addrs[i]->q_state) || 81847c478bd9Sstevel@tonic-gate QS_IS_SENT(addrs[i]->q_state) || 81857c478bd9Sstevel@tonic-gate QS_IS_DEAD(addrs[i]->q_state)) /* for paranoia's sake */ 81867c478bd9Sstevel@tonic-gate { 81877c478bd9Sstevel@tonic-gate if (i > ndead) 81887c478bd9Sstevel@tonic-gate { 81897c478bd9Sstevel@tonic-gate ADDRESS *tmp = addrs[i]; 81907c478bd9Sstevel@tonic-gate 81917c478bd9Sstevel@tonic-gate addrs[i] = addrs[ndead]; 81927c478bd9Sstevel@tonic-gate addrs[ndead] = tmp; 81937c478bd9Sstevel@tonic-gate } 81947c478bd9Sstevel@tonic-gate ++ndead; 81957c478bd9Sstevel@tonic-gate } 81967c478bd9Sstevel@tonic-gate } 81977c478bd9Sstevel@tonic-gate 81987c478bd9Sstevel@tonic-gate /* Check if no splitting required. */ 81997c478bd9Sstevel@tonic-gate if (nrcpt - ndead <= maxrcpt) 82007c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 82017c478bd9Sstevel@tonic-gate 82027c478bd9Sstevel@tonic-gate /* fix links */ 82037c478bd9Sstevel@tonic-gate for (i = 0; i < nrcpt - 1; ++i) 82047c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1]; 82057c478bd9Sstevel@tonic-gate addrs[nrcpt - 1]->q_next = NULL; 82067c478bd9Sstevel@tonic-gate e->e_sendqueue = addrs[0]; 82077c478bd9Sstevel@tonic-gate 82087c478bd9Sstevel@tonic-gate /* prepare buffer for logging */ 82097c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL) 82107c478bd9Sstevel@tonic-gate { 82117c478bd9Sstevel@tonic-gate l = MAXLINE; 82127c478bd9Sstevel@tonic-gate lsplits = sm_malloc(l); 82137c478bd9Sstevel@tonic-gate if (lsplits != NULL) 82147c478bd9Sstevel@tonic-gate *lsplits = '\0'; 82157c478bd9Sstevel@tonic-gate j = 0; 82167c478bd9Sstevel@tonic-gate } 82177c478bd9Sstevel@tonic-gate else 82187c478bd9Sstevel@tonic-gate { 82197c478bd9Sstevel@tonic-gate /* get rid of stupid compiler warnings */ 82207c478bd9Sstevel@tonic-gate lsplits = NULL; 82217c478bd9Sstevel@tonic-gate j = l = 0; 82227c478bd9Sstevel@tonic-gate } 82237c478bd9Sstevel@tonic-gate 82247c478bd9Sstevel@tonic-gate /* split the envelope */ 82257c478bd9Sstevel@tonic-gate firstsibling = e->e_sibling; 82267c478bd9Sstevel@tonic-gate i = maxrcpt + ndead; 82277c478bd9Sstevel@tonic-gate nsplit = 0; 82287c478bd9Sstevel@tonic-gate for (;;) 82297c478bd9Sstevel@tonic-gate { 82307c478bd9Sstevel@tonic-gate addrs[i - 1]->q_next = NULL; 82317c478bd9Sstevel@tonic-gate ee = split_env(e, addrs[i], e->e_qgrp, e->e_qdir); 82327c478bd9Sstevel@tonic-gate if (!dup_df(e, ee)) 82337c478bd9Sstevel@tonic-gate { 82347c478bd9Sstevel@tonic-gate 82357c478bd9Sstevel@tonic-gate ee = firstsibling; 82367c478bd9Sstevel@tonic-gate while (ee != NULL) 82377c478bd9Sstevel@tonic-gate { 82387c478bd9Sstevel@tonic-gate (void) unlink(queuename(ee, DATAFL_LETTER)); 82397c478bd9Sstevel@tonic-gate ee = ee->e_sibling; 82407c478bd9Sstevel@tonic-gate } 82417c478bd9Sstevel@tonic-gate 82427c478bd9Sstevel@tonic-gate /* Error. Restore e's sibling & recipient lists. */ 82437c478bd9Sstevel@tonic-gate e->e_sibling = firstsibling; 82447c478bd9Sstevel@tonic-gate for (i = 0; i < nrcpt - 1; ++i) 82457c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1]; 82467c478bd9Sstevel@tonic-gate if (lsplits != NULL) 82477c478bd9Sstevel@tonic-gate sm_free(lsplits); 82487c478bd9Sstevel@tonic-gate return SM_SPLIT_FAIL; 82497c478bd9Sstevel@tonic-gate } 82507c478bd9Sstevel@tonic-gate 82517c478bd9Sstevel@tonic-gate /* prepend the new envelope to e->e_sibling */ 82527c478bd9Sstevel@tonic-gate ee->e_sibling = e->e_sibling; 82537c478bd9Sstevel@tonic-gate e->e_sibling = ee; 82547c478bd9Sstevel@tonic-gate ++nsplit; 82557c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL) 82567c478bd9Sstevel@tonic-gate { 82577c478bd9Sstevel@tonic-gate if (j >= l - strlen(ee->e_id) - 3) 82587c478bd9Sstevel@tonic-gate { 82597c478bd9Sstevel@tonic-gate char *p; 82607c478bd9Sstevel@tonic-gate 82617c478bd9Sstevel@tonic-gate l += MAXLINE; 82627c478bd9Sstevel@tonic-gate p = sm_realloc(lsplits, l); 82637c478bd9Sstevel@tonic-gate if (p == NULL) 82647c478bd9Sstevel@tonic-gate { 82657c478bd9Sstevel@tonic-gate /* let's try to get this done */ 82667c478bd9Sstevel@tonic-gate sm_free(lsplits); 82677c478bd9Sstevel@tonic-gate lsplits = NULL; 82687c478bd9Sstevel@tonic-gate } 82697c478bd9Sstevel@tonic-gate else 82707c478bd9Sstevel@tonic-gate lsplits = p; 82717c478bd9Sstevel@tonic-gate } 82727c478bd9Sstevel@tonic-gate if (lsplits != NULL) 82737c478bd9Sstevel@tonic-gate { 82747c478bd9Sstevel@tonic-gate if (j == 0) 82757c478bd9Sstevel@tonic-gate j += sm_strlcat(lsplits + j, 82767c478bd9Sstevel@tonic-gate ee->e_id, 82777c478bd9Sstevel@tonic-gate l - j); 82787c478bd9Sstevel@tonic-gate else 82797c478bd9Sstevel@tonic-gate j += sm_strlcat2(lsplits + j, 82807c478bd9Sstevel@tonic-gate "; ", 82817c478bd9Sstevel@tonic-gate ee->e_id, 82827c478bd9Sstevel@tonic-gate l - j); 82837c478bd9Sstevel@tonic-gate SM_ASSERT(j < l); 82847c478bd9Sstevel@tonic-gate } 82857c478bd9Sstevel@tonic-gate } 82867c478bd9Sstevel@tonic-gate if (nrcpt - i <= maxrcpt) 82877c478bd9Sstevel@tonic-gate break; 82887c478bd9Sstevel@tonic-gate i += maxrcpt; 82897c478bd9Sstevel@tonic-gate } 82907c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL) 82917c478bd9Sstevel@tonic-gate { 82927c478bd9Sstevel@tonic-gate if (nsplit > 0) 82937c478bd9Sstevel@tonic-gate { 82947c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id, 82957c478bd9Sstevel@tonic-gate "split: maxrcpts=%d, rcpts=%d, count=%d, id%s=%s", 82967c478bd9Sstevel@tonic-gate maxrcpt, nrcpt - ndead, nsplit, 82977c478bd9Sstevel@tonic-gate nsplit > 1 ? "s" : "", lsplits); 82987c478bd9Sstevel@tonic-gate } 82997c478bd9Sstevel@tonic-gate sm_free(lsplits); 83007c478bd9Sstevel@tonic-gate } 83017c478bd9Sstevel@tonic-gate return SM_SPLIT_NEW(nsplit); 83027c478bd9Sstevel@tonic-gate } 83037c478bd9Sstevel@tonic-gate /* 83047c478bd9Sstevel@tonic-gate ** SPLIT_BY_RECIPIENT 83057c478bd9Sstevel@tonic-gate ** 83067c478bd9Sstevel@tonic-gate ** Split an envelope with multiple recipients into multiple 83077c478bd9Sstevel@tonic-gate ** envelopes as required by the sendmail configuration. 83087c478bd9Sstevel@tonic-gate ** 83097c478bd9Sstevel@tonic-gate ** Parameters: 83107c478bd9Sstevel@tonic-gate ** e -- envelope. 83117c478bd9Sstevel@tonic-gate ** 83127c478bd9Sstevel@tonic-gate ** Results: 83137c478bd9Sstevel@tonic-gate ** Returns true on success, false on failure. 83147c478bd9Sstevel@tonic-gate ** 83157c478bd9Sstevel@tonic-gate ** Side Effects: 83167c478bd9Sstevel@tonic-gate ** see split_across_queue_groups(), split_within_queue(e) 83177c478bd9Sstevel@tonic-gate */ 83187c478bd9Sstevel@tonic-gate 83197c478bd9Sstevel@tonic-gate bool 83207c478bd9Sstevel@tonic-gate split_by_recipient(e) 83217c478bd9Sstevel@tonic-gate ENVELOPE *e; 83227c478bd9Sstevel@tonic-gate { 83237c478bd9Sstevel@tonic-gate int split, n, i, j, l; 83247c478bd9Sstevel@tonic-gate char *lsplits; 83257c478bd9Sstevel@tonic-gate ENVELOPE *ee, *next, *firstsibling; 83267c478bd9Sstevel@tonic-gate 83277c478bd9Sstevel@tonic-gate if (OpMode == SM_VERIFY || !ISVALIDQGRP(e->e_qgrp) || 83287c478bd9Sstevel@tonic-gate bitset(EF_SPLIT, e->e_flags)) 83297c478bd9Sstevel@tonic-gate return true; 83307c478bd9Sstevel@tonic-gate n = split_across_queue_groups(e); 83317c478bd9Sstevel@tonic-gate if (n == SM_SPLIT_FAIL) 83327c478bd9Sstevel@tonic-gate return false; 83337c478bd9Sstevel@tonic-gate firstsibling = ee = e->e_sibling; 83347c478bd9Sstevel@tonic-gate if (n > 1 && LogLevel > SPLIT_LOG_LEVEL) 83357c478bd9Sstevel@tonic-gate { 83367c478bd9Sstevel@tonic-gate l = MAXLINE; 83377c478bd9Sstevel@tonic-gate lsplits = sm_malloc(l); 83387c478bd9Sstevel@tonic-gate if (lsplits != NULL) 83397c478bd9Sstevel@tonic-gate *lsplits = '\0'; 83407c478bd9Sstevel@tonic-gate j = 0; 83417c478bd9Sstevel@tonic-gate } 83427c478bd9Sstevel@tonic-gate else 83437c478bd9Sstevel@tonic-gate { 83447c478bd9Sstevel@tonic-gate /* get rid of stupid compiler warnings */ 83457c478bd9Sstevel@tonic-gate lsplits = NULL; 83467c478bd9Sstevel@tonic-gate j = l = 0; 83477c478bd9Sstevel@tonic-gate } 83487c478bd9Sstevel@tonic-gate for (i = 1; i < n; ++i) 83497c478bd9Sstevel@tonic-gate { 83507c478bd9Sstevel@tonic-gate next = ee->e_sibling; 83517c478bd9Sstevel@tonic-gate if (split_within_queue(ee) == SM_SPLIT_FAIL) 83527c478bd9Sstevel@tonic-gate { 83537c478bd9Sstevel@tonic-gate e->e_sibling = firstsibling; 83547c478bd9Sstevel@tonic-gate return false; 83557c478bd9Sstevel@tonic-gate } 83567c478bd9Sstevel@tonic-gate ee->e_flags |= EF_SPLIT; 83577c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL) 83587c478bd9Sstevel@tonic-gate { 83597c478bd9Sstevel@tonic-gate if (j >= l - strlen(ee->e_id) - 3) 83607c478bd9Sstevel@tonic-gate { 83617c478bd9Sstevel@tonic-gate char *p; 83627c478bd9Sstevel@tonic-gate 83637c478bd9Sstevel@tonic-gate l += MAXLINE; 83647c478bd9Sstevel@tonic-gate p = sm_realloc(lsplits, l); 83657c478bd9Sstevel@tonic-gate if (p == NULL) 83667c478bd9Sstevel@tonic-gate { 83677c478bd9Sstevel@tonic-gate /* let's try to get this done */ 83687c478bd9Sstevel@tonic-gate sm_free(lsplits); 83697c478bd9Sstevel@tonic-gate lsplits = NULL; 83707c478bd9Sstevel@tonic-gate } 83717c478bd9Sstevel@tonic-gate else 83727c478bd9Sstevel@tonic-gate lsplits = p; 83737c478bd9Sstevel@tonic-gate } 83747c478bd9Sstevel@tonic-gate if (lsplits != NULL) 83757c478bd9Sstevel@tonic-gate { 83767c478bd9Sstevel@tonic-gate if (j == 0) 83777c478bd9Sstevel@tonic-gate j += sm_strlcat(lsplits + j, 83787c478bd9Sstevel@tonic-gate ee->e_id, l - j); 83797c478bd9Sstevel@tonic-gate else 83807c478bd9Sstevel@tonic-gate j += sm_strlcat2(lsplits + j, "; ", 83817c478bd9Sstevel@tonic-gate ee->e_id, l - j); 83827c478bd9Sstevel@tonic-gate SM_ASSERT(j < l); 83837c478bd9Sstevel@tonic-gate } 83847c478bd9Sstevel@tonic-gate } 83857c478bd9Sstevel@tonic-gate ee = next; 83867c478bd9Sstevel@tonic-gate } 83877c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL && n > 1) 83887c478bd9Sstevel@tonic-gate { 83897c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id, "split: count=%d, id%s=%s", 83907c478bd9Sstevel@tonic-gate n - 1, n > 2 ? "s" : "", lsplits); 83917c478bd9Sstevel@tonic-gate sm_free(lsplits); 83927c478bd9Sstevel@tonic-gate } 83937c478bd9Sstevel@tonic-gate split = split_within_queue(e) != SM_SPLIT_FAIL; 83947c478bd9Sstevel@tonic-gate if (split) 83957c478bd9Sstevel@tonic-gate e->e_flags |= EF_SPLIT; 83967c478bd9Sstevel@tonic-gate return split; 83977c478bd9Sstevel@tonic-gate } 83987c478bd9Sstevel@tonic-gate 83997c478bd9Sstevel@tonic-gate /* 84007c478bd9Sstevel@tonic-gate ** QUARANTINE_QUEUE_ITEM -- {un,}quarantine a single envelope 84017c478bd9Sstevel@tonic-gate ** 84027c478bd9Sstevel@tonic-gate ** Add/remove quarantine reason and requeue appropriately. 84037c478bd9Sstevel@tonic-gate ** 84047c478bd9Sstevel@tonic-gate ** Parameters: 84057c478bd9Sstevel@tonic-gate ** qgrp -- queue group for the item 84067c478bd9Sstevel@tonic-gate ** qdir -- queue directory in the given queue group 84077c478bd9Sstevel@tonic-gate ** e -- envelope information for the item 84087c478bd9Sstevel@tonic-gate ** reason -- quarantine reason, NULL means unquarantine. 84097c478bd9Sstevel@tonic-gate ** 84107c478bd9Sstevel@tonic-gate ** Results: 84117c478bd9Sstevel@tonic-gate ** true if item changed, false otherwise 84127c478bd9Sstevel@tonic-gate ** 84137c478bd9Sstevel@tonic-gate ** Side Effects: 84147c478bd9Sstevel@tonic-gate ** Changes quarantine tag in queue file and renames it. 84157c478bd9Sstevel@tonic-gate */ 84167c478bd9Sstevel@tonic-gate 84177c478bd9Sstevel@tonic-gate static bool 84187c478bd9Sstevel@tonic-gate quarantine_queue_item(qgrp, qdir, e, reason) 84197c478bd9Sstevel@tonic-gate int qgrp; 84207c478bd9Sstevel@tonic-gate int qdir; 84217c478bd9Sstevel@tonic-gate ENVELOPE *e; 84227c478bd9Sstevel@tonic-gate char *reason; 84237c478bd9Sstevel@tonic-gate { 84247c478bd9Sstevel@tonic-gate bool dirty = false; 84257c478bd9Sstevel@tonic-gate bool failing = false; 84267c478bd9Sstevel@tonic-gate bool foundq = false; 84277c478bd9Sstevel@tonic-gate bool finished = false; 84287c478bd9Sstevel@tonic-gate int fd; 84297c478bd9Sstevel@tonic-gate int flags; 84307c478bd9Sstevel@tonic-gate int oldtype; 84317c478bd9Sstevel@tonic-gate int newtype; 84327c478bd9Sstevel@tonic-gate int save_errno; 84337c478bd9Sstevel@tonic-gate MODE_T oldumask = 0; 84347c478bd9Sstevel@tonic-gate SM_FILE_T *oldqfp, *tempqfp; 84357c478bd9Sstevel@tonic-gate char *bp; 8436*058561cbSjbeck int bufsize; 84377c478bd9Sstevel@tonic-gate char oldqf[MAXPATHLEN]; 84387c478bd9Sstevel@tonic-gate char tempqf[MAXPATHLEN]; 84397c478bd9Sstevel@tonic-gate char newqf[MAXPATHLEN]; 84407c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 84417c478bd9Sstevel@tonic-gate 84427c478bd9Sstevel@tonic-gate oldtype = queue_letter(e, ANYQFL_LETTER); 8443*058561cbSjbeck (void) sm_strlcpy(oldqf, queuename(e, ANYQFL_LETTER), sizeof(oldqf)); 8444*058561cbSjbeck (void) sm_strlcpy(tempqf, queuename(e, NEWQFL_LETTER), sizeof(tempqf)); 84457c478bd9Sstevel@tonic-gate 84467c478bd9Sstevel@tonic-gate /* 84477c478bd9Sstevel@tonic-gate ** Instead of duplicating all the open 84487c478bd9Sstevel@tonic-gate ** and lock code here, tell readqf() to 84497c478bd9Sstevel@tonic-gate ** do that work and return the open 84507c478bd9Sstevel@tonic-gate ** file pointer in e_lockfp. Note that 84517c478bd9Sstevel@tonic-gate ** we must release the locks properly when 84527c478bd9Sstevel@tonic-gate ** we are done. 84537c478bd9Sstevel@tonic-gate */ 84547c478bd9Sstevel@tonic-gate 84557c478bd9Sstevel@tonic-gate if (!readqf(e, true)) 84567c478bd9Sstevel@tonic-gate { 84577c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 84587c478bd9Sstevel@tonic-gate "Skipping %s\n", qid_printname(e)); 84597c478bd9Sstevel@tonic-gate return false; 84607c478bd9Sstevel@tonic-gate } 84617c478bd9Sstevel@tonic-gate oldqfp = e->e_lockfp; 84627c478bd9Sstevel@tonic-gate 84637c478bd9Sstevel@tonic-gate /* open the new queue file */ 84647c478bd9Sstevel@tonic-gate flags = O_CREAT|O_WRONLY|O_EXCL; 84657c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 84667c478bd9Sstevel@tonic-gate oldumask = umask(002); 84677c478bd9Sstevel@tonic-gate fd = open(tempqf, flags, QueueFileMode); 84687c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 84697c478bd9Sstevel@tonic-gate (void) umask(oldumask); 84707c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 84717c478bd9Sstevel@tonic-gate 84727c478bd9Sstevel@tonic-gate if (fd < 0) 84737c478bd9Sstevel@tonic-gate { 84747c478bd9Sstevel@tonic-gate save_errno = errno; 84757c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 84767c478bd9Sstevel@tonic-gate "Skipping %s: Could not open %s: %s\n", 84777c478bd9Sstevel@tonic-gate qid_printname(e), tempqf, 84787c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 84797c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT); 84807c478bd9Sstevel@tonic-gate return false; 84817c478bd9Sstevel@tonic-gate } 84827c478bd9Sstevel@tonic-gate if (!lockfile(fd, tempqf, NULL, LOCK_EX|LOCK_NB)) 84837c478bd9Sstevel@tonic-gate { 84847c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 84857c478bd9Sstevel@tonic-gate "Skipping %s: Could not lock %s\n", 84867c478bd9Sstevel@tonic-gate qid_printname(e), tempqf); 84877c478bd9Sstevel@tonic-gate (void) close(fd); 84887c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT); 84897c478bd9Sstevel@tonic-gate return false; 84907c478bd9Sstevel@tonic-gate } 84917c478bd9Sstevel@tonic-gate 84927c478bd9Sstevel@tonic-gate tempqfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &fd, 84937c478bd9Sstevel@tonic-gate SM_IO_WRONLY_B, NULL); 84947c478bd9Sstevel@tonic-gate if (tempqfp == NULL) 84957c478bd9Sstevel@tonic-gate { 84967c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 84977c478bd9Sstevel@tonic-gate "Skipping %s: Could not lock %s\n", 84987c478bd9Sstevel@tonic-gate qid_printname(e), tempqf); 84997c478bd9Sstevel@tonic-gate (void) close(fd); 85007c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT); 85017c478bd9Sstevel@tonic-gate return false; 85027c478bd9Sstevel@tonic-gate } 85037c478bd9Sstevel@tonic-gate 85047c478bd9Sstevel@tonic-gate /* Copy the data over, changing the quarantine reason */ 8505*058561cbSjbeck while (bufsize = sizeof(buf), 8506*058561cbSjbeck (bp = fgetfolded(buf, &bufsize, oldqfp)) != NULL) 85077c478bd9Sstevel@tonic-gate { 85087c478bd9Sstevel@tonic-gate if (tTd(40, 4)) 85097c478bd9Sstevel@tonic-gate sm_dprintf("+++++ %s\n", bp); 85107c478bd9Sstevel@tonic-gate switch (bp[0]) 85117c478bd9Sstevel@tonic-gate { 85127c478bd9Sstevel@tonic-gate case 'q': /* quarantine reason */ 85137c478bd9Sstevel@tonic-gate foundq = true; 85147c478bd9Sstevel@tonic-gate if (reason == NULL) 85157c478bd9Sstevel@tonic-gate { 85167c478bd9Sstevel@tonic-gate if (Verbose) 85177c478bd9Sstevel@tonic-gate { 85187c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 85197c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 85207c478bd9Sstevel@tonic-gate "%s: Removed quarantine of \"%s\"\n", 85217c478bd9Sstevel@tonic-gate e->e_id, &bp[1]); 85227c478bd9Sstevel@tonic-gate } 85237c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "unquarantine"); 85247c478bd9Sstevel@tonic-gate dirty = true; 85257c478bd9Sstevel@tonic-gate } 85267c478bd9Sstevel@tonic-gate else if (strcmp(reason, &bp[1]) == 0) 85277c478bd9Sstevel@tonic-gate { 85287c478bd9Sstevel@tonic-gate if (Verbose) 85297c478bd9Sstevel@tonic-gate { 85307c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 85317c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 85327c478bd9Sstevel@tonic-gate "%s: Already quarantined with \"%s\"\n", 85337c478bd9Sstevel@tonic-gate e->e_id, reason); 85347c478bd9Sstevel@tonic-gate } 85357c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 85367c478bd9Sstevel@tonic-gate "q%s\n", reason); 85377c478bd9Sstevel@tonic-gate } 85387c478bd9Sstevel@tonic-gate else 85397c478bd9Sstevel@tonic-gate { 85407c478bd9Sstevel@tonic-gate if (Verbose) 85417c478bd9Sstevel@tonic-gate { 85427c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 85437c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 85447c478bd9Sstevel@tonic-gate "%s: Quarantine changed from \"%s\" to \"%s\"\n", 85457c478bd9Sstevel@tonic-gate e->e_id, &bp[1], 85467c478bd9Sstevel@tonic-gate reason); 85477c478bd9Sstevel@tonic-gate } 85487c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 85497c478bd9Sstevel@tonic-gate "q%s\n", reason); 85507c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "quarantine=%s", 85517c478bd9Sstevel@tonic-gate reason); 85527c478bd9Sstevel@tonic-gate dirty = true; 85537c478bd9Sstevel@tonic-gate } 85547c478bd9Sstevel@tonic-gate break; 85557c478bd9Sstevel@tonic-gate 85567c478bd9Sstevel@tonic-gate case 'S': 85577c478bd9Sstevel@tonic-gate /* 85587c478bd9Sstevel@tonic-gate ** If we are quarantining an unquarantined item, 85597c478bd9Sstevel@tonic-gate ** need to put in a new 'q' line before it's 85607c478bd9Sstevel@tonic-gate ** too late. 85617c478bd9Sstevel@tonic-gate */ 85627c478bd9Sstevel@tonic-gate 85637c478bd9Sstevel@tonic-gate if (!foundq && reason != NULL) 85647c478bd9Sstevel@tonic-gate { 85657c478bd9Sstevel@tonic-gate if (Verbose) 85667c478bd9Sstevel@tonic-gate { 85677c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 85687c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 85697c478bd9Sstevel@tonic-gate "%s: Quarantined with \"%s\"\n", 85707c478bd9Sstevel@tonic-gate e->e_id, reason); 85717c478bd9Sstevel@tonic-gate } 85727c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 85737c478bd9Sstevel@tonic-gate "q%s\n", reason); 85747c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "quarantine=%s", 85757c478bd9Sstevel@tonic-gate reason); 85767c478bd9Sstevel@tonic-gate foundq = true; 85777c478bd9Sstevel@tonic-gate dirty = true; 85787c478bd9Sstevel@tonic-gate } 85797c478bd9Sstevel@tonic-gate 85807c478bd9Sstevel@tonic-gate /* Copy the line to the new file */ 85817c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 85827c478bd9Sstevel@tonic-gate "%s\n", bp); 85837c478bd9Sstevel@tonic-gate break; 85847c478bd9Sstevel@tonic-gate 85857c478bd9Sstevel@tonic-gate case '.': 85867c478bd9Sstevel@tonic-gate finished = true; 85877c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 85887c478bd9Sstevel@tonic-gate 85897c478bd9Sstevel@tonic-gate default: 85907c478bd9Sstevel@tonic-gate /* Copy the line to the new file */ 85917c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 85927c478bd9Sstevel@tonic-gate "%s\n", bp); 85937c478bd9Sstevel@tonic-gate break; 85947c478bd9Sstevel@tonic-gate } 8595*058561cbSjbeck if (bp != buf) 8596*058561cbSjbeck sm_free(bp); 85977c478bd9Sstevel@tonic-gate } 85987c478bd9Sstevel@tonic-gate 85997c478bd9Sstevel@tonic-gate /* Make sure we read the whole old file */ 86007c478bd9Sstevel@tonic-gate errno = sm_io_error(tempqfp); 86017c478bd9Sstevel@tonic-gate if (errno != 0 && errno != SM_IO_EOF) 86027c478bd9Sstevel@tonic-gate { 86037c478bd9Sstevel@tonic-gate save_errno = errno; 86047c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 86057c478bd9Sstevel@tonic-gate "Skipping %s: Error reading %s: %s\n", 86067c478bd9Sstevel@tonic-gate qid_printname(e), oldqf, 86077c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 86087c478bd9Sstevel@tonic-gate failing = true; 86097c478bd9Sstevel@tonic-gate } 86107c478bd9Sstevel@tonic-gate 86117c478bd9Sstevel@tonic-gate if (!failing && !finished) 86127c478bd9Sstevel@tonic-gate { 86137c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 86147c478bd9Sstevel@tonic-gate "Skipping %s: Incomplete file: %s\n", 86157c478bd9Sstevel@tonic-gate qid_printname(e), oldqf); 86167c478bd9Sstevel@tonic-gate failing = true; 86177c478bd9Sstevel@tonic-gate } 86187c478bd9Sstevel@tonic-gate 86197c478bd9Sstevel@tonic-gate /* Check if we actually changed anything or we can just bail now */ 86207c478bd9Sstevel@tonic-gate if (!dirty) 86217c478bd9Sstevel@tonic-gate { 86227c478bd9Sstevel@tonic-gate /* pretend we failed, even though we technically didn't */ 86237c478bd9Sstevel@tonic-gate failing = true; 86247c478bd9Sstevel@tonic-gate } 86257c478bd9Sstevel@tonic-gate 86267c478bd9Sstevel@tonic-gate /* Make sure we wrote things out safely */ 86277c478bd9Sstevel@tonic-gate if (!failing && 86287c478bd9Sstevel@tonic-gate (sm_io_flush(tempqfp, SM_TIME_DEFAULT) != 0 || 86297c478bd9Sstevel@tonic-gate ((SuperSafe == SAFE_REALLY || 86307c478bd9Sstevel@tonic-gate SuperSafe == SAFE_REALLY_POSTMILTER || 86317c478bd9Sstevel@tonic-gate SuperSafe == SAFE_INTERACTIVE) && 86327c478bd9Sstevel@tonic-gate fsync(sm_io_getinfo(tempqfp, SM_IO_WHAT_FD, NULL)) < 0) || 86337c478bd9Sstevel@tonic-gate ((errno = sm_io_error(tempqfp)) != 0))) 86347c478bd9Sstevel@tonic-gate { 86357c478bd9Sstevel@tonic-gate save_errno = errno; 86367c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 86377c478bd9Sstevel@tonic-gate "Skipping %s: Error writing %s: %s\n", 86387c478bd9Sstevel@tonic-gate qid_printname(e), tempqf, 86397c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 86407c478bd9Sstevel@tonic-gate failing = true; 86417c478bd9Sstevel@tonic-gate } 86427c478bd9Sstevel@tonic-gate 86437c478bd9Sstevel@tonic-gate 86447c478bd9Sstevel@tonic-gate /* Figure out the new filename */ 86457c478bd9Sstevel@tonic-gate newtype = (reason == NULL ? NORMQF_LETTER : QUARQF_LETTER); 86467c478bd9Sstevel@tonic-gate if (oldtype == newtype) 86477c478bd9Sstevel@tonic-gate { 86487c478bd9Sstevel@tonic-gate /* going to rename tempqf to oldqf */ 8649*058561cbSjbeck (void) sm_strlcpy(newqf, oldqf, sizeof(newqf)); 86507c478bd9Sstevel@tonic-gate } 86517c478bd9Sstevel@tonic-gate else 86527c478bd9Sstevel@tonic-gate { 86537c478bd9Sstevel@tonic-gate /* going to rename tempqf to new name based on newtype */ 8654*058561cbSjbeck (void) sm_strlcpy(newqf, queuename(e, newtype), sizeof(newqf)); 86557c478bd9Sstevel@tonic-gate } 86567c478bd9Sstevel@tonic-gate 86577c478bd9Sstevel@tonic-gate save_errno = 0; 86587c478bd9Sstevel@tonic-gate 86597c478bd9Sstevel@tonic-gate /* rename tempqf to newqf */ 86607c478bd9Sstevel@tonic-gate if (!failing && 86617c478bd9Sstevel@tonic-gate rename(tempqf, newqf) < 0) 86627c478bd9Sstevel@tonic-gate save_errno = (errno == 0) ? EINVAL : errno; 86637c478bd9Sstevel@tonic-gate 86647c478bd9Sstevel@tonic-gate /* Check rename() success */ 86657c478bd9Sstevel@tonic-gate if (!failing && save_errno != 0) 86667c478bd9Sstevel@tonic-gate { 86677c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, 86687c478bd9Sstevel@tonic-gate "quarantine_queue_item: rename(%s, %s): %s", 86697c478bd9Sstevel@tonic-gate tempqf, newqf, sm_errstring(save_errno)); 86707c478bd9Sstevel@tonic-gate 86717c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 86727c478bd9Sstevel@tonic-gate "Error renaming %s to %s: %s\n", 86737c478bd9Sstevel@tonic-gate tempqf, newqf, 86747c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 86757c478bd9Sstevel@tonic-gate if (oldtype == newtype) 86767c478bd9Sstevel@tonic-gate { 86777c478bd9Sstevel@tonic-gate /* 86787c478bd9Sstevel@tonic-gate ** Bail here since we don't know the state of 86797c478bd9Sstevel@tonic-gate ** the filesystem and may need to keep tempqf 86807c478bd9Sstevel@tonic-gate ** for the user to rescue us. 86817c478bd9Sstevel@tonic-gate */ 86827c478bd9Sstevel@tonic-gate 86837c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 86847c478bd9Sstevel@tonic-gate errno = save_errno; 86857c478bd9Sstevel@tonic-gate syserr("!452 Error renaming control file %s", tempqf); 86867c478bd9Sstevel@tonic-gate /* NOTREACHED */ 86877c478bd9Sstevel@tonic-gate } 86887c478bd9Sstevel@tonic-gate else 86897c478bd9Sstevel@tonic-gate { 86907c478bd9Sstevel@tonic-gate /* remove new file (if rename() half completed) */ 86917c478bd9Sstevel@tonic-gate if (xunlink(newqf) < 0) 86927c478bd9Sstevel@tonic-gate { 86937c478bd9Sstevel@tonic-gate save_errno = errno; 86947c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 86957c478bd9Sstevel@tonic-gate "Error removing %s: %s\n", 86967c478bd9Sstevel@tonic-gate newqf, 86977c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 86987c478bd9Sstevel@tonic-gate } 86997c478bd9Sstevel@tonic-gate 87007c478bd9Sstevel@tonic-gate /* tempqf removed below */ 87017c478bd9Sstevel@tonic-gate failing = true; 87027c478bd9Sstevel@tonic-gate } 87037c478bd9Sstevel@tonic-gate 87047c478bd9Sstevel@tonic-gate } 87057c478bd9Sstevel@tonic-gate 87067c478bd9Sstevel@tonic-gate /* If changing file types, need to remove old type */ 87077c478bd9Sstevel@tonic-gate if (!failing && oldtype != newtype) 87087c478bd9Sstevel@tonic-gate { 87097c478bd9Sstevel@tonic-gate if (xunlink(oldqf) < 0) 87107c478bd9Sstevel@tonic-gate { 87117c478bd9Sstevel@tonic-gate save_errno = errno; 87127c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 87137c478bd9Sstevel@tonic-gate "Error removing %s: %s\n", 87147c478bd9Sstevel@tonic-gate oldqf, sm_errstring(save_errno)); 87157c478bd9Sstevel@tonic-gate } 87167c478bd9Sstevel@tonic-gate } 87177c478bd9Sstevel@tonic-gate 87187c478bd9Sstevel@tonic-gate /* see if anything above failed */ 87197c478bd9Sstevel@tonic-gate if (failing) 87207c478bd9Sstevel@tonic-gate { 87217c478bd9Sstevel@tonic-gate /* Something failed: remove new file, old file still there */ 87227c478bd9Sstevel@tonic-gate (void) xunlink(tempqf); 87237c478bd9Sstevel@tonic-gate } 87247c478bd9Sstevel@tonic-gate 87257c478bd9Sstevel@tonic-gate /* 87267c478bd9Sstevel@tonic-gate ** fsync() after file operations to make sure metadata is 87277c478bd9Sstevel@tonic-gate ** written to disk on filesystems in which renames are 87287c478bd9Sstevel@tonic-gate ** not guaranteed. It's ok if they fail, mail won't be lost. 87297c478bd9Sstevel@tonic-gate */ 87307c478bd9Sstevel@tonic-gate 87317c478bd9Sstevel@tonic-gate if (SuperSafe != SAFE_NO) 87327c478bd9Sstevel@tonic-gate { 87337c478bd9Sstevel@tonic-gate /* for soft-updates */ 87347c478bd9Sstevel@tonic-gate (void) fsync(sm_io_getinfo(tempqfp, 87357c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, NULL)); 87367c478bd9Sstevel@tonic-gate 87377c478bd9Sstevel@tonic-gate if (!failing) 87387c478bd9Sstevel@tonic-gate { 87397c478bd9Sstevel@tonic-gate /* for soft-updates */ 87407c478bd9Sstevel@tonic-gate (void) fsync(sm_io_getinfo(oldqfp, 87417c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, NULL)); 87427c478bd9Sstevel@tonic-gate } 87437c478bd9Sstevel@tonic-gate 87447c478bd9Sstevel@tonic-gate /* for other odd filesystems */ 87457c478bd9Sstevel@tonic-gate SYNC_DIR(tempqf, false); 87467c478bd9Sstevel@tonic-gate } 87477c478bd9Sstevel@tonic-gate 87487c478bd9Sstevel@tonic-gate /* Close up shop */ 87497c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 87507c478bd9Sstevel@tonic-gate if (tempqfp != NULL) 87517c478bd9Sstevel@tonic-gate (void) sm_io_close(tempqfp, SM_TIME_DEFAULT); 87527c478bd9Sstevel@tonic-gate if (oldqfp != NULL) 87537c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT); 87547c478bd9Sstevel@tonic-gate 87557c478bd9Sstevel@tonic-gate /* All went well */ 87567c478bd9Sstevel@tonic-gate return !failing; 87577c478bd9Sstevel@tonic-gate } 87587c478bd9Sstevel@tonic-gate 87597c478bd9Sstevel@tonic-gate /* 87607c478bd9Sstevel@tonic-gate ** QUARANTINE_QUEUE -- {un,}quarantine matching items in the queue 87617c478bd9Sstevel@tonic-gate ** 87627c478bd9Sstevel@tonic-gate ** Read all matching queue items, add/remove quarantine 87637c478bd9Sstevel@tonic-gate ** reason, and requeue appropriately. 87647c478bd9Sstevel@tonic-gate ** 87657c478bd9Sstevel@tonic-gate ** Parameters: 87667c478bd9Sstevel@tonic-gate ** reason -- quarantine reason, "." means unquarantine. 87677c478bd9Sstevel@tonic-gate ** qgrplimit -- limit to single queue group unless NOQGRP 87687c478bd9Sstevel@tonic-gate ** 87697c478bd9Sstevel@tonic-gate ** Results: 87707c478bd9Sstevel@tonic-gate ** none. 87717c478bd9Sstevel@tonic-gate ** 87727c478bd9Sstevel@tonic-gate ** Side Effects: 87737c478bd9Sstevel@tonic-gate ** Lots of changes to the queue. 87747c478bd9Sstevel@tonic-gate */ 87757c478bd9Sstevel@tonic-gate 87767c478bd9Sstevel@tonic-gate void 87777c478bd9Sstevel@tonic-gate quarantine_queue(reason, qgrplimit) 87787c478bd9Sstevel@tonic-gate char *reason; 87797c478bd9Sstevel@tonic-gate int qgrplimit; 87807c478bd9Sstevel@tonic-gate { 87817c478bd9Sstevel@tonic-gate int changed = 0; 87827c478bd9Sstevel@tonic-gate int qgrp; 87837c478bd9Sstevel@tonic-gate 87847c478bd9Sstevel@tonic-gate /* Convert internal representation of unquarantine */ 87857c478bd9Sstevel@tonic-gate if (reason != NULL && reason[0] == '.' && reason[1] == '\0') 87867c478bd9Sstevel@tonic-gate reason = NULL; 87877c478bd9Sstevel@tonic-gate 87887c478bd9Sstevel@tonic-gate if (reason != NULL) 87897c478bd9Sstevel@tonic-gate { 87907c478bd9Sstevel@tonic-gate /* clean it */ 87917c478bd9Sstevel@tonic-gate reason = newstr(denlstring(reason, true, true)); 87927c478bd9Sstevel@tonic-gate } 87937c478bd9Sstevel@tonic-gate 87947c478bd9Sstevel@tonic-gate for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++) 87957c478bd9Sstevel@tonic-gate { 87967c478bd9Sstevel@tonic-gate int qdir; 87977c478bd9Sstevel@tonic-gate 87987c478bd9Sstevel@tonic-gate if (qgrplimit != NOQGRP && qgrplimit != qgrp) 87997c478bd9Sstevel@tonic-gate continue; 88007c478bd9Sstevel@tonic-gate 88017c478bd9Sstevel@tonic-gate for (qdir = 0; qdir < Queue[qgrp]->qg_numqueues; qdir++) 88027c478bd9Sstevel@tonic-gate { 88037c478bd9Sstevel@tonic-gate int i; 88047c478bd9Sstevel@tonic-gate int nrequests; 88057c478bd9Sstevel@tonic-gate 88067c478bd9Sstevel@tonic-gate if (StopRequest) 88077c478bd9Sstevel@tonic-gate stop_sendmail(); 88087c478bd9Sstevel@tonic-gate 88097c478bd9Sstevel@tonic-gate nrequests = gatherq(qgrp, qdir, true, NULL, NULL); 88107c478bd9Sstevel@tonic-gate 88117c478bd9Sstevel@tonic-gate /* first see if there is anything */ 88127c478bd9Sstevel@tonic-gate if (nrequests <= 0) 88137c478bd9Sstevel@tonic-gate { 88147c478bd9Sstevel@tonic-gate if (Verbose) 88157c478bd9Sstevel@tonic-gate { 88167c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 88177c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, "%s: no matches\n", 88187c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 88197c478bd9Sstevel@tonic-gate } 88207c478bd9Sstevel@tonic-gate continue; 88217c478bd9Sstevel@tonic-gate } 88227c478bd9Sstevel@tonic-gate 88237c478bd9Sstevel@tonic-gate if (Verbose) 88247c478bd9Sstevel@tonic-gate { 88257c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 88267c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, "Processing %s:\n", 88277c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 88287c478bd9Sstevel@tonic-gate } 88297c478bd9Sstevel@tonic-gate 88307c478bd9Sstevel@tonic-gate for (i = 0; i < WorkListCount; i++) 88317c478bd9Sstevel@tonic-gate { 88327c478bd9Sstevel@tonic-gate ENVELOPE e; 88337c478bd9Sstevel@tonic-gate 88347c478bd9Sstevel@tonic-gate if (StopRequest) 88357c478bd9Sstevel@tonic-gate stop_sendmail(); 88367c478bd9Sstevel@tonic-gate 88377c478bd9Sstevel@tonic-gate /* setup envelope */ 88387c478bd9Sstevel@tonic-gate clearenvelope(&e, true, sm_rpool_new_x(NULL)); 88397c478bd9Sstevel@tonic-gate e.e_id = WorkList[i].w_name + 2; 88407c478bd9Sstevel@tonic-gate e.e_qgrp = qgrp; 88417c478bd9Sstevel@tonic-gate e.e_qdir = qdir; 88427c478bd9Sstevel@tonic-gate 88437c478bd9Sstevel@tonic-gate if (tTd(70, 101)) 88447c478bd9Sstevel@tonic-gate { 88457c478bd9Sstevel@tonic-gate sm_io_fprintf(smioout, SM_TIME_DEFAULT, 88467c478bd9Sstevel@tonic-gate "Would do %s\n", e.e_id); 88477c478bd9Sstevel@tonic-gate changed++; 88487c478bd9Sstevel@tonic-gate } 88497c478bd9Sstevel@tonic-gate else if (quarantine_queue_item(qgrp, qdir, 88507c478bd9Sstevel@tonic-gate &e, reason)) 88517c478bd9Sstevel@tonic-gate changed++; 88527c478bd9Sstevel@tonic-gate 88537c478bd9Sstevel@tonic-gate /* clean up */ 88547c478bd9Sstevel@tonic-gate sm_rpool_free(e.e_rpool); 88557c478bd9Sstevel@tonic-gate e.e_rpool = NULL; 88567c478bd9Sstevel@tonic-gate } 88577c478bd9Sstevel@tonic-gate if (WorkList != NULL) 88587c478bd9Sstevel@tonic-gate sm_free(WorkList); /* XXX */ 88597c478bd9Sstevel@tonic-gate WorkList = NULL; 88607c478bd9Sstevel@tonic-gate WorkListSize = 0; 88617c478bd9Sstevel@tonic-gate WorkListCount = 0; 88627c478bd9Sstevel@tonic-gate } 88637c478bd9Sstevel@tonic-gate } 88647c478bd9Sstevel@tonic-gate if (Verbose) 88657c478bd9Sstevel@tonic-gate { 88667c478bd9Sstevel@tonic-gate if (changed == 0) 88677c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 88687c478bd9Sstevel@tonic-gate "No changes\n"); 88697c478bd9Sstevel@tonic-gate else 88707c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 88717c478bd9Sstevel@tonic-gate "%d change%s\n", 88727c478bd9Sstevel@tonic-gate changed, 88737c478bd9Sstevel@tonic-gate changed == 1 ? "" : "s"); 88747c478bd9Sstevel@tonic-gate } 88757c478bd9Sstevel@tonic-gate } 8876