# 2.11BSD#431 - /usr/src/usr.sbin/sendmail.MX/src/queue.c

##### Functions

    dowork            X
    orderq            X
    printqueue        X
    queuename         X
    queueup           X
    readqf            X
    runqueue          X
    unlockqueue       X
    workcmpf          X

##### Variables

    WorkQ             X

##### Macros

    NEED_P            X
    NEED_T            X

##### struct's

    work              X

##### typedef's

    WORK              X

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

#### Defined functions

dowork defined in line 557; used 1 times

- in line 357

orderq defined in line 385; used 2 times

- in line 349, 799

printqueue defined in line 788; used 1 times

- in /usr/src/usr.sbin/sendmail.MX/src/main.c line 487

queuename defined in line 917; used 15 times

- in line 82, 105, 235, 623, 694, 1037-1041(2)
- in /usr/src/usr.sbin/sendmail.MX/src/collect.c line 55
- in /usr/src/usr.sbin/sendmail.MX/src/envelope.c line 144, 355
- in /usr/src/usr.sbin/sendmail.MX/src/savemail.c line 181, 187, 473
- in /usr/src/usr.sbin/sendmail.MX/src/sendmail.h line 585
- in /usr/src/usr.sbin/sendmail.MX/src/srvrsmtp.c line 345

queueup defined in line 65; used 2 times

- in /usr/src/usr.sbin/sendmail.MX/src/deliver.c line 1387
- in /usr/src/usr.sbin/sendmail.MX/src/envelope.c line 149

readqf defined in line 680; used 1 times

- in line 640

runqueue defined in line 268; used 3 times

- in line 308
- in /usr/src/usr.sbin/sendmail.MX/src/main.c line 595, 630

unlockqueue defined in line 1026; used 2 times

- in /usr/src/usr.sbin/sendmail.MX/src/envelope.c line 157
- in /usr/src/usr.sbin/sendmail.MX/src/main.c line 775

workcmpf defined in line 530; used 2 times

- in line 394, 486

#### Defined variables

WorkQ defined in line 48; used 11 times

- in line 352-356(4), 397-401(2), 493, 500-501(2), 507, 819

sccsid defined in line 23; never used

#### Defined struct's

work defined in line 38; used 4 times

- in line 43-46(4)

#### Defined typedef's

WORK defined in line 46; used 10 times

- in line 48, 531-532(2), 558-354(2), 389-392(2), 399, 496, 790

#### Defined macros

NEED_P defined in line 382; used 2 times

- in line 453, 462

NEED_T defined in line 383; used 2 times

- in line 453, 467

Last modified: 1988-09-15 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2949 |