queue.c revision 43730
144603Sdcs/* 244603Sdcs * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 344603Sdcs * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 444603Sdcs * Copyright (c) 1988, 1993 544603Sdcs * The Regents of the University of California. All rights reserved. 644603Sdcs * 744603Sdcs * By using this file, you agree to the terms and conditions set 844603Sdcs * forth in the LICENSE file which can be found at the top level of 950477Speter * the sendmail distribution. 1044603Sdcs * 1144603Sdcs */ 1244603Sdcs 1344603Sdcs# include "sendmail.h" 1444603Sdcs 15293293Sdteske#ifndef lint 1644603Sdcs#if QUEUE 1765785Sdcsstatic char sccsid[] = "@(#)queue.c 8.211 (Berkeley) 1/25/1999 (with queueing)"; 1865785Sdcs#else 19135986Srustatic char sccsid[] = "@(#)queue.c 8.211 (Berkeley) 1/25/1999 (without queueing)"; 2044603Sdcs#endif 2197201Sgordon#endif /* not lint */ 2297201Sgordon 2397201Sgordon# include <errno.h> 2444603Sdcs# include <dirent.h> 2544603Sdcs 2644603Sdcs# if QUEUE 2744603Sdcs 2844603Sdcs/* 2944603Sdcs** Work queue. 3044603Sdcs*/ 3144603Sdcs 3247171Sdcsstruct work 3347171Sdcs{ 34230109Seadler char *w_name; /* name of control file */ 3544603Sdcs char *w_host; /* name of recipient host */ 3644603Sdcs bool w_lock; /* is message locked? */ 37230109Seadler bool w_tooyoung; /* is it too young to run? */ 3865939Sdcs long w_pri; /* priority of message, see below */ 3944603Sdcs time_t w_ctime; /* creation time of message */ 4044603Sdcs struct work *w_next; /* next in queue */ 4144603Sdcs}; 42293293Sdteske 43256381Smarkmtypedef struct work WORK; 44256381Smarkm 45256381SmarkmWORK *WorkQ; /* queue of things to be done */ 46256381Smarkm 47256381Smarkm#define QF_VERSION 2 /* version number of this queue format */ 48256381Smarkm 49256381Smarkmextern int orderq __P((bool)); 50256381Smarkm/* 51256381Smarkm** QUEUEUP -- queue a message up for future transmission. 52256381Smarkm** 53289508Strasz** Parameters: 54289508Strasz** e -- the envelope to queue up. 55289508Strasz** announce -- if TRUE, tell when you are queueing up. 56289508Strasz** 57289508Strasz** Returns: 58289508Strasz** none. 59289508Strasz** 60289508Strasz** Side Effects: 61289508Strasz** The current request are saved in a control file. 62289508Strasz** The queue file is left locked. 6344603Sdcs*/ 6444603Sdcs 6544603Sdcsvoid 66262702Sdteskequeueup(e, announce) 67262702Sdteske register ENVELOPE *e; 68146421Ssobomax bool announce; 69146421Ssobomax{ 70146421Ssobomax char *qf; 71172327Sru register FILE *tfp; 72172327Sru register HDR *h; 73281843Sdteske register ADDRESS *q; 74281843Sdteske int fd; 75281843Sdteske int i; 76293802Sallanjude bool newid; 77117090Sbrueffer register char *p; 78262701Sdteske MAILER nullmailer; 79227727Smiwi MCI mcibuf; 80149213Siedowse char tf[MAXQFNAME]; 81148515Sbrian char buf[MAXLINE]; 8254247Sdcs extern void printctladdr __P((ADDRESS *, FILE *)); 83133217Sjmg 8452749Sdcs /* 8554247Sdcs ** Create control file. 8654247Sdcs */ 87224408Srodrigc 88224408Srodrigc newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags); 89224408Srodrigc 90224408Srodrigc /* if newid, queuename will create a locked qf file in e->lockfp */ 91224408Srodrigc strcpy(tf, queuename(e, 't')); 92278602Sian tfp = e->e_lockfp; 9344603Sdcs if (tfp == NULL) 9444603Sdcs newid = FALSE; 9544603Sdcs 9644603Sdcs /* if newid, just write the qf file directly (instead of tf file) */ 9744603Sdcs if (!newid) 9844603Sdcs { 99148515Sbrian /* get a locked tf file */ 100148515Sbrian for (i = 0; i < 128; i++) 101148515Sbrian { 102148515Sbrian fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode); 103148515Sbrian if (fd < 0) 104148515Sbrian { 105148515Sbrian if (errno != EEXIST) 106150469Sru break; 107148515Sbrian if (LogLevel > 0 && (i % 32) == 0) 108148515Sbrian sm_syslog(LOG_ALERT, e->e_id, 109150469Sru "queueup: cannot create %s, uid=%d: %s", 110150469Sru tf, geteuid(), errstring(errno)); 111148515Sbrian } 112148515Sbrian else 113148515Sbrian { 114226833Spluknet if (lockfile(fd, tf, NULL, LOCK_EX|LOCK_NB)) 11554265Smsmith break; 116166486Simp else if (LogLevel > 0 && (i % 32) == 0) 117166486Simp sm_syslog(LOG_ALERT, e->e_id, 118166486Simp "queueup: cannot lock %s: %s", 11944603Sdcs tf, errstring(errno)); 12044603Sdcs close(fd); 12144603Sdcs } 12244603Sdcs 12344603Sdcs if ((i % 32) == 31) 12444603Sdcs { 125132853Sceri /* save the old temp file away */ 12699332Smini (void) rename(tf, queuename(e, 'T')); 12799332Smini } 12899332Smini else 12999332Smini sleep(i % 32); 13099332Smini } 13199332Smini if (fd < 0 || (tfp = fdopen(fd, "w")) == NULL) 13299332Smini { 13399332Smini printopenfds(TRUE); 13499332Smini syserr("!queueup: cannot create queue temp file %s, uid=%d", 13599332Smini tf, geteuid()); 13686902Srwatson } 137217689Spluknet } 138148817Skrion 13999332Smini if (tTd(40, 1)) 140202143Sbrooks printf("\n>>>>> queueing %s%s >>>>>\n", e->e_id, 14199332Smini newid ? " (new id)" : ""); 142225122Smarck if (tTd(40, 3)) 143225122Smarck { 144102862Sbrooks extern void printenvflags __P((ENVELOPE *)); 145106335Smini 14644603Sdcs printf(" e_flags="); 14799332Smini printenvflags(e); 14844603Sdcs } 14995524Sdcs if (tTd(40, 32)) 15095524Sdcs { 151125091Sdes printf(" sendq="); 152283971Sdteske printaddr(e->e_sendqueue, TRUE); 15370706Sjhb } 15470706Sjhb if (tTd(40, 9)) 15570706Sjhb { 156111749Sharti printf(" tfp="); 15744603Sdcs dumpfd(fileno(tfp), TRUE, FALSE); 15844603Sdcs printf(" lockfp="); 15944603Sdcs if (e->e_lockfp == NULL) 160293293Sdteske printf("NULL\n"); 161209466Sbrucec else 162209466Sbrucec dumpfd(fileno(e->e_lockfp), TRUE, FALSE); 163209466Sbrucec } 164209466Sbrucec 165209466Sbrucec /* 166209466Sbrucec ** If there is no data file yet, create one. 167209466Sbrucec */ 168209466Sbrucec 169209466Sbrucec if (!bitset(EF_HAS_DF, e->e_flags)) 170209466Sbrucec { 171209466Sbrucec register FILE *dfp = NULL; 172209466Sbrucec char dfname[MAXQFNAME]; 173209466Sbrucec struct stat stbuf; 174209466Sbrucec 175209466Sbrucec strcpy(dfname, queuename(e, 'd')); 176209466Sbrucec fd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode); 177209466Sbrucec if (fd < 0 || (dfp = fdopen(fd, "w")) == NULL) 178209466Sbrucec syserr("!queueup: cannot create data temp file %s, uid=%d", 179209466Sbrucec dfname, geteuid()); 180209466Sbrucec if (fstat(fd, &stbuf) < 0) 181209466Sbrucec e->e_dfino = -1; 182209466Sbrucec else 183209466Sbrucec { 184209466Sbrucec e->e_dfdev = stbuf.st_dev; 185209466Sbrucec e->e_dfino = stbuf.st_ino; 186209466Sbrucec } 18744603Sdcs e->e_flags |= EF_HAS_DF; 18844603Sdcs bzero(&mcibuf, sizeof mcibuf); 18944603Sdcs mcibuf.mci_out = dfp; 19044603Sdcs mcibuf.mci_mailer = FileMailer; 19144603Sdcs (*e->e_putbody)(&mcibuf, e, NULL); 19244603Sdcs (void) xfclose(dfp, "queueup dfp", e->e_id); 19377034Sru e->e_putbody = putbody; 194126455Sdes } 195161286Sbrueffer 19677162Sru /* 197135986Sru ** Output future work requests. 198135986Sru ** Priority and creation time should be first, since 19963962Ssheldonh ** they are required by orderq. 20044603Sdcs */ 201161448Sbrueffer 20277034Sru /* output queue version number (must be first!) */ 203168554Spjd fprintf(tfp, "V%d\n", QF_VERSION); 20444603Sdcs 20544603Sdcs /* output creation time */ 20644603Sdcs fprintf(tfp, "T%ld\n", (long) e->e_ctime); 207152307Spjd 208152307Spjd /* output last delivery time */ 209152307Spjd fprintf(tfp, "K%ld\n", (long) e->e_dtime); 210152307Spjd 211152309Spjd /* output number of delivery attempts */ 212152307Spjd fprintf(tfp, "N%d\n", e->e_ntries); 213152307Spjd 214182194Smatteo /* output message priority */ 215152307Spjd fprintf(tfp, "P%ld\n", e->e_msgpriority); 216152309Spjd 217166003Smaxim /* output inode number of data file */ 218152307Spjd /* XXX should probably include device major/minor too */ 219202437Strasz if (e->e_dfino != -1) 220152307Spjd { 221152307Spjd if (sizeof e->e_dfino > sizeof(long)) 222152307Spjd fprintf(tfp, "I%d/%d/%s\n", 223152307Spjd major(e->e_dfdev), minor(e->e_dfdev), 224152309Spjd quad_to_string(e->e_dfino)); 225152307Spjd else 22644603Sdcs fprintf(tfp, "I%d/%d/%lu\n", 22744603Sdcs major(e->e_dfdev), minor(e->e_dfdev), 22844603Sdcs (unsigned long) e->e_dfino); 229209466Sbrucec } 230209466Sbrucec 231209466Sbrucec /* output body type */ 232209466Sbrucec if (e->e_bodytype != NULL) 233209466Sbrucec fprintf(tfp, "B%s\n", denlstring(e->e_bodytype, TRUE, FALSE)); 234209466Sbrucec 235209466Sbrucec#if _FFR_SAVE_CHARSET 236209466Sbrucec if (e->e_charset != NULL) 237209466Sbrucec fprintf(tfp, "X%s\n", denlstring(e->e_charset, TRUE, FALSE)); 238209466Sbrucec#endif 239209466Sbrucec 240209466Sbrucec /* message from envelope, if it exists */ 24144603Sdcs if (e->e_message != NULL) 24244603Sdcs fprintf(tfp, "M%s\n", denlstring(e->e_message, TRUE, FALSE)); 24344603Sdcs 24444603Sdcs /* send various flag bits through */ 24544603Sdcs p = buf; 24644603Sdcs if (bitset(EF_WARNING, e->e_flags)) 24744603Sdcs *p++ = 'w'; 24844603Sdcs if (bitset(EF_RESPONSE, e->e_flags)) 24944603Sdcs *p++ = 'r'; 25044603Sdcs if (bitset(EF_HAS8BIT, e->e_flags)) 25144603Sdcs *p++ = '8'; 25244603Sdcs if (bitset(EF_DELETE_BCC, e->e_flags)) 25344603Sdcs *p++ = 'b'; 25444603Sdcs if (bitset(EF_RET_PARAM, e->e_flags)) 25544603Sdcs *p++ = 'd'; 25644603Sdcs if (bitset(EF_NO_BODY_RETN, e->e_flags)) 257197518Sbz *p++ = 'n'; 25847173Sdcs *p++ = '\0'; 25947173Sdcs if (buf[0] != '\0') 26044603Sdcs fprintf(tfp, "F%s\n", buf); 26144603Sdcs 26244603Sdcs /* $r and $s and $_ macro values */ 26344603Sdcs if ((p = macvalue('r', e)) != NULL) 26444603Sdcs fprintf(tfp, "$r%s\n", denlstring(p, TRUE, FALSE)); 26544603Sdcs if ((p = macvalue('s', e)) != NULL) 26644603Sdcs fprintf(tfp, "$s%s\n", denlstring(p, TRUE, FALSE)); 267166005Smaxim if ((p = macvalue('_', e)) != NULL) 268166005Smaxim fprintf(tfp, "$_%s\n", denlstring(p, TRUE, FALSE)); 269195892Sbz 270106335Smini /* output name of sender */ 271106335Smini if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 272106335Smini p = e->e_sender; 273106335Smini else 274106335Smini p = e->e_from.q_paddr; 27544603Sdcs fprintf(tfp, "S%s\n", denlstring(p, TRUE, FALSE)); 276106335Smini 27744603Sdcs /* output ESMTP-supplied "original" information */ 278126263Smlaier if (e->e_envid != NULL) 27944603Sdcs fprintf(tfp, "Z%s\n", denlstring(e->e_envid, TRUE, FALSE)); 28044603Sdcs 28144603Sdcs /* output list of recipient addresses */ 28247175Sdcs printctladdr(NULL, NULL); 28347175Sdcs for (q = e->e_sendqueue; q != NULL; q = q->q_next) 28447175Sdcs { 285218815Sdanger if (bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)) 28654020Sdcs { 287228576Sglebius#if XDEBUG 288183592Sstas if (bitset(QQUEUEUP, q->q_flags)) 289179106Syongari sm_syslog(LOG_DEBUG, e->e_id, 290193880Syongari "dropenvelope: q_flags = %x, paddr = %s", 291184870Syongari q->q_flags, q->q_paddr); 29255992Swpaul#endif 293148798Skrion continue; 294148817Skrion } 295148817Skrion printctladdr(q, tfp); 296161286Sbrueffer if (q->q_orcpt != NULL) 297135986Sru fprintf(tfp, "Q%s\n", 298161286Sbrueffer denlstring(q->q_orcpt, TRUE, FALSE)); 299218815Sdanger putc('R', tfp); 300209466Sbrucec if (bitset(QPRIMARY, q->q_flags)) 301204328Sweongyo putc('P', tfp); 302219647Sdavidch if (bitset(QHASNOTIFY, q->q_flags)) 303194246Smarius putc('N', tfp); 304106330Smini if (bitset(QPINGONSUCCESS, q->q_flags)) 305148817Skrion putc('S', tfp); 306148817Skrion if (bitset(QPINGONFAILURE, q->q_flags)) 307209466Sbrucec putc('F', tfp); 30855017Swpaul if (bitset(QPINGONDELAY, q->q_flags)) 309161286Sbrueffer putc('D', tfp); 310166005Smaxim putc(':', tfp); 311166005Smaxim fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE)); 312161286Sbrueffer if (announce) 313115054Smurray { 314106330Smini e->e_to = q->q_paddr; 315207630Sdelphij message("queued"); 316161286Sbrueffer if (LogLevel > 8) 317209466Sbrucec logdelivery(q->q_mailer, NULL, "queued", 318166005Smaxim NULL, (time_t) 0, e); 319166005Smaxim e->e_to = NULL; 32054019Sdcs } 321158569Smarius if (tTd(40, 1)) 322209466Sbrucec { 323158569Smarius printf("queueing "); 324115054Smurray printaddr(q, FALSE); 325177693Sbrueffer } 326161286Sbrueffer } 327166005Smaxim 328166005Smaxim /* 329209466Sbrucec ** Output headers for this message. 330161449Sbrueffer ** Expand macros completely here. Queue run will deal with 331177693Sbrueffer ** everything as absolute headers. 332179343Syongari ** All headers that must be relative to the recipient 333218815Sdanger ** can be cracked later. 334158569Smarius ** We set up a "null mailer" -- i.e., a mailer that will have 335166005Smaxim ** no effect on the addresses as they are output. 336166005Smaxim */ 337177990Sweongyo 338177990Sweongyo bzero((char *) &nullmailer, sizeof nullmailer); 339165145Syongari nullmailer.m_re_rwset = nullmailer.m_rh_rwset = 340161449Sbrueffer nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1; 341161286Sbrueffer nullmailer.m_eol = "\n"; 342161448Sbrueffer bzero(&mcibuf, sizeof mcibuf); 343161286Sbrueffer mcibuf.mci_mailer = &nullmailer; 344148817Skrion mcibuf.mci_out = tfp; 345177693Sbrueffer 346209466Sbrucec define('g', "\201f", e); 347106335Smini for (h = e->e_header; h != NULL; h = h->h_link) 348177693Sbrueffer { 349135986Sru extern bool bitzerop __P((BITMAP)); 35055017Swpaul 351148817Skrion if (h->h_value == NULL) 352209466Sbrucec continue; 353209466Sbrucec 354182912Sjhb /* don't output resent headers on non-resent messages */ 35554019Sdcs if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 356207630Sdelphij continue; 35754019Sdcs 358161286Sbrueffer /* expand macros; if null, don't output header at all */ 359106330Smini if (bitset(H_DEFAULT, h->h_flags)) 360161286Sbrueffer { 361161286Sbrueffer (void) expand(h->h_value, buf, sizeof buf, e); 36254019Sdcs if (buf[0] == '\0') 36354019Sdcs continue; 364161286Sbrueffer } 365106335Smini 366135986Sru /* output this header */ 367216829Syongari fprintf(tfp, "H"); 368190789Sweongyo 369148817Skrion /* if conditional, output the set of conditions */ 370181581Sweongyo if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags)) 371177693Sbrueffer { 372187614Sweongyo int j; 37354019Sdcs 374106330Smini (void) putc('?', tfp); 37554019Sdcs for (j = '\0'; j <= '\177'; j++) 37655992Swpaul if (bitnset(j, h->h_mflags)) 377177693Sbrueffer (void) putc(j, tfp); 378106330Smini (void) putc('?', tfp); 37954019Sdcs } 380209466Sbrucec 38147175Sdcs /* output the header: expand macros, convert addresses */ 382293293Sdteske if (bitset(H_DEFAULT, h->h_flags)) 38347175Sdcs { 38474212Sjhb fprintf(tfp, "%s: %s\n", 38574212Sjhb h->h_field, 38674212Sjhb denlstring(buf, FALSE, TRUE)); 38774212Sjhb } 38874212Sjhb else if (bitset(H_FROM|H_RCPT, h->h_flags)) 38974212Sjhb { 39074212Sjhb bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 39174212Sjhb FILE *savetrace = TrafficLogFile; 39274212Sjhb 393135986Sru TrafficLogFile = NULL; 394135986Sru 39574212Sjhb if (bitset(H_FROM, h->h_flags)) 396135986Sru oldstyle = FALSE; 39774212Sjhb 398135986Sru commaize(h, h->h_value, oldstyle, &mcibuf, e); 399135986Sru 40074212Sjhb TrafficLogFile = savetrace; 401135986Sru } 40274212Sjhb else 403135986Sru { 40474212Sjhb fprintf(tfp, "%s: %s\n", 405135986Sru h->h_field, 40674212Sjhb denlstring(h->h_value, FALSE, TRUE)); 407166005Smaxim } 408166005Smaxim } 409166004Smaxim 41074212Sjhb /* 41174212Sjhb ** Clean up. 41274212Sjhb ** 41374212Sjhb ** Write a terminator record -- this is to prevent 41474212Sjhb ** scurrilous crackers from appending any data. 41574212Sjhb */ 416166005Smaxim 417166005Smaxim fprintf(tfp, ".\n"); 418135986Sru 41974212Sjhb if (fflush(tfp) < 0 || 420166005Smaxim (SuperSafe && fsync(fileno(tfp)) < 0) || 421166005Smaxim ferror(tfp)) 42274212Sjhb { 423135986Sru if (newid) 42474212Sjhb syserr("!552 Error writing control file %s", tf); 425293293Sdteske else 42674212Sjhb syserr("!452 Error writing control file %s", tf); 42774212Sjhb } 42874212Sjhb 42974212Sjhb if (!newid) 430132248Stanimura { 43174212Sjhb /* rename (locked) tf to be (locked) qf */ 432135986Sru qf = queuename(e, 'q'); 433152979Sariff if (rename(tf, qf) < 0) 43474212Sjhb syserr("cannot rename(%s, %s), uid=%d", 435135986Sru tf, qf, geteuid()); 43674212Sjhb 43774212Sjhb /* close and unlock old (locked) qf */ 43874212Sjhb if (e->e_lockfp != NULL) 439160709Sache (void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id); 440161286Sbrueffer e->e_lockfp = tfp; 441162890Snetchild } 442135986Sru else 44374212Sjhb qf = tf; 44474212Sjhb errno = 0; 445162934Sariff e->e_flags |= EF_INQUEUE; 44688253Sjim 44774212Sjhb /* save log info */ 44874212Sjhb if (LogLevel > 79) 44974212Sjhb sm_syslog(LOG_DEBUG, e->e_id, "queueup, qf=%s", qf); 45074212Sjhb 451135986Sru if (tTd(40, 1)) 452135986Sru printf("<<<<< done queueing %s <<<<<\n\n", e->e_id); 45374212Sjhb return; 45474212Sjhb} 455162890Snetchild 45674212Sjhbvoid 457102011Sorionprintctladdr(a, tfp) 45874212Sjhb register ADDRESS *a; 459135986Sru FILE *tfp; 460107175Sdcs{ 46174212Sjhb char *uname; 462293293Sdteske register ADDRESS *q; 46374212Sjhb uid_t uid; 46453243Sn_hibma gid_t gid; 46553243Sn_hibma static ADDRESS *lastctladdr = NULL; 46653243Sn_hibma static uid_t lastuid; 46753548Sn_hibma 46859895Sn_hibma /* initialization */ 46953548Sn_hibma if (a == NULL || a->q_alias == NULL || tfp == NULL) 470209466Sbrucec { 47191609Salfred if (lastctladdr != NULL && tfp != NULL) 47253548Sn_hibma fprintf(tfp, "C\n"); 47353548Sn_hibma lastctladdr = NULL; 47453548Sn_hibma lastuid = 0; 47553548Sn_hibma return; 47653548Sn_hibma } 477209466Sbrucec 47867955Sn_hibma /* find the active uid */ 479209466Sbrucec q = getctladdr(a); 480209466Sbrucec if (q == NULL) 481209466Sbrucec { 48255162Swpaul uname = NULL; 483115054Smurray uid = 0; 484209466Sbrucec gid = 0; 48555944Swpaul } 48655429Swpaul else 487209466Sbrucec { 488177990Sweongyo uname = q->q_ruser != NULL ? q->q_ruser : q->q_user; 489209466Sbrucec uid = q->q_uid; 490209466Sbrucec gid = q->q_gid; 491177990Sweongyo } 492177990Sweongyo a = a->q_alias; 493135986Sru 49453243Sn_hibma /* check to see if this is the same as last time */ 495293293Sdteske if (lastctladdr != NULL && uid == lastuid && 49653243Sn_hibma strcmp(lastctladdr->q_paddr, a->q_paddr) == 0) 49744603Sdcs return; 49844603Sdcs lastuid = uid; 49944603Sdcs lastctladdr = a; 500209466Sbrucec 50147890Sroger if (uid == 0 || uname == NULL || uname[0] == '\0') 50261757Smjacob fprintf(tfp, "C"); 50374212Sjhb else 50474263Sjhb fprintf(tfp, "C%s:%ld:%ld", 505192247Sbrueffer denlstring(uname, TRUE, FALSE), (long) uid, (long) gid); 50674263Sjhb fprintf(tfp, ":%s\n", denlstring(a->q_paddr, TRUE, FALSE)); 507209466Sbrucec} 508209466Sbrucec/* 509209466Sbrucec** RUNQUEUE -- run the jobs in the queue. 51065689Smarkm** 511128280Scperciva** Gets the stuff out of the queue in some presumably logical 512181297Srpaulo** order and processes them. 513209466Sbrucec** 514209466Sbrucec** Parameters: 515209466Sbrucec** forkflag -- TRUE if the queue scanning should be done in 516189872Sdchagin** a child process. We double-fork so it is not our 517212861Snork** child and we don't have to clean up after it. 518232614Sbz** verbose -- if TRUE, print out status information. 51944603Sdcs** 520293293Sdteske** Returns: 52144603Sdcs** TRUE if the queue run successfully began. 52286133Siwasaki** 52386133Siwasaki** Side Effects: 52486133Siwasaki** runs things in the mail queue. 52586133Siwasaki*/ 52686133Siwasaki 52786133SiwasakiENVELOPE QueueEnvelope; /* the queue run envelope */ 52886133Siwasakiextern int get_num_procs_online __P((void)); 529126453Sdes 53086133Siwasakibool 531293293Sdteskerunqueue(forkflag, verbose) 53286133Siwasaki bool forkflag; 533293293Sdteske bool verbose; 534101187Srwatson{ 535101187Srwatson register ENVELOPE *e; 536101187Srwatson int njobs; 537101187Srwatson int sequenceno = 0; 538101187Srwatson time_t current_la_time; 539101187Srwatson extern ENVELOPE BlankEnvelope; 540101187Srwatson extern void clrdaemon __P((void)); 541101187Srwatson extern void runqueueevent __P((void)); 542101187Srwatson 543101187Srwatson DoQueueRun = FALSE; 544293293Sdteske 545101187Srwatson /* 54644603Sdcs ** If no work will ever be selected, don't even bother reading 54744603Sdcs ** the queue. 54844603Sdcs */ 54944603Sdcs 55044603Sdcs CurrentLA = getla(); /* get load average */ 55144603Sdcs current_la_time = curtime(); 55244603Sdcs 55344603Sdcs if (shouldqueue(WkRecipFact, current_la_time)) 55444603Sdcs { 55544603Sdcs char *msg = "Skipping queue run -- load average too high"; 556 557 if (verbose) 558 message("458 %s\n", msg); 559 if (LogLevel > 8) 560 sm_syslog(LOG_INFO, NOQID, 561 "runqueue: %s", 562 msg); 563 if (forkflag && QueueIntvl != 0) 564 (void) setevent(QueueIntvl, runqueueevent, 0); 565 return FALSE; 566 } 567 568 /* 569 ** See if we already have too many children. 570 */ 571 572 if (forkflag && QueueIntvl != 0 && 573 MaxChildren > 0 && CurChildren >= MaxChildren) 574 { 575 (void) setevent(QueueIntvl, runqueueevent, 0); 576 return FALSE; 577 } 578 579 /* 580 ** See if we want to go off and do other useful work. 581 */ 582 583 if (forkflag) 584 { 585 pid_t pid; 586 extern SIGFUNC_DECL intsig __P((int)); 587 extern SIGFUNC_DECL reapchild __P((int)); 588 589 blocksignal(SIGCHLD); 590 (void) setsignal(SIGCHLD, reapchild); 591 592 pid = dofork(); 593 if (pid == -1) 594 { 595 const char *msg = "Skipping queue run -- fork() failed"; 596 const char *err = errstring(errno); 597 598 if (verbose) 599 message("458 %s: %s\n", msg, err); 600 if (LogLevel > 8) 601 sm_syslog(LOG_INFO, NOQID, 602 "runqueue: %s: %s", 603 msg, err); 604 if (QueueIntvl != 0) 605 (void) setevent(QueueIntvl, runqueueevent, 0); 606 (void) releasesignal(SIGCHLD); 607 return FALSE; 608 } 609 if (pid != 0) 610 { 611 /* parent -- pick up intermediate zombie */ 612 (void) blocksignal(SIGALRM); 613 proc_list_add(pid, "Queue runner"); 614 (void) releasesignal(SIGALRM); 615 releasesignal(SIGCHLD); 616 if (QueueIntvl != 0) 617 (void) setevent(QueueIntvl, runqueueevent, 0); 618 return TRUE; 619 } 620 /* child -- double fork and clean up signals */ 621 clrcontrol(); 622 proc_list_clear(); 623 624 /* Add parent process as first child item */ 625 proc_list_add(getpid(), "Queue runner child process"); 626 releasesignal(SIGCHLD); 627 (void) setsignal(SIGCHLD, SIG_DFL); 628 (void) setsignal(SIGHUP, intsig); 629 } 630 631 sm_setproctitle(TRUE, "running queue: %s", QueueDir); 632 633 if (LogLevel > 69) 634 sm_syslog(LOG_DEBUG, NOQID, 635 "runqueue %s, pid=%d, forkflag=%d", 636 QueueDir, getpid(), forkflag); 637 638 /* 639 ** Release any resources used by the daemon code. 640 */ 641 642# if DAEMON 643 clrdaemon(); 644# endif /* DAEMON */ 645 646 /* force it to run expensive jobs */ 647 NoConnect = FALSE; 648 649 /* drop privileges */ 650 if (geteuid() == (uid_t) 0) 651 (void) drop_privileges(FALSE); 652 653 /* 654 ** Create ourselves an envelope 655 */ 656 657 CurEnv = &QueueEnvelope; 658 e = newenvelope(&QueueEnvelope, CurEnv); 659 e->e_flags = BlankEnvelope.e_flags; 660 661 /* make sure we have disconnected from parent */ 662 if (forkflag) 663 { 664 disconnect(1, e); 665 QuickAbort = FALSE; 666 } 667 668 /* 669 ** Make sure the alias database is open. 670 */ 671 672 initmaps(FALSE, e); 673 674 /* 675 ** If we are running part of the queue, always ignore stored 676 ** host status. 677 */ 678 679 if (QueueLimitId != NULL || QueueLimitSender != NULL || 680 QueueLimitRecipient != NULL) 681 { 682 IgnoreHostStatus = TRUE; 683 MinQueueAge = 0; 684 } 685 686 /* 687 ** Start making passes through the queue. 688 ** First, read and sort the entire queue. 689 ** Then, process the work in that order. 690 ** But if you take too long, start over. 691 */ 692 693 /* order the existing work requests */ 694 njobs = orderq(FALSE); 695 696 /* process them once at a time */ 697 while (WorkQ != NULL) 698 { 699 WORK *w = WorkQ; 700 701 WorkQ = WorkQ->w_next; 702 e->e_to = NULL; 703 704 /* 705 ** Ignore jobs that are too expensive for the moment. 706 ** 707 ** Get new load average every 30 seconds. 708 */ 709 710 if (current_la_time < curtime() - 30) 711 { 712 CurrentLA = getla(); 713 current_la_time = curtime(); 714 } 715 if (shouldqueue(WkRecipFact, current_la_time)) 716 { 717 char *msg = "Aborting queue run: load average too high"; 718 719 if (Verbose) 720 message("%s", msg); 721 if (LogLevel > 8) 722 sm_syslog(LOG_INFO, NOQID, 723 "runqueue: %s", 724 msg); 725 break; 726 } 727 sequenceno++; 728 if (shouldqueue(w->w_pri, w->w_ctime)) 729 { 730 if (Verbose) 731 message(""); 732 if (QueueSortOrder == QS_BYPRIORITY) 733 { 734 if (Verbose) 735 message("Skipping %s (sequence %d of %d) and flushing rest of queue", 736 w->w_name + 2, 737 sequenceno, 738 njobs); 739 if (LogLevel > 8) 740 sm_syslog(LOG_INFO, NOQID, 741 "runqueue: Flushing queue from %s (pri %ld, LA %d, %d of %d)", 742 w->w_name + 2, 743 w->w_pri, 744 CurrentLA, 745 sequenceno, 746 njobs); 747 break; 748 } 749 else if (Verbose) 750 message("Skipping %s (sequence %d of %d)", 751 w->w_name + 2, sequenceno, njobs); 752 } 753 else 754 { 755 pid_t pid; 756 757 if (Verbose) 758 { 759 message(""); 760 message("Running %s (sequence %d of %d)", 761 w->w_name + 2, sequenceno, njobs); 762 } 763 pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e); 764 errno = 0; 765 if (pid != 0) 766 (void) waitfor(pid); 767 } 768 free(w->w_name); 769 if (w->w_host) 770 free(w->w_host); 771 free((char *) w); 772 } 773 774 /* exit without the usual cleanup */ 775 e->e_id = NULL; 776 finis(TRUE, ExitStat); 777 /*NOTREACHED*/ 778 return TRUE; 779} 780 781 782/* 783** RUNQUEUEEVENT -- stub for use in setevent 784*/ 785 786void 787runqueueevent() 788{ 789 DoQueueRun = TRUE; 790} 791/* 792** ORDERQ -- order the work queue. 793** 794** Parameters: 795** doall -- if set, include everything in the queue (even 796** the jobs that cannot be run because the load 797** average is too high). Otherwise, exclude those 798** jobs. 799** 800** Returns: 801** The number of request in the queue (not necessarily 802** the number of requests in WorkQ however). 803** 804** Side Effects: 805** Sets WorkQ to the queue of available work, in order. 806*/ 807 808# define NEED_P 001 809# define NEED_T 002 810# define NEED_R 004 811# define NEED_S 010 812 813static WORK *WorkList = NULL; 814static int WorkListSize = 0; 815 816int 817orderq(doall) 818 bool doall; 819{ 820 register struct dirent *d; 821 register WORK *w; 822 register char *p; 823 DIR *f; 824 register int i; 825 int wn = -1; 826 int wc; 827 QUEUE_CHAR *check; 828 829 if (tTd(41, 1)) 830 { 831 printf("orderq:\n"); 832 833 check = QueueLimitId; 834 while (check != NULL) 835 { 836 printf("\tQueueLimitId = %s\n", 837 check->queue_match); 838 check = check->queue_next; 839 } 840 841 check = QueueLimitSender; 842 while (check != NULL) 843 { 844 printf("\tQueueLimitSender = %s\n", 845 check->queue_match); 846 check = check->queue_next; 847 } 848 849 check = QueueLimitRecipient; 850 while (check != NULL) 851 { 852 printf("\tQueueLimitRecipient = %s\n", 853 check->queue_match); 854 check = check->queue_next; 855 } 856 } 857 858 /* clear out old WorkQ */ 859 for (w = WorkQ; w != NULL; ) 860 { 861 register WORK *nw = w->w_next; 862 863 WorkQ = nw; 864 free(w->w_name); 865 if (w->w_host) 866 free(w->w_host); 867 free((char *) w); 868 w = nw; 869 } 870 871 /* open the queue directory */ 872 f = opendir("."); 873 if (f == NULL) 874 { 875 syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 876 return (0); 877 } 878 879 /* 880 ** Read the work directory. 881 */ 882 883 while ((d = readdir(f)) != NULL) 884 { 885 FILE *cf; 886 int qfver = 0; 887 char lbuf[MAXNAME + 1]; 888 extern bool strcontainedin __P((char *, char *)); 889 890 if (tTd(41, 50)) 891 printf("orderq: checking %s\n", d->d_name); 892 893 /* is this an interesting entry? */ 894 if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 895 continue; 896 897 if (strlen(d->d_name) > MAXQFNAME) 898 { 899 if (Verbose) 900 printf("orderq: %s too long, %d max characters\n", 901 d->d_name, MAXQFNAME); 902 if (LogLevel > 0) 903 sm_syslog(LOG_ALERT, NOQID, 904 "orderq: %s too long, %d max characters", 905 d->d_name, MAXQFNAME); 906 continue; 907 } 908 909 check = QueueLimitId; 910 while (check != NULL) 911 { 912 if (strcontainedin(check->queue_match, d->d_name)) 913 break; 914 else 915 check = check->queue_next; 916 } 917 if (QueueLimitId != NULL && check == NULL) 918 continue; 919 920#ifdef PICKY_QF_NAME_CHECK 921 /* 922 ** Check queue name for plausibility. This handles 923 ** both old and new type ids. 924 */ 925 926 p = d->d_name + 2; 927 if (isupper(p[0]) && isupper(p[2])) 928 p += 3; 929 else if (isupper(p[1])) 930 p += 2; 931 else 932 p = d->d_name; 933 for (i = 0; isdigit(*p); p++) 934 i++; 935 if (i < 5 || *p != '\0') 936 { 937 if (Verbose) 938 printf("orderq: bogus qf name %s\n", d->d_name); 939 if (LogLevel > 0) 940 sm_syslog(LOG_ALERT, NOQID, 941 "orderq: bogus qf name %s", 942 d->d_name); 943 if (strlen(d->d_name) > (SIZE_T) MAXNAME) 944 d->d_name[MAXNAME] = '\0'; 945 strcpy(lbuf, d->d_name); 946 lbuf[0] = 'Q'; 947 (void) rename(d->d_name, lbuf); 948 continue; 949 } 950#endif 951 952 /* open control file (if not too many files) */ 953 if (++wn >= MaxQueueRun && MaxQueueRun > 0) 954 { 955 if (wn == MaxQueueRun && LogLevel > 0) 956 sm_syslog(LOG_ALERT, NOQID, 957 "WorkList for %s maxed out at %d", 958 QueueDir, MaxQueueRun); 959 continue; 960 } 961 if (wn >= WorkListSize) 962 { 963 extern void grow_wlist __P((void)); 964 965 grow_wlist(); 966 if (wn >= WorkListSize) 967 continue; 968 } 969 970 cf = fopen(d->d_name, "r"); 971 if (cf == NULL) 972 { 973 /* this may be some random person sending hir msgs */ 974 /* syserr("orderq: cannot open %s", cbuf); */ 975 if (tTd(41, 2)) 976 printf("orderq: cannot open %s: %s\n", 977 d->d_name, errstring(errno)); 978 errno = 0; 979 wn--; 980 continue; 981 } 982 w = &WorkList[wn]; 983 w->w_name = newstr(d->d_name); 984 w->w_host = NULL; 985 w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB); 986 w->w_tooyoung = FALSE; 987 988 /* make sure jobs in creation don't clog queue */ 989 w->w_pri = 0x7fffffff; 990 w->w_ctime = 0; 991 992 /* extract useful information */ 993 i = NEED_P | NEED_T; 994 if (QueueLimitSender != NULL) 995 i |= NEED_S; 996 if (QueueSortOrder == QS_BYHOST || QueueLimitRecipient != NULL) 997 i |= NEED_R; 998 while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL) 999 { 1000 int c; 1001 time_t age; 1002 extern bool strcontainedin __P((char *, char *)); 1003 1004 p = strchr(lbuf, '\n'); 1005 if (p != NULL) 1006 *p = '\0'; 1007 else 1008 { 1009 /* flush rest of overly long line */ 1010 while ((c = getc(cf)) != EOF && c != '\n') 1011 continue; 1012 } 1013 1014 switch (lbuf[0]) 1015 { 1016 case 'V': 1017 qfver = atoi(&lbuf[1]); 1018 break; 1019 1020 case 'P': 1021 w->w_pri = atol(&lbuf[1]); 1022 i &= ~NEED_P; 1023 break; 1024 1025 case 'T': 1026 w->w_ctime = atol(&lbuf[1]); 1027 i &= ~NEED_T; 1028 break; 1029 1030 case 'R': 1031 if (w->w_host == NULL && 1032 (p = strrchr(&lbuf[1], '@')) != NULL) 1033 w->w_host = newstr(&p[1]); 1034 if (QueueLimitRecipient == NULL) 1035 { 1036 i &= ~NEED_R; 1037 break; 1038 } 1039 if (qfver > 0) 1040 { 1041 p = strchr(&lbuf[1], ':'); 1042 if (p == NULL) 1043 p = &lbuf[1]; 1044 } 1045 else 1046 p = &lbuf[1]; 1047 check = QueueLimitRecipient; 1048 while (check != NULL) 1049 { 1050 if (strcontainedin(check->queue_match, 1051 p)) 1052 break; 1053 else 1054 check = check->queue_next; 1055 } 1056 if (check != NULL) 1057 i &= ~NEED_R; 1058 break; 1059 1060 case 'S': 1061 check = QueueLimitSender; 1062 while (check != NULL) 1063 { 1064 if (strcontainedin(check->queue_match, 1065 &lbuf[1])) 1066 break; 1067 else 1068 check = check->queue_next; 1069 } 1070 if (check != NULL) 1071 i &= ~NEED_S; 1072 break; 1073 1074 case 'K': 1075 age = curtime() - (time_t) atol(&lbuf[1]); 1076 if (age >= 0 && MinQueueAge > 0 && 1077 age < MinQueueAge) 1078 w->w_tooyoung = TRUE; 1079 break; 1080 1081 case 'N': 1082 if (atol(&lbuf[1]) == 0) 1083 w->w_tooyoung = FALSE; 1084 break; 1085 } 1086 } 1087 (void) fclose(cf); 1088 1089 if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) || 1090 bitset(NEED_R|NEED_S, i)) 1091 { 1092 /* don't even bother sorting this job in */ 1093 if (tTd(41, 49)) 1094 printf("skipping %s (%x)\n", w->w_name, i); 1095 free(w->w_name); 1096 if (w->w_host) 1097 free(w->w_host); 1098 wn--; 1099 } 1100 } 1101 (void) closedir(f); 1102 wn++; 1103 1104 wc = min(wn, WorkListSize); 1105 if (wc > MaxQueueRun && MaxQueueRun > 0) 1106 wc = MaxQueueRun; 1107 1108 if (QueueSortOrder == QS_BYHOST) 1109 { 1110 extern int workcmpf1(); 1111 extern int workcmpf2(); 1112 1113 /* 1114 ** Sort the work directory for the first time, 1115 ** based on host name, lock status, and priority. 1116 */ 1117 1118 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1); 1119 1120 /* 1121 ** If one message to host is locked, "lock" all messages 1122 ** to that host. 1123 */ 1124 1125 i = 0; 1126 while (i < wc) 1127 { 1128 if (!WorkList[i].w_lock) 1129 { 1130 i++; 1131 continue; 1132 } 1133 w = &WorkList[i]; 1134 while (++i < wc) 1135 { 1136 extern int sm_strcasecmp __P((char *, char *)); 1137 1138 if (WorkList[i].w_host == NULL && 1139 w->w_host == NULL) 1140 WorkList[i].w_lock = TRUE; 1141 else if (WorkList[i].w_host != NULL && 1142 w->w_host != NULL && 1143 sm_strcasecmp(WorkList[i].w_host, w->w_host) == 0) 1144 WorkList[i].w_lock = TRUE; 1145 else 1146 break; 1147 } 1148 } 1149 1150 /* 1151 ** Sort the work directory for the second time, 1152 ** based on lock status, host name, and priority. 1153 */ 1154 1155 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2); 1156 } 1157 else if (QueueSortOrder == QS_BYTIME) 1158 { 1159 extern int workcmpf3(); 1160 1161 /* 1162 ** Simple sort based on submission time only. 1163 */ 1164 1165 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf3); 1166 } 1167 else 1168 { 1169 extern int workcmpf0(); 1170 1171 /* 1172 ** Simple sort based on queue priority only. 1173 */ 1174 1175 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0); 1176 } 1177 1178 /* 1179 ** Convert the work list into canonical form. 1180 ** Should be turning it into a list of envelopes here perhaps. 1181 */ 1182 1183 WorkQ = NULL; 1184 for (i = wc; --i >= 0; ) 1185 { 1186 w = (WORK *) xalloc(sizeof *w); 1187 w->w_name = WorkList[i].w_name; 1188 w->w_host = WorkList[i].w_host; 1189 w->w_lock = WorkList[i].w_lock; 1190 w->w_tooyoung = WorkList[i].w_tooyoung; 1191 w->w_pri = WorkList[i].w_pri; 1192 w->w_ctime = WorkList[i].w_ctime; 1193 w->w_next = WorkQ; 1194 WorkQ = w; 1195 } 1196 if (WorkList != NULL) 1197 free(WorkList); 1198 WorkList = NULL; 1199 WorkListSize = 0; 1200 1201 if (tTd(40, 1)) 1202 { 1203 for (w = WorkQ; w != NULL; w = w->w_next) 1204 printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 1205 } 1206 1207 return (wn); 1208} 1209/* 1210** GROW_WLIST -- make the work list larger 1211** 1212** Parameters: 1213** none. 1214** 1215** Returns: 1216** none. 1217** 1218** Side Effects: 1219** Adds another QUEUESEGSIZE entries to WorkList if possible. 1220** It can fail if there isn't enough memory, so WorkListSize 1221** should be checked again upon return. 1222*/ 1223 1224void 1225grow_wlist() 1226{ 1227 if (tTd(41, 1)) 1228 printf("grow_wlist: WorkListSize=%d\n", WorkListSize); 1229 if (WorkList == NULL) 1230 { 1231 WorkList = (WORK *) xalloc(sizeof(WORK) * (QUEUESEGSIZE + 1)); 1232 WorkListSize = QUEUESEGSIZE; 1233 } 1234 else 1235 { 1236 int newsize = WorkListSize + QUEUESEGSIZE; 1237 WORK *newlist = (WORK *) realloc((char *)WorkList, 1238 (unsigned)sizeof(WORK) * (newsize + 1)); 1239 1240 if (newlist != NULL) 1241 { 1242 WorkListSize = newsize; 1243 WorkList = newlist; 1244 if (LogLevel > 1) 1245 { 1246 sm_syslog(LOG_NOTICE, NOQID, 1247 "grew WorkList for %s to %d", 1248 QueueDir, WorkListSize); 1249 } 1250 } 1251 else if (LogLevel > 0) 1252 { 1253 sm_syslog(LOG_ALERT, NOQID, 1254 "FAILED to grow WorkList for %s to %d", 1255 QueueDir, newsize); 1256 } 1257 } 1258 if (tTd(41, 1)) 1259 printf("grow_wlist: WorkListSize now %d\n", WorkListSize); 1260} 1261/* 1262** WORKCMPF0 -- simple priority-only compare function. 1263** 1264** Parameters: 1265** a -- the first argument. 1266** b -- the second argument. 1267** 1268** Returns: 1269** -1 if a < b 1270** 0 if a == b 1271** +1 if a > b 1272** 1273** Side Effects: 1274** none. 1275*/ 1276 1277int 1278workcmpf0(a, b) 1279 register WORK *a; 1280 register WORK *b; 1281{ 1282 long pa = a->w_pri; 1283 long pb = b->w_pri; 1284 1285 if (pa == pb) 1286 return 0; 1287 else if (pa > pb) 1288 return 1; 1289 else 1290 return -1; 1291} 1292/* 1293** WORKCMPF1 -- first compare function for ordering work based on host name. 1294** 1295** Sorts on host name, lock status, and priority in that order. 1296** 1297** Parameters: 1298** a -- the first argument. 1299** b -- the second argument. 1300** 1301** Returns: 1302** <0 if a < b 1303** 0 if a == b 1304** >0 if a > b 1305** 1306** Side Effects: 1307** none. 1308*/ 1309 1310int 1311workcmpf1(a, b) 1312 register WORK *a; 1313 register WORK *b; 1314{ 1315 int i; 1316 extern int sm_strcasecmp __P((char *, char *)); 1317 1318 /* host name */ 1319 if (a->w_host != NULL && b->w_host == NULL) 1320 return 1; 1321 else if (a->w_host == NULL && b->w_host != NULL) 1322 return -1; 1323 if (a->w_host != NULL && b->w_host != NULL && 1324 (i = sm_strcasecmp(a->w_host, b->w_host)) != 0) 1325 return i; 1326 1327 /* lock status */ 1328 if (a->w_lock != b->w_lock) 1329 return b->w_lock - a->w_lock; 1330 1331 /* job priority */ 1332 return a->w_pri - b->w_pri; 1333} 1334/* 1335** WORKCMPF2 -- second compare function for ordering work based on host name. 1336** 1337** Sorts on lock status, host name, and priority in that order. 1338** 1339** Parameters: 1340** a -- the first argument. 1341** b -- the second argument. 1342** 1343** Returns: 1344** <0 if a < b 1345** 0 if a == b 1346** >0 if a > b 1347** 1348** Side Effects: 1349** none. 1350*/ 1351 1352int 1353workcmpf2(a, b) 1354 register WORK *a; 1355 register WORK *b; 1356{ 1357 int i; 1358 extern int sm_strcasecmp __P((char *, char *)); 1359 1360 /* lock status */ 1361 if (a->w_lock != b->w_lock) 1362 return a->w_lock - b->w_lock; 1363 1364 /* host name */ 1365 if (a->w_host != NULL && b->w_host == NULL) 1366 return 1; 1367 else if (a->w_host == NULL && b->w_host != NULL) 1368 return -1; 1369 if (a->w_host != NULL && b->w_host != NULL && 1370 (i = sm_strcasecmp(a->w_host, b->w_host)) != 0) 1371 return i; 1372 1373 /* job priority */ 1374 return a->w_pri - b->w_pri; 1375} 1376/* 1377** WORKCMPF3 -- simple submission-time-only compare function. 1378** 1379** Parameters: 1380** a -- the first argument. 1381** b -- the second argument. 1382** 1383** Returns: 1384** -1 if a < b 1385** 0 if a == b 1386** +1 if a > b 1387** 1388** Side Effects: 1389** none. 1390*/ 1391 1392int 1393workcmpf3(a, b) 1394 register WORK *a; 1395 register WORK *b; 1396{ 1397 if (a->w_ctime > b->w_ctime) 1398 return 1; 1399 else if (a->w_ctime < b->w_ctime) 1400 return -1; 1401 else 1402 return 0; 1403} 1404/* 1405** DOWORK -- do a work request. 1406** 1407** Parameters: 1408** id -- the ID of the job to run. 1409** forkflag -- if set, run this in background. 1410** requeueflag -- if set, reinstantiate the queue quickly. 1411** This is used when expanding aliases in the queue. 1412** If forkflag is also set, it doesn't wait for the 1413** child. 1414** e - the envelope in which to run it. 1415** 1416** Returns: 1417** process id of process that is running the queue job. 1418** 1419** Side Effects: 1420** The work request is satisfied if possible. 1421*/ 1422 1423pid_t 1424dowork(id, forkflag, requeueflag, e) 1425 char *id; 1426 bool forkflag; 1427 bool requeueflag; 1428 register ENVELOPE *e; 1429{ 1430 register pid_t pid; 1431 extern bool readqf __P((ENVELOPE *)); 1432 1433 if (tTd(40, 1)) 1434 printf("dowork(%s)\n", id); 1435 1436 /* 1437 ** Fork for work. 1438 */ 1439 1440 if (forkflag) 1441 { 1442 pid = fork(); 1443 if (pid < 0) 1444 { 1445 syserr("dowork: cannot fork"); 1446 return 0; 1447 } 1448 else if (pid > 0) 1449 { 1450 /* parent -- clean out connection cache */ 1451 mci_flush(FALSE, NULL); 1452 } 1453 else 1454 { 1455 /* child -- error messages to the transcript */ 1456 QuickAbort = OnlyOneError = FALSE; 1457 1458 /* 1459 ** Since the delivery may happen in a child and the 1460 ** parent does not wait, the parent may close the 1461 ** maps thereby removing any shared memory used by 1462 ** the map. Therefore, open a copy of the maps for 1463 ** the delivery process. 1464 */ 1465 1466 initmaps(FALSE, e); 1467 } 1468 } 1469 else 1470 { 1471 pid = 0; 1472 } 1473 1474 if (pid == 0) 1475 { 1476 /* 1477 ** CHILD 1478 ** Lock the control file to avoid duplicate deliveries. 1479 ** Then run the file as though we had just read it. 1480 ** We save an idea of the temporary name so we 1481 ** can recover on interrupt. 1482 */ 1483 1484 /* set basic modes, etc. */ 1485 (void) alarm(0); 1486 clearenvelope(e, FALSE); 1487 e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS; 1488 e->e_sendmode = SM_DELIVER; 1489 e->e_errormode = EM_MAIL; 1490 e->e_id = id; 1491 GrabTo = UseErrorsTo = FALSE; 1492 ExitStat = EX_OK; 1493 if (forkflag) 1494 { 1495 disconnect(1, e); 1496 OpMode = MD_DELIVER; 1497 } 1498 sm_setproctitle(TRUE, "%s: from queue", id); 1499 if (LogLevel > 76) 1500 sm_syslog(LOG_DEBUG, e->e_id, 1501 "dowork, pid=%d", 1502 getpid()); 1503 1504 /* don't use the headers from sendmail.cf... */ 1505 e->e_header = NULL; 1506 1507 /* read the queue control file -- return if locked */ 1508 if (!readqf(e)) 1509 { 1510 if (tTd(40, 4) && e->e_id != NULL) 1511 printf("readqf(%s) failed\n", e->e_id); 1512 e->e_id = NULL; 1513 if (forkflag) 1514 finis(FALSE, EX_OK); 1515 else 1516 return 0; 1517 } 1518 1519 e->e_flags |= EF_INQUEUE; 1520 eatheader(e, requeueflag); 1521 1522 if (requeueflag) 1523 queueup(e, FALSE); 1524 1525 /* do the delivery */ 1526 sendall(e, SM_DELIVER); 1527 1528 /* finish up and exit */ 1529 if (forkflag) 1530 finis(TRUE, ExitStat); 1531 else 1532 dropenvelope(e, TRUE); 1533 } 1534 e->e_id = NULL; 1535 return pid; 1536} 1537/* 1538** READQF -- read queue file and set up environment. 1539** 1540** Parameters: 1541** e -- the envelope of the job to run. 1542** 1543** Returns: 1544** TRUE if it successfully read the queue file. 1545** FALSE otherwise. 1546** 1547** Side Effects: 1548** The queue file is returned locked. 1549*/ 1550 1551bool 1552readqf(e) 1553 register ENVELOPE *e; 1554{ 1555 register FILE *qfp; 1556 ADDRESS *ctladdr; 1557 struct stat st; 1558 char *bp; 1559 int qfver = 0; 1560 long hdrsize = 0; 1561 register char *p; 1562 char *orcpt = NULL; 1563 bool nomore = FALSE; 1564 char qf[MAXQFNAME]; 1565 char buf[MAXLINE]; 1566 extern ADDRESS *setctluser __P((char *, int)); 1567 1568 /* 1569 ** Read and process the file. 1570 */ 1571 1572 strcpy(qf, queuename(e, 'q')); 1573 qfp = fopen(qf, "r+"); 1574 if (qfp == NULL) 1575 { 1576 if (tTd(40, 8)) 1577 printf("readqf(%s): fopen failure (%s)\n", 1578 qf, errstring(errno)); 1579 if (errno != ENOENT) 1580 syserr("readqf: no control file %s", qf); 1581 return FALSE; 1582 } 1583 1584 if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB)) 1585 { 1586 /* being processed by another queuer */ 1587 if (Verbose || tTd(40, 8)) 1588 printf("%s: locked\n", e->e_id); 1589 if (LogLevel > 19) 1590 sm_syslog(LOG_DEBUG, e->e_id, "locked"); 1591 (void) fclose(qfp); 1592 return FALSE; 1593 } 1594 1595 /* 1596 ** Check the queue file for plausibility to avoid attacks. 1597 */ 1598 1599 if (fstat(fileno(qfp), &st) < 0) 1600 { 1601 /* must have been being processed by someone else */ 1602 if (tTd(40, 8)) 1603 printf("readqf(%s): fstat failure (%s)\n", 1604 qf, errstring(errno)); 1605 fclose(qfp); 1606 return FALSE; 1607 } 1608 1609 if ((st.st_uid != geteuid() && geteuid() != RealUid) || 1610 bitset(S_IWOTH|S_IWGRP, st.st_mode)) 1611 { 1612 if (LogLevel > 0) 1613 { 1614 sm_syslog(LOG_ALERT, e->e_id, 1615 "bogus queue file, uid=%d, mode=%o", 1616 st.st_uid, st.st_mode); 1617 } 1618 if (tTd(40, 8)) 1619 printf("readqf(%s): bogus file\n", qf); 1620 loseqfile(e, "bogus file uid in mqueue"); 1621 fclose(qfp); 1622 return FALSE; 1623 } 1624 1625 if (st.st_size == 0) 1626 { 1627 /* must be a bogus file -- if also old, just remove it */ 1628 if (st.st_ctime + 10 * 60 < curtime()) 1629 { 1630 qf[0] = 'd'; 1631 (void) unlink(qf); 1632 qf[0] = 'q'; 1633 (void) unlink(qf); 1634 } 1635 fclose(qfp); 1636 return FALSE; 1637 } 1638 1639 if (st.st_nlink == 0) 1640 { 1641 /* 1642 ** Race condition -- we got a file just as it was being 1643 ** unlinked. Just assume it is zero length. 1644 */ 1645 1646 fclose(qfp); 1647 return FALSE; 1648 } 1649 1650 /* good file -- save this lock */ 1651 e->e_lockfp = qfp; 1652 1653 /* do basic system initialization */ 1654 initsys(e); 1655 define('i', e->e_id, e); 1656 1657 LineNumber = 0; 1658 e->e_flags |= EF_GLOBALERRS; 1659 OpMode = MD_DELIVER; 1660 ctladdr = NULL; 1661 e->e_dfino = -1; 1662 e->e_msgsize = -1; 1663 while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL) 1664 { 1665 register char *p; 1666 u_long qflags; 1667 ADDRESS *q; 1668 int mid; 1669 auto char *ep; 1670 1671 if (tTd(40, 4)) 1672 printf("+++++ %s\n", bp); 1673 if (nomore) 1674 { 1675 /* hack attack */ 1676 syserr("SECURITY ALERT: extra data in qf: %s", bp); 1677 fclose(qfp); 1678 loseqfile(e, "bogus queue line"); 1679 return FALSE; 1680 } 1681 switch (bp[0]) 1682 { 1683 case 'V': /* queue file version number */ 1684 qfver = atoi(&bp[1]); 1685 if (qfver <= QF_VERSION) 1686 break; 1687 syserr("Version number in qf (%d) greater than max (%d)", 1688 qfver, QF_VERSION); 1689 fclose(qfp); 1690 loseqfile(e, "unsupported qf file version"); 1691 return FALSE; 1692 1693 case 'C': /* specify controlling user */ 1694 ctladdr = setctluser(&bp[1], qfver); 1695 break; 1696 1697 case 'Q': /* original recipient */ 1698 orcpt = newstr(&bp[1]); 1699 break; 1700 1701 case 'R': /* specify recipient */ 1702 p = bp; 1703 qflags = 0; 1704 if (qfver >= 1) 1705 { 1706 /* get flag bits */ 1707 while (*++p != '\0' && *p != ':') 1708 { 1709 switch (*p) 1710 { 1711 case 'N': 1712 qflags |= QHASNOTIFY; 1713 break; 1714 1715 case 'S': 1716 qflags |= QPINGONSUCCESS; 1717 break; 1718 1719 case 'F': 1720 qflags |= QPINGONFAILURE; 1721 break; 1722 1723 case 'D': 1724 qflags |= QPINGONDELAY; 1725 break; 1726 1727 case 'P': 1728 qflags |= QPRIMARY; 1729 break; 1730 } 1731 } 1732 } 1733 else 1734 qflags |= QPRIMARY; 1735 q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e); 1736 if (q != NULL) 1737 { 1738 q->q_alias = ctladdr; 1739 if (qfver >= 1) 1740 q->q_flags &= ~Q_PINGFLAGS; 1741 q->q_flags |= qflags; 1742 q->q_orcpt = orcpt; 1743 (void) recipient(q, &e->e_sendqueue, 0, e); 1744 } 1745 orcpt = NULL; 1746 break; 1747 1748 case 'E': /* specify error recipient */ 1749 /* no longer used */ 1750 break; 1751 1752 case 'H': /* header */ 1753 (void) chompheader(&bp[1], FALSE, NULL, e); 1754 hdrsize += strlen(&bp[1]); 1755 break; 1756 1757 case 'L': /* Solaris Content-Length: */ 1758 case 'M': /* message */ 1759 /* ignore this; we want a new message next time */ 1760 break; 1761 1762 case 'S': /* sender */ 1763 setsender(newstr(&bp[1]), e, NULL, '\0', TRUE); 1764 break; 1765 1766 case 'B': /* body type */ 1767 e->e_bodytype = newstr(&bp[1]); 1768 break; 1769 1770#if _FFR_SAVE_CHARSET 1771 case 'X': /* character set */ 1772 e->e_charset = newstr(&bp[1]); 1773 break; 1774#endif 1775 1776 case 'D': /* data file name */ 1777 /* obsolete -- ignore */ 1778 break; 1779 1780 case 'T': /* init time */ 1781 e->e_ctime = atol(&bp[1]); 1782 break; 1783 1784 case 'I': /* data file's inode number */ 1785 /* regenerated below */ 1786 break; 1787 1788 case 'K': /* time of last deliver attempt */ 1789 e->e_dtime = atol(&buf[1]); 1790 break; 1791 1792 case 'N': /* number of delivery attempts */ 1793 e->e_ntries = atoi(&buf[1]); 1794 1795 /* if this has been tried recently, let it be */ 1796 if (e->e_ntries > 0 && 1797 MinQueueAge > 0 && e->e_dtime <= curtime() && 1798 curtime() < e->e_dtime + MinQueueAge) 1799 { 1800 char *howlong = pintvl(curtime() - e->e_dtime, TRUE); 1801 1802 if (Verbose || tTd(40, 8)) 1803 printf("%s: too young (%s)\n", 1804 e->e_id, howlong); 1805 if (LogLevel > 19) 1806 sm_syslog(LOG_DEBUG, e->e_id, 1807 "too young (%s)", 1808 howlong); 1809 e->e_id = NULL; 1810 unlockqueue(e); 1811 return FALSE; 1812 } 1813 break; 1814 1815 case 'P': /* message priority */ 1816 e->e_msgpriority = atol(&bp[1]) + WkTimeFact; 1817 break; 1818 1819 case 'F': /* flag bits */ 1820 if (strncmp(bp, "From ", 5) == 0) 1821 { 1822 /* we are being spoofed! */ 1823 syserr("SECURITY ALERT: bogus qf line %s", bp); 1824 fclose(qfp); 1825 loseqfile(e, "bogus queue line"); 1826 return FALSE; 1827 } 1828 for (p = &bp[1]; *p != '\0'; p++) 1829 { 1830 switch (*p) 1831 { 1832 case 'w': /* warning sent */ 1833 e->e_flags |= EF_WARNING; 1834 break; 1835 1836 case 'r': /* response */ 1837 e->e_flags |= EF_RESPONSE; 1838 break; 1839 1840 case '8': /* has 8 bit data */ 1841 e->e_flags |= EF_HAS8BIT; 1842 break; 1843 1844 case 'b': /* delete Bcc: header */ 1845 e->e_flags |= EF_DELETE_BCC; 1846 break; 1847 1848 case 'd': /* envelope has DSN RET= */ 1849 e->e_flags |= EF_RET_PARAM; 1850 break; 1851 1852 case 'n': /* don't return body */ 1853 e->e_flags |= EF_NO_BODY_RETN; 1854 break; 1855 } 1856 } 1857 break; 1858 1859 case 'Z': /* original envelope id from ESMTP */ 1860 e->e_envid = newstr(&bp[1]); 1861 break; 1862 1863 case '$': /* define macro */ 1864 mid = macid(&bp[1], &ep); 1865 define(mid, newstr(ep), e); 1866 break; 1867 1868 case '.': /* terminate file */ 1869 nomore = TRUE; 1870 break; 1871 1872 default: 1873 syserr("readqf: %s: line %d: bad line \"%s\"", 1874 qf, LineNumber, shortenstring(bp, MAXSHORTSTR)); 1875 fclose(qfp); 1876 loseqfile(e, "unrecognized line"); 1877 return FALSE; 1878 } 1879 1880 if (bp != buf) 1881 free(bp); 1882 } 1883 1884 /* 1885 ** If we haven't read any lines, this queue file is empty. 1886 ** Arrange to remove it without referencing any null pointers. 1887 */ 1888 1889 if (LineNumber == 0) 1890 { 1891 errno = 0; 1892 e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE; 1893 return TRUE; 1894 } 1895 1896 /* 1897 ** Arrange to read the data file. 1898 */ 1899 1900 p = queuename(e, 'd'); 1901 e->e_dfp = fopen(p, "r"); 1902 if (e->e_dfp == NULL) 1903 { 1904 syserr("readqf: cannot open %s", p); 1905 } 1906 else 1907 { 1908 e->e_flags |= EF_HAS_DF; 1909 if (fstat(fileno(e->e_dfp), &st) >= 0) 1910 { 1911 e->e_msgsize = st.st_size + hdrsize; 1912 e->e_dfdev = st.st_dev; 1913 e->e_dfino = st.st_ino; 1914 } 1915 } 1916 1917 return TRUE; 1918} 1919/* 1920** PRINTQUEUE -- print out a representation of the mail queue 1921** 1922** Parameters: 1923** none. 1924** 1925** Returns: 1926** none. 1927** 1928** Side Effects: 1929** Prints a listing of the mail queue on the standard output. 1930*/ 1931 1932void 1933printqueue() 1934{ 1935 register WORK *w; 1936 FILE *f; 1937 int nrequests; 1938 char buf[MAXLINE]; 1939 1940 /* 1941 ** Check for permission to print the queue 1942 */ 1943 1944 if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0) 1945 { 1946 struct stat st; 1947# ifdef NGROUPS_MAX 1948 int n; 1949 extern GIDSET_T InitialGidSet[NGROUPS_MAX]; 1950# endif 1951 1952 if (stat(QueueDir, &st) < 0) 1953 { 1954 syserr("Cannot stat %s", QueueDir); 1955 return; 1956 } 1957# ifdef NGROUPS_MAX 1958 n = NGROUPS_MAX; 1959 while (--n >= 0) 1960 { 1961 if (InitialGidSet[n] == st.st_gid) 1962 break; 1963 } 1964 if (n < 0 && RealGid != st.st_gid) 1965# else 1966 if (RealGid != st.st_gid) 1967# endif 1968 { 1969 usrerr("510 You are not permitted to see the queue"); 1970 setstat(EX_NOPERM); 1971 return; 1972 } 1973 } 1974 1975 /* 1976 ** Read and order the queue. 1977 */ 1978 1979 nrequests = orderq(TRUE); 1980 1981 /* 1982 ** Print the work list that we have read. 1983 */ 1984 1985 /* first see if there is anything */ 1986 if (nrequests <= 0) 1987 { 1988 printf("Mail queue is empty\n"); 1989 return; 1990 } 1991 1992 CurrentLA = getla(); /* get load average */ 1993 1994 printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); 1995 if (MaxQueueRun > 0 && nrequests > MaxQueueRun) 1996 printf(", only %d printed", MaxQueueRun); 1997 if (Verbose) 1998 printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n"); 1999 else 2000 printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 2001 for (w = WorkQ; w != NULL; w = w->w_next) 2002 { 2003 struct stat st; 2004 auto time_t submittime = 0; 2005 long dfsize; 2006 int flags = 0; 2007 int qfver; 2008 char statmsg[MAXLINE]; 2009 char bodytype[MAXNAME + 1]; 2010 2011 printf("%8s", w->w_name + 2); 2012 f = fopen(w->w_name, "r"); 2013 if (f == NULL) 2014 { 2015 printf(" (job completed)\n"); 2016 errno = 0; 2017 continue; 2018 } 2019 w->w_name[0] = 'd'; 2020 if (stat(w->w_name, &st) >= 0) 2021 dfsize = st.st_size; 2022 else 2023 dfsize = -1; 2024 if (w->w_lock) 2025 printf("*"); 2026 else if (w->w_tooyoung) 2027 printf("-"); 2028 else if (shouldqueue(w->w_pri, w->w_ctime)) 2029 printf("X"); 2030 else 2031 printf(" "); 2032 errno = 0; 2033 2034 statmsg[0] = bodytype[0] = '\0'; 2035 qfver = 0; 2036 while (fgets(buf, sizeof buf, f) != NULL) 2037 { 2038 register int i; 2039 register char *p; 2040 2041 fixcrlf(buf, TRUE); 2042 switch (buf[0]) 2043 { 2044 case 'V': /* queue file version */ 2045 qfver = atoi(&buf[1]); 2046 break; 2047 2048 case 'M': /* error message */ 2049 if ((i = strlen(&buf[1])) >= sizeof statmsg) 2050 i = sizeof statmsg - 1; 2051 bcopy(&buf[1], statmsg, i); 2052 statmsg[i] = '\0'; 2053 break; 2054 2055 case 'B': /* body type */ 2056 if ((i = strlen(&buf[1])) >= sizeof bodytype) 2057 i = sizeof bodytype - 1; 2058 bcopy(&buf[1], bodytype, i); 2059 bodytype[i] = '\0'; 2060 break; 2061 2062 case 'S': /* sender name */ 2063 if (Verbose) 2064 printf("%8ld %10ld%c%.12s %.78s", 2065 dfsize, 2066 w->w_pri, 2067 bitset(EF_WARNING, flags) ? '+' : ' ', 2068 ctime(&submittime) + 4, 2069 &buf[1]); 2070 else 2071 printf("%8ld %.16s %.45s", dfsize, 2072 ctime(&submittime), &buf[1]); 2073 if (statmsg[0] != '\0' || bodytype[0] != '\0') 2074 { 2075 printf("\n %10.10s", bodytype); 2076 if (statmsg[0] != '\0') 2077 printf(" (%.*s)", 2078 Verbose ? 100 : 60, 2079 statmsg); 2080 } 2081 break; 2082 2083 case 'C': /* controlling user */ 2084 if (Verbose) 2085 printf("\n\t\t\t\t (---%.74s---)", 2086 &buf[1]); 2087 break; 2088 2089 case 'R': /* recipient name */ 2090 p = &buf[1]; 2091 if (qfver >= 1) 2092 { 2093 p = strchr(p, ':'); 2094 if (p == NULL) 2095 break; 2096 p++; 2097 } 2098 if (Verbose) 2099 printf("\n\t\t\t\t\t %.78s", p); 2100 else 2101 printf("\n\t\t\t\t %.45s", p); 2102 break; 2103 2104 case 'T': /* creation time */ 2105 submittime = atol(&buf[1]); 2106 break; 2107 2108 case 'F': /* flag bits */ 2109 for (p = &buf[1]; *p != '\0'; p++) 2110 { 2111 switch (*p) 2112 { 2113 case 'w': 2114 flags |= EF_WARNING; 2115 break; 2116 } 2117 } 2118 } 2119 } 2120 if (submittime == (time_t) 0) 2121 printf(" (no control file)"); 2122 printf("\n"); 2123 (void) fclose(f); 2124 } 2125} 2126 2127# endif /* QUEUE */ 2128/* 2129** QUEUENAME -- build a file name in the queue directory for this envelope. 2130** 2131** Assigns an id code if one does not already exist. 2132** This code is very careful to avoid trashing existing files 2133** under any circumstances. 2134** 2135** Parameters: 2136** e -- envelope to build it in/from. 2137** type -- the file type, used as the first character 2138** of the file name. 2139** 2140** Returns: 2141** a pointer to the new file name (in a static buffer). 2142** 2143** Side Effects: 2144** If no id code is already assigned, queuename will 2145** assign an id code, create a qf file, and leave a 2146** locked, open-for-write file pointer in the envelope. 2147*/ 2148 2149#ifndef ENOLCK 2150# define ENOLCK -1 2151#endif 2152#ifndef ENOSPC 2153# define ENOSPC -1 2154#endif 2155 2156char * 2157queuename(e, type) 2158 register ENVELOPE *e; 2159 int type; 2160{ 2161 static pid_t pid = -1; 2162 static char c0; 2163 static char c1; 2164 static char c2; 2165 time_t now; 2166 struct tm *tm; 2167 static char buf[MAXNAME + 1]; 2168 2169 if (e->e_id == NULL) 2170 { 2171 char qf[MAXQFNAME]; 2172 2173 /* find a unique id */ 2174 if (pid != getpid()) 2175 { 2176 /* new process -- start back at "AA" */ 2177 pid = getpid(); 2178 now = curtime(); 2179 tm = localtime(&now); 2180 c0 = 'A' + tm->tm_hour; 2181 c1 = 'A'; 2182 c2 = 'A' - 1; 2183 } 2184 (void) snprintf(qf, sizeof qf, "qf%cAA%05d", c0, pid); 2185 2186 while (c1 < '~' || c2 < 'Z') 2187 { 2188 int i; 2189 int attempts = 0; 2190 2191 if (c2 >= 'Z') 2192 { 2193 c1++; 2194 c2 = 'A' - 1; 2195 } 2196 qf[3] = c1; 2197 qf[4] = ++c2; 2198 if (tTd(7, 20)) 2199 printf("queuename: trying \"%s\"\n", qf); 2200 2201 i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode); 2202 if (i < 0) 2203 { 2204 if (errno == EEXIST) 2205 continue; 2206 syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)", 2207 qf, QueueDir, geteuid()); 2208 finis(FALSE, EX_UNAVAILABLE); 2209 } 2210 do 2211 { 2212 if (attempts > 0) 2213 sleep(attempts); 2214 e->e_lockfp = 0; 2215 if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB)) 2216 { 2217 e->e_lockfp = fdopen(i, "w"); 2218 break; 2219 } 2220 } while ((errno == ENOLCK || errno == ENOSPC) && 2221 attempts++ < 4); 2222 2223 /* Successful lock */ 2224 if (e->e_lockfp != 0) 2225 break; 2226 2227#if !HASFLOCK 2228 if (errno != EAGAIN && errno != EACCES) 2229#else 2230 if (errno != EWOULDBLOCK) 2231#endif 2232 { 2233 syserr("queuename: Cannot lock \"%s\" in \"%s\" (euid=%d)", 2234 qf, QueueDir, geteuid()); 2235 finis(FALSE, EX_OSERR); 2236 } 2237 2238 /* a reader got the file; abandon it and try again */ 2239 (void) close(i); 2240 } 2241 if (c1 >= '~' && c2 >= 'Z') 2242 { 2243 syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)", 2244 qf, QueueDir, geteuid()); 2245 finis(FALSE, EX_OSERR); 2246 } 2247 e->e_id = newstr(&qf[2]); 2248 define('i', e->e_id, e); 2249 if (tTd(7, 1)) 2250 printf("queuename: assigned id %s, env=%lx\n", 2251 e->e_id, (u_long) e); 2252 if (tTd(7, 9)) 2253 { 2254 printf(" lockfd="); 2255 dumpfd(fileno(e->e_lockfp), TRUE, FALSE); 2256 } 2257 if (LogLevel > 93) 2258 sm_syslog(LOG_DEBUG, e->e_id, "assigned id"); 2259 } 2260 2261 if (type == '\0') 2262 return (NULL); 2263 (void) snprintf(buf, sizeof buf, "%cf%s", type, e->e_id); 2264 if (tTd(7, 2)) 2265 printf("queuename: %s\n", buf); 2266 return (buf); 2267} 2268/* 2269** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 2270** 2271** Parameters: 2272** e -- the envelope to unlock. 2273** 2274** Returns: 2275** none 2276** 2277** Side Effects: 2278** unlocks the queue for `e'. 2279*/ 2280 2281void 2282unlockqueue(e) 2283 ENVELOPE *e; 2284{ 2285 if (tTd(51, 4)) 2286 printf("unlockqueue(%s)\n", 2287 e->e_id == NULL ? "NOQUEUE" : e->e_id); 2288 2289 /* if there is a lock file in the envelope, close it */ 2290 if (e->e_lockfp != NULL) 2291 xfclose(e->e_lockfp, "unlockqueue", e->e_id); 2292 e->e_lockfp = NULL; 2293 2294 /* don't create a queue id if we don't already have one */ 2295 if (e->e_id == NULL) 2296 return; 2297 2298 /* remove the transcript */ 2299 if (LogLevel > 87) 2300 sm_syslog(LOG_DEBUG, e->e_id, "unlock"); 2301 if (!tTd(51, 104)) 2302 xunlink(queuename(e, 'x')); 2303 2304} 2305/* 2306** SETCTLUSER -- create a controlling address 2307** 2308** Create a fake "address" given only a local login name; this is 2309** used as a "controlling user" for future recipient addresses. 2310** 2311** Parameters: 2312** user -- the user name of the controlling user. 2313** qfver -- the version stamp of this qf file. 2314** 2315** Returns: 2316** An address descriptor for the controlling user. 2317** 2318** Side Effects: 2319** none. 2320*/ 2321 2322ADDRESS * 2323setctluser(user, qfver) 2324 char *user; 2325 int qfver; 2326{ 2327 register ADDRESS *a; 2328 struct passwd *pw; 2329 char *p; 2330 2331 /* 2332 ** See if this clears our concept of controlling user. 2333 */ 2334 2335 if (user == NULL || *user == '\0') 2336 return NULL; 2337 2338 /* 2339 ** Set up addr fields for controlling user. 2340 */ 2341 2342 a = (ADDRESS *) xalloc(sizeof *a); 2343 bzero((char *) a, sizeof *a); 2344 2345 if (*user == '\0') 2346 { 2347 p = NULL; 2348 a->q_user = newstr(DefUser); 2349 } 2350 else if (*user == ':') 2351 { 2352 p = &user[1]; 2353 a->q_user = newstr(p); 2354 } 2355 else 2356 { 2357 p = strtok(user, ":"); 2358 a->q_user = newstr(user); 2359 if (qfver >= 2) 2360 { 2361 if ((p = strtok(NULL, ":")) != NULL) 2362 a->q_uid = atoi(p); 2363 if ((p = strtok(NULL, ":")) != NULL) 2364 a->q_gid = atoi(p); 2365 if ((p = strtok(NULL, ":")) != NULL) 2366 a->q_flags |= QGOODUID; 2367 } 2368 else if ((pw = sm_getpwnam(user)) != NULL) 2369 { 2370 if (strcmp(pw->pw_dir, "/") == 0) 2371 a->q_home = ""; 2372 else 2373 a->q_home = newstr(pw->pw_dir); 2374 a->q_uid = pw->pw_uid; 2375 a->q_gid = pw->pw_gid; 2376 a->q_flags |= QGOODUID; 2377 } 2378 } 2379 2380 a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */ 2381 a->q_mailer = LocalMailer; 2382 if (p == NULL) 2383 a->q_paddr = a->q_user; 2384 else 2385 a->q_paddr = newstr(p); 2386 return a; 2387} 2388/* 2389** LOSEQFILE -- save the qf as Qf and try to let someone know 2390** 2391** Parameters: 2392** e -- the envelope (e->e_id will be used). 2393** why -- reported to whomever can hear. 2394** 2395** Returns: 2396** none. 2397*/ 2398 2399void 2400loseqfile(e, why) 2401 register ENVELOPE *e; 2402 char *why; 2403{ 2404 char *p; 2405 char buf[MAXQFNAME + 1]; 2406 2407 if (e == NULL || e->e_id == NULL) 2408 return; 2409 p = queuename(e, 'q'); 2410 if (strlen(p) > MAXQFNAME) 2411 { 2412 syserr("loseqfile: queuename (%s) too long", p); 2413 return; 2414 } 2415 strcpy(buf, p); 2416 p = queuename(e, 'Q'); 2417 if (rename(buf, p) < 0) 2418 syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid()); 2419 else if (LogLevel > 0) 2420 sm_syslog(LOG_ALERT, e->e_id, 2421 "Losing %s: %s", buf, why); 2422} 2423