diff options
author | Rom Lemarchand | 2013-03-20 15:46:53 -0500 |
---|---|---|
committer | Rom Lemarchand | 2013-03-20 18:26:22 -0500 |
commit | 6ad53df6335520befee74efafca41d625baa9023 (patch) | |
tree | 9322d7f88f97f808bfe4bccc98c130589ff4dc67 /logwrapper/logwrap.c | |
parent | 7bce39cac65166f39d0f26453da6e59e236d2ab5 (diff) | |
download | platform-system-core-6ad53df6335520befee74efafca41d625baa9023.tar.gz platform-system-core-6ad53df6335520befee74efafca41d625baa9023.tar.xz platform-system-core-6ad53df6335520befee74efafca41d625baa9023.zip |
liblogwrap: use POLLHUP flag to check when a child dies
Replace the old signal handling mechanism with a check of POLLHUP
to check when the child has died.
See http://b/8333626
Change-Id: Ic9909b6660b1c3d1ed3015568b1a1ee1c25afe20
Diffstat (limited to 'logwrapper/logwrap.c')
-rw-r--r-- | logwrapper/logwrap.c | 151 |
1 files changed, 49 insertions, 102 deletions
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c index 129ffb131..bf9197759 100644 --- a/logwrapper/logwrap.c +++ b/logwrapper/logwrap.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <string.h> | 17 | #include <string.h> |
18 | #include <sys/types.h> | 18 | #include <sys/types.h> |
19 | #include <sys/socket.h> | 19 | #include <sys/socket.h> |
20 | #include <signal.h> | ||
21 | #include <poll.h> | 20 | #include <poll.h> |
22 | #include <sys/wait.h> | 21 | #include <sys/wait.h> |
23 | #include <stdio.h> | 22 | #include <stdio.h> |
@@ -35,7 +34,6 @@ | |||
35 | 34 | ||
36 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) | 35 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) |
37 | 36 | ||
38 | static int signal_fd_write; | ||
39 | static pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER; | 37 | static pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER; |
40 | 38 | ||
41 | #define ERROR(fmt, args...) \ | 39 | #define ERROR(fmt, args...) \ |
@@ -50,94 +48,77 @@ do { \ | |||
50 | _exit(-1); \ | 48 | _exit(-1); \ |
51 | } while(0) | 49 | } while(0) |
52 | 50 | ||
53 | static int parent(const char *tag, int parent_read, int signal_fd, pid_t pid, | 51 | static int parent(const char *tag, int parent_read, pid_t pid, int *chld_sts, |
54 | int *chld_sts, bool logwrap) { | 52 | bool logwrap) { |
55 | int status = 0; | 53 | int status = 0; |
56 | char buffer[4096]; | 54 | char buffer[4096]; |
57 | struct pollfd poll_fds[] = { | 55 | struct pollfd poll_fds[] = { |
58 | [0] = { | 56 | [0] = { |
59 | .fd = signal_fd, | ||
60 | .events = POLLIN, | ||
61 | }, | ||
62 | [1] = { | ||
63 | .fd = parent_read, | 57 | .fd = parent_read, |
64 | .events = POLLIN, | 58 | .events = POLLIN, |
65 | }, | 59 | }, |
66 | }; | 60 | }; |
67 | int rc = 0; | 61 | int rc = 0; |
68 | sigset_t chldset; | ||
69 | 62 | ||
70 | int a = 0; // start index of unprocessed data | 63 | int a = 0; // start index of unprocessed data |
71 | int b = 0; // end index of unprocessed data | 64 | int b = 0; // end index of unprocessed data |
72 | int sz; | 65 | int sz; |
73 | bool remote_hung = false; | ||
74 | bool found_child = false; | 66 | bool found_child = false; |
75 | 67 | ||
76 | char *btag = basename(tag); | 68 | char *btag = basename(tag); |
77 | if (!btag) btag = (char*) tag; | 69 | if (!btag) btag = (char*) tag; |
78 | 70 | ||
79 | sigemptyset(&chldset); | ||
80 | sigaddset(&chldset, SIGCHLD); | ||
81 | pthread_sigmask(SIG_UNBLOCK, &chldset, NULL); | ||
82 | |||
83 | while (!found_child) { | 71 | while (!found_child) { |
84 | if (TEMP_FAILURE_RETRY(poll(poll_fds, remote_hung ? 1 : 2, -1)) < 0) { | 72 | if (TEMP_FAILURE_RETRY(poll(poll_fds, ARRAY_SIZE(poll_fds), -1)) < 0) { |
85 | ERROR("poll failed\n"); | 73 | ERROR("poll failed\n"); |
86 | rc = -1; | 74 | rc = -1; |
87 | goto err_poll; | 75 | goto err_poll; |
88 | } | 76 | } |
89 | 77 | ||
90 | if (!remote_hung) { | 78 | if (poll_fds[0].revents & POLLIN) { |
91 | if (poll_fds[1].revents & POLLIN) { | 79 | sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b); |
92 | sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b); | ||
93 | |||
94 | sz += b; | ||
95 | // Log one line at a time | ||
96 | for (b = 0; b < sz; b++) { | ||
97 | if (buffer[b] == '\r') { | ||
98 | buffer[b] = '\0'; | ||
99 | } else if (buffer[b] == '\n') { | ||
100 | buffer[b] = '\0'; | ||
101 | if (logwrap) | ||
102 | ALOG(LOG_INFO, btag, "%s", &buffer[a]); | ||
103 | a = b + 1; | ||
104 | } | ||
105 | } | ||
106 | 80 | ||
107 | if (a == 0 && b == sizeof(buffer) - 1) { | 81 | sz += b; |
108 | // buffer is full, flush | 82 | // Log one line at a time |
83 | for (b = 0; b < sz; b++) { | ||
84 | if (buffer[b] == '\r') { | ||
85 | buffer[b] = '\0'; | ||
86 | } else if (buffer[b] == '\n') { | ||
109 | buffer[b] = '\0'; | 87 | buffer[b] = '\0'; |
110 | if (logwrap) | 88 | if (logwrap) |
111 | ALOG(LOG_INFO, btag, "%s", &buffer[a]); | 89 | ALOG(LOG_INFO, btag, "%s", &buffer[a]); |
112 | b = 0; | 90 | a = b + 1; |
113 | } else if (a != b) { | ||
114 | // Keep left-overs | ||
115 | b -= a; | ||
116 | memmove(buffer, &buffer[a], b); | ||
117 | a = 0; | ||
118 | } else { | ||
119 | a = 0; | ||
120 | b = 0; | ||
121 | } | 91 | } |
122 | } | 92 | } |
123 | 93 | ||
124 | if (poll_fds[1].revents & POLLHUP) { | 94 | if (a == 0 && b == sizeof(buffer) - 1) { |
125 | remote_hung = true; | 95 | // buffer is full, flush |
96 | buffer[b] = '\0'; | ||
97 | if (logwrap) | ||
98 | ALOG(LOG_INFO, btag, "%s", &buffer[a]); | ||
99 | b = 0; | ||
100 | } else if (a != b) { | ||
101 | // Keep left-overs | ||
102 | b -= a; | ||
103 | memmove(buffer, &buffer[a], b); | ||
104 | a = 0; | ||
105 | } else { | ||
106 | a = 0; | ||
107 | b = 0; | ||
126 | } | 108 | } |
127 | } | 109 | } |
128 | 110 | ||
129 | if (poll_fds[0].revents & POLLIN) { | 111 | if (poll_fds[0].revents & POLLHUP) { |
130 | char tmp[32]; | ||
131 | int ret; | 112 | int ret; |
132 | 113 | ||
133 | read(signal_fd, tmp, sizeof(tmp)); | 114 | ret = waitpid(pid, &status, WNOHANG); |
134 | while (!found_child) { | 115 | if (ret < 0) { |
135 | ret = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG)); | 116 | rc = errno; |
136 | 117 | ALOG(LOG_ERROR, "logwrap", "waitpid failed with %s\n", strerror(errno)); | |
137 | if (ret <= 0) | 118 | goto err_waitpid; |
138 | break; | 119 | } |
139 | 120 | if (ret > 0) { | |
140 | found_child = (pid == ret); | 121 | found_child = true; |
141 | } | 122 | } |
142 | } | 123 | } |
143 | } | 124 | } |
@@ -171,6 +152,7 @@ static int parent(const char *tag, int parent_read, int signal_fd, pid_t pid, | |||
171 | } | 152 | } |
172 | } | 153 | } |
173 | 154 | ||
155 | err_waitpid: | ||
174 | err_poll: | 156 | err_poll: |
175 | return rc; | 157 | return rc; |
176 | } | 158 | } |
@@ -187,23 +169,16 @@ static void child(int argc, char* argv[], bool logwrap) { | |||
187 | } | 169 | } |
188 | } | 170 | } |
189 | 171 | ||
190 | static void sigchld_handler(int sig) { | ||
191 | write(signal_fd_write, &sig, 1); | ||
192 | } | ||
193 | |||
194 | int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_quit, | 172 | int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_quit, |
195 | bool logwrap) { | 173 | bool logwrap) { |
196 | pid_t pid; | 174 | pid_t pid; |
197 | int parent_ptty; | 175 | int parent_ptty; |
198 | int child_ptty; | 176 | int child_ptty; |
199 | char *child_devname = NULL; | 177 | char *child_devname = NULL; |
200 | struct sigaction chldact; | ||
201 | struct sigaction oldchldact; | ||
202 | struct sigaction intact; | 178 | struct sigaction intact; |
203 | struct sigaction quitact; | 179 | struct sigaction quitact; |
204 | sigset_t blockset; | 180 | sigset_t blockset; |
205 | sigset_t oldset; | 181 | sigset_t oldset; |
206 | int sockets[2]; | ||
207 | int rc = 0; | 182 | int rc = 0; |
208 | 183 | ||
209 | rc = pthread_mutex_lock(&fd_mutex); | 184 | rc = pthread_mutex_lock(&fd_mutex); |
@@ -227,14 +202,21 @@ int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_qui | |||
227 | goto err_ptty; | 202 | goto err_ptty; |
228 | } | 203 | } |
229 | 204 | ||
205 | child_ptty = open(child_devname, O_RDWR); | ||
206 | if (child_ptty < 0) { | ||
207 | ERROR("Cannot open child_ptty\n"); | ||
208 | rc = -1; | ||
209 | goto err_child_ptty; | ||
210 | } | ||
211 | |||
230 | sigemptyset(&blockset); | 212 | sigemptyset(&blockset); |
231 | sigaddset(&blockset, SIGINT); | 213 | sigaddset(&blockset, SIGINT); |
232 | sigaddset(&blockset, SIGQUIT); | 214 | sigaddset(&blockset, SIGQUIT); |
233 | sigaddset(&blockset, SIGCHLD); | ||
234 | pthread_sigmask(SIG_BLOCK, &blockset, &oldset); | 215 | pthread_sigmask(SIG_BLOCK, &blockset, &oldset); |
235 | 216 | ||
236 | pid = fork(); | 217 | pid = fork(); |
237 | if (pid < 0) { | 218 | if (pid < 0) { |
219 | close(child_ptty); | ||
238 | ERROR("Failed to fork\n"); | 220 | ERROR("Failed to fork\n"); |
239 | rc = -1; | 221 | rc = -1; |
240 | goto err_fork; | 222 | goto err_fork; |
@@ -243,12 +225,6 @@ int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_qui | |||
243 | pthread_sigmask(SIG_SETMASK, &oldset, NULL); | 225 | pthread_sigmask(SIG_SETMASK, &oldset, NULL); |
244 | close(parent_ptty); | 226 | close(parent_ptty); |
245 | 227 | ||
246 | child_ptty = open(child_devname, O_RDWR); | ||
247 | if (child_ptty < 0) { | ||
248 | FATAL_CHILD("Problem with child ptty\n"); | ||
249 | return -1; | ||
250 | } | ||
251 | |||
252 | // redirect stdout and stderr | 228 | // redirect stdout and stderr |
253 | dup2(child_ptty, 1); | 229 | dup2(child_ptty, 1); |
254 | dup2(child_ptty, 2); | 230 | dup2(child_ptty, 2); |
@@ -256,55 +232,26 @@ int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_qui | |||
256 | 232 | ||
257 | child(argc, argv, logwrap); | 233 | child(argc, argv, logwrap); |
258 | } else { | 234 | } else { |
259 | struct sigaction ignact; | 235 | close(child_ptty); |
260 | |||
261 | memset(&chldact, 0, sizeof(chldact)); | ||
262 | chldact.sa_handler = sigchld_handler; | ||
263 | chldact.sa_flags = SA_NOCLDSTOP; | ||
264 | |||
265 | sigaction(SIGCHLD, &chldact, &oldchldact); | ||
266 | if ((!(oldchldact.sa_flags & SA_SIGINFO) && | ||
267 | oldchldact.sa_handler != SIG_DFL && | ||
268 | oldchldact.sa_handler != SIG_IGN) || | ||
269 | ((oldchldact.sa_flags & SA_SIGINFO) && | ||
270 | oldchldact.sa_sigaction != NULL)) { | ||
271 | ALOG(LOG_WARN, "logwrapper", "logwrap replaced the SIGCHLD " | ||
272 | "handler and might cause interaction issues"); | ||
273 | } | ||
274 | |||
275 | if (ignore_int_quit) { | 236 | if (ignore_int_quit) { |
237 | struct sigaction ignact; | ||
238 | |||
276 | memset(&ignact, 0, sizeof(ignact)); | 239 | memset(&ignact, 0, sizeof(ignact)); |
277 | ignact.sa_handler = SIG_IGN; | 240 | ignact.sa_handler = SIG_IGN; |
278 | sigaction(SIGINT, &ignact, &intact); | 241 | sigaction(SIGINT, &ignact, &intact); |
279 | sigaction(SIGQUIT, &ignact, &quitact); | 242 | sigaction(SIGQUIT, &ignact, &quitact); |
280 | } | 243 | } |
281 | 244 | ||
282 | rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); | 245 | rc = parent(argv[0], parent_ptty, pid, status, logwrap); |
283 | if (rc == -1) { | ||
284 | ERROR("socketpair failed: %s\n", strerror(errno)); | ||
285 | goto err_socketpair; | ||
286 | } | ||
287 | |||
288 | fcntl(sockets[0], F_SETFD, FD_CLOEXEC); | ||
289 | fcntl(sockets[0], F_SETFL, O_NONBLOCK); | ||
290 | fcntl(sockets[1], F_SETFD, FD_CLOEXEC); | ||
291 | fcntl(sockets[1], F_SETFL, O_NONBLOCK); | ||
292 | |||
293 | signal_fd_write = sockets[0]; | ||
294 | |||
295 | rc = parent(argv[0], parent_ptty, sockets[1], pid, status, logwrap); | ||
296 | } | 246 | } |
297 | 247 | ||
298 | close(sockets[0]); | ||
299 | close(sockets[1]); | ||
300 | err_socketpair: | ||
301 | if (ignore_int_quit) { | 248 | if (ignore_int_quit) { |
302 | sigaction(SIGINT, &intact, NULL); | 249 | sigaction(SIGINT, &intact, NULL); |
303 | sigaction(SIGQUIT, &quitact, NULL); | 250 | sigaction(SIGQUIT, &quitact, NULL); |
304 | } | 251 | } |
305 | sigaction(SIGCHLD, &oldchldact, NULL); | ||
306 | err_fork: | 252 | err_fork: |
307 | pthread_sigmask(SIG_SETMASK, &oldset, NULL); | 253 | pthread_sigmask(SIG_SETMASK, &oldset, NULL); |
254 | err_child_ptty: | ||
308 | err_ptty: | 255 | err_ptty: |
309 | close(parent_ptty); | 256 | close(parent_ptty); |
310 | err_open: | 257 | err_open: |