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