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

##### Functions

    disconnect        X
    finis             X
    freeze            X
    initmacros        X
    intsig            X
    main              X
    thaw              X

##### Variables

    Argv              X
    BlankEnvelope     X
    FullName          X
    LastArgv          X
    MainEnvelope      X
    MetaMacros        X
    NextMailer        X
    NullAddress       X
    copyright         X
    edata             X
    end               X

##### Macros

    _DEFINE           X

##### struct's

    metamac           X

##### unions's

    frz               X

       1: /*
       2: **  Sendmail
       3: **  Copyright (c) 1983  Eric P. Allman
       4: **  Berkeley, California
       5: **
       6: **  Copyright (c) 1983 Regents of the University of California.
       7: **  All rights reserved.  The Berkeley software License Agreement
       8: **  specifies the terms and conditions for redistribution.
       9: */
      10:
      11: #if !defined(lint) && !defined(NOSCCS)
      12: char copyright[] =
      13: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
      14:  All rights reserved.\n";
      15:
      16: static char SccsId[] = "@(#)main.c	5.11.3 (2.11BSD GTE) 1996/10/24";
      17: #endif
      18:
      19: # define  _DEFINE
      20: # include <signal.h>
      21: # include <sgtty.h>
      22: # include "sendmail.h"
      23:
      24: # ifdef lint
      25: char    edata, end;
      26: # endif lint
      27:
      28: /*
      29: **  SENDMAIL -- Post mail to a set of destinations.
      30: **
      31: **	This is the basic mail router.  All user mail programs should
      32: **	call this routine to actually deliver mail.  Sendmail in
      33: **	turn calls a bunch of mail servers that do the real work of
      34: **	delivering the mail.
      35: **
      36: **	Sendmail is driven by tables read in from /etc/sendmail.cf
      37: **	(read by readcf.c).  Some more static configuration info,
      38: **	including some code that you may want to tailor for your
      39: **	installation, is in conf.c.  You may also want to touch
      40: **	daemon.c (if you have some other IPC mechanism), acct.c
      41: **	(to change your accounting), names.c (to adjust the name
      42: **	server mechanism).
      43: **
      44: **	Usage:
      45: **		/usr/sbin/sendmail [flags] addr ...
      46: **
      47: **		See the associated documentation for details.
      48: **
      49: **	Author:
      50: **		Eric Allman, UCB/INGRES (until 10/81)
      51: **			     Britton-Lee, Inc., purveyors of fine
      52: **				database computers (from 11/81)
      53: **		The support of the INGRES Project and Britton-Lee is
      54: **			gratefully acknowledged.  Britton-Lee in
      55: **			particular had absolutely nothing to gain from
      56: **			my involvement in this project.
      57: */
      58:
      59:
      60:
      61:
      62:
      63: int     NextMailer; /* "free" index into Mailer struct */
      64: char        *FullName;  /* sender's full name */
      65: ENVELOPE    BlankEnvelope;  /* a "blank" envelope */
      66: ENVELOPE    MainEnvelope;   /* the envelope around the basic letter */
      67: ADDRESS     NullAddress =   /* a null address */
      68:         { "", "", "" };
      69:
      70: /*
      71: **  Pointers for setproctitle.
      72: **	This allows "ps" listings to give more useful information.
      73: **	These must be kept out of BSS for frozen configuration files
      74: **		to work.
      75: */
      76:
      77: # ifdef SETPROCTITLE
      78: char        **Argv = NULL;      /* pointer to argument vector */
      79: char        *LastArgv = NULL;   /* end of argv */
      80: # endif SETPROCTITLE
      81:
      82: #ifdef DAEMON
      83: #ifndef SMTP
      84: ERROR %%%%   Cannot have daemon mode without SMTP   %%%% ERROR
      85: #endif SMTP
      86: #endif DAEMON
      87:
      88:
      89:
      90:
      91:
      92:
      93: main(argc, argv, envp)
      94:     int argc;
      95:     char **argv;
      96:     char **envp;
      97: {
      98:     register char *p;
      99:     char **av;
     100:     extern int finis();
     101:     char *from;
     102:     typedef int (*fnptr)();
     103:     STAB *st;
     104:     register int i;
     105:     bool readconfig = TRUE;
     106:     bool queuemode = FALSE;     /* process queue requests */
     107:     bool nothaw;
     108:     static bool reenter = FALSE;
     109:     char jbuf[30];          /* holds MyHostName */
     110:     extern bool safefile();
     111:     extern time_t convtime();
     112:     extern putheader(), putbody();
     113:     extern ENVELOPE *newenvelope();
     114:     extern intsig();
     115:     extern char **myhostname();
     116:     extern char *arpadate();
     117:     extern char **environ;
     118:
     119:     /*
     120: 	**  Check to see if we reentered.
     121: 	**	This would normally happen if e_putheader or e_putbody
     122: 	**	were NULL when invoked.
     123: 	*/
     124:
     125:     if (reenter)
     126:     {
     127:         syserr("main: reentered!");
     128:         abort();
     129:     }
     130:     reenter = TRUE;
     131:
     132:     /* Enforce use of local time */
     133:     unsetenv("TZ");
     134:
     135:     /*
     136: 	**  Be sure we have enough file descriptors.
     137: 	*/
     138:
     139:     for (i = 3; i < 50; i++)
     140:         (void) close(i);
     141:     errno = 0;
     142:
     143:     /*
     144: 	**  Set default values for variables.
     145: 	**	These cannot be in initialized data space.
     146: 	*/
     147:
     148:     setdefaults();
     149:
     150:     /* set up the blank envelope */
     151:     BlankEnvelope.e_puthdr = putheader;
     152:     BlankEnvelope.e_putbody = putbody;
     153:     BlankEnvelope.e_xfp = NULL;
     154:     STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
     155:     CurEnv = &BlankEnvelope;
     156:     STRUCTCOPY(NullAddress, MainEnvelope.e_from);
     157:
     158:     /*
     159: 	**  Do a quick prescan of the argument list.
     160: 	**	We do this to find out if we can potentially thaw the
     161: 	**	configuration file.  If not, we do the thaw now so that
     162: 	**	the argument processing applies to this run rather than
     163: 	**	to the run that froze the configuration.
     164: 	*/
     165:
     166:     argv[argc] = NULL;
     167:     av = argv;
     168:     nothaw = FALSE;
     169:     while ((p = *++av) != NULL)
     170:     {
     171:         if (strncmp(p, "-C", 2) == 0)
     172:         {
     173:             ConfFile = &p[2];
     174:             if (ConfFile[0] == '\0')
     175:                 ConfFile = "sendmail.cf";
     176:             (void) setgid(getrgid());
     177:             (void) setuid(getruid());
     178:             nothaw = TRUE;
     179:         }
     180:         else if (strncmp(p, "-bz", 3) == 0)
     181:             nothaw = TRUE;
     182: # ifdef DEBUG
     183:         else if (strncmp(p, "-d", 2) == 0)
     184:         {
     185:             tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
     186:             tTflag(&p[2]);
     187:             setbuf(stdout, (char *) NULL);
     188:             printf("Version %s\n", Version);
     189:         }
     190: # endif DEBUG
     191:     }
     192:     if (!nothaw)
     193:         readconfig = !thaw(FreezeFile);
     194:
     195:     /* reset the environment after the thaw */
     196:     for (i = 0; i < MAXUSERENVIRON && envp[i] != NULL; i++)
     197:         UserEnviron[i] = newstr(envp[i]);
     198:     UserEnviron[i] = NULL;
     199:     environ = UserEnviron;
     200:
     201: # ifdef SETPROCTITLE
     202:     /*
     203: 	**  Save start and extent of argv for setproctitle.
     204: 	*/
     205:
     206:     Argv = argv;
     207:     if (i > 0)
     208:         LastArgv = envp[i - 1] + strlen(envp[i - 1]);
     209:     else
     210:         LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
     211: # endif SETPROCTITLE
     212:
     213:     /*
     214: 	**  Now do basic initialization
     215: 	*/
     216:
     217:     InChannel = stdin;
     218:     OutChannel = stdout;
     219:     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
     220:         (void) signal(SIGINT, intsig);
     221:     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
     222:         (void) signal(SIGHUP, intsig);
     223:     (void) signal(SIGTERM, intsig);
     224:     (void) signal(SIGPIPE, SIG_IGN);
     225:     OldUmask = umask(0);
     226:     OpMode = MD_DELIVER;
     227:     MotherPid = getpid();
     228:     FullName = getenv("NAME");
     229:
     230: # ifdef LOG
     231:     openlog("sendmail", LOG_PID, LOG_MAIL);
     232: # endif LOG
     233:     errno = 0;
     234:     from = NULL;
     235:
     236:     if (readconfig)
     237:     {
     238:         /* initialize some macros, etc. */
     239:         initmacros();
     240:
     241:         /* hostname */
     242:         av = myhostname(jbuf, sizeof jbuf);
     243:         if (jbuf[0] != '\0')
     244:         {
     245: #ifdef DEBUG
     246:             if (tTd(0, 4))
     247:                 printf("canonical name: %s\n", jbuf);
     248: #endif DEBUG
     249:             p = newstr(jbuf);
     250:             define('w', p, CurEnv);
     251:             setclass('w', p);
     252:         }
     253:         while (av != NULL && *av != NULL)
     254:         {
     255: #ifdef DEBUG
     256:             if (tTd(0, 4))
     257:                 printf("\ta.k.a.: %s\n", *av);
     258: #endif DEBUG
     259:             setclass('w', *av++);
     260:         }
     261:
     262:         /* version */
     263:         define('v', Version, CurEnv);
     264:     }
     265:
     266:     /* current time */
     267:     define('b', arpadate((char *) NULL), CurEnv);
     268:
     269:     /*
     270: 	** Crack argv.
     271: 	*/
     272:
     273:     av = argv;
     274:     p = rindex(*av, '/');
     275:     if (p++ == NULL)
     276:         p = *av;
     277:     if (strcmp(p, "newaliases") == 0)
     278:         OpMode = MD_INITALIAS;
     279:     else if (strcmp(p, "mailq") == 0)
     280:         OpMode = MD_PRINT;
     281:     else if (strcmp(p, "smtpd") == 0)
     282:         OpMode = MD_DAEMON;
     283:     while ((p = *++av) != NULL && p[0] == '-')
     284:     {
     285:         switch (p[1])
     286:         {
     287:           case 'b': /* operations mode */
     288:             switch (p[2])
     289:             {
     290:               case MD_DAEMON:
     291: # ifndef DAEMON
     292:                 syserr("Daemon mode not implemented");
     293:                 break;
     294: # endif DAEMON
     295:               case MD_SMTP:
     296: # ifndef SMTP
     297:                 syserr("I don't speak SMTP");
     298:                 break;
     299: # endif SMTP
     300:               case MD_ARPAFTP:
     301:               case MD_DELIVER:
     302:               case MD_VERIFY:
     303:               case MD_TEST:
     304:               case MD_INITALIAS:
     305:               case MD_PRINT:
     306:               case MD_FREEZE:
     307:                 OpMode = p[2];
     308:                 break;
     309:
     310:               default:
     311:                 syserr("Invalid operation mode %c", p[2]);
     312:                 break;
     313:             }
     314:             break;
     315:
     316:           case 'C': /* select configuration file (already done) */
     317:             break;
     318:
     319: # ifdef DEBUG
     320:           case 'd': /* debugging -- redo in case frozen */
     321:             tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
     322:             tTflag(&p[2]);
     323:             setbuf(stdout, (char *) NULL);
     324:             break;
     325: # endif DEBUG
     326:
     327:           case 'f': /* from address */
     328:           case 'r': /* obsolete -f flag */
     329:             p += 2;
     330:             if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
     331:             {
     332:                 p = *++av;
     333:                 if (p == NULL || *p == '-')
     334:                 {
     335:                     syserr("No \"from\" person");
     336:                     av--;
     337:                     break;
     338:                 }
     339:             }
     340:             if (from != NULL)
     341:             {
     342:                 syserr("More than one \"from\" person");
     343:                 break;
     344:             }
     345:             from = newstr(denlstring(p));
     346:             break;
     347:
     348:           case 'F': /* set full name */
     349:             p += 2;
     350:             if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
     351:             {
     352:                 syserr("Bad -F flag");
     353:                 av--;
     354:                 break;
     355:             }
     356:             FullName = newstr(p);
     357:             break;
     358:
     359:           case 'h': /* hop count */
     360:             p += 2;
     361:             if (*p == '\0' && ((p = *++av) == NULL || !isdigit(*p)))
     362:             {
     363:                 syserr("Bad hop count (%s)", p);
     364:                 av--;
     365:                 break;
     366:             }
     367:             CurEnv->e_hopcount = atoi(p);
     368:             break;
     369:
     370:           case 'n': /* don't alias */
     371:             NoAlias = TRUE;
     372:             break;
     373:
     374:           case 'o': /* set option */
     375:             setoption(p[2], &p[3], FALSE, TRUE);
     376:             break;
     377:
     378:           case 'q': /* run queue files at intervals */
     379: # ifdef QUEUE
     380:             FullName = NULL;
     381:             queuemode = TRUE;
     382:             QueueIntvl = convtime(&p[2]);
     383: # else QUEUE
     384:             syserr("I don't know about queues");
     385: # endif QUEUE
     386:             break;
     387:
     388:           case 't': /* read recipients from message */
     389:             GrabTo = TRUE;
     390:             break;
     391:
     392:             /* compatibility flags */
     393:           case 'c': /* connect to non-local mailers */
     394:           case 'e': /* error message disposition */
     395:           case 'i': /* don't let dot stop me */
     396:           case 'm': /* send to me too */
     397:           case 'T': /* set timeout interval */
     398:           case 'v': /* give blow-by-blow description */
     399:             setoption(p[1], &p[2], FALSE, TRUE);
     400:             break;
     401:
     402:           case 's': /* save From lines in headers */
     403:             setoption('f', &p[2], FALSE, TRUE);
     404:             break;
     405:
     406: # ifdef DBM
     407:           case 'I': /* initialize alias DBM file */
     408:             OpMode = MD_INITALIAS;
     409:             break;
     410: # endif DBM
     411:         }
     412:     }
     413:
     414:     /*
     415: 	**  Do basic initialization.
     416: 	**	Read system control file.
     417: 	**	Extract special fields for local use.
     418: 	*/
     419:
     420:     if (OpMode == MD_FREEZE || readconfig)
     421:         readcf(ConfFile);
     422:
     423:     switch (OpMode)
     424:     {
     425:       case MD_FREEZE:
     426:         /* this is critical to avoid forgeries of the frozen config */
     427:         (void) setgid(getgid());
     428:         (void) setuid(getuid());
     429:
     430:         /* freeze the configuration */
     431:         freeze(FreezeFile);
     432:         exit(EX_OK);
     433:
     434:       case MD_INITALIAS:
     435:         Verbose = TRUE;
     436:         break;
     437:
     438:       case MD_DAEMON:
     439:         /* remove things that don't make sense in daemon mode */
     440:         FullName = NULL;
     441:         break;
     442:     }
     443:
     444:     /* full names can't have newlines */
     445:     if (FullName != NULL && strchr(FullName, '\n') != NULL)
     446:         FullName = newstr(denlstring(FullName));
     447:
     448:     /* do heuristic mode adjustment */
     449:     if (Verbose)
     450:     {
     451:         /* turn off noconnect option */
     452:         setoption('c', "F", TRUE, FALSE);
     453:
     454:         /* turn on interactive delivery */
     455:         setoption('d', "", TRUE, FALSE);
     456:     }
     457:
     458:     /* our name for SMTP codes */
     459:     expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
     460:     MyHostName = jbuf;
     461:
     462:     /* the indices of local and program mailers */
     463:     st = stab("local", ST_MAILER, ST_FIND);
     464:     if (st == NULL)
     465:         syserr("No local mailer defined");
     466:     else
     467:         LocalMailer = st->s_mailer;
     468:     st = stab("prog", ST_MAILER, ST_FIND);
     469:     if (st == NULL)
     470:         syserr("No prog mailer defined");
     471:     else
     472:         ProgMailer = st->s_mailer;
     473:
     474:     /* operate in queue directory */
     475:     if (chdir(QueueDir) < 0)
     476:     {
     477:         syserr("cannot chdir(%s)", QueueDir);
     478:         exit(EX_SOFTWARE);
     479:     }
     480:
     481:     /*
     482: 	**  Do operation-mode-dependent initialization.
     483: 	*/
     484:
     485:     switch (OpMode)
     486:     {
     487:       case MD_PRINT:
     488:         /* print the queue */
     489: #ifdef QUEUE
     490:         dropenvelope(CurEnv);
     491:         printqueue();
     492:         exit(EX_OK);
     493: #else QUEUE
     494:         usrerr("No queue to print");
     495:         finis();
     496: #endif QUEUE
     497:
     498:       case MD_INITALIAS:
     499:         /* initialize alias database */
     500:         initaliases(AliasFile, TRUE);
     501:         exit(EX_OK);
     502:
     503:       case MD_DAEMON:
     504:         /* don't open alias database -- done in srvrsmtp */
     505:         break;
     506:
     507:       default:
     508:         /* open the alias database */
     509:         initaliases(AliasFile, FALSE);
     510:         break;
     511:     }
     512:
     513: # ifdef DEBUG
     514:     if (tTd(0, 15))
     515:     {
     516:         /* print configuration table (or at least part of it) */
     517:         printrules();
     518:         for (i = 0; i < MAXMAILERS; i++)
     519:         {
     520:             register struct mailer *m = Mailer[i];
     521:             int j;
     522:
     523:             if (m == NULL)
     524:                 continue;
     525:             printf("mailer %d (%s): P=%s S=%d R=%d M=%ld F=", i, m->m_name,
     526:                 m->m_mailer, m->m_s_rwset, m->m_r_rwset,
     527:                 m->m_maxsize);
     528:             for (j = '\0'; j <= '\177'; j++)
     529:                 if (bitnset(j, m->m_flags))
     530:                     (void) putchar(j);
     531:             printf(" E=");
     532:             xputs(m->m_eol);
     533:             printf("\n");
     534:         }
     535:     }
     536: # endif DEBUG
     537:
     538:     /*
     539: 	**  Switch to the main envelope.
     540: 	*/
     541:
     542:     CurEnv = newenvelope(&MainEnvelope);
     543:     MainEnvelope.e_flags = BlankEnvelope.e_flags;
     544:
     545:     /*
     546: 	**  If test mode, read addresses from stdin and process.
     547: 	*/
     548:
     549:     if (OpMode == MD_TEST)
     550:     {
     551:         char buf[MAXLINE];
     552:
     553:         printf("ADDRESS TEST MODE\nEnter <ruleset> <address>\n");
     554:         for (;;)
     555:         {
     556:             register char **pvp;
     557:             char *q;
     558:             extern char *DelimChar;
     559:
     560:             printf("> ");
     561:             (void) fflush(stdout);
     562:             if (fgets(buf, sizeof buf, stdin) == NULL)
     563:                 finis();
     564:             for (p = buf; isspace(*p); *p++)
     565:                 continue;
     566:             q = p;
     567:             while (*p != '\0' && !isspace(*p))
     568:                 p++;
     569:             if (*p == '\0')
     570:                 continue;
     571:             *p = '\0';
     572:             do
     573:             {
     574:                 extern char **prescan();
     575:                 char pvpbuf[PSBUFSIZE];
     576:
     577:                 pvp = prescan(++p, ',', pvpbuf);
     578:                 if (pvp == NULL)
     579:                     continue;
     580:                 rewrite(pvp, 3);
     581:                 p = q;
     582:                 while (*p != '\0')
     583:                 {
     584:                     rewrite(pvp, atoi(p));
     585:                     while (*p != '\0' && *p++ != ',')
     586:                         continue;
     587:                 }
     588:             } while (*(p = DelimChar) != '\0');
     589:         }
     590:     }
     591:
     592: # ifdef QUEUE
     593:     /*
     594: 	**  If collecting stuff from the queue, go start doing that.
     595: 	*/
     596:
     597:     if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0)
     598:     {
     599:         runqueue(FALSE);
     600:         finis();
     601:     }
     602: # endif QUEUE
     603:
     604:     /*
     605: 	**  If a daemon, wait for a request.
     606: 	**	getrequests will always return in a child.
     607: 	**	If we should also be processing the queue, start
     608: 	**		doing it in background.
     609: 	**	We check for any errors that might have happened
     610: 	**		during startup.
     611: 	*/
     612:
     613:     if (OpMode == MD_DAEMON || QueueIntvl != 0)
     614:     {
     615:         if (!tTd(0, 1))
     616:         {
     617:             /* put us in background */
     618:             i = fork();
     619:             if (i < 0)
     620:                 syserr("daemon: cannot fork");
     621:             if (i != 0)
     622:                 exit(0);
     623:
     624:             /* get our pid right */
     625:             MotherPid = getpid();
     626:
     627:             /* disconnect from our controlling tty */
     628:             disconnect(TRUE);
     629:         }
     630:
     631: # ifdef QUEUE
     632:         if (queuemode)
     633:         {
     634:             runqueue(TRUE);
     635:             if (OpMode != MD_DAEMON)
     636:                 for (;;)
     637:                     pause();
     638:         }
     639: # endif QUEUE
     640:         dropenvelope(CurEnv);
     641:
     642: #ifdef DAEMON
     643:         getrequests();
     644:
     645:         /* at this point we are in a child: reset state */
     646:         OpMode = MD_SMTP;
     647:         (void) newenvelope(CurEnv);
     648:         openxscript(CurEnv);
     649: #endif DAEMON
     650:     }
     651:
     652: # ifdef SMTP
     653:     /*
     654: 	**  If running SMTP protocol, start collecting and executing
     655: 	**  commands.  This will never return.
     656: 	*/
     657:
     658:     if (OpMode == MD_SMTP)
     659:         smtp();
     660: # endif SMTP
     661:
     662:     /*
     663: 	**  Do basic system initialization and set the sender
     664: 	*/
     665:
     666:     initsys();
     667:     setsender(from);
     668:
     669:     if (OpMode != MD_ARPAFTP && *av == NULL && !GrabTo)
     670:     {
     671:         usrerr("Recipient names must be specified");
     672:
     673:         /* collect body for UUCP return */
     674:         if (OpMode != MD_VERIFY)
     675:             collect(FALSE);
     676:         finis();
     677:     }
     678:     if (OpMode == MD_VERIFY)
     679:         SendMode = SM_VERIFY;
     680:
     681:     /*
     682: 	**  Scan argv and deliver the message to everyone.
     683: 	*/
     684:
     685:     sendtoargv(av);
     686:
     687:     /* if we have had errors sofar, arrange a meaningful exit stat */
     688:     if (Errors > 0 && ExitStat == EX_OK)
     689:         ExitStat = EX_USAGE;
     690:
     691:     /*
     692: 	**  Read the input mail.
     693: 	*/
     694:
     695:     CurEnv->e_to = NULL;
     696:     if (OpMode != MD_VERIFY || GrabTo)
     697:         collect(FALSE);
     698:     errno = 0;
     699:
     700:     /* collect statistics */
     701:     if (OpMode != MD_VERIFY)
     702:         markstats(CurEnv, (ADDRESS *) NULL);
     703:
     704: # ifdef DEBUG
     705:     if (tTd(1, 1))
     706:         printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
     707: # endif DEBUG
     708:
     709:     /*
     710: 	**  Actually send everything.
     711: 	**	If verifying, just ack.
     712: 	*/
     713:
     714:     CurEnv->e_from.q_flags |= QDONTSEND;
     715:     CurEnv->e_to = NULL;
     716:     sendall(CurEnv, SM_DEFAULT);
     717:
     718:     /*
     719: 	** All done.
     720: 	*/
     721:
     722:     finis();
     723: }
     724: /*
     725: **  FINIS -- Clean up and exit.
     726: **
     727: **	Parameters:
     728: **		none
     729: **
     730: **	Returns:
     731: **		never
     732: **
     733: **	Side Effects:
     734: **		exits sendmail
     735: */
     736:
     737: finis()
     738: {
     739: # ifdef DEBUG
     740:     if (tTd(2, 1))
     741:         printf("\n====finis: stat %d e_flags %o\n", ExitStat, CurEnv->e_flags);
     742: # endif DEBUG
     743:
     744:     /* clean up temp files */
     745:     CurEnv->e_to = NULL;
     746:     dropenvelope(CurEnv);
     747:
     748:     /* post statistics */
     749:     poststats(StatFile);
     750:
     751:     /* and exit */
     752: # ifdef LOG
     753:     if (LogLevel > 11)
     754:         syslog(LOG_DEBUG, "finis, pid=%d", getpid());
     755: # endif LOG
     756:     if (ExitStat == EX_TEMPFAIL)
     757:         ExitStat = EX_OK;
     758:     exit(ExitStat);
     759: }
     760: /*
     761: **  INTSIG -- clean up on interrupt
     762: **
     763: **	This just arranges to exit.  It pessimises in that it
     764: **	may resend a message.
     765: **
     766: **	Parameters:
     767: **		none.
     768: **
     769: **	Returns:
     770: **		none.
     771: **
     772: **	Side Effects:
     773: **		Unlocks the current job.
     774: */
     775:
     776: intsig()
     777: {
     778:     FileName = NULL;
     779:     unlockqueue(CurEnv);
     780:     exit(EX_OK);
     781: }
     782: /*
     783: **  INITMACROS -- initialize the macro system
     784: **
     785: **	This just involves defining some macros that are actually
     786: **	used internally as metasymbols to be themselves.
     787: **
     788: **	Parameters:
     789: **		none.
     790: **
     791: **	Returns:
     792: **		none.
     793: **
     794: **	Side Effects:
     795: **		initializes several macros to be themselves.
     796: */
     797:
     798: struct metamac
     799: {
     800:     char    metaname;
     801:     char    metaval;
     802: };
     803:
     804: struct metamac  MetaMacros[] =
     805: {
     806:     /* LHS pattern matching characters */
     807:     '*', MATCHZANY, '+', MATCHANY,  '-', MATCHONE,  '=', MATCHCLASS,
     808:     '~', MATCHNCLASS,
     809:
     810:     /* these are RHS metasymbols */
     811:     '#', CANONNET,  '@', CANONHOST, ':', CANONUSER, '>', CALLSUBR,
     812:
     813:     /* the conditional operations */
     814:     '?', CONDIF,    '|', CONDELSE,  '.', CONDFI,
     815:
     816:     /* and finally the hostname lookup characters */
     817:     '[', HOSTBEGIN, ']', HOSTEND,
     818:
     819:     '\0'
     820: };
     821:
     822: initmacros()
     823: {
     824:     register struct metamac *m;
     825:     char buf[5];
     826:     register int c;
     827:
     828:     for (m = MetaMacros; m->metaname != '\0'; m++)
     829:     {
     830:         buf[0] = m->metaval;
     831:         buf[1] = '\0';
     832:         define(m->metaname, newstr(buf), CurEnv);
     833:     }
     834:     buf[0] = MATCHREPL;
     835:     buf[2] = '\0';
     836:     for (c = '0'; c <= '9'; c++)
     837:     {
     838:         buf[1] = c;
     839:         define(c, newstr(buf), CurEnv);
     840:     }
     841: }
     842: /*
     843: **  FREEZE -- freeze BSS & allocated memory
     844: **
     845: **	This will be used to efficiently load the configuration file.
     846: **
     847: **	Parameters:
     848: **		freezefile -- the name of the file to freeze to.
     849: **
     850: **	Returns:
     851: **		none.
     852: **
     853: **	Side Effects:
     854: **		Writes BSS and malloc'ed memory to freezefile
     855: */
     856:
     857: union frz
     858: {
     859:     char        frzpad[BUFSIZ]; /* insure we are on a BUFSIZ boundary */
     860:     struct
     861:     {
     862:         time_t  frzstamp;   /* timestamp on this freeze */
     863:         char    *frzbrk;    /* the current break */
     864:         char    *frzedata;  /* address of edata */
     865:         char    *frzend;    /* address of end */
     866:         char    frzver[252];    /* sendmail version */
     867:     } frzinfo;
     868: };
     869:
     870: freeze(freezefile)
     871:     char *freezefile;
     872: {
     873:     int f;
     874:     union frz fhdr;
     875:     extern char edata, end;
     876:     extern char *sbrk();
     877:
     878:     if (freezefile == NULL)
     879:         return;
     880:
     881:     /* try to open the freeze file */
     882:     f = creat(freezefile, FileMode);
     883:     if (f < 0)
     884:     {
     885:         syserr("Cannot freeze");
     886:         errno = 0;
     887:         return;
     888:     }
     889:
     890:     /* build the freeze header */
     891:     fhdr.frzinfo.frzstamp = curtime();
     892:     fhdr.frzinfo.frzbrk = sbrk(0);
     893:     fhdr.frzinfo.frzedata = &edata;
     894:     fhdr.frzinfo.frzend = &end;
     895:     (void) strcpy(fhdr.frzinfo.frzver, Version);
     896:
     897:     /* write out the freeze header */
     898:     if (write(f, (char *) &fhdr, sizeof fhdr) != sizeof fhdr ||
     899:         write(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) !=
     900:                     (int) (fhdr.frzinfo.frzbrk - &edata))
     901:     {
     902:         syserr("Cannot freeze");
     903:     }
     904:
     905:     /* fine, clean up */
     906:     (void) close(f);
     907: }
     908: /*
     909: **  THAW -- read in the frozen configuration file.
     910: **
     911: **	Parameters:
     912: **		freezefile -- the name of the file to thaw from.
     913: **
     914: **	Returns:
     915: **		TRUE if it successfully read the freeze file.
     916: **		FALSE otherwise.
     917: **
     918: **	Side Effects:
     919: **		reads freezefile in to BSS area.
     920: */
     921:
     922: thaw(freezefile)
     923:     char *freezefile;
     924: {
     925:     int f;
     926:     union frz fhdr;
     927:     extern char edata, end;
     928:     extern caddr_t brk();
     929:
     930:     if (freezefile == NULL)
     931:         return (FALSE);
     932:
     933:     /* open the freeze file */
     934:     f = open(freezefile, 0);
     935:     if (f < 0)
     936:     {
     937:         errno = 0;
     938:         return (FALSE);
     939:     }
     940:
     941:     /* read in the header */
     942:     if (read(f, (char *) &fhdr, sizeof fhdr) < (int)sizeof fhdr ||
     943:         fhdr.frzinfo.frzedata != &edata ||
     944:         fhdr.frzinfo.frzend != &end ||
     945:         strcmp(fhdr.frzinfo.frzver, Version) != 0)
     946:     {
     947:         (void) close(f);
     948:         return (FALSE);
     949:     }
     950:
     951:     /* arrange to have enough space */
     952:     if (brk(fhdr.frzinfo.frzbrk) == (caddr_t) -1)
     953:     {
     954:         syserr("Cannot break to %x", fhdr.frzinfo.frzbrk);
     955:         (void) close(f);
     956:         return (FALSE);
     957:     }
     958:
     959:     /* now read in the freeze file */
     960:     if (read(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) !=
     961:                     (int) (fhdr.frzinfo.frzbrk - &edata))
     962:     {
     963:         /* oops!  we have trashed memory..... */
     964:         (void) write(2, "Cannot read freeze file\n", 24);
     965:         _exit(EX_SOFTWARE);
     966:     }
     967:
     968:     (void) close(f);
     969:     return (TRUE);
     970: }
     971: /*
     972: **  DISCONNECT -- remove our connection with any foreground process
     973: **
     974: **	Parameters:
     975: **		fulldrop -- if set, we should also drop the controlling
     976: **			TTY if possible -- this should only be done when
     977: **			setting up the daemon since otherwise UUCP can
     978: **			leave us trying to open a dialin, and we will
     979: **			wait for the carrier.
     980: **
     981: **	Returns:
     982: **		none
     983: **
     984: **	Side Effects:
     985: **		Trys to insure that we are immune to vagaries of
     986: **		the controlling tty.
     987: */
     988:
     989: disconnect(fulldrop)
     990:     bool fulldrop;
     991: {
     992:     int fd;
     993:
     994: #ifdef DEBUG
     995:     if (tTd(52, 1))
     996:         printf("disconnect: In %d Out %d\n", fileno(InChannel),
     997:                         fileno(OutChannel));
     998:     if (tTd(52, 5))
     999:     {
    1000:         printf("don't\n");
    1001:         return;
    1002:     }
    1003: #endif DEBUG
    1004:
    1005:     /* be sure we don't get nasty signals */
    1006:     (void) signal(SIGHUP, SIG_IGN);
    1007:     (void) signal(SIGINT, SIG_IGN);
    1008:     (void) signal(SIGQUIT, SIG_IGN);
    1009:
    1010:     /* we can't communicate with our caller, so.... */
    1011:     HoldErrs = TRUE;
    1012:     ErrorMode = EM_MAIL;
    1013:     Verbose = FALSE;
    1014:
    1015:     /* all input from /dev/null */
    1016:     if (InChannel != stdin)
    1017:     {
    1018:         (void) fclose(InChannel);
    1019:         InChannel = stdin;
    1020:     }
    1021:     (void) freopen("/dev/null", "r", stdin);
    1022:
    1023:     /* output to the transcript */
    1024:     if (OutChannel != stdout)
    1025:     {
    1026:         (void) fclose(OutChannel);
    1027:         OutChannel = stdout;
    1028:     }
    1029:     if (CurEnv->e_xfp == NULL)
    1030:         CurEnv->e_xfp = fopen("/dev/null", "w");
    1031:     (void) fflush(stdout);
    1032:     (void) close(1);
    1033:     (void) close(2);
    1034:     while ((fd = dup(fileno(CurEnv->e_xfp))) < 2 && fd > 0)
    1035:         continue;
    1036:
    1037:     XXctime();  /* XXX - close pipes to ctimed */
    1038:
    1039: #ifdef TIOCNOTTY
    1040:     /* drop our controlling TTY completely if possible */
    1041:     if (fulldrop)
    1042:     {
    1043:         fd = open("/dev/tty", 2);
    1044:         if (fd >= 0)
    1045:         {
    1046:             (void) ioctl(fd, TIOCNOTTY, (char *) 0);
    1047:             (void) close(fd);
    1048:         }
    1049:         (void) setpgrp(0, 0);
    1050:         errno = 0;
    1051:     }
    1052: #endif TIOCNOTTY
    1053:
    1054: # ifdef LOG
    1055:     if (LogLevel > 11)
    1056:         syslog(LOG_DEBUG, "in background, pid=%d", getpid());
    1057: # endif LOG
    1058:
    1059:     errno = 0;
    1060: }

