Annotation of 43BSDReno/usr.sbin/sendmail/src/queue.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.