aboutsummaryrefslogtreecommitdiff
path: root/mailutils
diff options
context:
space:
mode:
Diffstat (limited to 'mailutils')
-rw-r--r--mailutils/mail.c56
1 files changed, 27 insertions, 29 deletions
diff --git a/mailutils/mail.c b/mailutils/mail.c
index 9735d48f6..7e9efdbfa 100644
--- a/mailutils/mail.c
+++ b/mailutils/mail.c
@@ -10,35 +10,35 @@
#include "libbb.h"
#include "mail.h"
-// generic signal handler
+// common signal handler
static void signal_handler(int signo)
{
-#define err signo
if (SIGALRM == signo) {
bb_simple_error_msg_and_die("timed out");
}
- // SIGCHLD. reap zombies
- if (safe_waitpid(G.helper_pid, &err, WNOHANG) > 0) {
- if (WIFSIGNALED(err))
- bb_error_msg_and_die("helper killed by signal %u", WTERMSIG(err));
- if (WIFEXITED(err)) {
- G.helper_pid = 0;
- if (WEXITSTATUS(err))
- bb_error_msg_and_die("helper exited (%u)", WEXITSTATUS(err));
- }
+ // SIGCHLD. reap the zombie if we expect one
+ if (G.helper_pid == 0)
+ return;
+#define status signo
+ if (safe_waitpid(G.helper_pid, &status, WNOHANG) > 0) {
+ G.helper_pid = 0;
+ if (WIFSIGNALED(status))
+ bb_error_msg_and_die("helper killed by signal %u", WTERMSIG(status));
+ if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
+ bb_error_msg_and_die("helper exited (%u)", WEXITSTATUS(status));
}
-#undef err
+#undef status
}
void FAST_FUNC launch_helper(const char **argv)
{
- // setup vanilla unidirectional pipes interchange
- int i;
- int pipes[4];
+ pid_t pid;
+ struct fd_pair child_out;
+ struct fd_pair child_in;
- xpipe(pipes);
- xpipe(pipes + 2);
+ xpiped_pair(child_out);
+ xpiped_pair(child_in);
// NB: handler must be installed before vfork
bb_signals(0
@@ -46,25 +46,23 @@ void FAST_FUNC launch_helper(const char **argv)
+ (1 << SIGALRM)
, signal_handler);
- G.helper_pid = xvfork();
-
- i = (!G.helper_pid) * 2; // for parent:0, for child:2
- close(pipes[i + 1]); // 1 or 3 - closing one write end
- close(pipes[2 - i]); // 2 or 0 - closing one read end
- xmove_fd(pipes[i], STDIN_FILENO); // 0 or 2 - using other read end
- xmove_fd(pipes[3 - i], STDOUT_FILENO); // 3 or 1 - using other write end
- // End result:
- // parent stdout [3] -> child stdin [2]
- // child stdout [1] -> parent stdin [0]
-
- if (!G.helper_pid) {
+ G.helper_pid = pid = xvfork();
+ if (pid == 0) {
// child
+ close(child_in.wr);
+ close(child_out.rd);
+ xmove_fd(child_in.rd, STDIN_FILENO);
+ xmove_fd(child_out.wr, STDOUT_FILENO);
// if parent dies, get SIGTERM
prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
// try to execute connection helper
// NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec
BB_EXECVP_or_die((char**)argv);
}
+ close(child_out.wr);
+ close(child_in.rd);
+ xmove_fd(child_out.rd, STDIN_FILENO);
+ xmove_fd(child_in.wr, STDOUT_FILENO);
// parent goes on
}