queue.c revision 42575
14Srgrimes/* 24Srgrimes * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 34Srgrimes * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 44Srgrimes * Copyright (c) 1988, 1993 54Srgrimes * The Regents of the University of California. All rights reserved. 64Srgrimes * 74Srgrimes * By using this file, you agree to the terms and conditions set 84Srgrimes * forth in the LICENSE file which can be found at the top level of 94Srgrimes * the sendmail distribution. 104Srgrimes * 114Srgrimes */ 124Srgrimes 134Srgrimes# include "sendmail.h" 144Srgrimes 154Srgrimes#ifndef lint 164Srgrimes#if QUEUE 174Srgrimesstatic char sccsid[] = "@(#)queue.c 8.210 (Berkeley) 10/15/1998 (with queueing)"; 184Srgrimes#else 194Srgrimesstatic char sccsid[] = "@(#)queue.c 8.210 (Berkeley) 10/15/1998 (without queueing)"; 204Srgrimes#endif 214Srgrimes#endif /* not lint */ 224Srgrimes 234Srgrimes# include <errno.h> 244Srgrimes# include <dirent.h> 254Srgrimes 264Srgrimes# if QUEUE 274Srgrimes 284Srgrimes/* 294Srgrimes** Work queue. 304Srgrimes*/ 314Srgrimes 324Srgrimesstruct work 334Srgrimes{ 344Srgrimes char *w_name; /* name of control file */ 354Srgrimes char *w_host; /* name of recipient host */ 364Srgrimes bool w_lock; /* is message locked? */ 374Srgrimes bool w_tooyoung; /* is it too young to run? */ 384Srgrimes long w_pri; /* priority of message, see below */ 394Srgrimes time_t w_ctime; /* creation time of message */ 404Srgrimes struct work *w_next; /* next in queue */ 414Srgrimes}; 424Srgrimes 434Srgrimestypedef struct work WORK; 444Srgrimes 454SrgrimesWORK *WorkQ; /* queue of things to be done */ 464Srgrimes 474Srgrimes#define QF_VERSION 2 /* version number of this queue format */ 484Srgrimes 494Srgrimesextern int orderq __P((bool)); 504Srgrimes/* 514Srgrimes** QUEUEUP -- queue a message up for future transmission. 524Srgrimes** 534Srgrimes** Parameters: 544Srgrimes** e -- the envelope to queue up. 554Srgrimes** announce -- if TRUE, tell when you are queueing up. 564Srgrimes** 574Srgrimes** Returns: 584Srgrimes** none. 594Srgrimes** 604Srgrimes** Side Effects: 614Srgrimes** The current request are saved in a control file. 624Srgrimes** The queue file is left locked. 634Srgrimes*/ 644Srgrimes 654Srgrimesvoid 664Srgrimesqueueup(e, announce) 674Srgrimes register ENVELOPE *e; 684Srgrimes bool announce; 694Srgrimes{ 704Srgrimes char *qf; 714Srgrimes register FILE *tfp; 724Srgrimes register HDR *h; 734Srgrimes register ADDRESS *q; 744Srgrimes int fd; 754Srgrimes int i; 764Srgrimes bool newid; 774Srgrimes register char *p; 784Srgrimes MAILER nullmailer; 794Srgrimes MCI mcibuf; 804Srgrimes char tf[MAXQFNAME]; 814Srgrimes char buf[MAXLINE]; 824Srgrimes extern void printctladdr __P((ADDRESS *, FILE *)); 834Srgrimes 844Srgrimes /* 854Srgrimes ** Create control file. 864Srgrimes */ 874Srgrimes 884Srgrimes newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags); 894Srgrimes 904Srgrimes /* if newid, queuename will create a locked qf file in e->lockfp */ 914Srgrimes strcpy(tf, queuename(e, 't')); 924Srgrimes tfp = e->e_lockfp; 934Srgrimes if (tfp == NULL) 944Srgrimes newid = FALSE; 954Srgrimes 964Srgrimes /* if newid, just write the qf file directly (instead of tf file) */ 974Srgrimes if (!newid) 984Srgrimes { 994Srgrimes /* get a locked tf file */ 1004Srgrimes for (i = 0; i < 128; i++) 1014Srgrimes { 1024Srgrimes fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode); 1034Srgrimes if (fd < 0) 1044Srgrimes { 1054Srgrimes if (errno != EEXIST) 1064Srgrimes break; 1074Srgrimes if (LogLevel > 0 && (i % 32) == 0) 1084Srgrimes sm_syslog(LOG_ALERT, e->e_id, 1094Srgrimes "queueup: cannot create %s, uid=%d: %s", 1104Srgrimes tf, geteuid(), errstring(errno)); 1114Srgrimes } 1124Srgrimes else 1134Srgrimes { 1144Srgrimes if (lockfile(fd, tf, NULL, LOCK_EX|LOCK_NB)) 1154Srgrimes break; 1164Srgrimes else if (LogLevel > 0 && (i % 32) == 0) 1174Srgrimes sm_syslog(LOG_ALERT, e->e_id, 1184Srgrimes "queueup: cannot lock %s: %s", 1194Srgrimes tf, errstring(errno)); 1204Srgrimes close(fd); 1214Srgrimes } 1224Srgrimes 1234Srgrimes if ((i % 32) == 31) 1244Srgrimes { 1254Srgrimes /* save the old temp file away */ 1264Srgrimes (void) rename(tf, queuename(e, 'T')); 1274Srgrimes } 1284Srgrimes else 1294Srgrimes sleep(i % 32); 1304Srgrimes } 1314Srgrimes if (fd < 0 || (tfp = fdopen(fd, "w")) == NULL) 1324Srgrimes { 1334Srgrimes printopenfds(TRUE); 1344Srgrimes syserr("!queueup: cannot create queue temp file %s, uid=%d", 1354Srgrimes tf, geteuid()); 1364Srgrimes } 1374Srgrimes } 1384Srgrimes 1394Srgrimes if (tTd(40, 1)) 1404Srgrimes printf("\n>>>>> queueing %s%s >>>>>\n", e->e_id, 1414Srgrimes newid ? " (new id)" : ""); 1424Srgrimes if (tTd(40, 3)) 1434Srgrimes { 1444Srgrimes extern void printenvflags __P((ENVELOPE *)); 1454Srgrimes 1464Srgrimes printf(" e_flags="); 1474Srgrimes printenvflags(e); 1484Srgrimes } 1494Srgrimes if (tTd(40, 32)) 1504Srgrimes { 1514Srgrimes printf(" sendq="); 1524Srgrimes printaddr(e->e_sendqueue, TRUE); 1534Srgrimes } 1544Srgrimes if (tTd(40, 9)) 1554Srgrimes { 1564Srgrimes printf(" tfp="); 1574Srgrimes dumpfd(fileno(tfp), TRUE, FALSE); 1584Srgrimes printf(" lockfp="); 1594Srgrimes if (e->e_lockfp == NULL) 1604Srgrimes printf("NULL\n"); 1614Srgrimes else 1624Srgrimes dumpfd(fileno(e->e_lockfp), TRUE, FALSE); 1634Srgrimes } 1644Srgrimes 1654Srgrimes /* 1664Srgrimes ** If there is no data file yet, create one. 1674Srgrimes */ 1684Srgrimes 1694Srgrimes if (!bitset(EF_HAS_DF, e->e_flags)) 1704Srgrimes { 1714Srgrimes register FILE *dfp = NULL; 1724Srgrimes char dfname[MAXQFNAME]; 1734Srgrimes struct stat stbuf; 1744Srgrimes 1754Srgrimes strcpy(dfname, queuename(e, 'd')); 1764Srgrimes fd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode); 1774Srgrimes if (fd < 0 || (dfp = fdopen(fd, "w")) == NULL) 1784Srgrimes syserr("!queueup: cannot create data temp file %s, uid=%d", 1794Srgrimes dfname, geteuid()); 1804Srgrimes if (fstat(fd, &stbuf) < 0) 1814Srgrimes e->e_dfino = -1; 1824Srgrimes else 1834Srgrimes { 1844Srgrimes e->e_dfdev = stbuf.st_dev; 1854Srgrimes e->e_dfino = stbuf.st_ino; 1864Srgrimes } 1874Srgrimes e->e_flags |= EF_HAS_DF; 1884Srgrimes bzero(&mcibuf, sizeof mcibuf); 1894Srgrimes mcibuf.mci_out = dfp; 1904Srgrimes mcibuf.mci_mailer = FileMailer; 1914Srgrimes (*e->e_putbody)(&mcibuf, e, NULL); 1924Srgrimes (void) xfclose(dfp, "queueup dfp", e->e_id); 1934Srgrimes e->e_putbody = putbody; 1944Srgrimes } 1954Srgrimes 1964Srgrimes /* 1974Srgrimes ** Output future work requests. 1984Srgrimes ** Priority and creation time should be first, since 1994Srgrimes ** they are required by orderq. 2004Srgrimes */ 2014Srgrimes 2024Srgrimes /* output queue version number (must be first!) */ 2034Srgrimes fprintf(tfp, "V%d\n", QF_VERSION); 2044Srgrimes 2054Srgrimes /* output creation time */ 2064Srgrimes fprintf(tfp, "T%ld\n", (long) e->e_ctime); 2074Srgrimes 2084Srgrimes /* output last delivery time */ 2094Srgrimes fprintf(tfp, "K%ld\n", (long) e->e_dtime); 2104Srgrimes 2114Srgrimes /* output number of delivery attempts */ 2124Srgrimes fprintf(tfp, "N%d\n", e->e_ntries); 2134Srgrimes 2144Srgrimes /* output message priority */ 2154Srgrimes fprintf(tfp, "P%ld\n", e->e_msgpriority); 2164Srgrimes 2174Srgrimes /* output inode number of data file */ 2184Srgrimes /* XXX should probably include device major/minor too */ 2194Srgrimes if (e->e_dfino != -1) 2204Srgrimes { 2214Srgrimes if (sizeof e->e_dfino > sizeof(long)) 2224Srgrimes fprintf(tfp, "I%d/%d/%s\n", 2234Srgrimes major(e->e_dfdev), minor(e->e_dfdev), 2244Srgrimes quad_to_string(e->e_dfino)); 2254Srgrimes else 2264Srgrimes fprintf(tfp, "I%d/%d/%lu\n", 2274Srgrimes major(e->e_dfdev), minor(e->e_dfdev), 2284Srgrimes (unsigned long) e->e_dfino); 2294Srgrimes } 2304Srgrimes 2314Srgrimes /* output body type */ 2324Srgrimes if (e->e_bodytype != NULL) 2334Srgrimes fprintf(tfp, "B%s\n", denlstring(e->e_bodytype, TRUE, FALSE)); 2344Srgrimes 2354Srgrimes#if _FFR_SAVE_CHARSET 2364Srgrimes if (e->e_charset != NULL) 2374Srgrimes fprintf(tfp, "X%s\n", denlstring(e->e_charset, TRUE, FALSE)); 2384Srgrimes#endif 2394Srgrimes 2404Srgrimes /* message from envelope, if it exists */ 2414Srgrimes if (e->e_message != NULL) 2424Srgrimes fprintf(tfp, "M%s\n", denlstring(e->e_message, TRUE, FALSE)); 2434Srgrimes 2444Srgrimes /* send various flag bits through */ 2454Srgrimes p = buf; 2464Srgrimes if (bitset(EF_WARNING, e->e_flags)) 2474Srgrimes *p++ = 'w'; 2484Srgrimes if (bitset(EF_RESPONSE, e->e_flags)) 2494Srgrimes *p++ = 'r'; 2504Srgrimes if (bitset(EF_HAS8BIT, e->e_flags)) 2514Srgrimes *p++ = '8'; 2524Srgrimes if (bitset(EF_DELETE_BCC, e->e_flags)) 2534Srgrimes *p++ = 'b'; 2544Srgrimes if (bitset(EF_RET_PARAM, e->e_flags)) 2554Srgrimes *p++ = 'd'; 2564Srgrimes if (bitset(EF_NO_BODY_RETN, e->e_flags)) 2574Srgrimes *p++ = 'n'; 2584Srgrimes *p++ = '\0'; 2594Srgrimes if (buf[0] != '\0') 2604Srgrimes fprintf(tfp, "F%s\n", buf); 2614Srgrimes 2624Srgrimes /* $r and $s and $_ macro values */ 2634Srgrimes if ((p = macvalue('r', e)) != NULL) 2644Srgrimes fprintf(tfp, "$r%s\n", denlstring(p, TRUE, FALSE)); 2654Srgrimes if ((p = macvalue('s', e)) != NULL) 2664Srgrimes fprintf(tfp, "$s%s\n", denlstring(p, TRUE, FALSE)); 2674Srgrimes if ((p = macvalue('_', e)) != NULL) 2684Srgrimes fprintf(tfp, "$_%s\n", denlstring(p, TRUE, FALSE)); 2694Srgrimes 2704Srgrimes /* output name of sender */ 2714Srgrimes if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 2724Srgrimes p = e->e_sender; 2734Srgrimes else 2744Srgrimes p = e->e_from.q_paddr; 2754Srgrimes fprintf(tfp, "S%s\n", denlstring(p, TRUE, FALSE)); 2764Srgrimes 2774Srgrimes /* output ESMTP-supplied "original" information */ 2784Srgrimes if (e->e_envid != NULL) 2794Srgrimes fprintf(tfp, "Z%s\n", denlstring(e->e_envid, TRUE, FALSE)); 2804Srgrimes 2814Srgrimes /* output list of recipient addresses */ 2824Srgrimes printctladdr(NULL, NULL); 2834Srgrimes for (q = e->e_sendqueue; q != NULL; q = q->q_next) 2844Srgrimes { 2854Srgrimes if (bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)) 2864Srgrimes { 2874Srgrimes#if XDEBUG 2884Srgrimes if (bitset(QQUEUEUP, q->q_flags)) 2894Srgrimes sm_syslog(LOG_DEBUG, e->e_id, 2904Srgrimes "dropenvelope: q_flags = %x, paddr = %s", 2914Srgrimes q->q_flags, q->q_paddr); 2924Srgrimes#endif 2934Srgrimes continue; 2944Srgrimes } 2954Srgrimes printctladdr(q, tfp); 2964Srgrimes if (q->q_orcpt != NULL) 2974Srgrimes fprintf(tfp, "Q%s\n", 2984Srgrimes denlstring(q->q_orcpt, TRUE, FALSE)); 2994Srgrimes putc('R', tfp); 3004Srgrimes if (bitset(QPRIMARY, q->q_flags)) 3014Srgrimes putc('P', tfp); 3024Srgrimes if (bitset(QHASNOTIFY, q->q_flags)) 3034Srgrimes putc('N', tfp); 3044Srgrimes if (bitset(QPINGONSUCCESS, q->q_flags)) 3054Srgrimes putc('S', tfp); 3064Srgrimes if (bitset(QPINGONFAILURE, q->q_flags)) 3074Srgrimes putc('F', tfp); 3084Srgrimes if (bitset(QPINGONDELAY, q->q_flags)) 3094Srgrimes putc('D', tfp); 3104Srgrimes putc(':', tfp); 3114Srgrimes fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE)); 3124Srgrimes if (announce) 3134Srgrimes { 3144Srgrimes e->e_to = q->q_paddr; 3154Srgrimes message("queued"); 3164Srgrimes if (LogLevel > 8) 3174Srgrimes logdelivery(q->q_mailer, NULL, "queued", 3184Srgrimes NULL, (time_t) 0, e); 3194Srgrimes e->e_to = NULL; 3204Srgrimes } 3214Srgrimes if (tTd(40, 1)) 3224Srgrimes { 3234Srgrimes printf("queueing "); 3244Srgrimes printaddr(q, FALSE); 3254Srgrimes } 3264Srgrimes } 3274Srgrimes 3284Srgrimes /* 3294Srgrimes ** Output headers for this message. 3304Srgrimes ** Expand macros completely here. Queue run will deal with 3314Srgrimes ** everything as absolute headers. 3324Srgrimes ** All headers that must be relative to the recipient 3334Srgrimes ** can be cracked later. 3344Srgrimes ** We set up a "null mailer" -- i.e., a mailer that will have 3354Srgrimes ** no effect on the addresses as they are output. 3364Srgrimes */ 3374Srgrimes 3384Srgrimes bzero((char *) &nullmailer, sizeof nullmailer); 3394Srgrimes nullmailer.m_re_rwset = nullmailer.m_rh_rwset = 3404Srgrimes nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1; 3414Srgrimes nullmailer.m_eol = "\n"; 3424Srgrimes bzero(&mcibuf, sizeof mcibuf); 3434Srgrimes mcibuf.mci_mailer = &nullmailer; 3444Srgrimes mcibuf.mci_out = tfp; 3454Srgrimes 3464Srgrimes define('g', "\201f", e); 3474Srgrimes for (h = e->e_header; h != NULL; h = h->h_link) 3484Srgrimes { 3494Srgrimes extern bool bitzerop __P((BITMAP)); 3504Srgrimes 3514Srgrimes /* don't output null headers */ 3524Srgrimes if (h->h_value == NULL || h->h_value[0] == '\0') 3534Srgrimes continue; 3544Srgrimes 3554Srgrimes /* don't output resent headers on non-resent messages */ 3564Srgrimes if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 3574Srgrimes continue; 3584Srgrimes 3594Srgrimes /* expand macros; if null, don't output header at all */ 3604Srgrimes if (bitset(H_DEFAULT, h->h_flags)) 3614Srgrimes { 3624Srgrimes (void) expand(h->h_value, buf, sizeof buf, e); 3634Srgrimes if (buf[0] == '\0') 3644Srgrimes continue; 3654Srgrimes } 3664Srgrimes 3674Srgrimes /* output this header */ 3684Srgrimes fprintf(tfp, "H"); 3694Srgrimes 3704Srgrimes /* if conditional, output the set of conditions */ 3714Srgrimes if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags)) 3724Srgrimes { 3734Srgrimes int j; 3744Srgrimes 3754Srgrimes (void) putc('?', tfp); 3764Srgrimes for (j = '\0'; j <= '\177'; j++) 3774Srgrimes if (bitnset(j, h->h_mflags)) 3784Srgrimes (void) putc(j, tfp); 3794Srgrimes (void) putc('?', tfp); 3804Srgrimes } 3814Srgrimes 3824Srgrimes /* output the header: expand macros, convert addresses */ 3834Srgrimes if (bitset(H_DEFAULT, h->h_flags)) 3844Srgrimes { 3854Srgrimes fprintf(tfp, "%s: %s\n", 3864Srgrimes h->h_field, 3874Srgrimes denlstring(buf, FALSE, TRUE)); 3884Srgrimes } 3894Srgrimes else if (bitset(H_FROM|H_RCPT, h->h_flags)) 3904Srgrimes { 3914Srgrimes bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 3924Srgrimes FILE *savetrace = TrafficLogFile; 3933723Sbde 3943723Sbde TrafficLogFile = NULL; 3953723Sbde 3963723Sbde if (bitset(H_FROM, h->h_flags)) 3973723Sbde oldstyle = FALSE; 3984Srgrimes 3994Srgrimes commaize(h, h->h_value, oldstyle, &mcibuf, e); 4004Srgrimes 4014Srgrimes TrafficLogFile = savetrace; 4024Srgrimes } 4034Srgrimes else 4044Srgrimes { 4054Srgrimes fprintf(tfp, "%s: %s\n", 4064Srgrimes h->h_field, 4074Srgrimes denlstring(h->h_value, FALSE, TRUE)); 4084Srgrimes } 4094Srgrimes } 4104Srgrimes 4114Srgrimes /* 4124Srgrimes ** Clean up. 4134Srgrimes ** 4144Srgrimes ** Write a terminator record -- this is to prevent 4154Srgrimes ** scurrilous crackers from appending any data. 4164Srgrimes */ 4174Srgrimes 4184Srgrimes fprintf(tfp, ".\n"); 4194Srgrimes 4204Srgrimes if (fflush(tfp) < 0 || 4214Srgrimes (SuperSafe && fsync(fileno(tfp)) < 0) || 4224Srgrimes ferror(tfp)) 4234Srgrimes { 4244Srgrimes if (newid) 4254Srgrimes syserr("!552 Error writing control file %s", tf); 4264Srgrimes else 4274Srgrimes syserr("!452 Error writing control file %s", tf); 4284Srgrimes } 4294Srgrimes 4304Srgrimes if (!newid) 4314Srgrimes { 4323723Sbde /* rename (locked) tf to be (locked) qf */ 4333723Sbde qf = queuename(e, 'q'); 4343723Sbde if (rename(tf, qf) < 0) 4353723Sbde syserr("cannot rename(%s, %s), uid=%d", 4363723Sbde tf, qf, geteuid()); 4374Srgrimes 4384Srgrimes /* close and unlock old (locked) qf */ 4394Srgrimes if (e->e_lockfp != NULL) 4404Srgrimes (void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id); 4414Srgrimes e->e_lockfp = tfp; 4424Srgrimes } 4434Srgrimes else 4444Srgrimes qf = tf; 4454Srgrimes errno = 0; 4464Srgrimes e->e_flags |= EF_INQUEUE; 4474Srgrimes 4484Srgrimes /* save log info */ 4494Srgrimes if (LogLevel > 79) 4504Srgrimes sm_syslog(LOG_DEBUG, e->e_id, "queueup, qf=%s", qf); 4514Srgrimes 4524Srgrimes if (tTd(40, 1)) 4534Srgrimes printf("<<<<< done queueing %s <<<<<\n\n", e->e_id); 4544Srgrimes return; 4554Srgrimes} 4564Srgrimes 4574Srgrimesvoid 4584Srgrimesprintctladdr(a, tfp) 4594Srgrimes register ADDRESS *a; 4602810Sbde FILE *tfp; 4612810Sbde{ 4624Srgrimes char *uname; 4634Srgrimes register ADDRESS *q; 4643723Sbde uid_t uid; 4654Srgrimes gid_t gid; 4664Srgrimes static ADDRESS *lastctladdr = NULL; 4674Srgrimes static uid_t lastuid; 4684Srgrimes 4694Srgrimes /* initialization */ 4704Srgrimes if (a == NULL || a->q_alias == NULL || tfp == NULL) 4714Srgrimes { 4724Srgrimes if (lastctladdr != NULL && tfp != NULL) 4734Srgrimes fprintf(tfp, "C\n"); 4744Srgrimes lastctladdr = NULL; 4754Srgrimes lastuid = 0; 4764Srgrimes return; 4774Srgrimes } 4784Srgrimes 4794Srgrimes /* find the active uid */ 4804Srgrimes q = getctladdr(a); 4814Srgrimes if (q == NULL) 4824Srgrimes { 4834Srgrimes uname = NULL; 4844Srgrimes uid = 0; 4854Srgrimes gid = 0; 4864Srgrimes } 4874Srgrimes else 4884Srgrimes { 4894Srgrimes uname = q->q_ruser != NULL ? q->q_ruser : q->q_user; 4904Srgrimes uid = q->q_uid; 4914Srgrimes gid = q->q_gid; 4924Srgrimes } 4932810Sbde a = a->q_alias; 4942810Sbde 4952810Sbde /* check to see if this is the same as last time */ 4962810Sbde if (lastctladdr != NULL && uid == lastuid && 4972810Sbde strcmp(lastctladdr->q_paddr, a->q_paddr) == 0) 4982810Sbde return; 4992810Sbde lastuid = uid; 5002810Sbde lastctladdr = a; 5012810Sbde 5024Srgrimes if (uid == 0 || uname == NULL || uname[0] == '\0') 5034Srgrimes fprintf(tfp, "C"); 5044Srgrimes else 5054Srgrimes fprintf(tfp, "C%s:%ld:%ld", 5064Srgrimes denlstring(uname, TRUE, FALSE), (long) uid, (long) gid); 5074Srgrimes fprintf(tfp, ":%s\n", denlstring(a->q_paddr, TRUE, FALSE)); 5084Srgrimes} 5094Srgrimes/* 5104Srgrimes** RUNQUEUE -- run the jobs in the queue. 5114Srgrimes** 5124Srgrimes** Gets the stuff out of the queue in some presumably logical 5134Srgrimes** order and processes them. 5144Srgrimes** 5154Srgrimes** Parameters: 5164Srgrimes** forkflag -- TRUE if the queue scanning should be done in 5174Srgrimes** a child process. We double-fork so it is not our 5184Srgrimes** child and we don't have to clean up after it. 5194Srgrimes** verbose -- if TRUE, print out status information. 5204Srgrimes** 5214Srgrimes** Returns: 5224Srgrimes** TRUE if the queue run successfully began. 5234Srgrimes** 5244Srgrimes** Side Effects: 5254Srgrimes** runs things in the mail queue. 5264Srgrimes*/ 5274Srgrimes 5284SrgrimesENVELOPE QueueEnvelope; /* the queue run envelope */ 5294Srgrimesextern int get_num_procs_online __P((void)); 5304Srgrimes 5314Srgrimesbool 5324Srgrimesrunqueue(forkflag, verbose) 5334Srgrimes bool forkflag; 5344Srgrimes bool verbose; 5354Srgrimes{ 5364Srgrimes register ENVELOPE *e; 5374Srgrimes int njobs; 5384Srgrimes int sequenceno = 0; 5394Srgrimes time_t current_la_time; 5404Srgrimes extern ENVELOPE BlankEnvelope; 5414Srgrimes extern void clrdaemon __P((void)); 5424Srgrimes extern void runqueueevent __P((void)); 5434Srgrimes 5444Srgrimes DoQueueRun = FALSE; 5454Srgrimes 5464Srgrimes /* 5474Srgrimes ** If no work will ever be selected, don't even bother reading 5484Srgrimes ** the queue. 5494Srgrimes */ 5504Srgrimes 5514Srgrimes CurrentLA = getla(); /* get load average */ 5524Srgrimes current_la_time = curtime(); 5534Srgrimes 5544Srgrimes if (shouldqueue(WkRecipFact, current_la_time)) 5554Srgrimes { 5564Srgrimes char *msg = "Skipping queue run -- load average too high"; 5574Srgrimes 5584Srgrimes if (verbose) 5594Srgrimes message("458 %s\n", msg); 5604Srgrimes if (LogLevel > 8) 5614Srgrimes sm_syslog(LOG_INFO, NOQID, 5624Srgrimes "runqueue: %s", 5634Srgrimes msg); 5644Srgrimes if (forkflag && QueueIntvl != 0) 5654Srgrimes (void) setevent(QueueIntvl, runqueueevent, 0); 5664Srgrimes return FALSE; 5674Srgrimes } 5684Srgrimes 5694Srgrimes /* 5704Srgrimes ** See if we already have too many children. 5714Srgrimes */ 5724Srgrimes 5734Srgrimes if (forkflag && QueueIntvl != 0 && 5744Srgrimes MaxChildren > 0 && CurChildren >= MaxChildren) 5754Srgrimes { 5764Srgrimes (void) setevent(QueueIntvl, runqueueevent, 0); 5774Srgrimes return FALSE; 5784Srgrimes } 5794Srgrimes 5804Srgrimes /* 5814Srgrimes ** See if we want to go off and do other useful work. 5824Srgrimes */ 5834Srgrimes 5844Srgrimes if (forkflag) 5854Srgrimes { 5864Srgrimes pid_t pid; 5874Srgrimes extern SIGFUNC_DECL intsig __P((int)); 5884Srgrimes extern SIGFUNC_DECL reapchild __P((int)); 5894Srgrimes 5904Srgrimes blocksignal(SIGCHLD); 5914Srgrimes (void) setsignal(SIGCHLD, reapchild); 5924Srgrimes 5934Srgrimes pid = dofork(); 5944Srgrimes if (pid == -1) 5954Srgrimes { 5964Srgrimes const char *msg = "Skipping queue run -- fork() failed"; 5974Srgrimes const char *err = errstring(errno); 5984Srgrimes 5994Srgrimes if (verbose) 6004Srgrimes message("458 %s: %s\n", msg, err); 6014Srgrimes if (LogLevel > 8) 6024Srgrimes sm_syslog(LOG_INFO, NOQID, 6034Srgrimes "runqueue: %s: %s", 6044Srgrimes msg, err); 6054Srgrimes if (QueueIntvl != 0) 6064Srgrimes (void) setevent(QueueIntvl, runqueueevent, 0); 6074Srgrimes (void) releasesignal(SIGCHLD); 6084Srgrimes return FALSE; 6094Srgrimes } 6104Srgrimes if (pid != 0) 6114Srgrimes { 6124Srgrimes /* parent -- pick up intermediate zombie */ 6134Srgrimes (void) blocksignal(SIGALRM); 6144Srgrimes proc_list_add(pid, "Queue runner"); 6154Srgrimes (void) releasesignal(SIGALRM); 6164Srgrimes releasesignal(SIGCHLD); 6174Srgrimes if (QueueIntvl != 0) 6184Srgrimes (void) setevent(QueueIntvl, runqueueevent, 0); 6194Srgrimes return TRUE; 6204Srgrimes } 6214Srgrimes /* child -- double fork and clean up signals */ 6224Srgrimes clrcontrol(); 6234Srgrimes proc_list_clear(); 6244Srgrimes 6254Srgrimes /* Add parent process as first child item */ 6264Srgrimes proc_list_add(getpid(), "Queue runner child process"); 6274Srgrimes releasesignal(SIGCHLD); 6284Srgrimes (void) setsignal(SIGCHLD, SIG_DFL); 6294Srgrimes (void) setsignal(SIGHUP, intsig); 6304Srgrimes } 6314Srgrimes 6324Srgrimes sm_setproctitle(TRUE, "running queue: %s", QueueDir); 6334Srgrimes 6344Srgrimes if (LogLevel > 69) 6354Srgrimes sm_syslog(LOG_DEBUG, NOQID, 6364Srgrimes "runqueue %s, pid=%d, forkflag=%d", 6374Srgrimes QueueDir, getpid(), forkflag); 6384Srgrimes 6394Srgrimes /* 6404Srgrimes ** Release any resources used by the daemon code. 6414Srgrimes */ 6424Srgrimes 6434Srgrimes# if DAEMON 6444Srgrimes clrdaemon(); 6454Srgrimes# endif /* DAEMON */ 6464Srgrimes 6474Srgrimes /* force it to run expensive jobs */ 6484Srgrimes NoConnect = FALSE; 6494Srgrimes 6504Srgrimes /* drop privileges */ 6514Srgrimes if (geteuid() == (uid_t) 0) 6524Srgrimes (void) drop_privileges(FALSE); 6534Srgrimes 6544Srgrimes /* 6554Srgrimes ** Create ourselves an envelope 6564Srgrimes */ 6574Srgrimes 6584Srgrimes CurEnv = &QueueEnvelope; 6594Srgrimes e = newenvelope(&QueueEnvelope, CurEnv); 6604Srgrimes e->e_flags = BlankEnvelope.e_flags; 6614Srgrimes 6624Srgrimes /* make sure we have disconnected from parent */ 6634Srgrimes if (forkflag) 6644Srgrimes { 6654Srgrimes disconnect(1, e); 6664Srgrimes QuickAbort = FALSE; 6674Srgrimes } 6684Srgrimes 6694Srgrimes /* 6704Srgrimes ** Make sure the alias database is open. 6714Srgrimes */ 6724Srgrimes 6734Srgrimes initmaps(FALSE, e); 6744Srgrimes 6754Srgrimes /* 6764Srgrimes ** If we are running part of the queue, always ignore stored 6774Srgrimes ** host status. 6784Srgrimes */ 6794Srgrimes 6804Srgrimes if (QueueLimitId != NULL || QueueLimitSender != NULL || 6814Srgrimes QueueLimitRecipient != NULL) 6824Srgrimes { 6834Srgrimes IgnoreHostStatus = TRUE; 6844Srgrimes MinQueueAge = 0; 6854Srgrimes } 6864Srgrimes 6874Srgrimes /* 6884Srgrimes ** Start making passes through the queue. 6894Srgrimes ** First, read and sort the entire queue. 6904Srgrimes ** Then, process the work in that order. 6914Srgrimes ** But if you take too long, start over. 6924Srgrimes */ 6934Srgrimes 6944Srgrimes /* order the existing work requests */ 6954Srgrimes njobs = orderq(FALSE); 6964Srgrimes 6974Srgrimes /* process them once at a time */ 6984Srgrimes while (WorkQ != NULL) 699 { 700 WORK *w = WorkQ; 701 702 WorkQ = WorkQ->w_next; 703 e->e_to = NULL; 704 705 /* 706 ** Ignore jobs that are too expensive for the moment. 707 ** 708 ** Get new load average every 30 seconds. 709 */ 710 711 if (current_la_time < curtime() - 30) 712 { 713 CurrentLA = getla(); 714 current_la_time = curtime(); 715 } 716 if (shouldqueue(WkRecipFact, current_la_time)) 717 { 718 char *msg = "Aborting queue run: load average too high"; 719 720 if (Verbose) 721 message("%s", msg); 722 if (LogLevel > 8) 723 sm_syslog(LOG_INFO, NOQID, 724 "runqueue: %s", 725 msg); 726 break; 727 } 728 sequenceno++; 729 if (shouldqueue(w->w_pri, w->w_ctime)) 730 { 731 if (Verbose) 732 message(""); 733 if (QueueSortOrder == QS_BYPRIORITY) 734 { 735 if (Verbose) 736 message("Skipping %s (sequence %d of %d) and flushing rest of queue", 737 w->w_name + 2, 738 sequenceno, 739 njobs); 740 if (LogLevel > 8) 741 sm_syslog(LOG_INFO, NOQID, 742 "runqueue: Flushing queue from %s (pri %ld, LA %d, %d of %d)", 743 w->w_name + 2, 744 w->w_pri, 745 CurrentLA, 746 sequenceno, 747 njobs); 748 break; 749 } 750 else if (Verbose) 751 message("Skipping %s (sequence %d of %d)", 752 w->w_name + 2, sequenceno, njobs); 753 } 754 else 755 { 756 pid_t pid; 757 758 if (Verbose) 759 { 760 message(""); 761 message("Running %s (sequence %d of %d)", 762 w->w_name + 2, sequenceno, njobs); 763 } 764 pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e); 765 errno = 0; 766 if (pid != 0) 767 (void) waitfor(pid); 768 } 769 free(w->w_name); 770 if (w->w_host) 771 free(w->w_host); 772 free((char *) w); 773 } 774 775 /* exit without the usual cleanup */ 776 e->e_id = NULL; 777 finis(TRUE, ExitStat); 778 /*NOTREACHED*/ 779 return TRUE; 780} 781 782 783/* 784** RUNQUEUEEVENT -- stub for use in setevent 785*/ 786 787void 788runqueueevent() 789{ 790 DoQueueRun = TRUE; 791} 792/* 793** ORDERQ -- order the work queue. 794** 795** Parameters: 796** doall -- if set, include everything in the queue (even 797** the jobs that cannot be run because the load 798** average is too high). Otherwise, exclude those 799** jobs. 800** 801** Returns: 802** The number of request in the queue (not necessarily 803** the number of requests in WorkQ however). 804** 805** Side Effects: 806** Sets WorkQ to the queue of available work, in order. 807*/ 808 809# define NEED_P 001 810# define NEED_T 002 811# define NEED_R 004 812# define NEED_S 010 813 814static WORK *WorkList = NULL; 815static int WorkListSize = 0; 816 817int 818orderq(doall) 819 bool doall; 820{ 821 register struct dirent *d; 822 register WORK *w; 823 register char *p; 824 DIR *f; 825 register int i; 826 int wn = -1; 827 int wc; 828 QUEUE_CHAR *check; 829 830 if (tTd(41, 1)) 831 { 832 printf("orderq:\n"); 833 834 check = QueueLimitId; 835 while (check != NULL) 836 { 837 printf("\tQueueLimitId = %s\n", 838 check->queue_match); 839 check = check->queue_next; 840 } 841 842 check = QueueLimitSender; 843 while (check != NULL) 844 { 845 printf("\tQueueLimitSender = %s\n", 846 check->queue_match); 847 check = check->queue_next; 848 } 849 850 check = QueueLimitRecipient; 851 while (check != NULL) 852 { 853 printf("\tQueueLimitRecipient = %s\n", 854 check->queue_match); 855 check = check->queue_next; 856 } 857 } 858 859 /* clear out old WorkQ */ 860 for (w = WorkQ; w != NULL; ) 861 { 862 register WORK *nw = w->w_next; 863 864 WorkQ = nw; 865 free(w->w_name); 866 if (w->w_host) 867 free(w->w_host); 868 free((char *) w); 869 w = nw; 870 } 871 872 /* open the queue directory */ 873 f = opendir("."); 874 if (f == NULL) 875 { 876 syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 877 return (0); 878 } 879 880 /* 881 ** Read the work directory. 882 */ 883 884 while ((d = readdir(f)) != NULL) 885 { 886 FILE *cf; 887 int qfver = 0; 888 char lbuf[MAXNAME + 1]; 889 extern bool strcontainedin __P((char *, char *)); 890 891 if (tTd(41, 50)) 892 printf("orderq: checking %s\n", d->d_name); 893 894 /* is this an interesting entry? */ 895 if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 896 continue; 897 898 if (strlen(d->d_name) > MAXQFNAME) 899 { 900 if (Verbose) 901 printf("orderq: %s too long, %d max characters\n", 902 d->d_name, MAXQFNAME); 903 if (LogLevel > 0) 904 sm_syslog(LOG_ALERT, NOQID, 905 "orderq: %s too long, %d max characters", 906 d->d_name, MAXQFNAME); 907 continue; 908 } 909 910 check = QueueLimitId; 911 while (check != NULL) 912 { 913 if (strcontainedin(check->queue_match, d->d_name)) 914 break; 915 else 916 check = check->queue_next; 917 } 918 if (QueueLimitId != NULL && check == NULL) 919 continue; 920 921#ifdef PICKY_QF_NAME_CHECK 922 /* 923 ** Check queue name for plausibility. This handles 924 ** both old and new type ids. 925 */ 926 927 p = d->d_name + 2; 928 if (isupper(p[0]) && isupper(p[2])) 929 p += 3; 930 else if (isupper(p[1])) 931 p += 2; 932 else 933 p = d->d_name; 934 for (i = 0; isdigit(*p); p++) 935 i++; 936 if (i < 5 || *p != '\0') 937 { 938 if (Verbose) 939 printf("orderq: bogus qf name %s\n", d->d_name); 940 if (LogLevel > 0) 941 sm_syslog(LOG_ALERT, NOQID, 942 "orderq: bogus qf name %s", 943 d->d_name); 944 if (strlen(d->d_name) > (SIZE_T) MAXNAME) 945 d->d_name[MAXNAME] = '\0'; 946 strcpy(lbuf, d->d_name); 947 lbuf[0] = 'Q'; 948 (void) rename(d->d_name, lbuf); 949 continue; 950 } 951#endif 952 953 /* open control file (if not too many files) */ 954 if (++wn >= MaxQueueRun && MaxQueueRun > 0) 955 { 956 if (wn == MaxQueueRun && LogLevel > 0) 957 sm_syslog(LOG_ALERT, NOQID, 958 "WorkList for %s maxed out at %d", 959 QueueDir, MaxQueueRun); 960 continue; 961 } 962 if (wn >= WorkListSize) 963 { 964 extern void grow_wlist __P((void)); 965 966 grow_wlist(); 967 if (wn >= WorkListSize) 968 continue; 969 } 970 971 cf = fopen(d->d_name, "r"); 972 if (cf == NULL) 973 { 974 /* this may be some random person sending hir msgs */ 975 /* syserr("orderq: cannot open %s", cbuf); */ 976 if (tTd(41, 2)) 977 printf("orderq: cannot open %s: %s\n", 978 d->d_name, errstring(errno)); 979 errno = 0; 980 wn--; 981 continue; 982 } 983 w = &WorkList[wn]; 984 w->w_name = newstr(d->d_name); 985 w->w_host = NULL; 986 w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB); 987 w->w_tooyoung = FALSE; 988 989 /* make sure jobs in creation don't clog queue */ 990 w->w_pri = 0x7fffffff; 991 w->w_ctime = 0; 992 993 /* extract useful information */ 994 i = NEED_P | NEED_T; 995 if (QueueLimitSender != NULL) 996 i |= NEED_S; 997 if (QueueSortOrder == QS_BYHOST || QueueLimitRecipient != NULL) 998 i |= NEED_R; 999 while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL) 1000 { 1001 int c; 1002 time_t age; 1003 extern bool strcontainedin __P((char *, char *)); 1004 1005 p = strchr(lbuf, '\n'); 1006 if (p != NULL) 1007 *p = '\0'; 1008 else 1009 { 1010 /* flush rest of overly long line */ 1011 while ((c = getc(cf)) != EOF && c != '\n') 1012 continue; 1013 } 1014 1015 switch (lbuf[0]) 1016 { 1017 case 'V': 1018 qfver = atoi(&lbuf[1]); 1019 break; 1020 1021 case 'P': 1022 w->w_pri = atol(&lbuf[1]); 1023 i &= ~NEED_P; 1024 break; 1025 1026 case 'T': 1027 w->w_ctime = atol(&lbuf[1]); 1028 i &= ~NEED_T; 1029 break; 1030 1031 case 'R': 1032 if (w->w_host == NULL && 1033 (p = strrchr(&lbuf[1], '@')) != NULL) 1034 w->w_host = newstr(&p[1]); 1035 if (QueueLimitRecipient == NULL) 1036 { 1037 i &= ~NEED_R; 1038 break; 1039 } 1040 if (qfver > 0) 1041 { 1042 p = strchr(&lbuf[1], ':'); 1043 if (p == NULL) 1044 p = &lbuf[1]; 1045 } 1046 else 1047 p = &lbuf[1]; 1048 check = QueueLimitRecipient; 1049 while (check != NULL) 1050 { 1051 if (strcontainedin(check->queue_match, 1052 p)) 1053 break; 1054 else 1055 check = check->queue_next; 1056 } 1057 if (check != NULL) 1058 i &= ~NEED_R; 1059 break; 1060 1061 case 'S': 1062 check = QueueLimitSender; 1063 while (check != NULL) 1064 { 1065 if (strcontainedin(check->queue_match, 1066 &lbuf[1])) 1067 break; 1068 else 1069 check = check->queue_next; 1070 } 1071 if (check != NULL) 1072 i &= ~NEED_S; 1073 break; 1074 1075 case 'K': 1076 age = curtime() - (time_t) atol(&lbuf[1]); 1077 if (age >= 0 && MinQueueAge > 0 && 1078 age < MinQueueAge) 1079 w->w_tooyoung = TRUE; 1080 break; 1081 1082 case 'N': 1083 if (atol(&lbuf[1]) == 0) 1084 w->w_tooyoung = FALSE; 1085 break; 1086 } 1087 } 1088 (void) fclose(cf); 1089 1090 if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) || 1091 bitset(NEED_R|NEED_S, i)) 1092 { 1093 /* don't even bother sorting this job in */ 1094 if (tTd(41, 49)) 1095 printf("skipping %s (%x)\n", w->w_name, i); 1096 free(w->w_name); 1097 if (w->w_host) 1098 free(w->w_host); 1099 wn--; 1100 } 1101 } 1102 (void) closedir(f); 1103 wn++; 1104 1105 wc = min(wn, WorkListSize); 1106 if (wc > MaxQueueRun && MaxQueueRun > 0) 1107 wc = MaxQueueRun; 1108 1109 if (QueueSortOrder == QS_BYHOST) 1110 { 1111 extern int workcmpf1(); 1112 extern int workcmpf2(); 1113 1114 /* 1115 ** Sort the work directory for the first time, 1116 ** based on host name, lock status, and priority. 1117 */ 1118 1119 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1); 1120 1121 /* 1122 ** If one message to host is locked, "lock" all messages 1123 ** to that host. 1124 */ 1125 1126 i = 0; 1127 while (i < wc) 1128 { 1129 if (!WorkList[i].w_lock) 1130 { 1131 i++; 1132 continue; 1133 } 1134 w = &WorkList[i]; 1135 while (++i < wc) 1136 { 1137 extern int sm_strcasecmp __P((char *, char *)); 1138 1139 if (WorkList[i].w_host == NULL && 1140 w->w_host == NULL) 1141 WorkList[i].w_lock = TRUE; 1142 else if (WorkList[i].w_host != NULL && 1143 w->w_host != NULL && 1144 sm_strcasecmp(WorkList[i].w_host, w->w_host) == 0) 1145 WorkList[i].w_lock = TRUE; 1146 else 1147 break; 1148 } 1149 } 1150 1151 /* 1152 ** Sort the work directory for the second time, 1153 ** based on lock status, host name, and priority. 1154 */ 1155 1156 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2); 1157 } 1158 else if (QueueSortOrder == QS_BYTIME) 1159 { 1160 extern int workcmpf3(); 1161 1162 /* 1163 ** Simple sort based on submission time only. 1164 */ 1165 1166 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf3); 1167 } 1168 else 1169 { 1170 extern int workcmpf0(); 1171 1172 /* 1173 ** Simple sort based on queue priority only. 1174 */ 1175 1176 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0); 1177 } 1178 1179 /* 1180 ** Convert the work list into canonical form. 1181 ** Should be turning it into a list of envelopes here perhaps. 1182 */ 1183 1184 WorkQ = NULL; 1185 for (i = wc; --i >= 0; ) 1186 { 1187 w = (WORK *) xalloc(sizeof *w); 1188 w->w_name = WorkList[i].w_name; 1189 w->w_host = WorkList[i].w_host; 1190 w->w_lock = WorkList[i].w_lock; 1191 w->w_tooyoung = WorkList[i].w_tooyoung; 1192 w->w_pri = WorkList[i].w_pri; 1193 w->w_ctime = WorkList[i].w_ctime; 1194 w->w_next = WorkQ; 1195 WorkQ = w; 1196 } 1197 if (WorkList != NULL) 1198 free(WorkList); 1199 WorkList = NULL; 1200 WorkListSize = 0; 1201 1202 if (tTd(40, 1)) 1203 { 1204 for (w = WorkQ; w != NULL; w = w->w_next) 1205 printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 1206 } 1207 1208 return (wn); 1209} 1210/* 1211** GROW_WLIST -- make the work list larger 1212** 1213** Parameters: 1214** none. 1215** 1216** Returns: 1217** none. 1218** 1219** Side Effects: 1220** Adds another QUEUESEGSIZE entries to WorkList if possible. 1221** It can fail if there isn't enough memory, so WorkListSize 1222** should be checked again upon return. 1223*/ 1224 1225void 1226grow_wlist() 1227{ 1228 if (tTd(41, 1)) 1229 printf("grow_wlist: WorkListSize=%d\n", WorkListSize); 1230 if (WorkList == NULL) 1231 { 1232 WorkList = (WORK *) xalloc(sizeof(WORK) * (QUEUESEGSIZE + 1)); 1233 WorkListSize = QUEUESEGSIZE; 1234 } 1235 else 1236 { 1237 int newsize = WorkListSize + QUEUESEGSIZE; 1238 WORK *newlist = (WORK *) realloc((char *)WorkList, 1239 (unsigned)sizeof(WORK) * (newsize + 1)); 1240 1241 if (newlist != NULL) 1242 { 1243 WorkListSize = newsize; 1244 WorkList = newlist; 1245 if (LogLevel > 1) 1246 { 1247 sm_syslog(LOG_NOTICE, NOQID, 1248 "grew WorkList for %s to %d", 1249 QueueDir, WorkListSize); 1250 } 1251 } 1252 else if (LogLevel > 0) 1253 { 1254 sm_syslog(LOG_ALERT, NOQID, 1255 "FAILED to grow WorkList for %s to %d", 1256 QueueDir, newsize); 1257 } 1258 } 1259 if (tTd(41, 1)) 1260 printf("grow_wlist: WorkListSize now %d\n", WorkListSize); 1261} 1262/* 1263** WORKCMPF0 -- simple priority-only compare function. 1264** 1265** Parameters: 1266** a -- the first argument. 1267** b -- the second argument. 1268** 1269** Returns: 1270** -1 if a < b 1271** 0 if a == b 1272** +1 if a > b 1273** 1274** Side Effects: 1275** none. 1276*/ 1277 1278int 1279workcmpf0(a, b) 1280 register WORK *a; 1281 register WORK *b; 1282{ 1283 long pa = a->w_pri; 1284 long pb = b->w_pri; 1285 1286 if (pa == pb) 1287 return 0; 1288 else if (pa > pb) 1289 return 1; 1290 else 1291 return -1; 1292} 1293/* 1294** WORKCMPF1 -- first compare function for ordering work based on host name. 1295** 1296** Sorts on host name, lock status, and priority in that order. 1297** 1298** Parameters: 1299** a -- the first argument. 1300** b -- the second argument. 1301** 1302** Returns: 1303** <0 if a < b 1304** 0 if a == b 1305** >0 if a > b 1306** 1307** Side Effects: 1308** none. 1309*/ 1310 1311int 1312workcmpf1(a, b) 1313 register WORK *a; 1314 register WORK *b; 1315{ 1316 int i; 1317 extern int sm_strcasecmp __P((char *, char *)); 1318 1319 /* host name */ 1320 if (a->w_host != NULL && b->w_host == NULL) 1321 return 1; 1322 else if (a->w_host == NULL && b->w_host != NULL) 1323 return -1; 1324 if (a->w_host != NULL && b->w_host != NULL && 1325 (i = sm_strcasecmp(a->w_host, b->w_host)) != 0) 1326 return i; 1327 1328 /* lock status */ 1329 if (a->w_lock != b->w_lock) 1330 return b->w_lock - a->w_lock; 1331 1332 /* job priority */ 1333 return a->w_pri - b->w_pri; 1334} 1335/* 1336** WORKCMPF2 -- second compare function for ordering work based on host name. 1337** 1338** Sorts on lock status, host name, and priority in that order. 1339** 1340** Parameters: 1341** a -- the first argument. 1342** b -- the second argument. 1343** 1344** Returns: 1345** <0 if a < b 1346** 0 if a == b 1347** >0 if a > b 1348** 1349** Side Effects: 1350** none. 1351*/ 1352 1353int 1354workcmpf2(a, b) 1355 register WORK *a; 1356 register WORK *b; 1357{ 1358 int i; 1359 extern int sm_strcasecmp __P((char *, char *)); 1360 1361 /* lock status */ 1362 if (a->w_lock != b->w_lock) 1363 return a->w_lock - b->w_lock; 1364 1365 /* host name */ 1366 if (a->w_host != NULL && b->w_host == NULL) 1367 return 1; 1368 else if (a->w_host == NULL && b->w_host != NULL) 1369 return -1; 1370 if (a->w_host != NULL && b->w_host != NULL && 1371 (i = sm_strcasecmp(a->w_host, b->w_host)) != 0) 1372 return i; 1373 1374 /* job priority */ 1375 return a->w_pri - b->w_pri; 1376} 1377/* 1378** WORKCMPF3 -- simple submission-time-only compare function. 1379** 1380** Parameters: 1381** a -- the first argument. 1382** b -- the second argument. 1383** 1384** Returns: 1385** -1 if a < b 1386** 0 if a == b 1387** +1 if a > b 1388** 1389** Side Effects: 1390** none. 1391*/ 1392 1393int 1394workcmpf3(a, b) 1395 register WORK *a; 1396 register WORK *b; 1397{ 1398 if (a->w_ctime > b->w_ctime) 1399 return 1; 1400 else if (a->w_ctime < b->w_ctime) 1401 return -1; 1402 else 1403 return 0; 1404} 1405/* 1406** DOWORK -- do a work request. 1407** 1408** Parameters: 1409** id -- the ID of the job to run. 1410** forkflag -- if set, run this in background. 1411** requeueflag -- if set, reinstantiate the queue quickly. 1412** This is used when expanding aliases in the queue. 1413** If forkflag is also set, it doesn't wait for the 1414** child. 1415** e - the envelope in which to run it. 1416** 1417** Returns: 1418** process id of process that is running the queue job. 1419** 1420** Side Effects: 1421** The work request is satisfied if possible. 1422*/ 1423 1424pid_t 1425dowork(id, forkflag, requeueflag, e) 1426 char *id; 1427 bool forkflag; 1428 bool requeueflag; 1429 register ENVELOPE *e; 1430{ 1431 register pid_t pid; 1432 extern bool readqf __P((ENVELOPE *)); 1433 1434 if (tTd(40, 1)) 1435 printf("dowork(%s)\n", id); 1436 1437 /* 1438 ** Fork for work. 1439 */ 1440 1441 if (forkflag) 1442 { 1443 pid = fork(); 1444 if (pid < 0) 1445 { 1446 syserr("dowork: cannot fork"); 1447 return 0; 1448 } 1449 else if (pid > 0) 1450 { 1451 /* parent -- clean out connection cache */ 1452 mci_flush(FALSE, NULL); 1453 } 1454 else 1455 { 1456 /* child -- error messages to the transcript */ 1457 QuickAbort = OnlyOneError = FALSE; 1458 1459 /* 1460 ** Since the delivery may happen in a child and the 1461 ** parent does not wait, the parent may close the 1462 ** maps thereby removing any shared memory used by 1463 ** the map. Therefore, open a copy of the maps for 1464 ** the delivery process. 1465 */ 1466 1467 initmaps(FALSE, e); 1468 } 1469 } 1470 else 1471 { 1472 pid = 0; 1473 } 1474 1475 if (pid == 0) 1476 { 1477 /* 1478 ** CHILD 1479 ** Lock the control file to avoid duplicate deliveries. 1480 ** Then run the file as though we had just read it. 1481 ** We save an idea of the temporary name so we 1482 ** can recover on interrupt. 1483 */ 1484 1485 /* set basic modes, etc. */ 1486 (void) alarm(0); 1487 clearenvelope(e, FALSE); 1488 e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS; 1489 e->e_sendmode = SM_DELIVER; 1490 e->e_errormode = EM_MAIL; 1491 e->e_id = id; 1492 GrabTo = UseErrorsTo = FALSE; 1493 ExitStat = EX_OK; 1494 if (forkflag) 1495 { 1496 disconnect(1, e); 1497 OpMode = MD_DELIVER; 1498 } 1499 sm_setproctitle(TRUE, "%s: from queue", id); 1500 if (LogLevel > 76) 1501 sm_syslog(LOG_DEBUG, e->e_id, 1502 "dowork, pid=%d", 1503 getpid()); 1504 1505 /* don't use the headers from sendmail.cf... */ 1506 e->e_header = NULL; 1507 1508 /* read the queue control file -- return if locked */ 1509 if (!readqf(e)) 1510 { 1511 if (tTd(40, 4) && e->e_id != NULL) 1512 printf("readqf(%s) failed\n", e->e_id); 1513 e->e_id = NULL; 1514 if (forkflag) 1515 finis(FALSE, EX_OK); 1516 else 1517 return 0; 1518 } 1519 1520 e->e_flags |= EF_INQUEUE; 1521 eatheader(e, requeueflag); 1522 1523 if (requeueflag) 1524 queueup(e, FALSE); 1525 1526 /* do the delivery */ 1527 sendall(e, SM_DELIVER); 1528 1529 /* finish up and exit */ 1530 if (forkflag) 1531 finis(TRUE, ExitStat); 1532 else 1533 dropenvelope(e, TRUE); 1534 } 1535 e->e_id = NULL; 1536 return pid; 1537} 1538/* 1539** READQF -- read queue file and set up environment. 1540** 1541** Parameters: 1542** e -- the envelope of the job to run. 1543** 1544** Returns: 1545** TRUE if it successfully read the queue file. 1546** FALSE otherwise. 1547** 1548** Side Effects: 1549** The queue file is returned locked. 1550*/ 1551 1552bool 1553readqf(e) 1554 register ENVELOPE *e; 1555{ 1556 register FILE *qfp; 1557 ADDRESS *ctladdr; 1558 struct stat st; 1559 char *bp; 1560 int qfver = 0; 1561 long hdrsize = 0; 1562 register char *p; 1563 char *orcpt = NULL; 1564 bool nomore = FALSE; 1565 char qf[MAXQFNAME]; 1566 char buf[MAXLINE]; 1567 extern ADDRESS *setctluser __P((char *, int)); 1568 1569 /* 1570 ** Read and process the file. 1571 */ 1572 1573 strcpy(qf, queuename(e, 'q')); 1574 qfp = fopen(qf, "r+"); 1575 if (qfp == NULL) 1576 { 1577 if (tTd(40, 8)) 1578 printf("readqf(%s): fopen failure (%s)\n", 1579 qf, errstring(errno)); 1580 if (errno != ENOENT) 1581 syserr("readqf: no control file %s", qf); 1582 return FALSE; 1583 } 1584 1585 if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB)) 1586 { 1587 /* being processed by another queuer */ 1588 if (Verbose || tTd(40, 8)) 1589 printf("%s: locked\n", e->e_id); 1590 if (LogLevel > 19) 1591 sm_syslog(LOG_DEBUG, e->e_id, "locked"); 1592 (void) fclose(qfp); 1593 return FALSE; 1594 } 1595 1596 /* 1597 ** Check the queue file for plausibility to avoid attacks. 1598 */ 1599 1600 if (fstat(fileno(qfp), &st) < 0) 1601 { 1602 /* must have been being processed by someone else */ 1603 if (tTd(40, 8)) 1604 printf("readqf(%s): fstat failure (%s)\n", 1605 qf, errstring(errno)); 1606 fclose(qfp); 1607 return FALSE; 1608 } 1609 1610 if ((st.st_uid != geteuid() && geteuid() != RealUid) || 1611 bitset(S_IWOTH|S_IWGRP, st.st_mode)) 1612 { 1613 if (LogLevel > 0) 1614 { 1615 sm_syslog(LOG_ALERT, e->e_id, 1616 "bogus queue file, uid=%d, mode=%o", 1617 st.st_uid, st.st_mode); 1618 } 1619 if (tTd(40, 8)) 1620 printf("readqf(%s): bogus file\n", qf); 1621 loseqfile(e, "bogus file uid in mqueue"); 1622 fclose(qfp); 1623 return FALSE; 1624 } 1625 1626 if (st.st_size == 0) 1627 { 1628 /* must be a bogus file -- if also old, just remove it */ 1629 if (st.st_ctime + 10 * 60 < curtime()) 1630 { 1631 qf[0] = 'd'; 1632 (void) unlink(qf); 1633 qf[0] = 'q'; 1634 (void) unlink(qf); 1635 } 1636 fclose(qfp); 1637 return FALSE; 1638 } 1639 1640 if (st.st_nlink == 0) 1641 { 1642 /* 1643 ** Race condition -- we got a file just as it was being 1644 ** unlinked. Just assume it is zero length. 1645 */ 1646 1647 fclose(qfp); 1648 return FALSE; 1649 } 1650 1651 /* good file -- save this lock */ 1652 e->e_lockfp = qfp; 1653 1654 /* do basic system initialization */ 1655 initsys(e); 1656 define('i', e->e_id, e); 1657 1658 LineNumber = 0; 1659 e->e_flags |= EF_GLOBALERRS; 1660 OpMode = MD_DELIVER; 1661 ctladdr = NULL; 1662 e->e_dfino = -1; 1663 e->e_msgsize = -1; 1664 while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL) 1665 { 1666 register char *p; 1667 u_long qflags; 1668 ADDRESS *q; 1669 int mid; 1670 auto char *ep; 1671 1672 if (tTd(40, 4)) 1673 printf("+++++ %s\n", bp); 1674 if (nomore) 1675 { 1676 /* hack attack */ 1677 syserr("SECURITY ALERT: extra data in qf: %s", bp); 1678 fclose(qfp); 1679 loseqfile(e, "bogus queue line"); 1680 return FALSE; 1681 } 1682 switch (bp[0]) 1683 { 1684 case 'V': /* queue file version number */ 1685 qfver = atoi(&bp[1]); 1686 if (qfver <= QF_VERSION) 1687 break; 1688 syserr("Version number in qf (%d) greater than max (%d)", 1689 qfver, QF_VERSION); 1690 fclose(qfp); 1691 loseqfile(e, "unsupported qf file version"); 1692 return FALSE; 1693 1694 case 'C': /* specify controlling user */ 1695 ctladdr = setctluser(&bp[1], qfver); 1696 break; 1697 1698 case 'Q': /* original recipient */ 1699 orcpt = newstr(&bp[1]); 1700 break; 1701 1702 case 'R': /* specify recipient */ 1703 p = bp; 1704 qflags = 0; 1705 if (qfver >= 1) 1706 { 1707 /* get flag bits */ 1708 while (*++p != '\0' && *p != ':') 1709 { 1710 switch (*p) 1711 { 1712 case 'N': 1713 qflags |= QHASNOTIFY; 1714 break; 1715 1716 case 'S': 1717 qflags |= QPINGONSUCCESS; 1718 break; 1719 1720 case 'F': 1721 qflags |= QPINGONFAILURE; 1722 break; 1723 1724 case 'D': 1725 qflags |= QPINGONDELAY; 1726 break; 1727 1728 case 'P': 1729 qflags |= QPRIMARY; 1730 break; 1731 } 1732 } 1733 } 1734 else 1735 qflags |= QPRIMARY; 1736 q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e); 1737 if (q != NULL) 1738 { 1739 q->q_alias = ctladdr; 1740 if (qfver >= 1) 1741 q->q_flags &= ~Q_PINGFLAGS; 1742 q->q_flags |= qflags; 1743 q->q_orcpt = orcpt; 1744 (void) recipient(q, &e->e_sendqueue, 0, e); 1745 } 1746 orcpt = NULL; 1747 break; 1748 1749 case 'E': /* specify error recipient */ 1750 /* no longer used */ 1751 break; 1752 1753 case 'H': /* header */ 1754 (void) chompheader(&bp[1], FALSE, NULL, e); 1755 hdrsize += strlen(&bp[1]); 1756 break; 1757 1758 case 'L': /* Solaris Content-Length: */ 1759 case 'M': /* message */ 1760 /* ignore this; we want a new message next time */ 1761 break; 1762 1763 case 'S': /* sender */ 1764 setsender(newstr(&bp[1]), e, NULL, '\0', TRUE); 1765 break; 1766 1767 case 'B': /* body type */ 1768 e->e_bodytype = newstr(&bp[1]); 1769 break; 1770 1771#if _FFR_SAVE_CHARSET 1772 case 'X': /* character set */ 1773 e->e_charset = newstr(&bp[1]); 1774 break; 1775#endif 1776 1777 case 'D': /* data file name */ 1778 /* obsolete -- ignore */ 1779 break; 1780 1781 case 'T': /* init time */ 1782 e->e_ctime = atol(&bp[1]); 1783 break; 1784 1785 case 'I': /* data file's inode number */ 1786 /* regenerated below */ 1787 break; 1788 1789 case 'K': /* time of last deliver attempt */ 1790 e->e_dtime = atol(&buf[1]); 1791 break; 1792 1793 case 'N': /* number of delivery attempts */ 1794 e->e_ntries = atoi(&buf[1]); 1795 1796 /* if this has been tried recently, let it be */ 1797 if (e->e_ntries > 0 && 1798 MinQueueAge > 0 && e->e_dtime <= curtime() && 1799 curtime() < e->e_dtime + MinQueueAge) 1800 { 1801 char *howlong = pintvl(curtime() - e->e_dtime, TRUE); 1802 1803 if (Verbose || tTd(40, 8)) 1804 printf("%s: too young (%s)\n", 1805 e->e_id, howlong); 1806 if (LogLevel > 19) 1807 sm_syslog(LOG_DEBUG, e->e_id, 1808 "too young (%s)", 1809 howlong); 1810 e->e_id = NULL; 1811 unlockqueue(e); 1812 return FALSE; 1813 } 1814 break; 1815 1816 case 'P': /* message priority */ 1817 e->e_msgpriority = atol(&bp[1]) + WkTimeFact; 1818 break; 1819 1820 case 'F': /* flag bits */ 1821 if (strncmp(bp, "From ", 5) == 0) 1822 { 1823 /* we are being spoofed! */ 1824 syserr("SECURITY ALERT: bogus qf line %s", bp); 1825 fclose(qfp); 1826 loseqfile(e, "bogus queue line"); 1827 return FALSE; 1828 } 1829 for (p = &bp[1]; *p != '\0'; p++) 1830 { 1831 switch (*p) 1832 { 1833 case 'w': /* warning sent */ 1834 e->e_flags |= EF_WARNING; 1835 break; 1836 1837 case 'r': /* response */ 1838 e->e_flags |= EF_RESPONSE; 1839 break; 1840 1841 case '8': /* has 8 bit data */ 1842 e->e_flags |= EF_HAS8BIT; 1843 break; 1844 1845 case 'b': /* delete Bcc: header */ 1846 e->e_flags |= EF_DELETE_BCC; 1847 break; 1848 1849 case 'd': /* envelope has DSN RET= */ 1850 e->e_flags |= EF_RET_PARAM; 1851 break; 1852 1853 case 'n': /* don't return body */ 1854 e->e_flags |= EF_NO_BODY_RETN; 1855 break; 1856 } 1857 } 1858 break; 1859 1860 case 'Z': /* original envelope id from ESMTP */ 1861 e->e_envid = newstr(&bp[1]); 1862 break; 1863 1864 case '$': /* define macro */ 1865 mid = macid(&bp[1], &ep); 1866 define(mid, newstr(ep), e); 1867 break; 1868 1869 case '.': /* terminate file */ 1870 nomore = TRUE; 1871 break; 1872 1873 default: 1874 syserr("readqf: %s: line %d: bad line \"%s\"", 1875 qf, LineNumber, shortenstring(bp, MAXSHORTSTR)); 1876 fclose(qfp); 1877 loseqfile(e, "unrecognized line"); 1878 return FALSE; 1879 } 1880 1881 if (bp != buf) 1882 free(bp); 1883 } 1884 1885 /* 1886 ** If we haven't read any lines, this queue file is empty. 1887 ** Arrange to remove it without referencing any null pointers. 1888 */ 1889 1890 if (LineNumber == 0) 1891 { 1892 errno = 0; 1893 e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE; 1894 return TRUE; 1895 } 1896 1897 /* 1898 ** Arrange to read the data file. 1899 */ 1900 1901 p = queuename(e, 'd'); 1902 e->e_dfp = fopen(p, "r"); 1903 if (e->e_dfp == NULL) 1904 { 1905 syserr("readqf: cannot open %s", p); 1906 } 1907 else 1908 { 1909 e->e_flags |= EF_HAS_DF; 1910 if (fstat(fileno(e->e_dfp), &st) >= 0) 1911 { 1912 e->e_msgsize = st.st_size + hdrsize; 1913 e->e_dfdev = st.st_dev; 1914 e->e_dfino = st.st_ino; 1915 } 1916 } 1917 1918 return TRUE; 1919} 1920/* 1921** PRINTQUEUE -- print out a representation of the mail queue 1922** 1923** Parameters: 1924** none. 1925** 1926** Returns: 1927** none. 1928** 1929** Side Effects: 1930** Prints a listing of the mail queue on the standard output. 1931*/ 1932 1933void 1934printqueue() 1935{ 1936 register WORK *w; 1937 FILE *f; 1938 int nrequests; 1939 char buf[MAXLINE]; 1940 1941 /* 1942 ** Check for permission to print the queue 1943 */ 1944 1945 if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0) 1946 { 1947 struct stat st; 1948# ifdef NGROUPS_MAX 1949 int n; 1950 extern GIDSET_T InitialGidSet[NGROUPS_MAX]; 1951# endif 1952 1953 if (stat(QueueDir, &st) < 0) 1954 { 1955 syserr("Cannot stat %s", QueueDir); 1956 return; 1957 } 1958# ifdef NGROUPS_MAX 1959 n = NGROUPS_MAX; 1960 while (--n >= 0) 1961 { 1962 if (InitialGidSet[n] == st.st_gid) 1963 break; 1964 } 1965 if (n < 0 && RealGid != st.st_gid) 1966# else 1967 if (RealGid != st.st_gid) 1968# endif 1969 { 1970 usrerr("510 You are not permitted to see the queue"); 1971 setstat(EX_NOPERM); 1972 return; 1973 } 1974 } 1975 1976 /* 1977 ** Read and order the queue. 1978 */ 1979 1980 nrequests = orderq(TRUE); 1981 1982 /* 1983 ** Print the work list that we have read. 1984 */ 1985 1986 /* first see if there is anything */ 1987 if (nrequests <= 0) 1988 { 1989 printf("Mail queue is empty\n"); 1990 return; 1991 } 1992 1993 CurrentLA = getla(); /* get load average */ 1994 1995 printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); 1996 if (MaxQueueRun > 0 && nrequests > MaxQueueRun) 1997 printf(", only %d printed", MaxQueueRun); 1998 if (Verbose) 1999 printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n"); 2000 else 2001 printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 2002 for (w = WorkQ; w != NULL; w = w->w_next) 2003 { 2004 struct stat st; 2005 auto time_t submittime = 0; 2006 long dfsize; 2007 int flags = 0; 2008 int qfver; 2009 char statmsg[MAXLINE]; 2010 char bodytype[MAXNAME + 1]; 2011 2012 printf("%8s", w->w_name + 2); 2013 f = fopen(w->w_name, "r"); 2014 if (f == NULL) 2015 { 2016 printf(" (job completed)\n"); 2017 errno = 0; 2018 continue; 2019 } 2020 w->w_name[0] = 'd'; 2021 if (stat(w->w_name, &st) >= 0) 2022 dfsize = st.st_size; 2023 else 2024 dfsize = -1; 2025 if (w->w_lock) 2026 printf("*"); 2027 else if (w->w_tooyoung) 2028 printf("-"); 2029 else if (shouldqueue(w->w_pri, w->w_ctime)) 2030 printf("X"); 2031 else 2032 printf(" "); 2033 errno = 0; 2034 2035 statmsg[0] = bodytype[0] = '\0'; 2036 qfver = 0; 2037 while (fgets(buf, sizeof buf, f) != NULL) 2038 { 2039 register int i; 2040 register char *p; 2041 2042 fixcrlf(buf, TRUE); 2043 switch (buf[0]) 2044 { 2045 case 'V': /* queue file version */ 2046 qfver = atoi(&buf[1]); 2047 break; 2048 2049 case 'M': /* error message */ 2050 if ((i = strlen(&buf[1])) >= sizeof statmsg) 2051 i = sizeof statmsg - 1; 2052 bcopy(&buf[1], statmsg, i); 2053 statmsg[i] = '\0'; 2054 break; 2055 2056 case 'B': /* body type */ 2057 if ((i = strlen(&buf[1])) >= sizeof bodytype) 2058 i = sizeof bodytype - 1; 2059 bcopy(&buf[1], bodytype, i); 2060 bodytype[i] = '\0'; 2061 break; 2062 2063 case 'S': /* sender name */ 2064 if (Verbose) 2065 printf("%8ld %10ld%c%.12s %.78s", 2066 dfsize, 2067 w->w_pri, 2068 bitset(EF_WARNING, flags) ? '+' : ' ', 2069 ctime(&submittime) + 4, 2070 &buf[1]); 2071 else 2072 printf("%8ld %.16s %.45s", dfsize, 2073 ctime(&submittime), &buf[1]); 2074 if (statmsg[0] != '\0' || bodytype[0] != '\0') 2075 { 2076 printf("\n %10.10s", bodytype); 2077 if (statmsg[0] != '\0') 2078 printf(" (%.*s)", 2079 Verbose ? 100 : 60, 2080 statmsg); 2081 } 2082 break; 2083 2084 case 'C': /* controlling user */ 2085 if (Verbose) 2086 printf("\n\t\t\t\t (---%.74s---)", 2087 &buf[1]); 2088 break; 2089 2090 case 'R': /* recipient name */ 2091 p = &buf[1]; 2092 if (qfver >= 1) 2093 { 2094 p = strchr(p, ':'); 2095 if (p == NULL) 2096 break; 2097 p++; 2098 } 2099 if (Verbose) 2100 printf("\n\t\t\t\t\t %.78s", p); 2101 else 2102 printf("\n\t\t\t\t %.45s", p); 2103 break; 2104 2105 case 'T': /* creation time */ 2106 submittime = atol(&buf[1]); 2107 break; 2108 2109 case 'F': /* flag bits */ 2110 for (p = &buf[1]; *p != '\0'; p++) 2111 { 2112 switch (*p) 2113 { 2114 case 'w': 2115 flags |= EF_WARNING; 2116 break; 2117 } 2118 } 2119 } 2120 } 2121 if (submittime == (time_t) 0) 2122 printf(" (no control file)"); 2123 printf("\n"); 2124 (void) fclose(f); 2125 } 2126} 2127 2128# endif /* QUEUE */ 2129/* 2130** QUEUENAME -- build a file name in the queue directory for this envelope. 2131** 2132** Assigns an id code if one does not already exist. 2133** This code is very careful to avoid trashing existing files 2134** under any circumstances. 2135** 2136** Parameters: 2137** e -- envelope to build it in/from. 2138** type -- the file type, used as the first character 2139** of the file name. 2140** 2141** Returns: 2142** a pointer to the new file name (in a static buffer). 2143** 2144** Side Effects: 2145** If no id code is already assigned, queuename will 2146** assign an id code, create a qf file, and leave a 2147** locked, open-for-write file pointer in the envelope. 2148*/ 2149 2150#ifndef ENOLCK 2151# define ENOLCK -1 2152#endif 2153#ifndef ENOSPC 2154# define ENOSPC -1 2155#endif 2156 2157char * 2158queuename(e, type) 2159 register ENVELOPE *e; 2160 int type; 2161{ 2162 static pid_t pid = -1; 2163 static char c0; 2164 static char c1; 2165 static char c2; 2166 time_t now; 2167 struct tm *tm; 2168 static char buf[MAXNAME + 1]; 2169 2170 if (e->e_id == NULL) 2171 { 2172 char qf[MAXQFNAME]; 2173 2174 /* find a unique id */ 2175 if (pid != getpid()) 2176 { 2177 /* new process -- start back at "AA" */ 2178 pid = getpid(); 2179 now = curtime(); 2180 tm = localtime(&now); 2181 c0 = 'A' + tm->tm_hour; 2182 c1 = 'A'; 2183 c2 = 'A' - 1; 2184 } 2185 (void) snprintf(qf, sizeof qf, "qf%cAA%05d", c0, pid); 2186 2187 while (c1 < '~' || c2 < 'Z') 2188 { 2189 int i; 2190 int attempts = 0; 2191 2192 if (c2 >= 'Z') 2193 { 2194 c1++; 2195 c2 = 'A' - 1; 2196 } 2197 qf[3] = c1; 2198 qf[4] = ++c2; 2199 if (tTd(7, 20)) 2200 printf("queuename: trying \"%s\"\n", qf); 2201 2202 i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode); 2203 if (i < 0) 2204 { 2205 if (errno == EEXIST) 2206 continue; 2207 syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)", 2208 qf, QueueDir, geteuid()); 2209 finis(FALSE, EX_UNAVAILABLE); 2210 } 2211 do 2212 { 2213 if (attempts > 0) 2214 sleep(attempts); 2215 e->e_lockfp = 0; 2216 if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB)) 2217 { 2218 e->e_lockfp = fdopen(i, "w"); 2219 break; 2220 } 2221 } while ((errno == ENOLCK || errno == ENOSPC) && 2222 attempts++ < 4); 2223 2224 /* Successful lock */ 2225 if (e->e_lockfp != 0) 2226 break; 2227 2228#if !HASFLOCK 2229 if (errno != EAGAIN && errno != EACCES) 2230#else 2231 if (errno != EWOULDBLOCK) 2232#endif 2233 { 2234 syserr("queuename: Cannot lock \"%s\" in \"%s\" (euid=%d)", 2235 qf, QueueDir, geteuid()); 2236 finis(FALSE, EX_OSERR); 2237 } 2238 2239 /* a reader got the file; abandon it and try again */ 2240 (void) close(i); 2241 } 2242 if (c1 >= '~' && c2 >= 'Z') 2243 { 2244 syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)", 2245 qf, QueueDir, geteuid()); 2246 finis(FALSE, EX_OSERR); 2247 } 2248 e->e_id = newstr(&qf[2]); 2249 define('i', e->e_id, e); 2250 if (tTd(7, 1)) 2251 printf("queuename: assigned id %s, env=%lx\n", 2252 e->e_id, (u_long) e); 2253 if (tTd(7, 9)) 2254 { 2255 printf(" lockfd="); 2256 dumpfd(fileno(e->e_lockfp), TRUE, FALSE); 2257 } 2258 if (LogLevel > 93) 2259 sm_syslog(LOG_DEBUG, e->e_id, "assigned id"); 2260 } 2261 2262 if (type == '\0') 2263 return (NULL); 2264 (void) snprintf(buf, sizeof buf, "%cf%s", type, e->e_id); 2265 if (tTd(7, 2)) 2266 printf("queuename: %s\n", buf); 2267 return (buf); 2268} 2269/* 2270** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 2271** 2272** Parameters: 2273** e -- the envelope to unlock. 2274** 2275** Returns: 2276** none 2277** 2278** Side Effects: 2279** unlocks the queue for `e'. 2280*/ 2281 2282void 2283unlockqueue(e) 2284 ENVELOPE *e; 2285{ 2286 if (tTd(51, 4)) 2287 printf("unlockqueue(%s)\n", 2288 e->e_id == NULL ? "NOQUEUE" : e->e_id); 2289 2290 /* if there is a lock file in the envelope, close it */ 2291 if (e->e_lockfp != NULL) 2292 xfclose(e->e_lockfp, "unlockqueue", e->e_id); 2293 e->e_lockfp = NULL; 2294 2295 /* don't create a queue id if we don't already have one */ 2296 if (e->e_id == NULL) 2297 return; 2298 2299 /* remove the transcript */ 2300 if (LogLevel > 87) 2301 sm_syslog(LOG_DEBUG, e->e_id, "unlock"); 2302 if (!tTd(51, 104)) 2303 xunlink(queuename(e, 'x')); 2304 2305} 2306/* 2307** SETCTLUSER -- create a controlling address 2308** 2309** Create a fake "address" given only a local login name; this is 2310** used as a "controlling user" for future recipient addresses. 2311** 2312** Parameters: 2313** user -- the user name of the controlling user. 2314** qfver -- the version stamp of this qf file. 2315** 2316** Returns: 2317** An address descriptor for the controlling user. 2318** 2319** Side Effects: 2320** none. 2321*/ 2322 2323ADDRESS * 2324setctluser(user, qfver) 2325 char *user; 2326 int qfver; 2327{ 2328 register ADDRESS *a; 2329 struct passwd *pw; 2330 char *p; 2331 2332 /* 2333 ** See if this clears our concept of controlling user. 2334 */ 2335 2336 if (user == NULL || *user == '\0') 2337 return NULL; 2338 2339 /* 2340 ** Set up addr fields for controlling user. 2341 */ 2342 2343 a = (ADDRESS *) xalloc(sizeof *a); 2344 bzero((char *) a, sizeof *a); 2345 2346 if (*user == '\0') 2347 { 2348 p = NULL; 2349 a->q_user = newstr(DefUser); 2350 } 2351 else if (*user == ':') 2352 { 2353 p = &user[1]; 2354 a->q_user = newstr(p); 2355 } 2356 else 2357 { 2358 p = strtok(user, ":"); 2359 a->q_user = newstr(user); 2360 if (qfver >= 2) 2361 { 2362 if ((p = strtok(NULL, ":")) != NULL) 2363 a->q_uid = atoi(p); 2364 if ((p = strtok(NULL, ":")) != NULL) 2365 a->q_gid = atoi(p); 2366 if ((p = strtok(NULL, ":")) != NULL) 2367 a->q_flags |= QGOODUID; 2368 } 2369 else if ((pw = sm_getpwnam(user)) != NULL) 2370 { 2371 if (strcmp(pw->pw_dir, "/") == 0) 2372 a->q_home = ""; 2373 else 2374 a->q_home = newstr(pw->pw_dir); 2375 a->q_uid = pw->pw_uid; 2376 a->q_gid = pw->pw_gid; 2377 a->q_flags |= QGOODUID; 2378 } 2379 } 2380 2381 a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */ 2382 a->q_mailer = LocalMailer; 2383 if (p == NULL) 2384 a->q_paddr = a->q_user; 2385 else 2386 a->q_paddr = newstr(p); 2387 return a; 2388} 2389/* 2390** LOSEQFILE -- save the qf as Qf and try to let someone know 2391** 2392** Parameters: 2393** e -- the envelope (e->e_id will be used). 2394** why -- reported to whomever can hear. 2395** 2396** Returns: 2397** none. 2398*/ 2399 2400void 2401loseqfile(e, why) 2402 register ENVELOPE *e; 2403 char *why; 2404{ 2405 char *p; 2406 char buf[MAXQFNAME + 1]; 2407 2408 if (e == NULL || e->e_id == NULL) 2409 return; 2410 p = queuename(e, 'q'); 2411 if (strlen(p) > MAXQFNAME) 2412 { 2413 syserr("loseqfile: queuename (%s) too long", p); 2414 return; 2415 } 2416 strcpy(buf, p); 2417 p = queuename(e, 'Q'); 2418 if (rename(buf, p) < 0) 2419 syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid()); 2420 else if (LogLevel > 0) 2421 sm_syslog(LOG_ALERT, e->e_id, 2422 "Losing %s: %s", buf, why); 2423} 2424