diff options
Diffstat (limited to 'mailutils/mail.c')
-rw-r--r-- | mailutils/mail.c | 88 |
1 files changed, 53 insertions, 35 deletions
diff --git a/mailutils/mail.c b/mailutils/mail.c index 3a1fd6949..f48b41bab 100644 --- a/mailutils/mail.c +++ b/mailutils/mail.c | |||
@@ -6,39 +6,45 @@ | |||
6 | * | 6 | * |
7 | * Licensed under GPLv2, see file LICENSE in this source tree. | 7 | * Licensed under GPLv2, see file LICENSE in this source tree. |
8 | */ | 8 | */ |
9 | #include <sys/prctl.h> | 9 | #if defined(__linux__) |
10 | # include <sys/prctl.h> | ||
11 | # define PRCTL | ||
12 | #elif defined(__FreeBSD__) | ||
13 | # include <sys/procctl.h> | ||
14 | # define PROCCTL | ||
15 | #endif | ||
10 | #include "libbb.h" | 16 | #include "libbb.h" |
11 | #include "mail.h" | 17 | #include "mail.h" |
12 | 18 | ||
13 | // generic signal handler | 19 | // common signal handler |
14 | static void signal_handler(int signo) | 20 | static void signal_handler(int signo) |
15 | { | 21 | { |
16 | #define err signo | ||
17 | if (SIGALRM == signo) { | 22 | if (SIGALRM == signo) { |
18 | bb_simple_error_msg_and_die("timed out"); | 23 | bb_simple_error_msg_and_die("timed out"); |
19 | } | 24 | } |
20 | 25 | ||
21 | // SIGCHLD. reap zombies | 26 | // SIGCHLD. reap the zombie if we expect one |
22 | if (safe_waitpid(G.helper_pid, &err, WNOHANG) > 0) { | 27 | if (G.helper_pid == 0) |
23 | if (WIFSIGNALED(err)) | 28 | return; |
24 | bb_error_msg_and_die("helper killed by signal %u", WTERMSIG(err)); | 29 | #define status signo |
25 | if (WIFEXITED(err)) { | 30 | if (safe_waitpid(G.helper_pid, &status, WNOHANG) > 0) { |
26 | G.helper_pid = 0; | 31 | G.helper_pid = 0; |
27 | if (WEXITSTATUS(err)) | 32 | if (WIFSIGNALED(status)) |
28 | bb_error_msg_and_die("helper exited (%u)", WEXITSTATUS(err)); | 33 | bb_error_msg_and_die("helper killed by signal %u", WTERMSIG(status)); |
29 | } | 34 | if (WIFEXITED(status) && WEXITSTATUS(status) != 0) |
35 | bb_error_msg_and_die("helper exited (%u)", WEXITSTATUS(status)); | ||
30 | } | 36 | } |
31 | #undef err | 37 | #undef status |
32 | } | 38 | } |
33 | 39 | ||
34 | void FAST_FUNC launch_helper(const char **argv) | 40 | void FAST_FUNC launch_helper(const char **argv) |
35 | { | 41 | { |
36 | // setup vanilla unidirectional pipes interchange | 42 | pid_t pid; |
37 | int i; | 43 | struct fd_pair child_out; |
38 | int pipes[4]; | 44 | struct fd_pair child_in; |
39 | 45 | ||
40 | xpipe(pipes); | 46 | xpiped_pair(child_out); |
41 | xpipe(pipes + 2); | 47 | xpiped_pair(child_in); |
42 | 48 | ||
43 | // NB: handler must be installed before vfork | 49 | // NB: handler must be installed before vfork |
44 | bb_signals(0 | 50 | bb_signals(0 |
@@ -46,40 +52,52 @@ void FAST_FUNC launch_helper(const char **argv) | |||
46 | + (1 << SIGALRM) | 52 | + (1 << SIGALRM) |
47 | , signal_handler); | 53 | , signal_handler); |
48 | 54 | ||
49 | G.helper_pid = xvfork(); | 55 | fflush_all(); |
50 | 56 | pid = xvfork(); | |
51 | i = (!G.helper_pid) * 2; // for parent:0, for child:2 | 57 | if (pid == 0) { |
52 | close(pipes[i + 1]); // 1 or 3 - closing one write end | ||
53 | close(pipes[2 - i]); // 2 or 0 - closing one read end | ||
54 | xmove_fd(pipes[i], STDIN_FILENO); // 0 or 2 - using other read end | ||
55 | xmove_fd(pipes[3 - i], STDOUT_FILENO); // 3 or 1 - using other write end | ||
56 | // End result: | ||
57 | // parent stdout [3] -> child stdin [2] | ||
58 | // child stdout [1] -> parent stdin [0] | ||
59 | |||
60 | if (!G.helper_pid) { | ||
61 | // child | 58 | // child |
59 | close(child_in.wr); | ||
60 | close(child_out.rd); | ||
61 | xmove_fd(child_in.rd, STDIN_FILENO); | ||
62 | xmove_fd(child_out.wr, STDOUT_FILENO); | ||
62 | // if parent dies, get SIGTERM | 63 | // if parent dies, get SIGTERM |
64 | #if defined(PRCTL) | ||
63 | prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); | 65 | prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); |
66 | #elif defined(PROCCTL) | ||
67 | { | ||
68 | int signum = SIGTERM; | ||
69 | procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum); | ||
70 | } | ||
71 | #endif | ||
64 | // try to execute connection helper | 72 | // try to execute connection helper |
65 | // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec | 73 | // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec |
66 | BB_EXECVP_or_die((char**)argv); | 74 | BB_EXECVP_or_die((char**)argv); |
67 | } | 75 | } |
76 | G.helper_pid = pid; | ||
77 | close(child_out.wr); | ||
78 | close(child_in.rd); | ||
79 | xmove_fd(child_out.rd, STDIN_FILENO); | ||
80 | xmove_fd(child_in.wr, STDOUT_FILENO); | ||
68 | 81 | ||
69 | // parent goes on | 82 | // parent goes on |
70 | } | 83 | } |
71 | 84 | ||
85 | void FAST_FUNC send_r_n(const char *s) | ||
86 | { | ||
87 | if (G.verbose) | ||
88 | bb_error_msg("send:'%s'", s); | ||
89 | printf("%s\r\n", s); | ||
90 | } | ||
91 | |||
72 | char* FAST_FUNC send_mail_command(const char *fmt, const char *param) | 92 | char* FAST_FUNC send_mail_command(const char *fmt, const char *param) |
73 | { | 93 | { |
74 | char *msg; | 94 | char *msg; |
75 | if (timeout) | 95 | if (G.timeout) |
76 | alarm(timeout); | 96 | alarm(G.timeout); |
77 | msg = (char*)fmt; | 97 | msg = (char*)fmt; |
78 | if (fmt) { | 98 | if (fmt) { |
79 | msg = xasprintf(fmt, param); | 99 | msg = xasprintf(fmt, param); |
80 | if (verbose) | 100 | send_r_n(msg); |
81 | bb_error_msg("send:'%s'", msg); | ||
82 | printf("%s\r\n", msg); | ||
83 | } | 101 | } |
84 | fflush_all(); | 102 | fflush_all(); |
85 | return msg; | 103 | return msg; |