📄 main.c
字号:
/* print configuration table (or at least part of it) */ printrules(); for (i = 0; i < MAXMAILERS; i++) { register struct mailer *m = Mailer[i]; int j; if (m == NULL) continue; printf("mailer %d (%s): P=%s S=%d R=%d M=%ld F=", i, m->m_name, m->m_mailer, m->m_s_rwset, m->m_r_rwset, m->m_maxsize); for (j = '\0'; j <= '\177'; j++) if (bitnset(j, m->m_flags)) (void) putchar(j); printf(" E="); xputs(m->m_eol); printf("\n"); } }# endif DEBUG /* ** Switch to the main envelope. */ MainEnvelope.e_from = NullAddress; CurEnv = newenvelope(&MainEnvelope); MainEnvelope.e_flags = BlankEnvelope.e_flags; /* ** If test mode, read addresses from stdin and process. */ if (OpMode == MD_TEST) { char buf[MAXLINE]; printf("ADDRESS TEST MODE\nEnter <ruleset> <address>\n"); for (;;) { register char **pvp; char *q; extern char *DelimChar; printf("> "); (void) fflush(stdout); if (fgets(buf, sizeof buf, stdin) == NULL) finis(); for (p = buf; isspace(*p); *p++) continue; q = p; while (*p != '\0' && !isspace(*p)) p++; if (*p == '\0') continue; *p = '\0'; do { extern char **prescan(); char pvpbuf[PSBUFSIZE]; pvp = prescan(++p, ',', pvpbuf); if (pvp == NULL) continue; rewrite(pvp, 3); p = q; while (*p != '\0') { rewrite(pvp, atoi(p)); while (*p != '\0' && *p++ != ',') continue; } } while (*(p = DelimChar) != '\0'); } }# ifdef QUEUE /* ** If collecting stuff from the queue, go start doing that. */ if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0) { runqueue(FALSE); finis(); }# endif QUEUE /* ** If a daemon, wait for a request. ** getrequests will always return in a child. ** If we should also be processing the queue, start ** doing it in background. ** We check for any errors that might have happened ** during startup. */ if (OpMode == MD_DAEMON || QueueIntvl != 0) { if (!tTd(0, 1)) { /* put us in background */ i = fork(); if (i < 0) syserr("daemon: cannot fork"); if (i != 0) exit(0); /* get our pid right */ MotherPid = getpid(); /* disconnect from our controlling tty */ disconnect(TRUE); }# ifdef QUEUE if (queuemode) { runqueue(TRUE); if (OpMode != MD_DAEMON) for (;;) pause(); }# endif QUEUE dropenvelope(CurEnv);#ifdef DAEMON getrequests(); /* at this point we are in a child: reset state */ OpMode = MD_SMTP; (void) newenvelope(CurEnv); openxscript(CurEnv);#endif DAEMON } # ifdef SMTP /* ** If running SMTP protocol, start collecting and executing ** commands. This will never return. */ if (OpMode == MD_SMTP) smtp();# endif SMTP /* ** Do basic system initialization and set the sender */ initsys(); setsender(from); if (OpMode != MD_ARPAFTP && *av == NULL && !GrabTo) { usrerr("Recipient names must be specified"); /* collect body for UUCP return */ if (OpMode != MD_VERIFY) collect(FALSE); finis(); } if (GrabTo && RemoteServer) NoAlias = TRUE; if (OpMode == MD_VERIFY) SendMode = SM_VERIFY; /* ** Scan argv and deliver the message to everyone. */ sendtoargv(av); /* if we have had errors sofar, arrange a meaningful exit stat */ if (Errors > 0 && ExitStat == EX_OK) ExitStat = EX_USAGE; /* ** Read the input mail. */ CurEnv->e_to = NULL; if (OpMode != MD_VERIFY || GrabTo) collect(FALSE); if (GrabTo && RemoteServer && OpMode == MD_DELIVER) { ExitStat = RemoteMode(from, NULL, CurEnv->e_sendqueue); finis(); } errno = 0; /* collect statistics */ if (OpMode != MD_VERIFY) markstats(CurEnv, (ADDRESS *) NULL);# ifdef DEBUG if (tTd(1, 1)) printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);# endif DEBUG /* ** Actually send everything. ** If verifying, just ack. */ CurEnv->e_from.q_flags |= QDONTSEND; CurEnv->e_to = NULL; sendall(CurEnv, SM_DEFAULT); /* ** All done. */ finis();}/*** FINIS -- Clean up and exit.**** Parameters:** none**** Returns:** never**** Side Effects:** exits sendmail*/finis(){# ifdef DEBUG if (tTd(2, 1)) printf("\n====finis: stat %d e_flags %o\n", ExitStat, CurEnv->e_flags);# endif DEBUG /* clean up temp files */ CurEnv->e_to = NULL; dropenvelope(CurEnv); /* post statistics */ poststats(StatFile); /* and exit */# ifdef LOG if (LogLevel > 11) syslog(LOG_DEBUG, "finis, pid=%d", getpid());# endif LOG if (ExitStat == EX_TEMPFAIL) ExitStat = EX_OK; exit(ExitStat);}/*** INTSIG -- clean up on interrupt**** This just arranges to exit. It pessimises in that it** may resend a message.**** Parameters:** none.**** Returns:** none.**** Side Effects:** Requeues the current job.*/intsig(){ register ADDRESS *q; FileName = NULL; q = CurEnv->e_sendqueue; if (q != NULL && !bitset(EF_INQUEUE,CurEnv->e_flags) && OpMode != MD_VERIFY) { for (; q != NULL; q = q->q_next) if (q != &CurEnv->e_from) q->q_flags &= ~QDONTSEND; queueup(CurEnv, TRUE, Verbose); } unlockqueue(CurEnv); exit(EX_OK);}/*** INITMACROS -- initialize the macro system**** This just involves defining some macros that are actually** used internally as metasymbols to be themselves.**** Parameters:** none.**** Returns:** none.**** Side Effects:** initializes several macros to be themselves.*/struct metamac MetaMacros[] ={ /* LHS pattern matching characters */ '*', MATCHZANY, '+', MATCHANY, '-', MATCHONE, '=', MATCHCLASS, '~', MATCHNCLASS, '%', MATCHYELLOW, '!', MATCHNYELLOW, /* these are RHS metasymbols */ '#', CANONNET, '@', CANONHOST, ':', CANONUSER, '>', CALLSUBR, /* the conditional operations */ '?', CONDIF, '|', CONDELSE, '.', CONDFI, /* the NIS lookup characters */ '{', YELLOWBEGIN, '}', YELLOWEND, /* and finally the hostname lookup characters */ '[', HOSTBEGIN, ']', HOSTEND, '\0'};initmacros(){ register struct metamac *m; char buf[5]; register int c; for (m = MetaMacros; m->metaname != '\0'; m++) { buf[0] = m->metaval; buf[1] = '\0'; define(m->metaname, newstr(buf), CurEnv); } buf[0] = MATCHREPL; buf[2] = '\0'; for (c = '0'; c <= '9'; c++) { buf[1] = c; define(c, newstr(buf), CurEnv); }}/*** FREEZE -- freeze BSS & allocated memory**** This will be used to efficiently load the configuration file.**** Parameters:** freezefile -- the name of the file to freeze to.**** Returns:** none.**** Side Effects:** Writes BSS and malloc'ed memory to freezefile*/union frz{ char frzpad[BUFSIZ]; /* insure we are on a BUFSIZ boundary */ struct { time_t frzstamp; /* timestamp on this freeze */ char *frzbrk; /* the current break */ char *frzedata; /* address of edata */ char *frzend; /* address of end */ char frzver[252]; /* sendmail version */ } frzinfo;};freeze(freezefile) char *freezefile;{ int f; union frz fhdr; extern char edata, end; extern char *sbrk(); extern char Version[]; if (freezefile == NULL) return; /* try to open the freeze file */ f = creat(freezefile, FreezeMode); if (f < 0) { syserr("Cannot freeze"); errno = 0; return; } /* build the freeze header */ fhdr.frzinfo.frzstamp = curtime(); fhdr.frzinfo.frzbrk = sbrk(0); fhdr.frzinfo.frzedata = &edata; fhdr.frzinfo.frzend = &end; (void) strcpy(fhdr.frzinfo.frzver, Version); /* write out the freeze header */ if (write(f, (char *) &fhdr, sizeof fhdr) != sizeof fhdr || write(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) != (int) (fhdr.frzinfo.frzbrk - &edata)) { syserr("Cannot freeze"); } /* fine, clean up */ (void) close(f);}/*** THAW -- read in the frozen configuration file.**** Parameters:** freezefile -- the name of the file to thaw from.**** Returns:** TRUE if it successfully read the freeze file.** FALSE otherwise.**** Side Effects:** reads freezefile in to BSS area.*/thaw(freezefile) char *freezefile;{ int f; union frz fhdr; extern char edata; extern char Version[]; extern caddr_t brk(); if (freezefile == NULL) return (FALSE); /* open the freeze file */ f = open(freezefile, 0); if (f < 0) { errno = 0; return (FALSE); } /* read in the header */ if (read(f, (char *) &fhdr, sizeof fhdr) < sizeof fhdr || fhdr.frzinfo.frzedata != &edata || fhdr.frzinfo.frzend != &end || strcmp(fhdr.frzinfo.frzver, Version) != 0) { (void) close(f); return (FALSE); } /* arrange to have enough space */ if (brk(fhdr.frzinfo.frzbrk) == (caddr_t) -1) { syserr("Cannot break to %x", fhdr.frzinfo.frzbrk); (void) close(f); return (FALSE); } /* now read in the freeze file */ if (read(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) != (int) (fhdr.frzinfo.frzbrk - &edata)) { /* oops! we have trashed memory..... */ (void) write(2, "Cannot read freeze file\n", 24); _exit(EX_SOFTWARE); } (void) close(f); return (TRUE);}/*** DISCONNECT -- remove our connection with any foreground process**** Parameters:** fulldrop -- if set, we should also drop the controlling** TTY if possible -- this should only be done when** setting up the daemon since otherwise UUCP can** leave us trying to open a dialin, and we will** wait for the carrier.**** Returns:** none**** Side Effects:** Trys to insure that we are immune to vagaries of** the controlling tty.*/disconnect(fulldrop) bool fulldrop;{ int fd;#ifdef DEBUG if (tTd(52, 1)) printf("disconnect: In %d Out %d\n", fileno(InChannel), fileno(OutChannel)); if (tTd(52, 5)) { printf("don't\n"); return; }#endif DEBUG /* be sure we don't get nasty signals */ (void) signal(SIGHUP, SIG_IGN); (void) signal(SIGINT, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); /* we can't communicate with our caller, so.... */ HoldErrs = TRUE; ErrorMode = EM_MAIL; Verbose = FALSE; /* all input from /dev/null */ if (InChannel != stdin) { (void) fclose(InChannel); InChannel = stdin; } (void) freopen("/dev/null", "r", stdin); /* output to the transcript */ if (OutChannel != stdout) { (void) fclose(OutChannel); OutChannel = stdout; } if (CurEnv->e_xfp == NULL) CurEnv->e_xfp = fopen("/dev/null", "w"); (void) fflush(stdout); (void) close(1); (void) close(2); if (CurEnv->e_xfp != NULL) while ((fd = dup(fileno(CurEnv->e_xfp))) < 2 && fd > 0) continue;#ifdef TIOCNOTTY /* drop our controlling TTY completely if possible */ if (fulldrop) { fd = open("/dev/tty", 2); if (fd >= 0) { (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0); (void) close(fd); } (void) setpgrp(0, 0); errno = 0; }#endif TIOCNOTTY# ifdef LOG if (LogLevel > 11) syslog(LOG_DEBUG, "in background, pid=%d", getpid());# endif LOG errno = 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -