📄 deliver.c
字号:
** Returns:** From a macro??? You've got to be kidding!**** Side Effects:** Modifies the ==> LOCAL <== variable 'pid', leaving:** pid of child in parent, zero in child.** -1 on unrecoverable error.**** Notes:** I'm awfully sorry this looks so awful. That's** vfork for you.....*/# define NFORKTRIES 5# ifdef VMUNIX# define XFORK vfork# else VMUNIX# define XFORK fork# endif VMUNIX# define DOFORK(fORKfN) \{\ register int i;\\ for (i = NFORKTRIES; --i >= 0; )\ {\ pid = fORKfN();\ if (pid >= 0)\ break;\ if (i > 0)\ sleep((unsigned) NFORKTRIES - i);\ }\}/*** DOFORK -- simple fork interface to DOFORK.**** Parameters:** none.**** Returns:** pid of child in parent.** zero in child.** -1 on error.**** Side Effects:** returns twice, once in parent and once in child.*/dofork(){ register int pid; DOFORK(fork); return (pid);}/*** SENDOFF -- send off call to mailer & collect response.**** Parameters:** e -- the envelope to mail.** m -- mailer descriptor.** pvp -- parameter vector to send to it.** ctladdr -- an address pointer controlling the** user/groupid etc. of the mailer.**** Returns:** exit status of mailer.**** Side Effects:** If exit status is -1, ExitStat and errno are set as from** openmailer().*/sendoff(e, m, pvp, ctladdr) register ENVELOPE *e; MAILER *m; char **pvp; ADDRESS *ctladdr;{ auto FILE *mfile; auto FILE *rfile; register int i; int pid; /* ** Create connection to mailer. */ pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); if (pid < 0) return (EX_TEMPFAIL); /* ** Format and send message. */ putfromline(mfile, m); (*e->e_puthdr)(mfile, m, e); putline("\n", mfile, m); (*e->e_putbody)(mfile, m, e); (void) fclose(mfile); i = endmailer(pid, pvp[0]); /* arrange a return receipt if requested */ if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags)) { e->e_flags |= EF_SENDRECEIPT; /* do we want to send back more info? */ } return (i);}/*** ENDMAILER -- Wait for mailer to terminate.**** We should never get fatal errors (e.g., segmentation** violation), so we report those specially. For other** errors, we choose a status message (into statmsg),** and if it represents an error, we print it.**** Parameters:** pid -- pid of mailer.** name -- name of mailer (for error messages).**** Returns:** exit code of mailer.**** Side Effects:** none.*/char *enderr[] = { "Zero", "Hangup", "Interrupt", "Quit", "Illegal instruction", "Trace", "IOT", "EMT", "Floating point exception", "Kill", "Bus error", "Segmentation violation", "Bad argument to system call", "Broken pipe", "Alarm clock", "Software termination", "Urgent", "Stop", "Stop from keyboard", "Continue", "Child status", "Background read", "Background write", "I/O", "CPU time limit exceeded", "File size limit exceeded", "Virtual time alarm", "Profiling timer alarm", "Window change"} ;#define MAXENDERR (sizeof(enderr)/sizeof(enderr[0]))endmailer(pid, name) int pid; char *name;{ int st; /* in the IPC case there is nothing to wait for */ if (pid == 0) return (EX_OK); if (tTd(38, 1)) syslog(LOG_INFO, "Before the wait on pid %d\n", pid); /* wait for the mailer process to die and collect status */ st = waitfor(pid); if (tTd(38, 1)) syslog(LOG_INFO, "After the wait on pid %d\n", pid); if (st == -1) { syserr("endmailer %s: wait", name); return (EX_SOFTWARE); } /* see if it died a horrid death */ if ((st & 0377) != 0) { if (st < 0 || st >= MAXENDERR) message(Arpa_Info, "%s delivery program died with signal %d", name, st); else message(Arpa_Info, "%s delivery program died with %s signal", name, enderr[st]); ExitStat = EX_TEMPFAIL; return (EX_TEMPFAIL); } /* normal death -- return status */ st = (st >> 8) & 0377; return (st);}/*** OPENMAILER -- open connection to mailer.**** Parameters:** m -- mailer descriptor.** pvp -- parameter vector to pass to mailer.** ctladdr -- controlling address for user.** clever -- create a full duplex connection.** pmfile -- pointer to mfile (to mailer) connection.** prfile -- pointer to rfile (from mailer) connection.**** Returns:** pid of mailer ( > 0 ).** -1 on error, with errno set appropriately.** zero on an IPC connection.**** Side Effects:** creates a mailer in a subprocess.** Sets errno if it returns -1.*/openmailer(m, pvp, ctladdr, clever, pmfile, prfile) MAILER *m; char **pvp; ADDRESS *ctladdr; bool clever; FILE **pmfile; FILE **prfile;{ int pid; int mpvect[2]; int rpvect[2]; FILE *mfile; FILE *rfile; extern FILE *fdopen(); extern int DtableSize; /* main.c -- from getdtablesize() */# ifdef DEBUG if (tTd(11, 1)) { printf("openmailer:"); printav(pvp); }# endif DEBUG errno = 0; /* ** Deal with the special case of mail handled through an IPC ** connection. ** In this case we don't actually fork. We must be ** running SMTP for this to work. We will return a ** zero pid to indicate that we are running IPC. ** We also handle a debug version that just talks to stdin/out. */#ifdef DEBUG /* check for Local Person Communication -- not for mortals!!! */ if (strcmp(m->m_mailer, "[LPC]") == 0) { *pmfile = stdout; *prfile = stdin; return (0); }#endif DEBUG if (strcmp(m->m_mailer, "[IPC]") == 0 || strcmp(m->m_mailer, "[TCP]") == 0) {#ifdef DAEMON register int i, j; register u_short port; CurHostName = pvp[1]; if (!clever || mx == NULL) syserr("non-clever TCP"); if (pvp[2] != NULL) port = atoi(pvp[2]); else port = 0; for (j = 0; j < mx->mx_number; j++) { CurHostName = mx->mx_hosts[j]; if (Verbose && !sameword(CurHostName, pvp[1])) printf("mail exchanger is %s\n", CurHostName); i = makeconnection(CurHostName, port, pmfile, prfile); if (i == EX_OK) return(0); } /* Note that errno is set for this case */ ExitStat = i; return (-1);#else DAEMON syserr("openmailer: no TCP"); return (-1);#endif DAEMON } /* create a pipe to shove the mail through */ if (pipe(mpvect) < 0) { syserr("openmailer: pipe (to mailer)"); return (-1); }#ifdef SMTP /* if this mailer speaks smtp, create a return pipe */ if (clever && pipe(rpvect) < 0) { syserr("openmailer: pipe (from mailer)"); (void) close(mpvect[0]); (void) close(mpvect[1]); return (-1); }#endif SMTP /* ** Actually fork the mailer process. ** DOFORK is clever about retrying. ** ** Dispose of SIGCHLD signal catchers that may be laying ** around so that endmail will get it. */ if (CurEnv->e_xfp != NULL) (void) fflush(CurEnv->e_xfp); /* for debugging */ (void) fflush(stdout);# ifdef SIGCHLD (void) signal(SIGCHLD, SIG_DFL);# endif SIGCHLD DOFORK(XFORK); /* pid is set by DOFORK */ if (pid < 0) { /* failure */ syserr("openmailer: cannot fork"); (void) close(mpvect[0]); (void) close(mpvect[1]);#ifdef SMTP if (clever) { (void) close(rpvect[0]); (void) close(rpvect[1]); }#endif SMTP return (-1); } else if (pid == 0) { int i; /* child -- set up input & exec mailer */ /* make diagnostic output be standard output */ (void) signal(SIGINT, SIG_IGN); (void) signal(SIGHUP, SIG_IGN); (void) signal(SIGTERM, SIG_DFL); /* arrange to filter standard & diag output of command */ if (clever) { (void) close(rpvect[0]); (void) close(1); (void) dup(rpvect[1]); (void) close(rpvect[1]); } else if (OpMode == MD_SMTP || HoldErrs) { /* put mailer output in transcript */ (void) close(1); (void) dup(fileno(CurEnv->e_xfp)); } (void) close(2); (void) dup(1); /* arrange to get standard input */ (void) close(mpvect[1]); (void) close(0); if (dup(mpvect[0]) < 0) { syserr("Cannot dup to zero!"); _exit(EX_OSERR); } (void) close(mpvect[0]); if (!bitnset(M_RESTR, m->m_flags)) { if (ctladdr == NULL || ctladdr->q_uid == 0) { (void) setgid(DefGid); (void) initgroups(DefUser, DefGid); (void) setuid(DefUid); } else { (void) setgid(ctladdr->q_gid); (void) initgroups(ctladdr->q_ruser? ctladdr->q_ruser: ctladdr->q_user, ctladdr->q_gid); (void) setuid(ctladdr->q_uid); } } /* arrange for all the files to be closed */ for (i = 3; i < DtableSize; i++)#ifdef FIOCLEX (void) ioctl(i, FIOCLEX, 0);#else FIOCLEX (void) close(i);#endif FIOCLEX /* try to execute the mailer */ execve(m->m_mailer, pvp, UserEnviron);#ifdef FIOCLEX syserr("Cannot exec %s", m->m_mailer);#else FIOCLEX printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); (void) fflush(stdout);#endif FIOCLEX if (m == LocalMailer || errno == EIO || errno == EAGAIN || errno == ENOMEM || errno == EPROCLIM) _exit(EX_TEMPFAIL); else _exit(EX_UNAVAILABLE); } /* ** Set up return value. */ if (tTd(38, 1)) syslog(LOG_INFO, "Fork with pid %d\n", pid); (void) close(mpvect[0]); mfile = fdopen(mpvect[1], "w"); if (clever) { (void) close(rpvect[1]); rfile = fdopen(rpvect[0], "r"); } else rfile = NULL; *pmfile = mfile; *prfile = rfile; return (pid);}/*** GIVERESPONSE -- Interpret an error response from a mailer**** Parameters:** stat -- the status code from the mailer (high byte** only; core dumps must have been taken care of** already).** m -- the mailer descriptor for this mailer.**** Returns:** none.**** Side Effects:** Errors may be incremented.** ExitStat may be set.*/giveresponse(stat, m, e) int stat; register MAILER *m; ENVELOPE *e;{ register char *statmsg; extern char *SysExMsg[]; register int i; extern int N_SysEx; char buf[MAXLINE];#ifdef lint if (m == NULL) return;#endif lint /* ** Compute status message from code. */ i = stat - EX__BASE; if (stat == 0) statmsg = "250 Sent"; else if (i < 0 || i > N_SysEx) { (void) sprintf(buf, "554 unknown mailer error %d", stat); stat = EX_UNAVAILABLE; statmsg = buf; } else if (stat == EX_TEMPFAIL) { extern char SmtpError[]; if (AlreadyKnown) (void) strcpy(buf, "250 Skipped"); else (void) strcpy(buf, SysExMsg[i]); if (SmtpError[0] != '\0' && (errno == 0 || errno == ECONNRESET) ) { (void) strcat(buf, ": "); (void) strcat(buf, SmtpError); } else if (errno) { extern char *errstring(); (void) strcat(buf, ": "); (void) strcat(buf, errstring(errno)); } statmsg = buf; } else { statmsg = SysExMsg[i]; } /* ** Print the message as appropriate ** Note the "%s" is needed to prevent percent signs in recipient ** names from being treated as formatting commands. */ if (stat == EX_OK || stat == EX_TEMPFAIL) message(Arpa_Info, "%s", &statmsg[4]); else { Errors++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -