1: /* 2: * Copyright (c) 1988 Regents of the University of California. 3: * All rights reserved. 4: * 5: * Redistribution and use in source and binary forms are permitted 6: * provided that this notice is preserved and that due credit is given 7: * to the University of California at Berkeley. The name of the University 8: * may not be used to endorse or promote products derived from this 9: * software without specific prior written permission. This software 10: * is provided ``as is'' without express or implied warranty. 11: * 12: * Sendmail 13: * Copyright (c) 1983 Eric P. Allman 14: * Berkeley, California 15: */ 16: 17: # include "sendmail.h" 18: 19: #if !defined(lint) && !defined(NOSCCS) 20: #ifdef QUEUE 21: static char sccsid[] = "@(#)queue.c 5.23 (Berkeley) 3/13/88 (with queueing)"; 22: #else 23: static char sccsid[] = "@(#)queue.c 5.23 (Berkeley) 3/13/88 (without queueing)"; 24: #endif 25: #endif /* not lint */ 26: 27: # include <sys/stat.h> 28: # include <sys/dir.h> 29: # include <signal.h> 30: # include <errno.h> 31: 32: # ifdef QUEUE 33: 34: /* 35: ** Work queue. 36: */ 37: 38: struct work 39: { 40: char *w_name; /* name of control file */ 41: long w_pri; /* priority of message, see below */ 42: time_t w_ctime; /* creation time of message */ 43: struct work *w_next; /* next in queue */ 44: }; 45: 46: typedef struct work WORK; 47: 48: WORK *WorkQ; /* queue of things to be done */ 49: /* 50: ** QUEUEUP -- queue a message up for future transmission. 51: ** 52: ** Parameters: 53: ** e -- the envelope to queue up. 54: ** queueall -- if TRUE, queue all addresses, rather than 55: ** just those with the QQUEUEUP flag set. 56: ** announce -- if TRUE, tell when you are queueing up. 57: ** 58: ** Returns: 59: ** none. 60: ** 61: ** Side Effects: 62: ** The current request are saved in a control file. 63: */ 64: 65: queueup(e, queueall, announce) 66: register ENVELOPE *e; 67: bool queueall; 68: bool announce; 69: { 70: char *tf; 71: char *qf; 72: char buf[MAXLINE]; 73: register FILE *tfp; 74: register HDR *h; 75: register ADDRESS *q; 76: MAILER nullmailer; 77: 78: /* 79: ** Create control file. 80: */ 81: 82: tf = newstr(queuename(e, 't')); 83: tfp = fopen(tf, "w"); 84: if (tfp == NULL) 85: { 86: syserr("queueup: cannot create temp file %s", tf); 87: return; 88: } 89: (void) chmod(tf, FileMode); 90: 91: # ifdef DEBUG 92: if (tTd(40, 1)) 93: printf("queueing %s\n", e->e_id); 94: # endif DEBUG 95: 96: /* 97: ** If there is no data file yet, create one. 98: */ 99: 100: if (e->e_df == NULL) 101: { 102: register FILE *dfp; 103: extern putbody(); 104: 105: e->e_df = newstr(queuename(e, 'd')); 106: dfp = fopen(e->e_df, "w"); 107: if (dfp == NULL) 108: { 109: syserr("queueup: cannot create %s", e->e_df); 110: (void) fclose(tfp); 111: return; 112: } 113: (void) chmod(e->e_df, FileMode); 114: (*e->e_putbody)(dfp, ProgMailer, e); 115: (void) fclose(dfp); 116: e->e_putbody = putbody; 117: } 118: 119: /* 120: ** Output future work requests. 121: ** Priority and creation time should be first, since 122: ** they are required by orderq. 123: */ 124: 125: /* output message priority */ 126: fprintf(tfp, "P%ld\n", e->e_msgpriority); 127: 128: /* output creation time */ 129: fprintf(tfp, "T%ld\n", e->e_ctime); 130: 131: /* output name of data file */ 132: fprintf(tfp, "D%s\n", e->e_df); 133: 134: /* message from envelope, if it exists */ 135: if (e->e_message != NULL) 136: fprintf(tfp, "M%s\n", e->e_message); 137: 138: /* output name of sender */ 139: fprintf(tfp, "S%s\n", e->e_from.q_paddr); 140: 141: /* output list of recipient addresses */ 142: for (q = e->e_sendqueue; q != NULL; q = q->q_next) 143: { 144: if (queueall ? !bitset(QDONTSEND, q->q_flags) : 145: bitset(QQUEUEUP, q->q_flags)) 146: { 147: fprintf(tfp, "R%s\n", q->q_paddr); 148: if (announce) 149: { 150: e->e_to = q->q_paddr; 151: message(Arpa_Info, "queued"); 152: if (LogLevel > 4) 153: logdelivery("queued"); 154: e->e_to = NULL; 155: } 156: #ifdef DEBUG 157: if (tTd(40, 1)) 158: { 159: printf("queueing "); 160: printaddr(q, FALSE); 161: } 162: #endif DEBUG 163: } 164: } 165: 166: /* output list of error recipients */ 167: for (q = e->e_errorqueue; q != NULL; q = q->q_next) 168: { 169: if (!bitset(QDONTSEND, q->q_flags)) 170: fprintf(tfp, "E%s\n", q->q_paddr); 171: } 172: 173: /* 174: ** Output headers for this message. 175: ** Expand macros completely here. Queue run will deal with 176: ** everything as absolute headers. 177: ** All headers that must be relative to the recipient 178: ** can be cracked later. 179: ** We set up a "null mailer" -- i.e., a mailer that will have 180: ** no effect on the addresses as they are output. 181: */ 182: 183: bzero((char *) &nullmailer, sizeof nullmailer); 184: nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1; 185: nullmailer.m_eol = "\n"; 186: 187: define('g', "\001f", e); 188: for (h = e->e_header; h != NULL; h = h->h_link) 189: { 190: extern bool bitzerop(); 191: 192: /* don't output null headers */ 193: if (h->h_value == NULL || h->h_value[0] == '\0') 194: continue; 195: 196: /* don't output resent headers on non-resent messages */ 197: if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 198: continue; 199: 200: /* output this header */ 201: fprintf(tfp, "H"); 202: 203: /* if conditional, output the set of conditions */ 204: if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags)) 205: { 206: int j; 207: 208: (void) putc('?', tfp); 209: for (j = '\0'; j <= '\177'; j++) 210: if (bitnset(j, h->h_mflags)) 211: (void) putc(j, tfp); 212: (void) putc('?', tfp); 213: } 214: 215: /* output the header: expand macros, convert addresses */ 216: if (bitset(H_DEFAULT, h->h_flags)) 217: { 218: (void) expand(h->h_value, buf, &buf[sizeof buf], e); 219: fprintf(tfp, "%s: %s\n", h->h_field, buf); 220: } 221: else if (bitset(H_FROM|H_RCPT, h->h_flags)) 222: { 223: commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags), 224: &nullmailer); 225: } 226: else 227: fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); 228: } 229: 230: /* 231: ** Clean up. 232: */ 233: 234: (void) fclose(tfp); 235: qf = queuename(e, 'q'); 236: if (tf != NULL) 237: { 238: (void) unlink(qf); 239: if (rename(tf, qf) < 0) 240: syserr("cannot unlink(%s, %s), df=%s", tf, qf, e->e_df); 241: errno = 0; 242: } 243: 244: # ifdef LOG 245: /* save log info */ 246: if (LogLevel > 15) 247: syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df); 248: # endif LOG 249: } 250: /* 251: ** RUNQUEUE -- run the jobs in the queue. 252: ** 253: ** Gets the stuff out of the queue in some presumably logical 254: ** order and processes them. 255: ** 256: ** Parameters: 257: ** forkflag -- TRUE if the queue scanning should be done in 258: ** a child process. We double-fork so it is not our 259: ** child and we don't have to clean up after it. 260: ** 261: ** Returns: 262: ** none. 263: ** 264: ** Side Effects: 265: ** runs things in the mail queue. 266: */ 267: 268: runqueue(forkflag) 269: bool forkflag; 270: { 271: extern bool shouldqueue(); 272: 273: /* 274: ** If no work will ever be selected, don't even bother reading 275: ** the queue. 276: */ 277: 278: if (shouldqueue(-100000000L)) 279: { 280: if (Verbose) 281: printf("Skipping queue run -- load average too high\n"); 282: 283: if (forkflag) 284: return; 285: finis(); 286: } 287: 288: /* 289: ** See if we want to go off and do other useful work. 290: */ 291: 292: if (forkflag) 293: { 294: int pid; 295: 296: pid = dofork(); 297: if (pid != 0) 298: { 299: extern reapchild(); 300: 301: /* parent -- pick up intermediate zombie */ 302: #ifndef SIGCHLD 303: (void) waitfor(pid); 304: #else SIGCHLD 305: (void) signal(SIGCHLD, reapchild); 306: #endif SIGCHLD 307: if (QueueIntvl != 0) 308: (void) setevent(QueueIntvl, runqueue, TRUE); 309: return; 310: } 311: /* child -- double fork */ 312: #ifndef SIGCHLD 313: if (fork() != 0) 314: exit(EX_OK); 315: #else SIGCHLD 316: (void) signal(SIGCHLD, SIG_DFL); 317: #endif SIGCHLD 318: } 319: 320: setproctitle("running queue"); 321: 322: # ifdef LOG 323: if (LogLevel > 11) 324: syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid()); 325: # endif LOG 326: 327: /* 328: ** Release any resources used by the daemon code. 329: */ 330: 331: # ifdef DAEMON 332: clrdaemon(); 333: # endif DAEMON 334: 335: /* 336: ** Make sure the alias database is open. 337: */ 338: 339: initaliases(AliasFile, FALSE); 340: 341: /* 342: ** Start making passes through the queue. 343: ** First, read and sort the entire queue. 344: ** Then, process the work in that order. 345: ** But if you take too long, start over. 346: */ 347: 348: /* order the existing work requests */ 349: (void) orderq(FALSE); 350: 351: /* process them once at a time */ 352: while (WorkQ != NULL) 353: { 354: WORK *w = WorkQ; 355: 356: WorkQ = WorkQ->w_next; 357: dowork(w); 358: free(w->w_name); 359: free((char *) w); 360: } 361: 362: /* exit without the usual cleanup */ 363: exit(ExitStat); 364: } 365: /* 366: ** ORDERQ -- order the work queue. 367: ** 368: ** Parameters: 369: ** doall -- if set, include everything in the queue (even 370: ** the jobs that cannot be run because the load 371: ** average is too high). Otherwise, exclude those 372: ** jobs. 373: ** 374: ** Returns: 375: ** The number of request in the queue (not necessarily 376: ** the number of requests in WorkQ however). 377: ** 378: ** Side Effects: 379: ** Sets WorkQ to the queue of available work, in order. 380: */ 381: 382: # define NEED_P 001 383: # define NEED_T 002 384: 385: orderq(doall) 386: bool doall; 387: { 388: register struct direct *d; 389: register WORK *w; 390: DIR *f; 391: register int i; 392: WORK wlist[QUEUESIZE+1]; 393: int wn = -1; 394: extern workcmpf(); 395: 396: /* clear out old WorkQ */ 397: for (w = WorkQ; w != NULL; ) 398: { 399: register WORK *nw = w->w_next; 400: 401: WorkQ = nw; 402: free(w->w_name); 403: free((char *) w); 404: w = nw; 405: } 406: 407: /* open the queue directory */ 408: f = opendir("."); 409: if (f == NULL) 410: { 411: syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 412: return (0); 413: } 414: 415: /* 416: ** Read the work directory. 417: */ 418: 419: while ((d = readdir(f)) != NULL) 420: { 421: FILE *cf; 422: char lbuf[MAXNAME]; 423: 424: /* is this an interesting entry? */ 425: if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 426: continue; 427: 428: /* yes -- open control file (if not too many files) */ 429: if (++wn >= QUEUESIZE) 430: continue; 431: cf = fopen(d->d_name, "r"); 432: if (cf == NULL) 433: { 434: /* this may be some random person sending hir msgs */ 435: /* syserr("orderq: cannot open %s", cbuf); */ 436: #ifdef DEBUG 437: if (tTd(41, 2)) 438: printf("orderq: cannot open %s (%d)\n", 439: d->d_name, errno); 440: #endif DEBUG 441: errno = 0; 442: wn--; 443: continue; 444: } 445: w = &wlist[wn]; 446: w->w_name = newstr(d->d_name); 447: 448: /* make sure jobs in creation don't clog queue */ 449: w->w_pri = 0x7fffffff; 450: w->w_ctime = 0; 451: 452: /* extract useful information */ 453: i = NEED_P | NEED_T; 454: while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL) 455: { 456: extern long atol(); 457: 458: switch (lbuf[0]) 459: { 460: case 'P': 461: w->w_pri = atol(&lbuf[1]); 462: i &= ~NEED_P; 463: break; 464: 465: case 'T': 466: w->w_ctime = atol(&lbuf[1]); 467: i &= ~NEED_T; 468: break; 469: } 470: } 471: (void) fclose(cf); 472: 473: if (!doall && shouldqueue(w->w_pri)) 474: { 475: /* don't even bother sorting this job in */ 476: wn--; 477: } 478: } 479: (void) closedir(f); 480: wn++; 481: 482: /* 483: ** Sort the work directory. 484: */ 485: 486: qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf); 487: 488: /* 489: ** Convert the work list into canonical form. 490: ** Should be turning it into a list of envelopes here perhaps. 491: */ 492: 493: WorkQ = NULL; 494: for (i = min(wn, QUEUESIZE); --i >= 0; ) 495: { 496: w = (WORK *) xalloc(sizeof *w); 497: w->w_name = wlist[i].w_name; 498: w->w_pri = wlist[i].w_pri; 499: w->w_ctime = wlist[i].w_ctime; 500: w->w_next = WorkQ; 501: WorkQ = w; 502: } 503: 504: # ifdef DEBUG 505: if (tTd(40, 1)) 506: { 507: for (w = WorkQ; w != NULL; w = w->w_next) 508: printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 509: } 510: # endif DEBUG 511: 512: return (wn); 513: } 514: /* 515: ** WORKCMPF -- compare function for ordering work. 516: ** 517: ** Parameters: 518: ** a -- the first argument. 519: ** b -- the second argument. 520: ** 521: ** Returns: 522: ** -1 if a < b 523: ** 0 if a == b 524: ** +1 if a > b 525: ** 526: ** Side Effects: 527: ** none. 528: */ 529: 530: workcmpf(a, b) 531: register WORK *a; 532: register WORK *b; 533: { 534: long pa = a->w_pri + a->w_ctime; 535: long pb = b->w_pri + b->w_ctime; 536: 537: if (pa == pb) 538: return (0); 539: else if (pa > pb) 540: return (1); 541: else 542: return (-1); 543: } 544: /* 545: ** DOWORK -- do a work request. 546: ** 547: ** Parameters: 548: ** w -- the work request to be satisfied. 549: ** 550: ** Returns: 551: ** none. 552: ** 553: ** Side Effects: 554: ** The work request is satisfied if possible. 555: */ 556: 557: dowork(w) 558: register WORK *w; 559: { 560: register int i; 561: extern bool shouldqueue(); 562: 563: # ifdef DEBUG 564: if (tTd(40, 1)) 565: printf("dowork: %s pri %ld\n", w->w_name, w->w_pri); 566: # endif DEBUG 567: 568: /* 569: ** Ignore jobs that are too expensive for the moment. 570: */ 571: 572: if (shouldqueue(w->w_pri)) 573: { 574: if (Verbose) 575: printf("\nSkipping %s\n", w->w_name + 2); 576: return; 577: } 578: 579: /* 580: ** Fork for work. 581: */ 582: 583: if (ForkQueueRuns) 584: { 585: i = fork(); 586: if (i < 0) 587: { 588: syserr("dowork: cannot fork"); 589: return; 590: } 591: } 592: else 593: { 594: i = 0; 595: } 596: 597: if (i == 0) 598: { 599: /* 600: ** CHILD 601: ** Lock the control file to avoid duplicate deliveries. 602: ** Then run the file as though we had just read it. 603: ** We save an idea of the temporary name so we 604: ** can recover on interrupt. 605: */ 606: 607: /* set basic modes, etc. */ 608: (void) alarm(0); 609: clearenvelope(CurEnv, FALSE); 610: QueueRun = TRUE; 611: ErrorMode = EM_MAIL; 612: CurEnv->e_id = &w->w_name[2]; 613: # ifdef LOG 614: if (LogLevel > 11) 615: syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id, 616: getpid()); 617: # endif LOG 618: 619: /* don't use the headers from sendmail.cf... */ 620: CurEnv->e_header = NULL; 621: 622: /* lock the control file during processing */ 623: if (link(w->w_name, queuename(CurEnv, 'l')) < 0) 624: { 625: /* being processed by another queuer */ 626: # ifdef LOG 627: if (LogLevel > 4) 628: syslog(LOG_DEBUG, "%s: locked", CurEnv->e_id); 629: # endif LOG 630: if (ForkQueueRuns) 631: exit(EX_OK); 632: else 633: return; 634: } 635: 636: /* do basic system initialization */ 637: initsys(); 638: 639: /* read the queue control file */ 640: readqf(CurEnv, TRUE); 641: CurEnv->e_flags |= EF_INQUEUE; 642: eatheader(CurEnv); 643: 644: /* do the delivery */ 645: if (!bitset(EF_FATALERRS, CurEnv->e_flags)) 646: sendall(CurEnv, SM_DELIVER); 647: 648: /* finish up and exit */ 649: if (ForkQueueRuns) 650: finis(); 651: else 652: dropenvelope(CurEnv); 653: } 654: else 655: { 656: /* 657: ** Parent -- pick up results. 658: */ 659: 660: errno = 0; 661: (void) waitfor(i); 662: } 663: } 664: /* 665: ** READQF -- read queue file and set up environment. 666: ** 667: ** Parameters: 668: ** e -- the envelope of the job to run. 669: ** full -- if set, read in all information. Otherwise just 670: ** read in info needed for a queue print. 671: ** 672: ** Returns: 673: ** none. 674: ** 675: ** Side Effects: 676: ** cf is read and created as the current job, as though 677: ** we had been invoked by argument. 678: */ 679: 680: readqf(e, full) 681: register ENVELOPE *e; 682: bool full; 683: { 684: char *qf; 685: register FILE *qfp; 686: char buf[MAXFIELD]; 687: extern char *fgetfolded(); 688: extern long atol(); 689: 690: /* 691: ** Read and process the file. 692: */ 693: 694: qf = queuename(e, 'q'); 695: qfp = fopen(qf, "r"); 696: if (qfp == NULL) 697: { 698: syserr("readqf: no control file %s", qf); 699: return; 700: } 701: FileName = qf; 702: LineNumber = 0; 703: if (Verbose && full) 704: printf("\nRunning %s\n", e->e_id); 705: while (fgetfolded(buf, sizeof buf, qfp) != NULL) 706: { 707: # ifdef DEBUG 708: if (tTd(40, 4)) 709: printf("+++++ %s\n", buf); 710: # endif DEBUG 711: switch (buf[0]) 712: { 713: case 'R': /* specify recipient */ 714: sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue); 715: break; 716: 717: case 'E': /* specify error recipient */ 718: sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_errorqueue); 719: break; 720: 721: case 'H': /* header */ 722: if (full) 723: (void) chompheader(&buf[1], FALSE); 724: break; 725: 726: case 'M': /* message */ 727: e->e_message = newstr(&buf[1]); 728: break; 729: 730: case 'S': /* sender */ 731: setsender(newstr(&buf[1])); 732: break; 733: 734: case 'D': /* data file name */ 735: if (!full) 736: break; 737: e->e_df = newstr(&buf[1]); 738: e->e_dfp = fopen(e->e_df, "r"); 739: if (e->e_dfp == NULL) 740: syserr("readqf: cannot open %s", e->e_df); 741: break; 742: 743: case 'T': /* init time */ 744: e->e_ctime = atol(&buf[1]); 745: break; 746: 747: case 'P': /* message priority */ 748: e->e_msgpriority = atol(&buf[1]) + WkTimeFact; 749: break; 750: 751: case '\0': /* blank line; ignore */ 752: break; 753: 754: default: 755: syserr("readqf(%s:%d): bad line \"%s\"", e->e_id, 756: LineNumber, buf); 757: break; 758: } 759: } 760: 761: (void) fclose(qfp); 762: FileName = NULL; 763: 764: /* 765: ** If we haven't read any lines, this queue file is empty. 766: ** Arrange to remove it without referencing any null pointers. 767: */ 768: 769: if (LineNumber == 0) 770: { 771: errno = 0; 772: e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE; 773: } 774: } 775: /* 776: ** PRINTQUEUE -- print out a representation of the mail queue 777: ** 778: ** Parameters: 779: ** none. 780: ** 781: ** Returns: 782: ** none. 783: ** 784: ** Side Effects: 785: ** Prints a listing of the mail queue on the standard output. 786: */ 787: 788: printqueue() 789: { 790: register WORK *w; 791: FILE *f; 792: int nrequests; 793: char buf[MAXLINE]; 794: 795: /* 796: ** Read and order the queue. 797: */ 798: 799: nrequests = orderq(TRUE); 800: 801: /* 802: ** Print the work list that we have read. 803: */ 804: 805: /* first see if there is anything */ 806: if (nrequests <= 0) 807: { 808: printf("Mail queue is empty\n"); 809: return; 810: } 811: 812: printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); 813: if (nrequests > QUEUESIZE) 814: printf(", only %d printed", QUEUESIZE); 815: if (Verbose) 816: printf(")\n--QID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n"); 817: else 818: printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 819: for (w = WorkQ; w != NULL; w = w->w_next) 820: { 821: struct stat st; 822: auto time_t submittime = 0; 823: long dfsize = -1; 824: char lf[20]; 825: char message[MAXLINE]; 826: extern bool shouldqueue(); 827: extern long atol(); 828: 829: f = fopen(w->w_name, "r"); 830: if (f == NULL) 831: { 832: errno = 0; 833: continue; 834: } 835: printf("%7s", w->w_name + 2); 836: (void) strcpy(lf, w->w_name); 837: lf[0] = 'l'; 838: if (stat(lf, &st) >= 0) 839: printf("*"); 840: else if (shouldqueue(w->w_pri)) 841: printf("X"); 842: else 843: printf(" "); 844: errno = 0; 845: 846: message[0] = '\0'; 847: while (fgets(buf, sizeof buf, f) != NULL) 848: { 849: fixcrlf(buf, TRUE); 850: switch (buf[0]) 851: { 852: case 'M': /* error message */ 853: (void) strcpy(message, &buf[1]); 854: break; 855: 856: case 'S': /* sender name */ 857: if (Verbose) 858: printf("%8ld %10ld %.12s %.38s", dfsize, 859: w->w_pri, ctime(&submittime) + 4, 860: &buf[1]); 861: else 862: printf("%8ld %.16s %.45s", dfsize, 863: ctime(&submittime), &buf[1]); 864: if (message[0] != '\0') 865: printf("\n\t\t (%.60s)", message); 866: break; 867: 868: case 'R': /* recipient name */ 869: if (Verbose) 870: printf("\n\t\t\t\t\t %.38s", &buf[1]); 871: else 872: printf("\n\t\t\t\t %.45s", &buf[1]); 873: break; 874: 875: case 'T': /* creation time */ 876: submittime = atol(&buf[1]); 877: break; 878: 879: case 'D': /* data file name */ 880: if (stat(&buf[1], &st) >= 0) 881: dfsize = st.st_size; 882: break; 883: } 884: } 885: if (submittime == (time_t) 0) 886: printf(" (no control file)"); 887: printf("\n"); 888: (void) fclose(f); 889: } 890: } 891: 892: # endif QUEUE 893: /* 894: ** QUEUENAME -- build a file name in the queue directory for this envelope. 895: ** 896: ** Assigns an id code if one does not already exist. 897: ** This code is very careful to avoid trashing existing files 898: ** under any circumstances. 899: ** We first create an nf file that is only used when 900: ** assigning an id. This file is always empty, so that 901: ** we can never accidently truncate an lf file. 902: ** 903: ** Parameters: 904: ** e -- envelope to build it in/from. 905: ** type -- the file type, used as the first character 906: ** of the file name. 907: ** 908: ** Returns: 909: ** a pointer to the new file name (in a static buffer). 910: ** 911: ** Side Effects: 912: ** Will create the lf and qf files if no id code is 913: ** already assigned. This will cause the envelope 914: ** to be modified. 915: */ 916: 917: char * 918: queuename(e, type) 919: register ENVELOPE *e; 920: char type; 921: { 922: static char buf[MAXNAME]; 923: static int pid = -1; 924: char c1 = 'A'; 925: char c2 = 'A'; 926: 927: if (e->e_id == NULL) 928: { 929: char qf[20]; 930: char nf[20]; 931: char lf[20]; 932: 933: /* find a unique id */ 934: if (pid != getpid()) 935: { 936: /* new process -- start back at "AA" */ 937: pid = getpid(); 938: c1 = 'A'; 939: c2 = 'A' - 1; 940: } 941: (void) sprintf(qf, "qfAA%05d", pid); 942: (void) strcpy(lf, qf); 943: lf[0] = 'l'; 944: (void) strcpy(nf, qf); 945: nf[0] = 'n'; 946: 947: while (c1 < '~' || c2 < 'Z') 948: { 949: int i; 950: 951: if (c2 >= 'Z') 952: { 953: c1++; 954: c2 = 'A' - 1; 955: } 956: lf[2] = nf[2] = qf[2] = c1; 957: lf[3] = nf[3] = qf[3] = ++c2; 958: # ifdef DEBUG 959: if (tTd(7, 20)) 960: printf("queuename: trying \"%s\"\n", nf); 961: # endif DEBUG 962: 963: # ifdef QUEUE 964: if (access(lf, 0) >= 0 || access(qf, 0) >= 0) 965: continue; 966: errno = 0; 967: i = creat(nf, FileMode); 968: if (i < 0) 969: { 970: (void) unlink(nf); /* kernel bug */ 971: continue; 972: } 973: (void) close(i); 974: i = link(nf, lf); 975: (void) unlink(nf); 976: if (i < 0) 977: continue; 978: if (link(lf, qf) >= 0) 979: break; 980: (void) unlink(lf); 981: # else QUEUE 982: if (close(creat(qf, FileMode)) >= 0) 983: break; 984: # endif QUEUE 985: } 986: if (c1 >= '~' && c2 >= 'Z') 987: { 988: syserr("queuename: Cannot create \"%s\" in \"%s\"", 989: qf, QueueDir); 990: exit(EX_OSERR); 991: } 992: e->e_id = newstr(&qf[2]); 993: define('i', e->e_id, e); 994: # ifdef DEBUG 995: if (tTd(7, 1)) 996: printf("queuename: assigned id %s, env=%x\n", e->e_id, e); 997: # ifdef LOG 998: if (LogLevel > 16) 999: syslog(LOG_DEBUG, "%s: assigned id", e->e_id); 1000: # endif LOG 1001: # endif DEBUG 1002: } 1003: 1004: if (type == '\0') 1005: return (NULL); 1006: (void) sprintf(buf, "%cf%s", type, e->e_id); 1007: # ifdef DEBUG 1008: if (tTd(7, 2)) 1009: printf("queuename: %s\n", buf); 1010: # endif DEBUG 1011: return (buf); 1012: } 1013: /* 1014: ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 1015: ** 1016: ** Parameters: 1017: ** e -- the envelope to unlock. 1018: ** 1019: ** Returns: 1020: ** none 1021: ** 1022: ** Side Effects: 1023: ** unlocks the queue for `e'. 1024: */ 1025: 1026: unlockqueue(e) 1027: ENVELOPE *e; 1028: { 1029: /* remove the transcript */ 1030: #ifdef DEBUG 1031: # ifdef LOG 1032: if (LogLevel > 19) 1033: syslog(LOG_DEBUG, "%s: unlock", e->e_id); 1034: # endif LOG 1035: if (!tTd(51, 4)) 1036: #endif DEBUG 1037: xunlink(queuename(e, 'x')); 1038: 1039: # ifdef QUEUE 1040: /* last but not least, remove the lock */ 1041: xunlink(queuename(e, 'l')); 1042: # endif QUEUE 1043: }