17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * Copyright (c) 1998-2005 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*445f2479Sjbeck SM_RCSID("@(#)$Id: queue.c,v 8.951 2006/03/02 19:13:38 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 */ 1527c478bd9Sstevel@tonic-gate static int workcmpf0(); 1537c478bd9Sstevel@tonic-gate static int workcmpf1(); 1547c478bd9Sstevel@tonic-gate static int workcmpf2(); 1557c478bd9Sstevel@tonic-gate static int workcmpf3(); 1567c478bd9Sstevel@tonic-gate static int workcmpf4(); 1577c478bd9Sstevel@tonic-gate static int randi = 3; /* index for workcmpf5() */ 1587c478bd9Sstevel@tonic-gate static int workcmpf5(); 1597c478bd9Sstevel@tonic-gate static int workcmpf6(); 1607c478bd9Sstevel@tonic-gate #if _FFR_RHS 1617c478bd9Sstevel@tonic-gate static int workcmpf7(); 1627c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate #if RANDOMSHIFT 1657c478bd9Sstevel@tonic-gate # define get_rand_mod(m) ((get_random() >> RANDOMSHIFT) % (m)) 1667c478bd9Sstevel@tonic-gate #else /* RANDOMSHIFT */ 1677c478bd9Sstevel@tonic-gate # define get_rand_mod(m) (get_random() % (m)) 1687c478bd9Sstevel@tonic-gate #endif /* RANDOMSHIFT */ 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate ** File system definition. 1727c478bd9Sstevel@tonic-gate ** Used to keep track of how much free space is available 1737c478bd9Sstevel@tonic-gate ** on a file system in which one or more queue directories reside. 1747c478bd9Sstevel@tonic-gate */ 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate typedef struct filesys_shared FILESYS; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate struct filesys_shared 1797c478bd9Sstevel@tonic-gate { 1807c478bd9Sstevel@tonic-gate dev_t fs_dev; /* unique device id */ 1817c478bd9Sstevel@tonic-gate long fs_avail; /* number of free blocks available */ 1827c478bd9Sstevel@tonic-gate long fs_blksize; /* block size, in bytes */ 1837c478bd9Sstevel@tonic-gate }; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate /* probably kept in shared memory */ 1867c478bd9Sstevel@tonic-gate static FILESYS FileSys[MAXFILESYS]; /* queue file systems */ 1877c478bd9Sstevel@tonic-gate static char *FSPath[MAXFILESYS]; /* pathnames for file systems */ 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* 1927c478bd9Sstevel@tonic-gate ** Shared memory data 1937c478bd9Sstevel@tonic-gate ** 1947c478bd9Sstevel@tonic-gate ** Current layout: 1957c478bd9Sstevel@tonic-gate ** size -- size of shared memory segment 1967c478bd9Sstevel@tonic-gate ** pid -- pid of owner, should be a unique id to avoid misinterpretations 1977c478bd9Sstevel@tonic-gate ** by other processes. 1987c478bd9Sstevel@tonic-gate ** tag -- should be a unique id to avoid misinterpretations by others. 1997c478bd9Sstevel@tonic-gate ** idea: hash over configuration data that will be stored here. 2007c478bd9Sstevel@tonic-gate ** NumFileSys -- number of file systems. 2017c478bd9Sstevel@tonic-gate ** FileSys -- (arrary of) structure for used file systems. 2027c478bd9Sstevel@tonic-gate ** RSATmpCnt -- counter for number of uses of ephemeral RSA key. 2037c478bd9Sstevel@tonic-gate ** QShm -- (array of) structure for information about queue directories. 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate /* 2077c478bd9Sstevel@tonic-gate ** Queue data in shared memory 2087c478bd9Sstevel@tonic-gate */ 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate typedef struct queue_shared QUEUE_SHM_T; 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate struct queue_shared 2137c478bd9Sstevel@tonic-gate { 2147c478bd9Sstevel@tonic-gate int qs_entries; /* number of entries */ 2157c478bd9Sstevel@tonic-gate /* XXX more to follow? */ 2167c478bd9Sstevel@tonic-gate }; 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate static void *Pshm; /* pointer to shared memory */ 2197c478bd9Sstevel@tonic-gate static FILESYS *PtrFileSys; /* pointer to queue file system array */ 2207c478bd9Sstevel@tonic-gate int ShmId = SM_SHM_NO_ID; /* shared memory id */ 2217c478bd9Sstevel@tonic-gate static QUEUE_SHM_T *QShm; /* pointer to shared queue data */ 2227c478bd9Sstevel@tonic-gate static size_t shms; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate # define SHM_OFF_PID(p) (((char *) (p)) + sizeof(int)) 2257c478bd9Sstevel@tonic-gate # define SHM_OFF_TAG(p) (((char *) (p)) + sizeof(pid_t) + sizeof(int)) 2267c478bd9Sstevel@tonic-gate # define SHM_OFF_HEAD (sizeof(pid_t) + sizeof(int) * 2) 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* how to access FileSys */ 2297c478bd9Sstevel@tonic-gate # define FILE_SYS(i) (PtrFileSys[i]) 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate /* first entry is a tag, for now just the size */ 2327c478bd9Sstevel@tonic-gate # define OFF_FILE_SYS(p) (((char *) (p)) + SHM_OFF_HEAD) 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate /* offset for PNumFileSys */ 2357c478bd9Sstevel@tonic-gate # define OFF_NUM_FILE_SYS(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys)) 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* offset for PRSATmpCnt */ 2387c478bd9Sstevel@tonic-gate # define OFF_RSA_TMP_CNT(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int)) 2397c478bd9Sstevel@tonic-gate int *PRSATmpCnt; 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate /* offset for queue_shm */ 2427c478bd9Sstevel@tonic-gate # define OFF_QUEUE_SHM(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2) 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate # define QSHM_ENTRIES(i) QShm[i].qs_entries 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* basic size of shared memory segment */ 2477c478bd9Sstevel@tonic-gate # define SM_T_SIZE (SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2) 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate static unsigned int hash_q __P((char *, unsigned int)); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate /* 2527c478bd9Sstevel@tonic-gate ** HASH_Q -- simple hash function 2537c478bd9Sstevel@tonic-gate ** 2547c478bd9Sstevel@tonic-gate ** Parameters: 2557c478bd9Sstevel@tonic-gate ** p -- string to hash. 2567c478bd9Sstevel@tonic-gate ** h -- hash start value (from previous run). 2577c478bd9Sstevel@tonic-gate ** 2587c478bd9Sstevel@tonic-gate ** Returns: 2597c478bd9Sstevel@tonic-gate ** hash value. 2607c478bd9Sstevel@tonic-gate */ 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate static unsigned int 2637c478bd9Sstevel@tonic-gate hash_q(p, h) 2647c478bd9Sstevel@tonic-gate char *p; 2657c478bd9Sstevel@tonic-gate unsigned int h; 2667c478bd9Sstevel@tonic-gate { 2677c478bd9Sstevel@tonic-gate int c, d; 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate while (*p != '\0') 2707c478bd9Sstevel@tonic-gate { 2717c478bd9Sstevel@tonic-gate d = *p++; 2727c478bd9Sstevel@tonic-gate c = d; 2737c478bd9Sstevel@tonic-gate c ^= c<<6; 2747c478bd9Sstevel@tonic-gate h += (c<<11) ^ (c>>1); 2757c478bd9Sstevel@tonic-gate h ^= (d<<14) + (d<<7) + (d<<4) + d; 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate return h; 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate #else /* SM_CONF_SHM */ 2827c478bd9Sstevel@tonic-gate # define FILE_SYS(i) FileSys[i] 2837c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate /* access to the various components of file system data */ 2867c478bd9Sstevel@tonic-gate #define FILE_SYS_NAME(i) FSPath[i] 2877c478bd9Sstevel@tonic-gate #define FILE_SYS_AVAIL(i) FILE_SYS(i).fs_avail 2887c478bd9Sstevel@tonic-gate #define FILE_SYS_BLKSIZE(i) FILE_SYS(i).fs_blksize 2897c478bd9Sstevel@tonic-gate #define FILE_SYS_DEV(i) FILE_SYS(i).fs_dev 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate /* 2937c478bd9Sstevel@tonic-gate ** Current qf file field assignments: 2947c478bd9Sstevel@tonic-gate ** 2957c478bd9Sstevel@tonic-gate ** A AUTH= parameter 2967c478bd9Sstevel@tonic-gate ** B body type 2977c478bd9Sstevel@tonic-gate ** C controlling user 2987c478bd9Sstevel@tonic-gate ** D data file name 2997c478bd9Sstevel@tonic-gate ** d data file directory name (added in 8.12) 3007c478bd9Sstevel@tonic-gate ** E error recipient 3017c478bd9Sstevel@tonic-gate ** F flag bits 3027c478bd9Sstevel@tonic-gate ** G free (was: queue delay algorithm if _FFR_QUEUEDELAY) 3037c478bd9Sstevel@tonic-gate ** H header 3047c478bd9Sstevel@tonic-gate ** I data file's inode number 3057c478bd9Sstevel@tonic-gate ** K time of last delivery attempt 3067c478bd9Sstevel@tonic-gate ** L Solaris Content-Length: header (obsolete) 3077c478bd9Sstevel@tonic-gate ** M message 3087c478bd9Sstevel@tonic-gate ** N number of delivery attempts 3097c478bd9Sstevel@tonic-gate ** P message priority 3107c478bd9Sstevel@tonic-gate ** q quarantine reason 3117c478bd9Sstevel@tonic-gate ** Q original recipient (ORCPT=) 3127c478bd9Sstevel@tonic-gate ** r final recipient (Final-Recipient: DSN field) 3137c478bd9Sstevel@tonic-gate ** R recipient 3147c478bd9Sstevel@tonic-gate ** S sender 3157c478bd9Sstevel@tonic-gate ** T init time 3167c478bd9Sstevel@tonic-gate ** V queue file version 3177c478bd9Sstevel@tonic-gate ** X free (was: character set if _FFR_SAVE_CHARSET) 3187c478bd9Sstevel@tonic-gate ** Y free (was: current delay if _FFR_QUEUEDELAY) 3197c478bd9Sstevel@tonic-gate ** Z original envelope id from ESMTP 3207c478bd9Sstevel@tonic-gate ** ! deliver by (added in 8.12) 3217c478bd9Sstevel@tonic-gate ** $ define macro 3227c478bd9Sstevel@tonic-gate ** . terminate file 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate /* 3267c478bd9Sstevel@tonic-gate ** QUEUEUP -- queue a message up for future transmission. 3277c478bd9Sstevel@tonic-gate ** 3287c478bd9Sstevel@tonic-gate ** Parameters: 3297c478bd9Sstevel@tonic-gate ** e -- the envelope to queue up. 3307c478bd9Sstevel@tonic-gate ** announce -- if true, tell when you are queueing up. 3317c478bd9Sstevel@tonic-gate ** msync -- if true, then fsync() if SuperSafe interactive mode. 3327c478bd9Sstevel@tonic-gate ** 3337c478bd9Sstevel@tonic-gate ** Returns: 3347c478bd9Sstevel@tonic-gate ** none. 3357c478bd9Sstevel@tonic-gate ** 3367c478bd9Sstevel@tonic-gate ** Side Effects: 3377c478bd9Sstevel@tonic-gate ** The current request is saved in a control file. 3387c478bd9Sstevel@tonic-gate ** The queue file is left locked. 3397c478bd9Sstevel@tonic-gate */ 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate void 3427c478bd9Sstevel@tonic-gate queueup(e, announce, msync) 3437c478bd9Sstevel@tonic-gate register ENVELOPE *e; 3447c478bd9Sstevel@tonic-gate bool announce; 3457c478bd9Sstevel@tonic-gate bool msync; 3467c478bd9Sstevel@tonic-gate { 3477c478bd9Sstevel@tonic-gate register SM_FILE_T *tfp; 3487c478bd9Sstevel@tonic-gate register HDR *h; 3497c478bd9Sstevel@tonic-gate register ADDRESS *q; 3507c478bd9Sstevel@tonic-gate int tfd = -1; 3517c478bd9Sstevel@tonic-gate int i; 3527c478bd9Sstevel@tonic-gate bool newid; 3537c478bd9Sstevel@tonic-gate register char *p; 3547c478bd9Sstevel@tonic-gate MAILER nullmailer; 3557c478bd9Sstevel@tonic-gate MCI mcibuf; 3567c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN]; 3577c478bd9Sstevel@tonic-gate char tf[MAXPATHLEN]; 3587c478bd9Sstevel@tonic-gate char df[MAXPATHLEN]; 3597c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate /* 3627c478bd9Sstevel@tonic-gate ** Create control file. 3637c478bd9Sstevel@tonic-gate */ 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate #define OPEN_TF do \ 3667c478bd9Sstevel@tonic-gate { \ 3677c478bd9Sstevel@tonic-gate MODE_T oldumask = 0; \ 3687c478bd9Sstevel@tonic-gate \ 3697c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) \ 3707c478bd9Sstevel@tonic-gate oldumask = umask(002); \ 3717c478bd9Sstevel@tonic-gate tfd = open(tf, TF_OPEN_FLAGS, QueueFileMode); \ 3727c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) \ 3737c478bd9Sstevel@tonic-gate (void) umask(oldumask); \ 3747c478bd9Sstevel@tonic-gate } while (0) 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags); 3787c478bd9Sstevel@tonic-gate (void) sm_strlcpy(tf, queuename(e, NEWQFL_LETTER), sizeof tf); 3797c478bd9Sstevel@tonic-gate tfp = e->e_lockfp; 3807c478bd9Sstevel@tonic-gate if (tfp == NULL && newid) 3817c478bd9Sstevel@tonic-gate { 3827c478bd9Sstevel@tonic-gate /* 3837c478bd9Sstevel@tonic-gate ** open qf file directly: this will give an error if the file 3847c478bd9Sstevel@tonic-gate ** already exists and hence prevent problems if a queue-id 3857c478bd9Sstevel@tonic-gate ** is reused (e.g., because the clock is set back). 3867c478bd9Sstevel@tonic-gate */ 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate (void) sm_strlcpy(tf, queuename(e, ANYQFL_LETTER), sizeof tf); 3897c478bd9Sstevel@tonic-gate OPEN_TF; 3907c478bd9Sstevel@tonic-gate if (tfd < 0 || 3917c478bd9Sstevel@tonic-gate #if !SM_OPEN_EXLOCK 3927c478bd9Sstevel@tonic-gate !lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB) || 3937c478bd9Sstevel@tonic-gate #endif /* !SM_OPEN_EXLOCK */ 3947c478bd9Sstevel@tonic-gate (tfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 3957c478bd9Sstevel@tonic-gate (void *) &tfd, SM_IO_WRONLY, 3967c478bd9Sstevel@tonic-gate NULL)) == NULL) 3977c478bd9Sstevel@tonic-gate { 3987c478bd9Sstevel@tonic-gate int save_errno = errno; 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate printopenfds(true); 4017c478bd9Sstevel@tonic-gate errno = save_errno; 4027c478bd9Sstevel@tonic-gate syserr("!queueup: cannot create queue file %s, euid=%d, fd=%d, fp=%p", 4037c478bd9Sstevel@tonic-gate tf, (int) geteuid(), tfd, tfp); 4047c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate e->e_lockfp = tfp; 4077c478bd9Sstevel@tonic-gate upd_qs(e, 1, 0, "queueup"); 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate /* if newid, write the queue file directly (instead of temp file) */ 4117c478bd9Sstevel@tonic-gate if (!newid) 4127c478bd9Sstevel@tonic-gate { 4137c478bd9Sstevel@tonic-gate /* get a locked tf file */ 4147c478bd9Sstevel@tonic-gate for (i = 0; i < 128; i++) 4157c478bd9Sstevel@tonic-gate { 4167c478bd9Sstevel@tonic-gate if (tfd < 0) 4177c478bd9Sstevel@tonic-gate { 4187c478bd9Sstevel@tonic-gate OPEN_TF; 4197c478bd9Sstevel@tonic-gate if (tfd < 0) 4207c478bd9Sstevel@tonic-gate { 4217c478bd9Sstevel@tonic-gate if (errno != EEXIST) 4227c478bd9Sstevel@tonic-gate break; 4237c478bd9Sstevel@tonic-gate if (LogLevel > 0 && (i % 32) == 0) 4247c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 4257c478bd9Sstevel@tonic-gate "queueup: cannot create %s, uid=%d: %s", 4267c478bd9Sstevel@tonic-gate tf, (int) geteuid(), 4277c478bd9Sstevel@tonic-gate sm_errstring(errno)); 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate #if SM_OPEN_EXLOCK 4307c478bd9Sstevel@tonic-gate else 4317c478bd9Sstevel@tonic-gate break; 4327c478bd9Sstevel@tonic-gate #endif /* SM_OPEN_EXLOCK */ 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate if (tfd >= 0) 4357c478bd9Sstevel@tonic-gate { 4367c478bd9Sstevel@tonic-gate #if SM_OPEN_EXLOCK 4377c478bd9Sstevel@tonic-gate /* file is locked by open() */ 4387c478bd9Sstevel@tonic-gate break; 4397c478bd9Sstevel@tonic-gate #else /* SM_OPEN_EXLOCK */ 4407c478bd9Sstevel@tonic-gate if (lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB)) 4417c478bd9Sstevel@tonic-gate break; 4427c478bd9Sstevel@tonic-gate else 4437c478bd9Sstevel@tonic-gate #endif /* SM_OPEN_EXLOCK */ 4447c478bd9Sstevel@tonic-gate if (LogLevel > 0 && (i % 32) == 0) 4457c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 4467c478bd9Sstevel@tonic-gate "queueup: cannot lock %s: %s", 4477c478bd9Sstevel@tonic-gate tf, sm_errstring(errno)); 4487c478bd9Sstevel@tonic-gate if ((i % 32) == 31) 4497c478bd9Sstevel@tonic-gate { 4507c478bd9Sstevel@tonic-gate (void) close(tfd); 4517c478bd9Sstevel@tonic-gate tfd = -1; 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate if ((i % 32) == 31) 4567c478bd9Sstevel@tonic-gate { 4577c478bd9Sstevel@tonic-gate /* save the old temp file away */ 4587c478bd9Sstevel@tonic-gate (void) rename(tf, queuename(e, TEMPQF_LETTER)); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate else 4617c478bd9Sstevel@tonic-gate (void) sleep(i % 32); 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate if (tfd < 0 || (tfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 4647c478bd9Sstevel@tonic-gate (void *) &tfd, SM_IO_WRONLY_B, 4657c478bd9Sstevel@tonic-gate NULL)) == NULL) 4667c478bd9Sstevel@tonic-gate { 4677c478bd9Sstevel@tonic-gate int save_errno = errno; 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate printopenfds(true); 4707c478bd9Sstevel@tonic-gate errno = save_errno; 4717c478bd9Sstevel@tonic-gate syserr("!queueup: cannot create queue temp file %s, uid=%d", 4727c478bd9Sstevel@tonic-gate tf, (int) geteuid()); 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 4777c478bd9Sstevel@tonic-gate sm_dprintf("\n>>>>> queueing %s/%s%s >>>>>\n", 4787c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir), 4797c478bd9Sstevel@tonic-gate queuename(e, ANYQFL_LETTER), 4807c478bd9Sstevel@tonic-gate newid ? " (new id)" : ""); 4817c478bd9Sstevel@tonic-gate if (tTd(40, 3)) 4827c478bd9Sstevel@tonic-gate { 4837c478bd9Sstevel@tonic-gate sm_dprintf(" e_flags="); 4847c478bd9Sstevel@tonic-gate printenvflags(e); 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate if (tTd(40, 32)) 4877c478bd9Sstevel@tonic-gate { 4887c478bd9Sstevel@tonic-gate sm_dprintf(" sendq="); 4897c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), e->e_sendqueue, true); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate if (tTd(40, 9)) 4927c478bd9Sstevel@tonic-gate { 4937c478bd9Sstevel@tonic-gate sm_dprintf(" tfp="); 4947c478bd9Sstevel@tonic-gate dumpfd(sm_io_getinfo(tfp, SM_IO_WHAT_FD, NULL), true, false); 4957c478bd9Sstevel@tonic-gate sm_dprintf(" lockfp="); 4967c478bd9Sstevel@tonic-gate if (e->e_lockfp == NULL) 4977c478bd9Sstevel@tonic-gate sm_dprintf("NULL\n"); 4987c478bd9Sstevel@tonic-gate else 4997c478bd9Sstevel@tonic-gate dumpfd(sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL), 5007c478bd9Sstevel@tonic-gate true, false); 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate /* 5047c478bd9Sstevel@tonic-gate ** If there is no data file yet, create one. 5057c478bd9Sstevel@tonic-gate */ 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate (void) sm_strlcpy(df, queuename(e, DATAFL_LETTER), sizeof df); 5087c478bd9Sstevel@tonic-gate if (bitset(EF_HAS_DF, e->e_flags)) 5097c478bd9Sstevel@tonic-gate { 5107c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL && 5117c478bd9Sstevel@tonic-gate SuperSafe != SAFE_REALLY && 5127c478bd9Sstevel@tonic-gate SuperSafe != SAFE_REALLY_POSTMILTER && 5137c478bd9Sstevel@tonic-gate sm_io_setinfo(e->e_dfp, SM_BF_COMMIT, NULL) < 0 && 5147c478bd9Sstevel@tonic-gate errno != EINVAL) 5157c478bd9Sstevel@tonic-gate { 5167c478bd9Sstevel@tonic-gate syserr("!queueup: cannot commit data file %s, uid=%d", 5177c478bd9Sstevel@tonic-gate queuename(e, DATAFL_LETTER), (int) geteuid()); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL && 5207c478bd9Sstevel@tonic-gate SuperSafe == SAFE_INTERACTIVE && msync) 5217c478bd9Sstevel@tonic-gate { 5227c478bd9Sstevel@tonic-gate if (tTd(40,32)) 5237c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 5247c478bd9Sstevel@tonic-gate "queueup: fsync(e->e_dfp)"); 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate if (fsync(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, 5277c478bd9Sstevel@tonic-gate NULL)) < 0) 5287c478bd9Sstevel@tonic-gate { 5297c478bd9Sstevel@tonic-gate if (newid) 5307c478bd9Sstevel@tonic-gate syserr("!552 Error writing data file %s", 5317c478bd9Sstevel@tonic-gate df); 5327c478bd9Sstevel@tonic-gate else 5337c478bd9Sstevel@tonic-gate syserr("!452 Error writing data file %s", 5347c478bd9Sstevel@tonic-gate df); 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate else 5397c478bd9Sstevel@tonic-gate { 5407c478bd9Sstevel@tonic-gate int dfd; 5417c478bd9Sstevel@tonic-gate MODE_T oldumask = 0; 5427c478bd9Sstevel@tonic-gate register SM_FILE_T *dfp = NULL; 5437c478bd9Sstevel@tonic-gate struct stat stbuf; 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL && 5467c478bd9Sstevel@tonic-gate sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE)) 5477c478bd9Sstevel@tonic-gate syserr("committing over bf file"); 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 5507c478bd9Sstevel@tonic-gate oldumask = umask(002); 5517c478bd9Sstevel@tonic-gate dfd = open(df, O_WRONLY|O_CREAT|O_TRUNC|QF_O_EXTRA, 5527c478bd9Sstevel@tonic-gate QueueFileMode); 5537c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 5547c478bd9Sstevel@tonic-gate (void) umask(oldumask); 5557c478bd9Sstevel@tonic-gate if (dfd < 0 || (dfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 5567c478bd9Sstevel@tonic-gate (void *) &dfd, SM_IO_WRONLY_B, 5577c478bd9Sstevel@tonic-gate NULL)) == NULL) 5587c478bd9Sstevel@tonic-gate syserr("!queueup: cannot create data temp file %s, uid=%d", 5597c478bd9Sstevel@tonic-gate df, (int) geteuid()); 5607c478bd9Sstevel@tonic-gate if (fstat(dfd, &stbuf) < 0) 5617c478bd9Sstevel@tonic-gate e->e_dfino = -1; 5627c478bd9Sstevel@tonic-gate else 5637c478bd9Sstevel@tonic-gate { 5647c478bd9Sstevel@tonic-gate e->e_dfdev = stbuf.st_dev; 5657c478bd9Sstevel@tonic-gate e->e_dfino = ST_INODE(stbuf); 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS_DF; 5687c478bd9Sstevel@tonic-gate memset(&mcibuf, '\0', sizeof mcibuf); 5697c478bd9Sstevel@tonic-gate mcibuf.mci_out = dfp; 5707c478bd9Sstevel@tonic-gate mcibuf.mci_mailer = FileMailer; 5717c478bd9Sstevel@tonic-gate (*e->e_putbody)(&mcibuf, e, NULL); 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate if (SuperSafe == SAFE_REALLY || 5747c478bd9Sstevel@tonic-gate SuperSafe == SAFE_REALLY_POSTMILTER || 5757c478bd9Sstevel@tonic-gate (SuperSafe == SAFE_INTERACTIVE && msync)) 5767c478bd9Sstevel@tonic-gate { 5777c478bd9Sstevel@tonic-gate if (tTd(40,32)) 5787c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 5797c478bd9Sstevel@tonic-gate "queueup: fsync(dfp)"); 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate if (fsync(sm_io_getinfo(dfp, SM_IO_WHAT_FD, NULL)) < 0) 5827c478bd9Sstevel@tonic-gate { 5837c478bd9Sstevel@tonic-gate if (newid) 5847c478bd9Sstevel@tonic-gate syserr("!552 Error writing data file %s", 5857c478bd9Sstevel@tonic-gate df); 5867c478bd9Sstevel@tonic-gate else 5877c478bd9Sstevel@tonic-gate syserr("!452 Error writing data file %s", 5887c478bd9Sstevel@tonic-gate df); 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate if (sm_io_close(dfp, SM_TIME_DEFAULT) < 0) 5937c478bd9Sstevel@tonic-gate syserr("!queueup: cannot save data temp file %s, uid=%d", 5947c478bd9Sstevel@tonic-gate df, (int) geteuid()); 5957c478bd9Sstevel@tonic-gate e->e_putbody = putbody; 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate /* 5997c478bd9Sstevel@tonic-gate ** Output future work requests. 6007c478bd9Sstevel@tonic-gate ** Priority and creation time should be first, since 6017c478bd9Sstevel@tonic-gate ** they are required by gatherq. 6027c478bd9Sstevel@tonic-gate */ 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate /* output queue version number (must be first!) */ 6057c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "V%d\n", QF_VERSION); 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate /* output creation time */ 6087c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "T%ld\n", (long) e->e_ctime); 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate /* output last delivery time */ 6117c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "K%ld\n", (long) e->e_dtime); 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate /* output number of delivery attempts */ 6147c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "N%d\n", e->e_ntries); 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate /* output message priority */ 6177c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "P%ld\n", e->e_msgpriority); 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate /* 6207c478bd9Sstevel@tonic-gate ** If data file is in a different directory than the queue file, 6217c478bd9Sstevel@tonic-gate ** output a "d" record naming the directory of the data file. 6227c478bd9Sstevel@tonic-gate */ 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate if (e->e_dfqgrp != e->e_qgrp) 6257c478bd9Sstevel@tonic-gate { 6267c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "d%s\n", 6277c478bd9Sstevel@tonic-gate Queue[e->e_dfqgrp]->qg_qpaths[e->e_dfqdir].qp_name); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate /* output inode number of data file */ 6317c478bd9Sstevel@tonic-gate /* XXX should probably include device major/minor too */ 6327c478bd9Sstevel@tonic-gate if (e->e_dfino != -1) 6337c478bd9Sstevel@tonic-gate { 6347c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "I%ld/%ld/%llu\n", 6357c478bd9Sstevel@tonic-gate (long) major(e->e_dfdev), 6367c478bd9Sstevel@tonic-gate (long) minor(e->e_dfdev), 6377c478bd9Sstevel@tonic-gate (ULONGLONG_T) e->e_dfino); 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /* output body type */ 6417c478bd9Sstevel@tonic-gate if (e->e_bodytype != NULL) 6427c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "B%s\n", 6437c478bd9Sstevel@tonic-gate denlstring(e->e_bodytype, true, false)); 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate /* quarantine reason */ 6467c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 6477c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "q%s\n", 6487c478bd9Sstevel@tonic-gate denlstring(e->e_quarmsg, true, false)); 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate /* message from envelope, if it exists */ 6517c478bd9Sstevel@tonic-gate if (e->e_message != NULL) 6527c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "M%s\n", 6537c478bd9Sstevel@tonic-gate denlstring(e->e_message, true, false)); 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /* send various flag bits through */ 6567c478bd9Sstevel@tonic-gate p = buf; 6577c478bd9Sstevel@tonic-gate if (bitset(EF_WARNING, e->e_flags)) 6587c478bd9Sstevel@tonic-gate *p++ = 'w'; 6597c478bd9Sstevel@tonic-gate if (bitset(EF_RESPONSE, e->e_flags)) 6607c478bd9Sstevel@tonic-gate *p++ = 'r'; 6617c478bd9Sstevel@tonic-gate if (bitset(EF_HAS8BIT, e->e_flags)) 6627c478bd9Sstevel@tonic-gate *p++ = '8'; 6637c478bd9Sstevel@tonic-gate if (bitset(EF_DELETE_BCC, e->e_flags)) 6647c478bd9Sstevel@tonic-gate *p++ = 'b'; 6657c478bd9Sstevel@tonic-gate if (bitset(EF_RET_PARAM, e->e_flags)) 6667c478bd9Sstevel@tonic-gate *p++ = 'd'; 6677c478bd9Sstevel@tonic-gate if (bitset(EF_NO_BODY_RETN, e->e_flags)) 6687c478bd9Sstevel@tonic-gate *p++ = 'n'; 6697c478bd9Sstevel@tonic-gate if (bitset(EF_SPLIT, e->e_flags)) 6707c478bd9Sstevel@tonic-gate *p++ = 's'; 6717c478bd9Sstevel@tonic-gate *p++ = '\0'; 6727c478bd9Sstevel@tonic-gate if (buf[0] != '\0') 6737c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "F%s\n", buf); 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate /* save $={persistentMacros} macro values */ 6767c478bd9Sstevel@tonic-gate queueup_macros(macid("{persistentMacros}"), tfp, e); 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate /* output name of sender */ 6797c478bd9Sstevel@tonic-gate if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 6807c478bd9Sstevel@tonic-gate p = e->e_sender; 6817c478bd9Sstevel@tonic-gate else 6827c478bd9Sstevel@tonic-gate p = e->e_from.q_paddr; 6837c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "S%s\n", 6847c478bd9Sstevel@tonic-gate denlstring(p, true, false)); 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate /* output ESMTP-supplied "original" information */ 6877c478bd9Sstevel@tonic-gate if (e->e_envid != NULL) 6887c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Z%s\n", 6897c478bd9Sstevel@tonic-gate denlstring(e->e_envid, true, false)); 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* output AUTH= parameter */ 6927c478bd9Sstevel@tonic-gate if (e->e_auth_param != NULL) 6937c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "A%s\n", 6947c478bd9Sstevel@tonic-gate denlstring(e->e_auth_param, true, false)); 6957c478bd9Sstevel@tonic-gate if (e->e_dlvr_flag != 0) 6967c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "!%c %ld\n", 6977c478bd9Sstevel@tonic-gate (char) e->e_dlvr_flag, e->e_deliver_by); 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate /* output list of recipient addresses */ 7007c478bd9Sstevel@tonic-gate printctladdr(NULL, NULL); 7017c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 7027c478bd9Sstevel@tonic-gate { 7037c478bd9Sstevel@tonic-gate if (!QS_IS_UNDELIVERED(q->q_state)) 7047c478bd9Sstevel@tonic-gate continue; 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate /* message for this recipient, if it exists */ 7077c478bd9Sstevel@tonic-gate if (q->q_message != NULL) 7087c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "M%s\n", 7097c478bd9Sstevel@tonic-gate denlstring(q->q_message, true, 7107c478bd9Sstevel@tonic-gate false)); 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate printctladdr(q, tfp); 7137c478bd9Sstevel@tonic-gate if (q->q_orcpt != NULL) 7147c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Q%s\n", 7157c478bd9Sstevel@tonic-gate denlstring(q->q_orcpt, true, 7167c478bd9Sstevel@tonic-gate false)); 7177c478bd9Sstevel@tonic-gate if (q->q_finalrcpt != NULL) 7187c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "r%s\n", 7197c478bd9Sstevel@tonic-gate denlstring(q->q_finalrcpt, true, 7207c478bd9Sstevel@tonic-gate false)); 7217c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'R'); 7227c478bd9Sstevel@tonic-gate if (bitset(QPRIMARY, q->q_flags)) 7237c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'P'); 7247c478bd9Sstevel@tonic-gate if (bitset(QHASNOTIFY, q->q_flags)) 7257c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'N'); 7267c478bd9Sstevel@tonic-gate if (bitset(QPINGONSUCCESS, q->q_flags)) 7277c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'S'); 7287c478bd9Sstevel@tonic-gate if (bitset(QPINGONFAILURE, q->q_flags)) 7297c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'F'); 7307c478bd9Sstevel@tonic-gate if (bitset(QPINGONDELAY, q->q_flags)) 7317c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'D'); 7327c478bd9Sstevel@tonic-gate if (q->q_alias != NULL && 7337c478bd9Sstevel@tonic-gate bitset(QALIAS, q->q_alias->q_flags)) 7347c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'A'); 7357c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, ':'); 7367c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s\n", 7377c478bd9Sstevel@tonic-gate denlstring(q->q_paddr, true, false)); 7387c478bd9Sstevel@tonic-gate if (announce) 7397c478bd9Sstevel@tonic-gate { 7407c478bd9Sstevel@tonic-gate char *tag = "queued"; 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 7437c478bd9Sstevel@tonic-gate tag = "quarantined"; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate e->e_to = q->q_paddr; 7467c478bd9Sstevel@tonic-gate message(tag); 7477c478bd9Sstevel@tonic-gate if (LogLevel > 8) 7487c478bd9Sstevel@tonic-gate logdelivery(q->q_mailer, NULL, q->q_status, 7497c478bd9Sstevel@tonic-gate tag, NULL, (time_t) 0, e); 7507c478bd9Sstevel@tonic-gate e->e_to = NULL; 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 7537c478bd9Sstevel@tonic-gate { 7547c478bd9Sstevel@tonic-gate sm_dprintf("queueing "); 7557c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), q, false); 7567c478bd9Sstevel@tonic-gate } 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate /* 7607c478bd9Sstevel@tonic-gate ** Output headers for this message. 7617c478bd9Sstevel@tonic-gate ** Expand macros completely here. Queue run will deal with 7627c478bd9Sstevel@tonic-gate ** everything as absolute headers. 7637c478bd9Sstevel@tonic-gate ** All headers that must be relative to the recipient 7647c478bd9Sstevel@tonic-gate ** can be cracked later. 7657c478bd9Sstevel@tonic-gate ** We set up a "null mailer" -- i.e., a mailer that will have 7667c478bd9Sstevel@tonic-gate ** no effect on the addresses as they are output. 7677c478bd9Sstevel@tonic-gate */ 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate memset((char *) &nullmailer, '\0', sizeof nullmailer); 7707c478bd9Sstevel@tonic-gate nullmailer.m_re_rwset = nullmailer.m_rh_rwset = 7717c478bd9Sstevel@tonic-gate nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1; 7727c478bd9Sstevel@tonic-gate nullmailer.m_eol = "\n"; 7737c478bd9Sstevel@tonic-gate memset(&mcibuf, '\0', sizeof mcibuf); 7747c478bd9Sstevel@tonic-gate mcibuf.mci_mailer = &nullmailer; 7757c478bd9Sstevel@tonic-gate mcibuf.mci_out = tfp; 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'g', "\201f"); 7787c478bd9Sstevel@tonic-gate for (h = e->e_header; h != NULL; h = h->h_link) 7797c478bd9Sstevel@tonic-gate { 7807c478bd9Sstevel@tonic-gate if (h->h_value == NULL) 7817c478bd9Sstevel@tonic-gate continue; 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate /* don't output resent headers on non-resent messages */ 7847c478bd9Sstevel@tonic-gate if (bitset(H_RESENT, h->h_flags) && 7857c478bd9Sstevel@tonic-gate !bitset(EF_RESENT, e->e_flags)) 7867c478bd9Sstevel@tonic-gate continue; 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate /* expand macros; if null, don't output header at all */ 7897c478bd9Sstevel@tonic-gate if (bitset(H_DEFAULT, h->h_flags)) 7907c478bd9Sstevel@tonic-gate { 7917c478bd9Sstevel@tonic-gate (void) expand(h->h_value, buf, sizeof buf, e); 7927c478bd9Sstevel@tonic-gate if (buf[0] == '\0') 7937c478bd9Sstevel@tonic-gate continue; 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate /* output this header */ 7977c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "H?"); 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate /* output conditional macro if present */ 8007c478bd9Sstevel@tonic-gate if (h->h_macro != '\0') 8017c478bd9Sstevel@tonic-gate { 8027c478bd9Sstevel@tonic-gate if (bitset(0200, h->h_macro)) 8037c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, 8047c478bd9Sstevel@tonic-gate "${%s}", 8057c478bd9Sstevel@tonic-gate macname(bitidx(h->h_macro))); 8067c478bd9Sstevel@tonic-gate else 8077c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, 8087c478bd9Sstevel@tonic-gate "$%c", h->h_macro); 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate else if (!bitzerop(h->h_mflags) && 8117c478bd9Sstevel@tonic-gate bitset(H_CHECK|H_ACHECK, h->h_flags)) 8127c478bd9Sstevel@tonic-gate { 8137c478bd9Sstevel@tonic-gate int j; 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate /* if conditional, output the set of conditions */ 8167c478bd9Sstevel@tonic-gate for (j = '\0'; j <= '\177'; j++) 8177c478bd9Sstevel@tonic-gate if (bitnset(j, h->h_mflags)) 8187c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 8197c478bd9Sstevel@tonic-gate j); 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, '?'); 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate /* output the header: expand macros, convert addresses */ 8247c478bd9Sstevel@tonic-gate if (bitset(H_DEFAULT, h->h_flags) && 8257c478bd9Sstevel@tonic-gate !bitset(H_BINDLATE, h->h_flags)) 8267c478bd9Sstevel@tonic-gate { 8277c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s: %s\n", 8287c478bd9Sstevel@tonic-gate h->h_field, 8297c478bd9Sstevel@tonic-gate denlstring(buf, false, true)); 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate else if (bitset(H_FROM|H_RCPT, h->h_flags) && 8327c478bd9Sstevel@tonic-gate !bitset(H_BINDLATE, h->h_flags)) 8337c478bd9Sstevel@tonic-gate { 8347c478bd9Sstevel@tonic-gate bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 8357c478bd9Sstevel@tonic-gate SM_FILE_T *savetrace = TrafficLogFile; 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate TrafficLogFile = NULL; 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate if (bitset(H_FROM, h->h_flags)) 8407c478bd9Sstevel@tonic-gate oldstyle = false; 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate commaize(h, h->h_value, oldstyle, &mcibuf, e); 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate TrafficLogFile = savetrace; 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate else 8477c478bd9Sstevel@tonic-gate { 8487c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s: %s\n", 8497c478bd9Sstevel@tonic-gate h->h_field, 8507c478bd9Sstevel@tonic-gate denlstring(h->h_value, false, 8517c478bd9Sstevel@tonic-gate true)); 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate /* 8567c478bd9Sstevel@tonic-gate ** Clean up. 8577c478bd9Sstevel@tonic-gate ** 8587c478bd9Sstevel@tonic-gate ** Write a terminator record -- this is to prevent 8597c478bd9Sstevel@tonic-gate ** scurrilous crackers from appending any data. 8607c478bd9Sstevel@tonic-gate */ 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, ".\n"); 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate if (sm_io_flush(tfp, SM_TIME_DEFAULT) != 0 || 8657c478bd9Sstevel@tonic-gate ((SuperSafe == SAFE_REALLY || 8667c478bd9Sstevel@tonic-gate SuperSafe == SAFE_REALLY_POSTMILTER || 8677c478bd9Sstevel@tonic-gate (SuperSafe == SAFE_INTERACTIVE && msync)) && 8687c478bd9Sstevel@tonic-gate fsync(sm_io_getinfo(tfp, SM_IO_WHAT_FD, NULL)) < 0) || 8697c478bd9Sstevel@tonic-gate sm_io_error(tfp)) 8707c478bd9Sstevel@tonic-gate { 8717c478bd9Sstevel@tonic-gate if (newid) 8727c478bd9Sstevel@tonic-gate syserr("!552 Error writing control file %s", tf); 8737c478bd9Sstevel@tonic-gate else 8747c478bd9Sstevel@tonic-gate syserr("!452 Error writing control file %s", tf); 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate if (!newid) 8787c478bd9Sstevel@tonic-gate { 8797c478bd9Sstevel@tonic-gate char new = queue_letter(e, ANYQFL_LETTER); 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate /* rename (locked) tf to be (locked) [qh]f */ 8827c478bd9Sstevel@tonic-gate (void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER), 8837c478bd9Sstevel@tonic-gate sizeof qf); 8847c478bd9Sstevel@tonic-gate if (rename(tf, qf) < 0) 8857c478bd9Sstevel@tonic-gate syserr("cannot rename(%s, %s), uid=%d", 8867c478bd9Sstevel@tonic-gate tf, qf, (int) geteuid()); 8877c478bd9Sstevel@tonic-gate else 8887c478bd9Sstevel@tonic-gate { 8897c478bd9Sstevel@tonic-gate /* 8907c478bd9Sstevel@tonic-gate ** Check if type has changed and only 8917c478bd9Sstevel@tonic-gate ** remove the old item if the rename above 8927c478bd9Sstevel@tonic-gate ** succeeded. 8937c478bd9Sstevel@tonic-gate */ 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate if (e->e_qfletter != '\0' && 8967c478bd9Sstevel@tonic-gate e->e_qfletter != new) 8977c478bd9Sstevel@tonic-gate { 8987c478bd9Sstevel@tonic-gate if (tTd(40, 5)) 8997c478bd9Sstevel@tonic-gate { 9007c478bd9Sstevel@tonic-gate sm_dprintf("type changed from %c to %c\n", 9017c478bd9Sstevel@tonic-gate e->e_qfletter, new); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate if (unlink(queuename(e, e->e_qfletter)) < 0) 9057c478bd9Sstevel@tonic-gate { 9067c478bd9Sstevel@tonic-gate /* XXX: something more drastic? */ 9077c478bd9Sstevel@tonic-gate if (LogLevel > 0) 9087c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 9097c478bd9Sstevel@tonic-gate "queueup: unlink(%s) failed: %s", 9107c478bd9Sstevel@tonic-gate queuename(e, e->e_qfletter), 9117c478bd9Sstevel@tonic-gate sm_errstring(errno)); 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate } 9157c478bd9Sstevel@tonic-gate e->e_qfletter = new; 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate /* 9187c478bd9Sstevel@tonic-gate ** fsync() after renaming to make sure metadata is 9197c478bd9Sstevel@tonic-gate ** written to disk on filesystems in which renames are 9207c478bd9Sstevel@tonic-gate ** not guaranteed. 9217c478bd9Sstevel@tonic-gate */ 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate if (SuperSafe != SAFE_NO) 9247c478bd9Sstevel@tonic-gate { 9257c478bd9Sstevel@tonic-gate /* for softupdates */ 9267c478bd9Sstevel@tonic-gate if (tfd >= 0 && fsync(tfd) < 0) 9277c478bd9Sstevel@tonic-gate { 9287c478bd9Sstevel@tonic-gate syserr("!queueup: cannot fsync queue temp file %s", 9297c478bd9Sstevel@tonic-gate tf); 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate SYNC_DIR(qf, true); 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate /* close and unlock old (locked) queue file */ 9357c478bd9Sstevel@tonic-gate if (e->e_lockfp != NULL) 9367c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT); 9377c478bd9Sstevel@tonic-gate e->e_lockfp = tfp; 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate /* save log info */ 9407c478bd9Sstevel@tonic-gate if (LogLevel > 79) 9417c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "queueup %s", qf); 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate else 9447c478bd9Sstevel@tonic-gate { 9457c478bd9Sstevel@tonic-gate /* save log info */ 9467c478bd9Sstevel@tonic-gate if (LogLevel > 79) 9477c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "queueup %s", tf); 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate e->e_qfletter = queue_letter(e, ANYQFL_LETTER); 9507c478bd9Sstevel@tonic-gate } 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate errno = 0; 9537c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE; 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 9567c478bd9Sstevel@tonic-gate sm_dprintf("<<<<< done queueing %s <<<<<\n\n", e->e_id); 9577c478bd9Sstevel@tonic-gate return; 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate /* 9617c478bd9Sstevel@tonic-gate ** PRINTCTLADDR -- print control address to file. 9627c478bd9Sstevel@tonic-gate ** 9637c478bd9Sstevel@tonic-gate ** Parameters: 9647c478bd9Sstevel@tonic-gate ** a -- address. 9657c478bd9Sstevel@tonic-gate ** tfp -- file pointer. 9667c478bd9Sstevel@tonic-gate ** 9677c478bd9Sstevel@tonic-gate ** Returns: 9687c478bd9Sstevel@tonic-gate ** none. 9697c478bd9Sstevel@tonic-gate ** 9707c478bd9Sstevel@tonic-gate ** Side Effects: 9717c478bd9Sstevel@tonic-gate ** The control address (if changed) is printed to the file. 9727c478bd9Sstevel@tonic-gate ** The last control address and uid are saved. 9737c478bd9Sstevel@tonic-gate */ 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate static void 9767c478bd9Sstevel@tonic-gate printctladdr(a, tfp) 9777c478bd9Sstevel@tonic-gate register ADDRESS *a; 9787c478bd9Sstevel@tonic-gate SM_FILE_T *tfp; 9797c478bd9Sstevel@tonic-gate { 9807c478bd9Sstevel@tonic-gate char *user; 9817c478bd9Sstevel@tonic-gate register ADDRESS *q; 9827c478bd9Sstevel@tonic-gate uid_t uid; 9837c478bd9Sstevel@tonic-gate gid_t gid; 9847c478bd9Sstevel@tonic-gate static ADDRESS *lastctladdr = NULL; 9857c478bd9Sstevel@tonic-gate static uid_t lastuid; 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate /* initialization */ 9887c478bd9Sstevel@tonic-gate if (a == NULL || a->q_alias == NULL || tfp == NULL) 9897c478bd9Sstevel@tonic-gate { 9907c478bd9Sstevel@tonic-gate if (lastctladdr != NULL && tfp != NULL) 9917c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C\n"); 9927c478bd9Sstevel@tonic-gate lastctladdr = NULL; 9937c478bd9Sstevel@tonic-gate lastuid = 0; 9947c478bd9Sstevel@tonic-gate return; 9957c478bd9Sstevel@tonic-gate } 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate /* find the active uid */ 9987c478bd9Sstevel@tonic-gate q = getctladdr(a); 9997c478bd9Sstevel@tonic-gate if (q == NULL) 10007c478bd9Sstevel@tonic-gate { 10017c478bd9Sstevel@tonic-gate user = NULL; 10027c478bd9Sstevel@tonic-gate uid = 0; 10037c478bd9Sstevel@tonic-gate gid = 0; 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate else 10067c478bd9Sstevel@tonic-gate { 10077c478bd9Sstevel@tonic-gate user = q->q_ruser != NULL ? q->q_ruser : q->q_user; 10087c478bd9Sstevel@tonic-gate uid = q->q_uid; 10097c478bd9Sstevel@tonic-gate gid = q->q_gid; 10107c478bd9Sstevel@tonic-gate } 10117c478bd9Sstevel@tonic-gate a = a->q_alias; 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate /* check to see if this is the same as last time */ 10147c478bd9Sstevel@tonic-gate if (lastctladdr != NULL && uid == lastuid && 10157c478bd9Sstevel@tonic-gate strcmp(lastctladdr->q_paddr, a->q_paddr) == 0) 10167c478bd9Sstevel@tonic-gate return; 10177c478bd9Sstevel@tonic-gate lastuid = uid; 10187c478bd9Sstevel@tonic-gate lastctladdr = a; 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate if (uid == 0 || user == NULL || user[0] == '\0') 10217c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C"); 10227c478bd9Sstevel@tonic-gate else 10237c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C%s:%ld:%ld", 10247c478bd9Sstevel@tonic-gate denlstring(user, true, false), (long) uid, 10257c478bd9Sstevel@tonic-gate (long) gid); 10267c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, ":%s\n", 10277c478bd9Sstevel@tonic-gate denlstring(a->q_paddr, true, false)); 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate /* 10317c478bd9Sstevel@tonic-gate ** RUNNERS_SIGTERM -- propagate a SIGTERM to queue runner process 10327c478bd9Sstevel@tonic-gate ** 10337c478bd9Sstevel@tonic-gate ** This propagates the signal to the child processes that are queue 10347c478bd9Sstevel@tonic-gate ** runners. This is for a queue runner "cleanup". After all of the 10357c478bd9Sstevel@tonic-gate ** child queue runner processes are signaled (it should be SIGTERM 10367c478bd9Sstevel@tonic-gate ** being the sig) then the old signal handler (Oldsh) is called 10377c478bd9Sstevel@tonic-gate ** to handle any cleanup set for this process (provided it is not 10387c478bd9Sstevel@tonic-gate ** SIG_DFL or SIG_IGN). The signal may not be handled immediately 10397c478bd9Sstevel@tonic-gate ** if the BlockOldsh flag is set. If the current process doesn't 10407c478bd9Sstevel@tonic-gate ** have a parent then handle the signal immediately, regardless of 10417c478bd9Sstevel@tonic-gate ** BlockOldsh. 10427c478bd9Sstevel@tonic-gate ** 10437c478bd9Sstevel@tonic-gate ** Parameters: 10447c478bd9Sstevel@tonic-gate ** sig -- the signal number being sent 10457c478bd9Sstevel@tonic-gate ** 10467c478bd9Sstevel@tonic-gate ** Returns: 10477c478bd9Sstevel@tonic-gate ** none. 10487c478bd9Sstevel@tonic-gate ** 10497c478bd9Sstevel@tonic-gate ** Side Effects: 10507c478bd9Sstevel@tonic-gate ** Sets the NoMoreRunners boolean to true to stop more runners 10517c478bd9Sstevel@tonic-gate ** from being started in runqueue(). 10527c478bd9Sstevel@tonic-gate ** 10537c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 10547c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 10557c478bd9Sstevel@tonic-gate ** DOING. 10567c478bd9Sstevel@tonic-gate */ 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate static bool volatile NoMoreRunners = false; 10597c478bd9Sstevel@tonic-gate static sigfunc_t Oldsh_term = SIG_DFL; 10607c478bd9Sstevel@tonic-gate static sigfunc_t Oldsh_hup = SIG_DFL; 10617c478bd9Sstevel@tonic-gate static sigfunc_t volatile Oldsh = SIG_DFL; 10627c478bd9Sstevel@tonic-gate static bool BlockOldsh = false; 10637c478bd9Sstevel@tonic-gate static int volatile Oldsig = 0; 10647c478bd9Sstevel@tonic-gate static SIGFUNC_DECL runners_sigterm __P((int)); 10657c478bd9Sstevel@tonic-gate static SIGFUNC_DECL runners_sighup __P((int)); 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate static SIGFUNC_DECL 10687c478bd9Sstevel@tonic-gate runners_sigterm(sig) 10697c478bd9Sstevel@tonic-gate int sig; 10707c478bd9Sstevel@tonic-gate { 10717c478bd9Sstevel@tonic-gate int save_errno = errno; 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, runners_sigterm); 10747c478bd9Sstevel@tonic-gate errno = save_errno; 10757c478bd9Sstevel@tonic-gate CHECK_CRITICAL(sig); 10767c478bd9Sstevel@tonic-gate NoMoreRunners = true; 10777c478bd9Sstevel@tonic-gate Oldsh = Oldsh_term; 10787c478bd9Sstevel@tonic-gate Oldsig = sig; 10797c478bd9Sstevel@tonic-gate proc_list_signal(PROC_QUEUE, sig); 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate if (!BlockOldsh || getppid() <= 1) 10827c478bd9Sstevel@tonic-gate { 10837c478bd9Sstevel@tonic-gate /* Check that a valid 'old signal handler' is callable */ 10847c478bd9Sstevel@tonic-gate if (Oldsh_term != SIG_DFL && Oldsh_term != SIG_IGN && 10857c478bd9Sstevel@tonic-gate Oldsh_term != runners_sigterm) 10867c478bd9Sstevel@tonic-gate (*Oldsh_term)(sig); 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate errno = save_errno; 10897c478bd9Sstevel@tonic-gate return SIGFUNC_RETURN; 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate /* 10927c478bd9Sstevel@tonic-gate ** RUNNERS_SIGHUP -- propagate a SIGHUP to queue runner process 10937c478bd9Sstevel@tonic-gate ** 10947c478bd9Sstevel@tonic-gate ** This propagates the signal to the child processes that are queue 10957c478bd9Sstevel@tonic-gate ** runners. This is for a queue runner "cleanup". After all of the 10967c478bd9Sstevel@tonic-gate ** child queue runner processes are signaled (it should be SIGHUP 10977c478bd9Sstevel@tonic-gate ** being the sig) then the old signal handler (Oldsh) is called to 10987c478bd9Sstevel@tonic-gate ** handle any cleanup set for this process (provided it is not SIG_DFL 10997c478bd9Sstevel@tonic-gate ** or SIG_IGN). The signal may not be handled immediately if the 11007c478bd9Sstevel@tonic-gate ** BlockOldsh flag is set. If the current process doesn't have 11017c478bd9Sstevel@tonic-gate ** a parent then handle the signal immediately, regardless of 11027c478bd9Sstevel@tonic-gate ** BlockOldsh. 11037c478bd9Sstevel@tonic-gate ** 11047c478bd9Sstevel@tonic-gate ** Parameters: 11057c478bd9Sstevel@tonic-gate ** sig -- the signal number being sent 11067c478bd9Sstevel@tonic-gate ** 11077c478bd9Sstevel@tonic-gate ** Returns: 11087c478bd9Sstevel@tonic-gate ** none. 11097c478bd9Sstevel@tonic-gate ** 11107c478bd9Sstevel@tonic-gate ** Side Effects: 11117c478bd9Sstevel@tonic-gate ** Sets the NoMoreRunners boolean to true to stop more runners 11127c478bd9Sstevel@tonic-gate ** from being started in runqueue(). 11137c478bd9Sstevel@tonic-gate ** 11147c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 11157c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 11167c478bd9Sstevel@tonic-gate ** DOING. 11177c478bd9Sstevel@tonic-gate */ 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate static SIGFUNC_DECL 11207c478bd9Sstevel@tonic-gate runners_sighup(sig) 11217c478bd9Sstevel@tonic-gate int sig; 11227c478bd9Sstevel@tonic-gate { 11237c478bd9Sstevel@tonic-gate int save_errno = errno; 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, runners_sighup); 11267c478bd9Sstevel@tonic-gate errno = save_errno; 11277c478bd9Sstevel@tonic-gate CHECK_CRITICAL(sig); 11287c478bd9Sstevel@tonic-gate NoMoreRunners = true; 11297c478bd9Sstevel@tonic-gate Oldsh = Oldsh_hup; 11307c478bd9Sstevel@tonic-gate Oldsig = sig; 11317c478bd9Sstevel@tonic-gate proc_list_signal(PROC_QUEUE, sig); 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate if (!BlockOldsh || getppid() <= 1) 11347c478bd9Sstevel@tonic-gate { 11357c478bd9Sstevel@tonic-gate /* Check that a valid 'old signal handler' is callable */ 11367c478bd9Sstevel@tonic-gate if (Oldsh_hup != SIG_DFL && Oldsh_hup != SIG_IGN && 11377c478bd9Sstevel@tonic-gate Oldsh_hup != runners_sighup) 11387c478bd9Sstevel@tonic-gate (*Oldsh_hup)(sig); 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate errno = save_errno; 11417c478bd9Sstevel@tonic-gate return SIGFUNC_RETURN; 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate /* 11447c478bd9Sstevel@tonic-gate ** MARK_WORK_GROUP_RESTART -- mark a work group as needing a restart 11457c478bd9Sstevel@tonic-gate ** 11467c478bd9Sstevel@tonic-gate ** Sets a workgroup for restarting. 11477c478bd9Sstevel@tonic-gate ** 11487c478bd9Sstevel@tonic-gate ** Parameters: 11497c478bd9Sstevel@tonic-gate ** wgrp -- the work group id to restart. 11507c478bd9Sstevel@tonic-gate ** reason -- why (signal?), -1 to turn off restart 11517c478bd9Sstevel@tonic-gate ** 11527c478bd9Sstevel@tonic-gate ** Returns: 11537c478bd9Sstevel@tonic-gate ** none. 11547c478bd9Sstevel@tonic-gate ** 11557c478bd9Sstevel@tonic-gate ** Side effects: 11567c478bd9Sstevel@tonic-gate ** May set global RestartWorkGroup to true. 11577c478bd9Sstevel@tonic-gate ** 11587c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 11597c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 11607c478bd9Sstevel@tonic-gate ** DOING. 11617c478bd9Sstevel@tonic-gate */ 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate void 11647c478bd9Sstevel@tonic-gate mark_work_group_restart(wgrp, reason) 11657c478bd9Sstevel@tonic-gate int wgrp; 11667c478bd9Sstevel@tonic-gate int reason; 11677c478bd9Sstevel@tonic-gate { 11687c478bd9Sstevel@tonic-gate if (wgrp < 0 || wgrp > NumWorkGroups) 11697c478bd9Sstevel@tonic-gate return; 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_restart = reason; 11727c478bd9Sstevel@tonic-gate if (reason >= 0) 11737c478bd9Sstevel@tonic-gate RestartWorkGroup = true; 11747c478bd9Sstevel@tonic-gate } 11757c478bd9Sstevel@tonic-gate /* 11767c478bd9Sstevel@tonic-gate ** RESTART_MARKED_WORK_GROUPS -- restart work groups marked as needing restart 11777c478bd9Sstevel@tonic-gate ** 11787c478bd9Sstevel@tonic-gate ** Restart any workgroup marked as needing a restart provided more 11797c478bd9Sstevel@tonic-gate ** runners are allowed. 11807c478bd9Sstevel@tonic-gate ** 11817c478bd9Sstevel@tonic-gate ** Parameters: 11827c478bd9Sstevel@tonic-gate ** none. 11837c478bd9Sstevel@tonic-gate ** 11847c478bd9Sstevel@tonic-gate ** Returns: 11857c478bd9Sstevel@tonic-gate ** none. 11867c478bd9Sstevel@tonic-gate ** 11877c478bd9Sstevel@tonic-gate ** Side effects: 11887c478bd9Sstevel@tonic-gate ** Sets global RestartWorkGroup to false. 11897c478bd9Sstevel@tonic-gate */ 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate void 11927c478bd9Sstevel@tonic-gate restart_marked_work_groups() 11937c478bd9Sstevel@tonic-gate { 11947c478bd9Sstevel@tonic-gate int i; 11957c478bd9Sstevel@tonic-gate int wasblocked; 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate if (NoMoreRunners) 11987c478bd9Sstevel@tonic-gate return; 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate /* Block SIGCHLD so reapchild() doesn't mess with us */ 12017c478bd9Sstevel@tonic-gate wasblocked = sm_blocksignal(SIGCHLD); 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate for (i = 0; i < NumWorkGroups; i++) 12047c478bd9Sstevel@tonic-gate { 12057c478bd9Sstevel@tonic-gate if (WorkGrp[i].wg_restart >= 0) 12067c478bd9Sstevel@tonic-gate { 12077c478bd9Sstevel@tonic-gate if (LogLevel > 8) 12087c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 12097c478bd9Sstevel@tonic-gate "restart queue runner=%d due to signal 0x%x", 12107c478bd9Sstevel@tonic-gate i, WorkGrp[i].wg_restart); 12117c478bd9Sstevel@tonic-gate restart_work_group(i); 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate if (wasblocked == 0) 12177c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGCHLD); 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate /* 12207c478bd9Sstevel@tonic-gate ** RESTART_WORK_GROUP -- restart a specific work group 12217c478bd9Sstevel@tonic-gate ** 12227c478bd9Sstevel@tonic-gate ** Restart a specific workgroup provided more runners are allowed. 12237c478bd9Sstevel@tonic-gate ** If the requested work group has been restarted too many times log 12247c478bd9Sstevel@tonic-gate ** this and refuse to restart. 12257c478bd9Sstevel@tonic-gate ** 12267c478bd9Sstevel@tonic-gate ** Parameters: 12277c478bd9Sstevel@tonic-gate ** wgrp -- the work group id to restart 12287c478bd9Sstevel@tonic-gate ** 12297c478bd9Sstevel@tonic-gate ** Returns: 12307c478bd9Sstevel@tonic-gate ** none. 12317c478bd9Sstevel@tonic-gate ** 12327c478bd9Sstevel@tonic-gate ** Side Effects: 12337c478bd9Sstevel@tonic-gate ** starts another process doing the work of wgrp 12347c478bd9Sstevel@tonic-gate */ 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate #define MAX_PERSIST_RESTART 10 /* max allowed number of restarts */ 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate static void 12397c478bd9Sstevel@tonic-gate restart_work_group(wgrp) 12407c478bd9Sstevel@tonic-gate int wgrp; 12417c478bd9Sstevel@tonic-gate { 12427c478bd9Sstevel@tonic-gate if (NoMoreRunners || 12437c478bd9Sstevel@tonic-gate wgrp < 0 || wgrp > NumWorkGroups) 12447c478bd9Sstevel@tonic-gate return; 12457c478bd9Sstevel@tonic-gate 12467c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_restart = -1; 12477c478bd9Sstevel@tonic-gate if (WorkGrp[wgrp].wg_restartcnt < MAX_PERSIST_RESTART) 12487c478bd9Sstevel@tonic-gate { 12497c478bd9Sstevel@tonic-gate /* avoid overflow; increment here */ 12507c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_restartcnt++; 12517c478bd9Sstevel@tonic-gate (void) run_work_group(wgrp, RWG_FORK|RWG_PERSISTENT|RWG_RUNALL); 12527c478bd9Sstevel@tonic-gate } 12537c478bd9Sstevel@tonic-gate else 12547c478bd9Sstevel@tonic-gate { 12557c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 12567c478bd9Sstevel@tonic-gate "ERROR: persistent queue runner=%d restarted too many times, queue runner lost", 12577c478bd9Sstevel@tonic-gate wgrp); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate /* 12617c478bd9Sstevel@tonic-gate ** SCHEDULE_QUEUE_RUNS -- schedule the next queue run for a work group. 12627c478bd9Sstevel@tonic-gate ** 12637c478bd9Sstevel@tonic-gate ** Parameters: 12647c478bd9Sstevel@tonic-gate ** runall -- schedule even if individual bit is not set. 12657c478bd9Sstevel@tonic-gate ** wgrp -- the work group id to schedule. 12667c478bd9Sstevel@tonic-gate ** didit -- the queue run was performed for this work group. 12677c478bd9Sstevel@tonic-gate ** 12687c478bd9Sstevel@tonic-gate ** Returns: 12697c478bd9Sstevel@tonic-gate ** nothing 12707c478bd9Sstevel@tonic-gate */ 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate #define INCR_MOD(v, m) if (++v >= m) \ 12737c478bd9Sstevel@tonic-gate v = 0; \ 12747c478bd9Sstevel@tonic-gate else 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate static void 12777c478bd9Sstevel@tonic-gate schedule_queue_runs(runall, wgrp, didit) 12787c478bd9Sstevel@tonic-gate bool runall; 12797c478bd9Sstevel@tonic-gate int wgrp; 12807c478bd9Sstevel@tonic-gate bool didit; 12817c478bd9Sstevel@tonic-gate { 12827c478bd9Sstevel@tonic-gate int qgrp, cgrp, endgrp; 12837c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 12847c478bd9Sstevel@tonic-gate time_t lastsched; 12857c478bd9Sstevel@tonic-gate bool sched; 12867c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 12877c478bd9Sstevel@tonic-gate time_t now; 12887c478bd9Sstevel@tonic-gate time_t minqintvl; 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate /* 12917c478bd9Sstevel@tonic-gate ** This is a bit ugly since we have to duplicate the 12927c478bd9Sstevel@tonic-gate ** code that "walks" through a work queue group. 12937c478bd9Sstevel@tonic-gate */ 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate now = curtime(); 12967c478bd9Sstevel@tonic-gate minqintvl = 0; 12977c478bd9Sstevel@tonic-gate cgrp = endgrp = WorkGrp[wgrp].wg_curqgrp; 12987c478bd9Sstevel@tonic-gate do 12997c478bd9Sstevel@tonic-gate { 13007c478bd9Sstevel@tonic-gate time_t qintvl; 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 13037c478bd9Sstevel@tonic-gate lastsched = 0; 13047c478bd9Sstevel@tonic-gate sched = false; 13057c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 13067c478bd9Sstevel@tonic-gate qgrp = WorkGrp[wgrp].wg_qgs[cgrp]->qg_index; 13077c478bd9Sstevel@tonic-gate if (Queue[qgrp]->qg_queueintvl > 0) 13087c478bd9Sstevel@tonic-gate qintvl = Queue[qgrp]->qg_queueintvl; 13097c478bd9Sstevel@tonic-gate else if (QueueIntvl > 0) 13107c478bd9Sstevel@tonic-gate qintvl = QueueIntvl; 13117c478bd9Sstevel@tonic-gate else 13127c478bd9Sstevel@tonic-gate qintvl = (time_t) 0; 13137c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 13147c478bd9Sstevel@tonic-gate lastsched = Queue[qgrp]->qg_nextrun; 13157c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 13167c478bd9Sstevel@tonic-gate if ((runall || Queue[qgrp]->qg_nextrun <= now) && qintvl > 0) 13177c478bd9Sstevel@tonic-gate { 13187c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 13197c478bd9Sstevel@tonic-gate sched = true; 13207c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 13217c478bd9Sstevel@tonic-gate if (minqintvl == 0 || qintvl < minqintvl) 13227c478bd9Sstevel@tonic-gate minqintvl = qintvl; 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate /* 13257c478bd9Sstevel@tonic-gate ** Only set a new time if a queue run was performed 13267c478bd9Sstevel@tonic-gate ** for this queue group. If the queue was not run, 13277c478bd9Sstevel@tonic-gate ** we could starve it by setting a new time on each 13287c478bd9Sstevel@tonic-gate ** call. 13297c478bd9Sstevel@tonic-gate */ 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate if (didit) 13327c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_nextrun += qintvl; 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 13357c478bd9Sstevel@tonic-gate if (tTd(69, 10)) 13367c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 13377c478bd9Sstevel@tonic-gate "sqr: wgrp=%d, cgrp=%d, qgrp=%d, intvl=%ld, QI=%ld, runall=%d, lastrun=%ld, nextrun=%ld, sched=%d", 13387c478bd9Sstevel@tonic-gate wgrp, cgrp, qgrp, Queue[qgrp]->qg_queueintvl, 13397c478bd9Sstevel@tonic-gate QueueIntvl, runall, lastsched, 13407c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_nextrun, sched); 13417c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 13427c478bd9Sstevel@tonic-gate INCR_MOD(cgrp, WorkGrp[wgrp].wg_numqgrp); 13437c478bd9Sstevel@tonic-gate } while (endgrp != cgrp); 13447c478bd9Sstevel@tonic-gate if (minqintvl > 0) 13457c478bd9Sstevel@tonic-gate (void) sm_setevent(minqintvl, runqueueevent, 0); 13467c478bd9Sstevel@tonic-gate } 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_RUN_PARANOIA 13497c478bd9Sstevel@tonic-gate /* 13507c478bd9Sstevel@tonic-gate ** CHECKQUEUERUNNER -- check whether a queue group hasn't been run. 13517c478bd9Sstevel@tonic-gate ** 13527c478bd9Sstevel@tonic-gate ** Use this if events may get lost and hence queue runners may not 13537c478bd9Sstevel@tonic-gate ** be started and mail will pile up in a queue. 13547c478bd9Sstevel@tonic-gate ** 13557c478bd9Sstevel@tonic-gate ** Parameters: 13567c478bd9Sstevel@tonic-gate ** none. 13577c478bd9Sstevel@tonic-gate ** 13587c478bd9Sstevel@tonic-gate ** Returns: 13597c478bd9Sstevel@tonic-gate ** true if a queue run is necessary. 13607c478bd9Sstevel@tonic-gate ** 13617c478bd9Sstevel@tonic-gate ** Side Effects: 13627c478bd9Sstevel@tonic-gate ** may schedule a queue run. 13637c478bd9Sstevel@tonic-gate */ 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate bool 13667c478bd9Sstevel@tonic-gate checkqueuerunner() 13677c478bd9Sstevel@tonic-gate { 13687c478bd9Sstevel@tonic-gate int qgrp; 13697c478bd9Sstevel@tonic-gate time_t now, minqintvl; 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate now = curtime(); 13727c478bd9Sstevel@tonic-gate minqintvl = 0; 13737c478bd9Sstevel@tonic-gate for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++) 13747c478bd9Sstevel@tonic-gate { 13757c478bd9Sstevel@tonic-gate time_t qintvl; 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate if (Queue[qgrp]->qg_queueintvl > 0) 13787c478bd9Sstevel@tonic-gate qintvl = Queue[qgrp]->qg_queueintvl; 13797c478bd9Sstevel@tonic-gate else if (QueueIntvl > 0) 13807c478bd9Sstevel@tonic-gate qintvl = QueueIntvl; 13817c478bd9Sstevel@tonic-gate else 13827c478bd9Sstevel@tonic-gate qintvl = (time_t) 0; 13837c478bd9Sstevel@tonic-gate if (Queue[qgrp]->qg_nextrun <= now - qintvl) 13847c478bd9Sstevel@tonic-gate { 13857c478bd9Sstevel@tonic-gate if (minqintvl == 0 || qintvl < minqintvl) 13867c478bd9Sstevel@tonic-gate minqintvl = qintvl; 13877c478bd9Sstevel@tonic-gate if (LogLevel > 1) 13887c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 13897c478bd9Sstevel@tonic-gate "checkqueuerunner: queue %d should have been run at %s, queue interval %ld", 13907c478bd9Sstevel@tonic-gate qgrp, 13917c478bd9Sstevel@tonic-gate arpadate(ctime(&Queue[qgrp]->qg_nextrun)), 13927c478bd9Sstevel@tonic-gate qintvl); 13937c478bd9Sstevel@tonic-gate } 13947c478bd9Sstevel@tonic-gate } 13957c478bd9Sstevel@tonic-gate if (minqintvl > 0) 13967c478bd9Sstevel@tonic-gate { 13977c478bd9Sstevel@tonic-gate (void) sm_setevent(minqintvl, runqueueevent, 0); 13987c478bd9Sstevel@tonic-gate return true; 13997c478bd9Sstevel@tonic-gate } 14007c478bd9Sstevel@tonic-gate return false; 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_RUN_PARANOIA */ 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate /* 14057c478bd9Sstevel@tonic-gate ** RUNQUEUE -- run the jobs in the queue. 14067c478bd9Sstevel@tonic-gate ** 14077c478bd9Sstevel@tonic-gate ** Gets the stuff out of the queue in some presumably logical 14087c478bd9Sstevel@tonic-gate ** order and processes them. 14097c478bd9Sstevel@tonic-gate ** 14107c478bd9Sstevel@tonic-gate ** Parameters: 14117c478bd9Sstevel@tonic-gate ** forkflag -- true if the queue scanning should be done in 14127c478bd9Sstevel@tonic-gate ** a child process. We double-fork so it is not our 14137c478bd9Sstevel@tonic-gate ** child and we don't have to clean up after it. 14147c478bd9Sstevel@tonic-gate ** false can be ignored if we have multiple queues. 14157c478bd9Sstevel@tonic-gate ** verbose -- if true, print out status information. 14167c478bd9Sstevel@tonic-gate ** persistent -- persistent queue runner? 14177c478bd9Sstevel@tonic-gate ** runall -- run all groups or only a subset (DoQueueRun)? 14187c478bd9Sstevel@tonic-gate ** 14197c478bd9Sstevel@tonic-gate ** Returns: 14207c478bd9Sstevel@tonic-gate ** true if the queue run successfully began. 14217c478bd9Sstevel@tonic-gate ** 14227c478bd9Sstevel@tonic-gate ** Side Effects: 14237c478bd9Sstevel@tonic-gate ** runs things in the mail queue using run_work_group(). 14247c478bd9Sstevel@tonic-gate ** maybe schedules next queue run. 14257c478bd9Sstevel@tonic-gate */ 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate static ENVELOPE QueueEnvelope; /* the queue run envelope */ 14287c478bd9Sstevel@tonic-gate static time_t LastQueueTime = 0; /* last time a queue ID assigned */ 14297c478bd9Sstevel@tonic-gate static pid_t LastQueuePid = -1; /* last PID which had a queue ID */ 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate /* values for qp_supdirs */ 14327c478bd9Sstevel@tonic-gate #define QP_NOSUB 0x0000 /* No subdirectories */ 14337c478bd9Sstevel@tonic-gate #define QP_SUBDF 0x0001 /* "df" subdirectory */ 14347c478bd9Sstevel@tonic-gate #define QP_SUBQF 0x0002 /* "qf" subdirectory */ 14357c478bd9Sstevel@tonic-gate #define QP_SUBXF 0x0004 /* "xf" subdirectory */ 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate bool 14387c478bd9Sstevel@tonic-gate runqueue(forkflag, verbose, persistent, runall) 14397c478bd9Sstevel@tonic-gate bool forkflag; 14407c478bd9Sstevel@tonic-gate bool verbose; 14417c478bd9Sstevel@tonic-gate bool persistent; 14427c478bd9Sstevel@tonic-gate bool runall; 14437c478bd9Sstevel@tonic-gate { 14447c478bd9Sstevel@tonic-gate int i; 14457c478bd9Sstevel@tonic-gate bool ret = true; 14467c478bd9Sstevel@tonic-gate static int curnum = 0; 14477c478bd9Sstevel@tonic-gate sigfunc_t cursh; 14487c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 14497c478bd9Sstevel@tonic-gate SM_NONVOLATILE int oldgroup = 0; 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugLeakQ, 1)) 14527c478bd9Sstevel@tonic-gate { 14537c478bd9Sstevel@tonic-gate oldgroup = sm_heap_group(); 14547c478bd9Sstevel@tonic-gate sm_heap_newgroup(); 14557c478bd9Sstevel@tonic-gate sm_dprintf("runqueue() heap group #%d\n", sm_heap_group()); 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate /* queue run has been started, don't do any more this time */ 14607c478bd9Sstevel@tonic-gate DoQueueRun = false; 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate /* more than one queue or more than one directory per queue */ 14637c478bd9Sstevel@tonic-gate if (!forkflag && !verbose && 14647c478bd9Sstevel@tonic-gate (WorkGrp[0].wg_qgs[0]->qg_numqueues > 1 || NumWorkGroups > 1 || 14657c478bd9Sstevel@tonic-gate WorkGrp[0].wg_numqgrp > 1)) 14667c478bd9Sstevel@tonic-gate forkflag = true; 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate /* 14697c478bd9Sstevel@tonic-gate ** For controlling queue runners via signals sent to this process. 14707c478bd9Sstevel@tonic-gate ** Oldsh* will get called too by runners_sig* (if it is not SIG_IGN 14717c478bd9Sstevel@tonic-gate ** or SIG_DFL) to preserve cleanup behavior. Now that this process 14727c478bd9Sstevel@tonic-gate ** will have children (and perhaps grandchildren) this handler will 14737c478bd9Sstevel@tonic-gate ** be left in place. This is because this process, once it has 14747c478bd9Sstevel@tonic-gate ** finished spinning off queue runners, may go back to doing something 14757c478bd9Sstevel@tonic-gate ** else (like being a daemon). And we still want on a SIG{TERM,HUP} to 14767c478bd9Sstevel@tonic-gate ** clean up the child queue runners. Only install 'runners_sig*' once 14777c478bd9Sstevel@tonic-gate ** else we'll get stuck looping forever. 14787c478bd9Sstevel@tonic-gate */ 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate cursh = sm_signal(SIGTERM, runners_sigterm); 14817c478bd9Sstevel@tonic-gate if (cursh != runners_sigterm) 14827c478bd9Sstevel@tonic-gate Oldsh_term = cursh; 14837c478bd9Sstevel@tonic-gate cursh = sm_signal(SIGHUP, runners_sighup); 14847c478bd9Sstevel@tonic-gate if (cursh != runners_sighup) 14857c478bd9Sstevel@tonic-gate Oldsh_hup = cursh; 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate for (i = 0; i < NumWorkGroups && !NoMoreRunners; i++) 14887c478bd9Sstevel@tonic-gate { 14897c478bd9Sstevel@tonic-gate int rwgflags = RWG_NONE; 14907c478bd9Sstevel@tonic-gate 14917c478bd9Sstevel@tonic-gate /* 14927c478bd9Sstevel@tonic-gate ** If MaxQueueChildren active then test whether the start 14937c478bd9Sstevel@tonic-gate ** of the next queue group's additional queue runners (maximum) 14947c478bd9Sstevel@tonic-gate ** will result in MaxQueueChildren being exceeded. 14957c478bd9Sstevel@tonic-gate ** 14967c478bd9Sstevel@tonic-gate ** Note: do not use continue; even though another workgroup 14977c478bd9Sstevel@tonic-gate ** may have fewer queue runners, this would be "unfair", 14987c478bd9Sstevel@tonic-gate ** i.e., this work group might "starve" then. 14997c478bd9Sstevel@tonic-gate */ 15007c478bd9Sstevel@tonic-gate 15017c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 15027c478bd9Sstevel@tonic-gate if (tTd(69, 10)) 15037c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 15047c478bd9Sstevel@tonic-gate "rq: curnum=%d, MaxQueueChildren=%d, CurRunners=%d, WorkGrp[curnum].wg_maxact=%d", 15057c478bd9Sstevel@tonic-gate curnum, MaxQueueChildren, CurRunners, 15067c478bd9Sstevel@tonic-gate WorkGrp[curnum].wg_maxact); 15077c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 15087c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && 15097c478bd9Sstevel@tonic-gate CurRunners + WorkGrp[curnum].wg_maxact > MaxQueueChildren) 15107c478bd9Sstevel@tonic-gate break; 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate /* 15137c478bd9Sstevel@tonic-gate ** Pick up where we left off (curnum), in case we 15147c478bd9Sstevel@tonic-gate ** used up all the children last time without finishing. 15157c478bd9Sstevel@tonic-gate ** This give a round-robin fairness to queue runs. 15167c478bd9Sstevel@tonic-gate ** 15177c478bd9Sstevel@tonic-gate ** Increment CurRunners before calling run_work_group() 15187c478bd9Sstevel@tonic-gate ** to avoid a "race condition" with proc_list_drop() which 15197c478bd9Sstevel@tonic-gate ** decrements CurRunners if the queue runners terminate. 15207c478bd9Sstevel@tonic-gate ** Notice: CurRunners is an upper limit, in some cases 15217c478bd9Sstevel@tonic-gate ** (too few jobs in the queue) this value is larger than 15227c478bd9Sstevel@tonic-gate ** the actual number of queue runners. The discrepancy can 15237c478bd9Sstevel@tonic-gate ** increase if some queue runners "hang" for a long time. 15247c478bd9Sstevel@tonic-gate */ 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate CurRunners += WorkGrp[curnum].wg_maxact; 15277c478bd9Sstevel@tonic-gate if (forkflag) 15287c478bd9Sstevel@tonic-gate rwgflags |= RWG_FORK; 15297c478bd9Sstevel@tonic-gate if (verbose) 15307c478bd9Sstevel@tonic-gate rwgflags |= RWG_VERBOSE; 15317c478bd9Sstevel@tonic-gate if (persistent) 15327c478bd9Sstevel@tonic-gate rwgflags |= RWG_PERSISTENT; 15337c478bd9Sstevel@tonic-gate if (runall) 15347c478bd9Sstevel@tonic-gate rwgflags |= RWG_RUNALL; 15357c478bd9Sstevel@tonic-gate ret = run_work_group(curnum, rwgflags); 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate /* 15387c478bd9Sstevel@tonic-gate ** Failure means a message was printed for ETRN 15397c478bd9Sstevel@tonic-gate ** and subsequent queues are likely to fail as well. 15407c478bd9Sstevel@tonic-gate ** Decrement CurRunners in that case because 15417c478bd9Sstevel@tonic-gate ** none have been started. 15427c478bd9Sstevel@tonic-gate */ 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate if (!ret) 15457c478bd9Sstevel@tonic-gate { 15467c478bd9Sstevel@tonic-gate CurRunners -= WorkGrp[curnum].wg_maxact; 15477c478bd9Sstevel@tonic-gate break; 15487c478bd9Sstevel@tonic-gate } 15497c478bd9Sstevel@tonic-gate 15507c478bd9Sstevel@tonic-gate if (!persistent) 15517c478bd9Sstevel@tonic-gate schedule_queue_runs(runall, curnum, true); 15527c478bd9Sstevel@tonic-gate INCR_MOD(curnum, NumWorkGroups); 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate 15557c478bd9Sstevel@tonic-gate /* schedule left over queue runs */ 15567c478bd9Sstevel@tonic-gate if (i < NumWorkGroups && !NoMoreRunners && !persistent) 15577c478bd9Sstevel@tonic-gate { 15587c478bd9Sstevel@tonic-gate int h; 15597c478bd9Sstevel@tonic-gate 15607c478bd9Sstevel@tonic-gate for (h = curnum; i < NumWorkGroups; i++) 15617c478bd9Sstevel@tonic-gate { 15627c478bd9Sstevel@tonic-gate schedule_queue_runs(runall, h, false); 15637c478bd9Sstevel@tonic-gate INCR_MOD(h, NumWorkGroups); 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate } 15667c478bd9Sstevel@tonic-gate 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 15697c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugLeakQ, 1)) 15707c478bd9Sstevel@tonic-gate sm_heap_setgroup(oldgroup); 15717c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 15727c478bd9Sstevel@tonic-gate return ret; 15737c478bd9Sstevel@tonic-gate } 15747c478bd9Sstevel@tonic-gate 15757c478bd9Sstevel@tonic-gate #if _FFR_SKIP_DOMAINS 15767c478bd9Sstevel@tonic-gate /* 15777c478bd9Sstevel@tonic-gate ** SKIP_DOMAINS -- Skip 'skip' number of domains in the WorkQ. 15787c478bd9Sstevel@tonic-gate ** 15797c478bd9Sstevel@tonic-gate ** Added by Stephen Frost <sfrost@snowman.net> to support 15807c478bd9Sstevel@tonic-gate ** having each runner process every N'th domain instead of 15817c478bd9Sstevel@tonic-gate ** every N'th message. 15827c478bd9Sstevel@tonic-gate ** 15837c478bd9Sstevel@tonic-gate ** Parameters: 15847c478bd9Sstevel@tonic-gate ** skip -- number of domains in WorkQ to skip. 15857c478bd9Sstevel@tonic-gate ** 15867c478bd9Sstevel@tonic-gate ** Returns: 15877c478bd9Sstevel@tonic-gate ** total number of messages skipped. 15887c478bd9Sstevel@tonic-gate ** 15897c478bd9Sstevel@tonic-gate ** Side Effects: 15907c478bd9Sstevel@tonic-gate ** may change WorkQ 15917c478bd9Sstevel@tonic-gate */ 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate static int 15947c478bd9Sstevel@tonic-gate skip_domains(skip) 15957c478bd9Sstevel@tonic-gate int skip; 15967c478bd9Sstevel@tonic-gate { 15977c478bd9Sstevel@tonic-gate int n, seqjump; 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate for (n = 0, seqjump = 0; n < skip && WorkQ != NULL; seqjump++) 16007c478bd9Sstevel@tonic-gate { 16017c478bd9Sstevel@tonic-gate if (WorkQ->w_next != NULL) 16027c478bd9Sstevel@tonic-gate { 16037c478bd9Sstevel@tonic-gate if (WorkQ->w_host != NULL && 16047c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host != NULL) 16057c478bd9Sstevel@tonic-gate { 16067c478bd9Sstevel@tonic-gate if (sm_strcasecmp(WorkQ->w_host, 16077c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host) != 0) 16087c478bd9Sstevel@tonic-gate n++; 16097c478bd9Sstevel@tonic-gate } 16107c478bd9Sstevel@tonic-gate else 16117c478bd9Sstevel@tonic-gate { 16127c478bd9Sstevel@tonic-gate if ((WorkQ->w_host != NULL && 16137c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host == NULL) || 16147c478bd9Sstevel@tonic-gate (WorkQ->w_host == NULL && 16157c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host != NULL)) 16167c478bd9Sstevel@tonic-gate n++; 16177c478bd9Sstevel@tonic-gate } 16187c478bd9Sstevel@tonic-gate } 16197c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next; 16207c478bd9Sstevel@tonic-gate } 16217c478bd9Sstevel@tonic-gate return seqjump; 16227c478bd9Sstevel@tonic-gate } 16237c478bd9Sstevel@tonic-gate #endif /* _FFR_SKIP_DOMAINS */ 16247c478bd9Sstevel@tonic-gate 16257c478bd9Sstevel@tonic-gate /* 16267c478bd9Sstevel@tonic-gate ** RUNNER_WORK -- have a queue runner do its work 16277c478bd9Sstevel@tonic-gate ** 16287c478bd9Sstevel@tonic-gate ** Have a queue runner do its work a list of entries. 16297c478bd9Sstevel@tonic-gate ** When work isn't directly being done then this process can take a signal 16307c478bd9Sstevel@tonic-gate ** and terminate immediately (in a clean fashion of course). 16317c478bd9Sstevel@tonic-gate ** When work is directly being done, it's not to be interrupted 16327c478bd9Sstevel@tonic-gate ** immediately: the work should be allowed to finish at a clean point 16337c478bd9Sstevel@tonic-gate ** before termination (in a clean fashion of course). 16347c478bd9Sstevel@tonic-gate ** 16357c478bd9Sstevel@tonic-gate ** Parameters: 16367c478bd9Sstevel@tonic-gate ** e -- envelope. 16377c478bd9Sstevel@tonic-gate ** sequenceno -- 'th process to run WorkQ. 16387c478bd9Sstevel@tonic-gate ** didfork -- did the calling process fork()? 16397c478bd9Sstevel@tonic-gate ** skip -- process only each skip'th item. 16407c478bd9Sstevel@tonic-gate ** njobs -- number of jobs in WorkQ. 16417c478bd9Sstevel@tonic-gate ** 16427c478bd9Sstevel@tonic-gate ** Returns: 16437c478bd9Sstevel@tonic-gate ** none. 16447c478bd9Sstevel@tonic-gate ** 16457c478bd9Sstevel@tonic-gate ** Side Effects: 16467c478bd9Sstevel@tonic-gate ** runs things in the mail queue. 16477c478bd9Sstevel@tonic-gate */ 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate static void 16507c478bd9Sstevel@tonic-gate runner_work(e, sequenceno, didfork, skip, njobs) 16517c478bd9Sstevel@tonic-gate register ENVELOPE *e; 16527c478bd9Sstevel@tonic-gate int sequenceno; 16537c478bd9Sstevel@tonic-gate bool didfork; 16547c478bd9Sstevel@tonic-gate int skip; 16557c478bd9Sstevel@tonic-gate int njobs; 16567c478bd9Sstevel@tonic-gate { 16577c478bd9Sstevel@tonic-gate int n, seqjump; 16587c478bd9Sstevel@tonic-gate WORK *w; 16597c478bd9Sstevel@tonic-gate time_t now; 16607c478bd9Sstevel@tonic-gate 16617c478bd9Sstevel@tonic-gate SM_GET_LA(now); 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate /* 16647c478bd9Sstevel@tonic-gate ** Here we temporarily block the second calling of the handlers. 16657c478bd9Sstevel@tonic-gate ** This allows us to handle the signal without terminating in the 16667c478bd9Sstevel@tonic-gate ** middle of direct work. If a signal does come, the test for 16677c478bd9Sstevel@tonic-gate ** NoMoreRunners will find it. 16687c478bd9Sstevel@tonic-gate */ 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate BlockOldsh = true; 16717c478bd9Sstevel@tonic-gate seqjump = skip; 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate /* process them once at a time */ 16747c478bd9Sstevel@tonic-gate while (WorkQ != NULL) 16757c478bd9Sstevel@tonic-gate { 16767c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 16777c478bd9Sstevel@tonic-gate SM_NONVOLATILE int oldgroup = 0; 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugLeakQ, 1)) 16807c478bd9Sstevel@tonic-gate { 16817c478bd9Sstevel@tonic-gate oldgroup = sm_heap_group(); 16827c478bd9Sstevel@tonic-gate sm_heap_newgroup(); 16837c478bd9Sstevel@tonic-gate sm_dprintf("run_queue_group() heap group #%d\n", 16847c478bd9Sstevel@tonic-gate sm_heap_group()); 16857c478bd9Sstevel@tonic-gate } 16867c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate /* do no more work */ 16897c478bd9Sstevel@tonic-gate if (NoMoreRunners) 16907c478bd9Sstevel@tonic-gate { 16917c478bd9Sstevel@tonic-gate /* Check that a valid signal handler is callable */ 16927c478bd9Sstevel@tonic-gate if (Oldsh != SIG_DFL && Oldsh != SIG_IGN && 16937c478bd9Sstevel@tonic-gate Oldsh != runners_sighup && 16947c478bd9Sstevel@tonic-gate Oldsh != runners_sigterm) 16957c478bd9Sstevel@tonic-gate (*Oldsh)(Oldsig); 16967c478bd9Sstevel@tonic-gate break; 16977c478bd9Sstevel@tonic-gate } 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate w = WorkQ; /* assign current work item */ 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate /* 17027c478bd9Sstevel@tonic-gate ** Set the head of the WorkQ to the next work item. 17037c478bd9Sstevel@tonic-gate ** It is set 'skip' ahead (the number of parallel queue 17047c478bd9Sstevel@tonic-gate ** runners working on WorkQ together) since each runner 17057c478bd9Sstevel@tonic-gate ** works on every 'skip'th (N-th) item. 17067c478bd9Sstevel@tonic-gate #if _FFR_SKIP_DOMAINS 17077c478bd9Sstevel@tonic-gate ** In the case of the BYHOST Queue Sort Order, the 'item' 17087c478bd9Sstevel@tonic-gate ** is a domain, so we work on every 'skip'th (N-th) domain. 17097c478bd9Sstevel@tonic-gate #endif * _FFR_SKIP_DOMAINS * 17107c478bd9Sstevel@tonic-gate */ 17117c478bd9Sstevel@tonic-gate 17127c478bd9Sstevel@tonic-gate #if _FFR_SKIP_DOMAINS 17137c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST) 17147c478bd9Sstevel@tonic-gate { 17157c478bd9Sstevel@tonic-gate seqjump = 1; 17167c478bd9Sstevel@tonic-gate if (WorkQ->w_next != NULL) 17177c478bd9Sstevel@tonic-gate { 17187c478bd9Sstevel@tonic-gate if (WorkQ->w_host != NULL && 17197c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host != NULL) 17207c478bd9Sstevel@tonic-gate { 17217c478bd9Sstevel@tonic-gate if (sm_strcasecmp(WorkQ->w_host, 17227c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host) 17237c478bd9Sstevel@tonic-gate != 0) 17247c478bd9Sstevel@tonic-gate seqjump = skip_domains(skip); 17257c478bd9Sstevel@tonic-gate else 17267c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next; 17277c478bd9Sstevel@tonic-gate } 17287c478bd9Sstevel@tonic-gate else 17297c478bd9Sstevel@tonic-gate { 17307c478bd9Sstevel@tonic-gate if ((WorkQ->w_host != NULL && 17317c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host == NULL) || 17327c478bd9Sstevel@tonic-gate (WorkQ->w_host == NULL && 17337c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host != NULL)) 17347c478bd9Sstevel@tonic-gate seqjump = skip_domains(skip); 17357c478bd9Sstevel@tonic-gate else 17367c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next; 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate else 17407c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next; 17417c478bd9Sstevel@tonic-gate } 17427c478bd9Sstevel@tonic-gate else 17437c478bd9Sstevel@tonic-gate #endif /* _FFR_SKIP_DOMAINS */ 17447c478bd9Sstevel@tonic-gate { 17457c478bd9Sstevel@tonic-gate for (n = 0; n < skip && WorkQ != NULL; n++) 17467c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next; 17477c478bd9Sstevel@tonic-gate } 17487c478bd9Sstevel@tonic-gate 17497c478bd9Sstevel@tonic-gate e->e_to = NULL; 17507c478bd9Sstevel@tonic-gate 17517c478bd9Sstevel@tonic-gate /* 17527c478bd9Sstevel@tonic-gate ** Ignore jobs that are too expensive for the moment. 17537c478bd9Sstevel@tonic-gate ** 17547c478bd9Sstevel@tonic-gate ** Get new load average every GET_NEW_LA_TIME seconds. 17557c478bd9Sstevel@tonic-gate */ 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate SM_GET_LA(now); 17587c478bd9Sstevel@tonic-gate if (shouldqueue(WkRecipFact, Current_LA_time)) 17597c478bd9Sstevel@tonic-gate { 17607c478bd9Sstevel@tonic-gate char *msg = "Aborting queue run: load average too high"; 17617c478bd9Sstevel@tonic-gate 17627c478bd9Sstevel@tonic-gate if (Verbose) 17637c478bd9Sstevel@tonic-gate message("%s", msg); 17647c478bd9Sstevel@tonic-gate if (LogLevel > 8) 17657c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "runqueue: %s", msg); 17667c478bd9Sstevel@tonic-gate break; 17677c478bd9Sstevel@tonic-gate } 17687c478bd9Sstevel@tonic-gate if (shouldqueue(w->w_pri, w->w_ctime)) 17697c478bd9Sstevel@tonic-gate { 17707c478bd9Sstevel@tonic-gate if (Verbose) 17717c478bd9Sstevel@tonic-gate message(EmptyString); 17727c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYPRIORITY) 17737c478bd9Sstevel@tonic-gate { 17747c478bd9Sstevel@tonic-gate if (Verbose) 17757c478bd9Sstevel@tonic-gate message("Skipping %s/%s (sequence %d of %d) and flushing rest of queue", 17767c478bd9Sstevel@tonic-gate qid_printqueue(w->w_qgrp, 17777c478bd9Sstevel@tonic-gate w->w_qdir), 17787c478bd9Sstevel@tonic-gate w->w_name + 2, sequenceno, 17797c478bd9Sstevel@tonic-gate njobs); 17807c478bd9Sstevel@tonic-gate if (LogLevel > 8) 17817c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 17827c478bd9Sstevel@tonic-gate "runqueue: Flushing queue from %s/%s (pri %ld, LA %d, %d of %d)", 17837c478bd9Sstevel@tonic-gate qid_printqueue(w->w_qgrp, 17847c478bd9Sstevel@tonic-gate w->w_qdir), 17857c478bd9Sstevel@tonic-gate w->w_name + 2, w->w_pri, 17867c478bd9Sstevel@tonic-gate CurrentLA, sequenceno, 17877c478bd9Sstevel@tonic-gate njobs); 17887c478bd9Sstevel@tonic-gate break; 17897c478bd9Sstevel@tonic-gate } 17907c478bd9Sstevel@tonic-gate else if (Verbose) 17917c478bd9Sstevel@tonic-gate message("Skipping %s/%s (sequence %d of %d)", 17927c478bd9Sstevel@tonic-gate qid_printqueue(w->w_qgrp, w->w_qdir), 17937c478bd9Sstevel@tonic-gate w->w_name + 2, sequenceno, njobs); 17947c478bd9Sstevel@tonic-gate } 17957c478bd9Sstevel@tonic-gate else 17967c478bd9Sstevel@tonic-gate { 17977c478bd9Sstevel@tonic-gate if (Verbose) 17987c478bd9Sstevel@tonic-gate { 17997c478bd9Sstevel@tonic-gate message(EmptyString); 18007c478bd9Sstevel@tonic-gate message("Running %s/%s (sequence %d of %d)", 18017c478bd9Sstevel@tonic-gate qid_printqueue(w->w_qgrp, w->w_qdir), 18027c478bd9Sstevel@tonic-gate w->w_name + 2, sequenceno, njobs); 18037c478bd9Sstevel@tonic-gate } 18047c478bd9Sstevel@tonic-gate if (didfork && MaxQueueChildren > 0) 18057c478bd9Sstevel@tonic-gate { 18067c478bd9Sstevel@tonic-gate sm_blocksignal(SIGCHLD); 18077c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, reapchild); 18087c478bd9Sstevel@tonic-gate } 18097c478bd9Sstevel@tonic-gate if (tTd(63, 100)) 18107c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, NOQID, 18117c478bd9Sstevel@tonic-gate "runqueue %s dowork(%s)", 18127c478bd9Sstevel@tonic-gate qid_printqueue(w->w_qgrp, w->w_qdir), 18137c478bd9Sstevel@tonic-gate w->w_name + 2); 18147c478bd9Sstevel@tonic-gate 18157c478bd9Sstevel@tonic-gate (void) dowork(w->w_qgrp, w->w_qdir, w->w_name + 2, 18167c478bd9Sstevel@tonic-gate ForkQueueRuns, false, e); 18177c478bd9Sstevel@tonic-gate errno = 0; 18187c478bd9Sstevel@tonic-gate } 18197c478bd9Sstevel@tonic-gate sm_free(w->w_name); /* XXX */ 18207c478bd9Sstevel@tonic-gate if (w->w_host != NULL) 18217c478bd9Sstevel@tonic-gate sm_free(w->w_host); /* XXX */ 18227c478bd9Sstevel@tonic-gate sm_free((char *) w); /* XXX */ 18237c478bd9Sstevel@tonic-gate sequenceno += seqjump; /* next sequence number */ 18247c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 18257c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugLeakQ, 1)) 18267c478bd9Sstevel@tonic-gate sm_heap_setgroup(oldgroup); 18277c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 18287c478bd9Sstevel@tonic-gate } 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate BlockOldsh = false; 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate /* check the signals didn't happen during the revert */ 18337c478bd9Sstevel@tonic-gate if (NoMoreRunners) 18347c478bd9Sstevel@tonic-gate { 18357c478bd9Sstevel@tonic-gate /* Check that a valid signal handler is callable */ 18367c478bd9Sstevel@tonic-gate if (Oldsh != SIG_DFL && Oldsh != SIG_IGN && 18377c478bd9Sstevel@tonic-gate Oldsh != runners_sighup && Oldsh != runners_sigterm) 18387c478bd9Sstevel@tonic-gate (*Oldsh)(Oldsig); 18397c478bd9Sstevel@tonic-gate } 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate Oldsh = SIG_DFL; /* after the NoMoreRunners check */ 18427c478bd9Sstevel@tonic-gate } 18437c478bd9Sstevel@tonic-gate /* 18447c478bd9Sstevel@tonic-gate ** RUN_WORK_GROUP -- run the jobs in a queue group from a work group. 18457c478bd9Sstevel@tonic-gate ** 18467c478bd9Sstevel@tonic-gate ** Gets the stuff out of the queue in some presumably logical 18477c478bd9Sstevel@tonic-gate ** order and processes them. 18487c478bd9Sstevel@tonic-gate ** 18497c478bd9Sstevel@tonic-gate ** Parameters: 18507c478bd9Sstevel@tonic-gate ** wgrp -- work group to process. 18517c478bd9Sstevel@tonic-gate ** flags -- RWG_* flags 18527c478bd9Sstevel@tonic-gate ** 18537c478bd9Sstevel@tonic-gate ** Returns: 18547c478bd9Sstevel@tonic-gate ** true if the queue run successfully began. 18557c478bd9Sstevel@tonic-gate ** 18567c478bd9Sstevel@tonic-gate ** Side Effects: 18577c478bd9Sstevel@tonic-gate ** runs things in the mail queue. 18587c478bd9Sstevel@tonic-gate */ 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate /* Minimum sleep time for persistent queue runners */ 18617c478bd9Sstevel@tonic-gate #define MIN_SLEEP_TIME 5 18627c478bd9Sstevel@tonic-gate 18637c478bd9Sstevel@tonic-gate bool 18647c478bd9Sstevel@tonic-gate run_work_group(wgrp, flags) 18657c478bd9Sstevel@tonic-gate int wgrp; 18667c478bd9Sstevel@tonic-gate int flags; 18677c478bd9Sstevel@tonic-gate { 18687c478bd9Sstevel@tonic-gate register ENVELOPE *e; 18697c478bd9Sstevel@tonic-gate int njobs, qdir; 18707c478bd9Sstevel@tonic-gate int sequenceno = 1; 18717c478bd9Sstevel@tonic-gate int qgrp, endgrp, h, i; 18727c478bd9Sstevel@tonic-gate time_t now; 18737c478bd9Sstevel@tonic-gate bool full, more; 18747c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool; 18757c478bd9Sstevel@tonic-gate extern void rmexpstab __P((void)); 18767c478bd9Sstevel@tonic-gate extern ENVELOPE BlankEnvelope; 18777c478bd9Sstevel@tonic-gate extern SIGFUNC_DECL reapchild __P((int)); 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate if (wgrp < 0) 18807c478bd9Sstevel@tonic-gate return false; 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate /* 18837c478bd9Sstevel@tonic-gate ** If no work will ever be selected, don't even bother reading 18847c478bd9Sstevel@tonic-gate ** the queue. 18857c478bd9Sstevel@tonic-gate */ 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate SM_GET_LA(now); 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate if (!bitset(RWG_PERSISTENT, flags) && 18907c478bd9Sstevel@tonic-gate shouldqueue(WkRecipFact, Current_LA_time)) 18917c478bd9Sstevel@tonic-gate { 18927c478bd9Sstevel@tonic-gate char *msg = "Skipping queue run -- load average too high"; 18937c478bd9Sstevel@tonic-gate 18947c478bd9Sstevel@tonic-gate if (bitset(RWG_VERBOSE, flags)) 18957c478bd9Sstevel@tonic-gate message("458 %s\n", msg); 18967c478bd9Sstevel@tonic-gate if (LogLevel > 8) 18977c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "runqueue: %s", msg); 18987c478bd9Sstevel@tonic-gate return false; 18997c478bd9Sstevel@tonic-gate } 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate /* 19027c478bd9Sstevel@tonic-gate ** See if we already have too many children. 19037c478bd9Sstevel@tonic-gate */ 19047c478bd9Sstevel@tonic-gate 19057c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags) && 19067c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_lowqintvl > 0 && 19077c478bd9Sstevel@tonic-gate !bitset(RWG_PERSISTENT, flags) && 19087c478bd9Sstevel@tonic-gate MaxChildren > 0 && CurChildren >= MaxChildren) 19097c478bd9Sstevel@tonic-gate { 19107c478bd9Sstevel@tonic-gate char *msg = "Skipping queue run -- too many children"; 19117c478bd9Sstevel@tonic-gate 19127c478bd9Sstevel@tonic-gate if (bitset(RWG_VERBOSE, flags)) 19137c478bd9Sstevel@tonic-gate message("458 %s (%d)\n", msg, CurChildren); 19147c478bd9Sstevel@tonic-gate if (LogLevel > 8) 19157c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "runqueue: %s (%d)", 19167c478bd9Sstevel@tonic-gate msg, CurChildren); 19177c478bd9Sstevel@tonic-gate return false; 19187c478bd9Sstevel@tonic-gate } 19197c478bd9Sstevel@tonic-gate 19207c478bd9Sstevel@tonic-gate /* 19217c478bd9Sstevel@tonic-gate ** See if we want to go off and do other useful work. 19227c478bd9Sstevel@tonic-gate */ 19237c478bd9Sstevel@tonic-gate 19247c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags)) 19257c478bd9Sstevel@tonic-gate { 19267c478bd9Sstevel@tonic-gate pid_t pid; 19277c478bd9Sstevel@tonic-gate 19287c478bd9Sstevel@tonic-gate (void) sm_blocksignal(SIGCHLD); 19297c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, reapchild); 19307c478bd9Sstevel@tonic-gate 19317c478bd9Sstevel@tonic-gate pid = dofork(); 19327c478bd9Sstevel@tonic-gate if (pid == -1) 19337c478bd9Sstevel@tonic-gate { 19347c478bd9Sstevel@tonic-gate const char *msg = "Skipping queue run -- fork() failed"; 19357c478bd9Sstevel@tonic-gate const char *err = sm_errstring(errno); 19367c478bd9Sstevel@tonic-gate 19377c478bd9Sstevel@tonic-gate if (bitset(RWG_VERBOSE, flags)) 19387c478bd9Sstevel@tonic-gate message("458 %s: %s\n", msg, err); 19397c478bd9Sstevel@tonic-gate if (LogLevel > 8) 19407c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "runqueue: %s: %s", 19417c478bd9Sstevel@tonic-gate msg, err); 19427c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGCHLD); 19437c478bd9Sstevel@tonic-gate return false; 19447c478bd9Sstevel@tonic-gate } 19457c478bd9Sstevel@tonic-gate if (pid != 0) 19467c478bd9Sstevel@tonic-gate { 19477c478bd9Sstevel@tonic-gate /* parent -- pick up intermediate zombie */ 19487c478bd9Sstevel@tonic-gate (void) sm_blocksignal(SIGALRM); 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate /* wgrp only used when queue runners are persistent */ 19517c478bd9Sstevel@tonic-gate proc_list_add(pid, "Queue runner", PROC_QUEUE, 19527c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_maxact, 19537c478bd9Sstevel@tonic-gate bitset(RWG_PERSISTENT, flags) ? wgrp : -1, 19547c478bd9Sstevel@tonic-gate NULL); 19557c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGALRM); 19567c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGCHLD); 19577c478bd9Sstevel@tonic-gate return true; 19587c478bd9Sstevel@tonic-gate } 19597c478bd9Sstevel@tonic-gate 19607c478bd9Sstevel@tonic-gate /* child -- clean up signals */ 19617c478bd9Sstevel@tonic-gate 19627c478bd9Sstevel@tonic-gate /* Reset global flags */ 19637c478bd9Sstevel@tonic-gate RestartRequest = NULL; 19647c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 19657c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 19667c478bd9Sstevel@tonic-gate PendingSignal = 0; 19677c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 19687c478bd9Sstevel@tonic-gate close_sendmail_pid(); 19697c478bd9Sstevel@tonic-gate 19707c478bd9Sstevel@tonic-gate /* 19717c478bd9Sstevel@tonic-gate ** Initialize exception stack and default exception 19727c478bd9Sstevel@tonic-gate ** handler for child process. 19737c478bd9Sstevel@tonic-gate */ 19747c478bd9Sstevel@tonic-gate 19757c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error); 19767c478bd9Sstevel@tonic-gate clrcontrol(); 19777c478bd9Sstevel@tonic-gate proc_list_clear(); 19787c478bd9Sstevel@tonic-gate 19797c478bd9Sstevel@tonic-gate /* Add parent process as first child item */ 19807c478bd9Sstevel@tonic-gate proc_list_add(CurrentPid, "Queue runner child process", 19817c478bd9Sstevel@tonic-gate PROC_QUEUE_CHILD, 0, -1, NULL); 19827c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGCHLD); 19837c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 19847c478bd9Sstevel@tonic-gate (void) sm_signal(SIGHUP, SIG_DFL); 19857c478bd9Sstevel@tonic-gate (void) sm_signal(SIGTERM, intsig); 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate /* 19897c478bd9Sstevel@tonic-gate ** Release any resources used by the daemon code. 19907c478bd9Sstevel@tonic-gate */ 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate clrdaemon(); 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate /* force it to run expensive jobs */ 19957c478bd9Sstevel@tonic-gate NoConnect = false; 19967c478bd9Sstevel@tonic-gate 19977c478bd9Sstevel@tonic-gate /* drop privileges */ 19987c478bd9Sstevel@tonic-gate if (geteuid() == (uid_t) 0) 19997c478bd9Sstevel@tonic-gate (void) drop_privileges(false); 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate /* 20027c478bd9Sstevel@tonic-gate ** Create ourselves an envelope 20037c478bd9Sstevel@tonic-gate */ 20047c478bd9Sstevel@tonic-gate 20057c478bd9Sstevel@tonic-gate CurEnv = &QueueEnvelope; 20067c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL); 20077c478bd9Sstevel@tonic-gate e = newenvelope(&QueueEnvelope, CurEnv, rpool); 20087c478bd9Sstevel@tonic-gate e->e_flags = BlankEnvelope.e_flags; 20097c478bd9Sstevel@tonic-gate e->e_parent = NULL; 20107c478bd9Sstevel@tonic-gate 20117c478bd9Sstevel@tonic-gate /* make sure we have disconnected from parent */ 20127c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags)) 20137c478bd9Sstevel@tonic-gate { 20147c478bd9Sstevel@tonic-gate disconnect(1, e); 20157c478bd9Sstevel@tonic-gate QuickAbort = false; 20167c478bd9Sstevel@tonic-gate } 20177c478bd9Sstevel@tonic-gate 20187c478bd9Sstevel@tonic-gate /* 20197c478bd9Sstevel@tonic-gate ** If we are running part of the queue, always ignore stored 20207c478bd9Sstevel@tonic-gate ** host status. 20217c478bd9Sstevel@tonic-gate */ 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate if (QueueLimitId != NULL || QueueLimitSender != NULL || 20247c478bd9Sstevel@tonic-gate QueueLimitQuarantine != NULL || 20257c478bd9Sstevel@tonic-gate QueueLimitRecipient != NULL) 20267c478bd9Sstevel@tonic-gate { 20277c478bd9Sstevel@tonic-gate IgnoreHostStatus = true; 20287c478bd9Sstevel@tonic-gate MinQueueAge = 0; 20297c478bd9Sstevel@tonic-gate } 20307c478bd9Sstevel@tonic-gate 20317c478bd9Sstevel@tonic-gate /* 20327c478bd9Sstevel@tonic-gate ** Here is where we choose the queue group from the work group. 20337c478bd9Sstevel@tonic-gate ** The caller of the "domorework" label must setup a new envelope. 20347c478bd9Sstevel@tonic-gate */ 20357c478bd9Sstevel@tonic-gate 20367c478bd9Sstevel@tonic-gate endgrp = WorkGrp[wgrp].wg_curqgrp; /* to not spin endlessly */ 20377c478bd9Sstevel@tonic-gate 20387c478bd9Sstevel@tonic-gate domorework: 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate /* 20417c478bd9Sstevel@tonic-gate ** Run a queue group if: 20427c478bd9Sstevel@tonic-gate ** RWG_RUNALL bit is set or the bit for this group is set. 20437c478bd9Sstevel@tonic-gate */ 20447c478bd9Sstevel@tonic-gate 20457c478bd9Sstevel@tonic-gate now = curtime(); 20467c478bd9Sstevel@tonic-gate for (;;) 20477c478bd9Sstevel@tonic-gate { 20487c478bd9Sstevel@tonic-gate /* 20497c478bd9Sstevel@tonic-gate ** Find the next queue group within the work group that 20507c478bd9Sstevel@tonic-gate ** has been marked as needing a run. 20517c478bd9Sstevel@tonic-gate */ 20527c478bd9Sstevel@tonic-gate 20537c478bd9Sstevel@tonic-gate qgrp = WorkGrp[wgrp].wg_qgs[WorkGrp[wgrp].wg_curqgrp]->qg_index; 20547c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_curqgrp++; /* advance */ 20557c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_curqgrp %= WorkGrp[wgrp].wg_numqgrp; /* wrap */ 20567c478bd9Sstevel@tonic-gate if (bitset(RWG_RUNALL, flags) || 20577c478bd9Sstevel@tonic-gate (Queue[qgrp]->qg_nextrun <= now && 20587c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_nextrun != (time_t) -1)) 20597c478bd9Sstevel@tonic-gate break; 20607c478bd9Sstevel@tonic-gate if (endgrp == WorkGrp[wgrp].wg_curqgrp) 20617c478bd9Sstevel@tonic-gate { 20627c478bd9Sstevel@tonic-gate e->e_id = NULL; 20637c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags)) 20647c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 20657c478bd9Sstevel@tonic-gate return true; /* we're done */ 20667c478bd9Sstevel@tonic-gate } 20677c478bd9Sstevel@tonic-gate } 20687c478bd9Sstevel@tonic-gate 20697c478bd9Sstevel@tonic-gate qdir = Queue[qgrp]->qg_curnum; /* round-robin init of queue position */ 20707c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 20717c478bd9Sstevel@tonic-gate if (tTd(69, 12)) 20727c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 20737c478bd9Sstevel@tonic-gate "rwg: wgrp=%d, qgrp=%d, qdir=%d, name=%s, curqgrp=%d, numgrps=%d", 20747c478bd9Sstevel@tonic-gate wgrp, qgrp, qdir, qid_printqueue(qgrp, qdir), 20757c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_curqgrp, WorkGrp[wgrp].wg_numqgrp); 20767c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate #if HASNICE 20797c478bd9Sstevel@tonic-gate /* tweak niceness of queue runs */ 20807c478bd9Sstevel@tonic-gate if (Queue[qgrp]->qg_nice > 0) 20817c478bd9Sstevel@tonic-gate (void) nice(Queue[qgrp]->qg_nice); 20827c478bd9Sstevel@tonic-gate #endif /* HASNICE */ 20837c478bd9Sstevel@tonic-gate 20847c478bd9Sstevel@tonic-gate /* XXX running queue group... */ 20857c478bd9Sstevel@tonic-gate sm_setproctitle(true, CurEnv, "running queue: %s", 20867c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 20877c478bd9Sstevel@tonic-gate 20887c478bd9Sstevel@tonic-gate if (LogLevel > 69 || tTd(63, 99)) 20897c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, NOQID, 20907c478bd9Sstevel@tonic-gate "runqueue %s, pid=%d, forkflag=%d", 20917c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), (int) CurrentPid, 20927c478bd9Sstevel@tonic-gate bitset(RWG_FORK, flags)); 20937c478bd9Sstevel@tonic-gate 20947c478bd9Sstevel@tonic-gate /* 20957c478bd9Sstevel@tonic-gate ** Start making passes through the queue. 20967c478bd9Sstevel@tonic-gate ** First, read and sort the entire queue. 20977c478bd9Sstevel@tonic-gate ** Then, process the work in that order. 20987c478bd9Sstevel@tonic-gate ** But if you take too long, start over. 20997c478bd9Sstevel@tonic-gate */ 21007c478bd9Sstevel@tonic-gate 21017c478bd9Sstevel@tonic-gate for (i = 0; i < Queue[qgrp]->qg_numqueues; i++) 21027c478bd9Sstevel@tonic-gate { 21037c478bd9Sstevel@tonic-gate h = gatherq(qgrp, qdir, false, &full, &more); 21047c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 21057c478bd9Sstevel@tonic-gate if (ShmId != SM_SHM_NO_ID) 21067c478bd9Sstevel@tonic-gate QSHM_ENTRIES(Queue[qgrp]->qg_qpaths[qdir].qp_idx) = h; 21077c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 21087c478bd9Sstevel@tonic-gate /* If there are no more items in this queue advance */ 21097c478bd9Sstevel@tonic-gate if (!more) 21107c478bd9Sstevel@tonic-gate { 21117c478bd9Sstevel@tonic-gate /* A round-robin advance */ 21127c478bd9Sstevel@tonic-gate qdir++; 21137c478bd9Sstevel@tonic-gate qdir %= Queue[qgrp]->qg_numqueues; 21147c478bd9Sstevel@tonic-gate } 21157c478bd9Sstevel@tonic-gate 21167c478bd9Sstevel@tonic-gate /* Has the WorkList reached the limit? */ 21177c478bd9Sstevel@tonic-gate if (full) 21187c478bd9Sstevel@tonic-gate break; /* don't try to gather more */ 21197c478bd9Sstevel@tonic-gate } 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate /* order the existing work requests */ 21227c478bd9Sstevel@tonic-gate njobs = sortq(Queue[qgrp]->qg_maxlist); 21237c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_curnum = qdir; /* update */ 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate 21267c478bd9Sstevel@tonic-gate if (!Verbose && bitnset(QD_FORK, Queue[qgrp]->qg_flags)) 21277c478bd9Sstevel@tonic-gate { 21287c478bd9Sstevel@tonic-gate int loop, maxrunners; 21297c478bd9Sstevel@tonic-gate pid_t pid; 21307c478bd9Sstevel@tonic-gate 21317c478bd9Sstevel@tonic-gate /* 21327c478bd9Sstevel@tonic-gate ** For this WorkQ we want to fork off N children (maxrunners) 21337c478bd9Sstevel@tonic-gate ** at this point. Each child has a copy of WorkQ. Each child 21347c478bd9Sstevel@tonic-gate ** will process every N-th item. The parent will wait for all 21357c478bd9Sstevel@tonic-gate ** of the children to finish before moving on to the next 21367c478bd9Sstevel@tonic-gate ** queue group within the work group. This saves us forking 21377c478bd9Sstevel@tonic-gate ** a new runner-child for each work item. 21387c478bd9Sstevel@tonic-gate ** It's valid for qg_maxqrun == 0 since this may be an 21397c478bd9Sstevel@tonic-gate ** explicit "don't run this queue" setting. 21407c478bd9Sstevel@tonic-gate */ 21417c478bd9Sstevel@tonic-gate 21427c478bd9Sstevel@tonic-gate maxrunners = Queue[qgrp]->qg_maxqrun; 21437c478bd9Sstevel@tonic-gate 21447c478bd9Sstevel@tonic-gate /* No need to have more runners then there are jobs */ 21457c478bd9Sstevel@tonic-gate if (maxrunners > njobs) 21467c478bd9Sstevel@tonic-gate maxrunners = njobs; 21477c478bd9Sstevel@tonic-gate for (loop = 0; loop < maxrunners; loop++) 21487c478bd9Sstevel@tonic-gate { 21497c478bd9Sstevel@tonic-gate /* 21507c478bd9Sstevel@tonic-gate ** Since the delivery may happen in a child and the 21517c478bd9Sstevel@tonic-gate ** parent does not wait, the parent may close the 21527c478bd9Sstevel@tonic-gate ** maps thereby removing any shared memory used by 21537c478bd9Sstevel@tonic-gate ** the map. Therefore, close the maps now so the 21547c478bd9Sstevel@tonic-gate ** child will dynamically open them if necessary. 21557c478bd9Sstevel@tonic-gate */ 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate closemaps(false); 21587c478bd9Sstevel@tonic-gate 21597c478bd9Sstevel@tonic-gate pid = fork(); 21607c478bd9Sstevel@tonic-gate if (pid < 0) 21617c478bd9Sstevel@tonic-gate { 21627c478bd9Sstevel@tonic-gate syserr("run_work_group: cannot fork"); 21637c478bd9Sstevel@tonic-gate return false; 21647c478bd9Sstevel@tonic-gate } 21657c478bd9Sstevel@tonic-gate else if (pid > 0) 21667c478bd9Sstevel@tonic-gate { 21677c478bd9Sstevel@tonic-gate /* parent -- clean out connection cache */ 21687c478bd9Sstevel@tonic-gate mci_flush(false, NULL); 21697c478bd9Sstevel@tonic-gate #if _FFR_SKIP_DOMAINS 21707c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST) 21717c478bd9Sstevel@tonic-gate { 21727c478bd9Sstevel@tonic-gate sequenceno += skip_domains(1); 21737c478bd9Sstevel@tonic-gate } 21747c478bd9Sstevel@tonic-gate else 21757c478bd9Sstevel@tonic-gate #endif /* _FFR_SKIP_DOMAINS */ 21767c478bd9Sstevel@tonic-gate { 21777c478bd9Sstevel@tonic-gate /* for the skip */ 21787c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next; 21797c478bd9Sstevel@tonic-gate sequenceno++; 21807c478bd9Sstevel@tonic-gate } 21817c478bd9Sstevel@tonic-gate proc_list_add(pid, "Queue child runner process", 21827c478bd9Sstevel@tonic-gate PROC_QUEUE_CHILD, 0, -1, NULL); 21837c478bd9Sstevel@tonic-gate 21847c478bd9Sstevel@tonic-gate /* No additional work, no additional runners */ 21857c478bd9Sstevel@tonic-gate if (WorkQ == NULL) 21867c478bd9Sstevel@tonic-gate break; 21877c478bd9Sstevel@tonic-gate } 21887c478bd9Sstevel@tonic-gate else 21897c478bd9Sstevel@tonic-gate { 21907c478bd9Sstevel@tonic-gate /* child -- Reset global flags */ 21917c478bd9Sstevel@tonic-gate RestartRequest = NULL; 21927c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 21937c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 21947c478bd9Sstevel@tonic-gate PendingSignal = 0; 21957c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 21967c478bd9Sstevel@tonic-gate close_sendmail_pid(); 21977c478bd9Sstevel@tonic-gate 21987c478bd9Sstevel@tonic-gate /* 21997c478bd9Sstevel@tonic-gate ** Initialize exception stack and default 22007c478bd9Sstevel@tonic-gate ** exception handler for child process. 22017c478bd9Sstevel@tonic-gate ** When fork()'d the child now has a private 22027c478bd9Sstevel@tonic-gate ** copy of WorkQ at its current position. 22037c478bd9Sstevel@tonic-gate */ 22047c478bd9Sstevel@tonic-gate 22057c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error); 22067c478bd9Sstevel@tonic-gate 22077c478bd9Sstevel@tonic-gate /* 22087c478bd9Sstevel@tonic-gate ** SMTP processes (whether -bd or -bs) set 22097c478bd9Sstevel@tonic-gate ** SIGCHLD to reapchild to collect 22107c478bd9Sstevel@tonic-gate ** children status. However, at delivery 22117c478bd9Sstevel@tonic-gate ** time, that status must be collected 22127c478bd9Sstevel@tonic-gate ** by sm_wait() to be dealt with properly 22137c478bd9Sstevel@tonic-gate ** (check success of delivery based 22147c478bd9Sstevel@tonic-gate ** on status code, etc). Therefore, if we 22157c478bd9Sstevel@tonic-gate ** are an SMTP process, reset SIGCHLD 22167c478bd9Sstevel@tonic-gate ** back to the default so reapchild 22177c478bd9Sstevel@tonic-gate ** doesn't collect status before 22187c478bd9Sstevel@tonic-gate ** sm_wait(). 22197c478bd9Sstevel@tonic-gate */ 22207c478bd9Sstevel@tonic-gate 22217c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP || 22227c478bd9Sstevel@tonic-gate OpMode == MD_DAEMON || 22237c478bd9Sstevel@tonic-gate MaxQueueChildren > 0) 22247c478bd9Sstevel@tonic-gate { 22257c478bd9Sstevel@tonic-gate proc_list_clear(); 22267c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD); 22277c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 22287c478bd9Sstevel@tonic-gate } 22297c478bd9Sstevel@tonic-gate 22307c478bd9Sstevel@tonic-gate /* child -- error messages to the transcript */ 22317c478bd9Sstevel@tonic-gate QuickAbort = OnlyOneError = false; 22327c478bd9Sstevel@tonic-gate runner_work(e, sequenceno, true, 22337c478bd9Sstevel@tonic-gate maxrunners, njobs); 22347c478bd9Sstevel@tonic-gate 22357c478bd9Sstevel@tonic-gate /* This child is done */ 22367c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 22377c478bd9Sstevel@tonic-gate /* NOTREACHED */ 22387c478bd9Sstevel@tonic-gate } 22397c478bd9Sstevel@tonic-gate } 22407c478bd9Sstevel@tonic-gate 22417c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD); 22427c478bd9Sstevel@tonic-gate 22437c478bd9Sstevel@tonic-gate /* 22447c478bd9Sstevel@tonic-gate ** Wait until all of the runners have completed before 22457c478bd9Sstevel@tonic-gate ** seeing if there is another queue group in the 22467c478bd9Sstevel@tonic-gate ** work group to process. 22477c478bd9Sstevel@tonic-gate ** XXX Future enhancement: don't wait() for all children 22487c478bd9Sstevel@tonic-gate ** here, just go ahead and make sure that overall the number 22497c478bd9Sstevel@tonic-gate ** of children is not exceeded. 22507c478bd9Sstevel@tonic-gate */ 22517c478bd9Sstevel@tonic-gate 22527c478bd9Sstevel@tonic-gate while (CurChildren > 0) 22537c478bd9Sstevel@tonic-gate { 22547c478bd9Sstevel@tonic-gate int status; 22557c478bd9Sstevel@tonic-gate pid_t ret; 22567c478bd9Sstevel@tonic-gate 22577c478bd9Sstevel@tonic-gate while ((ret = sm_wait(&status)) <= 0) 22587c478bd9Sstevel@tonic-gate continue; 22597c478bd9Sstevel@tonic-gate proc_list_drop(ret, status, NULL); 22607c478bd9Sstevel@tonic-gate } 22617c478bd9Sstevel@tonic-gate } 22627c478bd9Sstevel@tonic-gate else if (Queue[qgrp]->qg_maxqrun > 0 || bitset(RWG_FORCE, flags)) 22637c478bd9Sstevel@tonic-gate { 22647c478bd9Sstevel@tonic-gate /* 22657c478bd9Sstevel@tonic-gate ** When current process will not fork children to do the work, 22667c478bd9Sstevel@tonic-gate ** it will do the work itself. The 'skip' will be 1 since 22677c478bd9Sstevel@tonic-gate ** there are no child runners to divide the work across. 22687c478bd9Sstevel@tonic-gate */ 22697c478bd9Sstevel@tonic-gate 22707c478bd9Sstevel@tonic-gate runner_work(e, sequenceno, false, 1, njobs); 22717c478bd9Sstevel@tonic-gate } 22727c478bd9Sstevel@tonic-gate 22737c478bd9Sstevel@tonic-gate /* free memory allocated by newenvelope() above */ 22747c478bd9Sstevel@tonic-gate sm_rpool_free(rpool); 22757c478bd9Sstevel@tonic-gate QueueEnvelope.e_rpool = NULL; 22767c478bd9Sstevel@tonic-gate 22777c478bd9Sstevel@tonic-gate /* Are there still more queues in the work group to process? */ 22787c478bd9Sstevel@tonic-gate if (endgrp != WorkGrp[wgrp].wg_curqgrp) 22797c478bd9Sstevel@tonic-gate { 22807c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL); 22817c478bd9Sstevel@tonic-gate e = newenvelope(&QueueEnvelope, CurEnv, rpool); 22827c478bd9Sstevel@tonic-gate e->e_flags = BlankEnvelope.e_flags; 22837c478bd9Sstevel@tonic-gate goto domorework; 22847c478bd9Sstevel@tonic-gate } 22857c478bd9Sstevel@tonic-gate 22867c478bd9Sstevel@tonic-gate /* No more queues in work group to process. Now check persistent. */ 22877c478bd9Sstevel@tonic-gate if (bitset(RWG_PERSISTENT, flags)) 22887c478bd9Sstevel@tonic-gate { 22897c478bd9Sstevel@tonic-gate sequenceno = 1; 22907c478bd9Sstevel@tonic-gate sm_setproctitle(true, CurEnv, "running queue: %s", 22917c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 22927c478bd9Sstevel@tonic-gate 22937c478bd9Sstevel@tonic-gate /* 22947c478bd9Sstevel@tonic-gate ** close bogus maps, i.e., maps which caused a tempfail, 22957c478bd9Sstevel@tonic-gate ** so we get fresh map connections on the next lookup. 22967c478bd9Sstevel@tonic-gate ** closemaps() is also called when children are started. 22977c478bd9Sstevel@tonic-gate */ 22987c478bd9Sstevel@tonic-gate 22997c478bd9Sstevel@tonic-gate closemaps(true); 23007c478bd9Sstevel@tonic-gate 23017c478bd9Sstevel@tonic-gate /* Close any cached connections. */ 23027c478bd9Sstevel@tonic-gate mci_flush(true, NULL); 23037c478bd9Sstevel@tonic-gate 23047c478bd9Sstevel@tonic-gate /* Clean out expired related entries. */ 23057c478bd9Sstevel@tonic-gate rmexpstab(); 23067c478bd9Sstevel@tonic-gate 23077c478bd9Sstevel@tonic-gate #if NAMED_BIND 23087c478bd9Sstevel@tonic-gate /* Update MX records for FallbackMX. */ 23097c478bd9Sstevel@tonic-gate if (FallbackMX != NULL) 23107c478bd9Sstevel@tonic-gate (void) getfallbackmxrr(FallbackMX); 23117c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 23127c478bd9Sstevel@tonic-gate 23137c478bd9Sstevel@tonic-gate #if USERDB 23147c478bd9Sstevel@tonic-gate /* close UserDatabase */ 23157c478bd9Sstevel@tonic-gate _udbx_close(); 23167c478bd9Sstevel@tonic-gate #endif /* USERDB */ 23177c478bd9Sstevel@tonic-gate 23187c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 23197c478bd9Sstevel@tonic-gate if (sm_debug_active(&SmHeapCheck, 2) 23207c478bd9Sstevel@tonic-gate && access("memdump", F_OK) == 0 23217c478bd9Sstevel@tonic-gate ) 23227c478bd9Sstevel@tonic-gate { 23237c478bd9Sstevel@tonic-gate SM_FILE_T *out; 23247c478bd9Sstevel@tonic-gate 23257c478bd9Sstevel@tonic-gate remove("memdump"); 23267c478bd9Sstevel@tonic-gate out = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, 23277c478bd9Sstevel@tonic-gate "memdump.out", SM_IO_APPEND, NULL); 23287c478bd9Sstevel@tonic-gate if (out != NULL) 23297c478bd9Sstevel@tonic-gate { 23307c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, "----------------------\n"); 23317c478bd9Sstevel@tonic-gate sm_heap_report(out, 23327c478bd9Sstevel@tonic-gate sm_debug_level(&SmHeapCheck) - 1); 23337c478bd9Sstevel@tonic-gate (void) sm_io_close(out, SM_TIME_DEFAULT); 23347c478bd9Sstevel@tonic-gate } 23357c478bd9Sstevel@tonic-gate } 23367c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 23377c478bd9Sstevel@tonic-gate 23387c478bd9Sstevel@tonic-gate /* let me rest for a second to catch my breath */ 23397c478bd9Sstevel@tonic-gate if (njobs == 0 && WorkGrp[wgrp].wg_lowqintvl < MIN_SLEEP_TIME) 23407c478bd9Sstevel@tonic-gate sleep(MIN_SLEEP_TIME); 23417c478bd9Sstevel@tonic-gate else if (WorkGrp[wgrp].wg_lowqintvl <= 0) 23427c478bd9Sstevel@tonic-gate sleep(QueueIntvl > 0 ? QueueIntvl : MIN_SLEEP_TIME); 23437c478bd9Sstevel@tonic-gate else 23447c478bd9Sstevel@tonic-gate sleep(WorkGrp[wgrp].wg_lowqintvl); 23457c478bd9Sstevel@tonic-gate 23467c478bd9Sstevel@tonic-gate /* 23477c478bd9Sstevel@tonic-gate ** Get the LA outside the WorkQ loop if necessary. 23487c478bd9Sstevel@tonic-gate ** In a persistent queue runner the code is repeated over 23497c478bd9Sstevel@tonic-gate ** and over but gatherq() may ignore entries due to 23507c478bd9Sstevel@tonic-gate ** shouldqueue() (do we really have to do this twice?). 23517c478bd9Sstevel@tonic-gate ** Hence the queue runners would just idle around when once 23527c478bd9Sstevel@tonic-gate ** CurrentLA caused all entries in a queue to be ignored. 23537c478bd9Sstevel@tonic-gate */ 23547c478bd9Sstevel@tonic-gate 23557c478bd9Sstevel@tonic-gate if (njobs == 0) 23567c478bd9Sstevel@tonic-gate SM_GET_LA(now); 23577c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL); 23587c478bd9Sstevel@tonic-gate e = newenvelope(&QueueEnvelope, CurEnv, rpool); 23597c478bd9Sstevel@tonic-gate e->e_flags = BlankEnvelope.e_flags; 23607c478bd9Sstevel@tonic-gate goto domorework; 23617c478bd9Sstevel@tonic-gate } 23627c478bd9Sstevel@tonic-gate 23637c478bd9Sstevel@tonic-gate /* exit without the usual cleanup */ 23647c478bd9Sstevel@tonic-gate e->e_id = NULL; 23657c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags)) 23667c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 23677c478bd9Sstevel@tonic-gate /* NOTREACHED */ 23687c478bd9Sstevel@tonic-gate return true; 23697c478bd9Sstevel@tonic-gate } 23707c478bd9Sstevel@tonic-gate 23717c478bd9Sstevel@tonic-gate /* 23727c478bd9Sstevel@tonic-gate ** DOQUEUERUN -- do a queue run? 23737c478bd9Sstevel@tonic-gate */ 23747c478bd9Sstevel@tonic-gate 23757c478bd9Sstevel@tonic-gate bool 23767c478bd9Sstevel@tonic-gate doqueuerun() 23777c478bd9Sstevel@tonic-gate { 23787c478bd9Sstevel@tonic-gate return DoQueueRun; 23797c478bd9Sstevel@tonic-gate } 23807c478bd9Sstevel@tonic-gate 23817c478bd9Sstevel@tonic-gate /* 23827c478bd9Sstevel@tonic-gate ** RUNQUEUEEVENT -- Sets a flag to indicate that a queue run should be done. 23837c478bd9Sstevel@tonic-gate ** 23847c478bd9Sstevel@tonic-gate ** Parameters: 23857c478bd9Sstevel@tonic-gate ** none. 23867c478bd9Sstevel@tonic-gate ** 23877c478bd9Sstevel@tonic-gate ** Returns: 23887c478bd9Sstevel@tonic-gate ** none. 23897c478bd9Sstevel@tonic-gate ** 23907c478bd9Sstevel@tonic-gate ** Side Effects: 23917c478bd9Sstevel@tonic-gate ** The invocation of this function via an alarm may interrupt 23927c478bd9Sstevel@tonic-gate ** a set of actions. Thus errno may be set in that context. 23937c478bd9Sstevel@tonic-gate ** We need to restore errno at the end of this function to ensure 23947c478bd9Sstevel@tonic-gate ** that any work done here that sets errno doesn't return a 23957c478bd9Sstevel@tonic-gate ** misleading/false errno value. Errno may be EINTR upon entry to 23967c478bd9Sstevel@tonic-gate ** this function because of non-restartable/continuable system 23977c478bd9Sstevel@tonic-gate ** API was active. Iff this is true we will override errno as 23987c478bd9Sstevel@tonic-gate ** a timeout (as a more accurate error message). 23997c478bd9Sstevel@tonic-gate ** 24007c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 24017c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 24027c478bd9Sstevel@tonic-gate ** DOING. 24037c478bd9Sstevel@tonic-gate */ 24047c478bd9Sstevel@tonic-gate 24057c478bd9Sstevel@tonic-gate void 24067c478bd9Sstevel@tonic-gate runqueueevent(ignore) 24077c478bd9Sstevel@tonic-gate int ignore; 24087c478bd9Sstevel@tonic-gate { 24097c478bd9Sstevel@tonic-gate int save_errno = errno; 24107c478bd9Sstevel@tonic-gate 24117c478bd9Sstevel@tonic-gate /* 24127c478bd9Sstevel@tonic-gate ** Set the general bit that we want a queue run, 24137c478bd9Sstevel@tonic-gate ** tested in doqueuerun() 24147c478bd9Sstevel@tonic-gate */ 24157c478bd9Sstevel@tonic-gate 24167c478bd9Sstevel@tonic-gate DoQueueRun = true; 24177c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 24187c478bd9Sstevel@tonic-gate if (tTd(69, 10)) 24197c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "rqe: done"); 24207c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 24217c478bd9Sstevel@tonic-gate 24227c478bd9Sstevel@tonic-gate errno = save_errno; 24237c478bd9Sstevel@tonic-gate if (errno == EINTR) 24247c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 24257c478bd9Sstevel@tonic-gate } 24267c478bd9Sstevel@tonic-gate /* 24277c478bd9Sstevel@tonic-gate ** GATHERQ -- gather messages from the message queue(s) the work queue. 24287c478bd9Sstevel@tonic-gate ** 24297c478bd9Sstevel@tonic-gate ** Parameters: 24307c478bd9Sstevel@tonic-gate ** qgrp -- the index of the queue group. 24317c478bd9Sstevel@tonic-gate ** qdir -- the index of the queue directory. 24327c478bd9Sstevel@tonic-gate ** doall -- if set, include everything in the queue (even 24337c478bd9Sstevel@tonic-gate ** the jobs that cannot be run because the load 24347c478bd9Sstevel@tonic-gate ** average is too high, or MaxQueueRun is reached). 24357c478bd9Sstevel@tonic-gate ** Otherwise, exclude those jobs. 24367c478bd9Sstevel@tonic-gate ** full -- (optional) to be set 'true' if WorkList is full 24377c478bd9Sstevel@tonic-gate ** more -- (optional) to be set 'true' if there are still more 24387c478bd9Sstevel@tonic-gate ** messages in this queue not added to WorkList 24397c478bd9Sstevel@tonic-gate ** 24407c478bd9Sstevel@tonic-gate ** Returns: 24417c478bd9Sstevel@tonic-gate ** The number of request in the queue (not necessarily 24427c478bd9Sstevel@tonic-gate ** the number of requests in WorkList however). 24437c478bd9Sstevel@tonic-gate ** 24447c478bd9Sstevel@tonic-gate ** Side Effects: 24457c478bd9Sstevel@tonic-gate ** prepares available work into WorkList 24467c478bd9Sstevel@tonic-gate */ 24477c478bd9Sstevel@tonic-gate 24487c478bd9Sstevel@tonic-gate #define NEED_P 0001 /* 'P': priority */ 24497c478bd9Sstevel@tonic-gate #define NEED_T 0002 /* 'T': time */ 24507c478bd9Sstevel@tonic-gate #define NEED_R 0004 /* 'R': recipient */ 24517c478bd9Sstevel@tonic-gate #define NEED_S 0010 /* 'S': sender */ 24527c478bd9Sstevel@tonic-gate #define NEED_H 0020 /* host */ 24537c478bd9Sstevel@tonic-gate #define HAS_QUARANTINE 0040 /* has an unexpected 'q' line */ 24547c478bd9Sstevel@tonic-gate #define NEED_QUARANTINE 0100 /* 'q': reason */ 24557c478bd9Sstevel@tonic-gate 24567c478bd9Sstevel@tonic-gate static WORK *WorkList = NULL; /* list of unsort work */ 24577c478bd9Sstevel@tonic-gate static int WorkListSize = 0; /* current max size of WorkList */ 24587c478bd9Sstevel@tonic-gate static int WorkListCount = 0; /* # of work items in WorkList */ 24597c478bd9Sstevel@tonic-gate 24607c478bd9Sstevel@tonic-gate static int 24617c478bd9Sstevel@tonic-gate gatherq(qgrp, qdir, doall, full, more) 24627c478bd9Sstevel@tonic-gate int qgrp; 24637c478bd9Sstevel@tonic-gate int qdir; 24647c478bd9Sstevel@tonic-gate bool doall; 24657c478bd9Sstevel@tonic-gate bool *full; 24667c478bd9Sstevel@tonic-gate bool *more; 24677c478bd9Sstevel@tonic-gate { 24687c478bd9Sstevel@tonic-gate register struct dirent *d; 24697c478bd9Sstevel@tonic-gate register WORK *w; 24707c478bd9Sstevel@tonic-gate register char *p; 24717c478bd9Sstevel@tonic-gate DIR *f; 24727c478bd9Sstevel@tonic-gate int i, num_ent; 24737c478bd9Sstevel@tonic-gate int wn; 24747c478bd9Sstevel@tonic-gate QUEUE_CHAR *check; 24757c478bd9Sstevel@tonic-gate char qd[MAXPATHLEN]; 24767c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN]; 24777c478bd9Sstevel@tonic-gate 24787c478bd9Sstevel@tonic-gate wn = WorkListCount - 1; 24797c478bd9Sstevel@tonic-gate num_ent = 0; 24807c478bd9Sstevel@tonic-gate if (qdir == NOQDIR) 24817c478bd9Sstevel@tonic-gate (void) sm_strlcpy(qd, ".", sizeof qd); 24827c478bd9Sstevel@tonic-gate else 24837c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(qd, sizeof qd, 2, 24847c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name, 24857c478bd9Sstevel@tonic-gate (bitset(QP_SUBQF, 24867c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs) 24877c478bd9Sstevel@tonic-gate ? "/qf" : "")); 24887c478bd9Sstevel@tonic-gate 24897c478bd9Sstevel@tonic-gate if (tTd(41, 1)) 24907c478bd9Sstevel@tonic-gate { 24917c478bd9Sstevel@tonic-gate sm_dprintf("gatherq:\n"); 24927c478bd9Sstevel@tonic-gate 24937c478bd9Sstevel@tonic-gate check = QueueLimitId; 24947c478bd9Sstevel@tonic-gate while (check != NULL) 24957c478bd9Sstevel@tonic-gate { 24967c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitId = %s%s\n", 24977c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "", 24987c478bd9Sstevel@tonic-gate check->queue_match); 24997c478bd9Sstevel@tonic-gate check = check->queue_next; 25007c478bd9Sstevel@tonic-gate } 25017c478bd9Sstevel@tonic-gate 25027c478bd9Sstevel@tonic-gate check = QueueLimitSender; 25037c478bd9Sstevel@tonic-gate while (check != NULL) 25047c478bd9Sstevel@tonic-gate { 25057c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitSender = %s%s\n", 25067c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "", 25077c478bd9Sstevel@tonic-gate check->queue_match); 25087c478bd9Sstevel@tonic-gate check = check->queue_next; 25097c478bd9Sstevel@tonic-gate } 25107c478bd9Sstevel@tonic-gate 25117c478bd9Sstevel@tonic-gate check = QueueLimitRecipient; 25127c478bd9Sstevel@tonic-gate while (check != NULL) 25137c478bd9Sstevel@tonic-gate { 25147c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitRecipient = %s%s\n", 25157c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "", 25167c478bd9Sstevel@tonic-gate check->queue_match); 25177c478bd9Sstevel@tonic-gate check = check->queue_next; 25187c478bd9Sstevel@tonic-gate } 25197c478bd9Sstevel@tonic-gate 25207c478bd9Sstevel@tonic-gate if (QueueMode == QM_QUARANTINE) 25217c478bd9Sstevel@tonic-gate { 25227c478bd9Sstevel@tonic-gate check = QueueLimitQuarantine; 25237c478bd9Sstevel@tonic-gate while (check != NULL) 25247c478bd9Sstevel@tonic-gate { 25257c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitQuarantine = %s%s\n", 25267c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "", 25277c478bd9Sstevel@tonic-gate check->queue_match); 25287c478bd9Sstevel@tonic-gate check = check->queue_next; 25297c478bd9Sstevel@tonic-gate } 25307c478bd9Sstevel@tonic-gate } 25317c478bd9Sstevel@tonic-gate } 25327c478bd9Sstevel@tonic-gate 25337c478bd9Sstevel@tonic-gate /* open the queue directory */ 25347c478bd9Sstevel@tonic-gate f = opendir(qd); 25357c478bd9Sstevel@tonic-gate if (f == NULL) 25367c478bd9Sstevel@tonic-gate { 25377c478bd9Sstevel@tonic-gate syserr("gatherq: cannot open \"%s\"", 25387c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 25397c478bd9Sstevel@tonic-gate if (full != NULL) 25407c478bd9Sstevel@tonic-gate *full = WorkListCount >= MaxQueueRun && MaxQueueRun > 0; 25417c478bd9Sstevel@tonic-gate if (more != NULL) 25427c478bd9Sstevel@tonic-gate *more = false; 25437c478bd9Sstevel@tonic-gate return 0; 25447c478bd9Sstevel@tonic-gate } 25457c478bd9Sstevel@tonic-gate 25467c478bd9Sstevel@tonic-gate /* 25477c478bd9Sstevel@tonic-gate ** Read the work directory. 25487c478bd9Sstevel@tonic-gate */ 25497c478bd9Sstevel@tonic-gate 25507c478bd9Sstevel@tonic-gate while ((d = readdir(f)) != NULL) 25517c478bd9Sstevel@tonic-gate { 25527c478bd9Sstevel@tonic-gate SM_FILE_T *cf; 25537c478bd9Sstevel@tonic-gate int qfver = 0; 25547c478bd9Sstevel@tonic-gate char lbuf[MAXNAME + 1]; 25557c478bd9Sstevel@tonic-gate struct stat sbuf; 25567c478bd9Sstevel@tonic-gate 25577c478bd9Sstevel@tonic-gate if (tTd(41, 50)) 25587c478bd9Sstevel@tonic-gate sm_dprintf("gatherq: checking %s..", d->d_name); 25597c478bd9Sstevel@tonic-gate 25607c478bd9Sstevel@tonic-gate /* is this an interesting entry? */ 25617c478bd9Sstevel@tonic-gate if (!(((QueueMode == QM_NORMAL && 25627c478bd9Sstevel@tonic-gate d->d_name[0] == NORMQF_LETTER) || 25637c478bd9Sstevel@tonic-gate (QueueMode == QM_QUARANTINE && 25647c478bd9Sstevel@tonic-gate d->d_name[0] == QUARQF_LETTER) || 25657c478bd9Sstevel@tonic-gate (QueueMode == QM_LOST && 25667c478bd9Sstevel@tonic-gate d->d_name[0] == LOSEQF_LETTER)) && 25677c478bd9Sstevel@tonic-gate d->d_name[1] == 'f')) 25687c478bd9Sstevel@tonic-gate { 25697c478bd9Sstevel@tonic-gate if (tTd(41, 50)) 25707c478bd9Sstevel@tonic-gate sm_dprintf(" skipping\n"); 25717c478bd9Sstevel@tonic-gate continue; 25727c478bd9Sstevel@tonic-gate } 25737c478bd9Sstevel@tonic-gate if (tTd(41, 50)) 25747c478bd9Sstevel@tonic-gate sm_dprintf("\n"); 25757c478bd9Sstevel@tonic-gate 25767c478bd9Sstevel@tonic-gate if (strlen(d->d_name) >= MAXQFNAME) 25777c478bd9Sstevel@tonic-gate { 25787c478bd9Sstevel@tonic-gate if (Verbose) 25797c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 25807c478bd9Sstevel@tonic-gate "gatherq: %s too long, %d max characters\n", 25817c478bd9Sstevel@tonic-gate d->d_name, MAXQFNAME); 25827c478bd9Sstevel@tonic-gate if (LogLevel > 0) 25837c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, NOQID, 25847c478bd9Sstevel@tonic-gate "gatherq: %s too long, %d max characters", 25857c478bd9Sstevel@tonic-gate d->d_name, MAXQFNAME); 25867c478bd9Sstevel@tonic-gate continue; 25877c478bd9Sstevel@tonic-gate } 25887c478bd9Sstevel@tonic-gate 25897c478bd9Sstevel@tonic-gate check = QueueLimitId; 25907c478bd9Sstevel@tonic-gate while (check != NULL) 25917c478bd9Sstevel@tonic-gate { 25927c478bd9Sstevel@tonic-gate if (strcontainedin(false, check->queue_match, 25937c478bd9Sstevel@tonic-gate d->d_name) != check->queue_negate) 25947c478bd9Sstevel@tonic-gate break; 25957c478bd9Sstevel@tonic-gate else 25967c478bd9Sstevel@tonic-gate check = check->queue_next; 25977c478bd9Sstevel@tonic-gate } 25987c478bd9Sstevel@tonic-gate if (QueueLimitId != NULL && check == NULL) 25997c478bd9Sstevel@tonic-gate continue; 26007c478bd9Sstevel@tonic-gate 26017c478bd9Sstevel@tonic-gate /* grow work list if necessary */ 26027c478bd9Sstevel@tonic-gate if (++wn >= MaxQueueRun && MaxQueueRun > 0) 26037c478bd9Sstevel@tonic-gate { 26047c478bd9Sstevel@tonic-gate if (wn == MaxQueueRun && LogLevel > 0) 26057c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 26067c478bd9Sstevel@tonic-gate "WorkList for %s maxed out at %d", 26077c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), 26087c478bd9Sstevel@tonic-gate MaxQueueRun); 26097c478bd9Sstevel@tonic-gate if (doall) 26107c478bd9Sstevel@tonic-gate continue; /* just count entries */ 26117c478bd9Sstevel@tonic-gate break; 26127c478bd9Sstevel@tonic-gate } 26137c478bd9Sstevel@tonic-gate if (wn >= WorkListSize) 26147c478bd9Sstevel@tonic-gate { 26157c478bd9Sstevel@tonic-gate grow_wlist(qgrp, qdir); 26167c478bd9Sstevel@tonic-gate if (wn >= WorkListSize) 26177c478bd9Sstevel@tonic-gate continue; 26187c478bd9Sstevel@tonic-gate } 26197c478bd9Sstevel@tonic-gate SM_ASSERT(wn >= 0); 26207c478bd9Sstevel@tonic-gate w = &WorkList[wn]; 26217c478bd9Sstevel@tonic-gate 26227c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(qf, sizeof qf, 3, qd, "/", d->d_name); 26237c478bd9Sstevel@tonic-gate if (stat(qf, &sbuf) < 0) 26247c478bd9Sstevel@tonic-gate { 26257c478bd9Sstevel@tonic-gate if (errno != ENOENT) 26267c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 26277c478bd9Sstevel@tonic-gate "gatherq: can't stat %s/%s", 26287c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), 26297c478bd9Sstevel@tonic-gate d->d_name); 26307c478bd9Sstevel@tonic-gate wn--; 26317c478bd9Sstevel@tonic-gate continue; 26327c478bd9Sstevel@tonic-gate } 26337c478bd9Sstevel@tonic-gate if (!bitset(S_IFREG, sbuf.st_mode)) 26347c478bd9Sstevel@tonic-gate { 26357c478bd9Sstevel@tonic-gate /* Yikes! Skip it or we will hang on open! */ 26367c478bd9Sstevel@tonic-gate if (!((d->d_name[0] == DATAFL_LETTER || 26377c478bd9Sstevel@tonic-gate d->d_name[0] == NORMQF_LETTER || 26387c478bd9Sstevel@tonic-gate d->d_name[0] == QUARQF_LETTER || 26397c478bd9Sstevel@tonic-gate d->d_name[0] == LOSEQF_LETTER || 26407c478bd9Sstevel@tonic-gate d->d_name[0] == XSCRPT_LETTER) && 26417c478bd9Sstevel@tonic-gate d->d_name[1] == 'f' && d->d_name[2] == '\0')) 26427c478bd9Sstevel@tonic-gate syserr("gatherq: %s/%s is not a regular file", 26437c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), d->d_name); 26447c478bd9Sstevel@tonic-gate wn--; 26457c478bd9Sstevel@tonic-gate continue; 26467c478bd9Sstevel@tonic-gate } 26477c478bd9Sstevel@tonic-gate 26487c478bd9Sstevel@tonic-gate /* avoid work if possible */ 26497c478bd9Sstevel@tonic-gate if ((QueueSortOrder == QSO_BYFILENAME || 26507c478bd9Sstevel@tonic-gate QueueSortOrder == QSO_BYMODTIME || 26517c478bd9Sstevel@tonic-gate QueueSortOrder == QSO_RANDOM) && 26527c478bd9Sstevel@tonic-gate QueueLimitQuarantine == NULL && 26537c478bd9Sstevel@tonic-gate QueueLimitSender == NULL && 26547c478bd9Sstevel@tonic-gate QueueLimitRecipient == NULL) 26557c478bd9Sstevel@tonic-gate { 26567c478bd9Sstevel@tonic-gate w->w_qgrp = qgrp; 26577c478bd9Sstevel@tonic-gate w->w_qdir = qdir; 26587c478bd9Sstevel@tonic-gate w->w_name = newstr(d->d_name); 26597c478bd9Sstevel@tonic-gate w->w_host = NULL; 26607c478bd9Sstevel@tonic-gate w->w_lock = w->w_tooyoung = false; 26617c478bd9Sstevel@tonic-gate w->w_pri = 0; 26627c478bd9Sstevel@tonic-gate w->w_ctime = 0; 26637c478bd9Sstevel@tonic-gate w->w_mtime = sbuf.st_mtime; 26647c478bd9Sstevel@tonic-gate ++num_ent; 26657c478bd9Sstevel@tonic-gate continue; 26667c478bd9Sstevel@tonic-gate } 26677c478bd9Sstevel@tonic-gate 26687c478bd9Sstevel@tonic-gate /* open control file */ 26697c478bd9Sstevel@tonic-gate cf = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY_B, 26707c478bd9Sstevel@tonic-gate NULL); 26717c478bd9Sstevel@tonic-gate if (cf == NULL && OpMode != MD_PRINT) 26727c478bd9Sstevel@tonic-gate { 26737c478bd9Sstevel@tonic-gate /* this may be some random person sending hir msgs */ 26747c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 26757c478bd9Sstevel@tonic-gate sm_dprintf("gatherq: cannot open %s: %s\n", 26767c478bd9Sstevel@tonic-gate d->d_name, sm_errstring(errno)); 26777c478bd9Sstevel@tonic-gate errno = 0; 26787c478bd9Sstevel@tonic-gate wn--; 26797c478bd9Sstevel@tonic-gate continue; 26807c478bd9Sstevel@tonic-gate } 26817c478bd9Sstevel@tonic-gate w->w_qgrp = qgrp; 26827c478bd9Sstevel@tonic-gate w->w_qdir = qdir; 26837c478bd9Sstevel@tonic-gate w->w_name = newstr(d->d_name); 26847c478bd9Sstevel@tonic-gate w->w_host = NULL; 26857c478bd9Sstevel@tonic-gate if (cf != NULL) 26867c478bd9Sstevel@tonic-gate { 26877c478bd9Sstevel@tonic-gate w->w_lock = !lockfile(sm_io_getinfo(cf, SM_IO_WHAT_FD, 26887c478bd9Sstevel@tonic-gate NULL), 26897c478bd9Sstevel@tonic-gate w->w_name, NULL, 26907c478bd9Sstevel@tonic-gate LOCK_SH|LOCK_NB); 26917c478bd9Sstevel@tonic-gate } 26927c478bd9Sstevel@tonic-gate w->w_tooyoung = false; 26937c478bd9Sstevel@tonic-gate 26947c478bd9Sstevel@tonic-gate /* make sure jobs in creation don't clog queue */ 26957c478bd9Sstevel@tonic-gate w->w_pri = 0x7fffffff; 26967c478bd9Sstevel@tonic-gate w->w_ctime = 0; 26977c478bd9Sstevel@tonic-gate w->w_mtime = sbuf.st_mtime; 26987c478bd9Sstevel@tonic-gate 26997c478bd9Sstevel@tonic-gate /* extract useful information */ 27007c478bd9Sstevel@tonic-gate i = NEED_P|NEED_T; 27017c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST 27027c478bd9Sstevel@tonic-gate #if _FFR_RHS 27037c478bd9Sstevel@tonic-gate || QueueSortOrder == QSO_BYSHUFFLE 27047c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 27057c478bd9Sstevel@tonic-gate ) 27067c478bd9Sstevel@tonic-gate { 27077c478bd9Sstevel@tonic-gate /* need w_host set for host sort order */ 27087c478bd9Sstevel@tonic-gate i |= NEED_H; 27097c478bd9Sstevel@tonic-gate } 27107c478bd9Sstevel@tonic-gate if (QueueLimitSender != NULL) 27117c478bd9Sstevel@tonic-gate i |= NEED_S; 27127c478bd9Sstevel@tonic-gate if (QueueLimitRecipient != NULL) 27137c478bd9Sstevel@tonic-gate i |= NEED_R; 27147c478bd9Sstevel@tonic-gate if (QueueLimitQuarantine != NULL) 27157c478bd9Sstevel@tonic-gate i |= NEED_QUARANTINE; 27167c478bd9Sstevel@tonic-gate while (cf != NULL && i != 0 && 27177c478bd9Sstevel@tonic-gate sm_io_fgets(cf, SM_TIME_DEFAULT, lbuf, 27187c478bd9Sstevel@tonic-gate sizeof lbuf) != NULL) 27197c478bd9Sstevel@tonic-gate { 27207c478bd9Sstevel@tonic-gate int c; 27217c478bd9Sstevel@tonic-gate time_t age; 27227c478bd9Sstevel@tonic-gate 27237c478bd9Sstevel@tonic-gate p = strchr(lbuf, '\n'); 27247c478bd9Sstevel@tonic-gate if (p != NULL) 27257c478bd9Sstevel@tonic-gate *p = '\0'; 27267c478bd9Sstevel@tonic-gate else 27277c478bd9Sstevel@tonic-gate { 27287c478bd9Sstevel@tonic-gate /* flush rest of overly long line */ 27297c478bd9Sstevel@tonic-gate while ((c = sm_io_getc(cf, SM_TIME_DEFAULT)) 27307c478bd9Sstevel@tonic-gate != SM_IO_EOF && c != '\n') 27317c478bd9Sstevel@tonic-gate continue; 27327c478bd9Sstevel@tonic-gate } 27337c478bd9Sstevel@tonic-gate 27347c478bd9Sstevel@tonic-gate switch (lbuf[0]) 27357c478bd9Sstevel@tonic-gate { 27367c478bd9Sstevel@tonic-gate case 'V': 27377c478bd9Sstevel@tonic-gate qfver = atoi(&lbuf[1]); 27387c478bd9Sstevel@tonic-gate break; 27397c478bd9Sstevel@tonic-gate 27407c478bd9Sstevel@tonic-gate case 'P': 27417c478bd9Sstevel@tonic-gate w->w_pri = atol(&lbuf[1]); 27427c478bd9Sstevel@tonic-gate i &= ~NEED_P; 27437c478bd9Sstevel@tonic-gate break; 27447c478bd9Sstevel@tonic-gate 27457c478bd9Sstevel@tonic-gate case 'T': 27467c478bd9Sstevel@tonic-gate w->w_ctime = atol(&lbuf[1]); 27477c478bd9Sstevel@tonic-gate i &= ~NEED_T; 27487c478bd9Sstevel@tonic-gate break; 27497c478bd9Sstevel@tonic-gate 27507c478bd9Sstevel@tonic-gate case 'q': 27517c478bd9Sstevel@tonic-gate if (QueueMode != QM_QUARANTINE && 27527c478bd9Sstevel@tonic-gate QueueMode != QM_LOST) 27537c478bd9Sstevel@tonic-gate { 27547c478bd9Sstevel@tonic-gate if (tTd(41, 49)) 27557c478bd9Sstevel@tonic-gate sm_dprintf("%s not marked as quarantined but has a 'q' line\n", 27567c478bd9Sstevel@tonic-gate w->w_name); 27577c478bd9Sstevel@tonic-gate i |= HAS_QUARANTINE; 27587c478bd9Sstevel@tonic-gate } 27597c478bd9Sstevel@tonic-gate else if (QueueMode == QM_QUARANTINE) 27607c478bd9Sstevel@tonic-gate { 27617c478bd9Sstevel@tonic-gate if (QueueLimitQuarantine == NULL) 27627c478bd9Sstevel@tonic-gate { 27637c478bd9Sstevel@tonic-gate i &= ~NEED_QUARANTINE; 27647c478bd9Sstevel@tonic-gate break; 27657c478bd9Sstevel@tonic-gate } 27667c478bd9Sstevel@tonic-gate p = &lbuf[1]; 27677c478bd9Sstevel@tonic-gate check = QueueLimitQuarantine; 27687c478bd9Sstevel@tonic-gate while (check != NULL) 27697c478bd9Sstevel@tonic-gate { 27707c478bd9Sstevel@tonic-gate if (strcontainedin(false, 27717c478bd9Sstevel@tonic-gate check->queue_match, 27727c478bd9Sstevel@tonic-gate p) != 27737c478bd9Sstevel@tonic-gate check->queue_negate) 27747c478bd9Sstevel@tonic-gate break; 27757c478bd9Sstevel@tonic-gate else 27767c478bd9Sstevel@tonic-gate check = check->queue_next; 27777c478bd9Sstevel@tonic-gate } 27787c478bd9Sstevel@tonic-gate if (check != NULL) 27797c478bd9Sstevel@tonic-gate i &= ~NEED_QUARANTINE; 27807c478bd9Sstevel@tonic-gate } 27817c478bd9Sstevel@tonic-gate break; 27827c478bd9Sstevel@tonic-gate 27837c478bd9Sstevel@tonic-gate case 'R': 27847c478bd9Sstevel@tonic-gate if (w->w_host == NULL && 27857c478bd9Sstevel@tonic-gate (p = strrchr(&lbuf[1], '@')) != NULL) 27867c478bd9Sstevel@tonic-gate { 27877c478bd9Sstevel@tonic-gate #if _FFR_RHS 27887c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYSHUFFLE) 27897c478bd9Sstevel@tonic-gate w->w_host = newstr(&p[1]); 27907c478bd9Sstevel@tonic-gate else 27917c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 27927c478bd9Sstevel@tonic-gate w->w_host = strrev(&p[1]); 27937c478bd9Sstevel@tonic-gate makelower(w->w_host); 27947c478bd9Sstevel@tonic-gate i &= ~NEED_H; 27957c478bd9Sstevel@tonic-gate } 27967c478bd9Sstevel@tonic-gate if (QueueLimitRecipient == NULL) 27977c478bd9Sstevel@tonic-gate { 27987c478bd9Sstevel@tonic-gate i &= ~NEED_R; 27997c478bd9Sstevel@tonic-gate break; 28007c478bd9Sstevel@tonic-gate } 28017c478bd9Sstevel@tonic-gate if (qfver > 0) 28027c478bd9Sstevel@tonic-gate { 28037c478bd9Sstevel@tonic-gate p = strchr(&lbuf[1], ':'); 28047c478bd9Sstevel@tonic-gate if (p == NULL) 28057c478bd9Sstevel@tonic-gate p = &lbuf[1]; 28067c478bd9Sstevel@tonic-gate else 28077c478bd9Sstevel@tonic-gate ++p; /* skip over ':' */ 28087c478bd9Sstevel@tonic-gate } 28097c478bd9Sstevel@tonic-gate else 28107c478bd9Sstevel@tonic-gate p = &lbuf[1]; 28117c478bd9Sstevel@tonic-gate check = QueueLimitRecipient; 28127c478bd9Sstevel@tonic-gate while (check != NULL) 28137c478bd9Sstevel@tonic-gate { 28147c478bd9Sstevel@tonic-gate if (strcontainedin(true, 28157c478bd9Sstevel@tonic-gate check->queue_match, 28167c478bd9Sstevel@tonic-gate p) != 28177c478bd9Sstevel@tonic-gate check->queue_negate) 28187c478bd9Sstevel@tonic-gate break; 28197c478bd9Sstevel@tonic-gate else 28207c478bd9Sstevel@tonic-gate check = check->queue_next; 28217c478bd9Sstevel@tonic-gate } 28227c478bd9Sstevel@tonic-gate if (check != NULL) 28237c478bd9Sstevel@tonic-gate i &= ~NEED_R; 28247c478bd9Sstevel@tonic-gate break; 28257c478bd9Sstevel@tonic-gate 28267c478bd9Sstevel@tonic-gate case 'S': 28277c478bd9Sstevel@tonic-gate check = QueueLimitSender; 28287c478bd9Sstevel@tonic-gate while (check != NULL) 28297c478bd9Sstevel@tonic-gate { 28307c478bd9Sstevel@tonic-gate if (strcontainedin(true, 28317c478bd9Sstevel@tonic-gate check->queue_match, 28327c478bd9Sstevel@tonic-gate &lbuf[1]) != 28337c478bd9Sstevel@tonic-gate check->queue_negate) 28347c478bd9Sstevel@tonic-gate break; 28357c478bd9Sstevel@tonic-gate else 28367c478bd9Sstevel@tonic-gate check = check->queue_next; 28377c478bd9Sstevel@tonic-gate } 28387c478bd9Sstevel@tonic-gate if (check != NULL) 28397c478bd9Sstevel@tonic-gate i &= ~NEED_S; 28407c478bd9Sstevel@tonic-gate break; 28417c478bd9Sstevel@tonic-gate 28427c478bd9Sstevel@tonic-gate case 'K': 28437c478bd9Sstevel@tonic-gate age = curtime() - (time_t) atol(&lbuf[1]); 28447c478bd9Sstevel@tonic-gate if (age >= 0 && MinQueueAge > 0 && 28457c478bd9Sstevel@tonic-gate age < MinQueueAge) 28467c478bd9Sstevel@tonic-gate w->w_tooyoung = true; 28477c478bd9Sstevel@tonic-gate break; 28487c478bd9Sstevel@tonic-gate 28497c478bd9Sstevel@tonic-gate case 'N': 28507c478bd9Sstevel@tonic-gate if (atol(&lbuf[1]) == 0) 28517c478bd9Sstevel@tonic-gate w->w_tooyoung = false; 28527c478bd9Sstevel@tonic-gate break; 28537c478bd9Sstevel@tonic-gate } 28547c478bd9Sstevel@tonic-gate } 28557c478bd9Sstevel@tonic-gate if (cf != NULL) 28567c478bd9Sstevel@tonic-gate (void) sm_io_close(cf, SM_TIME_DEFAULT); 28577c478bd9Sstevel@tonic-gate 2858*445f2479Sjbeck if ((!doall && (shouldqueue(w->w_pri, w->w_ctime) || 2859*445f2479Sjbeck w->w_tooyoung)) || 28607c478bd9Sstevel@tonic-gate bitset(HAS_QUARANTINE, i) || 28617c478bd9Sstevel@tonic-gate bitset(NEED_QUARANTINE, i) || 28627c478bd9Sstevel@tonic-gate bitset(NEED_R|NEED_S, i)) 28637c478bd9Sstevel@tonic-gate { 28647c478bd9Sstevel@tonic-gate /* don't even bother sorting this job in */ 28657c478bd9Sstevel@tonic-gate if (tTd(41, 49)) 28667c478bd9Sstevel@tonic-gate sm_dprintf("skipping %s (%x)\n", w->w_name, i); 28677c478bd9Sstevel@tonic-gate sm_free(w->w_name); /* XXX */ 28687c478bd9Sstevel@tonic-gate if (w->w_host != NULL) 28697c478bd9Sstevel@tonic-gate sm_free(w->w_host); /* XXX */ 28707c478bd9Sstevel@tonic-gate wn--; 28717c478bd9Sstevel@tonic-gate } 28727c478bd9Sstevel@tonic-gate else 28737c478bd9Sstevel@tonic-gate ++num_ent; 28747c478bd9Sstevel@tonic-gate } 28757c478bd9Sstevel@tonic-gate (void) closedir(f); 28767c478bd9Sstevel@tonic-gate wn++; 28777c478bd9Sstevel@tonic-gate 28787c478bd9Sstevel@tonic-gate i = wn - WorkListCount; 28797c478bd9Sstevel@tonic-gate WorkListCount += SM_MIN(num_ent, WorkListSize); 28807c478bd9Sstevel@tonic-gate 28817c478bd9Sstevel@tonic-gate if (more != NULL) 28827c478bd9Sstevel@tonic-gate *more = WorkListCount < wn; 28837c478bd9Sstevel@tonic-gate 28847c478bd9Sstevel@tonic-gate if (full != NULL) 28857c478bd9Sstevel@tonic-gate *full = (wn >= MaxQueueRun && MaxQueueRun > 0) || 28867c478bd9Sstevel@tonic-gate (WorkList == NULL && wn > 0); 28877c478bd9Sstevel@tonic-gate 28887c478bd9Sstevel@tonic-gate return i; 28897c478bd9Sstevel@tonic-gate } 28907c478bd9Sstevel@tonic-gate /* 28917c478bd9Sstevel@tonic-gate ** SORTQ -- sort the work list 28927c478bd9Sstevel@tonic-gate ** 28937c478bd9Sstevel@tonic-gate ** First the old WorkQ is cleared away. Then the WorkList is sorted 28947c478bd9Sstevel@tonic-gate ** for all items so that important (higher sorting value) items are not 28957c478bd9Sstevel@tonic-gate ** trunctated off. Then the most important items are moved from 28967c478bd9Sstevel@tonic-gate ** WorkList to WorkQ. The lower count of 'max' or MaxListCount items 28977c478bd9Sstevel@tonic-gate ** are moved. 28987c478bd9Sstevel@tonic-gate ** 28997c478bd9Sstevel@tonic-gate ** Parameters: 29007c478bd9Sstevel@tonic-gate ** max -- maximum number of items to be placed in WorkQ 29017c478bd9Sstevel@tonic-gate ** 29027c478bd9Sstevel@tonic-gate ** Returns: 29037c478bd9Sstevel@tonic-gate ** the number of items in WorkQ 29047c478bd9Sstevel@tonic-gate ** 29057c478bd9Sstevel@tonic-gate ** Side Effects: 29067c478bd9Sstevel@tonic-gate ** WorkQ gets released and filled with new work. WorkList 29077c478bd9Sstevel@tonic-gate ** gets released. Work items get sorted in order. 29087c478bd9Sstevel@tonic-gate */ 29097c478bd9Sstevel@tonic-gate 29107c478bd9Sstevel@tonic-gate static int 29117c478bd9Sstevel@tonic-gate sortq(max) 29127c478bd9Sstevel@tonic-gate int max; 29137c478bd9Sstevel@tonic-gate { 29147c478bd9Sstevel@tonic-gate register int i; /* local counter */ 29157c478bd9Sstevel@tonic-gate register WORK *w; /* tmp item pointer */ 29167c478bd9Sstevel@tonic-gate int wc = WorkListCount; /* trim size for WorkQ */ 29177c478bd9Sstevel@tonic-gate 29187c478bd9Sstevel@tonic-gate if (WorkQ != NULL) 29197c478bd9Sstevel@tonic-gate { 29207c478bd9Sstevel@tonic-gate WORK *nw; 29217c478bd9Sstevel@tonic-gate 29227c478bd9Sstevel@tonic-gate /* Clear out old WorkQ. */ 29237c478bd9Sstevel@tonic-gate for (w = WorkQ; w != NULL; w = nw) 29247c478bd9Sstevel@tonic-gate { 29257c478bd9Sstevel@tonic-gate nw = w->w_next; 29267c478bd9Sstevel@tonic-gate sm_free(w->w_name); /* XXX */ 29277c478bd9Sstevel@tonic-gate if (w->w_host != NULL) 29287c478bd9Sstevel@tonic-gate sm_free(w->w_host); /* XXX */ 29297c478bd9Sstevel@tonic-gate sm_free((char *) w); /* XXX */ 29307c478bd9Sstevel@tonic-gate } 29317c478bd9Sstevel@tonic-gate WorkQ = NULL; 29327c478bd9Sstevel@tonic-gate } 29337c478bd9Sstevel@tonic-gate 29347c478bd9Sstevel@tonic-gate if (WorkList == NULL || wc <= 0) 29357c478bd9Sstevel@tonic-gate return 0; 29367c478bd9Sstevel@tonic-gate 29377c478bd9Sstevel@tonic-gate /* 29387c478bd9Sstevel@tonic-gate ** The sort now takes place using all of the items in WorkList. 29397c478bd9Sstevel@tonic-gate ** The list gets trimmed to the most important items after the sort. 29407c478bd9Sstevel@tonic-gate ** If the trim were to happen before the sort then one or more 29417c478bd9Sstevel@tonic-gate ** important items might get truncated off -- not what we want. 29427c478bd9Sstevel@tonic-gate */ 29437c478bd9Sstevel@tonic-gate 29447c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST) 29457c478bd9Sstevel@tonic-gate { 29467c478bd9Sstevel@tonic-gate /* 29477c478bd9Sstevel@tonic-gate ** Sort the work directory for the first time, 29487c478bd9Sstevel@tonic-gate ** based on host name, lock status, and priority. 29497c478bd9Sstevel@tonic-gate */ 29507c478bd9Sstevel@tonic-gate 29517c478bd9Sstevel@tonic-gate qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1); 29527c478bd9Sstevel@tonic-gate 29537c478bd9Sstevel@tonic-gate /* 29547c478bd9Sstevel@tonic-gate ** If one message to host is locked, "lock" all messages 29557c478bd9Sstevel@tonic-gate ** to that host. 29567c478bd9Sstevel@tonic-gate */ 29577c478bd9Sstevel@tonic-gate 29587c478bd9Sstevel@tonic-gate i = 0; 29597c478bd9Sstevel@tonic-gate while (i < wc) 29607c478bd9Sstevel@tonic-gate { 29617c478bd9Sstevel@tonic-gate if (!WorkList[i].w_lock) 29627c478bd9Sstevel@tonic-gate { 29637c478bd9Sstevel@tonic-gate i++; 29647c478bd9Sstevel@tonic-gate continue; 29657c478bd9Sstevel@tonic-gate } 29667c478bd9Sstevel@tonic-gate w = &WorkList[i]; 29677c478bd9Sstevel@tonic-gate while (++i < wc) 29687c478bd9Sstevel@tonic-gate { 29697c478bd9Sstevel@tonic-gate if (WorkList[i].w_host == NULL && 29707c478bd9Sstevel@tonic-gate w->w_host == NULL) 29717c478bd9Sstevel@tonic-gate WorkList[i].w_lock = true; 29727c478bd9Sstevel@tonic-gate else if (WorkList[i].w_host != NULL && 29737c478bd9Sstevel@tonic-gate w->w_host != NULL && 29747c478bd9Sstevel@tonic-gate sm_strcasecmp(WorkList[i].w_host, 29757c478bd9Sstevel@tonic-gate w->w_host) == 0) 29767c478bd9Sstevel@tonic-gate WorkList[i].w_lock = true; 29777c478bd9Sstevel@tonic-gate else 29787c478bd9Sstevel@tonic-gate break; 29797c478bd9Sstevel@tonic-gate } 29807c478bd9Sstevel@tonic-gate } 29817c478bd9Sstevel@tonic-gate 29827c478bd9Sstevel@tonic-gate /* 29837c478bd9Sstevel@tonic-gate ** Sort the work directory for the second time, 29847c478bd9Sstevel@tonic-gate ** based on lock status, host name, and priority. 29857c478bd9Sstevel@tonic-gate */ 29867c478bd9Sstevel@tonic-gate 29877c478bd9Sstevel@tonic-gate qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2); 29887c478bd9Sstevel@tonic-gate } 29897c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYTIME) 29907c478bd9Sstevel@tonic-gate { 29917c478bd9Sstevel@tonic-gate /* 29927c478bd9Sstevel@tonic-gate ** Simple sort based on submission time only. 29937c478bd9Sstevel@tonic-gate */ 29947c478bd9Sstevel@tonic-gate 29957c478bd9Sstevel@tonic-gate qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf3); 29967c478bd9Sstevel@tonic-gate } 29977c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYFILENAME) 29987c478bd9Sstevel@tonic-gate { 29997c478bd9Sstevel@tonic-gate /* 30007c478bd9Sstevel@tonic-gate ** Sort based on queue filename. 30017c478bd9Sstevel@tonic-gate */ 30027c478bd9Sstevel@tonic-gate 30037c478bd9Sstevel@tonic-gate qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf4); 30047c478bd9Sstevel@tonic-gate } 30057c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_RANDOM) 30067c478bd9Sstevel@tonic-gate { 30077c478bd9Sstevel@tonic-gate /* 30087c478bd9Sstevel@tonic-gate ** Sort randomly. To avoid problems with an instable sort, 30097c478bd9Sstevel@tonic-gate ** use a random index into the queue file name to start 30107c478bd9Sstevel@tonic-gate ** comparison. 30117c478bd9Sstevel@tonic-gate */ 30127c478bd9Sstevel@tonic-gate 30137c478bd9Sstevel@tonic-gate randi = get_rand_mod(MAXQFNAME); 30147c478bd9Sstevel@tonic-gate if (randi < 2) 30157c478bd9Sstevel@tonic-gate randi = 3; 30167c478bd9Sstevel@tonic-gate qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf5); 30177c478bd9Sstevel@tonic-gate } 30187c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYMODTIME) 30197c478bd9Sstevel@tonic-gate { 30207c478bd9Sstevel@tonic-gate /* 30217c478bd9Sstevel@tonic-gate ** Simple sort based on modification time of queue file. 30227c478bd9Sstevel@tonic-gate ** This puts the oldest items first. 30237c478bd9Sstevel@tonic-gate */ 30247c478bd9Sstevel@tonic-gate 30257c478bd9Sstevel@tonic-gate qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf6); 30267c478bd9Sstevel@tonic-gate } 30277c478bd9Sstevel@tonic-gate #if _FFR_RHS 30287c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYSHUFFLE) 30297c478bd9Sstevel@tonic-gate { 30307c478bd9Sstevel@tonic-gate /* 30317c478bd9Sstevel@tonic-gate ** Simple sort based on shuffled host name. 30327c478bd9Sstevel@tonic-gate */ 30337c478bd9Sstevel@tonic-gate 30347c478bd9Sstevel@tonic-gate init_shuffle_alphabet(); 30357c478bd9Sstevel@tonic-gate qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf7); 30367c478bd9Sstevel@tonic-gate } 30377c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 30387c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYPRIORITY) 30397c478bd9Sstevel@tonic-gate { 30407c478bd9Sstevel@tonic-gate /* 30417c478bd9Sstevel@tonic-gate ** Simple sort based on queue priority only. 30427c478bd9Sstevel@tonic-gate */ 30437c478bd9Sstevel@tonic-gate 30447c478bd9Sstevel@tonic-gate qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0); 30457c478bd9Sstevel@tonic-gate } 30467c478bd9Sstevel@tonic-gate /* else don't sort at all */ 30477c478bd9Sstevel@tonic-gate 304849218d4fSjbeck /* Check if the per queue group item limit will be exceeded */ 304949218d4fSjbeck if (wc > max && max > 0) 305049218d4fSjbeck wc = max; 305149218d4fSjbeck 30527c478bd9Sstevel@tonic-gate /* 30537c478bd9Sstevel@tonic-gate ** Convert the work list into canonical form. 30547c478bd9Sstevel@tonic-gate ** Should be turning it into a list of envelopes here perhaps. 30557c478bd9Sstevel@tonic-gate ** Only take the most important items up to the per queue group 30567c478bd9Sstevel@tonic-gate ** maximum. 30577c478bd9Sstevel@tonic-gate */ 30587c478bd9Sstevel@tonic-gate 30597c478bd9Sstevel@tonic-gate for (i = wc; --i >= 0; ) 30607c478bd9Sstevel@tonic-gate { 30617c478bd9Sstevel@tonic-gate w = (WORK *) xalloc(sizeof *w); 30627c478bd9Sstevel@tonic-gate w->w_qgrp = WorkList[i].w_qgrp; 30637c478bd9Sstevel@tonic-gate w->w_qdir = WorkList[i].w_qdir; 30647c478bd9Sstevel@tonic-gate w->w_name = WorkList[i].w_name; 30657c478bd9Sstevel@tonic-gate w->w_host = WorkList[i].w_host; 30667c478bd9Sstevel@tonic-gate w->w_lock = WorkList[i].w_lock; 30677c478bd9Sstevel@tonic-gate w->w_tooyoung = WorkList[i].w_tooyoung; 30687c478bd9Sstevel@tonic-gate w->w_pri = WorkList[i].w_pri; 30697c478bd9Sstevel@tonic-gate w->w_ctime = WorkList[i].w_ctime; 30707c478bd9Sstevel@tonic-gate w->w_mtime = WorkList[i].w_mtime; 30717c478bd9Sstevel@tonic-gate w->w_next = WorkQ; 30727c478bd9Sstevel@tonic-gate WorkQ = w; 30737c478bd9Sstevel@tonic-gate } 30747c478bd9Sstevel@tonic-gate 30757c478bd9Sstevel@tonic-gate /* free the rest of the list */ 30767c478bd9Sstevel@tonic-gate for (i = WorkListCount; --i >= wc; ) 30777c478bd9Sstevel@tonic-gate { 30787c478bd9Sstevel@tonic-gate sm_free(WorkList[i].w_name); 30797c478bd9Sstevel@tonic-gate if (WorkList[i].w_host != NULL) 30807c478bd9Sstevel@tonic-gate sm_free(WorkList[i].w_host); 30817c478bd9Sstevel@tonic-gate } 30827c478bd9Sstevel@tonic-gate 30837c478bd9Sstevel@tonic-gate if (WorkList != NULL) 30847c478bd9Sstevel@tonic-gate sm_free(WorkList); /* XXX */ 30857c478bd9Sstevel@tonic-gate WorkList = NULL; 30867c478bd9Sstevel@tonic-gate WorkListSize = 0; 30877c478bd9Sstevel@tonic-gate WorkListCount = 0; 30887c478bd9Sstevel@tonic-gate 30897c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 30907c478bd9Sstevel@tonic-gate { 30917c478bd9Sstevel@tonic-gate for (w = WorkQ; w != NULL; w = w->w_next) 30927c478bd9Sstevel@tonic-gate { 30937c478bd9Sstevel@tonic-gate if (w->w_host != NULL) 30947c478bd9Sstevel@tonic-gate sm_dprintf("%22s: pri=%ld %s\n", 30957c478bd9Sstevel@tonic-gate w->w_name, w->w_pri, w->w_host); 30967c478bd9Sstevel@tonic-gate else 30977c478bd9Sstevel@tonic-gate sm_dprintf("%32s: pri=%ld\n", 30987c478bd9Sstevel@tonic-gate w->w_name, w->w_pri); 30997c478bd9Sstevel@tonic-gate } 31007c478bd9Sstevel@tonic-gate } 31017c478bd9Sstevel@tonic-gate 31027c478bd9Sstevel@tonic-gate return wc; /* return number of WorkQ items */ 31037c478bd9Sstevel@tonic-gate } 31047c478bd9Sstevel@tonic-gate /* 31057c478bd9Sstevel@tonic-gate ** GROW_WLIST -- make the work list larger 31067c478bd9Sstevel@tonic-gate ** 31077c478bd9Sstevel@tonic-gate ** Parameters: 31087c478bd9Sstevel@tonic-gate ** qgrp -- the index for the queue group. 31097c478bd9Sstevel@tonic-gate ** qdir -- the index for the queue directory. 31107c478bd9Sstevel@tonic-gate ** 31117c478bd9Sstevel@tonic-gate ** Returns: 31127c478bd9Sstevel@tonic-gate ** none. 31137c478bd9Sstevel@tonic-gate ** 31147c478bd9Sstevel@tonic-gate ** Side Effects: 31157c478bd9Sstevel@tonic-gate ** Adds another QUEUESEGSIZE entries to WorkList if possible. 31167c478bd9Sstevel@tonic-gate ** It can fail if there isn't enough memory, so WorkListSize 31177c478bd9Sstevel@tonic-gate ** should be checked again upon return. 31187c478bd9Sstevel@tonic-gate */ 31197c478bd9Sstevel@tonic-gate 31207c478bd9Sstevel@tonic-gate static void 31217c478bd9Sstevel@tonic-gate grow_wlist(qgrp, qdir) 31227c478bd9Sstevel@tonic-gate int qgrp; 31237c478bd9Sstevel@tonic-gate int qdir; 31247c478bd9Sstevel@tonic-gate { 31257c478bd9Sstevel@tonic-gate if (tTd(41, 1)) 31267c478bd9Sstevel@tonic-gate sm_dprintf("grow_wlist: WorkListSize=%d\n", WorkListSize); 31277c478bd9Sstevel@tonic-gate if (WorkList == NULL) 31287c478bd9Sstevel@tonic-gate { 31297c478bd9Sstevel@tonic-gate WorkList = (WORK *) xalloc((sizeof *WorkList) * 31307c478bd9Sstevel@tonic-gate (QUEUESEGSIZE + 1)); 31317c478bd9Sstevel@tonic-gate WorkListSize = QUEUESEGSIZE; 31327c478bd9Sstevel@tonic-gate } 31337c478bd9Sstevel@tonic-gate else 31347c478bd9Sstevel@tonic-gate { 31357c478bd9Sstevel@tonic-gate int newsize = WorkListSize + QUEUESEGSIZE; 31367c478bd9Sstevel@tonic-gate WORK *newlist = (WORK *) sm_realloc((char *) WorkList, 31377c478bd9Sstevel@tonic-gate (unsigned) sizeof(WORK) * (newsize + 1)); 31387c478bd9Sstevel@tonic-gate 31397c478bd9Sstevel@tonic-gate if (newlist != NULL) 31407c478bd9Sstevel@tonic-gate { 31417c478bd9Sstevel@tonic-gate WorkListSize = newsize; 31427c478bd9Sstevel@tonic-gate WorkList = newlist; 31437c478bd9Sstevel@tonic-gate if (LogLevel > 1) 31447c478bd9Sstevel@tonic-gate { 31457c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 31467c478bd9Sstevel@tonic-gate "grew WorkList for %s to %d", 31477c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), 31487c478bd9Sstevel@tonic-gate WorkListSize); 31497c478bd9Sstevel@tonic-gate } 31507c478bd9Sstevel@tonic-gate } 31517c478bd9Sstevel@tonic-gate else if (LogLevel > 0) 31527c478bd9Sstevel@tonic-gate { 31537c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, NOQID, 31547c478bd9Sstevel@tonic-gate "FAILED to grow WorkList for %s to %d", 31557c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), newsize); 31567c478bd9Sstevel@tonic-gate } 31577c478bd9Sstevel@tonic-gate } 31587c478bd9Sstevel@tonic-gate if (tTd(41, 1)) 31597c478bd9Sstevel@tonic-gate sm_dprintf("grow_wlist: WorkListSize now %d\n", WorkListSize); 31607c478bd9Sstevel@tonic-gate } 31617c478bd9Sstevel@tonic-gate /* 31627c478bd9Sstevel@tonic-gate ** WORKCMPF0 -- simple priority-only compare function. 31637c478bd9Sstevel@tonic-gate ** 31647c478bd9Sstevel@tonic-gate ** Parameters: 31657c478bd9Sstevel@tonic-gate ** a -- the first argument. 31667c478bd9Sstevel@tonic-gate ** b -- the second argument. 31677c478bd9Sstevel@tonic-gate ** 31687c478bd9Sstevel@tonic-gate ** Returns: 31697c478bd9Sstevel@tonic-gate ** -1 if a < b 31707c478bd9Sstevel@tonic-gate ** 0 if a == b 31717c478bd9Sstevel@tonic-gate ** +1 if a > b 31727c478bd9Sstevel@tonic-gate ** 31737c478bd9Sstevel@tonic-gate */ 31747c478bd9Sstevel@tonic-gate 31757c478bd9Sstevel@tonic-gate static int 31767c478bd9Sstevel@tonic-gate workcmpf0(a, b) 31777c478bd9Sstevel@tonic-gate register WORK *a; 31787c478bd9Sstevel@tonic-gate register WORK *b; 31797c478bd9Sstevel@tonic-gate { 31807c478bd9Sstevel@tonic-gate long pa = a->w_pri; 31817c478bd9Sstevel@tonic-gate long pb = b->w_pri; 31827c478bd9Sstevel@tonic-gate 31837c478bd9Sstevel@tonic-gate if (pa == pb) 31847c478bd9Sstevel@tonic-gate return 0; 31857c478bd9Sstevel@tonic-gate else if (pa > pb) 31867c478bd9Sstevel@tonic-gate return 1; 31877c478bd9Sstevel@tonic-gate else 31887c478bd9Sstevel@tonic-gate return -1; 31897c478bd9Sstevel@tonic-gate } 31907c478bd9Sstevel@tonic-gate /* 31917c478bd9Sstevel@tonic-gate ** WORKCMPF1 -- first compare function for ordering work based on host name. 31927c478bd9Sstevel@tonic-gate ** 31937c478bd9Sstevel@tonic-gate ** Sorts on host name, lock status, and priority in that order. 31947c478bd9Sstevel@tonic-gate ** 31957c478bd9Sstevel@tonic-gate ** Parameters: 31967c478bd9Sstevel@tonic-gate ** a -- the first argument. 31977c478bd9Sstevel@tonic-gate ** b -- the second argument. 31987c478bd9Sstevel@tonic-gate ** 31997c478bd9Sstevel@tonic-gate ** Returns: 32007c478bd9Sstevel@tonic-gate ** <0 if a < b 32017c478bd9Sstevel@tonic-gate ** 0 if a == b 32027c478bd9Sstevel@tonic-gate ** >0 if a > b 32037c478bd9Sstevel@tonic-gate ** 32047c478bd9Sstevel@tonic-gate */ 32057c478bd9Sstevel@tonic-gate 32067c478bd9Sstevel@tonic-gate static int 32077c478bd9Sstevel@tonic-gate workcmpf1(a, b) 32087c478bd9Sstevel@tonic-gate register WORK *a; 32097c478bd9Sstevel@tonic-gate register WORK *b; 32107c478bd9Sstevel@tonic-gate { 32117c478bd9Sstevel@tonic-gate int i; 32127c478bd9Sstevel@tonic-gate 32137c478bd9Sstevel@tonic-gate /* host name */ 32147c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host == NULL) 32157c478bd9Sstevel@tonic-gate return 1; 32167c478bd9Sstevel@tonic-gate else if (a->w_host == NULL && b->w_host != NULL) 32177c478bd9Sstevel@tonic-gate return -1; 32187c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host != NULL && 32197c478bd9Sstevel@tonic-gate (i = sm_strcasecmp(a->w_host, b->w_host)) != 0) 32207c478bd9Sstevel@tonic-gate return i; 32217c478bd9Sstevel@tonic-gate 32227c478bd9Sstevel@tonic-gate /* lock status */ 32237c478bd9Sstevel@tonic-gate if (a->w_lock != b->w_lock) 32247c478bd9Sstevel@tonic-gate return b->w_lock - a->w_lock; 32257c478bd9Sstevel@tonic-gate 32267c478bd9Sstevel@tonic-gate /* job priority */ 32277c478bd9Sstevel@tonic-gate return workcmpf0(a, b); 32287c478bd9Sstevel@tonic-gate } 32297c478bd9Sstevel@tonic-gate /* 32307c478bd9Sstevel@tonic-gate ** WORKCMPF2 -- second compare function for ordering work based on host name. 32317c478bd9Sstevel@tonic-gate ** 32327c478bd9Sstevel@tonic-gate ** Sorts on lock status, host name, and priority in that order. 32337c478bd9Sstevel@tonic-gate ** 32347c478bd9Sstevel@tonic-gate ** Parameters: 32357c478bd9Sstevel@tonic-gate ** a -- the first argument. 32367c478bd9Sstevel@tonic-gate ** b -- the second argument. 32377c478bd9Sstevel@tonic-gate ** 32387c478bd9Sstevel@tonic-gate ** Returns: 32397c478bd9Sstevel@tonic-gate ** <0 if a < b 32407c478bd9Sstevel@tonic-gate ** 0 if a == b 32417c478bd9Sstevel@tonic-gate ** >0 if a > b 32427c478bd9Sstevel@tonic-gate ** 32437c478bd9Sstevel@tonic-gate */ 32447c478bd9Sstevel@tonic-gate 32457c478bd9Sstevel@tonic-gate static int 32467c478bd9Sstevel@tonic-gate workcmpf2(a, b) 32477c478bd9Sstevel@tonic-gate register WORK *a; 32487c478bd9Sstevel@tonic-gate register WORK *b; 32497c478bd9Sstevel@tonic-gate { 32507c478bd9Sstevel@tonic-gate int i; 32517c478bd9Sstevel@tonic-gate 32527c478bd9Sstevel@tonic-gate /* lock status */ 32537c478bd9Sstevel@tonic-gate if (a->w_lock != b->w_lock) 32547c478bd9Sstevel@tonic-gate return a->w_lock - b->w_lock; 32557c478bd9Sstevel@tonic-gate 32567c478bd9Sstevel@tonic-gate /* host name */ 32577c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host == NULL) 32587c478bd9Sstevel@tonic-gate return 1; 32597c478bd9Sstevel@tonic-gate else if (a->w_host == NULL && b->w_host != NULL) 32607c478bd9Sstevel@tonic-gate return -1; 32617c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host != NULL && 32627c478bd9Sstevel@tonic-gate (i = sm_strcasecmp(a->w_host, b->w_host)) != 0) 32637c478bd9Sstevel@tonic-gate return i; 32647c478bd9Sstevel@tonic-gate 32657c478bd9Sstevel@tonic-gate /* job priority */ 32667c478bd9Sstevel@tonic-gate return workcmpf0(a, b); 32677c478bd9Sstevel@tonic-gate } 32687c478bd9Sstevel@tonic-gate /* 32697c478bd9Sstevel@tonic-gate ** WORKCMPF3 -- simple submission-time-only compare function. 32707c478bd9Sstevel@tonic-gate ** 32717c478bd9Sstevel@tonic-gate ** Parameters: 32727c478bd9Sstevel@tonic-gate ** a -- the first argument. 32737c478bd9Sstevel@tonic-gate ** b -- the second argument. 32747c478bd9Sstevel@tonic-gate ** 32757c478bd9Sstevel@tonic-gate ** Returns: 32767c478bd9Sstevel@tonic-gate ** -1 if a < b 32777c478bd9Sstevel@tonic-gate ** 0 if a == b 32787c478bd9Sstevel@tonic-gate ** +1 if a > b 32797c478bd9Sstevel@tonic-gate ** 32807c478bd9Sstevel@tonic-gate */ 32817c478bd9Sstevel@tonic-gate 32827c478bd9Sstevel@tonic-gate static int 32837c478bd9Sstevel@tonic-gate workcmpf3(a, b) 32847c478bd9Sstevel@tonic-gate register WORK *a; 32857c478bd9Sstevel@tonic-gate register WORK *b; 32867c478bd9Sstevel@tonic-gate { 32877c478bd9Sstevel@tonic-gate if (a->w_ctime > b->w_ctime) 32887c478bd9Sstevel@tonic-gate return 1; 32897c478bd9Sstevel@tonic-gate else if (a->w_ctime < b->w_ctime) 32907c478bd9Sstevel@tonic-gate return -1; 32917c478bd9Sstevel@tonic-gate else 32927c478bd9Sstevel@tonic-gate return 0; 32937c478bd9Sstevel@tonic-gate } 32947c478bd9Sstevel@tonic-gate /* 32957c478bd9Sstevel@tonic-gate ** WORKCMPF4 -- compare based on file name 32967c478bd9Sstevel@tonic-gate ** 32977c478bd9Sstevel@tonic-gate ** Parameters: 32987c478bd9Sstevel@tonic-gate ** a -- the first argument. 32997c478bd9Sstevel@tonic-gate ** b -- the second argument. 33007c478bd9Sstevel@tonic-gate ** 33017c478bd9Sstevel@tonic-gate ** Returns: 33027c478bd9Sstevel@tonic-gate ** -1 if a < b 33037c478bd9Sstevel@tonic-gate ** 0 if a == b 33047c478bd9Sstevel@tonic-gate ** +1 if a > b 33057c478bd9Sstevel@tonic-gate ** 33067c478bd9Sstevel@tonic-gate */ 33077c478bd9Sstevel@tonic-gate 33087c478bd9Sstevel@tonic-gate static int 33097c478bd9Sstevel@tonic-gate workcmpf4(a, b) 33107c478bd9Sstevel@tonic-gate register WORK *a; 33117c478bd9Sstevel@tonic-gate register WORK *b; 33127c478bd9Sstevel@tonic-gate { 33137c478bd9Sstevel@tonic-gate return strcmp(a->w_name, b->w_name); 33147c478bd9Sstevel@tonic-gate } 33157c478bd9Sstevel@tonic-gate /* 33167c478bd9Sstevel@tonic-gate ** WORKCMPF5 -- compare based on assigned random number 33177c478bd9Sstevel@tonic-gate ** 33187c478bd9Sstevel@tonic-gate ** Parameters: 33197c478bd9Sstevel@tonic-gate ** a -- the first argument (ignored). 33207c478bd9Sstevel@tonic-gate ** b -- the second argument (ignored). 33217c478bd9Sstevel@tonic-gate ** 33227c478bd9Sstevel@tonic-gate ** Returns: 33237c478bd9Sstevel@tonic-gate ** randomly 1/-1 33247c478bd9Sstevel@tonic-gate */ 33257c478bd9Sstevel@tonic-gate 33267c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 33277c478bd9Sstevel@tonic-gate static int 33287c478bd9Sstevel@tonic-gate workcmpf5(a, b) 33297c478bd9Sstevel@tonic-gate register WORK *a; 33307c478bd9Sstevel@tonic-gate register WORK *b; 33317c478bd9Sstevel@tonic-gate { 33327c478bd9Sstevel@tonic-gate if (strlen(a->w_name) < randi || strlen(b->w_name) < randi) 33337c478bd9Sstevel@tonic-gate return -1; 33347c478bd9Sstevel@tonic-gate return a->w_name[randi] - b->w_name[randi]; 33357c478bd9Sstevel@tonic-gate } 33367c478bd9Sstevel@tonic-gate /* 33377c478bd9Sstevel@tonic-gate ** WORKCMPF6 -- simple modification-time-only compare function. 33387c478bd9Sstevel@tonic-gate ** 33397c478bd9Sstevel@tonic-gate ** Parameters: 33407c478bd9Sstevel@tonic-gate ** a -- the first argument. 33417c478bd9Sstevel@tonic-gate ** b -- the second argument. 33427c478bd9Sstevel@tonic-gate ** 33437c478bd9Sstevel@tonic-gate ** Returns: 33447c478bd9Sstevel@tonic-gate ** -1 if a < b 33457c478bd9Sstevel@tonic-gate ** 0 if a == b 33467c478bd9Sstevel@tonic-gate ** +1 if a > b 33477c478bd9Sstevel@tonic-gate ** 33487c478bd9Sstevel@tonic-gate */ 33497c478bd9Sstevel@tonic-gate 33507c478bd9Sstevel@tonic-gate static int 33517c478bd9Sstevel@tonic-gate workcmpf6(a, b) 33527c478bd9Sstevel@tonic-gate register WORK *a; 33537c478bd9Sstevel@tonic-gate register WORK *b; 33547c478bd9Sstevel@tonic-gate { 33557c478bd9Sstevel@tonic-gate if (a->w_mtime > b->w_mtime) 33567c478bd9Sstevel@tonic-gate return 1; 33577c478bd9Sstevel@tonic-gate else if (a->w_mtime < b->w_mtime) 33587c478bd9Sstevel@tonic-gate return -1; 33597c478bd9Sstevel@tonic-gate else 33607c478bd9Sstevel@tonic-gate return 0; 33617c478bd9Sstevel@tonic-gate } 33627c478bd9Sstevel@tonic-gate #if _FFR_RHS 33637c478bd9Sstevel@tonic-gate /* 33647c478bd9Sstevel@tonic-gate ** WORKCMPF7 -- compare function for ordering work based on shuffled host name. 33657c478bd9Sstevel@tonic-gate ** 33667c478bd9Sstevel@tonic-gate ** Sorts on lock status, host name, and priority in that order. 33677c478bd9Sstevel@tonic-gate ** 33687c478bd9Sstevel@tonic-gate ** Parameters: 33697c478bd9Sstevel@tonic-gate ** a -- the first argument. 33707c478bd9Sstevel@tonic-gate ** b -- the second argument. 33717c478bd9Sstevel@tonic-gate ** 33727c478bd9Sstevel@tonic-gate ** Returns: 33737c478bd9Sstevel@tonic-gate ** <0 if a < b 33747c478bd9Sstevel@tonic-gate ** 0 if a == b 33757c478bd9Sstevel@tonic-gate ** >0 if a > b 33767c478bd9Sstevel@tonic-gate ** 33777c478bd9Sstevel@tonic-gate */ 33787c478bd9Sstevel@tonic-gate 33797c478bd9Sstevel@tonic-gate static int 33807c478bd9Sstevel@tonic-gate workcmpf7(a, b) 33817c478bd9Sstevel@tonic-gate register WORK *a; 33827c478bd9Sstevel@tonic-gate register WORK *b; 33837c478bd9Sstevel@tonic-gate { 33847c478bd9Sstevel@tonic-gate int i; 33857c478bd9Sstevel@tonic-gate 33867c478bd9Sstevel@tonic-gate /* lock status */ 33877c478bd9Sstevel@tonic-gate if (a->w_lock != b->w_lock) 33887c478bd9Sstevel@tonic-gate return a->w_lock - b->w_lock; 33897c478bd9Sstevel@tonic-gate 33907c478bd9Sstevel@tonic-gate /* host name */ 33917c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host == NULL) 33927c478bd9Sstevel@tonic-gate return 1; 33937c478bd9Sstevel@tonic-gate else if (a->w_host == NULL && b->w_host != NULL) 33947c478bd9Sstevel@tonic-gate return -1; 33957c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host != NULL && 33967c478bd9Sstevel@tonic-gate (i = sm_strshufflecmp(a->w_host, b->w_host)) != 0) 33977c478bd9Sstevel@tonic-gate return i; 33987c478bd9Sstevel@tonic-gate 33997c478bd9Sstevel@tonic-gate /* job priority */ 34007c478bd9Sstevel@tonic-gate return workcmpf0(a, b); 34017c478bd9Sstevel@tonic-gate } 34027c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 34037c478bd9Sstevel@tonic-gate /* 34047c478bd9Sstevel@tonic-gate ** STRREV -- reverse string 34057c478bd9Sstevel@tonic-gate ** 34067c478bd9Sstevel@tonic-gate ** Returns a pointer to a new string that is the reverse of 34077c478bd9Sstevel@tonic-gate ** the string pointed to by fwd. The space for the new 34087c478bd9Sstevel@tonic-gate ** string is obtained using xalloc(). 34097c478bd9Sstevel@tonic-gate ** 34107c478bd9Sstevel@tonic-gate ** Parameters: 34117c478bd9Sstevel@tonic-gate ** fwd -- the string to reverse. 34127c478bd9Sstevel@tonic-gate ** 34137c478bd9Sstevel@tonic-gate ** Returns: 34147c478bd9Sstevel@tonic-gate ** the reversed string. 34157c478bd9Sstevel@tonic-gate */ 34167c478bd9Sstevel@tonic-gate 34177c478bd9Sstevel@tonic-gate static char * 34187c478bd9Sstevel@tonic-gate strrev(fwd) 34197c478bd9Sstevel@tonic-gate char *fwd; 34207c478bd9Sstevel@tonic-gate { 34217c478bd9Sstevel@tonic-gate char *rev = NULL; 34227c478bd9Sstevel@tonic-gate int len, cnt; 34237c478bd9Sstevel@tonic-gate 34247c478bd9Sstevel@tonic-gate len = strlen(fwd); 34257c478bd9Sstevel@tonic-gate rev = xalloc(len + 1); 34267c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < len; ++cnt) 34277c478bd9Sstevel@tonic-gate rev[cnt] = fwd[len - cnt - 1]; 34287c478bd9Sstevel@tonic-gate rev[len] = '\0'; 34297c478bd9Sstevel@tonic-gate return rev; 34307c478bd9Sstevel@tonic-gate } 34317c478bd9Sstevel@tonic-gate 34327c478bd9Sstevel@tonic-gate #if _FFR_RHS 34337c478bd9Sstevel@tonic-gate 34347c478bd9Sstevel@tonic-gate # define NASCII 128 34357c478bd9Sstevel@tonic-gate # define NCHAR 256 34367c478bd9Sstevel@tonic-gate 34377c478bd9Sstevel@tonic-gate static unsigned char ShuffledAlphabet[NCHAR]; 34387c478bd9Sstevel@tonic-gate 34397c478bd9Sstevel@tonic-gate void 34407c478bd9Sstevel@tonic-gate init_shuffle_alphabet() 34417c478bd9Sstevel@tonic-gate { 34427c478bd9Sstevel@tonic-gate static bool init = false; 34437c478bd9Sstevel@tonic-gate int i; 34447c478bd9Sstevel@tonic-gate 34457c478bd9Sstevel@tonic-gate if (init) 34467c478bd9Sstevel@tonic-gate return; 34477c478bd9Sstevel@tonic-gate 34487c478bd9Sstevel@tonic-gate /* fill the ShuffledAlphabet */ 344949218d4fSjbeck for (i = 0; i < NASCII; i++) 34507c478bd9Sstevel@tonic-gate ShuffledAlphabet[i] = i; 34517c478bd9Sstevel@tonic-gate 34527c478bd9Sstevel@tonic-gate /* mix it */ 345349218d4fSjbeck for (i = 1; i < NASCII; i++) 34547c478bd9Sstevel@tonic-gate { 345549218d4fSjbeck register int j = get_random() % NASCII; 34567c478bd9Sstevel@tonic-gate register int tmp; 34577c478bd9Sstevel@tonic-gate 34587c478bd9Sstevel@tonic-gate tmp = ShuffledAlphabet[j]; 34597c478bd9Sstevel@tonic-gate ShuffledAlphabet[j] = ShuffledAlphabet[i]; 34607c478bd9Sstevel@tonic-gate ShuffledAlphabet[i] = tmp; 34617c478bd9Sstevel@tonic-gate } 34627c478bd9Sstevel@tonic-gate 34637c478bd9Sstevel@tonic-gate /* make it case insensitive */ 34647c478bd9Sstevel@tonic-gate for (i = 'A'; i <= 'Z'; i++) 34657c478bd9Sstevel@tonic-gate ShuffledAlphabet[i] = ShuffledAlphabet[i + 'a' - 'A']; 34667c478bd9Sstevel@tonic-gate 34677c478bd9Sstevel@tonic-gate /* fill the upper part */ 346849218d4fSjbeck for (i = 0; i < NASCII; i++) 346949218d4fSjbeck ShuffledAlphabet[i + NASCII] = ShuffledAlphabet[i]; 34707c478bd9Sstevel@tonic-gate init = true; 34717c478bd9Sstevel@tonic-gate } 34727c478bd9Sstevel@tonic-gate 34737c478bd9Sstevel@tonic-gate static int 34747c478bd9Sstevel@tonic-gate sm_strshufflecmp(a, b) 34757c478bd9Sstevel@tonic-gate char *a; 34767c478bd9Sstevel@tonic-gate char *b; 34777c478bd9Sstevel@tonic-gate { 34787c478bd9Sstevel@tonic-gate const unsigned char *us1 = (const unsigned char *) a; 34797c478bd9Sstevel@tonic-gate const unsigned char *us2 = (const unsigned char *) b; 34807c478bd9Sstevel@tonic-gate 34817c478bd9Sstevel@tonic-gate while (ShuffledAlphabet[*us1] == ShuffledAlphabet[*us2++]) 34827c478bd9Sstevel@tonic-gate { 34837c478bd9Sstevel@tonic-gate if (*us1++ == '\0') 34847c478bd9Sstevel@tonic-gate return 0; 34857c478bd9Sstevel@tonic-gate } 34867c478bd9Sstevel@tonic-gate return (ShuffledAlphabet[*us1] - ShuffledAlphabet[*--us2]); 34877c478bd9Sstevel@tonic-gate } 34887c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 34897c478bd9Sstevel@tonic-gate 34907c478bd9Sstevel@tonic-gate /* 34917c478bd9Sstevel@tonic-gate ** DOWORK -- do a work request. 34927c478bd9Sstevel@tonic-gate ** 34937c478bd9Sstevel@tonic-gate ** Parameters: 34947c478bd9Sstevel@tonic-gate ** qgrp -- the index of the queue group for the job. 34957c478bd9Sstevel@tonic-gate ** qdir -- the index of the queue directory for the job. 34967c478bd9Sstevel@tonic-gate ** id -- the ID of the job to run. 34977c478bd9Sstevel@tonic-gate ** forkflag -- if set, run this in background. 34987c478bd9Sstevel@tonic-gate ** requeueflag -- if set, reinstantiate the queue quickly. 34997c478bd9Sstevel@tonic-gate ** This is used when expanding aliases in the queue. 35007c478bd9Sstevel@tonic-gate ** If forkflag is also set, it doesn't wait for the 35017c478bd9Sstevel@tonic-gate ** child. 35027c478bd9Sstevel@tonic-gate ** e - the envelope in which to run it. 35037c478bd9Sstevel@tonic-gate ** 35047c478bd9Sstevel@tonic-gate ** Returns: 35057c478bd9Sstevel@tonic-gate ** process id of process that is running the queue job. 35067c478bd9Sstevel@tonic-gate ** 35077c478bd9Sstevel@tonic-gate ** Side Effects: 35087c478bd9Sstevel@tonic-gate ** The work request is satisfied if possible. 35097c478bd9Sstevel@tonic-gate */ 35107c478bd9Sstevel@tonic-gate 35117c478bd9Sstevel@tonic-gate pid_t 35127c478bd9Sstevel@tonic-gate dowork(qgrp, qdir, id, forkflag, requeueflag, e) 35137c478bd9Sstevel@tonic-gate int qgrp; 35147c478bd9Sstevel@tonic-gate int qdir; 35157c478bd9Sstevel@tonic-gate char *id; 35167c478bd9Sstevel@tonic-gate bool forkflag; 35177c478bd9Sstevel@tonic-gate bool requeueflag; 35187c478bd9Sstevel@tonic-gate register ENVELOPE *e; 35197c478bd9Sstevel@tonic-gate { 35207c478bd9Sstevel@tonic-gate register pid_t pid; 35217c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool; 35227c478bd9Sstevel@tonic-gate 35237c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 35247c478bd9Sstevel@tonic-gate sm_dprintf("dowork(%s/%s)\n", qid_printqueue(qgrp, qdir), id); 35257c478bd9Sstevel@tonic-gate 35267c478bd9Sstevel@tonic-gate /* 35277c478bd9Sstevel@tonic-gate ** Fork for work. 35287c478bd9Sstevel@tonic-gate */ 35297c478bd9Sstevel@tonic-gate 35307c478bd9Sstevel@tonic-gate if (forkflag) 35317c478bd9Sstevel@tonic-gate { 35327c478bd9Sstevel@tonic-gate /* 35337c478bd9Sstevel@tonic-gate ** Since the delivery may happen in a child and the 35347c478bd9Sstevel@tonic-gate ** parent does not wait, the parent may close the 35357c478bd9Sstevel@tonic-gate ** maps thereby removing any shared memory used by 35367c478bd9Sstevel@tonic-gate ** the map. Therefore, close the maps now so the 35377c478bd9Sstevel@tonic-gate ** child will dynamically open them if necessary. 35387c478bd9Sstevel@tonic-gate */ 35397c478bd9Sstevel@tonic-gate 35407c478bd9Sstevel@tonic-gate closemaps(false); 35417c478bd9Sstevel@tonic-gate 35427c478bd9Sstevel@tonic-gate pid = fork(); 35437c478bd9Sstevel@tonic-gate if (pid < 0) 35447c478bd9Sstevel@tonic-gate { 35457c478bd9Sstevel@tonic-gate syserr("dowork: cannot fork"); 35467c478bd9Sstevel@tonic-gate return 0; 35477c478bd9Sstevel@tonic-gate } 35487c478bd9Sstevel@tonic-gate else if (pid > 0) 35497c478bd9Sstevel@tonic-gate { 35507c478bd9Sstevel@tonic-gate /* parent -- clean out connection cache */ 35517c478bd9Sstevel@tonic-gate mci_flush(false, NULL); 35527c478bd9Sstevel@tonic-gate } 35537c478bd9Sstevel@tonic-gate else 35547c478bd9Sstevel@tonic-gate { 35557c478bd9Sstevel@tonic-gate /* 35567c478bd9Sstevel@tonic-gate ** Initialize exception stack and default exception 35577c478bd9Sstevel@tonic-gate ** handler for child process. 35587c478bd9Sstevel@tonic-gate */ 35597c478bd9Sstevel@tonic-gate 35607c478bd9Sstevel@tonic-gate /* Reset global flags */ 35617c478bd9Sstevel@tonic-gate RestartRequest = NULL; 35627c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 35637c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 35647c478bd9Sstevel@tonic-gate PendingSignal = 0; 35657c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 35667c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error); 35677c478bd9Sstevel@tonic-gate 35687c478bd9Sstevel@tonic-gate /* 35697c478bd9Sstevel@tonic-gate ** See note above about SMTP processes and SIGCHLD. 35707c478bd9Sstevel@tonic-gate */ 35717c478bd9Sstevel@tonic-gate 35727c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP || 35737c478bd9Sstevel@tonic-gate OpMode == MD_DAEMON || 35747c478bd9Sstevel@tonic-gate MaxQueueChildren > 0) 35757c478bd9Sstevel@tonic-gate { 35767c478bd9Sstevel@tonic-gate proc_list_clear(); 35777c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD); 35787c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 35797c478bd9Sstevel@tonic-gate } 35807c478bd9Sstevel@tonic-gate 35817c478bd9Sstevel@tonic-gate /* child -- error messages to the transcript */ 35827c478bd9Sstevel@tonic-gate QuickAbort = OnlyOneError = false; 35837c478bd9Sstevel@tonic-gate } 35847c478bd9Sstevel@tonic-gate } 35857c478bd9Sstevel@tonic-gate else 35867c478bd9Sstevel@tonic-gate { 35877c478bd9Sstevel@tonic-gate pid = 0; 35887c478bd9Sstevel@tonic-gate } 35897c478bd9Sstevel@tonic-gate 35907c478bd9Sstevel@tonic-gate if (pid == 0) 35917c478bd9Sstevel@tonic-gate { 35927c478bd9Sstevel@tonic-gate /* 35937c478bd9Sstevel@tonic-gate ** CHILD 35947c478bd9Sstevel@tonic-gate ** Lock the control file to avoid duplicate deliveries. 35957c478bd9Sstevel@tonic-gate ** Then run the file as though we had just read it. 35967c478bd9Sstevel@tonic-gate ** We save an idea of the temporary name so we 35977c478bd9Sstevel@tonic-gate ** can recover on interrupt. 35987c478bd9Sstevel@tonic-gate */ 35997c478bd9Sstevel@tonic-gate 36007c478bd9Sstevel@tonic-gate if (forkflag) 36017c478bd9Sstevel@tonic-gate { 36027c478bd9Sstevel@tonic-gate /* Reset global flags */ 36037c478bd9Sstevel@tonic-gate RestartRequest = NULL; 36047c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 36057c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 36067c478bd9Sstevel@tonic-gate PendingSignal = 0; 36077c478bd9Sstevel@tonic-gate } 36087c478bd9Sstevel@tonic-gate 36097c478bd9Sstevel@tonic-gate /* set basic modes, etc. */ 36107c478bd9Sstevel@tonic-gate sm_clear_events(); 36117c478bd9Sstevel@tonic-gate clearstats(); 36127c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL); 36137c478bd9Sstevel@tonic-gate clearenvelope(e, false, rpool); 36147c478bd9Sstevel@tonic-gate e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS; 36157c478bd9Sstevel@tonic-gate set_delivery_mode(SM_DELIVER, e); 36167c478bd9Sstevel@tonic-gate e->e_errormode = EM_MAIL; 36177c478bd9Sstevel@tonic-gate e->e_id = id; 36187c478bd9Sstevel@tonic-gate e->e_qgrp = qgrp; 36197c478bd9Sstevel@tonic-gate e->e_qdir = qdir; 36207c478bd9Sstevel@tonic-gate GrabTo = UseErrorsTo = false; 36217c478bd9Sstevel@tonic-gate ExitStat = EX_OK; 36227c478bd9Sstevel@tonic-gate if (forkflag) 36237c478bd9Sstevel@tonic-gate { 36247c478bd9Sstevel@tonic-gate disconnect(1, e); 36257c478bd9Sstevel@tonic-gate set_op_mode(MD_QUEUERUN); 36267c478bd9Sstevel@tonic-gate } 36277c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s from queue", qid_printname(e)); 36287c478bd9Sstevel@tonic-gate if (LogLevel > 76) 36297c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "dowork, pid=%d", 36307c478bd9Sstevel@tonic-gate (int) CurrentPid); 36317c478bd9Sstevel@tonic-gate 36327c478bd9Sstevel@tonic-gate /* don't use the headers from sendmail.cf... */ 36337c478bd9Sstevel@tonic-gate e->e_header = NULL; 36347c478bd9Sstevel@tonic-gate 36357c478bd9Sstevel@tonic-gate /* read the queue control file -- return if locked */ 36367c478bd9Sstevel@tonic-gate if (!readqf(e, false)) 36377c478bd9Sstevel@tonic-gate { 36387c478bd9Sstevel@tonic-gate if (tTd(40, 4) && e->e_id != NULL) 36397c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s) failed\n", 36407c478bd9Sstevel@tonic-gate qid_printname(e)); 36417c478bd9Sstevel@tonic-gate e->e_id = NULL; 36427c478bd9Sstevel@tonic-gate if (forkflag) 36437c478bd9Sstevel@tonic-gate finis(false, true, EX_OK); 36447c478bd9Sstevel@tonic-gate else 36457c478bd9Sstevel@tonic-gate { 36467c478bd9Sstevel@tonic-gate /* adding this frees 8 bytes */ 36477c478bd9Sstevel@tonic-gate clearenvelope(e, false, rpool); 36487c478bd9Sstevel@tonic-gate 36497c478bd9Sstevel@tonic-gate /* adding this frees 12 bytes */ 36507c478bd9Sstevel@tonic-gate sm_rpool_free(rpool); 36517c478bd9Sstevel@tonic-gate e->e_rpool = NULL; 36527c478bd9Sstevel@tonic-gate return 0; 36537c478bd9Sstevel@tonic-gate } 36547c478bd9Sstevel@tonic-gate } 36557c478bd9Sstevel@tonic-gate 36567c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE; 36577c478bd9Sstevel@tonic-gate eatheader(e, requeueflag, true); 36587c478bd9Sstevel@tonic-gate 36597c478bd9Sstevel@tonic-gate if (requeueflag) 36607c478bd9Sstevel@tonic-gate queueup(e, false, false); 36617c478bd9Sstevel@tonic-gate 36627c478bd9Sstevel@tonic-gate /* do the delivery */ 36637c478bd9Sstevel@tonic-gate sendall(e, SM_DELIVER); 36647c478bd9Sstevel@tonic-gate 36657c478bd9Sstevel@tonic-gate /* finish up and exit */ 36667c478bd9Sstevel@tonic-gate if (forkflag) 36677c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 36687c478bd9Sstevel@tonic-gate else 36697c478bd9Sstevel@tonic-gate { 36707c478bd9Sstevel@tonic-gate dropenvelope(e, true, false); 36717c478bd9Sstevel@tonic-gate sm_rpool_free(rpool); 36727c478bd9Sstevel@tonic-gate e->e_rpool = NULL; 36737c478bd9Sstevel@tonic-gate } 36747c478bd9Sstevel@tonic-gate } 36757c478bd9Sstevel@tonic-gate e->e_id = NULL; 36767c478bd9Sstevel@tonic-gate return pid; 36777c478bd9Sstevel@tonic-gate } 36787c478bd9Sstevel@tonic-gate 36797c478bd9Sstevel@tonic-gate /* 36807c478bd9Sstevel@tonic-gate ** DOWORKLIST -- process a list of envelopes as work requests 36817c478bd9Sstevel@tonic-gate ** 36827c478bd9Sstevel@tonic-gate ** Similar to dowork(), except that after forking, it processes an 36837c478bd9Sstevel@tonic-gate ** envelope and its siblings, treating each envelope as a work request. 36847c478bd9Sstevel@tonic-gate ** 36857c478bd9Sstevel@tonic-gate ** Parameters: 36867c478bd9Sstevel@tonic-gate ** el -- envelope to be processed including its siblings. 36877c478bd9Sstevel@tonic-gate ** forkflag -- if set, run this in background. 36887c478bd9Sstevel@tonic-gate ** requeueflag -- if set, reinstantiate the queue quickly. 36897c478bd9Sstevel@tonic-gate ** This is used when expanding aliases in the queue. 36907c478bd9Sstevel@tonic-gate ** If forkflag is also set, it doesn't wait for the 36917c478bd9Sstevel@tonic-gate ** child. 36927c478bd9Sstevel@tonic-gate ** 36937c478bd9Sstevel@tonic-gate ** Returns: 36947c478bd9Sstevel@tonic-gate ** process id of process that is running the queue job. 36957c478bd9Sstevel@tonic-gate ** 36967c478bd9Sstevel@tonic-gate ** Side Effects: 36977c478bd9Sstevel@tonic-gate ** The work request is satisfied if possible. 36987c478bd9Sstevel@tonic-gate */ 36997c478bd9Sstevel@tonic-gate 37007c478bd9Sstevel@tonic-gate pid_t 37017c478bd9Sstevel@tonic-gate doworklist(el, forkflag, requeueflag) 37027c478bd9Sstevel@tonic-gate ENVELOPE *el; 37037c478bd9Sstevel@tonic-gate bool forkflag; 37047c478bd9Sstevel@tonic-gate bool requeueflag; 37057c478bd9Sstevel@tonic-gate { 37067c478bd9Sstevel@tonic-gate register pid_t pid; 37077c478bd9Sstevel@tonic-gate ENVELOPE *ei; 37087c478bd9Sstevel@tonic-gate 37097c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 37107c478bd9Sstevel@tonic-gate sm_dprintf("doworklist()\n"); 37117c478bd9Sstevel@tonic-gate 37127c478bd9Sstevel@tonic-gate /* 37137c478bd9Sstevel@tonic-gate ** Fork for work. 37147c478bd9Sstevel@tonic-gate */ 37157c478bd9Sstevel@tonic-gate 37167c478bd9Sstevel@tonic-gate if (forkflag) 37177c478bd9Sstevel@tonic-gate { 37187c478bd9Sstevel@tonic-gate /* 37197c478bd9Sstevel@tonic-gate ** Since the delivery may happen in a child and the 37207c478bd9Sstevel@tonic-gate ** parent does not wait, the parent may close the 37217c478bd9Sstevel@tonic-gate ** maps thereby removing any shared memory used by 37227c478bd9Sstevel@tonic-gate ** the map. Therefore, close the maps now so the 37237c478bd9Sstevel@tonic-gate ** child will dynamically open them if necessary. 37247c478bd9Sstevel@tonic-gate */ 37257c478bd9Sstevel@tonic-gate 37267c478bd9Sstevel@tonic-gate closemaps(false); 37277c478bd9Sstevel@tonic-gate 37287c478bd9Sstevel@tonic-gate pid = fork(); 37297c478bd9Sstevel@tonic-gate if (pid < 0) 37307c478bd9Sstevel@tonic-gate { 37317c478bd9Sstevel@tonic-gate syserr("doworklist: cannot fork"); 37327c478bd9Sstevel@tonic-gate return 0; 37337c478bd9Sstevel@tonic-gate } 37347c478bd9Sstevel@tonic-gate else if (pid > 0) 37357c478bd9Sstevel@tonic-gate { 37367c478bd9Sstevel@tonic-gate /* parent -- clean out connection cache */ 37377c478bd9Sstevel@tonic-gate mci_flush(false, NULL); 37387c478bd9Sstevel@tonic-gate } 37397c478bd9Sstevel@tonic-gate else 37407c478bd9Sstevel@tonic-gate { 37417c478bd9Sstevel@tonic-gate /* 37427c478bd9Sstevel@tonic-gate ** Initialize exception stack and default exception 37437c478bd9Sstevel@tonic-gate ** handler for child process. 37447c478bd9Sstevel@tonic-gate */ 37457c478bd9Sstevel@tonic-gate 37467c478bd9Sstevel@tonic-gate /* Reset global flags */ 37477c478bd9Sstevel@tonic-gate RestartRequest = NULL; 37487c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 37497c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 37507c478bd9Sstevel@tonic-gate PendingSignal = 0; 37517c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 37527c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error); 37537c478bd9Sstevel@tonic-gate 37547c478bd9Sstevel@tonic-gate /* 37557c478bd9Sstevel@tonic-gate ** See note above about SMTP processes and SIGCHLD. 37567c478bd9Sstevel@tonic-gate */ 37577c478bd9Sstevel@tonic-gate 37587c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP || 37597c478bd9Sstevel@tonic-gate OpMode == MD_DAEMON || 37607c478bd9Sstevel@tonic-gate MaxQueueChildren > 0) 37617c478bd9Sstevel@tonic-gate { 37627c478bd9Sstevel@tonic-gate proc_list_clear(); 37637c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD); 37647c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 37657c478bd9Sstevel@tonic-gate } 37667c478bd9Sstevel@tonic-gate 37677c478bd9Sstevel@tonic-gate /* child -- error messages to the transcript */ 37687c478bd9Sstevel@tonic-gate QuickAbort = OnlyOneError = false; 37697c478bd9Sstevel@tonic-gate } 37707c478bd9Sstevel@tonic-gate } 37717c478bd9Sstevel@tonic-gate else 37727c478bd9Sstevel@tonic-gate { 37737c478bd9Sstevel@tonic-gate pid = 0; 37747c478bd9Sstevel@tonic-gate } 37757c478bd9Sstevel@tonic-gate 37767c478bd9Sstevel@tonic-gate if (pid != 0) 37777c478bd9Sstevel@tonic-gate return pid; 37787c478bd9Sstevel@tonic-gate 37797c478bd9Sstevel@tonic-gate /* 37807c478bd9Sstevel@tonic-gate ** IN CHILD 37817c478bd9Sstevel@tonic-gate ** Lock the control file to avoid duplicate deliveries. 37827c478bd9Sstevel@tonic-gate ** Then run the file as though we had just read it. 37837c478bd9Sstevel@tonic-gate ** We save an idea of the temporary name so we 37847c478bd9Sstevel@tonic-gate ** can recover on interrupt. 37857c478bd9Sstevel@tonic-gate */ 37867c478bd9Sstevel@tonic-gate 37877c478bd9Sstevel@tonic-gate if (forkflag) 37887c478bd9Sstevel@tonic-gate { 37897c478bd9Sstevel@tonic-gate /* Reset global flags */ 37907c478bd9Sstevel@tonic-gate RestartRequest = NULL; 37917c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 37927c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 37937c478bd9Sstevel@tonic-gate PendingSignal = 0; 37947c478bd9Sstevel@tonic-gate } 37957c478bd9Sstevel@tonic-gate 37967c478bd9Sstevel@tonic-gate /* set basic modes, etc. */ 37977c478bd9Sstevel@tonic-gate sm_clear_events(); 37987c478bd9Sstevel@tonic-gate clearstats(); 37997c478bd9Sstevel@tonic-gate GrabTo = UseErrorsTo = false; 38007c478bd9Sstevel@tonic-gate ExitStat = EX_OK; 38017c478bd9Sstevel@tonic-gate if (forkflag) 38027c478bd9Sstevel@tonic-gate { 38037c478bd9Sstevel@tonic-gate disconnect(1, el); 38047c478bd9Sstevel@tonic-gate set_op_mode(MD_QUEUERUN); 38057c478bd9Sstevel@tonic-gate } 38067c478bd9Sstevel@tonic-gate if (LogLevel > 76) 38077c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, el->e_id, "doworklist, pid=%d", 38087c478bd9Sstevel@tonic-gate (int) CurrentPid); 38097c478bd9Sstevel@tonic-gate 38107c478bd9Sstevel@tonic-gate for (ei = el; ei != NULL; ei = ei->e_sibling) 38117c478bd9Sstevel@tonic-gate { 38127c478bd9Sstevel@tonic-gate ENVELOPE e; 38137c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool; 38147c478bd9Sstevel@tonic-gate 38157c478bd9Sstevel@tonic-gate if (WILL_BE_QUEUED(ei->e_sendmode)) 38167c478bd9Sstevel@tonic-gate continue; 38177c478bd9Sstevel@tonic-gate else if (QueueMode != QM_QUARANTINE && 38187c478bd9Sstevel@tonic-gate ei->e_quarmsg != NULL) 38197c478bd9Sstevel@tonic-gate continue; 38207c478bd9Sstevel@tonic-gate 38217c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL); 38227c478bd9Sstevel@tonic-gate clearenvelope(&e, true, rpool); 38237c478bd9Sstevel@tonic-gate e.e_flags |= EF_QUEUERUN|EF_GLOBALERRS; 38247c478bd9Sstevel@tonic-gate set_delivery_mode(SM_DELIVER, &e); 38257c478bd9Sstevel@tonic-gate e.e_errormode = EM_MAIL; 38267c478bd9Sstevel@tonic-gate e.e_id = ei->e_id; 38277c478bd9Sstevel@tonic-gate e.e_qgrp = ei->e_qgrp; 38287c478bd9Sstevel@tonic-gate e.e_qdir = ei->e_qdir; 38297c478bd9Sstevel@tonic-gate openxscript(&e); 38307c478bd9Sstevel@tonic-gate sm_setproctitle(true, &e, "%s from queue", qid_printname(&e)); 38317c478bd9Sstevel@tonic-gate 38327c478bd9Sstevel@tonic-gate /* don't use the headers from sendmail.cf... */ 38337c478bd9Sstevel@tonic-gate e.e_header = NULL; 38347c478bd9Sstevel@tonic-gate CurEnv = &e; 38357c478bd9Sstevel@tonic-gate 38367c478bd9Sstevel@tonic-gate /* read the queue control file -- return if locked */ 38377c478bd9Sstevel@tonic-gate if (readqf(&e, false)) 38387c478bd9Sstevel@tonic-gate { 38397c478bd9Sstevel@tonic-gate e.e_flags |= EF_INQUEUE; 38407c478bd9Sstevel@tonic-gate eatheader(&e, requeueflag, true); 38417c478bd9Sstevel@tonic-gate 38427c478bd9Sstevel@tonic-gate if (requeueflag) 38437c478bd9Sstevel@tonic-gate queueup(&e, false, false); 38447c478bd9Sstevel@tonic-gate 38457c478bd9Sstevel@tonic-gate /* do the delivery */ 38467c478bd9Sstevel@tonic-gate sendall(&e, SM_DELIVER); 38477c478bd9Sstevel@tonic-gate dropenvelope(&e, true, false); 38487c478bd9Sstevel@tonic-gate } 38497c478bd9Sstevel@tonic-gate else 38507c478bd9Sstevel@tonic-gate { 38517c478bd9Sstevel@tonic-gate if (tTd(40, 4) && e.e_id != NULL) 38527c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s) failed\n", 38537c478bd9Sstevel@tonic-gate qid_printname(&e)); 38547c478bd9Sstevel@tonic-gate } 38557c478bd9Sstevel@tonic-gate sm_rpool_free(rpool); 38567c478bd9Sstevel@tonic-gate ei->e_id = NULL; 38577c478bd9Sstevel@tonic-gate } 38587c478bd9Sstevel@tonic-gate 38597c478bd9Sstevel@tonic-gate /* restore CurEnv */ 38607c478bd9Sstevel@tonic-gate CurEnv = el; 38617c478bd9Sstevel@tonic-gate 38627c478bd9Sstevel@tonic-gate /* finish up and exit */ 38637c478bd9Sstevel@tonic-gate if (forkflag) 38647c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 38657c478bd9Sstevel@tonic-gate return 0; 38667c478bd9Sstevel@tonic-gate } 38677c478bd9Sstevel@tonic-gate /* 38687c478bd9Sstevel@tonic-gate ** READQF -- read queue file and set up environment. 38697c478bd9Sstevel@tonic-gate ** 38707c478bd9Sstevel@tonic-gate ** Parameters: 38717c478bd9Sstevel@tonic-gate ** e -- the envelope of the job to run. 38727c478bd9Sstevel@tonic-gate ** openonly -- only open the qf (returned as e_lockfp) 38737c478bd9Sstevel@tonic-gate ** 38747c478bd9Sstevel@tonic-gate ** Returns: 38757c478bd9Sstevel@tonic-gate ** true if it successfully read the queue file. 38767c478bd9Sstevel@tonic-gate ** false otherwise. 38777c478bd9Sstevel@tonic-gate ** 38787c478bd9Sstevel@tonic-gate ** Side Effects: 38797c478bd9Sstevel@tonic-gate ** The queue file is returned locked. 38807c478bd9Sstevel@tonic-gate */ 38817c478bd9Sstevel@tonic-gate 38827c478bd9Sstevel@tonic-gate static bool 38837c478bd9Sstevel@tonic-gate readqf(e, openonly) 38847c478bd9Sstevel@tonic-gate register ENVELOPE *e; 38857c478bd9Sstevel@tonic-gate bool openonly; 38867c478bd9Sstevel@tonic-gate { 38877c478bd9Sstevel@tonic-gate register SM_FILE_T *qfp; 38887c478bd9Sstevel@tonic-gate ADDRESS *ctladdr; 38897c478bd9Sstevel@tonic-gate struct stat st, stf; 38907c478bd9Sstevel@tonic-gate char *bp; 38917c478bd9Sstevel@tonic-gate int qfver = 0; 38927c478bd9Sstevel@tonic-gate long hdrsize = 0; 38937c478bd9Sstevel@tonic-gate register char *p; 38947c478bd9Sstevel@tonic-gate char *frcpt = NULL; 38957c478bd9Sstevel@tonic-gate char *orcpt = NULL; 38967c478bd9Sstevel@tonic-gate bool nomore = false; 38977c478bd9Sstevel@tonic-gate bool bogus = false; 38987c478bd9Sstevel@tonic-gate MODE_T qsafe; 38997c478bd9Sstevel@tonic-gate char *err; 39007c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN]; 39017c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 39027c478bd9Sstevel@tonic-gate 39037c478bd9Sstevel@tonic-gate /* 39047c478bd9Sstevel@tonic-gate ** Read and process the file. 39057c478bd9Sstevel@tonic-gate */ 39067c478bd9Sstevel@tonic-gate 39077c478bd9Sstevel@tonic-gate (void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER), sizeof qf); 39087c478bd9Sstevel@tonic-gate qfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDWR_B, NULL); 39097c478bd9Sstevel@tonic-gate if (qfp == NULL) 39107c478bd9Sstevel@tonic-gate { 39117c478bd9Sstevel@tonic-gate int save_errno = errno; 39127c478bd9Sstevel@tonic-gate 39137c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 39147c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s): sm_io_open failure (%s)\n", 39157c478bd9Sstevel@tonic-gate qf, sm_errstring(errno)); 39167c478bd9Sstevel@tonic-gate errno = save_errno; 39177c478bd9Sstevel@tonic-gate if (errno != ENOENT 39187c478bd9Sstevel@tonic-gate ) 39197c478bd9Sstevel@tonic-gate syserr("readqf: no control file %s", qf); 39207c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 39217c478bd9Sstevel@tonic-gate return false; 39227c478bd9Sstevel@tonic-gate } 39237c478bd9Sstevel@tonic-gate 39247c478bd9Sstevel@tonic-gate if (!lockfile(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), qf, NULL, 39257c478bd9Sstevel@tonic-gate LOCK_EX|LOCK_NB)) 39267c478bd9Sstevel@tonic-gate { 39277c478bd9Sstevel@tonic-gate /* being processed by another queuer */ 39287c478bd9Sstevel@tonic-gate if (Verbose) 39297c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 39307c478bd9Sstevel@tonic-gate "%s: locked\n", e->e_id); 39317c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 39327c478bd9Sstevel@tonic-gate sm_dprintf("%s: locked\n", e->e_id); 39337c478bd9Sstevel@tonic-gate if (LogLevel > 19) 39347c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "locked"); 39357c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 39367c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 39377c478bd9Sstevel@tonic-gate return false; 39387c478bd9Sstevel@tonic-gate } 39397c478bd9Sstevel@tonic-gate 39407c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 39417c478bd9Sstevel@tonic-gate 39427c478bd9Sstevel@tonic-gate /* 39437c478bd9Sstevel@tonic-gate ** Prevent locking race condition. 39447c478bd9Sstevel@tonic-gate ** 39457c478bd9Sstevel@tonic-gate ** Process A: readqf(): qfp = fopen(qffile) 39467c478bd9Sstevel@tonic-gate ** Process B: queueup(): rename(tf, qf) 39477c478bd9Sstevel@tonic-gate ** Process B: unlocks(tf) 39487c478bd9Sstevel@tonic-gate ** Process A: lockfile(qf); 39497c478bd9Sstevel@tonic-gate ** 39507c478bd9Sstevel@tonic-gate ** Process A (us) has the old qf file (before the rename deleted 39517c478bd9Sstevel@tonic-gate ** the directory entry) and will be delivering based on old data. 39527c478bd9Sstevel@tonic-gate ** This can lead to multiple deliveries of the same recipients. 39537c478bd9Sstevel@tonic-gate ** 39547c478bd9Sstevel@tonic-gate ** Catch this by checking if the underlying qf file has changed 39557c478bd9Sstevel@tonic-gate ** *after* acquiring our lock and if so, act as though the file 39567c478bd9Sstevel@tonic-gate ** was still locked (i.e., just return like the lockfile() case 39577c478bd9Sstevel@tonic-gate ** above. 39587c478bd9Sstevel@tonic-gate */ 39597c478bd9Sstevel@tonic-gate 39607c478bd9Sstevel@tonic-gate if (stat(qf, &stf) < 0 || 39617c478bd9Sstevel@tonic-gate fstat(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), &st) < 0) 39627c478bd9Sstevel@tonic-gate { 39637c478bd9Sstevel@tonic-gate /* must have been being processed by someone else */ 39647c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 39657c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s): [f]stat failure (%s)\n", 39667c478bd9Sstevel@tonic-gate qf, sm_errstring(errno)); 39677c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 39687c478bd9Sstevel@tonic-gate return false; 39697c478bd9Sstevel@tonic-gate } 39707c478bd9Sstevel@tonic-gate 39717c478bd9Sstevel@tonic-gate if (st.st_nlink != stf.st_nlink || 39727c478bd9Sstevel@tonic-gate st.st_dev != stf.st_dev || 39737c478bd9Sstevel@tonic-gate ST_INODE(st) != ST_INODE(stf) || 39747c478bd9Sstevel@tonic-gate #if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */ 39757c478bd9Sstevel@tonic-gate st.st_gen != stf.st_gen || 39767c478bd9Sstevel@tonic-gate #endif /* HAS_ST_GEN && 0 */ 39777c478bd9Sstevel@tonic-gate st.st_uid != stf.st_uid || 39787c478bd9Sstevel@tonic-gate st.st_gid != stf.st_gid || 39797c478bd9Sstevel@tonic-gate st.st_size != stf.st_size) 39807c478bd9Sstevel@tonic-gate { 39817c478bd9Sstevel@tonic-gate /* changed after opened */ 39827c478bd9Sstevel@tonic-gate if (Verbose) 39837c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 39847c478bd9Sstevel@tonic-gate "%s: changed\n", e->e_id); 39857c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 39867c478bd9Sstevel@tonic-gate sm_dprintf("%s: changed\n", e->e_id); 39877c478bd9Sstevel@tonic-gate if (LogLevel > 19) 39887c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "changed"); 39897c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 39907c478bd9Sstevel@tonic-gate return false; 39917c478bd9Sstevel@tonic-gate } 39927c478bd9Sstevel@tonic-gate 39937c478bd9Sstevel@tonic-gate /* 39947c478bd9Sstevel@tonic-gate ** Check the queue file for plausibility to avoid attacks. 39957c478bd9Sstevel@tonic-gate */ 39967c478bd9Sstevel@tonic-gate 39977c478bd9Sstevel@tonic-gate qsafe = S_IWOTH|S_IWGRP; 39987c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 39997c478bd9Sstevel@tonic-gate qsafe &= ~S_IWGRP; 40007c478bd9Sstevel@tonic-gate 40017c478bd9Sstevel@tonic-gate bogus = st.st_uid != geteuid() && 40027c478bd9Sstevel@tonic-gate st.st_uid != TrustedUid && 40037c478bd9Sstevel@tonic-gate geteuid() != RealUid; 40047c478bd9Sstevel@tonic-gate 40057c478bd9Sstevel@tonic-gate /* 40067c478bd9Sstevel@tonic-gate ** If this qf file results from a set-group-ID binary, then 40077c478bd9Sstevel@tonic-gate ** we check whether the directory is group-writable, 40087c478bd9Sstevel@tonic-gate ** the queue file mode contains the group-writable bit, and 40097c478bd9Sstevel@tonic-gate ** the groups are the same. 40107c478bd9Sstevel@tonic-gate ** Notice: this requires that the set-group-ID binary is used to 40117c478bd9Sstevel@tonic-gate ** run the queue! 40127c478bd9Sstevel@tonic-gate */ 40137c478bd9Sstevel@tonic-gate 40147c478bd9Sstevel@tonic-gate if (bogus && st.st_gid == getegid() && UseMSP) 40157c478bd9Sstevel@tonic-gate { 40167c478bd9Sstevel@tonic-gate char delim; 40177c478bd9Sstevel@tonic-gate struct stat dst; 40187c478bd9Sstevel@tonic-gate 40197c478bd9Sstevel@tonic-gate bp = SM_LAST_DIR_DELIM(qf); 40207c478bd9Sstevel@tonic-gate if (bp == NULL) 40217c478bd9Sstevel@tonic-gate delim = '\0'; 40227c478bd9Sstevel@tonic-gate else 40237c478bd9Sstevel@tonic-gate { 40247c478bd9Sstevel@tonic-gate delim = *bp; 40257c478bd9Sstevel@tonic-gate *bp = '\0'; 40267c478bd9Sstevel@tonic-gate } 40277c478bd9Sstevel@tonic-gate if (stat(delim == '\0' ? "." : qf, &dst) < 0) 40287c478bd9Sstevel@tonic-gate syserr("readqf: cannot stat directory %s", 40297c478bd9Sstevel@tonic-gate delim == '\0' ? "." : qf); 40307c478bd9Sstevel@tonic-gate else 40317c478bd9Sstevel@tonic-gate { 40327c478bd9Sstevel@tonic-gate bogus = !(bitset(S_IWGRP, QueueFileMode) && 40337c478bd9Sstevel@tonic-gate bitset(S_IWGRP, dst.st_mode) && 40347c478bd9Sstevel@tonic-gate dst.st_gid == st.st_gid); 40357c478bd9Sstevel@tonic-gate } 40367c478bd9Sstevel@tonic-gate if (delim != '\0') 40377c478bd9Sstevel@tonic-gate *bp = delim; 40387c478bd9Sstevel@tonic-gate } 40397c478bd9Sstevel@tonic-gate if (!bogus) 40407c478bd9Sstevel@tonic-gate bogus = bitset(qsafe, st.st_mode); 40417c478bd9Sstevel@tonic-gate if (bogus) 40427c478bd9Sstevel@tonic-gate { 40437c478bd9Sstevel@tonic-gate if (LogLevel > 0) 40447c478bd9Sstevel@tonic-gate { 40457c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 40467c478bd9Sstevel@tonic-gate "bogus queue file, uid=%d, gid=%d, mode=%o", 40477c478bd9Sstevel@tonic-gate st.st_uid, st.st_gid, st.st_mode); 40487c478bd9Sstevel@tonic-gate } 40497c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 40507c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s): bogus file\n", qf); 40517c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE; 40527c478bd9Sstevel@tonic-gate if (!openonly) 40537c478bd9Sstevel@tonic-gate loseqfile(e, "bogus file uid/gid in mqueue"); 40547c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 40557c478bd9Sstevel@tonic-gate return false; 40567c478bd9Sstevel@tonic-gate } 40577c478bd9Sstevel@tonic-gate 40587c478bd9Sstevel@tonic-gate if (st.st_size == 0) 40597c478bd9Sstevel@tonic-gate { 40607c478bd9Sstevel@tonic-gate /* must be a bogus file -- if also old, just remove it */ 40617c478bd9Sstevel@tonic-gate if (!openonly && st.st_ctime + 10 * 60 < curtime()) 40627c478bd9Sstevel@tonic-gate { 40637c478bd9Sstevel@tonic-gate (void) xunlink(queuename(e, DATAFL_LETTER)); 40647c478bd9Sstevel@tonic-gate (void) xunlink(queuename(e, ANYQFL_LETTER)); 40657c478bd9Sstevel@tonic-gate } 40667c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 40677c478bd9Sstevel@tonic-gate return false; 40687c478bd9Sstevel@tonic-gate } 40697c478bd9Sstevel@tonic-gate 40707c478bd9Sstevel@tonic-gate if (st.st_nlink == 0) 40717c478bd9Sstevel@tonic-gate { 40727c478bd9Sstevel@tonic-gate /* 40737c478bd9Sstevel@tonic-gate ** Race condition -- we got a file just as it was being 40747c478bd9Sstevel@tonic-gate ** unlinked. Just assume it is zero length. 40757c478bd9Sstevel@tonic-gate */ 40767c478bd9Sstevel@tonic-gate 40777c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 40787c478bd9Sstevel@tonic-gate return false; 40797c478bd9Sstevel@tonic-gate } 40807c478bd9Sstevel@tonic-gate 40817c478bd9Sstevel@tonic-gate #if _FFR_TRUSTED_QF 40827c478bd9Sstevel@tonic-gate /* 40837c478bd9Sstevel@tonic-gate ** If we don't own the file mark it as unsafe. 40847c478bd9Sstevel@tonic-gate ** However, allow TrustedUser to own it as well 40857c478bd9Sstevel@tonic-gate ** in case TrustedUser manipulates the queue. 40867c478bd9Sstevel@tonic-gate */ 40877c478bd9Sstevel@tonic-gate 40887c478bd9Sstevel@tonic-gate if (st.st_uid != geteuid() && st.st_uid != TrustedUid) 40897c478bd9Sstevel@tonic-gate e->e_flags |= EF_UNSAFE; 40907c478bd9Sstevel@tonic-gate #else /* _FFR_TRUSTED_QF */ 40917c478bd9Sstevel@tonic-gate /* If we don't own the file mark it as unsafe */ 40927c478bd9Sstevel@tonic-gate if (st.st_uid != geteuid()) 40937c478bd9Sstevel@tonic-gate e->e_flags |= EF_UNSAFE; 40947c478bd9Sstevel@tonic-gate #endif /* _FFR_TRUSTED_QF */ 40957c478bd9Sstevel@tonic-gate 40967c478bd9Sstevel@tonic-gate /* good file -- save this lock */ 40977c478bd9Sstevel@tonic-gate e->e_lockfp = qfp; 40987c478bd9Sstevel@tonic-gate 40997c478bd9Sstevel@tonic-gate /* Just wanted the open file */ 41007c478bd9Sstevel@tonic-gate if (openonly) 41017c478bd9Sstevel@tonic-gate return true; 41027c478bd9Sstevel@tonic-gate 41037c478bd9Sstevel@tonic-gate /* do basic system initialization */ 41047c478bd9Sstevel@tonic-gate initsys(e); 41057c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'i', e->e_id); 41067c478bd9Sstevel@tonic-gate 41077c478bd9Sstevel@tonic-gate LineNumber = 0; 41087c478bd9Sstevel@tonic-gate e->e_flags |= EF_GLOBALERRS; 41097c478bd9Sstevel@tonic-gate set_op_mode(MD_QUEUERUN); 41107c478bd9Sstevel@tonic-gate ctladdr = NULL; 41117c478bd9Sstevel@tonic-gate e->e_qfletter = queue_letter(e, ANYQFL_LETTER); 41127c478bd9Sstevel@tonic-gate e->e_dfqgrp = e->e_qgrp; 41137c478bd9Sstevel@tonic-gate e->e_dfqdir = e->e_qdir; 41147c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_MACRO 41157c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{queue}"), 41167c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir)); 41177c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_MACRO */ 41187c478bd9Sstevel@tonic-gate e->e_dfino = -1; 41197c478bd9Sstevel@tonic-gate e->e_msgsize = -1; 41207c478bd9Sstevel@tonic-gate while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL) 41217c478bd9Sstevel@tonic-gate { 41227c478bd9Sstevel@tonic-gate unsigned long qflags; 41237c478bd9Sstevel@tonic-gate ADDRESS *q; 41247c478bd9Sstevel@tonic-gate int r; 41257c478bd9Sstevel@tonic-gate time_t now; 41267c478bd9Sstevel@tonic-gate auto char *ep; 41277c478bd9Sstevel@tonic-gate 41287c478bd9Sstevel@tonic-gate if (tTd(40, 4)) 41297c478bd9Sstevel@tonic-gate sm_dprintf("+++++ %s\n", bp); 41307c478bd9Sstevel@tonic-gate if (nomore) 41317c478bd9Sstevel@tonic-gate { 41327c478bd9Sstevel@tonic-gate /* hack attack */ 41337c478bd9Sstevel@tonic-gate hackattack: 41347c478bd9Sstevel@tonic-gate syserr("SECURITY ALERT: extra or bogus data in queue file: %s", 41357c478bd9Sstevel@tonic-gate bp); 41367c478bd9Sstevel@tonic-gate err = "bogus queue line"; 41377c478bd9Sstevel@tonic-gate goto fail; 41387c478bd9Sstevel@tonic-gate } 41397c478bd9Sstevel@tonic-gate switch (bp[0]) 41407c478bd9Sstevel@tonic-gate { 41417c478bd9Sstevel@tonic-gate case 'A': /* AUTH= parameter */ 41427c478bd9Sstevel@tonic-gate if (!xtextok(&bp[1])) 41437c478bd9Sstevel@tonic-gate goto hackattack; 41447c478bd9Sstevel@tonic-gate e->e_auth_param = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 41457c478bd9Sstevel@tonic-gate break; 41467c478bd9Sstevel@tonic-gate 41477c478bd9Sstevel@tonic-gate case 'B': /* body type */ 41487c478bd9Sstevel@tonic-gate r = check_bodytype(&bp[1]); 41497c478bd9Sstevel@tonic-gate if (!BODYTYPE_VALID(r)) 41507c478bd9Sstevel@tonic-gate goto hackattack; 41517c478bd9Sstevel@tonic-gate e->e_bodytype = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 41527c478bd9Sstevel@tonic-gate break; 41537c478bd9Sstevel@tonic-gate 41547c478bd9Sstevel@tonic-gate case 'C': /* specify controlling user */ 41557c478bd9Sstevel@tonic-gate ctladdr = setctluser(&bp[1], qfver, e); 41567c478bd9Sstevel@tonic-gate break; 41577c478bd9Sstevel@tonic-gate 41587c478bd9Sstevel@tonic-gate case 'D': /* data file name */ 41597c478bd9Sstevel@tonic-gate /* obsolete -- ignore */ 41607c478bd9Sstevel@tonic-gate break; 41617c478bd9Sstevel@tonic-gate 41627c478bd9Sstevel@tonic-gate case 'd': /* data file directory name */ 41637c478bd9Sstevel@tonic-gate { 41647c478bd9Sstevel@tonic-gate int qgrp, qdir; 41657c478bd9Sstevel@tonic-gate 41667c478bd9Sstevel@tonic-gate #if _FFR_MSP_PARANOIA 41677c478bd9Sstevel@tonic-gate /* forbid queue groups in MSP? */ 41687c478bd9Sstevel@tonic-gate if (UseMSP) 41697c478bd9Sstevel@tonic-gate goto hackattack; 41707c478bd9Sstevel@tonic-gate #endif /* _FFR_MSP_PARANOIA */ 41717c478bd9Sstevel@tonic-gate for (qgrp = 0; 41727c478bd9Sstevel@tonic-gate qgrp < NumQueue && Queue[qgrp] != NULL; 41737c478bd9Sstevel@tonic-gate ++qgrp) 41747c478bd9Sstevel@tonic-gate { 41757c478bd9Sstevel@tonic-gate for (qdir = 0; 41767c478bd9Sstevel@tonic-gate qdir < Queue[qgrp]->qg_numqueues; 41777c478bd9Sstevel@tonic-gate ++qdir) 41787c478bd9Sstevel@tonic-gate { 41797c478bd9Sstevel@tonic-gate if (strcmp(&bp[1], 41807c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name) 41817c478bd9Sstevel@tonic-gate == 0) 41827c478bd9Sstevel@tonic-gate { 41837c478bd9Sstevel@tonic-gate e->e_dfqgrp = qgrp; 41847c478bd9Sstevel@tonic-gate e->e_dfqdir = qdir; 41857c478bd9Sstevel@tonic-gate goto done; 41867c478bd9Sstevel@tonic-gate } 41877c478bd9Sstevel@tonic-gate } 41887c478bd9Sstevel@tonic-gate } 41897c478bd9Sstevel@tonic-gate err = "bogus queue file directory"; 41907c478bd9Sstevel@tonic-gate goto fail; 41917c478bd9Sstevel@tonic-gate done: 41927c478bd9Sstevel@tonic-gate break; 41937c478bd9Sstevel@tonic-gate } 41947c478bd9Sstevel@tonic-gate 41957c478bd9Sstevel@tonic-gate case 'E': /* specify error recipient */ 41967c478bd9Sstevel@tonic-gate /* no longer used */ 41977c478bd9Sstevel@tonic-gate break; 41987c478bd9Sstevel@tonic-gate 41997c478bd9Sstevel@tonic-gate case 'F': /* flag bits */ 42007c478bd9Sstevel@tonic-gate if (strncmp(bp, "From ", 5) == 0) 42017c478bd9Sstevel@tonic-gate { 42027c478bd9Sstevel@tonic-gate /* we are being spoofed! */ 42037c478bd9Sstevel@tonic-gate syserr("SECURITY ALERT: bogus qf line %s", bp); 42047c478bd9Sstevel@tonic-gate err = "bogus queue line"; 42057c478bd9Sstevel@tonic-gate goto fail; 42067c478bd9Sstevel@tonic-gate } 42077c478bd9Sstevel@tonic-gate for (p = &bp[1]; *p != '\0'; p++) 42087c478bd9Sstevel@tonic-gate { 42097c478bd9Sstevel@tonic-gate switch (*p) 42107c478bd9Sstevel@tonic-gate { 42117c478bd9Sstevel@tonic-gate case '8': /* has 8 bit data */ 42127c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS8BIT; 42137c478bd9Sstevel@tonic-gate break; 42147c478bd9Sstevel@tonic-gate 42157c478bd9Sstevel@tonic-gate case 'b': /* delete Bcc: header */ 42167c478bd9Sstevel@tonic-gate e->e_flags |= EF_DELETE_BCC; 42177c478bd9Sstevel@tonic-gate break; 42187c478bd9Sstevel@tonic-gate 42197c478bd9Sstevel@tonic-gate case 'd': /* envelope has DSN RET= */ 42207c478bd9Sstevel@tonic-gate e->e_flags |= EF_RET_PARAM; 42217c478bd9Sstevel@tonic-gate break; 42227c478bd9Sstevel@tonic-gate 42237c478bd9Sstevel@tonic-gate case 'n': /* don't return body */ 42247c478bd9Sstevel@tonic-gate e->e_flags |= EF_NO_BODY_RETN; 42257c478bd9Sstevel@tonic-gate break; 42267c478bd9Sstevel@tonic-gate 42277c478bd9Sstevel@tonic-gate case 'r': /* response */ 42287c478bd9Sstevel@tonic-gate e->e_flags |= EF_RESPONSE; 42297c478bd9Sstevel@tonic-gate break; 42307c478bd9Sstevel@tonic-gate 42317c478bd9Sstevel@tonic-gate case 's': /* split */ 42327c478bd9Sstevel@tonic-gate e->e_flags |= EF_SPLIT; 42337c478bd9Sstevel@tonic-gate break; 42347c478bd9Sstevel@tonic-gate 42357c478bd9Sstevel@tonic-gate case 'w': /* warning sent */ 42367c478bd9Sstevel@tonic-gate e->e_flags |= EF_WARNING; 42377c478bd9Sstevel@tonic-gate break; 42387c478bd9Sstevel@tonic-gate } 42397c478bd9Sstevel@tonic-gate } 42407c478bd9Sstevel@tonic-gate break; 42417c478bd9Sstevel@tonic-gate 42427c478bd9Sstevel@tonic-gate case 'q': /* quarantine reason */ 42437c478bd9Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 42447c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 42457c478bd9Sstevel@tonic-gate macid("{quarantine}"), e->e_quarmsg); 42467c478bd9Sstevel@tonic-gate break; 42477c478bd9Sstevel@tonic-gate 42487c478bd9Sstevel@tonic-gate case 'H': /* header */ 42497c478bd9Sstevel@tonic-gate 42507c478bd9Sstevel@tonic-gate /* 42517c478bd9Sstevel@tonic-gate ** count size before chompheader() destroys the line. 42527c478bd9Sstevel@tonic-gate ** this isn't accurate due to macro expansion, but 42537c478bd9Sstevel@tonic-gate ** better than before. "-3" to skip H?? at least. 42547c478bd9Sstevel@tonic-gate */ 42557c478bd9Sstevel@tonic-gate 42567c478bd9Sstevel@tonic-gate hdrsize += strlen(bp) - 3; 42577c478bd9Sstevel@tonic-gate (void) chompheader(&bp[1], CHHDR_QUEUE, NULL, e); 42587c478bd9Sstevel@tonic-gate break; 42597c478bd9Sstevel@tonic-gate 42607c478bd9Sstevel@tonic-gate case 'I': /* data file's inode number */ 42617c478bd9Sstevel@tonic-gate /* regenerated below */ 42627c478bd9Sstevel@tonic-gate break; 42637c478bd9Sstevel@tonic-gate 42647c478bd9Sstevel@tonic-gate case 'K': /* time of last delivery attempt */ 42657c478bd9Sstevel@tonic-gate e->e_dtime = atol(&buf[1]); 42667c478bd9Sstevel@tonic-gate break; 42677c478bd9Sstevel@tonic-gate 42687c478bd9Sstevel@tonic-gate case 'L': /* Solaris Content-Length: */ 42697c478bd9Sstevel@tonic-gate case 'M': /* message */ 42707c478bd9Sstevel@tonic-gate /* ignore this; we want a new message next time */ 42717c478bd9Sstevel@tonic-gate break; 42727c478bd9Sstevel@tonic-gate 42737c478bd9Sstevel@tonic-gate case 'N': /* number of delivery attempts */ 42747c478bd9Sstevel@tonic-gate e->e_ntries = atoi(&buf[1]); 42757c478bd9Sstevel@tonic-gate 42767c478bd9Sstevel@tonic-gate /* if this has been tried recently, let it be */ 42777c478bd9Sstevel@tonic-gate now = curtime(); 42787c478bd9Sstevel@tonic-gate if (e->e_ntries > 0 && e->e_dtime <= now && 42797c478bd9Sstevel@tonic-gate now < e->e_dtime + MinQueueAge) 42807c478bd9Sstevel@tonic-gate { 42817c478bd9Sstevel@tonic-gate char *howlong; 42827c478bd9Sstevel@tonic-gate 42837c478bd9Sstevel@tonic-gate howlong = pintvl(now - e->e_dtime, true); 42847c478bd9Sstevel@tonic-gate if (Verbose) 42857c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 42867c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 42877c478bd9Sstevel@tonic-gate "%s: too young (%s)\n", 42887c478bd9Sstevel@tonic-gate e->e_id, howlong); 42897c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 42907c478bd9Sstevel@tonic-gate sm_dprintf("%s: too young (%s)\n", 42917c478bd9Sstevel@tonic-gate e->e_id, howlong); 42927c478bd9Sstevel@tonic-gate if (LogLevel > 19) 42937c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, 42947c478bd9Sstevel@tonic-gate "too young (%s)", 42957c478bd9Sstevel@tonic-gate howlong); 42967c478bd9Sstevel@tonic-gate e->e_id = NULL; 42977c478bd9Sstevel@tonic-gate unlockqueue(e); 42987c478bd9Sstevel@tonic-gate return false; 42997c478bd9Sstevel@tonic-gate } 43007c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, 43017c478bd9Sstevel@tonic-gate macid("{ntries}"), &buf[1]); 43027c478bd9Sstevel@tonic-gate 43037c478bd9Sstevel@tonic-gate #if NAMED_BIND 43047c478bd9Sstevel@tonic-gate /* adjust BIND parameters immediately */ 43057c478bd9Sstevel@tonic-gate if (e->e_ntries == 0) 43067c478bd9Sstevel@tonic-gate { 43077c478bd9Sstevel@tonic-gate _res.retry = TimeOuts.res_retry[RES_TO_FIRST]; 43087c478bd9Sstevel@tonic-gate _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; 43097c478bd9Sstevel@tonic-gate } 43107c478bd9Sstevel@tonic-gate else 43117c478bd9Sstevel@tonic-gate { 43127c478bd9Sstevel@tonic-gate _res.retry = TimeOuts.res_retry[RES_TO_NORMAL]; 43137c478bd9Sstevel@tonic-gate _res.retrans = TimeOuts.res_retrans[RES_TO_NORMAL]; 43147c478bd9Sstevel@tonic-gate } 43157c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 43167c478bd9Sstevel@tonic-gate break; 43177c478bd9Sstevel@tonic-gate 43187c478bd9Sstevel@tonic-gate case 'P': /* message priority */ 43197c478bd9Sstevel@tonic-gate e->e_msgpriority = atol(&bp[1]) + WkTimeFact; 43207c478bd9Sstevel@tonic-gate break; 43217c478bd9Sstevel@tonic-gate 43227c478bd9Sstevel@tonic-gate case 'Q': /* original recipient */ 43237c478bd9Sstevel@tonic-gate orcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 43247c478bd9Sstevel@tonic-gate break; 43257c478bd9Sstevel@tonic-gate 43267c478bd9Sstevel@tonic-gate case 'r': /* final recipient */ 43277c478bd9Sstevel@tonic-gate frcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 43287c478bd9Sstevel@tonic-gate break; 43297c478bd9Sstevel@tonic-gate 43307c478bd9Sstevel@tonic-gate case 'R': /* specify recipient */ 43317c478bd9Sstevel@tonic-gate p = bp; 43327c478bd9Sstevel@tonic-gate qflags = 0; 43337c478bd9Sstevel@tonic-gate if (qfver >= 1) 43347c478bd9Sstevel@tonic-gate { 43357c478bd9Sstevel@tonic-gate /* get flag bits */ 43367c478bd9Sstevel@tonic-gate while (*++p != '\0' && *p != ':') 43377c478bd9Sstevel@tonic-gate { 43387c478bd9Sstevel@tonic-gate switch (*p) 43397c478bd9Sstevel@tonic-gate { 43407c478bd9Sstevel@tonic-gate case 'N': 43417c478bd9Sstevel@tonic-gate qflags |= QHASNOTIFY; 43427c478bd9Sstevel@tonic-gate break; 43437c478bd9Sstevel@tonic-gate 43447c478bd9Sstevel@tonic-gate case 'S': 43457c478bd9Sstevel@tonic-gate qflags |= QPINGONSUCCESS; 43467c478bd9Sstevel@tonic-gate break; 43477c478bd9Sstevel@tonic-gate 43487c478bd9Sstevel@tonic-gate case 'F': 43497c478bd9Sstevel@tonic-gate qflags |= QPINGONFAILURE; 43507c478bd9Sstevel@tonic-gate break; 43517c478bd9Sstevel@tonic-gate 43527c478bd9Sstevel@tonic-gate case 'D': 43537c478bd9Sstevel@tonic-gate qflags |= QPINGONDELAY; 43547c478bd9Sstevel@tonic-gate break; 43557c478bd9Sstevel@tonic-gate 43567c478bd9Sstevel@tonic-gate case 'P': 43577c478bd9Sstevel@tonic-gate qflags |= QPRIMARY; 43587c478bd9Sstevel@tonic-gate break; 43597c478bd9Sstevel@tonic-gate 43607c478bd9Sstevel@tonic-gate case 'A': 43617c478bd9Sstevel@tonic-gate if (ctladdr != NULL) 43627c478bd9Sstevel@tonic-gate ctladdr->q_flags |= QALIAS; 43637c478bd9Sstevel@tonic-gate break; 43647c478bd9Sstevel@tonic-gate 43657c478bd9Sstevel@tonic-gate default: /* ignore or complain? */ 43667c478bd9Sstevel@tonic-gate break; 43677c478bd9Sstevel@tonic-gate } 43687c478bd9Sstevel@tonic-gate } 43697c478bd9Sstevel@tonic-gate } 43707c478bd9Sstevel@tonic-gate else 43717c478bd9Sstevel@tonic-gate qflags |= QPRIMARY; 43727c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), 43737c478bd9Sstevel@tonic-gate "e r"); 43747c478bd9Sstevel@tonic-gate if (*p != '\0') 43757c478bd9Sstevel@tonic-gate q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', 43767c478bd9Sstevel@tonic-gate NULL, e, true); 43777c478bd9Sstevel@tonic-gate else 43787c478bd9Sstevel@tonic-gate q = NULL; 43797c478bd9Sstevel@tonic-gate if (q != NULL) 43807c478bd9Sstevel@tonic-gate { 43817c478bd9Sstevel@tonic-gate /* make sure we keep the current qgrp */ 43827c478bd9Sstevel@tonic-gate if (ISVALIDQGRP(e->e_qgrp)) 43837c478bd9Sstevel@tonic-gate q->q_qgrp = e->e_qgrp; 43847c478bd9Sstevel@tonic-gate q->q_alias = ctladdr; 43857c478bd9Sstevel@tonic-gate if (qfver >= 1) 43867c478bd9Sstevel@tonic-gate q->q_flags &= ~Q_PINGFLAGS; 43877c478bd9Sstevel@tonic-gate q->q_flags |= qflags; 43887c478bd9Sstevel@tonic-gate q->q_finalrcpt = frcpt; 43897c478bd9Sstevel@tonic-gate q->q_orcpt = orcpt; 43907c478bd9Sstevel@tonic-gate (void) recipient(q, &e->e_sendqueue, 0, e); 43917c478bd9Sstevel@tonic-gate } 43927c478bd9Sstevel@tonic-gate frcpt = NULL; 43937c478bd9Sstevel@tonic-gate orcpt = NULL; 43947c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), 43957c478bd9Sstevel@tonic-gate NULL); 43967c478bd9Sstevel@tonic-gate break; 43977c478bd9Sstevel@tonic-gate 43987c478bd9Sstevel@tonic-gate case 'S': /* sender */ 43997c478bd9Sstevel@tonic-gate setsender(sm_rpool_strdup_x(e->e_rpool, &bp[1]), 44007c478bd9Sstevel@tonic-gate e, NULL, '\0', true); 44017c478bd9Sstevel@tonic-gate break; 44027c478bd9Sstevel@tonic-gate 44037c478bd9Sstevel@tonic-gate case 'T': /* init time */ 44047c478bd9Sstevel@tonic-gate e->e_ctime = atol(&bp[1]); 44057c478bd9Sstevel@tonic-gate break; 44067c478bd9Sstevel@tonic-gate 44077c478bd9Sstevel@tonic-gate case 'V': /* queue file version number */ 44087c478bd9Sstevel@tonic-gate qfver = atoi(&bp[1]); 44097c478bd9Sstevel@tonic-gate if (qfver <= QF_VERSION) 44107c478bd9Sstevel@tonic-gate break; 44117c478bd9Sstevel@tonic-gate syserr("Version number in queue file (%d) greater than max (%d)", 44127c478bd9Sstevel@tonic-gate qfver, QF_VERSION); 44137c478bd9Sstevel@tonic-gate err = "unsupported queue file version"; 44147c478bd9Sstevel@tonic-gate goto fail; 44157c478bd9Sstevel@tonic-gate /* NOTREACHED */ 44167c478bd9Sstevel@tonic-gate break; 44177c478bd9Sstevel@tonic-gate 44187c478bd9Sstevel@tonic-gate case 'Z': /* original envelope id from ESMTP */ 44197c478bd9Sstevel@tonic-gate e->e_envid = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 44207c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 44217c478bd9Sstevel@tonic-gate macid("{dsn_envid}"), e->e_envid); 44227c478bd9Sstevel@tonic-gate break; 44237c478bd9Sstevel@tonic-gate 44247c478bd9Sstevel@tonic-gate case '!': /* deliver by */ 44257c478bd9Sstevel@tonic-gate 44267c478bd9Sstevel@tonic-gate /* format: flag (1 char) space long-integer */ 44277c478bd9Sstevel@tonic-gate e->e_dlvr_flag = buf[1]; 44287c478bd9Sstevel@tonic-gate e->e_deliver_by = strtol(&buf[3], NULL, 10); 44297c478bd9Sstevel@tonic-gate 44307c478bd9Sstevel@tonic-gate case '$': /* define macro */ 44317c478bd9Sstevel@tonic-gate { 44327c478bd9Sstevel@tonic-gate char *p; 44337c478bd9Sstevel@tonic-gate 44347c478bd9Sstevel@tonic-gate /* XXX elimate p? */ 44357c478bd9Sstevel@tonic-gate r = macid_parse(&bp[1], &ep); 44367c478bd9Sstevel@tonic-gate if (r == 0) 44377c478bd9Sstevel@tonic-gate break; 44387c478bd9Sstevel@tonic-gate p = sm_rpool_strdup_x(e->e_rpool, ep); 44397c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, r, p); 44407c478bd9Sstevel@tonic-gate } 44417c478bd9Sstevel@tonic-gate break; 44427c478bd9Sstevel@tonic-gate 44437c478bd9Sstevel@tonic-gate case '.': /* terminate file */ 44447c478bd9Sstevel@tonic-gate nomore = true; 44457c478bd9Sstevel@tonic-gate break; 44467c478bd9Sstevel@tonic-gate 44477c478bd9Sstevel@tonic-gate #if _FFR_QUEUEDELAY 44487c478bd9Sstevel@tonic-gate case 'G': 44497c478bd9Sstevel@tonic-gate case 'Y': 44507c478bd9Sstevel@tonic-gate 44517c478bd9Sstevel@tonic-gate /* 44527c478bd9Sstevel@tonic-gate ** Maintain backward compatibility for 44537c478bd9Sstevel@tonic-gate ** users who defined _FFR_QUEUEDELAY in 44547c478bd9Sstevel@tonic-gate ** previous releases. Remove this 44557c478bd9Sstevel@tonic-gate ** code in 8.14 or 8.15. 44567c478bd9Sstevel@tonic-gate */ 44577c478bd9Sstevel@tonic-gate 44587c478bd9Sstevel@tonic-gate if (qfver == 5 || qfver == 7) 44597c478bd9Sstevel@tonic-gate break; 44607c478bd9Sstevel@tonic-gate 44617c478bd9Sstevel@tonic-gate /* If not qfver 5 or 7, then 'G' or 'Y' is invalid */ 44627c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 44637c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUEDELAY */ 44647c478bd9Sstevel@tonic-gate 44657c478bd9Sstevel@tonic-gate default: 44667c478bd9Sstevel@tonic-gate syserr("readqf: %s: line %d: bad line \"%s\"", 44677c478bd9Sstevel@tonic-gate qf, LineNumber, shortenstring(bp, MAXSHORTSTR)); 44687c478bd9Sstevel@tonic-gate err = "unrecognized line"; 44697c478bd9Sstevel@tonic-gate goto fail; 44707c478bd9Sstevel@tonic-gate } 44717c478bd9Sstevel@tonic-gate 44727c478bd9Sstevel@tonic-gate if (bp != buf) 44737c478bd9Sstevel@tonic-gate sm_free(bp); /* XXX */ 44747c478bd9Sstevel@tonic-gate } 44757c478bd9Sstevel@tonic-gate 44767c478bd9Sstevel@tonic-gate /* 44777c478bd9Sstevel@tonic-gate ** If we haven't read any lines, this queue file is empty. 44787c478bd9Sstevel@tonic-gate ** Arrange to remove it without referencing any null pointers. 44797c478bd9Sstevel@tonic-gate */ 44807c478bd9Sstevel@tonic-gate 44817c478bd9Sstevel@tonic-gate if (LineNumber == 0) 44827c478bd9Sstevel@tonic-gate { 44837c478bd9Sstevel@tonic-gate errno = 0; 44847c478bd9Sstevel@tonic-gate e->e_flags |= EF_CLRQUEUE|EF_FATALERRS|EF_RESPONSE; 44857c478bd9Sstevel@tonic-gate return true; 44867c478bd9Sstevel@tonic-gate } 44877c478bd9Sstevel@tonic-gate 44887c478bd9Sstevel@tonic-gate /* Check to make sure we have a complete queue file read */ 44897c478bd9Sstevel@tonic-gate if (!nomore) 44907c478bd9Sstevel@tonic-gate { 44917c478bd9Sstevel@tonic-gate syserr("readqf: %s: incomplete queue file read", qf); 44927c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 44937c478bd9Sstevel@tonic-gate return false; 44947c478bd9Sstevel@tonic-gate } 44957c478bd9Sstevel@tonic-gate 44967c478bd9Sstevel@tonic-gate /* possibly set ${dsn_ret} macro */ 44977c478bd9Sstevel@tonic-gate if (bitset(EF_RET_PARAM, e->e_flags)) 44987c478bd9Sstevel@tonic-gate { 44997c478bd9Sstevel@tonic-gate if (bitset(EF_NO_BODY_RETN, e->e_flags)) 45007c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 45017c478bd9Sstevel@tonic-gate macid("{dsn_ret}"), "hdrs"); 45027c478bd9Sstevel@tonic-gate else 45037c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 45047c478bd9Sstevel@tonic-gate macid("{dsn_ret}"), "full"); 45057c478bd9Sstevel@tonic-gate } 45067c478bd9Sstevel@tonic-gate 45077c478bd9Sstevel@tonic-gate /* 45087c478bd9Sstevel@tonic-gate ** Arrange to read the data file. 45097c478bd9Sstevel@tonic-gate */ 45107c478bd9Sstevel@tonic-gate 45117c478bd9Sstevel@tonic-gate p = queuename(e, DATAFL_LETTER); 45127c478bd9Sstevel@tonic-gate e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, p, SM_IO_RDONLY_B, 45137c478bd9Sstevel@tonic-gate NULL); 45147c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL) 45157c478bd9Sstevel@tonic-gate { 45167c478bd9Sstevel@tonic-gate syserr("readqf: cannot open %s", p); 45177c478bd9Sstevel@tonic-gate } 45187c478bd9Sstevel@tonic-gate else 45197c478bd9Sstevel@tonic-gate { 45207c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS_DF; 45217c478bd9Sstevel@tonic-gate if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &st) 45227c478bd9Sstevel@tonic-gate >= 0) 45237c478bd9Sstevel@tonic-gate { 45247c478bd9Sstevel@tonic-gate e->e_msgsize = st.st_size + hdrsize; 45257c478bd9Sstevel@tonic-gate e->e_dfdev = st.st_dev; 45267c478bd9Sstevel@tonic-gate e->e_dfino = ST_INODE(st); 45277c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%ld", 45287c478bd9Sstevel@tonic-gate e->e_msgsize); 45297c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), 45307c478bd9Sstevel@tonic-gate buf); 45317c478bd9Sstevel@tonic-gate } 45327c478bd9Sstevel@tonic-gate } 45337c478bd9Sstevel@tonic-gate 45347c478bd9Sstevel@tonic-gate return true; 45357c478bd9Sstevel@tonic-gate 45367c478bd9Sstevel@tonic-gate fail: 45377c478bd9Sstevel@tonic-gate /* 45387c478bd9Sstevel@tonic-gate ** There was some error reading the qf file (reason is in err var.) 45397c478bd9Sstevel@tonic-gate ** Cleanup: 45407c478bd9Sstevel@tonic-gate ** close file; clear e_lockfp since it is the same as qfp, 45417c478bd9Sstevel@tonic-gate ** hence it is invalid (as file) after qfp is closed; 45427c478bd9Sstevel@tonic-gate ** the qf file is on disk, so set the flag to avoid calling 45437c478bd9Sstevel@tonic-gate ** queueup() with bogus data. 45447c478bd9Sstevel@tonic-gate */ 45457c478bd9Sstevel@tonic-gate 45467c478bd9Sstevel@tonic-gate if (qfp != NULL) 45477c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 45487c478bd9Sstevel@tonic-gate e->e_lockfp = NULL; 45497c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE; 45507c478bd9Sstevel@tonic-gate loseqfile(e, err); 45517c478bd9Sstevel@tonic-gate return false; 45527c478bd9Sstevel@tonic-gate } 45537c478bd9Sstevel@tonic-gate /* 45547c478bd9Sstevel@tonic-gate ** PRTSTR -- print a string, "unprintable" characters are shown as \oct 45557c478bd9Sstevel@tonic-gate ** 45567c478bd9Sstevel@tonic-gate ** Parameters: 45577c478bd9Sstevel@tonic-gate ** s -- string to print 45587c478bd9Sstevel@tonic-gate ** ml -- maximum length of output 45597c478bd9Sstevel@tonic-gate ** 45607c478bd9Sstevel@tonic-gate ** Returns: 45617c478bd9Sstevel@tonic-gate ** number of entries 45627c478bd9Sstevel@tonic-gate ** 45637c478bd9Sstevel@tonic-gate ** Side Effects: 45647c478bd9Sstevel@tonic-gate ** Prints a string on stdout. 45657c478bd9Sstevel@tonic-gate */ 45667c478bd9Sstevel@tonic-gate 45677c478bd9Sstevel@tonic-gate static void 45687c478bd9Sstevel@tonic-gate prtstr(s, ml) 45697c478bd9Sstevel@tonic-gate char *s; 45707c478bd9Sstevel@tonic-gate int ml; 45717c478bd9Sstevel@tonic-gate { 45727c478bd9Sstevel@tonic-gate int c; 45737c478bd9Sstevel@tonic-gate 45747c478bd9Sstevel@tonic-gate if (s == NULL) 45757c478bd9Sstevel@tonic-gate return; 45767c478bd9Sstevel@tonic-gate while (ml-- > 0 && ((c = *s++) != '\0')) 45777c478bd9Sstevel@tonic-gate { 45787c478bd9Sstevel@tonic-gate if (c == '\\') 45797c478bd9Sstevel@tonic-gate { 45807c478bd9Sstevel@tonic-gate if (ml-- > 0) 45817c478bd9Sstevel@tonic-gate { 45827c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c); 45837c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c); 45847c478bd9Sstevel@tonic-gate } 45857c478bd9Sstevel@tonic-gate } 45867c478bd9Sstevel@tonic-gate else if (isascii(c) && isprint(c)) 45877c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c); 45887c478bd9Sstevel@tonic-gate else 45897c478bd9Sstevel@tonic-gate { 45907c478bd9Sstevel@tonic-gate if ((ml -= 3) > 0) 45917c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 45927c478bd9Sstevel@tonic-gate "\\%03o", c & 0xFF); 45937c478bd9Sstevel@tonic-gate } 45947c478bd9Sstevel@tonic-gate } 45957c478bd9Sstevel@tonic-gate } 45967c478bd9Sstevel@tonic-gate /* 45977c478bd9Sstevel@tonic-gate ** PRINTNQE -- print out number of entries in the mail queue 45987c478bd9Sstevel@tonic-gate ** 45997c478bd9Sstevel@tonic-gate ** Parameters: 46007c478bd9Sstevel@tonic-gate ** out -- output file pointer. 46017c478bd9Sstevel@tonic-gate ** prefix -- string to output in front of each line. 46027c478bd9Sstevel@tonic-gate ** 46037c478bd9Sstevel@tonic-gate ** Returns: 46047c478bd9Sstevel@tonic-gate ** none. 46057c478bd9Sstevel@tonic-gate */ 46067c478bd9Sstevel@tonic-gate 46077c478bd9Sstevel@tonic-gate void 46087c478bd9Sstevel@tonic-gate printnqe(out, prefix) 46097c478bd9Sstevel@tonic-gate SM_FILE_T *out; 46107c478bd9Sstevel@tonic-gate char *prefix; 46117c478bd9Sstevel@tonic-gate { 46127c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 46137c478bd9Sstevel@tonic-gate int i, k = 0, nrequests = 0; 46147c478bd9Sstevel@tonic-gate bool unknown = false; 46157c478bd9Sstevel@tonic-gate 46167c478bd9Sstevel@tonic-gate if (ShmId == SM_SHM_NO_ID) 46177c478bd9Sstevel@tonic-gate { 46187c478bd9Sstevel@tonic-gate if (prefix == NULL) 46197c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46207c478bd9Sstevel@tonic-gate "Data unavailable: shared memory not updated\n"); 46217c478bd9Sstevel@tonic-gate else 46227c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46237c478bd9Sstevel@tonic-gate "%sNOTCONFIGURED:-1\r\n", prefix); 46247c478bd9Sstevel@tonic-gate return; 46257c478bd9Sstevel@tonic-gate } 46267c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 46277c478bd9Sstevel@tonic-gate { 46287c478bd9Sstevel@tonic-gate int j; 46297c478bd9Sstevel@tonic-gate 46307c478bd9Sstevel@tonic-gate k++; 46317c478bd9Sstevel@tonic-gate for (j = 0; j < Queue[i]->qg_numqueues; j++) 46327c478bd9Sstevel@tonic-gate { 46337c478bd9Sstevel@tonic-gate int n; 46347c478bd9Sstevel@tonic-gate 46357c478bd9Sstevel@tonic-gate if (StopRequest) 46367c478bd9Sstevel@tonic-gate stop_sendmail(); 46377c478bd9Sstevel@tonic-gate 46387c478bd9Sstevel@tonic-gate n = QSHM_ENTRIES(Queue[i]->qg_qpaths[j].qp_idx); 46397c478bd9Sstevel@tonic-gate if (prefix != NULL) 46407c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46417c478bd9Sstevel@tonic-gate "%s%s:%d\r\n", 46427c478bd9Sstevel@tonic-gate prefix, qid_printqueue(i, j), n); 46437c478bd9Sstevel@tonic-gate else if (n < 0) 46447c478bd9Sstevel@tonic-gate { 46457c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46467c478bd9Sstevel@tonic-gate "%s: unknown number of entries\n", 46477c478bd9Sstevel@tonic-gate qid_printqueue(i, j)); 46487c478bd9Sstevel@tonic-gate unknown = true; 46497c478bd9Sstevel@tonic-gate } 46507c478bd9Sstevel@tonic-gate else if (n == 0) 46517c478bd9Sstevel@tonic-gate { 46527c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46537c478bd9Sstevel@tonic-gate "%s is empty\n", 46547c478bd9Sstevel@tonic-gate qid_printqueue(i, j)); 46557c478bd9Sstevel@tonic-gate } 46567c478bd9Sstevel@tonic-gate else if (n > 0) 46577c478bd9Sstevel@tonic-gate { 46587c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46597c478bd9Sstevel@tonic-gate "%s: entries=%d\n", 46607c478bd9Sstevel@tonic-gate qid_printqueue(i, j), n); 46617c478bd9Sstevel@tonic-gate nrequests += n; 46627c478bd9Sstevel@tonic-gate k++; 46637c478bd9Sstevel@tonic-gate } 46647c478bd9Sstevel@tonic-gate } 46657c478bd9Sstevel@tonic-gate } 46667c478bd9Sstevel@tonic-gate if (prefix == NULL && k > 1) 46677c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46687c478bd9Sstevel@tonic-gate "\t\tTotal requests: %d%s\n", 46697c478bd9Sstevel@tonic-gate nrequests, unknown ? " (about)" : ""); 46707c478bd9Sstevel@tonic-gate #else /* SM_CONF_SHM */ 46717c478bd9Sstevel@tonic-gate if (prefix == NULL) 46727c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46737c478bd9Sstevel@tonic-gate "Data unavailable without shared memory support\n"); 46747c478bd9Sstevel@tonic-gate else 46757c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46767c478bd9Sstevel@tonic-gate "%sNOTAVAILABLE:-1\r\n", prefix); 46777c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 46787c478bd9Sstevel@tonic-gate } 46797c478bd9Sstevel@tonic-gate /* 46807c478bd9Sstevel@tonic-gate ** PRINTQUEUE -- print out a representation of the mail queue 46817c478bd9Sstevel@tonic-gate ** 46827c478bd9Sstevel@tonic-gate ** Parameters: 46837c478bd9Sstevel@tonic-gate ** none. 46847c478bd9Sstevel@tonic-gate ** 46857c478bd9Sstevel@tonic-gate ** Returns: 46867c478bd9Sstevel@tonic-gate ** none. 46877c478bd9Sstevel@tonic-gate ** 46887c478bd9Sstevel@tonic-gate ** Side Effects: 46897c478bd9Sstevel@tonic-gate ** Prints a listing of the mail queue on the standard output. 46907c478bd9Sstevel@tonic-gate */ 46917c478bd9Sstevel@tonic-gate 46927c478bd9Sstevel@tonic-gate void 46937c478bd9Sstevel@tonic-gate printqueue() 46947c478bd9Sstevel@tonic-gate { 46957c478bd9Sstevel@tonic-gate int i, k = 0, nrequests = 0; 46967c478bd9Sstevel@tonic-gate 46977c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 46987c478bd9Sstevel@tonic-gate { 46997c478bd9Sstevel@tonic-gate int j; 47007c478bd9Sstevel@tonic-gate 47017c478bd9Sstevel@tonic-gate k++; 47027c478bd9Sstevel@tonic-gate for (j = 0; j < Queue[i]->qg_numqueues; j++) 47037c478bd9Sstevel@tonic-gate { 47047c478bd9Sstevel@tonic-gate if (StopRequest) 47057c478bd9Sstevel@tonic-gate stop_sendmail(); 47067c478bd9Sstevel@tonic-gate nrequests += print_single_queue(i, j); 47077c478bd9Sstevel@tonic-gate k++; 47087c478bd9Sstevel@tonic-gate } 47097c478bd9Sstevel@tonic-gate } 47107c478bd9Sstevel@tonic-gate if (k > 1) 47117c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 47127c478bd9Sstevel@tonic-gate "\t\tTotal requests: %d\n", 47137c478bd9Sstevel@tonic-gate nrequests); 47147c478bd9Sstevel@tonic-gate } 47157c478bd9Sstevel@tonic-gate /* 47167c478bd9Sstevel@tonic-gate ** PRINT_SINGLE_QUEUE -- print out a representation of a single mail queue 47177c478bd9Sstevel@tonic-gate ** 47187c478bd9Sstevel@tonic-gate ** Parameters: 47197c478bd9Sstevel@tonic-gate ** qgrp -- the index of the queue group. 47207c478bd9Sstevel@tonic-gate ** qdir -- the queue directory. 47217c478bd9Sstevel@tonic-gate ** 47227c478bd9Sstevel@tonic-gate ** Returns: 47237c478bd9Sstevel@tonic-gate ** number of requests in mail queue. 47247c478bd9Sstevel@tonic-gate ** 47257c478bd9Sstevel@tonic-gate ** Side Effects: 47267c478bd9Sstevel@tonic-gate ** Prints a listing of the mail queue on the standard output. 47277c478bd9Sstevel@tonic-gate */ 47287c478bd9Sstevel@tonic-gate 47297c478bd9Sstevel@tonic-gate int 47307c478bd9Sstevel@tonic-gate print_single_queue(qgrp, qdir) 47317c478bd9Sstevel@tonic-gate int qgrp; 47327c478bd9Sstevel@tonic-gate int qdir; 47337c478bd9Sstevel@tonic-gate { 47347c478bd9Sstevel@tonic-gate register WORK *w; 47357c478bd9Sstevel@tonic-gate SM_FILE_T *f; 47367c478bd9Sstevel@tonic-gate int nrequests; 47377c478bd9Sstevel@tonic-gate char qd[MAXPATHLEN]; 47387c478bd9Sstevel@tonic-gate char qddf[MAXPATHLEN]; 47397c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 47407c478bd9Sstevel@tonic-gate 47417c478bd9Sstevel@tonic-gate if (qdir == NOQDIR) 47427c478bd9Sstevel@tonic-gate { 47437c478bd9Sstevel@tonic-gate (void) sm_strlcpy(qd, ".", sizeof qd); 47447c478bd9Sstevel@tonic-gate (void) sm_strlcpy(qddf, ".", sizeof qddf); 47457c478bd9Sstevel@tonic-gate } 47467c478bd9Sstevel@tonic-gate else 47477c478bd9Sstevel@tonic-gate { 47487c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(qd, sizeof qd, 2, 47497c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name, 47507c478bd9Sstevel@tonic-gate (bitset(QP_SUBQF, 47517c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs) 47527c478bd9Sstevel@tonic-gate ? "/qf" : "")); 47537c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(qddf, sizeof qddf, 2, 47547c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name, 47557c478bd9Sstevel@tonic-gate (bitset(QP_SUBDF, 47567c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs) 47577c478bd9Sstevel@tonic-gate ? "/df" : "")); 47587c478bd9Sstevel@tonic-gate } 47597c478bd9Sstevel@tonic-gate 47607c478bd9Sstevel@tonic-gate /* 47617c478bd9Sstevel@tonic-gate ** Check for permission to print the queue 47627c478bd9Sstevel@tonic-gate */ 47637c478bd9Sstevel@tonic-gate 47647c478bd9Sstevel@tonic-gate if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0) 47657c478bd9Sstevel@tonic-gate { 47667c478bd9Sstevel@tonic-gate struct stat st; 47677c478bd9Sstevel@tonic-gate #ifdef NGROUPS_MAX 47687c478bd9Sstevel@tonic-gate int n; 47697c478bd9Sstevel@tonic-gate extern GIDSET_T InitialGidSet[NGROUPS_MAX]; 47707c478bd9Sstevel@tonic-gate #endif /* NGROUPS_MAX */ 47717c478bd9Sstevel@tonic-gate 47727c478bd9Sstevel@tonic-gate if (stat(qd, &st) < 0) 47737c478bd9Sstevel@tonic-gate { 47747c478bd9Sstevel@tonic-gate syserr("Cannot stat %s", 47757c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 47767c478bd9Sstevel@tonic-gate return 0; 47777c478bd9Sstevel@tonic-gate } 47787c478bd9Sstevel@tonic-gate #ifdef NGROUPS_MAX 47797c478bd9Sstevel@tonic-gate n = NGROUPS_MAX; 47807c478bd9Sstevel@tonic-gate while (--n >= 0) 47817c478bd9Sstevel@tonic-gate { 47827c478bd9Sstevel@tonic-gate if (InitialGidSet[n] == st.st_gid) 47837c478bd9Sstevel@tonic-gate break; 47847c478bd9Sstevel@tonic-gate } 47857c478bd9Sstevel@tonic-gate if (n < 0 && RealGid != st.st_gid) 47867c478bd9Sstevel@tonic-gate #else /* NGROUPS_MAX */ 47877c478bd9Sstevel@tonic-gate if (RealGid != st.st_gid) 47887c478bd9Sstevel@tonic-gate #endif /* NGROUPS_MAX */ 47897c478bd9Sstevel@tonic-gate { 47907c478bd9Sstevel@tonic-gate usrerr("510 You are not permitted to see the queue"); 47917c478bd9Sstevel@tonic-gate setstat(EX_NOPERM); 47927c478bd9Sstevel@tonic-gate return 0; 47937c478bd9Sstevel@tonic-gate } 47947c478bd9Sstevel@tonic-gate } 47957c478bd9Sstevel@tonic-gate 47967c478bd9Sstevel@tonic-gate /* 47977c478bd9Sstevel@tonic-gate ** Read and order the queue. 47987c478bd9Sstevel@tonic-gate */ 47997c478bd9Sstevel@tonic-gate 48007c478bd9Sstevel@tonic-gate nrequests = gatherq(qgrp, qdir, true, NULL, NULL); 48017c478bd9Sstevel@tonic-gate (void) sortq(Queue[qgrp]->qg_maxlist); 48027c478bd9Sstevel@tonic-gate 48037c478bd9Sstevel@tonic-gate /* 48047c478bd9Sstevel@tonic-gate ** Print the work list that we have read. 48057c478bd9Sstevel@tonic-gate */ 48067c478bd9Sstevel@tonic-gate 48077c478bd9Sstevel@tonic-gate /* first see if there is anything */ 48087c478bd9Sstevel@tonic-gate if (nrequests <= 0) 48097c478bd9Sstevel@tonic-gate { 48107c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s is empty\n", 48117c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 48127c478bd9Sstevel@tonic-gate return 0; 48137c478bd9Sstevel@tonic-gate } 48147c478bd9Sstevel@tonic-gate 48157c478bd9Sstevel@tonic-gate sm_getla(); /* get load average */ 48167c478bd9Sstevel@tonic-gate 48177c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\t\t%s (%d request%s", 48187c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), 48197c478bd9Sstevel@tonic-gate nrequests, nrequests == 1 ? "" : "s"); 48207c478bd9Sstevel@tonic-gate if (MaxQueueRun > 0 && nrequests > MaxQueueRun) 48217c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48227c478bd9Sstevel@tonic-gate ", only %d printed", MaxQueueRun); 48237c478bd9Sstevel@tonic-gate if (Verbose) 48247c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48257c478bd9Sstevel@tonic-gate ")\n-----Q-ID----- --Size-- -Priority- ---Q-Time--- --------Sender/Recipient--------\n"); 48267c478bd9Sstevel@tonic-gate else 48277c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48287c478bd9Sstevel@tonic-gate ")\n-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------\n"); 48297c478bd9Sstevel@tonic-gate for (w = WorkQ; w != NULL; w = w->w_next) 48307c478bd9Sstevel@tonic-gate { 48317c478bd9Sstevel@tonic-gate struct stat st; 48327c478bd9Sstevel@tonic-gate auto time_t submittime = 0; 48337c478bd9Sstevel@tonic-gate long dfsize; 48347c478bd9Sstevel@tonic-gate int flags = 0; 48357c478bd9Sstevel@tonic-gate int qfver; 48367c478bd9Sstevel@tonic-gate char quarmsg[MAXLINE]; 48377c478bd9Sstevel@tonic-gate char statmsg[MAXLINE]; 48387c478bd9Sstevel@tonic-gate char bodytype[MAXNAME + 1]; 48397c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN]; 48407c478bd9Sstevel@tonic-gate 48417c478bd9Sstevel@tonic-gate if (StopRequest) 48427c478bd9Sstevel@tonic-gate stop_sendmail(); 48437c478bd9Sstevel@tonic-gate 48447c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%13s", 48457c478bd9Sstevel@tonic-gate w->w_name + 2); 48467c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(qf, sizeof qf, 3, qd, "/", w->w_name); 48477c478bd9Sstevel@tonic-gate f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY_B, 48487c478bd9Sstevel@tonic-gate NULL); 48497c478bd9Sstevel@tonic-gate if (f == NULL) 48507c478bd9Sstevel@tonic-gate { 48517c478bd9Sstevel@tonic-gate if (errno == EPERM) 48527c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48537c478bd9Sstevel@tonic-gate " (permission denied)\n"); 48547c478bd9Sstevel@tonic-gate else if (errno == ENOENT) 48557c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48567c478bd9Sstevel@tonic-gate " (job completed)\n"); 48577c478bd9Sstevel@tonic-gate else 48587c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48597c478bd9Sstevel@tonic-gate " (%s)\n", 48607c478bd9Sstevel@tonic-gate sm_errstring(errno)); 48617c478bd9Sstevel@tonic-gate errno = 0; 48627c478bd9Sstevel@tonic-gate continue; 48637c478bd9Sstevel@tonic-gate } 48647c478bd9Sstevel@tonic-gate w->w_name[0] = DATAFL_LETTER; 48657c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(qf, sizeof qf, 3, qddf, "/", w->w_name); 48667c478bd9Sstevel@tonic-gate if (stat(qf, &st) >= 0) 48677c478bd9Sstevel@tonic-gate dfsize = st.st_size; 48687c478bd9Sstevel@tonic-gate else 48697c478bd9Sstevel@tonic-gate { 48707c478bd9Sstevel@tonic-gate ENVELOPE e; 48717c478bd9Sstevel@tonic-gate 48727c478bd9Sstevel@tonic-gate /* 48737c478bd9Sstevel@tonic-gate ** Maybe the df file can't be statted because 48747c478bd9Sstevel@tonic-gate ** it is in a different directory than the qf file. 48757c478bd9Sstevel@tonic-gate ** In order to find out, we must read the qf file. 48767c478bd9Sstevel@tonic-gate */ 48777c478bd9Sstevel@tonic-gate 48787c478bd9Sstevel@tonic-gate newenvelope(&e, &BlankEnvelope, sm_rpool_new_x(NULL)); 48797c478bd9Sstevel@tonic-gate e.e_id = w->w_name + 2; 48807c478bd9Sstevel@tonic-gate e.e_qgrp = qgrp; 48817c478bd9Sstevel@tonic-gate e.e_qdir = qdir; 48827c478bd9Sstevel@tonic-gate dfsize = -1; 48837c478bd9Sstevel@tonic-gate if (readqf(&e, false)) 48847c478bd9Sstevel@tonic-gate { 48857c478bd9Sstevel@tonic-gate char *df = queuename(&e, DATAFL_LETTER); 48867c478bd9Sstevel@tonic-gate if (stat(df, &st) >= 0) 48877c478bd9Sstevel@tonic-gate dfsize = st.st_size; 48887c478bd9Sstevel@tonic-gate } 48897c478bd9Sstevel@tonic-gate if (e.e_lockfp != NULL) 48907c478bd9Sstevel@tonic-gate { 48917c478bd9Sstevel@tonic-gate (void) sm_io_close(e.e_lockfp, SM_TIME_DEFAULT); 48927c478bd9Sstevel@tonic-gate e.e_lockfp = NULL; 48937c478bd9Sstevel@tonic-gate } 48947c478bd9Sstevel@tonic-gate clearenvelope(&e, false, e.e_rpool); 48957c478bd9Sstevel@tonic-gate sm_rpool_free(e.e_rpool); 48967c478bd9Sstevel@tonic-gate } 48977c478bd9Sstevel@tonic-gate if (w->w_lock) 48987c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "*"); 48997c478bd9Sstevel@tonic-gate else if (QueueMode == QM_LOST) 49007c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "?"); 49017c478bd9Sstevel@tonic-gate else if (w->w_tooyoung) 49027c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "-"); 49037c478bd9Sstevel@tonic-gate else if (shouldqueue(w->w_pri, w->w_ctime)) 49047c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "X"); 49057c478bd9Sstevel@tonic-gate else 49067c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " "); 49077c478bd9Sstevel@tonic-gate 49087c478bd9Sstevel@tonic-gate errno = 0; 49097c478bd9Sstevel@tonic-gate 49107c478bd9Sstevel@tonic-gate quarmsg[0] = '\0'; 49117c478bd9Sstevel@tonic-gate statmsg[0] = bodytype[0] = '\0'; 49127c478bd9Sstevel@tonic-gate qfver = 0; 49137c478bd9Sstevel@tonic-gate while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf) != NULL) 49147c478bd9Sstevel@tonic-gate { 49157c478bd9Sstevel@tonic-gate register int i; 49167c478bd9Sstevel@tonic-gate register char *p; 49177c478bd9Sstevel@tonic-gate 49187c478bd9Sstevel@tonic-gate if (StopRequest) 49197c478bd9Sstevel@tonic-gate stop_sendmail(); 49207c478bd9Sstevel@tonic-gate 49217c478bd9Sstevel@tonic-gate fixcrlf(buf, true); 49227c478bd9Sstevel@tonic-gate switch (buf[0]) 49237c478bd9Sstevel@tonic-gate { 49247c478bd9Sstevel@tonic-gate case 'V': /* queue file version */ 49257c478bd9Sstevel@tonic-gate qfver = atoi(&buf[1]); 49267c478bd9Sstevel@tonic-gate break; 49277c478bd9Sstevel@tonic-gate 49287c478bd9Sstevel@tonic-gate case 'M': /* error message */ 49297c478bd9Sstevel@tonic-gate if ((i = strlen(&buf[1])) >= sizeof statmsg) 49307c478bd9Sstevel@tonic-gate i = sizeof statmsg - 1; 49317c478bd9Sstevel@tonic-gate memmove(statmsg, &buf[1], i); 49327c478bd9Sstevel@tonic-gate statmsg[i] = '\0'; 49337c478bd9Sstevel@tonic-gate break; 49347c478bd9Sstevel@tonic-gate 49357c478bd9Sstevel@tonic-gate case 'q': /* quarantine reason */ 49367c478bd9Sstevel@tonic-gate if ((i = strlen(&buf[1])) >= sizeof quarmsg) 49377c478bd9Sstevel@tonic-gate i = sizeof quarmsg - 1; 49387c478bd9Sstevel@tonic-gate memmove(quarmsg, &buf[1], i); 49397c478bd9Sstevel@tonic-gate quarmsg[i] = '\0'; 49407c478bd9Sstevel@tonic-gate break; 49417c478bd9Sstevel@tonic-gate 49427c478bd9Sstevel@tonic-gate case 'B': /* body type */ 49437c478bd9Sstevel@tonic-gate if ((i = strlen(&buf[1])) >= sizeof bodytype) 49447c478bd9Sstevel@tonic-gate i = sizeof bodytype - 1; 49457c478bd9Sstevel@tonic-gate memmove(bodytype, &buf[1], i); 49467c478bd9Sstevel@tonic-gate bodytype[i] = '\0'; 49477c478bd9Sstevel@tonic-gate break; 49487c478bd9Sstevel@tonic-gate 49497c478bd9Sstevel@tonic-gate case 'S': /* sender name */ 49507c478bd9Sstevel@tonic-gate if (Verbose) 49517c478bd9Sstevel@tonic-gate { 49527c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 49537c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49547c478bd9Sstevel@tonic-gate "%8ld %10ld%c%.12s ", 49557c478bd9Sstevel@tonic-gate dfsize, 49567c478bd9Sstevel@tonic-gate w->w_pri, 49577c478bd9Sstevel@tonic-gate bitset(EF_WARNING, flags) 49587c478bd9Sstevel@tonic-gate ? '+' : ' ', 49597c478bd9Sstevel@tonic-gate ctime(&submittime) + 4); 49607c478bd9Sstevel@tonic-gate prtstr(&buf[1], 78); 49617c478bd9Sstevel@tonic-gate } 49627c478bd9Sstevel@tonic-gate else 49637c478bd9Sstevel@tonic-gate { 49647c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 49657c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49667c478bd9Sstevel@tonic-gate "%8ld %.16s ", 49677c478bd9Sstevel@tonic-gate dfsize, 49687c478bd9Sstevel@tonic-gate ctime(&submittime)); 49697c478bd9Sstevel@tonic-gate prtstr(&buf[1], 39); 49707c478bd9Sstevel@tonic-gate } 49717c478bd9Sstevel@tonic-gate 49727c478bd9Sstevel@tonic-gate if (quarmsg[0] != '\0') 49737c478bd9Sstevel@tonic-gate { 49747c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 49757c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49767c478bd9Sstevel@tonic-gate "\n QUARANTINE: %.*s", 49777c478bd9Sstevel@tonic-gate Verbose ? 100 : 60, 49787c478bd9Sstevel@tonic-gate quarmsg); 49797c478bd9Sstevel@tonic-gate quarmsg[0] = '\0'; 49807c478bd9Sstevel@tonic-gate } 49817c478bd9Sstevel@tonic-gate 49827c478bd9Sstevel@tonic-gate if (statmsg[0] != '\0' || bodytype[0] != '\0') 49837c478bd9Sstevel@tonic-gate { 49847c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 49857c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49867c478bd9Sstevel@tonic-gate "\n %10.10s", 49877c478bd9Sstevel@tonic-gate bodytype); 49887c478bd9Sstevel@tonic-gate if (statmsg[0] != '\0') 49897c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 49907c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49917c478bd9Sstevel@tonic-gate " (%.*s)", 49927c478bd9Sstevel@tonic-gate Verbose ? 100 : 60, 49937c478bd9Sstevel@tonic-gate statmsg); 49947c478bd9Sstevel@tonic-gate statmsg[0] = '\0'; 49957c478bd9Sstevel@tonic-gate } 49967c478bd9Sstevel@tonic-gate break; 49977c478bd9Sstevel@tonic-gate 49987c478bd9Sstevel@tonic-gate case 'C': /* controlling user */ 49997c478bd9Sstevel@tonic-gate if (Verbose) 50007c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50017c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50027c478bd9Sstevel@tonic-gate "\n\t\t\t\t\t\t(---%.64s---)", 50037c478bd9Sstevel@tonic-gate &buf[1]); 50047c478bd9Sstevel@tonic-gate break; 50057c478bd9Sstevel@tonic-gate 50067c478bd9Sstevel@tonic-gate case 'R': /* recipient name */ 50077c478bd9Sstevel@tonic-gate p = &buf[1]; 50087c478bd9Sstevel@tonic-gate if (qfver >= 1) 50097c478bd9Sstevel@tonic-gate { 50107c478bd9Sstevel@tonic-gate p = strchr(p, ':'); 50117c478bd9Sstevel@tonic-gate if (p == NULL) 50127c478bd9Sstevel@tonic-gate break; 50137c478bd9Sstevel@tonic-gate p++; 50147c478bd9Sstevel@tonic-gate } 50157c478bd9Sstevel@tonic-gate if (Verbose) 50167c478bd9Sstevel@tonic-gate { 50177c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50187c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50197c478bd9Sstevel@tonic-gate "\n\t\t\t\t\t\t"); 50207c478bd9Sstevel@tonic-gate prtstr(p, 71); 50217c478bd9Sstevel@tonic-gate } 50227c478bd9Sstevel@tonic-gate else 50237c478bd9Sstevel@tonic-gate { 50247c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50257c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50267c478bd9Sstevel@tonic-gate "\n\t\t\t\t\t "); 50277c478bd9Sstevel@tonic-gate prtstr(p, 38); 50287c478bd9Sstevel@tonic-gate } 50297c478bd9Sstevel@tonic-gate if (Verbose && statmsg[0] != '\0') 50307c478bd9Sstevel@tonic-gate { 50317c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50327c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50337c478bd9Sstevel@tonic-gate "\n\t\t (%.100s)", 50347c478bd9Sstevel@tonic-gate statmsg); 50357c478bd9Sstevel@tonic-gate statmsg[0] = '\0'; 50367c478bd9Sstevel@tonic-gate } 50377c478bd9Sstevel@tonic-gate break; 50387c478bd9Sstevel@tonic-gate 50397c478bd9Sstevel@tonic-gate case 'T': /* creation time */ 50407c478bd9Sstevel@tonic-gate submittime = atol(&buf[1]); 50417c478bd9Sstevel@tonic-gate break; 50427c478bd9Sstevel@tonic-gate 50437c478bd9Sstevel@tonic-gate case 'F': /* flag bits */ 50447c478bd9Sstevel@tonic-gate for (p = &buf[1]; *p != '\0'; p++) 50457c478bd9Sstevel@tonic-gate { 50467c478bd9Sstevel@tonic-gate switch (*p) 50477c478bd9Sstevel@tonic-gate { 50487c478bd9Sstevel@tonic-gate case 'w': 50497c478bd9Sstevel@tonic-gate flags |= EF_WARNING; 50507c478bd9Sstevel@tonic-gate break; 50517c478bd9Sstevel@tonic-gate } 50527c478bd9Sstevel@tonic-gate } 50537c478bd9Sstevel@tonic-gate } 50547c478bd9Sstevel@tonic-gate } 50557c478bd9Sstevel@tonic-gate if (submittime == (time_t) 0) 50567c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 50577c478bd9Sstevel@tonic-gate " (no control file)"); 50587c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); 50597c478bd9Sstevel@tonic-gate (void) sm_io_close(f, SM_TIME_DEFAULT); 50607c478bd9Sstevel@tonic-gate } 50617c478bd9Sstevel@tonic-gate return nrequests; 50627c478bd9Sstevel@tonic-gate } 50637c478bd9Sstevel@tonic-gate 50647c478bd9Sstevel@tonic-gate /* 50657c478bd9Sstevel@tonic-gate ** QUEUE_LETTER -- get the proper queue letter for the current QueueMode. 50667c478bd9Sstevel@tonic-gate ** 50677c478bd9Sstevel@tonic-gate ** Parameters: 50687c478bd9Sstevel@tonic-gate ** e -- envelope to build it in/from. 50697c478bd9Sstevel@tonic-gate ** type -- the file type, used as the first character 50707c478bd9Sstevel@tonic-gate ** of the file name. 50717c478bd9Sstevel@tonic-gate ** 50727c478bd9Sstevel@tonic-gate ** Returns: 50737c478bd9Sstevel@tonic-gate ** the letter to use 50747c478bd9Sstevel@tonic-gate */ 50757c478bd9Sstevel@tonic-gate 50767c478bd9Sstevel@tonic-gate static char 50777c478bd9Sstevel@tonic-gate queue_letter(e, type) 50787c478bd9Sstevel@tonic-gate ENVELOPE *e; 50797c478bd9Sstevel@tonic-gate int type; 50807c478bd9Sstevel@tonic-gate { 50817c478bd9Sstevel@tonic-gate /* Change type according to QueueMode */ 50827c478bd9Sstevel@tonic-gate if (type == ANYQFL_LETTER) 50837c478bd9Sstevel@tonic-gate { 50847c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 50857c478bd9Sstevel@tonic-gate type = QUARQF_LETTER; 50867c478bd9Sstevel@tonic-gate else 50877c478bd9Sstevel@tonic-gate { 50887c478bd9Sstevel@tonic-gate switch (QueueMode) 50897c478bd9Sstevel@tonic-gate { 50907c478bd9Sstevel@tonic-gate case QM_NORMAL: 50917c478bd9Sstevel@tonic-gate type = NORMQF_LETTER; 50927c478bd9Sstevel@tonic-gate break; 50937c478bd9Sstevel@tonic-gate 50947c478bd9Sstevel@tonic-gate case QM_QUARANTINE: 50957c478bd9Sstevel@tonic-gate type = QUARQF_LETTER; 50967c478bd9Sstevel@tonic-gate break; 50977c478bd9Sstevel@tonic-gate 50987c478bd9Sstevel@tonic-gate case QM_LOST: 50997c478bd9Sstevel@tonic-gate type = LOSEQF_LETTER; 51007c478bd9Sstevel@tonic-gate break; 51017c478bd9Sstevel@tonic-gate 51027c478bd9Sstevel@tonic-gate default: 51037c478bd9Sstevel@tonic-gate /* should never happen */ 51047c478bd9Sstevel@tonic-gate abort(); 51057c478bd9Sstevel@tonic-gate /* NOTREACHED */ 51067c478bd9Sstevel@tonic-gate } 51077c478bd9Sstevel@tonic-gate } 51087c478bd9Sstevel@tonic-gate } 51097c478bd9Sstevel@tonic-gate return type; 51107c478bd9Sstevel@tonic-gate } 51117c478bd9Sstevel@tonic-gate 51127c478bd9Sstevel@tonic-gate /* 51137c478bd9Sstevel@tonic-gate ** QUEUENAME -- build a file name in the queue directory for this envelope. 51147c478bd9Sstevel@tonic-gate ** 51157c478bd9Sstevel@tonic-gate ** Parameters: 51167c478bd9Sstevel@tonic-gate ** e -- envelope to build it in/from. 51177c478bd9Sstevel@tonic-gate ** type -- the file type, used as the first character 51187c478bd9Sstevel@tonic-gate ** of the file name. 51197c478bd9Sstevel@tonic-gate ** 51207c478bd9Sstevel@tonic-gate ** Returns: 51217c478bd9Sstevel@tonic-gate ** a pointer to the queue name (in a static buffer). 51227c478bd9Sstevel@tonic-gate ** 51237c478bd9Sstevel@tonic-gate ** Side Effects: 51247c478bd9Sstevel@tonic-gate ** If no id code is already assigned, queuename() will 51257c478bd9Sstevel@tonic-gate ** assign an id code with assign_queueid(). If no queue 51267c478bd9Sstevel@tonic-gate ** directory is assigned, one will be set with setnewqueue(). 51277c478bd9Sstevel@tonic-gate */ 51287c478bd9Sstevel@tonic-gate 51297c478bd9Sstevel@tonic-gate char * 51307c478bd9Sstevel@tonic-gate queuename(e, type) 51317c478bd9Sstevel@tonic-gate register ENVELOPE *e; 51327c478bd9Sstevel@tonic-gate int type; 51337c478bd9Sstevel@tonic-gate { 51347c478bd9Sstevel@tonic-gate int qd, qg; 51357c478bd9Sstevel@tonic-gate char *sub = "/"; 51367c478bd9Sstevel@tonic-gate char pref[3]; 51377c478bd9Sstevel@tonic-gate static char buf[MAXPATHLEN]; 51387c478bd9Sstevel@tonic-gate 51397c478bd9Sstevel@tonic-gate /* Assign an ID if needed */ 51407c478bd9Sstevel@tonic-gate if (e->e_id == NULL) 51417c478bd9Sstevel@tonic-gate assign_queueid(e); 51427c478bd9Sstevel@tonic-gate type = queue_letter(e, type); 51437c478bd9Sstevel@tonic-gate 51447c478bd9Sstevel@tonic-gate /* begin of filename */ 51457c478bd9Sstevel@tonic-gate pref[0] = (char) type; 51467c478bd9Sstevel@tonic-gate pref[1] = 'f'; 51477c478bd9Sstevel@tonic-gate pref[2] = '\0'; 51487c478bd9Sstevel@tonic-gate 51497c478bd9Sstevel@tonic-gate /* Assign a queue group/directory if needed */ 51507c478bd9Sstevel@tonic-gate if (type == XSCRPT_LETTER) 51517c478bd9Sstevel@tonic-gate { 51527c478bd9Sstevel@tonic-gate /* 51537c478bd9Sstevel@tonic-gate ** We don't want to call setnewqueue() if we are fetching 51547c478bd9Sstevel@tonic-gate ** the pathname of the transcript file, because setnewqueue 51557c478bd9Sstevel@tonic-gate ** chooses a queue, and sometimes we need to write to the 51567c478bd9Sstevel@tonic-gate ** transcript file before we have gathered enough information 51577c478bd9Sstevel@tonic-gate ** to choose a queue. 51587c478bd9Sstevel@tonic-gate */ 51597c478bd9Sstevel@tonic-gate 51607c478bd9Sstevel@tonic-gate if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR) 51617c478bd9Sstevel@tonic-gate { 51627c478bd9Sstevel@tonic-gate if (e->e_qgrp != NOQGRP && e->e_qdir != NOQDIR) 51637c478bd9Sstevel@tonic-gate { 51647c478bd9Sstevel@tonic-gate e->e_xfqgrp = e->e_qgrp; 51657c478bd9Sstevel@tonic-gate e->e_xfqdir = e->e_qdir; 51667c478bd9Sstevel@tonic-gate } 51677c478bd9Sstevel@tonic-gate else 51687c478bd9Sstevel@tonic-gate { 51697c478bd9Sstevel@tonic-gate e->e_xfqgrp = 0; 51707c478bd9Sstevel@tonic-gate if (Queue[e->e_xfqgrp]->qg_numqueues <= 1) 51717c478bd9Sstevel@tonic-gate e->e_xfqdir = 0; 51727c478bd9Sstevel@tonic-gate else 51737c478bd9Sstevel@tonic-gate { 51747c478bd9Sstevel@tonic-gate e->e_xfqdir = get_rand_mod( 51757c478bd9Sstevel@tonic-gate Queue[e->e_xfqgrp]->qg_numqueues); 51767c478bd9Sstevel@tonic-gate } 51777c478bd9Sstevel@tonic-gate } 51787c478bd9Sstevel@tonic-gate } 51797c478bd9Sstevel@tonic-gate qd = e->e_xfqdir; 51807c478bd9Sstevel@tonic-gate qg = e->e_xfqgrp; 51817c478bd9Sstevel@tonic-gate } 51827c478bd9Sstevel@tonic-gate else 51837c478bd9Sstevel@tonic-gate { 51847c478bd9Sstevel@tonic-gate if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR) 51857c478bd9Sstevel@tonic-gate setnewqueue(e); 51867c478bd9Sstevel@tonic-gate if (type == DATAFL_LETTER) 51877c478bd9Sstevel@tonic-gate { 51887c478bd9Sstevel@tonic-gate qd = e->e_dfqdir; 51897c478bd9Sstevel@tonic-gate qg = e->e_dfqgrp; 51907c478bd9Sstevel@tonic-gate } 51917c478bd9Sstevel@tonic-gate else 51927c478bd9Sstevel@tonic-gate { 51937c478bd9Sstevel@tonic-gate qd = e->e_qdir; 51947c478bd9Sstevel@tonic-gate qg = e->e_qgrp; 51957c478bd9Sstevel@tonic-gate } 51967c478bd9Sstevel@tonic-gate } 51977c478bd9Sstevel@tonic-gate 51987c478bd9Sstevel@tonic-gate /* xf files always have a valid qd and qg picked above */ 51997c478bd9Sstevel@tonic-gate if (e->e_qdir == NOQDIR && type != XSCRPT_LETTER) 52007c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(buf, sizeof buf, 2, pref, e->e_id); 52017c478bd9Sstevel@tonic-gate else 52027c478bd9Sstevel@tonic-gate { 52037c478bd9Sstevel@tonic-gate switch (type) 52047c478bd9Sstevel@tonic-gate { 52057c478bd9Sstevel@tonic-gate case DATAFL_LETTER: 52067c478bd9Sstevel@tonic-gate if (bitset(QP_SUBDF, Queue[qg]->qg_qpaths[qd].qp_subdirs)) 52077c478bd9Sstevel@tonic-gate sub = "/df/"; 52087c478bd9Sstevel@tonic-gate break; 52097c478bd9Sstevel@tonic-gate 52107c478bd9Sstevel@tonic-gate case QUARQF_LETTER: 52117c478bd9Sstevel@tonic-gate case TEMPQF_LETTER: 52127c478bd9Sstevel@tonic-gate case NEWQFL_LETTER: 52137c478bd9Sstevel@tonic-gate case LOSEQF_LETTER: 52147c478bd9Sstevel@tonic-gate case NORMQF_LETTER: 52157c478bd9Sstevel@tonic-gate if (bitset(QP_SUBQF, Queue[qg]->qg_qpaths[qd].qp_subdirs)) 52167c478bd9Sstevel@tonic-gate sub = "/qf/"; 52177c478bd9Sstevel@tonic-gate break; 52187c478bd9Sstevel@tonic-gate 52197c478bd9Sstevel@tonic-gate case XSCRPT_LETTER: 52207c478bd9Sstevel@tonic-gate if (bitset(QP_SUBXF, Queue[qg]->qg_qpaths[qd].qp_subdirs)) 52217c478bd9Sstevel@tonic-gate sub = "/xf/"; 52227c478bd9Sstevel@tonic-gate break; 52237c478bd9Sstevel@tonic-gate 52247c478bd9Sstevel@tonic-gate default: 52257c478bd9Sstevel@tonic-gate sm_abort("queuename: bad queue file type %d", type); 52267c478bd9Sstevel@tonic-gate } 52277c478bd9Sstevel@tonic-gate 52287c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(buf, sizeof buf, 4, 52297c478bd9Sstevel@tonic-gate Queue[qg]->qg_qpaths[qd].qp_name, 52307c478bd9Sstevel@tonic-gate sub, pref, e->e_id); 52317c478bd9Sstevel@tonic-gate } 52327c478bd9Sstevel@tonic-gate 52337c478bd9Sstevel@tonic-gate if (tTd(7, 2)) 52347c478bd9Sstevel@tonic-gate sm_dprintf("queuename: %s\n", buf); 52357c478bd9Sstevel@tonic-gate return buf; 52367c478bd9Sstevel@tonic-gate } 52377c478bd9Sstevel@tonic-gate 52387c478bd9Sstevel@tonic-gate /* 52397c478bd9Sstevel@tonic-gate ** INIT_QID_ALG -- Initialize the (static) parameters that are used to 52407c478bd9Sstevel@tonic-gate ** generate a queue ID. 52417c478bd9Sstevel@tonic-gate ** 52427c478bd9Sstevel@tonic-gate ** This function is called by the daemon to reset 52437c478bd9Sstevel@tonic-gate ** LastQueueTime and LastQueuePid which are used by assign_queueid(). 52447c478bd9Sstevel@tonic-gate ** Otherwise the algorithm may cause problems because 52457c478bd9Sstevel@tonic-gate ** LastQueueTime and LastQueuePid are set indirectly by main() 52467c478bd9Sstevel@tonic-gate ** before the daemon process is started, hence LastQueuePid is not 52477c478bd9Sstevel@tonic-gate ** the pid of the daemon and therefore a child of the daemon can 52487c478bd9Sstevel@tonic-gate ** actually have the same pid as LastQueuePid which means the section 52497c478bd9Sstevel@tonic-gate ** in assign_queueid(): 52507c478bd9Sstevel@tonic-gate ** * see if we need to get a new base time/pid * 52517c478bd9Sstevel@tonic-gate ** is NOT triggered which will cause the same queue id to be generated. 52527c478bd9Sstevel@tonic-gate ** 52537c478bd9Sstevel@tonic-gate ** Parameters: 52547c478bd9Sstevel@tonic-gate ** none 52557c478bd9Sstevel@tonic-gate ** 52567c478bd9Sstevel@tonic-gate ** Returns: 52577c478bd9Sstevel@tonic-gate ** none. 52587c478bd9Sstevel@tonic-gate */ 52597c478bd9Sstevel@tonic-gate 52607c478bd9Sstevel@tonic-gate void 52617c478bd9Sstevel@tonic-gate init_qid_alg() 52627c478bd9Sstevel@tonic-gate { 52637c478bd9Sstevel@tonic-gate LastQueueTime = 0; 52647c478bd9Sstevel@tonic-gate LastQueuePid = -1; 52657c478bd9Sstevel@tonic-gate } 52667c478bd9Sstevel@tonic-gate 52677c478bd9Sstevel@tonic-gate /* 52687c478bd9Sstevel@tonic-gate ** ASSIGN_QUEUEID -- assign a queue ID for this envelope. 52697c478bd9Sstevel@tonic-gate ** 52707c478bd9Sstevel@tonic-gate ** Assigns an id code if one does not already exist. 52717c478bd9Sstevel@tonic-gate ** This code assumes that nothing will remain in the queue for 52727c478bd9Sstevel@tonic-gate ** longer than 60 years. It is critical that files with the given 52737c478bd9Sstevel@tonic-gate ** name do not already exist in the queue. 52747c478bd9Sstevel@tonic-gate ** [No longer initializes e_qdir to NOQDIR.] 52757c478bd9Sstevel@tonic-gate ** 52767c478bd9Sstevel@tonic-gate ** Parameters: 52777c478bd9Sstevel@tonic-gate ** e -- envelope to set it in. 52787c478bd9Sstevel@tonic-gate ** 52797c478bd9Sstevel@tonic-gate ** Returns: 52807c478bd9Sstevel@tonic-gate ** none. 52817c478bd9Sstevel@tonic-gate */ 52827c478bd9Sstevel@tonic-gate 52837c478bd9Sstevel@tonic-gate static const char QueueIdChars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 52847c478bd9Sstevel@tonic-gate # define QIC_LEN 60 52857c478bd9Sstevel@tonic-gate # define QIC_LEN_R 62 52867c478bd9Sstevel@tonic-gate 52877c478bd9Sstevel@tonic-gate /* 52887c478bd9Sstevel@tonic-gate ** Note: the length is "officially" 60 because minutes and seconds are 52897c478bd9Sstevel@tonic-gate ** usually only 0-59. However (Linux): 52907c478bd9Sstevel@tonic-gate ** tm_sec The number of seconds after the minute, normally in 52917c478bd9Sstevel@tonic-gate ** the range 0 to 59, but can be up to 61 to allow for 52927c478bd9Sstevel@tonic-gate ** leap seconds. 52937c478bd9Sstevel@tonic-gate ** Hence the real length of the string is 62 to take this into account. 52947c478bd9Sstevel@tonic-gate ** Alternatively % QIC_LEN can (should) be used for access everywhere. 52957c478bd9Sstevel@tonic-gate */ 52967c478bd9Sstevel@tonic-gate 52977c478bd9Sstevel@tonic-gate # define queuenextid() CurrentPid 52987c478bd9Sstevel@tonic-gate 52997c478bd9Sstevel@tonic-gate 53007c478bd9Sstevel@tonic-gate void 53017c478bd9Sstevel@tonic-gate assign_queueid(e) 53027c478bd9Sstevel@tonic-gate register ENVELOPE *e; 53037c478bd9Sstevel@tonic-gate { 53047c478bd9Sstevel@tonic-gate pid_t pid = queuenextid(); 53057c478bd9Sstevel@tonic-gate static int cX = 0; 53067c478bd9Sstevel@tonic-gate static long random_offset; 53077c478bd9Sstevel@tonic-gate struct tm *tm; 53087c478bd9Sstevel@tonic-gate char idbuf[MAXQFNAME - 2]; 53097c478bd9Sstevel@tonic-gate int seq; 53107c478bd9Sstevel@tonic-gate 53117c478bd9Sstevel@tonic-gate if (e->e_id != NULL) 53127c478bd9Sstevel@tonic-gate return; 53137c478bd9Sstevel@tonic-gate 53147c478bd9Sstevel@tonic-gate /* see if we need to get a new base time/pid */ 53157c478bd9Sstevel@tonic-gate if (cX >= QIC_LEN * QIC_LEN || LastQueueTime == 0 || 53167c478bd9Sstevel@tonic-gate LastQueuePid != pid) 53177c478bd9Sstevel@tonic-gate { 53187c478bd9Sstevel@tonic-gate time_t then = LastQueueTime; 53197c478bd9Sstevel@tonic-gate 53207c478bd9Sstevel@tonic-gate /* if the first time through, pick a random offset */ 53217c478bd9Sstevel@tonic-gate if (LastQueueTime == 0) 53227c478bd9Sstevel@tonic-gate random_offset = get_random(); 53237c478bd9Sstevel@tonic-gate 53247c478bd9Sstevel@tonic-gate while ((LastQueueTime = curtime()) == then && 53257c478bd9Sstevel@tonic-gate LastQueuePid == pid) 53267c478bd9Sstevel@tonic-gate { 53277c478bd9Sstevel@tonic-gate (void) sleep(1); 53287c478bd9Sstevel@tonic-gate } 53297c478bd9Sstevel@tonic-gate LastQueuePid = queuenextid(); 53307c478bd9Sstevel@tonic-gate cX = 0; 53317c478bd9Sstevel@tonic-gate } 53327c478bd9Sstevel@tonic-gate 53337c478bd9Sstevel@tonic-gate /* 53347c478bd9Sstevel@tonic-gate ** Generate a new sequence number between 0 and QIC_LEN*QIC_LEN-1. 53357c478bd9Sstevel@tonic-gate ** This lets us generate up to QIC_LEN*QIC_LEN unique queue ids 53367c478bd9Sstevel@tonic-gate ** per second, per process. With envelope splitting, 53377c478bd9Sstevel@tonic-gate ** a single message can consume many queue ids. 53387c478bd9Sstevel@tonic-gate */ 53397c478bd9Sstevel@tonic-gate 53407c478bd9Sstevel@tonic-gate seq = (int)((cX + random_offset) % (QIC_LEN * QIC_LEN)); 53417c478bd9Sstevel@tonic-gate ++cX; 53427c478bd9Sstevel@tonic-gate if (tTd(7, 50)) 53437c478bd9Sstevel@tonic-gate sm_dprintf("assign_queueid: random_offset = %ld (%d)\n", 53447c478bd9Sstevel@tonic-gate random_offset, seq); 53457c478bd9Sstevel@tonic-gate 53467c478bd9Sstevel@tonic-gate tm = gmtime(&LastQueueTime); 53477c478bd9Sstevel@tonic-gate idbuf[0] = QueueIdChars[tm->tm_year % QIC_LEN]; 53487c478bd9Sstevel@tonic-gate idbuf[1] = QueueIdChars[tm->tm_mon]; 53497c478bd9Sstevel@tonic-gate idbuf[2] = QueueIdChars[tm->tm_mday]; 53507c478bd9Sstevel@tonic-gate idbuf[3] = QueueIdChars[tm->tm_hour]; 53517c478bd9Sstevel@tonic-gate idbuf[4] = QueueIdChars[tm->tm_min % QIC_LEN_R]; 53527c478bd9Sstevel@tonic-gate idbuf[5] = QueueIdChars[tm->tm_sec % QIC_LEN_R]; 53537c478bd9Sstevel@tonic-gate idbuf[6] = QueueIdChars[seq / QIC_LEN]; 53547c478bd9Sstevel@tonic-gate idbuf[7] = QueueIdChars[seq % QIC_LEN]; 53557c478bd9Sstevel@tonic-gate (void) sm_snprintf(&idbuf[8], sizeof idbuf - 8, "%06d", 53567c478bd9Sstevel@tonic-gate (int) LastQueuePid); 53577c478bd9Sstevel@tonic-gate e->e_id = sm_rpool_strdup_x(e->e_rpool, idbuf); 53587c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'i', e->e_id); 53597c478bd9Sstevel@tonic-gate #if 0 53607c478bd9Sstevel@tonic-gate /* XXX: inherited from MainEnvelope */ 53617c478bd9Sstevel@tonic-gate e->e_qgrp = NOQGRP; /* too early to do anything else */ 53627c478bd9Sstevel@tonic-gate e->e_qdir = NOQDIR; 53637c478bd9Sstevel@tonic-gate e->e_xfqgrp = NOQGRP; 53647c478bd9Sstevel@tonic-gate #endif /* 0 */ 53657c478bd9Sstevel@tonic-gate 53667c478bd9Sstevel@tonic-gate /* New ID means it's not on disk yet */ 53677c478bd9Sstevel@tonic-gate e->e_qfletter = '\0'; 53687c478bd9Sstevel@tonic-gate 53697c478bd9Sstevel@tonic-gate if (tTd(7, 1)) 53707c478bd9Sstevel@tonic-gate sm_dprintf("assign_queueid: assigned id %s, e=%p\n", 53717c478bd9Sstevel@tonic-gate e->e_id, e); 53727c478bd9Sstevel@tonic-gate if (LogLevel > 93) 53737c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "assigned id"); 53747c478bd9Sstevel@tonic-gate } 53757c478bd9Sstevel@tonic-gate /* 53767c478bd9Sstevel@tonic-gate ** SYNC_QUEUE_TIME -- Assure exclusive PID in any given second 53777c478bd9Sstevel@tonic-gate ** 53787c478bd9Sstevel@tonic-gate ** Make sure one PID can't be used by two processes in any one second. 53797c478bd9Sstevel@tonic-gate ** 53807c478bd9Sstevel@tonic-gate ** If the system rotates PIDs fast enough, may get the 53817c478bd9Sstevel@tonic-gate ** same pid in the same second for two distinct processes. 53827c478bd9Sstevel@tonic-gate ** This will interfere with the queue file naming system. 53837c478bd9Sstevel@tonic-gate ** 53847c478bd9Sstevel@tonic-gate ** Parameters: 53857c478bd9Sstevel@tonic-gate ** none 53867c478bd9Sstevel@tonic-gate ** 53877c478bd9Sstevel@tonic-gate ** Returns: 53887c478bd9Sstevel@tonic-gate ** none 53897c478bd9Sstevel@tonic-gate */ 53907c478bd9Sstevel@tonic-gate 53917c478bd9Sstevel@tonic-gate void 53927c478bd9Sstevel@tonic-gate sync_queue_time() 53937c478bd9Sstevel@tonic-gate { 53947c478bd9Sstevel@tonic-gate #if FAST_PID_RECYCLE 53957c478bd9Sstevel@tonic-gate if (OpMode != MD_TEST && 53967c478bd9Sstevel@tonic-gate OpMode != MD_VERIFY && 53977c478bd9Sstevel@tonic-gate LastQueueTime > 0 && 53987c478bd9Sstevel@tonic-gate LastQueuePid == CurrentPid && 53997c478bd9Sstevel@tonic-gate curtime() == LastQueueTime) 54007c478bd9Sstevel@tonic-gate (void) sleep(1); 54017c478bd9Sstevel@tonic-gate #endif /* FAST_PID_RECYCLE */ 54027c478bd9Sstevel@tonic-gate } 54037c478bd9Sstevel@tonic-gate /* 54047c478bd9Sstevel@tonic-gate ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 54057c478bd9Sstevel@tonic-gate ** 54067c478bd9Sstevel@tonic-gate ** Parameters: 54077c478bd9Sstevel@tonic-gate ** e -- the envelope to unlock. 54087c478bd9Sstevel@tonic-gate ** 54097c478bd9Sstevel@tonic-gate ** Returns: 54107c478bd9Sstevel@tonic-gate ** none 54117c478bd9Sstevel@tonic-gate ** 54127c478bd9Sstevel@tonic-gate ** Side Effects: 54137c478bd9Sstevel@tonic-gate ** unlocks the queue for `e'. 54147c478bd9Sstevel@tonic-gate */ 54157c478bd9Sstevel@tonic-gate 54167c478bd9Sstevel@tonic-gate void 54177c478bd9Sstevel@tonic-gate unlockqueue(e) 54187c478bd9Sstevel@tonic-gate ENVELOPE *e; 54197c478bd9Sstevel@tonic-gate { 54207c478bd9Sstevel@tonic-gate if (tTd(51, 4)) 54217c478bd9Sstevel@tonic-gate sm_dprintf("unlockqueue(%s)\n", 54227c478bd9Sstevel@tonic-gate e->e_id == NULL ? "NOQUEUE" : e->e_id); 54237c478bd9Sstevel@tonic-gate 54247c478bd9Sstevel@tonic-gate 54257c478bd9Sstevel@tonic-gate /* if there is a lock file in the envelope, close it */ 54267c478bd9Sstevel@tonic-gate if (e->e_lockfp != NULL) 54277c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT); 54287c478bd9Sstevel@tonic-gate e->e_lockfp = NULL; 54297c478bd9Sstevel@tonic-gate 54307c478bd9Sstevel@tonic-gate /* don't create a queue id if we don't already have one */ 54317c478bd9Sstevel@tonic-gate if (e->e_id == NULL) 54327c478bd9Sstevel@tonic-gate return; 54337c478bd9Sstevel@tonic-gate 54347c478bd9Sstevel@tonic-gate /* remove the transcript */ 54357c478bd9Sstevel@tonic-gate if (LogLevel > 87) 54367c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "unlock"); 54377c478bd9Sstevel@tonic-gate if (!tTd(51, 104)) 54387c478bd9Sstevel@tonic-gate (void) xunlink(queuename(e, XSCRPT_LETTER)); 54397c478bd9Sstevel@tonic-gate } 54407c478bd9Sstevel@tonic-gate /* 54417c478bd9Sstevel@tonic-gate ** SETCTLUSER -- create a controlling address 54427c478bd9Sstevel@tonic-gate ** 54437c478bd9Sstevel@tonic-gate ** Create a fake "address" given only a local login name; this is 54447c478bd9Sstevel@tonic-gate ** used as a "controlling user" for future recipient addresses. 54457c478bd9Sstevel@tonic-gate ** 54467c478bd9Sstevel@tonic-gate ** Parameters: 54477c478bd9Sstevel@tonic-gate ** user -- the user name of the controlling user. 54487c478bd9Sstevel@tonic-gate ** qfver -- the version stamp of this queue file. 54497c478bd9Sstevel@tonic-gate ** e -- envelope 54507c478bd9Sstevel@tonic-gate ** 54517c478bd9Sstevel@tonic-gate ** Returns: 54527c478bd9Sstevel@tonic-gate ** An address descriptor for the controlling user, 54537c478bd9Sstevel@tonic-gate ** using storage allocated from e->e_rpool. 54547c478bd9Sstevel@tonic-gate ** 54557c478bd9Sstevel@tonic-gate */ 54567c478bd9Sstevel@tonic-gate 54577c478bd9Sstevel@tonic-gate static ADDRESS * 54587c478bd9Sstevel@tonic-gate setctluser(user, qfver, e) 54597c478bd9Sstevel@tonic-gate char *user; 54607c478bd9Sstevel@tonic-gate int qfver; 54617c478bd9Sstevel@tonic-gate ENVELOPE *e; 54627c478bd9Sstevel@tonic-gate { 54637c478bd9Sstevel@tonic-gate register ADDRESS *a; 54647c478bd9Sstevel@tonic-gate struct passwd *pw; 54657c478bd9Sstevel@tonic-gate char *p; 54667c478bd9Sstevel@tonic-gate 54677c478bd9Sstevel@tonic-gate /* 54687c478bd9Sstevel@tonic-gate ** See if this clears our concept of controlling user. 54697c478bd9Sstevel@tonic-gate */ 54707c478bd9Sstevel@tonic-gate 54717c478bd9Sstevel@tonic-gate if (user == NULL || *user == '\0') 54727c478bd9Sstevel@tonic-gate return NULL; 54737c478bd9Sstevel@tonic-gate 54747c478bd9Sstevel@tonic-gate /* 54757c478bd9Sstevel@tonic-gate ** Set up addr fields for controlling user. 54767c478bd9Sstevel@tonic-gate */ 54777c478bd9Sstevel@tonic-gate 54787c478bd9Sstevel@tonic-gate a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof *a); 54797c478bd9Sstevel@tonic-gate memset((char *) a, '\0', sizeof *a); 54807c478bd9Sstevel@tonic-gate 54817c478bd9Sstevel@tonic-gate if (*user == ':') 54827c478bd9Sstevel@tonic-gate { 54837c478bd9Sstevel@tonic-gate p = &user[1]; 54847c478bd9Sstevel@tonic-gate a->q_user = sm_rpool_strdup_x(e->e_rpool, p); 54857c478bd9Sstevel@tonic-gate } 54867c478bd9Sstevel@tonic-gate else 54877c478bd9Sstevel@tonic-gate { 54887c478bd9Sstevel@tonic-gate p = strtok(user, ":"); 54897c478bd9Sstevel@tonic-gate a->q_user = sm_rpool_strdup_x(e->e_rpool, user); 54907c478bd9Sstevel@tonic-gate if (qfver >= 2) 54917c478bd9Sstevel@tonic-gate { 54927c478bd9Sstevel@tonic-gate if ((p = strtok(NULL, ":")) != NULL) 54937c478bd9Sstevel@tonic-gate a->q_uid = atoi(p); 54947c478bd9Sstevel@tonic-gate if ((p = strtok(NULL, ":")) != NULL) 54957c478bd9Sstevel@tonic-gate a->q_gid = atoi(p); 54967c478bd9Sstevel@tonic-gate if ((p = strtok(NULL, ":")) != NULL) 54977c478bd9Sstevel@tonic-gate { 54987c478bd9Sstevel@tonic-gate char *o; 54997c478bd9Sstevel@tonic-gate 55007c478bd9Sstevel@tonic-gate a->q_flags |= QGOODUID; 55017c478bd9Sstevel@tonic-gate 55027c478bd9Sstevel@tonic-gate /* if there is another ':': restore it */ 55037c478bd9Sstevel@tonic-gate if ((o = strtok(NULL, ":")) != NULL && o > p) 55047c478bd9Sstevel@tonic-gate o[-1] = ':'; 55057c478bd9Sstevel@tonic-gate } 55067c478bd9Sstevel@tonic-gate } 55077c478bd9Sstevel@tonic-gate else if ((pw = sm_getpwnam(user)) != NULL) 55087c478bd9Sstevel@tonic-gate { 55097c478bd9Sstevel@tonic-gate if (*pw->pw_dir == '\0') 55107c478bd9Sstevel@tonic-gate a->q_home = NULL; 55117c478bd9Sstevel@tonic-gate else if (strcmp(pw->pw_dir, "/") == 0) 55127c478bd9Sstevel@tonic-gate a->q_home = ""; 55137c478bd9Sstevel@tonic-gate else 55147c478bd9Sstevel@tonic-gate a->q_home = sm_rpool_strdup_x(e->e_rpool, pw->pw_dir); 55157c478bd9Sstevel@tonic-gate a->q_uid = pw->pw_uid; 55167c478bd9Sstevel@tonic-gate a->q_gid = pw->pw_gid; 55177c478bd9Sstevel@tonic-gate a->q_flags |= QGOODUID; 55187c478bd9Sstevel@tonic-gate } 55197c478bd9Sstevel@tonic-gate } 55207c478bd9Sstevel@tonic-gate 55217c478bd9Sstevel@tonic-gate a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */ 55227c478bd9Sstevel@tonic-gate a->q_mailer = LocalMailer; 55237c478bd9Sstevel@tonic-gate if (p == NULL) 55247c478bd9Sstevel@tonic-gate a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user); 55257c478bd9Sstevel@tonic-gate else 55267c478bd9Sstevel@tonic-gate a->q_paddr = sm_rpool_strdup_x(e->e_rpool, p); 55277c478bd9Sstevel@tonic-gate return a; 55287c478bd9Sstevel@tonic-gate } 55297c478bd9Sstevel@tonic-gate /* 55307c478bd9Sstevel@tonic-gate ** LOSEQFILE -- rename queue file with LOSEQF_LETTER & try to let someone know 55317c478bd9Sstevel@tonic-gate ** 55327c478bd9Sstevel@tonic-gate ** Parameters: 55337c478bd9Sstevel@tonic-gate ** e -- the envelope (e->e_id will be used). 55347c478bd9Sstevel@tonic-gate ** why -- reported to whomever can hear. 55357c478bd9Sstevel@tonic-gate ** 55367c478bd9Sstevel@tonic-gate ** Returns: 55377c478bd9Sstevel@tonic-gate ** none. 55387c478bd9Sstevel@tonic-gate */ 55397c478bd9Sstevel@tonic-gate 55407c478bd9Sstevel@tonic-gate void 55417c478bd9Sstevel@tonic-gate loseqfile(e, why) 55427c478bd9Sstevel@tonic-gate register ENVELOPE *e; 55437c478bd9Sstevel@tonic-gate char *why; 55447c478bd9Sstevel@tonic-gate { 55457c478bd9Sstevel@tonic-gate bool loseit = true; 55467c478bd9Sstevel@tonic-gate char *p; 55477c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN]; 55487c478bd9Sstevel@tonic-gate 55497c478bd9Sstevel@tonic-gate if (e == NULL || e->e_id == NULL) 55507c478bd9Sstevel@tonic-gate return; 55517c478bd9Sstevel@tonic-gate p = queuename(e, ANYQFL_LETTER); 55527c478bd9Sstevel@tonic-gate if (sm_strlcpy(buf, p, sizeof buf) >= sizeof buf) 55537c478bd9Sstevel@tonic-gate return; 55547c478bd9Sstevel@tonic-gate if (!bitset(EF_INQUEUE, e->e_flags)) 55557c478bd9Sstevel@tonic-gate queueup(e, false, true); 55567c478bd9Sstevel@tonic-gate else if (QueueMode == QM_LOST) 55577c478bd9Sstevel@tonic-gate loseit = false; 55587c478bd9Sstevel@tonic-gate 55597c478bd9Sstevel@tonic-gate /* if already lost, no need to re-lose */ 55607c478bd9Sstevel@tonic-gate if (loseit) 55617c478bd9Sstevel@tonic-gate { 55627c478bd9Sstevel@tonic-gate p = queuename(e, LOSEQF_LETTER); 55637c478bd9Sstevel@tonic-gate if (rename(buf, p) < 0) 55647c478bd9Sstevel@tonic-gate syserr("cannot rename(%s, %s), uid=%d", 55657c478bd9Sstevel@tonic-gate buf, p, (int) geteuid()); 55667c478bd9Sstevel@tonic-gate else if (LogLevel > 0) 55677c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 55687c478bd9Sstevel@tonic-gate "Losing %s: %s", buf, why); 55697c478bd9Sstevel@tonic-gate } 55707c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL) 55717c478bd9Sstevel@tonic-gate { 55727c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); 55737c478bd9Sstevel@tonic-gate e->e_dfp = NULL; 55747c478bd9Sstevel@tonic-gate } 55757c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_HAS_DF; 55767c478bd9Sstevel@tonic-gate } 55777c478bd9Sstevel@tonic-gate /* 55787c478bd9Sstevel@tonic-gate ** NAME2QID -- translate a queue group name to a queue group id 55797c478bd9Sstevel@tonic-gate ** 55807c478bd9Sstevel@tonic-gate ** Parameters: 55817c478bd9Sstevel@tonic-gate ** queuename -- name of queue group. 55827c478bd9Sstevel@tonic-gate ** 55837c478bd9Sstevel@tonic-gate ** Returns: 55847c478bd9Sstevel@tonic-gate ** queue group id if found. 55857c478bd9Sstevel@tonic-gate ** NOQGRP otherwise. 55867c478bd9Sstevel@tonic-gate */ 55877c478bd9Sstevel@tonic-gate 55887c478bd9Sstevel@tonic-gate int 55897c478bd9Sstevel@tonic-gate name2qid(queuename) 55907c478bd9Sstevel@tonic-gate char *queuename; 55917c478bd9Sstevel@tonic-gate { 55927c478bd9Sstevel@tonic-gate register STAB *s; 55937c478bd9Sstevel@tonic-gate 55947c478bd9Sstevel@tonic-gate s = stab(queuename, ST_QUEUE, ST_FIND); 55957c478bd9Sstevel@tonic-gate if (s == NULL) 55967c478bd9Sstevel@tonic-gate return NOQGRP; 55977c478bd9Sstevel@tonic-gate return s->s_quegrp->qg_index; 55987c478bd9Sstevel@tonic-gate } 55997c478bd9Sstevel@tonic-gate /* 56007c478bd9Sstevel@tonic-gate ** QID_PRINTNAME -- create externally printable version of queue id 56017c478bd9Sstevel@tonic-gate ** 56027c478bd9Sstevel@tonic-gate ** Parameters: 56037c478bd9Sstevel@tonic-gate ** e -- the envelope. 56047c478bd9Sstevel@tonic-gate ** 56057c478bd9Sstevel@tonic-gate ** Returns: 56067c478bd9Sstevel@tonic-gate ** a printable version 56077c478bd9Sstevel@tonic-gate */ 56087c478bd9Sstevel@tonic-gate 56097c478bd9Sstevel@tonic-gate char * 56107c478bd9Sstevel@tonic-gate qid_printname(e) 56117c478bd9Sstevel@tonic-gate ENVELOPE *e; 56127c478bd9Sstevel@tonic-gate { 56137c478bd9Sstevel@tonic-gate char *id; 56147c478bd9Sstevel@tonic-gate static char idbuf[MAXQFNAME + 34]; 56157c478bd9Sstevel@tonic-gate 56167c478bd9Sstevel@tonic-gate if (e == NULL) 56177c478bd9Sstevel@tonic-gate return ""; 56187c478bd9Sstevel@tonic-gate 56197c478bd9Sstevel@tonic-gate if (e->e_id == NULL) 56207c478bd9Sstevel@tonic-gate id = ""; 56217c478bd9Sstevel@tonic-gate else 56227c478bd9Sstevel@tonic-gate id = e->e_id; 56237c478bd9Sstevel@tonic-gate 56247c478bd9Sstevel@tonic-gate if (e->e_qdir == NOQDIR) 56257c478bd9Sstevel@tonic-gate return id; 56267c478bd9Sstevel@tonic-gate 56277c478bd9Sstevel@tonic-gate (void) sm_snprintf(idbuf, sizeof idbuf, "%.32s/%s", 56287c478bd9Sstevel@tonic-gate Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_name, 56297c478bd9Sstevel@tonic-gate id); 56307c478bd9Sstevel@tonic-gate return idbuf; 56317c478bd9Sstevel@tonic-gate } 56327c478bd9Sstevel@tonic-gate /* 56337c478bd9Sstevel@tonic-gate ** QID_PRINTQUEUE -- create full version of queue directory for data files 56347c478bd9Sstevel@tonic-gate ** 56357c478bd9Sstevel@tonic-gate ** Parameters: 56367c478bd9Sstevel@tonic-gate ** qgrp -- index in queue group. 56377c478bd9Sstevel@tonic-gate ** qdir -- the short version of the queue directory 56387c478bd9Sstevel@tonic-gate ** 56397c478bd9Sstevel@tonic-gate ** Returns: 56407c478bd9Sstevel@tonic-gate ** the full pathname to the queue (might point to a static var) 56417c478bd9Sstevel@tonic-gate */ 56427c478bd9Sstevel@tonic-gate 56437c478bd9Sstevel@tonic-gate char * 56447c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir) 56457c478bd9Sstevel@tonic-gate int qgrp; 56467c478bd9Sstevel@tonic-gate int qdir; 56477c478bd9Sstevel@tonic-gate { 56487c478bd9Sstevel@tonic-gate char *subdir; 56497c478bd9Sstevel@tonic-gate static char dir[MAXPATHLEN]; 56507c478bd9Sstevel@tonic-gate 56517c478bd9Sstevel@tonic-gate if (qdir == NOQDIR) 56527c478bd9Sstevel@tonic-gate return Queue[qgrp]->qg_qdir; 56537c478bd9Sstevel@tonic-gate 56547c478bd9Sstevel@tonic-gate if (strcmp(Queue[qgrp]->qg_qpaths[qdir].qp_name, ".") == 0) 56557c478bd9Sstevel@tonic-gate subdir = NULL; 56567c478bd9Sstevel@tonic-gate else 56577c478bd9Sstevel@tonic-gate subdir = Queue[qgrp]->qg_qpaths[qdir].qp_name; 56587c478bd9Sstevel@tonic-gate 56597c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(dir, sizeof dir, 4, 56607c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qdir, 56617c478bd9Sstevel@tonic-gate subdir == NULL ? "" : "/", 56627c478bd9Sstevel@tonic-gate subdir == NULL ? "" : subdir, 56637c478bd9Sstevel@tonic-gate (bitset(QP_SUBDF, 56647c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs) 56657c478bd9Sstevel@tonic-gate ? "/df" : "")); 56667c478bd9Sstevel@tonic-gate return dir; 56677c478bd9Sstevel@tonic-gate } 56687c478bd9Sstevel@tonic-gate 56697c478bd9Sstevel@tonic-gate /* 56707c478bd9Sstevel@tonic-gate ** PICKQDIR -- Pick a queue directory from a queue group 56717c478bd9Sstevel@tonic-gate ** 56727c478bd9Sstevel@tonic-gate ** Parameters: 56737c478bd9Sstevel@tonic-gate ** qg -- queue group 56747c478bd9Sstevel@tonic-gate ** fsize -- file size in bytes 56757c478bd9Sstevel@tonic-gate ** e -- envelope, or NULL 56767c478bd9Sstevel@tonic-gate ** 56777c478bd9Sstevel@tonic-gate ** Result: 56787c478bd9Sstevel@tonic-gate ** NOQDIR if no queue directory in qg has enough free space to 56797c478bd9Sstevel@tonic-gate ** hold a file of size 'fsize', otherwise the index of 56807c478bd9Sstevel@tonic-gate ** a randomly selected queue directory which resides on a 56817c478bd9Sstevel@tonic-gate ** file system with enough disk space. 56827c478bd9Sstevel@tonic-gate ** XXX This could be extended to select a queuedir with 56837c478bd9Sstevel@tonic-gate ** a few (the fewest?) number of entries. That data 56847c478bd9Sstevel@tonic-gate ** is available if shared memory is used. 56857c478bd9Sstevel@tonic-gate ** 56867c478bd9Sstevel@tonic-gate ** Side Effects: 56877c478bd9Sstevel@tonic-gate ** If the request fails and e != NULL then sm_syslog is called. 56887c478bd9Sstevel@tonic-gate */ 56897c478bd9Sstevel@tonic-gate 56907c478bd9Sstevel@tonic-gate int 56917c478bd9Sstevel@tonic-gate pickqdir(qg, fsize, e) 56927c478bd9Sstevel@tonic-gate QUEUEGRP *qg; 56937c478bd9Sstevel@tonic-gate long fsize; 56947c478bd9Sstevel@tonic-gate ENVELOPE *e; 56957c478bd9Sstevel@tonic-gate { 56967c478bd9Sstevel@tonic-gate int qdir; 56977c478bd9Sstevel@tonic-gate int i; 56987c478bd9Sstevel@tonic-gate long avail = 0; 56997c478bd9Sstevel@tonic-gate 57007c478bd9Sstevel@tonic-gate /* Pick a random directory, as a starting point. */ 57017c478bd9Sstevel@tonic-gate if (qg->qg_numqueues <= 1) 57027c478bd9Sstevel@tonic-gate qdir = 0; 57037c478bd9Sstevel@tonic-gate else 57047c478bd9Sstevel@tonic-gate qdir = get_rand_mod(qg->qg_numqueues); 57057c478bd9Sstevel@tonic-gate 57067c478bd9Sstevel@tonic-gate if (MinBlocksFree <= 0 && fsize <= 0) 57077c478bd9Sstevel@tonic-gate return qdir; 57087c478bd9Sstevel@tonic-gate 57097c478bd9Sstevel@tonic-gate /* 57107c478bd9Sstevel@tonic-gate ** Now iterate over the queue directories, 57117c478bd9Sstevel@tonic-gate ** looking for a directory with enough space for this message. 57127c478bd9Sstevel@tonic-gate */ 57137c478bd9Sstevel@tonic-gate 57147c478bd9Sstevel@tonic-gate i = qdir; 57157c478bd9Sstevel@tonic-gate do 57167c478bd9Sstevel@tonic-gate { 57177c478bd9Sstevel@tonic-gate QPATHS *qp = &qg->qg_qpaths[i]; 57187c478bd9Sstevel@tonic-gate long needed = 0; 57197c478bd9Sstevel@tonic-gate long fsavail = 0; 57207c478bd9Sstevel@tonic-gate 57217c478bd9Sstevel@tonic-gate if (fsize > 0) 57227c478bd9Sstevel@tonic-gate needed += fsize / FILE_SYS_BLKSIZE(qp->qp_fsysidx) 57237c478bd9Sstevel@tonic-gate + ((fsize % FILE_SYS_BLKSIZE(qp->qp_fsysidx) 57247c478bd9Sstevel@tonic-gate > 0) ? 1 : 0); 57257c478bd9Sstevel@tonic-gate if (MinBlocksFree > 0) 57267c478bd9Sstevel@tonic-gate needed += MinBlocksFree; 57277c478bd9Sstevel@tonic-gate fsavail = FILE_SYS_AVAIL(qp->qp_fsysidx); 57287c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 57297c478bd9Sstevel@tonic-gate if (fsavail <= 0) 57307c478bd9Sstevel@tonic-gate { 57317c478bd9Sstevel@tonic-gate long blksize; 57327c478bd9Sstevel@tonic-gate 57337c478bd9Sstevel@tonic-gate /* 57347c478bd9Sstevel@tonic-gate ** might be not correctly updated, 57357c478bd9Sstevel@tonic-gate ** let's try to get the info directly. 57367c478bd9Sstevel@tonic-gate */ 57377c478bd9Sstevel@tonic-gate 57387c478bd9Sstevel@tonic-gate fsavail = freediskspace(FILE_SYS_NAME(qp->qp_fsysidx), 57397c478bd9Sstevel@tonic-gate &blksize); 57407c478bd9Sstevel@tonic-gate if (fsavail < 0) 57417c478bd9Sstevel@tonic-gate fsavail = 0; 57427c478bd9Sstevel@tonic-gate } 57437c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 57447c478bd9Sstevel@tonic-gate if (needed <= fsavail) 57457c478bd9Sstevel@tonic-gate return i; 57467c478bd9Sstevel@tonic-gate if (avail < fsavail) 57477c478bd9Sstevel@tonic-gate avail = fsavail; 57487c478bd9Sstevel@tonic-gate 57497c478bd9Sstevel@tonic-gate if (qg->qg_numqueues > 0) 57507c478bd9Sstevel@tonic-gate i = (i + 1) % qg->qg_numqueues; 57517c478bd9Sstevel@tonic-gate } while (i != qdir); 57527c478bd9Sstevel@tonic-gate 57537c478bd9Sstevel@tonic-gate if (e != NULL && LogLevel > 0) 57547c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 57557c478bd9Sstevel@tonic-gate "low on space (%s needs %ld bytes + %ld blocks in %s), max avail: %ld", 57567c478bd9Sstevel@tonic-gate CurHostName == NULL ? "SMTP-DAEMON" : CurHostName, 57577c478bd9Sstevel@tonic-gate fsize, MinBlocksFree, 57587c478bd9Sstevel@tonic-gate qg->qg_qdir, avail); 57597c478bd9Sstevel@tonic-gate return NOQDIR; 57607c478bd9Sstevel@tonic-gate } 57617c478bd9Sstevel@tonic-gate /* 57627c478bd9Sstevel@tonic-gate ** SETNEWQUEUE -- Sets a new queue group and directory 57637c478bd9Sstevel@tonic-gate ** 57647c478bd9Sstevel@tonic-gate ** Assign a queue group and directory to an envelope and store the 57657c478bd9Sstevel@tonic-gate ** directory in e->e_qdir. 57667c478bd9Sstevel@tonic-gate ** 57677c478bd9Sstevel@tonic-gate ** Parameters: 57687c478bd9Sstevel@tonic-gate ** e -- envelope to assign a queue for. 57697c478bd9Sstevel@tonic-gate ** 57707c478bd9Sstevel@tonic-gate ** Returns: 57717c478bd9Sstevel@tonic-gate ** true if successful 57727c478bd9Sstevel@tonic-gate ** false otherwise 57737c478bd9Sstevel@tonic-gate ** 57747c478bd9Sstevel@tonic-gate ** Side Effects: 57757c478bd9Sstevel@tonic-gate ** On success, e->e_qgrp and e->e_qdir are non-negative. 57767c478bd9Sstevel@tonic-gate ** On failure (not enough disk space), 57777c478bd9Sstevel@tonic-gate ** e->qgrp = NOQGRP, e->e_qdir = NOQDIR 57787c478bd9Sstevel@tonic-gate ** and usrerr() is invoked (which could raise an exception). 57797c478bd9Sstevel@tonic-gate */ 57807c478bd9Sstevel@tonic-gate 57817c478bd9Sstevel@tonic-gate bool 57827c478bd9Sstevel@tonic-gate setnewqueue(e) 57837c478bd9Sstevel@tonic-gate ENVELOPE *e; 57847c478bd9Sstevel@tonic-gate { 57857c478bd9Sstevel@tonic-gate if (tTd(41, 20)) 57867c478bd9Sstevel@tonic-gate sm_dprintf("setnewqueue: called\n"); 57877c478bd9Sstevel@tonic-gate 57887c478bd9Sstevel@tonic-gate /* not set somewhere else */ 57897c478bd9Sstevel@tonic-gate if (e->e_qgrp == NOQGRP) 57907c478bd9Sstevel@tonic-gate { 57917c478bd9Sstevel@tonic-gate ADDRESS *q; 57927c478bd9Sstevel@tonic-gate 57937c478bd9Sstevel@tonic-gate /* 57947c478bd9Sstevel@tonic-gate ** Use the queue group of the "first" recipient, as set by 57957c478bd9Sstevel@tonic-gate ** the "queuegroup" rule set. If that is not defined, then 57967c478bd9Sstevel@tonic-gate ** use the queue group of the mailer of the first recipient. 57977c478bd9Sstevel@tonic-gate ** If that is not defined either, then use the default 57987c478bd9Sstevel@tonic-gate ** queue group. 57997c478bd9Sstevel@tonic-gate ** Notice: "first" depends on the sorting of sendqueue 58007c478bd9Sstevel@tonic-gate ** in recipient(). 58017c478bd9Sstevel@tonic-gate ** To avoid problems with "bad" recipients look 58027c478bd9Sstevel@tonic-gate ** for a valid address first. 58037c478bd9Sstevel@tonic-gate */ 58047c478bd9Sstevel@tonic-gate 58057c478bd9Sstevel@tonic-gate q = e->e_sendqueue; 58067c478bd9Sstevel@tonic-gate while (q != NULL && 58077c478bd9Sstevel@tonic-gate (QS_IS_BADADDR(q->q_state) || QS_IS_DEAD(q->q_state))) 58087c478bd9Sstevel@tonic-gate { 58097c478bd9Sstevel@tonic-gate q = q->q_next; 58107c478bd9Sstevel@tonic-gate } 58117c478bd9Sstevel@tonic-gate if (q == NULL) 58127c478bd9Sstevel@tonic-gate e->e_qgrp = 0; 58137c478bd9Sstevel@tonic-gate else if (q->q_qgrp >= 0) 58147c478bd9Sstevel@tonic-gate e->e_qgrp = q->q_qgrp; 58157c478bd9Sstevel@tonic-gate else if (q->q_mailer != NULL && 58167c478bd9Sstevel@tonic-gate ISVALIDQGRP(q->q_mailer->m_qgrp)) 58177c478bd9Sstevel@tonic-gate e->e_qgrp = q->q_mailer->m_qgrp; 58187c478bd9Sstevel@tonic-gate else 58197c478bd9Sstevel@tonic-gate e->e_qgrp = 0; 58207c478bd9Sstevel@tonic-gate e->e_dfqgrp = e->e_qgrp; 58217c478bd9Sstevel@tonic-gate } 58227c478bd9Sstevel@tonic-gate 58237c478bd9Sstevel@tonic-gate if (ISVALIDQDIR(e->e_qdir) && ISVALIDQDIR(e->e_dfqdir)) 58247c478bd9Sstevel@tonic-gate { 58257c478bd9Sstevel@tonic-gate if (tTd(41, 20)) 58267c478bd9Sstevel@tonic-gate sm_dprintf("setnewqueue: e_qdir already assigned (%s)\n", 58277c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir)); 58287c478bd9Sstevel@tonic-gate return true; 58297c478bd9Sstevel@tonic-gate } 58307c478bd9Sstevel@tonic-gate 58317c478bd9Sstevel@tonic-gate filesys_update(); 58327c478bd9Sstevel@tonic-gate e->e_qdir = pickqdir(Queue[e->e_qgrp], e->e_msgsize, e); 58337c478bd9Sstevel@tonic-gate if (e->e_qdir == NOQDIR) 58347c478bd9Sstevel@tonic-gate { 58357c478bd9Sstevel@tonic-gate e->e_qgrp = NOQGRP; 58367c478bd9Sstevel@tonic-gate if (!bitset(EF_FATALERRS, e->e_flags)) 58377c478bd9Sstevel@tonic-gate usrerr("452 4.4.5 Insufficient disk space; try again later"); 58387c478bd9Sstevel@tonic-gate e->e_flags |= EF_FATALERRS; 58397c478bd9Sstevel@tonic-gate return false; 58407c478bd9Sstevel@tonic-gate } 58417c478bd9Sstevel@tonic-gate 58427c478bd9Sstevel@tonic-gate if (tTd(41, 3)) 58437c478bd9Sstevel@tonic-gate sm_dprintf("setnewqueue: Assigned queue directory %s\n", 58447c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir)); 58457c478bd9Sstevel@tonic-gate 58467c478bd9Sstevel@tonic-gate if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR) 58477c478bd9Sstevel@tonic-gate { 58487c478bd9Sstevel@tonic-gate e->e_xfqgrp = e->e_qgrp; 58497c478bd9Sstevel@tonic-gate e->e_xfqdir = e->e_qdir; 58507c478bd9Sstevel@tonic-gate } 58517c478bd9Sstevel@tonic-gate e->e_dfqdir = e->e_qdir; 58527c478bd9Sstevel@tonic-gate return true; 58537c478bd9Sstevel@tonic-gate } 58547c478bd9Sstevel@tonic-gate /* 58557c478bd9Sstevel@tonic-gate ** CHKQDIR -- check a queue directory 58567c478bd9Sstevel@tonic-gate ** 58577c478bd9Sstevel@tonic-gate ** Parameters: 58587c478bd9Sstevel@tonic-gate ** name -- name of queue directory 58597c478bd9Sstevel@tonic-gate ** sff -- flags for safefile() 58607c478bd9Sstevel@tonic-gate ** 58617c478bd9Sstevel@tonic-gate ** Returns: 58627c478bd9Sstevel@tonic-gate ** is it a queue directory? 58637c478bd9Sstevel@tonic-gate */ 58647c478bd9Sstevel@tonic-gate 58657c478bd9Sstevel@tonic-gate static bool 58667c478bd9Sstevel@tonic-gate chkqdir(name, sff) 58677c478bd9Sstevel@tonic-gate char *name; 58687c478bd9Sstevel@tonic-gate long sff; 58697c478bd9Sstevel@tonic-gate { 58707c478bd9Sstevel@tonic-gate struct stat statb; 58717c478bd9Sstevel@tonic-gate int i; 58727c478bd9Sstevel@tonic-gate 58737c478bd9Sstevel@tonic-gate /* skip over . and .. directories */ 58747c478bd9Sstevel@tonic-gate if (name[0] == '.' && 58757c478bd9Sstevel@tonic-gate (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) 58767c478bd9Sstevel@tonic-gate return false; 58777c478bd9Sstevel@tonic-gate #if HASLSTAT 58787c478bd9Sstevel@tonic-gate if (lstat(name, &statb) < 0) 58797c478bd9Sstevel@tonic-gate #else /* HASLSTAT */ 58807c478bd9Sstevel@tonic-gate if (stat(name, &statb) < 0) 58817c478bd9Sstevel@tonic-gate #endif /* HASLSTAT */ 58827c478bd9Sstevel@tonic-gate { 58837c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 58847c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: stat(\"%s\"): %s\n", 58857c478bd9Sstevel@tonic-gate name, sm_errstring(errno)); 58867c478bd9Sstevel@tonic-gate return false; 58877c478bd9Sstevel@tonic-gate } 58887c478bd9Sstevel@tonic-gate #if HASLSTAT 58897c478bd9Sstevel@tonic-gate if (S_ISLNK(statb.st_mode)) 58907c478bd9Sstevel@tonic-gate { 58917c478bd9Sstevel@tonic-gate /* 58927c478bd9Sstevel@tonic-gate ** For a symlink we need to make sure the 58937c478bd9Sstevel@tonic-gate ** target is a directory 58947c478bd9Sstevel@tonic-gate */ 58957c478bd9Sstevel@tonic-gate 58967c478bd9Sstevel@tonic-gate if (stat(name, &statb) < 0) 58977c478bd9Sstevel@tonic-gate { 58987c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 58997c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: stat(\"%s\"): %s\n", 59007c478bd9Sstevel@tonic-gate name, sm_errstring(errno)); 59017c478bd9Sstevel@tonic-gate return false; 59027c478bd9Sstevel@tonic-gate } 59037c478bd9Sstevel@tonic-gate } 59047c478bd9Sstevel@tonic-gate #endif /* HASLSTAT */ 59057c478bd9Sstevel@tonic-gate 59067c478bd9Sstevel@tonic-gate if (!S_ISDIR(statb.st_mode)) 59077c478bd9Sstevel@tonic-gate { 59087c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 59097c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: \"%s\": Not a directory\n", 59107c478bd9Sstevel@tonic-gate name); 59117c478bd9Sstevel@tonic-gate return false; 59127c478bd9Sstevel@tonic-gate } 59137c478bd9Sstevel@tonic-gate 59147c478bd9Sstevel@tonic-gate /* Print a warning if unsafe (but still use it) */ 59157c478bd9Sstevel@tonic-gate /* XXX do this only if we want the warning? */ 59167c478bd9Sstevel@tonic-gate i = safedirpath(name, RunAsUid, RunAsGid, NULL, sff, 0, 0); 59177c478bd9Sstevel@tonic-gate if (i != 0) 59187c478bd9Sstevel@tonic-gate { 59197c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 59207c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: \"%s\": Not safe: %s\n", 59217c478bd9Sstevel@tonic-gate name, sm_errstring(i)); 59227c478bd9Sstevel@tonic-gate #if _FFR_CHK_QUEUE 59237c478bd9Sstevel@tonic-gate if (LogLevel > 8) 59247c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 59257c478bd9Sstevel@tonic-gate "queue directory \"%s\": Not safe: %s", 59267c478bd9Sstevel@tonic-gate name, sm_errstring(i)); 59277c478bd9Sstevel@tonic-gate #endif /* _FFR_CHK_QUEUE */ 59287c478bd9Sstevel@tonic-gate } 59297c478bd9Sstevel@tonic-gate return true; 59307c478bd9Sstevel@tonic-gate } 59317c478bd9Sstevel@tonic-gate /* 59327c478bd9Sstevel@tonic-gate ** MULTIQUEUE_CACHE -- cache a list of paths to queues. 59337c478bd9Sstevel@tonic-gate ** 59347c478bd9Sstevel@tonic-gate ** Each potential queue is checked as the cache is built. 59357c478bd9Sstevel@tonic-gate ** Thereafter, each is blindly trusted. 59367c478bd9Sstevel@tonic-gate ** Note that we can be called again after a timeout to rebuild 59377c478bd9Sstevel@tonic-gate ** (although code for that is not ready yet). 59387c478bd9Sstevel@tonic-gate ** 59397c478bd9Sstevel@tonic-gate ** Parameters: 59407c478bd9Sstevel@tonic-gate ** basedir -- base of all queue directories. 59417c478bd9Sstevel@tonic-gate ** blen -- strlen(basedir). 59427c478bd9Sstevel@tonic-gate ** qg -- queue group. 59437c478bd9Sstevel@tonic-gate ** qn -- number of queue directories already cached. 59447c478bd9Sstevel@tonic-gate ** phash -- pointer to hash value over queue dirs. 59457c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 59467c478bd9Sstevel@tonic-gate ** only used if shared memory is active. 59477c478bd9Sstevel@tonic-gate #endif * SM_CONF_SHM * 59487c478bd9Sstevel@tonic-gate ** 59497c478bd9Sstevel@tonic-gate ** Returns: 59507c478bd9Sstevel@tonic-gate ** new number of queue directories. 59517c478bd9Sstevel@tonic-gate */ 59527c478bd9Sstevel@tonic-gate 59537c478bd9Sstevel@tonic-gate #define INITIAL_SLOTS 20 59547c478bd9Sstevel@tonic-gate #define ADD_SLOTS 10 59557c478bd9Sstevel@tonic-gate 59567c478bd9Sstevel@tonic-gate static int 59577c478bd9Sstevel@tonic-gate multiqueue_cache(basedir, blen, qg, qn, phash) 59587c478bd9Sstevel@tonic-gate char *basedir; 59597c478bd9Sstevel@tonic-gate int blen; 59607c478bd9Sstevel@tonic-gate QUEUEGRP *qg; 59617c478bd9Sstevel@tonic-gate int qn; 59627c478bd9Sstevel@tonic-gate unsigned int *phash; 59637c478bd9Sstevel@tonic-gate { 59647c478bd9Sstevel@tonic-gate char *cp; 59657c478bd9Sstevel@tonic-gate int i, len; 59667c478bd9Sstevel@tonic-gate int slotsleft = 0; 59677c478bd9Sstevel@tonic-gate long sff = SFF_ANYFILE; 59687c478bd9Sstevel@tonic-gate char qpath[MAXPATHLEN]; 59697c478bd9Sstevel@tonic-gate char subdir[MAXPATHLEN]; 59707c478bd9Sstevel@tonic-gate char prefix[MAXPATHLEN]; /* dir relative to basedir */ 59717c478bd9Sstevel@tonic-gate 59727c478bd9Sstevel@tonic-gate if (tTd(41, 20)) 59737c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: called\n"); 59747c478bd9Sstevel@tonic-gate 59757c478bd9Sstevel@tonic-gate /* Initialize to current directory */ 59767c478bd9Sstevel@tonic-gate prefix[0] = '.'; 59777c478bd9Sstevel@tonic-gate prefix[1] = '\0'; 59787c478bd9Sstevel@tonic-gate if (qg->qg_numqueues != 0 && qg->qg_qpaths != NULL) 59797c478bd9Sstevel@tonic-gate { 59807c478bd9Sstevel@tonic-gate for (i = 0; i < qg->qg_numqueues; i++) 59817c478bd9Sstevel@tonic-gate { 59827c478bd9Sstevel@tonic-gate if (qg->qg_qpaths[i].qp_name != NULL) 59837c478bd9Sstevel@tonic-gate (void) sm_free(qg->qg_qpaths[i].qp_name); /* XXX */ 59847c478bd9Sstevel@tonic-gate } 59857c478bd9Sstevel@tonic-gate (void) sm_free((char *) qg->qg_qpaths); /* XXX */ 59867c478bd9Sstevel@tonic-gate qg->qg_qpaths = NULL; 59877c478bd9Sstevel@tonic-gate qg->qg_numqueues = 0; 59887c478bd9Sstevel@tonic-gate } 59897c478bd9Sstevel@tonic-gate 59907c478bd9Sstevel@tonic-gate /* If running as root, allow safedirpath() checks to use privs */ 59917c478bd9Sstevel@tonic-gate if (RunAsUid == 0) 59927c478bd9Sstevel@tonic-gate sff |= SFF_ROOTOK; 59937c478bd9Sstevel@tonic-gate #if _FFR_CHK_QUEUE 59947c478bd9Sstevel@tonic-gate sff |= SFF_SAFEDIRPATH|SFF_NOWWFILES; 59957c478bd9Sstevel@tonic-gate if (!UseMSP) 59967c478bd9Sstevel@tonic-gate sff |= SFF_NOGWFILES; 59977c478bd9Sstevel@tonic-gate #endif /* _FFR_CHK_QUEUE */ 59987c478bd9Sstevel@tonic-gate 59997c478bd9Sstevel@tonic-gate if (!SM_IS_DIR_START(qg->qg_qdir)) 60007c478bd9Sstevel@tonic-gate { 60017c478bd9Sstevel@tonic-gate /* 60027c478bd9Sstevel@tonic-gate ** XXX we could add basedir, but then we have to realloc() 60037c478bd9Sstevel@tonic-gate ** the string... Maybe another time. 60047c478bd9Sstevel@tonic-gate */ 60057c478bd9Sstevel@tonic-gate 60067c478bd9Sstevel@tonic-gate syserr("QueuePath %s not absolute", qg->qg_qdir); 60077c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 60087c478bd9Sstevel@tonic-gate return qn; 60097c478bd9Sstevel@tonic-gate } 60107c478bd9Sstevel@tonic-gate 60117c478bd9Sstevel@tonic-gate /* qpath: directory of current workgroup */ 60127c478bd9Sstevel@tonic-gate len = sm_strlcpy(qpath, qg->qg_qdir, sizeof qpath); 60137c478bd9Sstevel@tonic-gate if (len >= sizeof qpath) 60147c478bd9Sstevel@tonic-gate { 60157c478bd9Sstevel@tonic-gate syserr("QueuePath %.256s too long (%d max)", 60167c478bd9Sstevel@tonic-gate qg->qg_qdir, (int) sizeof qpath); 60177c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 60187c478bd9Sstevel@tonic-gate return qn; 60197c478bd9Sstevel@tonic-gate } 60207c478bd9Sstevel@tonic-gate 60217c478bd9Sstevel@tonic-gate /* begin of qpath must be same as basedir */ 60227c478bd9Sstevel@tonic-gate if (strncmp(basedir, qpath, blen) != 0 && 60237c478bd9Sstevel@tonic-gate (strncmp(basedir, qpath, blen - 1) != 0 || len != blen - 1)) 60247c478bd9Sstevel@tonic-gate { 60257c478bd9Sstevel@tonic-gate syserr("QueuePath %s not subpath of QueueDirectory %s", 60267c478bd9Sstevel@tonic-gate qpath, basedir); 60277c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 60287c478bd9Sstevel@tonic-gate return qn; 60297c478bd9Sstevel@tonic-gate } 60307c478bd9Sstevel@tonic-gate 60317c478bd9Sstevel@tonic-gate /* Do we have a nested subdirectory? */ 60327c478bd9Sstevel@tonic-gate if (blen < len && SM_FIRST_DIR_DELIM(qg->qg_qdir + blen) != NULL) 60337c478bd9Sstevel@tonic-gate { 60347c478bd9Sstevel@tonic-gate 60357c478bd9Sstevel@tonic-gate /* Copy subdirectory into prefix for later use */ 60367c478bd9Sstevel@tonic-gate if (sm_strlcpy(prefix, qg->qg_qdir + blen, sizeof prefix) >= 60377c478bd9Sstevel@tonic-gate sizeof prefix) 60387c478bd9Sstevel@tonic-gate { 60397c478bd9Sstevel@tonic-gate syserr("QueuePath %.256s too long (%d max)", 60407c478bd9Sstevel@tonic-gate qg->qg_qdir, (int) sizeof qpath); 60417c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 60427c478bd9Sstevel@tonic-gate return qn; 60437c478bd9Sstevel@tonic-gate } 60447c478bd9Sstevel@tonic-gate cp = SM_LAST_DIR_DELIM(prefix); 60457c478bd9Sstevel@tonic-gate SM_ASSERT(cp != NULL); 60467c478bd9Sstevel@tonic-gate *cp = '\0'; /* cut off trailing / */ 60477c478bd9Sstevel@tonic-gate } 60487c478bd9Sstevel@tonic-gate 60497c478bd9Sstevel@tonic-gate /* This is guaranteed by the basedir check above */ 60507c478bd9Sstevel@tonic-gate SM_ASSERT(len >= blen - 1); 60517c478bd9Sstevel@tonic-gate cp = &qpath[len - 1]; 60527c478bd9Sstevel@tonic-gate if (*cp == '*') 60537c478bd9Sstevel@tonic-gate { 60547c478bd9Sstevel@tonic-gate register DIR *dp; 60557c478bd9Sstevel@tonic-gate register struct dirent *d; 60567c478bd9Sstevel@tonic-gate int off; 60577c478bd9Sstevel@tonic-gate char *delim; 60587c478bd9Sstevel@tonic-gate char relpath[MAXPATHLEN]; 60597c478bd9Sstevel@tonic-gate 60607c478bd9Sstevel@tonic-gate *cp = '\0'; /* Overwrite wildcard */ 60617c478bd9Sstevel@tonic-gate if ((cp = SM_LAST_DIR_DELIM(qpath)) == NULL) 60627c478bd9Sstevel@tonic-gate { 60637c478bd9Sstevel@tonic-gate syserr("QueueDirectory: can not wildcard relative path"); 60647c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 60657c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: \"%s*\": Can not wildcard relative path.\n", 60667c478bd9Sstevel@tonic-gate qpath); 60677c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 60687c478bd9Sstevel@tonic-gate return qn; 60697c478bd9Sstevel@tonic-gate } 60707c478bd9Sstevel@tonic-gate if (cp == qpath) 60717c478bd9Sstevel@tonic-gate { 60727c478bd9Sstevel@tonic-gate /* 60737c478bd9Sstevel@tonic-gate ** Special case of top level wildcard, like /foo* 60747c478bd9Sstevel@tonic-gate ** Change to //foo* 60757c478bd9Sstevel@tonic-gate */ 60767c478bd9Sstevel@tonic-gate 60777c478bd9Sstevel@tonic-gate (void) sm_strlcpy(qpath + 1, qpath, sizeof qpath - 1); 60787c478bd9Sstevel@tonic-gate ++cp; 60797c478bd9Sstevel@tonic-gate } 60807c478bd9Sstevel@tonic-gate delim = cp; 60817c478bd9Sstevel@tonic-gate *(cp++) = '\0'; /* Replace / with \0 */ 60827c478bd9Sstevel@tonic-gate len = strlen(cp); /* Last component of queue directory */ 60837c478bd9Sstevel@tonic-gate 60847c478bd9Sstevel@tonic-gate /* 60857c478bd9Sstevel@tonic-gate ** Path relative to basedir, with trailing / 60867c478bd9Sstevel@tonic-gate ** It will be modified below to specify the subdirectories 60877c478bd9Sstevel@tonic-gate ** so they can be opened without chdir(). 60887c478bd9Sstevel@tonic-gate */ 60897c478bd9Sstevel@tonic-gate 60907c478bd9Sstevel@tonic-gate off = sm_strlcpyn(relpath, sizeof relpath, 2, prefix, "/"); 60917c478bd9Sstevel@tonic-gate SM_ASSERT(off < sizeof relpath); 60927c478bd9Sstevel@tonic-gate 60937c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 60947c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: prefix=\"%s%s\"\n", 60957c478bd9Sstevel@tonic-gate relpath, cp); 60967c478bd9Sstevel@tonic-gate 60977c478bd9Sstevel@tonic-gate /* It is always basedir: we don't need to store it per group */ 60987c478bd9Sstevel@tonic-gate /* XXX: optimize this! -> one more global? */ 60997c478bd9Sstevel@tonic-gate qg->qg_qdir = newstr(basedir); 61007c478bd9Sstevel@tonic-gate qg->qg_qdir[blen - 1] = '\0'; /* cut off trailing / */ 61017c478bd9Sstevel@tonic-gate 61027c478bd9Sstevel@tonic-gate /* 61037c478bd9Sstevel@tonic-gate ** XXX Should probably wrap this whole loop in a timeout 61047c478bd9Sstevel@tonic-gate ** in case some wag decides to NFS mount the queues. 61057c478bd9Sstevel@tonic-gate */ 61067c478bd9Sstevel@tonic-gate 61077c478bd9Sstevel@tonic-gate /* Test path to get warning messages. */ 61087c478bd9Sstevel@tonic-gate if (qn == 0) 61097c478bd9Sstevel@tonic-gate { 61107c478bd9Sstevel@tonic-gate /* XXX qg_runasuid and qg_runasgid for specials? */ 61117c478bd9Sstevel@tonic-gate i = safedirpath(basedir, RunAsUid, RunAsGid, NULL, 61127c478bd9Sstevel@tonic-gate sff, 0, 0); 61137c478bd9Sstevel@tonic-gate if (i != 0 && tTd(41, 2)) 61147c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: \"%s\": Not safe: %s\n", 61157c478bd9Sstevel@tonic-gate basedir, sm_errstring(i)); 61167c478bd9Sstevel@tonic-gate } 61177c478bd9Sstevel@tonic-gate 61187c478bd9Sstevel@tonic-gate if ((dp = opendir(prefix)) == NULL) 61197c478bd9Sstevel@tonic-gate { 61207c478bd9Sstevel@tonic-gate syserr("can not opendir(%s/%s)", qg->qg_qdir, prefix); 61217c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 61227c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: opendir(\"%s/%s\"): %s\n", 61237c478bd9Sstevel@tonic-gate qg->qg_qdir, prefix, 61247c478bd9Sstevel@tonic-gate sm_errstring(errno)); 61257c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 61267c478bd9Sstevel@tonic-gate return qn; 61277c478bd9Sstevel@tonic-gate } 61287c478bd9Sstevel@tonic-gate while ((d = readdir(dp)) != NULL) 61297c478bd9Sstevel@tonic-gate { 61307c478bd9Sstevel@tonic-gate i = strlen(d->d_name); 61317c478bd9Sstevel@tonic-gate if (i < len || strncmp(d->d_name, cp, len) != 0) 61327c478bd9Sstevel@tonic-gate { 61337c478bd9Sstevel@tonic-gate if (tTd(41, 5)) 61347c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: \"%s\", skipped\n", 61357c478bd9Sstevel@tonic-gate d->d_name); 61367c478bd9Sstevel@tonic-gate continue; 61377c478bd9Sstevel@tonic-gate } 61387c478bd9Sstevel@tonic-gate 61397c478bd9Sstevel@tonic-gate /* Create relative pathname: prefix + local directory */ 61407c478bd9Sstevel@tonic-gate i = sizeof(relpath) - off; 61417c478bd9Sstevel@tonic-gate if (sm_strlcpy(relpath + off, d->d_name, i) >= i) 61427c478bd9Sstevel@tonic-gate continue; /* way too long */ 61437c478bd9Sstevel@tonic-gate 61447c478bd9Sstevel@tonic-gate if (!chkqdir(relpath, sff)) 61457c478bd9Sstevel@tonic-gate continue; 61467c478bd9Sstevel@tonic-gate 61477c478bd9Sstevel@tonic-gate if (qg->qg_qpaths == NULL) 61487c478bd9Sstevel@tonic-gate { 61497c478bd9Sstevel@tonic-gate slotsleft = INITIAL_SLOTS; 61507c478bd9Sstevel@tonic-gate qg->qg_qpaths = (QPATHS *)xalloc((sizeof *qg->qg_qpaths) * 61517c478bd9Sstevel@tonic-gate slotsleft); 61527c478bd9Sstevel@tonic-gate qg->qg_numqueues = 0; 61537c478bd9Sstevel@tonic-gate } 61547c478bd9Sstevel@tonic-gate else if (slotsleft < 1) 61557c478bd9Sstevel@tonic-gate { 61567c478bd9Sstevel@tonic-gate qg->qg_qpaths = (QPATHS *)sm_realloc((char *)qg->qg_qpaths, 61577c478bd9Sstevel@tonic-gate (sizeof *qg->qg_qpaths) * 61587c478bd9Sstevel@tonic-gate (qg->qg_numqueues + 61597c478bd9Sstevel@tonic-gate ADD_SLOTS)); 61607c478bd9Sstevel@tonic-gate if (qg->qg_qpaths == NULL) 61617c478bd9Sstevel@tonic-gate { 61627c478bd9Sstevel@tonic-gate (void) closedir(dp); 61637c478bd9Sstevel@tonic-gate return qn; 61647c478bd9Sstevel@tonic-gate } 61657c478bd9Sstevel@tonic-gate slotsleft += ADD_SLOTS; 61667c478bd9Sstevel@tonic-gate } 61677c478bd9Sstevel@tonic-gate 61687c478bd9Sstevel@tonic-gate /* check subdirs */ 61697c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_subdirs = QP_NOSUB; 61707c478bd9Sstevel@tonic-gate 61717c478bd9Sstevel@tonic-gate #define CHKRSUBDIR(name, flag) \ 61727c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(subdir, sizeof subdir, 3, relpath, "/", name); \ 61737c478bd9Sstevel@tonic-gate if (chkqdir(subdir, sff)) \ 61747c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_subdirs |= flag; \ 61757c478bd9Sstevel@tonic-gate else 61767c478bd9Sstevel@tonic-gate 61777c478bd9Sstevel@tonic-gate 61787c478bd9Sstevel@tonic-gate CHKRSUBDIR("qf", QP_SUBQF); 61797c478bd9Sstevel@tonic-gate CHKRSUBDIR("df", QP_SUBDF); 61807c478bd9Sstevel@tonic-gate CHKRSUBDIR("xf", QP_SUBXF); 61817c478bd9Sstevel@tonic-gate 61827c478bd9Sstevel@tonic-gate /* assert(strlen(d->d_name) < MAXPATHLEN - 14) */ 61837c478bd9Sstevel@tonic-gate /* maybe even - 17 (subdirs) */ 61847c478bd9Sstevel@tonic-gate 61857c478bd9Sstevel@tonic-gate if (prefix[0] != '.') 61867c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_name = 61877c478bd9Sstevel@tonic-gate newstr(relpath); 61887c478bd9Sstevel@tonic-gate else 61897c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_name = 61907c478bd9Sstevel@tonic-gate newstr(d->d_name); 61917c478bd9Sstevel@tonic-gate 61927c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 61937c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: %d: \"%s\" cached (%x).\n", 61947c478bd9Sstevel@tonic-gate qg->qg_numqueues, relpath, 61957c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_subdirs); 61967c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 61977c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_idx = qn; 61987c478bd9Sstevel@tonic-gate *phash = hash_q(relpath, *phash); 61997c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 62007c478bd9Sstevel@tonic-gate qg->qg_numqueues++; 62017c478bd9Sstevel@tonic-gate ++qn; 62027c478bd9Sstevel@tonic-gate slotsleft--; 62037c478bd9Sstevel@tonic-gate } 62047c478bd9Sstevel@tonic-gate (void) closedir(dp); 62057c478bd9Sstevel@tonic-gate 62067c478bd9Sstevel@tonic-gate /* undo damage */ 62077c478bd9Sstevel@tonic-gate *delim = '/'; 62087c478bd9Sstevel@tonic-gate } 62097c478bd9Sstevel@tonic-gate if (qg->qg_numqueues == 0) 62107c478bd9Sstevel@tonic-gate { 62117c478bd9Sstevel@tonic-gate qg->qg_qpaths = (QPATHS *) xalloc(sizeof *qg->qg_qpaths); 62127c478bd9Sstevel@tonic-gate 62137c478bd9Sstevel@tonic-gate /* test path to get warning messages */ 62147c478bd9Sstevel@tonic-gate i = safedirpath(qpath, RunAsUid, RunAsGid, NULL, sff, 0, 0); 62157c478bd9Sstevel@tonic-gate if (i == ENOENT) 62167c478bd9Sstevel@tonic-gate { 62177c478bd9Sstevel@tonic-gate syserr("can not opendir(%s)", qpath); 62187c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 62197c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: opendir(\"%s\"): %s\n", 62207c478bd9Sstevel@tonic-gate qpath, sm_errstring(i)); 62217c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 62227c478bd9Sstevel@tonic-gate return qn; 62237c478bd9Sstevel@tonic-gate } 62247c478bd9Sstevel@tonic-gate 62257c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_subdirs = QP_NOSUB; 62267c478bd9Sstevel@tonic-gate qg->qg_numqueues = 1; 62277c478bd9Sstevel@tonic-gate 62287c478bd9Sstevel@tonic-gate /* check subdirs */ 62297c478bd9Sstevel@tonic-gate #define CHKSUBDIR(name, flag) \ 62307c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(subdir, sizeof subdir, 3, qg->qg_qdir, "/", name); \ 62317c478bd9Sstevel@tonic-gate if (chkqdir(subdir, sff)) \ 62327c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_subdirs |= flag; \ 62337c478bd9Sstevel@tonic-gate else 62347c478bd9Sstevel@tonic-gate 62357c478bd9Sstevel@tonic-gate CHKSUBDIR("qf", QP_SUBQF); 62367c478bd9Sstevel@tonic-gate CHKSUBDIR("df", QP_SUBDF); 62377c478bd9Sstevel@tonic-gate CHKSUBDIR("xf", QP_SUBXF); 62387c478bd9Sstevel@tonic-gate 62397c478bd9Sstevel@tonic-gate if (qg->qg_qdir[blen - 1] != '\0' && 62407c478bd9Sstevel@tonic-gate qg->qg_qdir[blen] != '\0') 62417c478bd9Sstevel@tonic-gate { 62427c478bd9Sstevel@tonic-gate /* 62437c478bd9Sstevel@tonic-gate ** Copy the last component into qpaths and 62447c478bd9Sstevel@tonic-gate ** cut off qdir 62457c478bd9Sstevel@tonic-gate */ 62467c478bd9Sstevel@tonic-gate 62477c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_name = newstr(qg->qg_qdir + blen); 62487c478bd9Sstevel@tonic-gate qg->qg_qdir[blen - 1] = '\0'; 62497c478bd9Sstevel@tonic-gate } 62507c478bd9Sstevel@tonic-gate else 62517c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_name = newstr("."); 62527c478bd9Sstevel@tonic-gate 62537c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 62547c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_idx = qn; 62557c478bd9Sstevel@tonic-gate *phash = hash_q(qg->qg_qpaths[0].qp_name, *phash); 62567c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 62577c478bd9Sstevel@tonic-gate ++qn; 62587c478bd9Sstevel@tonic-gate } 62597c478bd9Sstevel@tonic-gate return qn; 62607c478bd9Sstevel@tonic-gate } 62617c478bd9Sstevel@tonic-gate 62627c478bd9Sstevel@tonic-gate /* 62637c478bd9Sstevel@tonic-gate ** FILESYS_FIND -- find entry in FileSys table, or add new one 62647c478bd9Sstevel@tonic-gate ** 62657c478bd9Sstevel@tonic-gate ** Given the pathname of a directory, determine the file system 62667c478bd9Sstevel@tonic-gate ** in which that directory resides, and return a pointer to the 62677c478bd9Sstevel@tonic-gate ** entry in the FileSys table that describes the file system. 62687c478bd9Sstevel@tonic-gate ** A new entry is added if necessary (and requested). 62697c478bd9Sstevel@tonic-gate ** If the directory does not exist, -1 is returned. 62707c478bd9Sstevel@tonic-gate ** 62717c478bd9Sstevel@tonic-gate ** Parameters: 627249218d4fSjbeck ** name -- name of directory (must be persistent!) 627349218d4fSjbeck ** path -- pathname of directory (name plus maybe "/df") 62747c478bd9Sstevel@tonic-gate ** add -- add to structure if not found. 62757c478bd9Sstevel@tonic-gate ** 62767c478bd9Sstevel@tonic-gate ** Returns: 62777c478bd9Sstevel@tonic-gate ** >=0: found: index in file system table 62787c478bd9Sstevel@tonic-gate ** <0: some error, i.e., 62797c478bd9Sstevel@tonic-gate ** FSF_TOO_MANY: too many filesystems (-> syserr()) 62807c478bd9Sstevel@tonic-gate ** FSF_STAT_FAIL: can't stat() filesystem (-> syserr()) 62817c478bd9Sstevel@tonic-gate ** FSF_NOT_FOUND: not in list 62827c478bd9Sstevel@tonic-gate */ 62837c478bd9Sstevel@tonic-gate 628449218d4fSjbeck static short filesys_find __P((char *, char *, bool)); 62857c478bd9Sstevel@tonic-gate 62867c478bd9Sstevel@tonic-gate #define FSF_NOT_FOUND (-1) 62877c478bd9Sstevel@tonic-gate #define FSF_STAT_FAIL (-2) 62887c478bd9Sstevel@tonic-gate #define FSF_TOO_MANY (-3) 62897c478bd9Sstevel@tonic-gate 62907c478bd9Sstevel@tonic-gate static short 629149218d4fSjbeck filesys_find(name, path, add) 629249218d4fSjbeck char *name; 62937c478bd9Sstevel@tonic-gate char *path; 62947c478bd9Sstevel@tonic-gate bool add; 62957c478bd9Sstevel@tonic-gate { 62967c478bd9Sstevel@tonic-gate struct stat st; 62977c478bd9Sstevel@tonic-gate short i; 62987c478bd9Sstevel@tonic-gate 62997c478bd9Sstevel@tonic-gate if (stat(path, &st) < 0) 63007c478bd9Sstevel@tonic-gate { 63017c478bd9Sstevel@tonic-gate syserr("cannot stat queue directory %s", path); 63027c478bd9Sstevel@tonic-gate return FSF_STAT_FAIL; 63037c478bd9Sstevel@tonic-gate } 63047c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i) 63057c478bd9Sstevel@tonic-gate { 63067c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(i) == st.st_dev) 63077c478bd9Sstevel@tonic-gate return i; 63087c478bd9Sstevel@tonic-gate } 63097c478bd9Sstevel@tonic-gate if (i >= MAXFILESYS) 63107c478bd9Sstevel@tonic-gate { 63117c478bd9Sstevel@tonic-gate syserr("too many queue file systems (%d max)", MAXFILESYS); 63127c478bd9Sstevel@tonic-gate return FSF_TOO_MANY; 63137c478bd9Sstevel@tonic-gate } 63147c478bd9Sstevel@tonic-gate if (!add) 63157c478bd9Sstevel@tonic-gate return FSF_NOT_FOUND; 63167c478bd9Sstevel@tonic-gate 63177c478bd9Sstevel@tonic-gate ++NumFileSys; 631849218d4fSjbeck FILE_SYS_NAME(i) = name; 63197c478bd9Sstevel@tonic-gate FILE_SYS_DEV(i) = st.st_dev; 63207c478bd9Sstevel@tonic-gate FILE_SYS_AVAIL(i) = 0; 63217c478bd9Sstevel@tonic-gate FILE_SYS_BLKSIZE(i) = 1024; /* avoid divide by zero */ 63227c478bd9Sstevel@tonic-gate return i; 63237c478bd9Sstevel@tonic-gate } 63247c478bd9Sstevel@tonic-gate 63257c478bd9Sstevel@tonic-gate /* 63267c478bd9Sstevel@tonic-gate ** FILESYS_SETUP -- set up mapping from queue directories to file systems 63277c478bd9Sstevel@tonic-gate ** 63287c478bd9Sstevel@tonic-gate ** This data structure is used to efficiently check the amount of 63297c478bd9Sstevel@tonic-gate ** free space available in a set of queue directories. 63307c478bd9Sstevel@tonic-gate ** 63317c478bd9Sstevel@tonic-gate ** Parameters: 63327c478bd9Sstevel@tonic-gate ** add -- initialize structure if necessary. 63337c478bd9Sstevel@tonic-gate ** 63347c478bd9Sstevel@tonic-gate ** Returns: 63357c478bd9Sstevel@tonic-gate ** 0: success 63367c478bd9Sstevel@tonic-gate ** <0: some error, i.e., 63377c478bd9Sstevel@tonic-gate ** FSF_NOT_FOUND: not in list 63387c478bd9Sstevel@tonic-gate ** FSF_STAT_FAIL: can't stat() filesystem (-> syserr()) 63397c478bd9Sstevel@tonic-gate ** FSF_TOO_MANY: too many filesystems (-> syserr()) 63407c478bd9Sstevel@tonic-gate */ 63417c478bd9Sstevel@tonic-gate 63427c478bd9Sstevel@tonic-gate static int filesys_setup __P((bool)); 63437c478bd9Sstevel@tonic-gate 63447c478bd9Sstevel@tonic-gate static int 63457c478bd9Sstevel@tonic-gate filesys_setup(add) 63467c478bd9Sstevel@tonic-gate bool add; 63477c478bd9Sstevel@tonic-gate { 63487c478bd9Sstevel@tonic-gate int i, j; 63497c478bd9Sstevel@tonic-gate short fs; 63507c478bd9Sstevel@tonic-gate int ret; 63517c478bd9Sstevel@tonic-gate 63527c478bd9Sstevel@tonic-gate ret = 0; 63537c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 63547c478bd9Sstevel@tonic-gate { 63557c478bd9Sstevel@tonic-gate for (j = 0; j < Queue[i]->qg_numqueues; ++j) 63567c478bd9Sstevel@tonic-gate { 63577c478bd9Sstevel@tonic-gate QPATHS *qp = &Queue[i]->qg_qpaths[j]; 635849218d4fSjbeck char qddf[MAXPATHLEN]; 63597c478bd9Sstevel@tonic-gate 636049218d4fSjbeck (void) sm_strlcpyn(qddf, sizeof qddf, 2, qp->qp_name, 636149218d4fSjbeck (bitset(QP_SUBDF, qp->qp_subdirs) 636249218d4fSjbeck ? "/df" : "")); 636349218d4fSjbeck fs = filesys_find(qp->qp_name, qddf, add); 63647c478bd9Sstevel@tonic-gate if (fs >= 0) 63657c478bd9Sstevel@tonic-gate qp->qp_fsysidx = fs; 63667c478bd9Sstevel@tonic-gate else 63677c478bd9Sstevel@tonic-gate qp->qp_fsysidx = 0; 63687c478bd9Sstevel@tonic-gate if (fs < ret) 63697c478bd9Sstevel@tonic-gate ret = fs; 63707c478bd9Sstevel@tonic-gate } 63717c478bd9Sstevel@tonic-gate } 63727c478bd9Sstevel@tonic-gate return ret; 63737c478bd9Sstevel@tonic-gate } 63747c478bd9Sstevel@tonic-gate 63757c478bd9Sstevel@tonic-gate /* 63767c478bd9Sstevel@tonic-gate ** FILESYS_UPDATE -- update amount of free space on all file systems 63777c478bd9Sstevel@tonic-gate ** 63787c478bd9Sstevel@tonic-gate ** The FileSys table is used to cache the amount of free space 63797c478bd9Sstevel@tonic-gate ** available on all queue directory file systems. 63807c478bd9Sstevel@tonic-gate ** This function updates the cached information if it has expired. 63817c478bd9Sstevel@tonic-gate ** 63827c478bd9Sstevel@tonic-gate ** Parameters: 63837c478bd9Sstevel@tonic-gate ** none. 63847c478bd9Sstevel@tonic-gate ** 63857c478bd9Sstevel@tonic-gate ** Returns: 63867c478bd9Sstevel@tonic-gate ** none. 63877c478bd9Sstevel@tonic-gate ** 63887c478bd9Sstevel@tonic-gate ** Side Effects: 63897c478bd9Sstevel@tonic-gate ** Updates FileSys table. 63907c478bd9Sstevel@tonic-gate */ 63917c478bd9Sstevel@tonic-gate 63927c478bd9Sstevel@tonic-gate void 63937c478bd9Sstevel@tonic-gate filesys_update() 63947c478bd9Sstevel@tonic-gate { 63957c478bd9Sstevel@tonic-gate int i; 63967c478bd9Sstevel@tonic-gate long avail, blksize; 63977c478bd9Sstevel@tonic-gate time_t now; 63987c478bd9Sstevel@tonic-gate static time_t nextupdate = 0; 63997c478bd9Sstevel@tonic-gate 64007c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 64017c478bd9Sstevel@tonic-gate /* only the daemon updates this structure */ 64027c478bd9Sstevel@tonic-gate if (ShmId != SM_SHM_NO_ID && DaemonPid != CurrentPid) 64037c478bd9Sstevel@tonic-gate return; 64047c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 64057c478bd9Sstevel@tonic-gate now = curtime(); 64067c478bd9Sstevel@tonic-gate if (now < nextupdate) 64077c478bd9Sstevel@tonic-gate return; 64087c478bd9Sstevel@tonic-gate nextupdate = now + FILESYS_UPDATE_INTERVAL; 64097c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i) 64107c478bd9Sstevel@tonic-gate { 64117c478bd9Sstevel@tonic-gate FILESYS *fs = &FILE_SYS(i); 64127c478bd9Sstevel@tonic-gate 64137c478bd9Sstevel@tonic-gate avail = freediskspace(FILE_SYS_NAME(i), &blksize); 64147c478bd9Sstevel@tonic-gate if (avail < 0 || blksize <= 0) 64157c478bd9Sstevel@tonic-gate { 64167c478bd9Sstevel@tonic-gate if (LogLevel > 5) 64177c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 64187c478bd9Sstevel@tonic-gate "filesys_update failed: %s, fs=%s, avail=%ld, blocksize=%ld", 64197c478bd9Sstevel@tonic-gate sm_errstring(errno), 64207c478bd9Sstevel@tonic-gate FILE_SYS_NAME(i), avail, blksize); 64217c478bd9Sstevel@tonic-gate fs->fs_avail = 0; 64227c478bd9Sstevel@tonic-gate fs->fs_blksize = 1024; /* avoid divide by zero */ 64237c478bd9Sstevel@tonic-gate nextupdate = now + 2; /* let's do this soon again */ 64247c478bd9Sstevel@tonic-gate } 64257c478bd9Sstevel@tonic-gate else 64267c478bd9Sstevel@tonic-gate { 64277c478bd9Sstevel@tonic-gate fs->fs_avail = avail; 64287c478bd9Sstevel@tonic-gate fs->fs_blksize = blksize; 64297c478bd9Sstevel@tonic-gate } 64307c478bd9Sstevel@tonic-gate } 64317c478bd9Sstevel@tonic-gate } 64327c478bd9Sstevel@tonic-gate 64337c478bd9Sstevel@tonic-gate #if _FFR_ANY_FREE_FS 64347c478bd9Sstevel@tonic-gate /* 64357c478bd9Sstevel@tonic-gate ** FILESYS_FREE -- check whether there is at least one fs with enough space. 64367c478bd9Sstevel@tonic-gate ** 64377c478bd9Sstevel@tonic-gate ** Parameters: 64387c478bd9Sstevel@tonic-gate ** fsize -- file size in bytes 64397c478bd9Sstevel@tonic-gate ** 64407c478bd9Sstevel@tonic-gate ** Returns: 64417c478bd9Sstevel@tonic-gate ** true iff there is one fs with more than fsize bytes free. 64427c478bd9Sstevel@tonic-gate */ 64437c478bd9Sstevel@tonic-gate 64447c478bd9Sstevel@tonic-gate bool 64457c478bd9Sstevel@tonic-gate filesys_free(fsize) 64467c478bd9Sstevel@tonic-gate long fsize; 64477c478bd9Sstevel@tonic-gate { 64487c478bd9Sstevel@tonic-gate int i; 64497c478bd9Sstevel@tonic-gate 64507c478bd9Sstevel@tonic-gate if (fsize <= 0) 64517c478bd9Sstevel@tonic-gate return true; 64527c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i) 64537c478bd9Sstevel@tonic-gate { 64547c478bd9Sstevel@tonic-gate long needed = 0; 64557c478bd9Sstevel@tonic-gate 64567c478bd9Sstevel@tonic-gate if (FILE_SYS_AVAIL(i) < 0 || FILE_SYS_BLKSIZE(i) <= 0) 64577c478bd9Sstevel@tonic-gate continue; 64587c478bd9Sstevel@tonic-gate needed += fsize / FILE_SYS_BLKSIZE(i) 64597c478bd9Sstevel@tonic-gate + ((fsize % FILE_SYS_BLKSIZE(i) 64607c478bd9Sstevel@tonic-gate > 0) ? 1 : 0) 64617c478bd9Sstevel@tonic-gate + MinBlocksFree; 64627c478bd9Sstevel@tonic-gate if (needed <= FILE_SYS_AVAIL(i)) 64637c478bd9Sstevel@tonic-gate return true; 64647c478bd9Sstevel@tonic-gate } 64657c478bd9Sstevel@tonic-gate return false; 64667c478bd9Sstevel@tonic-gate } 64677c478bd9Sstevel@tonic-gate #endif /* _FFR_ANY_FREE_FS */ 64687c478bd9Sstevel@tonic-gate 64697c478bd9Sstevel@tonic-gate #if _FFR_CONTROL_MSTAT 64707c478bd9Sstevel@tonic-gate /* 64717c478bd9Sstevel@tonic-gate ** DISK_STATUS -- show amount of free space in queue directories 64727c478bd9Sstevel@tonic-gate ** 64737c478bd9Sstevel@tonic-gate ** Parameters: 64747c478bd9Sstevel@tonic-gate ** out -- output file pointer. 64757c478bd9Sstevel@tonic-gate ** prefix -- string to output in front of each line. 64767c478bd9Sstevel@tonic-gate ** 64777c478bd9Sstevel@tonic-gate ** Returns: 64787c478bd9Sstevel@tonic-gate ** none. 64797c478bd9Sstevel@tonic-gate */ 64807c478bd9Sstevel@tonic-gate 64817c478bd9Sstevel@tonic-gate void 64827c478bd9Sstevel@tonic-gate disk_status(out, prefix) 64837c478bd9Sstevel@tonic-gate SM_FILE_T *out; 64847c478bd9Sstevel@tonic-gate char *prefix; 64857c478bd9Sstevel@tonic-gate { 64867c478bd9Sstevel@tonic-gate int i; 64877c478bd9Sstevel@tonic-gate long avail, blksize; 64887c478bd9Sstevel@tonic-gate long free; 64897c478bd9Sstevel@tonic-gate 64907c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i) 64917c478bd9Sstevel@tonic-gate { 64927c478bd9Sstevel@tonic-gate avail = freediskspace(FILE_SYS_NAME(i), &blksize); 64937c478bd9Sstevel@tonic-gate if (avail >= 0 && blksize > 0) 64947c478bd9Sstevel@tonic-gate { 64957c478bd9Sstevel@tonic-gate free = (long)((double) avail * 64967c478bd9Sstevel@tonic-gate ((double) blksize / 1024)); 64977c478bd9Sstevel@tonic-gate } 64987c478bd9Sstevel@tonic-gate else 64997c478bd9Sstevel@tonic-gate free = -1; 65007c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 65017c478bd9Sstevel@tonic-gate "%s%d/%s/%ld\r\n", 65027c478bd9Sstevel@tonic-gate prefix, i, 65037c478bd9Sstevel@tonic-gate FILE_SYS_NAME(i), 65047c478bd9Sstevel@tonic-gate free); 65057c478bd9Sstevel@tonic-gate } 65067c478bd9Sstevel@tonic-gate } 65077c478bd9Sstevel@tonic-gate #endif /* _FFR_CONTROL_MSTAT */ 65087c478bd9Sstevel@tonic-gate 65097c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 65107c478bd9Sstevel@tonic-gate 65117c478bd9Sstevel@tonic-gate /* 65127c478bd9Sstevel@tonic-gate ** INIT_SEM -- initialize semaphore system 65137c478bd9Sstevel@tonic-gate ** 65147c478bd9Sstevel@tonic-gate ** Parameters: 65157c478bd9Sstevel@tonic-gate ** owner -- is this the owner of semaphores? 65167c478bd9Sstevel@tonic-gate ** 65177c478bd9Sstevel@tonic-gate ** Returns: 65187c478bd9Sstevel@tonic-gate ** none. 65197c478bd9Sstevel@tonic-gate */ 65207c478bd9Sstevel@tonic-gate 65217c478bd9Sstevel@tonic-gate #if _FFR_USE_SEM_LOCKING 65227c478bd9Sstevel@tonic-gate #if SM_CONF_SEM 65237c478bd9Sstevel@tonic-gate static int SemId = -1; /* Semaphore Id */ 65247c478bd9Sstevel@tonic-gate int SemKey = SM_SEM_KEY; 65257c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SEM */ 65267c478bd9Sstevel@tonic-gate #endif /* _FFR_USE_SEM_LOCKING */ 65277c478bd9Sstevel@tonic-gate 65287c478bd9Sstevel@tonic-gate static void init_sem __P((bool)); 65297c478bd9Sstevel@tonic-gate 65307c478bd9Sstevel@tonic-gate static void 65317c478bd9Sstevel@tonic-gate init_sem(owner) 65327c478bd9Sstevel@tonic-gate bool owner; 65337c478bd9Sstevel@tonic-gate { 65347c478bd9Sstevel@tonic-gate #if _FFR_USE_SEM_LOCKING 65357c478bd9Sstevel@tonic-gate #if SM_CONF_SEM 65367c478bd9Sstevel@tonic-gate SemId = sm_sem_start(SemKey, 1, 0, owner); 65377c478bd9Sstevel@tonic-gate if (SemId < 0) 65387c478bd9Sstevel@tonic-gate { 65397c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 65407c478bd9Sstevel@tonic-gate "func=init_sem, sem_key=%ld, sm_sem_start=%d", 65417c478bd9Sstevel@tonic-gate (long) SemKey, SemId); 65427c478bd9Sstevel@tonic-gate return; 65437c478bd9Sstevel@tonic-gate } 65447c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SEM */ 65457c478bd9Sstevel@tonic-gate #endif /* _FFR_USE_SEM_LOCKING */ 65467c478bd9Sstevel@tonic-gate return; 65477c478bd9Sstevel@tonic-gate } 65487c478bd9Sstevel@tonic-gate 65497c478bd9Sstevel@tonic-gate /* 65507c478bd9Sstevel@tonic-gate ** STOP_SEM -- stop semaphore system 65517c478bd9Sstevel@tonic-gate ** 65527c478bd9Sstevel@tonic-gate ** Parameters: 65537c478bd9Sstevel@tonic-gate ** owner -- is this the owner of semaphores? 65547c478bd9Sstevel@tonic-gate ** 65557c478bd9Sstevel@tonic-gate ** Returns: 65567c478bd9Sstevel@tonic-gate ** none. 65577c478bd9Sstevel@tonic-gate */ 65587c478bd9Sstevel@tonic-gate 65597c478bd9Sstevel@tonic-gate static void stop_sem __P((bool)); 65607c478bd9Sstevel@tonic-gate 65617c478bd9Sstevel@tonic-gate static void 65627c478bd9Sstevel@tonic-gate stop_sem(owner) 65637c478bd9Sstevel@tonic-gate bool owner; 65647c478bd9Sstevel@tonic-gate { 65657c478bd9Sstevel@tonic-gate #if _FFR_USE_SEM_LOCKING 65667c478bd9Sstevel@tonic-gate #if SM_CONF_SEM 65677c478bd9Sstevel@tonic-gate if (owner && SemId >= 0) 65687c478bd9Sstevel@tonic-gate sm_sem_stop(SemId); 65697c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SEM */ 65707c478bd9Sstevel@tonic-gate #endif /* _FFR_USE_SEM_LOCKING */ 65717c478bd9Sstevel@tonic-gate return; 65727c478bd9Sstevel@tonic-gate } 65737c478bd9Sstevel@tonic-gate 65747c478bd9Sstevel@tonic-gate /* 65757c478bd9Sstevel@tonic-gate ** UPD_QS -- update information about queue when adding/deleting an entry 65767c478bd9Sstevel@tonic-gate ** 65777c478bd9Sstevel@tonic-gate ** Parameters: 65787c478bd9Sstevel@tonic-gate ** e -- envelope. 65797c478bd9Sstevel@tonic-gate ** count -- add/remove entry (+1/0/-1: add/no change/remove) 65807c478bd9Sstevel@tonic-gate ** space -- update the space available as well. 65817c478bd9Sstevel@tonic-gate ** (>0/0/<0: add/no change/remove) 65827c478bd9Sstevel@tonic-gate ** where -- caller (for logging) 65837c478bd9Sstevel@tonic-gate ** 65847c478bd9Sstevel@tonic-gate ** Returns: 65857c478bd9Sstevel@tonic-gate ** none. 65867c478bd9Sstevel@tonic-gate ** 65877c478bd9Sstevel@tonic-gate ** Side Effects: 65887c478bd9Sstevel@tonic-gate ** Modifies available space in filesystem. 65897c478bd9Sstevel@tonic-gate ** Changes number of entries in queue directory. 65907c478bd9Sstevel@tonic-gate */ 65917c478bd9Sstevel@tonic-gate 65927c478bd9Sstevel@tonic-gate void 65937c478bd9Sstevel@tonic-gate upd_qs(e, count, space, where) 65947c478bd9Sstevel@tonic-gate ENVELOPE *e; 65957c478bd9Sstevel@tonic-gate int count; 65967c478bd9Sstevel@tonic-gate int space; 65977c478bd9Sstevel@tonic-gate char *where; 65987c478bd9Sstevel@tonic-gate { 65997c478bd9Sstevel@tonic-gate short fidx; 66007c478bd9Sstevel@tonic-gate int idx; 66017c478bd9Sstevel@tonic-gate # if _FFR_USE_SEM_LOCKING 66027c478bd9Sstevel@tonic-gate int r; 66037c478bd9Sstevel@tonic-gate # endif /* _FFR_USE_SEM_LOCKING */ 66047c478bd9Sstevel@tonic-gate long s; 66057c478bd9Sstevel@tonic-gate 66067c478bd9Sstevel@tonic-gate if (ShmId == SM_SHM_NO_ID || e == NULL) 66077c478bd9Sstevel@tonic-gate return; 66087c478bd9Sstevel@tonic-gate if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR) 66097c478bd9Sstevel@tonic-gate return; 66107c478bd9Sstevel@tonic-gate idx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_idx; 66117c478bd9Sstevel@tonic-gate if (tTd(73,2)) 66127c478bd9Sstevel@tonic-gate sm_dprintf("func=upd_qs, count=%d, space=%d, where=%s, idx=%d, entries=%d\n", 66137c478bd9Sstevel@tonic-gate count, space, where, idx, QSHM_ENTRIES(idx)); 66147c478bd9Sstevel@tonic-gate 66157c478bd9Sstevel@tonic-gate /* XXX in theory this needs to be protected with a mutex */ 66167c478bd9Sstevel@tonic-gate if (QSHM_ENTRIES(idx) >= 0 && count != 0) 66177c478bd9Sstevel@tonic-gate { 66187c478bd9Sstevel@tonic-gate # if _FFR_USE_SEM_LOCKING 66197c478bd9Sstevel@tonic-gate r = sm_sem_acq(SemId, 0, 1); 66207c478bd9Sstevel@tonic-gate # endif /* _FFR_USE_SEM_LOCKING */ 66217c478bd9Sstevel@tonic-gate QSHM_ENTRIES(idx) += count; 66227c478bd9Sstevel@tonic-gate # if _FFR_USE_SEM_LOCKING 66237c478bd9Sstevel@tonic-gate if (r >= 0) 66247c478bd9Sstevel@tonic-gate r = sm_sem_rel(SemId, 0, 1); 66257c478bd9Sstevel@tonic-gate # endif /* _FFR_USE_SEM_LOCKING */ 66267c478bd9Sstevel@tonic-gate } 66277c478bd9Sstevel@tonic-gate 66287c478bd9Sstevel@tonic-gate fidx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_fsysidx; 66297c478bd9Sstevel@tonic-gate if (fidx < 0) 66307c478bd9Sstevel@tonic-gate return; 66317c478bd9Sstevel@tonic-gate 66327c478bd9Sstevel@tonic-gate /* update available space also? (might be loseqfile) */ 66337c478bd9Sstevel@tonic-gate if (space == 0) 66347c478bd9Sstevel@tonic-gate return; 66357c478bd9Sstevel@tonic-gate 66367c478bd9Sstevel@tonic-gate /* convert size to blocks; this causes rounding errors */ 66377c478bd9Sstevel@tonic-gate s = e->e_msgsize / FILE_SYS_BLKSIZE(fidx); 66387c478bd9Sstevel@tonic-gate if (s == 0) 66397c478bd9Sstevel@tonic-gate return; 66407c478bd9Sstevel@tonic-gate 66417c478bd9Sstevel@tonic-gate /* XXX in theory this needs to be protected with a mutex */ 66427c478bd9Sstevel@tonic-gate if (space > 0) 66437c478bd9Sstevel@tonic-gate FILE_SYS_AVAIL(fidx) += s; 66447c478bd9Sstevel@tonic-gate else 66457c478bd9Sstevel@tonic-gate FILE_SYS_AVAIL(fidx) -= s; 66467c478bd9Sstevel@tonic-gate 66477c478bd9Sstevel@tonic-gate } 66487c478bd9Sstevel@tonic-gate 66497c478bd9Sstevel@tonic-gate #if _FFR_SELECT_SHM 66507c478bd9Sstevel@tonic-gate 66517c478bd9Sstevel@tonic-gate static bool write_key_file __P((char *, long)); 66527c478bd9Sstevel@tonic-gate static long read_key_file __P((char *, long)); 66537c478bd9Sstevel@tonic-gate 66547c478bd9Sstevel@tonic-gate /* 66557c478bd9Sstevel@tonic-gate ** WRITE_KEY_FILE -- record some key into a file. 66567c478bd9Sstevel@tonic-gate ** 66577c478bd9Sstevel@tonic-gate ** Parameters: 66587c478bd9Sstevel@tonic-gate ** keypath -- file name. 66597c478bd9Sstevel@tonic-gate ** key -- key to write. 66607c478bd9Sstevel@tonic-gate ** 66617c478bd9Sstevel@tonic-gate ** Returns: 66627c478bd9Sstevel@tonic-gate ** true iff file could be written. 66637c478bd9Sstevel@tonic-gate ** 66647c478bd9Sstevel@tonic-gate ** Side Effects: 66657c478bd9Sstevel@tonic-gate ** writes file. 66667c478bd9Sstevel@tonic-gate */ 66677c478bd9Sstevel@tonic-gate 66687c478bd9Sstevel@tonic-gate static bool 66697c478bd9Sstevel@tonic-gate write_key_file(keypath, key) 66707c478bd9Sstevel@tonic-gate char *keypath; 66717c478bd9Sstevel@tonic-gate long key; 66727c478bd9Sstevel@tonic-gate { 66737c478bd9Sstevel@tonic-gate bool ok; 66747c478bd9Sstevel@tonic-gate long sff; 66757c478bd9Sstevel@tonic-gate SM_FILE_T *keyf; 66767c478bd9Sstevel@tonic-gate 66777c478bd9Sstevel@tonic-gate ok = false; 66787c478bd9Sstevel@tonic-gate if (keypath == NULL || *keypath == '\0') 66797c478bd9Sstevel@tonic-gate return ok; 66807c478bd9Sstevel@tonic-gate sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT; 66817c478bd9Sstevel@tonic-gate if (TrustedUid != 0 && RealUid == TrustedUid) 66827c478bd9Sstevel@tonic-gate sff |= SFF_OPENASROOT; 66837c478bd9Sstevel@tonic-gate keyf = safefopen(keypath, O_WRONLY|O_TRUNC, FileMode, sff); 66847c478bd9Sstevel@tonic-gate if (keyf == NULL) 66857c478bd9Sstevel@tonic-gate { 66867c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, "unable to write %s: %s", 66877c478bd9Sstevel@tonic-gate keypath, sm_errstring(errno)); 66887c478bd9Sstevel@tonic-gate } 66897c478bd9Sstevel@tonic-gate else 66907c478bd9Sstevel@tonic-gate { 669149218d4fSjbeck if (geteuid() == 0 && RunAsUid != 0) 669249218d4fSjbeck { 669349218d4fSjbeck # if HASFCHOWN 669449218d4fSjbeck int fd; 669549218d4fSjbeck 669649218d4fSjbeck fd = keyf->f_file; 669749218d4fSjbeck if (fd >= 0 && fchown(fd, RunAsUid, -1) < 0) 669849218d4fSjbeck { 669949218d4fSjbeck int err = errno; 670049218d4fSjbeck 670149218d4fSjbeck sm_syslog(LOG_ALERT, NOQID, 670249218d4fSjbeck "ownership change on %s to %d failed: %s", 670349218d4fSjbeck keypath, RunAsUid, sm_errstring(err)); 670449218d4fSjbeck } 670549218d4fSjbeck # endif /* HASFCHOWN */ 670649218d4fSjbeck } 67077c478bd9Sstevel@tonic-gate ok = sm_io_fprintf(keyf, SM_TIME_DEFAULT, "%ld\n", key) != 67087c478bd9Sstevel@tonic-gate SM_IO_EOF; 67097c478bd9Sstevel@tonic-gate ok = (sm_io_close(keyf, SM_TIME_DEFAULT) != SM_IO_EOF) && ok; 67107c478bd9Sstevel@tonic-gate } 67117c478bd9Sstevel@tonic-gate return ok; 67127c478bd9Sstevel@tonic-gate } 67137c478bd9Sstevel@tonic-gate 67147c478bd9Sstevel@tonic-gate /* 67157c478bd9Sstevel@tonic-gate ** READ_KEY_FILE -- read a key from a file. 67167c478bd9Sstevel@tonic-gate ** 67177c478bd9Sstevel@tonic-gate ** Parameters: 67187c478bd9Sstevel@tonic-gate ** keypath -- file name. 67197c478bd9Sstevel@tonic-gate ** key -- default key. 67207c478bd9Sstevel@tonic-gate ** 67217c478bd9Sstevel@tonic-gate ** Returns: 67227c478bd9Sstevel@tonic-gate ** key. 67237c478bd9Sstevel@tonic-gate */ 67247c478bd9Sstevel@tonic-gate 67257c478bd9Sstevel@tonic-gate static long 67267c478bd9Sstevel@tonic-gate read_key_file(keypath, key) 67277c478bd9Sstevel@tonic-gate char *keypath; 67287c478bd9Sstevel@tonic-gate long key; 67297c478bd9Sstevel@tonic-gate { 67307c478bd9Sstevel@tonic-gate int r; 67317c478bd9Sstevel@tonic-gate long sff, n; 67327c478bd9Sstevel@tonic-gate SM_FILE_T *keyf; 67337c478bd9Sstevel@tonic-gate 67347c478bd9Sstevel@tonic-gate if (keypath == NULL || *keypath == '\0') 67357c478bd9Sstevel@tonic-gate return key; 67367c478bd9Sstevel@tonic-gate sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY; 67377c478bd9Sstevel@tonic-gate if (RealUid == 0 || (TrustedUid != 0 && RealUid == TrustedUid)) 67387c478bd9Sstevel@tonic-gate sff |= SFF_OPENASROOT; 67397c478bd9Sstevel@tonic-gate keyf = safefopen(keypath, O_RDONLY, FileMode, sff); 67407c478bd9Sstevel@tonic-gate if (keyf == NULL) 67417c478bd9Sstevel@tonic-gate { 67427c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, "unable to read %s: %s", 67437c478bd9Sstevel@tonic-gate keypath, sm_errstring(errno)); 67447c478bd9Sstevel@tonic-gate } 67457c478bd9Sstevel@tonic-gate else 67467c478bd9Sstevel@tonic-gate { 67477c478bd9Sstevel@tonic-gate r = sm_io_fscanf(keyf, SM_TIME_DEFAULT, "%ld", &n); 67487c478bd9Sstevel@tonic-gate if (r == 1) 67497c478bd9Sstevel@tonic-gate key = n; 67507c478bd9Sstevel@tonic-gate (void) sm_io_close(keyf, SM_TIME_DEFAULT); 67517c478bd9Sstevel@tonic-gate } 67527c478bd9Sstevel@tonic-gate return key; 67537c478bd9Sstevel@tonic-gate } 67547c478bd9Sstevel@tonic-gate #endif /* _FFR_SELECT_SHM */ 67557c478bd9Sstevel@tonic-gate 67567c478bd9Sstevel@tonic-gate /* 67577c478bd9Sstevel@tonic-gate ** INIT_SHM -- initialize shared memory structure 67587c478bd9Sstevel@tonic-gate ** 67597c478bd9Sstevel@tonic-gate ** Initialize or attach to shared memory segment. 67607c478bd9Sstevel@tonic-gate ** Currently it is not a fatal error if this doesn't work. 67617c478bd9Sstevel@tonic-gate ** However, it causes us to have a "fallback" storage location 67627c478bd9Sstevel@tonic-gate ** for everything that is supposed to be in the shared memory, 67637c478bd9Sstevel@tonic-gate ** which makes the code slightly ugly. 67647c478bd9Sstevel@tonic-gate ** 67657c478bd9Sstevel@tonic-gate ** Parameters: 67667c478bd9Sstevel@tonic-gate ** qn -- number of queue directories. 67677c478bd9Sstevel@tonic-gate ** owner -- owner of shared memory. 67687c478bd9Sstevel@tonic-gate ** hash -- identifies data that is stored in shared memory. 67697c478bd9Sstevel@tonic-gate ** 67707c478bd9Sstevel@tonic-gate ** Returns: 67717c478bd9Sstevel@tonic-gate ** none. 67727c478bd9Sstevel@tonic-gate */ 67737c478bd9Sstevel@tonic-gate 67747c478bd9Sstevel@tonic-gate static void init_shm __P((int, bool, unsigned int)); 67757c478bd9Sstevel@tonic-gate 67767c478bd9Sstevel@tonic-gate static void 67777c478bd9Sstevel@tonic-gate init_shm(qn, owner, hash) 67787c478bd9Sstevel@tonic-gate int qn; 67797c478bd9Sstevel@tonic-gate bool owner; 67807c478bd9Sstevel@tonic-gate unsigned int hash; 67817c478bd9Sstevel@tonic-gate { 67827c478bd9Sstevel@tonic-gate int i; 67837c478bd9Sstevel@tonic-gate int count; 67847c478bd9Sstevel@tonic-gate int save_errno; 67857c478bd9Sstevel@tonic-gate #if _FFR_SELECT_SHM 67867c478bd9Sstevel@tonic-gate bool keyselect; 67877c478bd9Sstevel@tonic-gate #endif /* _FFR_SELECT_SHM */ 67887c478bd9Sstevel@tonic-gate 67897c478bd9Sstevel@tonic-gate PtrFileSys = &FileSys[0]; 67907c478bd9Sstevel@tonic-gate PNumFileSys = &Numfilesys; 67917c478bd9Sstevel@tonic-gate #if _FFR_SELECT_SHM 67927c478bd9Sstevel@tonic-gate /* if this "key" is specified: select one yourself */ 67937c478bd9Sstevel@tonic-gate # define SEL_SHM_KEY ((key_t) -1) 67947c478bd9Sstevel@tonic-gate # define FIRST_SHM_KEY 25 67957c478bd9Sstevel@tonic-gate #endif /* _FFR_SELECT_SHM */ 67967c478bd9Sstevel@tonic-gate 67977c478bd9Sstevel@tonic-gate /* This allows us to disable shared memory at runtime. */ 67987c478bd9Sstevel@tonic-gate if (ShmKey == 0) 67997c478bd9Sstevel@tonic-gate return; 68007c478bd9Sstevel@tonic-gate 68017c478bd9Sstevel@tonic-gate count = 0; 68027c478bd9Sstevel@tonic-gate shms = SM_T_SIZE + qn * sizeof(QUEUE_SHM_T); 68037c478bd9Sstevel@tonic-gate #if _FFR_SELECT_SHM 68047c478bd9Sstevel@tonic-gate keyselect = ShmKey == SEL_SHM_KEY; 68057c478bd9Sstevel@tonic-gate if (keyselect) 68067c478bd9Sstevel@tonic-gate { 68077c478bd9Sstevel@tonic-gate if (owner) 68087c478bd9Sstevel@tonic-gate ShmKey = FIRST_SHM_KEY; 68097c478bd9Sstevel@tonic-gate else 68107c478bd9Sstevel@tonic-gate { 68117c478bd9Sstevel@tonic-gate ShmKey = read_key_file(ShmKeyFile, ShmKey); 68127c478bd9Sstevel@tonic-gate keyselect = false; 68137c478bd9Sstevel@tonic-gate if (ShmKey == SEL_SHM_KEY) 68147c478bd9Sstevel@tonic-gate goto error; 68157c478bd9Sstevel@tonic-gate } 68167c478bd9Sstevel@tonic-gate } 68177c478bd9Sstevel@tonic-gate #endif /* _FFR_SELECT_SHM */ 68187c478bd9Sstevel@tonic-gate for (;;) 68197c478bd9Sstevel@tonic-gate { 68207c478bd9Sstevel@tonic-gate /* allow read/write access for group? */ 68217c478bd9Sstevel@tonic-gate Pshm = sm_shmstart(ShmKey, shms, 68227c478bd9Sstevel@tonic-gate SHM_R|SHM_W|(SHM_R>>3)|(SHM_W>>3), 68237c478bd9Sstevel@tonic-gate &ShmId, owner); 68247c478bd9Sstevel@tonic-gate save_errno = errno; 68257c478bd9Sstevel@tonic-gate if (Pshm != NULL || !sm_file_exists(save_errno)) 68267c478bd9Sstevel@tonic-gate break; 68277c478bd9Sstevel@tonic-gate if (++count >= 3) 68287c478bd9Sstevel@tonic-gate { 68297c478bd9Sstevel@tonic-gate #if _FFR_SELECT_SHM 68307c478bd9Sstevel@tonic-gate if (keyselect) 68317c478bd9Sstevel@tonic-gate { 68327c478bd9Sstevel@tonic-gate ++ShmKey; 68337c478bd9Sstevel@tonic-gate 68347c478bd9Sstevel@tonic-gate /* back where we started? */ 68357c478bd9Sstevel@tonic-gate if (ShmKey == SEL_SHM_KEY) 68367c478bd9Sstevel@tonic-gate break; 68377c478bd9Sstevel@tonic-gate continue; 68387c478bd9Sstevel@tonic-gate } 68397c478bd9Sstevel@tonic-gate #endif /* _FFR_SELECT_SHM */ 68407c478bd9Sstevel@tonic-gate break; 68417c478bd9Sstevel@tonic-gate } 68427c478bd9Sstevel@tonic-gate #if _FFR_SELECT_SHM 68437c478bd9Sstevel@tonic-gate /* only sleep if we are at the first key */ 68447c478bd9Sstevel@tonic-gate if (!keyselect || ShmKey == SEL_SHM_KEY) 68457c478bd9Sstevel@tonic-gate #endif /* _FFR_SELECT_SHM */ 68467c478bd9Sstevel@tonic-gate sleep(count); 68477c478bd9Sstevel@tonic-gate } 68487c478bd9Sstevel@tonic-gate if (Pshm != NULL) 68497c478bd9Sstevel@tonic-gate { 68507c478bd9Sstevel@tonic-gate int *p; 68517c478bd9Sstevel@tonic-gate 68527c478bd9Sstevel@tonic-gate #if _FFR_SELECT_SHM 68537c478bd9Sstevel@tonic-gate if (keyselect) 68547c478bd9Sstevel@tonic-gate (void) write_key_file(ShmKeyFile, (long) ShmKey); 68557c478bd9Sstevel@tonic-gate #endif /* _FFR_SELECT_SHM */ 68567c478bd9Sstevel@tonic-gate if (owner && RunAsUid != 0) 68577c478bd9Sstevel@tonic-gate { 6858*445f2479Sjbeck i = sm_shmsetowner(ShmId, RunAsUid, RunAsGid, 0660); 68597c478bd9Sstevel@tonic-gate if (i != 0) 68607c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 68617c478bd9Sstevel@tonic-gate "key=%ld, sm_shmsetowner=%d, RunAsUid=%d, RunAsGid=%d", 6862*445f2479Sjbeck (long) ShmKey, i, RunAsUid, RunAsGid); 68637c478bd9Sstevel@tonic-gate } 68647c478bd9Sstevel@tonic-gate p = (int *) Pshm; 68657c478bd9Sstevel@tonic-gate if (owner) 68667c478bd9Sstevel@tonic-gate { 68677c478bd9Sstevel@tonic-gate *p = (int) shms; 68687c478bd9Sstevel@tonic-gate *((pid_t *) SHM_OFF_PID(Pshm)) = CurrentPid; 68697c478bd9Sstevel@tonic-gate p = (int *) SHM_OFF_TAG(Pshm); 68707c478bd9Sstevel@tonic-gate *p = hash; 68717c478bd9Sstevel@tonic-gate } 68727c478bd9Sstevel@tonic-gate else 68737c478bd9Sstevel@tonic-gate { 68747c478bd9Sstevel@tonic-gate if (*p != (int) shms) 68757c478bd9Sstevel@tonic-gate { 68767c478bd9Sstevel@tonic-gate save_errno = EINVAL; 68777c478bd9Sstevel@tonic-gate cleanup_shm(false); 68787c478bd9Sstevel@tonic-gate goto error; 68797c478bd9Sstevel@tonic-gate } 68807c478bd9Sstevel@tonic-gate p = (int *) SHM_OFF_TAG(Pshm); 68817c478bd9Sstevel@tonic-gate if (*p != (int) hash) 68827c478bd9Sstevel@tonic-gate { 68837c478bd9Sstevel@tonic-gate save_errno = EINVAL; 68847c478bd9Sstevel@tonic-gate cleanup_shm(false); 68857c478bd9Sstevel@tonic-gate goto error; 68867c478bd9Sstevel@tonic-gate } 68877c478bd9Sstevel@tonic-gate 68887c478bd9Sstevel@tonic-gate /* 68897c478bd9Sstevel@tonic-gate ** XXX how to check the pid? 68907c478bd9Sstevel@tonic-gate ** Read it from the pid-file? That does 68917c478bd9Sstevel@tonic-gate ** not need to exist. 68927c478bd9Sstevel@tonic-gate ** We could disable shm if we can't confirm 68937c478bd9Sstevel@tonic-gate ** that it is the right one. 68947c478bd9Sstevel@tonic-gate */ 68957c478bd9Sstevel@tonic-gate } 68967c478bd9Sstevel@tonic-gate 68977c478bd9Sstevel@tonic-gate PtrFileSys = (FILESYS *) OFF_FILE_SYS(Pshm); 68987c478bd9Sstevel@tonic-gate PNumFileSys = (int *) OFF_NUM_FILE_SYS(Pshm); 68997c478bd9Sstevel@tonic-gate QShm = (QUEUE_SHM_T *) OFF_QUEUE_SHM(Pshm); 69007c478bd9Sstevel@tonic-gate PRSATmpCnt = (int *) OFF_RSA_TMP_CNT(Pshm); 69017c478bd9Sstevel@tonic-gate *PRSATmpCnt = 0; 69027c478bd9Sstevel@tonic-gate if (owner) 69037c478bd9Sstevel@tonic-gate { 69047c478bd9Sstevel@tonic-gate /* initialize values in shared memory */ 69057c478bd9Sstevel@tonic-gate NumFileSys = 0; 69067c478bd9Sstevel@tonic-gate for (i = 0; i < qn; i++) 69077c478bd9Sstevel@tonic-gate QShm[i].qs_entries = -1; 69087c478bd9Sstevel@tonic-gate } 69097c478bd9Sstevel@tonic-gate init_sem(owner); 69107c478bd9Sstevel@tonic-gate return; 69117c478bd9Sstevel@tonic-gate } 69127c478bd9Sstevel@tonic-gate error: 69137c478bd9Sstevel@tonic-gate if (LogLevel > (owner ? 8 : 11)) 69147c478bd9Sstevel@tonic-gate { 69157c478bd9Sstevel@tonic-gate sm_syslog(owner ? LOG_ERR : LOG_NOTICE, NOQID, 69167c478bd9Sstevel@tonic-gate "can't %s shared memory, key=%ld: %s", 69177c478bd9Sstevel@tonic-gate owner ? "initialize" : "attach to", 69187c478bd9Sstevel@tonic-gate (long) ShmKey, sm_errstring(save_errno)); 69197c478bd9Sstevel@tonic-gate } 69207c478bd9Sstevel@tonic-gate } 69217c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 69227c478bd9Sstevel@tonic-gate 69237c478bd9Sstevel@tonic-gate 69247c478bd9Sstevel@tonic-gate /* 69257c478bd9Sstevel@tonic-gate ** SETUP_QUEUES -- setup all queue groups 69267c478bd9Sstevel@tonic-gate ** 69277c478bd9Sstevel@tonic-gate ** Parameters: 69287c478bd9Sstevel@tonic-gate ** owner -- owner of shared memory. 69297c478bd9Sstevel@tonic-gate ** 69307c478bd9Sstevel@tonic-gate ** Returns: 69317c478bd9Sstevel@tonic-gate ** none. 69327c478bd9Sstevel@tonic-gate ** 69337c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 69347c478bd9Sstevel@tonic-gate ** Side Effects: 69357c478bd9Sstevel@tonic-gate ** attaches shared memory. 69367c478bd9Sstevel@tonic-gate #endif * SM_CONF_SHM * 69377c478bd9Sstevel@tonic-gate */ 69387c478bd9Sstevel@tonic-gate 69397c478bd9Sstevel@tonic-gate void 69407c478bd9Sstevel@tonic-gate setup_queues(owner) 69417c478bd9Sstevel@tonic-gate bool owner; 69427c478bd9Sstevel@tonic-gate { 69437c478bd9Sstevel@tonic-gate int i, qn, len; 69447c478bd9Sstevel@tonic-gate unsigned int hashval; 69457c478bd9Sstevel@tonic-gate time_t now; 69467c478bd9Sstevel@tonic-gate char basedir[MAXPATHLEN]; 69477c478bd9Sstevel@tonic-gate struct stat st; 69487c478bd9Sstevel@tonic-gate 69497c478bd9Sstevel@tonic-gate /* 69507c478bd9Sstevel@tonic-gate ** Determine basedir for all queue directories. 69517c478bd9Sstevel@tonic-gate ** All queue directories must be (first level) subdirectories 69527c478bd9Sstevel@tonic-gate ** of the basedir. The basedir is the QueueDir 69537c478bd9Sstevel@tonic-gate ** without wildcards, but with trailing / 69547c478bd9Sstevel@tonic-gate */ 69557c478bd9Sstevel@tonic-gate 69567c478bd9Sstevel@tonic-gate hashval = 0; 69577c478bd9Sstevel@tonic-gate errno = 0; 69587c478bd9Sstevel@tonic-gate len = sm_strlcpy(basedir, QueueDir, sizeof basedir); 69597c478bd9Sstevel@tonic-gate 69607c478bd9Sstevel@tonic-gate /* Provide space for trailing '/' */ 69617c478bd9Sstevel@tonic-gate if (len >= sizeof basedir - 1) 69627c478bd9Sstevel@tonic-gate { 69637c478bd9Sstevel@tonic-gate syserr("QueueDirectory: path too long: %d, max %d", 69647c478bd9Sstevel@tonic-gate len, (int) sizeof basedir - 1); 69657c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 69667c478bd9Sstevel@tonic-gate return; 69677c478bd9Sstevel@tonic-gate } 69687c478bd9Sstevel@tonic-gate SM_ASSERT(len > 0); 69697c478bd9Sstevel@tonic-gate if (basedir[len - 1] == '*') 69707c478bd9Sstevel@tonic-gate { 69717c478bd9Sstevel@tonic-gate char *cp; 69727c478bd9Sstevel@tonic-gate 69737c478bd9Sstevel@tonic-gate cp = SM_LAST_DIR_DELIM(basedir); 69747c478bd9Sstevel@tonic-gate if (cp == NULL) 69757c478bd9Sstevel@tonic-gate { 69767c478bd9Sstevel@tonic-gate syserr("QueueDirectory: can not wildcard relative path \"%s\"", 69777c478bd9Sstevel@tonic-gate QueueDir); 69787c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 69797c478bd9Sstevel@tonic-gate sm_dprintf("setup_queues: \"%s\": Can not wildcard relative path.\n", 69807c478bd9Sstevel@tonic-gate QueueDir); 69817c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 69827c478bd9Sstevel@tonic-gate return; 69837c478bd9Sstevel@tonic-gate } 69847c478bd9Sstevel@tonic-gate 69857c478bd9Sstevel@tonic-gate /* cut off wildcard pattern */ 69867c478bd9Sstevel@tonic-gate *++cp = '\0'; 69877c478bd9Sstevel@tonic-gate len = cp - basedir; 69887c478bd9Sstevel@tonic-gate } 69897c478bd9Sstevel@tonic-gate else if (!SM_IS_DIR_DELIM(basedir[len - 1])) 69907c478bd9Sstevel@tonic-gate { 69917c478bd9Sstevel@tonic-gate /* append trailing slash since it is a directory */ 69927c478bd9Sstevel@tonic-gate basedir[len] = '/'; 69937c478bd9Sstevel@tonic-gate basedir[++len] = '\0'; 69947c478bd9Sstevel@tonic-gate } 69957c478bd9Sstevel@tonic-gate 69967c478bd9Sstevel@tonic-gate /* len counts up to the last directory delimiter */ 69977c478bd9Sstevel@tonic-gate SM_ASSERT(basedir[len - 1] == '/'); 69987c478bd9Sstevel@tonic-gate 69997c478bd9Sstevel@tonic-gate if (chdir(basedir) < 0) 70007c478bd9Sstevel@tonic-gate { 70017c478bd9Sstevel@tonic-gate int save_errno = errno; 70027c478bd9Sstevel@tonic-gate 70037c478bd9Sstevel@tonic-gate syserr("can not chdir(%s)", basedir); 70047c478bd9Sstevel@tonic-gate if (save_errno == EACCES) 70057c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 70067c478bd9Sstevel@tonic-gate "Program mode requires special privileges, e.g., root or TrustedUser.\n"); 70077c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 70087c478bd9Sstevel@tonic-gate sm_dprintf("setup_queues: \"%s\": %s\n", 70097c478bd9Sstevel@tonic-gate basedir, sm_errstring(errno)); 70107c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 70117c478bd9Sstevel@tonic-gate return; 70127c478bd9Sstevel@tonic-gate } 70137c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 70147c478bd9Sstevel@tonic-gate hashval = hash_q(basedir, hashval); 70157c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 70167c478bd9Sstevel@tonic-gate 70177c478bd9Sstevel@tonic-gate /* initialize for queue runs */ 70187c478bd9Sstevel@tonic-gate DoQueueRun = false; 70197c478bd9Sstevel@tonic-gate now = curtime(); 70207c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 70217c478bd9Sstevel@tonic-gate Queue[i]->qg_nextrun = now; 70227c478bd9Sstevel@tonic-gate 70237c478bd9Sstevel@tonic-gate 70247c478bd9Sstevel@tonic-gate if (UseMSP && OpMode != MD_TEST) 70257c478bd9Sstevel@tonic-gate { 70267c478bd9Sstevel@tonic-gate long sff = SFF_CREAT; 70277c478bd9Sstevel@tonic-gate 70287c478bd9Sstevel@tonic-gate if (stat(".", &st) < 0) 70297c478bd9Sstevel@tonic-gate { 70307c478bd9Sstevel@tonic-gate syserr("can not stat(%s)", basedir); 70317c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 70327c478bd9Sstevel@tonic-gate sm_dprintf("setup_queues: \"%s\": %s\n", 70337c478bd9Sstevel@tonic-gate basedir, sm_errstring(errno)); 70347c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 70357c478bd9Sstevel@tonic-gate return; 70367c478bd9Sstevel@tonic-gate } 70377c478bd9Sstevel@tonic-gate if (RunAsUid == 0) 70387c478bd9Sstevel@tonic-gate sff |= SFF_ROOTOK; 70397c478bd9Sstevel@tonic-gate 70407c478bd9Sstevel@tonic-gate /* 70417c478bd9Sstevel@tonic-gate ** Check queue directory permissions. 70427c478bd9Sstevel@tonic-gate ** Can we write to a group writable queue directory? 70437c478bd9Sstevel@tonic-gate */ 70447c478bd9Sstevel@tonic-gate 70457c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode) && 70467c478bd9Sstevel@tonic-gate bitset(S_IWGRP, st.st_mode) && 70477c478bd9Sstevel@tonic-gate safefile(" ", RunAsUid, RunAsGid, RunAsUserName, sff, 70487c478bd9Sstevel@tonic-gate QueueFileMode, NULL) != 0) 70497c478bd9Sstevel@tonic-gate { 70507c478bd9Sstevel@tonic-gate syserr("can not write to queue directory %s (RunAsGid=%d, required=%d)", 70517c478bd9Sstevel@tonic-gate basedir, (int) RunAsGid, (int) st.st_gid); 70527c478bd9Sstevel@tonic-gate } 70537c478bd9Sstevel@tonic-gate if (bitset(S_IWOTH|S_IXOTH, st.st_mode)) 70547c478bd9Sstevel@tonic-gate { 70557c478bd9Sstevel@tonic-gate #if _FFR_MSP_PARANOIA 70567c478bd9Sstevel@tonic-gate syserr("dangerous permissions=%o on queue directory %s", 70577c478bd9Sstevel@tonic-gate (int) st.st_mode, basedir); 70587c478bd9Sstevel@tonic-gate #else /* _FFR_MSP_PARANOIA */ 70597c478bd9Sstevel@tonic-gate if (LogLevel > 0) 70607c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 70617c478bd9Sstevel@tonic-gate "dangerous permissions=%o on queue directory %s", 70627c478bd9Sstevel@tonic-gate (int) st.st_mode, basedir); 70637c478bd9Sstevel@tonic-gate #endif /* _FFR_MSP_PARANOIA */ 70647c478bd9Sstevel@tonic-gate } 70657c478bd9Sstevel@tonic-gate #if _FFR_MSP_PARANOIA 70667c478bd9Sstevel@tonic-gate if (NumQueue > 1) 70677c478bd9Sstevel@tonic-gate syserr("can not use multiple queues for MSP"); 70687c478bd9Sstevel@tonic-gate #endif /* _FFR_MSP_PARANOIA */ 70697c478bd9Sstevel@tonic-gate } 70707c478bd9Sstevel@tonic-gate 70717c478bd9Sstevel@tonic-gate /* initial number of queue directories */ 70727c478bd9Sstevel@tonic-gate qn = 0; 70737c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 70747c478bd9Sstevel@tonic-gate qn = multiqueue_cache(basedir, len, Queue[i], qn, &hashval); 70757c478bd9Sstevel@tonic-gate 70767c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 70777c478bd9Sstevel@tonic-gate init_shm(qn, owner, hashval); 70787c478bd9Sstevel@tonic-gate i = filesys_setup(owner || ShmId == SM_SHM_NO_ID); 70797c478bd9Sstevel@tonic-gate if (i == FSF_NOT_FOUND) 70807c478bd9Sstevel@tonic-gate { 70817c478bd9Sstevel@tonic-gate /* 70827c478bd9Sstevel@tonic-gate ** We didn't get the right filesystem data 70837c478bd9Sstevel@tonic-gate ** This may happen if we don't have the right shared memory. 70847c478bd9Sstevel@tonic-gate ** So let's do this without shared memory. 70857c478bd9Sstevel@tonic-gate */ 70867c478bd9Sstevel@tonic-gate 70877c478bd9Sstevel@tonic-gate SM_ASSERT(!owner); 70887c478bd9Sstevel@tonic-gate cleanup_shm(false); /* release shared memory */ 70897c478bd9Sstevel@tonic-gate i = filesys_setup(false); 70907c478bd9Sstevel@tonic-gate if (i < 0) 70917c478bd9Sstevel@tonic-gate syserr("filesys_setup failed twice, result=%d", i); 70927c478bd9Sstevel@tonic-gate else if (LogLevel > 8) 70937c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 70947c478bd9Sstevel@tonic-gate "shared memory does not contain expected data, ignored"); 70957c478bd9Sstevel@tonic-gate } 70967c478bd9Sstevel@tonic-gate #else /* SM_CONF_SHM */ 70977c478bd9Sstevel@tonic-gate i = filesys_setup(true); 70987c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 70997c478bd9Sstevel@tonic-gate if (i < 0) 71007c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 71017c478bd9Sstevel@tonic-gate } 71027c478bd9Sstevel@tonic-gate 71037c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 71047c478bd9Sstevel@tonic-gate /* 71057c478bd9Sstevel@tonic-gate ** CLEANUP_SHM -- do some cleanup work for shared memory etc 71067c478bd9Sstevel@tonic-gate ** 71077c478bd9Sstevel@tonic-gate ** Parameters: 71087c478bd9Sstevel@tonic-gate ** owner -- owner of shared memory? 71097c478bd9Sstevel@tonic-gate ** 71107c478bd9Sstevel@tonic-gate ** Returns: 71117c478bd9Sstevel@tonic-gate ** none. 71127c478bd9Sstevel@tonic-gate ** 71137c478bd9Sstevel@tonic-gate ** Side Effects: 71147c478bd9Sstevel@tonic-gate ** detaches shared memory. 71157c478bd9Sstevel@tonic-gate */ 71167c478bd9Sstevel@tonic-gate 71177c478bd9Sstevel@tonic-gate void 71187c478bd9Sstevel@tonic-gate cleanup_shm(owner) 71197c478bd9Sstevel@tonic-gate bool owner; 71207c478bd9Sstevel@tonic-gate { 71217c478bd9Sstevel@tonic-gate if (ShmId != SM_SHM_NO_ID) 71227c478bd9Sstevel@tonic-gate { 71237c478bd9Sstevel@tonic-gate if (sm_shmstop(Pshm, ShmId, owner) < 0 && LogLevel > 8) 71247c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "sm_shmstop failed=%s", 71257c478bd9Sstevel@tonic-gate sm_errstring(errno)); 71267c478bd9Sstevel@tonic-gate Pshm = NULL; 71277c478bd9Sstevel@tonic-gate ShmId = SM_SHM_NO_ID; 71287c478bd9Sstevel@tonic-gate } 71297c478bd9Sstevel@tonic-gate stop_sem(owner); 71307c478bd9Sstevel@tonic-gate } 71317c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 71327c478bd9Sstevel@tonic-gate 71337c478bd9Sstevel@tonic-gate /* 71347c478bd9Sstevel@tonic-gate ** CLEANUP_QUEUES -- do some cleanup work for queues 71357c478bd9Sstevel@tonic-gate ** 71367c478bd9Sstevel@tonic-gate ** Parameters: 71377c478bd9Sstevel@tonic-gate ** none. 71387c478bd9Sstevel@tonic-gate ** 71397c478bd9Sstevel@tonic-gate ** Returns: 71407c478bd9Sstevel@tonic-gate ** none. 71417c478bd9Sstevel@tonic-gate ** 71427c478bd9Sstevel@tonic-gate */ 71437c478bd9Sstevel@tonic-gate 71447c478bd9Sstevel@tonic-gate void 71457c478bd9Sstevel@tonic-gate cleanup_queues() 71467c478bd9Sstevel@tonic-gate { 71477c478bd9Sstevel@tonic-gate sync_queue_time(); 71487c478bd9Sstevel@tonic-gate } 71497c478bd9Sstevel@tonic-gate /* 71507c478bd9Sstevel@tonic-gate ** SET_DEF_QUEUEVAL -- set default values for a queue group. 71517c478bd9Sstevel@tonic-gate ** 71527c478bd9Sstevel@tonic-gate ** Parameters: 71537c478bd9Sstevel@tonic-gate ** qg -- queue group 71547c478bd9Sstevel@tonic-gate ** all -- set all values (true for default group)? 71557c478bd9Sstevel@tonic-gate ** 71567c478bd9Sstevel@tonic-gate ** Returns: 71577c478bd9Sstevel@tonic-gate ** none. 71587c478bd9Sstevel@tonic-gate ** 71597c478bd9Sstevel@tonic-gate ** Side Effects: 71607c478bd9Sstevel@tonic-gate ** sets default values for the queue group. 71617c478bd9Sstevel@tonic-gate */ 71627c478bd9Sstevel@tonic-gate 71637c478bd9Sstevel@tonic-gate void 71647c478bd9Sstevel@tonic-gate set_def_queueval(qg, all) 71657c478bd9Sstevel@tonic-gate QUEUEGRP *qg; 71667c478bd9Sstevel@tonic-gate bool all; 71677c478bd9Sstevel@tonic-gate { 71687c478bd9Sstevel@tonic-gate if (bitnset(QD_DEFINED, qg->qg_flags)) 71697c478bd9Sstevel@tonic-gate return; 71707c478bd9Sstevel@tonic-gate if (all) 71717c478bd9Sstevel@tonic-gate qg->qg_qdir = QueueDir; 71727c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_GROUP_SORTORDER 71737c478bd9Sstevel@tonic-gate qg->qg_sortorder = QueueSortOrder; 71747c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_GROUP_SORTORDER */ 71757c478bd9Sstevel@tonic-gate qg->qg_maxqrun = all ? MaxRunnersPerQueue : -1; 71767c478bd9Sstevel@tonic-gate qg->qg_nice = NiceQueueRun; 71777c478bd9Sstevel@tonic-gate } 71787c478bd9Sstevel@tonic-gate /* 71797c478bd9Sstevel@tonic-gate ** MAKEQUEUE -- define a new queue. 71807c478bd9Sstevel@tonic-gate ** 71817c478bd9Sstevel@tonic-gate ** Parameters: 71827c478bd9Sstevel@tonic-gate ** line -- description of queue. This is in labeled fields. 71837c478bd9Sstevel@tonic-gate ** The fields are: 71847c478bd9Sstevel@tonic-gate ** F -- the flags associated with the queue 71857c478bd9Sstevel@tonic-gate ** I -- the interval between running the queue 71867c478bd9Sstevel@tonic-gate ** J -- the maximum # of jobs in work list 71877c478bd9Sstevel@tonic-gate ** [M -- the maximum # of jobs in a queue run] 71887c478bd9Sstevel@tonic-gate ** N -- the niceness at which to run 71897c478bd9Sstevel@tonic-gate ** P -- the path to the queue 71907c478bd9Sstevel@tonic-gate ** S -- the queue sorting order 71917c478bd9Sstevel@tonic-gate ** R -- number of parallel queue runners 71927c478bd9Sstevel@tonic-gate ** r -- max recipients per envelope 71937c478bd9Sstevel@tonic-gate ** The first word is the canonical name of the queue. 71947c478bd9Sstevel@tonic-gate ** qdef -- this is a 'Q' definition from .cf 71957c478bd9Sstevel@tonic-gate ** 71967c478bd9Sstevel@tonic-gate ** Returns: 71977c478bd9Sstevel@tonic-gate ** none. 71987c478bd9Sstevel@tonic-gate ** 71997c478bd9Sstevel@tonic-gate ** Side Effects: 72007c478bd9Sstevel@tonic-gate ** enters the queue into the queue table. 72017c478bd9Sstevel@tonic-gate */ 72027c478bd9Sstevel@tonic-gate 72037c478bd9Sstevel@tonic-gate void 72047c478bd9Sstevel@tonic-gate makequeue(line, qdef) 72057c478bd9Sstevel@tonic-gate char *line; 72067c478bd9Sstevel@tonic-gate bool qdef; 72077c478bd9Sstevel@tonic-gate { 72087c478bd9Sstevel@tonic-gate register char *p; 72097c478bd9Sstevel@tonic-gate register QUEUEGRP *qg; 72107c478bd9Sstevel@tonic-gate register STAB *s; 72117c478bd9Sstevel@tonic-gate int i; 72127c478bd9Sstevel@tonic-gate char fcode; 72137c478bd9Sstevel@tonic-gate 72147c478bd9Sstevel@tonic-gate /* allocate a queue and set up defaults */ 72157c478bd9Sstevel@tonic-gate qg = (QUEUEGRP *) xalloc(sizeof *qg); 72167c478bd9Sstevel@tonic-gate memset((char *) qg, '\0', sizeof *qg); 72177c478bd9Sstevel@tonic-gate 72187c478bd9Sstevel@tonic-gate if (line[0] == '\0') 72197c478bd9Sstevel@tonic-gate { 72207c478bd9Sstevel@tonic-gate syserr("name required for queue"); 72217c478bd9Sstevel@tonic-gate return; 72227c478bd9Sstevel@tonic-gate } 72237c478bd9Sstevel@tonic-gate 72247c478bd9Sstevel@tonic-gate /* collect the queue name */ 72257c478bd9Sstevel@tonic-gate for (p = line; 72267c478bd9Sstevel@tonic-gate *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); 72277c478bd9Sstevel@tonic-gate p++) 72287c478bd9Sstevel@tonic-gate continue; 72297c478bd9Sstevel@tonic-gate if (*p != '\0') 72307c478bd9Sstevel@tonic-gate *p++ = '\0'; 72317c478bd9Sstevel@tonic-gate qg->qg_name = newstr(line); 72327c478bd9Sstevel@tonic-gate 72337c478bd9Sstevel@tonic-gate /* set default values, can be overridden below */ 72347c478bd9Sstevel@tonic-gate set_def_queueval(qg, false); 72357c478bd9Sstevel@tonic-gate 72367c478bd9Sstevel@tonic-gate /* now scan through and assign info from the fields */ 72377c478bd9Sstevel@tonic-gate while (*p != '\0') 72387c478bd9Sstevel@tonic-gate { 72397c478bd9Sstevel@tonic-gate auto char *delimptr; 72407c478bd9Sstevel@tonic-gate 72417c478bd9Sstevel@tonic-gate while (*p != '\0' && 72427c478bd9Sstevel@tonic-gate (*p == ',' || (isascii(*p) && isspace(*p)))) 72437c478bd9Sstevel@tonic-gate p++; 72447c478bd9Sstevel@tonic-gate 72457c478bd9Sstevel@tonic-gate /* p now points to field code */ 72467c478bd9Sstevel@tonic-gate fcode = *p; 72477c478bd9Sstevel@tonic-gate while (*p != '\0' && *p != '=' && *p != ',') 72487c478bd9Sstevel@tonic-gate p++; 72497c478bd9Sstevel@tonic-gate if (*p++ != '=') 72507c478bd9Sstevel@tonic-gate { 72517c478bd9Sstevel@tonic-gate syserr("queue %s: `=' expected", qg->qg_name); 72527c478bd9Sstevel@tonic-gate return; 72537c478bd9Sstevel@tonic-gate } 72547c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p)) 72557c478bd9Sstevel@tonic-gate p++; 72567c478bd9Sstevel@tonic-gate 72577c478bd9Sstevel@tonic-gate /* p now points to the field body */ 72587c478bd9Sstevel@tonic-gate p = munchstring(p, &delimptr, ','); 72597c478bd9Sstevel@tonic-gate 72607c478bd9Sstevel@tonic-gate /* install the field into the queue struct */ 72617c478bd9Sstevel@tonic-gate switch (fcode) 72627c478bd9Sstevel@tonic-gate { 72637c478bd9Sstevel@tonic-gate case 'P': /* pathname */ 72647c478bd9Sstevel@tonic-gate if (*p == '\0') 72657c478bd9Sstevel@tonic-gate syserr("queue %s: empty path name", 72667c478bd9Sstevel@tonic-gate qg->qg_name); 72677c478bd9Sstevel@tonic-gate else 72687c478bd9Sstevel@tonic-gate qg->qg_qdir = newstr(p); 72697c478bd9Sstevel@tonic-gate break; 72707c478bd9Sstevel@tonic-gate 72717c478bd9Sstevel@tonic-gate case 'F': /* flags */ 72727c478bd9Sstevel@tonic-gate for (; *p != '\0'; p++) 72737c478bd9Sstevel@tonic-gate if (!(isascii(*p) && isspace(*p))) 72747c478bd9Sstevel@tonic-gate setbitn(*p, qg->qg_flags); 72757c478bd9Sstevel@tonic-gate break; 72767c478bd9Sstevel@tonic-gate 72777c478bd9Sstevel@tonic-gate /* 72787c478bd9Sstevel@tonic-gate ** Do we need two intervals here: 72797c478bd9Sstevel@tonic-gate ** One for persistent queue runners, 72807c478bd9Sstevel@tonic-gate ** one for "normal" queue runs? 72817c478bd9Sstevel@tonic-gate */ 72827c478bd9Sstevel@tonic-gate 72837c478bd9Sstevel@tonic-gate case 'I': /* interval between running the queue */ 72847c478bd9Sstevel@tonic-gate qg->qg_queueintvl = convtime(p, 'm'); 72857c478bd9Sstevel@tonic-gate break; 72867c478bd9Sstevel@tonic-gate 72877c478bd9Sstevel@tonic-gate case 'N': /* run niceness */ 72887c478bd9Sstevel@tonic-gate qg->qg_nice = atoi(p); 72897c478bd9Sstevel@tonic-gate break; 72907c478bd9Sstevel@tonic-gate 72917c478bd9Sstevel@tonic-gate case 'R': /* maximum # of runners for the group */ 72927c478bd9Sstevel@tonic-gate i = atoi(p); 72937c478bd9Sstevel@tonic-gate 72947c478bd9Sstevel@tonic-gate /* can't have more runners than allowed total */ 72957c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && i > MaxQueueChildren) 72967c478bd9Sstevel@tonic-gate { 72977c478bd9Sstevel@tonic-gate qg->qg_maxqrun = MaxQueueChildren; 72987c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 72997c478bd9Sstevel@tonic-gate "Q=%s: R=%d exceeds MaxQueueChildren=%d, set to MaxQueueChildren\n", 73007c478bd9Sstevel@tonic-gate qg->qg_name, i, 73017c478bd9Sstevel@tonic-gate MaxQueueChildren); 73027c478bd9Sstevel@tonic-gate } 73037c478bd9Sstevel@tonic-gate else 73047c478bd9Sstevel@tonic-gate qg->qg_maxqrun = i; 73057c478bd9Sstevel@tonic-gate break; 73067c478bd9Sstevel@tonic-gate 73077c478bd9Sstevel@tonic-gate case 'J': /* maximum # of jobs in work list */ 73087c478bd9Sstevel@tonic-gate qg->qg_maxlist = atoi(p); 73097c478bd9Sstevel@tonic-gate break; 73107c478bd9Sstevel@tonic-gate 73117c478bd9Sstevel@tonic-gate case 'r': /* max recipients per envelope */ 73127c478bd9Sstevel@tonic-gate qg->qg_maxrcpt = atoi(p); 73137c478bd9Sstevel@tonic-gate break; 73147c478bd9Sstevel@tonic-gate 73157c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_GROUP_SORTORDER 73167c478bd9Sstevel@tonic-gate case 'S': /* queue sorting order */ 73177c478bd9Sstevel@tonic-gate switch (*p) 73187c478bd9Sstevel@tonic-gate { 73197c478bd9Sstevel@tonic-gate case 'h': /* Host first */ 73207c478bd9Sstevel@tonic-gate case 'H': 73217c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYHOST; 73227c478bd9Sstevel@tonic-gate break; 73237c478bd9Sstevel@tonic-gate 73247c478bd9Sstevel@tonic-gate case 'p': /* Priority order */ 73257c478bd9Sstevel@tonic-gate case 'P': 73267c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYPRIORITY; 73277c478bd9Sstevel@tonic-gate break; 73287c478bd9Sstevel@tonic-gate 73297c478bd9Sstevel@tonic-gate case 't': /* Submission time */ 73307c478bd9Sstevel@tonic-gate case 'T': 73317c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYTIME; 73327c478bd9Sstevel@tonic-gate break; 73337c478bd9Sstevel@tonic-gate 73347c478bd9Sstevel@tonic-gate case 'f': /* File name */ 73357c478bd9Sstevel@tonic-gate case 'F': 73367c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYFILENAME; 73377c478bd9Sstevel@tonic-gate break; 73387c478bd9Sstevel@tonic-gate 73397c478bd9Sstevel@tonic-gate case 'm': /* Modification time */ 73407c478bd9Sstevel@tonic-gate case 'M': 73417c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYMODTIME; 73427c478bd9Sstevel@tonic-gate break; 73437c478bd9Sstevel@tonic-gate 73447c478bd9Sstevel@tonic-gate case 'r': /* Random */ 73457c478bd9Sstevel@tonic-gate case 'R': 73467c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_RANDOM; 73477c478bd9Sstevel@tonic-gate break; 73487c478bd9Sstevel@tonic-gate 73497c478bd9Sstevel@tonic-gate # if _FFR_RHS 73507c478bd9Sstevel@tonic-gate case 's': /* Shuffled host name */ 73517c478bd9Sstevel@tonic-gate case 'S': 73527c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYSHUFFLE; 73537c478bd9Sstevel@tonic-gate break; 73547c478bd9Sstevel@tonic-gate # endif /* _FFR_RHS */ 73557c478bd9Sstevel@tonic-gate 73567c478bd9Sstevel@tonic-gate case 'n': /* none */ 73577c478bd9Sstevel@tonic-gate case 'N': 73587c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_NONE; 73597c478bd9Sstevel@tonic-gate break; 73607c478bd9Sstevel@tonic-gate 73617c478bd9Sstevel@tonic-gate default: 73627c478bd9Sstevel@tonic-gate syserr("Invalid queue sort order \"%s\"", p); 73637c478bd9Sstevel@tonic-gate } 73647c478bd9Sstevel@tonic-gate break; 73657c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_GROUP_SORTORDER */ 73667c478bd9Sstevel@tonic-gate 73677c478bd9Sstevel@tonic-gate default: 73687c478bd9Sstevel@tonic-gate syserr("Q%s: unknown queue equate %c=", 73697c478bd9Sstevel@tonic-gate qg->qg_name, fcode); 73707c478bd9Sstevel@tonic-gate break; 73717c478bd9Sstevel@tonic-gate } 73727c478bd9Sstevel@tonic-gate 73737c478bd9Sstevel@tonic-gate p = delimptr; 73747c478bd9Sstevel@tonic-gate } 73757c478bd9Sstevel@tonic-gate 73767c478bd9Sstevel@tonic-gate #if !HASNICE 73777c478bd9Sstevel@tonic-gate if (qg->qg_nice != NiceQueueRun) 73787c478bd9Sstevel@tonic-gate { 73797c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 73807c478bd9Sstevel@tonic-gate "Q%s: Warning: N= set on system that doesn't support nice()\n", 73817c478bd9Sstevel@tonic-gate qg->qg_name); 73827c478bd9Sstevel@tonic-gate } 73837c478bd9Sstevel@tonic-gate #endif /* !HASNICE */ 73847c478bd9Sstevel@tonic-gate 73857c478bd9Sstevel@tonic-gate /* do some rationality checking */ 73867c478bd9Sstevel@tonic-gate if (NumQueue >= MAXQUEUEGROUPS) 73877c478bd9Sstevel@tonic-gate { 73887c478bd9Sstevel@tonic-gate syserr("too many queue groups defined (%d max)", 73897c478bd9Sstevel@tonic-gate MAXQUEUEGROUPS); 73907c478bd9Sstevel@tonic-gate return; 73917c478bd9Sstevel@tonic-gate } 73927c478bd9Sstevel@tonic-gate 73937c478bd9Sstevel@tonic-gate if (qg->qg_qdir == NULL) 73947c478bd9Sstevel@tonic-gate { 73957c478bd9Sstevel@tonic-gate if (QueueDir == NULL || *QueueDir == '\0') 73967c478bd9Sstevel@tonic-gate { 73977c478bd9Sstevel@tonic-gate syserr("QueueDir must be defined before queue groups"); 73987c478bd9Sstevel@tonic-gate return; 73997c478bd9Sstevel@tonic-gate } 74007c478bd9Sstevel@tonic-gate qg->qg_qdir = newstr(QueueDir); 74017c478bd9Sstevel@tonic-gate } 74027c478bd9Sstevel@tonic-gate 74037c478bd9Sstevel@tonic-gate if (qg->qg_maxqrun > 1 && !bitnset(QD_FORK, qg->qg_flags)) 74047c478bd9Sstevel@tonic-gate { 74057c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 74067c478bd9Sstevel@tonic-gate "Warning: Q=%s: R=%d: multiple queue runners specified\n\tbut flag '%c' is not set\n", 74077c478bd9Sstevel@tonic-gate qg->qg_name, qg->qg_maxqrun, QD_FORK); 74087c478bd9Sstevel@tonic-gate } 74097c478bd9Sstevel@tonic-gate 74107c478bd9Sstevel@tonic-gate /* enter the queue into the symbol table */ 74117c478bd9Sstevel@tonic-gate if (tTd(37, 8)) 74127c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 74137c478bd9Sstevel@tonic-gate "Adding %s to stab, path: %s", qg->qg_name, 74147c478bd9Sstevel@tonic-gate qg->qg_qdir); 74157c478bd9Sstevel@tonic-gate s = stab(qg->qg_name, ST_QUEUE, ST_ENTER); 74167c478bd9Sstevel@tonic-gate if (s->s_quegrp != NULL) 74177c478bd9Sstevel@tonic-gate { 74187c478bd9Sstevel@tonic-gate i = s->s_quegrp->qg_index; 74197c478bd9Sstevel@tonic-gate 74207c478bd9Sstevel@tonic-gate /* XXX what about the pointers inside this struct? */ 74217c478bd9Sstevel@tonic-gate sm_free(s->s_quegrp); /* XXX */ 74227c478bd9Sstevel@tonic-gate } 74237c478bd9Sstevel@tonic-gate else 74247c478bd9Sstevel@tonic-gate i = NumQueue++; 74257c478bd9Sstevel@tonic-gate Queue[i] = s->s_quegrp = qg; 74267c478bd9Sstevel@tonic-gate qg->qg_index = i; 74277c478bd9Sstevel@tonic-gate 74287c478bd9Sstevel@tonic-gate /* set default value for max queue runners */ 74297c478bd9Sstevel@tonic-gate if (qg->qg_maxqrun < 0) 74307c478bd9Sstevel@tonic-gate { 74317c478bd9Sstevel@tonic-gate if (MaxRunnersPerQueue > 0) 74327c478bd9Sstevel@tonic-gate qg->qg_maxqrun = MaxRunnersPerQueue; 74337c478bd9Sstevel@tonic-gate else 74347c478bd9Sstevel@tonic-gate qg->qg_maxqrun = 1; 74357c478bd9Sstevel@tonic-gate } 74367c478bd9Sstevel@tonic-gate if (qdef) 74377c478bd9Sstevel@tonic-gate setbitn(QD_DEFINED, qg->qg_flags); 74387c478bd9Sstevel@tonic-gate } 74397c478bd9Sstevel@tonic-gate #if 0 74407c478bd9Sstevel@tonic-gate /* 74417c478bd9Sstevel@tonic-gate ** HASHFQN -- calculate a hash value for a fully qualified host name 74427c478bd9Sstevel@tonic-gate ** 74437c478bd9Sstevel@tonic-gate ** Arguments: 74447c478bd9Sstevel@tonic-gate ** fqn -- an all lower-case host.domain string 74457c478bd9Sstevel@tonic-gate ** buckets -- the number of buckets (queue directories) 74467c478bd9Sstevel@tonic-gate ** 74477c478bd9Sstevel@tonic-gate ** Returns: 74487c478bd9Sstevel@tonic-gate ** a bucket number (signed integer) 74497c478bd9Sstevel@tonic-gate ** -1 on error 74507c478bd9Sstevel@tonic-gate ** 74517c478bd9Sstevel@tonic-gate ** Contributed by Exactis.com, Inc. 74527c478bd9Sstevel@tonic-gate */ 74537c478bd9Sstevel@tonic-gate 74547c478bd9Sstevel@tonic-gate int 74557c478bd9Sstevel@tonic-gate hashfqn(fqn, buckets) 74567c478bd9Sstevel@tonic-gate register char *fqn; 74577c478bd9Sstevel@tonic-gate int buckets; 74587c478bd9Sstevel@tonic-gate { 74597c478bd9Sstevel@tonic-gate register char *p; 74607c478bd9Sstevel@tonic-gate register int h = 0, hash, cnt; 74617c478bd9Sstevel@tonic-gate 74627c478bd9Sstevel@tonic-gate if (fqn == NULL) 74637c478bd9Sstevel@tonic-gate return -1; 74647c478bd9Sstevel@tonic-gate 74657c478bd9Sstevel@tonic-gate /* 74667c478bd9Sstevel@tonic-gate ** A variation on the gdb hash 74677c478bd9Sstevel@tonic-gate ** This is the best as of Feb 19, 1996 --bcx 74687c478bd9Sstevel@tonic-gate */ 74697c478bd9Sstevel@tonic-gate 74707c478bd9Sstevel@tonic-gate p = fqn; 74717c478bd9Sstevel@tonic-gate h = 0x238F13AF * strlen(p); 74727c478bd9Sstevel@tonic-gate for (cnt = 0; *p != 0; ++p, cnt++) 74737c478bd9Sstevel@tonic-gate { 74747c478bd9Sstevel@tonic-gate h = (h + (*p << (cnt * 5 % 24))) & 0x7FFFFFFF; 74757c478bd9Sstevel@tonic-gate } 74767c478bd9Sstevel@tonic-gate h = (1103515243 * h + 12345) & 0x7FFFFFFF; 74777c478bd9Sstevel@tonic-gate if (buckets < 2) 74787c478bd9Sstevel@tonic-gate hash = 0; 74797c478bd9Sstevel@tonic-gate else 74807c478bd9Sstevel@tonic-gate hash = (h % buckets); 74817c478bd9Sstevel@tonic-gate 74827c478bd9Sstevel@tonic-gate return hash; 74837c478bd9Sstevel@tonic-gate } 74847c478bd9Sstevel@tonic-gate #endif /* 0 */ 74857c478bd9Sstevel@tonic-gate 74867c478bd9Sstevel@tonic-gate /* 74877c478bd9Sstevel@tonic-gate ** A structure for sorting Queue according to maxqrun without 74887c478bd9Sstevel@tonic-gate ** screwing up Queue itself. 74897c478bd9Sstevel@tonic-gate */ 74907c478bd9Sstevel@tonic-gate 74917c478bd9Sstevel@tonic-gate struct sortqgrp 74927c478bd9Sstevel@tonic-gate { 74937c478bd9Sstevel@tonic-gate int sg_idx; /* original index */ 74947c478bd9Sstevel@tonic-gate int sg_maxqrun; /* max queue runners */ 74957c478bd9Sstevel@tonic-gate }; 74967c478bd9Sstevel@tonic-gate typedef struct sortqgrp SORTQGRP_T; 74977c478bd9Sstevel@tonic-gate static int cmpidx __P((const void *, const void *)); 74987c478bd9Sstevel@tonic-gate 74997c478bd9Sstevel@tonic-gate static int 75007c478bd9Sstevel@tonic-gate cmpidx(a, b) 75017c478bd9Sstevel@tonic-gate const void *a; 75027c478bd9Sstevel@tonic-gate const void *b; 75037c478bd9Sstevel@tonic-gate { 75047c478bd9Sstevel@tonic-gate /* The sort is highest to lowest, so the comparison is reversed */ 75057c478bd9Sstevel@tonic-gate if (((SORTQGRP_T *)a)->sg_maxqrun < ((SORTQGRP_T *)b)->sg_maxqrun) 75067c478bd9Sstevel@tonic-gate return 1; 75077c478bd9Sstevel@tonic-gate else if (((SORTQGRP_T *)a)->sg_maxqrun > ((SORTQGRP_T *)b)->sg_maxqrun) 75087c478bd9Sstevel@tonic-gate return -1; 75097c478bd9Sstevel@tonic-gate else 75107c478bd9Sstevel@tonic-gate return 0; 75117c478bd9Sstevel@tonic-gate } 75127c478bd9Sstevel@tonic-gate 75137c478bd9Sstevel@tonic-gate /* 75147c478bd9Sstevel@tonic-gate ** MAKEWORKGROUP -- balance queue groups into work groups per MaxQueueChildren 75157c478bd9Sstevel@tonic-gate ** 75167c478bd9Sstevel@tonic-gate ** Take the now defined queue groups and assign them to work groups. 75177c478bd9Sstevel@tonic-gate ** This is done to balance out the number of concurrently active 75187c478bd9Sstevel@tonic-gate ** queue runners such that MaxQueueChildren is not exceeded. This may 75197c478bd9Sstevel@tonic-gate ** result in more than one queue group per work group. In such a case 75207c478bd9Sstevel@tonic-gate ** the number of running queue groups in that work group will have no 75217c478bd9Sstevel@tonic-gate ** more than the work group maximum number of runners (a "fair" portion 75227c478bd9Sstevel@tonic-gate ** of MaxQueueRunners). All queue groups within a work group will get a 75237c478bd9Sstevel@tonic-gate ** chance at running. 75247c478bd9Sstevel@tonic-gate ** 75257c478bd9Sstevel@tonic-gate ** Parameters: 75267c478bd9Sstevel@tonic-gate ** none. 75277c478bd9Sstevel@tonic-gate ** 75287c478bd9Sstevel@tonic-gate ** Returns: 75297c478bd9Sstevel@tonic-gate ** nothing. 75307c478bd9Sstevel@tonic-gate ** 75317c478bd9Sstevel@tonic-gate ** Side Effects: 75327c478bd9Sstevel@tonic-gate ** Sets up WorkGrp structure. 75337c478bd9Sstevel@tonic-gate */ 75347c478bd9Sstevel@tonic-gate 75357c478bd9Sstevel@tonic-gate void 75367c478bd9Sstevel@tonic-gate makeworkgroups() 75377c478bd9Sstevel@tonic-gate { 75387c478bd9Sstevel@tonic-gate int i, j, total_runners, dir, h; 75397c478bd9Sstevel@tonic-gate SORTQGRP_T si[MAXQUEUEGROUPS + 1]; 75407c478bd9Sstevel@tonic-gate 75417c478bd9Sstevel@tonic-gate total_runners = 0; 75427c478bd9Sstevel@tonic-gate if (NumQueue == 1 && strcmp(Queue[0]->qg_name, "mqueue") == 0) 75437c478bd9Sstevel@tonic-gate { 75447c478bd9Sstevel@tonic-gate /* 75457c478bd9Sstevel@tonic-gate ** There is only the "mqueue" queue group (a default) 75467c478bd9Sstevel@tonic-gate ** containing all of the queues. We want to provide to 75477c478bd9Sstevel@tonic-gate ** this queue group the maximum allowable queue runners. 75487c478bd9Sstevel@tonic-gate ** To match older behavior (8.10/8.11) we'll try for 75497c478bd9Sstevel@tonic-gate ** 1 runner per queue capping it at MaxQueueChildren. 75507c478bd9Sstevel@tonic-gate ** So if there are N queues, then there will be N runners 75517c478bd9Sstevel@tonic-gate ** for the "mqueue" queue group (where N is kept less than 75527c478bd9Sstevel@tonic-gate ** MaxQueueChildren). 75537c478bd9Sstevel@tonic-gate */ 75547c478bd9Sstevel@tonic-gate 75557c478bd9Sstevel@tonic-gate NumWorkGroups = 1; 75567c478bd9Sstevel@tonic-gate WorkGrp[0].wg_numqgrp = 1; 75577c478bd9Sstevel@tonic-gate WorkGrp[0].wg_qgs = (QUEUEGRP **) xalloc(sizeof(QUEUEGRP *)); 75587c478bd9Sstevel@tonic-gate WorkGrp[0].wg_qgs[0] = Queue[0]; 75597c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && 75607c478bd9Sstevel@tonic-gate Queue[0]->qg_numqueues > MaxQueueChildren) 75617c478bd9Sstevel@tonic-gate WorkGrp[0].wg_runners = MaxQueueChildren; 75627c478bd9Sstevel@tonic-gate else 75637c478bd9Sstevel@tonic-gate WorkGrp[0].wg_runners = Queue[0]->qg_numqueues; 75647c478bd9Sstevel@tonic-gate 75657c478bd9Sstevel@tonic-gate Queue[0]->qg_wgrp = 0; 75667c478bd9Sstevel@tonic-gate 75677c478bd9Sstevel@tonic-gate /* can't have more runners than allowed total */ 75687c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && 75697c478bd9Sstevel@tonic-gate Queue[0]->qg_maxqrun > MaxQueueChildren) 75707c478bd9Sstevel@tonic-gate Queue[0]->qg_maxqrun = MaxQueueChildren; 75717c478bd9Sstevel@tonic-gate WorkGrp[0].wg_maxact = Queue[0]->qg_maxqrun; 75727c478bd9Sstevel@tonic-gate WorkGrp[0].wg_lowqintvl = Queue[0]->qg_queueintvl; 75737c478bd9Sstevel@tonic-gate return; 75747c478bd9Sstevel@tonic-gate } 75757c478bd9Sstevel@tonic-gate 75767c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue; i++) 75777c478bd9Sstevel@tonic-gate { 75787c478bd9Sstevel@tonic-gate si[i].sg_maxqrun = Queue[i]->qg_maxqrun; 75797c478bd9Sstevel@tonic-gate si[i].sg_idx = i; 75807c478bd9Sstevel@tonic-gate } 75817c478bd9Sstevel@tonic-gate qsort(si, NumQueue, sizeof(si[0]), cmpidx); 75827c478bd9Sstevel@tonic-gate 75837c478bd9Sstevel@tonic-gate NumWorkGroups = 0; 75847c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue; i++) 75857c478bd9Sstevel@tonic-gate { 75867c478bd9Sstevel@tonic-gate total_runners += si[i].sg_maxqrun; 75877c478bd9Sstevel@tonic-gate if (MaxQueueChildren <= 0 || total_runners <= MaxQueueChildren) 75887c478bd9Sstevel@tonic-gate NumWorkGroups++; 75897c478bd9Sstevel@tonic-gate else 75907c478bd9Sstevel@tonic-gate break; 75917c478bd9Sstevel@tonic-gate } 75927c478bd9Sstevel@tonic-gate 75937c478bd9Sstevel@tonic-gate if (NumWorkGroups < 1) 75947c478bd9Sstevel@tonic-gate NumWorkGroups = 1; /* gotta have one at least */ 75957c478bd9Sstevel@tonic-gate else if (NumWorkGroups > MAXWORKGROUPS) 75967c478bd9Sstevel@tonic-gate NumWorkGroups = MAXWORKGROUPS; /* the limit */ 75977c478bd9Sstevel@tonic-gate 75987c478bd9Sstevel@tonic-gate /* 75997c478bd9Sstevel@tonic-gate ** We now know the number of work groups to pack the queue groups 76007c478bd9Sstevel@tonic-gate ** into. The queue groups in 'Queue' are sorted from highest 76017c478bd9Sstevel@tonic-gate ** to lowest for the number of runners per queue group. 76027c478bd9Sstevel@tonic-gate ** We put the queue groups with the largest number of runners 76037c478bd9Sstevel@tonic-gate ** into work groups first. Then the smaller ones are fitted in 76047c478bd9Sstevel@tonic-gate ** where it looks best. 76057c478bd9Sstevel@tonic-gate */ 76067c478bd9Sstevel@tonic-gate 76077c478bd9Sstevel@tonic-gate j = 0; 76087c478bd9Sstevel@tonic-gate dir = 1; 76097c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue; i++) 76107c478bd9Sstevel@tonic-gate { 76117c478bd9Sstevel@tonic-gate /* a to-and-fro packing scheme, continue from last position */ 76127c478bd9Sstevel@tonic-gate if (j >= NumWorkGroups) 76137c478bd9Sstevel@tonic-gate { 76147c478bd9Sstevel@tonic-gate dir = -1; 76157c478bd9Sstevel@tonic-gate j = NumWorkGroups - 1; 76167c478bd9Sstevel@tonic-gate } 76177c478bd9Sstevel@tonic-gate else if (j < 0) 76187c478bd9Sstevel@tonic-gate { 76197c478bd9Sstevel@tonic-gate j = 0; 76207c478bd9Sstevel@tonic-gate dir = 1; 76217c478bd9Sstevel@tonic-gate } 76227c478bd9Sstevel@tonic-gate 76237c478bd9Sstevel@tonic-gate if (WorkGrp[j].wg_qgs == NULL) 76247c478bd9Sstevel@tonic-gate WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_malloc(sizeof(QUEUEGRP *) * 76257c478bd9Sstevel@tonic-gate (WorkGrp[j].wg_numqgrp + 1)); 76267c478bd9Sstevel@tonic-gate else 76277c478bd9Sstevel@tonic-gate WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_realloc(WorkGrp[j].wg_qgs, 76287c478bd9Sstevel@tonic-gate sizeof(QUEUEGRP *) * 76297c478bd9Sstevel@tonic-gate (WorkGrp[j].wg_numqgrp + 1)); 76307c478bd9Sstevel@tonic-gate if (WorkGrp[j].wg_qgs == NULL) 76317c478bd9Sstevel@tonic-gate { 76327c478bd9Sstevel@tonic-gate syserr("!cannot allocate memory for work queues, need %d bytes", 76337c478bd9Sstevel@tonic-gate (int) (sizeof(QUEUEGRP *) * 76347c478bd9Sstevel@tonic-gate (WorkGrp[j].wg_numqgrp + 1))); 76357c478bd9Sstevel@tonic-gate } 76367c478bd9Sstevel@tonic-gate 76377c478bd9Sstevel@tonic-gate h = si[i].sg_idx; 76387c478bd9Sstevel@tonic-gate WorkGrp[j].wg_qgs[WorkGrp[j].wg_numqgrp] = Queue[h]; 76397c478bd9Sstevel@tonic-gate WorkGrp[j].wg_numqgrp++; 76407c478bd9Sstevel@tonic-gate WorkGrp[j].wg_runners += Queue[h]->qg_maxqrun; 76417c478bd9Sstevel@tonic-gate Queue[h]->qg_wgrp = j; 76427c478bd9Sstevel@tonic-gate 76437c478bd9Sstevel@tonic-gate if (WorkGrp[j].wg_maxact == 0) 76447c478bd9Sstevel@tonic-gate { 76457c478bd9Sstevel@tonic-gate /* can't have more runners than allowed total */ 76467c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && 76477c478bd9Sstevel@tonic-gate Queue[h]->qg_maxqrun > MaxQueueChildren) 76487c478bd9Sstevel@tonic-gate Queue[h]->qg_maxqrun = MaxQueueChildren; 76497c478bd9Sstevel@tonic-gate WorkGrp[j].wg_maxact = Queue[h]->qg_maxqrun; 76507c478bd9Sstevel@tonic-gate } 76517c478bd9Sstevel@tonic-gate 76527c478bd9Sstevel@tonic-gate /* 76537c478bd9Sstevel@tonic-gate ** XXX: must wg_lowqintvl be the GCD? 76547c478bd9Sstevel@tonic-gate ** qg1: 2m, qg2: 3m, minimum: 2m, when do queue runs for 76557c478bd9Sstevel@tonic-gate ** qg2 occur? 76567c478bd9Sstevel@tonic-gate */ 76577c478bd9Sstevel@tonic-gate 76587c478bd9Sstevel@tonic-gate /* keep track of the lowest interval for a persistent runner */ 76597c478bd9Sstevel@tonic-gate if (Queue[h]->qg_queueintvl > 0 && 76607c478bd9Sstevel@tonic-gate WorkGrp[j].wg_lowqintvl < Queue[h]->qg_queueintvl) 76617c478bd9Sstevel@tonic-gate WorkGrp[j].wg_lowqintvl = Queue[h]->qg_queueintvl; 76627c478bd9Sstevel@tonic-gate j += dir; 76637c478bd9Sstevel@tonic-gate } 76647c478bd9Sstevel@tonic-gate if (tTd(41, 9)) 76657c478bd9Sstevel@tonic-gate { 76667c478bd9Sstevel@tonic-gate for (i = 0; i < NumWorkGroups; i++) 76677c478bd9Sstevel@tonic-gate { 76687c478bd9Sstevel@tonic-gate sm_dprintf("Workgroup[%d]=", i); 76697c478bd9Sstevel@tonic-gate for (j = 0; j < WorkGrp[i].wg_numqgrp; j++) 76707c478bd9Sstevel@tonic-gate { 76717c478bd9Sstevel@tonic-gate sm_dprintf("%s, ", 76727c478bd9Sstevel@tonic-gate WorkGrp[i].wg_qgs[j]->qg_name); 76737c478bd9Sstevel@tonic-gate } 76747c478bd9Sstevel@tonic-gate sm_dprintf("\n"); 76757c478bd9Sstevel@tonic-gate } 76767c478bd9Sstevel@tonic-gate } 76777c478bd9Sstevel@tonic-gate } 76787c478bd9Sstevel@tonic-gate 76797c478bd9Sstevel@tonic-gate /* 76807c478bd9Sstevel@tonic-gate ** DUP_DF -- duplicate envelope data file 76817c478bd9Sstevel@tonic-gate ** 76827c478bd9Sstevel@tonic-gate ** Copy the data file from the 'old' envelope to the 'new' envelope 76837c478bd9Sstevel@tonic-gate ** in the most efficient way possible. 76847c478bd9Sstevel@tonic-gate ** 76857c478bd9Sstevel@tonic-gate ** Create a hard link from the 'old' data file to the 'new' data file. 76867c478bd9Sstevel@tonic-gate ** If the old and new queue directories are on different file systems, 76877c478bd9Sstevel@tonic-gate ** then the new data file link is created in the old queue directory, 76887c478bd9Sstevel@tonic-gate ** and the new queue file will contain a 'd' record pointing to the 76897c478bd9Sstevel@tonic-gate ** directory containing the new data file. 76907c478bd9Sstevel@tonic-gate ** 76917c478bd9Sstevel@tonic-gate ** Parameters: 76927c478bd9Sstevel@tonic-gate ** old -- old envelope. 76937c478bd9Sstevel@tonic-gate ** new -- new envelope. 76947c478bd9Sstevel@tonic-gate ** 76957c478bd9Sstevel@tonic-gate ** Results: 76967c478bd9Sstevel@tonic-gate ** Returns true on success, false on failure. 76977c478bd9Sstevel@tonic-gate ** 76987c478bd9Sstevel@tonic-gate ** Side Effects: 76997c478bd9Sstevel@tonic-gate ** On success, the new data file is created. 77007c478bd9Sstevel@tonic-gate ** On fatal failure, EF_FATALERRS is set in old->e_flags. 77017c478bd9Sstevel@tonic-gate */ 77027c478bd9Sstevel@tonic-gate 77037c478bd9Sstevel@tonic-gate static bool dup_df __P((ENVELOPE *, ENVELOPE *)); 77047c478bd9Sstevel@tonic-gate 77057c478bd9Sstevel@tonic-gate static bool 77067c478bd9Sstevel@tonic-gate dup_df(old, new) 77077c478bd9Sstevel@tonic-gate ENVELOPE *old; 77087c478bd9Sstevel@tonic-gate ENVELOPE *new; 77097c478bd9Sstevel@tonic-gate { 77107c478bd9Sstevel@tonic-gate int ofs, nfs, r; 77117c478bd9Sstevel@tonic-gate char opath[MAXPATHLEN]; 77127c478bd9Sstevel@tonic-gate char npath[MAXPATHLEN]; 77137c478bd9Sstevel@tonic-gate 77147c478bd9Sstevel@tonic-gate if (!bitset(EF_HAS_DF, old->e_flags)) 77157c478bd9Sstevel@tonic-gate { 77167c478bd9Sstevel@tonic-gate /* 77177c478bd9Sstevel@tonic-gate ** this can happen if: SuperSafe != True 77187c478bd9Sstevel@tonic-gate ** and a bounce mail is sent that is split. 77197c478bd9Sstevel@tonic-gate */ 77207c478bd9Sstevel@tonic-gate 77217c478bd9Sstevel@tonic-gate queueup(old, false, true); 77227c478bd9Sstevel@tonic-gate } 77237c478bd9Sstevel@tonic-gate SM_REQUIRE(ISVALIDQGRP(old->e_qgrp) && ISVALIDQDIR(old->e_qdir)); 77247c478bd9Sstevel@tonic-gate SM_REQUIRE(ISVALIDQGRP(new->e_qgrp) && ISVALIDQDIR(new->e_qdir)); 77257c478bd9Sstevel@tonic-gate 77267c478bd9Sstevel@tonic-gate (void) sm_strlcpy(opath, queuename(old, DATAFL_LETTER), sizeof opath); 77277c478bd9Sstevel@tonic-gate (void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof npath); 77287c478bd9Sstevel@tonic-gate 77297c478bd9Sstevel@tonic-gate if (old->e_dfp != NULL) 77307c478bd9Sstevel@tonic-gate { 77317c478bd9Sstevel@tonic-gate r = sm_io_setinfo(old->e_dfp, SM_BF_COMMIT, NULL); 77327c478bd9Sstevel@tonic-gate if (r < 0 && errno != EINVAL) 77337c478bd9Sstevel@tonic-gate { 77347c478bd9Sstevel@tonic-gate syserr("@can't commit %s", opath); 77357c478bd9Sstevel@tonic-gate old->e_flags |= EF_FATALERRS; 77367c478bd9Sstevel@tonic-gate return false; 77377c478bd9Sstevel@tonic-gate } 77387c478bd9Sstevel@tonic-gate } 77397c478bd9Sstevel@tonic-gate 77407c478bd9Sstevel@tonic-gate /* 77417c478bd9Sstevel@tonic-gate ** Attempt to create a hard link, if we think both old and new 77427c478bd9Sstevel@tonic-gate ** are on the same file system, otherwise copy the file. 77437c478bd9Sstevel@tonic-gate ** 77447c478bd9Sstevel@tonic-gate ** Don't waste time attempting a hard link unless old and new 77457c478bd9Sstevel@tonic-gate ** are on the same file system. 77467c478bd9Sstevel@tonic-gate */ 77477c478bd9Sstevel@tonic-gate 774849218d4fSjbeck SM_REQUIRE(ISVALIDQGRP(old->e_dfqgrp) && ISVALIDQDIR(old->e_dfqdir)); 774949218d4fSjbeck SM_REQUIRE(ISVALIDQGRP(new->e_dfqgrp) && ISVALIDQDIR(new->e_dfqdir)); 775049218d4fSjbeck 775149218d4fSjbeck ofs = Queue[old->e_dfqgrp]->qg_qpaths[old->e_dfqdir].qp_fsysidx; 775249218d4fSjbeck nfs = Queue[new->e_dfqgrp]->qg_qpaths[new->e_dfqdir].qp_fsysidx; 77537c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(ofs) == FILE_SYS_DEV(nfs)) 77547c478bd9Sstevel@tonic-gate { 77557c478bd9Sstevel@tonic-gate if (link(opath, npath) == 0) 77567c478bd9Sstevel@tonic-gate { 77577c478bd9Sstevel@tonic-gate new->e_flags |= EF_HAS_DF; 77587c478bd9Sstevel@tonic-gate SYNC_DIR(npath, true); 77597c478bd9Sstevel@tonic-gate return true; 77607c478bd9Sstevel@tonic-gate } 77617c478bd9Sstevel@tonic-gate goto error; 77627c478bd9Sstevel@tonic-gate } 77637c478bd9Sstevel@tonic-gate 77647c478bd9Sstevel@tonic-gate /* 77657c478bd9Sstevel@tonic-gate ** Can't link across queue directories, so try to create a hard 77667c478bd9Sstevel@tonic-gate ** link in the same queue directory as the old df file. 77677c478bd9Sstevel@tonic-gate ** The qf file will refer to the new df file using a 'd' record. 77687c478bd9Sstevel@tonic-gate */ 77697c478bd9Sstevel@tonic-gate 77707c478bd9Sstevel@tonic-gate new->e_dfqgrp = old->e_dfqgrp; 77717c478bd9Sstevel@tonic-gate new->e_dfqdir = old->e_dfqdir; 77727c478bd9Sstevel@tonic-gate (void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof npath); 77737c478bd9Sstevel@tonic-gate if (link(opath, npath) == 0) 77747c478bd9Sstevel@tonic-gate { 77757c478bd9Sstevel@tonic-gate new->e_flags |= EF_HAS_DF; 77767c478bd9Sstevel@tonic-gate SYNC_DIR(npath, true); 77777c478bd9Sstevel@tonic-gate return true; 77787c478bd9Sstevel@tonic-gate } 77797c478bd9Sstevel@tonic-gate 77807c478bd9Sstevel@tonic-gate error: 77817c478bd9Sstevel@tonic-gate if (LogLevel > 0) 77827c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, old->e_id, 77837c478bd9Sstevel@tonic-gate "dup_df: can't link %s to %s, error=%s, envelope splitting failed", 77847c478bd9Sstevel@tonic-gate opath, npath, sm_errstring(errno)); 77857c478bd9Sstevel@tonic-gate return false; 77867c478bd9Sstevel@tonic-gate } 77877c478bd9Sstevel@tonic-gate 77887c478bd9Sstevel@tonic-gate /* 77897c478bd9Sstevel@tonic-gate ** SPLIT_ENV -- Allocate a new envelope based on a given envelope. 77907c478bd9Sstevel@tonic-gate ** 77917c478bd9Sstevel@tonic-gate ** Parameters: 77927c478bd9Sstevel@tonic-gate ** e -- envelope. 77937c478bd9Sstevel@tonic-gate ** sendqueue -- sendqueue for new envelope. 77947c478bd9Sstevel@tonic-gate ** qgrp -- index of queue group. 77957c478bd9Sstevel@tonic-gate ** qdir -- queue directory. 77967c478bd9Sstevel@tonic-gate ** 77977c478bd9Sstevel@tonic-gate ** Results: 77987c478bd9Sstevel@tonic-gate ** new envelope. 77997c478bd9Sstevel@tonic-gate ** 78007c478bd9Sstevel@tonic-gate */ 78017c478bd9Sstevel@tonic-gate 78027c478bd9Sstevel@tonic-gate static ENVELOPE *split_env __P((ENVELOPE *, ADDRESS *, int, int)); 78037c478bd9Sstevel@tonic-gate 78047c478bd9Sstevel@tonic-gate static ENVELOPE * 78057c478bd9Sstevel@tonic-gate split_env(e, sendqueue, qgrp, qdir) 78067c478bd9Sstevel@tonic-gate ENVELOPE *e; 78077c478bd9Sstevel@tonic-gate ADDRESS *sendqueue; 78087c478bd9Sstevel@tonic-gate int qgrp; 78097c478bd9Sstevel@tonic-gate int qdir; 78107c478bd9Sstevel@tonic-gate { 78117c478bd9Sstevel@tonic-gate ENVELOPE *ee; 78127c478bd9Sstevel@tonic-gate 78137c478bd9Sstevel@tonic-gate ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool, sizeof *ee); 78147c478bd9Sstevel@tonic-gate STRUCTCOPY(*e, *ee); 78157c478bd9Sstevel@tonic-gate ee->e_message = NULL; /* XXX use original message? */ 78167c478bd9Sstevel@tonic-gate ee->e_id = NULL; 78177c478bd9Sstevel@tonic-gate assign_queueid(ee); 78187c478bd9Sstevel@tonic-gate ee->e_sendqueue = sendqueue; 78197c478bd9Sstevel@tonic-gate ee->e_flags &= ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS 78207c478bd9Sstevel@tonic-gate |EF_SENDRECEIPT|EF_RET_PARAM|EF_HAS_DF); 78217c478bd9Sstevel@tonic-gate ee->e_flags |= EF_NORECEIPT; /* XXX really? */ 78227c478bd9Sstevel@tonic-gate ee->e_from.q_state = QS_SENDER; 78237c478bd9Sstevel@tonic-gate ee->e_dfp = NULL; 78247c478bd9Sstevel@tonic-gate ee->e_lockfp = NULL; 78257c478bd9Sstevel@tonic-gate if (e->e_xfp != NULL) 78267c478bd9Sstevel@tonic-gate ee->e_xfp = sm_io_dup(e->e_xfp); 78277c478bd9Sstevel@tonic-gate 78287c478bd9Sstevel@tonic-gate /* failed to dup e->e_xfp, start a new transcript */ 78297c478bd9Sstevel@tonic-gate if (ee->e_xfp == NULL) 78307c478bd9Sstevel@tonic-gate openxscript(ee); 78317c478bd9Sstevel@tonic-gate 78327c478bd9Sstevel@tonic-gate ee->e_qgrp = ee->e_dfqgrp = qgrp; 78337c478bd9Sstevel@tonic-gate ee->e_qdir = ee->e_dfqdir = qdir; 78347c478bd9Sstevel@tonic-gate ee->e_errormode = EM_MAIL; 78357c478bd9Sstevel@tonic-gate ee->e_statmsg = NULL; 78367c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 78377c478bd9Sstevel@tonic-gate ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool, 78387c478bd9Sstevel@tonic-gate e->e_quarmsg); 78397c478bd9Sstevel@tonic-gate 78407c478bd9Sstevel@tonic-gate /* 78417c478bd9Sstevel@tonic-gate ** XXX Not sure if this copying is necessary. 78427c478bd9Sstevel@tonic-gate ** sendall() does this copying, but I (dm) don't know if that is 78437c478bd9Sstevel@tonic-gate ** because of the storage management discipline we were using 78447c478bd9Sstevel@tonic-gate ** before rpools were introduced, or if it is because these lists 78457c478bd9Sstevel@tonic-gate ** can be modified later. 78467c478bd9Sstevel@tonic-gate */ 78477c478bd9Sstevel@tonic-gate 78487c478bd9Sstevel@tonic-gate ee->e_header = copyheader(e->e_header, ee->e_rpool); 78497c478bd9Sstevel@tonic-gate ee->e_errorqueue = copyqueue(e->e_errorqueue, ee->e_rpool); 78507c478bd9Sstevel@tonic-gate 78517c478bd9Sstevel@tonic-gate return ee; 78527c478bd9Sstevel@tonic-gate } 78537c478bd9Sstevel@tonic-gate 78547c478bd9Sstevel@tonic-gate /* return values from split functions, check also below! */ 78557c478bd9Sstevel@tonic-gate #define SM_SPLIT_FAIL (0) 78567c478bd9Sstevel@tonic-gate #define SM_SPLIT_NONE (1) 78577c478bd9Sstevel@tonic-gate #define SM_SPLIT_NEW(n) (1 + (n)) 78587c478bd9Sstevel@tonic-gate 78597c478bd9Sstevel@tonic-gate /* 78607c478bd9Sstevel@tonic-gate ** SPLIT_ACROSS_QUEUE_GROUPS 78617c478bd9Sstevel@tonic-gate ** 78627c478bd9Sstevel@tonic-gate ** This function splits an envelope across multiple queue groups 78637c478bd9Sstevel@tonic-gate ** based on the queue group of each recipient. 78647c478bd9Sstevel@tonic-gate ** 78657c478bd9Sstevel@tonic-gate ** Parameters: 78667c478bd9Sstevel@tonic-gate ** e -- envelope. 78677c478bd9Sstevel@tonic-gate ** 78687c478bd9Sstevel@tonic-gate ** Results: 78697c478bd9Sstevel@tonic-gate ** SM_SPLIT_FAIL on failure 78707c478bd9Sstevel@tonic-gate ** SM_SPLIT_NONE if no splitting occurred, 78717c478bd9Sstevel@tonic-gate ** or 1 + the number of additional envelopes created. 78727c478bd9Sstevel@tonic-gate ** 78737c478bd9Sstevel@tonic-gate ** Side Effects: 78747c478bd9Sstevel@tonic-gate ** On success, e->e_sibling points to a list of zero or more 78757c478bd9Sstevel@tonic-gate ** additional envelopes, and the associated data files exist 78767c478bd9Sstevel@tonic-gate ** on disk. But the queue files are not created. 78777c478bd9Sstevel@tonic-gate ** 78787c478bd9Sstevel@tonic-gate ** On failure, e->e_sibling is not changed. 78797c478bd9Sstevel@tonic-gate ** The order of recipients in e->e_sendqueue is permuted. 78807c478bd9Sstevel@tonic-gate ** Abandoned data files for additional envelopes that failed 78817c478bd9Sstevel@tonic-gate ** to be created may exist on disk. 78827c478bd9Sstevel@tonic-gate */ 78837c478bd9Sstevel@tonic-gate 78847c478bd9Sstevel@tonic-gate static int q_qgrp_compare __P((const void *, const void *)); 78857c478bd9Sstevel@tonic-gate static int e_filesys_compare __P((const void *, const void *)); 78867c478bd9Sstevel@tonic-gate 78877c478bd9Sstevel@tonic-gate static int 78887c478bd9Sstevel@tonic-gate q_qgrp_compare(p1, p2) 78897c478bd9Sstevel@tonic-gate const void *p1; 78907c478bd9Sstevel@tonic-gate const void *p2; 78917c478bd9Sstevel@tonic-gate { 78927c478bd9Sstevel@tonic-gate ADDRESS **pq1 = (ADDRESS **) p1; 78937c478bd9Sstevel@tonic-gate ADDRESS **pq2 = (ADDRESS **) p2; 78947c478bd9Sstevel@tonic-gate 78957c478bd9Sstevel@tonic-gate return (*pq1)->q_qgrp - (*pq2)->q_qgrp; 78967c478bd9Sstevel@tonic-gate } 78977c478bd9Sstevel@tonic-gate 78987c478bd9Sstevel@tonic-gate static int 78997c478bd9Sstevel@tonic-gate e_filesys_compare(p1, p2) 79007c478bd9Sstevel@tonic-gate const void *p1; 79017c478bd9Sstevel@tonic-gate const void *p2; 79027c478bd9Sstevel@tonic-gate { 79037c478bd9Sstevel@tonic-gate ENVELOPE **pe1 = (ENVELOPE **) p1; 79047c478bd9Sstevel@tonic-gate ENVELOPE **pe2 = (ENVELOPE **) p2; 79057c478bd9Sstevel@tonic-gate int fs1, fs2; 79067c478bd9Sstevel@tonic-gate 79077c478bd9Sstevel@tonic-gate fs1 = Queue[(*pe1)->e_qgrp]->qg_qpaths[(*pe1)->e_qdir].qp_fsysidx; 79087c478bd9Sstevel@tonic-gate fs2 = Queue[(*pe2)->e_qgrp]->qg_qpaths[(*pe2)->e_qdir].qp_fsysidx; 79097c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(fs1) < FILE_SYS_DEV(fs2)) 79107c478bd9Sstevel@tonic-gate return -1; 79117c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(fs1) > FILE_SYS_DEV(fs2)) 79127c478bd9Sstevel@tonic-gate return 1; 79137c478bd9Sstevel@tonic-gate return 0; 79147c478bd9Sstevel@tonic-gate } 79157c478bd9Sstevel@tonic-gate 79167c478bd9Sstevel@tonic-gate static int 79177c478bd9Sstevel@tonic-gate split_across_queue_groups(e) 79187c478bd9Sstevel@tonic-gate ENVELOPE *e; 79197c478bd9Sstevel@tonic-gate { 79207c478bd9Sstevel@tonic-gate int naddrs, nsplits, i; 79217c478bd9Sstevel@tonic-gate bool changed; 79227c478bd9Sstevel@tonic-gate char **pvp; 79237c478bd9Sstevel@tonic-gate ADDRESS *q, **addrs; 79247c478bd9Sstevel@tonic-gate ENVELOPE *ee, *es; 79257c478bd9Sstevel@tonic-gate ENVELOPE *splits[MAXQUEUEGROUPS]; 79267c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE]; 79277c478bd9Sstevel@tonic-gate 79287c478bd9Sstevel@tonic-gate SM_REQUIRE(ISVALIDQGRP(e->e_qgrp)); 79297c478bd9Sstevel@tonic-gate 79307c478bd9Sstevel@tonic-gate /* Count addresses and assign queue groups. */ 79317c478bd9Sstevel@tonic-gate naddrs = 0; 79327c478bd9Sstevel@tonic-gate changed = false; 79337c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 79347c478bd9Sstevel@tonic-gate { 79357c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 79367c478bd9Sstevel@tonic-gate continue; 79377c478bd9Sstevel@tonic-gate ++naddrs; 79387c478bd9Sstevel@tonic-gate 79397c478bd9Sstevel@tonic-gate /* bad addresses and those already sent stay put */ 79407c478bd9Sstevel@tonic-gate if (QS_IS_BADADDR(q->q_state) || 79417c478bd9Sstevel@tonic-gate QS_IS_SENT(q->q_state)) 79427c478bd9Sstevel@tonic-gate q->q_qgrp = e->e_qgrp; 79437c478bd9Sstevel@tonic-gate else if (!ISVALIDQGRP(q->q_qgrp)) 79447c478bd9Sstevel@tonic-gate { 79457c478bd9Sstevel@tonic-gate /* call ruleset which should return a queue group */ 79467c478bd9Sstevel@tonic-gate i = rscap(RS_QUEUEGROUP, q->q_user, NULL, e, &pvp, 79477c478bd9Sstevel@tonic-gate pvpbuf, sizeof(pvpbuf)); 79487c478bd9Sstevel@tonic-gate if (i == EX_OK && 79497c478bd9Sstevel@tonic-gate pvp != NULL && pvp[0] != NULL && 79507c478bd9Sstevel@tonic-gate (pvp[0][0] & 0377) == CANONNET && 79517c478bd9Sstevel@tonic-gate pvp[1] != NULL && pvp[1][0] != '\0') 79527c478bd9Sstevel@tonic-gate { 79537c478bd9Sstevel@tonic-gate i = name2qid(pvp[1]); 79547c478bd9Sstevel@tonic-gate if (ISVALIDQGRP(i)) 79557c478bd9Sstevel@tonic-gate { 79567c478bd9Sstevel@tonic-gate q->q_qgrp = i; 79577c478bd9Sstevel@tonic-gate changed = true; 79587c478bd9Sstevel@tonic-gate if (tTd(20, 4)) 79597c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 79607c478bd9Sstevel@tonic-gate "queue group name %s -> %d", 79617c478bd9Sstevel@tonic-gate pvp[1], i); 79627c478bd9Sstevel@tonic-gate continue; 79637c478bd9Sstevel@tonic-gate } 79647c478bd9Sstevel@tonic-gate else if (LogLevel > 10) 79657c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 79667c478bd9Sstevel@tonic-gate "can't find queue group name %s, selection ignored", 79677c478bd9Sstevel@tonic-gate pvp[1]); 79687c478bd9Sstevel@tonic-gate } 79697c478bd9Sstevel@tonic-gate if (q->q_mailer != NULL && 79707c478bd9Sstevel@tonic-gate ISVALIDQGRP(q->q_mailer->m_qgrp)) 79717c478bd9Sstevel@tonic-gate { 79727c478bd9Sstevel@tonic-gate changed = true; 79737c478bd9Sstevel@tonic-gate q->q_qgrp = q->q_mailer->m_qgrp; 79747c478bd9Sstevel@tonic-gate } 79757c478bd9Sstevel@tonic-gate else if (ISVALIDQGRP(e->e_qgrp)) 79767c478bd9Sstevel@tonic-gate q->q_qgrp = e->e_qgrp; 79777c478bd9Sstevel@tonic-gate else 79787c478bd9Sstevel@tonic-gate q->q_qgrp = 0; 79797c478bd9Sstevel@tonic-gate } 79807c478bd9Sstevel@tonic-gate } 79817c478bd9Sstevel@tonic-gate 79827c478bd9Sstevel@tonic-gate /* only one address? nothing to split. */ 79837c478bd9Sstevel@tonic-gate if (naddrs <= 1 && !changed) 79847c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 79857c478bd9Sstevel@tonic-gate 79867c478bd9Sstevel@tonic-gate /* sort the addresses by queue group */ 79877c478bd9Sstevel@tonic-gate addrs = sm_rpool_malloc_x(e->e_rpool, naddrs * sizeof(ADDRESS *)); 79887c478bd9Sstevel@tonic-gate for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next) 79897c478bd9Sstevel@tonic-gate { 79907c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 79917c478bd9Sstevel@tonic-gate continue; 79927c478bd9Sstevel@tonic-gate addrs[i++] = q; 79937c478bd9Sstevel@tonic-gate } 79947c478bd9Sstevel@tonic-gate qsort(addrs, naddrs, sizeof(ADDRESS *), q_qgrp_compare); 79957c478bd9Sstevel@tonic-gate 79967c478bd9Sstevel@tonic-gate /* split into multiple envelopes, by queue group */ 79977c478bd9Sstevel@tonic-gate nsplits = 0; 79987c478bd9Sstevel@tonic-gate es = NULL; 79997c478bd9Sstevel@tonic-gate e->e_sendqueue = NULL; 80007c478bd9Sstevel@tonic-gate for (i = 0; i < naddrs; ++i) 80017c478bd9Sstevel@tonic-gate { 80027c478bd9Sstevel@tonic-gate if (i == naddrs - 1 || addrs[i]->q_qgrp != addrs[i + 1]->q_qgrp) 80037c478bd9Sstevel@tonic-gate addrs[i]->q_next = NULL; 80047c478bd9Sstevel@tonic-gate else 80057c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1]; 80067c478bd9Sstevel@tonic-gate 80077c478bd9Sstevel@tonic-gate /* same queue group as original envelope? */ 80087c478bd9Sstevel@tonic-gate if (addrs[i]->q_qgrp == e->e_qgrp) 80097c478bd9Sstevel@tonic-gate { 80107c478bd9Sstevel@tonic-gate if (e->e_sendqueue == NULL) 80117c478bd9Sstevel@tonic-gate e->e_sendqueue = addrs[i]; 80127c478bd9Sstevel@tonic-gate continue; 80137c478bd9Sstevel@tonic-gate } 80147c478bd9Sstevel@tonic-gate 80157c478bd9Sstevel@tonic-gate /* different queue group than original envelope */ 80167c478bd9Sstevel@tonic-gate if (es == NULL || addrs[i]->q_qgrp != es->e_qgrp) 80177c478bd9Sstevel@tonic-gate { 80187c478bd9Sstevel@tonic-gate ee = split_env(e, addrs[i], addrs[i]->q_qgrp, NOQDIR); 80197c478bd9Sstevel@tonic-gate es = ee; 80207c478bd9Sstevel@tonic-gate splits[nsplits++] = ee; 80217c478bd9Sstevel@tonic-gate } 80227c478bd9Sstevel@tonic-gate } 80237c478bd9Sstevel@tonic-gate 80247c478bd9Sstevel@tonic-gate /* no splits? return right now. */ 80257c478bd9Sstevel@tonic-gate if (nsplits <= 0) 80267c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 80277c478bd9Sstevel@tonic-gate 80287c478bd9Sstevel@tonic-gate /* assign a queue directory to each additional envelope */ 80297c478bd9Sstevel@tonic-gate for (i = 0; i < nsplits; ++i) 80307c478bd9Sstevel@tonic-gate { 80317c478bd9Sstevel@tonic-gate es = splits[i]; 80327c478bd9Sstevel@tonic-gate #if 0 80337c478bd9Sstevel@tonic-gate es->e_qdir = pickqdir(Queue[es->e_qgrp], es->e_msgsize, es); 80347c478bd9Sstevel@tonic-gate #endif /* 0 */ 80357c478bd9Sstevel@tonic-gate if (!setnewqueue(es)) 80367c478bd9Sstevel@tonic-gate goto failure; 80377c478bd9Sstevel@tonic-gate } 80387c478bd9Sstevel@tonic-gate 80397c478bd9Sstevel@tonic-gate /* sort the additional envelopes by queue file system */ 80407c478bd9Sstevel@tonic-gate qsort(splits, nsplits, sizeof(ENVELOPE *), e_filesys_compare); 80417c478bd9Sstevel@tonic-gate 80427c478bd9Sstevel@tonic-gate /* create data files for each additional envelope */ 80437c478bd9Sstevel@tonic-gate if (!dup_df(e, splits[0])) 80447c478bd9Sstevel@tonic-gate { 80457c478bd9Sstevel@tonic-gate i = 0; 80467c478bd9Sstevel@tonic-gate goto failure; 80477c478bd9Sstevel@tonic-gate } 80487c478bd9Sstevel@tonic-gate for (i = 1; i < nsplits; ++i) 80497c478bd9Sstevel@tonic-gate { 80507c478bd9Sstevel@tonic-gate /* copy or link to the previous data file */ 80517c478bd9Sstevel@tonic-gate if (!dup_df(splits[i - 1], splits[i])) 80527c478bd9Sstevel@tonic-gate goto failure; 80537c478bd9Sstevel@tonic-gate } 80547c478bd9Sstevel@tonic-gate 80557c478bd9Sstevel@tonic-gate /* success: prepend the new envelopes to the e->e_sibling list */ 80567c478bd9Sstevel@tonic-gate for (i = 0; i < nsplits; ++i) 80577c478bd9Sstevel@tonic-gate { 80587c478bd9Sstevel@tonic-gate es = splits[i]; 80597c478bd9Sstevel@tonic-gate es->e_sibling = e->e_sibling; 80607c478bd9Sstevel@tonic-gate e->e_sibling = es; 80617c478bd9Sstevel@tonic-gate } 80627c478bd9Sstevel@tonic-gate return SM_SPLIT_NEW(nsplits); 80637c478bd9Sstevel@tonic-gate 80647c478bd9Sstevel@tonic-gate /* failure: clean up */ 80657c478bd9Sstevel@tonic-gate failure: 80667c478bd9Sstevel@tonic-gate if (i > 0) 80677c478bd9Sstevel@tonic-gate { 80687c478bd9Sstevel@tonic-gate int j; 80697c478bd9Sstevel@tonic-gate 80707c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++) 80717c478bd9Sstevel@tonic-gate (void) unlink(queuename(splits[j], DATAFL_LETTER)); 80727c478bd9Sstevel@tonic-gate } 80737c478bd9Sstevel@tonic-gate e->e_sendqueue = addrs[0]; 80747c478bd9Sstevel@tonic-gate for (i = 0; i < naddrs - 1; ++i) 80757c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1]; 80767c478bd9Sstevel@tonic-gate addrs[naddrs - 1]->q_next = NULL; 80777c478bd9Sstevel@tonic-gate return SM_SPLIT_FAIL; 80787c478bd9Sstevel@tonic-gate } 80797c478bd9Sstevel@tonic-gate 80807c478bd9Sstevel@tonic-gate /* 80817c478bd9Sstevel@tonic-gate ** SPLIT_WITHIN_QUEUE 80827c478bd9Sstevel@tonic-gate ** 80837c478bd9Sstevel@tonic-gate ** Split an envelope with multiple recipients into several 80847c478bd9Sstevel@tonic-gate ** envelopes within the same queue directory, if the number of 80857c478bd9Sstevel@tonic-gate ** recipients exceeds the limit for the queue group. 80867c478bd9Sstevel@tonic-gate ** 80877c478bd9Sstevel@tonic-gate ** Parameters: 80887c478bd9Sstevel@tonic-gate ** e -- envelope. 80897c478bd9Sstevel@tonic-gate ** 80907c478bd9Sstevel@tonic-gate ** Results: 80917c478bd9Sstevel@tonic-gate ** SM_SPLIT_FAIL on failure 80927c478bd9Sstevel@tonic-gate ** SM_SPLIT_NONE if no splitting occurred, 80937c478bd9Sstevel@tonic-gate ** or 1 + the number of additional envelopes created. 80947c478bd9Sstevel@tonic-gate */ 80957c478bd9Sstevel@tonic-gate 80967c478bd9Sstevel@tonic-gate #define SPLIT_LOG_LEVEL 8 80977c478bd9Sstevel@tonic-gate 80987c478bd9Sstevel@tonic-gate static int split_within_queue __P((ENVELOPE *)); 80997c478bd9Sstevel@tonic-gate 81007c478bd9Sstevel@tonic-gate static int 81017c478bd9Sstevel@tonic-gate split_within_queue(e) 81027c478bd9Sstevel@tonic-gate ENVELOPE *e; 81037c478bd9Sstevel@tonic-gate { 81047c478bd9Sstevel@tonic-gate int maxrcpt, nrcpt, ndead, nsplit, i; 81057c478bd9Sstevel@tonic-gate int j, l; 81067c478bd9Sstevel@tonic-gate char *lsplits; 81077c478bd9Sstevel@tonic-gate ADDRESS *q, **addrs; 81087c478bd9Sstevel@tonic-gate ENVELOPE *ee, *firstsibling; 81097c478bd9Sstevel@tonic-gate 81107c478bd9Sstevel@tonic-gate if (!ISVALIDQGRP(e->e_qgrp) || bitset(EF_SPLIT, e->e_flags)) 81117c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 81127c478bd9Sstevel@tonic-gate 81137c478bd9Sstevel@tonic-gate /* don't bother if there is no recipient limit */ 81147c478bd9Sstevel@tonic-gate maxrcpt = Queue[e->e_qgrp]->qg_maxrcpt; 81157c478bd9Sstevel@tonic-gate if (maxrcpt <= 0) 81167c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 81177c478bd9Sstevel@tonic-gate 81187c478bd9Sstevel@tonic-gate /* count recipients */ 81197c478bd9Sstevel@tonic-gate nrcpt = 0; 81207c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 81217c478bd9Sstevel@tonic-gate { 81227c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 81237c478bd9Sstevel@tonic-gate continue; 81247c478bd9Sstevel@tonic-gate ++nrcpt; 81257c478bd9Sstevel@tonic-gate } 81267c478bd9Sstevel@tonic-gate if (nrcpt <= maxrcpt) 81277c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 81287c478bd9Sstevel@tonic-gate 81297c478bd9Sstevel@tonic-gate /* 81307c478bd9Sstevel@tonic-gate ** Preserve the recipient list 81317c478bd9Sstevel@tonic-gate ** so that we can restore it in case of error. 81327c478bd9Sstevel@tonic-gate ** (But we discard dead addresses.) 81337c478bd9Sstevel@tonic-gate */ 81347c478bd9Sstevel@tonic-gate 81357c478bd9Sstevel@tonic-gate addrs = sm_rpool_malloc_x(e->e_rpool, nrcpt * sizeof(ADDRESS *)); 81367c478bd9Sstevel@tonic-gate for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next) 81377c478bd9Sstevel@tonic-gate { 81387c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 81397c478bd9Sstevel@tonic-gate continue; 81407c478bd9Sstevel@tonic-gate addrs[i++] = q; 81417c478bd9Sstevel@tonic-gate } 81427c478bd9Sstevel@tonic-gate 81437c478bd9Sstevel@tonic-gate /* 81447c478bd9Sstevel@tonic-gate ** Partition the recipient list so that bad and sent addresses 81457c478bd9Sstevel@tonic-gate ** come first. These will go with the original envelope, and 81467c478bd9Sstevel@tonic-gate ** do not count towards the maxrcpt limit. 81477c478bd9Sstevel@tonic-gate ** addrs[] does not contain QS_IS_DEAD() addresses. 81487c478bd9Sstevel@tonic-gate */ 81497c478bd9Sstevel@tonic-gate 81507c478bd9Sstevel@tonic-gate ndead = 0; 81517c478bd9Sstevel@tonic-gate for (i = 0; i < nrcpt; ++i) 81527c478bd9Sstevel@tonic-gate { 81537c478bd9Sstevel@tonic-gate if (QS_IS_BADADDR(addrs[i]->q_state) || 81547c478bd9Sstevel@tonic-gate QS_IS_SENT(addrs[i]->q_state) || 81557c478bd9Sstevel@tonic-gate QS_IS_DEAD(addrs[i]->q_state)) /* for paranoia's sake */ 81567c478bd9Sstevel@tonic-gate { 81577c478bd9Sstevel@tonic-gate if (i > ndead) 81587c478bd9Sstevel@tonic-gate { 81597c478bd9Sstevel@tonic-gate ADDRESS *tmp = addrs[i]; 81607c478bd9Sstevel@tonic-gate 81617c478bd9Sstevel@tonic-gate addrs[i] = addrs[ndead]; 81627c478bd9Sstevel@tonic-gate addrs[ndead] = tmp; 81637c478bd9Sstevel@tonic-gate } 81647c478bd9Sstevel@tonic-gate ++ndead; 81657c478bd9Sstevel@tonic-gate } 81667c478bd9Sstevel@tonic-gate } 81677c478bd9Sstevel@tonic-gate 81687c478bd9Sstevel@tonic-gate /* Check if no splitting required. */ 81697c478bd9Sstevel@tonic-gate if (nrcpt - ndead <= maxrcpt) 81707c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 81717c478bd9Sstevel@tonic-gate 81727c478bd9Sstevel@tonic-gate /* fix links */ 81737c478bd9Sstevel@tonic-gate for (i = 0; i < nrcpt - 1; ++i) 81747c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1]; 81757c478bd9Sstevel@tonic-gate addrs[nrcpt - 1]->q_next = NULL; 81767c478bd9Sstevel@tonic-gate e->e_sendqueue = addrs[0]; 81777c478bd9Sstevel@tonic-gate 81787c478bd9Sstevel@tonic-gate /* prepare buffer for logging */ 81797c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL) 81807c478bd9Sstevel@tonic-gate { 81817c478bd9Sstevel@tonic-gate l = MAXLINE; 81827c478bd9Sstevel@tonic-gate lsplits = sm_malloc(l); 81837c478bd9Sstevel@tonic-gate if (lsplits != NULL) 81847c478bd9Sstevel@tonic-gate *lsplits = '\0'; 81857c478bd9Sstevel@tonic-gate j = 0; 81867c478bd9Sstevel@tonic-gate } 81877c478bd9Sstevel@tonic-gate else 81887c478bd9Sstevel@tonic-gate { 81897c478bd9Sstevel@tonic-gate /* get rid of stupid compiler warnings */ 81907c478bd9Sstevel@tonic-gate lsplits = NULL; 81917c478bd9Sstevel@tonic-gate j = l = 0; 81927c478bd9Sstevel@tonic-gate } 81937c478bd9Sstevel@tonic-gate 81947c478bd9Sstevel@tonic-gate /* split the envelope */ 81957c478bd9Sstevel@tonic-gate firstsibling = e->e_sibling; 81967c478bd9Sstevel@tonic-gate i = maxrcpt + ndead; 81977c478bd9Sstevel@tonic-gate nsplit = 0; 81987c478bd9Sstevel@tonic-gate for (;;) 81997c478bd9Sstevel@tonic-gate { 82007c478bd9Sstevel@tonic-gate addrs[i - 1]->q_next = NULL; 82017c478bd9Sstevel@tonic-gate ee = split_env(e, addrs[i], e->e_qgrp, e->e_qdir); 82027c478bd9Sstevel@tonic-gate if (!dup_df(e, ee)) 82037c478bd9Sstevel@tonic-gate { 82047c478bd9Sstevel@tonic-gate 82057c478bd9Sstevel@tonic-gate ee = firstsibling; 82067c478bd9Sstevel@tonic-gate while (ee != NULL) 82077c478bd9Sstevel@tonic-gate { 82087c478bd9Sstevel@tonic-gate (void) unlink(queuename(ee, DATAFL_LETTER)); 82097c478bd9Sstevel@tonic-gate ee = ee->e_sibling; 82107c478bd9Sstevel@tonic-gate } 82117c478bd9Sstevel@tonic-gate 82127c478bd9Sstevel@tonic-gate /* Error. Restore e's sibling & recipient lists. */ 82137c478bd9Sstevel@tonic-gate e->e_sibling = firstsibling; 82147c478bd9Sstevel@tonic-gate for (i = 0; i < nrcpt - 1; ++i) 82157c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1]; 82167c478bd9Sstevel@tonic-gate if (lsplits != NULL) 82177c478bd9Sstevel@tonic-gate sm_free(lsplits); 82187c478bd9Sstevel@tonic-gate return SM_SPLIT_FAIL; 82197c478bd9Sstevel@tonic-gate } 82207c478bd9Sstevel@tonic-gate 82217c478bd9Sstevel@tonic-gate /* prepend the new envelope to e->e_sibling */ 82227c478bd9Sstevel@tonic-gate ee->e_sibling = e->e_sibling; 82237c478bd9Sstevel@tonic-gate e->e_sibling = ee; 82247c478bd9Sstevel@tonic-gate ++nsplit; 82257c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL) 82267c478bd9Sstevel@tonic-gate { 82277c478bd9Sstevel@tonic-gate if (j >= l - strlen(ee->e_id) - 3) 82287c478bd9Sstevel@tonic-gate { 82297c478bd9Sstevel@tonic-gate char *p; 82307c478bd9Sstevel@tonic-gate 82317c478bd9Sstevel@tonic-gate l += MAXLINE; 82327c478bd9Sstevel@tonic-gate p = sm_realloc(lsplits, l); 82337c478bd9Sstevel@tonic-gate if (p == NULL) 82347c478bd9Sstevel@tonic-gate { 82357c478bd9Sstevel@tonic-gate /* let's try to get this done */ 82367c478bd9Sstevel@tonic-gate sm_free(lsplits); 82377c478bd9Sstevel@tonic-gate lsplits = NULL; 82387c478bd9Sstevel@tonic-gate } 82397c478bd9Sstevel@tonic-gate else 82407c478bd9Sstevel@tonic-gate lsplits = p; 82417c478bd9Sstevel@tonic-gate } 82427c478bd9Sstevel@tonic-gate if (lsplits != NULL) 82437c478bd9Sstevel@tonic-gate { 82447c478bd9Sstevel@tonic-gate if (j == 0) 82457c478bd9Sstevel@tonic-gate j += sm_strlcat(lsplits + j, 82467c478bd9Sstevel@tonic-gate ee->e_id, 82477c478bd9Sstevel@tonic-gate l - j); 82487c478bd9Sstevel@tonic-gate else 82497c478bd9Sstevel@tonic-gate j += sm_strlcat2(lsplits + j, 82507c478bd9Sstevel@tonic-gate "; ", 82517c478bd9Sstevel@tonic-gate ee->e_id, 82527c478bd9Sstevel@tonic-gate l - j); 82537c478bd9Sstevel@tonic-gate SM_ASSERT(j < l); 82547c478bd9Sstevel@tonic-gate } 82557c478bd9Sstevel@tonic-gate } 82567c478bd9Sstevel@tonic-gate if (nrcpt - i <= maxrcpt) 82577c478bd9Sstevel@tonic-gate break; 82587c478bd9Sstevel@tonic-gate i += maxrcpt; 82597c478bd9Sstevel@tonic-gate } 82607c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL) 82617c478bd9Sstevel@tonic-gate { 82627c478bd9Sstevel@tonic-gate if (nsplit > 0) 82637c478bd9Sstevel@tonic-gate { 82647c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id, 82657c478bd9Sstevel@tonic-gate "split: maxrcpts=%d, rcpts=%d, count=%d, id%s=%s", 82667c478bd9Sstevel@tonic-gate maxrcpt, nrcpt - ndead, nsplit, 82677c478bd9Sstevel@tonic-gate nsplit > 1 ? "s" : "", lsplits); 82687c478bd9Sstevel@tonic-gate } 82697c478bd9Sstevel@tonic-gate sm_free(lsplits); 82707c478bd9Sstevel@tonic-gate } 82717c478bd9Sstevel@tonic-gate return SM_SPLIT_NEW(nsplit); 82727c478bd9Sstevel@tonic-gate } 82737c478bd9Sstevel@tonic-gate /* 82747c478bd9Sstevel@tonic-gate ** SPLIT_BY_RECIPIENT 82757c478bd9Sstevel@tonic-gate ** 82767c478bd9Sstevel@tonic-gate ** Split an envelope with multiple recipients into multiple 82777c478bd9Sstevel@tonic-gate ** envelopes as required by the sendmail configuration. 82787c478bd9Sstevel@tonic-gate ** 82797c478bd9Sstevel@tonic-gate ** Parameters: 82807c478bd9Sstevel@tonic-gate ** e -- envelope. 82817c478bd9Sstevel@tonic-gate ** 82827c478bd9Sstevel@tonic-gate ** Results: 82837c478bd9Sstevel@tonic-gate ** Returns true on success, false on failure. 82847c478bd9Sstevel@tonic-gate ** 82857c478bd9Sstevel@tonic-gate ** Side Effects: 82867c478bd9Sstevel@tonic-gate ** see split_across_queue_groups(), split_within_queue(e) 82877c478bd9Sstevel@tonic-gate */ 82887c478bd9Sstevel@tonic-gate 82897c478bd9Sstevel@tonic-gate bool 82907c478bd9Sstevel@tonic-gate split_by_recipient(e) 82917c478bd9Sstevel@tonic-gate ENVELOPE *e; 82927c478bd9Sstevel@tonic-gate { 82937c478bd9Sstevel@tonic-gate int split, n, i, j, l; 82947c478bd9Sstevel@tonic-gate char *lsplits; 82957c478bd9Sstevel@tonic-gate ENVELOPE *ee, *next, *firstsibling; 82967c478bd9Sstevel@tonic-gate 82977c478bd9Sstevel@tonic-gate if (OpMode == SM_VERIFY || !ISVALIDQGRP(e->e_qgrp) || 82987c478bd9Sstevel@tonic-gate bitset(EF_SPLIT, e->e_flags)) 82997c478bd9Sstevel@tonic-gate return true; 83007c478bd9Sstevel@tonic-gate n = split_across_queue_groups(e); 83017c478bd9Sstevel@tonic-gate if (n == SM_SPLIT_FAIL) 83027c478bd9Sstevel@tonic-gate return false; 83037c478bd9Sstevel@tonic-gate firstsibling = ee = e->e_sibling; 83047c478bd9Sstevel@tonic-gate if (n > 1 && LogLevel > SPLIT_LOG_LEVEL) 83057c478bd9Sstevel@tonic-gate { 83067c478bd9Sstevel@tonic-gate l = MAXLINE; 83077c478bd9Sstevel@tonic-gate lsplits = sm_malloc(l); 83087c478bd9Sstevel@tonic-gate if (lsplits != NULL) 83097c478bd9Sstevel@tonic-gate *lsplits = '\0'; 83107c478bd9Sstevel@tonic-gate j = 0; 83117c478bd9Sstevel@tonic-gate } 83127c478bd9Sstevel@tonic-gate else 83137c478bd9Sstevel@tonic-gate { 83147c478bd9Sstevel@tonic-gate /* get rid of stupid compiler warnings */ 83157c478bd9Sstevel@tonic-gate lsplits = NULL; 83167c478bd9Sstevel@tonic-gate j = l = 0; 83177c478bd9Sstevel@tonic-gate } 83187c478bd9Sstevel@tonic-gate for (i = 1; i < n; ++i) 83197c478bd9Sstevel@tonic-gate { 83207c478bd9Sstevel@tonic-gate next = ee->e_sibling; 83217c478bd9Sstevel@tonic-gate if (split_within_queue(ee) == SM_SPLIT_FAIL) 83227c478bd9Sstevel@tonic-gate { 83237c478bd9Sstevel@tonic-gate e->e_sibling = firstsibling; 83247c478bd9Sstevel@tonic-gate return false; 83257c478bd9Sstevel@tonic-gate } 83267c478bd9Sstevel@tonic-gate ee->e_flags |= EF_SPLIT; 83277c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL) 83287c478bd9Sstevel@tonic-gate { 83297c478bd9Sstevel@tonic-gate if (j >= l - strlen(ee->e_id) - 3) 83307c478bd9Sstevel@tonic-gate { 83317c478bd9Sstevel@tonic-gate char *p; 83327c478bd9Sstevel@tonic-gate 83337c478bd9Sstevel@tonic-gate l += MAXLINE; 83347c478bd9Sstevel@tonic-gate p = sm_realloc(lsplits, l); 83357c478bd9Sstevel@tonic-gate if (p == NULL) 83367c478bd9Sstevel@tonic-gate { 83377c478bd9Sstevel@tonic-gate /* let's try to get this done */ 83387c478bd9Sstevel@tonic-gate sm_free(lsplits); 83397c478bd9Sstevel@tonic-gate lsplits = NULL; 83407c478bd9Sstevel@tonic-gate } 83417c478bd9Sstevel@tonic-gate else 83427c478bd9Sstevel@tonic-gate lsplits = p; 83437c478bd9Sstevel@tonic-gate } 83447c478bd9Sstevel@tonic-gate if (lsplits != NULL) 83457c478bd9Sstevel@tonic-gate { 83467c478bd9Sstevel@tonic-gate if (j == 0) 83477c478bd9Sstevel@tonic-gate j += sm_strlcat(lsplits + j, 83487c478bd9Sstevel@tonic-gate ee->e_id, l - j); 83497c478bd9Sstevel@tonic-gate else 83507c478bd9Sstevel@tonic-gate j += sm_strlcat2(lsplits + j, "; ", 83517c478bd9Sstevel@tonic-gate ee->e_id, l - j); 83527c478bd9Sstevel@tonic-gate SM_ASSERT(j < l); 83537c478bd9Sstevel@tonic-gate } 83547c478bd9Sstevel@tonic-gate } 83557c478bd9Sstevel@tonic-gate ee = next; 83567c478bd9Sstevel@tonic-gate } 83577c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL && n > 1) 83587c478bd9Sstevel@tonic-gate { 83597c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id, "split: count=%d, id%s=%s", 83607c478bd9Sstevel@tonic-gate n - 1, n > 2 ? "s" : "", lsplits); 83617c478bd9Sstevel@tonic-gate sm_free(lsplits); 83627c478bd9Sstevel@tonic-gate } 83637c478bd9Sstevel@tonic-gate split = split_within_queue(e) != SM_SPLIT_FAIL; 83647c478bd9Sstevel@tonic-gate if (split) 83657c478bd9Sstevel@tonic-gate e->e_flags |= EF_SPLIT; 83667c478bd9Sstevel@tonic-gate return split; 83677c478bd9Sstevel@tonic-gate } 83687c478bd9Sstevel@tonic-gate 83697c478bd9Sstevel@tonic-gate /* 83707c478bd9Sstevel@tonic-gate ** QUARANTINE_QUEUE_ITEM -- {un,}quarantine a single envelope 83717c478bd9Sstevel@tonic-gate ** 83727c478bd9Sstevel@tonic-gate ** Add/remove quarantine reason and requeue appropriately. 83737c478bd9Sstevel@tonic-gate ** 83747c478bd9Sstevel@tonic-gate ** Parameters: 83757c478bd9Sstevel@tonic-gate ** qgrp -- queue group for the item 83767c478bd9Sstevel@tonic-gate ** qdir -- queue directory in the given queue group 83777c478bd9Sstevel@tonic-gate ** e -- envelope information for the item 83787c478bd9Sstevel@tonic-gate ** reason -- quarantine reason, NULL means unquarantine. 83797c478bd9Sstevel@tonic-gate ** 83807c478bd9Sstevel@tonic-gate ** Results: 83817c478bd9Sstevel@tonic-gate ** true if item changed, false otherwise 83827c478bd9Sstevel@tonic-gate ** 83837c478bd9Sstevel@tonic-gate ** Side Effects: 83847c478bd9Sstevel@tonic-gate ** Changes quarantine tag in queue file and renames it. 83857c478bd9Sstevel@tonic-gate */ 83867c478bd9Sstevel@tonic-gate 83877c478bd9Sstevel@tonic-gate static bool 83887c478bd9Sstevel@tonic-gate quarantine_queue_item(qgrp, qdir, e, reason) 83897c478bd9Sstevel@tonic-gate int qgrp; 83907c478bd9Sstevel@tonic-gate int qdir; 83917c478bd9Sstevel@tonic-gate ENVELOPE *e; 83927c478bd9Sstevel@tonic-gate char *reason; 83937c478bd9Sstevel@tonic-gate { 83947c478bd9Sstevel@tonic-gate bool dirty = false; 83957c478bd9Sstevel@tonic-gate bool failing = false; 83967c478bd9Sstevel@tonic-gate bool foundq = false; 83977c478bd9Sstevel@tonic-gate bool finished = false; 83987c478bd9Sstevel@tonic-gate int fd; 83997c478bd9Sstevel@tonic-gate int flags; 84007c478bd9Sstevel@tonic-gate int oldtype; 84017c478bd9Sstevel@tonic-gate int newtype; 84027c478bd9Sstevel@tonic-gate int save_errno; 84037c478bd9Sstevel@tonic-gate MODE_T oldumask = 0; 84047c478bd9Sstevel@tonic-gate SM_FILE_T *oldqfp, *tempqfp; 84057c478bd9Sstevel@tonic-gate char *bp; 84067c478bd9Sstevel@tonic-gate char oldqf[MAXPATHLEN]; 84077c478bd9Sstevel@tonic-gate char tempqf[MAXPATHLEN]; 84087c478bd9Sstevel@tonic-gate char newqf[MAXPATHLEN]; 84097c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 84107c478bd9Sstevel@tonic-gate 84117c478bd9Sstevel@tonic-gate oldtype = queue_letter(e, ANYQFL_LETTER); 84127c478bd9Sstevel@tonic-gate (void) sm_strlcpy(oldqf, queuename(e, ANYQFL_LETTER), sizeof oldqf); 84137c478bd9Sstevel@tonic-gate (void) sm_strlcpy(tempqf, queuename(e, NEWQFL_LETTER), sizeof tempqf); 84147c478bd9Sstevel@tonic-gate 84157c478bd9Sstevel@tonic-gate /* 84167c478bd9Sstevel@tonic-gate ** Instead of duplicating all the open 84177c478bd9Sstevel@tonic-gate ** and lock code here, tell readqf() to 84187c478bd9Sstevel@tonic-gate ** do that work and return the open 84197c478bd9Sstevel@tonic-gate ** file pointer in e_lockfp. Note that 84207c478bd9Sstevel@tonic-gate ** we must release the locks properly when 84217c478bd9Sstevel@tonic-gate ** we are done. 84227c478bd9Sstevel@tonic-gate */ 84237c478bd9Sstevel@tonic-gate 84247c478bd9Sstevel@tonic-gate if (!readqf(e, true)) 84257c478bd9Sstevel@tonic-gate { 84267c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 84277c478bd9Sstevel@tonic-gate "Skipping %s\n", qid_printname(e)); 84287c478bd9Sstevel@tonic-gate return false; 84297c478bd9Sstevel@tonic-gate } 84307c478bd9Sstevel@tonic-gate oldqfp = e->e_lockfp; 84317c478bd9Sstevel@tonic-gate 84327c478bd9Sstevel@tonic-gate /* open the new queue file */ 84337c478bd9Sstevel@tonic-gate flags = O_CREAT|O_WRONLY|O_EXCL; 84347c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 84357c478bd9Sstevel@tonic-gate oldumask = umask(002); 84367c478bd9Sstevel@tonic-gate fd = open(tempqf, flags, QueueFileMode); 84377c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 84387c478bd9Sstevel@tonic-gate (void) umask(oldumask); 84397c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 84407c478bd9Sstevel@tonic-gate 84417c478bd9Sstevel@tonic-gate if (fd < 0) 84427c478bd9Sstevel@tonic-gate { 84437c478bd9Sstevel@tonic-gate save_errno = errno; 84447c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 84457c478bd9Sstevel@tonic-gate "Skipping %s: Could not open %s: %s\n", 84467c478bd9Sstevel@tonic-gate qid_printname(e), tempqf, 84477c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 84487c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT); 84497c478bd9Sstevel@tonic-gate return false; 84507c478bd9Sstevel@tonic-gate } 84517c478bd9Sstevel@tonic-gate if (!lockfile(fd, tempqf, NULL, LOCK_EX|LOCK_NB)) 84527c478bd9Sstevel@tonic-gate { 84537c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 84547c478bd9Sstevel@tonic-gate "Skipping %s: Could not lock %s\n", 84557c478bd9Sstevel@tonic-gate qid_printname(e), tempqf); 84567c478bd9Sstevel@tonic-gate (void) close(fd); 84577c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT); 84587c478bd9Sstevel@tonic-gate return false; 84597c478bd9Sstevel@tonic-gate } 84607c478bd9Sstevel@tonic-gate 84617c478bd9Sstevel@tonic-gate tempqfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &fd, 84627c478bd9Sstevel@tonic-gate SM_IO_WRONLY_B, NULL); 84637c478bd9Sstevel@tonic-gate if (tempqfp == NULL) 84647c478bd9Sstevel@tonic-gate { 84657c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 84667c478bd9Sstevel@tonic-gate "Skipping %s: Could not lock %s\n", 84677c478bd9Sstevel@tonic-gate qid_printname(e), tempqf); 84687c478bd9Sstevel@tonic-gate (void) close(fd); 84697c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT); 84707c478bd9Sstevel@tonic-gate return false; 84717c478bd9Sstevel@tonic-gate } 84727c478bd9Sstevel@tonic-gate 84737c478bd9Sstevel@tonic-gate /* Copy the data over, changing the quarantine reason */ 84747c478bd9Sstevel@tonic-gate while ((bp = fgetfolded(buf, sizeof buf, oldqfp)) != NULL) 84757c478bd9Sstevel@tonic-gate { 84767c478bd9Sstevel@tonic-gate if (tTd(40, 4)) 84777c478bd9Sstevel@tonic-gate sm_dprintf("+++++ %s\n", bp); 84787c478bd9Sstevel@tonic-gate switch (bp[0]) 84797c478bd9Sstevel@tonic-gate { 84807c478bd9Sstevel@tonic-gate case 'q': /* quarantine reason */ 84817c478bd9Sstevel@tonic-gate foundq = true; 84827c478bd9Sstevel@tonic-gate if (reason == NULL) 84837c478bd9Sstevel@tonic-gate { 84847c478bd9Sstevel@tonic-gate if (Verbose) 84857c478bd9Sstevel@tonic-gate { 84867c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 84877c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 84887c478bd9Sstevel@tonic-gate "%s: Removed quarantine of \"%s\"\n", 84897c478bd9Sstevel@tonic-gate e->e_id, &bp[1]); 84907c478bd9Sstevel@tonic-gate } 84917c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "unquarantine"); 84927c478bd9Sstevel@tonic-gate dirty = true; 84937c478bd9Sstevel@tonic-gate continue; 84947c478bd9Sstevel@tonic-gate } 84957c478bd9Sstevel@tonic-gate else if (strcmp(reason, &bp[1]) == 0) 84967c478bd9Sstevel@tonic-gate { 84977c478bd9Sstevel@tonic-gate if (Verbose) 84987c478bd9Sstevel@tonic-gate { 84997c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 85007c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 85017c478bd9Sstevel@tonic-gate "%s: Already quarantined with \"%s\"\n", 85027c478bd9Sstevel@tonic-gate e->e_id, reason); 85037c478bd9Sstevel@tonic-gate } 85047c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 85057c478bd9Sstevel@tonic-gate "q%s\n", reason); 85067c478bd9Sstevel@tonic-gate } 85077c478bd9Sstevel@tonic-gate else 85087c478bd9Sstevel@tonic-gate { 85097c478bd9Sstevel@tonic-gate if (Verbose) 85107c478bd9Sstevel@tonic-gate { 85117c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 85127c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 85137c478bd9Sstevel@tonic-gate "%s: Quarantine changed from \"%s\" to \"%s\"\n", 85147c478bd9Sstevel@tonic-gate e->e_id, &bp[1], 85157c478bd9Sstevel@tonic-gate reason); 85167c478bd9Sstevel@tonic-gate } 85177c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 85187c478bd9Sstevel@tonic-gate "q%s\n", reason); 85197c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "quarantine=%s", 85207c478bd9Sstevel@tonic-gate reason); 85217c478bd9Sstevel@tonic-gate dirty = true; 85227c478bd9Sstevel@tonic-gate } 85237c478bd9Sstevel@tonic-gate break; 85247c478bd9Sstevel@tonic-gate 85257c478bd9Sstevel@tonic-gate case 'S': 85267c478bd9Sstevel@tonic-gate /* 85277c478bd9Sstevel@tonic-gate ** If we are quarantining an unquarantined item, 85287c478bd9Sstevel@tonic-gate ** need to put in a new 'q' line before it's 85297c478bd9Sstevel@tonic-gate ** too late. 85307c478bd9Sstevel@tonic-gate */ 85317c478bd9Sstevel@tonic-gate 85327c478bd9Sstevel@tonic-gate if (!foundq && reason != NULL) 85337c478bd9Sstevel@tonic-gate { 85347c478bd9Sstevel@tonic-gate if (Verbose) 85357c478bd9Sstevel@tonic-gate { 85367c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 85377c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 85387c478bd9Sstevel@tonic-gate "%s: Quarantined with \"%s\"\n", 85397c478bd9Sstevel@tonic-gate e->e_id, reason); 85407c478bd9Sstevel@tonic-gate } 85417c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 85427c478bd9Sstevel@tonic-gate "q%s\n", reason); 85437c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "quarantine=%s", 85447c478bd9Sstevel@tonic-gate reason); 85457c478bd9Sstevel@tonic-gate foundq = true; 85467c478bd9Sstevel@tonic-gate dirty = true; 85477c478bd9Sstevel@tonic-gate } 85487c478bd9Sstevel@tonic-gate 85497c478bd9Sstevel@tonic-gate /* Copy the line to the new file */ 85507c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 85517c478bd9Sstevel@tonic-gate "%s\n", bp); 85527c478bd9Sstevel@tonic-gate break; 85537c478bd9Sstevel@tonic-gate 85547c478bd9Sstevel@tonic-gate case '.': 85557c478bd9Sstevel@tonic-gate finished = true; 85567c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 85577c478bd9Sstevel@tonic-gate 85587c478bd9Sstevel@tonic-gate default: 85597c478bd9Sstevel@tonic-gate /* Copy the line to the new file */ 85607c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 85617c478bd9Sstevel@tonic-gate "%s\n", bp); 85627c478bd9Sstevel@tonic-gate break; 85637c478bd9Sstevel@tonic-gate } 85647c478bd9Sstevel@tonic-gate } 85657c478bd9Sstevel@tonic-gate 85667c478bd9Sstevel@tonic-gate /* Make sure we read the whole old file */ 85677c478bd9Sstevel@tonic-gate errno = sm_io_error(tempqfp); 85687c478bd9Sstevel@tonic-gate if (errno != 0 && errno != SM_IO_EOF) 85697c478bd9Sstevel@tonic-gate { 85707c478bd9Sstevel@tonic-gate save_errno = errno; 85717c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 85727c478bd9Sstevel@tonic-gate "Skipping %s: Error reading %s: %s\n", 85737c478bd9Sstevel@tonic-gate qid_printname(e), oldqf, 85747c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 85757c478bd9Sstevel@tonic-gate failing = true; 85767c478bd9Sstevel@tonic-gate } 85777c478bd9Sstevel@tonic-gate 85787c478bd9Sstevel@tonic-gate if (!failing && !finished) 85797c478bd9Sstevel@tonic-gate { 85807c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 85817c478bd9Sstevel@tonic-gate "Skipping %s: Incomplete file: %s\n", 85827c478bd9Sstevel@tonic-gate qid_printname(e), oldqf); 85837c478bd9Sstevel@tonic-gate failing = true; 85847c478bd9Sstevel@tonic-gate } 85857c478bd9Sstevel@tonic-gate 85867c478bd9Sstevel@tonic-gate /* Check if we actually changed anything or we can just bail now */ 85877c478bd9Sstevel@tonic-gate if (!dirty) 85887c478bd9Sstevel@tonic-gate { 85897c478bd9Sstevel@tonic-gate /* pretend we failed, even though we technically didn't */ 85907c478bd9Sstevel@tonic-gate failing = true; 85917c478bd9Sstevel@tonic-gate } 85927c478bd9Sstevel@tonic-gate 85937c478bd9Sstevel@tonic-gate /* Make sure we wrote things out safely */ 85947c478bd9Sstevel@tonic-gate if (!failing && 85957c478bd9Sstevel@tonic-gate (sm_io_flush(tempqfp, SM_TIME_DEFAULT) != 0 || 85967c478bd9Sstevel@tonic-gate ((SuperSafe == SAFE_REALLY || 85977c478bd9Sstevel@tonic-gate SuperSafe == SAFE_REALLY_POSTMILTER || 85987c478bd9Sstevel@tonic-gate SuperSafe == SAFE_INTERACTIVE) && 85997c478bd9Sstevel@tonic-gate fsync(sm_io_getinfo(tempqfp, SM_IO_WHAT_FD, NULL)) < 0) || 86007c478bd9Sstevel@tonic-gate ((errno = sm_io_error(tempqfp)) != 0))) 86017c478bd9Sstevel@tonic-gate { 86027c478bd9Sstevel@tonic-gate save_errno = errno; 86037c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 86047c478bd9Sstevel@tonic-gate "Skipping %s: Error writing %s: %s\n", 86057c478bd9Sstevel@tonic-gate qid_printname(e), tempqf, 86067c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 86077c478bd9Sstevel@tonic-gate failing = true; 86087c478bd9Sstevel@tonic-gate } 86097c478bd9Sstevel@tonic-gate 86107c478bd9Sstevel@tonic-gate 86117c478bd9Sstevel@tonic-gate /* Figure out the new filename */ 86127c478bd9Sstevel@tonic-gate newtype = (reason == NULL ? NORMQF_LETTER : QUARQF_LETTER); 86137c478bd9Sstevel@tonic-gate if (oldtype == newtype) 86147c478bd9Sstevel@tonic-gate { 86157c478bd9Sstevel@tonic-gate /* going to rename tempqf to oldqf */ 86167c478bd9Sstevel@tonic-gate (void) sm_strlcpy(newqf, oldqf, sizeof newqf); 86177c478bd9Sstevel@tonic-gate } 86187c478bd9Sstevel@tonic-gate else 86197c478bd9Sstevel@tonic-gate { 86207c478bd9Sstevel@tonic-gate /* going to rename tempqf to new name based on newtype */ 86217c478bd9Sstevel@tonic-gate (void) sm_strlcpy(newqf, queuename(e, newtype), sizeof newqf); 86227c478bd9Sstevel@tonic-gate } 86237c478bd9Sstevel@tonic-gate 86247c478bd9Sstevel@tonic-gate save_errno = 0; 86257c478bd9Sstevel@tonic-gate 86267c478bd9Sstevel@tonic-gate /* rename tempqf to newqf */ 86277c478bd9Sstevel@tonic-gate if (!failing && 86287c478bd9Sstevel@tonic-gate rename(tempqf, newqf) < 0) 86297c478bd9Sstevel@tonic-gate save_errno = (errno == 0) ? EINVAL : errno; 86307c478bd9Sstevel@tonic-gate 86317c478bd9Sstevel@tonic-gate /* Check rename() success */ 86327c478bd9Sstevel@tonic-gate if (!failing && save_errno != 0) 86337c478bd9Sstevel@tonic-gate { 86347c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, 86357c478bd9Sstevel@tonic-gate "quarantine_queue_item: rename(%s, %s): %s", 86367c478bd9Sstevel@tonic-gate tempqf, newqf, sm_errstring(save_errno)); 86377c478bd9Sstevel@tonic-gate 86387c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 86397c478bd9Sstevel@tonic-gate "Error renaming %s to %s: %s\n", 86407c478bd9Sstevel@tonic-gate tempqf, newqf, 86417c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 86427c478bd9Sstevel@tonic-gate if (oldtype == newtype) 86437c478bd9Sstevel@tonic-gate { 86447c478bd9Sstevel@tonic-gate /* 86457c478bd9Sstevel@tonic-gate ** Bail here since we don't know the state of 86467c478bd9Sstevel@tonic-gate ** the filesystem and may need to keep tempqf 86477c478bd9Sstevel@tonic-gate ** for the user to rescue us. 86487c478bd9Sstevel@tonic-gate */ 86497c478bd9Sstevel@tonic-gate 86507c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 86517c478bd9Sstevel@tonic-gate errno = save_errno; 86527c478bd9Sstevel@tonic-gate syserr("!452 Error renaming control file %s", tempqf); 86537c478bd9Sstevel@tonic-gate /* NOTREACHED */ 86547c478bd9Sstevel@tonic-gate } 86557c478bd9Sstevel@tonic-gate else 86567c478bd9Sstevel@tonic-gate { 86577c478bd9Sstevel@tonic-gate /* remove new file (if rename() half completed) */ 86587c478bd9Sstevel@tonic-gate if (xunlink(newqf) < 0) 86597c478bd9Sstevel@tonic-gate { 86607c478bd9Sstevel@tonic-gate save_errno = errno; 86617c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 86627c478bd9Sstevel@tonic-gate "Error removing %s: %s\n", 86637c478bd9Sstevel@tonic-gate newqf, 86647c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 86657c478bd9Sstevel@tonic-gate } 86667c478bd9Sstevel@tonic-gate 86677c478bd9Sstevel@tonic-gate /* tempqf removed below */ 86687c478bd9Sstevel@tonic-gate failing = true; 86697c478bd9Sstevel@tonic-gate } 86707c478bd9Sstevel@tonic-gate 86717c478bd9Sstevel@tonic-gate } 86727c478bd9Sstevel@tonic-gate 86737c478bd9Sstevel@tonic-gate /* If changing file types, need to remove old type */ 86747c478bd9Sstevel@tonic-gate if (!failing && oldtype != newtype) 86757c478bd9Sstevel@tonic-gate { 86767c478bd9Sstevel@tonic-gate if (xunlink(oldqf) < 0) 86777c478bd9Sstevel@tonic-gate { 86787c478bd9Sstevel@tonic-gate save_errno = errno; 86797c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 86807c478bd9Sstevel@tonic-gate "Error removing %s: %s\n", 86817c478bd9Sstevel@tonic-gate oldqf, sm_errstring(save_errno)); 86827c478bd9Sstevel@tonic-gate } 86837c478bd9Sstevel@tonic-gate } 86847c478bd9Sstevel@tonic-gate 86857c478bd9Sstevel@tonic-gate /* see if anything above failed */ 86867c478bd9Sstevel@tonic-gate if (failing) 86877c478bd9Sstevel@tonic-gate { 86887c478bd9Sstevel@tonic-gate /* Something failed: remove new file, old file still there */ 86897c478bd9Sstevel@tonic-gate (void) xunlink(tempqf); 86907c478bd9Sstevel@tonic-gate } 86917c478bd9Sstevel@tonic-gate 86927c478bd9Sstevel@tonic-gate /* 86937c478bd9Sstevel@tonic-gate ** fsync() after file operations to make sure metadata is 86947c478bd9Sstevel@tonic-gate ** written to disk on filesystems in which renames are 86957c478bd9Sstevel@tonic-gate ** not guaranteed. It's ok if they fail, mail won't be lost. 86967c478bd9Sstevel@tonic-gate */ 86977c478bd9Sstevel@tonic-gate 86987c478bd9Sstevel@tonic-gate if (SuperSafe != SAFE_NO) 86997c478bd9Sstevel@tonic-gate { 87007c478bd9Sstevel@tonic-gate /* for soft-updates */ 87017c478bd9Sstevel@tonic-gate (void) fsync(sm_io_getinfo(tempqfp, 87027c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, NULL)); 87037c478bd9Sstevel@tonic-gate 87047c478bd9Sstevel@tonic-gate if (!failing) 87057c478bd9Sstevel@tonic-gate { 87067c478bd9Sstevel@tonic-gate /* for soft-updates */ 87077c478bd9Sstevel@tonic-gate (void) fsync(sm_io_getinfo(oldqfp, 87087c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, NULL)); 87097c478bd9Sstevel@tonic-gate } 87107c478bd9Sstevel@tonic-gate 87117c478bd9Sstevel@tonic-gate /* for other odd filesystems */ 87127c478bd9Sstevel@tonic-gate SYNC_DIR(tempqf, false); 87137c478bd9Sstevel@tonic-gate } 87147c478bd9Sstevel@tonic-gate 87157c478bd9Sstevel@tonic-gate /* Close up shop */ 87167c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 87177c478bd9Sstevel@tonic-gate if (tempqfp != NULL) 87187c478bd9Sstevel@tonic-gate (void) sm_io_close(tempqfp, SM_TIME_DEFAULT); 87197c478bd9Sstevel@tonic-gate if (oldqfp != NULL) 87207c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT); 87217c478bd9Sstevel@tonic-gate 87227c478bd9Sstevel@tonic-gate /* All went well */ 87237c478bd9Sstevel@tonic-gate return !failing; 87247c478bd9Sstevel@tonic-gate } 87257c478bd9Sstevel@tonic-gate 87267c478bd9Sstevel@tonic-gate /* 87277c478bd9Sstevel@tonic-gate ** QUARANTINE_QUEUE -- {un,}quarantine matching items in the queue 87287c478bd9Sstevel@tonic-gate ** 87297c478bd9Sstevel@tonic-gate ** Read all matching queue items, add/remove quarantine 87307c478bd9Sstevel@tonic-gate ** reason, and requeue appropriately. 87317c478bd9Sstevel@tonic-gate ** 87327c478bd9Sstevel@tonic-gate ** Parameters: 87337c478bd9Sstevel@tonic-gate ** reason -- quarantine reason, "." means unquarantine. 87347c478bd9Sstevel@tonic-gate ** qgrplimit -- limit to single queue group unless NOQGRP 87357c478bd9Sstevel@tonic-gate ** 87367c478bd9Sstevel@tonic-gate ** Results: 87377c478bd9Sstevel@tonic-gate ** none. 87387c478bd9Sstevel@tonic-gate ** 87397c478bd9Sstevel@tonic-gate ** Side Effects: 87407c478bd9Sstevel@tonic-gate ** Lots of changes to the queue. 87417c478bd9Sstevel@tonic-gate */ 87427c478bd9Sstevel@tonic-gate 87437c478bd9Sstevel@tonic-gate void 87447c478bd9Sstevel@tonic-gate quarantine_queue(reason, qgrplimit) 87457c478bd9Sstevel@tonic-gate char *reason; 87467c478bd9Sstevel@tonic-gate int qgrplimit; 87477c478bd9Sstevel@tonic-gate { 87487c478bd9Sstevel@tonic-gate int changed = 0; 87497c478bd9Sstevel@tonic-gate int qgrp; 87507c478bd9Sstevel@tonic-gate 87517c478bd9Sstevel@tonic-gate /* Convert internal representation of unquarantine */ 87527c478bd9Sstevel@tonic-gate if (reason != NULL && reason[0] == '.' && reason[1] == '\0') 87537c478bd9Sstevel@tonic-gate reason = NULL; 87547c478bd9Sstevel@tonic-gate 87557c478bd9Sstevel@tonic-gate if (reason != NULL) 87567c478bd9Sstevel@tonic-gate { 87577c478bd9Sstevel@tonic-gate /* clean it */ 87587c478bd9Sstevel@tonic-gate reason = newstr(denlstring(reason, true, true)); 87597c478bd9Sstevel@tonic-gate } 87607c478bd9Sstevel@tonic-gate 87617c478bd9Sstevel@tonic-gate for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++) 87627c478bd9Sstevel@tonic-gate { 87637c478bd9Sstevel@tonic-gate int qdir; 87647c478bd9Sstevel@tonic-gate 87657c478bd9Sstevel@tonic-gate if (qgrplimit != NOQGRP && qgrplimit != qgrp) 87667c478bd9Sstevel@tonic-gate continue; 87677c478bd9Sstevel@tonic-gate 87687c478bd9Sstevel@tonic-gate for (qdir = 0; qdir < Queue[qgrp]->qg_numqueues; qdir++) 87697c478bd9Sstevel@tonic-gate { 87707c478bd9Sstevel@tonic-gate int i; 87717c478bd9Sstevel@tonic-gate int nrequests; 87727c478bd9Sstevel@tonic-gate 87737c478bd9Sstevel@tonic-gate if (StopRequest) 87747c478bd9Sstevel@tonic-gate stop_sendmail(); 87757c478bd9Sstevel@tonic-gate 87767c478bd9Sstevel@tonic-gate nrequests = gatherq(qgrp, qdir, true, NULL, NULL); 87777c478bd9Sstevel@tonic-gate 87787c478bd9Sstevel@tonic-gate /* first see if there is anything */ 87797c478bd9Sstevel@tonic-gate if (nrequests <= 0) 87807c478bd9Sstevel@tonic-gate { 87817c478bd9Sstevel@tonic-gate if (Verbose) 87827c478bd9Sstevel@tonic-gate { 87837c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 87847c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, "%s: no matches\n", 87857c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 87867c478bd9Sstevel@tonic-gate } 87877c478bd9Sstevel@tonic-gate continue; 87887c478bd9Sstevel@tonic-gate } 87897c478bd9Sstevel@tonic-gate 87907c478bd9Sstevel@tonic-gate if (Verbose) 87917c478bd9Sstevel@tonic-gate { 87927c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 87937c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, "Processing %s:\n", 87947c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 87957c478bd9Sstevel@tonic-gate } 87967c478bd9Sstevel@tonic-gate 87977c478bd9Sstevel@tonic-gate for (i = 0; i < WorkListCount; i++) 87987c478bd9Sstevel@tonic-gate { 87997c478bd9Sstevel@tonic-gate ENVELOPE e; 88007c478bd9Sstevel@tonic-gate 88017c478bd9Sstevel@tonic-gate if (StopRequest) 88027c478bd9Sstevel@tonic-gate stop_sendmail(); 88037c478bd9Sstevel@tonic-gate 88047c478bd9Sstevel@tonic-gate /* setup envelope */ 88057c478bd9Sstevel@tonic-gate clearenvelope(&e, true, sm_rpool_new_x(NULL)); 88067c478bd9Sstevel@tonic-gate e.e_id = WorkList[i].w_name + 2; 88077c478bd9Sstevel@tonic-gate e.e_qgrp = qgrp; 88087c478bd9Sstevel@tonic-gate e.e_qdir = qdir; 88097c478bd9Sstevel@tonic-gate 88107c478bd9Sstevel@tonic-gate if (tTd(70, 101)) 88117c478bd9Sstevel@tonic-gate { 88127c478bd9Sstevel@tonic-gate sm_io_fprintf(smioout, SM_TIME_DEFAULT, 88137c478bd9Sstevel@tonic-gate "Would do %s\n", e.e_id); 88147c478bd9Sstevel@tonic-gate changed++; 88157c478bd9Sstevel@tonic-gate } 88167c478bd9Sstevel@tonic-gate else if (quarantine_queue_item(qgrp, qdir, 88177c478bd9Sstevel@tonic-gate &e, reason)) 88187c478bd9Sstevel@tonic-gate changed++; 88197c478bd9Sstevel@tonic-gate 88207c478bd9Sstevel@tonic-gate /* clean up */ 88217c478bd9Sstevel@tonic-gate sm_rpool_free(e.e_rpool); 88227c478bd9Sstevel@tonic-gate e.e_rpool = NULL; 88237c478bd9Sstevel@tonic-gate } 88247c478bd9Sstevel@tonic-gate if (WorkList != NULL) 88257c478bd9Sstevel@tonic-gate sm_free(WorkList); /* XXX */ 88267c478bd9Sstevel@tonic-gate WorkList = NULL; 88277c478bd9Sstevel@tonic-gate WorkListSize = 0; 88287c478bd9Sstevel@tonic-gate WorkListCount = 0; 88297c478bd9Sstevel@tonic-gate } 88307c478bd9Sstevel@tonic-gate } 88317c478bd9Sstevel@tonic-gate if (Verbose) 88327c478bd9Sstevel@tonic-gate { 88337c478bd9Sstevel@tonic-gate if (changed == 0) 88347c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 88357c478bd9Sstevel@tonic-gate "No changes\n"); 88367c478bd9Sstevel@tonic-gate else 88377c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 88387c478bd9Sstevel@tonic-gate "%d change%s\n", 88397c478bd9Sstevel@tonic-gate changed, 88407c478bd9Sstevel@tonic-gate changed == 1 ? "" : "s"); 88417c478bd9Sstevel@tonic-gate } 88427c478bd9Sstevel@tonic-gate } 8843