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