17c478bd9Sstevel@tonic-gate /* 24aac33d3Sjbeck * Copyright (c) 1998-2007 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*7800901eSjbeck SM_RCSID("@(#)$Id: queue.c,v 8.975 2007/06/18 20:08:40 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 */ 152058561cbSjbeck 153058561cbSjbeck /* 154058561cbSjbeck ** Note: workcmpf?() don't use a prototype because it will cause a conflict 155058561cbSjbeck ** with the qsort() call (which expects something like 156058561cbSjbeck ** int (*compar)(const void *, const void *), not (WORK *, WORK *)) 157058561cbSjbeck */ 158058561cbSjbeck 1597c478bd9Sstevel@tonic-gate static int workcmpf0(); 1607c478bd9Sstevel@tonic-gate static int workcmpf1(); 1617c478bd9Sstevel@tonic-gate static int workcmpf2(); 1627c478bd9Sstevel@tonic-gate static int workcmpf3(); 1637c478bd9Sstevel@tonic-gate static int workcmpf4(); 1647c478bd9Sstevel@tonic-gate static int randi = 3; /* index for workcmpf5() */ 1657c478bd9Sstevel@tonic-gate static int workcmpf5(); 1667c478bd9Sstevel@tonic-gate static int workcmpf6(); 1677c478bd9Sstevel@tonic-gate #if _FFR_RHS 1687c478bd9Sstevel@tonic-gate static int workcmpf7(); 1697c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate #if RANDOMSHIFT 1727c478bd9Sstevel@tonic-gate # define get_rand_mod(m) ((get_random() >> RANDOMSHIFT) % (m)) 1737c478bd9Sstevel@tonic-gate #else /* RANDOMSHIFT */ 1747c478bd9Sstevel@tonic-gate # define get_rand_mod(m) (get_random() % (m)) 1757c478bd9Sstevel@tonic-gate #endif /* RANDOMSHIFT */ 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate /* 1787c478bd9Sstevel@tonic-gate ** File system definition. 1797c478bd9Sstevel@tonic-gate ** Used to keep track of how much free space is available 1807c478bd9Sstevel@tonic-gate ** on a file system in which one or more queue directories reside. 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate typedef struct filesys_shared FILESYS; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate struct filesys_shared 1867c478bd9Sstevel@tonic-gate { 1877c478bd9Sstevel@tonic-gate dev_t fs_dev; /* unique device id */ 1887c478bd9Sstevel@tonic-gate long fs_avail; /* number of free blocks available */ 1897c478bd9Sstevel@tonic-gate long fs_blksize; /* block size, in bytes */ 1907c478bd9Sstevel@tonic-gate }; 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate /* probably kept in shared memory */ 1937c478bd9Sstevel@tonic-gate static FILESYS FileSys[MAXFILESYS]; /* queue file systems */ 194058561cbSjbeck static const char *FSPath[MAXFILESYS]; /* pathnames for file systems */ 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate ** Shared memory data 2007c478bd9Sstevel@tonic-gate ** 2017c478bd9Sstevel@tonic-gate ** Current layout: 2027c478bd9Sstevel@tonic-gate ** size -- size of shared memory segment 2037c478bd9Sstevel@tonic-gate ** pid -- pid of owner, should be a unique id to avoid misinterpretations 2047c478bd9Sstevel@tonic-gate ** by other processes. 2057c478bd9Sstevel@tonic-gate ** tag -- should be a unique id to avoid misinterpretations by others. 2067c478bd9Sstevel@tonic-gate ** idea: hash over configuration data that will be stored here. 2077c478bd9Sstevel@tonic-gate ** NumFileSys -- number of file systems. 2087c478bd9Sstevel@tonic-gate ** FileSys -- (arrary of) structure for used file systems. 2097c478bd9Sstevel@tonic-gate ** RSATmpCnt -- counter for number of uses of ephemeral RSA key. 2107c478bd9Sstevel@tonic-gate ** QShm -- (array of) structure for information about queue directories. 2117c478bd9Sstevel@tonic-gate */ 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate ** Queue data in shared memory 2157c478bd9Sstevel@tonic-gate */ 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate typedef struct queue_shared QUEUE_SHM_T; 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate struct queue_shared 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate int qs_entries; /* number of entries */ 2227c478bd9Sstevel@tonic-gate /* XXX more to follow? */ 2237c478bd9Sstevel@tonic-gate }; 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate static void *Pshm; /* pointer to shared memory */ 2267c478bd9Sstevel@tonic-gate static FILESYS *PtrFileSys; /* pointer to queue file system array */ 2277c478bd9Sstevel@tonic-gate int ShmId = SM_SHM_NO_ID; /* shared memory id */ 2287c478bd9Sstevel@tonic-gate static QUEUE_SHM_T *QShm; /* pointer to shared queue data */ 2297c478bd9Sstevel@tonic-gate static size_t shms; 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate # define SHM_OFF_PID(p) (((char *) (p)) + sizeof(int)) 2327c478bd9Sstevel@tonic-gate # define SHM_OFF_TAG(p) (((char *) (p)) + sizeof(pid_t) + sizeof(int)) 2337c478bd9Sstevel@tonic-gate # define SHM_OFF_HEAD (sizeof(pid_t) + sizeof(int) * 2) 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* how to access FileSys */ 2367c478bd9Sstevel@tonic-gate # define FILE_SYS(i) (PtrFileSys[i]) 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* first entry is a tag, for now just the size */ 2397c478bd9Sstevel@tonic-gate # define OFF_FILE_SYS(p) (((char *) (p)) + SHM_OFF_HEAD) 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate /* offset for PNumFileSys */ 2427c478bd9Sstevel@tonic-gate # define OFF_NUM_FILE_SYS(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys)) 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate /* offset for PRSATmpCnt */ 2457c478bd9Sstevel@tonic-gate # define OFF_RSA_TMP_CNT(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int)) 2467c478bd9Sstevel@tonic-gate int *PRSATmpCnt; 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate /* offset for queue_shm */ 2497c478bd9Sstevel@tonic-gate # define OFF_QUEUE_SHM(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2) 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate # define QSHM_ENTRIES(i) QShm[i].qs_entries 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate /* basic size of shared memory segment */ 2547c478bd9Sstevel@tonic-gate # define SM_T_SIZE (SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2) 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate static unsigned int hash_q __P((char *, unsigned int)); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* 2597c478bd9Sstevel@tonic-gate ** HASH_Q -- simple hash function 2607c478bd9Sstevel@tonic-gate ** 2617c478bd9Sstevel@tonic-gate ** Parameters: 2627c478bd9Sstevel@tonic-gate ** p -- string to hash. 2637c478bd9Sstevel@tonic-gate ** h -- hash start value (from previous run). 2647c478bd9Sstevel@tonic-gate ** 2657c478bd9Sstevel@tonic-gate ** Returns: 2667c478bd9Sstevel@tonic-gate ** hash value. 2677c478bd9Sstevel@tonic-gate */ 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate static unsigned int 2707c478bd9Sstevel@tonic-gate hash_q(p, h) 2717c478bd9Sstevel@tonic-gate char *p; 2727c478bd9Sstevel@tonic-gate unsigned int h; 2737c478bd9Sstevel@tonic-gate { 2747c478bd9Sstevel@tonic-gate int c, d; 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate while (*p != '\0') 2777c478bd9Sstevel@tonic-gate { 2787c478bd9Sstevel@tonic-gate d = *p++; 2797c478bd9Sstevel@tonic-gate c = d; 2807c478bd9Sstevel@tonic-gate c ^= c<<6; 2817c478bd9Sstevel@tonic-gate h += (c<<11) ^ (c>>1); 2827c478bd9Sstevel@tonic-gate h ^= (d<<14) + (d<<7) + (d<<4) + d; 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate return h; 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate #else /* SM_CONF_SHM */ 2897c478bd9Sstevel@tonic-gate # define FILE_SYS(i) FileSys[i] 2907c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate /* access to the various components of file system data */ 2937c478bd9Sstevel@tonic-gate #define FILE_SYS_NAME(i) FSPath[i] 2947c478bd9Sstevel@tonic-gate #define FILE_SYS_AVAIL(i) FILE_SYS(i).fs_avail 2957c478bd9Sstevel@tonic-gate #define FILE_SYS_BLKSIZE(i) FILE_SYS(i).fs_blksize 2967c478bd9Sstevel@tonic-gate #define FILE_SYS_DEV(i) FILE_SYS(i).fs_dev 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate /* 3007c478bd9Sstevel@tonic-gate ** Current qf file field assignments: 3017c478bd9Sstevel@tonic-gate ** 3027c478bd9Sstevel@tonic-gate ** A AUTH= parameter 3037c478bd9Sstevel@tonic-gate ** B body type 3047c478bd9Sstevel@tonic-gate ** C controlling user 3057c478bd9Sstevel@tonic-gate ** D data file name 3067c478bd9Sstevel@tonic-gate ** d data file directory name (added in 8.12) 3077c478bd9Sstevel@tonic-gate ** E error recipient 3087c478bd9Sstevel@tonic-gate ** F flag bits 3097c478bd9Sstevel@tonic-gate ** G free (was: queue delay algorithm if _FFR_QUEUEDELAY) 3107c478bd9Sstevel@tonic-gate ** H header 3117c478bd9Sstevel@tonic-gate ** I data file's inode number 3127c478bd9Sstevel@tonic-gate ** K time of last delivery attempt 3137c478bd9Sstevel@tonic-gate ** L Solaris Content-Length: header (obsolete) 3147c478bd9Sstevel@tonic-gate ** M message 3157c478bd9Sstevel@tonic-gate ** N number of delivery attempts 3167c478bd9Sstevel@tonic-gate ** P message priority 3177c478bd9Sstevel@tonic-gate ** q quarantine reason 3187c478bd9Sstevel@tonic-gate ** Q original recipient (ORCPT=) 3197c478bd9Sstevel@tonic-gate ** r final recipient (Final-Recipient: DSN field) 3207c478bd9Sstevel@tonic-gate ** R recipient 3217c478bd9Sstevel@tonic-gate ** S sender 3227c478bd9Sstevel@tonic-gate ** T init time 3237c478bd9Sstevel@tonic-gate ** V queue file version 3247c478bd9Sstevel@tonic-gate ** X free (was: character set if _FFR_SAVE_CHARSET) 3257c478bd9Sstevel@tonic-gate ** Y free (was: current delay if _FFR_QUEUEDELAY) 3267c478bd9Sstevel@tonic-gate ** Z original envelope id from ESMTP 3277c478bd9Sstevel@tonic-gate ** ! deliver by (added in 8.12) 3287c478bd9Sstevel@tonic-gate ** $ define macro 3297c478bd9Sstevel@tonic-gate ** . terminate file 3307c478bd9Sstevel@tonic-gate */ 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate ** QUEUEUP -- queue a message up for future transmission. 3347c478bd9Sstevel@tonic-gate ** 3357c478bd9Sstevel@tonic-gate ** Parameters: 3367c478bd9Sstevel@tonic-gate ** e -- the envelope to queue up. 3377c478bd9Sstevel@tonic-gate ** announce -- if true, tell when you are queueing up. 3387c478bd9Sstevel@tonic-gate ** msync -- if true, then fsync() if SuperSafe interactive mode. 3397c478bd9Sstevel@tonic-gate ** 3407c478bd9Sstevel@tonic-gate ** Returns: 3417c478bd9Sstevel@tonic-gate ** none. 3427c478bd9Sstevel@tonic-gate ** 3437c478bd9Sstevel@tonic-gate ** Side Effects: 3447c478bd9Sstevel@tonic-gate ** The current request is saved in a control file. 3457c478bd9Sstevel@tonic-gate ** The queue file is left locked. 3467c478bd9Sstevel@tonic-gate */ 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate void 3497c478bd9Sstevel@tonic-gate queueup(e, announce, msync) 3507c478bd9Sstevel@tonic-gate register ENVELOPE *e; 3517c478bd9Sstevel@tonic-gate bool announce; 3527c478bd9Sstevel@tonic-gate bool msync; 3537c478bd9Sstevel@tonic-gate { 3547c478bd9Sstevel@tonic-gate register SM_FILE_T *tfp; 3557c478bd9Sstevel@tonic-gate register HDR *h; 3567c478bd9Sstevel@tonic-gate register ADDRESS *q; 3577c478bd9Sstevel@tonic-gate int tfd = -1; 3587c478bd9Sstevel@tonic-gate int i; 3597c478bd9Sstevel@tonic-gate bool newid; 3607c478bd9Sstevel@tonic-gate register char *p; 3617c478bd9Sstevel@tonic-gate MAILER nullmailer; 3627c478bd9Sstevel@tonic-gate MCI mcibuf; 3637c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN]; 3647c478bd9Sstevel@tonic-gate char tf[MAXPATHLEN]; 3657c478bd9Sstevel@tonic-gate char df[MAXPATHLEN]; 3667c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate ** Create control file. 3707c478bd9Sstevel@tonic-gate */ 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate #define OPEN_TF do \ 3737c478bd9Sstevel@tonic-gate { \ 3747c478bd9Sstevel@tonic-gate MODE_T oldumask = 0; \ 3757c478bd9Sstevel@tonic-gate \ 3767c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) \ 3777c478bd9Sstevel@tonic-gate oldumask = umask(002); \ 3787c478bd9Sstevel@tonic-gate tfd = open(tf, TF_OPEN_FLAGS, QueueFileMode); \ 3797c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) \ 3807c478bd9Sstevel@tonic-gate (void) umask(oldumask); \ 3817c478bd9Sstevel@tonic-gate } while (0) 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags); 385058561cbSjbeck (void) sm_strlcpy(tf, queuename(e, NEWQFL_LETTER), sizeof(tf)); 3867c478bd9Sstevel@tonic-gate tfp = e->e_lockfp; 3877c478bd9Sstevel@tonic-gate if (tfp == NULL && newid) 3887c478bd9Sstevel@tonic-gate { 3897c478bd9Sstevel@tonic-gate /* 3907c478bd9Sstevel@tonic-gate ** open qf file directly: this will give an error if the file 3917c478bd9Sstevel@tonic-gate ** already exists and hence prevent problems if a queue-id 3927c478bd9Sstevel@tonic-gate ** is reused (e.g., because the clock is set back). 3937c478bd9Sstevel@tonic-gate */ 3947c478bd9Sstevel@tonic-gate 395058561cbSjbeck (void) sm_strlcpy(tf, queuename(e, ANYQFL_LETTER), sizeof(tf)); 3967c478bd9Sstevel@tonic-gate OPEN_TF; 3977c478bd9Sstevel@tonic-gate if (tfd < 0 || 3987c478bd9Sstevel@tonic-gate #if !SM_OPEN_EXLOCK 3997c478bd9Sstevel@tonic-gate !lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB) || 4007c478bd9Sstevel@tonic-gate #endif /* !SM_OPEN_EXLOCK */ 4017c478bd9Sstevel@tonic-gate (tfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 4027c478bd9Sstevel@tonic-gate (void *) &tfd, SM_IO_WRONLY, 4037c478bd9Sstevel@tonic-gate NULL)) == NULL) 4047c478bd9Sstevel@tonic-gate { 4057c478bd9Sstevel@tonic-gate int save_errno = errno; 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate printopenfds(true); 4087c478bd9Sstevel@tonic-gate errno = save_errno; 4097c478bd9Sstevel@tonic-gate syserr("!queueup: cannot create queue file %s, euid=%d, fd=%d, fp=%p", 4107c478bd9Sstevel@tonic-gate tf, (int) geteuid(), tfd, tfp); 4117c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate e->e_lockfp = tfp; 4147c478bd9Sstevel@tonic-gate upd_qs(e, 1, 0, "queueup"); 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* if newid, write the queue file directly (instead of temp file) */ 4187c478bd9Sstevel@tonic-gate if (!newid) 4197c478bd9Sstevel@tonic-gate { 4207c478bd9Sstevel@tonic-gate /* get a locked tf file */ 4217c478bd9Sstevel@tonic-gate for (i = 0; i < 128; i++) 4227c478bd9Sstevel@tonic-gate { 4237c478bd9Sstevel@tonic-gate if (tfd < 0) 4247c478bd9Sstevel@tonic-gate { 4257c478bd9Sstevel@tonic-gate OPEN_TF; 4267c478bd9Sstevel@tonic-gate if (tfd < 0) 4277c478bd9Sstevel@tonic-gate { 4287c478bd9Sstevel@tonic-gate if (errno != EEXIST) 4297c478bd9Sstevel@tonic-gate break; 4307c478bd9Sstevel@tonic-gate if (LogLevel > 0 && (i % 32) == 0) 4317c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 432*7800901eSjbeck "queueup: cannot create %s, euid=%d: %s", 4337c478bd9Sstevel@tonic-gate tf, (int) geteuid(), 4347c478bd9Sstevel@tonic-gate sm_errstring(errno)); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate #if SM_OPEN_EXLOCK 4377c478bd9Sstevel@tonic-gate else 4387c478bd9Sstevel@tonic-gate break; 4397c478bd9Sstevel@tonic-gate #endif /* SM_OPEN_EXLOCK */ 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate if (tfd >= 0) 4427c478bd9Sstevel@tonic-gate { 4437c478bd9Sstevel@tonic-gate #if SM_OPEN_EXLOCK 4447c478bd9Sstevel@tonic-gate /* file is locked by open() */ 4457c478bd9Sstevel@tonic-gate break; 4467c478bd9Sstevel@tonic-gate #else /* SM_OPEN_EXLOCK */ 4477c478bd9Sstevel@tonic-gate if (lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB)) 4487c478bd9Sstevel@tonic-gate break; 4497c478bd9Sstevel@tonic-gate else 4507c478bd9Sstevel@tonic-gate #endif /* SM_OPEN_EXLOCK */ 4517c478bd9Sstevel@tonic-gate if (LogLevel > 0 && (i % 32) == 0) 4527c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 4537c478bd9Sstevel@tonic-gate "queueup: cannot lock %s: %s", 4547c478bd9Sstevel@tonic-gate tf, sm_errstring(errno)); 4557c478bd9Sstevel@tonic-gate if ((i % 32) == 31) 4567c478bd9Sstevel@tonic-gate { 4577c478bd9Sstevel@tonic-gate (void) close(tfd); 4587c478bd9Sstevel@tonic-gate tfd = -1; 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate if ((i % 32) == 31) 4637c478bd9Sstevel@tonic-gate { 4647c478bd9Sstevel@tonic-gate /* save the old temp file away */ 4657c478bd9Sstevel@tonic-gate (void) rename(tf, queuename(e, TEMPQF_LETTER)); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate else 4687c478bd9Sstevel@tonic-gate (void) sleep(i % 32); 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate if (tfd < 0 || (tfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 4717c478bd9Sstevel@tonic-gate (void *) &tfd, SM_IO_WRONLY_B, 4727c478bd9Sstevel@tonic-gate NULL)) == NULL) 4737c478bd9Sstevel@tonic-gate { 4747c478bd9Sstevel@tonic-gate int save_errno = errno; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate printopenfds(true); 4777c478bd9Sstevel@tonic-gate errno = save_errno; 4787c478bd9Sstevel@tonic-gate syserr("!queueup: cannot create queue temp file %s, uid=%d", 4797c478bd9Sstevel@tonic-gate tf, (int) geteuid()); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 4847c478bd9Sstevel@tonic-gate sm_dprintf("\n>>>>> queueing %s/%s%s >>>>>\n", 4857c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir), 4867c478bd9Sstevel@tonic-gate queuename(e, ANYQFL_LETTER), 4877c478bd9Sstevel@tonic-gate newid ? " (new id)" : ""); 4887c478bd9Sstevel@tonic-gate if (tTd(40, 3)) 4897c478bd9Sstevel@tonic-gate { 4907c478bd9Sstevel@tonic-gate sm_dprintf(" e_flags="); 4917c478bd9Sstevel@tonic-gate printenvflags(e); 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate if (tTd(40, 32)) 4947c478bd9Sstevel@tonic-gate { 4957c478bd9Sstevel@tonic-gate sm_dprintf(" sendq="); 4967c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), e->e_sendqueue, true); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate if (tTd(40, 9)) 4997c478bd9Sstevel@tonic-gate { 5007c478bd9Sstevel@tonic-gate sm_dprintf(" tfp="); 5017c478bd9Sstevel@tonic-gate dumpfd(sm_io_getinfo(tfp, SM_IO_WHAT_FD, NULL), true, false); 5027c478bd9Sstevel@tonic-gate sm_dprintf(" lockfp="); 5037c478bd9Sstevel@tonic-gate if (e->e_lockfp == NULL) 5047c478bd9Sstevel@tonic-gate sm_dprintf("NULL\n"); 5057c478bd9Sstevel@tonic-gate else 5067c478bd9Sstevel@tonic-gate dumpfd(sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL), 5077c478bd9Sstevel@tonic-gate true, false); 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* 5117c478bd9Sstevel@tonic-gate ** If there is no data file yet, create one. 5127c478bd9Sstevel@tonic-gate */ 5137c478bd9Sstevel@tonic-gate 514058561cbSjbeck (void) sm_strlcpy(df, queuename(e, DATAFL_LETTER), sizeof(df)); 5157c478bd9Sstevel@tonic-gate if (bitset(EF_HAS_DF, e->e_flags)) 5167c478bd9Sstevel@tonic-gate { 5177c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL && 5187c478bd9Sstevel@tonic-gate SuperSafe != SAFE_REALLY && 5197c478bd9Sstevel@tonic-gate SuperSafe != SAFE_REALLY_POSTMILTER && 5207c478bd9Sstevel@tonic-gate sm_io_setinfo(e->e_dfp, SM_BF_COMMIT, NULL) < 0 && 5217c478bd9Sstevel@tonic-gate errno != EINVAL) 5227c478bd9Sstevel@tonic-gate { 5237c478bd9Sstevel@tonic-gate syserr("!queueup: cannot commit data file %s, uid=%d", 5247c478bd9Sstevel@tonic-gate queuename(e, DATAFL_LETTER), (int) geteuid()); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL && 5277c478bd9Sstevel@tonic-gate SuperSafe == SAFE_INTERACTIVE && msync) 5287c478bd9Sstevel@tonic-gate { 5297c478bd9Sstevel@tonic-gate if (tTd(40,32)) 5307c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 5317c478bd9Sstevel@tonic-gate "queueup: fsync(e->e_dfp)"); 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate if (fsync(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, 5347c478bd9Sstevel@tonic-gate NULL)) < 0) 5357c478bd9Sstevel@tonic-gate { 5367c478bd9Sstevel@tonic-gate if (newid) 5377c478bd9Sstevel@tonic-gate syserr("!552 Error writing data file %s", 5387c478bd9Sstevel@tonic-gate df); 5397c478bd9Sstevel@tonic-gate else 5407c478bd9Sstevel@tonic-gate syserr("!452 Error writing data file %s", 5417c478bd9Sstevel@tonic-gate df); 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate else 5467c478bd9Sstevel@tonic-gate { 5477c478bd9Sstevel@tonic-gate int dfd; 5487c478bd9Sstevel@tonic-gate MODE_T oldumask = 0; 5497c478bd9Sstevel@tonic-gate register SM_FILE_T *dfp = NULL; 5507c478bd9Sstevel@tonic-gate struct stat stbuf; 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL && 5537c478bd9Sstevel@tonic-gate sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE)) 5547c478bd9Sstevel@tonic-gate syserr("committing over bf file"); 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 5577c478bd9Sstevel@tonic-gate oldumask = umask(002); 5587c478bd9Sstevel@tonic-gate dfd = open(df, O_WRONLY|O_CREAT|O_TRUNC|QF_O_EXTRA, 5597c478bd9Sstevel@tonic-gate QueueFileMode); 5607c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 5617c478bd9Sstevel@tonic-gate (void) umask(oldumask); 5627c478bd9Sstevel@tonic-gate if (dfd < 0 || (dfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 5637c478bd9Sstevel@tonic-gate (void *) &dfd, SM_IO_WRONLY_B, 5647c478bd9Sstevel@tonic-gate NULL)) == NULL) 5657c478bd9Sstevel@tonic-gate syserr("!queueup: cannot create data temp file %s, uid=%d", 5667c478bd9Sstevel@tonic-gate df, (int) geteuid()); 5677c478bd9Sstevel@tonic-gate if (fstat(dfd, &stbuf) < 0) 5687c478bd9Sstevel@tonic-gate e->e_dfino = -1; 5697c478bd9Sstevel@tonic-gate else 5707c478bd9Sstevel@tonic-gate { 5717c478bd9Sstevel@tonic-gate e->e_dfdev = stbuf.st_dev; 5727c478bd9Sstevel@tonic-gate e->e_dfino = ST_INODE(stbuf); 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS_DF; 575058561cbSjbeck memset(&mcibuf, '\0', sizeof(mcibuf)); 5767c478bd9Sstevel@tonic-gate mcibuf.mci_out = dfp; 5777c478bd9Sstevel@tonic-gate mcibuf.mci_mailer = FileMailer; 5787c478bd9Sstevel@tonic-gate (*e->e_putbody)(&mcibuf, e, NULL); 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate if (SuperSafe == SAFE_REALLY || 5817c478bd9Sstevel@tonic-gate SuperSafe == SAFE_REALLY_POSTMILTER || 5827c478bd9Sstevel@tonic-gate (SuperSafe == SAFE_INTERACTIVE && msync)) 5837c478bd9Sstevel@tonic-gate { 5847c478bd9Sstevel@tonic-gate if (tTd(40,32)) 5857c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 5867c478bd9Sstevel@tonic-gate "queueup: fsync(dfp)"); 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate if (fsync(sm_io_getinfo(dfp, SM_IO_WHAT_FD, NULL)) < 0) 5897c478bd9Sstevel@tonic-gate { 5907c478bd9Sstevel@tonic-gate if (newid) 5917c478bd9Sstevel@tonic-gate syserr("!552 Error writing data file %s", 5927c478bd9Sstevel@tonic-gate df); 5937c478bd9Sstevel@tonic-gate else 5947c478bd9Sstevel@tonic-gate syserr("!452 Error writing data file %s", 5957c478bd9Sstevel@tonic-gate df); 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate if (sm_io_close(dfp, SM_TIME_DEFAULT) < 0) 6007c478bd9Sstevel@tonic-gate syserr("!queueup: cannot save data temp file %s, uid=%d", 6017c478bd9Sstevel@tonic-gate df, (int) geteuid()); 6027c478bd9Sstevel@tonic-gate e->e_putbody = putbody; 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate /* 6067c478bd9Sstevel@tonic-gate ** Output future work requests. 6077c478bd9Sstevel@tonic-gate ** Priority and creation time should be first, since 6087c478bd9Sstevel@tonic-gate ** they are required by gatherq. 6097c478bd9Sstevel@tonic-gate */ 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate /* output queue version number (must be first!) */ 6127c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "V%d\n", QF_VERSION); 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate /* output creation time */ 6157c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "T%ld\n", (long) e->e_ctime); 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate /* output last delivery time */ 6187c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "K%ld\n", (long) e->e_dtime); 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate /* output number of delivery attempts */ 6217c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "N%d\n", e->e_ntries); 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate /* output message priority */ 6247c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "P%ld\n", e->e_msgpriority); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate /* 6277c478bd9Sstevel@tonic-gate ** If data file is in a different directory than the queue file, 6287c478bd9Sstevel@tonic-gate ** output a "d" record naming the directory of the data file. 6297c478bd9Sstevel@tonic-gate */ 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate if (e->e_dfqgrp != e->e_qgrp) 6327c478bd9Sstevel@tonic-gate { 6337c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "d%s\n", 6347c478bd9Sstevel@tonic-gate Queue[e->e_dfqgrp]->qg_qpaths[e->e_dfqdir].qp_name); 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate /* output inode number of data file */ 6387c478bd9Sstevel@tonic-gate /* XXX should probably include device major/minor too */ 6397c478bd9Sstevel@tonic-gate if (e->e_dfino != -1) 6407c478bd9Sstevel@tonic-gate { 6417c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "I%ld/%ld/%llu\n", 6427c478bd9Sstevel@tonic-gate (long) major(e->e_dfdev), 6437c478bd9Sstevel@tonic-gate (long) minor(e->e_dfdev), 6447c478bd9Sstevel@tonic-gate (ULONGLONG_T) e->e_dfino); 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate /* output body type */ 6487c478bd9Sstevel@tonic-gate if (e->e_bodytype != NULL) 6497c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "B%s\n", 6507c478bd9Sstevel@tonic-gate denlstring(e->e_bodytype, true, false)); 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate /* quarantine reason */ 6537c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 6547c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "q%s\n", 6557c478bd9Sstevel@tonic-gate denlstring(e->e_quarmsg, true, false)); 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate /* message from envelope, if it exists */ 6587c478bd9Sstevel@tonic-gate if (e->e_message != NULL) 6597c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "M%s\n", 6607c478bd9Sstevel@tonic-gate denlstring(e->e_message, true, false)); 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate /* send various flag bits through */ 6637c478bd9Sstevel@tonic-gate p = buf; 6647c478bd9Sstevel@tonic-gate if (bitset(EF_WARNING, e->e_flags)) 6657c478bd9Sstevel@tonic-gate *p++ = 'w'; 6667c478bd9Sstevel@tonic-gate if (bitset(EF_RESPONSE, e->e_flags)) 6677c478bd9Sstevel@tonic-gate *p++ = 'r'; 6687c478bd9Sstevel@tonic-gate if (bitset(EF_HAS8BIT, e->e_flags)) 6697c478bd9Sstevel@tonic-gate *p++ = '8'; 6707c478bd9Sstevel@tonic-gate if (bitset(EF_DELETE_BCC, e->e_flags)) 6717c478bd9Sstevel@tonic-gate *p++ = 'b'; 6727c478bd9Sstevel@tonic-gate if (bitset(EF_RET_PARAM, e->e_flags)) 6737c478bd9Sstevel@tonic-gate *p++ = 'd'; 6747c478bd9Sstevel@tonic-gate if (bitset(EF_NO_BODY_RETN, e->e_flags)) 6757c478bd9Sstevel@tonic-gate *p++ = 'n'; 6767c478bd9Sstevel@tonic-gate if (bitset(EF_SPLIT, e->e_flags)) 6777c478bd9Sstevel@tonic-gate *p++ = 's'; 6787c478bd9Sstevel@tonic-gate *p++ = '\0'; 6797c478bd9Sstevel@tonic-gate if (buf[0] != '\0') 6807c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "F%s\n", buf); 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate /* save $={persistentMacros} macro values */ 6837c478bd9Sstevel@tonic-gate queueup_macros(macid("{persistentMacros}"), tfp, e); 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate /* output name of sender */ 6867c478bd9Sstevel@tonic-gate if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 6877c478bd9Sstevel@tonic-gate p = e->e_sender; 6887c478bd9Sstevel@tonic-gate else 6897c478bd9Sstevel@tonic-gate p = e->e_from.q_paddr; 6907c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "S%s\n", 6917c478bd9Sstevel@tonic-gate denlstring(p, true, false)); 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate /* output ESMTP-supplied "original" information */ 6947c478bd9Sstevel@tonic-gate if (e->e_envid != NULL) 6957c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Z%s\n", 6967c478bd9Sstevel@tonic-gate denlstring(e->e_envid, true, false)); 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate /* output AUTH= parameter */ 6997c478bd9Sstevel@tonic-gate if (e->e_auth_param != NULL) 7007c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "A%s\n", 7017c478bd9Sstevel@tonic-gate denlstring(e->e_auth_param, true, false)); 7027c478bd9Sstevel@tonic-gate if (e->e_dlvr_flag != 0) 7037c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "!%c %ld\n", 7047c478bd9Sstevel@tonic-gate (char) e->e_dlvr_flag, e->e_deliver_by); 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate /* output list of recipient addresses */ 7077c478bd9Sstevel@tonic-gate printctladdr(NULL, NULL); 7087c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 7097c478bd9Sstevel@tonic-gate { 7107c478bd9Sstevel@tonic-gate if (!QS_IS_UNDELIVERED(q->q_state)) 7117c478bd9Sstevel@tonic-gate continue; 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate /* message for this recipient, if it exists */ 7147c478bd9Sstevel@tonic-gate if (q->q_message != NULL) 7157c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "M%s\n", 7167c478bd9Sstevel@tonic-gate denlstring(q->q_message, true, 7177c478bd9Sstevel@tonic-gate false)); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate printctladdr(q, tfp); 7207c478bd9Sstevel@tonic-gate if (q->q_orcpt != NULL) 7217c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Q%s\n", 7227c478bd9Sstevel@tonic-gate denlstring(q->q_orcpt, true, 7237c478bd9Sstevel@tonic-gate false)); 7247c478bd9Sstevel@tonic-gate if (q->q_finalrcpt != NULL) 7257c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "r%s\n", 7267c478bd9Sstevel@tonic-gate denlstring(q->q_finalrcpt, true, 7277c478bd9Sstevel@tonic-gate false)); 7287c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'R'); 7297c478bd9Sstevel@tonic-gate if (bitset(QPRIMARY, q->q_flags)) 7307c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'P'); 7317c478bd9Sstevel@tonic-gate if (bitset(QHASNOTIFY, q->q_flags)) 7327c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'N'); 7337c478bd9Sstevel@tonic-gate if (bitset(QPINGONSUCCESS, q->q_flags)) 7347c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'S'); 7357c478bd9Sstevel@tonic-gate if (bitset(QPINGONFAILURE, q->q_flags)) 7367c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'F'); 7377c478bd9Sstevel@tonic-gate if (bitset(QPINGONDELAY, q->q_flags)) 7387c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'D'); 7397c478bd9Sstevel@tonic-gate if (q->q_alias != NULL && 7407c478bd9Sstevel@tonic-gate bitset(QALIAS, q->q_alias->q_flags)) 7417c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'A'); 7427c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, ':'); 7437c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s\n", 7447c478bd9Sstevel@tonic-gate denlstring(q->q_paddr, true, false)); 7457c478bd9Sstevel@tonic-gate if (announce) 7467c478bd9Sstevel@tonic-gate { 7477c478bd9Sstevel@tonic-gate char *tag = "queued"; 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 7507c478bd9Sstevel@tonic-gate tag = "quarantined"; 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate e->e_to = q->q_paddr; 7537c478bd9Sstevel@tonic-gate message(tag); 7547c478bd9Sstevel@tonic-gate if (LogLevel > 8) 7557c478bd9Sstevel@tonic-gate logdelivery(q->q_mailer, NULL, q->q_status, 7567c478bd9Sstevel@tonic-gate tag, NULL, (time_t) 0, e); 7577c478bd9Sstevel@tonic-gate e->e_to = NULL; 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 7607c478bd9Sstevel@tonic-gate { 7617c478bd9Sstevel@tonic-gate sm_dprintf("queueing "); 7627c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), q, false); 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate /* 7677c478bd9Sstevel@tonic-gate ** Output headers for this message. 7687c478bd9Sstevel@tonic-gate ** Expand macros completely here. Queue run will deal with 7697c478bd9Sstevel@tonic-gate ** everything as absolute headers. 7707c478bd9Sstevel@tonic-gate ** All headers that must be relative to the recipient 7717c478bd9Sstevel@tonic-gate ** can be cracked later. 7727c478bd9Sstevel@tonic-gate ** We set up a "null mailer" -- i.e., a mailer that will have 7737c478bd9Sstevel@tonic-gate ** no effect on the addresses as they are output. 7747c478bd9Sstevel@tonic-gate */ 7757c478bd9Sstevel@tonic-gate 776058561cbSjbeck memset((char *) &nullmailer, '\0', sizeof(nullmailer)); 7777c478bd9Sstevel@tonic-gate nullmailer.m_re_rwset = nullmailer.m_rh_rwset = 7787c478bd9Sstevel@tonic-gate nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1; 7797c478bd9Sstevel@tonic-gate nullmailer.m_eol = "\n"; 780058561cbSjbeck memset(&mcibuf, '\0', sizeof(mcibuf)); 7817c478bd9Sstevel@tonic-gate mcibuf.mci_mailer = &nullmailer; 7827c478bd9Sstevel@tonic-gate mcibuf.mci_out = tfp; 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'g', "\201f"); 7857c478bd9Sstevel@tonic-gate for (h = e->e_header; h != NULL; h = h->h_link) 7867c478bd9Sstevel@tonic-gate { 7877c478bd9Sstevel@tonic-gate if (h->h_value == NULL) 7887c478bd9Sstevel@tonic-gate continue; 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate /* don't output resent headers on non-resent messages */ 7917c478bd9Sstevel@tonic-gate if (bitset(H_RESENT, h->h_flags) && 7927c478bd9Sstevel@tonic-gate !bitset(EF_RESENT, e->e_flags)) 7937c478bd9Sstevel@tonic-gate continue; 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate /* expand macros; if null, don't output header at all */ 7967c478bd9Sstevel@tonic-gate if (bitset(H_DEFAULT, h->h_flags)) 7977c478bd9Sstevel@tonic-gate { 798058561cbSjbeck (void) expand(h->h_value, buf, sizeof(buf), e); 7997c478bd9Sstevel@tonic-gate if (buf[0] == '\0') 8007c478bd9Sstevel@tonic-gate continue; 8014aac33d3Sjbeck if (buf[0] == ' ' && buf[1] == '\0') 8024aac33d3Sjbeck continue; 8037c478bd9Sstevel@tonic-gate } 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate /* output this header */ 8067c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "H?"); 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate /* output conditional macro if present */ 8097c478bd9Sstevel@tonic-gate if (h->h_macro != '\0') 8107c478bd9Sstevel@tonic-gate { 8117c478bd9Sstevel@tonic-gate if (bitset(0200, h->h_macro)) 8127c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, 8137c478bd9Sstevel@tonic-gate "${%s}", 8147c478bd9Sstevel@tonic-gate macname(bitidx(h->h_macro))); 8157c478bd9Sstevel@tonic-gate else 8167c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, 8177c478bd9Sstevel@tonic-gate "$%c", h->h_macro); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate else if (!bitzerop(h->h_mflags) && 8207c478bd9Sstevel@tonic-gate bitset(H_CHECK|H_ACHECK, h->h_flags)) 8217c478bd9Sstevel@tonic-gate { 8227c478bd9Sstevel@tonic-gate int j; 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate /* if conditional, output the set of conditions */ 8257c478bd9Sstevel@tonic-gate for (j = '\0'; j <= '\177'; j++) 8267c478bd9Sstevel@tonic-gate if (bitnset(j, h->h_mflags)) 8277c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 8287c478bd9Sstevel@tonic-gate j); 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate (void) sm_io_putc(tfp, SM_TIME_DEFAULT, '?'); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate /* output the header: expand macros, convert addresses */ 8337c478bd9Sstevel@tonic-gate if (bitset(H_DEFAULT, h->h_flags) && 8347c478bd9Sstevel@tonic-gate !bitset(H_BINDLATE, h->h_flags)) 8357c478bd9Sstevel@tonic-gate { 836058561cbSjbeck (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s:%s\n", 8377c478bd9Sstevel@tonic-gate h->h_field, 8387c478bd9Sstevel@tonic-gate denlstring(buf, false, true)); 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate else if (bitset(H_FROM|H_RCPT, h->h_flags) && 8417c478bd9Sstevel@tonic-gate !bitset(H_BINDLATE, h->h_flags)) 8427c478bd9Sstevel@tonic-gate { 8437c478bd9Sstevel@tonic-gate bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 8447c478bd9Sstevel@tonic-gate SM_FILE_T *savetrace = TrafficLogFile; 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate TrafficLogFile = NULL; 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate if (bitset(H_FROM, h->h_flags)) 8497c478bd9Sstevel@tonic-gate oldstyle = false; 850*7800901eSjbeck commaize(h, h->h_value, oldstyle, &mcibuf, e, 851*7800901eSjbeck PXLF_HEADER); 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate TrafficLogFile = savetrace; 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate else 8567c478bd9Sstevel@tonic-gate { 857058561cbSjbeck (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s:%s\n", 8587c478bd9Sstevel@tonic-gate h->h_field, 8597c478bd9Sstevel@tonic-gate denlstring(h->h_value, false, 8607c478bd9Sstevel@tonic-gate true)); 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate /* 8657c478bd9Sstevel@tonic-gate ** Clean up. 8667c478bd9Sstevel@tonic-gate ** 8677c478bd9Sstevel@tonic-gate ** Write a terminator record -- this is to prevent 8687c478bd9Sstevel@tonic-gate ** scurrilous crackers from appending any data. 8697c478bd9Sstevel@tonic-gate */ 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, ".\n"); 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate if (sm_io_flush(tfp, SM_TIME_DEFAULT) != 0 || 8747c478bd9Sstevel@tonic-gate ((SuperSafe == SAFE_REALLY || 8757c478bd9Sstevel@tonic-gate SuperSafe == SAFE_REALLY_POSTMILTER || 8767c478bd9Sstevel@tonic-gate (SuperSafe == SAFE_INTERACTIVE && msync)) && 8777c478bd9Sstevel@tonic-gate fsync(sm_io_getinfo(tfp, SM_IO_WHAT_FD, NULL)) < 0) || 8787c478bd9Sstevel@tonic-gate sm_io_error(tfp)) 8797c478bd9Sstevel@tonic-gate { 8807c478bd9Sstevel@tonic-gate if (newid) 8817c478bd9Sstevel@tonic-gate syserr("!552 Error writing control file %s", tf); 8827c478bd9Sstevel@tonic-gate else 8837c478bd9Sstevel@tonic-gate syserr("!452 Error writing control file %s", tf); 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate if (!newid) 8877c478bd9Sstevel@tonic-gate { 8887c478bd9Sstevel@tonic-gate char new = queue_letter(e, ANYQFL_LETTER); 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate /* rename (locked) tf to be (locked) [qh]f */ 8917c478bd9Sstevel@tonic-gate (void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER), 892058561cbSjbeck sizeof(qf)); 8937c478bd9Sstevel@tonic-gate if (rename(tf, qf) < 0) 8947c478bd9Sstevel@tonic-gate syserr("cannot rename(%s, %s), uid=%d", 8957c478bd9Sstevel@tonic-gate tf, qf, (int) geteuid()); 8967c478bd9Sstevel@tonic-gate else 8977c478bd9Sstevel@tonic-gate { 8987c478bd9Sstevel@tonic-gate /* 8997c478bd9Sstevel@tonic-gate ** Check if type has changed and only 9007c478bd9Sstevel@tonic-gate ** remove the old item if the rename above 9017c478bd9Sstevel@tonic-gate ** succeeded. 9027c478bd9Sstevel@tonic-gate */ 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate if (e->e_qfletter != '\0' && 9057c478bd9Sstevel@tonic-gate e->e_qfletter != new) 9067c478bd9Sstevel@tonic-gate { 9077c478bd9Sstevel@tonic-gate if (tTd(40, 5)) 9087c478bd9Sstevel@tonic-gate { 9097c478bd9Sstevel@tonic-gate sm_dprintf("type changed from %c to %c\n", 9107c478bd9Sstevel@tonic-gate e->e_qfletter, new); 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate if (unlink(queuename(e, e->e_qfletter)) < 0) 9147c478bd9Sstevel@tonic-gate { 9157c478bd9Sstevel@tonic-gate /* XXX: something more drastic? */ 9167c478bd9Sstevel@tonic-gate if (LogLevel > 0) 9177c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 9187c478bd9Sstevel@tonic-gate "queueup: unlink(%s) failed: %s", 9197c478bd9Sstevel@tonic-gate queuename(e, e->e_qfletter), 9207c478bd9Sstevel@tonic-gate sm_errstring(errno)); 9217c478bd9Sstevel@tonic-gate } 9227c478bd9Sstevel@tonic-gate } 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate e->e_qfletter = new; 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate /* 9277c478bd9Sstevel@tonic-gate ** fsync() after renaming to make sure metadata is 9287c478bd9Sstevel@tonic-gate ** written to disk on filesystems in which renames are 9297c478bd9Sstevel@tonic-gate ** not guaranteed. 9307c478bd9Sstevel@tonic-gate */ 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate if (SuperSafe != SAFE_NO) 9337c478bd9Sstevel@tonic-gate { 9347c478bd9Sstevel@tonic-gate /* for softupdates */ 9357c478bd9Sstevel@tonic-gate if (tfd >= 0 && fsync(tfd) < 0) 9367c478bd9Sstevel@tonic-gate { 9377c478bd9Sstevel@tonic-gate syserr("!queueup: cannot fsync queue temp file %s", 9387c478bd9Sstevel@tonic-gate tf); 9397c478bd9Sstevel@tonic-gate } 9407c478bd9Sstevel@tonic-gate SYNC_DIR(qf, true); 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate /* close and unlock old (locked) queue file */ 9447c478bd9Sstevel@tonic-gate if (e->e_lockfp != NULL) 9457c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT); 9467c478bd9Sstevel@tonic-gate e->e_lockfp = tfp; 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate /* save log info */ 9497c478bd9Sstevel@tonic-gate if (LogLevel > 79) 9507c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "queueup %s", qf); 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate else 9537c478bd9Sstevel@tonic-gate { 9547c478bd9Sstevel@tonic-gate /* save log info */ 9557c478bd9Sstevel@tonic-gate if (LogLevel > 79) 9567c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "queueup %s", tf); 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate e->e_qfletter = queue_letter(e, ANYQFL_LETTER); 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate errno = 0; 9627c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE; 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 9657c478bd9Sstevel@tonic-gate sm_dprintf("<<<<< done queueing %s <<<<<\n\n", e->e_id); 9667c478bd9Sstevel@tonic-gate return; 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate /* 9707c478bd9Sstevel@tonic-gate ** PRINTCTLADDR -- print control address to file. 9717c478bd9Sstevel@tonic-gate ** 9727c478bd9Sstevel@tonic-gate ** Parameters: 9737c478bd9Sstevel@tonic-gate ** a -- address. 9747c478bd9Sstevel@tonic-gate ** tfp -- file pointer. 9757c478bd9Sstevel@tonic-gate ** 9767c478bd9Sstevel@tonic-gate ** Returns: 9777c478bd9Sstevel@tonic-gate ** none. 9787c478bd9Sstevel@tonic-gate ** 9797c478bd9Sstevel@tonic-gate ** Side Effects: 9807c478bd9Sstevel@tonic-gate ** The control address (if changed) is printed to the file. 9817c478bd9Sstevel@tonic-gate ** The last control address and uid are saved. 9827c478bd9Sstevel@tonic-gate */ 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate static void 9857c478bd9Sstevel@tonic-gate printctladdr(a, tfp) 9867c478bd9Sstevel@tonic-gate register ADDRESS *a; 9877c478bd9Sstevel@tonic-gate SM_FILE_T *tfp; 9887c478bd9Sstevel@tonic-gate { 9897c478bd9Sstevel@tonic-gate char *user; 9907c478bd9Sstevel@tonic-gate register ADDRESS *q; 9917c478bd9Sstevel@tonic-gate uid_t uid; 9927c478bd9Sstevel@tonic-gate gid_t gid; 9937c478bd9Sstevel@tonic-gate static ADDRESS *lastctladdr = NULL; 9947c478bd9Sstevel@tonic-gate static uid_t lastuid; 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate /* initialization */ 9977c478bd9Sstevel@tonic-gate if (a == NULL || a->q_alias == NULL || tfp == NULL) 9987c478bd9Sstevel@tonic-gate { 9997c478bd9Sstevel@tonic-gate if (lastctladdr != NULL && tfp != NULL) 10007c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C\n"); 10017c478bd9Sstevel@tonic-gate lastctladdr = NULL; 10027c478bd9Sstevel@tonic-gate lastuid = 0; 10037c478bd9Sstevel@tonic-gate return; 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate /* find the active uid */ 10077c478bd9Sstevel@tonic-gate q = getctladdr(a); 10087c478bd9Sstevel@tonic-gate if (q == NULL) 10097c478bd9Sstevel@tonic-gate { 10107c478bd9Sstevel@tonic-gate user = NULL; 10117c478bd9Sstevel@tonic-gate uid = 0; 10127c478bd9Sstevel@tonic-gate gid = 0; 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate else 10157c478bd9Sstevel@tonic-gate { 10167c478bd9Sstevel@tonic-gate user = q->q_ruser != NULL ? q->q_ruser : q->q_user; 10177c478bd9Sstevel@tonic-gate uid = q->q_uid; 10187c478bd9Sstevel@tonic-gate gid = q->q_gid; 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate a = a->q_alias; 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate /* check to see if this is the same as last time */ 10237c478bd9Sstevel@tonic-gate if (lastctladdr != NULL && uid == lastuid && 10247c478bd9Sstevel@tonic-gate strcmp(lastctladdr->q_paddr, a->q_paddr) == 0) 10257c478bd9Sstevel@tonic-gate return; 10267c478bd9Sstevel@tonic-gate lastuid = uid; 10277c478bd9Sstevel@tonic-gate lastctladdr = a; 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate if (uid == 0 || user == NULL || user[0] == '\0') 10307c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C"); 10317c478bd9Sstevel@tonic-gate else 10327c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C%s:%ld:%ld", 10337c478bd9Sstevel@tonic-gate denlstring(user, true, false), (long) uid, 10347c478bd9Sstevel@tonic-gate (long) gid); 10357c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, ":%s\n", 10367c478bd9Sstevel@tonic-gate denlstring(a->q_paddr, true, false)); 10377c478bd9Sstevel@tonic-gate } 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate /* 10407c478bd9Sstevel@tonic-gate ** RUNNERS_SIGTERM -- propagate a SIGTERM to queue runner process 10417c478bd9Sstevel@tonic-gate ** 10427c478bd9Sstevel@tonic-gate ** This propagates the signal to the child processes that are queue 10437c478bd9Sstevel@tonic-gate ** runners. This is for a queue runner "cleanup". After all of the 10447c478bd9Sstevel@tonic-gate ** child queue runner processes are signaled (it should be SIGTERM 10457c478bd9Sstevel@tonic-gate ** being the sig) then the old signal handler (Oldsh) is called 10467c478bd9Sstevel@tonic-gate ** to handle any cleanup set for this process (provided it is not 10477c478bd9Sstevel@tonic-gate ** SIG_DFL or SIG_IGN). The signal may not be handled immediately 10487c478bd9Sstevel@tonic-gate ** if the BlockOldsh flag is set. If the current process doesn't 10497c478bd9Sstevel@tonic-gate ** have a parent then handle the signal immediately, regardless of 10507c478bd9Sstevel@tonic-gate ** BlockOldsh. 10517c478bd9Sstevel@tonic-gate ** 10527c478bd9Sstevel@tonic-gate ** Parameters: 10537c478bd9Sstevel@tonic-gate ** sig -- the signal number being sent 10547c478bd9Sstevel@tonic-gate ** 10557c478bd9Sstevel@tonic-gate ** Returns: 10567c478bd9Sstevel@tonic-gate ** none. 10577c478bd9Sstevel@tonic-gate ** 10587c478bd9Sstevel@tonic-gate ** Side Effects: 10597c478bd9Sstevel@tonic-gate ** Sets the NoMoreRunners boolean to true to stop more runners 10607c478bd9Sstevel@tonic-gate ** from being started in runqueue(). 10617c478bd9Sstevel@tonic-gate ** 10627c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 10637c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 10647c478bd9Sstevel@tonic-gate ** DOING. 10657c478bd9Sstevel@tonic-gate */ 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate static bool volatile NoMoreRunners = false; 10687c478bd9Sstevel@tonic-gate static sigfunc_t Oldsh_term = SIG_DFL; 10697c478bd9Sstevel@tonic-gate static sigfunc_t Oldsh_hup = SIG_DFL; 10707c478bd9Sstevel@tonic-gate static sigfunc_t volatile Oldsh = SIG_DFL; 10717c478bd9Sstevel@tonic-gate static bool BlockOldsh = false; 10727c478bd9Sstevel@tonic-gate static int volatile Oldsig = 0; 10737c478bd9Sstevel@tonic-gate static SIGFUNC_DECL runners_sigterm __P((int)); 10747c478bd9Sstevel@tonic-gate static SIGFUNC_DECL runners_sighup __P((int)); 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate static SIGFUNC_DECL 10777c478bd9Sstevel@tonic-gate runners_sigterm(sig) 10787c478bd9Sstevel@tonic-gate int sig; 10797c478bd9Sstevel@tonic-gate { 10807c478bd9Sstevel@tonic-gate int save_errno = errno; 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, runners_sigterm); 10837c478bd9Sstevel@tonic-gate errno = save_errno; 10847c478bd9Sstevel@tonic-gate CHECK_CRITICAL(sig); 10857c478bd9Sstevel@tonic-gate NoMoreRunners = true; 10867c478bd9Sstevel@tonic-gate Oldsh = Oldsh_term; 10877c478bd9Sstevel@tonic-gate Oldsig = sig; 10887c478bd9Sstevel@tonic-gate proc_list_signal(PROC_QUEUE, sig); 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate if (!BlockOldsh || getppid() <= 1) 10917c478bd9Sstevel@tonic-gate { 10927c478bd9Sstevel@tonic-gate /* Check that a valid 'old signal handler' is callable */ 10937c478bd9Sstevel@tonic-gate if (Oldsh_term != SIG_DFL && Oldsh_term != SIG_IGN && 10947c478bd9Sstevel@tonic-gate Oldsh_term != runners_sigterm) 10957c478bd9Sstevel@tonic-gate (*Oldsh_term)(sig); 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate errno = save_errno; 10987c478bd9Sstevel@tonic-gate return SIGFUNC_RETURN; 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate /* 11017c478bd9Sstevel@tonic-gate ** RUNNERS_SIGHUP -- propagate a SIGHUP to queue runner process 11027c478bd9Sstevel@tonic-gate ** 11037c478bd9Sstevel@tonic-gate ** This propagates the signal to the child processes that are queue 11047c478bd9Sstevel@tonic-gate ** runners. This is for a queue runner "cleanup". After all of the 11057c478bd9Sstevel@tonic-gate ** child queue runner processes are signaled (it should be SIGHUP 11067c478bd9Sstevel@tonic-gate ** being the sig) then the old signal handler (Oldsh) is called to 11077c478bd9Sstevel@tonic-gate ** handle any cleanup set for this process (provided it is not SIG_DFL 11087c478bd9Sstevel@tonic-gate ** or SIG_IGN). The signal may not be handled immediately if the 11097c478bd9Sstevel@tonic-gate ** BlockOldsh flag is set. If the current process doesn't have 11107c478bd9Sstevel@tonic-gate ** a parent then handle the signal immediately, regardless of 11117c478bd9Sstevel@tonic-gate ** BlockOldsh. 11127c478bd9Sstevel@tonic-gate ** 11137c478bd9Sstevel@tonic-gate ** Parameters: 11147c478bd9Sstevel@tonic-gate ** sig -- the signal number being sent 11157c478bd9Sstevel@tonic-gate ** 11167c478bd9Sstevel@tonic-gate ** Returns: 11177c478bd9Sstevel@tonic-gate ** none. 11187c478bd9Sstevel@tonic-gate ** 11197c478bd9Sstevel@tonic-gate ** Side Effects: 11207c478bd9Sstevel@tonic-gate ** Sets the NoMoreRunners boolean to true to stop more runners 11217c478bd9Sstevel@tonic-gate ** from being started in runqueue(). 11227c478bd9Sstevel@tonic-gate ** 11237c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 11247c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 11257c478bd9Sstevel@tonic-gate ** DOING. 11267c478bd9Sstevel@tonic-gate */ 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate static SIGFUNC_DECL 11297c478bd9Sstevel@tonic-gate runners_sighup(sig) 11307c478bd9Sstevel@tonic-gate int sig; 11317c478bd9Sstevel@tonic-gate { 11327c478bd9Sstevel@tonic-gate int save_errno = errno; 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, runners_sighup); 11357c478bd9Sstevel@tonic-gate errno = save_errno; 11367c478bd9Sstevel@tonic-gate CHECK_CRITICAL(sig); 11377c478bd9Sstevel@tonic-gate NoMoreRunners = true; 11387c478bd9Sstevel@tonic-gate Oldsh = Oldsh_hup; 11397c478bd9Sstevel@tonic-gate Oldsig = sig; 11407c478bd9Sstevel@tonic-gate proc_list_signal(PROC_QUEUE, sig); 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate if (!BlockOldsh || getppid() <= 1) 11437c478bd9Sstevel@tonic-gate { 11447c478bd9Sstevel@tonic-gate /* Check that a valid 'old signal handler' is callable */ 11457c478bd9Sstevel@tonic-gate if (Oldsh_hup != SIG_DFL && Oldsh_hup != SIG_IGN && 11467c478bd9Sstevel@tonic-gate Oldsh_hup != runners_sighup) 11477c478bd9Sstevel@tonic-gate (*Oldsh_hup)(sig); 11487c478bd9Sstevel@tonic-gate } 11497c478bd9Sstevel@tonic-gate errno = save_errno; 11507c478bd9Sstevel@tonic-gate return SIGFUNC_RETURN; 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate /* 11537c478bd9Sstevel@tonic-gate ** MARK_WORK_GROUP_RESTART -- mark a work group as needing a restart 11547c478bd9Sstevel@tonic-gate ** 11557c478bd9Sstevel@tonic-gate ** Sets a workgroup for restarting. 11567c478bd9Sstevel@tonic-gate ** 11577c478bd9Sstevel@tonic-gate ** Parameters: 11587c478bd9Sstevel@tonic-gate ** wgrp -- the work group id to restart. 11597c478bd9Sstevel@tonic-gate ** reason -- why (signal?), -1 to turn off restart 11607c478bd9Sstevel@tonic-gate ** 11617c478bd9Sstevel@tonic-gate ** Returns: 11627c478bd9Sstevel@tonic-gate ** none. 11637c478bd9Sstevel@tonic-gate ** 11647c478bd9Sstevel@tonic-gate ** Side effects: 11657c478bd9Sstevel@tonic-gate ** May set global RestartWorkGroup to true. 11667c478bd9Sstevel@tonic-gate ** 11677c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 11687c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 11697c478bd9Sstevel@tonic-gate ** DOING. 11707c478bd9Sstevel@tonic-gate */ 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate void 11737c478bd9Sstevel@tonic-gate mark_work_group_restart(wgrp, reason) 11747c478bd9Sstevel@tonic-gate int wgrp; 11757c478bd9Sstevel@tonic-gate int reason; 11767c478bd9Sstevel@tonic-gate { 11777c478bd9Sstevel@tonic-gate if (wgrp < 0 || wgrp > NumWorkGroups) 11787c478bd9Sstevel@tonic-gate return; 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_restart = reason; 11817c478bd9Sstevel@tonic-gate if (reason >= 0) 11827c478bd9Sstevel@tonic-gate RestartWorkGroup = true; 11837c478bd9Sstevel@tonic-gate } 11847c478bd9Sstevel@tonic-gate /* 11857c478bd9Sstevel@tonic-gate ** RESTART_MARKED_WORK_GROUPS -- restart work groups marked as needing restart 11867c478bd9Sstevel@tonic-gate ** 11877c478bd9Sstevel@tonic-gate ** Restart any workgroup marked as needing a restart provided more 11887c478bd9Sstevel@tonic-gate ** runners are allowed. 11897c478bd9Sstevel@tonic-gate ** 11907c478bd9Sstevel@tonic-gate ** Parameters: 11917c478bd9Sstevel@tonic-gate ** none. 11927c478bd9Sstevel@tonic-gate ** 11937c478bd9Sstevel@tonic-gate ** Returns: 11947c478bd9Sstevel@tonic-gate ** none. 11957c478bd9Sstevel@tonic-gate ** 11967c478bd9Sstevel@tonic-gate ** Side effects: 11977c478bd9Sstevel@tonic-gate ** Sets global RestartWorkGroup to false. 11987c478bd9Sstevel@tonic-gate */ 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate void 12017c478bd9Sstevel@tonic-gate restart_marked_work_groups() 12027c478bd9Sstevel@tonic-gate { 12037c478bd9Sstevel@tonic-gate int i; 12047c478bd9Sstevel@tonic-gate int wasblocked; 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate if (NoMoreRunners) 12077c478bd9Sstevel@tonic-gate return; 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate /* Block SIGCHLD so reapchild() doesn't mess with us */ 12107c478bd9Sstevel@tonic-gate wasblocked = sm_blocksignal(SIGCHLD); 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate for (i = 0; i < NumWorkGroups; i++) 12137c478bd9Sstevel@tonic-gate { 12147c478bd9Sstevel@tonic-gate if (WorkGrp[i].wg_restart >= 0) 12157c478bd9Sstevel@tonic-gate { 12167c478bd9Sstevel@tonic-gate if (LogLevel > 8) 12177c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 12187c478bd9Sstevel@tonic-gate "restart queue runner=%d due to signal 0x%x", 12197c478bd9Sstevel@tonic-gate i, WorkGrp[i].wg_restart); 12207c478bd9Sstevel@tonic-gate restart_work_group(i); 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate } 12237c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate if (wasblocked == 0) 12267c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGCHLD); 12277c478bd9Sstevel@tonic-gate } 12287c478bd9Sstevel@tonic-gate /* 12297c478bd9Sstevel@tonic-gate ** RESTART_WORK_GROUP -- restart a specific work group 12307c478bd9Sstevel@tonic-gate ** 12317c478bd9Sstevel@tonic-gate ** Restart a specific workgroup provided more runners are allowed. 12327c478bd9Sstevel@tonic-gate ** If the requested work group has been restarted too many times log 12337c478bd9Sstevel@tonic-gate ** this and refuse to restart. 12347c478bd9Sstevel@tonic-gate ** 12357c478bd9Sstevel@tonic-gate ** Parameters: 12367c478bd9Sstevel@tonic-gate ** wgrp -- the work group id to restart 12377c478bd9Sstevel@tonic-gate ** 12387c478bd9Sstevel@tonic-gate ** Returns: 12397c478bd9Sstevel@tonic-gate ** none. 12407c478bd9Sstevel@tonic-gate ** 12417c478bd9Sstevel@tonic-gate ** Side Effects: 12427c478bd9Sstevel@tonic-gate ** starts another process doing the work of wgrp 12437c478bd9Sstevel@tonic-gate */ 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate #define MAX_PERSIST_RESTART 10 /* max allowed number of restarts */ 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate static void 12487c478bd9Sstevel@tonic-gate restart_work_group(wgrp) 12497c478bd9Sstevel@tonic-gate int wgrp; 12507c478bd9Sstevel@tonic-gate { 12517c478bd9Sstevel@tonic-gate if (NoMoreRunners || 12527c478bd9Sstevel@tonic-gate wgrp < 0 || wgrp > NumWorkGroups) 12537c478bd9Sstevel@tonic-gate return; 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_restart = -1; 12567c478bd9Sstevel@tonic-gate if (WorkGrp[wgrp].wg_restartcnt < MAX_PERSIST_RESTART) 12577c478bd9Sstevel@tonic-gate { 12587c478bd9Sstevel@tonic-gate /* avoid overflow; increment here */ 12597c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_restartcnt++; 12607c478bd9Sstevel@tonic-gate (void) run_work_group(wgrp, RWG_FORK|RWG_PERSISTENT|RWG_RUNALL); 12617c478bd9Sstevel@tonic-gate } 12627c478bd9Sstevel@tonic-gate else 12637c478bd9Sstevel@tonic-gate { 12647c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 12657c478bd9Sstevel@tonic-gate "ERROR: persistent queue runner=%d restarted too many times, queue runner lost", 12667c478bd9Sstevel@tonic-gate wgrp); 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate /* 12707c478bd9Sstevel@tonic-gate ** SCHEDULE_QUEUE_RUNS -- schedule the next queue run for a work group. 12717c478bd9Sstevel@tonic-gate ** 12727c478bd9Sstevel@tonic-gate ** Parameters: 12737c478bd9Sstevel@tonic-gate ** runall -- schedule even if individual bit is not set. 12747c478bd9Sstevel@tonic-gate ** wgrp -- the work group id to schedule. 12757c478bd9Sstevel@tonic-gate ** didit -- the queue run was performed for this work group. 12767c478bd9Sstevel@tonic-gate ** 12777c478bd9Sstevel@tonic-gate ** Returns: 12787c478bd9Sstevel@tonic-gate ** nothing 12797c478bd9Sstevel@tonic-gate */ 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate #define INCR_MOD(v, m) if (++v >= m) \ 12827c478bd9Sstevel@tonic-gate v = 0; \ 12837c478bd9Sstevel@tonic-gate else 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate static void 12867c478bd9Sstevel@tonic-gate schedule_queue_runs(runall, wgrp, didit) 12877c478bd9Sstevel@tonic-gate bool runall; 12887c478bd9Sstevel@tonic-gate int wgrp; 12897c478bd9Sstevel@tonic-gate bool didit; 12907c478bd9Sstevel@tonic-gate { 12917c478bd9Sstevel@tonic-gate int qgrp, cgrp, endgrp; 12927c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 12937c478bd9Sstevel@tonic-gate time_t lastsched; 12947c478bd9Sstevel@tonic-gate bool sched; 12957c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 12967c478bd9Sstevel@tonic-gate time_t now; 12977c478bd9Sstevel@tonic-gate time_t minqintvl; 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate /* 13007c478bd9Sstevel@tonic-gate ** This is a bit ugly since we have to duplicate the 13017c478bd9Sstevel@tonic-gate ** code that "walks" through a work queue group. 13027c478bd9Sstevel@tonic-gate */ 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate now = curtime(); 13057c478bd9Sstevel@tonic-gate minqintvl = 0; 13067c478bd9Sstevel@tonic-gate cgrp = endgrp = WorkGrp[wgrp].wg_curqgrp; 13077c478bd9Sstevel@tonic-gate do 13087c478bd9Sstevel@tonic-gate { 13097c478bd9Sstevel@tonic-gate time_t qintvl; 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 13127c478bd9Sstevel@tonic-gate lastsched = 0; 13137c478bd9Sstevel@tonic-gate sched = false; 13147c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 13157c478bd9Sstevel@tonic-gate qgrp = WorkGrp[wgrp].wg_qgs[cgrp]->qg_index; 13167c478bd9Sstevel@tonic-gate if (Queue[qgrp]->qg_queueintvl > 0) 13177c478bd9Sstevel@tonic-gate qintvl = Queue[qgrp]->qg_queueintvl; 13187c478bd9Sstevel@tonic-gate else if (QueueIntvl > 0) 13197c478bd9Sstevel@tonic-gate qintvl = QueueIntvl; 13207c478bd9Sstevel@tonic-gate else 13217c478bd9Sstevel@tonic-gate qintvl = (time_t) 0; 13227c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 13237c478bd9Sstevel@tonic-gate lastsched = Queue[qgrp]->qg_nextrun; 13247c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 13257c478bd9Sstevel@tonic-gate if ((runall || Queue[qgrp]->qg_nextrun <= now) && qintvl > 0) 13267c478bd9Sstevel@tonic-gate { 13277c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 13287c478bd9Sstevel@tonic-gate sched = true; 13297c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 13307c478bd9Sstevel@tonic-gate if (minqintvl == 0 || qintvl < minqintvl) 13317c478bd9Sstevel@tonic-gate minqintvl = qintvl; 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate /* 13347c478bd9Sstevel@tonic-gate ** Only set a new time if a queue run was performed 13357c478bd9Sstevel@tonic-gate ** for this queue group. If the queue was not run, 13367c478bd9Sstevel@tonic-gate ** we could starve it by setting a new time on each 13377c478bd9Sstevel@tonic-gate ** call. 13387c478bd9Sstevel@tonic-gate */ 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate if (didit) 13417c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_nextrun += qintvl; 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 13447c478bd9Sstevel@tonic-gate if (tTd(69, 10)) 13457c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 13467c478bd9Sstevel@tonic-gate "sqr: wgrp=%d, cgrp=%d, qgrp=%d, intvl=%ld, QI=%ld, runall=%d, lastrun=%ld, nextrun=%ld, sched=%d", 13477c478bd9Sstevel@tonic-gate wgrp, cgrp, qgrp, Queue[qgrp]->qg_queueintvl, 13487c478bd9Sstevel@tonic-gate QueueIntvl, runall, lastsched, 13497c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_nextrun, sched); 13507c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 13517c478bd9Sstevel@tonic-gate INCR_MOD(cgrp, WorkGrp[wgrp].wg_numqgrp); 13527c478bd9Sstevel@tonic-gate } while (endgrp != cgrp); 13537c478bd9Sstevel@tonic-gate if (minqintvl > 0) 13547c478bd9Sstevel@tonic-gate (void) sm_setevent(minqintvl, runqueueevent, 0); 13557c478bd9Sstevel@tonic-gate } 13567c478bd9Sstevel@tonic-gate 13577c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_RUN_PARANOIA 13587c478bd9Sstevel@tonic-gate /* 13597c478bd9Sstevel@tonic-gate ** CHECKQUEUERUNNER -- check whether a queue group hasn't been run. 13607c478bd9Sstevel@tonic-gate ** 13617c478bd9Sstevel@tonic-gate ** Use this if events may get lost and hence queue runners may not 13627c478bd9Sstevel@tonic-gate ** be started and mail will pile up in a queue. 13637c478bd9Sstevel@tonic-gate ** 13647c478bd9Sstevel@tonic-gate ** Parameters: 13657c478bd9Sstevel@tonic-gate ** none. 13667c478bd9Sstevel@tonic-gate ** 13677c478bd9Sstevel@tonic-gate ** Returns: 13687c478bd9Sstevel@tonic-gate ** true if a queue run is necessary. 13697c478bd9Sstevel@tonic-gate ** 13707c478bd9Sstevel@tonic-gate ** Side Effects: 13717c478bd9Sstevel@tonic-gate ** may schedule a queue run. 13727c478bd9Sstevel@tonic-gate */ 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate bool 13757c478bd9Sstevel@tonic-gate checkqueuerunner() 13767c478bd9Sstevel@tonic-gate { 13777c478bd9Sstevel@tonic-gate int qgrp; 13787c478bd9Sstevel@tonic-gate time_t now, minqintvl; 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate now = curtime(); 13817c478bd9Sstevel@tonic-gate minqintvl = 0; 13827c478bd9Sstevel@tonic-gate for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++) 13837c478bd9Sstevel@tonic-gate { 13847c478bd9Sstevel@tonic-gate time_t qintvl; 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate if (Queue[qgrp]->qg_queueintvl > 0) 13877c478bd9Sstevel@tonic-gate qintvl = Queue[qgrp]->qg_queueintvl; 13887c478bd9Sstevel@tonic-gate else if (QueueIntvl > 0) 13897c478bd9Sstevel@tonic-gate qintvl = QueueIntvl; 13907c478bd9Sstevel@tonic-gate else 13917c478bd9Sstevel@tonic-gate qintvl = (time_t) 0; 13927c478bd9Sstevel@tonic-gate if (Queue[qgrp]->qg_nextrun <= now - qintvl) 13937c478bd9Sstevel@tonic-gate { 13947c478bd9Sstevel@tonic-gate if (minqintvl == 0 || qintvl < minqintvl) 13957c478bd9Sstevel@tonic-gate minqintvl = qintvl; 13967c478bd9Sstevel@tonic-gate if (LogLevel > 1) 13977c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 13987c478bd9Sstevel@tonic-gate "checkqueuerunner: queue %d should have been run at %s, queue interval %ld", 13997c478bd9Sstevel@tonic-gate qgrp, 14007c478bd9Sstevel@tonic-gate arpadate(ctime(&Queue[qgrp]->qg_nextrun)), 14017c478bd9Sstevel@tonic-gate qintvl); 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate } 14047c478bd9Sstevel@tonic-gate if (minqintvl > 0) 14057c478bd9Sstevel@tonic-gate { 14067c478bd9Sstevel@tonic-gate (void) sm_setevent(minqintvl, runqueueevent, 0); 14077c478bd9Sstevel@tonic-gate return true; 14087c478bd9Sstevel@tonic-gate } 14097c478bd9Sstevel@tonic-gate return false; 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_RUN_PARANOIA */ 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate /* 14147c478bd9Sstevel@tonic-gate ** RUNQUEUE -- run the jobs in the queue. 14157c478bd9Sstevel@tonic-gate ** 14167c478bd9Sstevel@tonic-gate ** Gets the stuff out of the queue in some presumably logical 14177c478bd9Sstevel@tonic-gate ** order and processes them. 14187c478bd9Sstevel@tonic-gate ** 14197c478bd9Sstevel@tonic-gate ** Parameters: 14207c478bd9Sstevel@tonic-gate ** forkflag -- true if the queue scanning should be done in 14217c478bd9Sstevel@tonic-gate ** a child process. We double-fork so it is not our 14227c478bd9Sstevel@tonic-gate ** child and we don't have to clean up after it. 14237c478bd9Sstevel@tonic-gate ** false can be ignored if we have multiple queues. 14247c478bd9Sstevel@tonic-gate ** verbose -- if true, print out status information. 14257c478bd9Sstevel@tonic-gate ** persistent -- persistent queue runner? 14267c478bd9Sstevel@tonic-gate ** runall -- run all groups or only a subset (DoQueueRun)? 14277c478bd9Sstevel@tonic-gate ** 14287c478bd9Sstevel@tonic-gate ** Returns: 14297c478bd9Sstevel@tonic-gate ** true if the queue run successfully began. 14307c478bd9Sstevel@tonic-gate ** 14317c478bd9Sstevel@tonic-gate ** Side Effects: 14327c478bd9Sstevel@tonic-gate ** runs things in the mail queue using run_work_group(). 14337c478bd9Sstevel@tonic-gate ** maybe schedules next queue run. 14347c478bd9Sstevel@tonic-gate */ 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate static ENVELOPE QueueEnvelope; /* the queue run envelope */ 14377c478bd9Sstevel@tonic-gate static time_t LastQueueTime = 0; /* last time a queue ID assigned */ 14387c478bd9Sstevel@tonic-gate static pid_t LastQueuePid = -1; /* last PID which had a queue ID */ 14397c478bd9Sstevel@tonic-gate 14407c478bd9Sstevel@tonic-gate /* values for qp_supdirs */ 14417c478bd9Sstevel@tonic-gate #define QP_NOSUB 0x0000 /* No subdirectories */ 14427c478bd9Sstevel@tonic-gate #define QP_SUBDF 0x0001 /* "df" subdirectory */ 14437c478bd9Sstevel@tonic-gate #define QP_SUBQF 0x0002 /* "qf" subdirectory */ 14447c478bd9Sstevel@tonic-gate #define QP_SUBXF 0x0004 /* "xf" subdirectory */ 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate bool 14477c478bd9Sstevel@tonic-gate runqueue(forkflag, verbose, persistent, runall) 14487c478bd9Sstevel@tonic-gate bool forkflag; 14497c478bd9Sstevel@tonic-gate bool verbose; 14507c478bd9Sstevel@tonic-gate bool persistent; 14517c478bd9Sstevel@tonic-gate bool runall; 14527c478bd9Sstevel@tonic-gate { 14537c478bd9Sstevel@tonic-gate int i; 14547c478bd9Sstevel@tonic-gate bool ret = true; 14557c478bd9Sstevel@tonic-gate static int curnum = 0; 14567c478bd9Sstevel@tonic-gate sigfunc_t cursh; 14577c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 14587c478bd9Sstevel@tonic-gate SM_NONVOLATILE int oldgroup = 0; 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugLeakQ, 1)) 14617c478bd9Sstevel@tonic-gate { 14627c478bd9Sstevel@tonic-gate oldgroup = sm_heap_group(); 14637c478bd9Sstevel@tonic-gate sm_heap_newgroup(); 14647c478bd9Sstevel@tonic-gate sm_dprintf("runqueue() heap group #%d\n", sm_heap_group()); 14657c478bd9Sstevel@tonic-gate } 14667c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate /* queue run has been started, don't do any more this time */ 14697c478bd9Sstevel@tonic-gate DoQueueRun = false; 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate /* more than one queue or more than one directory per queue */ 14727c478bd9Sstevel@tonic-gate if (!forkflag && !verbose && 14737c478bd9Sstevel@tonic-gate (WorkGrp[0].wg_qgs[0]->qg_numqueues > 1 || NumWorkGroups > 1 || 14747c478bd9Sstevel@tonic-gate WorkGrp[0].wg_numqgrp > 1)) 14757c478bd9Sstevel@tonic-gate forkflag = true; 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate /* 14787c478bd9Sstevel@tonic-gate ** For controlling queue runners via signals sent to this process. 14797c478bd9Sstevel@tonic-gate ** Oldsh* will get called too by runners_sig* (if it is not SIG_IGN 14807c478bd9Sstevel@tonic-gate ** or SIG_DFL) to preserve cleanup behavior. Now that this process 14817c478bd9Sstevel@tonic-gate ** will have children (and perhaps grandchildren) this handler will 14827c478bd9Sstevel@tonic-gate ** be left in place. This is because this process, once it has 14837c478bd9Sstevel@tonic-gate ** finished spinning off queue runners, may go back to doing something 14847c478bd9Sstevel@tonic-gate ** else (like being a daemon). And we still want on a SIG{TERM,HUP} to 14857c478bd9Sstevel@tonic-gate ** clean up the child queue runners. Only install 'runners_sig*' once 14867c478bd9Sstevel@tonic-gate ** else we'll get stuck looping forever. 14877c478bd9Sstevel@tonic-gate */ 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate cursh = sm_signal(SIGTERM, runners_sigterm); 14907c478bd9Sstevel@tonic-gate if (cursh != runners_sigterm) 14917c478bd9Sstevel@tonic-gate Oldsh_term = cursh; 14927c478bd9Sstevel@tonic-gate cursh = sm_signal(SIGHUP, runners_sighup); 14937c478bd9Sstevel@tonic-gate if (cursh != runners_sighup) 14947c478bd9Sstevel@tonic-gate Oldsh_hup = cursh; 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate for (i = 0; i < NumWorkGroups && !NoMoreRunners; i++) 14977c478bd9Sstevel@tonic-gate { 14987c478bd9Sstevel@tonic-gate int rwgflags = RWG_NONE; 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate /* 15017c478bd9Sstevel@tonic-gate ** If MaxQueueChildren active then test whether the start 15027c478bd9Sstevel@tonic-gate ** of the next queue group's additional queue runners (maximum) 15037c478bd9Sstevel@tonic-gate ** will result in MaxQueueChildren being exceeded. 15047c478bd9Sstevel@tonic-gate ** 15057c478bd9Sstevel@tonic-gate ** Note: do not use continue; even though another workgroup 15067c478bd9Sstevel@tonic-gate ** may have fewer queue runners, this would be "unfair", 15077c478bd9Sstevel@tonic-gate ** i.e., this work group might "starve" then. 15087c478bd9Sstevel@tonic-gate */ 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 15117c478bd9Sstevel@tonic-gate if (tTd(69, 10)) 15127c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 15137c478bd9Sstevel@tonic-gate "rq: curnum=%d, MaxQueueChildren=%d, CurRunners=%d, WorkGrp[curnum].wg_maxact=%d", 15147c478bd9Sstevel@tonic-gate curnum, MaxQueueChildren, CurRunners, 15157c478bd9Sstevel@tonic-gate WorkGrp[curnum].wg_maxact); 15167c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 15177c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && 15187c478bd9Sstevel@tonic-gate CurRunners + WorkGrp[curnum].wg_maxact > MaxQueueChildren) 15197c478bd9Sstevel@tonic-gate break; 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate /* 15227c478bd9Sstevel@tonic-gate ** Pick up where we left off (curnum), in case we 15237c478bd9Sstevel@tonic-gate ** used up all the children last time without finishing. 15247c478bd9Sstevel@tonic-gate ** This give a round-robin fairness to queue runs. 15257c478bd9Sstevel@tonic-gate ** 15267c478bd9Sstevel@tonic-gate ** Increment CurRunners before calling run_work_group() 15277c478bd9Sstevel@tonic-gate ** to avoid a "race condition" with proc_list_drop() which 15287c478bd9Sstevel@tonic-gate ** decrements CurRunners if the queue runners terminate. 15297c478bd9Sstevel@tonic-gate ** Notice: CurRunners is an upper limit, in some cases 15307c478bd9Sstevel@tonic-gate ** (too few jobs in the queue) this value is larger than 15317c478bd9Sstevel@tonic-gate ** the actual number of queue runners. The discrepancy can 15327c478bd9Sstevel@tonic-gate ** increase if some queue runners "hang" for a long time. 15337c478bd9Sstevel@tonic-gate */ 15347c478bd9Sstevel@tonic-gate 15357c478bd9Sstevel@tonic-gate CurRunners += WorkGrp[curnum].wg_maxact; 15367c478bd9Sstevel@tonic-gate if (forkflag) 15377c478bd9Sstevel@tonic-gate rwgflags |= RWG_FORK; 15387c478bd9Sstevel@tonic-gate if (verbose) 15397c478bd9Sstevel@tonic-gate rwgflags |= RWG_VERBOSE; 15407c478bd9Sstevel@tonic-gate if (persistent) 15417c478bd9Sstevel@tonic-gate rwgflags |= RWG_PERSISTENT; 15427c478bd9Sstevel@tonic-gate if (runall) 15437c478bd9Sstevel@tonic-gate rwgflags |= RWG_RUNALL; 15447c478bd9Sstevel@tonic-gate ret = run_work_group(curnum, rwgflags); 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate /* 15477c478bd9Sstevel@tonic-gate ** Failure means a message was printed for ETRN 15487c478bd9Sstevel@tonic-gate ** and subsequent queues are likely to fail as well. 15497c478bd9Sstevel@tonic-gate ** Decrement CurRunners in that case because 15507c478bd9Sstevel@tonic-gate ** none have been started. 15517c478bd9Sstevel@tonic-gate */ 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate if (!ret) 15547c478bd9Sstevel@tonic-gate { 15557c478bd9Sstevel@tonic-gate CurRunners -= WorkGrp[curnum].wg_maxact; 15567c478bd9Sstevel@tonic-gate break; 15577c478bd9Sstevel@tonic-gate } 15587c478bd9Sstevel@tonic-gate 15597c478bd9Sstevel@tonic-gate if (!persistent) 15607c478bd9Sstevel@tonic-gate schedule_queue_runs(runall, curnum, true); 15617c478bd9Sstevel@tonic-gate INCR_MOD(curnum, NumWorkGroups); 15627c478bd9Sstevel@tonic-gate } 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate /* schedule left over queue runs */ 15657c478bd9Sstevel@tonic-gate if (i < NumWorkGroups && !NoMoreRunners && !persistent) 15667c478bd9Sstevel@tonic-gate { 15677c478bd9Sstevel@tonic-gate int h; 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate for (h = curnum; i < NumWorkGroups; i++) 15707c478bd9Sstevel@tonic-gate { 15717c478bd9Sstevel@tonic-gate schedule_queue_runs(runall, h, false); 15727c478bd9Sstevel@tonic-gate INCR_MOD(h, NumWorkGroups); 15737c478bd9Sstevel@tonic-gate } 15747c478bd9Sstevel@tonic-gate } 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 15787c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugLeakQ, 1)) 15797c478bd9Sstevel@tonic-gate sm_heap_setgroup(oldgroup); 15807c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 15817c478bd9Sstevel@tonic-gate return ret; 15827c478bd9Sstevel@tonic-gate } 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate #if _FFR_SKIP_DOMAINS 15857c478bd9Sstevel@tonic-gate /* 15867c478bd9Sstevel@tonic-gate ** SKIP_DOMAINS -- Skip 'skip' number of domains in the WorkQ. 15877c478bd9Sstevel@tonic-gate ** 15887c478bd9Sstevel@tonic-gate ** Added by Stephen Frost <sfrost@snowman.net> to support 15897c478bd9Sstevel@tonic-gate ** having each runner process every N'th domain instead of 15907c478bd9Sstevel@tonic-gate ** every N'th message. 15917c478bd9Sstevel@tonic-gate ** 15927c478bd9Sstevel@tonic-gate ** Parameters: 15937c478bd9Sstevel@tonic-gate ** skip -- number of domains in WorkQ to skip. 15947c478bd9Sstevel@tonic-gate ** 15957c478bd9Sstevel@tonic-gate ** Returns: 15967c478bd9Sstevel@tonic-gate ** total number of messages skipped. 15977c478bd9Sstevel@tonic-gate ** 15987c478bd9Sstevel@tonic-gate ** Side Effects: 15997c478bd9Sstevel@tonic-gate ** may change WorkQ 16007c478bd9Sstevel@tonic-gate */ 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate static int 16037c478bd9Sstevel@tonic-gate skip_domains(skip) 16047c478bd9Sstevel@tonic-gate int skip; 16057c478bd9Sstevel@tonic-gate { 16067c478bd9Sstevel@tonic-gate int n, seqjump; 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate for (n = 0, seqjump = 0; n < skip && WorkQ != NULL; seqjump++) 16097c478bd9Sstevel@tonic-gate { 16107c478bd9Sstevel@tonic-gate if (WorkQ->w_next != NULL) 16117c478bd9Sstevel@tonic-gate { 16127c478bd9Sstevel@tonic-gate if (WorkQ->w_host != NULL && 16137c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host != NULL) 16147c478bd9Sstevel@tonic-gate { 16157c478bd9Sstevel@tonic-gate if (sm_strcasecmp(WorkQ->w_host, 16167c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host) != 0) 16177c478bd9Sstevel@tonic-gate n++; 16187c478bd9Sstevel@tonic-gate } 16197c478bd9Sstevel@tonic-gate else 16207c478bd9Sstevel@tonic-gate { 16217c478bd9Sstevel@tonic-gate if ((WorkQ->w_host != NULL && 16227c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host == NULL) || 16237c478bd9Sstevel@tonic-gate (WorkQ->w_host == NULL && 16247c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host != NULL)) 16257c478bd9Sstevel@tonic-gate n++; 16267c478bd9Sstevel@tonic-gate } 16277c478bd9Sstevel@tonic-gate } 16287c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next; 16297c478bd9Sstevel@tonic-gate } 16307c478bd9Sstevel@tonic-gate return seqjump; 16317c478bd9Sstevel@tonic-gate } 16327c478bd9Sstevel@tonic-gate #endif /* _FFR_SKIP_DOMAINS */ 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate /* 16357c478bd9Sstevel@tonic-gate ** RUNNER_WORK -- have a queue runner do its work 16367c478bd9Sstevel@tonic-gate ** 16377c478bd9Sstevel@tonic-gate ** Have a queue runner do its work a list of entries. 16387c478bd9Sstevel@tonic-gate ** When work isn't directly being done then this process can take a signal 16397c478bd9Sstevel@tonic-gate ** and terminate immediately (in a clean fashion of course). 16407c478bd9Sstevel@tonic-gate ** When work is directly being done, it's not to be interrupted 16417c478bd9Sstevel@tonic-gate ** immediately: the work should be allowed to finish at a clean point 16427c478bd9Sstevel@tonic-gate ** before termination (in a clean fashion of course). 16437c478bd9Sstevel@tonic-gate ** 16447c478bd9Sstevel@tonic-gate ** Parameters: 16457c478bd9Sstevel@tonic-gate ** e -- envelope. 16467c478bd9Sstevel@tonic-gate ** sequenceno -- 'th process to run WorkQ. 16477c478bd9Sstevel@tonic-gate ** didfork -- did the calling process fork()? 16487c478bd9Sstevel@tonic-gate ** skip -- process only each skip'th item. 16497c478bd9Sstevel@tonic-gate ** njobs -- number of jobs in WorkQ. 16507c478bd9Sstevel@tonic-gate ** 16517c478bd9Sstevel@tonic-gate ** Returns: 16527c478bd9Sstevel@tonic-gate ** none. 16537c478bd9Sstevel@tonic-gate ** 16547c478bd9Sstevel@tonic-gate ** Side Effects: 16557c478bd9Sstevel@tonic-gate ** runs things in the mail queue. 16567c478bd9Sstevel@tonic-gate */ 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate static void 16597c478bd9Sstevel@tonic-gate runner_work(e, sequenceno, didfork, skip, njobs) 16607c478bd9Sstevel@tonic-gate register ENVELOPE *e; 16617c478bd9Sstevel@tonic-gate int sequenceno; 16627c478bd9Sstevel@tonic-gate bool didfork; 16637c478bd9Sstevel@tonic-gate int skip; 16647c478bd9Sstevel@tonic-gate int njobs; 16657c478bd9Sstevel@tonic-gate { 16667c478bd9Sstevel@tonic-gate int n, seqjump; 16677c478bd9Sstevel@tonic-gate WORK *w; 16687c478bd9Sstevel@tonic-gate time_t now; 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate SM_GET_LA(now); 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate /* 16737c478bd9Sstevel@tonic-gate ** Here we temporarily block the second calling of the handlers. 16747c478bd9Sstevel@tonic-gate ** This allows us to handle the signal without terminating in the 16757c478bd9Sstevel@tonic-gate ** middle of direct work. If a signal does come, the test for 16767c478bd9Sstevel@tonic-gate ** NoMoreRunners will find it. 16777c478bd9Sstevel@tonic-gate */ 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate BlockOldsh = true; 16807c478bd9Sstevel@tonic-gate seqjump = skip; 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate /* process them once at a time */ 16837c478bd9Sstevel@tonic-gate while (WorkQ != NULL) 16847c478bd9Sstevel@tonic-gate { 16857c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 16867c478bd9Sstevel@tonic-gate SM_NONVOLATILE int oldgroup = 0; 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugLeakQ, 1)) 16897c478bd9Sstevel@tonic-gate { 16907c478bd9Sstevel@tonic-gate oldgroup = sm_heap_group(); 16917c478bd9Sstevel@tonic-gate sm_heap_newgroup(); 16927c478bd9Sstevel@tonic-gate sm_dprintf("run_queue_group() heap group #%d\n", 16937c478bd9Sstevel@tonic-gate sm_heap_group()); 16947c478bd9Sstevel@tonic-gate } 16957c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate /* do no more work */ 16987c478bd9Sstevel@tonic-gate if (NoMoreRunners) 16997c478bd9Sstevel@tonic-gate { 17007c478bd9Sstevel@tonic-gate /* Check that a valid signal handler is callable */ 17017c478bd9Sstevel@tonic-gate if (Oldsh != SIG_DFL && Oldsh != SIG_IGN && 17027c478bd9Sstevel@tonic-gate Oldsh != runners_sighup && 17037c478bd9Sstevel@tonic-gate Oldsh != runners_sigterm) 17047c478bd9Sstevel@tonic-gate (*Oldsh)(Oldsig); 17057c478bd9Sstevel@tonic-gate break; 17067c478bd9Sstevel@tonic-gate } 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate w = WorkQ; /* assign current work item */ 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate /* 17117c478bd9Sstevel@tonic-gate ** Set the head of the WorkQ to the next work item. 17127c478bd9Sstevel@tonic-gate ** It is set 'skip' ahead (the number of parallel queue 17137c478bd9Sstevel@tonic-gate ** runners working on WorkQ together) since each runner 17147c478bd9Sstevel@tonic-gate ** works on every 'skip'th (N-th) item. 17157c478bd9Sstevel@tonic-gate #if _FFR_SKIP_DOMAINS 17167c478bd9Sstevel@tonic-gate ** In the case of the BYHOST Queue Sort Order, the 'item' 17177c478bd9Sstevel@tonic-gate ** is a domain, so we work on every 'skip'th (N-th) domain. 17187c478bd9Sstevel@tonic-gate #endif * _FFR_SKIP_DOMAINS * 17197c478bd9Sstevel@tonic-gate */ 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate #if _FFR_SKIP_DOMAINS 17227c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST) 17237c478bd9Sstevel@tonic-gate { 17247c478bd9Sstevel@tonic-gate seqjump = 1; 17257c478bd9Sstevel@tonic-gate if (WorkQ->w_next != NULL) 17267c478bd9Sstevel@tonic-gate { 17277c478bd9Sstevel@tonic-gate if (WorkQ->w_host != NULL && 17287c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host != NULL) 17297c478bd9Sstevel@tonic-gate { 17307c478bd9Sstevel@tonic-gate if (sm_strcasecmp(WorkQ->w_host, 17317c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host) 17327c478bd9Sstevel@tonic-gate != 0) 17337c478bd9Sstevel@tonic-gate seqjump = skip_domains(skip); 17347c478bd9Sstevel@tonic-gate else 17357c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next; 17367c478bd9Sstevel@tonic-gate } 17377c478bd9Sstevel@tonic-gate else 17387c478bd9Sstevel@tonic-gate { 17397c478bd9Sstevel@tonic-gate if ((WorkQ->w_host != NULL && 17407c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host == NULL) || 17417c478bd9Sstevel@tonic-gate (WorkQ->w_host == NULL && 17427c478bd9Sstevel@tonic-gate WorkQ->w_next->w_host != NULL)) 17437c478bd9Sstevel@tonic-gate seqjump = skip_domains(skip); 17447c478bd9Sstevel@tonic-gate else 17457c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next; 17467c478bd9Sstevel@tonic-gate } 17477c478bd9Sstevel@tonic-gate } 17487c478bd9Sstevel@tonic-gate else 17497c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next; 17507c478bd9Sstevel@tonic-gate } 17517c478bd9Sstevel@tonic-gate else 17527c478bd9Sstevel@tonic-gate #endif /* _FFR_SKIP_DOMAINS */ 17537c478bd9Sstevel@tonic-gate { 17547c478bd9Sstevel@tonic-gate for (n = 0; n < skip && WorkQ != NULL; n++) 17557c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next; 17567c478bd9Sstevel@tonic-gate } 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate e->e_to = NULL; 17597c478bd9Sstevel@tonic-gate 17607c478bd9Sstevel@tonic-gate /* 17617c478bd9Sstevel@tonic-gate ** Ignore jobs that are too expensive for the moment. 17627c478bd9Sstevel@tonic-gate ** 17637c478bd9Sstevel@tonic-gate ** Get new load average every GET_NEW_LA_TIME seconds. 17647c478bd9Sstevel@tonic-gate */ 17657c478bd9Sstevel@tonic-gate 17667c478bd9Sstevel@tonic-gate SM_GET_LA(now); 17677c478bd9Sstevel@tonic-gate if (shouldqueue(WkRecipFact, Current_LA_time)) 17687c478bd9Sstevel@tonic-gate { 17697c478bd9Sstevel@tonic-gate char *msg = "Aborting queue run: load average too high"; 17707c478bd9Sstevel@tonic-gate 17717c478bd9Sstevel@tonic-gate if (Verbose) 17727c478bd9Sstevel@tonic-gate message("%s", msg); 17737c478bd9Sstevel@tonic-gate if (LogLevel > 8) 17747c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "runqueue: %s", msg); 17757c478bd9Sstevel@tonic-gate break; 17767c478bd9Sstevel@tonic-gate } 17777c478bd9Sstevel@tonic-gate if (shouldqueue(w->w_pri, w->w_ctime)) 17787c478bd9Sstevel@tonic-gate { 17797c478bd9Sstevel@tonic-gate if (Verbose) 17807c478bd9Sstevel@tonic-gate message(EmptyString); 17817c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYPRIORITY) 17827c478bd9Sstevel@tonic-gate { 17837c478bd9Sstevel@tonic-gate if (Verbose) 17847c478bd9Sstevel@tonic-gate message("Skipping %s/%s (sequence %d of %d) and flushing rest of queue", 17857c478bd9Sstevel@tonic-gate qid_printqueue(w->w_qgrp, 17867c478bd9Sstevel@tonic-gate w->w_qdir), 17877c478bd9Sstevel@tonic-gate w->w_name + 2, sequenceno, 17887c478bd9Sstevel@tonic-gate njobs); 17897c478bd9Sstevel@tonic-gate if (LogLevel > 8) 17907c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 17917c478bd9Sstevel@tonic-gate "runqueue: Flushing queue from %s/%s (pri %ld, LA %d, %d of %d)", 17927c478bd9Sstevel@tonic-gate qid_printqueue(w->w_qgrp, 17937c478bd9Sstevel@tonic-gate w->w_qdir), 17947c478bd9Sstevel@tonic-gate w->w_name + 2, w->w_pri, 17957c478bd9Sstevel@tonic-gate CurrentLA, sequenceno, 17967c478bd9Sstevel@tonic-gate njobs); 17977c478bd9Sstevel@tonic-gate break; 17987c478bd9Sstevel@tonic-gate } 17997c478bd9Sstevel@tonic-gate else if (Verbose) 18007c478bd9Sstevel@tonic-gate message("Skipping %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 else 18057c478bd9Sstevel@tonic-gate { 18067c478bd9Sstevel@tonic-gate if (Verbose) 18077c478bd9Sstevel@tonic-gate { 18087c478bd9Sstevel@tonic-gate message(EmptyString); 18097c478bd9Sstevel@tonic-gate message("Running %s/%s (sequence %d of %d)", 18107c478bd9Sstevel@tonic-gate qid_printqueue(w->w_qgrp, w->w_qdir), 18117c478bd9Sstevel@tonic-gate w->w_name + 2, sequenceno, njobs); 18127c478bd9Sstevel@tonic-gate } 18137c478bd9Sstevel@tonic-gate if (didfork && MaxQueueChildren > 0) 18147c478bd9Sstevel@tonic-gate { 18157c478bd9Sstevel@tonic-gate sm_blocksignal(SIGCHLD); 18167c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, reapchild); 18177c478bd9Sstevel@tonic-gate } 18187c478bd9Sstevel@tonic-gate if (tTd(63, 100)) 18197c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, NOQID, 18207c478bd9Sstevel@tonic-gate "runqueue %s dowork(%s)", 18217c478bd9Sstevel@tonic-gate qid_printqueue(w->w_qgrp, w->w_qdir), 18227c478bd9Sstevel@tonic-gate w->w_name + 2); 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate (void) dowork(w->w_qgrp, w->w_qdir, w->w_name + 2, 18257c478bd9Sstevel@tonic-gate ForkQueueRuns, false, e); 18267c478bd9Sstevel@tonic-gate errno = 0; 18277c478bd9Sstevel@tonic-gate } 18287c478bd9Sstevel@tonic-gate sm_free(w->w_name); /* XXX */ 18297c478bd9Sstevel@tonic-gate if (w->w_host != NULL) 18307c478bd9Sstevel@tonic-gate sm_free(w->w_host); /* XXX */ 18317c478bd9Sstevel@tonic-gate sm_free((char *) w); /* XXX */ 18327c478bd9Sstevel@tonic-gate sequenceno += seqjump; /* next sequence number */ 18337c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 18347c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugLeakQ, 1)) 18357c478bd9Sstevel@tonic-gate sm_heap_setgroup(oldgroup); 18367c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 18377c478bd9Sstevel@tonic-gate } 18387c478bd9Sstevel@tonic-gate 18397c478bd9Sstevel@tonic-gate BlockOldsh = false; 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate /* check the signals didn't happen during the revert */ 18427c478bd9Sstevel@tonic-gate if (NoMoreRunners) 18437c478bd9Sstevel@tonic-gate { 18447c478bd9Sstevel@tonic-gate /* Check that a valid signal handler is callable */ 18457c478bd9Sstevel@tonic-gate if (Oldsh != SIG_DFL && Oldsh != SIG_IGN && 18467c478bd9Sstevel@tonic-gate Oldsh != runners_sighup && Oldsh != runners_sigterm) 18477c478bd9Sstevel@tonic-gate (*Oldsh)(Oldsig); 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate Oldsh = SIG_DFL; /* after the NoMoreRunners check */ 18517c478bd9Sstevel@tonic-gate } 18527c478bd9Sstevel@tonic-gate /* 18537c478bd9Sstevel@tonic-gate ** RUN_WORK_GROUP -- run the jobs in a queue group from a work group. 18547c478bd9Sstevel@tonic-gate ** 18557c478bd9Sstevel@tonic-gate ** Gets the stuff out of the queue in some presumably logical 18567c478bd9Sstevel@tonic-gate ** order and processes them. 18577c478bd9Sstevel@tonic-gate ** 18587c478bd9Sstevel@tonic-gate ** Parameters: 18597c478bd9Sstevel@tonic-gate ** wgrp -- work group to process. 18607c478bd9Sstevel@tonic-gate ** flags -- RWG_* flags 18617c478bd9Sstevel@tonic-gate ** 18627c478bd9Sstevel@tonic-gate ** Returns: 18637c478bd9Sstevel@tonic-gate ** true if the queue run successfully began. 18647c478bd9Sstevel@tonic-gate ** 18657c478bd9Sstevel@tonic-gate ** Side Effects: 18667c478bd9Sstevel@tonic-gate ** runs things in the mail queue. 18677c478bd9Sstevel@tonic-gate */ 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate /* Minimum sleep time for persistent queue runners */ 18707c478bd9Sstevel@tonic-gate #define MIN_SLEEP_TIME 5 18717c478bd9Sstevel@tonic-gate 18727c478bd9Sstevel@tonic-gate bool 18737c478bd9Sstevel@tonic-gate run_work_group(wgrp, flags) 18747c478bd9Sstevel@tonic-gate int wgrp; 18757c478bd9Sstevel@tonic-gate int flags; 18767c478bd9Sstevel@tonic-gate { 18777c478bd9Sstevel@tonic-gate register ENVELOPE *e; 18787c478bd9Sstevel@tonic-gate int njobs, qdir; 18797c478bd9Sstevel@tonic-gate int sequenceno = 1; 18807c478bd9Sstevel@tonic-gate int qgrp, endgrp, h, i; 18817c478bd9Sstevel@tonic-gate time_t now; 18827c478bd9Sstevel@tonic-gate bool full, more; 18837c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool; 18847c478bd9Sstevel@tonic-gate extern ENVELOPE BlankEnvelope; 18857c478bd9Sstevel@tonic-gate extern SIGFUNC_DECL reapchild __P((int)); 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate if (wgrp < 0) 18887c478bd9Sstevel@tonic-gate return false; 18897c478bd9Sstevel@tonic-gate 18907c478bd9Sstevel@tonic-gate /* 18917c478bd9Sstevel@tonic-gate ** If no work will ever be selected, don't even bother reading 18927c478bd9Sstevel@tonic-gate ** the queue. 18937c478bd9Sstevel@tonic-gate */ 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate SM_GET_LA(now); 18967c478bd9Sstevel@tonic-gate 18977c478bd9Sstevel@tonic-gate if (!bitset(RWG_PERSISTENT, flags) && 18987c478bd9Sstevel@tonic-gate shouldqueue(WkRecipFact, Current_LA_time)) 18997c478bd9Sstevel@tonic-gate { 19007c478bd9Sstevel@tonic-gate char *msg = "Skipping queue run -- load average too high"; 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate if (bitset(RWG_VERBOSE, flags)) 19037c478bd9Sstevel@tonic-gate message("458 %s\n", msg); 19047c478bd9Sstevel@tonic-gate if (LogLevel > 8) 19057c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "runqueue: %s", msg); 19067c478bd9Sstevel@tonic-gate return false; 19077c478bd9Sstevel@tonic-gate } 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate /* 19107c478bd9Sstevel@tonic-gate ** See if we already have too many children. 19117c478bd9Sstevel@tonic-gate */ 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags) && 19147c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_lowqintvl > 0 && 19157c478bd9Sstevel@tonic-gate !bitset(RWG_PERSISTENT, flags) && 19167c478bd9Sstevel@tonic-gate MaxChildren > 0 && CurChildren >= MaxChildren) 19177c478bd9Sstevel@tonic-gate { 19187c478bd9Sstevel@tonic-gate char *msg = "Skipping queue run -- too many children"; 19197c478bd9Sstevel@tonic-gate 19207c478bd9Sstevel@tonic-gate if (bitset(RWG_VERBOSE, flags)) 19217c478bd9Sstevel@tonic-gate message("458 %s (%d)\n", msg, CurChildren); 19227c478bd9Sstevel@tonic-gate if (LogLevel > 8) 19237c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "runqueue: %s (%d)", 19247c478bd9Sstevel@tonic-gate msg, CurChildren); 19257c478bd9Sstevel@tonic-gate return false; 19267c478bd9Sstevel@tonic-gate } 19277c478bd9Sstevel@tonic-gate 19287c478bd9Sstevel@tonic-gate /* 19297c478bd9Sstevel@tonic-gate ** See if we want to go off and do other useful work. 19307c478bd9Sstevel@tonic-gate */ 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags)) 19337c478bd9Sstevel@tonic-gate { 19347c478bd9Sstevel@tonic-gate pid_t pid; 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate (void) sm_blocksignal(SIGCHLD); 19377c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, reapchild); 19387c478bd9Sstevel@tonic-gate 19397c478bd9Sstevel@tonic-gate pid = dofork(); 19407c478bd9Sstevel@tonic-gate if (pid == -1) 19417c478bd9Sstevel@tonic-gate { 19427c478bd9Sstevel@tonic-gate const char *msg = "Skipping queue run -- fork() failed"; 19437c478bd9Sstevel@tonic-gate const char *err = sm_errstring(errno); 19447c478bd9Sstevel@tonic-gate 19457c478bd9Sstevel@tonic-gate if (bitset(RWG_VERBOSE, flags)) 19467c478bd9Sstevel@tonic-gate message("458 %s: %s\n", msg, err); 19477c478bd9Sstevel@tonic-gate if (LogLevel > 8) 19487c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "runqueue: %s: %s", 19497c478bd9Sstevel@tonic-gate msg, err); 19507c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGCHLD); 19517c478bd9Sstevel@tonic-gate return false; 19527c478bd9Sstevel@tonic-gate } 19537c478bd9Sstevel@tonic-gate if (pid != 0) 19547c478bd9Sstevel@tonic-gate { 19557c478bd9Sstevel@tonic-gate /* parent -- pick up intermediate zombie */ 19567c478bd9Sstevel@tonic-gate (void) sm_blocksignal(SIGALRM); 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate /* wgrp only used when queue runners are persistent */ 19597c478bd9Sstevel@tonic-gate proc_list_add(pid, "Queue runner", PROC_QUEUE, 19607c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_maxact, 19617c478bd9Sstevel@tonic-gate bitset(RWG_PERSISTENT, flags) ? wgrp : -1, 19627c478bd9Sstevel@tonic-gate NULL); 19637c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGALRM); 19647c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGCHLD); 19657c478bd9Sstevel@tonic-gate return true; 19667c478bd9Sstevel@tonic-gate } 19677c478bd9Sstevel@tonic-gate 19687c478bd9Sstevel@tonic-gate /* child -- clean up signals */ 19697c478bd9Sstevel@tonic-gate 19707c478bd9Sstevel@tonic-gate /* Reset global flags */ 19717c478bd9Sstevel@tonic-gate RestartRequest = NULL; 19727c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 19737c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 19747c478bd9Sstevel@tonic-gate PendingSignal = 0; 19757c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 19767c478bd9Sstevel@tonic-gate close_sendmail_pid(); 19777c478bd9Sstevel@tonic-gate 19787c478bd9Sstevel@tonic-gate /* 19797c478bd9Sstevel@tonic-gate ** Initialize exception stack and default exception 19807c478bd9Sstevel@tonic-gate ** handler for child process. 19817c478bd9Sstevel@tonic-gate */ 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error); 19847c478bd9Sstevel@tonic-gate clrcontrol(); 19857c478bd9Sstevel@tonic-gate proc_list_clear(); 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate /* Add parent process as first child item */ 19887c478bd9Sstevel@tonic-gate proc_list_add(CurrentPid, "Queue runner child process", 19897c478bd9Sstevel@tonic-gate PROC_QUEUE_CHILD, 0, -1, NULL); 19907c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGCHLD); 19917c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 19927c478bd9Sstevel@tonic-gate (void) sm_signal(SIGHUP, SIG_DFL); 19937c478bd9Sstevel@tonic-gate (void) sm_signal(SIGTERM, intsig); 19947c478bd9Sstevel@tonic-gate } 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate /* 19977c478bd9Sstevel@tonic-gate ** Release any resources used by the daemon code. 19987c478bd9Sstevel@tonic-gate */ 19997c478bd9Sstevel@tonic-gate 20007c478bd9Sstevel@tonic-gate clrdaemon(); 20017c478bd9Sstevel@tonic-gate 20027c478bd9Sstevel@tonic-gate /* force it to run expensive jobs */ 20037c478bd9Sstevel@tonic-gate NoConnect = false; 20047c478bd9Sstevel@tonic-gate 20057c478bd9Sstevel@tonic-gate /* drop privileges */ 20067c478bd9Sstevel@tonic-gate if (geteuid() == (uid_t) 0) 20077c478bd9Sstevel@tonic-gate (void) drop_privileges(false); 20087c478bd9Sstevel@tonic-gate 20097c478bd9Sstevel@tonic-gate /* 20107c478bd9Sstevel@tonic-gate ** Create ourselves an envelope 20117c478bd9Sstevel@tonic-gate */ 20127c478bd9Sstevel@tonic-gate 20137c478bd9Sstevel@tonic-gate CurEnv = &QueueEnvelope; 20147c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL); 20157c478bd9Sstevel@tonic-gate e = newenvelope(&QueueEnvelope, CurEnv, rpool); 20167c478bd9Sstevel@tonic-gate e->e_flags = BlankEnvelope.e_flags; 20177c478bd9Sstevel@tonic-gate e->e_parent = NULL; 20187c478bd9Sstevel@tonic-gate 20197c478bd9Sstevel@tonic-gate /* make sure we have disconnected from parent */ 20207c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags)) 20217c478bd9Sstevel@tonic-gate { 20227c478bd9Sstevel@tonic-gate disconnect(1, e); 20237c478bd9Sstevel@tonic-gate QuickAbort = false; 20247c478bd9Sstevel@tonic-gate } 20257c478bd9Sstevel@tonic-gate 20267c478bd9Sstevel@tonic-gate /* 20277c478bd9Sstevel@tonic-gate ** If we are running part of the queue, always ignore stored 20287c478bd9Sstevel@tonic-gate ** host status. 20297c478bd9Sstevel@tonic-gate */ 20307c478bd9Sstevel@tonic-gate 20317c478bd9Sstevel@tonic-gate if (QueueLimitId != NULL || QueueLimitSender != NULL || 20327c478bd9Sstevel@tonic-gate QueueLimitQuarantine != NULL || 20337c478bd9Sstevel@tonic-gate QueueLimitRecipient != NULL) 20347c478bd9Sstevel@tonic-gate { 20357c478bd9Sstevel@tonic-gate IgnoreHostStatus = true; 20367c478bd9Sstevel@tonic-gate MinQueueAge = 0; 20377c478bd9Sstevel@tonic-gate } 20387c478bd9Sstevel@tonic-gate 20397c478bd9Sstevel@tonic-gate /* 20407c478bd9Sstevel@tonic-gate ** Here is where we choose the queue group from the work group. 20417c478bd9Sstevel@tonic-gate ** The caller of the "domorework" label must setup a new envelope. 20427c478bd9Sstevel@tonic-gate */ 20437c478bd9Sstevel@tonic-gate 20447c478bd9Sstevel@tonic-gate endgrp = WorkGrp[wgrp].wg_curqgrp; /* to not spin endlessly */ 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate domorework: 20477c478bd9Sstevel@tonic-gate 20487c478bd9Sstevel@tonic-gate /* 20497c478bd9Sstevel@tonic-gate ** Run a queue group if: 20507c478bd9Sstevel@tonic-gate ** RWG_RUNALL bit is set or the bit for this group is set. 20517c478bd9Sstevel@tonic-gate */ 20527c478bd9Sstevel@tonic-gate 20537c478bd9Sstevel@tonic-gate now = curtime(); 20547c478bd9Sstevel@tonic-gate for (;;) 20557c478bd9Sstevel@tonic-gate { 20567c478bd9Sstevel@tonic-gate /* 20577c478bd9Sstevel@tonic-gate ** Find the next queue group within the work group that 20587c478bd9Sstevel@tonic-gate ** has been marked as needing a run. 20597c478bd9Sstevel@tonic-gate */ 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate qgrp = WorkGrp[wgrp].wg_qgs[WorkGrp[wgrp].wg_curqgrp]->qg_index; 20627c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_curqgrp++; /* advance */ 20637c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_curqgrp %= WorkGrp[wgrp].wg_numqgrp; /* wrap */ 20647c478bd9Sstevel@tonic-gate if (bitset(RWG_RUNALL, flags) || 20657c478bd9Sstevel@tonic-gate (Queue[qgrp]->qg_nextrun <= now && 20667c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_nextrun != (time_t) -1)) 20677c478bd9Sstevel@tonic-gate break; 20687c478bd9Sstevel@tonic-gate if (endgrp == WorkGrp[wgrp].wg_curqgrp) 20697c478bd9Sstevel@tonic-gate { 20707c478bd9Sstevel@tonic-gate e->e_id = NULL; 20717c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags)) 20727c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 20737c478bd9Sstevel@tonic-gate return true; /* we're done */ 20747c478bd9Sstevel@tonic-gate } 20757c478bd9Sstevel@tonic-gate } 20767c478bd9Sstevel@tonic-gate 20777c478bd9Sstevel@tonic-gate qdir = Queue[qgrp]->qg_curnum; /* round-robin init of queue position */ 20787c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 20797c478bd9Sstevel@tonic-gate if (tTd(69, 12)) 20807c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 20817c478bd9Sstevel@tonic-gate "rwg: wgrp=%d, qgrp=%d, qdir=%d, name=%s, curqgrp=%d, numgrps=%d", 20827c478bd9Sstevel@tonic-gate wgrp, qgrp, qdir, qid_printqueue(qgrp, qdir), 20837c478bd9Sstevel@tonic-gate WorkGrp[wgrp].wg_curqgrp, WorkGrp[wgrp].wg_numqgrp); 20847c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate #if HASNICE 20877c478bd9Sstevel@tonic-gate /* tweak niceness of queue runs */ 20887c478bd9Sstevel@tonic-gate if (Queue[qgrp]->qg_nice > 0) 20897c478bd9Sstevel@tonic-gate (void) nice(Queue[qgrp]->qg_nice); 20907c478bd9Sstevel@tonic-gate #endif /* HASNICE */ 20917c478bd9Sstevel@tonic-gate 20927c478bd9Sstevel@tonic-gate /* XXX running queue group... */ 20937c478bd9Sstevel@tonic-gate sm_setproctitle(true, CurEnv, "running queue: %s", 20947c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 20957c478bd9Sstevel@tonic-gate 20967c478bd9Sstevel@tonic-gate if (LogLevel > 69 || tTd(63, 99)) 20977c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, NOQID, 20987c478bd9Sstevel@tonic-gate "runqueue %s, pid=%d, forkflag=%d", 20997c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), (int) CurrentPid, 21007c478bd9Sstevel@tonic-gate bitset(RWG_FORK, flags)); 21017c478bd9Sstevel@tonic-gate 21027c478bd9Sstevel@tonic-gate /* 21037c478bd9Sstevel@tonic-gate ** Start making passes through the queue. 21047c478bd9Sstevel@tonic-gate ** First, read and sort the entire queue. 21057c478bd9Sstevel@tonic-gate ** Then, process the work in that order. 21067c478bd9Sstevel@tonic-gate ** But if you take too long, start over. 21077c478bd9Sstevel@tonic-gate */ 21087c478bd9Sstevel@tonic-gate 21097c478bd9Sstevel@tonic-gate for (i = 0; i < Queue[qgrp]->qg_numqueues; i++) 21107c478bd9Sstevel@tonic-gate { 21117c478bd9Sstevel@tonic-gate h = gatherq(qgrp, qdir, false, &full, &more); 21127c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 21137c478bd9Sstevel@tonic-gate if (ShmId != SM_SHM_NO_ID) 21147c478bd9Sstevel@tonic-gate QSHM_ENTRIES(Queue[qgrp]->qg_qpaths[qdir].qp_idx) = h; 21157c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 21167c478bd9Sstevel@tonic-gate /* If there are no more items in this queue advance */ 21177c478bd9Sstevel@tonic-gate if (!more) 21187c478bd9Sstevel@tonic-gate { 21197c478bd9Sstevel@tonic-gate /* A round-robin advance */ 21207c478bd9Sstevel@tonic-gate qdir++; 21217c478bd9Sstevel@tonic-gate qdir %= Queue[qgrp]->qg_numqueues; 21227c478bd9Sstevel@tonic-gate } 21237c478bd9Sstevel@tonic-gate 21247c478bd9Sstevel@tonic-gate /* Has the WorkList reached the limit? */ 21257c478bd9Sstevel@tonic-gate if (full) 21267c478bd9Sstevel@tonic-gate break; /* don't try to gather more */ 21277c478bd9Sstevel@tonic-gate } 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate /* order the existing work requests */ 21307c478bd9Sstevel@tonic-gate njobs = sortq(Queue[qgrp]->qg_maxlist); 21317c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_curnum = qdir; /* update */ 21327c478bd9Sstevel@tonic-gate 21337c478bd9Sstevel@tonic-gate 21347c478bd9Sstevel@tonic-gate if (!Verbose && bitnset(QD_FORK, Queue[qgrp]->qg_flags)) 21357c478bd9Sstevel@tonic-gate { 21367c478bd9Sstevel@tonic-gate int loop, maxrunners; 21377c478bd9Sstevel@tonic-gate pid_t pid; 21387c478bd9Sstevel@tonic-gate 21397c478bd9Sstevel@tonic-gate /* 21407c478bd9Sstevel@tonic-gate ** For this WorkQ we want to fork off N children (maxrunners) 21417c478bd9Sstevel@tonic-gate ** at this point. Each child has a copy of WorkQ. Each child 21427c478bd9Sstevel@tonic-gate ** will process every N-th item. The parent will wait for all 21437c478bd9Sstevel@tonic-gate ** of the children to finish before moving on to the next 21447c478bd9Sstevel@tonic-gate ** queue group within the work group. This saves us forking 21457c478bd9Sstevel@tonic-gate ** a new runner-child for each work item. 21467c478bd9Sstevel@tonic-gate ** It's valid for qg_maxqrun == 0 since this may be an 21477c478bd9Sstevel@tonic-gate ** explicit "don't run this queue" setting. 21487c478bd9Sstevel@tonic-gate */ 21497c478bd9Sstevel@tonic-gate 21507c478bd9Sstevel@tonic-gate maxrunners = Queue[qgrp]->qg_maxqrun; 21517c478bd9Sstevel@tonic-gate 2152*7800901eSjbeck /* 2153*7800901eSjbeck ** If no runners are configured for this group but 2154*7800901eSjbeck ** the queue is "forced" then lets use 1 runner. 2155*7800901eSjbeck */ 2156*7800901eSjbeck 2157*7800901eSjbeck if (maxrunners == 0 && bitset(RWG_FORCE, flags)) 2158*7800901eSjbeck maxrunners = 1; 2159*7800901eSjbeck 21607c478bd9Sstevel@tonic-gate /* No need to have more runners then there are jobs */ 21617c478bd9Sstevel@tonic-gate if (maxrunners > njobs) 21627c478bd9Sstevel@tonic-gate maxrunners = njobs; 21637c478bd9Sstevel@tonic-gate for (loop = 0; loop < maxrunners; loop++) 21647c478bd9Sstevel@tonic-gate { 21657c478bd9Sstevel@tonic-gate /* 21667c478bd9Sstevel@tonic-gate ** Since the delivery may happen in a child and the 21677c478bd9Sstevel@tonic-gate ** parent does not wait, the parent may close the 21687c478bd9Sstevel@tonic-gate ** maps thereby removing any shared memory used by 21697c478bd9Sstevel@tonic-gate ** the map. Therefore, close the maps now so the 21707c478bd9Sstevel@tonic-gate ** child will dynamically open them if necessary. 21717c478bd9Sstevel@tonic-gate */ 21727c478bd9Sstevel@tonic-gate 21737c478bd9Sstevel@tonic-gate closemaps(false); 21747c478bd9Sstevel@tonic-gate 21757c478bd9Sstevel@tonic-gate pid = fork(); 21767c478bd9Sstevel@tonic-gate if (pid < 0) 21777c478bd9Sstevel@tonic-gate { 21787c478bd9Sstevel@tonic-gate syserr("run_work_group: cannot fork"); 21797c478bd9Sstevel@tonic-gate return false; 21807c478bd9Sstevel@tonic-gate } 21817c478bd9Sstevel@tonic-gate else if (pid > 0) 21827c478bd9Sstevel@tonic-gate { 21837c478bd9Sstevel@tonic-gate /* parent -- clean out connection cache */ 21847c478bd9Sstevel@tonic-gate mci_flush(false, NULL); 21857c478bd9Sstevel@tonic-gate #if _FFR_SKIP_DOMAINS 21867c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST) 21877c478bd9Sstevel@tonic-gate { 21887c478bd9Sstevel@tonic-gate sequenceno += skip_domains(1); 21897c478bd9Sstevel@tonic-gate } 21907c478bd9Sstevel@tonic-gate else 21917c478bd9Sstevel@tonic-gate #endif /* _FFR_SKIP_DOMAINS */ 21927c478bd9Sstevel@tonic-gate { 21937c478bd9Sstevel@tonic-gate /* for the skip */ 21947c478bd9Sstevel@tonic-gate WorkQ = WorkQ->w_next; 21957c478bd9Sstevel@tonic-gate sequenceno++; 21967c478bd9Sstevel@tonic-gate } 21977c478bd9Sstevel@tonic-gate proc_list_add(pid, "Queue child runner process", 21987c478bd9Sstevel@tonic-gate PROC_QUEUE_CHILD, 0, -1, NULL); 21997c478bd9Sstevel@tonic-gate 22007c478bd9Sstevel@tonic-gate /* No additional work, no additional runners */ 22017c478bd9Sstevel@tonic-gate if (WorkQ == NULL) 22027c478bd9Sstevel@tonic-gate break; 22037c478bd9Sstevel@tonic-gate } 22047c478bd9Sstevel@tonic-gate else 22057c478bd9Sstevel@tonic-gate { 22067c478bd9Sstevel@tonic-gate /* child -- Reset global flags */ 22077c478bd9Sstevel@tonic-gate RestartRequest = NULL; 22087c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 22097c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 22107c478bd9Sstevel@tonic-gate PendingSignal = 0; 22117c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 22127c478bd9Sstevel@tonic-gate close_sendmail_pid(); 22137c478bd9Sstevel@tonic-gate 22147c478bd9Sstevel@tonic-gate /* 22157c478bd9Sstevel@tonic-gate ** Initialize exception stack and default 22167c478bd9Sstevel@tonic-gate ** exception handler for child process. 22177c478bd9Sstevel@tonic-gate ** When fork()'d the child now has a private 22187c478bd9Sstevel@tonic-gate ** copy of WorkQ at its current position. 22197c478bd9Sstevel@tonic-gate */ 22207c478bd9Sstevel@tonic-gate 22217c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error); 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate /* 22247c478bd9Sstevel@tonic-gate ** SMTP processes (whether -bd or -bs) set 22257c478bd9Sstevel@tonic-gate ** SIGCHLD to reapchild to collect 22267c478bd9Sstevel@tonic-gate ** children status. However, at delivery 22277c478bd9Sstevel@tonic-gate ** time, that status must be collected 22287c478bd9Sstevel@tonic-gate ** by sm_wait() to be dealt with properly 22297c478bd9Sstevel@tonic-gate ** (check success of delivery based 22307c478bd9Sstevel@tonic-gate ** on status code, etc). Therefore, if we 22317c478bd9Sstevel@tonic-gate ** are an SMTP process, reset SIGCHLD 22327c478bd9Sstevel@tonic-gate ** back to the default so reapchild 22337c478bd9Sstevel@tonic-gate ** doesn't collect status before 22347c478bd9Sstevel@tonic-gate ** sm_wait(). 22357c478bd9Sstevel@tonic-gate */ 22367c478bd9Sstevel@tonic-gate 22377c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP || 22387c478bd9Sstevel@tonic-gate OpMode == MD_DAEMON || 22397c478bd9Sstevel@tonic-gate MaxQueueChildren > 0) 22407c478bd9Sstevel@tonic-gate { 22417c478bd9Sstevel@tonic-gate proc_list_clear(); 22427c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD); 22437c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 22447c478bd9Sstevel@tonic-gate } 22457c478bd9Sstevel@tonic-gate 22467c478bd9Sstevel@tonic-gate /* child -- error messages to the transcript */ 22477c478bd9Sstevel@tonic-gate QuickAbort = OnlyOneError = false; 22487c478bd9Sstevel@tonic-gate runner_work(e, sequenceno, true, 22497c478bd9Sstevel@tonic-gate maxrunners, njobs); 22507c478bd9Sstevel@tonic-gate 22517c478bd9Sstevel@tonic-gate /* This child is done */ 22527c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 22537c478bd9Sstevel@tonic-gate /* NOTREACHED */ 22547c478bd9Sstevel@tonic-gate } 22557c478bd9Sstevel@tonic-gate } 22567c478bd9Sstevel@tonic-gate 22577c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD); 22587c478bd9Sstevel@tonic-gate 22597c478bd9Sstevel@tonic-gate /* 22607c478bd9Sstevel@tonic-gate ** Wait until all of the runners have completed before 22617c478bd9Sstevel@tonic-gate ** seeing if there is another queue group in the 22627c478bd9Sstevel@tonic-gate ** work group to process. 22637c478bd9Sstevel@tonic-gate ** XXX Future enhancement: don't wait() for all children 22647c478bd9Sstevel@tonic-gate ** here, just go ahead and make sure that overall the number 22657c478bd9Sstevel@tonic-gate ** of children is not exceeded. 22667c478bd9Sstevel@tonic-gate */ 22677c478bd9Sstevel@tonic-gate 22687c478bd9Sstevel@tonic-gate while (CurChildren > 0) 22697c478bd9Sstevel@tonic-gate { 22707c478bd9Sstevel@tonic-gate int status; 22717c478bd9Sstevel@tonic-gate pid_t ret; 22727c478bd9Sstevel@tonic-gate 22737c478bd9Sstevel@tonic-gate while ((ret = sm_wait(&status)) <= 0) 22747c478bd9Sstevel@tonic-gate continue; 22757c478bd9Sstevel@tonic-gate proc_list_drop(ret, status, NULL); 22767c478bd9Sstevel@tonic-gate } 22777c478bd9Sstevel@tonic-gate } 22787c478bd9Sstevel@tonic-gate else if (Queue[qgrp]->qg_maxqrun > 0 || bitset(RWG_FORCE, flags)) 22797c478bd9Sstevel@tonic-gate { 22807c478bd9Sstevel@tonic-gate /* 22817c478bd9Sstevel@tonic-gate ** When current process will not fork children to do the work, 22827c478bd9Sstevel@tonic-gate ** it will do the work itself. The 'skip' will be 1 since 22837c478bd9Sstevel@tonic-gate ** there are no child runners to divide the work across. 22847c478bd9Sstevel@tonic-gate */ 22857c478bd9Sstevel@tonic-gate 22867c478bd9Sstevel@tonic-gate runner_work(e, sequenceno, false, 1, njobs); 22877c478bd9Sstevel@tonic-gate } 22887c478bd9Sstevel@tonic-gate 22897c478bd9Sstevel@tonic-gate /* free memory allocated by newenvelope() above */ 22907c478bd9Sstevel@tonic-gate sm_rpool_free(rpool); 22917c478bd9Sstevel@tonic-gate QueueEnvelope.e_rpool = NULL; 22927c478bd9Sstevel@tonic-gate 22937c478bd9Sstevel@tonic-gate /* Are there still more queues in the work group to process? */ 22947c478bd9Sstevel@tonic-gate if (endgrp != WorkGrp[wgrp].wg_curqgrp) 22957c478bd9Sstevel@tonic-gate { 22967c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL); 22977c478bd9Sstevel@tonic-gate e = newenvelope(&QueueEnvelope, CurEnv, rpool); 22987c478bd9Sstevel@tonic-gate e->e_flags = BlankEnvelope.e_flags; 22997c478bd9Sstevel@tonic-gate goto domorework; 23007c478bd9Sstevel@tonic-gate } 23017c478bd9Sstevel@tonic-gate 23027c478bd9Sstevel@tonic-gate /* No more queues in work group to process. Now check persistent. */ 23037c478bd9Sstevel@tonic-gate if (bitset(RWG_PERSISTENT, flags)) 23047c478bd9Sstevel@tonic-gate { 23057c478bd9Sstevel@tonic-gate sequenceno = 1; 23067c478bd9Sstevel@tonic-gate sm_setproctitle(true, CurEnv, "running queue: %s", 23077c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 23087c478bd9Sstevel@tonic-gate 23097c478bd9Sstevel@tonic-gate /* 23107c478bd9Sstevel@tonic-gate ** close bogus maps, i.e., maps which caused a tempfail, 23117c478bd9Sstevel@tonic-gate ** so we get fresh map connections on the next lookup. 23127c478bd9Sstevel@tonic-gate ** closemaps() is also called when children are started. 23137c478bd9Sstevel@tonic-gate */ 23147c478bd9Sstevel@tonic-gate 23157c478bd9Sstevel@tonic-gate closemaps(true); 23167c478bd9Sstevel@tonic-gate 23177c478bd9Sstevel@tonic-gate /* Close any cached connections. */ 23187c478bd9Sstevel@tonic-gate mci_flush(true, NULL); 23197c478bd9Sstevel@tonic-gate 23207c478bd9Sstevel@tonic-gate /* Clean out expired related entries. */ 23217c478bd9Sstevel@tonic-gate rmexpstab(); 23227c478bd9Sstevel@tonic-gate 23237c478bd9Sstevel@tonic-gate #if NAMED_BIND 23247c478bd9Sstevel@tonic-gate /* Update MX records for FallbackMX. */ 23257c478bd9Sstevel@tonic-gate if (FallbackMX != NULL) 23267c478bd9Sstevel@tonic-gate (void) getfallbackmxrr(FallbackMX); 23277c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 23287c478bd9Sstevel@tonic-gate 23297c478bd9Sstevel@tonic-gate #if USERDB 23307c478bd9Sstevel@tonic-gate /* close UserDatabase */ 23317c478bd9Sstevel@tonic-gate _udbx_close(); 23327c478bd9Sstevel@tonic-gate #endif /* USERDB */ 23337c478bd9Sstevel@tonic-gate 23347c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 23357c478bd9Sstevel@tonic-gate if (sm_debug_active(&SmHeapCheck, 2) 23367c478bd9Sstevel@tonic-gate && access("memdump", F_OK) == 0 23377c478bd9Sstevel@tonic-gate ) 23387c478bd9Sstevel@tonic-gate { 23397c478bd9Sstevel@tonic-gate SM_FILE_T *out; 23407c478bd9Sstevel@tonic-gate 23417c478bd9Sstevel@tonic-gate remove("memdump"); 23427c478bd9Sstevel@tonic-gate out = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, 23437c478bd9Sstevel@tonic-gate "memdump.out", SM_IO_APPEND, NULL); 23447c478bd9Sstevel@tonic-gate if (out != NULL) 23457c478bd9Sstevel@tonic-gate { 23467c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, "----------------------\n"); 23477c478bd9Sstevel@tonic-gate sm_heap_report(out, 23487c478bd9Sstevel@tonic-gate sm_debug_level(&SmHeapCheck) - 1); 23497c478bd9Sstevel@tonic-gate (void) sm_io_close(out, SM_TIME_DEFAULT); 23507c478bd9Sstevel@tonic-gate } 23517c478bd9Sstevel@tonic-gate } 23527c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate /* let me rest for a second to catch my breath */ 23557c478bd9Sstevel@tonic-gate if (njobs == 0 && WorkGrp[wgrp].wg_lowqintvl < MIN_SLEEP_TIME) 23567c478bd9Sstevel@tonic-gate sleep(MIN_SLEEP_TIME); 23577c478bd9Sstevel@tonic-gate else if (WorkGrp[wgrp].wg_lowqintvl <= 0) 23587c478bd9Sstevel@tonic-gate sleep(QueueIntvl > 0 ? QueueIntvl : MIN_SLEEP_TIME); 23597c478bd9Sstevel@tonic-gate else 23607c478bd9Sstevel@tonic-gate sleep(WorkGrp[wgrp].wg_lowqintvl); 23617c478bd9Sstevel@tonic-gate 23627c478bd9Sstevel@tonic-gate /* 23637c478bd9Sstevel@tonic-gate ** Get the LA outside the WorkQ loop if necessary. 23647c478bd9Sstevel@tonic-gate ** In a persistent queue runner the code is repeated over 23657c478bd9Sstevel@tonic-gate ** and over but gatherq() may ignore entries due to 23667c478bd9Sstevel@tonic-gate ** shouldqueue() (do we really have to do this twice?). 23677c478bd9Sstevel@tonic-gate ** Hence the queue runners would just idle around when once 23687c478bd9Sstevel@tonic-gate ** CurrentLA caused all entries in a queue to be ignored. 23697c478bd9Sstevel@tonic-gate */ 23707c478bd9Sstevel@tonic-gate 23717c478bd9Sstevel@tonic-gate if (njobs == 0) 23727c478bd9Sstevel@tonic-gate SM_GET_LA(now); 23737c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL); 23747c478bd9Sstevel@tonic-gate e = newenvelope(&QueueEnvelope, CurEnv, rpool); 23757c478bd9Sstevel@tonic-gate e->e_flags = BlankEnvelope.e_flags; 23767c478bd9Sstevel@tonic-gate goto domorework; 23777c478bd9Sstevel@tonic-gate } 23787c478bd9Sstevel@tonic-gate 23797c478bd9Sstevel@tonic-gate /* exit without the usual cleanup */ 23807c478bd9Sstevel@tonic-gate e->e_id = NULL; 23817c478bd9Sstevel@tonic-gate if (bitset(RWG_FORK, flags)) 23827c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 23837c478bd9Sstevel@tonic-gate /* NOTREACHED */ 23847c478bd9Sstevel@tonic-gate return true; 23857c478bd9Sstevel@tonic-gate } 23867c478bd9Sstevel@tonic-gate 23877c478bd9Sstevel@tonic-gate /* 23887c478bd9Sstevel@tonic-gate ** DOQUEUERUN -- do a queue run? 23897c478bd9Sstevel@tonic-gate */ 23907c478bd9Sstevel@tonic-gate 23917c478bd9Sstevel@tonic-gate bool 23927c478bd9Sstevel@tonic-gate doqueuerun() 23937c478bd9Sstevel@tonic-gate { 23947c478bd9Sstevel@tonic-gate return DoQueueRun; 23957c478bd9Sstevel@tonic-gate } 23967c478bd9Sstevel@tonic-gate 23977c478bd9Sstevel@tonic-gate /* 23987c478bd9Sstevel@tonic-gate ** RUNQUEUEEVENT -- Sets a flag to indicate that a queue run should be done. 23997c478bd9Sstevel@tonic-gate ** 24007c478bd9Sstevel@tonic-gate ** Parameters: 24017c478bd9Sstevel@tonic-gate ** none. 24027c478bd9Sstevel@tonic-gate ** 24037c478bd9Sstevel@tonic-gate ** Returns: 24047c478bd9Sstevel@tonic-gate ** none. 24057c478bd9Sstevel@tonic-gate ** 24067c478bd9Sstevel@tonic-gate ** Side Effects: 24077c478bd9Sstevel@tonic-gate ** The invocation of this function via an alarm may interrupt 24087c478bd9Sstevel@tonic-gate ** a set of actions. Thus errno may be set in that context. 24097c478bd9Sstevel@tonic-gate ** We need to restore errno at the end of this function to ensure 24107c478bd9Sstevel@tonic-gate ** that any work done here that sets errno doesn't return a 24117c478bd9Sstevel@tonic-gate ** misleading/false errno value. Errno may be EINTR upon entry to 24127c478bd9Sstevel@tonic-gate ** this function because of non-restartable/continuable system 24137c478bd9Sstevel@tonic-gate ** API was active. Iff this is true we will override errno as 24147c478bd9Sstevel@tonic-gate ** a timeout (as a more accurate error message). 24157c478bd9Sstevel@tonic-gate ** 24167c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 24177c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 24187c478bd9Sstevel@tonic-gate ** DOING. 24197c478bd9Sstevel@tonic-gate */ 24207c478bd9Sstevel@tonic-gate 24217c478bd9Sstevel@tonic-gate void 24227c478bd9Sstevel@tonic-gate runqueueevent(ignore) 24237c478bd9Sstevel@tonic-gate int ignore; 24247c478bd9Sstevel@tonic-gate { 24257c478bd9Sstevel@tonic-gate int save_errno = errno; 24267c478bd9Sstevel@tonic-gate 24277c478bd9Sstevel@tonic-gate /* 24287c478bd9Sstevel@tonic-gate ** Set the general bit that we want a queue run, 24297c478bd9Sstevel@tonic-gate ** tested in doqueuerun() 24307c478bd9Sstevel@tonic-gate */ 24317c478bd9Sstevel@tonic-gate 24327c478bd9Sstevel@tonic-gate DoQueueRun = true; 24337c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_SCHED_DBG 24347c478bd9Sstevel@tonic-gate if (tTd(69, 10)) 24357c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "rqe: done"); 24367c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_SCHED_DBG */ 24377c478bd9Sstevel@tonic-gate 24387c478bd9Sstevel@tonic-gate errno = save_errno; 24397c478bd9Sstevel@tonic-gate if (errno == EINTR) 24407c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 24417c478bd9Sstevel@tonic-gate } 24427c478bd9Sstevel@tonic-gate /* 24437c478bd9Sstevel@tonic-gate ** GATHERQ -- gather messages from the message queue(s) the work queue. 24447c478bd9Sstevel@tonic-gate ** 24457c478bd9Sstevel@tonic-gate ** Parameters: 24467c478bd9Sstevel@tonic-gate ** qgrp -- the index of the queue group. 24477c478bd9Sstevel@tonic-gate ** qdir -- the index of the queue directory. 24487c478bd9Sstevel@tonic-gate ** doall -- if set, include everything in the queue (even 24497c478bd9Sstevel@tonic-gate ** the jobs that cannot be run because the load 24507c478bd9Sstevel@tonic-gate ** average is too high, or MaxQueueRun is reached). 24517c478bd9Sstevel@tonic-gate ** Otherwise, exclude those jobs. 24527c478bd9Sstevel@tonic-gate ** full -- (optional) to be set 'true' if WorkList is full 24537c478bd9Sstevel@tonic-gate ** more -- (optional) to be set 'true' if there are still more 24547c478bd9Sstevel@tonic-gate ** messages in this queue not added to WorkList 24557c478bd9Sstevel@tonic-gate ** 24567c478bd9Sstevel@tonic-gate ** Returns: 24577c478bd9Sstevel@tonic-gate ** The number of request in the queue (not necessarily 24587c478bd9Sstevel@tonic-gate ** the number of requests in WorkList however). 24597c478bd9Sstevel@tonic-gate ** 24607c478bd9Sstevel@tonic-gate ** Side Effects: 24617c478bd9Sstevel@tonic-gate ** prepares available work into WorkList 24627c478bd9Sstevel@tonic-gate */ 24637c478bd9Sstevel@tonic-gate 24647c478bd9Sstevel@tonic-gate #define NEED_P 0001 /* 'P': priority */ 24657c478bd9Sstevel@tonic-gate #define NEED_T 0002 /* 'T': time */ 24667c478bd9Sstevel@tonic-gate #define NEED_R 0004 /* 'R': recipient */ 24677c478bd9Sstevel@tonic-gate #define NEED_S 0010 /* 'S': sender */ 24687c478bd9Sstevel@tonic-gate #define NEED_H 0020 /* host */ 24697c478bd9Sstevel@tonic-gate #define HAS_QUARANTINE 0040 /* has an unexpected 'q' line */ 24707c478bd9Sstevel@tonic-gate #define NEED_QUARANTINE 0100 /* 'q': reason */ 24717c478bd9Sstevel@tonic-gate 24727c478bd9Sstevel@tonic-gate static WORK *WorkList = NULL; /* list of unsort work */ 24737c478bd9Sstevel@tonic-gate static int WorkListSize = 0; /* current max size of WorkList */ 24747c478bd9Sstevel@tonic-gate static int WorkListCount = 0; /* # of work items in WorkList */ 24757c478bd9Sstevel@tonic-gate 24767c478bd9Sstevel@tonic-gate static int 24777c478bd9Sstevel@tonic-gate gatherq(qgrp, qdir, doall, full, more) 24787c478bd9Sstevel@tonic-gate int qgrp; 24797c478bd9Sstevel@tonic-gate int qdir; 24807c478bd9Sstevel@tonic-gate bool doall; 24817c478bd9Sstevel@tonic-gate bool *full; 24827c478bd9Sstevel@tonic-gate bool *more; 24837c478bd9Sstevel@tonic-gate { 24847c478bd9Sstevel@tonic-gate register struct dirent *d; 24857c478bd9Sstevel@tonic-gate register WORK *w; 24867c478bd9Sstevel@tonic-gate register char *p; 24877c478bd9Sstevel@tonic-gate DIR *f; 24887c478bd9Sstevel@tonic-gate int i, num_ent; 24897c478bd9Sstevel@tonic-gate int wn; 24907c478bd9Sstevel@tonic-gate QUEUE_CHAR *check; 24917c478bd9Sstevel@tonic-gate char qd[MAXPATHLEN]; 24927c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN]; 24937c478bd9Sstevel@tonic-gate 24947c478bd9Sstevel@tonic-gate wn = WorkListCount - 1; 24957c478bd9Sstevel@tonic-gate num_ent = 0; 24967c478bd9Sstevel@tonic-gate if (qdir == NOQDIR) 2497058561cbSjbeck (void) sm_strlcpy(qd, ".", sizeof(qd)); 24987c478bd9Sstevel@tonic-gate else 2499058561cbSjbeck (void) sm_strlcpyn(qd, sizeof(qd), 2, 25007c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name, 25017c478bd9Sstevel@tonic-gate (bitset(QP_SUBQF, 25027c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs) 25037c478bd9Sstevel@tonic-gate ? "/qf" : "")); 25047c478bd9Sstevel@tonic-gate 25057c478bd9Sstevel@tonic-gate if (tTd(41, 1)) 25067c478bd9Sstevel@tonic-gate { 25077c478bd9Sstevel@tonic-gate sm_dprintf("gatherq:\n"); 25087c478bd9Sstevel@tonic-gate 25097c478bd9Sstevel@tonic-gate check = QueueLimitId; 25107c478bd9Sstevel@tonic-gate while (check != NULL) 25117c478bd9Sstevel@tonic-gate { 25127c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitId = %s%s\n", 25137c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "", 25147c478bd9Sstevel@tonic-gate check->queue_match); 25157c478bd9Sstevel@tonic-gate check = check->queue_next; 25167c478bd9Sstevel@tonic-gate } 25177c478bd9Sstevel@tonic-gate 25187c478bd9Sstevel@tonic-gate check = QueueLimitSender; 25197c478bd9Sstevel@tonic-gate while (check != NULL) 25207c478bd9Sstevel@tonic-gate { 25217c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitSender = %s%s\n", 25227c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "", 25237c478bd9Sstevel@tonic-gate check->queue_match); 25247c478bd9Sstevel@tonic-gate check = check->queue_next; 25257c478bd9Sstevel@tonic-gate } 25267c478bd9Sstevel@tonic-gate 25277c478bd9Sstevel@tonic-gate check = QueueLimitRecipient; 25287c478bd9Sstevel@tonic-gate while (check != NULL) 25297c478bd9Sstevel@tonic-gate { 25307c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitRecipient = %s%s\n", 25317c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "", 25327c478bd9Sstevel@tonic-gate check->queue_match); 25337c478bd9Sstevel@tonic-gate check = check->queue_next; 25347c478bd9Sstevel@tonic-gate } 25357c478bd9Sstevel@tonic-gate 25367c478bd9Sstevel@tonic-gate if (QueueMode == QM_QUARANTINE) 25377c478bd9Sstevel@tonic-gate { 25387c478bd9Sstevel@tonic-gate check = QueueLimitQuarantine; 25397c478bd9Sstevel@tonic-gate while (check != NULL) 25407c478bd9Sstevel@tonic-gate { 25417c478bd9Sstevel@tonic-gate sm_dprintf("\tQueueLimitQuarantine = %s%s\n", 25427c478bd9Sstevel@tonic-gate check->queue_negate ? "!" : "", 25437c478bd9Sstevel@tonic-gate check->queue_match); 25447c478bd9Sstevel@tonic-gate check = check->queue_next; 25457c478bd9Sstevel@tonic-gate } 25467c478bd9Sstevel@tonic-gate } 25477c478bd9Sstevel@tonic-gate } 25487c478bd9Sstevel@tonic-gate 25497c478bd9Sstevel@tonic-gate /* open the queue directory */ 25507c478bd9Sstevel@tonic-gate f = opendir(qd); 25517c478bd9Sstevel@tonic-gate if (f == NULL) 25527c478bd9Sstevel@tonic-gate { 25537c478bd9Sstevel@tonic-gate syserr("gatherq: cannot open \"%s\"", 25547c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 25557c478bd9Sstevel@tonic-gate if (full != NULL) 25567c478bd9Sstevel@tonic-gate *full = WorkListCount >= MaxQueueRun && MaxQueueRun > 0; 25577c478bd9Sstevel@tonic-gate if (more != NULL) 25587c478bd9Sstevel@tonic-gate *more = false; 25597c478bd9Sstevel@tonic-gate return 0; 25607c478bd9Sstevel@tonic-gate } 25617c478bd9Sstevel@tonic-gate 25627c478bd9Sstevel@tonic-gate /* 25637c478bd9Sstevel@tonic-gate ** Read the work directory. 25647c478bd9Sstevel@tonic-gate */ 25657c478bd9Sstevel@tonic-gate 25667c478bd9Sstevel@tonic-gate while ((d = readdir(f)) != NULL) 25677c478bd9Sstevel@tonic-gate { 25687c478bd9Sstevel@tonic-gate SM_FILE_T *cf; 25697c478bd9Sstevel@tonic-gate int qfver = 0; 25707c478bd9Sstevel@tonic-gate char lbuf[MAXNAME + 1]; 25717c478bd9Sstevel@tonic-gate struct stat sbuf; 25727c478bd9Sstevel@tonic-gate 25737c478bd9Sstevel@tonic-gate if (tTd(41, 50)) 25747c478bd9Sstevel@tonic-gate sm_dprintf("gatherq: checking %s..", d->d_name); 25757c478bd9Sstevel@tonic-gate 25767c478bd9Sstevel@tonic-gate /* is this an interesting entry? */ 25777c478bd9Sstevel@tonic-gate if (!(((QueueMode == QM_NORMAL && 25787c478bd9Sstevel@tonic-gate d->d_name[0] == NORMQF_LETTER) || 25797c478bd9Sstevel@tonic-gate (QueueMode == QM_QUARANTINE && 25807c478bd9Sstevel@tonic-gate d->d_name[0] == QUARQF_LETTER) || 25817c478bd9Sstevel@tonic-gate (QueueMode == QM_LOST && 25827c478bd9Sstevel@tonic-gate d->d_name[0] == LOSEQF_LETTER)) && 25837c478bd9Sstevel@tonic-gate d->d_name[1] == 'f')) 25847c478bd9Sstevel@tonic-gate { 25857c478bd9Sstevel@tonic-gate if (tTd(41, 50)) 25867c478bd9Sstevel@tonic-gate sm_dprintf(" skipping\n"); 25877c478bd9Sstevel@tonic-gate continue; 25887c478bd9Sstevel@tonic-gate } 25897c478bd9Sstevel@tonic-gate if (tTd(41, 50)) 25907c478bd9Sstevel@tonic-gate sm_dprintf("\n"); 25917c478bd9Sstevel@tonic-gate 25927c478bd9Sstevel@tonic-gate if (strlen(d->d_name) >= MAXQFNAME) 25937c478bd9Sstevel@tonic-gate { 25947c478bd9Sstevel@tonic-gate if (Verbose) 25957c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 25967c478bd9Sstevel@tonic-gate "gatherq: %s too long, %d max characters\n", 25977c478bd9Sstevel@tonic-gate d->d_name, MAXQFNAME); 25987c478bd9Sstevel@tonic-gate if (LogLevel > 0) 25997c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, NOQID, 26007c478bd9Sstevel@tonic-gate "gatherq: %s too long, %d max characters", 26017c478bd9Sstevel@tonic-gate d->d_name, MAXQFNAME); 26027c478bd9Sstevel@tonic-gate continue; 26037c478bd9Sstevel@tonic-gate } 26047c478bd9Sstevel@tonic-gate 26057c478bd9Sstevel@tonic-gate check = QueueLimitId; 26067c478bd9Sstevel@tonic-gate while (check != NULL) 26077c478bd9Sstevel@tonic-gate { 26087c478bd9Sstevel@tonic-gate if (strcontainedin(false, check->queue_match, 26097c478bd9Sstevel@tonic-gate d->d_name) != check->queue_negate) 26107c478bd9Sstevel@tonic-gate break; 26117c478bd9Sstevel@tonic-gate else 26127c478bd9Sstevel@tonic-gate check = check->queue_next; 26137c478bd9Sstevel@tonic-gate } 26147c478bd9Sstevel@tonic-gate if (QueueLimitId != NULL && check == NULL) 26157c478bd9Sstevel@tonic-gate continue; 26167c478bd9Sstevel@tonic-gate 26177c478bd9Sstevel@tonic-gate /* grow work list if necessary */ 26187c478bd9Sstevel@tonic-gate if (++wn >= MaxQueueRun && MaxQueueRun > 0) 26197c478bd9Sstevel@tonic-gate { 26207c478bd9Sstevel@tonic-gate if (wn == MaxQueueRun && LogLevel > 0) 26217c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 26227c478bd9Sstevel@tonic-gate "WorkList for %s maxed out at %d", 26237c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), 26247c478bd9Sstevel@tonic-gate MaxQueueRun); 26257c478bd9Sstevel@tonic-gate if (doall) 26267c478bd9Sstevel@tonic-gate continue; /* just count entries */ 26277c478bd9Sstevel@tonic-gate break; 26287c478bd9Sstevel@tonic-gate } 26297c478bd9Sstevel@tonic-gate if (wn >= WorkListSize) 26307c478bd9Sstevel@tonic-gate { 26317c478bd9Sstevel@tonic-gate grow_wlist(qgrp, qdir); 26327c478bd9Sstevel@tonic-gate if (wn >= WorkListSize) 26337c478bd9Sstevel@tonic-gate continue; 26347c478bd9Sstevel@tonic-gate } 26357c478bd9Sstevel@tonic-gate SM_ASSERT(wn >= 0); 26367c478bd9Sstevel@tonic-gate w = &WorkList[wn]; 26377c478bd9Sstevel@tonic-gate 2638058561cbSjbeck (void) sm_strlcpyn(qf, sizeof(qf), 3, qd, "/", d->d_name); 26397c478bd9Sstevel@tonic-gate if (stat(qf, &sbuf) < 0) 26407c478bd9Sstevel@tonic-gate { 26417c478bd9Sstevel@tonic-gate if (errno != ENOENT) 26427c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 26437c478bd9Sstevel@tonic-gate "gatherq: can't stat %s/%s", 26447c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), 26457c478bd9Sstevel@tonic-gate d->d_name); 26467c478bd9Sstevel@tonic-gate wn--; 26477c478bd9Sstevel@tonic-gate continue; 26487c478bd9Sstevel@tonic-gate } 26497c478bd9Sstevel@tonic-gate if (!bitset(S_IFREG, sbuf.st_mode)) 26507c478bd9Sstevel@tonic-gate { 26517c478bd9Sstevel@tonic-gate /* Yikes! Skip it or we will hang on open! */ 26527c478bd9Sstevel@tonic-gate if (!((d->d_name[0] == DATAFL_LETTER || 26537c478bd9Sstevel@tonic-gate d->d_name[0] == NORMQF_LETTER || 26547c478bd9Sstevel@tonic-gate d->d_name[0] == QUARQF_LETTER || 26557c478bd9Sstevel@tonic-gate d->d_name[0] == LOSEQF_LETTER || 26567c478bd9Sstevel@tonic-gate d->d_name[0] == XSCRPT_LETTER) && 26577c478bd9Sstevel@tonic-gate d->d_name[1] == 'f' && d->d_name[2] == '\0')) 26587c478bd9Sstevel@tonic-gate syserr("gatherq: %s/%s is not a regular file", 26597c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), d->d_name); 26607c478bd9Sstevel@tonic-gate wn--; 26617c478bd9Sstevel@tonic-gate continue; 26627c478bd9Sstevel@tonic-gate } 26637c478bd9Sstevel@tonic-gate 26647c478bd9Sstevel@tonic-gate /* avoid work if possible */ 26657c478bd9Sstevel@tonic-gate if ((QueueSortOrder == QSO_BYFILENAME || 26667c478bd9Sstevel@tonic-gate QueueSortOrder == QSO_BYMODTIME || 26671daa5768Sjbeck QueueSortOrder == QSO_NONE || 26687c478bd9Sstevel@tonic-gate QueueSortOrder == QSO_RANDOM) && 26697c478bd9Sstevel@tonic-gate QueueLimitQuarantine == NULL && 26707c478bd9Sstevel@tonic-gate QueueLimitSender == NULL && 26717c478bd9Sstevel@tonic-gate QueueLimitRecipient == NULL) 26727c478bd9Sstevel@tonic-gate { 26737c478bd9Sstevel@tonic-gate w->w_qgrp = qgrp; 26747c478bd9Sstevel@tonic-gate w->w_qdir = qdir; 26757c478bd9Sstevel@tonic-gate w->w_name = newstr(d->d_name); 26767c478bd9Sstevel@tonic-gate w->w_host = NULL; 26777c478bd9Sstevel@tonic-gate w->w_lock = w->w_tooyoung = false; 26787c478bd9Sstevel@tonic-gate w->w_pri = 0; 26797c478bd9Sstevel@tonic-gate w->w_ctime = 0; 26807c478bd9Sstevel@tonic-gate w->w_mtime = sbuf.st_mtime; 26817c478bd9Sstevel@tonic-gate ++num_ent; 26827c478bd9Sstevel@tonic-gate continue; 26837c478bd9Sstevel@tonic-gate } 26847c478bd9Sstevel@tonic-gate 26857c478bd9Sstevel@tonic-gate /* open control file */ 26867c478bd9Sstevel@tonic-gate cf = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY_B, 26877c478bd9Sstevel@tonic-gate NULL); 26887c478bd9Sstevel@tonic-gate if (cf == NULL && OpMode != MD_PRINT) 26897c478bd9Sstevel@tonic-gate { 26907c478bd9Sstevel@tonic-gate /* this may be some random person sending hir msgs */ 26917c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 26927c478bd9Sstevel@tonic-gate sm_dprintf("gatherq: cannot open %s: %s\n", 26937c478bd9Sstevel@tonic-gate d->d_name, sm_errstring(errno)); 26947c478bd9Sstevel@tonic-gate errno = 0; 26957c478bd9Sstevel@tonic-gate wn--; 26967c478bd9Sstevel@tonic-gate continue; 26977c478bd9Sstevel@tonic-gate } 26987c478bd9Sstevel@tonic-gate w->w_qgrp = qgrp; 26997c478bd9Sstevel@tonic-gate w->w_qdir = qdir; 27007c478bd9Sstevel@tonic-gate w->w_name = newstr(d->d_name); 27017c478bd9Sstevel@tonic-gate w->w_host = NULL; 27027c478bd9Sstevel@tonic-gate if (cf != NULL) 27037c478bd9Sstevel@tonic-gate { 27047c478bd9Sstevel@tonic-gate w->w_lock = !lockfile(sm_io_getinfo(cf, SM_IO_WHAT_FD, 27057c478bd9Sstevel@tonic-gate NULL), 27067c478bd9Sstevel@tonic-gate w->w_name, NULL, 27077c478bd9Sstevel@tonic-gate LOCK_SH|LOCK_NB); 27087c478bd9Sstevel@tonic-gate } 27097c478bd9Sstevel@tonic-gate w->w_tooyoung = false; 27107c478bd9Sstevel@tonic-gate 27117c478bd9Sstevel@tonic-gate /* make sure jobs in creation don't clog queue */ 27127c478bd9Sstevel@tonic-gate w->w_pri = 0x7fffffff; 27137c478bd9Sstevel@tonic-gate w->w_ctime = 0; 27147c478bd9Sstevel@tonic-gate w->w_mtime = sbuf.st_mtime; 27157c478bd9Sstevel@tonic-gate 27167c478bd9Sstevel@tonic-gate /* extract useful information */ 27177c478bd9Sstevel@tonic-gate i = NEED_P|NEED_T; 27187c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST 27197c478bd9Sstevel@tonic-gate #if _FFR_RHS 27207c478bd9Sstevel@tonic-gate || QueueSortOrder == QSO_BYSHUFFLE 27217c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 27227c478bd9Sstevel@tonic-gate ) 27237c478bd9Sstevel@tonic-gate { 27247c478bd9Sstevel@tonic-gate /* need w_host set for host sort order */ 27257c478bd9Sstevel@tonic-gate i |= NEED_H; 27267c478bd9Sstevel@tonic-gate } 27277c478bd9Sstevel@tonic-gate if (QueueLimitSender != NULL) 27287c478bd9Sstevel@tonic-gate i |= NEED_S; 27297c478bd9Sstevel@tonic-gate if (QueueLimitRecipient != NULL) 27307c478bd9Sstevel@tonic-gate i |= NEED_R; 27317c478bd9Sstevel@tonic-gate if (QueueLimitQuarantine != NULL) 27327c478bd9Sstevel@tonic-gate i |= NEED_QUARANTINE; 27337c478bd9Sstevel@tonic-gate while (cf != NULL && i != 0 && 27347c478bd9Sstevel@tonic-gate sm_io_fgets(cf, SM_TIME_DEFAULT, lbuf, 2735058561cbSjbeck sizeof(lbuf)) != NULL) 27367c478bd9Sstevel@tonic-gate { 27377c478bd9Sstevel@tonic-gate int c; 27387c478bd9Sstevel@tonic-gate time_t age; 27397c478bd9Sstevel@tonic-gate 27407c478bd9Sstevel@tonic-gate p = strchr(lbuf, '\n'); 27417c478bd9Sstevel@tonic-gate if (p != NULL) 27427c478bd9Sstevel@tonic-gate *p = '\0'; 27437c478bd9Sstevel@tonic-gate else 27447c478bd9Sstevel@tonic-gate { 27457c478bd9Sstevel@tonic-gate /* flush rest of overly long line */ 27467c478bd9Sstevel@tonic-gate while ((c = sm_io_getc(cf, SM_TIME_DEFAULT)) 27477c478bd9Sstevel@tonic-gate != SM_IO_EOF && c != '\n') 27487c478bd9Sstevel@tonic-gate continue; 27497c478bd9Sstevel@tonic-gate } 27507c478bd9Sstevel@tonic-gate 27517c478bd9Sstevel@tonic-gate switch (lbuf[0]) 27527c478bd9Sstevel@tonic-gate { 27537c478bd9Sstevel@tonic-gate case 'V': 27547c478bd9Sstevel@tonic-gate qfver = atoi(&lbuf[1]); 27557c478bd9Sstevel@tonic-gate break; 27567c478bd9Sstevel@tonic-gate 27577c478bd9Sstevel@tonic-gate case 'P': 27587c478bd9Sstevel@tonic-gate w->w_pri = atol(&lbuf[1]); 27597c478bd9Sstevel@tonic-gate i &= ~NEED_P; 27607c478bd9Sstevel@tonic-gate break; 27617c478bd9Sstevel@tonic-gate 27627c478bd9Sstevel@tonic-gate case 'T': 27637c478bd9Sstevel@tonic-gate w->w_ctime = atol(&lbuf[1]); 27647c478bd9Sstevel@tonic-gate i &= ~NEED_T; 27657c478bd9Sstevel@tonic-gate break; 27667c478bd9Sstevel@tonic-gate 27677c478bd9Sstevel@tonic-gate case 'q': 27687c478bd9Sstevel@tonic-gate if (QueueMode != QM_QUARANTINE && 27697c478bd9Sstevel@tonic-gate QueueMode != QM_LOST) 27707c478bd9Sstevel@tonic-gate { 27717c478bd9Sstevel@tonic-gate if (tTd(41, 49)) 27727c478bd9Sstevel@tonic-gate sm_dprintf("%s not marked as quarantined but has a 'q' line\n", 27737c478bd9Sstevel@tonic-gate w->w_name); 27747c478bd9Sstevel@tonic-gate i |= HAS_QUARANTINE; 27757c478bd9Sstevel@tonic-gate } 27767c478bd9Sstevel@tonic-gate else if (QueueMode == QM_QUARANTINE) 27777c478bd9Sstevel@tonic-gate { 27787c478bd9Sstevel@tonic-gate if (QueueLimitQuarantine == NULL) 27797c478bd9Sstevel@tonic-gate { 27807c478bd9Sstevel@tonic-gate i &= ~NEED_QUARANTINE; 27817c478bd9Sstevel@tonic-gate break; 27827c478bd9Sstevel@tonic-gate } 27837c478bd9Sstevel@tonic-gate p = &lbuf[1]; 27847c478bd9Sstevel@tonic-gate check = QueueLimitQuarantine; 27857c478bd9Sstevel@tonic-gate while (check != NULL) 27867c478bd9Sstevel@tonic-gate { 27877c478bd9Sstevel@tonic-gate if (strcontainedin(false, 27887c478bd9Sstevel@tonic-gate check->queue_match, 27897c478bd9Sstevel@tonic-gate p) != 27907c478bd9Sstevel@tonic-gate check->queue_negate) 27917c478bd9Sstevel@tonic-gate break; 27927c478bd9Sstevel@tonic-gate else 27937c478bd9Sstevel@tonic-gate check = check->queue_next; 27947c478bd9Sstevel@tonic-gate } 27957c478bd9Sstevel@tonic-gate if (check != NULL) 27967c478bd9Sstevel@tonic-gate i &= ~NEED_QUARANTINE; 27977c478bd9Sstevel@tonic-gate } 27987c478bd9Sstevel@tonic-gate break; 27997c478bd9Sstevel@tonic-gate 28007c478bd9Sstevel@tonic-gate case 'R': 28017c478bd9Sstevel@tonic-gate if (w->w_host == NULL && 28027c478bd9Sstevel@tonic-gate (p = strrchr(&lbuf[1], '@')) != NULL) 28037c478bd9Sstevel@tonic-gate { 28047c478bd9Sstevel@tonic-gate #if _FFR_RHS 28057c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYSHUFFLE) 28067c478bd9Sstevel@tonic-gate w->w_host = newstr(&p[1]); 28077c478bd9Sstevel@tonic-gate else 28087c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 28097c478bd9Sstevel@tonic-gate w->w_host = strrev(&p[1]); 28107c478bd9Sstevel@tonic-gate makelower(w->w_host); 28117c478bd9Sstevel@tonic-gate i &= ~NEED_H; 28127c478bd9Sstevel@tonic-gate } 28137c478bd9Sstevel@tonic-gate if (QueueLimitRecipient == NULL) 28147c478bd9Sstevel@tonic-gate { 28157c478bd9Sstevel@tonic-gate i &= ~NEED_R; 28167c478bd9Sstevel@tonic-gate break; 28177c478bd9Sstevel@tonic-gate } 28187c478bd9Sstevel@tonic-gate if (qfver > 0) 28197c478bd9Sstevel@tonic-gate { 28207c478bd9Sstevel@tonic-gate p = strchr(&lbuf[1], ':'); 28217c478bd9Sstevel@tonic-gate if (p == NULL) 28227c478bd9Sstevel@tonic-gate p = &lbuf[1]; 28237c478bd9Sstevel@tonic-gate else 28247c478bd9Sstevel@tonic-gate ++p; /* skip over ':' */ 28257c478bd9Sstevel@tonic-gate } 28267c478bd9Sstevel@tonic-gate else 28277c478bd9Sstevel@tonic-gate p = &lbuf[1]; 28287c478bd9Sstevel@tonic-gate check = QueueLimitRecipient; 28297c478bd9Sstevel@tonic-gate while (check != NULL) 28307c478bd9Sstevel@tonic-gate { 28317c478bd9Sstevel@tonic-gate if (strcontainedin(true, 28327c478bd9Sstevel@tonic-gate check->queue_match, 28337c478bd9Sstevel@tonic-gate p) != 28347c478bd9Sstevel@tonic-gate check->queue_negate) 28357c478bd9Sstevel@tonic-gate break; 28367c478bd9Sstevel@tonic-gate else 28377c478bd9Sstevel@tonic-gate check = check->queue_next; 28387c478bd9Sstevel@tonic-gate } 28397c478bd9Sstevel@tonic-gate if (check != NULL) 28407c478bd9Sstevel@tonic-gate i &= ~NEED_R; 28417c478bd9Sstevel@tonic-gate break; 28427c478bd9Sstevel@tonic-gate 28437c478bd9Sstevel@tonic-gate case 'S': 28447c478bd9Sstevel@tonic-gate check = QueueLimitSender; 28457c478bd9Sstevel@tonic-gate while (check != NULL) 28467c478bd9Sstevel@tonic-gate { 28477c478bd9Sstevel@tonic-gate if (strcontainedin(true, 28487c478bd9Sstevel@tonic-gate check->queue_match, 28497c478bd9Sstevel@tonic-gate &lbuf[1]) != 28507c478bd9Sstevel@tonic-gate check->queue_negate) 28517c478bd9Sstevel@tonic-gate break; 28527c478bd9Sstevel@tonic-gate else 28537c478bd9Sstevel@tonic-gate check = check->queue_next; 28547c478bd9Sstevel@tonic-gate } 28557c478bd9Sstevel@tonic-gate if (check != NULL) 28567c478bd9Sstevel@tonic-gate i &= ~NEED_S; 28577c478bd9Sstevel@tonic-gate break; 28587c478bd9Sstevel@tonic-gate 28597c478bd9Sstevel@tonic-gate case 'K': 28607c478bd9Sstevel@tonic-gate age = curtime() - (time_t) atol(&lbuf[1]); 28617c478bd9Sstevel@tonic-gate if (age >= 0 && MinQueueAge > 0 && 28627c478bd9Sstevel@tonic-gate age < MinQueueAge) 28637c478bd9Sstevel@tonic-gate w->w_tooyoung = true; 28647c478bd9Sstevel@tonic-gate break; 28657c478bd9Sstevel@tonic-gate 28667c478bd9Sstevel@tonic-gate case 'N': 28677c478bd9Sstevel@tonic-gate if (atol(&lbuf[1]) == 0) 28687c478bd9Sstevel@tonic-gate w->w_tooyoung = false; 28697c478bd9Sstevel@tonic-gate break; 28707c478bd9Sstevel@tonic-gate } 28717c478bd9Sstevel@tonic-gate } 28727c478bd9Sstevel@tonic-gate if (cf != NULL) 28737c478bd9Sstevel@tonic-gate (void) sm_io_close(cf, SM_TIME_DEFAULT); 28747c478bd9Sstevel@tonic-gate 2875445f2479Sjbeck if ((!doall && (shouldqueue(w->w_pri, w->w_ctime) || 2876445f2479Sjbeck w->w_tooyoung)) || 28777c478bd9Sstevel@tonic-gate bitset(HAS_QUARANTINE, i) || 28787c478bd9Sstevel@tonic-gate bitset(NEED_QUARANTINE, i) || 28797c478bd9Sstevel@tonic-gate bitset(NEED_R|NEED_S, i)) 28807c478bd9Sstevel@tonic-gate { 28817c478bd9Sstevel@tonic-gate /* don't even bother sorting this job in */ 28827c478bd9Sstevel@tonic-gate if (tTd(41, 49)) 28837c478bd9Sstevel@tonic-gate sm_dprintf("skipping %s (%x)\n", w->w_name, i); 28847c478bd9Sstevel@tonic-gate sm_free(w->w_name); /* XXX */ 28857c478bd9Sstevel@tonic-gate if (w->w_host != NULL) 28867c478bd9Sstevel@tonic-gate sm_free(w->w_host); /* XXX */ 28877c478bd9Sstevel@tonic-gate wn--; 28887c478bd9Sstevel@tonic-gate } 28897c478bd9Sstevel@tonic-gate else 28907c478bd9Sstevel@tonic-gate ++num_ent; 28917c478bd9Sstevel@tonic-gate } 28927c478bd9Sstevel@tonic-gate (void) closedir(f); 28937c478bd9Sstevel@tonic-gate wn++; 28947c478bd9Sstevel@tonic-gate 28957c478bd9Sstevel@tonic-gate i = wn - WorkListCount; 28967c478bd9Sstevel@tonic-gate WorkListCount += SM_MIN(num_ent, WorkListSize); 28977c478bd9Sstevel@tonic-gate 28987c478bd9Sstevel@tonic-gate if (more != NULL) 28997c478bd9Sstevel@tonic-gate *more = WorkListCount < wn; 29007c478bd9Sstevel@tonic-gate 29017c478bd9Sstevel@tonic-gate if (full != NULL) 29027c478bd9Sstevel@tonic-gate *full = (wn >= MaxQueueRun && MaxQueueRun > 0) || 29037c478bd9Sstevel@tonic-gate (WorkList == NULL && wn > 0); 29047c478bd9Sstevel@tonic-gate 29057c478bd9Sstevel@tonic-gate return i; 29067c478bd9Sstevel@tonic-gate } 29077c478bd9Sstevel@tonic-gate /* 29087c478bd9Sstevel@tonic-gate ** SORTQ -- sort the work list 29097c478bd9Sstevel@tonic-gate ** 29107c478bd9Sstevel@tonic-gate ** First the old WorkQ is cleared away. Then the WorkList is sorted 29117c478bd9Sstevel@tonic-gate ** for all items so that important (higher sorting value) items are not 29127c478bd9Sstevel@tonic-gate ** trunctated off. Then the most important items are moved from 29137c478bd9Sstevel@tonic-gate ** WorkList to WorkQ. The lower count of 'max' or MaxListCount items 29147c478bd9Sstevel@tonic-gate ** are moved. 29157c478bd9Sstevel@tonic-gate ** 29167c478bd9Sstevel@tonic-gate ** Parameters: 29177c478bd9Sstevel@tonic-gate ** max -- maximum number of items to be placed in WorkQ 29187c478bd9Sstevel@tonic-gate ** 29197c478bd9Sstevel@tonic-gate ** Returns: 29207c478bd9Sstevel@tonic-gate ** the number of items in WorkQ 29217c478bd9Sstevel@tonic-gate ** 29227c478bd9Sstevel@tonic-gate ** Side Effects: 29237c478bd9Sstevel@tonic-gate ** WorkQ gets released and filled with new work. WorkList 29247c478bd9Sstevel@tonic-gate ** gets released. Work items get sorted in order. 29257c478bd9Sstevel@tonic-gate */ 29267c478bd9Sstevel@tonic-gate 29277c478bd9Sstevel@tonic-gate static int 29287c478bd9Sstevel@tonic-gate sortq(max) 29297c478bd9Sstevel@tonic-gate int max; 29307c478bd9Sstevel@tonic-gate { 29317c478bd9Sstevel@tonic-gate register int i; /* local counter */ 29327c478bd9Sstevel@tonic-gate register WORK *w; /* tmp item pointer */ 29337c478bd9Sstevel@tonic-gate int wc = WorkListCount; /* trim size for WorkQ */ 29347c478bd9Sstevel@tonic-gate 29357c478bd9Sstevel@tonic-gate if (WorkQ != NULL) 29367c478bd9Sstevel@tonic-gate { 29377c478bd9Sstevel@tonic-gate WORK *nw; 29387c478bd9Sstevel@tonic-gate 29397c478bd9Sstevel@tonic-gate /* Clear out old WorkQ. */ 29407c478bd9Sstevel@tonic-gate for (w = WorkQ; w != NULL; w = nw) 29417c478bd9Sstevel@tonic-gate { 29427c478bd9Sstevel@tonic-gate nw = w->w_next; 29437c478bd9Sstevel@tonic-gate sm_free(w->w_name); /* XXX */ 29447c478bd9Sstevel@tonic-gate if (w->w_host != NULL) 29457c478bd9Sstevel@tonic-gate sm_free(w->w_host); /* XXX */ 29467c478bd9Sstevel@tonic-gate sm_free((char *) w); /* XXX */ 29477c478bd9Sstevel@tonic-gate } 29487c478bd9Sstevel@tonic-gate WorkQ = NULL; 29497c478bd9Sstevel@tonic-gate } 29507c478bd9Sstevel@tonic-gate 29517c478bd9Sstevel@tonic-gate if (WorkList == NULL || wc <= 0) 29527c478bd9Sstevel@tonic-gate return 0; 29537c478bd9Sstevel@tonic-gate 29547c478bd9Sstevel@tonic-gate /* 29557c478bd9Sstevel@tonic-gate ** The sort now takes place using all of the items in WorkList. 29567c478bd9Sstevel@tonic-gate ** The list gets trimmed to the most important items after the sort. 29577c478bd9Sstevel@tonic-gate ** If the trim were to happen before the sort then one or more 29587c478bd9Sstevel@tonic-gate ** important items might get truncated off -- not what we want. 29597c478bd9Sstevel@tonic-gate */ 29607c478bd9Sstevel@tonic-gate 29617c478bd9Sstevel@tonic-gate if (QueueSortOrder == QSO_BYHOST) 29627c478bd9Sstevel@tonic-gate { 29637c478bd9Sstevel@tonic-gate /* 29647c478bd9Sstevel@tonic-gate ** Sort the work directory for the first time, 29657c478bd9Sstevel@tonic-gate ** based on host name, lock status, and priority. 29667c478bd9Sstevel@tonic-gate */ 29677c478bd9Sstevel@tonic-gate 2968058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf1); 29697c478bd9Sstevel@tonic-gate 29707c478bd9Sstevel@tonic-gate /* 29717c478bd9Sstevel@tonic-gate ** If one message to host is locked, "lock" all messages 29727c478bd9Sstevel@tonic-gate ** to that host. 29737c478bd9Sstevel@tonic-gate */ 29747c478bd9Sstevel@tonic-gate 29757c478bd9Sstevel@tonic-gate i = 0; 29767c478bd9Sstevel@tonic-gate while (i < wc) 29777c478bd9Sstevel@tonic-gate { 29787c478bd9Sstevel@tonic-gate if (!WorkList[i].w_lock) 29797c478bd9Sstevel@tonic-gate { 29807c478bd9Sstevel@tonic-gate i++; 29817c478bd9Sstevel@tonic-gate continue; 29827c478bd9Sstevel@tonic-gate } 29837c478bd9Sstevel@tonic-gate w = &WorkList[i]; 29847c478bd9Sstevel@tonic-gate while (++i < wc) 29857c478bd9Sstevel@tonic-gate { 29867c478bd9Sstevel@tonic-gate if (WorkList[i].w_host == NULL && 29877c478bd9Sstevel@tonic-gate w->w_host == NULL) 29887c478bd9Sstevel@tonic-gate WorkList[i].w_lock = true; 29897c478bd9Sstevel@tonic-gate else if (WorkList[i].w_host != NULL && 29907c478bd9Sstevel@tonic-gate w->w_host != NULL && 29917c478bd9Sstevel@tonic-gate sm_strcasecmp(WorkList[i].w_host, 29927c478bd9Sstevel@tonic-gate w->w_host) == 0) 29937c478bd9Sstevel@tonic-gate WorkList[i].w_lock = true; 29947c478bd9Sstevel@tonic-gate else 29957c478bd9Sstevel@tonic-gate break; 29967c478bd9Sstevel@tonic-gate } 29977c478bd9Sstevel@tonic-gate } 29987c478bd9Sstevel@tonic-gate 29997c478bd9Sstevel@tonic-gate /* 30007c478bd9Sstevel@tonic-gate ** Sort the work directory for the second time, 30017c478bd9Sstevel@tonic-gate ** based on lock status, host name, and priority. 30027c478bd9Sstevel@tonic-gate */ 30037c478bd9Sstevel@tonic-gate 3004058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf2); 30057c478bd9Sstevel@tonic-gate } 30067c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYTIME) 30077c478bd9Sstevel@tonic-gate { 30087c478bd9Sstevel@tonic-gate /* 30097c478bd9Sstevel@tonic-gate ** Simple sort based on submission time only. 30107c478bd9Sstevel@tonic-gate */ 30117c478bd9Sstevel@tonic-gate 3012058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf3); 30137c478bd9Sstevel@tonic-gate } 30147c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYFILENAME) 30157c478bd9Sstevel@tonic-gate { 30167c478bd9Sstevel@tonic-gate /* 30177c478bd9Sstevel@tonic-gate ** Sort based on queue filename. 30187c478bd9Sstevel@tonic-gate */ 30197c478bd9Sstevel@tonic-gate 3020058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf4); 30217c478bd9Sstevel@tonic-gate } 30227c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_RANDOM) 30237c478bd9Sstevel@tonic-gate { 30247c478bd9Sstevel@tonic-gate /* 30257c478bd9Sstevel@tonic-gate ** Sort randomly. To avoid problems with an instable sort, 30267c478bd9Sstevel@tonic-gate ** use a random index into the queue file name to start 30277c478bd9Sstevel@tonic-gate ** comparison. 30287c478bd9Sstevel@tonic-gate */ 30297c478bd9Sstevel@tonic-gate 30307c478bd9Sstevel@tonic-gate randi = get_rand_mod(MAXQFNAME); 30317c478bd9Sstevel@tonic-gate if (randi < 2) 30327c478bd9Sstevel@tonic-gate randi = 3; 3033058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf5); 30347c478bd9Sstevel@tonic-gate } 30357c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYMODTIME) 30367c478bd9Sstevel@tonic-gate { 30377c478bd9Sstevel@tonic-gate /* 30387c478bd9Sstevel@tonic-gate ** Simple sort based on modification time of queue file. 30397c478bd9Sstevel@tonic-gate ** This puts the oldest items first. 30407c478bd9Sstevel@tonic-gate */ 30417c478bd9Sstevel@tonic-gate 3042058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf6); 30437c478bd9Sstevel@tonic-gate } 30447c478bd9Sstevel@tonic-gate #if _FFR_RHS 30457c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYSHUFFLE) 30467c478bd9Sstevel@tonic-gate { 30477c478bd9Sstevel@tonic-gate /* 30487c478bd9Sstevel@tonic-gate ** Simple sort based on shuffled host name. 30497c478bd9Sstevel@tonic-gate */ 30507c478bd9Sstevel@tonic-gate 30517c478bd9Sstevel@tonic-gate init_shuffle_alphabet(); 3052058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf7); 30537c478bd9Sstevel@tonic-gate } 30547c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 30557c478bd9Sstevel@tonic-gate else if (QueueSortOrder == QSO_BYPRIORITY) 30567c478bd9Sstevel@tonic-gate { 30577c478bd9Sstevel@tonic-gate /* 30587c478bd9Sstevel@tonic-gate ** Simple sort based on queue priority only. 30597c478bd9Sstevel@tonic-gate */ 30607c478bd9Sstevel@tonic-gate 3061058561cbSjbeck qsort((char *) WorkList, wc, sizeof(*WorkList), workcmpf0); 30627c478bd9Sstevel@tonic-gate } 30637c478bd9Sstevel@tonic-gate /* else don't sort at all */ 30647c478bd9Sstevel@tonic-gate 306549218d4fSjbeck /* Check if the per queue group item limit will be exceeded */ 306649218d4fSjbeck if (wc > max && max > 0) 306749218d4fSjbeck wc = max; 306849218d4fSjbeck 30697c478bd9Sstevel@tonic-gate /* 30707c478bd9Sstevel@tonic-gate ** Convert the work list into canonical form. 30717c478bd9Sstevel@tonic-gate ** Should be turning it into a list of envelopes here perhaps. 30727c478bd9Sstevel@tonic-gate ** Only take the most important items up to the per queue group 30737c478bd9Sstevel@tonic-gate ** maximum. 30747c478bd9Sstevel@tonic-gate */ 30757c478bd9Sstevel@tonic-gate 30767c478bd9Sstevel@tonic-gate for (i = wc; --i >= 0; ) 30777c478bd9Sstevel@tonic-gate { 3078058561cbSjbeck w = (WORK *) xalloc(sizeof(*w)); 30797c478bd9Sstevel@tonic-gate w->w_qgrp = WorkList[i].w_qgrp; 30807c478bd9Sstevel@tonic-gate w->w_qdir = WorkList[i].w_qdir; 30817c478bd9Sstevel@tonic-gate w->w_name = WorkList[i].w_name; 30827c478bd9Sstevel@tonic-gate w->w_host = WorkList[i].w_host; 30837c478bd9Sstevel@tonic-gate w->w_lock = WorkList[i].w_lock; 30847c478bd9Sstevel@tonic-gate w->w_tooyoung = WorkList[i].w_tooyoung; 30857c478bd9Sstevel@tonic-gate w->w_pri = WorkList[i].w_pri; 30867c478bd9Sstevel@tonic-gate w->w_ctime = WorkList[i].w_ctime; 30877c478bd9Sstevel@tonic-gate w->w_mtime = WorkList[i].w_mtime; 30887c478bd9Sstevel@tonic-gate w->w_next = WorkQ; 30897c478bd9Sstevel@tonic-gate WorkQ = w; 30907c478bd9Sstevel@tonic-gate } 30917c478bd9Sstevel@tonic-gate 30927c478bd9Sstevel@tonic-gate /* free the rest of the list */ 30937c478bd9Sstevel@tonic-gate for (i = WorkListCount; --i >= wc; ) 30947c478bd9Sstevel@tonic-gate { 30957c478bd9Sstevel@tonic-gate sm_free(WorkList[i].w_name); 30967c478bd9Sstevel@tonic-gate if (WorkList[i].w_host != NULL) 30977c478bd9Sstevel@tonic-gate sm_free(WorkList[i].w_host); 30987c478bd9Sstevel@tonic-gate } 30997c478bd9Sstevel@tonic-gate 31007c478bd9Sstevel@tonic-gate if (WorkList != NULL) 31017c478bd9Sstevel@tonic-gate sm_free(WorkList); /* XXX */ 31027c478bd9Sstevel@tonic-gate WorkList = NULL; 31037c478bd9Sstevel@tonic-gate WorkListSize = 0; 31047c478bd9Sstevel@tonic-gate WorkListCount = 0; 31057c478bd9Sstevel@tonic-gate 31067c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 31077c478bd9Sstevel@tonic-gate { 31087c478bd9Sstevel@tonic-gate for (w = WorkQ; w != NULL; w = w->w_next) 31097c478bd9Sstevel@tonic-gate { 31107c478bd9Sstevel@tonic-gate if (w->w_host != NULL) 31117c478bd9Sstevel@tonic-gate sm_dprintf("%22s: pri=%ld %s\n", 31127c478bd9Sstevel@tonic-gate w->w_name, w->w_pri, w->w_host); 31137c478bd9Sstevel@tonic-gate else 31147c478bd9Sstevel@tonic-gate sm_dprintf("%32s: pri=%ld\n", 31157c478bd9Sstevel@tonic-gate w->w_name, w->w_pri); 31167c478bd9Sstevel@tonic-gate } 31177c478bd9Sstevel@tonic-gate } 31187c478bd9Sstevel@tonic-gate 31197c478bd9Sstevel@tonic-gate return wc; /* return number of WorkQ items */ 31207c478bd9Sstevel@tonic-gate } 31217c478bd9Sstevel@tonic-gate /* 31227c478bd9Sstevel@tonic-gate ** GROW_WLIST -- make the work list larger 31237c478bd9Sstevel@tonic-gate ** 31247c478bd9Sstevel@tonic-gate ** Parameters: 31257c478bd9Sstevel@tonic-gate ** qgrp -- the index for the queue group. 31267c478bd9Sstevel@tonic-gate ** qdir -- the index for the queue directory. 31277c478bd9Sstevel@tonic-gate ** 31287c478bd9Sstevel@tonic-gate ** Returns: 31297c478bd9Sstevel@tonic-gate ** none. 31307c478bd9Sstevel@tonic-gate ** 31317c478bd9Sstevel@tonic-gate ** Side Effects: 31327c478bd9Sstevel@tonic-gate ** Adds another QUEUESEGSIZE entries to WorkList if possible. 31337c478bd9Sstevel@tonic-gate ** It can fail if there isn't enough memory, so WorkListSize 31347c478bd9Sstevel@tonic-gate ** should be checked again upon return. 31357c478bd9Sstevel@tonic-gate */ 31367c478bd9Sstevel@tonic-gate 31377c478bd9Sstevel@tonic-gate static void 31387c478bd9Sstevel@tonic-gate grow_wlist(qgrp, qdir) 31397c478bd9Sstevel@tonic-gate int qgrp; 31407c478bd9Sstevel@tonic-gate int qdir; 31417c478bd9Sstevel@tonic-gate { 31427c478bd9Sstevel@tonic-gate if (tTd(41, 1)) 31437c478bd9Sstevel@tonic-gate sm_dprintf("grow_wlist: WorkListSize=%d\n", WorkListSize); 31447c478bd9Sstevel@tonic-gate if (WorkList == NULL) 31457c478bd9Sstevel@tonic-gate { 3146058561cbSjbeck WorkList = (WORK *) xalloc((sizeof(*WorkList)) * 31477c478bd9Sstevel@tonic-gate (QUEUESEGSIZE + 1)); 31487c478bd9Sstevel@tonic-gate WorkListSize = QUEUESEGSIZE; 31497c478bd9Sstevel@tonic-gate } 31507c478bd9Sstevel@tonic-gate else 31517c478bd9Sstevel@tonic-gate { 31527c478bd9Sstevel@tonic-gate int newsize = WorkListSize + QUEUESEGSIZE; 31537c478bd9Sstevel@tonic-gate WORK *newlist = (WORK *) sm_realloc((char *) WorkList, 31547c478bd9Sstevel@tonic-gate (unsigned) sizeof(WORK) * (newsize + 1)); 31557c478bd9Sstevel@tonic-gate 31567c478bd9Sstevel@tonic-gate if (newlist != NULL) 31577c478bd9Sstevel@tonic-gate { 31587c478bd9Sstevel@tonic-gate WorkListSize = newsize; 31597c478bd9Sstevel@tonic-gate WorkList = newlist; 31607c478bd9Sstevel@tonic-gate if (LogLevel > 1) 31617c478bd9Sstevel@tonic-gate { 31627c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 31637c478bd9Sstevel@tonic-gate "grew WorkList for %s to %d", 31647c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), 31657c478bd9Sstevel@tonic-gate WorkListSize); 31667c478bd9Sstevel@tonic-gate } 31677c478bd9Sstevel@tonic-gate } 31687c478bd9Sstevel@tonic-gate else if (LogLevel > 0) 31697c478bd9Sstevel@tonic-gate { 31707c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, NOQID, 31717c478bd9Sstevel@tonic-gate "FAILED to grow WorkList for %s to %d", 31727c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), newsize); 31737c478bd9Sstevel@tonic-gate } 31747c478bd9Sstevel@tonic-gate } 31757c478bd9Sstevel@tonic-gate if (tTd(41, 1)) 31767c478bd9Sstevel@tonic-gate sm_dprintf("grow_wlist: WorkListSize now %d\n", WorkListSize); 31777c478bd9Sstevel@tonic-gate } 31787c478bd9Sstevel@tonic-gate /* 31797c478bd9Sstevel@tonic-gate ** WORKCMPF0 -- simple priority-only compare function. 31807c478bd9Sstevel@tonic-gate ** 31817c478bd9Sstevel@tonic-gate ** Parameters: 31827c478bd9Sstevel@tonic-gate ** a -- the first argument. 31837c478bd9Sstevel@tonic-gate ** b -- the second argument. 31847c478bd9Sstevel@tonic-gate ** 31857c478bd9Sstevel@tonic-gate ** Returns: 31867c478bd9Sstevel@tonic-gate ** -1 if a < b 31877c478bd9Sstevel@tonic-gate ** 0 if a == b 31887c478bd9Sstevel@tonic-gate ** +1 if a > b 31897c478bd9Sstevel@tonic-gate ** 31907c478bd9Sstevel@tonic-gate */ 31917c478bd9Sstevel@tonic-gate 31927c478bd9Sstevel@tonic-gate static int 31937c478bd9Sstevel@tonic-gate workcmpf0(a, b) 31947c478bd9Sstevel@tonic-gate register WORK *a; 31957c478bd9Sstevel@tonic-gate register WORK *b; 31967c478bd9Sstevel@tonic-gate { 31977c478bd9Sstevel@tonic-gate long pa = a->w_pri; 31987c478bd9Sstevel@tonic-gate long pb = b->w_pri; 31997c478bd9Sstevel@tonic-gate 32007c478bd9Sstevel@tonic-gate if (pa == pb) 32017c478bd9Sstevel@tonic-gate return 0; 32027c478bd9Sstevel@tonic-gate else if (pa > pb) 32037c478bd9Sstevel@tonic-gate return 1; 32047c478bd9Sstevel@tonic-gate else 32057c478bd9Sstevel@tonic-gate return -1; 32067c478bd9Sstevel@tonic-gate } 32077c478bd9Sstevel@tonic-gate /* 32087c478bd9Sstevel@tonic-gate ** WORKCMPF1 -- first compare function for ordering work based on host name. 32097c478bd9Sstevel@tonic-gate ** 32107c478bd9Sstevel@tonic-gate ** Sorts on host name, lock status, and priority in that order. 32117c478bd9Sstevel@tonic-gate ** 32127c478bd9Sstevel@tonic-gate ** Parameters: 32137c478bd9Sstevel@tonic-gate ** a -- the first argument. 32147c478bd9Sstevel@tonic-gate ** b -- the second argument. 32157c478bd9Sstevel@tonic-gate ** 32167c478bd9Sstevel@tonic-gate ** Returns: 32177c478bd9Sstevel@tonic-gate ** <0 if a < b 32187c478bd9Sstevel@tonic-gate ** 0 if a == b 32197c478bd9Sstevel@tonic-gate ** >0 if a > b 32207c478bd9Sstevel@tonic-gate ** 32217c478bd9Sstevel@tonic-gate */ 32227c478bd9Sstevel@tonic-gate 32237c478bd9Sstevel@tonic-gate static int 32247c478bd9Sstevel@tonic-gate workcmpf1(a, b) 32257c478bd9Sstevel@tonic-gate register WORK *a; 32267c478bd9Sstevel@tonic-gate register WORK *b; 32277c478bd9Sstevel@tonic-gate { 32287c478bd9Sstevel@tonic-gate int i; 32297c478bd9Sstevel@tonic-gate 32307c478bd9Sstevel@tonic-gate /* host name */ 32317c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host == NULL) 32327c478bd9Sstevel@tonic-gate return 1; 32337c478bd9Sstevel@tonic-gate else if (a->w_host == NULL && b->w_host != NULL) 32347c478bd9Sstevel@tonic-gate return -1; 32357c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host != NULL && 32367c478bd9Sstevel@tonic-gate (i = sm_strcasecmp(a->w_host, b->w_host)) != 0) 32377c478bd9Sstevel@tonic-gate return i; 32387c478bd9Sstevel@tonic-gate 32397c478bd9Sstevel@tonic-gate /* lock status */ 32407c478bd9Sstevel@tonic-gate if (a->w_lock != b->w_lock) 32417c478bd9Sstevel@tonic-gate return b->w_lock - a->w_lock; 32427c478bd9Sstevel@tonic-gate 32437c478bd9Sstevel@tonic-gate /* job priority */ 32447c478bd9Sstevel@tonic-gate return workcmpf0(a, b); 32457c478bd9Sstevel@tonic-gate } 32467c478bd9Sstevel@tonic-gate /* 32477c478bd9Sstevel@tonic-gate ** WORKCMPF2 -- second compare function for ordering work based on host name. 32487c478bd9Sstevel@tonic-gate ** 32497c478bd9Sstevel@tonic-gate ** Sorts on lock status, host name, and priority in that order. 32507c478bd9Sstevel@tonic-gate ** 32517c478bd9Sstevel@tonic-gate ** Parameters: 32527c478bd9Sstevel@tonic-gate ** a -- the first argument. 32537c478bd9Sstevel@tonic-gate ** b -- the second argument. 32547c478bd9Sstevel@tonic-gate ** 32557c478bd9Sstevel@tonic-gate ** Returns: 32567c478bd9Sstevel@tonic-gate ** <0 if a < b 32577c478bd9Sstevel@tonic-gate ** 0 if a == b 32587c478bd9Sstevel@tonic-gate ** >0 if a > b 32597c478bd9Sstevel@tonic-gate ** 32607c478bd9Sstevel@tonic-gate */ 32617c478bd9Sstevel@tonic-gate 32627c478bd9Sstevel@tonic-gate static int 32637c478bd9Sstevel@tonic-gate workcmpf2(a, b) 32647c478bd9Sstevel@tonic-gate register WORK *a; 32657c478bd9Sstevel@tonic-gate register WORK *b; 32667c478bd9Sstevel@tonic-gate { 32677c478bd9Sstevel@tonic-gate int i; 32687c478bd9Sstevel@tonic-gate 32697c478bd9Sstevel@tonic-gate /* lock status */ 32707c478bd9Sstevel@tonic-gate if (a->w_lock != b->w_lock) 32717c478bd9Sstevel@tonic-gate return a->w_lock - b->w_lock; 32727c478bd9Sstevel@tonic-gate 32737c478bd9Sstevel@tonic-gate /* host name */ 32747c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host == NULL) 32757c478bd9Sstevel@tonic-gate return 1; 32767c478bd9Sstevel@tonic-gate else if (a->w_host == NULL && b->w_host != NULL) 32777c478bd9Sstevel@tonic-gate return -1; 32787c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host != NULL && 32797c478bd9Sstevel@tonic-gate (i = sm_strcasecmp(a->w_host, b->w_host)) != 0) 32807c478bd9Sstevel@tonic-gate return i; 32817c478bd9Sstevel@tonic-gate 32827c478bd9Sstevel@tonic-gate /* job priority */ 32837c478bd9Sstevel@tonic-gate return workcmpf0(a, b); 32847c478bd9Sstevel@tonic-gate } 32857c478bd9Sstevel@tonic-gate /* 32867c478bd9Sstevel@tonic-gate ** WORKCMPF3 -- simple submission-time-only compare function. 32877c478bd9Sstevel@tonic-gate ** 32887c478bd9Sstevel@tonic-gate ** Parameters: 32897c478bd9Sstevel@tonic-gate ** a -- the first argument. 32907c478bd9Sstevel@tonic-gate ** b -- the second argument. 32917c478bd9Sstevel@tonic-gate ** 32927c478bd9Sstevel@tonic-gate ** Returns: 32937c478bd9Sstevel@tonic-gate ** -1 if a < b 32947c478bd9Sstevel@tonic-gate ** 0 if a == b 32957c478bd9Sstevel@tonic-gate ** +1 if a > b 32967c478bd9Sstevel@tonic-gate ** 32977c478bd9Sstevel@tonic-gate */ 32987c478bd9Sstevel@tonic-gate 32997c478bd9Sstevel@tonic-gate static int 33007c478bd9Sstevel@tonic-gate workcmpf3(a, b) 33017c478bd9Sstevel@tonic-gate register WORK *a; 33027c478bd9Sstevel@tonic-gate register WORK *b; 33037c478bd9Sstevel@tonic-gate { 33047c478bd9Sstevel@tonic-gate if (a->w_ctime > b->w_ctime) 33057c478bd9Sstevel@tonic-gate return 1; 33067c478bd9Sstevel@tonic-gate else if (a->w_ctime < b->w_ctime) 33077c478bd9Sstevel@tonic-gate return -1; 33087c478bd9Sstevel@tonic-gate else 33097c478bd9Sstevel@tonic-gate return 0; 33107c478bd9Sstevel@tonic-gate } 33117c478bd9Sstevel@tonic-gate /* 33127c478bd9Sstevel@tonic-gate ** WORKCMPF4 -- compare based on file name 33137c478bd9Sstevel@tonic-gate ** 33147c478bd9Sstevel@tonic-gate ** Parameters: 33157c478bd9Sstevel@tonic-gate ** a -- the first argument. 33167c478bd9Sstevel@tonic-gate ** b -- the second argument. 33177c478bd9Sstevel@tonic-gate ** 33187c478bd9Sstevel@tonic-gate ** Returns: 33197c478bd9Sstevel@tonic-gate ** -1 if a < b 33207c478bd9Sstevel@tonic-gate ** 0 if a == b 33217c478bd9Sstevel@tonic-gate ** +1 if a > b 33227c478bd9Sstevel@tonic-gate ** 33237c478bd9Sstevel@tonic-gate */ 33247c478bd9Sstevel@tonic-gate 33257c478bd9Sstevel@tonic-gate static int 33267c478bd9Sstevel@tonic-gate workcmpf4(a, b) 33277c478bd9Sstevel@tonic-gate register WORK *a; 33287c478bd9Sstevel@tonic-gate register WORK *b; 33297c478bd9Sstevel@tonic-gate { 33307c478bd9Sstevel@tonic-gate return strcmp(a->w_name, b->w_name); 33317c478bd9Sstevel@tonic-gate } 33327c478bd9Sstevel@tonic-gate /* 33337c478bd9Sstevel@tonic-gate ** WORKCMPF5 -- compare based on assigned random number 33347c478bd9Sstevel@tonic-gate ** 33357c478bd9Sstevel@tonic-gate ** Parameters: 33367c478bd9Sstevel@tonic-gate ** a -- the first argument (ignored). 33377c478bd9Sstevel@tonic-gate ** b -- the second argument (ignored). 33387c478bd9Sstevel@tonic-gate ** 33397c478bd9Sstevel@tonic-gate ** Returns: 33407c478bd9Sstevel@tonic-gate ** randomly 1/-1 33417c478bd9Sstevel@tonic-gate */ 33427c478bd9Sstevel@tonic-gate 33437c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 33447c478bd9Sstevel@tonic-gate static int 33457c478bd9Sstevel@tonic-gate workcmpf5(a, b) 33467c478bd9Sstevel@tonic-gate register WORK *a; 33477c478bd9Sstevel@tonic-gate register WORK *b; 33487c478bd9Sstevel@tonic-gate { 33497c478bd9Sstevel@tonic-gate if (strlen(a->w_name) < randi || strlen(b->w_name) < randi) 33507c478bd9Sstevel@tonic-gate return -1; 33517c478bd9Sstevel@tonic-gate return a->w_name[randi] - b->w_name[randi]; 33527c478bd9Sstevel@tonic-gate } 33537c478bd9Sstevel@tonic-gate /* 33547c478bd9Sstevel@tonic-gate ** WORKCMPF6 -- simple modification-time-only compare function. 33557c478bd9Sstevel@tonic-gate ** 33567c478bd9Sstevel@tonic-gate ** Parameters: 33577c478bd9Sstevel@tonic-gate ** a -- the first argument. 33587c478bd9Sstevel@tonic-gate ** b -- the second argument. 33597c478bd9Sstevel@tonic-gate ** 33607c478bd9Sstevel@tonic-gate ** Returns: 33617c478bd9Sstevel@tonic-gate ** -1 if a < b 33627c478bd9Sstevel@tonic-gate ** 0 if a == b 33637c478bd9Sstevel@tonic-gate ** +1 if a > b 33647c478bd9Sstevel@tonic-gate ** 33657c478bd9Sstevel@tonic-gate */ 33667c478bd9Sstevel@tonic-gate 33677c478bd9Sstevel@tonic-gate static int 33687c478bd9Sstevel@tonic-gate workcmpf6(a, b) 33697c478bd9Sstevel@tonic-gate register WORK *a; 33707c478bd9Sstevel@tonic-gate register WORK *b; 33717c478bd9Sstevel@tonic-gate { 33727c478bd9Sstevel@tonic-gate if (a->w_mtime > b->w_mtime) 33737c478bd9Sstevel@tonic-gate return 1; 33747c478bd9Sstevel@tonic-gate else if (a->w_mtime < b->w_mtime) 33757c478bd9Sstevel@tonic-gate return -1; 33767c478bd9Sstevel@tonic-gate else 33777c478bd9Sstevel@tonic-gate return 0; 33787c478bd9Sstevel@tonic-gate } 33797c478bd9Sstevel@tonic-gate #if _FFR_RHS 33807c478bd9Sstevel@tonic-gate /* 33817c478bd9Sstevel@tonic-gate ** WORKCMPF7 -- compare function for ordering work based on shuffled host name. 33827c478bd9Sstevel@tonic-gate ** 33837c478bd9Sstevel@tonic-gate ** Sorts on lock status, host name, and priority in that order. 33847c478bd9Sstevel@tonic-gate ** 33857c478bd9Sstevel@tonic-gate ** Parameters: 33867c478bd9Sstevel@tonic-gate ** a -- the first argument. 33877c478bd9Sstevel@tonic-gate ** b -- the second argument. 33887c478bd9Sstevel@tonic-gate ** 33897c478bd9Sstevel@tonic-gate ** Returns: 33907c478bd9Sstevel@tonic-gate ** <0 if a < b 33917c478bd9Sstevel@tonic-gate ** 0 if a == b 33927c478bd9Sstevel@tonic-gate ** >0 if a > b 33937c478bd9Sstevel@tonic-gate ** 33947c478bd9Sstevel@tonic-gate */ 33957c478bd9Sstevel@tonic-gate 33967c478bd9Sstevel@tonic-gate static int 33977c478bd9Sstevel@tonic-gate workcmpf7(a, b) 33987c478bd9Sstevel@tonic-gate register WORK *a; 33997c478bd9Sstevel@tonic-gate register WORK *b; 34007c478bd9Sstevel@tonic-gate { 34017c478bd9Sstevel@tonic-gate int i; 34027c478bd9Sstevel@tonic-gate 34037c478bd9Sstevel@tonic-gate /* lock status */ 34047c478bd9Sstevel@tonic-gate if (a->w_lock != b->w_lock) 34057c478bd9Sstevel@tonic-gate return a->w_lock - b->w_lock; 34067c478bd9Sstevel@tonic-gate 34077c478bd9Sstevel@tonic-gate /* host name */ 34087c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host == NULL) 34097c478bd9Sstevel@tonic-gate return 1; 34107c478bd9Sstevel@tonic-gate else if (a->w_host == NULL && b->w_host != NULL) 34117c478bd9Sstevel@tonic-gate return -1; 34127c478bd9Sstevel@tonic-gate if (a->w_host != NULL && b->w_host != NULL && 34137c478bd9Sstevel@tonic-gate (i = sm_strshufflecmp(a->w_host, b->w_host)) != 0) 34147c478bd9Sstevel@tonic-gate return i; 34157c478bd9Sstevel@tonic-gate 34167c478bd9Sstevel@tonic-gate /* job priority */ 34177c478bd9Sstevel@tonic-gate return workcmpf0(a, b); 34187c478bd9Sstevel@tonic-gate } 34197c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 34207c478bd9Sstevel@tonic-gate /* 34217c478bd9Sstevel@tonic-gate ** STRREV -- reverse string 34227c478bd9Sstevel@tonic-gate ** 34237c478bd9Sstevel@tonic-gate ** Returns a pointer to a new string that is the reverse of 34247c478bd9Sstevel@tonic-gate ** the string pointed to by fwd. The space for the new 34257c478bd9Sstevel@tonic-gate ** string is obtained using xalloc(). 34267c478bd9Sstevel@tonic-gate ** 34277c478bd9Sstevel@tonic-gate ** Parameters: 34287c478bd9Sstevel@tonic-gate ** fwd -- the string to reverse. 34297c478bd9Sstevel@tonic-gate ** 34307c478bd9Sstevel@tonic-gate ** Returns: 34317c478bd9Sstevel@tonic-gate ** the reversed string. 34327c478bd9Sstevel@tonic-gate */ 34337c478bd9Sstevel@tonic-gate 34347c478bd9Sstevel@tonic-gate static char * 34357c478bd9Sstevel@tonic-gate strrev(fwd) 34367c478bd9Sstevel@tonic-gate char *fwd; 34377c478bd9Sstevel@tonic-gate { 34387c478bd9Sstevel@tonic-gate char *rev = NULL; 34397c478bd9Sstevel@tonic-gate int len, cnt; 34407c478bd9Sstevel@tonic-gate 34417c478bd9Sstevel@tonic-gate len = strlen(fwd); 34427c478bd9Sstevel@tonic-gate rev = xalloc(len + 1); 34437c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < len; ++cnt) 34447c478bd9Sstevel@tonic-gate rev[cnt] = fwd[len - cnt - 1]; 34457c478bd9Sstevel@tonic-gate rev[len] = '\0'; 34467c478bd9Sstevel@tonic-gate return rev; 34477c478bd9Sstevel@tonic-gate } 34487c478bd9Sstevel@tonic-gate 34497c478bd9Sstevel@tonic-gate #if _FFR_RHS 34507c478bd9Sstevel@tonic-gate 34517c478bd9Sstevel@tonic-gate # define NASCII 128 34527c478bd9Sstevel@tonic-gate # define NCHAR 256 34537c478bd9Sstevel@tonic-gate 34547c478bd9Sstevel@tonic-gate static unsigned char ShuffledAlphabet[NCHAR]; 34557c478bd9Sstevel@tonic-gate 34567c478bd9Sstevel@tonic-gate void 34577c478bd9Sstevel@tonic-gate init_shuffle_alphabet() 34587c478bd9Sstevel@tonic-gate { 34597c478bd9Sstevel@tonic-gate static bool init = false; 34607c478bd9Sstevel@tonic-gate int i; 34617c478bd9Sstevel@tonic-gate 34627c478bd9Sstevel@tonic-gate if (init) 34637c478bd9Sstevel@tonic-gate return; 34647c478bd9Sstevel@tonic-gate 34657c478bd9Sstevel@tonic-gate /* fill the ShuffledAlphabet */ 346649218d4fSjbeck for (i = 0; i < NASCII; i++) 34677c478bd9Sstevel@tonic-gate ShuffledAlphabet[i] = i; 34687c478bd9Sstevel@tonic-gate 34697c478bd9Sstevel@tonic-gate /* mix it */ 347049218d4fSjbeck for (i = 1; i < NASCII; i++) 34717c478bd9Sstevel@tonic-gate { 347249218d4fSjbeck register int j = get_random() % NASCII; 34737c478bd9Sstevel@tonic-gate register int tmp; 34747c478bd9Sstevel@tonic-gate 34757c478bd9Sstevel@tonic-gate tmp = ShuffledAlphabet[j]; 34767c478bd9Sstevel@tonic-gate ShuffledAlphabet[j] = ShuffledAlphabet[i]; 34777c478bd9Sstevel@tonic-gate ShuffledAlphabet[i] = tmp; 34787c478bd9Sstevel@tonic-gate } 34797c478bd9Sstevel@tonic-gate 34807c478bd9Sstevel@tonic-gate /* make it case insensitive */ 34817c478bd9Sstevel@tonic-gate for (i = 'A'; i <= 'Z'; i++) 34827c478bd9Sstevel@tonic-gate ShuffledAlphabet[i] = ShuffledAlphabet[i + 'a' - 'A']; 34837c478bd9Sstevel@tonic-gate 34847c478bd9Sstevel@tonic-gate /* fill the upper part */ 348549218d4fSjbeck for (i = 0; i < NASCII; i++) 348649218d4fSjbeck ShuffledAlphabet[i + NASCII] = ShuffledAlphabet[i]; 34877c478bd9Sstevel@tonic-gate init = true; 34887c478bd9Sstevel@tonic-gate } 34897c478bd9Sstevel@tonic-gate 34907c478bd9Sstevel@tonic-gate static int 34917c478bd9Sstevel@tonic-gate sm_strshufflecmp(a, b) 34927c478bd9Sstevel@tonic-gate char *a; 34937c478bd9Sstevel@tonic-gate char *b; 34947c478bd9Sstevel@tonic-gate { 34957c478bd9Sstevel@tonic-gate const unsigned char *us1 = (const unsigned char *) a; 34967c478bd9Sstevel@tonic-gate const unsigned char *us2 = (const unsigned char *) b; 34977c478bd9Sstevel@tonic-gate 34987c478bd9Sstevel@tonic-gate while (ShuffledAlphabet[*us1] == ShuffledAlphabet[*us2++]) 34997c478bd9Sstevel@tonic-gate { 35007c478bd9Sstevel@tonic-gate if (*us1++ == '\0') 35017c478bd9Sstevel@tonic-gate return 0; 35027c478bd9Sstevel@tonic-gate } 35037c478bd9Sstevel@tonic-gate return (ShuffledAlphabet[*us1] - ShuffledAlphabet[*--us2]); 35047c478bd9Sstevel@tonic-gate } 35057c478bd9Sstevel@tonic-gate #endif /* _FFR_RHS */ 35067c478bd9Sstevel@tonic-gate 35077c478bd9Sstevel@tonic-gate /* 35087c478bd9Sstevel@tonic-gate ** DOWORK -- do a work request. 35097c478bd9Sstevel@tonic-gate ** 35107c478bd9Sstevel@tonic-gate ** Parameters: 35117c478bd9Sstevel@tonic-gate ** qgrp -- the index of the queue group for the job. 35127c478bd9Sstevel@tonic-gate ** qdir -- the index of the queue directory for the job. 35137c478bd9Sstevel@tonic-gate ** id -- the ID of the job to run. 35147c478bd9Sstevel@tonic-gate ** forkflag -- if set, run this in background. 35157c478bd9Sstevel@tonic-gate ** requeueflag -- if set, reinstantiate the queue quickly. 35167c478bd9Sstevel@tonic-gate ** This is used when expanding aliases in the queue. 35177c478bd9Sstevel@tonic-gate ** If forkflag is also set, it doesn't wait for the 35187c478bd9Sstevel@tonic-gate ** child. 35197c478bd9Sstevel@tonic-gate ** e - the envelope in which to run it. 35207c478bd9Sstevel@tonic-gate ** 35217c478bd9Sstevel@tonic-gate ** Returns: 35227c478bd9Sstevel@tonic-gate ** process id of process that is running the queue job. 35237c478bd9Sstevel@tonic-gate ** 35247c478bd9Sstevel@tonic-gate ** Side Effects: 35257c478bd9Sstevel@tonic-gate ** The work request is satisfied if possible. 35267c478bd9Sstevel@tonic-gate */ 35277c478bd9Sstevel@tonic-gate 35287c478bd9Sstevel@tonic-gate pid_t 35297c478bd9Sstevel@tonic-gate dowork(qgrp, qdir, id, forkflag, requeueflag, e) 35307c478bd9Sstevel@tonic-gate int qgrp; 35317c478bd9Sstevel@tonic-gate int qdir; 35327c478bd9Sstevel@tonic-gate char *id; 35337c478bd9Sstevel@tonic-gate bool forkflag; 35347c478bd9Sstevel@tonic-gate bool requeueflag; 35357c478bd9Sstevel@tonic-gate register ENVELOPE *e; 35367c478bd9Sstevel@tonic-gate { 35377c478bd9Sstevel@tonic-gate register pid_t pid; 35387c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool; 35397c478bd9Sstevel@tonic-gate 35407c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 35417c478bd9Sstevel@tonic-gate sm_dprintf("dowork(%s/%s)\n", qid_printqueue(qgrp, qdir), id); 35427c478bd9Sstevel@tonic-gate 35437c478bd9Sstevel@tonic-gate /* 35447c478bd9Sstevel@tonic-gate ** Fork for work. 35457c478bd9Sstevel@tonic-gate */ 35467c478bd9Sstevel@tonic-gate 35477c478bd9Sstevel@tonic-gate if (forkflag) 35487c478bd9Sstevel@tonic-gate { 35497c478bd9Sstevel@tonic-gate /* 35507c478bd9Sstevel@tonic-gate ** Since the delivery may happen in a child and the 35517c478bd9Sstevel@tonic-gate ** parent does not wait, the parent may close the 35527c478bd9Sstevel@tonic-gate ** maps thereby removing any shared memory used by 35537c478bd9Sstevel@tonic-gate ** the map. Therefore, close the maps now so the 35547c478bd9Sstevel@tonic-gate ** child will dynamically open them if necessary. 35557c478bd9Sstevel@tonic-gate */ 35567c478bd9Sstevel@tonic-gate 35577c478bd9Sstevel@tonic-gate closemaps(false); 35587c478bd9Sstevel@tonic-gate 35597c478bd9Sstevel@tonic-gate pid = fork(); 35607c478bd9Sstevel@tonic-gate if (pid < 0) 35617c478bd9Sstevel@tonic-gate { 35627c478bd9Sstevel@tonic-gate syserr("dowork: cannot fork"); 35637c478bd9Sstevel@tonic-gate return 0; 35647c478bd9Sstevel@tonic-gate } 35657c478bd9Sstevel@tonic-gate else if (pid > 0) 35667c478bd9Sstevel@tonic-gate { 35677c478bd9Sstevel@tonic-gate /* parent -- clean out connection cache */ 35687c478bd9Sstevel@tonic-gate mci_flush(false, NULL); 35697c478bd9Sstevel@tonic-gate } 35707c478bd9Sstevel@tonic-gate else 35717c478bd9Sstevel@tonic-gate { 35727c478bd9Sstevel@tonic-gate /* 35737c478bd9Sstevel@tonic-gate ** Initialize exception stack and default exception 35747c478bd9Sstevel@tonic-gate ** handler for child process. 35757c478bd9Sstevel@tonic-gate */ 35767c478bd9Sstevel@tonic-gate 35777c478bd9Sstevel@tonic-gate /* Reset global flags */ 35787c478bd9Sstevel@tonic-gate RestartRequest = NULL; 35797c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 35807c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 35817c478bd9Sstevel@tonic-gate PendingSignal = 0; 35827c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 35837c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error); 35847c478bd9Sstevel@tonic-gate 35857c478bd9Sstevel@tonic-gate /* 35867c478bd9Sstevel@tonic-gate ** See note above about SMTP processes and SIGCHLD. 35877c478bd9Sstevel@tonic-gate */ 35887c478bd9Sstevel@tonic-gate 35897c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP || 35907c478bd9Sstevel@tonic-gate OpMode == MD_DAEMON || 35917c478bd9Sstevel@tonic-gate MaxQueueChildren > 0) 35927c478bd9Sstevel@tonic-gate { 35937c478bd9Sstevel@tonic-gate proc_list_clear(); 35947c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD); 35957c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 35967c478bd9Sstevel@tonic-gate } 35977c478bd9Sstevel@tonic-gate 35987c478bd9Sstevel@tonic-gate /* child -- error messages to the transcript */ 35997c478bd9Sstevel@tonic-gate QuickAbort = OnlyOneError = false; 36007c478bd9Sstevel@tonic-gate } 36017c478bd9Sstevel@tonic-gate } 36027c478bd9Sstevel@tonic-gate else 36037c478bd9Sstevel@tonic-gate { 36047c478bd9Sstevel@tonic-gate pid = 0; 36057c478bd9Sstevel@tonic-gate } 36067c478bd9Sstevel@tonic-gate 36077c478bd9Sstevel@tonic-gate if (pid == 0) 36087c478bd9Sstevel@tonic-gate { 36097c478bd9Sstevel@tonic-gate /* 36107c478bd9Sstevel@tonic-gate ** CHILD 36117c478bd9Sstevel@tonic-gate ** Lock the control file to avoid duplicate deliveries. 36127c478bd9Sstevel@tonic-gate ** Then run the file as though we had just read it. 36137c478bd9Sstevel@tonic-gate ** We save an idea of the temporary name so we 36147c478bd9Sstevel@tonic-gate ** can recover on interrupt. 36157c478bd9Sstevel@tonic-gate */ 36167c478bd9Sstevel@tonic-gate 36177c478bd9Sstevel@tonic-gate if (forkflag) 36187c478bd9Sstevel@tonic-gate { 36197c478bd9Sstevel@tonic-gate /* Reset global flags */ 36207c478bd9Sstevel@tonic-gate RestartRequest = NULL; 36217c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 36227c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 36237c478bd9Sstevel@tonic-gate PendingSignal = 0; 36247c478bd9Sstevel@tonic-gate } 36257c478bd9Sstevel@tonic-gate 36267c478bd9Sstevel@tonic-gate /* set basic modes, etc. */ 36277c478bd9Sstevel@tonic-gate sm_clear_events(); 36287c478bd9Sstevel@tonic-gate clearstats(); 36297c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL); 36307c478bd9Sstevel@tonic-gate clearenvelope(e, false, rpool); 36317c478bd9Sstevel@tonic-gate e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS; 36327c478bd9Sstevel@tonic-gate set_delivery_mode(SM_DELIVER, e); 36337c478bd9Sstevel@tonic-gate e->e_errormode = EM_MAIL; 36347c478bd9Sstevel@tonic-gate e->e_id = id; 36357c478bd9Sstevel@tonic-gate e->e_qgrp = qgrp; 36367c478bd9Sstevel@tonic-gate e->e_qdir = qdir; 36377c478bd9Sstevel@tonic-gate GrabTo = UseErrorsTo = false; 36387c478bd9Sstevel@tonic-gate ExitStat = EX_OK; 36397c478bd9Sstevel@tonic-gate if (forkflag) 36407c478bd9Sstevel@tonic-gate { 36417c478bd9Sstevel@tonic-gate disconnect(1, e); 36427c478bd9Sstevel@tonic-gate set_op_mode(MD_QUEUERUN); 36437c478bd9Sstevel@tonic-gate } 36447c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s from queue", qid_printname(e)); 36457c478bd9Sstevel@tonic-gate if (LogLevel > 76) 36467c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "dowork, pid=%d", 36477c478bd9Sstevel@tonic-gate (int) CurrentPid); 36487c478bd9Sstevel@tonic-gate 36497c478bd9Sstevel@tonic-gate /* don't use the headers from sendmail.cf... */ 36507c478bd9Sstevel@tonic-gate e->e_header = NULL; 36517c478bd9Sstevel@tonic-gate 36527c478bd9Sstevel@tonic-gate /* read the queue control file -- return if locked */ 36537c478bd9Sstevel@tonic-gate if (!readqf(e, false)) 36547c478bd9Sstevel@tonic-gate { 36557c478bd9Sstevel@tonic-gate if (tTd(40, 4) && e->e_id != NULL) 36567c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s) failed\n", 36577c478bd9Sstevel@tonic-gate qid_printname(e)); 36587c478bd9Sstevel@tonic-gate e->e_id = NULL; 36597c478bd9Sstevel@tonic-gate if (forkflag) 36607c478bd9Sstevel@tonic-gate finis(false, true, EX_OK); 36617c478bd9Sstevel@tonic-gate else 36627c478bd9Sstevel@tonic-gate { 36637c478bd9Sstevel@tonic-gate /* adding this frees 8 bytes */ 36647c478bd9Sstevel@tonic-gate clearenvelope(e, false, rpool); 36657c478bd9Sstevel@tonic-gate 36667c478bd9Sstevel@tonic-gate /* adding this frees 12 bytes */ 36677c478bd9Sstevel@tonic-gate sm_rpool_free(rpool); 36687c478bd9Sstevel@tonic-gate e->e_rpool = NULL; 36697c478bd9Sstevel@tonic-gate return 0; 36707c478bd9Sstevel@tonic-gate } 36717c478bd9Sstevel@tonic-gate } 36727c478bd9Sstevel@tonic-gate 36737c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE; 36747c478bd9Sstevel@tonic-gate eatheader(e, requeueflag, true); 36757c478bd9Sstevel@tonic-gate 36767c478bd9Sstevel@tonic-gate if (requeueflag) 36777c478bd9Sstevel@tonic-gate queueup(e, false, false); 36787c478bd9Sstevel@tonic-gate 36797c478bd9Sstevel@tonic-gate /* do the delivery */ 36807c478bd9Sstevel@tonic-gate sendall(e, SM_DELIVER); 36817c478bd9Sstevel@tonic-gate 36827c478bd9Sstevel@tonic-gate /* finish up and exit */ 36837c478bd9Sstevel@tonic-gate if (forkflag) 36847c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 36857c478bd9Sstevel@tonic-gate else 36867c478bd9Sstevel@tonic-gate { 36877c478bd9Sstevel@tonic-gate dropenvelope(e, true, false); 36887c478bd9Sstevel@tonic-gate sm_rpool_free(rpool); 36897c478bd9Sstevel@tonic-gate e->e_rpool = NULL; 36907c478bd9Sstevel@tonic-gate } 36917c478bd9Sstevel@tonic-gate } 36927c478bd9Sstevel@tonic-gate e->e_id = NULL; 36937c478bd9Sstevel@tonic-gate return pid; 36947c478bd9Sstevel@tonic-gate } 36957c478bd9Sstevel@tonic-gate 36967c478bd9Sstevel@tonic-gate /* 36977c478bd9Sstevel@tonic-gate ** DOWORKLIST -- process a list of envelopes as work requests 36987c478bd9Sstevel@tonic-gate ** 36997c478bd9Sstevel@tonic-gate ** Similar to dowork(), except that after forking, it processes an 37007c478bd9Sstevel@tonic-gate ** envelope and its siblings, treating each envelope as a work request. 37017c478bd9Sstevel@tonic-gate ** 37027c478bd9Sstevel@tonic-gate ** Parameters: 37037c478bd9Sstevel@tonic-gate ** el -- envelope to be processed including its siblings. 37047c478bd9Sstevel@tonic-gate ** forkflag -- if set, run this in background. 37057c478bd9Sstevel@tonic-gate ** requeueflag -- if set, reinstantiate the queue quickly. 37067c478bd9Sstevel@tonic-gate ** This is used when expanding aliases in the queue. 37077c478bd9Sstevel@tonic-gate ** If forkflag is also set, it doesn't wait for the 37087c478bd9Sstevel@tonic-gate ** child. 37097c478bd9Sstevel@tonic-gate ** 37107c478bd9Sstevel@tonic-gate ** Returns: 37117c478bd9Sstevel@tonic-gate ** process id of process that is running the queue job. 37127c478bd9Sstevel@tonic-gate ** 37137c478bd9Sstevel@tonic-gate ** Side Effects: 37147c478bd9Sstevel@tonic-gate ** The work request is satisfied if possible. 37157c478bd9Sstevel@tonic-gate */ 37167c478bd9Sstevel@tonic-gate 37177c478bd9Sstevel@tonic-gate pid_t 37187c478bd9Sstevel@tonic-gate doworklist(el, forkflag, requeueflag) 37197c478bd9Sstevel@tonic-gate ENVELOPE *el; 37207c478bd9Sstevel@tonic-gate bool forkflag; 37217c478bd9Sstevel@tonic-gate bool requeueflag; 37227c478bd9Sstevel@tonic-gate { 37237c478bd9Sstevel@tonic-gate register pid_t pid; 37247c478bd9Sstevel@tonic-gate ENVELOPE *ei; 37257c478bd9Sstevel@tonic-gate 37267c478bd9Sstevel@tonic-gate if (tTd(40, 1)) 37277c478bd9Sstevel@tonic-gate sm_dprintf("doworklist()\n"); 37287c478bd9Sstevel@tonic-gate 37297c478bd9Sstevel@tonic-gate /* 37307c478bd9Sstevel@tonic-gate ** Fork for work. 37317c478bd9Sstevel@tonic-gate */ 37327c478bd9Sstevel@tonic-gate 37337c478bd9Sstevel@tonic-gate if (forkflag) 37347c478bd9Sstevel@tonic-gate { 37357c478bd9Sstevel@tonic-gate /* 37367c478bd9Sstevel@tonic-gate ** Since the delivery may happen in a child and the 37377c478bd9Sstevel@tonic-gate ** parent does not wait, the parent may close the 37387c478bd9Sstevel@tonic-gate ** maps thereby removing any shared memory used by 37397c478bd9Sstevel@tonic-gate ** the map. Therefore, close the maps now so the 37407c478bd9Sstevel@tonic-gate ** child will dynamically open them if necessary. 37417c478bd9Sstevel@tonic-gate */ 37427c478bd9Sstevel@tonic-gate 37437c478bd9Sstevel@tonic-gate closemaps(false); 37447c478bd9Sstevel@tonic-gate 37457c478bd9Sstevel@tonic-gate pid = fork(); 37467c478bd9Sstevel@tonic-gate if (pid < 0) 37477c478bd9Sstevel@tonic-gate { 37487c478bd9Sstevel@tonic-gate syserr("doworklist: cannot fork"); 37497c478bd9Sstevel@tonic-gate return 0; 37507c478bd9Sstevel@tonic-gate } 37517c478bd9Sstevel@tonic-gate else if (pid > 0) 37527c478bd9Sstevel@tonic-gate { 37537c478bd9Sstevel@tonic-gate /* parent -- clean out connection cache */ 37547c478bd9Sstevel@tonic-gate mci_flush(false, NULL); 37557c478bd9Sstevel@tonic-gate } 37567c478bd9Sstevel@tonic-gate else 37577c478bd9Sstevel@tonic-gate { 37587c478bd9Sstevel@tonic-gate /* 37597c478bd9Sstevel@tonic-gate ** Initialize exception stack and default exception 37607c478bd9Sstevel@tonic-gate ** handler for child process. 37617c478bd9Sstevel@tonic-gate */ 37627c478bd9Sstevel@tonic-gate 37637c478bd9Sstevel@tonic-gate /* Reset global flags */ 37647c478bd9Sstevel@tonic-gate RestartRequest = NULL; 37657c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 37667c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 37677c478bd9Sstevel@tonic-gate PendingSignal = 0; 37687c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 37697c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error); 37707c478bd9Sstevel@tonic-gate 37717c478bd9Sstevel@tonic-gate /* 37727c478bd9Sstevel@tonic-gate ** See note above about SMTP processes and SIGCHLD. 37737c478bd9Sstevel@tonic-gate */ 37747c478bd9Sstevel@tonic-gate 37757c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP || 37767c478bd9Sstevel@tonic-gate OpMode == MD_DAEMON || 37777c478bd9Sstevel@tonic-gate MaxQueueChildren > 0) 37787c478bd9Sstevel@tonic-gate { 37797c478bd9Sstevel@tonic-gate proc_list_clear(); 37807c478bd9Sstevel@tonic-gate sm_releasesignal(SIGCHLD); 37817c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 37827c478bd9Sstevel@tonic-gate } 37837c478bd9Sstevel@tonic-gate 37847c478bd9Sstevel@tonic-gate /* child -- error messages to the transcript */ 37857c478bd9Sstevel@tonic-gate QuickAbort = OnlyOneError = false; 37867c478bd9Sstevel@tonic-gate } 37877c478bd9Sstevel@tonic-gate } 37887c478bd9Sstevel@tonic-gate else 37897c478bd9Sstevel@tonic-gate { 37907c478bd9Sstevel@tonic-gate pid = 0; 37917c478bd9Sstevel@tonic-gate } 37927c478bd9Sstevel@tonic-gate 37937c478bd9Sstevel@tonic-gate if (pid != 0) 37947c478bd9Sstevel@tonic-gate return pid; 37957c478bd9Sstevel@tonic-gate 37967c478bd9Sstevel@tonic-gate /* 37977c478bd9Sstevel@tonic-gate ** IN CHILD 37987c478bd9Sstevel@tonic-gate ** Lock the control file to avoid duplicate deliveries. 37997c478bd9Sstevel@tonic-gate ** Then run the file as though we had just read it. 38007c478bd9Sstevel@tonic-gate ** We save an idea of the temporary name so we 38017c478bd9Sstevel@tonic-gate ** can recover on interrupt. 38027c478bd9Sstevel@tonic-gate */ 38037c478bd9Sstevel@tonic-gate 38047c478bd9Sstevel@tonic-gate if (forkflag) 38057c478bd9Sstevel@tonic-gate { 38067c478bd9Sstevel@tonic-gate /* Reset global flags */ 38077c478bd9Sstevel@tonic-gate RestartRequest = NULL; 38087c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 38097c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 38107c478bd9Sstevel@tonic-gate PendingSignal = 0; 38117c478bd9Sstevel@tonic-gate } 38127c478bd9Sstevel@tonic-gate 38137c478bd9Sstevel@tonic-gate /* set basic modes, etc. */ 38147c478bd9Sstevel@tonic-gate sm_clear_events(); 38157c478bd9Sstevel@tonic-gate clearstats(); 38167c478bd9Sstevel@tonic-gate GrabTo = UseErrorsTo = false; 38177c478bd9Sstevel@tonic-gate ExitStat = EX_OK; 38187c478bd9Sstevel@tonic-gate if (forkflag) 38197c478bd9Sstevel@tonic-gate { 38207c478bd9Sstevel@tonic-gate disconnect(1, el); 38217c478bd9Sstevel@tonic-gate set_op_mode(MD_QUEUERUN); 38227c478bd9Sstevel@tonic-gate } 38237c478bd9Sstevel@tonic-gate if (LogLevel > 76) 38247c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, el->e_id, "doworklist, pid=%d", 38257c478bd9Sstevel@tonic-gate (int) CurrentPid); 38267c478bd9Sstevel@tonic-gate 38277c478bd9Sstevel@tonic-gate for (ei = el; ei != NULL; ei = ei->e_sibling) 38287c478bd9Sstevel@tonic-gate { 38297c478bd9Sstevel@tonic-gate ENVELOPE e; 38307c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool; 38317c478bd9Sstevel@tonic-gate 38327c478bd9Sstevel@tonic-gate if (WILL_BE_QUEUED(ei->e_sendmode)) 38337c478bd9Sstevel@tonic-gate continue; 38347c478bd9Sstevel@tonic-gate else if (QueueMode != QM_QUARANTINE && 38357c478bd9Sstevel@tonic-gate ei->e_quarmsg != NULL) 38367c478bd9Sstevel@tonic-gate continue; 38377c478bd9Sstevel@tonic-gate 38387c478bd9Sstevel@tonic-gate rpool = sm_rpool_new_x(NULL); 38397c478bd9Sstevel@tonic-gate clearenvelope(&e, true, rpool); 38407c478bd9Sstevel@tonic-gate e.e_flags |= EF_QUEUERUN|EF_GLOBALERRS; 38417c478bd9Sstevel@tonic-gate set_delivery_mode(SM_DELIVER, &e); 38427c478bd9Sstevel@tonic-gate e.e_errormode = EM_MAIL; 38437c478bd9Sstevel@tonic-gate e.e_id = ei->e_id; 38447c478bd9Sstevel@tonic-gate e.e_qgrp = ei->e_qgrp; 38457c478bd9Sstevel@tonic-gate e.e_qdir = ei->e_qdir; 38467c478bd9Sstevel@tonic-gate openxscript(&e); 38477c478bd9Sstevel@tonic-gate sm_setproctitle(true, &e, "%s from queue", qid_printname(&e)); 38487c478bd9Sstevel@tonic-gate 38497c478bd9Sstevel@tonic-gate /* don't use the headers from sendmail.cf... */ 38507c478bd9Sstevel@tonic-gate e.e_header = NULL; 38517c478bd9Sstevel@tonic-gate CurEnv = &e; 38527c478bd9Sstevel@tonic-gate 38537c478bd9Sstevel@tonic-gate /* read the queue control file -- return if locked */ 38547c478bd9Sstevel@tonic-gate if (readqf(&e, false)) 38557c478bd9Sstevel@tonic-gate { 38567c478bd9Sstevel@tonic-gate e.e_flags |= EF_INQUEUE; 38577c478bd9Sstevel@tonic-gate eatheader(&e, requeueflag, true); 38587c478bd9Sstevel@tonic-gate 38597c478bd9Sstevel@tonic-gate if (requeueflag) 38607c478bd9Sstevel@tonic-gate queueup(&e, false, false); 38617c478bd9Sstevel@tonic-gate 38627c478bd9Sstevel@tonic-gate /* do the delivery */ 38637c478bd9Sstevel@tonic-gate sendall(&e, SM_DELIVER); 38647c478bd9Sstevel@tonic-gate dropenvelope(&e, true, false); 38657c478bd9Sstevel@tonic-gate } 38667c478bd9Sstevel@tonic-gate else 38677c478bd9Sstevel@tonic-gate { 38687c478bd9Sstevel@tonic-gate if (tTd(40, 4) && e.e_id != NULL) 38697c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s) failed\n", 38707c478bd9Sstevel@tonic-gate qid_printname(&e)); 38717c478bd9Sstevel@tonic-gate } 38727c478bd9Sstevel@tonic-gate sm_rpool_free(rpool); 38737c478bd9Sstevel@tonic-gate ei->e_id = NULL; 38747c478bd9Sstevel@tonic-gate } 38757c478bd9Sstevel@tonic-gate 38767c478bd9Sstevel@tonic-gate /* restore CurEnv */ 38777c478bd9Sstevel@tonic-gate CurEnv = el; 38787c478bd9Sstevel@tonic-gate 38797c478bd9Sstevel@tonic-gate /* finish up and exit */ 38807c478bd9Sstevel@tonic-gate if (forkflag) 38817c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 38827c478bd9Sstevel@tonic-gate return 0; 38837c478bd9Sstevel@tonic-gate } 38847c478bd9Sstevel@tonic-gate /* 38857c478bd9Sstevel@tonic-gate ** READQF -- read queue file and set up environment. 38867c478bd9Sstevel@tonic-gate ** 38877c478bd9Sstevel@tonic-gate ** Parameters: 38887c478bd9Sstevel@tonic-gate ** e -- the envelope of the job to run. 38897c478bd9Sstevel@tonic-gate ** openonly -- only open the qf (returned as e_lockfp) 38907c478bd9Sstevel@tonic-gate ** 38917c478bd9Sstevel@tonic-gate ** Returns: 38927c478bd9Sstevel@tonic-gate ** true if it successfully read the queue file. 38937c478bd9Sstevel@tonic-gate ** false otherwise. 38947c478bd9Sstevel@tonic-gate ** 38957c478bd9Sstevel@tonic-gate ** Side Effects: 38967c478bd9Sstevel@tonic-gate ** The queue file is returned locked. 38977c478bd9Sstevel@tonic-gate */ 38987c478bd9Sstevel@tonic-gate 38997c478bd9Sstevel@tonic-gate static bool 39007c478bd9Sstevel@tonic-gate readqf(e, openonly) 39017c478bd9Sstevel@tonic-gate register ENVELOPE *e; 39027c478bd9Sstevel@tonic-gate bool openonly; 39037c478bd9Sstevel@tonic-gate { 39047c478bd9Sstevel@tonic-gate register SM_FILE_T *qfp; 39057c478bd9Sstevel@tonic-gate ADDRESS *ctladdr; 39067c478bd9Sstevel@tonic-gate struct stat st, stf; 39077c478bd9Sstevel@tonic-gate char *bp; 39087c478bd9Sstevel@tonic-gate int qfver = 0; 39097c478bd9Sstevel@tonic-gate long hdrsize = 0; 39107c478bd9Sstevel@tonic-gate register char *p; 39117c478bd9Sstevel@tonic-gate char *frcpt = NULL; 39127c478bd9Sstevel@tonic-gate char *orcpt = NULL; 39137c478bd9Sstevel@tonic-gate bool nomore = false; 39147c478bd9Sstevel@tonic-gate bool bogus = false; 39157c478bd9Sstevel@tonic-gate MODE_T qsafe; 39167c478bd9Sstevel@tonic-gate char *err; 39177c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN]; 39187c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 3919058561cbSjbeck int bufsize; 39207c478bd9Sstevel@tonic-gate 39217c478bd9Sstevel@tonic-gate /* 39227c478bd9Sstevel@tonic-gate ** Read and process the file. 39237c478bd9Sstevel@tonic-gate */ 39247c478bd9Sstevel@tonic-gate 39254aac33d3Sjbeck SM_REQUIRE(e != NULL); 39263ee0e492Sjbeck bp = NULL; 3927058561cbSjbeck (void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER), sizeof(qf)); 39287c478bd9Sstevel@tonic-gate qfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDWR_B, NULL); 39297c478bd9Sstevel@tonic-gate if (qfp == NULL) 39307c478bd9Sstevel@tonic-gate { 39317c478bd9Sstevel@tonic-gate int save_errno = errno; 39327c478bd9Sstevel@tonic-gate 39337c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 39347c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s): sm_io_open failure (%s)\n", 39357c478bd9Sstevel@tonic-gate qf, sm_errstring(errno)); 39367c478bd9Sstevel@tonic-gate errno = save_errno; 39377c478bd9Sstevel@tonic-gate if (errno != ENOENT 39387c478bd9Sstevel@tonic-gate ) 39397c478bd9Sstevel@tonic-gate syserr("readqf: no control file %s", qf); 39407c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 39417c478bd9Sstevel@tonic-gate return false; 39427c478bd9Sstevel@tonic-gate } 39437c478bd9Sstevel@tonic-gate 39447c478bd9Sstevel@tonic-gate if (!lockfile(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), qf, NULL, 39457c478bd9Sstevel@tonic-gate LOCK_EX|LOCK_NB)) 39467c478bd9Sstevel@tonic-gate { 39477c478bd9Sstevel@tonic-gate /* being processed by another queuer */ 39487c478bd9Sstevel@tonic-gate if (Verbose) 39497c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 39507c478bd9Sstevel@tonic-gate "%s: locked\n", e->e_id); 39517c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 39527c478bd9Sstevel@tonic-gate sm_dprintf("%s: locked\n", e->e_id); 39537c478bd9Sstevel@tonic-gate if (LogLevel > 19) 39547c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "locked"); 39557c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 39567c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 39577c478bd9Sstevel@tonic-gate return false; 39587c478bd9Sstevel@tonic-gate } 39597c478bd9Sstevel@tonic-gate 39607c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 39617c478bd9Sstevel@tonic-gate 39627c478bd9Sstevel@tonic-gate /* 39637c478bd9Sstevel@tonic-gate ** Prevent locking race condition. 39647c478bd9Sstevel@tonic-gate ** 39657c478bd9Sstevel@tonic-gate ** Process A: readqf(): qfp = fopen(qffile) 39667c478bd9Sstevel@tonic-gate ** Process B: queueup(): rename(tf, qf) 39677c478bd9Sstevel@tonic-gate ** Process B: unlocks(tf) 39687c478bd9Sstevel@tonic-gate ** Process A: lockfile(qf); 39697c478bd9Sstevel@tonic-gate ** 39707c478bd9Sstevel@tonic-gate ** Process A (us) has the old qf file (before the rename deleted 39717c478bd9Sstevel@tonic-gate ** the directory entry) and will be delivering based on old data. 39727c478bd9Sstevel@tonic-gate ** This can lead to multiple deliveries of the same recipients. 39737c478bd9Sstevel@tonic-gate ** 39747c478bd9Sstevel@tonic-gate ** Catch this by checking if the underlying qf file has changed 39757c478bd9Sstevel@tonic-gate ** *after* acquiring our lock and if so, act as though the file 39767c478bd9Sstevel@tonic-gate ** was still locked (i.e., just return like the lockfile() case 39777c478bd9Sstevel@tonic-gate ** above. 39787c478bd9Sstevel@tonic-gate */ 39797c478bd9Sstevel@tonic-gate 39807c478bd9Sstevel@tonic-gate if (stat(qf, &stf) < 0 || 39817c478bd9Sstevel@tonic-gate fstat(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), &st) < 0) 39827c478bd9Sstevel@tonic-gate { 39837c478bd9Sstevel@tonic-gate /* must have been being processed by someone else */ 39847c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 39857c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s): [f]stat failure (%s)\n", 39867c478bd9Sstevel@tonic-gate qf, sm_errstring(errno)); 39877c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 39887c478bd9Sstevel@tonic-gate return false; 39897c478bd9Sstevel@tonic-gate } 39907c478bd9Sstevel@tonic-gate 39917c478bd9Sstevel@tonic-gate if (st.st_nlink != stf.st_nlink || 39927c478bd9Sstevel@tonic-gate st.st_dev != stf.st_dev || 39937c478bd9Sstevel@tonic-gate ST_INODE(st) != ST_INODE(stf) || 39947c478bd9Sstevel@tonic-gate #if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */ 39957c478bd9Sstevel@tonic-gate st.st_gen != stf.st_gen || 39967c478bd9Sstevel@tonic-gate #endif /* HAS_ST_GEN && 0 */ 39977c478bd9Sstevel@tonic-gate st.st_uid != stf.st_uid || 39987c478bd9Sstevel@tonic-gate st.st_gid != stf.st_gid || 39997c478bd9Sstevel@tonic-gate st.st_size != stf.st_size) 40007c478bd9Sstevel@tonic-gate { 40017c478bd9Sstevel@tonic-gate /* changed after opened */ 40027c478bd9Sstevel@tonic-gate if (Verbose) 40037c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 40047c478bd9Sstevel@tonic-gate "%s: changed\n", e->e_id); 40057c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 40067c478bd9Sstevel@tonic-gate sm_dprintf("%s: changed\n", e->e_id); 40077c478bd9Sstevel@tonic-gate if (LogLevel > 19) 40087c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "changed"); 40097c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 40107c478bd9Sstevel@tonic-gate return false; 40117c478bd9Sstevel@tonic-gate } 40127c478bd9Sstevel@tonic-gate 40137c478bd9Sstevel@tonic-gate /* 40147c478bd9Sstevel@tonic-gate ** Check the queue file for plausibility to avoid attacks. 40157c478bd9Sstevel@tonic-gate */ 40167c478bd9Sstevel@tonic-gate 40177c478bd9Sstevel@tonic-gate qsafe = S_IWOTH|S_IWGRP; 40187c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 40197c478bd9Sstevel@tonic-gate qsafe &= ~S_IWGRP; 40207c478bd9Sstevel@tonic-gate 40217c478bd9Sstevel@tonic-gate bogus = st.st_uid != geteuid() && 40227c478bd9Sstevel@tonic-gate st.st_uid != TrustedUid && 40237c478bd9Sstevel@tonic-gate geteuid() != RealUid; 40247c478bd9Sstevel@tonic-gate 40257c478bd9Sstevel@tonic-gate /* 40267c478bd9Sstevel@tonic-gate ** If this qf file results from a set-group-ID binary, then 40277c478bd9Sstevel@tonic-gate ** we check whether the directory is group-writable, 40287c478bd9Sstevel@tonic-gate ** the queue file mode contains the group-writable bit, and 40297c478bd9Sstevel@tonic-gate ** the groups are the same. 40307c478bd9Sstevel@tonic-gate ** Notice: this requires that the set-group-ID binary is used to 40317c478bd9Sstevel@tonic-gate ** run the queue! 40327c478bd9Sstevel@tonic-gate */ 40337c478bd9Sstevel@tonic-gate 40347c478bd9Sstevel@tonic-gate if (bogus && st.st_gid == getegid() && UseMSP) 40357c478bd9Sstevel@tonic-gate { 40367c478bd9Sstevel@tonic-gate char delim; 40377c478bd9Sstevel@tonic-gate struct stat dst; 40387c478bd9Sstevel@tonic-gate 40397c478bd9Sstevel@tonic-gate bp = SM_LAST_DIR_DELIM(qf); 40407c478bd9Sstevel@tonic-gate if (bp == NULL) 40417c478bd9Sstevel@tonic-gate delim = '\0'; 40427c478bd9Sstevel@tonic-gate else 40437c478bd9Sstevel@tonic-gate { 40447c478bd9Sstevel@tonic-gate delim = *bp; 40457c478bd9Sstevel@tonic-gate *bp = '\0'; 40467c478bd9Sstevel@tonic-gate } 40477c478bd9Sstevel@tonic-gate if (stat(delim == '\0' ? "." : qf, &dst) < 0) 40487c478bd9Sstevel@tonic-gate syserr("readqf: cannot stat directory %s", 40497c478bd9Sstevel@tonic-gate delim == '\0' ? "." : qf); 40507c478bd9Sstevel@tonic-gate else 40517c478bd9Sstevel@tonic-gate { 40527c478bd9Sstevel@tonic-gate bogus = !(bitset(S_IWGRP, QueueFileMode) && 40537c478bd9Sstevel@tonic-gate bitset(S_IWGRP, dst.st_mode) && 40547c478bd9Sstevel@tonic-gate dst.st_gid == st.st_gid); 40557c478bd9Sstevel@tonic-gate } 40567c478bd9Sstevel@tonic-gate if (delim != '\0') 40577c478bd9Sstevel@tonic-gate *bp = delim; 40583ee0e492Sjbeck bp = NULL; 40597c478bd9Sstevel@tonic-gate } 40607c478bd9Sstevel@tonic-gate if (!bogus) 40617c478bd9Sstevel@tonic-gate bogus = bitset(qsafe, st.st_mode); 40627c478bd9Sstevel@tonic-gate if (bogus) 40637c478bd9Sstevel@tonic-gate { 40647c478bd9Sstevel@tonic-gate if (LogLevel > 0) 40657c478bd9Sstevel@tonic-gate { 40667c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 40677c478bd9Sstevel@tonic-gate "bogus queue file, uid=%d, gid=%d, mode=%o", 40687c478bd9Sstevel@tonic-gate st.st_uid, st.st_gid, st.st_mode); 40697c478bd9Sstevel@tonic-gate } 40707c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 40717c478bd9Sstevel@tonic-gate sm_dprintf("readqf(%s): bogus file\n", qf); 40727c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE; 40737c478bd9Sstevel@tonic-gate if (!openonly) 40747c478bd9Sstevel@tonic-gate loseqfile(e, "bogus file uid/gid in mqueue"); 40757c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 40767c478bd9Sstevel@tonic-gate return false; 40777c478bd9Sstevel@tonic-gate } 40787c478bd9Sstevel@tonic-gate 40797c478bd9Sstevel@tonic-gate if (st.st_size == 0) 40807c478bd9Sstevel@tonic-gate { 40817c478bd9Sstevel@tonic-gate /* must be a bogus file -- if also old, just remove it */ 40827c478bd9Sstevel@tonic-gate if (!openonly && st.st_ctime + 10 * 60 < curtime()) 40837c478bd9Sstevel@tonic-gate { 40847c478bd9Sstevel@tonic-gate (void) xunlink(queuename(e, DATAFL_LETTER)); 40857c478bd9Sstevel@tonic-gate (void) xunlink(queuename(e, ANYQFL_LETTER)); 40867c478bd9Sstevel@tonic-gate } 40877c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 40887c478bd9Sstevel@tonic-gate return false; 40897c478bd9Sstevel@tonic-gate } 40907c478bd9Sstevel@tonic-gate 40917c478bd9Sstevel@tonic-gate if (st.st_nlink == 0) 40927c478bd9Sstevel@tonic-gate { 40937c478bd9Sstevel@tonic-gate /* 40947c478bd9Sstevel@tonic-gate ** Race condition -- we got a file just as it was being 40957c478bd9Sstevel@tonic-gate ** unlinked. Just assume it is zero length. 40967c478bd9Sstevel@tonic-gate */ 40977c478bd9Sstevel@tonic-gate 40987c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 40997c478bd9Sstevel@tonic-gate return false; 41007c478bd9Sstevel@tonic-gate } 41017c478bd9Sstevel@tonic-gate 41027c478bd9Sstevel@tonic-gate #if _FFR_TRUSTED_QF 41037c478bd9Sstevel@tonic-gate /* 41047c478bd9Sstevel@tonic-gate ** If we don't own the file mark it as unsafe. 41057c478bd9Sstevel@tonic-gate ** However, allow TrustedUser to own it as well 41067c478bd9Sstevel@tonic-gate ** in case TrustedUser manipulates the queue. 41077c478bd9Sstevel@tonic-gate */ 41087c478bd9Sstevel@tonic-gate 41097c478bd9Sstevel@tonic-gate if (st.st_uid != geteuid() && st.st_uid != TrustedUid) 41107c478bd9Sstevel@tonic-gate e->e_flags |= EF_UNSAFE; 41117c478bd9Sstevel@tonic-gate #else /* _FFR_TRUSTED_QF */ 41127c478bd9Sstevel@tonic-gate /* If we don't own the file mark it as unsafe */ 41137c478bd9Sstevel@tonic-gate if (st.st_uid != geteuid()) 41147c478bd9Sstevel@tonic-gate e->e_flags |= EF_UNSAFE; 41157c478bd9Sstevel@tonic-gate #endif /* _FFR_TRUSTED_QF */ 41167c478bd9Sstevel@tonic-gate 41177c478bd9Sstevel@tonic-gate /* good file -- save this lock */ 41187c478bd9Sstevel@tonic-gate e->e_lockfp = qfp; 41197c478bd9Sstevel@tonic-gate 41207c478bd9Sstevel@tonic-gate /* Just wanted the open file */ 41217c478bd9Sstevel@tonic-gate if (openonly) 41227c478bd9Sstevel@tonic-gate return true; 41237c478bd9Sstevel@tonic-gate 41247c478bd9Sstevel@tonic-gate /* do basic system initialization */ 41257c478bd9Sstevel@tonic-gate initsys(e); 41267c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'i', e->e_id); 41277c478bd9Sstevel@tonic-gate 41287c478bd9Sstevel@tonic-gate LineNumber = 0; 41297c478bd9Sstevel@tonic-gate e->e_flags |= EF_GLOBALERRS; 41307c478bd9Sstevel@tonic-gate set_op_mode(MD_QUEUERUN); 41317c478bd9Sstevel@tonic-gate ctladdr = NULL; 41327c478bd9Sstevel@tonic-gate e->e_qfletter = queue_letter(e, ANYQFL_LETTER); 41337c478bd9Sstevel@tonic-gate e->e_dfqgrp = e->e_qgrp; 41347c478bd9Sstevel@tonic-gate e->e_dfqdir = e->e_qdir; 41357c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_MACRO 41367c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{queue}"), 41377c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir)); 41387c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_MACRO */ 41397c478bd9Sstevel@tonic-gate e->e_dfino = -1; 41407c478bd9Sstevel@tonic-gate e->e_msgsize = -1; 4141058561cbSjbeck while (bufsize = sizeof(buf), 4142058561cbSjbeck (bp = fgetfolded(buf, &bufsize, qfp)) != NULL) 41437c478bd9Sstevel@tonic-gate { 41447c478bd9Sstevel@tonic-gate unsigned long qflags; 41457c478bd9Sstevel@tonic-gate ADDRESS *q; 41467c478bd9Sstevel@tonic-gate int r; 41477c478bd9Sstevel@tonic-gate time_t now; 41487c478bd9Sstevel@tonic-gate auto char *ep; 41497c478bd9Sstevel@tonic-gate 41507c478bd9Sstevel@tonic-gate if (tTd(40, 4)) 41517c478bd9Sstevel@tonic-gate sm_dprintf("+++++ %s\n", bp); 41527c478bd9Sstevel@tonic-gate if (nomore) 41537c478bd9Sstevel@tonic-gate { 41547c478bd9Sstevel@tonic-gate /* hack attack */ 41557c478bd9Sstevel@tonic-gate hackattack: 41567c478bd9Sstevel@tonic-gate syserr("SECURITY ALERT: extra or bogus data in queue file: %s", 41577c478bd9Sstevel@tonic-gate bp); 41587c478bd9Sstevel@tonic-gate err = "bogus queue line"; 41597c478bd9Sstevel@tonic-gate goto fail; 41607c478bd9Sstevel@tonic-gate } 41617c478bd9Sstevel@tonic-gate switch (bp[0]) 41627c478bd9Sstevel@tonic-gate { 41637c478bd9Sstevel@tonic-gate case 'A': /* AUTH= parameter */ 41647c478bd9Sstevel@tonic-gate if (!xtextok(&bp[1])) 41657c478bd9Sstevel@tonic-gate goto hackattack; 41667c478bd9Sstevel@tonic-gate e->e_auth_param = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 41677c478bd9Sstevel@tonic-gate break; 41687c478bd9Sstevel@tonic-gate 41697c478bd9Sstevel@tonic-gate case 'B': /* body type */ 41707c478bd9Sstevel@tonic-gate r = check_bodytype(&bp[1]); 41717c478bd9Sstevel@tonic-gate if (!BODYTYPE_VALID(r)) 41727c478bd9Sstevel@tonic-gate goto hackattack; 41737c478bd9Sstevel@tonic-gate e->e_bodytype = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 41747c478bd9Sstevel@tonic-gate break; 41757c478bd9Sstevel@tonic-gate 41767c478bd9Sstevel@tonic-gate case 'C': /* specify controlling user */ 41777c478bd9Sstevel@tonic-gate ctladdr = setctluser(&bp[1], qfver, e); 41787c478bd9Sstevel@tonic-gate break; 41797c478bd9Sstevel@tonic-gate 41807c478bd9Sstevel@tonic-gate case 'D': /* data file name */ 41817c478bd9Sstevel@tonic-gate /* obsolete -- ignore */ 41827c478bd9Sstevel@tonic-gate break; 41837c478bd9Sstevel@tonic-gate 41847c478bd9Sstevel@tonic-gate case 'd': /* data file directory name */ 41857c478bd9Sstevel@tonic-gate { 41867c478bd9Sstevel@tonic-gate int qgrp, qdir; 41877c478bd9Sstevel@tonic-gate 41887c478bd9Sstevel@tonic-gate #if _FFR_MSP_PARANOIA 41897c478bd9Sstevel@tonic-gate /* forbid queue groups in MSP? */ 41907c478bd9Sstevel@tonic-gate if (UseMSP) 41917c478bd9Sstevel@tonic-gate goto hackattack; 41927c478bd9Sstevel@tonic-gate #endif /* _FFR_MSP_PARANOIA */ 41937c478bd9Sstevel@tonic-gate for (qgrp = 0; 41947c478bd9Sstevel@tonic-gate qgrp < NumQueue && Queue[qgrp] != NULL; 41957c478bd9Sstevel@tonic-gate ++qgrp) 41967c478bd9Sstevel@tonic-gate { 41977c478bd9Sstevel@tonic-gate for (qdir = 0; 41987c478bd9Sstevel@tonic-gate qdir < Queue[qgrp]->qg_numqueues; 41997c478bd9Sstevel@tonic-gate ++qdir) 42007c478bd9Sstevel@tonic-gate { 42017c478bd9Sstevel@tonic-gate if (strcmp(&bp[1], 42027c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name) 42037c478bd9Sstevel@tonic-gate == 0) 42047c478bd9Sstevel@tonic-gate { 42057c478bd9Sstevel@tonic-gate e->e_dfqgrp = qgrp; 42067c478bd9Sstevel@tonic-gate e->e_dfqdir = qdir; 42077c478bd9Sstevel@tonic-gate goto done; 42087c478bd9Sstevel@tonic-gate } 42097c478bd9Sstevel@tonic-gate } 42107c478bd9Sstevel@tonic-gate } 42117c478bd9Sstevel@tonic-gate err = "bogus queue file directory"; 42127c478bd9Sstevel@tonic-gate goto fail; 42137c478bd9Sstevel@tonic-gate done: 42147c478bd9Sstevel@tonic-gate break; 42157c478bd9Sstevel@tonic-gate } 42167c478bd9Sstevel@tonic-gate 42177c478bd9Sstevel@tonic-gate case 'E': /* specify error recipient */ 42187c478bd9Sstevel@tonic-gate /* no longer used */ 42197c478bd9Sstevel@tonic-gate break; 42207c478bd9Sstevel@tonic-gate 42217c478bd9Sstevel@tonic-gate case 'F': /* flag bits */ 42227c478bd9Sstevel@tonic-gate if (strncmp(bp, "From ", 5) == 0) 42237c478bd9Sstevel@tonic-gate { 42247c478bd9Sstevel@tonic-gate /* we are being spoofed! */ 42257c478bd9Sstevel@tonic-gate syserr("SECURITY ALERT: bogus qf line %s", bp); 42267c478bd9Sstevel@tonic-gate err = "bogus queue line"; 42277c478bd9Sstevel@tonic-gate goto fail; 42287c478bd9Sstevel@tonic-gate } 42297c478bd9Sstevel@tonic-gate for (p = &bp[1]; *p != '\0'; p++) 42307c478bd9Sstevel@tonic-gate { 42317c478bd9Sstevel@tonic-gate switch (*p) 42327c478bd9Sstevel@tonic-gate { 42337c478bd9Sstevel@tonic-gate case '8': /* has 8 bit data */ 42347c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS8BIT; 42357c478bd9Sstevel@tonic-gate break; 42367c478bd9Sstevel@tonic-gate 42377c478bd9Sstevel@tonic-gate case 'b': /* delete Bcc: header */ 42387c478bd9Sstevel@tonic-gate e->e_flags |= EF_DELETE_BCC; 42397c478bd9Sstevel@tonic-gate break; 42407c478bd9Sstevel@tonic-gate 42417c478bd9Sstevel@tonic-gate case 'd': /* envelope has DSN RET= */ 42427c478bd9Sstevel@tonic-gate e->e_flags |= EF_RET_PARAM; 42437c478bd9Sstevel@tonic-gate break; 42447c478bd9Sstevel@tonic-gate 42457c478bd9Sstevel@tonic-gate case 'n': /* don't return body */ 42467c478bd9Sstevel@tonic-gate e->e_flags |= EF_NO_BODY_RETN; 42477c478bd9Sstevel@tonic-gate break; 42487c478bd9Sstevel@tonic-gate 42497c478bd9Sstevel@tonic-gate case 'r': /* response */ 42507c478bd9Sstevel@tonic-gate e->e_flags |= EF_RESPONSE; 42517c478bd9Sstevel@tonic-gate break; 42527c478bd9Sstevel@tonic-gate 42537c478bd9Sstevel@tonic-gate case 's': /* split */ 42547c478bd9Sstevel@tonic-gate e->e_flags |= EF_SPLIT; 42557c478bd9Sstevel@tonic-gate break; 42567c478bd9Sstevel@tonic-gate 42577c478bd9Sstevel@tonic-gate case 'w': /* warning sent */ 42587c478bd9Sstevel@tonic-gate e->e_flags |= EF_WARNING; 42597c478bd9Sstevel@tonic-gate break; 42607c478bd9Sstevel@tonic-gate } 42617c478bd9Sstevel@tonic-gate } 42627c478bd9Sstevel@tonic-gate break; 42637c478bd9Sstevel@tonic-gate 42647c478bd9Sstevel@tonic-gate case 'q': /* quarantine reason */ 42657c478bd9Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 42667c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 42677c478bd9Sstevel@tonic-gate macid("{quarantine}"), e->e_quarmsg); 42687c478bd9Sstevel@tonic-gate break; 42697c478bd9Sstevel@tonic-gate 42707c478bd9Sstevel@tonic-gate case 'H': /* header */ 42717c478bd9Sstevel@tonic-gate 42727c478bd9Sstevel@tonic-gate /* 42737c478bd9Sstevel@tonic-gate ** count size before chompheader() destroys the line. 42747c478bd9Sstevel@tonic-gate ** this isn't accurate due to macro expansion, but 42757c478bd9Sstevel@tonic-gate ** better than before. "-3" to skip H?? at least. 42767c478bd9Sstevel@tonic-gate */ 42777c478bd9Sstevel@tonic-gate 42787c478bd9Sstevel@tonic-gate hdrsize += strlen(bp) - 3; 42797c478bd9Sstevel@tonic-gate (void) chompheader(&bp[1], CHHDR_QUEUE, NULL, e); 42807c478bd9Sstevel@tonic-gate break; 42817c478bd9Sstevel@tonic-gate 42827c478bd9Sstevel@tonic-gate case 'I': /* data file's inode number */ 42837c478bd9Sstevel@tonic-gate /* regenerated below */ 42847c478bd9Sstevel@tonic-gate break; 42857c478bd9Sstevel@tonic-gate 42867c478bd9Sstevel@tonic-gate case 'K': /* time of last delivery attempt */ 42877c478bd9Sstevel@tonic-gate e->e_dtime = atol(&buf[1]); 42887c478bd9Sstevel@tonic-gate break; 42897c478bd9Sstevel@tonic-gate 42907c478bd9Sstevel@tonic-gate case 'L': /* Solaris Content-Length: */ 42917c478bd9Sstevel@tonic-gate case 'M': /* message */ 42927c478bd9Sstevel@tonic-gate /* ignore this; we want a new message next time */ 42937c478bd9Sstevel@tonic-gate break; 42947c478bd9Sstevel@tonic-gate 42957c478bd9Sstevel@tonic-gate case 'N': /* number of delivery attempts */ 42967c478bd9Sstevel@tonic-gate e->e_ntries = atoi(&buf[1]); 42977c478bd9Sstevel@tonic-gate 42987c478bd9Sstevel@tonic-gate /* if this has been tried recently, let it be */ 42997c478bd9Sstevel@tonic-gate now = curtime(); 43007c478bd9Sstevel@tonic-gate if (e->e_ntries > 0 && e->e_dtime <= now && 43017c478bd9Sstevel@tonic-gate now < e->e_dtime + MinQueueAge) 43027c478bd9Sstevel@tonic-gate { 43037c478bd9Sstevel@tonic-gate char *howlong; 43047c478bd9Sstevel@tonic-gate 43057c478bd9Sstevel@tonic-gate howlong = pintvl(now - e->e_dtime, true); 43067c478bd9Sstevel@tonic-gate if (Verbose) 43077c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 43087c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 43097c478bd9Sstevel@tonic-gate "%s: too young (%s)\n", 43107c478bd9Sstevel@tonic-gate e->e_id, howlong); 43117c478bd9Sstevel@tonic-gate if (tTd(40, 8)) 43127c478bd9Sstevel@tonic-gate sm_dprintf("%s: too young (%s)\n", 43137c478bd9Sstevel@tonic-gate e->e_id, howlong); 43147c478bd9Sstevel@tonic-gate if (LogLevel > 19) 43157c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, 43167c478bd9Sstevel@tonic-gate "too young (%s)", 43177c478bd9Sstevel@tonic-gate howlong); 43187c478bd9Sstevel@tonic-gate e->e_id = NULL; 43197c478bd9Sstevel@tonic-gate unlockqueue(e); 4320058561cbSjbeck if (bp != buf) 4321058561cbSjbeck sm_free(bp); 43227c478bd9Sstevel@tonic-gate return false; 43237c478bd9Sstevel@tonic-gate } 43247c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, 43257c478bd9Sstevel@tonic-gate macid("{ntries}"), &buf[1]); 43267c478bd9Sstevel@tonic-gate 43277c478bd9Sstevel@tonic-gate #if NAMED_BIND 43287c478bd9Sstevel@tonic-gate /* adjust BIND parameters immediately */ 43297c478bd9Sstevel@tonic-gate if (e->e_ntries == 0) 43307c478bd9Sstevel@tonic-gate { 43317c478bd9Sstevel@tonic-gate _res.retry = TimeOuts.res_retry[RES_TO_FIRST]; 43327c478bd9Sstevel@tonic-gate _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; 43337c478bd9Sstevel@tonic-gate } 43347c478bd9Sstevel@tonic-gate else 43357c478bd9Sstevel@tonic-gate { 43367c478bd9Sstevel@tonic-gate _res.retry = TimeOuts.res_retry[RES_TO_NORMAL]; 43377c478bd9Sstevel@tonic-gate _res.retrans = TimeOuts.res_retrans[RES_TO_NORMAL]; 43387c478bd9Sstevel@tonic-gate } 43397c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 43407c478bd9Sstevel@tonic-gate break; 43417c478bd9Sstevel@tonic-gate 43427c478bd9Sstevel@tonic-gate case 'P': /* message priority */ 43437c478bd9Sstevel@tonic-gate e->e_msgpriority = atol(&bp[1]) + WkTimeFact; 43447c478bd9Sstevel@tonic-gate break; 43457c478bd9Sstevel@tonic-gate 43467c478bd9Sstevel@tonic-gate case 'Q': /* original recipient */ 43477c478bd9Sstevel@tonic-gate orcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 43487c478bd9Sstevel@tonic-gate break; 43497c478bd9Sstevel@tonic-gate 43507c478bd9Sstevel@tonic-gate case 'r': /* final recipient */ 43517c478bd9Sstevel@tonic-gate frcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 43527c478bd9Sstevel@tonic-gate break; 43537c478bd9Sstevel@tonic-gate 43547c478bd9Sstevel@tonic-gate case 'R': /* specify recipient */ 43557c478bd9Sstevel@tonic-gate p = bp; 43567c478bd9Sstevel@tonic-gate qflags = 0; 43577c478bd9Sstevel@tonic-gate if (qfver >= 1) 43587c478bd9Sstevel@tonic-gate { 43597c478bd9Sstevel@tonic-gate /* get flag bits */ 43607c478bd9Sstevel@tonic-gate while (*++p != '\0' && *p != ':') 43617c478bd9Sstevel@tonic-gate { 43627c478bd9Sstevel@tonic-gate switch (*p) 43637c478bd9Sstevel@tonic-gate { 43647c478bd9Sstevel@tonic-gate case 'N': 43657c478bd9Sstevel@tonic-gate qflags |= QHASNOTIFY; 43667c478bd9Sstevel@tonic-gate break; 43677c478bd9Sstevel@tonic-gate 43687c478bd9Sstevel@tonic-gate case 'S': 43697c478bd9Sstevel@tonic-gate qflags |= QPINGONSUCCESS; 43707c478bd9Sstevel@tonic-gate break; 43717c478bd9Sstevel@tonic-gate 43727c478bd9Sstevel@tonic-gate case 'F': 43737c478bd9Sstevel@tonic-gate qflags |= QPINGONFAILURE; 43747c478bd9Sstevel@tonic-gate break; 43757c478bd9Sstevel@tonic-gate 43767c478bd9Sstevel@tonic-gate case 'D': 43777c478bd9Sstevel@tonic-gate qflags |= QPINGONDELAY; 43787c478bd9Sstevel@tonic-gate break; 43797c478bd9Sstevel@tonic-gate 43807c478bd9Sstevel@tonic-gate case 'P': 43817c478bd9Sstevel@tonic-gate qflags |= QPRIMARY; 43827c478bd9Sstevel@tonic-gate break; 43837c478bd9Sstevel@tonic-gate 43847c478bd9Sstevel@tonic-gate case 'A': 43857c478bd9Sstevel@tonic-gate if (ctladdr != NULL) 43867c478bd9Sstevel@tonic-gate ctladdr->q_flags |= QALIAS; 43877c478bd9Sstevel@tonic-gate break; 43887c478bd9Sstevel@tonic-gate 43897c478bd9Sstevel@tonic-gate default: /* ignore or complain? */ 43907c478bd9Sstevel@tonic-gate break; 43917c478bd9Sstevel@tonic-gate } 43927c478bd9Sstevel@tonic-gate } 43937c478bd9Sstevel@tonic-gate } 43947c478bd9Sstevel@tonic-gate else 43957c478bd9Sstevel@tonic-gate qflags |= QPRIMARY; 43967c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), 43977c478bd9Sstevel@tonic-gate "e r"); 43987c478bd9Sstevel@tonic-gate if (*p != '\0') 43997c478bd9Sstevel@tonic-gate q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', 44007c478bd9Sstevel@tonic-gate NULL, e, true); 44017c478bd9Sstevel@tonic-gate else 44027c478bd9Sstevel@tonic-gate q = NULL; 44037c478bd9Sstevel@tonic-gate if (q != NULL) 44047c478bd9Sstevel@tonic-gate { 44057c478bd9Sstevel@tonic-gate /* make sure we keep the current qgrp */ 44067c478bd9Sstevel@tonic-gate if (ISVALIDQGRP(e->e_qgrp)) 44077c478bd9Sstevel@tonic-gate q->q_qgrp = e->e_qgrp; 44087c478bd9Sstevel@tonic-gate q->q_alias = ctladdr; 44097c478bd9Sstevel@tonic-gate if (qfver >= 1) 44107c478bd9Sstevel@tonic-gate q->q_flags &= ~Q_PINGFLAGS; 44117c478bd9Sstevel@tonic-gate q->q_flags |= qflags; 44127c478bd9Sstevel@tonic-gate q->q_finalrcpt = frcpt; 44137c478bd9Sstevel@tonic-gate q->q_orcpt = orcpt; 44147c478bd9Sstevel@tonic-gate (void) recipient(q, &e->e_sendqueue, 0, e); 44157c478bd9Sstevel@tonic-gate } 44167c478bd9Sstevel@tonic-gate frcpt = NULL; 44177c478bd9Sstevel@tonic-gate orcpt = NULL; 44187c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), 44197c478bd9Sstevel@tonic-gate NULL); 44207c478bd9Sstevel@tonic-gate break; 44217c478bd9Sstevel@tonic-gate 44227c478bd9Sstevel@tonic-gate case 'S': /* sender */ 44237c478bd9Sstevel@tonic-gate setsender(sm_rpool_strdup_x(e->e_rpool, &bp[1]), 44247c478bd9Sstevel@tonic-gate e, NULL, '\0', true); 44257c478bd9Sstevel@tonic-gate break; 44267c478bd9Sstevel@tonic-gate 44277c478bd9Sstevel@tonic-gate case 'T': /* init time */ 44287c478bd9Sstevel@tonic-gate e->e_ctime = atol(&bp[1]); 44297c478bd9Sstevel@tonic-gate break; 44307c478bd9Sstevel@tonic-gate 44317c478bd9Sstevel@tonic-gate case 'V': /* queue file version number */ 44327c478bd9Sstevel@tonic-gate qfver = atoi(&bp[1]); 44337c478bd9Sstevel@tonic-gate if (qfver <= QF_VERSION) 44347c478bd9Sstevel@tonic-gate break; 44357c478bd9Sstevel@tonic-gate syserr("Version number in queue file (%d) greater than max (%d)", 44367c478bd9Sstevel@tonic-gate qfver, QF_VERSION); 44377c478bd9Sstevel@tonic-gate err = "unsupported queue file version"; 44387c478bd9Sstevel@tonic-gate goto fail; 44397c478bd9Sstevel@tonic-gate /* NOTREACHED */ 44407c478bd9Sstevel@tonic-gate break; 44417c478bd9Sstevel@tonic-gate 44427c478bd9Sstevel@tonic-gate case 'Z': /* original envelope id from ESMTP */ 44437c478bd9Sstevel@tonic-gate e->e_envid = sm_rpool_strdup_x(e->e_rpool, &bp[1]); 44447c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 44457c478bd9Sstevel@tonic-gate macid("{dsn_envid}"), e->e_envid); 44467c478bd9Sstevel@tonic-gate break; 44477c478bd9Sstevel@tonic-gate 44487c478bd9Sstevel@tonic-gate case '!': /* deliver by */ 44497c478bd9Sstevel@tonic-gate 44507c478bd9Sstevel@tonic-gate /* format: flag (1 char) space long-integer */ 44517c478bd9Sstevel@tonic-gate e->e_dlvr_flag = buf[1]; 44527c478bd9Sstevel@tonic-gate e->e_deliver_by = strtol(&buf[3], NULL, 10); 44537c478bd9Sstevel@tonic-gate 44547c478bd9Sstevel@tonic-gate case '$': /* define macro */ 44557c478bd9Sstevel@tonic-gate { 44567c478bd9Sstevel@tonic-gate char *p; 44577c478bd9Sstevel@tonic-gate 44587c478bd9Sstevel@tonic-gate /* XXX elimate p? */ 44597c478bd9Sstevel@tonic-gate r = macid_parse(&bp[1], &ep); 44607c478bd9Sstevel@tonic-gate if (r == 0) 44617c478bd9Sstevel@tonic-gate break; 44627c478bd9Sstevel@tonic-gate p = sm_rpool_strdup_x(e->e_rpool, ep); 44637c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, r, p); 44647c478bd9Sstevel@tonic-gate } 44657c478bd9Sstevel@tonic-gate break; 44667c478bd9Sstevel@tonic-gate 44677c478bd9Sstevel@tonic-gate case '.': /* terminate file */ 44687c478bd9Sstevel@tonic-gate nomore = true; 44697c478bd9Sstevel@tonic-gate break; 44707c478bd9Sstevel@tonic-gate 44717c478bd9Sstevel@tonic-gate #if _FFR_QUEUEDELAY 44727c478bd9Sstevel@tonic-gate case 'G': 44737c478bd9Sstevel@tonic-gate case 'Y': 44747c478bd9Sstevel@tonic-gate 44757c478bd9Sstevel@tonic-gate /* 44767c478bd9Sstevel@tonic-gate ** Maintain backward compatibility for 44777c478bd9Sstevel@tonic-gate ** users who defined _FFR_QUEUEDELAY in 44787c478bd9Sstevel@tonic-gate ** previous releases. Remove this 44797c478bd9Sstevel@tonic-gate ** code in 8.14 or 8.15. 44807c478bd9Sstevel@tonic-gate */ 44817c478bd9Sstevel@tonic-gate 44827c478bd9Sstevel@tonic-gate if (qfver == 5 || qfver == 7) 44837c478bd9Sstevel@tonic-gate break; 44847c478bd9Sstevel@tonic-gate 44857c478bd9Sstevel@tonic-gate /* If not qfver 5 or 7, then 'G' or 'Y' is invalid */ 44867c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 44877c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUEDELAY */ 44887c478bd9Sstevel@tonic-gate 44897c478bd9Sstevel@tonic-gate default: 44907c478bd9Sstevel@tonic-gate syserr("readqf: %s: line %d: bad line \"%s\"", 44917c478bd9Sstevel@tonic-gate qf, LineNumber, shortenstring(bp, MAXSHORTSTR)); 44927c478bd9Sstevel@tonic-gate err = "unrecognized line"; 44937c478bd9Sstevel@tonic-gate goto fail; 44947c478bd9Sstevel@tonic-gate } 44957c478bd9Sstevel@tonic-gate 44967c478bd9Sstevel@tonic-gate if (bp != buf) 4497058561cbSjbeck SM_FREE(bp); 44987c478bd9Sstevel@tonic-gate } 44997c478bd9Sstevel@tonic-gate 45007c478bd9Sstevel@tonic-gate /* 45017c478bd9Sstevel@tonic-gate ** If we haven't read any lines, this queue file is empty. 45027c478bd9Sstevel@tonic-gate ** Arrange to remove it without referencing any null pointers. 45037c478bd9Sstevel@tonic-gate */ 45047c478bd9Sstevel@tonic-gate 45057c478bd9Sstevel@tonic-gate if (LineNumber == 0) 45067c478bd9Sstevel@tonic-gate { 45077c478bd9Sstevel@tonic-gate errno = 0; 45087c478bd9Sstevel@tonic-gate e->e_flags |= EF_CLRQUEUE|EF_FATALERRS|EF_RESPONSE; 45097c478bd9Sstevel@tonic-gate return true; 45107c478bd9Sstevel@tonic-gate } 45117c478bd9Sstevel@tonic-gate 45127c478bd9Sstevel@tonic-gate /* Check to make sure we have a complete queue file read */ 45137c478bd9Sstevel@tonic-gate if (!nomore) 45147c478bd9Sstevel@tonic-gate { 45157c478bd9Sstevel@tonic-gate syserr("readqf: %s: incomplete queue file read", qf); 45167c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 45177c478bd9Sstevel@tonic-gate return false; 45187c478bd9Sstevel@tonic-gate } 45194aac33d3Sjbeck 45204aac33d3Sjbeck #if _FFR_QF_PARANOIA 45214aac33d3Sjbeck /* Check to make sure key fields were read */ 45224aac33d3Sjbeck if (e->e_from.q_mailer == NULL) 45234aac33d3Sjbeck { 45244aac33d3Sjbeck syserr("readqf: %s: sender not specified in queue file", qf); 45254aac33d3Sjbeck (void) sm_io_close(qfp, SM_TIME_DEFAULT); 45264aac33d3Sjbeck return false; 45274aac33d3Sjbeck } 45284aac33d3Sjbeck /* other checks? */ 45294aac33d3Sjbeck #endif /* _FFR_QF_PARANOIA */ 45307c478bd9Sstevel@tonic-gate 45317c478bd9Sstevel@tonic-gate /* possibly set ${dsn_ret} macro */ 45327c478bd9Sstevel@tonic-gate if (bitset(EF_RET_PARAM, e->e_flags)) 45337c478bd9Sstevel@tonic-gate { 45347c478bd9Sstevel@tonic-gate if (bitset(EF_NO_BODY_RETN, e->e_flags)) 45357c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 45367c478bd9Sstevel@tonic-gate macid("{dsn_ret}"), "hdrs"); 45377c478bd9Sstevel@tonic-gate else 45387c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 45397c478bd9Sstevel@tonic-gate macid("{dsn_ret}"), "full"); 45407c478bd9Sstevel@tonic-gate } 45417c478bd9Sstevel@tonic-gate 45427c478bd9Sstevel@tonic-gate /* 45437c478bd9Sstevel@tonic-gate ** Arrange to read the data file. 45447c478bd9Sstevel@tonic-gate */ 45457c478bd9Sstevel@tonic-gate 45467c478bd9Sstevel@tonic-gate p = queuename(e, DATAFL_LETTER); 45477c478bd9Sstevel@tonic-gate e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, p, SM_IO_RDONLY_B, 45487c478bd9Sstevel@tonic-gate NULL); 45497c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL) 45507c478bd9Sstevel@tonic-gate { 45517c478bd9Sstevel@tonic-gate syserr("readqf: cannot open %s", p); 45527c478bd9Sstevel@tonic-gate } 45537c478bd9Sstevel@tonic-gate else 45547c478bd9Sstevel@tonic-gate { 45557c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS_DF; 45567c478bd9Sstevel@tonic-gate if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &st) 45577c478bd9Sstevel@tonic-gate >= 0) 45587c478bd9Sstevel@tonic-gate { 45597c478bd9Sstevel@tonic-gate e->e_msgsize = st.st_size + hdrsize; 45607c478bd9Sstevel@tonic-gate e->e_dfdev = st.st_dev; 45617c478bd9Sstevel@tonic-gate e->e_dfino = ST_INODE(st); 4562058561cbSjbeck (void) sm_snprintf(buf, sizeof(buf), "%ld", 45637c478bd9Sstevel@tonic-gate e->e_msgsize); 45647c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), 45657c478bd9Sstevel@tonic-gate buf); 45667c478bd9Sstevel@tonic-gate } 45677c478bd9Sstevel@tonic-gate } 45687c478bd9Sstevel@tonic-gate 45697c478bd9Sstevel@tonic-gate return true; 45707c478bd9Sstevel@tonic-gate 45717c478bd9Sstevel@tonic-gate fail: 45727c478bd9Sstevel@tonic-gate /* 45737c478bd9Sstevel@tonic-gate ** There was some error reading the qf file (reason is in err var.) 45747c478bd9Sstevel@tonic-gate ** Cleanup: 45757c478bd9Sstevel@tonic-gate ** close file; clear e_lockfp since it is the same as qfp, 45767c478bd9Sstevel@tonic-gate ** hence it is invalid (as file) after qfp is closed; 45777c478bd9Sstevel@tonic-gate ** the qf file is on disk, so set the flag to avoid calling 45787c478bd9Sstevel@tonic-gate ** queueup() with bogus data. 45797c478bd9Sstevel@tonic-gate */ 45807c478bd9Sstevel@tonic-gate 4581058561cbSjbeck if (bp != buf) 4582058561cbSjbeck SM_FREE(bp); 45837c478bd9Sstevel@tonic-gate if (qfp != NULL) 45847c478bd9Sstevel@tonic-gate (void) sm_io_close(qfp, SM_TIME_DEFAULT); 45857c478bd9Sstevel@tonic-gate e->e_lockfp = NULL; 45867c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE; 45877c478bd9Sstevel@tonic-gate loseqfile(e, err); 45887c478bd9Sstevel@tonic-gate return false; 45897c478bd9Sstevel@tonic-gate } 45907c478bd9Sstevel@tonic-gate /* 45917c478bd9Sstevel@tonic-gate ** PRTSTR -- print a string, "unprintable" characters are shown as \oct 45927c478bd9Sstevel@tonic-gate ** 45937c478bd9Sstevel@tonic-gate ** Parameters: 45947c478bd9Sstevel@tonic-gate ** s -- string to print 45957c478bd9Sstevel@tonic-gate ** ml -- maximum length of output 45967c478bd9Sstevel@tonic-gate ** 45977c478bd9Sstevel@tonic-gate ** Returns: 45987c478bd9Sstevel@tonic-gate ** number of entries 45997c478bd9Sstevel@tonic-gate ** 46007c478bd9Sstevel@tonic-gate ** Side Effects: 46017c478bd9Sstevel@tonic-gate ** Prints a string on stdout. 46027c478bd9Sstevel@tonic-gate */ 46037c478bd9Sstevel@tonic-gate 4604058561cbSjbeck static void prtstr __P((char *, int)); 4605058561cbSjbeck 46067c478bd9Sstevel@tonic-gate static void 46077c478bd9Sstevel@tonic-gate prtstr(s, ml) 46087c478bd9Sstevel@tonic-gate char *s; 46097c478bd9Sstevel@tonic-gate int ml; 46107c478bd9Sstevel@tonic-gate { 46117c478bd9Sstevel@tonic-gate int c; 46127c478bd9Sstevel@tonic-gate 46137c478bd9Sstevel@tonic-gate if (s == NULL) 46147c478bd9Sstevel@tonic-gate return; 46157c478bd9Sstevel@tonic-gate while (ml-- > 0 && ((c = *s++) != '\0')) 46167c478bd9Sstevel@tonic-gate { 46177c478bd9Sstevel@tonic-gate if (c == '\\') 46187c478bd9Sstevel@tonic-gate { 46197c478bd9Sstevel@tonic-gate if (ml-- > 0) 46207c478bd9Sstevel@tonic-gate { 46217c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c); 46227c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c); 46237c478bd9Sstevel@tonic-gate } 46247c478bd9Sstevel@tonic-gate } 46257c478bd9Sstevel@tonic-gate else if (isascii(c) && isprint(c)) 46267c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c); 46277c478bd9Sstevel@tonic-gate else 46287c478bd9Sstevel@tonic-gate { 46297c478bd9Sstevel@tonic-gate if ((ml -= 3) > 0) 46307c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 46317c478bd9Sstevel@tonic-gate "\\%03o", c & 0xFF); 46327c478bd9Sstevel@tonic-gate } 46337c478bd9Sstevel@tonic-gate } 46347c478bd9Sstevel@tonic-gate } 46357c478bd9Sstevel@tonic-gate /* 46367c478bd9Sstevel@tonic-gate ** PRINTNQE -- print out number of entries in the mail queue 46377c478bd9Sstevel@tonic-gate ** 46387c478bd9Sstevel@tonic-gate ** Parameters: 46397c478bd9Sstevel@tonic-gate ** out -- output file pointer. 46407c478bd9Sstevel@tonic-gate ** prefix -- string to output in front of each line. 46417c478bd9Sstevel@tonic-gate ** 46427c478bd9Sstevel@tonic-gate ** Returns: 46437c478bd9Sstevel@tonic-gate ** none. 46447c478bd9Sstevel@tonic-gate */ 46457c478bd9Sstevel@tonic-gate 46467c478bd9Sstevel@tonic-gate void 46477c478bd9Sstevel@tonic-gate printnqe(out, prefix) 46487c478bd9Sstevel@tonic-gate SM_FILE_T *out; 46497c478bd9Sstevel@tonic-gate char *prefix; 46507c478bd9Sstevel@tonic-gate { 46517c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 46527c478bd9Sstevel@tonic-gate int i, k = 0, nrequests = 0; 46537c478bd9Sstevel@tonic-gate bool unknown = false; 46547c478bd9Sstevel@tonic-gate 46557c478bd9Sstevel@tonic-gate if (ShmId == SM_SHM_NO_ID) 46567c478bd9Sstevel@tonic-gate { 46577c478bd9Sstevel@tonic-gate if (prefix == NULL) 46587c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46597c478bd9Sstevel@tonic-gate "Data unavailable: shared memory not updated\n"); 46607c478bd9Sstevel@tonic-gate else 46617c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46627c478bd9Sstevel@tonic-gate "%sNOTCONFIGURED:-1\r\n", prefix); 46637c478bd9Sstevel@tonic-gate return; 46647c478bd9Sstevel@tonic-gate } 46657c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 46667c478bd9Sstevel@tonic-gate { 46677c478bd9Sstevel@tonic-gate int j; 46687c478bd9Sstevel@tonic-gate 46697c478bd9Sstevel@tonic-gate k++; 46707c478bd9Sstevel@tonic-gate for (j = 0; j < Queue[i]->qg_numqueues; j++) 46717c478bd9Sstevel@tonic-gate { 46727c478bd9Sstevel@tonic-gate int n; 46737c478bd9Sstevel@tonic-gate 46747c478bd9Sstevel@tonic-gate if (StopRequest) 46757c478bd9Sstevel@tonic-gate stop_sendmail(); 46767c478bd9Sstevel@tonic-gate 46777c478bd9Sstevel@tonic-gate n = QSHM_ENTRIES(Queue[i]->qg_qpaths[j].qp_idx); 46787c478bd9Sstevel@tonic-gate if (prefix != NULL) 46797c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46807c478bd9Sstevel@tonic-gate "%s%s:%d\r\n", 46817c478bd9Sstevel@tonic-gate prefix, qid_printqueue(i, j), n); 46827c478bd9Sstevel@tonic-gate else if (n < 0) 46837c478bd9Sstevel@tonic-gate { 46847c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46857c478bd9Sstevel@tonic-gate "%s: unknown number of entries\n", 46867c478bd9Sstevel@tonic-gate qid_printqueue(i, j)); 46877c478bd9Sstevel@tonic-gate unknown = true; 46887c478bd9Sstevel@tonic-gate } 46897c478bd9Sstevel@tonic-gate else if (n == 0) 46907c478bd9Sstevel@tonic-gate { 46917c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46927c478bd9Sstevel@tonic-gate "%s is empty\n", 46937c478bd9Sstevel@tonic-gate qid_printqueue(i, j)); 46947c478bd9Sstevel@tonic-gate } 46957c478bd9Sstevel@tonic-gate else if (n > 0) 46967c478bd9Sstevel@tonic-gate { 46977c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 46987c478bd9Sstevel@tonic-gate "%s: entries=%d\n", 46997c478bd9Sstevel@tonic-gate qid_printqueue(i, j), n); 47007c478bd9Sstevel@tonic-gate nrequests += n; 47017c478bd9Sstevel@tonic-gate k++; 47027c478bd9Sstevel@tonic-gate } 47037c478bd9Sstevel@tonic-gate } 47047c478bd9Sstevel@tonic-gate } 47057c478bd9Sstevel@tonic-gate if (prefix == NULL && k > 1) 47067c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 47077c478bd9Sstevel@tonic-gate "\t\tTotal requests: %d%s\n", 47087c478bd9Sstevel@tonic-gate nrequests, unknown ? " (about)" : ""); 47097c478bd9Sstevel@tonic-gate #else /* SM_CONF_SHM */ 47107c478bd9Sstevel@tonic-gate if (prefix == NULL) 47117c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 47127c478bd9Sstevel@tonic-gate "Data unavailable without shared memory support\n"); 47137c478bd9Sstevel@tonic-gate else 47147c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 47157c478bd9Sstevel@tonic-gate "%sNOTAVAILABLE:-1\r\n", prefix); 47167c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 47177c478bd9Sstevel@tonic-gate } 47187c478bd9Sstevel@tonic-gate /* 47197c478bd9Sstevel@tonic-gate ** PRINTQUEUE -- print out a representation of the mail queue 47207c478bd9Sstevel@tonic-gate ** 47217c478bd9Sstevel@tonic-gate ** Parameters: 47227c478bd9Sstevel@tonic-gate ** none. 47237c478bd9Sstevel@tonic-gate ** 47247c478bd9Sstevel@tonic-gate ** Returns: 47257c478bd9Sstevel@tonic-gate ** none. 47267c478bd9Sstevel@tonic-gate ** 47277c478bd9Sstevel@tonic-gate ** Side Effects: 47287c478bd9Sstevel@tonic-gate ** Prints a listing of the mail queue on the standard output. 47297c478bd9Sstevel@tonic-gate */ 47307c478bd9Sstevel@tonic-gate 47317c478bd9Sstevel@tonic-gate void 47327c478bd9Sstevel@tonic-gate printqueue() 47337c478bd9Sstevel@tonic-gate { 47347c478bd9Sstevel@tonic-gate int i, k = 0, nrequests = 0; 47357c478bd9Sstevel@tonic-gate 47367c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 47377c478bd9Sstevel@tonic-gate { 47387c478bd9Sstevel@tonic-gate int j; 47397c478bd9Sstevel@tonic-gate 47407c478bd9Sstevel@tonic-gate k++; 47417c478bd9Sstevel@tonic-gate for (j = 0; j < Queue[i]->qg_numqueues; j++) 47427c478bd9Sstevel@tonic-gate { 47437c478bd9Sstevel@tonic-gate if (StopRequest) 47447c478bd9Sstevel@tonic-gate stop_sendmail(); 47457c478bd9Sstevel@tonic-gate nrequests += print_single_queue(i, j); 47467c478bd9Sstevel@tonic-gate k++; 47477c478bd9Sstevel@tonic-gate } 47487c478bd9Sstevel@tonic-gate } 47497c478bd9Sstevel@tonic-gate if (k > 1) 47507c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 47517c478bd9Sstevel@tonic-gate "\t\tTotal requests: %d\n", 47527c478bd9Sstevel@tonic-gate nrequests); 47537c478bd9Sstevel@tonic-gate } 47547c478bd9Sstevel@tonic-gate /* 47557c478bd9Sstevel@tonic-gate ** PRINT_SINGLE_QUEUE -- print out a representation of a single mail queue 47567c478bd9Sstevel@tonic-gate ** 47577c478bd9Sstevel@tonic-gate ** Parameters: 47587c478bd9Sstevel@tonic-gate ** qgrp -- the index of the queue group. 47597c478bd9Sstevel@tonic-gate ** qdir -- the queue directory. 47607c478bd9Sstevel@tonic-gate ** 47617c478bd9Sstevel@tonic-gate ** Returns: 47627c478bd9Sstevel@tonic-gate ** number of requests in mail queue. 47637c478bd9Sstevel@tonic-gate ** 47647c478bd9Sstevel@tonic-gate ** Side Effects: 47657c478bd9Sstevel@tonic-gate ** Prints a listing of the mail queue on the standard output. 47667c478bd9Sstevel@tonic-gate */ 47677c478bd9Sstevel@tonic-gate 47687c478bd9Sstevel@tonic-gate int 47697c478bd9Sstevel@tonic-gate print_single_queue(qgrp, qdir) 47707c478bd9Sstevel@tonic-gate int qgrp; 47717c478bd9Sstevel@tonic-gate int qdir; 47727c478bd9Sstevel@tonic-gate { 47737c478bd9Sstevel@tonic-gate register WORK *w; 47747c478bd9Sstevel@tonic-gate SM_FILE_T *f; 47757c478bd9Sstevel@tonic-gate int nrequests; 47767c478bd9Sstevel@tonic-gate char qd[MAXPATHLEN]; 47777c478bd9Sstevel@tonic-gate char qddf[MAXPATHLEN]; 47787c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 47797c478bd9Sstevel@tonic-gate 47807c478bd9Sstevel@tonic-gate if (qdir == NOQDIR) 47817c478bd9Sstevel@tonic-gate { 4782058561cbSjbeck (void) sm_strlcpy(qd, ".", sizeof(qd)); 4783058561cbSjbeck (void) sm_strlcpy(qddf, ".", sizeof(qddf)); 47847c478bd9Sstevel@tonic-gate } 47857c478bd9Sstevel@tonic-gate else 47867c478bd9Sstevel@tonic-gate { 4787058561cbSjbeck (void) sm_strlcpyn(qd, sizeof(qd), 2, 47887c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name, 47897c478bd9Sstevel@tonic-gate (bitset(QP_SUBQF, 47907c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs) 47917c478bd9Sstevel@tonic-gate ? "/qf" : "")); 4792058561cbSjbeck (void) sm_strlcpyn(qddf, sizeof(qddf), 2, 47937c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_name, 47947c478bd9Sstevel@tonic-gate (bitset(QP_SUBDF, 47957c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs) 47967c478bd9Sstevel@tonic-gate ? "/df" : "")); 47977c478bd9Sstevel@tonic-gate } 47987c478bd9Sstevel@tonic-gate 47997c478bd9Sstevel@tonic-gate /* 48007c478bd9Sstevel@tonic-gate ** Check for permission to print the queue 48017c478bd9Sstevel@tonic-gate */ 48027c478bd9Sstevel@tonic-gate 48037c478bd9Sstevel@tonic-gate if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0) 48047c478bd9Sstevel@tonic-gate { 48057c478bd9Sstevel@tonic-gate struct stat st; 48067c478bd9Sstevel@tonic-gate #ifdef NGROUPS_MAX 48077c478bd9Sstevel@tonic-gate int n; 48087c478bd9Sstevel@tonic-gate extern GIDSET_T InitialGidSet[NGROUPS_MAX]; 48097c478bd9Sstevel@tonic-gate #endif /* NGROUPS_MAX */ 48107c478bd9Sstevel@tonic-gate 48117c478bd9Sstevel@tonic-gate if (stat(qd, &st) < 0) 48127c478bd9Sstevel@tonic-gate { 48137c478bd9Sstevel@tonic-gate syserr("Cannot stat %s", 48147c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 48157c478bd9Sstevel@tonic-gate return 0; 48167c478bd9Sstevel@tonic-gate } 48177c478bd9Sstevel@tonic-gate #ifdef NGROUPS_MAX 48187c478bd9Sstevel@tonic-gate n = NGROUPS_MAX; 48197c478bd9Sstevel@tonic-gate while (--n >= 0) 48207c478bd9Sstevel@tonic-gate { 48217c478bd9Sstevel@tonic-gate if (InitialGidSet[n] == st.st_gid) 48227c478bd9Sstevel@tonic-gate break; 48237c478bd9Sstevel@tonic-gate } 48247c478bd9Sstevel@tonic-gate if (n < 0 && RealGid != st.st_gid) 48257c478bd9Sstevel@tonic-gate #else /* NGROUPS_MAX */ 48267c478bd9Sstevel@tonic-gate if (RealGid != st.st_gid) 48277c478bd9Sstevel@tonic-gate #endif /* NGROUPS_MAX */ 48287c478bd9Sstevel@tonic-gate { 48297c478bd9Sstevel@tonic-gate usrerr("510 You are not permitted to see the queue"); 48307c478bd9Sstevel@tonic-gate setstat(EX_NOPERM); 48317c478bd9Sstevel@tonic-gate return 0; 48327c478bd9Sstevel@tonic-gate } 48337c478bd9Sstevel@tonic-gate } 48347c478bd9Sstevel@tonic-gate 48357c478bd9Sstevel@tonic-gate /* 48367c478bd9Sstevel@tonic-gate ** Read and order the queue. 48377c478bd9Sstevel@tonic-gate */ 48387c478bd9Sstevel@tonic-gate 48397c478bd9Sstevel@tonic-gate nrequests = gatherq(qgrp, qdir, true, NULL, NULL); 48407c478bd9Sstevel@tonic-gate (void) sortq(Queue[qgrp]->qg_maxlist); 48417c478bd9Sstevel@tonic-gate 48427c478bd9Sstevel@tonic-gate /* 48437c478bd9Sstevel@tonic-gate ** Print the work list that we have read. 48447c478bd9Sstevel@tonic-gate */ 48457c478bd9Sstevel@tonic-gate 48467c478bd9Sstevel@tonic-gate /* first see if there is anything */ 48477c478bd9Sstevel@tonic-gate if (nrequests <= 0) 48487c478bd9Sstevel@tonic-gate { 48497c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s is empty\n", 48507c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 48517c478bd9Sstevel@tonic-gate return 0; 48527c478bd9Sstevel@tonic-gate } 48537c478bd9Sstevel@tonic-gate 48547c478bd9Sstevel@tonic-gate sm_getla(); /* get load average */ 48557c478bd9Sstevel@tonic-gate 48567c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\t\t%s (%d request%s", 48577c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir), 48587c478bd9Sstevel@tonic-gate nrequests, nrequests == 1 ? "" : "s"); 48597c478bd9Sstevel@tonic-gate if (MaxQueueRun > 0 && nrequests > MaxQueueRun) 48607c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48617c478bd9Sstevel@tonic-gate ", only %d printed", MaxQueueRun); 48627c478bd9Sstevel@tonic-gate if (Verbose) 48637c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48647c478bd9Sstevel@tonic-gate ")\n-----Q-ID----- --Size-- -Priority- ---Q-Time--- --------Sender/Recipient--------\n"); 48657c478bd9Sstevel@tonic-gate else 48667c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48677c478bd9Sstevel@tonic-gate ")\n-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------\n"); 48687c478bd9Sstevel@tonic-gate for (w = WorkQ; w != NULL; w = w->w_next) 48697c478bd9Sstevel@tonic-gate { 48707c478bd9Sstevel@tonic-gate struct stat st; 48717c478bd9Sstevel@tonic-gate auto time_t submittime = 0; 48727c478bd9Sstevel@tonic-gate long dfsize; 48737c478bd9Sstevel@tonic-gate int flags = 0; 48747c478bd9Sstevel@tonic-gate int qfver; 48757c478bd9Sstevel@tonic-gate char quarmsg[MAXLINE]; 48767c478bd9Sstevel@tonic-gate char statmsg[MAXLINE]; 48777c478bd9Sstevel@tonic-gate char bodytype[MAXNAME + 1]; 48787c478bd9Sstevel@tonic-gate char qf[MAXPATHLEN]; 48797c478bd9Sstevel@tonic-gate 48807c478bd9Sstevel@tonic-gate if (StopRequest) 48817c478bd9Sstevel@tonic-gate stop_sendmail(); 48827c478bd9Sstevel@tonic-gate 48837c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%13s", 48847c478bd9Sstevel@tonic-gate w->w_name + 2); 4885058561cbSjbeck (void) sm_strlcpyn(qf, sizeof(qf), 3, qd, "/", w->w_name); 48867c478bd9Sstevel@tonic-gate f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY_B, 48877c478bd9Sstevel@tonic-gate NULL); 48887c478bd9Sstevel@tonic-gate if (f == NULL) 48897c478bd9Sstevel@tonic-gate { 48907c478bd9Sstevel@tonic-gate if (errno == EPERM) 48917c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48927c478bd9Sstevel@tonic-gate " (permission denied)\n"); 48937c478bd9Sstevel@tonic-gate else if (errno == ENOENT) 48947c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48957c478bd9Sstevel@tonic-gate " (job completed)\n"); 48967c478bd9Sstevel@tonic-gate else 48977c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 48987c478bd9Sstevel@tonic-gate " (%s)\n", 48997c478bd9Sstevel@tonic-gate sm_errstring(errno)); 49007c478bd9Sstevel@tonic-gate errno = 0; 49017c478bd9Sstevel@tonic-gate continue; 49027c478bd9Sstevel@tonic-gate } 49037c478bd9Sstevel@tonic-gate w->w_name[0] = DATAFL_LETTER; 4904058561cbSjbeck (void) sm_strlcpyn(qf, sizeof(qf), 3, qddf, "/", w->w_name); 49057c478bd9Sstevel@tonic-gate if (stat(qf, &st) >= 0) 49067c478bd9Sstevel@tonic-gate dfsize = st.st_size; 49077c478bd9Sstevel@tonic-gate else 49087c478bd9Sstevel@tonic-gate { 49097c478bd9Sstevel@tonic-gate ENVELOPE e; 49107c478bd9Sstevel@tonic-gate 49117c478bd9Sstevel@tonic-gate /* 49127c478bd9Sstevel@tonic-gate ** Maybe the df file can't be statted because 49137c478bd9Sstevel@tonic-gate ** it is in a different directory than the qf file. 49147c478bd9Sstevel@tonic-gate ** In order to find out, we must read the qf file. 49157c478bd9Sstevel@tonic-gate */ 49167c478bd9Sstevel@tonic-gate 49177c478bd9Sstevel@tonic-gate newenvelope(&e, &BlankEnvelope, sm_rpool_new_x(NULL)); 49187c478bd9Sstevel@tonic-gate e.e_id = w->w_name + 2; 49197c478bd9Sstevel@tonic-gate e.e_qgrp = qgrp; 49207c478bd9Sstevel@tonic-gate e.e_qdir = qdir; 49217c478bd9Sstevel@tonic-gate dfsize = -1; 49227c478bd9Sstevel@tonic-gate if (readqf(&e, false)) 49237c478bd9Sstevel@tonic-gate { 49247c478bd9Sstevel@tonic-gate char *df = queuename(&e, DATAFL_LETTER); 49257c478bd9Sstevel@tonic-gate if (stat(df, &st) >= 0) 49267c478bd9Sstevel@tonic-gate dfsize = st.st_size; 49277c478bd9Sstevel@tonic-gate } 49287c478bd9Sstevel@tonic-gate if (e.e_lockfp != NULL) 49297c478bd9Sstevel@tonic-gate { 49307c478bd9Sstevel@tonic-gate (void) sm_io_close(e.e_lockfp, SM_TIME_DEFAULT); 49317c478bd9Sstevel@tonic-gate e.e_lockfp = NULL; 49327c478bd9Sstevel@tonic-gate } 49337c478bd9Sstevel@tonic-gate clearenvelope(&e, false, e.e_rpool); 49347c478bd9Sstevel@tonic-gate sm_rpool_free(e.e_rpool); 49357c478bd9Sstevel@tonic-gate } 49367c478bd9Sstevel@tonic-gate if (w->w_lock) 49377c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "*"); 49387c478bd9Sstevel@tonic-gate else if (QueueMode == QM_LOST) 49397c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "?"); 49407c478bd9Sstevel@tonic-gate else if (w->w_tooyoung) 49417c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "-"); 49427c478bd9Sstevel@tonic-gate else if (shouldqueue(w->w_pri, w->w_ctime)) 49437c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "X"); 49447c478bd9Sstevel@tonic-gate else 49457c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " "); 49467c478bd9Sstevel@tonic-gate 49477c478bd9Sstevel@tonic-gate errno = 0; 49487c478bd9Sstevel@tonic-gate 49497c478bd9Sstevel@tonic-gate quarmsg[0] = '\0'; 49507c478bd9Sstevel@tonic-gate statmsg[0] = bodytype[0] = '\0'; 49517c478bd9Sstevel@tonic-gate qfver = 0; 4952058561cbSjbeck while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL) 49537c478bd9Sstevel@tonic-gate { 49547c478bd9Sstevel@tonic-gate register int i; 49557c478bd9Sstevel@tonic-gate register char *p; 49567c478bd9Sstevel@tonic-gate 49577c478bd9Sstevel@tonic-gate if (StopRequest) 49587c478bd9Sstevel@tonic-gate stop_sendmail(); 49597c478bd9Sstevel@tonic-gate 49607c478bd9Sstevel@tonic-gate fixcrlf(buf, true); 49617c478bd9Sstevel@tonic-gate switch (buf[0]) 49627c478bd9Sstevel@tonic-gate { 49637c478bd9Sstevel@tonic-gate case 'V': /* queue file version */ 49647c478bd9Sstevel@tonic-gate qfver = atoi(&buf[1]); 49657c478bd9Sstevel@tonic-gate break; 49667c478bd9Sstevel@tonic-gate 49677c478bd9Sstevel@tonic-gate case 'M': /* error message */ 4968058561cbSjbeck if ((i = strlen(&buf[1])) >= sizeof(statmsg)) 4969058561cbSjbeck i = sizeof(statmsg) - 1; 49707c478bd9Sstevel@tonic-gate memmove(statmsg, &buf[1], i); 49717c478bd9Sstevel@tonic-gate statmsg[i] = '\0'; 49727c478bd9Sstevel@tonic-gate break; 49737c478bd9Sstevel@tonic-gate 49747c478bd9Sstevel@tonic-gate case 'q': /* quarantine reason */ 4975058561cbSjbeck if ((i = strlen(&buf[1])) >= sizeof(quarmsg)) 4976058561cbSjbeck i = sizeof(quarmsg) - 1; 49777c478bd9Sstevel@tonic-gate memmove(quarmsg, &buf[1], i); 49787c478bd9Sstevel@tonic-gate quarmsg[i] = '\0'; 49797c478bd9Sstevel@tonic-gate break; 49807c478bd9Sstevel@tonic-gate 49817c478bd9Sstevel@tonic-gate case 'B': /* body type */ 4982058561cbSjbeck if ((i = strlen(&buf[1])) >= sizeof(bodytype)) 4983058561cbSjbeck i = sizeof(bodytype) - 1; 49847c478bd9Sstevel@tonic-gate memmove(bodytype, &buf[1], i); 49857c478bd9Sstevel@tonic-gate bodytype[i] = '\0'; 49867c478bd9Sstevel@tonic-gate break; 49877c478bd9Sstevel@tonic-gate 49887c478bd9Sstevel@tonic-gate case 'S': /* sender name */ 49897c478bd9Sstevel@tonic-gate if (Verbose) 49907c478bd9Sstevel@tonic-gate { 49917c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 49927c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49937c478bd9Sstevel@tonic-gate "%8ld %10ld%c%.12s ", 49947c478bd9Sstevel@tonic-gate dfsize, 49957c478bd9Sstevel@tonic-gate w->w_pri, 49967c478bd9Sstevel@tonic-gate bitset(EF_WARNING, flags) 49977c478bd9Sstevel@tonic-gate ? '+' : ' ', 49987c478bd9Sstevel@tonic-gate ctime(&submittime) + 4); 49997c478bd9Sstevel@tonic-gate prtstr(&buf[1], 78); 50007c478bd9Sstevel@tonic-gate } 50017c478bd9Sstevel@tonic-gate else 50027c478bd9Sstevel@tonic-gate { 50037c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50047c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50057c478bd9Sstevel@tonic-gate "%8ld %.16s ", 50067c478bd9Sstevel@tonic-gate dfsize, 50077c478bd9Sstevel@tonic-gate ctime(&submittime)); 50087c478bd9Sstevel@tonic-gate prtstr(&buf[1], 39); 50097c478bd9Sstevel@tonic-gate } 50107c478bd9Sstevel@tonic-gate 50117c478bd9Sstevel@tonic-gate if (quarmsg[0] != '\0') 50127c478bd9Sstevel@tonic-gate { 50137c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50147c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50157c478bd9Sstevel@tonic-gate "\n QUARANTINE: %.*s", 50167c478bd9Sstevel@tonic-gate Verbose ? 100 : 60, 50177c478bd9Sstevel@tonic-gate quarmsg); 50187c478bd9Sstevel@tonic-gate quarmsg[0] = '\0'; 50197c478bd9Sstevel@tonic-gate } 50207c478bd9Sstevel@tonic-gate 50217c478bd9Sstevel@tonic-gate if (statmsg[0] != '\0' || bodytype[0] != '\0') 50227c478bd9Sstevel@tonic-gate { 50237c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50247c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50257c478bd9Sstevel@tonic-gate "\n %10.10s", 50267c478bd9Sstevel@tonic-gate bodytype); 50277c478bd9Sstevel@tonic-gate if (statmsg[0] != '\0') 50287c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50297c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50307c478bd9Sstevel@tonic-gate " (%.*s)", 50317c478bd9Sstevel@tonic-gate Verbose ? 100 : 60, 50327c478bd9Sstevel@tonic-gate statmsg); 50337c478bd9Sstevel@tonic-gate statmsg[0] = '\0'; 50347c478bd9Sstevel@tonic-gate } 50357c478bd9Sstevel@tonic-gate break; 50367c478bd9Sstevel@tonic-gate 50377c478bd9Sstevel@tonic-gate case 'C': /* controlling user */ 50387c478bd9Sstevel@tonic-gate if (Verbose) 50397c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50407c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50417c478bd9Sstevel@tonic-gate "\n\t\t\t\t\t\t(---%.64s---)", 50427c478bd9Sstevel@tonic-gate &buf[1]); 50437c478bd9Sstevel@tonic-gate break; 50447c478bd9Sstevel@tonic-gate 50457c478bd9Sstevel@tonic-gate case 'R': /* recipient name */ 50467c478bd9Sstevel@tonic-gate p = &buf[1]; 50477c478bd9Sstevel@tonic-gate if (qfver >= 1) 50487c478bd9Sstevel@tonic-gate { 50497c478bd9Sstevel@tonic-gate p = strchr(p, ':'); 50507c478bd9Sstevel@tonic-gate if (p == NULL) 50517c478bd9Sstevel@tonic-gate break; 50527c478bd9Sstevel@tonic-gate p++; 50537c478bd9Sstevel@tonic-gate } 50547c478bd9Sstevel@tonic-gate if (Verbose) 50557c478bd9Sstevel@tonic-gate { 50567c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50577c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50587c478bd9Sstevel@tonic-gate "\n\t\t\t\t\t\t"); 50597c478bd9Sstevel@tonic-gate prtstr(p, 71); 50607c478bd9Sstevel@tonic-gate } 50617c478bd9Sstevel@tonic-gate else 50627c478bd9Sstevel@tonic-gate { 50637c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50647c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50657c478bd9Sstevel@tonic-gate "\n\t\t\t\t\t "); 50667c478bd9Sstevel@tonic-gate prtstr(p, 38); 50677c478bd9Sstevel@tonic-gate } 50687c478bd9Sstevel@tonic-gate if (Verbose && statmsg[0] != '\0') 50697c478bd9Sstevel@tonic-gate { 50707c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 50717c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 50727c478bd9Sstevel@tonic-gate "\n\t\t (%.100s)", 50737c478bd9Sstevel@tonic-gate statmsg); 50747c478bd9Sstevel@tonic-gate statmsg[0] = '\0'; 50757c478bd9Sstevel@tonic-gate } 50767c478bd9Sstevel@tonic-gate break; 50777c478bd9Sstevel@tonic-gate 50787c478bd9Sstevel@tonic-gate case 'T': /* creation time */ 50797c478bd9Sstevel@tonic-gate submittime = atol(&buf[1]); 50807c478bd9Sstevel@tonic-gate break; 50817c478bd9Sstevel@tonic-gate 50827c478bd9Sstevel@tonic-gate case 'F': /* flag bits */ 50837c478bd9Sstevel@tonic-gate for (p = &buf[1]; *p != '\0'; p++) 50847c478bd9Sstevel@tonic-gate { 50857c478bd9Sstevel@tonic-gate switch (*p) 50867c478bd9Sstevel@tonic-gate { 50877c478bd9Sstevel@tonic-gate case 'w': 50887c478bd9Sstevel@tonic-gate flags |= EF_WARNING; 50897c478bd9Sstevel@tonic-gate break; 50907c478bd9Sstevel@tonic-gate } 50917c478bd9Sstevel@tonic-gate } 50927c478bd9Sstevel@tonic-gate } 50937c478bd9Sstevel@tonic-gate } 50947c478bd9Sstevel@tonic-gate if (submittime == (time_t) 0) 50957c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 50967c478bd9Sstevel@tonic-gate " (no control file)"); 50977c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); 50987c478bd9Sstevel@tonic-gate (void) sm_io_close(f, SM_TIME_DEFAULT); 50997c478bd9Sstevel@tonic-gate } 51007c478bd9Sstevel@tonic-gate return nrequests; 51017c478bd9Sstevel@tonic-gate } 51027c478bd9Sstevel@tonic-gate 51037c478bd9Sstevel@tonic-gate /* 51047c478bd9Sstevel@tonic-gate ** QUEUE_LETTER -- get the proper queue letter for the current QueueMode. 51057c478bd9Sstevel@tonic-gate ** 51067c478bd9Sstevel@tonic-gate ** Parameters: 51077c478bd9Sstevel@tonic-gate ** e -- envelope to build it in/from. 51087c478bd9Sstevel@tonic-gate ** type -- the file type, used as the first character 51097c478bd9Sstevel@tonic-gate ** of the file name. 51107c478bd9Sstevel@tonic-gate ** 51117c478bd9Sstevel@tonic-gate ** Returns: 51127c478bd9Sstevel@tonic-gate ** the letter to use 51137c478bd9Sstevel@tonic-gate */ 51147c478bd9Sstevel@tonic-gate 51157c478bd9Sstevel@tonic-gate static char 51167c478bd9Sstevel@tonic-gate queue_letter(e, type) 51177c478bd9Sstevel@tonic-gate ENVELOPE *e; 51187c478bd9Sstevel@tonic-gate int type; 51197c478bd9Sstevel@tonic-gate { 51207c478bd9Sstevel@tonic-gate /* Change type according to QueueMode */ 51217c478bd9Sstevel@tonic-gate if (type == ANYQFL_LETTER) 51227c478bd9Sstevel@tonic-gate { 51237c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 51247c478bd9Sstevel@tonic-gate type = QUARQF_LETTER; 51257c478bd9Sstevel@tonic-gate else 51267c478bd9Sstevel@tonic-gate { 51277c478bd9Sstevel@tonic-gate switch (QueueMode) 51287c478bd9Sstevel@tonic-gate { 51297c478bd9Sstevel@tonic-gate case QM_NORMAL: 51307c478bd9Sstevel@tonic-gate type = NORMQF_LETTER; 51317c478bd9Sstevel@tonic-gate break; 51327c478bd9Sstevel@tonic-gate 51337c478bd9Sstevel@tonic-gate case QM_QUARANTINE: 51347c478bd9Sstevel@tonic-gate type = QUARQF_LETTER; 51357c478bd9Sstevel@tonic-gate break; 51367c478bd9Sstevel@tonic-gate 51377c478bd9Sstevel@tonic-gate case QM_LOST: 51387c478bd9Sstevel@tonic-gate type = LOSEQF_LETTER; 51397c478bd9Sstevel@tonic-gate break; 51407c478bd9Sstevel@tonic-gate 51417c478bd9Sstevel@tonic-gate default: 51427c478bd9Sstevel@tonic-gate /* should never happen */ 51437c478bd9Sstevel@tonic-gate abort(); 51447c478bd9Sstevel@tonic-gate /* NOTREACHED */ 51457c478bd9Sstevel@tonic-gate } 51467c478bd9Sstevel@tonic-gate } 51477c478bd9Sstevel@tonic-gate } 51487c478bd9Sstevel@tonic-gate return type; 51497c478bd9Sstevel@tonic-gate } 51507c478bd9Sstevel@tonic-gate 51517c478bd9Sstevel@tonic-gate /* 51527c478bd9Sstevel@tonic-gate ** QUEUENAME -- build a file name in the queue directory for this envelope. 51537c478bd9Sstevel@tonic-gate ** 51547c478bd9Sstevel@tonic-gate ** Parameters: 51557c478bd9Sstevel@tonic-gate ** e -- envelope to build it in/from. 51567c478bd9Sstevel@tonic-gate ** type -- the file type, used as the first character 51577c478bd9Sstevel@tonic-gate ** of the file name. 51587c478bd9Sstevel@tonic-gate ** 51597c478bd9Sstevel@tonic-gate ** Returns: 51607c478bd9Sstevel@tonic-gate ** a pointer to the queue name (in a static buffer). 51617c478bd9Sstevel@tonic-gate ** 51627c478bd9Sstevel@tonic-gate ** Side Effects: 51637c478bd9Sstevel@tonic-gate ** If no id code is already assigned, queuename() will 51647c478bd9Sstevel@tonic-gate ** assign an id code with assign_queueid(). If no queue 51657c478bd9Sstevel@tonic-gate ** directory is assigned, one will be set with setnewqueue(). 51667c478bd9Sstevel@tonic-gate */ 51677c478bd9Sstevel@tonic-gate 51687c478bd9Sstevel@tonic-gate char * 51697c478bd9Sstevel@tonic-gate queuename(e, type) 51707c478bd9Sstevel@tonic-gate register ENVELOPE *e; 51717c478bd9Sstevel@tonic-gate int type; 51727c478bd9Sstevel@tonic-gate { 51737c478bd9Sstevel@tonic-gate int qd, qg; 51747c478bd9Sstevel@tonic-gate char *sub = "/"; 51757c478bd9Sstevel@tonic-gate char pref[3]; 51767c478bd9Sstevel@tonic-gate static char buf[MAXPATHLEN]; 51777c478bd9Sstevel@tonic-gate 51787c478bd9Sstevel@tonic-gate /* Assign an ID if needed */ 51797c478bd9Sstevel@tonic-gate if (e->e_id == NULL) 51807c478bd9Sstevel@tonic-gate assign_queueid(e); 51817c478bd9Sstevel@tonic-gate type = queue_letter(e, type); 51827c478bd9Sstevel@tonic-gate 51837c478bd9Sstevel@tonic-gate /* begin of filename */ 51847c478bd9Sstevel@tonic-gate pref[0] = (char) type; 51857c478bd9Sstevel@tonic-gate pref[1] = 'f'; 51867c478bd9Sstevel@tonic-gate pref[2] = '\0'; 51877c478bd9Sstevel@tonic-gate 51887c478bd9Sstevel@tonic-gate /* Assign a queue group/directory if needed */ 51897c478bd9Sstevel@tonic-gate if (type == XSCRPT_LETTER) 51907c478bd9Sstevel@tonic-gate { 51917c478bd9Sstevel@tonic-gate /* 51927c478bd9Sstevel@tonic-gate ** We don't want to call setnewqueue() if we are fetching 51937c478bd9Sstevel@tonic-gate ** the pathname of the transcript file, because setnewqueue 51947c478bd9Sstevel@tonic-gate ** chooses a queue, and sometimes we need to write to the 51957c478bd9Sstevel@tonic-gate ** transcript file before we have gathered enough information 51967c478bd9Sstevel@tonic-gate ** to choose a queue. 51977c478bd9Sstevel@tonic-gate */ 51987c478bd9Sstevel@tonic-gate 51997c478bd9Sstevel@tonic-gate if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR) 52007c478bd9Sstevel@tonic-gate { 52017c478bd9Sstevel@tonic-gate if (e->e_qgrp != NOQGRP && e->e_qdir != NOQDIR) 52027c478bd9Sstevel@tonic-gate { 52037c478bd9Sstevel@tonic-gate e->e_xfqgrp = e->e_qgrp; 52047c478bd9Sstevel@tonic-gate e->e_xfqdir = e->e_qdir; 52057c478bd9Sstevel@tonic-gate } 52067c478bd9Sstevel@tonic-gate else 52077c478bd9Sstevel@tonic-gate { 52087c478bd9Sstevel@tonic-gate e->e_xfqgrp = 0; 52097c478bd9Sstevel@tonic-gate if (Queue[e->e_xfqgrp]->qg_numqueues <= 1) 52107c478bd9Sstevel@tonic-gate e->e_xfqdir = 0; 52117c478bd9Sstevel@tonic-gate else 52127c478bd9Sstevel@tonic-gate { 52137c478bd9Sstevel@tonic-gate e->e_xfqdir = get_rand_mod( 52147c478bd9Sstevel@tonic-gate Queue[e->e_xfqgrp]->qg_numqueues); 52157c478bd9Sstevel@tonic-gate } 52167c478bd9Sstevel@tonic-gate } 52177c478bd9Sstevel@tonic-gate } 52187c478bd9Sstevel@tonic-gate qd = e->e_xfqdir; 52197c478bd9Sstevel@tonic-gate qg = e->e_xfqgrp; 52207c478bd9Sstevel@tonic-gate } 52217c478bd9Sstevel@tonic-gate else 52227c478bd9Sstevel@tonic-gate { 52237c478bd9Sstevel@tonic-gate if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR) 52243ee0e492Sjbeck (void) setnewqueue(e); 52257c478bd9Sstevel@tonic-gate if (type == DATAFL_LETTER) 52267c478bd9Sstevel@tonic-gate { 52277c478bd9Sstevel@tonic-gate qd = e->e_dfqdir; 52287c478bd9Sstevel@tonic-gate qg = e->e_dfqgrp; 52297c478bd9Sstevel@tonic-gate } 52307c478bd9Sstevel@tonic-gate else 52317c478bd9Sstevel@tonic-gate { 52327c478bd9Sstevel@tonic-gate qd = e->e_qdir; 52337c478bd9Sstevel@tonic-gate qg = e->e_qgrp; 52347c478bd9Sstevel@tonic-gate } 52357c478bd9Sstevel@tonic-gate } 52367c478bd9Sstevel@tonic-gate 52377c478bd9Sstevel@tonic-gate /* xf files always have a valid qd and qg picked above */ 52383ee0e492Sjbeck if ((qd == NOQDIR || qg == NOQGRP) && type != XSCRPT_LETTER) 5239058561cbSjbeck (void) sm_strlcpyn(buf, sizeof(buf), 2, pref, e->e_id); 52407c478bd9Sstevel@tonic-gate else 52417c478bd9Sstevel@tonic-gate { 52427c478bd9Sstevel@tonic-gate switch (type) 52437c478bd9Sstevel@tonic-gate { 52447c478bd9Sstevel@tonic-gate case DATAFL_LETTER: 52457c478bd9Sstevel@tonic-gate if (bitset(QP_SUBDF, Queue[qg]->qg_qpaths[qd].qp_subdirs)) 52467c478bd9Sstevel@tonic-gate sub = "/df/"; 52477c478bd9Sstevel@tonic-gate break; 52487c478bd9Sstevel@tonic-gate 52497c478bd9Sstevel@tonic-gate case QUARQF_LETTER: 52507c478bd9Sstevel@tonic-gate case TEMPQF_LETTER: 52517c478bd9Sstevel@tonic-gate case NEWQFL_LETTER: 52527c478bd9Sstevel@tonic-gate case LOSEQF_LETTER: 52537c478bd9Sstevel@tonic-gate case NORMQF_LETTER: 52547c478bd9Sstevel@tonic-gate if (bitset(QP_SUBQF, Queue[qg]->qg_qpaths[qd].qp_subdirs)) 52557c478bd9Sstevel@tonic-gate sub = "/qf/"; 52567c478bd9Sstevel@tonic-gate break; 52577c478bd9Sstevel@tonic-gate 52587c478bd9Sstevel@tonic-gate case XSCRPT_LETTER: 52597c478bd9Sstevel@tonic-gate if (bitset(QP_SUBXF, Queue[qg]->qg_qpaths[qd].qp_subdirs)) 52607c478bd9Sstevel@tonic-gate sub = "/xf/"; 52617c478bd9Sstevel@tonic-gate break; 52627c478bd9Sstevel@tonic-gate 52637c478bd9Sstevel@tonic-gate default: 52647c478bd9Sstevel@tonic-gate sm_abort("queuename: bad queue file type %d", type); 52657c478bd9Sstevel@tonic-gate } 52667c478bd9Sstevel@tonic-gate 5267058561cbSjbeck (void) sm_strlcpyn(buf, sizeof(buf), 4, 52687c478bd9Sstevel@tonic-gate Queue[qg]->qg_qpaths[qd].qp_name, 52697c478bd9Sstevel@tonic-gate sub, pref, e->e_id); 52707c478bd9Sstevel@tonic-gate } 52717c478bd9Sstevel@tonic-gate 52727c478bd9Sstevel@tonic-gate if (tTd(7, 2)) 52737c478bd9Sstevel@tonic-gate sm_dprintf("queuename: %s\n", buf); 52747c478bd9Sstevel@tonic-gate return buf; 52757c478bd9Sstevel@tonic-gate } 52767c478bd9Sstevel@tonic-gate 52777c478bd9Sstevel@tonic-gate /* 52787c478bd9Sstevel@tonic-gate ** INIT_QID_ALG -- Initialize the (static) parameters that are used to 52797c478bd9Sstevel@tonic-gate ** generate a queue ID. 52807c478bd9Sstevel@tonic-gate ** 52817c478bd9Sstevel@tonic-gate ** This function is called by the daemon to reset 52827c478bd9Sstevel@tonic-gate ** LastQueueTime and LastQueuePid which are used by assign_queueid(). 52837c478bd9Sstevel@tonic-gate ** Otherwise the algorithm may cause problems because 52847c478bd9Sstevel@tonic-gate ** LastQueueTime and LastQueuePid are set indirectly by main() 52857c478bd9Sstevel@tonic-gate ** before the daemon process is started, hence LastQueuePid is not 52867c478bd9Sstevel@tonic-gate ** the pid of the daemon and therefore a child of the daemon can 52877c478bd9Sstevel@tonic-gate ** actually have the same pid as LastQueuePid which means the section 52887c478bd9Sstevel@tonic-gate ** in assign_queueid(): 52897c478bd9Sstevel@tonic-gate ** * see if we need to get a new base time/pid * 52907c478bd9Sstevel@tonic-gate ** is NOT triggered which will cause the same queue id to be generated. 52917c478bd9Sstevel@tonic-gate ** 52927c478bd9Sstevel@tonic-gate ** Parameters: 52937c478bd9Sstevel@tonic-gate ** none 52947c478bd9Sstevel@tonic-gate ** 52957c478bd9Sstevel@tonic-gate ** Returns: 52967c478bd9Sstevel@tonic-gate ** none. 52977c478bd9Sstevel@tonic-gate */ 52987c478bd9Sstevel@tonic-gate 52997c478bd9Sstevel@tonic-gate void 53007c478bd9Sstevel@tonic-gate init_qid_alg() 53017c478bd9Sstevel@tonic-gate { 53027c478bd9Sstevel@tonic-gate LastQueueTime = 0; 53037c478bd9Sstevel@tonic-gate LastQueuePid = -1; 53047c478bd9Sstevel@tonic-gate } 53057c478bd9Sstevel@tonic-gate 53067c478bd9Sstevel@tonic-gate /* 53077c478bd9Sstevel@tonic-gate ** ASSIGN_QUEUEID -- assign a queue ID for this envelope. 53087c478bd9Sstevel@tonic-gate ** 53097c478bd9Sstevel@tonic-gate ** Assigns an id code if one does not already exist. 53107c478bd9Sstevel@tonic-gate ** This code assumes that nothing will remain in the queue for 53117c478bd9Sstevel@tonic-gate ** longer than 60 years. It is critical that files with the given 53127c478bd9Sstevel@tonic-gate ** name do not already exist in the queue. 53137c478bd9Sstevel@tonic-gate ** [No longer initializes e_qdir to NOQDIR.] 53147c478bd9Sstevel@tonic-gate ** 53157c478bd9Sstevel@tonic-gate ** Parameters: 53167c478bd9Sstevel@tonic-gate ** e -- envelope to set it in. 53177c478bd9Sstevel@tonic-gate ** 53187c478bd9Sstevel@tonic-gate ** Returns: 53197c478bd9Sstevel@tonic-gate ** none. 53207c478bd9Sstevel@tonic-gate */ 53217c478bd9Sstevel@tonic-gate 53227c478bd9Sstevel@tonic-gate static const char QueueIdChars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 53237c478bd9Sstevel@tonic-gate # define QIC_LEN 60 53247c478bd9Sstevel@tonic-gate # define QIC_LEN_R 62 53257c478bd9Sstevel@tonic-gate 53267c478bd9Sstevel@tonic-gate /* 53277c478bd9Sstevel@tonic-gate ** Note: the length is "officially" 60 because minutes and seconds are 53287c478bd9Sstevel@tonic-gate ** usually only 0-59. However (Linux): 53297c478bd9Sstevel@tonic-gate ** tm_sec The number of seconds after the minute, normally in 53307c478bd9Sstevel@tonic-gate ** the range 0 to 59, but can be up to 61 to allow for 53317c478bd9Sstevel@tonic-gate ** leap seconds. 53327c478bd9Sstevel@tonic-gate ** Hence the real length of the string is 62 to take this into account. 53337c478bd9Sstevel@tonic-gate ** Alternatively % QIC_LEN can (should) be used for access everywhere. 53347c478bd9Sstevel@tonic-gate */ 53357c478bd9Sstevel@tonic-gate 53367c478bd9Sstevel@tonic-gate # define queuenextid() CurrentPid 53377c478bd9Sstevel@tonic-gate 53387c478bd9Sstevel@tonic-gate 53397c478bd9Sstevel@tonic-gate void 53407c478bd9Sstevel@tonic-gate assign_queueid(e) 53417c478bd9Sstevel@tonic-gate register ENVELOPE *e; 53427c478bd9Sstevel@tonic-gate { 53437c478bd9Sstevel@tonic-gate pid_t pid = queuenextid(); 53447c478bd9Sstevel@tonic-gate static int cX = 0; 53457c478bd9Sstevel@tonic-gate static long random_offset; 53467c478bd9Sstevel@tonic-gate struct tm *tm; 53477c478bd9Sstevel@tonic-gate char idbuf[MAXQFNAME - 2]; 53487c478bd9Sstevel@tonic-gate int seq; 53497c478bd9Sstevel@tonic-gate 53507c478bd9Sstevel@tonic-gate if (e->e_id != NULL) 53517c478bd9Sstevel@tonic-gate return; 53527c478bd9Sstevel@tonic-gate 53537c478bd9Sstevel@tonic-gate /* see if we need to get a new base time/pid */ 53547c478bd9Sstevel@tonic-gate if (cX >= QIC_LEN * QIC_LEN || LastQueueTime == 0 || 53557c478bd9Sstevel@tonic-gate LastQueuePid != pid) 53567c478bd9Sstevel@tonic-gate { 53577c478bd9Sstevel@tonic-gate time_t then = LastQueueTime; 53587c478bd9Sstevel@tonic-gate 53597c478bd9Sstevel@tonic-gate /* if the first time through, pick a random offset */ 53607c478bd9Sstevel@tonic-gate if (LastQueueTime == 0) 53617c478bd9Sstevel@tonic-gate random_offset = get_random(); 53627c478bd9Sstevel@tonic-gate 53637c478bd9Sstevel@tonic-gate while ((LastQueueTime = curtime()) == then && 53647c478bd9Sstevel@tonic-gate LastQueuePid == pid) 53657c478bd9Sstevel@tonic-gate { 53667c478bd9Sstevel@tonic-gate (void) sleep(1); 53677c478bd9Sstevel@tonic-gate } 53687c478bd9Sstevel@tonic-gate LastQueuePid = queuenextid(); 53697c478bd9Sstevel@tonic-gate cX = 0; 53707c478bd9Sstevel@tonic-gate } 53717c478bd9Sstevel@tonic-gate 53727c478bd9Sstevel@tonic-gate /* 53737c478bd9Sstevel@tonic-gate ** Generate a new sequence number between 0 and QIC_LEN*QIC_LEN-1. 53747c478bd9Sstevel@tonic-gate ** This lets us generate up to QIC_LEN*QIC_LEN unique queue ids 53757c478bd9Sstevel@tonic-gate ** per second, per process. With envelope splitting, 53767c478bd9Sstevel@tonic-gate ** a single message can consume many queue ids. 53777c478bd9Sstevel@tonic-gate */ 53787c478bd9Sstevel@tonic-gate 53797c478bd9Sstevel@tonic-gate seq = (int)((cX + random_offset) % (QIC_LEN * QIC_LEN)); 53807c478bd9Sstevel@tonic-gate ++cX; 53817c478bd9Sstevel@tonic-gate if (tTd(7, 50)) 53827c478bd9Sstevel@tonic-gate sm_dprintf("assign_queueid: random_offset = %ld (%d)\n", 53837c478bd9Sstevel@tonic-gate random_offset, seq); 53847c478bd9Sstevel@tonic-gate 53857c478bd9Sstevel@tonic-gate tm = gmtime(&LastQueueTime); 53867c478bd9Sstevel@tonic-gate idbuf[0] = QueueIdChars[tm->tm_year % QIC_LEN]; 53877c478bd9Sstevel@tonic-gate idbuf[1] = QueueIdChars[tm->tm_mon]; 53887c478bd9Sstevel@tonic-gate idbuf[2] = QueueIdChars[tm->tm_mday]; 53897c478bd9Sstevel@tonic-gate idbuf[3] = QueueIdChars[tm->tm_hour]; 53907c478bd9Sstevel@tonic-gate idbuf[4] = QueueIdChars[tm->tm_min % QIC_LEN_R]; 53917c478bd9Sstevel@tonic-gate idbuf[5] = QueueIdChars[tm->tm_sec % QIC_LEN_R]; 53927c478bd9Sstevel@tonic-gate idbuf[6] = QueueIdChars[seq / QIC_LEN]; 53937c478bd9Sstevel@tonic-gate idbuf[7] = QueueIdChars[seq % QIC_LEN]; 5394058561cbSjbeck (void) sm_snprintf(&idbuf[8], sizeof(idbuf) - 8, "%06d", 53957c478bd9Sstevel@tonic-gate (int) LastQueuePid); 53967c478bd9Sstevel@tonic-gate e->e_id = sm_rpool_strdup_x(e->e_rpool, idbuf); 53977c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'i', e->e_id); 53987c478bd9Sstevel@tonic-gate #if 0 53997c478bd9Sstevel@tonic-gate /* XXX: inherited from MainEnvelope */ 54007c478bd9Sstevel@tonic-gate e->e_qgrp = NOQGRP; /* too early to do anything else */ 54017c478bd9Sstevel@tonic-gate e->e_qdir = NOQDIR; 54027c478bd9Sstevel@tonic-gate e->e_xfqgrp = NOQGRP; 54037c478bd9Sstevel@tonic-gate #endif /* 0 */ 54047c478bd9Sstevel@tonic-gate 54057c478bd9Sstevel@tonic-gate /* New ID means it's not on disk yet */ 54067c478bd9Sstevel@tonic-gate e->e_qfletter = '\0'; 54077c478bd9Sstevel@tonic-gate 54087c478bd9Sstevel@tonic-gate if (tTd(7, 1)) 54097c478bd9Sstevel@tonic-gate sm_dprintf("assign_queueid: assigned id %s, e=%p\n", 54107c478bd9Sstevel@tonic-gate e->e_id, e); 54117c478bd9Sstevel@tonic-gate if (LogLevel > 93) 54127c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "assigned id"); 54137c478bd9Sstevel@tonic-gate } 54147c478bd9Sstevel@tonic-gate /* 54157c478bd9Sstevel@tonic-gate ** SYNC_QUEUE_TIME -- Assure exclusive PID in any given second 54167c478bd9Sstevel@tonic-gate ** 54177c478bd9Sstevel@tonic-gate ** Make sure one PID can't be used by two processes in any one second. 54187c478bd9Sstevel@tonic-gate ** 54197c478bd9Sstevel@tonic-gate ** If the system rotates PIDs fast enough, may get the 54207c478bd9Sstevel@tonic-gate ** same pid in the same second for two distinct processes. 54217c478bd9Sstevel@tonic-gate ** This will interfere with the queue file naming system. 54227c478bd9Sstevel@tonic-gate ** 54237c478bd9Sstevel@tonic-gate ** Parameters: 54247c478bd9Sstevel@tonic-gate ** none 54257c478bd9Sstevel@tonic-gate ** 54267c478bd9Sstevel@tonic-gate ** Returns: 54277c478bd9Sstevel@tonic-gate ** none 54287c478bd9Sstevel@tonic-gate */ 54297c478bd9Sstevel@tonic-gate 54307c478bd9Sstevel@tonic-gate void 54317c478bd9Sstevel@tonic-gate sync_queue_time() 54327c478bd9Sstevel@tonic-gate { 54337c478bd9Sstevel@tonic-gate #if FAST_PID_RECYCLE 54347c478bd9Sstevel@tonic-gate if (OpMode != MD_TEST && 54357c478bd9Sstevel@tonic-gate OpMode != MD_VERIFY && 54367c478bd9Sstevel@tonic-gate LastQueueTime > 0 && 54377c478bd9Sstevel@tonic-gate LastQueuePid == CurrentPid && 54387c478bd9Sstevel@tonic-gate curtime() == LastQueueTime) 54397c478bd9Sstevel@tonic-gate (void) sleep(1); 54407c478bd9Sstevel@tonic-gate #endif /* FAST_PID_RECYCLE */ 54417c478bd9Sstevel@tonic-gate } 54427c478bd9Sstevel@tonic-gate /* 54437c478bd9Sstevel@tonic-gate ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 54447c478bd9Sstevel@tonic-gate ** 54457c478bd9Sstevel@tonic-gate ** Parameters: 54467c478bd9Sstevel@tonic-gate ** e -- the envelope to unlock. 54477c478bd9Sstevel@tonic-gate ** 54487c478bd9Sstevel@tonic-gate ** Returns: 54497c478bd9Sstevel@tonic-gate ** none 54507c478bd9Sstevel@tonic-gate ** 54517c478bd9Sstevel@tonic-gate ** Side Effects: 54527c478bd9Sstevel@tonic-gate ** unlocks the queue for `e'. 54537c478bd9Sstevel@tonic-gate */ 54547c478bd9Sstevel@tonic-gate 54557c478bd9Sstevel@tonic-gate void 54567c478bd9Sstevel@tonic-gate unlockqueue(e) 54577c478bd9Sstevel@tonic-gate ENVELOPE *e; 54587c478bd9Sstevel@tonic-gate { 54597c478bd9Sstevel@tonic-gate if (tTd(51, 4)) 54607c478bd9Sstevel@tonic-gate sm_dprintf("unlockqueue(%s)\n", 54617c478bd9Sstevel@tonic-gate e->e_id == NULL ? "NOQUEUE" : e->e_id); 54627c478bd9Sstevel@tonic-gate 54637c478bd9Sstevel@tonic-gate 54647c478bd9Sstevel@tonic-gate /* if there is a lock file in the envelope, close it */ 54657c478bd9Sstevel@tonic-gate if (e->e_lockfp != NULL) 54667c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT); 54677c478bd9Sstevel@tonic-gate e->e_lockfp = NULL; 54687c478bd9Sstevel@tonic-gate 54697c478bd9Sstevel@tonic-gate /* don't create a queue id if we don't already have one */ 54707c478bd9Sstevel@tonic-gate if (e->e_id == NULL) 54717c478bd9Sstevel@tonic-gate return; 54727c478bd9Sstevel@tonic-gate 54737c478bd9Sstevel@tonic-gate /* remove the transcript */ 54747c478bd9Sstevel@tonic-gate if (LogLevel > 87) 54757c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "unlock"); 54767c478bd9Sstevel@tonic-gate if (!tTd(51, 104)) 54777c478bd9Sstevel@tonic-gate (void) xunlink(queuename(e, XSCRPT_LETTER)); 54787c478bd9Sstevel@tonic-gate } 54797c478bd9Sstevel@tonic-gate /* 54807c478bd9Sstevel@tonic-gate ** SETCTLUSER -- create a controlling address 54817c478bd9Sstevel@tonic-gate ** 54827c478bd9Sstevel@tonic-gate ** Create a fake "address" given only a local login name; this is 54837c478bd9Sstevel@tonic-gate ** used as a "controlling user" for future recipient addresses. 54847c478bd9Sstevel@tonic-gate ** 54857c478bd9Sstevel@tonic-gate ** Parameters: 54867c478bd9Sstevel@tonic-gate ** user -- the user name of the controlling user. 54877c478bd9Sstevel@tonic-gate ** qfver -- the version stamp of this queue file. 54887c478bd9Sstevel@tonic-gate ** e -- envelope 54897c478bd9Sstevel@tonic-gate ** 54907c478bd9Sstevel@tonic-gate ** Returns: 54917c478bd9Sstevel@tonic-gate ** An address descriptor for the controlling user, 54927c478bd9Sstevel@tonic-gate ** using storage allocated from e->e_rpool. 54937c478bd9Sstevel@tonic-gate ** 54947c478bd9Sstevel@tonic-gate */ 54957c478bd9Sstevel@tonic-gate 54967c478bd9Sstevel@tonic-gate static ADDRESS * 54977c478bd9Sstevel@tonic-gate setctluser(user, qfver, e) 54987c478bd9Sstevel@tonic-gate char *user; 54997c478bd9Sstevel@tonic-gate int qfver; 55007c478bd9Sstevel@tonic-gate ENVELOPE *e; 55017c478bd9Sstevel@tonic-gate { 55027c478bd9Sstevel@tonic-gate register ADDRESS *a; 55037c478bd9Sstevel@tonic-gate struct passwd *pw; 55047c478bd9Sstevel@tonic-gate char *p; 55057c478bd9Sstevel@tonic-gate 55067c478bd9Sstevel@tonic-gate /* 55077c478bd9Sstevel@tonic-gate ** See if this clears our concept of controlling user. 55087c478bd9Sstevel@tonic-gate */ 55097c478bd9Sstevel@tonic-gate 55107c478bd9Sstevel@tonic-gate if (user == NULL || *user == '\0') 55117c478bd9Sstevel@tonic-gate return NULL; 55127c478bd9Sstevel@tonic-gate 55137c478bd9Sstevel@tonic-gate /* 55147c478bd9Sstevel@tonic-gate ** Set up addr fields for controlling user. 55157c478bd9Sstevel@tonic-gate */ 55167c478bd9Sstevel@tonic-gate 5517058561cbSjbeck a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof(*a)); 5518058561cbSjbeck memset((char *) a, '\0', sizeof(*a)); 55197c478bd9Sstevel@tonic-gate 55207c478bd9Sstevel@tonic-gate if (*user == ':') 55217c478bd9Sstevel@tonic-gate { 55227c478bd9Sstevel@tonic-gate p = &user[1]; 55237c478bd9Sstevel@tonic-gate a->q_user = sm_rpool_strdup_x(e->e_rpool, p); 55247c478bd9Sstevel@tonic-gate } 55257c478bd9Sstevel@tonic-gate else 55267c478bd9Sstevel@tonic-gate { 55277c478bd9Sstevel@tonic-gate p = strtok(user, ":"); 55287c478bd9Sstevel@tonic-gate a->q_user = sm_rpool_strdup_x(e->e_rpool, user); 55297c478bd9Sstevel@tonic-gate if (qfver >= 2) 55307c478bd9Sstevel@tonic-gate { 55317c478bd9Sstevel@tonic-gate if ((p = strtok(NULL, ":")) != NULL) 55327c478bd9Sstevel@tonic-gate a->q_uid = atoi(p); 55337c478bd9Sstevel@tonic-gate if ((p = strtok(NULL, ":")) != NULL) 55347c478bd9Sstevel@tonic-gate a->q_gid = atoi(p); 55357c478bd9Sstevel@tonic-gate if ((p = strtok(NULL, ":")) != NULL) 55367c478bd9Sstevel@tonic-gate { 55377c478bd9Sstevel@tonic-gate char *o; 55387c478bd9Sstevel@tonic-gate 55397c478bd9Sstevel@tonic-gate a->q_flags |= QGOODUID; 55407c478bd9Sstevel@tonic-gate 55417c478bd9Sstevel@tonic-gate /* if there is another ':': restore it */ 55427c478bd9Sstevel@tonic-gate if ((o = strtok(NULL, ":")) != NULL && o > p) 55437c478bd9Sstevel@tonic-gate o[-1] = ':'; 55447c478bd9Sstevel@tonic-gate } 55457c478bd9Sstevel@tonic-gate } 55467c478bd9Sstevel@tonic-gate else if ((pw = sm_getpwnam(user)) != NULL) 55477c478bd9Sstevel@tonic-gate { 55487c478bd9Sstevel@tonic-gate if (*pw->pw_dir == '\0') 55497c478bd9Sstevel@tonic-gate a->q_home = NULL; 55507c478bd9Sstevel@tonic-gate else if (strcmp(pw->pw_dir, "/") == 0) 55517c478bd9Sstevel@tonic-gate a->q_home = ""; 55527c478bd9Sstevel@tonic-gate else 55537c478bd9Sstevel@tonic-gate a->q_home = sm_rpool_strdup_x(e->e_rpool, pw->pw_dir); 55547c478bd9Sstevel@tonic-gate a->q_uid = pw->pw_uid; 55557c478bd9Sstevel@tonic-gate a->q_gid = pw->pw_gid; 55567c478bd9Sstevel@tonic-gate a->q_flags |= QGOODUID; 55577c478bd9Sstevel@tonic-gate } 55587c478bd9Sstevel@tonic-gate } 55597c478bd9Sstevel@tonic-gate 55607c478bd9Sstevel@tonic-gate a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */ 55617c478bd9Sstevel@tonic-gate a->q_mailer = LocalMailer; 55627c478bd9Sstevel@tonic-gate if (p == NULL) 55637c478bd9Sstevel@tonic-gate a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user); 55647c478bd9Sstevel@tonic-gate else 55657c478bd9Sstevel@tonic-gate a->q_paddr = sm_rpool_strdup_x(e->e_rpool, p); 55667c478bd9Sstevel@tonic-gate return a; 55677c478bd9Sstevel@tonic-gate } 55687c478bd9Sstevel@tonic-gate /* 55697c478bd9Sstevel@tonic-gate ** LOSEQFILE -- rename queue file with LOSEQF_LETTER & try to let someone know 55707c478bd9Sstevel@tonic-gate ** 55717c478bd9Sstevel@tonic-gate ** Parameters: 55727c478bd9Sstevel@tonic-gate ** e -- the envelope (e->e_id will be used). 55737c478bd9Sstevel@tonic-gate ** why -- reported to whomever can hear. 55747c478bd9Sstevel@tonic-gate ** 55757c478bd9Sstevel@tonic-gate ** Returns: 55767c478bd9Sstevel@tonic-gate ** none. 55777c478bd9Sstevel@tonic-gate */ 55787c478bd9Sstevel@tonic-gate 55797c478bd9Sstevel@tonic-gate void 55807c478bd9Sstevel@tonic-gate loseqfile(e, why) 55817c478bd9Sstevel@tonic-gate register ENVELOPE *e; 55827c478bd9Sstevel@tonic-gate char *why; 55837c478bd9Sstevel@tonic-gate { 55847c478bd9Sstevel@tonic-gate bool loseit = true; 55857c478bd9Sstevel@tonic-gate char *p; 55867c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN]; 55877c478bd9Sstevel@tonic-gate 55887c478bd9Sstevel@tonic-gate if (e == NULL || e->e_id == NULL) 55897c478bd9Sstevel@tonic-gate return; 55907c478bd9Sstevel@tonic-gate p = queuename(e, ANYQFL_LETTER); 5591058561cbSjbeck if (sm_strlcpy(buf, p, sizeof(buf)) >= sizeof(buf)) 55927c478bd9Sstevel@tonic-gate return; 55937c478bd9Sstevel@tonic-gate if (!bitset(EF_INQUEUE, e->e_flags)) 55947c478bd9Sstevel@tonic-gate queueup(e, false, true); 55957c478bd9Sstevel@tonic-gate else if (QueueMode == QM_LOST) 55967c478bd9Sstevel@tonic-gate loseit = false; 55977c478bd9Sstevel@tonic-gate 55987c478bd9Sstevel@tonic-gate /* if already lost, no need to re-lose */ 55997c478bd9Sstevel@tonic-gate if (loseit) 56007c478bd9Sstevel@tonic-gate { 56017c478bd9Sstevel@tonic-gate p = queuename(e, LOSEQF_LETTER); 56027c478bd9Sstevel@tonic-gate if (rename(buf, p) < 0) 56037c478bd9Sstevel@tonic-gate syserr("cannot rename(%s, %s), uid=%d", 56047c478bd9Sstevel@tonic-gate buf, p, (int) geteuid()); 56057c478bd9Sstevel@tonic-gate else if (LogLevel > 0) 56067c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 56077c478bd9Sstevel@tonic-gate "Losing %s: %s", buf, why); 56087c478bd9Sstevel@tonic-gate } 56097c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL) 56107c478bd9Sstevel@tonic-gate { 56117c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); 56127c478bd9Sstevel@tonic-gate e->e_dfp = NULL; 56137c478bd9Sstevel@tonic-gate } 56147c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_HAS_DF; 56157c478bd9Sstevel@tonic-gate } 56167c478bd9Sstevel@tonic-gate /* 56177c478bd9Sstevel@tonic-gate ** NAME2QID -- translate a queue group name to a queue group id 56187c478bd9Sstevel@tonic-gate ** 56197c478bd9Sstevel@tonic-gate ** Parameters: 56207c478bd9Sstevel@tonic-gate ** queuename -- name of queue group. 56217c478bd9Sstevel@tonic-gate ** 56227c478bd9Sstevel@tonic-gate ** Returns: 56237c478bd9Sstevel@tonic-gate ** queue group id if found. 56247c478bd9Sstevel@tonic-gate ** NOQGRP otherwise. 56257c478bd9Sstevel@tonic-gate */ 56267c478bd9Sstevel@tonic-gate 56277c478bd9Sstevel@tonic-gate int 56287c478bd9Sstevel@tonic-gate name2qid(queuename) 56297c478bd9Sstevel@tonic-gate char *queuename; 56307c478bd9Sstevel@tonic-gate { 56317c478bd9Sstevel@tonic-gate register STAB *s; 56327c478bd9Sstevel@tonic-gate 56337c478bd9Sstevel@tonic-gate s = stab(queuename, ST_QUEUE, ST_FIND); 56347c478bd9Sstevel@tonic-gate if (s == NULL) 56357c478bd9Sstevel@tonic-gate return NOQGRP; 56367c478bd9Sstevel@tonic-gate return s->s_quegrp->qg_index; 56377c478bd9Sstevel@tonic-gate } 56387c478bd9Sstevel@tonic-gate /* 56397c478bd9Sstevel@tonic-gate ** QID_PRINTNAME -- create externally printable version of queue id 56407c478bd9Sstevel@tonic-gate ** 56417c478bd9Sstevel@tonic-gate ** Parameters: 56427c478bd9Sstevel@tonic-gate ** e -- the envelope. 56437c478bd9Sstevel@tonic-gate ** 56447c478bd9Sstevel@tonic-gate ** Returns: 56457c478bd9Sstevel@tonic-gate ** a printable version 56467c478bd9Sstevel@tonic-gate */ 56477c478bd9Sstevel@tonic-gate 56487c478bd9Sstevel@tonic-gate char * 56497c478bd9Sstevel@tonic-gate qid_printname(e) 56507c478bd9Sstevel@tonic-gate ENVELOPE *e; 56517c478bd9Sstevel@tonic-gate { 56527c478bd9Sstevel@tonic-gate char *id; 56537c478bd9Sstevel@tonic-gate static char idbuf[MAXQFNAME + 34]; 56547c478bd9Sstevel@tonic-gate 56557c478bd9Sstevel@tonic-gate if (e == NULL) 56567c478bd9Sstevel@tonic-gate return ""; 56577c478bd9Sstevel@tonic-gate 56587c478bd9Sstevel@tonic-gate if (e->e_id == NULL) 56597c478bd9Sstevel@tonic-gate id = ""; 56607c478bd9Sstevel@tonic-gate else 56617c478bd9Sstevel@tonic-gate id = e->e_id; 56627c478bd9Sstevel@tonic-gate 56637c478bd9Sstevel@tonic-gate if (e->e_qdir == NOQDIR) 56647c478bd9Sstevel@tonic-gate return id; 56657c478bd9Sstevel@tonic-gate 5666058561cbSjbeck (void) sm_snprintf(idbuf, sizeof(idbuf), "%.32s/%s", 56677c478bd9Sstevel@tonic-gate Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_name, 56687c478bd9Sstevel@tonic-gate id); 56697c478bd9Sstevel@tonic-gate return idbuf; 56707c478bd9Sstevel@tonic-gate } 56717c478bd9Sstevel@tonic-gate /* 56727c478bd9Sstevel@tonic-gate ** QID_PRINTQUEUE -- create full version of queue directory for data files 56737c478bd9Sstevel@tonic-gate ** 56747c478bd9Sstevel@tonic-gate ** Parameters: 56757c478bd9Sstevel@tonic-gate ** qgrp -- index in queue group. 56767c478bd9Sstevel@tonic-gate ** qdir -- the short version of the queue directory 56777c478bd9Sstevel@tonic-gate ** 56787c478bd9Sstevel@tonic-gate ** Returns: 56797c478bd9Sstevel@tonic-gate ** the full pathname to the queue (might point to a static var) 56807c478bd9Sstevel@tonic-gate */ 56817c478bd9Sstevel@tonic-gate 56827c478bd9Sstevel@tonic-gate char * 56837c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir) 56847c478bd9Sstevel@tonic-gate int qgrp; 56857c478bd9Sstevel@tonic-gate int qdir; 56867c478bd9Sstevel@tonic-gate { 56877c478bd9Sstevel@tonic-gate char *subdir; 56887c478bd9Sstevel@tonic-gate static char dir[MAXPATHLEN]; 56897c478bd9Sstevel@tonic-gate 56907c478bd9Sstevel@tonic-gate if (qdir == NOQDIR) 56917c478bd9Sstevel@tonic-gate return Queue[qgrp]->qg_qdir; 56927c478bd9Sstevel@tonic-gate 56937c478bd9Sstevel@tonic-gate if (strcmp(Queue[qgrp]->qg_qpaths[qdir].qp_name, ".") == 0) 56947c478bd9Sstevel@tonic-gate subdir = NULL; 56957c478bd9Sstevel@tonic-gate else 56967c478bd9Sstevel@tonic-gate subdir = Queue[qgrp]->qg_qpaths[qdir].qp_name; 56977c478bd9Sstevel@tonic-gate 5698058561cbSjbeck (void) sm_strlcpyn(dir, sizeof(dir), 4, 56997c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qdir, 57007c478bd9Sstevel@tonic-gate subdir == NULL ? "" : "/", 57017c478bd9Sstevel@tonic-gate subdir == NULL ? "" : subdir, 57027c478bd9Sstevel@tonic-gate (bitset(QP_SUBDF, 57037c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_qpaths[qdir].qp_subdirs) 57047c478bd9Sstevel@tonic-gate ? "/df" : "")); 57057c478bd9Sstevel@tonic-gate return dir; 57067c478bd9Sstevel@tonic-gate } 57077c478bd9Sstevel@tonic-gate 57087c478bd9Sstevel@tonic-gate /* 57097c478bd9Sstevel@tonic-gate ** PICKQDIR -- Pick a queue directory from a queue group 57107c478bd9Sstevel@tonic-gate ** 57117c478bd9Sstevel@tonic-gate ** Parameters: 57127c478bd9Sstevel@tonic-gate ** qg -- queue group 57137c478bd9Sstevel@tonic-gate ** fsize -- file size in bytes 57147c478bd9Sstevel@tonic-gate ** e -- envelope, or NULL 57157c478bd9Sstevel@tonic-gate ** 57167c478bd9Sstevel@tonic-gate ** Result: 57177c478bd9Sstevel@tonic-gate ** NOQDIR if no queue directory in qg has enough free space to 57187c478bd9Sstevel@tonic-gate ** hold a file of size 'fsize', otherwise the index of 57197c478bd9Sstevel@tonic-gate ** a randomly selected queue directory which resides on a 57207c478bd9Sstevel@tonic-gate ** file system with enough disk space. 57217c478bd9Sstevel@tonic-gate ** XXX This could be extended to select a queuedir with 57227c478bd9Sstevel@tonic-gate ** a few (the fewest?) number of entries. That data 57237c478bd9Sstevel@tonic-gate ** is available if shared memory is used. 57247c478bd9Sstevel@tonic-gate ** 57257c478bd9Sstevel@tonic-gate ** Side Effects: 57267c478bd9Sstevel@tonic-gate ** If the request fails and e != NULL then sm_syslog is called. 57277c478bd9Sstevel@tonic-gate */ 57287c478bd9Sstevel@tonic-gate 57297c478bd9Sstevel@tonic-gate int 57307c478bd9Sstevel@tonic-gate pickqdir(qg, fsize, e) 57317c478bd9Sstevel@tonic-gate QUEUEGRP *qg; 57327c478bd9Sstevel@tonic-gate long fsize; 57337c478bd9Sstevel@tonic-gate ENVELOPE *e; 57347c478bd9Sstevel@tonic-gate { 57357c478bd9Sstevel@tonic-gate int qdir; 57367c478bd9Sstevel@tonic-gate int i; 57377c478bd9Sstevel@tonic-gate long avail = 0; 57387c478bd9Sstevel@tonic-gate 57397c478bd9Sstevel@tonic-gate /* Pick a random directory, as a starting point. */ 57407c478bd9Sstevel@tonic-gate if (qg->qg_numqueues <= 1) 57417c478bd9Sstevel@tonic-gate qdir = 0; 57427c478bd9Sstevel@tonic-gate else 57437c478bd9Sstevel@tonic-gate qdir = get_rand_mod(qg->qg_numqueues); 57447c478bd9Sstevel@tonic-gate 57457c478bd9Sstevel@tonic-gate if (MinBlocksFree <= 0 && fsize <= 0) 57467c478bd9Sstevel@tonic-gate return qdir; 57477c478bd9Sstevel@tonic-gate 57487c478bd9Sstevel@tonic-gate /* 57497c478bd9Sstevel@tonic-gate ** Now iterate over the queue directories, 57507c478bd9Sstevel@tonic-gate ** looking for a directory with enough space for this message. 57517c478bd9Sstevel@tonic-gate */ 57527c478bd9Sstevel@tonic-gate 57537c478bd9Sstevel@tonic-gate i = qdir; 57547c478bd9Sstevel@tonic-gate do 57557c478bd9Sstevel@tonic-gate { 57567c478bd9Sstevel@tonic-gate QPATHS *qp = &qg->qg_qpaths[i]; 57577c478bd9Sstevel@tonic-gate long needed = 0; 57587c478bd9Sstevel@tonic-gate long fsavail = 0; 57597c478bd9Sstevel@tonic-gate 57607c478bd9Sstevel@tonic-gate if (fsize > 0) 57617c478bd9Sstevel@tonic-gate needed += fsize / FILE_SYS_BLKSIZE(qp->qp_fsysidx) 57627c478bd9Sstevel@tonic-gate + ((fsize % FILE_SYS_BLKSIZE(qp->qp_fsysidx) 57637c478bd9Sstevel@tonic-gate > 0) ? 1 : 0); 57647c478bd9Sstevel@tonic-gate if (MinBlocksFree > 0) 57657c478bd9Sstevel@tonic-gate needed += MinBlocksFree; 57667c478bd9Sstevel@tonic-gate fsavail = FILE_SYS_AVAIL(qp->qp_fsysidx); 57677c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 57687c478bd9Sstevel@tonic-gate if (fsavail <= 0) 57697c478bd9Sstevel@tonic-gate { 57707c478bd9Sstevel@tonic-gate long blksize; 57717c478bd9Sstevel@tonic-gate 57727c478bd9Sstevel@tonic-gate /* 57737c478bd9Sstevel@tonic-gate ** might be not correctly updated, 57747c478bd9Sstevel@tonic-gate ** let's try to get the info directly. 57757c478bd9Sstevel@tonic-gate */ 57767c478bd9Sstevel@tonic-gate 57777c478bd9Sstevel@tonic-gate fsavail = freediskspace(FILE_SYS_NAME(qp->qp_fsysidx), 57787c478bd9Sstevel@tonic-gate &blksize); 57797c478bd9Sstevel@tonic-gate if (fsavail < 0) 57807c478bd9Sstevel@tonic-gate fsavail = 0; 57817c478bd9Sstevel@tonic-gate } 57827c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 57837c478bd9Sstevel@tonic-gate if (needed <= fsavail) 57847c478bd9Sstevel@tonic-gate return i; 57857c478bd9Sstevel@tonic-gate if (avail < fsavail) 57867c478bd9Sstevel@tonic-gate avail = fsavail; 57877c478bd9Sstevel@tonic-gate 57887c478bd9Sstevel@tonic-gate if (qg->qg_numqueues > 0) 57897c478bd9Sstevel@tonic-gate i = (i + 1) % qg->qg_numqueues; 57907c478bd9Sstevel@tonic-gate } while (i != qdir); 57917c478bd9Sstevel@tonic-gate 57927c478bd9Sstevel@tonic-gate if (e != NULL && LogLevel > 0) 57937c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id, 57947c478bd9Sstevel@tonic-gate "low on space (%s needs %ld bytes + %ld blocks in %s), max avail: %ld", 57957c478bd9Sstevel@tonic-gate CurHostName == NULL ? "SMTP-DAEMON" : CurHostName, 57967c478bd9Sstevel@tonic-gate fsize, MinBlocksFree, 57977c478bd9Sstevel@tonic-gate qg->qg_qdir, avail); 57987c478bd9Sstevel@tonic-gate return NOQDIR; 57997c478bd9Sstevel@tonic-gate } 58007c478bd9Sstevel@tonic-gate /* 58017c478bd9Sstevel@tonic-gate ** SETNEWQUEUE -- Sets a new queue group and directory 58027c478bd9Sstevel@tonic-gate ** 58037c478bd9Sstevel@tonic-gate ** Assign a queue group and directory to an envelope and store the 58047c478bd9Sstevel@tonic-gate ** directory in e->e_qdir. 58057c478bd9Sstevel@tonic-gate ** 58067c478bd9Sstevel@tonic-gate ** Parameters: 58077c478bd9Sstevel@tonic-gate ** e -- envelope to assign a queue for. 58087c478bd9Sstevel@tonic-gate ** 58097c478bd9Sstevel@tonic-gate ** Returns: 58107c478bd9Sstevel@tonic-gate ** true if successful 58117c478bd9Sstevel@tonic-gate ** false otherwise 58127c478bd9Sstevel@tonic-gate ** 58137c478bd9Sstevel@tonic-gate ** Side Effects: 58147c478bd9Sstevel@tonic-gate ** On success, e->e_qgrp and e->e_qdir are non-negative. 58157c478bd9Sstevel@tonic-gate ** On failure (not enough disk space), 58167c478bd9Sstevel@tonic-gate ** e->qgrp = NOQGRP, e->e_qdir = NOQDIR 58177c478bd9Sstevel@tonic-gate ** and usrerr() is invoked (which could raise an exception). 58187c478bd9Sstevel@tonic-gate */ 58197c478bd9Sstevel@tonic-gate 58207c478bd9Sstevel@tonic-gate bool 58217c478bd9Sstevel@tonic-gate setnewqueue(e) 58227c478bd9Sstevel@tonic-gate ENVELOPE *e; 58237c478bd9Sstevel@tonic-gate { 58247c478bd9Sstevel@tonic-gate if (tTd(41, 20)) 58257c478bd9Sstevel@tonic-gate sm_dprintf("setnewqueue: called\n"); 58267c478bd9Sstevel@tonic-gate 58277c478bd9Sstevel@tonic-gate /* not set somewhere else */ 58287c478bd9Sstevel@tonic-gate if (e->e_qgrp == NOQGRP) 58297c478bd9Sstevel@tonic-gate { 58307c478bd9Sstevel@tonic-gate ADDRESS *q; 58317c478bd9Sstevel@tonic-gate 58327c478bd9Sstevel@tonic-gate /* 58337c478bd9Sstevel@tonic-gate ** Use the queue group of the "first" recipient, as set by 58347c478bd9Sstevel@tonic-gate ** the "queuegroup" rule set. If that is not defined, then 58357c478bd9Sstevel@tonic-gate ** use the queue group of the mailer of the first recipient. 58367c478bd9Sstevel@tonic-gate ** If that is not defined either, then use the default 58377c478bd9Sstevel@tonic-gate ** queue group. 58387c478bd9Sstevel@tonic-gate ** Notice: "first" depends on the sorting of sendqueue 58397c478bd9Sstevel@tonic-gate ** in recipient(). 58407c478bd9Sstevel@tonic-gate ** To avoid problems with "bad" recipients look 58417c478bd9Sstevel@tonic-gate ** for a valid address first. 58427c478bd9Sstevel@tonic-gate */ 58437c478bd9Sstevel@tonic-gate 58447c478bd9Sstevel@tonic-gate q = e->e_sendqueue; 58457c478bd9Sstevel@tonic-gate while (q != NULL && 58467c478bd9Sstevel@tonic-gate (QS_IS_BADADDR(q->q_state) || QS_IS_DEAD(q->q_state))) 58477c478bd9Sstevel@tonic-gate { 58487c478bd9Sstevel@tonic-gate q = q->q_next; 58497c478bd9Sstevel@tonic-gate } 58507c478bd9Sstevel@tonic-gate if (q == NULL) 58517c478bd9Sstevel@tonic-gate e->e_qgrp = 0; 58527c478bd9Sstevel@tonic-gate else if (q->q_qgrp >= 0) 58537c478bd9Sstevel@tonic-gate e->e_qgrp = q->q_qgrp; 58547c478bd9Sstevel@tonic-gate else if (q->q_mailer != NULL && 58557c478bd9Sstevel@tonic-gate ISVALIDQGRP(q->q_mailer->m_qgrp)) 58567c478bd9Sstevel@tonic-gate e->e_qgrp = q->q_mailer->m_qgrp; 58577c478bd9Sstevel@tonic-gate else 58587c478bd9Sstevel@tonic-gate e->e_qgrp = 0; 58597c478bd9Sstevel@tonic-gate e->e_dfqgrp = e->e_qgrp; 58607c478bd9Sstevel@tonic-gate } 58617c478bd9Sstevel@tonic-gate 58627c478bd9Sstevel@tonic-gate if (ISVALIDQDIR(e->e_qdir) && ISVALIDQDIR(e->e_dfqdir)) 58637c478bd9Sstevel@tonic-gate { 58647c478bd9Sstevel@tonic-gate if (tTd(41, 20)) 58657c478bd9Sstevel@tonic-gate sm_dprintf("setnewqueue: e_qdir already assigned (%s)\n", 58667c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir)); 58677c478bd9Sstevel@tonic-gate return true; 58687c478bd9Sstevel@tonic-gate } 58697c478bd9Sstevel@tonic-gate 58707c478bd9Sstevel@tonic-gate filesys_update(); 58717c478bd9Sstevel@tonic-gate e->e_qdir = pickqdir(Queue[e->e_qgrp], e->e_msgsize, e); 58727c478bd9Sstevel@tonic-gate if (e->e_qdir == NOQDIR) 58737c478bd9Sstevel@tonic-gate { 58747c478bd9Sstevel@tonic-gate e->e_qgrp = NOQGRP; 58757c478bd9Sstevel@tonic-gate if (!bitset(EF_FATALERRS, e->e_flags)) 58767c478bd9Sstevel@tonic-gate usrerr("452 4.4.5 Insufficient disk space; try again later"); 58777c478bd9Sstevel@tonic-gate e->e_flags |= EF_FATALERRS; 58787c478bd9Sstevel@tonic-gate return false; 58797c478bd9Sstevel@tonic-gate } 58807c478bd9Sstevel@tonic-gate 58817c478bd9Sstevel@tonic-gate if (tTd(41, 3)) 58827c478bd9Sstevel@tonic-gate sm_dprintf("setnewqueue: Assigned queue directory %s\n", 58837c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir)); 58847c478bd9Sstevel@tonic-gate 58857c478bd9Sstevel@tonic-gate if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR) 58867c478bd9Sstevel@tonic-gate { 58877c478bd9Sstevel@tonic-gate e->e_xfqgrp = e->e_qgrp; 58887c478bd9Sstevel@tonic-gate e->e_xfqdir = e->e_qdir; 58897c478bd9Sstevel@tonic-gate } 58907c478bd9Sstevel@tonic-gate e->e_dfqdir = e->e_qdir; 58917c478bd9Sstevel@tonic-gate return true; 58927c478bd9Sstevel@tonic-gate } 58937c478bd9Sstevel@tonic-gate /* 58947c478bd9Sstevel@tonic-gate ** CHKQDIR -- check a queue directory 58957c478bd9Sstevel@tonic-gate ** 58967c478bd9Sstevel@tonic-gate ** Parameters: 58977c478bd9Sstevel@tonic-gate ** name -- name of queue directory 58987c478bd9Sstevel@tonic-gate ** sff -- flags for safefile() 58997c478bd9Sstevel@tonic-gate ** 59007c478bd9Sstevel@tonic-gate ** Returns: 59017c478bd9Sstevel@tonic-gate ** is it a queue directory? 59027c478bd9Sstevel@tonic-gate */ 59037c478bd9Sstevel@tonic-gate 5904058561cbSjbeck static bool chkqdir __P((char *, long)); 5905058561cbSjbeck 59067c478bd9Sstevel@tonic-gate static bool 59077c478bd9Sstevel@tonic-gate chkqdir(name, sff) 59087c478bd9Sstevel@tonic-gate char *name; 59097c478bd9Sstevel@tonic-gate long sff; 59107c478bd9Sstevel@tonic-gate { 59117c478bd9Sstevel@tonic-gate struct stat statb; 59127c478bd9Sstevel@tonic-gate int i; 59137c478bd9Sstevel@tonic-gate 59147c478bd9Sstevel@tonic-gate /* skip over . and .. directories */ 59157c478bd9Sstevel@tonic-gate if (name[0] == '.' && 59167c478bd9Sstevel@tonic-gate (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) 59177c478bd9Sstevel@tonic-gate return false; 59187c478bd9Sstevel@tonic-gate #if HASLSTAT 59197c478bd9Sstevel@tonic-gate if (lstat(name, &statb) < 0) 59207c478bd9Sstevel@tonic-gate #else /* HASLSTAT */ 59217c478bd9Sstevel@tonic-gate if (stat(name, &statb) < 0) 59227c478bd9Sstevel@tonic-gate #endif /* HASLSTAT */ 59237c478bd9Sstevel@tonic-gate { 59247c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 59257c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: stat(\"%s\"): %s\n", 59267c478bd9Sstevel@tonic-gate name, sm_errstring(errno)); 59277c478bd9Sstevel@tonic-gate return false; 59287c478bd9Sstevel@tonic-gate } 59297c478bd9Sstevel@tonic-gate #if HASLSTAT 59307c478bd9Sstevel@tonic-gate if (S_ISLNK(statb.st_mode)) 59317c478bd9Sstevel@tonic-gate { 59327c478bd9Sstevel@tonic-gate /* 59337c478bd9Sstevel@tonic-gate ** For a symlink we need to make sure the 59347c478bd9Sstevel@tonic-gate ** target is a directory 59357c478bd9Sstevel@tonic-gate */ 59367c478bd9Sstevel@tonic-gate 59377c478bd9Sstevel@tonic-gate if (stat(name, &statb) < 0) 59387c478bd9Sstevel@tonic-gate { 59397c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 59407c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: stat(\"%s\"): %s\n", 59417c478bd9Sstevel@tonic-gate name, sm_errstring(errno)); 59427c478bd9Sstevel@tonic-gate return false; 59437c478bd9Sstevel@tonic-gate } 59447c478bd9Sstevel@tonic-gate } 59457c478bd9Sstevel@tonic-gate #endif /* HASLSTAT */ 59467c478bd9Sstevel@tonic-gate 59477c478bd9Sstevel@tonic-gate if (!S_ISDIR(statb.st_mode)) 59487c478bd9Sstevel@tonic-gate { 59497c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 59507c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: \"%s\": Not a directory\n", 59517c478bd9Sstevel@tonic-gate name); 59527c478bd9Sstevel@tonic-gate return false; 59537c478bd9Sstevel@tonic-gate } 59547c478bd9Sstevel@tonic-gate 59557c478bd9Sstevel@tonic-gate /* Print a warning if unsafe (but still use it) */ 59567c478bd9Sstevel@tonic-gate /* XXX do this only if we want the warning? */ 59577c478bd9Sstevel@tonic-gate i = safedirpath(name, RunAsUid, RunAsGid, NULL, sff, 0, 0); 59587c478bd9Sstevel@tonic-gate if (i != 0) 59597c478bd9Sstevel@tonic-gate { 59607c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 59617c478bd9Sstevel@tonic-gate sm_dprintf("chkqdir: \"%s\": Not safe: %s\n", 59627c478bd9Sstevel@tonic-gate name, sm_errstring(i)); 59637c478bd9Sstevel@tonic-gate #if _FFR_CHK_QUEUE 59647c478bd9Sstevel@tonic-gate if (LogLevel > 8) 59657c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 59667c478bd9Sstevel@tonic-gate "queue directory \"%s\": Not safe: %s", 59677c478bd9Sstevel@tonic-gate name, sm_errstring(i)); 59687c478bd9Sstevel@tonic-gate #endif /* _FFR_CHK_QUEUE */ 59697c478bd9Sstevel@tonic-gate } 59707c478bd9Sstevel@tonic-gate return true; 59717c478bd9Sstevel@tonic-gate } 59727c478bd9Sstevel@tonic-gate /* 59737c478bd9Sstevel@tonic-gate ** MULTIQUEUE_CACHE -- cache a list of paths to queues. 59747c478bd9Sstevel@tonic-gate ** 59757c478bd9Sstevel@tonic-gate ** Each potential queue is checked as the cache is built. 59767c478bd9Sstevel@tonic-gate ** Thereafter, each is blindly trusted. 59777c478bd9Sstevel@tonic-gate ** Note that we can be called again after a timeout to rebuild 59787c478bd9Sstevel@tonic-gate ** (although code for that is not ready yet). 59797c478bd9Sstevel@tonic-gate ** 59807c478bd9Sstevel@tonic-gate ** Parameters: 59817c478bd9Sstevel@tonic-gate ** basedir -- base of all queue directories. 59827c478bd9Sstevel@tonic-gate ** blen -- strlen(basedir). 59837c478bd9Sstevel@tonic-gate ** qg -- queue group. 59847c478bd9Sstevel@tonic-gate ** qn -- number of queue directories already cached. 59857c478bd9Sstevel@tonic-gate ** phash -- pointer to hash value over queue dirs. 59867c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 59877c478bd9Sstevel@tonic-gate ** only used if shared memory is active. 59887c478bd9Sstevel@tonic-gate #endif * SM_CONF_SHM * 59897c478bd9Sstevel@tonic-gate ** 59907c478bd9Sstevel@tonic-gate ** Returns: 59917c478bd9Sstevel@tonic-gate ** new number of queue directories. 59927c478bd9Sstevel@tonic-gate */ 59937c478bd9Sstevel@tonic-gate 59947c478bd9Sstevel@tonic-gate #define INITIAL_SLOTS 20 59957c478bd9Sstevel@tonic-gate #define ADD_SLOTS 10 59967c478bd9Sstevel@tonic-gate 59977c478bd9Sstevel@tonic-gate static int 59987c478bd9Sstevel@tonic-gate multiqueue_cache(basedir, blen, qg, qn, phash) 59997c478bd9Sstevel@tonic-gate char *basedir; 60007c478bd9Sstevel@tonic-gate int blen; 60017c478bd9Sstevel@tonic-gate QUEUEGRP *qg; 60027c478bd9Sstevel@tonic-gate int qn; 60037c478bd9Sstevel@tonic-gate unsigned int *phash; 60047c478bd9Sstevel@tonic-gate { 60057c478bd9Sstevel@tonic-gate char *cp; 60067c478bd9Sstevel@tonic-gate int i, len; 60077c478bd9Sstevel@tonic-gate int slotsleft = 0; 60087c478bd9Sstevel@tonic-gate long sff = SFF_ANYFILE; 60097c478bd9Sstevel@tonic-gate char qpath[MAXPATHLEN]; 60107c478bd9Sstevel@tonic-gate char subdir[MAXPATHLEN]; 60117c478bd9Sstevel@tonic-gate char prefix[MAXPATHLEN]; /* dir relative to basedir */ 60127c478bd9Sstevel@tonic-gate 60137c478bd9Sstevel@tonic-gate if (tTd(41, 20)) 60147c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: called\n"); 60157c478bd9Sstevel@tonic-gate 60167c478bd9Sstevel@tonic-gate /* Initialize to current directory */ 60177c478bd9Sstevel@tonic-gate prefix[0] = '.'; 60187c478bd9Sstevel@tonic-gate prefix[1] = '\0'; 60197c478bd9Sstevel@tonic-gate if (qg->qg_numqueues != 0 && qg->qg_qpaths != NULL) 60207c478bd9Sstevel@tonic-gate { 60217c478bd9Sstevel@tonic-gate for (i = 0; i < qg->qg_numqueues; i++) 60227c478bd9Sstevel@tonic-gate { 60237c478bd9Sstevel@tonic-gate if (qg->qg_qpaths[i].qp_name != NULL) 60247c478bd9Sstevel@tonic-gate (void) sm_free(qg->qg_qpaths[i].qp_name); /* XXX */ 60257c478bd9Sstevel@tonic-gate } 60267c478bd9Sstevel@tonic-gate (void) sm_free((char *) qg->qg_qpaths); /* XXX */ 60277c478bd9Sstevel@tonic-gate qg->qg_qpaths = NULL; 60287c478bd9Sstevel@tonic-gate qg->qg_numqueues = 0; 60297c478bd9Sstevel@tonic-gate } 60307c478bd9Sstevel@tonic-gate 60317c478bd9Sstevel@tonic-gate /* If running as root, allow safedirpath() checks to use privs */ 60327c478bd9Sstevel@tonic-gate if (RunAsUid == 0) 60337c478bd9Sstevel@tonic-gate sff |= SFF_ROOTOK; 60347c478bd9Sstevel@tonic-gate #if _FFR_CHK_QUEUE 60357c478bd9Sstevel@tonic-gate sff |= SFF_SAFEDIRPATH|SFF_NOWWFILES; 60367c478bd9Sstevel@tonic-gate if (!UseMSP) 60377c478bd9Sstevel@tonic-gate sff |= SFF_NOGWFILES; 60387c478bd9Sstevel@tonic-gate #endif /* _FFR_CHK_QUEUE */ 60397c478bd9Sstevel@tonic-gate 60407c478bd9Sstevel@tonic-gate if (!SM_IS_DIR_START(qg->qg_qdir)) 60417c478bd9Sstevel@tonic-gate { 60427c478bd9Sstevel@tonic-gate /* 60437c478bd9Sstevel@tonic-gate ** XXX we could add basedir, but then we have to realloc() 60447c478bd9Sstevel@tonic-gate ** the string... Maybe another time. 60457c478bd9Sstevel@tonic-gate */ 60467c478bd9Sstevel@tonic-gate 60477c478bd9Sstevel@tonic-gate syserr("QueuePath %s not absolute", qg->qg_qdir); 60487c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 60497c478bd9Sstevel@tonic-gate return qn; 60507c478bd9Sstevel@tonic-gate } 60517c478bd9Sstevel@tonic-gate 60527c478bd9Sstevel@tonic-gate /* qpath: directory of current workgroup */ 6053058561cbSjbeck len = sm_strlcpy(qpath, qg->qg_qdir, sizeof(qpath)); 6054058561cbSjbeck if (len >= sizeof(qpath)) 60557c478bd9Sstevel@tonic-gate { 60567c478bd9Sstevel@tonic-gate syserr("QueuePath %.256s too long (%d max)", 6057058561cbSjbeck qg->qg_qdir, (int) sizeof(qpath)); 60587c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 60597c478bd9Sstevel@tonic-gate return qn; 60607c478bd9Sstevel@tonic-gate } 60617c478bd9Sstevel@tonic-gate 60627c478bd9Sstevel@tonic-gate /* begin of qpath must be same as basedir */ 60637c478bd9Sstevel@tonic-gate if (strncmp(basedir, qpath, blen) != 0 && 60647c478bd9Sstevel@tonic-gate (strncmp(basedir, qpath, blen - 1) != 0 || len != blen - 1)) 60657c478bd9Sstevel@tonic-gate { 60667c478bd9Sstevel@tonic-gate syserr("QueuePath %s not subpath of QueueDirectory %s", 60677c478bd9Sstevel@tonic-gate qpath, basedir); 60687c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 60697c478bd9Sstevel@tonic-gate return qn; 60707c478bd9Sstevel@tonic-gate } 60717c478bd9Sstevel@tonic-gate 60727c478bd9Sstevel@tonic-gate /* Do we have a nested subdirectory? */ 60737c478bd9Sstevel@tonic-gate if (blen < len && SM_FIRST_DIR_DELIM(qg->qg_qdir + blen) != NULL) 60747c478bd9Sstevel@tonic-gate { 60757c478bd9Sstevel@tonic-gate 60767c478bd9Sstevel@tonic-gate /* Copy subdirectory into prefix for later use */ 6077058561cbSjbeck if (sm_strlcpy(prefix, qg->qg_qdir + blen, sizeof(prefix)) >= 6078058561cbSjbeck sizeof(prefix)) 60797c478bd9Sstevel@tonic-gate { 60807c478bd9Sstevel@tonic-gate syserr("QueuePath %.256s too long (%d max)", 6081058561cbSjbeck qg->qg_qdir, (int) sizeof(qpath)); 60827c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 60837c478bd9Sstevel@tonic-gate return qn; 60847c478bd9Sstevel@tonic-gate } 60857c478bd9Sstevel@tonic-gate cp = SM_LAST_DIR_DELIM(prefix); 60867c478bd9Sstevel@tonic-gate SM_ASSERT(cp != NULL); 60877c478bd9Sstevel@tonic-gate *cp = '\0'; /* cut off trailing / */ 60887c478bd9Sstevel@tonic-gate } 60897c478bd9Sstevel@tonic-gate 60907c478bd9Sstevel@tonic-gate /* This is guaranteed by the basedir check above */ 60917c478bd9Sstevel@tonic-gate SM_ASSERT(len >= blen - 1); 60927c478bd9Sstevel@tonic-gate cp = &qpath[len - 1]; 60937c478bd9Sstevel@tonic-gate if (*cp == '*') 60947c478bd9Sstevel@tonic-gate { 60957c478bd9Sstevel@tonic-gate register DIR *dp; 60967c478bd9Sstevel@tonic-gate register struct dirent *d; 60977c478bd9Sstevel@tonic-gate int off; 60987c478bd9Sstevel@tonic-gate char *delim; 60997c478bd9Sstevel@tonic-gate char relpath[MAXPATHLEN]; 61007c478bd9Sstevel@tonic-gate 61017c478bd9Sstevel@tonic-gate *cp = '\0'; /* Overwrite wildcard */ 61027c478bd9Sstevel@tonic-gate if ((cp = SM_LAST_DIR_DELIM(qpath)) == NULL) 61037c478bd9Sstevel@tonic-gate { 61047c478bd9Sstevel@tonic-gate syserr("QueueDirectory: can not wildcard relative path"); 61057c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 61067c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: \"%s*\": Can not wildcard relative path.\n", 61077c478bd9Sstevel@tonic-gate qpath); 61087c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 61097c478bd9Sstevel@tonic-gate return qn; 61107c478bd9Sstevel@tonic-gate } 61117c478bd9Sstevel@tonic-gate if (cp == qpath) 61127c478bd9Sstevel@tonic-gate { 61137c478bd9Sstevel@tonic-gate /* 61147c478bd9Sstevel@tonic-gate ** Special case of top level wildcard, like /foo* 61157c478bd9Sstevel@tonic-gate ** Change to //foo* 61167c478bd9Sstevel@tonic-gate */ 61177c478bd9Sstevel@tonic-gate 6118058561cbSjbeck (void) sm_strlcpy(qpath + 1, qpath, sizeof(qpath) - 1); 61197c478bd9Sstevel@tonic-gate ++cp; 61207c478bd9Sstevel@tonic-gate } 61217c478bd9Sstevel@tonic-gate delim = cp; 61227c478bd9Sstevel@tonic-gate *(cp++) = '\0'; /* Replace / with \0 */ 61237c478bd9Sstevel@tonic-gate len = strlen(cp); /* Last component of queue directory */ 61247c478bd9Sstevel@tonic-gate 61257c478bd9Sstevel@tonic-gate /* 61267c478bd9Sstevel@tonic-gate ** Path relative to basedir, with trailing / 61277c478bd9Sstevel@tonic-gate ** It will be modified below to specify the subdirectories 61287c478bd9Sstevel@tonic-gate ** so they can be opened without chdir(). 61297c478bd9Sstevel@tonic-gate */ 61307c478bd9Sstevel@tonic-gate 6131058561cbSjbeck off = sm_strlcpyn(relpath, sizeof(relpath), 2, prefix, "/"); 6132058561cbSjbeck SM_ASSERT(off < sizeof(relpath)); 61337c478bd9Sstevel@tonic-gate 61347c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 61357c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: prefix=\"%s%s\"\n", 61367c478bd9Sstevel@tonic-gate relpath, cp); 61377c478bd9Sstevel@tonic-gate 61387c478bd9Sstevel@tonic-gate /* It is always basedir: we don't need to store it per group */ 61397c478bd9Sstevel@tonic-gate /* XXX: optimize this! -> one more global? */ 61407c478bd9Sstevel@tonic-gate qg->qg_qdir = newstr(basedir); 61417c478bd9Sstevel@tonic-gate qg->qg_qdir[blen - 1] = '\0'; /* cut off trailing / */ 61427c478bd9Sstevel@tonic-gate 61437c478bd9Sstevel@tonic-gate /* 61447c478bd9Sstevel@tonic-gate ** XXX Should probably wrap this whole loop in a timeout 61457c478bd9Sstevel@tonic-gate ** in case some wag decides to NFS mount the queues. 61467c478bd9Sstevel@tonic-gate */ 61477c478bd9Sstevel@tonic-gate 61487c478bd9Sstevel@tonic-gate /* Test path to get warning messages. */ 61497c478bd9Sstevel@tonic-gate if (qn == 0) 61507c478bd9Sstevel@tonic-gate { 61517c478bd9Sstevel@tonic-gate /* XXX qg_runasuid and qg_runasgid for specials? */ 61527c478bd9Sstevel@tonic-gate i = safedirpath(basedir, RunAsUid, RunAsGid, NULL, 61537c478bd9Sstevel@tonic-gate sff, 0, 0); 61547c478bd9Sstevel@tonic-gate if (i != 0 && tTd(41, 2)) 61557c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: \"%s\": Not safe: %s\n", 61567c478bd9Sstevel@tonic-gate basedir, sm_errstring(i)); 61577c478bd9Sstevel@tonic-gate } 61587c478bd9Sstevel@tonic-gate 61597c478bd9Sstevel@tonic-gate if ((dp = opendir(prefix)) == NULL) 61607c478bd9Sstevel@tonic-gate { 61617c478bd9Sstevel@tonic-gate syserr("can not opendir(%s/%s)", qg->qg_qdir, prefix); 61627c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 61637c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: opendir(\"%s/%s\"): %s\n", 61647c478bd9Sstevel@tonic-gate qg->qg_qdir, prefix, 61657c478bd9Sstevel@tonic-gate sm_errstring(errno)); 61667c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 61677c478bd9Sstevel@tonic-gate return qn; 61687c478bd9Sstevel@tonic-gate } 61697c478bd9Sstevel@tonic-gate while ((d = readdir(dp)) != NULL) 61707c478bd9Sstevel@tonic-gate { 6171058561cbSjbeck /* Skip . and .. directories */ 6172058561cbSjbeck if (strcmp(d->d_name, ".") == 0 || 6173058561cbSjbeck strcmp(d->d_name, "..") == 0) 6174058561cbSjbeck continue; 6175058561cbSjbeck 61767c478bd9Sstevel@tonic-gate i = strlen(d->d_name); 61777c478bd9Sstevel@tonic-gate if (i < len || strncmp(d->d_name, cp, len) != 0) 61787c478bd9Sstevel@tonic-gate { 61797c478bd9Sstevel@tonic-gate if (tTd(41, 5)) 61807c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: \"%s\", skipped\n", 61817c478bd9Sstevel@tonic-gate d->d_name); 61827c478bd9Sstevel@tonic-gate continue; 61837c478bd9Sstevel@tonic-gate } 61847c478bd9Sstevel@tonic-gate 61857c478bd9Sstevel@tonic-gate /* Create relative pathname: prefix + local directory */ 61867c478bd9Sstevel@tonic-gate i = sizeof(relpath) - off; 61877c478bd9Sstevel@tonic-gate if (sm_strlcpy(relpath + off, d->d_name, i) >= i) 61887c478bd9Sstevel@tonic-gate continue; /* way too long */ 61897c478bd9Sstevel@tonic-gate 61907c478bd9Sstevel@tonic-gate if (!chkqdir(relpath, sff)) 61917c478bd9Sstevel@tonic-gate continue; 61927c478bd9Sstevel@tonic-gate 61937c478bd9Sstevel@tonic-gate if (qg->qg_qpaths == NULL) 61947c478bd9Sstevel@tonic-gate { 61957c478bd9Sstevel@tonic-gate slotsleft = INITIAL_SLOTS; 6196058561cbSjbeck qg->qg_qpaths = (QPATHS *)xalloc((sizeof(*qg->qg_qpaths)) * 61977c478bd9Sstevel@tonic-gate slotsleft); 61987c478bd9Sstevel@tonic-gate qg->qg_numqueues = 0; 61997c478bd9Sstevel@tonic-gate } 62007c478bd9Sstevel@tonic-gate else if (slotsleft < 1) 62017c478bd9Sstevel@tonic-gate { 62027c478bd9Sstevel@tonic-gate qg->qg_qpaths = (QPATHS *)sm_realloc((char *)qg->qg_qpaths, 6203058561cbSjbeck (sizeof(*qg->qg_qpaths)) * 62047c478bd9Sstevel@tonic-gate (qg->qg_numqueues + 62057c478bd9Sstevel@tonic-gate ADD_SLOTS)); 62067c478bd9Sstevel@tonic-gate if (qg->qg_qpaths == NULL) 62077c478bd9Sstevel@tonic-gate { 62087c478bd9Sstevel@tonic-gate (void) closedir(dp); 62097c478bd9Sstevel@tonic-gate return qn; 62107c478bd9Sstevel@tonic-gate } 62117c478bd9Sstevel@tonic-gate slotsleft += ADD_SLOTS; 62127c478bd9Sstevel@tonic-gate } 62137c478bd9Sstevel@tonic-gate 62147c478bd9Sstevel@tonic-gate /* check subdirs */ 62157c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_subdirs = QP_NOSUB; 62167c478bd9Sstevel@tonic-gate 62177c478bd9Sstevel@tonic-gate #define CHKRSUBDIR(name, flag) \ 6218058561cbSjbeck (void) sm_strlcpyn(subdir, sizeof(subdir), 3, relpath, "/", name); \ 62197c478bd9Sstevel@tonic-gate if (chkqdir(subdir, sff)) \ 62207c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_subdirs |= flag; \ 62217c478bd9Sstevel@tonic-gate else 62227c478bd9Sstevel@tonic-gate 62237c478bd9Sstevel@tonic-gate 62247c478bd9Sstevel@tonic-gate CHKRSUBDIR("qf", QP_SUBQF); 62257c478bd9Sstevel@tonic-gate CHKRSUBDIR("df", QP_SUBDF); 62267c478bd9Sstevel@tonic-gate CHKRSUBDIR("xf", QP_SUBXF); 62277c478bd9Sstevel@tonic-gate 62287c478bd9Sstevel@tonic-gate /* assert(strlen(d->d_name) < MAXPATHLEN - 14) */ 62297c478bd9Sstevel@tonic-gate /* maybe even - 17 (subdirs) */ 62307c478bd9Sstevel@tonic-gate 62317c478bd9Sstevel@tonic-gate if (prefix[0] != '.') 62327c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_name = 62337c478bd9Sstevel@tonic-gate newstr(relpath); 62347c478bd9Sstevel@tonic-gate else 62357c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_name = 62367c478bd9Sstevel@tonic-gate newstr(d->d_name); 62377c478bd9Sstevel@tonic-gate 62387c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 62397c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: %d: \"%s\" cached (%x).\n", 62407c478bd9Sstevel@tonic-gate qg->qg_numqueues, relpath, 62417c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_subdirs); 62427c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 62437c478bd9Sstevel@tonic-gate qg->qg_qpaths[qg->qg_numqueues].qp_idx = qn; 62447c478bd9Sstevel@tonic-gate *phash = hash_q(relpath, *phash); 62457c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 62467c478bd9Sstevel@tonic-gate qg->qg_numqueues++; 62477c478bd9Sstevel@tonic-gate ++qn; 62487c478bd9Sstevel@tonic-gate slotsleft--; 62497c478bd9Sstevel@tonic-gate } 62507c478bd9Sstevel@tonic-gate (void) closedir(dp); 62517c478bd9Sstevel@tonic-gate 62527c478bd9Sstevel@tonic-gate /* undo damage */ 62537c478bd9Sstevel@tonic-gate *delim = '/'; 62547c478bd9Sstevel@tonic-gate } 62557c478bd9Sstevel@tonic-gate if (qg->qg_numqueues == 0) 62567c478bd9Sstevel@tonic-gate { 6257058561cbSjbeck qg->qg_qpaths = (QPATHS *) xalloc(sizeof(*qg->qg_qpaths)); 62587c478bd9Sstevel@tonic-gate 62597c478bd9Sstevel@tonic-gate /* test path to get warning messages */ 62607c478bd9Sstevel@tonic-gate i = safedirpath(qpath, RunAsUid, RunAsGid, NULL, sff, 0, 0); 62617c478bd9Sstevel@tonic-gate if (i == ENOENT) 62627c478bd9Sstevel@tonic-gate { 62637c478bd9Sstevel@tonic-gate syserr("can not opendir(%s)", qpath); 62647c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 62657c478bd9Sstevel@tonic-gate sm_dprintf("multiqueue_cache: opendir(\"%s\"): %s\n", 62667c478bd9Sstevel@tonic-gate qpath, sm_errstring(i)); 62677c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 62687c478bd9Sstevel@tonic-gate return qn; 62697c478bd9Sstevel@tonic-gate } 62707c478bd9Sstevel@tonic-gate 62717c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_subdirs = QP_NOSUB; 62727c478bd9Sstevel@tonic-gate qg->qg_numqueues = 1; 62737c478bd9Sstevel@tonic-gate 62747c478bd9Sstevel@tonic-gate /* check subdirs */ 62757c478bd9Sstevel@tonic-gate #define CHKSUBDIR(name, flag) \ 6276058561cbSjbeck (void) sm_strlcpyn(subdir, sizeof(subdir), 3, qg->qg_qdir, "/", name); \ 62777c478bd9Sstevel@tonic-gate if (chkqdir(subdir, sff)) \ 62787c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_subdirs |= flag; \ 62797c478bd9Sstevel@tonic-gate else 62807c478bd9Sstevel@tonic-gate 62817c478bd9Sstevel@tonic-gate CHKSUBDIR("qf", QP_SUBQF); 62827c478bd9Sstevel@tonic-gate CHKSUBDIR("df", QP_SUBDF); 62837c478bd9Sstevel@tonic-gate CHKSUBDIR("xf", QP_SUBXF); 62847c478bd9Sstevel@tonic-gate 62857c478bd9Sstevel@tonic-gate if (qg->qg_qdir[blen - 1] != '\0' && 62867c478bd9Sstevel@tonic-gate qg->qg_qdir[blen] != '\0') 62877c478bd9Sstevel@tonic-gate { 62887c478bd9Sstevel@tonic-gate /* 62897c478bd9Sstevel@tonic-gate ** Copy the last component into qpaths and 62907c478bd9Sstevel@tonic-gate ** cut off qdir 62917c478bd9Sstevel@tonic-gate */ 62927c478bd9Sstevel@tonic-gate 62937c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_name = newstr(qg->qg_qdir + blen); 62947c478bd9Sstevel@tonic-gate qg->qg_qdir[blen - 1] = '\0'; 62957c478bd9Sstevel@tonic-gate } 62967c478bd9Sstevel@tonic-gate else 62977c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_name = newstr("."); 62987c478bd9Sstevel@tonic-gate 62997c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 63007c478bd9Sstevel@tonic-gate qg->qg_qpaths[0].qp_idx = qn; 63017c478bd9Sstevel@tonic-gate *phash = hash_q(qg->qg_qpaths[0].qp_name, *phash); 63027c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 63037c478bd9Sstevel@tonic-gate ++qn; 63047c478bd9Sstevel@tonic-gate } 63057c478bd9Sstevel@tonic-gate return qn; 63067c478bd9Sstevel@tonic-gate } 63077c478bd9Sstevel@tonic-gate 63087c478bd9Sstevel@tonic-gate /* 63097c478bd9Sstevel@tonic-gate ** FILESYS_FIND -- find entry in FileSys table, or add new one 63107c478bd9Sstevel@tonic-gate ** 63117c478bd9Sstevel@tonic-gate ** Given the pathname of a directory, determine the file system 63127c478bd9Sstevel@tonic-gate ** in which that directory resides, and return a pointer to the 63137c478bd9Sstevel@tonic-gate ** entry in the FileSys table that describes the file system. 63147c478bd9Sstevel@tonic-gate ** A new entry is added if necessary (and requested). 63157c478bd9Sstevel@tonic-gate ** If the directory does not exist, -1 is returned. 63167c478bd9Sstevel@tonic-gate ** 63177c478bd9Sstevel@tonic-gate ** Parameters: 631849218d4fSjbeck ** name -- name of directory (must be persistent!) 631949218d4fSjbeck ** path -- pathname of directory (name plus maybe "/df") 63207c478bd9Sstevel@tonic-gate ** add -- add to structure if not found. 63217c478bd9Sstevel@tonic-gate ** 63227c478bd9Sstevel@tonic-gate ** Returns: 63237c478bd9Sstevel@tonic-gate ** >=0: found: index in file system table 63247c478bd9Sstevel@tonic-gate ** <0: some error, i.e., 63257c478bd9Sstevel@tonic-gate ** FSF_TOO_MANY: too many filesystems (-> syserr()) 63267c478bd9Sstevel@tonic-gate ** FSF_STAT_FAIL: can't stat() filesystem (-> syserr()) 63277c478bd9Sstevel@tonic-gate ** FSF_NOT_FOUND: not in list 63287c478bd9Sstevel@tonic-gate */ 63297c478bd9Sstevel@tonic-gate 6330058561cbSjbeck static short filesys_find __P((const char *, const char *, bool)); 63317c478bd9Sstevel@tonic-gate 63327c478bd9Sstevel@tonic-gate #define FSF_NOT_FOUND (-1) 63337c478bd9Sstevel@tonic-gate #define FSF_STAT_FAIL (-2) 63347c478bd9Sstevel@tonic-gate #define FSF_TOO_MANY (-3) 63357c478bd9Sstevel@tonic-gate 63367c478bd9Sstevel@tonic-gate static short 633749218d4fSjbeck filesys_find(name, path, add) 6338058561cbSjbeck const char *name; 6339058561cbSjbeck const char *path; 63407c478bd9Sstevel@tonic-gate bool add; 63417c478bd9Sstevel@tonic-gate { 63427c478bd9Sstevel@tonic-gate struct stat st; 63437c478bd9Sstevel@tonic-gate short i; 63447c478bd9Sstevel@tonic-gate 63457c478bd9Sstevel@tonic-gate if (stat(path, &st) < 0) 63467c478bd9Sstevel@tonic-gate { 63477c478bd9Sstevel@tonic-gate syserr("cannot stat queue directory %s", path); 63487c478bd9Sstevel@tonic-gate return FSF_STAT_FAIL; 63497c478bd9Sstevel@tonic-gate } 63507c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i) 63517c478bd9Sstevel@tonic-gate { 63527c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(i) == st.st_dev) 63531daa5768Sjbeck { 63541daa5768Sjbeck /* 63551daa5768Sjbeck ** Make sure the file system (FS) name is set: 63561daa5768Sjbeck ** even though the source code indicates that 63571daa5768Sjbeck ** FILE_SYS_DEV() is only set below, it could be 63581daa5768Sjbeck ** set via shared memory, hence we need to perform 63591daa5768Sjbeck ** this check/assignment here. 63601daa5768Sjbeck */ 63611daa5768Sjbeck 63621daa5768Sjbeck if (NULL == FILE_SYS_NAME(i)) 63631daa5768Sjbeck FILE_SYS_NAME(i) = name; 63647c478bd9Sstevel@tonic-gate return i; 63651daa5768Sjbeck } 63667c478bd9Sstevel@tonic-gate } 63677c478bd9Sstevel@tonic-gate if (i >= MAXFILESYS) 63687c478bd9Sstevel@tonic-gate { 63697c478bd9Sstevel@tonic-gate syserr("too many queue file systems (%d max)", MAXFILESYS); 63707c478bd9Sstevel@tonic-gate return FSF_TOO_MANY; 63717c478bd9Sstevel@tonic-gate } 63727c478bd9Sstevel@tonic-gate if (!add) 63737c478bd9Sstevel@tonic-gate return FSF_NOT_FOUND; 63747c478bd9Sstevel@tonic-gate 63757c478bd9Sstevel@tonic-gate ++NumFileSys; 637649218d4fSjbeck FILE_SYS_NAME(i) = name; 63777c478bd9Sstevel@tonic-gate FILE_SYS_DEV(i) = st.st_dev; 63787c478bd9Sstevel@tonic-gate FILE_SYS_AVAIL(i) = 0; 63797c478bd9Sstevel@tonic-gate FILE_SYS_BLKSIZE(i) = 1024; /* avoid divide by zero */ 63807c478bd9Sstevel@tonic-gate return i; 63817c478bd9Sstevel@tonic-gate } 63827c478bd9Sstevel@tonic-gate 63837c478bd9Sstevel@tonic-gate /* 63847c478bd9Sstevel@tonic-gate ** FILESYS_SETUP -- set up mapping from queue directories to file systems 63857c478bd9Sstevel@tonic-gate ** 63867c478bd9Sstevel@tonic-gate ** This data structure is used to efficiently check the amount of 63877c478bd9Sstevel@tonic-gate ** free space available in a set of queue directories. 63887c478bd9Sstevel@tonic-gate ** 63897c478bd9Sstevel@tonic-gate ** Parameters: 63907c478bd9Sstevel@tonic-gate ** add -- initialize structure if necessary. 63917c478bd9Sstevel@tonic-gate ** 63927c478bd9Sstevel@tonic-gate ** Returns: 63937c478bd9Sstevel@tonic-gate ** 0: success 63947c478bd9Sstevel@tonic-gate ** <0: some error, i.e., 63957c478bd9Sstevel@tonic-gate ** FSF_NOT_FOUND: not in list 63967c478bd9Sstevel@tonic-gate ** FSF_STAT_FAIL: can't stat() filesystem (-> syserr()) 63977c478bd9Sstevel@tonic-gate ** FSF_TOO_MANY: too many filesystems (-> syserr()) 63987c478bd9Sstevel@tonic-gate */ 63997c478bd9Sstevel@tonic-gate 64007c478bd9Sstevel@tonic-gate static int filesys_setup __P((bool)); 64017c478bd9Sstevel@tonic-gate 64027c478bd9Sstevel@tonic-gate static int 64037c478bd9Sstevel@tonic-gate filesys_setup(add) 64047c478bd9Sstevel@tonic-gate bool add; 64057c478bd9Sstevel@tonic-gate { 64067c478bd9Sstevel@tonic-gate int i, j; 64077c478bd9Sstevel@tonic-gate short fs; 64087c478bd9Sstevel@tonic-gate int ret; 64097c478bd9Sstevel@tonic-gate 64107c478bd9Sstevel@tonic-gate ret = 0; 64117c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 64127c478bd9Sstevel@tonic-gate { 64137c478bd9Sstevel@tonic-gate for (j = 0; j < Queue[i]->qg_numqueues; ++j) 64147c478bd9Sstevel@tonic-gate { 64157c478bd9Sstevel@tonic-gate QPATHS *qp = &Queue[i]->qg_qpaths[j]; 641649218d4fSjbeck char qddf[MAXPATHLEN]; 64177c478bd9Sstevel@tonic-gate 6418058561cbSjbeck (void) sm_strlcpyn(qddf, sizeof(qddf), 2, qp->qp_name, 641949218d4fSjbeck (bitset(QP_SUBDF, qp->qp_subdirs) 642049218d4fSjbeck ? "/df" : "")); 642149218d4fSjbeck fs = filesys_find(qp->qp_name, qddf, add); 64227c478bd9Sstevel@tonic-gate if (fs >= 0) 64237c478bd9Sstevel@tonic-gate qp->qp_fsysidx = fs; 64247c478bd9Sstevel@tonic-gate else 64257c478bd9Sstevel@tonic-gate qp->qp_fsysidx = 0; 64267c478bd9Sstevel@tonic-gate if (fs < ret) 64277c478bd9Sstevel@tonic-gate ret = fs; 64287c478bd9Sstevel@tonic-gate } 64297c478bd9Sstevel@tonic-gate } 64307c478bd9Sstevel@tonic-gate return ret; 64317c478bd9Sstevel@tonic-gate } 64327c478bd9Sstevel@tonic-gate 64337c478bd9Sstevel@tonic-gate /* 64347c478bd9Sstevel@tonic-gate ** FILESYS_UPDATE -- update amount of free space on all file systems 64357c478bd9Sstevel@tonic-gate ** 64367c478bd9Sstevel@tonic-gate ** The FileSys table is used to cache the amount of free space 64377c478bd9Sstevel@tonic-gate ** available on all queue directory file systems. 64387c478bd9Sstevel@tonic-gate ** This function updates the cached information if it has expired. 64397c478bd9Sstevel@tonic-gate ** 64407c478bd9Sstevel@tonic-gate ** Parameters: 64417c478bd9Sstevel@tonic-gate ** none. 64427c478bd9Sstevel@tonic-gate ** 64437c478bd9Sstevel@tonic-gate ** Returns: 64447c478bd9Sstevel@tonic-gate ** none. 64457c478bd9Sstevel@tonic-gate ** 64467c478bd9Sstevel@tonic-gate ** Side Effects: 64477c478bd9Sstevel@tonic-gate ** Updates FileSys table. 64487c478bd9Sstevel@tonic-gate */ 64497c478bd9Sstevel@tonic-gate 64507c478bd9Sstevel@tonic-gate void 64517c478bd9Sstevel@tonic-gate filesys_update() 64527c478bd9Sstevel@tonic-gate { 64537c478bd9Sstevel@tonic-gate int i; 64547c478bd9Sstevel@tonic-gate long avail, blksize; 64557c478bd9Sstevel@tonic-gate time_t now; 64567c478bd9Sstevel@tonic-gate static time_t nextupdate = 0; 64577c478bd9Sstevel@tonic-gate 64587c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 6459058561cbSjbeck /* 6460058561cbSjbeck ** Only the daemon updates the shared memory, i.e., 6461058561cbSjbeck ** if shared memory is available but the pid is not the 6462058561cbSjbeck ** one of the daemon, then don't do anything. 6463058561cbSjbeck */ 6464058561cbSjbeck 64651daa5768Sjbeck if (ShmId != SM_SHM_NO_ID && DaemonPid != CurrentPid) 64667c478bd9Sstevel@tonic-gate return; 64677c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 64687c478bd9Sstevel@tonic-gate now = curtime(); 64697c478bd9Sstevel@tonic-gate if (now < nextupdate) 64707c478bd9Sstevel@tonic-gate return; 64717c478bd9Sstevel@tonic-gate nextupdate = now + FILESYS_UPDATE_INTERVAL; 64727c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i) 64737c478bd9Sstevel@tonic-gate { 64747c478bd9Sstevel@tonic-gate FILESYS *fs = &FILE_SYS(i); 64757c478bd9Sstevel@tonic-gate 64767c478bd9Sstevel@tonic-gate avail = freediskspace(FILE_SYS_NAME(i), &blksize); 64777c478bd9Sstevel@tonic-gate if (avail < 0 || blksize <= 0) 64787c478bd9Sstevel@tonic-gate { 64797c478bd9Sstevel@tonic-gate if (LogLevel > 5) 64807c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 64817c478bd9Sstevel@tonic-gate "filesys_update failed: %s, fs=%s, avail=%ld, blocksize=%ld", 64827c478bd9Sstevel@tonic-gate sm_errstring(errno), 64837c478bd9Sstevel@tonic-gate FILE_SYS_NAME(i), avail, blksize); 64847c478bd9Sstevel@tonic-gate fs->fs_avail = 0; 64857c478bd9Sstevel@tonic-gate fs->fs_blksize = 1024; /* avoid divide by zero */ 64867c478bd9Sstevel@tonic-gate nextupdate = now + 2; /* let's do this soon again */ 64877c478bd9Sstevel@tonic-gate } 64887c478bd9Sstevel@tonic-gate else 64897c478bd9Sstevel@tonic-gate { 64907c478bd9Sstevel@tonic-gate fs->fs_avail = avail; 64917c478bd9Sstevel@tonic-gate fs->fs_blksize = blksize; 64927c478bd9Sstevel@tonic-gate } 64937c478bd9Sstevel@tonic-gate } 64947c478bd9Sstevel@tonic-gate } 64957c478bd9Sstevel@tonic-gate 64967c478bd9Sstevel@tonic-gate #if _FFR_ANY_FREE_FS 64977c478bd9Sstevel@tonic-gate /* 64987c478bd9Sstevel@tonic-gate ** FILESYS_FREE -- check whether there is at least one fs with enough space. 64997c478bd9Sstevel@tonic-gate ** 65007c478bd9Sstevel@tonic-gate ** Parameters: 65017c478bd9Sstevel@tonic-gate ** fsize -- file size in bytes 65027c478bd9Sstevel@tonic-gate ** 65037c478bd9Sstevel@tonic-gate ** Returns: 65047c478bd9Sstevel@tonic-gate ** true iff there is one fs with more than fsize bytes free. 65057c478bd9Sstevel@tonic-gate */ 65067c478bd9Sstevel@tonic-gate 65077c478bd9Sstevel@tonic-gate bool 65087c478bd9Sstevel@tonic-gate filesys_free(fsize) 65097c478bd9Sstevel@tonic-gate long fsize; 65107c478bd9Sstevel@tonic-gate { 65117c478bd9Sstevel@tonic-gate int i; 65127c478bd9Sstevel@tonic-gate 65137c478bd9Sstevel@tonic-gate if (fsize <= 0) 65147c478bd9Sstevel@tonic-gate return true; 65157c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i) 65167c478bd9Sstevel@tonic-gate { 65177c478bd9Sstevel@tonic-gate long needed = 0; 65187c478bd9Sstevel@tonic-gate 65197c478bd9Sstevel@tonic-gate if (FILE_SYS_AVAIL(i) < 0 || FILE_SYS_BLKSIZE(i) <= 0) 65207c478bd9Sstevel@tonic-gate continue; 65217c478bd9Sstevel@tonic-gate needed += fsize / FILE_SYS_BLKSIZE(i) 65227c478bd9Sstevel@tonic-gate + ((fsize % FILE_SYS_BLKSIZE(i) 65237c478bd9Sstevel@tonic-gate > 0) ? 1 : 0) 65247c478bd9Sstevel@tonic-gate + MinBlocksFree; 65257c478bd9Sstevel@tonic-gate if (needed <= FILE_SYS_AVAIL(i)) 65267c478bd9Sstevel@tonic-gate return true; 65277c478bd9Sstevel@tonic-gate } 65287c478bd9Sstevel@tonic-gate return false; 65297c478bd9Sstevel@tonic-gate } 65307c478bd9Sstevel@tonic-gate #endif /* _FFR_ANY_FREE_FS */ 65317c478bd9Sstevel@tonic-gate 65327c478bd9Sstevel@tonic-gate /* 65337c478bd9Sstevel@tonic-gate ** DISK_STATUS -- show amount of free space in queue directories 65347c478bd9Sstevel@tonic-gate ** 65357c478bd9Sstevel@tonic-gate ** Parameters: 65367c478bd9Sstevel@tonic-gate ** out -- output file pointer. 65377c478bd9Sstevel@tonic-gate ** prefix -- string to output in front of each line. 65387c478bd9Sstevel@tonic-gate ** 65397c478bd9Sstevel@tonic-gate ** Returns: 65407c478bd9Sstevel@tonic-gate ** none. 65417c478bd9Sstevel@tonic-gate */ 65427c478bd9Sstevel@tonic-gate 65437c478bd9Sstevel@tonic-gate void 65447c478bd9Sstevel@tonic-gate disk_status(out, prefix) 65457c478bd9Sstevel@tonic-gate SM_FILE_T *out; 65467c478bd9Sstevel@tonic-gate char *prefix; 65477c478bd9Sstevel@tonic-gate { 65487c478bd9Sstevel@tonic-gate int i; 65497c478bd9Sstevel@tonic-gate long avail, blksize; 65507c478bd9Sstevel@tonic-gate long free; 65517c478bd9Sstevel@tonic-gate 65527c478bd9Sstevel@tonic-gate for (i = 0; i < NumFileSys; ++i) 65537c478bd9Sstevel@tonic-gate { 65547c478bd9Sstevel@tonic-gate avail = freediskspace(FILE_SYS_NAME(i), &blksize); 65557c478bd9Sstevel@tonic-gate if (avail >= 0 && blksize > 0) 65567c478bd9Sstevel@tonic-gate { 65577c478bd9Sstevel@tonic-gate free = (long)((double) avail * 65587c478bd9Sstevel@tonic-gate ((double) blksize / 1024)); 65597c478bd9Sstevel@tonic-gate } 65607c478bd9Sstevel@tonic-gate else 65617c478bd9Sstevel@tonic-gate free = -1; 65627c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(out, SM_TIME_DEFAULT, 65637c478bd9Sstevel@tonic-gate "%s%d/%s/%ld\r\n", 65647c478bd9Sstevel@tonic-gate prefix, i, 65657c478bd9Sstevel@tonic-gate FILE_SYS_NAME(i), 65667c478bd9Sstevel@tonic-gate free); 65677c478bd9Sstevel@tonic-gate } 65687c478bd9Sstevel@tonic-gate } 65697c478bd9Sstevel@tonic-gate 65707c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 65717c478bd9Sstevel@tonic-gate 65727c478bd9Sstevel@tonic-gate /* 65737c478bd9Sstevel@tonic-gate ** INIT_SEM -- initialize semaphore system 65747c478bd9Sstevel@tonic-gate ** 65757c478bd9Sstevel@tonic-gate ** Parameters: 65767c478bd9Sstevel@tonic-gate ** owner -- is this the owner of semaphores? 65777c478bd9Sstevel@tonic-gate ** 65787c478bd9Sstevel@tonic-gate ** Returns: 65797c478bd9Sstevel@tonic-gate ** none. 65807c478bd9Sstevel@tonic-gate */ 65817c478bd9Sstevel@tonic-gate 65827c478bd9Sstevel@tonic-gate #if _FFR_USE_SEM_LOCKING 65837c478bd9Sstevel@tonic-gate #if SM_CONF_SEM 65847c478bd9Sstevel@tonic-gate static int SemId = -1; /* Semaphore Id */ 65857c478bd9Sstevel@tonic-gate int SemKey = SM_SEM_KEY; 65867c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SEM */ 65877c478bd9Sstevel@tonic-gate #endif /* _FFR_USE_SEM_LOCKING */ 65887c478bd9Sstevel@tonic-gate 65897c478bd9Sstevel@tonic-gate static void init_sem __P((bool)); 65907c478bd9Sstevel@tonic-gate 65917c478bd9Sstevel@tonic-gate static void 65927c478bd9Sstevel@tonic-gate init_sem(owner) 65937c478bd9Sstevel@tonic-gate bool owner; 65947c478bd9Sstevel@tonic-gate { 65957c478bd9Sstevel@tonic-gate #if _FFR_USE_SEM_LOCKING 65967c478bd9Sstevel@tonic-gate #if SM_CONF_SEM 65977c478bd9Sstevel@tonic-gate SemId = sm_sem_start(SemKey, 1, 0, owner); 65987c478bd9Sstevel@tonic-gate if (SemId < 0) 65997c478bd9Sstevel@tonic-gate { 66007c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 66017c478bd9Sstevel@tonic-gate "func=init_sem, sem_key=%ld, sm_sem_start=%d", 66027c478bd9Sstevel@tonic-gate (long) SemKey, SemId); 66037c478bd9Sstevel@tonic-gate return; 66047c478bd9Sstevel@tonic-gate } 66057c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SEM */ 66067c478bd9Sstevel@tonic-gate #endif /* _FFR_USE_SEM_LOCKING */ 66077c478bd9Sstevel@tonic-gate return; 66087c478bd9Sstevel@tonic-gate } 66097c478bd9Sstevel@tonic-gate 66107c478bd9Sstevel@tonic-gate /* 66117c478bd9Sstevel@tonic-gate ** STOP_SEM -- stop semaphore system 66127c478bd9Sstevel@tonic-gate ** 66137c478bd9Sstevel@tonic-gate ** Parameters: 66147c478bd9Sstevel@tonic-gate ** owner -- is this the owner of semaphores? 66157c478bd9Sstevel@tonic-gate ** 66167c478bd9Sstevel@tonic-gate ** Returns: 66177c478bd9Sstevel@tonic-gate ** none. 66187c478bd9Sstevel@tonic-gate */ 66197c478bd9Sstevel@tonic-gate 66207c478bd9Sstevel@tonic-gate static void stop_sem __P((bool)); 66217c478bd9Sstevel@tonic-gate 66227c478bd9Sstevel@tonic-gate static void 66237c478bd9Sstevel@tonic-gate stop_sem(owner) 66247c478bd9Sstevel@tonic-gate bool owner; 66257c478bd9Sstevel@tonic-gate { 66267c478bd9Sstevel@tonic-gate #if _FFR_USE_SEM_LOCKING 66277c478bd9Sstevel@tonic-gate #if SM_CONF_SEM 66287c478bd9Sstevel@tonic-gate if (owner && SemId >= 0) 66297c478bd9Sstevel@tonic-gate sm_sem_stop(SemId); 66307c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SEM */ 66317c478bd9Sstevel@tonic-gate #endif /* _FFR_USE_SEM_LOCKING */ 66327c478bd9Sstevel@tonic-gate return; 66337c478bd9Sstevel@tonic-gate } 66347c478bd9Sstevel@tonic-gate 66357c478bd9Sstevel@tonic-gate /* 66367c478bd9Sstevel@tonic-gate ** UPD_QS -- update information about queue when adding/deleting an entry 66377c478bd9Sstevel@tonic-gate ** 66387c478bd9Sstevel@tonic-gate ** Parameters: 66397c478bd9Sstevel@tonic-gate ** e -- envelope. 66407c478bd9Sstevel@tonic-gate ** count -- add/remove entry (+1/0/-1: add/no change/remove) 66417c478bd9Sstevel@tonic-gate ** space -- update the space available as well. 66427c478bd9Sstevel@tonic-gate ** (>0/0/<0: add/no change/remove) 66437c478bd9Sstevel@tonic-gate ** where -- caller (for logging) 66447c478bd9Sstevel@tonic-gate ** 66457c478bd9Sstevel@tonic-gate ** Returns: 66467c478bd9Sstevel@tonic-gate ** none. 66477c478bd9Sstevel@tonic-gate ** 66487c478bd9Sstevel@tonic-gate ** Side Effects: 66497c478bd9Sstevel@tonic-gate ** Modifies available space in filesystem. 66507c478bd9Sstevel@tonic-gate ** Changes number of entries in queue directory. 66517c478bd9Sstevel@tonic-gate */ 66527c478bd9Sstevel@tonic-gate 66537c478bd9Sstevel@tonic-gate void 66547c478bd9Sstevel@tonic-gate upd_qs(e, count, space, where) 66557c478bd9Sstevel@tonic-gate ENVELOPE *e; 66567c478bd9Sstevel@tonic-gate int count; 66577c478bd9Sstevel@tonic-gate int space; 66587c478bd9Sstevel@tonic-gate char *where; 66597c478bd9Sstevel@tonic-gate { 66607c478bd9Sstevel@tonic-gate short fidx; 66617c478bd9Sstevel@tonic-gate int idx; 66627c478bd9Sstevel@tonic-gate # if _FFR_USE_SEM_LOCKING 66637c478bd9Sstevel@tonic-gate int r; 66647c478bd9Sstevel@tonic-gate # endif /* _FFR_USE_SEM_LOCKING */ 66657c478bd9Sstevel@tonic-gate long s; 66667c478bd9Sstevel@tonic-gate 66677c478bd9Sstevel@tonic-gate if (ShmId == SM_SHM_NO_ID || e == NULL) 66687c478bd9Sstevel@tonic-gate return; 66697c478bd9Sstevel@tonic-gate if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR) 66707c478bd9Sstevel@tonic-gate return; 66717c478bd9Sstevel@tonic-gate idx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_idx; 66727c478bd9Sstevel@tonic-gate if (tTd(73,2)) 66737c478bd9Sstevel@tonic-gate sm_dprintf("func=upd_qs, count=%d, space=%d, where=%s, idx=%d, entries=%d\n", 66747c478bd9Sstevel@tonic-gate count, space, where, idx, QSHM_ENTRIES(idx)); 66757c478bd9Sstevel@tonic-gate 66767c478bd9Sstevel@tonic-gate /* XXX in theory this needs to be protected with a mutex */ 66777c478bd9Sstevel@tonic-gate if (QSHM_ENTRIES(idx) >= 0 && count != 0) 66787c478bd9Sstevel@tonic-gate { 66797c478bd9Sstevel@tonic-gate # if _FFR_USE_SEM_LOCKING 66807c478bd9Sstevel@tonic-gate r = sm_sem_acq(SemId, 0, 1); 66817c478bd9Sstevel@tonic-gate # endif /* _FFR_USE_SEM_LOCKING */ 66827c478bd9Sstevel@tonic-gate QSHM_ENTRIES(idx) += count; 66837c478bd9Sstevel@tonic-gate # if _FFR_USE_SEM_LOCKING 66847c478bd9Sstevel@tonic-gate if (r >= 0) 66857c478bd9Sstevel@tonic-gate r = sm_sem_rel(SemId, 0, 1); 66867c478bd9Sstevel@tonic-gate # endif /* _FFR_USE_SEM_LOCKING */ 66877c478bd9Sstevel@tonic-gate } 66887c478bd9Sstevel@tonic-gate 66897c478bd9Sstevel@tonic-gate fidx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_fsysidx; 66907c478bd9Sstevel@tonic-gate if (fidx < 0) 66917c478bd9Sstevel@tonic-gate return; 66927c478bd9Sstevel@tonic-gate 66937c478bd9Sstevel@tonic-gate /* update available space also? (might be loseqfile) */ 66947c478bd9Sstevel@tonic-gate if (space == 0) 66957c478bd9Sstevel@tonic-gate return; 66967c478bd9Sstevel@tonic-gate 66977c478bd9Sstevel@tonic-gate /* convert size to blocks; this causes rounding errors */ 66987c478bd9Sstevel@tonic-gate s = e->e_msgsize / FILE_SYS_BLKSIZE(fidx); 66997c478bd9Sstevel@tonic-gate if (s == 0) 67007c478bd9Sstevel@tonic-gate return; 67017c478bd9Sstevel@tonic-gate 67027c478bd9Sstevel@tonic-gate /* XXX in theory this needs to be protected with a mutex */ 67037c478bd9Sstevel@tonic-gate if (space > 0) 67047c478bd9Sstevel@tonic-gate FILE_SYS_AVAIL(fidx) += s; 67057c478bd9Sstevel@tonic-gate else 67067c478bd9Sstevel@tonic-gate FILE_SYS_AVAIL(fidx) -= s; 67077c478bd9Sstevel@tonic-gate 67087c478bd9Sstevel@tonic-gate } 67097c478bd9Sstevel@tonic-gate 67107c478bd9Sstevel@tonic-gate static bool write_key_file __P((char *, long)); 67117c478bd9Sstevel@tonic-gate static long read_key_file __P((char *, long)); 67127c478bd9Sstevel@tonic-gate 67137c478bd9Sstevel@tonic-gate /* 67147c478bd9Sstevel@tonic-gate ** WRITE_KEY_FILE -- record some key into a file. 67157c478bd9Sstevel@tonic-gate ** 67167c478bd9Sstevel@tonic-gate ** Parameters: 67177c478bd9Sstevel@tonic-gate ** keypath -- file name. 67187c478bd9Sstevel@tonic-gate ** key -- key to write. 67197c478bd9Sstevel@tonic-gate ** 67207c478bd9Sstevel@tonic-gate ** Returns: 67217c478bd9Sstevel@tonic-gate ** true iff file could be written. 67227c478bd9Sstevel@tonic-gate ** 67237c478bd9Sstevel@tonic-gate ** Side Effects: 67247c478bd9Sstevel@tonic-gate ** writes file. 67257c478bd9Sstevel@tonic-gate */ 67267c478bd9Sstevel@tonic-gate 67277c478bd9Sstevel@tonic-gate static bool 67287c478bd9Sstevel@tonic-gate write_key_file(keypath, key) 67297c478bd9Sstevel@tonic-gate char *keypath; 67307c478bd9Sstevel@tonic-gate long key; 67317c478bd9Sstevel@tonic-gate { 67327c478bd9Sstevel@tonic-gate bool ok; 67337c478bd9Sstevel@tonic-gate long sff; 67347c478bd9Sstevel@tonic-gate SM_FILE_T *keyf; 67357c478bd9Sstevel@tonic-gate 67367c478bd9Sstevel@tonic-gate ok = false; 67377c478bd9Sstevel@tonic-gate if (keypath == NULL || *keypath == '\0') 67387c478bd9Sstevel@tonic-gate return ok; 67397c478bd9Sstevel@tonic-gate sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT; 67407c478bd9Sstevel@tonic-gate if (TrustedUid != 0 && RealUid == TrustedUid) 67417c478bd9Sstevel@tonic-gate sff |= SFF_OPENASROOT; 67427c478bd9Sstevel@tonic-gate keyf = safefopen(keypath, O_WRONLY|O_TRUNC, FileMode, sff); 67437c478bd9Sstevel@tonic-gate if (keyf == NULL) 67447c478bd9Sstevel@tonic-gate { 67457c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, "unable to write %s: %s", 67467c478bd9Sstevel@tonic-gate keypath, sm_errstring(errno)); 67477c478bd9Sstevel@tonic-gate } 67487c478bd9Sstevel@tonic-gate else 67497c478bd9Sstevel@tonic-gate { 675049218d4fSjbeck if (geteuid() == 0 && RunAsUid != 0) 675149218d4fSjbeck { 675249218d4fSjbeck # if HASFCHOWN 675349218d4fSjbeck int fd; 675449218d4fSjbeck 675549218d4fSjbeck fd = keyf->f_file; 675649218d4fSjbeck if (fd >= 0 && fchown(fd, RunAsUid, -1) < 0) 675749218d4fSjbeck { 675849218d4fSjbeck int err = errno; 675949218d4fSjbeck 676049218d4fSjbeck sm_syslog(LOG_ALERT, NOQID, 676149218d4fSjbeck "ownership change on %s to %d failed: %s", 676249218d4fSjbeck keypath, RunAsUid, sm_errstring(err)); 676349218d4fSjbeck } 676449218d4fSjbeck # endif /* HASFCHOWN */ 676549218d4fSjbeck } 67667c478bd9Sstevel@tonic-gate ok = sm_io_fprintf(keyf, SM_TIME_DEFAULT, "%ld\n", key) != 67677c478bd9Sstevel@tonic-gate SM_IO_EOF; 67687c478bd9Sstevel@tonic-gate ok = (sm_io_close(keyf, SM_TIME_DEFAULT) != SM_IO_EOF) && ok; 67697c478bd9Sstevel@tonic-gate } 67707c478bd9Sstevel@tonic-gate return ok; 67717c478bd9Sstevel@tonic-gate } 67727c478bd9Sstevel@tonic-gate 67737c478bd9Sstevel@tonic-gate /* 67747c478bd9Sstevel@tonic-gate ** READ_KEY_FILE -- read a key from a file. 67757c478bd9Sstevel@tonic-gate ** 67767c478bd9Sstevel@tonic-gate ** Parameters: 67777c478bd9Sstevel@tonic-gate ** keypath -- file name. 67787c478bd9Sstevel@tonic-gate ** key -- default key. 67797c478bd9Sstevel@tonic-gate ** 67807c478bd9Sstevel@tonic-gate ** Returns: 67817c478bd9Sstevel@tonic-gate ** key. 67827c478bd9Sstevel@tonic-gate */ 67837c478bd9Sstevel@tonic-gate 67847c478bd9Sstevel@tonic-gate static long 67857c478bd9Sstevel@tonic-gate read_key_file(keypath, key) 67867c478bd9Sstevel@tonic-gate char *keypath; 67877c478bd9Sstevel@tonic-gate long key; 67887c478bd9Sstevel@tonic-gate { 67897c478bd9Sstevel@tonic-gate int r; 67907c478bd9Sstevel@tonic-gate long sff, n; 67917c478bd9Sstevel@tonic-gate SM_FILE_T *keyf; 67927c478bd9Sstevel@tonic-gate 67937c478bd9Sstevel@tonic-gate if (keypath == NULL || *keypath == '\0') 67947c478bd9Sstevel@tonic-gate return key; 67957c478bd9Sstevel@tonic-gate sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY; 67967c478bd9Sstevel@tonic-gate if (RealUid == 0 || (TrustedUid != 0 && RealUid == TrustedUid)) 67977c478bd9Sstevel@tonic-gate sff |= SFF_OPENASROOT; 67987c478bd9Sstevel@tonic-gate keyf = safefopen(keypath, O_RDONLY, FileMode, sff); 67997c478bd9Sstevel@tonic-gate if (keyf == NULL) 68007c478bd9Sstevel@tonic-gate { 68017c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, "unable to read %s: %s", 68027c478bd9Sstevel@tonic-gate keypath, sm_errstring(errno)); 68037c478bd9Sstevel@tonic-gate } 68047c478bd9Sstevel@tonic-gate else 68057c478bd9Sstevel@tonic-gate { 68067c478bd9Sstevel@tonic-gate r = sm_io_fscanf(keyf, SM_TIME_DEFAULT, "%ld", &n); 68077c478bd9Sstevel@tonic-gate if (r == 1) 68087c478bd9Sstevel@tonic-gate key = n; 68097c478bd9Sstevel@tonic-gate (void) sm_io_close(keyf, SM_TIME_DEFAULT); 68107c478bd9Sstevel@tonic-gate } 68117c478bd9Sstevel@tonic-gate return key; 68127c478bd9Sstevel@tonic-gate } 68137c478bd9Sstevel@tonic-gate 68147c478bd9Sstevel@tonic-gate /* 68157c478bd9Sstevel@tonic-gate ** INIT_SHM -- initialize shared memory structure 68167c478bd9Sstevel@tonic-gate ** 68177c478bd9Sstevel@tonic-gate ** Initialize or attach to shared memory segment. 68187c478bd9Sstevel@tonic-gate ** Currently it is not a fatal error if this doesn't work. 68197c478bd9Sstevel@tonic-gate ** However, it causes us to have a "fallback" storage location 68207c478bd9Sstevel@tonic-gate ** for everything that is supposed to be in the shared memory, 68217c478bd9Sstevel@tonic-gate ** which makes the code slightly ugly. 68227c478bd9Sstevel@tonic-gate ** 68237c478bd9Sstevel@tonic-gate ** Parameters: 68247c478bd9Sstevel@tonic-gate ** qn -- number of queue directories. 68257c478bd9Sstevel@tonic-gate ** owner -- owner of shared memory. 68267c478bd9Sstevel@tonic-gate ** hash -- identifies data that is stored in shared memory. 68277c478bd9Sstevel@tonic-gate ** 68287c478bd9Sstevel@tonic-gate ** Returns: 68297c478bd9Sstevel@tonic-gate ** none. 68307c478bd9Sstevel@tonic-gate */ 68317c478bd9Sstevel@tonic-gate 68327c478bd9Sstevel@tonic-gate static void init_shm __P((int, bool, unsigned int)); 68337c478bd9Sstevel@tonic-gate 68347c478bd9Sstevel@tonic-gate static void 68357c478bd9Sstevel@tonic-gate init_shm(qn, owner, hash) 68367c478bd9Sstevel@tonic-gate int qn; 68377c478bd9Sstevel@tonic-gate bool owner; 68387c478bd9Sstevel@tonic-gate unsigned int hash; 68397c478bd9Sstevel@tonic-gate { 68407c478bd9Sstevel@tonic-gate int i; 68417c478bd9Sstevel@tonic-gate int count; 68427c478bd9Sstevel@tonic-gate int save_errno; 68437c478bd9Sstevel@tonic-gate bool keyselect; 68447c478bd9Sstevel@tonic-gate 68457c478bd9Sstevel@tonic-gate PtrFileSys = &FileSys[0]; 68467c478bd9Sstevel@tonic-gate PNumFileSys = &Numfilesys; 68477c478bd9Sstevel@tonic-gate /* if this "key" is specified: select one yourself */ 6848058561cbSjbeck #define SEL_SHM_KEY ((key_t) -1) 6849058561cbSjbeck #define FIRST_SHM_KEY 25 68507c478bd9Sstevel@tonic-gate 68517c478bd9Sstevel@tonic-gate /* This allows us to disable shared memory at runtime. */ 68527c478bd9Sstevel@tonic-gate if (ShmKey == 0) 68537c478bd9Sstevel@tonic-gate return; 68547c478bd9Sstevel@tonic-gate 68557c478bd9Sstevel@tonic-gate count = 0; 68567c478bd9Sstevel@tonic-gate shms = SM_T_SIZE + qn * sizeof(QUEUE_SHM_T); 68577c478bd9Sstevel@tonic-gate keyselect = ShmKey == SEL_SHM_KEY; 68587c478bd9Sstevel@tonic-gate if (keyselect) 68597c478bd9Sstevel@tonic-gate { 68607c478bd9Sstevel@tonic-gate if (owner) 68617c478bd9Sstevel@tonic-gate ShmKey = FIRST_SHM_KEY; 68627c478bd9Sstevel@tonic-gate else 68637c478bd9Sstevel@tonic-gate { 6864058561cbSjbeck errno = 0; 68657c478bd9Sstevel@tonic-gate ShmKey = read_key_file(ShmKeyFile, ShmKey); 68667c478bd9Sstevel@tonic-gate keyselect = false; 68677c478bd9Sstevel@tonic-gate if (ShmKey == SEL_SHM_KEY) 6868058561cbSjbeck { 6869058561cbSjbeck save_errno = (errno != 0) ? errno : EINVAL; 68707c478bd9Sstevel@tonic-gate goto error; 6871058561cbSjbeck } 68727c478bd9Sstevel@tonic-gate } 68737c478bd9Sstevel@tonic-gate } 68747c478bd9Sstevel@tonic-gate for (;;) 68757c478bd9Sstevel@tonic-gate { 68767c478bd9Sstevel@tonic-gate /* allow read/write access for group? */ 68777c478bd9Sstevel@tonic-gate Pshm = sm_shmstart(ShmKey, shms, 68787c478bd9Sstevel@tonic-gate SHM_R|SHM_W|(SHM_R>>3)|(SHM_W>>3), 68797c478bd9Sstevel@tonic-gate &ShmId, owner); 68807c478bd9Sstevel@tonic-gate save_errno = errno; 68817c478bd9Sstevel@tonic-gate if (Pshm != NULL || !sm_file_exists(save_errno)) 68827c478bd9Sstevel@tonic-gate break; 68837c478bd9Sstevel@tonic-gate if (++count >= 3) 68847c478bd9Sstevel@tonic-gate { 68857c478bd9Sstevel@tonic-gate if (keyselect) 68867c478bd9Sstevel@tonic-gate { 68877c478bd9Sstevel@tonic-gate ++ShmKey; 68887c478bd9Sstevel@tonic-gate 68897c478bd9Sstevel@tonic-gate /* back where we started? */ 68907c478bd9Sstevel@tonic-gate if (ShmKey == SEL_SHM_KEY) 68917c478bd9Sstevel@tonic-gate break; 68927c478bd9Sstevel@tonic-gate continue; 68937c478bd9Sstevel@tonic-gate } 68947c478bd9Sstevel@tonic-gate break; 68957c478bd9Sstevel@tonic-gate } 6896058561cbSjbeck 68977c478bd9Sstevel@tonic-gate /* only sleep if we are at the first key */ 68987c478bd9Sstevel@tonic-gate if (!keyselect || ShmKey == SEL_SHM_KEY) 6899058561cbSjbeck sleep(count); 69007c478bd9Sstevel@tonic-gate } 69017c478bd9Sstevel@tonic-gate if (Pshm != NULL) 69027c478bd9Sstevel@tonic-gate { 69037c478bd9Sstevel@tonic-gate int *p; 69047c478bd9Sstevel@tonic-gate 69057c478bd9Sstevel@tonic-gate if (keyselect) 69067c478bd9Sstevel@tonic-gate (void) write_key_file(ShmKeyFile, (long) ShmKey); 69077c478bd9Sstevel@tonic-gate if (owner && RunAsUid != 0) 69087c478bd9Sstevel@tonic-gate { 6909445f2479Sjbeck i = sm_shmsetowner(ShmId, RunAsUid, RunAsGid, 0660); 69107c478bd9Sstevel@tonic-gate if (i != 0) 69117c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 6912445f2479Sjbeck "key=%ld, sm_shmsetowner=%d, RunAsUid=%d, RunAsGid=%d", 6913445f2479Sjbeck (long) ShmKey, i, RunAsUid, RunAsGid); 69147c478bd9Sstevel@tonic-gate } 69157c478bd9Sstevel@tonic-gate p = (int *) Pshm; 69167c478bd9Sstevel@tonic-gate if (owner) 69177c478bd9Sstevel@tonic-gate { 69187c478bd9Sstevel@tonic-gate *p = (int) shms; 69197c478bd9Sstevel@tonic-gate *((pid_t *) SHM_OFF_PID(Pshm)) = CurrentPid; 69207c478bd9Sstevel@tonic-gate p = (int *) SHM_OFF_TAG(Pshm); 69217c478bd9Sstevel@tonic-gate *p = hash; 69227c478bd9Sstevel@tonic-gate } 69237c478bd9Sstevel@tonic-gate else 69247c478bd9Sstevel@tonic-gate { 69257c478bd9Sstevel@tonic-gate if (*p != (int) shms) 69267c478bd9Sstevel@tonic-gate { 69277c478bd9Sstevel@tonic-gate save_errno = EINVAL; 69287c478bd9Sstevel@tonic-gate cleanup_shm(false); 69297c478bd9Sstevel@tonic-gate goto error; 69307c478bd9Sstevel@tonic-gate } 69317c478bd9Sstevel@tonic-gate p = (int *) SHM_OFF_TAG(Pshm); 69327c478bd9Sstevel@tonic-gate if (*p != (int) hash) 69337c478bd9Sstevel@tonic-gate { 69347c478bd9Sstevel@tonic-gate save_errno = EINVAL; 69357c478bd9Sstevel@tonic-gate cleanup_shm(false); 69367c478bd9Sstevel@tonic-gate goto error; 69377c478bd9Sstevel@tonic-gate } 69387c478bd9Sstevel@tonic-gate 69397c478bd9Sstevel@tonic-gate /* 69407c478bd9Sstevel@tonic-gate ** XXX how to check the pid? 69417c478bd9Sstevel@tonic-gate ** Read it from the pid-file? That does 69427c478bd9Sstevel@tonic-gate ** not need to exist. 69437c478bd9Sstevel@tonic-gate ** We could disable shm if we can't confirm 69447c478bd9Sstevel@tonic-gate ** that it is the right one. 69457c478bd9Sstevel@tonic-gate */ 69467c478bd9Sstevel@tonic-gate } 69477c478bd9Sstevel@tonic-gate 69487c478bd9Sstevel@tonic-gate PtrFileSys = (FILESYS *) OFF_FILE_SYS(Pshm); 69497c478bd9Sstevel@tonic-gate PNumFileSys = (int *) OFF_NUM_FILE_SYS(Pshm); 69507c478bd9Sstevel@tonic-gate QShm = (QUEUE_SHM_T *) OFF_QUEUE_SHM(Pshm); 69517c478bd9Sstevel@tonic-gate PRSATmpCnt = (int *) OFF_RSA_TMP_CNT(Pshm); 69527c478bd9Sstevel@tonic-gate *PRSATmpCnt = 0; 69537c478bd9Sstevel@tonic-gate if (owner) 69547c478bd9Sstevel@tonic-gate { 69557c478bd9Sstevel@tonic-gate /* initialize values in shared memory */ 69567c478bd9Sstevel@tonic-gate NumFileSys = 0; 69577c478bd9Sstevel@tonic-gate for (i = 0; i < qn; i++) 69587c478bd9Sstevel@tonic-gate QShm[i].qs_entries = -1; 69597c478bd9Sstevel@tonic-gate } 69607c478bd9Sstevel@tonic-gate init_sem(owner); 69617c478bd9Sstevel@tonic-gate return; 69627c478bd9Sstevel@tonic-gate } 69637c478bd9Sstevel@tonic-gate error: 69647c478bd9Sstevel@tonic-gate if (LogLevel > (owner ? 8 : 11)) 69657c478bd9Sstevel@tonic-gate { 69667c478bd9Sstevel@tonic-gate sm_syslog(owner ? LOG_ERR : LOG_NOTICE, NOQID, 69677c478bd9Sstevel@tonic-gate "can't %s shared memory, key=%ld: %s", 69687c478bd9Sstevel@tonic-gate owner ? "initialize" : "attach to", 69697c478bd9Sstevel@tonic-gate (long) ShmKey, sm_errstring(save_errno)); 69707c478bd9Sstevel@tonic-gate } 69717c478bd9Sstevel@tonic-gate } 69727c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 69737c478bd9Sstevel@tonic-gate 69747c478bd9Sstevel@tonic-gate 69757c478bd9Sstevel@tonic-gate /* 6976058561cbSjbeck ** SETUP_QUEUES -- set up all queue groups 69777c478bd9Sstevel@tonic-gate ** 69787c478bd9Sstevel@tonic-gate ** Parameters: 6979058561cbSjbeck ** owner -- owner of shared memory? 69807c478bd9Sstevel@tonic-gate ** 69817c478bd9Sstevel@tonic-gate ** Returns: 69827c478bd9Sstevel@tonic-gate ** none. 69837c478bd9Sstevel@tonic-gate ** 69847c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 69857c478bd9Sstevel@tonic-gate ** Side Effects: 69867c478bd9Sstevel@tonic-gate ** attaches shared memory. 69877c478bd9Sstevel@tonic-gate #endif * SM_CONF_SHM * 69887c478bd9Sstevel@tonic-gate */ 69897c478bd9Sstevel@tonic-gate 69907c478bd9Sstevel@tonic-gate void 69917c478bd9Sstevel@tonic-gate setup_queues(owner) 69927c478bd9Sstevel@tonic-gate bool owner; 69937c478bd9Sstevel@tonic-gate { 69947c478bd9Sstevel@tonic-gate int i, qn, len; 69957c478bd9Sstevel@tonic-gate unsigned int hashval; 69967c478bd9Sstevel@tonic-gate time_t now; 69977c478bd9Sstevel@tonic-gate char basedir[MAXPATHLEN]; 69987c478bd9Sstevel@tonic-gate struct stat st; 69997c478bd9Sstevel@tonic-gate 70007c478bd9Sstevel@tonic-gate /* 70017c478bd9Sstevel@tonic-gate ** Determine basedir for all queue directories. 70027c478bd9Sstevel@tonic-gate ** All queue directories must be (first level) subdirectories 70037c478bd9Sstevel@tonic-gate ** of the basedir. The basedir is the QueueDir 70047c478bd9Sstevel@tonic-gate ** without wildcards, but with trailing / 70057c478bd9Sstevel@tonic-gate */ 70067c478bd9Sstevel@tonic-gate 70077c478bd9Sstevel@tonic-gate hashval = 0; 70087c478bd9Sstevel@tonic-gate errno = 0; 7009058561cbSjbeck len = sm_strlcpy(basedir, QueueDir, sizeof(basedir)); 70107c478bd9Sstevel@tonic-gate 70117c478bd9Sstevel@tonic-gate /* Provide space for trailing '/' */ 7012058561cbSjbeck if (len >= sizeof(basedir) - 1) 70137c478bd9Sstevel@tonic-gate { 70147c478bd9Sstevel@tonic-gate syserr("QueueDirectory: path too long: %d, max %d", 7015058561cbSjbeck len, (int) sizeof(basedir) - 1); 70167c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 70177c478bd9Sstevel@tonic-gate return; 70187c478bd9Sstevel@tonic-gate } 70197c478bd9Sstevel@tonic-gate SM_ASSERT(len > 0); 70207c478bd9Sstevel@tonic-gate if (basedir[len - 1] == '*') 70217c478bd9Sstevel@tonic-gate { 70227c478bd9Sstevel@tonic-gate char *cp; 70237c478bd9Sstevel@tonic-gate 70247c478bd9Sstevel@tonic-gate cp = SM_LAST_DIR_DELIM(basedir); 70257c478bd9Sstevel@tonic-gate if (cp == NULL) 70267c478bd9Sstevel@tonic-gate { 70277c478bd9Sstevel@tonic-gate syserr("QueueDirectory: can not wildcard relative path \"%s\"", 70287c478bd9Sstevel@tonic-gate QueueDir); 70297c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 70307c478bd9Sstevel@tonic-gate sm_dprintf("setup_queues: \"%s\": Can not wildcard relative path.\n", 70317c478bd9Sstevel@tonic-gate QueueDir); 70327c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 70337c478bd9Sstevel@tonic-gate return; 70347c478bd9Sstevel@tonic-gate } 70357c478bd9Sstevel@tonic-gate 70367c478bd9Sstevel@tonic-gate /* cut off wildcard pattern */ 70377c478bd9Sstevel@tonic-gate *++cp = '\0'; 70387c478bd9Sstevel@tonic-gate len = cp - basedir; 70397c478bd9Sstevel@tonic-gate } 70407c478bd9Sstevel@tonic-gate else if (!SM_IS_DIR_DELIM(basedir[len - 1])) 70417c478bd9Sstevel@tonic-gate { 70427c478bd9Sstevel@tonic-gate /* append trailing slash since it is a directory */ 70437c478bd9Sstevel@tonic-gate basedir[len] = '/'; 70447c478bd9Sstevel@tonic-gate basedir[++len] = '\0'; 70457c478bd9Sstevel@tonic-gate } 70467c478bd9Sstevel@tonic-gate 70477c478bd9Sstevel@tonic-gate /* len counts up to the last directory delimiter */ 70487c478bd9Sstevel@tonic-gate SM_ASSERT(basedir[len - 1] == '/'); 70497c478bd9Sstevel@tonic-gate 70507c478bd9Sstevel@tonic-gate if (chdir(basedir) < 0) 70517c478bd9Sstevel@tonic-gate { 70527c478bd9Sstevel@tonic-gate int save_errno = errno; 70537c478bd9Sstevel@tonic-gate 70547c478bd9Sstevel@tonic-gate syserr("can not chdir(%s)", basedir); 70557c478bd9Sstevel@tonic-gate if (save_errno == EACCES) 70567c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 70577c478bd9Sstevel@tonic-gate "Program mode requires special privileges, e.g., root or TrustedUser.\n"); 70587c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 70597c478bd9Sstevel@tonic-gate sm_dprintf("setup_queues: \"%s\": %s\n", 70607c478bd9Sstevel@tonic-gate basedir, sm_errstring(errno)); 70617c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 70627c478bd9Sstevel@tonic-gate return; 70637c478bd9Sstevel@tonic-gate } 70647c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 70657c478bd9Sstevel@tonic-gate hashval = hash_q(basedir, hashval); 70667c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 70677c478bd9Sstevel@tonic-gate 70687c478bd9Sstevel@tonic-gate /* initialize for queue runs */ 70697c478bd9Sstevel@tonic-gate DoQueueRun = false; 70707c478bd9Sstevel@tonic-gate now = curtime(); 70717c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 70727c478bd9Sstevel@tonic-gate Queue[i]->qg_nextrun = now; 70737c478bd9Sstevel@tonic-gate 70747c478bd9Sstevel@tonic-gate 70757c478bd9Sstevel@tonic-gate if (UseMSP && OpMode != MD_TEST) 70767c478bd9Sstevel@tonic-gate { 70777c478bd9Sstevel@tonic-gate long sff = SFF_CREAT; 70787c478bd9Sstevel@tonic-gate 70797c478bd9Sstevel@tonic-gate if (stat(".", &st) < 0) 70807c478bd9Sstevel@tonic-gate { 70817c478bd9Sstevel@tonic-gate syserr("can not stat(%s)", basedir); 70827c478bd9Sstevel@tonic-gate if (tTd(41, 2)) 70837c478bd9Sstevel@tonic-gate sm_dprintf("setup_queues: \"%s\": %s\n", 70847c478bd9Sstevel@tonic-gate basedir, sm_errstring(errno)); 70857c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 70867c478bd9Sstevel@tonic-gate return; 70877c478bd9Sstevel@tonic-gate } 70887c478bd9Sstevel@tonic-gate if (RunAsUid == 0) 70897c478bd9Sstevel@tonic-gate sff |= SFF_ROOTOK; 70907c478bd9Sstevel@tonic-gate 70917c478bd9Sstevel@tonic-gate /* 70927c478bd9Sstevel@tonic-gate ** Check queue directory permissions. 70937c478bd9Sstevel@tonic-gate ** Can we write to a group writable queue directory? 70947c478bd9Sstevel@tonic-gate */ 70957c478bd9Sstevel@tonic-gate 70967c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode) && 70977c478bd9Sstevel@tonic-gate bitset(S_IWGRP, st.st_mode) && 70987c478bd9Sstevel@tonic-gate safefile(" ", RunAsUid, RunAsGid, RunAsUserName, sff, 70997c478bd9Sstevel@tonic-gate QueueFileMode, NULL) != 0) 71007c478bd9Sstevel@tonic-gate { 71017c478bd9Sstevel@tonic-gate syserr("can not write to queue directory %s (RunAsGid=%d, required=%d)", 71027c478bd9Sstevel@tonic-gate basedir, (int) RunAsGid, (int) st.st_gid); 71037c478bd9Sstevel@tonic-gate } 71047c478bd9Sstevel@tonic-gate if (bitset(S_IWOTH|S_IXOTH, st.st_mode)) 71057c478bd9Sstevel@tonic-gate { 71067c478bd9Sstevel@tonic-gate #if _FFR_MSP_PARANOIA 71077c478bd9Sstevel@tonic-gate syserr("dangerous permissions=%o on queue directory %s", 71087c478bd9Sstevel@tonic-gate (int) st.st_mode, basedir); 71097c478bd9Sstevel@tonic-gate #else /* _FFR_MSP_PARANOIA */ 71107c478bd9Sstevel@tonic-gate if (LogLevel > 0) 71117c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 71127c478bd9Sstevel@tonic-gate "dangerous permissions=%o on queue directory %s", 71137c478bd9Sstevel@tonic-gate (int) st.st_mode, basedir); 71147c478bd9Sstevel@tonic-gate #endif /* _FFR_MSP_PARANOIA */ 71157c478bd9Sstevel@tonic-gate } 71167c478bd9Sstevel@tonic-gate #if _FFR_MSP_PARANOIA 71177c478bd9Sstevel@tonic-gate if (NumQueue > 1) 71187c478bd9Sstevel@tonic-gate syserr("can not use multiple queues for MSP"); 71197c478bd9Sstevel@tonic-gate #endif /* _FFR_MSP_PARANOIA */ 71207c478bd9Sstevel@tonic-gate } 71217c478bd9Sstevel@tonic-gate 71227c478bd9Sstevel@tonic-gate /* initial number of queue directories */ 71237c478bd9Sstevel@tonic-gate qn = 0; 71247c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; i++) 71257c478bd9Sstevel@tonic-gate qn = multiqueue_cache(basedir, len, Queue[i], qn, &hashval); 71267c478bd9Sstevel@tonic-gate 71277c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 71287c478bd9Sstevel@tonic-gate init_shm(qn, owner, hashval); 71297c478bd9Sstevel@tonic-gate i = filesys_setup(owner || ShmId == SM_SHM_NO_ID); 71307c478bd9Sstevel@tonic-gate if (i == FSF_NOT_FOUND) 71317c478bd9Sstevel@tonic-gate { 71327c478bd9Sstevel@tonic-gate /* 71337c478bd9Sstevel@tonic-gate ** We didn't get the right filesystem data 71347c478bd9Sstevel@tonic-gate ** This may happen if we don't have the right shared memory. 71357c478bd9Sstevel@tonic-gate ** So let's do this without shared memory. 71367c478bd9Sstevel@tonic-gate */ 71377c478bd9Sstevel@tonic-gate 71387c478bd9Sstevel@tonic-gate SM_ASSERT(!owner); 71397c478bd9Sstevel@tonic-gate cleanup_shm(false); /* release shared memory */ 71407c478bd9Sstevel@tonic-gate i = filesys_setup(false); 71417c478bd9Sstevel@tonic-gate if (i < 0) 71427c478bd9Sstevel@tonic-gate syserr("filesys_setup failed twice, result=%d", i); 71437c478bd9Sstevel@tonic-gate else if (LogLevel > 8) 71447c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 71457c478bd9Sstevel@tonic-gate "shared memory does not contain expected data, ignored"); 71467c478bd9Sstevel@tonic-gate } 71477c478bd9Sstevel@tonic-gate #else /* SM_CONF_SHM */ 71487c478bd9Sstevel@tonic-gate i = filesys_setup(true); 71497c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 71507c478bd9Sstevel@tonic-gate if (i < 0) 71517c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 71527c478bd9Sstevel@tonic-gate } 71537c478bd9Sstevel@tonic-gate 71547c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 71557c478bd9Sstevel@tonic-gate /* 71567c478bd9Sstevel@tonic-gate ** CLEANUP_SHM -- do some cleanup work for shared memory etc 71577c478bd9Sstevel@tonic-gate ** 71587c478bd9Sstevel@tonic-gate ** Parameters: 71597c478bd9Sstevel@tonic-gate ** owner -- owner of shared memory? 71607c478bd9Sstevel@tonic-gate ** 71617c478bd9Sstevel@tonic-gate ** Returns: 71627c478bd9Sstevel@tonic-gate ** none. 71637c478bd9Sstevel@tonic-gate ** 71647c478bd9Sstevel@tonic-gate ** Side Effects: 71657c478bd9Sstevel@tonic-gate ** detaches shared memory. 71667c478bd9Sstevel@tonic-gate */ 71677c478bd9Sstevel@tonic-gate 71687c478bd9Sstevel@tonic-gate void 71697c478bd9Sstevel@tonic-gate cleanup_shm(owner) 71707c478bd9Sstevel@tonic-gate bool owner; 71717c478bd9Sstevel@tonic-gate { 71727c478bd9Sstevel@tonic-gate if (ShmId != SM_SHM_NO_ID) 71737c478bd9Sstevel@tonic-gate { 71747c478bd9Sstevel@tonic-gate if (sm_shmstop(Pshm, ShmId, owner) < 0 && LogLevel > 8) 71757c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "sm_shmstop failed=%s", 71767c478bd9Sstevel@tonic-gate sm_errstring(errno)); 71777c478bd9Sstevel@tonic-gate Pshm = NULL; 71787c478bd9Sstevel@tonic-gate ShmId = SM_SHM_NO_ID; 71797c478bd9Sstevel@tonic-gate } 71807c478bd9Sstevel@tonic-gate stop_sem(owner); 71817c478bd9Sstevel@tonic-gate } 71827c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 71837c478bd9Sstevel@tonic-gate 71847c478bd9Sstevel@tonic-gate /* 71857c478bd9Sstevel@tonic-gate ** CLEANUP_QUEUES -- do some cleanup work for queues 71867c478bd9Sstevel@tonic-gate ** 71877c478bd9Sstevel@tonic-gate ** Parameters: 71887c478bd9Sstevel@tonic-gate ** none. 71897c478bd9Sstevel@tonic-gate ** 71907c478bd9Sstevel@tonic-gate ** Returns: 71917c478bd9Sstevel@tonic-gate ** none. 71927c478bd9Sstevel@tonic-gate ** 71937c478bd9Sstevel@tonic-gate */ 71947c478bd9Sstevel@tonic-gate 71957c478bd9Sstevel@tonic-gate void 71967c478bd9Sstevel@tonic-gate cleanup_queues() 71977c478bd9Sstevel@tonic-gate { 71987c478bd9Sstevel@tonic-gate sync_queue_time(); 71997c478bd9Sstevel@tonic-gate } 72007c478bd9Sstevel@tonic-gate /* 72017c478bd9Sstevel@tonic-gate ** SET_DEF_QUEUEVAL -- set default values for a queue group. 72027c478bd9Sstevel@tonic-gate ** 72037c478bd9Sstevel@tonic-gate ** Parameters: 72047c478bd9Sstevel@tonic-gate ** qg -- queue group 72057c478bd9Sstevel@tonic-gate ** all -- set all values (true for default group)? 72067c478bd9Sstevel@tonic-gate ** 72077c478bd9Sstevel@tonic-gate ** Returns: 72087c478bd9Sstevel@tonic-gate ** none. 72097c478bd9Sstevel@tonic-gate ** 72107c478bd9Sstevel@tonic-gate ** Side Effects: 72117c478bd9Sstevel@tonic-gate ** sets default values for the queue group. 72127c478bd9Sstevel@tonic-gate */ 72137c478bd9Sstevel@tonic-gate 72147c478bd9Sstevel@tonic-gate void 72157c478bd9Sstevel@tonic-gate set_def_queueval(qg, all) 72167c478bd9Sstevel@tonic-gate QUEUEGRP *qg; 72177c478bd9Sstevel@tonic-gate bool all; 72187c478bd9Sstevel@tonic-gate { 72197c478bd9Sstevel@tonic-gate if (bitnset(QD_DEFINED, qg->qg_flags)) 72207c478bd9Sstevel@tonic-gate return; 72217c478bd9Sstevel@tonic-gate if (all) 72227c478bd9Sstevel@tonic-gate qg->qg_qdir = QueueDir; 72237c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_GROUP_SORTORDER 72247c478bd9Sstevel@tonic-gate qg->qg_sortorder = QueueSortOrder; 72257c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_GROUP_SORTORDER */ 72267c478bd9Sstevel@tonic-gate qg->qg_maxqrun = all ? MaxRunnersPerQueue : -1; 72277c478bd9Sstevel@tonic-gate qg->qg_nice = NiceQueueRun; 72287c478bd9Sstevel@tonic-gate } 72297c478bd9Sstevel@tonic-gate /* 72307c478bd9Sstevel@tonic-gate ** MAKEQUEUE -- define a new queue. 72317c478bd9Sstevel@tonic-gate ** 72327c478bd9Sstevel@tonic-gate ** Parameters: 72337c478bd9Sstevel@tonic-gate ** line -- description of queue. This is in labeled fields. 72347c478bd9Sstevel@tonic-gate ** The fields are: 72357c478bd9Sstevel@tonic-gate ** F -- the flags associated with the queue 72367c478bd9Sstevel@tonic-gate ** I -- the interval between running the queue 72377c478bd9Sstevel@tonic-gate ** J -- the maximum # of jobs in work list 72387c478bd9Sstevel@tonic-gate ** [M -- the maximum # of jobs in a queue run] 72397c478bd9Sstevel@tonic-gate ** N -- the niceness at which to run 72407c478bd9Sstevel@tonic-gate ** P -- the path to the queue 72417c478bd9Sstevel@tonic-gate ** S -- the queue sorting order 72427c478bd9Sstevel@tonic-gate ** R -- number of parallel queue runners 72437c478bd9Sstevel@tonic-gate ** r -- max recipients per envelope 72447c478bd9Sstevel@tonic-gate ** The first word is the canonical name of the queue. 72457c478bd9Sstevel@tonic-gate ** qdef -- this is a 'Q' definition from .cf 72467c478bd9Sstevel@tonic-gate ** 72477c478bd9Sstevel@tonic-gate ** Returns: 72487c478bd9Sstevel@tonic-gate ** none. 72497c478bd9Sstevel@tonic-gate ** 72507c478bd9Sstevel@tonic-gate ** Side Effects: 72517c478bd9Sstevel@tonic-gate ** enters the queue into the queue table. 72527c478bd9Sstevel@tonic-gate */ 72537c478bd9Sstevel@tonic-gate 72547c478bd9Sstevel@tonic-gate void 72557c478bd9Sstevel@tonic-gate makequeue(line, qdef) 72567c478bd9Sstevel@tonic-gate char *line; 72577c478bd9Sstevel@tonic-gate bool qdef; 72587c478bd9Sstevel@tonic-gate { 72597c478bd9Sstevel@tonic-gate register char *p; 72607c478bd9Sstevel@tonic-gate register QUEUEGRP *qg; 72617c478bd9Sstevel@tonic-gate register STAB *s; 72627c478bd9Sstevel@tonic-gate int i; 72637c478bd9Sstevel@tonic-gate char fcode; 72647c478bd9Sstevel@tonic-gate 72657c478bd9Sstevel@tonic-gate /* allocate a queue and set up defaults */ 7266058561cbSjbeck qg = (QUEUEGRP *) xalloc(sizeof(*qg)); 7267058561cbSjbeck memset((char *) qg, '\0', sizeof(*qg)); 72687c478bd9Sstevel@tonic-gate 72697c478bd9Sstevel@tonic-gate if (line[0] == '\0') 72707c478bd9Sstevel@tonic-gate { 72717c478bd9Sstevel@tonic-gate syserr("name required for queue"); 72727c478bd9Sstevel@tonic-gate return; 72737c478bd9Sstevel@tonic-gate } 72747c478bd9Sstevel@tonic-gate 72757c478bd9Sstevel@tonic-gate /* collect the queue name */ 72767c478bd9Sstevel@tonic-gate for (p = line; 72777c478bd9Sstevel@tonic-gate *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); 72787c478bd9Sstevel@tonic-gate p++) 72797c478bd9Sstevel@tonic-gate continue; 72807c478bd9Sstevel@tonic-gate if (*p != '\0') 72817c478bd9Sstevel@tonic-gate *p++ = '\0'; 72827c478bd9Sstevel@tonic-gate qg->qg_name = newstr(line); 72837c478bd9Sstevel@tonic-gate 72847c478bd9Sstevel@tonic-gate /* set default values, can be overridden below */ 72857c478bd9Sstevel@tonic-gate set_def_queueval(qg, false); 72867c478bd9Sstevel@tonic-gate 72877c478bd9Sstevel@tonic-gate /* now scan through and assign info from the fields */ 72887c478bd9Sstevel@tonic-gate while (*p != '\0') 72897c478bd9Sstevel@tonic-gate { 72907c478bd9Sstevel@tonic-gate auto char *delimptr; 72917c478bd9Sstevel@tonic-gate 72927c478bd9Sstevel@tonic-gate while (*p != '\0' && 72937c478bd9Sstevel@tonic-gate (*p == ',' || (isascii(*p) && isspace(*p)))) 72947c478bd9Sstevel@tonic-gate p++; 72957c478bd9Sstevel@tonic-gate 72967c478bd9Sstevel@tonic-gate /* p now points to field code */ 72977c478bd9Sstevel@tonic-gate fcode = *p; 72987c478bd9Sstevel@tonic-gate while (*p != '\0' && *p != '=' && *p != ',') 72997c478bd9Sstevel@tonic-gate p++; 73007c478bd9Sstevel@tonic-gate if (*p++ != '=') 73017c478bd9Sstevel@tonic-gate { 73027c478bd9Sstevel@tonic-gate syserr("queue %s: `=' expected", qg->qg_name); 73037c478bd9Sstevel@tonic-gate return; 73047c478bd9Sstevel@tonic-gate } 73057c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p)) 73067c478bd9Sstevel@tonic-gate p++; 73077c478bd9Sstevel@tonic-gate 73087c478bd9Sstevel@tonic-gate /* p now points to the field body */ 73097c478bd9Sstevel@tonic-gate p = munchstring(p, &delimptr, ','); 73107c478bd9Sstevel@tonic-gate 73117c478bd9Sstevel@tonic-gate /* install the field into the queue struct */ 73127c478bd9Sstevel@tonic-gate switch (fcode) 73137c478bd9Sstevel@tonic-gate { 73147c478bd9Sstevel@tonic-gate case 'P': /* pathname */ 73157c478bd9Sstevel@tonic-gate if (*p == '\0') 73167c478bd9Sstevel@tonic-gate syserr("queue %s: empty path name", 73177c478bd9Sstevel@tonic-gate qg->qg_name); 73187c478bd9Sstevel@tonic-gate else 73197c478bd9Sstevel@tonic-gate qg->qg_qdir = newstr(p); 73207c478bd9Sstevel@tonic-gate break; 73217c478bd9Sstevel@tonic-gate 73227c478bd9Sstevel@tonic-gate case 'F': /* flags */ 73237c478bd9Sstevel@tonic-gate for (; *p != '\0'; p++) 73247c478bd9Sstevel@tonic-gate if (!(isascii(*p) && isspace(*p))) 73257c478bd9Sstevel@tonic-gate setbitn(*p, qg->qg_flags); 73267c478bd9Sstevel@tonic-gate break; 73277c478bd9Sstevel@tonic-gate 73287c478bd9Sstevel@tonic-gate /* 73297c478bd9Sstevel@tonic-gate ** Do we need two intervals here: 73307c478bd9Sstevel@tonic-gate ** One for persistent queue runners, 73317c478bd9Sstevel@tonic-gate ** one for "normal" queue runs? 73327c478bd9Sstevel@tonic-gate */ 73337c478bd9Sstevel@tonic-gate 73347c478bd9Sstevel@tonic-gate case 'I': /* interval between running the queue */ 73357c478bd9Sstevel@tonic-gate qg->qg_queueintvl = convtime(p, 'm'); 73367c478bd9Sstevel@tonic-gate break; 73377c478bd9Sstevel@tonic-gate 73387c478bd9Sstevel@tonic-gate case 'N': /* run niceness */ 73397c478bd9Sstevel@tonic-gate qg->qg_nice = atoi(p); 73407c478bd9Sstevel@tonic-gate break; 73417c478bd9Sstevel@tonic-gate 73427c478bd9Sstevel@tonic-gate case 'R': /* maximum # of runners for the group */ 73437c478bd9Sstevel@tonic-gate i = atoi(p); 73447c478bd9Sstevel@tonic-gate 73457c478bd9Sstevel@tonic-gate /* can't have more runners than allowed total */ 73467c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && i > MaxQueueChildren) 73477c478bd9Sstevel@tonic-gate { 73487c478bd9Sstevel@tonic-gate qg->qg_maxqrun = MaxQueueChildren; 73497c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 73507c478bd9Sstevel@tonic-gate "Q=%s: R=%d exceeds MaxQueueChildren=%d, set to MaxQueueChildren\n", 73517c478bd9Sstevel@tonic-gate qg->qg_name, i, 73527c478bd9Sstevel@tonic-gate MaxQueueChildren); 73537c478bd9Sstevel@tonic-gate } 73547c478bd9Sstevel@tonic-gate else 73557c478bd9Sstevel@tonic-gate qg->qg_maxqrun = i; 73567c478bd9Sstevel@tonic-gate break; 73577c478bd9Sstevel@tonic-gate 73587c478bd9Sstevel@tonic-gate case 'J': /* maximum # of jobs in work list */ 73597c478bd9Sstevel@tonic-gate qg->qg_maxlist = atoi(p); 73607c478bd9Sstevel@tonic-gate break; 73617c478bd9Sstevel@tonic-gate 73627c478bd9Sstevel@tonic-gate case 'r': /* max recipients per envelope */ 73637c478bd9Sstevel@tonic-gate qg->qg_maxrcpt = atoi(p); 73647c478bd9Sstevel@tonic-gate break; 73657c478bd9Sstevel@tonic-gate 73667c478bd9Sstevel@tonic-gate #if _FFR_QUEUE_GROUP_SORTORDER 73677c478bd9Sstevel@tonic-gate case 'S': /* queue sorting order */ 73687c478bd9Sstevel@tonic-gate switch (*p) 73697c478bd9Sstevel@tonic-gate { 73707c478bd9Sstevel@tonic-gate case 'h': /* Host first */ 73717c478bd9Sstevel@tonic-gate case 'H': 73727c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYHOST; 73737c478bd9Sstevel@tonic-gate break; 73747c478bd9Sstevel@tonic-gate 73757c478bd9Sstevel@tonic-gate case 'p': /* Priority order */ 73767c478bd9Sstevel@tonic-gate case 'P': 73777c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYPRIORITY; 73787c478bd9Sstevel@tonic-gate break; 73797c478bd9Sstevel@tonic-gate 73807c478bd9Sstevel@tonic-gate case 't': /* Submission time */ 73817c478bd9Sstevel@tonic-gate case 'T': 73827c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYTIME; 73837c478bd9Sstevel@tonic-gate break; 73847c478bd9Sstevel@tonic-gate 73857c478bd9Sstevel@tonic-gate case 'f': /* File name */ 73867c478bd9Sstevel@tonic-gate case 'F': 73877c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYFILENAME; 73887c478bd9Sstevel@tonic-gate break; 73897c478bd9Sstevel@tonic-gate 73907c478bd9Sstevel@tonic-gate case 'm': /* Modification time */ 73917c478bd9Sstevel@tonic-gate case 'M': 73927c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYMODTIME; 73937c478bd9Sstevel@tonic-gate break; 73947c478bd9Sstevel@tonic-gate 73957c478bd9Sstevel@tonic-gate case 'r': /* Random */ 73967c478bd9Sstevel@tonic-gate case 'R': 73977c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_RANDOM; 73987c478bd9Sstevel@tonic-gate break; 73997c478bd9Sstevel@tonic-gate 74007c478bd9Sstevel@tonic-gate # if _FFR_RHS 74017c478bd9Sstevel@tonic-gate case 's': /* Shuffled host name */ 74027c478bd9Sstevel@tonic-gate case 'S': 74037c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_BYSHUFFLE; 74047c478bd9Sstevel@tonic-gate break; 74057c478bd9Sstevel@tonic-gate # endif /* _FFR_RHS */ 74067c478bd9Sstevel@tonic-gate 74077c478bd9Sstevel@tonic-gate case 'n': /* none */ 74087c478bd9Sstevel@tonic-gate case 'N': 74097c478bd9Sstevel@tonic-gate qg->qg_sortorder = QSO_NONE; 74107c478bd9Sstevel@tonic-gate break; 74117c478bd9Sstevel@tonic-gate 74127c478bd9Sstevel@tonic-gate default: 74137c478bd9Sstevel@tonic-gate syserr("Invalid queue sort order \"%s\"", p); 74147c478bd9Sstevel@tonic-gate } 74157c478bd9Sstevel@tonic-gate break; 74167c478bd9Sstevel@tonic-gate #endif /* _FFR_QUEUE_GROUP_SORTORDER */ 74177c478bd9Sstevel@tonic-gate 74187c478bd9Sstevel@tonic-gate default: 74197c478bd9Sstevel@tonic-gate syserr("Q%s: unknown queue equate %c=", 74207c478bd9Sstevel@tonic-gate qg->qg_name, fcode); 74217c478bd9Sstevel@tonic-gate break; 74227c478bd9Sstevel@tonic-gate } 74237c478bd9Sstevel@tonic-gate 74247c478bd9Sstevel@tonic-gate p = delimptr; 74257c478bd9Sstevel@tonic-gate } 74267c478bd9Sstevel@tonic-gate 74277c478bd9Sstevel@tonic-gate #if !HASNICE 74287c478bd9Sstevel@tonic-gate if (qg->qg_nice != NiceQueueRun) 74297c478bd9Sstevel@tonic-gate { 74307c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 74317c478bd9Sstevel@tonic-gate "Q%s: Warning: N= set on system that doesn't support nice()\n", 74327c478bd9Sstevel@tonic-gate qg->qg_name); 74337c478bd9Sstevel@tonic-gate } 74347c478bd9Sstevel@tonic-gate #endif /* !HASNICE */ 74357c478bd9Sstevel@tonic-gate 74367c478bd9Sstevel@tonic-gate /* do some rationality checking */ 74377c478bd9Sstevel@tonic-gate if (NumQueue >= MAXQUEUEGROUPS) 74387c478bd9Sstevel@tonic-gate { 74397c478bd9Sstevel@tonic-gate syserr("too many queue groups defined (%d max)", 74407c478bd9Sstevel@tonic-gate MAXQUEUEGROUPS); 74417c478bd9Sstevel@tonic-gate return; 74427c478bd9Sstevel@tonic-gate } 74437c478bd9Sstevel@tonic-gate 74447c478bd9Sstevel@tonic-gate if (qg->qg_qdir == NULL) 74457c478bd9Sstevel@tonic-gate { 74467c478bd9Sstevel@tonic-gate if (QueueDir == NULL || *QueueDir == '\0') 74477c478bd9Sstevel@tonic-gate { 74487c478bd9Sstevel@tonic-gate syserr("QueueDir must be defined before queue groups"); 74497c478bd9Sstevel@tonic-gate return; 74507c478bd9Sstevel@tonic-gate } 74517c478bd9Sstevel@tonic-gate qg->qg_qdir = newstr(QueueDir); 74527c478bd9Sstevel@tonic-gate } 74537c478bd9Sstevel@tonic-gate 74547c478bd9Sstevel@tonic-gate if (qg->qg_maxqrun > 1 && !bitnset(QD_FORK, qg->qg_flags)) 74557c478bd9Sstevel@tonic-gate { 74567c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 74577c478bd9Sstevel@tonic-gate "Warning: Q=%s: R=%d: multiple queue runners specified\n\tbut flag '%c' is not set\n", 74587c478bd9Sstevel@tonic-gate qg->qg_name, qg->qg_maxqrun, QD_FORK); 74597c478bd9Sstevel@tonic-gate } 74607c478bd9Sstevel@tonic-gate 74617c478bd9Sstevel@tonic-gate /* enter the queue into the symbol table */ 74627c478bd9Sstevel@tonic-gate if (tTd(37, 8)) 74637c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 74647c478bd9Sstevel@tonic-gate "Adding %s to stab, path: %s", qg->qg_name, 74657c478bd9Sstevel@tonic-gate qg->qg_qdir); 74667c478bd9Sstevel@tonic-gate s = stab(qg->qg_name, ST_QUEUE, ST_ENTER); 74677c478bd9Sstevel@tonic-gate if (s->s_quegrp != NULL) 74687c478bd9Sstevel@tonic-gate { 74697c478bd9Sstevel@tonic-gate i = s->s_quegrp->qg_index; 74707c478bd9Sstevel@tonic-gate 74717c478bd9Sstevel@tonic-gate /* XXX what about the pointers inside this struct? */ 74727c478bd9Sstevel@tonic-gate sm_free(s->s_quegrp); /* XXX */ 74737c478bd9Sstevel@tonic-gate } 74747c478bd9Sstevel@tonic-gate else 74757c478bd9Sstevel@tonic-gate i = NumQueue++; 74767c478bd9Sstevel@tonic-gate Queue[i] = s->s_quegrp = qg; 74777c478bd9Sstevel@tonic-gate qg->qg_index = i; 74787c478bd9Sstevel@tonic-gate 74797c478bd9Sstevel@tonic-gate /* set default value for max queue runners */ 74807c478bd9Sstevel@tonic-gate if (qg->qg_maxqrun < 0) 74817c478bd9Sstevel@tonic-gate { 74827c478bd9Sstevel@tonic-gate if (MaxRunnersPerQueue > 0) 74837c478bd9Sstevel@tonic-gate qg->qg_maxqrun = MaxRunnersPerQueue; 74847c478bd9Sstevel@tonic-gate else 74857c478bd9Sstevel@tonic-gate qg->qg_maxqrun = 1; 74867c478bd9Sstevel@tonic-gate } 74877c478bd9Sstevel@tonic-gate if (qdef) 74887c478bd9Sstevel@tonic-gate setbitn(QD_DEFINED, qg->qg_flags); 74897c478bd9Sstevel@tonic-gate } 74907c478bd9Sstevel@tonic-gate #if 0 74917c478bd9Sstevel@tonic-gate /* 74927c478bd9Sstevel@tonic-gate ** HASHFQN -- calculate a hash value for a fully qualified host name 74937c478bd9Sstevel@tonic-gate ** 74947c478bd9Sstevel@tonic-gate ** Arguments: 74957c478bd9Sstevel@tonic-gate ** fqn -- an all lower-case host.domain string 74967c478bd9Sstevel@tonic-gate ** buckets -- the number of buckets (queue directories) 74977c478bd9Sstevel@tonic-gate ** 74987c478bd9Sstevel@tonic-gate ** Returns: 74997c478bd9Sstevel@tonic-gate ** a bucket number (signed integer) 75007c478bd9Sstevel@tonic-gate ** -1 on error 75017c478bd9Sstevel@tonic-gate ** 75027c478bd9Sstevel@tonic-gate ** Contributed by Exactis.com, Inc. 75037c478bd9Sstevel@tonic-gate */ 75047c478bd9Sstevel@tonic-gate 75057c478bd9Sstevel@tonic-gate int 75067c478bd9Sstevel@tonic-gate hashfqn(fqn, buckets) 75077c478bd9Sstevel@tonic-gate register char *fqn; 75087c478bd9Sstevel@tonic-gate int buckets; 75097c478bd9Sstevel@tonic-gate { 75107c478bd9Sstevel@tonic-gate register char *p; 75117c478bd9Sstevel@tonic-gate register int h = 0, hash, cnt; 75127c478bd9Sstevel@tonic-gate 75137c478bd9Sstevel@tonic-gate if (fqn == NULL) 75147c478bd9Sstevel@tonic-gate return -1; 75157c478bd9Sstevel@tonic-gate 75167c478bd9Sstevel@tonic-gate /* 75177c478bd9Sstevel@tonic-gate ** A variation on the gdb hash 75187c478bd9Sstevel@tonic-gate ** This is the best as of Feb 19, 1996 --bcx 75197c478bd9Sstevel@tonic-gate */ 75207c478bd9Sstevel@tonic-gate 75217c478bd9Sstevel@tonic-gate p = fqn; 75227c478bd9Sstevel@tonic-gate h = 0x238F13AF * strlen(p); 75237c478bd9Sstevel@tonic-gate for (cnt = 0; *p != 0; ++p, cnt++) 75247c478bd9Sstevel@tonic-gate { 75257c478bd9Sstevel@tonic-gate h = (h + (*p << (cnt * 5 % 24))) & 0x7FFFFFFF; 75267c478bd9Sstevel@tonic-gate } 75277c478bd9Sstevel@tonic-gate h = (1103515243 * h + 12345) & 0x7FFFFFFF; 75287c478bd9Sstevel@tonic-gate if (buckets < 2) 75297c478bd9Sstevel@tonic-gate hash = 0; 75307c478bd9Sstevel@tonic-gate else 75317c478bd9Sstevel@tonic-gate hash = (h % buckets); 75327c478bd9Sstevel@tonic-gate 75337c478bd9Sstevel@tonic-gate return hash; 75347c478bd9Sstevel@tonic-gate } 75357c478bd9Sstevel@tonic-gate #endif /* 0 */ 75367c478bd9Sstevel@tonic-gate 75377c478bd9Sstevel@tonic-gate /* 75387c478bd9Sstevel@tonic-gate ** A structure for sorting Queue according to maxqrun without 75397c478bd9Sstevel@tonic-gate ** screwing up Queue itself. 75407c478bd9Sstevel@tonic-gate */ 75417c478bd9Sstevel@tonic-gate 75427c478bd9Sstevel@tonic-gate struct sortqgrp 75437c478bd9Sstevel@tonic-gate { 75447c478bd9Sstevel@tonic-gate int sg_idx; /* original index */ 75457c478bd9Sstevel@tonic-gate int sg_maxqrun; /* max queue runners */ 75467c478bd9Sstevel@tonic-gate }; 75477c478bd9Sstevel@tonic-gate typedef struct sortqgrp SORTQGRP_T; 75487c478bd9Sstevel@tonic-gate static int cmpidx __P((const void *, const void *)); 75497c478bd9Sstevel@tonic-gate 75507c478bd9Sstevel@tonic-gate static int 75517c478bd9Sstevel@tonic-gate cmpidx(a, b) 75527c478bd9Sstevel@tonic-gate const void *a; 75537c478bd9Sstevel@tonic-gate const void *b; 75547c478bd9Sstevel@tonic-gate { 75557c478bd9Sstevel@tonic-gate /* The sort is highest to lowest, so the comparison is reversed */ 75567c478bd9Sstevel@tonic-gate if (((SORTQGRP_T *)a)->sg_maxqrun < ((SORTQGRP_T *)b)->sg_maxqrun) 75577c478bd9Sstevel@tonic-gate return 1; 75587c478bd9Sstevel@tonic-gate else if (((SORTQGRP_T *)a)->sg_maxqrun > ((SORTQGRP_T *)b)->sg_maxqrun) 75597c478bd9Sstevel@tonic-gate return -1; 75607c478bd9Sstevel@tonic-gate else 75617c478bd9Sstevel@tonic-gate return 0; 75627c478bd9Sstevel@tonic-gate } 75637c478bd9Sstevel@tonic-gate 75647c478bd9Sstevel@tonic-gate /* 75657c478bd9Sstevel@tonic-gate ** MAKEWORKGROUP -- balance queue groups into work groups per MaxQueueChildren 75667c478bd9Sstevel@tonic-gate ** 75677c478bd9Sstevel@tonic-gate ** Take the now defined queue groups and assign them to work groups. 75687c478bd9Sstevel@tonic-gate ** This is done to balance out the number of concurrently active 75697c478bd9Sstevel@tonic-gate ** queue runners such that MaxQueueChildren is not exceeded. This may 75707c478bd9Sstevel@tonic-gate ** result in more than one queue group per work group. In such a case 75717c478bd9Sstevel@tonic-gate ** the number of running queue groups in that work group will have no 75727c478bd9Sstevel@tonic-gate ** more than the work group maximum number of runners (a "fair" portion 75737c478bd9Sstevel@tonic-gate ** of MaxQueueRunners). All queue groups within a work group will get a 75747c478bd9Sstevel@tonic-gate ** chance at running. 75757c478bd9Sstevel@tonic-gate ** 75767c478bd9Sstevel@tonic-gate ** Parameters: 75777c478bd9Sstevel@tonic-gate ** none. 75787c478bd9Sstevel@tonic-gate ** 75797c478bd9Sstevel@tonic-gate ** Returns: 75807c478bd9Sstevel@tonic-gate ** nothing. 75817c478bd9Sstevel@tonic-gate ** 75827c478bd9Sstevel@tonic-gate ** Side Effects: 75837c478bd9Sstevel@tonic-gate ** Sets up WorkGrp structure. 75847c478bd9Sstevel@tonic-gate */ 75857c478bd9Sstevel@tonic-gate 75867c478bd9Sstevel@tonic-gate void 75877c478bd9Sstevel@tonic-gate makeworkgroups() 75887c478bd9Sstevel@tonic-gate { 75897c478bd9Sstevel@tonic-gate int i, j, total_runners, dir, h; 75907c478bd9Sstevel@tonic-gate SORTQGRP_T si[MAXQUEUEGROUPS + 1]; 75917c478bd9Sstevel@tonic-gate 75927c478bd9Sstevel@tonic-gate total_runners = 0; 75937c478bd9Sstevel@tonic-gate if (NumQueue == 1 && strcmp(Queue[0]->qg_name, "mqueue") == 0) 75947c478bd9Sstevel@tonic-gate { 75957c478bd9Sstevel@tonic-gate /* 75967c478bd9Sstevel@tonic-gate ** There is only the "mqueue" queue group (a default) 75977c478bd9Sstevel@tonic-gate ** containing all of the queues. We want to provide to 75987c478bd9Sstevel@tonic-gate ** this queue group the maximum allowable queue runners. 75997c478bd9Sstevel@tonic-gate ** To match older behavior (8.10/8.11) we'll try for 76007c478bd9Sstevel@tonic-gate ** 1 runner per queue capping it at MaxQueueChildren. 76017c478bd9Sstevel@tonic-gate ** So if there are N queues, then there will be N runners 76027c478bd9Sstevel@tonic-gate ** for the "mqueue" queue group (where N is kept less than 76037c478bd9Sstevel@tonic-gate ** MaxQueueChildren). 76047c478bd9Sstevel@tonic-gate */ 76057c478bd9Sstevel@tonic-gate 76067c478bd9Sstevel@tonic-gate NumWorkGroups = 1; 76077c478bd9Sstevel@tonic-gate WorkGrp[0].wg_numqgrp = 1; 76087c478bd9Sstevel@tonic-gate WorkGrp[0].wg_qgs = (QUEUEGRP **) xalloc(sizeof(QUEUEGRP *)); 76097c478bd9Sstevel@tonic-gate WorkGrp[0].wg_qgs[0] = Queue[0]; 76107c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && 76117c478bd9Sstevel@tonic-gate Queue[0]->qg_numqueues > MaxQueueChildren) 76127c478bd9Sstevel@tonic-gate WorkGrp[0].wg_runners = MaxQueueChildren; 76137c478bd9Sstevel@tonic-gate else 76147c478bd9Sstevel@tonic-gate WorkGrp[0].wg_runners = Queue[0]->qg_numqueues; 76157c478bd9Sstevel@tonic-gate 76167c478bd9Sstevel@tonic-gate Queue[0]->qg_wgrp = 0; 76177c478bd9Sstevel@tonic-gate 76187c478bd9Sstevel@tonic-gate /* can't have more runners than allowed total */ 76197c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && 76207c478bd9Sstevel@tonic-gate Queue[0]->qg_maxqrun > MaxQueueChildren) 76217c478bd9Sstevel@tonic-gate Queue[0]->qg_maxqrun = MaxQueueChildren; 76227c478bd9Sstevel@tonic-gate WorkGrp[0].wg_maxact = Queue[0]->qg_maxqrun; 76237c478bd9Sstevel@tonic-gate WorkGrp[0].wg_lowqintvl = Queue[0]->qg_queueintvl; 76247c478bd9Sstevel@tonic-gate return; 76257c478bd9Sstevel@tonic-gate } 76267c478bd9Sstevel@tonic-gate 76277c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue; i++) 76287c478bd9Sstevel@tonic-gate { 76297c478bd9Sstevel@tonic-gate si[i].sg_maxqrun = Queue[i]->qg_maxqrun; 76307c478bd9Sstevel@tonic-gate si[i].sg_idx = i; 76317c478bd9Sstevel@tonic-gate } 76327c478bd9Sstevel@tonic-gate qsort(si, NumQueue, sizeof(si[0]), cmpidx); 76337c478bd9Sstevel@tonic-gate 76347c478bd9Sstevel@tonic-gate NumWorkGroups = 0; 76357c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue; i++) 76367c478bd9Sstevel@tonic-gate { 76377c478bd9Sstevel@tonic-gate total_runners += si[i].sg_maxqrun; 76387c478bd9Sstevel@tonic-gate if (MaxQueueChildren <= 0 || total_runners <= MaxQueueChildren) 76397c478bd9Sstevel@tonic-gate NumWorkGroups++; 76407c478bd9Sstevel@tonic-gate else 76417c478bd9Sstevel@tonic-gate break; 76427c478bd9Sstevel@tonic-gate } 76437c478bd9Sstevel@tonic-gate 76447c478bd9Sstevel@tonic-gate if (NumWorkGroups < 1) 76457c478bd9Sstevel@tonic-gate NumWorkGroups = 1; /* gotta have one at least */ 76467c478bd9Sstevel@tonic-gate else if (NumWorkGroups > MAXWORKGROUPS) 76477c478bd9Sstevel@tonic-gate NumWorkGroups = MAXWORKGROUPS; /* the limit */ 76487c478bd9Sstevel@tonic-gate 76497c478bd9Sstevel@tonic-gate /* 76507c478bd9Sstevel@tonic-gate ** We now know the number of work groups to pack the queue groups 76517c478bd9Sstevel@tonic-gate ** into. The queue groups in 'Queue' are sorted from highest 76527c478bd9Sstevel@tonic-gate ** to lowest for the number of runners per queue group. 76537c478bd9Sstevel@tonic-gate ** We put the queue groups with the largest number of runners 76547c478bd9Sstevel@tonic-gate ** into work groups first. Then the smaller ones are fitted in 76557c478bd9Sstevel@tonic-gate ** where it looks best. 76567c478bd9Sstevel@tonic-gate */ 76577c478bd9Sstevel@tonic-gate 76587c478bd9Sstevel@tonic-gate j = 0; 76597c478bd9Sstevel@tonic-gate dir = 1; 76607c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue; i++) 76617c478bd9Sstevel@tonic-gate { 76627c478bd9Sstevel@tonic-gate /* a to-and-fro packing scheme, continue from last position */ 76637c478bd9Sstevel@tonic-gate if (j >= NumWorkGroups) 76647c478bd9Sstevel@tonic-gate { 76657c478bd9Sstevel@tonic-gate dir = -1; 76667c478bd9Sstevel@tonic-gate j = NumWorkGroups - 1; 76677c478bd9Sstevel@tonic-gate } 76687c478bd9Sstevel@tonic-gate else if (j < 0) 76697c478bd9Sstevel@tonic-gate { 76707c478bd9Sstevel@tonic-gate j = 0; 76717c478bd9Sstevel@tonic-gate dir = 1; 76727c478bd9Sstevel@tonic-gate } 76737c478bd9Sstevel@tonic-gate 76747c478bd9Sstevel@tonic-gate if (WorkGrp[j].wg_qgs == NULL) 76757c478bd9Sstevel@tonic-gate WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_malloc(sizeof(QUEUEGRP *) * 76767c478bd9Sstevel@tonic-gate (WorkGrp[j].wg_numqgrp + 1)); 76777c478bd9Sstevel@tonic-gate else 76787c478bd9Sstevel@tonic-gate WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_realloc(WorkGrp[j].wg_qgs, 76797c478bd9Sstevel@tonic-gate sizeof(QUEUEGRP *) * 76807c478bd9Sstevel@tonic-gate (WorkGrp[j].wg_numqgrp + 1)); 76817c478bd9Sstevel@tonic-gate if (WorkGrp[j].wg_qgs == NULL) 76827c478bd9Sstevel@tonic-gate { 76837c478bd9Sstevel@tonic-gate syserr("!cannot allocate memory for work queues, need %d bytes", 76847c478bd9Sstevel@tonic-gate (int) (sizeof(QUEUEGRP *) * 76857c478bd9Sstevel@tonic-gate (WorkGrp[j].wg_numqgrp + 1))); 76867c478bd9Sstevel@tonic-gate } 76877c478bd9Sstevel@tonic-gate 76887c478bd9Sstevel@tonic-gate h = si[i].sg_idx; 76897c478bd9Sstevel@tonic-gate WorkGrp[j].wg_qgs[WorkGrp[j].wg_numqgrp] = Queue[h]; 76907c478bd9Sstevel@tonic-gate WorkGrp[j].wg_numqgrp++; 76917c478bd9Sstevel@tonic-gate WorkGrp[j].wg_runners += Queue[h]->qg_maxqrun; 76927c478bd9Sstevel@tonic-gate Queue[h]->qg_wgrp = j; 76937c478bd9Sstevel@tonic-gate 76947c478bd9Sstevel@tonic-gate if (WorkGrp[j].wg_maxact == 0) 76957c478bd9Sstevel@tonic-gate { 76967c478bd9Sstevel@tonic-gate /* can't have more runners than allowed total */ 76977c478bd9Sstevel@tonic-gate if (MaxQueueChildren > 0 && 76987c478bd9Sstevel@tonic-gate Queue[h]->qg_maxqrun > MaxQueueChildren) 76997c478bd9Sstevel@tonic-gate Queue[h]->qg_maxqrun = MaxQueueChildren; 77007c478bd9Sstevel@tonic-gate WorkGrp[j].wg_maxact = Queue[h]->qg_maxqrun; 77017c478bd9Sstevel@tonic-gate } 77027c478bd9Sstevel@tonic-gate 77037c478bd9Sstevel@tonic-gate /* 77047c478bd9Sstevel@tonic-gate ** XXX: must wg_lowqintvl be the GCD? 77057c478bd9Sstevel@tonic-gate ** qg1: 2m, qg2: 3m, minimum: 2m, when do queue runs for 77067c478bd9Sstevel@tonic-gate ** qg2 occur? 77077c478bd9Sstevel@tonic-gate */ 77087c478bd9Sstevel@tonic-gate 77097c478bd9Sstevel@tonic-gate /* keep track of the lowest interval for a persistent runner */ 77107c478bd9Sstevel@tonic-gate if (Queue[h]->qg_queueintvl > 0 && 77117c478bd9Sstevel@tonic-gate WorkGrp[j].wg_lowqintvl < Queue[h]->qg_queueintvl) 77127c478bd9Sstevel@tonic-gate WorkGrp[j].wg_lowqintvl = Queue[h]->qg_queueintvl; 77137c478bd9Sstevel@tonic-gate j += dir; 77147c478bd9Sstevel@tonic-gate } 77157c478bd9Sstevel@tonic-gate if (tTd(41, 9)) 77167c478bd9Sstevel@tonic-gate { 77177c478bd9Sstevel@tonic-gate for (i = 0; i < NumWorkGroups; i++) 77187c478bd9Sstevel@tonic-gate { 77197c478bd9Sstevel@tonic-gate sm_dprintf("Workgroup[%d]=", i); 77207c478bd9Sstevel@tonic-gate for (j = 0; j < WorkGrp[i].wg_numqgrp; j++) 77217c478bd9Sstevel@tonic-gate { 77227c478bd9Sstevel@tonic-gate sm_dprintf("%s, ", 77237c478bd9Sstevel@tonic-gate WorkGrp[i].wg_qgs[j]->qg_name); 77247c478bd9Sstevel@tonic-gate } 77257c478bd9Sstevel@tonic-gate sm_dprintf("\n"); 77267c478bd9Sstevel@tonic-gate } 77277c478bd9Sstevel@tonic-gate } 77287c478bd9Sstevel@tonic-gate } 77297c478bd9Sstevel@tonic-gate 77307c478bd9Sstevel@tonic-gate /* 77317c478bd9Sstevel@tonic-gate ** DUP_DF -- duplicate envelope data file 77327c478bd9Sstevel@tonic-gate ** 77337c478bd9Sstevel@tonic-gate ** Copy the data file from the 'old' envelope to the 'new' envelope 77347c478bd9Sstevel@tonic-gate ** in the most efficient way possible. 77357c478bd9Sstevel@tonic-gate ** 77367c478bd9Sstevel@tonic-gate ** Create a hard link from the 'old' data file to the 'new' data file. 77377c478bd9Sstevel@tonic-gate ** If the old and new queue directories are on different file systems, 77387c478bd9Sstevel@tonic-gate ** then the new data file link is created in the old queue directory, 77397c478bd9Sstevel@tonic-gate ** and the new queue file will contain a 'd' record pointing to the 77407c478bd9Sstevel@tonic-gate ** directory containing the new data file. 77417c478bd9Sstevel@tonic-gate ** 77427c478bd9Sstevel@tonic-gate ** Parameters: 77437c478bd9Sstevel@tonic-gate ** old -- old envelope. 77447c478bd9Sstevel@tonic-gate ** new -- new envelope. 77457c478bd9Sstevel@tonic-gate ** 77467c478bd9Sstevel@tonic-gate ** Results: 77477c478bd9Sstevel@tonic-gate ** Returns true on success, false on failure. 77487c478bd9Sstevel@tonic-gate ** 77497c478bd9Sstevel@tonic-gate ** Side Effects: 77507c478bd9Sstevel@tonic-gate ** On success, the new data file is created. 77517c478bd9Sstevel@tonic-gate ** On fatal failure, EF_FATALERRS is set in old->e_flags. 77527c478bd9Sstevel@tonic-gate */ 77537c478bd9Sstevel@tonic-gate 77547c478bd9Sstevel@tonic-gate static bool dup_df __P((ENVELOPE *, ENVELOPE *)); 77557c478bd9Sstevel@tonic-gate 77567c478bd9Sstevel@tonic-gate static bool 77577c478bd9Sstevel@tonic-gate dup_df(old, new) 77587c478bd9Sstevel@tonic-gate ENVELOPE *old; 77597c478bd9Sstevel@tonic-gate ENVELOPE *new; 77607c478bd9Sstevel@tonic-gate { 77617c478bd9Sstevel@tonic-gate int ofs, nfs, r; 77627c478bd9Sstevel@tonic-gate char opath[MAXPATHLEN]; 77637c478bd9Sstevel@tonic-gate char npath[MAXPATHLEN]; 77647c478bd9Sstevel@tonic-gate 77657c478bd9Sstevel@tonic-gate if (!bitset(EF_HAS_DF, old->e_flags)) 77667c478bd9Sstevel@tonic-gate { 77677c478bd9Sstevel@tonic-gate /* 77687c478bd9Sstevel@tonic-gate ** this can happen if: SuperSafe != True 77697c478bd9Sstevel@tonic-gate ** and a bounce mail is sent that is split. 77707c478bd9Sstevel@tonic-gate */ 77717c478bd9Sstevel@tonic-gate 77727c478bd9Sstevel@tonic-gate queueup(old, false, true); 77737c478bd9Sstevel@tonic-gate } 77747c478bd9Sstevel@tonic-gate SM_REQUIRE(ISVALIDQGRP(old->e_qgrp) && ISVALIDQDIR(old->e_qdir)); 77757c478bd9Sstevel@tonic-gate SM_REQUIRE(ISVALIDQGRP(new->e_qgrp) && ISVALIDQDIR(new->e_qdir)); 77767c478bd9Sstevel@tonic-gate 7777058561cbSjbeck (void) sm_strlcpy(opath, queuename(old, DATAFL_LETTER), sizeof(opath)); 7778058561cbSjbeck (void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof(npath)); 77797c478bd9Sstevel@tonic-gate 77807c478bd9Sstevel@tonic-gate if (old->e_dfp != NULL) 77817c478bd9Sstevel@tonic-gate { 77827c478bd9Sstevel@tonic-gate r = sm_io_setinfo(old->e_dfp, SM_BF_COMMIT, NULL); 77837c478bd9Sstevel@tonic-gate if (r < 0 && errno != EINVAL) 77847c478bd9Sstevel@tonic-gate { 77857c478bd9Sstevel@tonic-gate syserr("@can't commit %s", opath); 77867c478bd9Sstevel@tonic-gate old->e_flags |= EF_FATALERRS; 77877c478bd9Sstevel@tonic-gate return false; 77887c478bd9Sstevel@tonic-gate } 77897c478bd9Sstevel@tonic-gate } 77907c478bd9Sstevel@tonic-gate 77917c478bd9Sstevel@tonic-gate /* 77927c478bd9Sstevel@tonic-gate ** Attempt to create a hard link, if we think both old and new 77937c478bd9Sstevel@tonic-gate ** are on the same file system, otherwise copy the file. 77947c478bd9Sstevel@tonic-gate ** 77957c478bd9Sstevel@tonic-gate ** Don't waste time attempting a hard link unless old and new 77967c478bd9Sstevel@tonic-gate ** are on the same file system. 77977c478bd9Sstevel@tonic-gate */ 77987c478bd9Sstevel@tonic-gate 779949218d4fSjbeck SM_REQUIRE(ISVALIDQGRP(old->e_dfqgrp) && ISVALIDQDIR(old->e_dfqdir)); 780049218d4fSjbeck SM_REQUIRE(ISVALIDQGRP(new->e_dfqgrp) && ISVALIDQDIR(new->e_dfqdir)); 780149218d4fSjbeck 780249218d4fSjbeck ofs = Queue[old->e_dfqgrp]->qg_qpaths[old->e_dfqdir].qp_fsysidx; 780349218d4fSjbeck nfs = Queue[new->e_dfqgrp]->qg_qpaths[new->e_dfqdir].qp_fsysidx; 78047c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(ofs) == FILE_SYS_DEV(nfs)) 78057c478bd9Sstevel@tonic-gate { 78067c478bd9Sstevel@tonic-gate if (link(opath, npath) == 0) 78077c478bd9Sstevel@tonic-gate { 78087c478bd9Sstevel@tonic-gate new->e_flags |= EF_HAS_DF; 78097c478bd9Sstevel@tonic-gate SYNC_DIR(npath, true); 78107c478bd9Sstevel@tonic-gate return true; 78117c478bd9Sstevel@tonic-gate } 78127c478bd9Sstevel@tonic-gate goto error; 78137c478bd9Sstevel@tonic-gate } 78147c478bd9Sstevel@tonic-gate 78157c478bd9Sstevel@tonic-gate /* 78167c478bd9Sstevel@tonic-gate ** Can't link across queue directories, so try to create a hard 78177c478bd9Sstevel@tonic-gate ** link in the same queue directory as the old df file. 78187c478bd9Sstevel@tonic-gate ** The qf file will refer to the new df file using a 'd' record. 78197c478bd9Sstevel@tonic-gate */ 78207c478bd9Sstevel@tonic-gate 78217c478bd9Sstevel@tonic-gate new->e_dfqgrp = old->e_dfqgrp; 78227c478bd9Sstevel@tonic-gate new->e_dfqdir = old->e_dfqdir; 7823058561cbSjbeck (void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof(npath)); 78247c478bd9Sstevel@tonic-gate if (link(opath, npath) == 0) 78257c478bd9Sstevel@tonic-gate { 78267c478bd9Sstevel@tonic-gate new->e_flags |= EF_HAS_DF; 78277c478bd9Sstevel@tonic-gate SYNC_DIR(npath, true); 78287c478bd9Sstevel@tonic-gate return true; 78297c478bd9Sstevel@tonic-gate } 78307c478bd9Sstevel@tonic-gate 78317c478bd9Sstevel@tonic-gate error: 78327c478bd9Sstevel@tonic-gate if (LogLevel > 0) 78337c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, old->e_id, 78347c478bd9Sstevel@tonic-gate "dup_df: can't link %s to %s, error=%s, envelope splitting failed", 78357c478bd9Sstevel@tonic-gate opath, npath, sm_errstring(errno)); 78367c478bd9Sstevel@tonic-gate return false; 78377c478bd9Sstevel@tonic-gate } 78387c478bd9Sstevel@tonic-gate 78397c478bd9Sstevel@tonic-gate /* 78407c478bd9Sstevel@tonic-gate ** SPLIT_ENV -- Allocate a new envelope based on a given envelope. 78417c478bd9Sstevel@tonic-gate ** 78427c478bd9Sstevel@tonic-gate ** Parameters: 78437c478bd9Sstevel@tonic-gate ** e -- envelope. 78447c478bd9Sstevel@tonic-gate ** sendqueue -- sendqueue for new envelope. 78457c478bd9Sstevel@tonic-gate ** qgrp -- index of queue group. 78467c478bd9Sstevel@tonic-gate ** qdir -- queue directory. 78477c478bd9Sstevel@tonic-gate ** 78487c478bd9Sstevel@tonic-gate ** Results: 78497c478bd9Sstevel@tonic-gate ** new envelope. 78507c478bd9Sstevel@tonic-gate ** 78517c478bd9Sstevel@tonic-gate */ 78527c478bd9Sstevel@tonic-gate 78537c478bd9Sstevel@tonic-gate static ENVELOPE *split_env __P((ENVELOPE *, ADDRESS *, int, int)); 78547c478bd9Sstevel@tonic-gate 78557c478bd9Sstevel@tonic-gate static ENVELOPE * 78567c478bd9Sstevel@tonic-gate split_env(e, sendqueue, qgrp, qdir) 78577c478bd9Sstevel@tonic-gate ENVELOPE *e; 78587c478bd9Sstevel@tonic-gate ADDRESS *sendqueue; 78597c478bd9Sstevel@tonic-gate int qgrp; 78607c478bd9Sstevel@tonic-gate int qdir; 78617c478bd9Sstevel@tonic-gate { 78627c478bd9Sstevel@tonic-gate ENVELOPE *ee; 78637c478bd9Sstevel@tonic-gate 7864058561cbSjbeck ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool, sizeof(*ee)); 78657c478bd9Sstevel@tonic-gate STRUCTCOPY(*e, *ee); 78667c478bd9Sstevel@tonic-gate ee->e_message = NULL; /* XXX use original message? */ 78677c478bd9Sstevel@tonic-gate ee->e_id = NULL; 78687c478bd9Sstevel@tonic-gate assign_queueid(ee); 78697c478bd9Sstevel@tonic-gate ee->e_sendqueue = sendqueue; 78707c478bd9Sstevel@tonic-gate ee->e_flags &= ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS 78717c478bd9Sstevel@tonic-gate |EF_SENDRECEIPT|EF_RET_PARAM|EF_HAS_DF); 78727c478bd9Sstevel@tonic-gate ee->e_flags |= EF_NORECEIPT; /* XXX really? */ 78737c478bd9Sstevel@tonic-gate ee->e_from.q_state = QS_SENDER; 78747c478bd9Sstevel@tonic-gate ee->e_dfp = NULL; 78757c478bd9Sstevel@tonic-gate ee->e_lockfp = NULL; 78767c478bd9Sstevel@tonic-gate if (e->e_xfp != NULL) 78777c478bd9Sstevel@tonic-gate ee->e_xfp = sm_io_dup(e->e_xfp); 78787c478bd9Sstevel@tonic-gate 78797c478bd9Sstevel@tonic-gate /* failed to dup e->e_xfp, start a new transcript */ 78807c478bd9Sstevel@tonic-gate if (ee->e_xfp == NULL) 78817c478bd9Sstevel@tonic-gate openxscript(ee); 78827c478bd9Sstevel@tonic-gate 78837c478bd9Sstevel@tonic-gate ee->e_qgrp = ee->e_dfqgrp = qgrp; 78847c478bd9Sstevel@tonic-gate ee->e_qdir = ee->e_dfqdir = qdir; 78857c478bd9Sstevel@tonic-gate ee->e_errormode = EM_MAIL; 78867c478bd9Sstevel@tonic-gate ee->e_statmsg = NULL; 78877c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 78887c478bd9Sstevel@tonic-gate ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool, 78897c478bd9Sstevel@tonic-gate e->e_quarmsg); 78907c478bd9Sstevel@tonic-gate 78917c478bd9Sstevel@tonic-gate /* 78927c478bd9Sstevel@tonic-gate ** XXX Not sure if this copying is necessary. 78937c478bd9Sstevel@tonic-gate ** sendall() does this copying, but I (dm) don't know if that is 78947c478bd9Sstevel@tonic-gate ** because of the storage management discipline we were using 78957c478bd9Sstevel@tonic-gate ** before rpools were introduced, or if it is because these lists 78967c478bd9Sstevel@tonic-gate ** can be modified later. 78977c478bd9Sstevel@tonic-gate */ 78987c478bd9Sstevel@tonic-gate 78997c478bd9Sstevel@tonic-gate ee->e_header = copyheader(e->e_header, ee->e_rpool); 79007c478bd9Sstevel@tonic-gate ee->e_errorqueue = copyqueue(e->e_errorqueue, ee->e_rpool); 79017c478bd9Sstevel@tonic-gate 79027c478bd9Sstevel@tonic-gate return ee; 79037c478bd9Sstevel@tonic-gate } 79047c478bd9Sstevel@tonic-gate 79057c478bd9Sstevel@tonic-gate /* return values from split functions, check also below! */ 79067c478bd9Sstevel@tonic-gate #define SM_SPLIT_FAIL (0) 79077c478bd9Sstevel@tonic-gate #define SM_SPLIT_NONE (1) 79087c478bd9Sstevel@tonic-gate #define SM_SPLIT_NEW(n) (1 + (n)) 79097c478bd9Sstevel@tonic-gate 79107c478bd9Sstevel@tonic-gate /* 79117c478bd9Sstevel@tonic-gate ** SPLIT_ACROSS_QUEUE_GROUPS 79127c478bd9Sstevel@tonic-gate ** 79137c478bd9Sstevel@tonic-gate ** This function splits an envelope across multiple queue groups 79147c478bd9Sstevel@tonic-gate ** based on the queue group of each recipient. 79157c478bd9Sstevel@tonic-gate ** 79167c478bd9Sstevel@tonic-gate ** Parameters: 79177c478bd9Sstevel@tonic-gate ** e -- envelope. 79187c478bd9Sstevel@tonic-gate ** 79197c478bd9Sstevel@tonic-gate ** Results: 79207c478bd9Sstevel@tonic-gate ** SM_SPLIT_FAIL on failure 79217c478bd9Sstevel@tonic-gate ** SM_SPLIT_NONE if no splitting occurred, 79227c478bd9Sstevel@tonic-gate ** or 1 + the number of additional envelopes created. 79237c478bd9Sstevel@tonic-gate ** 79247c478bd9Sstevel@tonic-gate ** Side Effects: 79257c478bd9Sstevel@tonic-gate ** On success, e->e_sibling points to a list of zero or more 79267c478bd9Sstevel@tonic-gate ** additional envelopes, and the associated data files exist 79277c478bd9Sstevel@tonic-gate ** on disk. But the queue files are not created. 79287c478bd9Sstevel@tonic-gate ** 79297c478bd9Sstevel@tonic-gate ** On failure, e->e_sibling is not changed. 79307c478bd9Sstevel@tonic-gate ** The order of recipients in e->e_sendqueue is permuted. 79317c478bd9Sstevel@tonic-gate ** Abandoned data files for additional envelopes that failed 79327c478bd9Sstevel@tonic-gate ** to be created may exist on disk. 79337c478bd9Sstevel@tonic-gate */ 79347c478bd9Sstevel@tonic-gate 79357c478bd9Sstevel@tonic-gate static int q_qgrp_compare __P((const void *, const void *)); 79367c478bd9Sstevel@tonic-gate static int e_filesys_compare __P((const void *, const void *)); 79377c478bd9Sstevel@tonic-gate 79387c478bd9Sstevel@tonic-gate static int 79397c478bd9Sstevel@tonic-gate q_qgrp_compare(p1, p2) 79407c478bd9Sstevel@tonic-gate const void *p1; 79417c478bd9Sstevel@tonic-gate const void *p2; 79427c478bd9Sstevel@tonic-gate { 79437c478bd9Sstevel@tonic-gate ADDRESS **pq1 = (ADDRESS **) p1; 79447c478bd9Sstevel@tonic-gate ADDRESS **pq2 = (ADDRESS **) p2; 79457c478bd9Sstevel@tonic-gate 79467c478bd9Sstevel@tonic-gate return (*pq1)->q_qgrp - (*pq2)->q_qgrp; 79477c478bd9Sstevel@tonic-gate } 79487c478bd9Sstevel@tonic-gate 79497c478bd9Sstevel@tonic-gate static int 79507c478bd9Sstevel@tonic-gate e_filesys_compare(p1, p2) 79517c478bd9Sstevel@tonic-gate const void *p1; 79527c478bd9Sstevel@tonic-gate const void *p2; 79537c478bd9Sstevel@tonic-gate { 79547c478bd9Sstevel@tonic-gate ENVELOPE **pe1 = (ENVELOPE **) p1; 79557c478bd9Sstevel@tonic-gate ENVELOPE **pe2 = (ENVELOPE **) p2; 79567c478bd9Sstevel@tonic-gate int fs1, fs2; 79577c478bd9Sstevel@tonic-gate 79587c478bd9Sstevel@tonic-gate fs1 = Queue[(*pe1)->e_qgrp]->qg_qpaths[(*pe1)->e_qdir].qp_fsysidx; 79597c478bd9Sstevel@tonic-gate fs2 = Queue[(*pe2)->e_qgrp]->qg_qpaths[(*pe2)->e_qdir].qp_fsysidx; 79607c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(fs1) < FILE_SYS_DEV(fs2)) 79617c478bd9Sstevel@tonic-gate return -1; 79627c478bd9Sstevel@tonic-gate if (FILE_SYS_DEV(fs1) > FILE_SYS_DEV(fs2)) 79637c478bd9Sstevel@tonic-gate return 1; 79647c478bd9Sstevel@tonic-gate return 0; 79657c478bd9Sstevel@tonic-gate } 79667c478bd9Sstevel@tonic-gate 7967058561cbSjbeck static int split_across_queue_groups __P((ENVELOPE *)); 79687c478bd9Sstevel@tonic-gate static int 79697c478bd9Sstevel@tonic-gate split_across_queue_groups(e) 79707c478bd9Sstevel@tonic-gate ENVELOPE *e; 79717c478bd9Sstevel@tonic-gate { 79727c478bd9Sstevel@tonic-gate int naddrs, nsplits, i; 79737c478bd9Sstevel@tonic-gate bool changed; 79747c478bd9Sstevel@tonic-gate char **pvp; 79757c478bd9Sstevel@tonic-gate ADDRESS *q, **addrs; 79767c478bd9Sstevel@tonic-gate ENVELOPE *ee, *es; 79777c478bd9Sstevel@tonic-gate ENVELOPE *splits[MAXQUEUEGROUPS]; 79787c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE]; 79797c478bd9Sstevel@tonic-gate 79807c478bd9Sstevel@tonic-gate SM_REQUIRE(ISVALIDQGRP(e->e_qgrp)); 79817c478bd9Sstevel@tonic-gate 79827c478bd9Sstevel@tonic-gate /* Count addresses and assign queue groups. */ 79837c478bd9Sstevel@tonic-gate naddrs = 0; 79847c478bd9Sstevel@tonic-gate changed = false; 79857c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 79867c478bd9Sstevel@tonic-gate { 79877c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 79887c478bd9Sstevel@tonic-gate continue; 79897c478bd9Sstevel@tonic-gate ++naddrs; 79907c478bd9Sstevel@tonic-gate 79917c478bd9Sstevel@tonic-gate /* bad addresses and those already sent stay put */ 79927c478bd9Sstevel@tonic-gate if (QS_IS_BADADDR(q->q_state) || 79937c478bd9Sstevel@tonic-gate QS_IS_SENT(q->q_state)) 79947c478bd9Sstevel@tonic-gate q->q_qgrp = e->e_qgrp; 79957c478bd9Sstevel@tonic-gate else if (!ISVALIDQGRP(q->q_qgrp)) 79967c478bd9Sstevel@tonic-gate { 79977c478bd9Sstevel@tonic-gate /* call ruleset which should return a queue group */ 79987c478bd9Sstevel@tonic-gate i = rscap(RS_QUEUEGROUP, q->q_user, NULL, e, &pvp, 79997c478bd9Sstevel@tonic-gate pvpbuf, sizeof(pvpbuf)); 80007c478bd9Sstevel@tonic-gate if (i == EX_OK && 80017c478bd9Sstevel@tonic-gate pvp != NULL && pvp[0] != NULL && 80027c478bd9Sstevel@tonic-gate (pvp[0][0] & 0377) == CANONNET && 80037c478bd9Sstevel@tonic-gate pvp[1] != NULL && pvp[1][0] != '\0') 80047c478bd9Sstevel@tonic-gate { 80057c478bd9Sstevel@tonic-gate i = name2qid(pvp[1]); 80067c478bd9Sstevel@tonic-gate if (ISVALIDQGRP(i)) 80077c478bd9Sstevel@tonic-gate { 80087c478bd9Sstevel@tonic-gate q->q_qgrp = i; 80097c478bd9Sstevel@tonic-gate changed = true; 80107c478bd9Sstevel@tonic-gate if (tTd(20, 4)) 80117c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 80127c478bd9Sstevel@tonic-gate "queue group name %s -> %d", 80137c478bd9Sstevel@tonic-gate pvp[1], i); 80147c478bd9Sstevel@tonic-gate continue; 80157c478bd9Sstevel@tonic-gate } 80167c478bd9Sstevel@tonic-gate else if (LogLevel > 10) 80177c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 80187c478bd9Sstevel@tonic-gate "can't find queue group name %s, selection ignored", 80197c478bd9Sstevel@tonic-gate pvp[1]); 80207c478bd9Sstevel@tonic-gate } 80217c478bd9Sstevel@tonic-gate if (q->q_mailer != NULL && 80227c478bd9Sstevel@tonic-gate ISVALIDQGRP(q->q_mailer->m_qgrp)) 80237c478bd9Sstevel@tonic-gate { 80247c478bd9Sstevel@tonic-gate changed = true; 80257c478bd9Sstevel@tonic-gate q->q_qgrp = q->q_mailer->m_qgrp; 80267c478bd9Sstevel@tonic-gate } 80277c478bd9Sstevel@tonic-gate else if (ISVALIDQGRP(e->e_qgrp)) 80287c478bd9Sstevel@tonic-gate q->q_qgrp = e->e_qgrp; 80297c478bd9Sstevel@tonic-gate else 80307c478bd9Sstevel@tonic-gate q->q_qgrp = 0; 80317c478bd9Sstevel@tonic-gate } 80327c478bd9Sstevel@tonic-gate } 80337c478bd9Sstevel@tonic-gate 80347c478bd9Sstevel@tonic-gate /* only one address? nothing to split. */ 80357c478bd9Sstevel@tonic-gate if (naddrs <= 1 && !changed) 80367c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 80377c478bd9Sstevel@tonic-gate 80387c478bd9Sstevel@tonic-gate /* sort the addresses by queue group */ 80397c478bd9Sstevel@tonic-gate addrs = sm_rpool_malloc_x(e->e_rpool, naddrs * sizeof(ADDRESS *)); 80407c478bd9Sstevel@tonic-gate for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next) 80417c478bd9Sstevel@tonic-gate { 80427c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 80437c478bd9Sstevel@tonic-gate continue; 80447c478bd9Sstevel@tonic-gate addrs[i++] = q; 80457c478bd9Sstevel@tonic-gate } 80467c478bd9Sstevel@tonic-gate qsort(addrs, naddrs, sizeof(ADDRESS *), q_qgrp_compare); 80477c478bd9Sstevel@tonic-gate 80487c478bd9Sstevel@tonic-gate /* split into multiple envelopes, by queue group */ 80497c478bd9Sstevel@tonic-gate nsplits = 0; 80507c478bd9Sstevel@tonic-gate es = NULL; 80517c478bd9Sstevel@tonic-gate e->e_sendqueue = NULL; 80527c478bd9Sstevel@tonic-gate for (i = 0; i < naddrs; ++i) 80537c478bd9Sstevel@tonic-gate { 80547c478bd9Sstevel@tonic-gate if (i == naddrs - 1 || addrs[i]->q_qgrp != addrs[i + 1]->q_qgrp) 80557c478bd9Sstevel@tonic-gate addrs[i]->q_next = NULL; 80567c478bd9Sstevel@tonic-gate else 80577c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1]; 80587c478bd9Sstevel@tonic-gate 80597c478bd9Sstevel@tonic-gate /* same queue group as original envelope? */ 80607c478bd9Sstevel@tonic-gate if (addrs[i]->q_qgrp == e->e_qgrp) 80617c478bd9Sstevel@tonic-gate { 80627c478bd9Sstevel@tonic-gate if (e->e_sendqueue == NULL) 80637c478bd9Sstevel@tonic-gate e->e_sendqueue = addrs[i]; 80647c478bd9Sstevel@tonic-gate continue; 80657c478bd9Sstevel@tonic-gate } 80667c478bd9Sstevel@tonic-gate 80677c478bd9Sstevel@tonic-gate /* different queue group than original envelope */ 80687c478bd9Sstevel@tonic-gate if (es == NULL || addrs[i]->q_qgrp != es->e_qgrp) 80697c478bd9Sstevel@tonic-gate { 80707c478bd9Sstevel@tonic-gate ee = split_env(e, addrs[i], addrs[i]->q_qgrp, NOQDIR); 80717c478bd9Sstevel@tonic-gate es = ee; 80727c478bd9Sstevel@tonic-gate splits[nsplits++] = ee; 80737c478bd9Sstevel@tonic-gate } 80747c478bd9Sstevel@tonic-gate } 80757c478bd9Sstevel@tonic-gate 80767c478bd9Sstevel@tonic-gate /* no splits? return right now. */ 80777c478bd9Sstevel@tonic-gate if (nsplits <= 0) 80787c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 80797c478bd9Sstevel@tonic-gate 80807c478bd9Sstevel@tonic-gate /* assign a queue directory to each additional envelope */ 80817c478bd9Sstevel@tonic-gate for (i = 0; i < nsplits; ++i) 80827c478bd9Sstevel@tonic-gate { 80837c478bd9Sstevel@tonic-gate es = splits[i]; 80847c478bd9Sstevel@tonic-gate #if 0 80857c478bd9Sstevel@tonic-gate es->e_qdir = pickqdir(Queue[es->e_qgrp], es->e_msgsize, es); 80867c478bd9Sstevel@tonic-gate #endif /* 0 */ 80877c478bd9Sstevel@tonic-gate if (!setnewqueue(es)) 80887c478bd9Sstevel@tonic-gate goto failure; 80897c478bd9Sstevel@tonic-gate } 80907c478bd9Sstevel@tonic-gate 80917c478bd9Sstevel@tonic-gate /* sort the additional envelopes by queue file system */ 80927c478bd9Sstevel@tonic-gate qsort(splits, nsplits, sizeof(ENVELOPE *), e_filesys_compare); 80937c478bd9Sstevel@tonic-gate 80947c478bd9Sstevel@tonic-gate /* create data files for each additional envelope */ 80957c478bd9Sstevel@tonic-gate if (!dup_df(e, splits[0])) 80967c478bd9Sstevel@tonic-gate { 80977c478bd9Sstevel@tonic-gate i = 0; 80987c478bd9Sstevel@tonic-gate goto failure; 80997c478bd9Sstevel@tonic-gate } 81007c478bd9Sstevel@tonic-gate for (i = 1; i < nsplits; ++i) 81017c478bd9Sstevel@tonic-gate { 81027c478bd9Sstevel@tonic-gate /* copy or link to the previous data file */ 81037c478bd9Sstevel@tonic-gate if (!dup_df(splits[i - 1], splits[i])) 81047c478bd9Sstevel@tonic-gate goto failure; 81057c478bd9Sstevel@tonic-gate } 81067c478bd9Sstevel@tonic-gate 81077c478bd9Sstevel@tonic-gate /* success: prepend the new envelopes to the e->e_sibling list */ 81087c478bd9Sstevel@tonic-gate for (i = 0; i < nsplits; ++i) 81097c478bd9Sstevel@tonic-gate { 81107c478bd9Sstevel@tonic-gate es = splits[i]; 81117c478bd9Sstevel@tonic-gate es->e_sibling = e->e_sibling; 81127c478bd9Sstevel@tonic-gate e->e_sibling = es; 81137c478bd9Sstevel@tonic-gate } 81147c478bd9Sstevel@tonic-gate return SM_SPLIT_NEW(nsplits); 81157c478bd9Sstevel@tonic-gate 81167c478bd9Sstevel@tonic-gate /* failure: clean up */ 81177c478bd9Sstevel@tonic-gate failure: 81187c478bd9Sstevel@tonic-gate if (i > 0) 81197c478bd9Sstevel@tonic-gate { 81207c478bd9Sstevel@tonic-gate int j; 81217c478bd9Sstevel@tonic-gate 81227c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++) 81237c478bd9Sstevel@tonic-gate (void) unlink(queuename(splits[j], DATAFL_LETTER)); 81247c478bd9Sstevel@tonic-gate } 81257c478bd9Sstevel@tonic-gate e->e_sendqueue = addrs[0]; 81267c478bd9Sstevel@tonic-gate for (i = 0; i < naddrs - 1; ++i) 81277c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1]; 81287c478bd9Sstevel@tonic-gate addrs[naddrs - 1]->q_next = NULL; 81297c478bd9Sstevel@tonic-gate return SM_SPLIT_FAIL; 81307c478bd9Sstevel@tonic-gate } 81317c478bd9Sstevel@tonic-gate 81327c478bd9Sstevel@tonic-gate /* 81337c478bd9Sstevel@tonic-gate ** SPLIT_WITHIN_QUEUE 81347c478bd9Sstevel@tonic-gate ** 81357c478bd9Sstevel@tonic-gate ** Split an envelope with multiple recipients into several 81367c478bd9Sstevel@tonic-gate ** envelopes within the same queue directory, if the number of 81377c478bd9Sstevel@tonic-gate ** recipients exceeds the limit for the queue group. 81387c478bd9Sstevel@tonic-gate ** 81397c478bd9Sstevel@tonic-gate ** Parameters: 81407c478bd9Sstevel@tonic-gate ** e -- envelope. 81417c478bd9Sstevel@tonic-gate ** 81427c478bd9Sstevel@tonic-gate ** Results: 81437c478bd9Sstevel@tonic-gate ** SM_SPLIT_FAIL on failure 81447c478bd9Sstevel@tonic-gate ** SM_SPLIT_NONE if no splitting occurred, 81457c478bd9Sstevel@tonic-gate ** or 1 + the number of additional envelopes created. 81467c478bd9Sstevel@tonic-gate */ 81477c478bd9Sstevel@tonic-gate 81487c478bd9Sstevel@tonic-gate #define SPLIT_LOG_LEVEL 8 81497c478bd9Sstevel@tonic-gate 81507c478bd9Sstevel@tonic-gate static int split_within_queue __P((ENVELOPE *)); 81517c478bd9Sstevel@tonic-gate 81527c478bd9Sstevel@tonic-gate static int 81537c478bd9Sstevel@tonic-gate split_within_queue(e) 81547c478bd9Sstevel@tonic-gate ENVELOPE *e; 81557c478bd9Sstevel@tonic-gate { 81567c478bd9Sstevel@tonic-gate int maxrcpt, nrcpt, ndead, nsplit, i; 81577c478bd9Sstevel@tonic-gate int j, l; 81587c478bd9Sstevel@tonic-gate char *lsplits; 81597c478bd9Sstevel@tonic-gate ADDRESS *q, **addrs; 81607c478bd9Sstevel@tonic-gate ENVELOPE *ee, *firstsibling; 81617c478bd9Sstevel@tonic-gate 81627c478bd9Sstevel@tonic-gate if (!ISVALIDQGRP(e->e_qgrp) || bitset(EF_SPLIT, e->e_flags)) 81637c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 81647c478bd9Sstevel@tonic-gate 81657c478bd9Sstevel@tonic-gate /* don't bother if there is no recipient limit */ 81667c478bd9Sstevel@tonic-gate maxrcpt = Queue[e->e_qgrp]->qg_maxrcpt; 81677c478bd9Sstevel@tonic-gate if (maxrcpt <= 0) 81687c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 81697c478bd9Sstevel@tonic-gate 81707c478bd9Sstevel@tonic-gate /* count recipients */ 81717c478bd9Sstevel@tonic-gate nrcpt = 0; 81727c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 81737c478bd9Sstevel@tonic-gate { 81747c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 81757c478bd9Sstevel@tonic-gate continue; 81767c478bd9Sstevel@tonic-gate ++nrcpt; 81777c478bd9Sstevel@tonic-gate } 81787c478bd9Sstevel@tonic-gate if (nrcpt <= maxrcpt) 81797c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 81807c478bd9Sstevel@tonic-gate 81817c478bd9Sstevel@tonic-gate /* 81827c478bd9Sstevel@tonic-gate ** Preserve the recipient list 81837c478bd9Sstevel@tonic-gate ** so that we can restore it in case of error. 81847c478bd9Sstevel@tonic-gate ** (But we discard dead addresses.) 81857c478bd9Sstevel@tonic-gate */ 81867c478bd9Sstevel@tonic-gate 81877c478bd9Sstevel@tonic-gate addrs = sm_rpool_malloc_x(e->e_rpool, nrcpt * sizeof(ADDRESS *)); 81887c478bd9Sstevel@tonic-gate for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next) 81897c478bd9Sstevel@tonic-gate { 81907c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 81917c478bd9Sstevel@tonic-gate continue; 81927c478bd9Sstevel@tonic-gate addrs[i++] = q; 81937c478bd9Sstevel@tonic-gate } 81947c478bd9Sstevel@tonic-gate 81957c478bd9Sstevel@tonic-gate /* 81967c478bd9Sstevel@tonic-gate ** Partition the recipient list so that bad and sent addresses 81977c478bd9Sstevel@tonic-gate ** come first. These will go with the original envelope, and 81987c478bd9Sstevel@tonic-gate ** do not count towards the maxrcpt limit. 81997c478bd9Sstevel@tonic-gate ** addrs[] does not contain QS_IS_DEAD() addresses. 82007c478bd9Sstevel@tonic-gate */ 82017c478bd9Sstevel@tonic-gate 82027c478bd9Sstevel@tonic-gate ndead = 0; 82037c478bd9Sstevel@tonic-gate for (i = 0; i < nrcpt; ++i) 82047c478bd9Sstevel@tonic-gate { 82057c478bd9Sstevel@tonic-gate if (QS_IS_BADADDR(addrs[i]->q_state) || 82067c478bd9Sstevel@tonic-gate QS_IS_SENT(addrs[i]->q_state) || 82077c478bd9Sstevel@tonic-gate QS_IS_DEAD(addrs[i]->q_state)) /* for paranoia's sake */ 82087c478bd9Sstevel@tonic-gate { 82097c478bd9Sstevel@tonic-gate if (i > ndead) 82107c478bd9Sstevel@tonic-gate { 82117c478bd9Sstevel@tonic-gate ADDRESS *tmp = addrs[i]; 82127c478bd9Sstevel@tonic-gate 82137c478bd9Sstevel@tonic-gate addrs[i] = addrs[ndead]; 82147c478bd9Sstevel@tonic-gate addrs[ndead] = tmp; 82157c478bd9Sstevel@tonic-gate } 82167c478bd9Sstevel@tonic-gate ++ndead; 82177c478bd9Sstevel@tonic-gate } 82187c478bd9Sstevel@tonic-gate } 82197c478bd9Sstevel@tonic-gate 82207c478bd9Sstevel@tonic-gate /* Check if no splitting required. */ 82217c478bd9Sstevel@tonic-gate if (nrcpt - ndead <= maxrcpt) 82227c478bd9Sstevel@tonic-gate return SM_SPLIT_NONE; 82237c478bd9Sstevel@tonic-gate 82247c478bd9Sstevel@tonic-gate /* fix links */ 82257c478bd9Sstevel@tonic-gate for (i = 0; i < nrcpt - 1; ++i) 82267c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1]; 82277c478bd9Sstevel@tonic-gate addrs[nrcpt - 1]->q_next = NULL; 82287c478bd9Sstevel@tonic-gate e->e_sendqueue = addrs[0]; 82297c478bd9Sstevel@tonic-gate 82307c478bd9Sstevel@tonic-gate /* prepare buffer for logging */ 82317c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL) 82327c478bd9Sstevel@tonic-gate { 82337c478bd9Sstevel@tonic-gate l = MAXLINE; 82347c478bd9Sstevel@tonic-gate lsplits = sm_malloc(l); 82357c478bd9Sstevel@tonic-gate if (lsplits != NULL) 82367c478bd9Sstevel@tonic-gate *lsplits = '\0'; 82377c478bd9Sstevel@tonic-gate j = 0; 82387c478bd9Sstevel@tonic-gate } 82397c478bd9Sstevel@tonic-gate else 82407c478bd9Sstevel@tonic-gate { 82417c478bd9Sstevel@tonic-gate /* get rid of stupid compiler warnings */ 82427c478bd9Sstevel@tonic-gate lsplits = NULL; 82437c478bd9Sstevel@tonic-gate j = l = 0; 82447c478bd9Sstevel@tonic-gate } 82457c478bd9Sstevel@tonic-gate 82467c478bd9Sstevel@tonic-gate /* split the envelope */ 82477c478bd9Sstevel@tonic-gate firstsibling = e->e_sibling; 82487c478bd9Sstevel@tonic-gate i = maxrcpt + ndead; 82497c478bd9Sstevel@tonic-gate nsplit = 0; 82507c478bd9Sstevel@tonic-gate for (;;) 82517c478bd9Sstevel@tonic-gate { 82527c478bd9Sstevel@tonic-gate addrs[i - 1]->q_next = NULL; 82537c478bd9Sstevel@tonic-gate ee = split_env(e, addrs[i], e->e_qgrp, e->e_qdir); 82547c478bd9Sstevel@tonic-gate if (!dup_df(e, ee)) 82557c478bd9Sstevel@tonic-gate { 82567c478bd9Sstevel@tonic-gate 82577c478bd9Sstevel@tonic-gate ee = firstsibling; 82587c478bd9Sstevel@tonic-gate while (ee != NULL) 82597c478bd9Sstevel@tonic-gate { 82607c478bd9Sstevel@tonic-gate (void) unlink(queuename(ee, DATAFL_LETTER)); 82617c478bd9Sstevel@tonic-gate ee = ee->e_sibling; 82627c478bd9Sstevel@tonic-gate } 82637c478bd9Sstevel@tonic-gate 82647c478bd9Sstevel@tonic-gate /* Error. Restore e's sibling & recipient lists. */ 82657c478bd9Sstevel@tonic-gate e->e_sibling = firstsibling; 82667c478bd9Sstevel@tonic-gate for (i = 0; i < nrcpt - 1; ++i) 82677c478bd9Sstevel@tonic-gate addrs[i]->q_next = addrs[i + 1]; 82687c478bd9Sstevel@tonic-gate if (lsplits != NULL) 82697c478bd9Sstevel@tonic-gate sm_free(lsplits); 82707c478bd9Sstevel@tonic-gate return SM_SPLIT_FAIL; 82717c478bd9Sstevel@tonic-gate } 82727c478bd9Sstevel@tonic-gate 82737c478bd9Sstevel@tonic-gate /* prepend the new envelope to e->e_sibling */ 82747c478bd9Sstevel@tonic-gate ee->e_sibling = e->e_sibling; 82757c478bd9Sstevel@tonic-gate e->e_sibling = ee; 82767c478bd9Sstevel@tonic-gate ++nsplit; 82777c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL) 82787c478bd9Sstevel@tonic-gate { 82797c478bd9Sstevel@tonic-gate if (j >= l - strlen(ee->e_id) - 3) 82807c478bd9Sstevel@tonic-gate { 82817c478bd9Sstevel@tonic-gate char *p; 82827c478bd9Sstevel@tonic-gate 82837c478bd9Sstevel@tonic-gate l += MAXLINE; 82847c478bd9Sstevel@tonic-gate p = sm_realloc(lsplits, l); 82857c478bd9Sstevel@tonic-gate if (p == NULL) 82867c478bd9Sstevel@tonic-gate { 82877c478bd9Sstevel@tonic-gate /* let's try to get this done */ 82887c478bd9Sstevel@tonic-gate sm_free(lsplits); 82897c478bd9Sstevel@tonic-gate lsplits = NULL; 82907c478bd9Sstevel@tonic-gate } 82917c478bd9Sstevel@tonic-gate else 82927c478bd9Sstevel@tonic-gate lsplits = p; 82937c478bd9Sstevel@tonic-gate } 82947c478bd9Sstevel@tonic-gate if (lsplits != NULL) 82957c478bd9Sstevel@tonic-gate { 82967c478bd9Sstevel@tonic-gate if (j == 0) 82977c478bd9Sstevel@tonic-gate j += sm_strlcat(lsplits + j, 82987c478bd9Sstevel@tonic-gate ee->e_id, 82997c478bd9Sstevel@tonic-gate l - j); 83007c478bd9Sstevel@tonic-gate else 83017c478bd9Sstevel@tonic-gate j += sm_strlcat2(lsplits + j, 83027c478bd9Sstevel@tonic-gate "; ", 83037c478bd9Sstevel@tonic-gate ee->e_id, 83047c478bd9Sstevel@tonic-gate l - j); 83057c478bd9Sstevel@tonic-gate SM_ASSERT(j < l); 83067c478bd9Sstevel@tonic-gate } 83077c478bd9Sstevel@tonic-gate } 83087c478bd9Sstevel@tonic-gate if (nrcpt - i <= maxrcpt) 83097c478bd9Sstevel@tonic-gate break; 83107c478bd9Sstevel@tonic-gate i += maxrcpt; 83117c478bd9Sstevel@tonic-gate } 83127c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL) 83137c478bd9Sstevel@tonic-gate { 83147c478bd9Sstevel@tonic-gate if (nsplit > 0) 83157c478bd9Sstevel@tonic-gate { 83167c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id, 83177c478bd9Sstevel@tonic-gate "split: maxrcpts=%d, rcpts=%d, count=%d, id%s=%s", 83187c478bd9Sstevel@tonic-gate maxrcpt, nrcpt - ndead, nsplit, 83197c478bd9Sstevel@tonic-gate nsplit > 1 ? "s" : "", lsplits); 83207c478bd9Sstevel@tonic-gate } 83217c478bd9Sstevel@tonic-gate sm_free(lsplits); 83227c478bd9Sstevel@tonic-gate } 83237c478bd9Sstevel@tonic-gate return SM_SPLIT_NEW(nsplit); 83247c478bd9Sstevel@tonic-gate } 83257c478bd9Sstevel@tonic-gate /* 83267c478bd9Sstevel@tonic-gate ** SPLIT_BY_RECIPIENT 83277c478bd9Sstevel@tonic-gate ** 83287c478bd9Sstevel@tonic-gate ** Split an envelope with multiple recipients into multiple 83297c478bd9Sstevel@tonic-gate ** envelopes as required by the sendmail configuration. 83307c478bd9Sstevel@tonic-gate ** 83317c478bd9Sstevel@tonic-gate ** Parameters: 83327c478bd9Sstevel@tonic-gate ** e -- envelope. 83337c478bd9Sstevel@tonic-gate ** 83347c478bd9Sstevel@tonic-gate ** Results: 83357c478bd9Sstevel@tonic-gate ** Returns true on success, false on failure. 83367c478bd9Sstevel@tonic-gate ** 83377c478bd9Sstevel@tonic-gate ** Side Effects: 83387c478bd9Sstevel@tonic-gate ** see split_across_queue_groups(), split_within_queue(e) 83397c478bd9Sstevel@tonic-gate */ 83407c478bd9Sstevel@tonic-gate 83417c478bd9Sstevel@tonic-gate bool 83427c478bd9Sstevel@tonic-gate split_by_recipient(e) 83437c478bd9Sstevel@tonic-gate ENVELOPE *e; 83447c478bd9Sstevel@tonic-gate { 83457c478bd9Sstevel@tonic-gate int split, n, i, j, l; 83467c478bd9Sstevel@tonic-gate char *lsplits; 83477c478bd9Sstevel@tonic-gate ENVELOPE *ee, *next, *firstsibling; 83487c478bd9Sstevel@tonic-gate 83497c478bd9Sstevel@tonic-gate if (OpMode == SM_VERIFY || !ISVALIDQGRP(e->e_qgrp) || 83507c478bd9Sstevel@tonic-gate bitset(EF_SPLIT, e->e_flags)) 83517c478bd9Sstevel@tonic-gate return true; 83527c478bd9Sstevel@tonic-gate n = split_across_queue_groups(e); 83537c478bd9Sstevel@tonic-gate if (n == SM_SPLIT_FAIL) 83547c478bd9Sstevel@tonic-gate return false; 83557c478bd9Sstevel@tonic-gate firstsibling = ee = e->e_sibling; 83567c478bd9Sstevel@tonic-gate if (n > 1 && LogLevel > SPLIT_LOG_LEVEL) 83577c478bd9Sstevel@tonic-gate { 83587c478bd9Sstevel@tonic-gate l = MAXLINE; 83597c478bd9Sstevel@tonic-gate lsplits = sm_malloc(l); 83607c478bd9Sstevel@tonic-gate if (lsplits != NULL) 83617c478bd9Sstevel@tonic-gate *lsplits = '\0'; 83627c478bd9Sstevel@tonic-gate j = 0; 83637c478bd9Sstevel@tonic-gate } 83647c478bd9Sstevel@tonic-gate else 83657c478bd9Sstevel@tonic-gate { 83667c478bd9Sstevel@tonic-gate /* get rid of stupid compiler warnings */ 83677c478bd9Sstevel@tonic-gate lsplits = NULL; 83687c478bd9Sstevel@tonic-gate j = l = 0; 83697c478bd9Sstevel@tonic-gate } 83707c478bd9Sstevel@tonic-gate for (i = 1; i < n; ++i) 83717c478bd9Sstevel@tonic-gate { 83727c478bd9Sstevel@tonic-gate next = ee->e_sibling; 83737c478bd9Sstevel@tonic-gate if (split_within_queue(ee) == SM_SPLIT_FAIL) 83747c478bd9Sstevel@tonic-gate { 83757c478bd9Sstevel@tonic-gate e->e_sibling = firstsibling; 83767c478bd9Sstevel@tonic-gate return false; 83777c478bd9Sstevel@tonic-gate } 83787c478bd9Sstevel@tonic-gate ee->e_flags |= EF_SPLIT; 83797c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL) 83807c478bd9Sstevel@tonic-gate { 83817c478bd9Sstevel@tonic-gate if (j >= l - strlen(ee->e_id) - 3) 83827c478bd9Sstevel@tonic-gate { 83837c478bd9Sstevel@tonic-gate char *p; 83847c478bd9Sstevel@tonic-gate 83857c478bd9Sstevel@tonic-gate l += MAXLINE; 83867c478bd9Sstevel@tonic-gate p = sm_realloc(lsplits, l); 83877c478bd9Sstevel@tonic-gate if (p == NULL) 83887c478bd9Sstevel@tonic-gate { 83897c478bd9Sstevel@tonic-gate /* let's try to get this done */ 83907c478bd9Sstevel@tonic-gate sm_free(lsplits); 83917c478bd9Sstevel@tonic-gate lsplits = NULL; 83927c478bd9Sstevel@tonic-gate } 83937c478bd9Sstevel@tonic-gate else 83947c478bd9Sstevel@tonic-gate lsplits = p; 83957c478bd9Sstevel@tonic-gate } 83967c478bd9Sstevel@tonic-gate if (lsplits != NULL) 83977c478bd9Sstevel@tonic-gate { 83987c478bd9Sstevel@tonic-gate if (j == 0) 83997c478bd9Sstevel@tonic-gate j += sm_strlcat(lsplits + j, 84007c478bd9Sstevel@tonic-gate ee->e_id, l - j); 84017c478bd9Sstevel@tonic-gate else 84027c478bd9Sstevel@tonic-gate j += sm_strlcat2(lsplits + j, "; ", 84037c478bd9Sstevel@tonic-gate ee->e_id, l - j); 84047c478bd9Sstevel@tonic-gate SM_ASSERT(j < l); 84057c478bd9Sstevel@tonic-gate } 84067c478bd9Sstevel@tonic-gate } 84077c478bd9Sstevel@tonic-gate ee = next; 84087c478bd9Sstevel@tonic-gate } 84097c478bd9Sstevel@tonic-gate if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL && n > 1) 84107c478bd9Sstevel@tonic-gate { 84117c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id, "split: count=%d, id%s=%s", 84127c478bd9Sstevel@tonic-gate n - 1, n > 2 ? "s" : "", lsplits); 84137c478bd9Sstevel@tonic-gate sm_free(lsplits); 84147c478bd9Sstevel@tonic-gate } 84157c478bd9Sstevel@tonic-gate split = split_within_queue(e) != SM_SPLIT_FAIL; 84167c478bd9Sstevel@tonic-gate if (split) 84177c478bd9Sstevel@tonic-gate e->e_flags |= EF_SPLIT; 84187c478bd9Sstevel@tonic-gate return split; 84197c478bd9Sstevel@tonic-gate } 84207c478bd9Sstevel@tonic-gate 84217c478bd9Sstevel@tonic-gate /* 84227c478bd9Sstevel@tonic-gate ** QUARANTINE_QUEUE_ITEM -- {un,}quarantine a single envelope 84237c478bd9Sstevel@tonic-gate ** 84247c478bd9Sstevel@tonic-gate ** Add/remove quarantine reason and requeue appropriately. 84257c478bd9Sstevel@tonic-gate ** 84267c478bd9Sstevel@tonic-gate ** Parameters: 84277c478bd9Sstevel@tonic-gate ** qgrp -- queue group for the item 84287c478bd9Sstevel@tonic-gate ** qdir -- queue directory in the given queue group 84297c478bd9Sstevel@tonic-gate ** e -- envelope information for the item 84307c478bd9Sstevel@tonic-gate ** reason -- quarantine reason, NULL means unquarantine. 84317c478bd9Sstevel@tonic-gate ** 84327c478bd9Sstevel@tonic-gate ** Results: 84337c478bd9Sstevel@tonic-gate ** true if item changed, false otherwise 84347c478bd9Sstevel@tonic-gate ** 84357c478bd9Sstevel@tonic-gate ** Side Effects: 84367c478bd9Sstevel@tonic-gate ** Changes quarantine tag in queue file and renames it. 84377c478bd9Sstevel@tonic-gate */ 84387c478bd9Sstevel@tonic-gate 84397c478bd9Sstevel@tonic-gate static bool 84407c478bd9Sstevel@tonic-gate quarantine_queue_item(qgrp, qdir, e, reason) 84417c478bd9Sstevel@tonic-gate int qgrp; 84427c478bd9Sstevel@tonic-gate int qdir; 84437c478bd9Sstevel@tonic-gate ENVELOPE *e; 84447c478bd9Sstevel@tonic-gate char *reason; 84457c478bd9Sstevel@tonic-gate { 84467c478bd9Sstevel@tonic-gate bool dirty = false; 84477c478bd9Sstevel@tonic-gate bool failing = false; 84487c478bd9Sstevel@tonic-gate bool foundq = false; 84497c478bd9Sstevel@tonic-gate bool finished = false; 84507c478bd9Sstevel@tonic-gate int fd; 84517c478bd9Sstevel@tonic-gate int flags; 84527c478bd9Sstevel@tonic-gate int oldtype; 84537c478bd9Sstevel@tonic-gate int newtype; 84547c478bd9Sstevel@tonic-gate int save_errno; 84557c478bd9Sstevel@tonic-gate MODE_T oldumask = 0; 84567c478bd9Sstevel@tonic-gate SM_FILE_T *oldqfp, *tempqfp; 84577c478bd9Sstevel@tonic-gate char *bp; 8458058561cbSjbeck int bufsize; 84597c478bd9Sstevel@tonic-gate char oldqf[MAXPATHLEN]; 84607c478bd9Sstevel@tonic-gate char tempqf[MAXPATHLEN]; 84617c478bd9Sstevel@tonic-gate char newqf[MAXPATHLEN]; 84627c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 84637c478bd9Sstevel@tonic-gate 84647c478bd9Sstevel@tonic-gate oldtype = queue_letter(e, ANYQFL_LETTER); 8465058561cbSjbeck (void) sm_strlcpy(oldqf, queuename(e, ANYQFL_LETTER), sizeof(oldqf)); 8466058561cbSjbeck (void) sm_strlcpy(tempqf, queuename(e, NEWQFL_LETTER), sizeof(tempqf)); 84677c478bd9Sstevel@tonic-gate 84687c478bd9Sstevel@tonic-gate /* 84697c478bd9Sstevel@tonic-gate ** Instead of duplicating all the open 84707c478bd9Sstevel@tonic-gate ** and lock code here, tell readqf() to 84717c478bd9Sstevel@tonic-gate ** do that work and return the open 84727c478bd9Sstevel@tonic-gate ** file pointer in e_lockfp. Note that 84737c478bd9Sstevel@tonic-gate ** we must release the locks properly when 84747c478bd9Sstevel@tonic-gate ** we are done. 84757c478bd9Sstevel@tonic-gate */ 84767c478bd9Sstevel@tonic-gate 84777c478bd9Sstevel@tonic-gate if (!readqf(e, true)) 84787c478bd9Sstevel@tonic-gate { 84797c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 84807c478bd9Sstevel@tonic-gate "Skipping %s\n", qid_printname(e)); 84817c478bd9Sstevel@tonic-gate return false; 84827c478bd9Sstevel@tonic-gate } 84837c478bd9Sstevel@tonic-gate oldqfp = e->e_lockfp; 84847c478bd9Sstevel@tonic-gate 84857c478bd9Sstevel@tonic-gate /* open the new queue file */ 84867c478bd9Sstevel@tonic-gate flags = O_CREAT|O_WRONLY|O_EXCL; 84877c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 84887c478bd9Sstevel@tonic-gate oldumask = umask(002); 84897c478bd9Sstevel@tonic-gate fd = open(tempqf, flags, QueueFileMode); 84907c478bd9Sstevel@tonic-gate if (bitset(S_IWGRP, QueueFileMode)) 84917c478bd9Sstevel@tonic-gate (void) umask(oldumask); 84927c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 84937c478bd9Sstevel@tonic-gate 84947c478bd9Sstevel@tonic-gate if (fd < 0) 84957c478bd9Sstevel@tonic-gate { 84967c478bd9Sstevel@tonic-gate save_errno = errno; 84977c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 84987c478bd9Sstevel@tonic-gate "Skipping %s: Could not open %s: %s\n", 84997c478bd9Sstevel@tonic-gate qid_printname(e), tempqf, 85007c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 85017c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT); 85027c478bd9Sstevel@tonic-gate return false; 85037c478bd9Sstevel@tonic-gate } 85047c478bd9Sstevel@tonic-gate if (!lockfile(fd, tempqf, NULL, LOCK_EX|LOCK_NB)) 85057c478bd9Sstevel@tonic-gate { 85067c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 85077c478bd9Sstevel@tonic-gate "Skipping %s: Could not lock %s\n", 85087c478bd9Sstevel@tonic-gate qid_printname(e), tempqf); 85097c478bd9Sstevel@tonic-gate (void) close(fd); 85107c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT); 85117c478bd9Sstevel@tonic-gate return false; 85127c478bd9Sstevel@tonic-gate } 85137c478bd9Sstevel@tonic-gate 85147c478bd9Sstevel@tonic-gate tempqfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &fd, 85157c478bd9Sstevel@tonic-gate SM_IO_WRONLY_B, NULL); 85167c478bd9Sstevel@tonic-gate if (tempqfp == NULL) 85177c478bd9Sstevel@tonic-gate { 85187c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 85197c478bd9Sstevel@tonic-gate "Skipping %s: Could not lock %s\n", 85207c478bd9Sstevel@tonic-gate qid_printname(e), tempqf); 85217c478bd9Sstevel@tonic-gate (void) close(fd); 85227c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT); 85237c478bd9Sstevel@tonic-gate return false; 85247c478bd9Sstevel@tonic-gate } 85257c478bd9Sstevel@tonic-gate 85267c478bd9Sstevel@tonic-gate /* Copy the data over, changing the quarantine reason */ 8527058561cbSjbeck while (bufsize = sizeof(buf), 8528058561cbSjbeck (bp = fgetfolded(buf, &bufsize, oldqfp)) != NULL) 85297c478bd9Sstevel@tonic-gate { 85307c478bd9Sstevel@tonic-gate if (tTd(40, 4)) 85317c478bd9Sstevel@tonic-gate sm_dprintf("+++++ %s\n", bp); 85327c478bd9Sstevel@tonic-gate switch (bp[0]) 85337c478bd9Sstevel@tonic-gate { 85347c478bd9Sstevel@tonic-gate case 'q': /* quarantine reason */ 85357c478bd9Sstevel@tonic-gate foundq = true; 85367c478bd9Sstevel@tonic-gate if (reason == NULL) 85377c478bd9Sstevel@tonic-gate { 85387c478bd9Sstevel@tonic-gate if (Verbose) 85397c478bd9Sstevel@tonic-gate { 85407c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 85417c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 85427c478bd9Sstevel@tonic-gate "%s: Removed quarantine of \"%s\"\n", 85437c478bd9Sstevel@tonic-gate e->e_id, &bp[1]); 85447c478bd9Sstevel@tonic-gate } 85457c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "unquarantine"); 85467c478bd9Sstevel@tonic-gate dirty = true; 85477c478bd9Sstevel@tonic-gate } 85487c478bd9Sstevel@tonic-gate else if (strcmp(reason, &bp[1]) == 0) 85497c478bd9Sstevel@tonic-gate { 85507c478bd9Sstevel@tonic-gate if (Verbose) 85517c478bd9Sstevel@tonic-gate { 85527c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 85537c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 85547c478bd9Sstevel@tonic-gate "%s: Already quarantined with \"%s\"\n", 85557c478bd9Sstevel@tonic-gate e->e_id, reason); 85567c478bd9Sstevel@tonic-gate } 85577c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 85587c478bd9Sstevel@tonic-gate "q%s\n", reason); 85597c478bd9Sstevel@tonic-gate } 85607c478bd9Sstevel@tonic-gate else 85617c478bd9Sstevel@tonic-gate { 85627c478bd9Sstevel@tonic-gate if (Verbose) 85637c478bd9Sstevel@tonic-gate { 85647c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 85657c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 85667c478bd9Sstevel@tonic-gate "%s: Quarantine changed from \"%s\" to \"%s\"\n", 85677c478bd9Sstevel@tonic-gate e->e_id, &bp[1], 85687c478bd9Sstevel@tonic-gate reason); 85697c478bd9Sstevel@tonic-gate } 85707c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 85717c478bd9Sstevel@tonic-gate "q%s\n", reason); 85727c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "quarantine=%s", 85737c478bd9Sstevel@tonic-gate reason); 85747c478bd9Sstevel@tonic-gate dirty = true; 85757c478bd9Sstevel@tonic-gate } 85767c478bd9Sstevel@tonic-gate break; 85777c478bd9Sstevel@tonic-gate 85787c478bd9Sstevel@tonic-gate case 'S': 85797c478bd9Sstevel@tonic-gate /* 85807c478bd9Sstevel@tonic-gate ** If we are quarantining an unquarantined item, 85817c478bd9Sstevel@tonic-gate ** need to put in a new 'q' line before it's 85827c478bd9Sstevel@tonic-gate ** too late. 85837c478bd9Sstevel@tonic-gate */ 85847c478bd9Sstevel@tonic-gate 85857c478bd9Sstevel@tonic-gate if (!foundq && reason != NULL) 85867c478bd9Sstevel@tonic-gate { 85877c478bd9Sstevel@tonic-gate if (Verbose) 85887c478bd9Sstevel@tonic-gate { 85897c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 85907c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 85917c478bd9Sstevel@tonic-gate "%s: Quarantined with \"%s\"\n", 85927c478bd9Sstevel@tonic-gate e->e_id, reason); 85937c478bd9Sstevel@tonic-gate } 85947c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 85957c478bd9Sstevel@tonic-gate "q%s\n", reason); 85967c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "quarantine=%s", 85977c478bd9Sstevel@tonic-gate reason); 85987c478bd9Sstevel@tonic-gate foundq = true; 85997c478bd9Sstevel@tonic-gate dirty = true; 86007c478bd9Sstevel@tonic-gate } 86017c478bd9Sstevel@tonic-gate 86027c478bd9Sstevel@tonic-gate /* Copy the line to the new file */ 86037c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 86047c478bd9Sstevel@tonic-gate "%s\n", bp); 86057c478bd9Sstevel@tonic-gate break; 86067c478bd9Sstevel@tonic-gate 86077c478bd9Sstevel@tonic-gate case '.': 86087c478bd9Sstevel@tonic-gate finished = true; 86097c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 86107c478bd9Sstevel@tonic-gate 86117c478bd9Sstevel@tonic-gate default: 86127c478bd9Sstevel@tonic-gate /* Copy the line to the new file */ 86137c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT, 86147c478bd9Sstevel@tonic-gate "%s\n", bp); 86157c478bd9Sstevel@tonic-gate break; 86167c478bd9Sstevel@tonic-gate } 8617058561cbSjbeck if (bp != buf) 8618058561cbSjbeck sm_free(bp); 86197c478bd9Sstevel@tonic-gate } 86207c478bd9Sstevel@tonic-gate 86217c478bd9Sstevel@tonic-gate /* Make sure we read the whole old file */ 86227c478bd9Sstevel@tonic-gate errno = sm_io_error(tempqfp); 86237c478bd9Sstevel@tonic-gate if (errno != 0 && errno != SM_IO_EOF) 86247c478bd9Sstevel@tonic-gate { 86257c478bd9Sstevel@tonic-gate save_errno = errno; 86267c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 86277c478bd9Sstevel@tonic-gate "Skipping %s: Error reading %s: %s\n", 86287c478bd9Sstevel@tonic-gate qid_printname(e), oldqf, 86297c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 86307c478bd9Sstevel@tonic-gate failing = true; 86317c478bd9Sstevel@tonic-gate } 86327c478bd9Sstevel@tonic-gate 86337c478bd9Sstevel@tonic-gate if (!failing && !finished) 86347c478bd9Sstevel@tonic-gate { 86357c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 86367c478bd9Sstevel@tonic-gate "Skipping %s: Incomplete file: %s\n", 86377c478bd9Sstevel@tonic-gate qid_printname(e), oldqf); 86387c478bd9Sstevel@tonic-gate failing = true; 86397c478bd9Sstevel@tonic-gate } 86407c478bd9Sstevel@tonic-gate 86417c478bd9Sstevel@tonic-gate /* Check if we actually changed anything or we can just bail now */ 86427c478bd9Sstevel@tonic-gate if (!dirty) 86437c478bd9Sstevel@tonic-gate { 86447c478bd9Sstevel@tonic-gate /* pretend we failed, even though we technically didn't */ 86457c478bd9Sstevel@tonic-gate failing = true; 86467c478bd9Sstevel@tonic-gate } 86477c478bd9Sstevel@tonic-gate 86487c478bd9Sstevel@tonic-gate /* Make sure we wrote things out safely */ 86497c478bd9Sstevel@tonic-gate if (!failing && 86507c478bd9Sstevel@tonic-gate (sm_io_flush(tempqfp, SM_TIME_DEFAULT) != 0 || 86517c478bd9Sstevel@tonic-gate ((SuperSafe == SAFE_REALLY || 86527c478bd9Sstevel@tonic-gate SuperSafe == SAFE_REALLY_POSTMILTER || 86537c478bd9Sstevel@tonic-gate SuperSafe == SAFE_INTERACTIVE) && 86547c478bd9Sstevel@tonic-gate fsync(sm_io_getinfo(tempqfp, SM_IO_WHAT_FD, NULL)) < 0) || 86557c478bd9Sstevel@tonic-gate ((errno = sm_io_error(tempqfp)) != 0))) 86567c478bd9Sstevel@tonic-gate { 86577c478bd9Sstevel@tonic-gate save_errno = errno; 86587c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 86597c478bd9Sstevel@tonic-gate "Skipping %s: Error writing %s: %s\n", 86607c478bd9Sstevel@tonic-gate qid_printname(e), tempqf, 86617c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 86627c478bd9Sstevel@tonic-gate failing = true; 86637c478bd9Sstevel@tonic-gate } 86647c478bd9Sstevel@tonic-gate 86657c478bd9Sstevel@tonic-gate 86667c478bd9Sstevel@tonic-gate /* Figure out the new filename */ 86677c478bd9Sstevel@tonic-gate newtype = (reason == NULL ? NORMQF_LETTER : QUARQF_LETTER); 86687c478bd9Sstevel@tonic-gate if (oldtype == newtype) 86697c478bd9Sstevel@tonic-gate { 86707c478bd9Sstevel@tonic-gate /* going to rename tempqf to oldqf */ 8671058561cbSjbeck (void) sm_strlcpy(newqf, oldqf, sizeof(newqf)); 86727c478bd9Sstevel@tonic-gate } 86737c478bd9Sstevel@tonic-gate else 86747c478bd9Sstevel@tonic-gate { 86757c478bd9Sstevel@tonic-gate /* going to rename tempqf to new name based on newtype */ 8676058561cbSjbeck (void) sm_strlcpy(newqf, queuename(e, newtype), sizeof(newqf)); 86777c478bd9Sstevel@tonic-gate } 86787c478bd9Sstevel@tonic-gate 86797c478bd9Sstevel@tonic-gate save_errno = 0; 86807c478bd9Sstevel@tonic-gate 86817c478bd9Sstevel@tonic-gate /* rename tempqf to newqf */ 86827c478bd9Sstevel@tonic-gate if (!failing && 86837c478bd9Sstevel@tonic-gate rename(tempqf, newqf) < 0) 86847c478bd9Sstevel@tonic-gate save_errno = (errno == 0) ? EINVAL : errno; 86857c478bd9Sstevel@tonic-gate 86867c478bd9Sstevel@tonic-gate /* Check rename() success */ 86877c478bd9Sstevel@tonic-gate if (!failing && save_errno != 0) 86887c478bd9Sstevel@tonic-gate { 86897c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, 86907c478bd9Sstevel@tonic-gate "quarantine_queue_item: rename(%s, %s): %s", 86917c478bd9Sstevel@tonic-gate tempqf, newqf, sm_errstring(save_errno)); 86927c478bd9Sstevel@tonic-gate 86937c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 86947c478bd9Sstevel@tonic-gate "Error renaming %s to %s: %s\n", 86957c478bd9Sstevel@tonic-gate tempqf, newqf, 86967c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 86977c478bd9Sstevel@tonic-gate if (oldtype == newtype) 86987c478bd9Sstevel@tonic-gate { 86997c478bd9Sstevel@tonic-gate /* 87007c478bd9Sstevel@tonic-gate ** Bail here since we don't know the state of 87017c478bd9Sstevel@tonic-gate ** the filesystem and may need to keep tempqf 87027c478bd9Sstevel@tonic-gate ** for the user to rescue us. 87037c478bd9Sstevel@tonic-gate */ 87047c478bd9Sstevel@tonic-gate 87057c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 87067c478bd9Sstevel@tonic-gate errno = save_errno; 87077c478bd9Sstevel@tonic-gate syserr("!452 Error renaming control file %s", tempqf); 87087c478bd9Sstevel@tonic-gate /* NOTREACHED */ 87097c478bd9Sstevel@tonic-gate } 87107c478bd9Sstevel@tonic-gate else 87117c478bd9Sstevel@tonic-gate { 87127c478bd9Sstevel@tonic-gate /* remove new file (if rename() half completed) */ 87137c478bd9Sstevel@tonic-gate if (xunlink(newqf) < 0) 87147c478bd9Sstevel@tonic-gate { 87157c478bd9Sstevel@tonic-gate save_errno = errno; 87167c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 87177c478bd9Sstevel@tonic-gate "Error removing %s: %s\n", 87187c478bd9Sstevel@tonic-gate newqf, 87197c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 87207c478bd9Sstevel@tonic-gate } 87217c478bd9Sstevel@tonic-gate 87227c478bd9Sstevel@tonic-gate /* tempqf removed below */ 87237c478bd9Sstevel@tonic-gate failing = true; 87247c478bd9Sstevel@tonic-gate } 87257c478bd9Sstevel@tonic-gate 87267c478bd9Sstevel@tonic-gate } 87277c478bd9Sstevel@tonic-gate 87287c478bd9Sstevel@tonic-gate /* If changing file types, need to remove old type */ 87297c478bd9Sstevel@tonic-gate if (!failing && oldtype != newtype) 87307c478bd9Sstevel@tonic-gate { 87317c478bd9Sstevel@tonic-gate if (xunlink(oldqf) < 0) 87327c478bd9Sstevel@tonic-gate { 87337c478bd9Sstevel@tonic-gate save_errno = errno; 87347c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 87357c478bd9Sstevel@tonic-gate "Error removing %s: %s\n", 87367c478bd9Sstevel@tonic-gate oldqf, sm_errstring(save_errno)); 87377c478bd9Sstevel@tonic-gate } 87387c478bd9Sstevel@tonic-gate } 87397c478bd9Sstevel@tonic-gate 87407c478bd9Sstevel@tonic-gate /* see if anything above failed */ 87417c478bd9Sstevel@tonic-gate if (failing) 87427c478bd9Sstevel@tonic-gate { 87437c478bd9Sstevel@tonic-gate /* Something failed: remove new file, old file still there */ 87447c478bd9Sstevel@tonic-gate (void) xunlink(tempqf); 87457c478bd9Sstevel@tonic-gate } 87467c478bd9Sstevel@tonic-gate 87477c478bd9Sstevel@tonic-gate /* 87487c478bd9Sstevel@tonic-gate ** fsync() after file operations to make sure metadata is 87497c478bd9Sstevel@tonic-gate ** written to disk on filesystems in which renames are 87507c478bd9Sstevel@tonic-gate ** not guaranteed. It's ok if they fail, mail won't be lost. 87517c478bd9Sstevel@tonic-gate */ 87527c478bd9Sstevel@tonic-gate 87537c478bd9Sstevel@tonic-gate if (SuperSafe != SAFE_NO) 87547c478bd9Sstevel@tonic-gate { 87557c478bd9Sstevel@tonic-gate /* for soft-updates */ 87567c478bd9Sstevel@tonic-gate (void) fsync(sm_io_getinfo(tempqfp, 87577c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, NULL)); 87587c478bd9Sstevel@tonic-gate 87597c478bd9Sstevel@tonic-gate if (!failing) 87607c478bd9Sstevel@tonic-gate { 87617c478bd9Sstevel@tonic-gate /* for soft-updates */ 87627c478bd9Sstevel@tonic-gate (void) fsync(sm_io_getinfo(oldqfp, 87637c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, NULL)); 87647c478bd9Sstevel@tonic-gate } 87657c478bd9Sstevel@tonic-gate 87667c478bd9Sstevel@tonic-gate /* for other odd filesystems */ 87677c478bd9Sstevel@tonic-gate SYNC_DIR(tempqf, false); 87687c478bd9Sstevel@tonic-gate } 87697c478bd9Sstevel@tonic-gate 87707c478bd9Sstevel@tonic-gate /* Close up shop */ 87717c478bd9Sstevel@tonic-gate RELEASE_QUEUE; 87727c478bd9Sstevel@tonic-gate if (tempqfp != NULL) 87737c478bd9Sstevel@tonic-gate (void) sm_io_close(tempqfp, SM_TIME_DEFAULT); 87747c478bd9Sstevel@tonic-gate if (oldqfp != NULL) 87757c478bd9Sstevel@tonic-gate (void) sm_io_close(oldqfp, SM_TIME_DEFAULT); 87767c478bd9Sstevel@tonic-gate 87777c478bd9Sstevel@tonic-gate /* All went well */ 87787c478bd9Sstevel@tonic-gate return !failing; 87797c478bd9Sstevel@tonic-gate } 87807c478bd9Sstevel@tonic-gate 87817c478bd9Sstevel@tonic-gate /* 87827c478bd9Sstevel@tonic-gate ** QUARANTINE_QUEUE -- {un,}quarantine matching items in the queue 87837c478bd9Sstevel@tonic-gate ** 87847c478bd9Sstevel@tonic-gate ** Read all matching queue items, add/remove quarantine 87857c478bd9Sstevel@tonic-gate ** reason, and requeue appropriately. 87867c478bd9Sstevel@tonic-gate ** 87877c478bd9Sstevel@tonic-gate ** Parameters: 87887c478bd9Sstevel@tonic-gate ** reason -- quarantine reason, "." means unquarantine. 87897c478bd9Sstevel@tonic-gate ** qgrplimit -- limit to single queue group unless NOQGRP 87907c478bd9Sstevel@tonic-gate ** 87917c478bd9Sstevel@tonic-gate ** Results: 87927c478bd9Sstevel@tonic-gate ** none. 87937c478bd9Sstevel@tonic-gate ** 87947c478bd9Sstevel@tonic-gate ** Side Effects: 87957c478bd9Sstevel@tonic-gate ** Lots of changes to the queue. 87967c478bd9Sstevel@tonic-gate */ 87977c478bd9Sstevel@tonic-gate 87987c478bd9Sstevel@tonic-gate void 87997c478bd9Sstevel@tonic-gate quarantine_queue(reason, qgrplimit) 88007c478bd9Sstevel@tonic-gate char *reason; 88017c478bd9Sstevel@tonic-gate int qgrplimit; 88027c478bd9Sstevel@tonic-gate { 88037c478bd9Sstevel@tonic-gate int changed = 0; 88047c478bd9Sstevel@tonic-gate int qgrp; 88057c478bd9Sstevel@tonic-gate 88067c478bd9Sstevel@tonic-gate /* Convert internal representation of unquarantine */ 88077c478bd9Sstevel@tonic-gate if (reason != NULL && reason[0] == '.' && reason[1] == '\0') 88087c478bd9Sstevel@tonic-gate reason = NULL; 88097c478bd9Sstevel@tonic-gate 88107c478bd9Sstevel@tonic-gate if (reason != NULL) 88117c478bd9Sstevel@tonic-gate { 88127c478bd9Sstevel@tonic-gate /* clean it */ 88137c478bd9Sstevel@tonic-gate reason = newstr(denlstring(reason, true, true)); 88147c478bd9Sstevel@tonic-gate } 88157c478bd9Sstevel@tonic-gate 88167c478bd9Sstevel@tonic-gate for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++) 88177c478bd9Sstevel@tonic-gate { 88187c478bd9Sstevel@tonic-gate int qdir; 88197c478bd9Sstevel@tonic-gate 88207c478bd9Sstevel@tonic-gate if (qgrplimit != NOQGRP && qgrplimit != qgrp) 88217c478bd9Sstevel@tonic-gate continue; 88227c478bd9Sstevel@tonic-gate 88237c478bd9Sstevel@tonic-gate for (qdir = 0; qdir < Queue[qgrp]->qg_numqueues; qdir++) 88247c478bd9Sstevel@tonic-gate { 88257c478bd9Sstevel@tonic-gate int i; 88267c478bd9Sstevel@tonic-gate int nrequests; 88277c478bd9Sstevel@tonic-gate 88287c478bd9Sstevel@tonic-gate if (StopRequest) 88297c478bd9Sstevel@tonic-gate stop_sendmail(); 88307c478bd9Sstevel@tonic-gate 88317c478bd9Sstevel@tonic-gate nrequests = gatherq(qgrp, qdir, true, NULL, NULL); 88327c478bd9Sstevel@tonic-gate 88337c478bd9Sstevel@tonic-gate /* first see if there is anything */ 88347c478bd9Sstevel@tonic-gate if (nrequests <= 0) 88357c478bd9Sstevel@tonic-gate { 88367c478bd9Sstevel@tonic-gate if (Verbose) 88377c478bd9Sstevel@tonic-gate { 88387c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 88397c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, "%s: no matches\n", 88407c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 88417c478bd9Sstevel@tonic-gate } 88427c478bd9Sstevel@tonic-gate continue; 88437c478bd9Sstevel@tonic-gate } 88447c478bd9Sstevel@tonic-gate 88457c478bd9Sstevel@tonic-gate if (Verbose) 88467c478bd9Sstevel@tonic-gate { 88477c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 88487c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, "Processing %s:\n", 88497c478bd9Sstevel@tonic-gate qid_printqueue(qgrp, qdir)); 88507c478bd9Sstevel@tonic-gate } 88517c478bd9Sstevel@tonic-gate 88527c478bd9Sstevel@tonic-gate for (i = 0; i < WorkListCount; i++) 88537c478bd9Sstevel@tonic-gate { 88547c478bd9Sstevel@tonic-gate ENVELOPE e; 88557c478bd9Sstevel@tonic-gate 88567c478bd9Sstevel@tonic-gate if (StopRequest) 88577c478bd9Sstevel@tonic-gate stop_sendmail(); 88587c478bd9Sstevel@tonic-gate 88597c478bd9Sstevel@tonic-gate /* setup envelope */ 88607c478bd9Sstevel@tonic-gate clearenvelope(&e, true, sm_rpool_new_x(NULL)); 88617c478bd9Sstevel@tonic-gate e.e_id = WorkList[i].w_name + 2; 88627c478bd9Sstevel@tonic-gate e.e_qgrp = qgrp; 88637c478bd9Sstevel@tonic-gate e.e_qdir = qdir; 88647c478bd9Sstevel@tonic-gate 88657c478bd9Sstevel@tonic-gate if (tTd(70, 101)) 88667c478bd9Sstevel@tonic-gate { 88677c478bd9Sstevel@tonic-gate sm_io_fprintf(smioout, SM_TIME_DEFAULT, 88687c478bd9Sstevel@tonic-gate "Would do %s\n", e.e_id); 88697c478bd9Sstevel@tonic-gate changed++; 88707c478bd9Sstevel@tonic-gate } 88717c478bd9Sstevel@tonic-gate else if (quarantine_queue_item(qgrp, qdir, 88727c478bd9Sstevel@tonic-gate &e, reason)) 88737c478bd9Sstevel@tonic-gate changed++; 88747c478bd9Sstevel@tonic-gate 88757c478bd9Sstevel@tonic-gate /* clean up */ 88767c478bd9Sstevel@tonic-gate sm_rpool_free(e.e_rpool); 88777c478bd9Sstevel@tonic-gate e.e_rpool = NULL; 88787c478bd9Sstevel@tonic-gate } 88797c478bd9Sstevel@tonic-gate if (WorkList != NULL) 88807c478bd9Sstevel@tonic-gate sm_free(WorkList); /* XXX */ 88817c478bd9Sstevel@tonic-gate WorkList = NULL; 88827c478bd9Sstevel@tonic-gate WorkListSize = 0; 88837c478bd9Sstevel@tonic-gate WorkListCount = 0; 88847c478bd9Sstevel@tonic-gate } 88857c478bd9Sstevel@tonic-gate } 88867c478bd9Sstevel@tonic-gate if (Verbose) 88877c478bd9Sstevel@tonic-gate { 88887c478bd9Sstevel@tonic-gate if (changed == 0) 88897c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 88907c478bd9Sstevel@tonic-gate "No changes\n"); 88917c478bd9Sstevel@tonic-gate else 88927c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 88937c478bd9Sstevel@tonic-gate "%d change%s\n", 88947c478bd9Sstevel@tonic-gate changed, 88957c478bd9Sstevel@tonic-gate changed == 1 ? "" : "s"); 88967c478bd9Sstevel@tonic-gate } 88977c478bd9Sstevel@tonic-gate } 8898