blob: e8a90e647ad7f9534d66f9024f86e5fa0c6f24f3 [file] [log] [blame]
San Mehat49e2bce2009-10-12 16:29:01 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <string.h>
Rom Lemarchandb9dcde72012-12-27 10:45:02 -080018#include <sys/select.h>
19#include <sys/socket.h>
San Mehat49e2bce2009-10-12 16:29:01 -070020#include <sys/types.h>
21#include <sys/wait.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <unistd.h>
25#include <errno.h>
26#include <fcntl.h>
Rom Lemarchandb9dcde72012-12-27 10:45:02 -080027#include <pthread.h>
San Mehat49e2bce2009-10-12 16:29:01 -070028
29#include "private/android_filesystem_config.h"
30#include "cutils/log.h"
Glenn Kasten1b4807b2012-03-05 15:14:33 -080031#include "cutils/sched_policy.h"
San Mehat49e2bce2009-10-12 16:29:01 -070032
Rom Lemarchandb9dcde72012-12-27 10:45:02 -080033struct monitor_data {
34 const char *tag;
35 int fd;
36};
37
38static int parent(const char *tag, int parent_read, int monitor_read) {
San Mehat49e2bce2009-10-12 16:29:01 -070039 int status;
40 char buffer[4096];
Rom Lemarchandb9dcde72012-12-27 10:45:02 -080041 fd_set fds;
42 int maxfd;
43 int rc = -EAGAIN;
San Mehat49e2bce2009-10-12 16:29:01 -070044
45 int a = 0; // start index of unprocessed data
46 int b = 0; // end index of unprocessed data
47 int sz;
San Mehat49e2bce2009-10-12 16:29:01 -070048
Rom Lemarchandb9dcde72012-12-27 10:45:02 -080049 maxfd = 1 + (parent_read > monitor_read ? parent_read : monitor_read);
San Mehat49e2bce2009-10-12 16:29:01 -070050
Rom Lemarchandb9dcde72012-12-27 10:45:02 -080051 do {
52 FD_ZERO(&fds);
53 FD_SET(parent_read, &fds);
54 FD_SET(monitor_read, &fds);
55
56 if (select(maxfd, &fds, NULL, NULL, NULL) <= 0) {
57 ALOG(LOG_INFO, "logwrapper", "select failed");
58 break;
59 }
60
61 if (FD_ISSET(parent_read, &fds)) {
62 sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b);
63
64 sz += b;
65 // Log one line at a time
66 for (b = 0; b < sz; b++) {
67 if (buffer[b] == '\r') {
68 buffer[b] = '\0';
69 } else if (buffer[b] == '\n') {
70 buffer[b] = '\0';
71
72 ALOG(LOG_INFO, tag, "%s", &buffer[a]);
73 a = b + 1;
74 }
75 }
76
77 if (a == 0 && b == sizeof(buffer) - 1) {
78 // buffer is full, flush
79 buffer[b] = '\0';
Steve Block8c487332011-10-12 17:28:59 +010080 ALOG(LOG_INFO, tag, "%s", &buffer[a]);
Rom Lemarchandb9dcde72012-12-27 10:45:02 -080081 b = 0;
82 } else if (a != b) {
83 // Keep left-overs
84 b -= a;
85 memmove(buffer, &buffer[a], b);
86 a = 0;
87 } else {
88 a = 0;
89 b = 0;
San Mehat49e2bce2009-10-12 16:29:01 -070090 }
91 }
92
Rom Lemarchandb9dcde72012-12-27 10:45:02 -080093 // Child exited, get return status and exit loop
94 if (FD_ISSET(monitor_read, &fds)) {
95 if (read(monitor_read, &rc, sizeof(rc)) != sizeof(rc)) {
96 ALOG(LOG_ERROR, "logwrapper", "Unable to read child return "
97 "status");
98 rc = -ECHILD;
99 }
100 break;
San Mehat49e2bce2009-10-12 16:29:01 -0700101 }
Rom Lemarchandb9dcde72012-12-27 10:45:02 -0800102 } while (1);
San Mehat49e2bce2009-10-12 16:29:01 -0700103
San Mehat49e2bce2009-10-12 16:29:01 -0700104 // Flush remaining data
105 if (a != b) {
106 buffer[b] = '\0';
Steve Block8c487332011-10-12 17:28:59 +0100107 ALOG(LOG_INFO, tag, "%s", &buffer[a]);
San Mehat49e2bce2009-10-12 16:29:01 -0700108 }
Rom Lemarchandb9dcde72012-12-27 10:45:02 -0800109
110 return rc;
San Mehat49e2bce2009-10-12 16:29:01 -0700111}
112
Rom Lemarchandb9dcde72012-12-27 10:45:02 -0800113static void child(int argc, const char**argv) {
San Mehat49e2bce2009-10-12 16:29:01 -0700114 // create null terminated argv_child array
115 char* argv_child[argc + 1];
116 memcpy(argv_child, argv, argc * sizeof(char *));
117 argv_child[argc] = NULL;
118
119 // XXX: PROTECT FROM VIKING KILLER
120 if (execv(argv_child[0], argv_child)) {
Steve Block8c487332011-10-12 17:28:59 +0100121 ALOG(LOG_ERROR, "logwrapper",
San Mehat49e2bce2009-10-12 16:29:01 -0700122 "executing %s failed: %s", argv_child[0], strerror(errno));
Rom Lemarchande90c1742012-12-21 11:35:43 -0800123 _exit(-1);
San Mehat49e2bce2009-10-12 16:29:01 -0700124 }
125}
126
Rom Lemarchandb9dcde72012-12-27 10:45:02 -0800127static void *monitor(void *arg)
128{
129 struct monitor_data *data = arg;
130 int status;
131 int rc = -EAGAIN;
132
133 if (wait(&status) != -1) { // Wait for child
134 if (WIFEXITED(status)) {
135 if (WEXITSTATUS(status) != 0) {
136 ALOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)",
137 data->tag, WEXITSTATUS(status));
138 }
139 rc = WEXITSTATUS(status);
140 } else if (WIFSIGNALED(status))
141 ALOG(LOG_INFO, "logwrapper", "%s terminated by signal %d",
142 data->tag, WTERMSIG(status));
143 else if (WIFSTOPPED(status))
144 ALOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", data->tag,
145 WSTOPSIG(status));
146 } else
147 ALOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", data->tag,
148 strerror(errno), errno);
149
150 write(data->fd, &rc, sizeof(rc));
151 return NULL;
152}
153
San Mehat49e2bce2009-10-12 16:29:01 -0700154int logwrap(int argc, const char* argv[], int background)
155{
156 pid_t pid;
157
158 int parent_ptty;
159 int child_ptty;
160 char *child_devname = NULL;
161
162 /* Use ptty instead of socketpair so that STDOUT is not buffered */
163 parent_ptty = open("/dev/ptmx", O_RDWR);
164 if (parent_ptty < 0) {
Steve Block8c487332011-10-12 17:28:59 +0100165 ALOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty");
166 return -errno;
San Mehat49e2bce2009-10-12 16:29:01 -0700167 }
168
169 if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
170 ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
San Mehat8c940ef2010-02-13 14:19:53 -0800171 close(parent_ptty);
Steve Block8c487332011-10-12 17:28:59 +0100172 ALOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx");
173 return -1;
San Mehat49e2bce2009-10-12 16:29:01 -0700174 }
175
176 pid = fork();
177 if (pid < 0) {
Brad Fitzpatrick1b15d462010-09-20 11:11:46 -0700178 close(parent_ptty);
Steve Block8c487332011-10-12 17:28:59 +0100179 ALOG(LOG_ERROR, "logwrapper", "Failed to fork");
San Mehat49e2bce2009-10-12 16:29:01 -0700180 return -errno;
181 } else if (pid == 0) {
San Mehat8c940ef2010-02-13 14:19:53 -0800182 /*
183 * Child
184 */
Rom Lemarchandb9dcde72012-12-27 10:45:02 -0800185 close(parent_ptty);
San Mehat49e2bce2009-10-12 16:29:01 -0700186 child_ptty = open(child_devname, O_RDWR);
187 if (child_ptty < 0) {
Steve Block8c487332011-10-12 17:28:59 +0100188 ALOG(LOG_ERROR, "logwrapper", "Problem with child ptty");
Rom Lemarchande90c1742012-12-21 11:35:43 -0800189 _exit(-errno);
San Mehat49e2bce2009-10-12 16:29:01 -0700190 }
191
192 // redirect stdout and stderr
San Mehat49e2bce2009-10-12 16:29:01 -0700193 dup2(child_ptty, 1);
194 dup2(child_ptty, 2);
195 close(child_ptty);
196
197 if (background) {
Glenn Kasten1b4807b2012-03-05 15:14:33 -0800198 int err = set_sched_policy(getpid(), SP_BACKGROUND);
199 if (err < 0) {
Steve Block8c487332011-10-12 17:28:59 +0100200 ALOG(LOG_WARN, "logwrapper",
Glenn Kasten1b4807b2012-03-05 15:14:33 -0800201 "Unable to background process (%s)", strerror(-err));
San Mehat49e2bce2009-10-12 16:29:01 -0700202 }
203 }
204
205 child(argc, argv);
206 } else {
San Mehat8c940ef2010-02-13 14:19:53 -0800207 /*
208 * Parent
209 */
Rom Lemarchandb9dcde72012-12-27 10:45:02 -0800210 int rc, err;
211 int sockets[2];
212 pthread_t thread_id;
213 struct monitor_data data;
214
215 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets)) {
216 err = errno;
217 ALOG(LOG_ERROR, "logwrapper", "Unable to create monitoring "
218 "socket: %s (%d)", strerror(err), err);
219 exit(-err);
220 }
221 data.tag = argv[0];
222 data.fd = sockets[1];
223 err = pthread_create(&thread_id, NULL, monitor, &data);
224 if (err != 0) {
225 ALOG(LOG_ERROR, "logwrapper", "Unable to create monitoring "
226 "thread: %s (%d)", strerror(err), err);
227 exit(-err);
228 }
229 rc = parent(argv[0], parent_ptty, sockets[0]);
San Mehat8c940ef2010-02-13 14:19:53 -0800230 close(parent_ptty);
Rom Lemarchandb9dcde72012-12-27 10:45:02 -0800231 close(sockets[0]);
232 close(sockets[1]);
San Mehat8c940ef2010-02-13 14:19:53 -0800233 return rc;
San Mehat49e2bce2009-10-12 16:29:01 -0700234 }
235
236 return 0;
237}