send.c:
/*
* Fork, set up the temporary mail file as standard
* input for "mail", and exec with the user list we generated
* far above.
*/
pid = fork();
if (pid == -1) {
warn("fork");
savedeadletter(mtf);
goto out;
}
if (pid == 0) {
sigset_t nset;
sigemptyset(&nset);
sigaddset(&nset, SIGHUP);
sigaddset(&nset, SIGINT);
sigaddset(&nset, SIGQUIT);
sigaddset(&nset, SIGTSTP);
sigaddset(&nset, SIGTTIN);
sigaddset(&nset, SIGTTOU);
prepare_child(&nset, fileno(mtf), -1);
if ((cp = value("sendmail")) != NULL)
cp = expand(cp);
else
cp = _PATH_SENDMAIL;
execv(cp, namelist);
warn("%s", cp);
_exit(1);
}
#ifndef DEBIAN
if (value("verbose") != NULL)
(void)wait_child(pid);
else
free_child(pid);
#else
/*
* Always wait for sendmail and check its error code.
* See: Bug#145379
*/
if ((w = wait_child(pid))) {
fprintf(stderr, "Can't send mail: sendmail process failed");
if (w > 0)
fprintf(stderr, " with error code %d", w);
fprintf(stderr, "\n");
savedeadletter(mtf);
}
#endif
main.c:
/*
* Set up a reasonable environment.
* Figure out whether we are being run interactively,
* start the SIGCHLD catcher, and so forth.
*/
(void)signal(SIGCHLD, sigchild);
popen.c:
/* ARGSUSED */
void
sigchild(int signo)
{
pid_t pid;
int status;
struct child *cp;
int save_errno = errno;
while ((pid = waitpid((pid_t)-1, &status, WNOHANG)) > 0) {
cp = findchild(pid, 1);
if (!cp)
continue;
if (cp->free)
delchild(cp);
else {
cp->done = 1;
cp->status = status;
}
}
errno = save_errno;
}
int wait_status;
/*
* Wait for a specific child to die.
*/
int
wait_child(pid_t pid)
{
struct child *cp;
sigset_t nset, oset;
pid_t rv = 0;
sigemptyset(&nset);
sigaddset(&nset, SIGCHLD);
sigprocmask(SIG_BLOCK, &nset, &oset);
/*
* If we have not already waited on the pid (via sigchild)
* wait on it now. Otherwise, use the wait status stashed
* by sigchild.
*/
cp = findchild(pid, 1);
if (cp == NULL || !cp->done)
rv = waitpid(pid, &wait_status, 0);
else
wait_status = cp->status;
if (cp != NULL)
delchild(cp);
sigprocmask(SIG_SETMASK, &oset, NULL);
if (rv >= 0 && (WIFEXITED(wait_status)))
return (WEXITSTATUS(wait_status));
else
return(-1);
}