Annotation of 42BSD/usr.lib/sendmail/src/main.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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