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