#### Defined functions

disconnect defined in line 989; used 2 times

- in line 628
- in /usr/src/usr.sbin/sendmail/src/deliver.c line 1373

finis defined in line 737; used 24 times

- in line 100, 495, 563, 600, 676, 722
- in /usr/src/usr.sbin/sendmail/src/collect.c line 54, 185
- in /usr/src/usr.sbin/sendmail/src/daemon.c line 124
- in /usr/src/usr.sbin/sendmail/src/deliver.c line 1454
- in /usr/src/usr.sbin/sendmail/src/envelope.c line 545
- in /usr/src/usr.sbin/sendmail/src/queue.c line 274, 350, 637
- in /usr/src/usr.sbin/sendmail/src/savemail.c line 88
- in /usr/src/usr.sbin/sendmail/src/srvrsmtp.c line 143, 161, 253, 352, 364, 377, 405, 422, 662

freeze defined in line 870; used 1 times

- in line 431

initmacros defined in line 822; used 1 times

- in line 239

intsig defined in line 776; used 4 times

- in line 114, 220-223(3)

main defined in line 84; never used
thaw defined in line 922; used 1 times

- in line 193

#### Defined variables

Argv defined in line 78; used 1 times

- in line 206

BlankEnvelope defined in line 65; used 6 times

- in line 151-155(5), 543

FullName defined in line 64; used 8 times

- in line 228, 356, 380, 440-446(5)

LastArgv defined in line 79; used 2 times

- in line 208-210(2)

MainEnvelope defined in line 66; used 3 times

- in line 156, 542-543(2)

MetaMacros defined in line 804; used 1 times

- in line 828

NextMailer defined in line 63; never used
NullAddress defined in line 67; used 2 times

- in line 154-156(2)

SccsId defined in line 16; never used
copyright defined in line 12; never used
edata defined in line 25; used 10 times

- in line 875, 893, 899-900(3), 927, 943, 960-961(3)

end defined in line 25; used 4 times

- in line 875, 894, 927, 944

#### Defined struct's

metamac defined in line 798; used 4 times

- in line 804(2), 824(2)

#### Defined union's

frz defined in line 857; used 4 times

- in line 874(2), 926(2)

#### Defined macros

_DEFINE defined in line 19; never used

Last modified: 1996-10-25 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 3267 |