OSDN Git Service

Fix cryptfs to work with a raw block device for key storage
[android-x86/system-vold.git] / logwrapper.c
1 /*
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>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <fcntl.h>
25
26 #include "private/android_filesystem_config.h"
27 #include "cutils/log.h"
28
29 int parent(const char *tag, int parent_read) {
30     int status;
31     char buffer[4096];
32
33     int a = 0;  // start index of unprocessed data
34     int b = 0;  // end index of unprocessed data
35     int sz;
36     while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
37
38         sz += b;
39         // Log one line at a time
40         for (b = 0; b < sz; b++) {
41             if (buffer[b] == '\r') {
42                 buffer[b] = '\0';
43             } else if (buffer[b] == '\n') {
44                 buffer[b] = '\0';
45
46                 LOG(LOG_INFO, tag, "%s", &buffer[a]);
47                 a = b + 1;
48             }
49         }
50
51         if (a == 0 && b == sizeof(buffer) - 1) {
52             // buffer is full, flush
53             buffer[b] = '\0';
54             LOG(LOG_INFO, tag, "%s", &buffer[a]);
55             b = 0;
56         } else if (a != b) {
57             // Keep left-overs
58             b -= a;
59             memmove(buffer, &buffer[a], b);
60             a = 0;
61         } else {
62             a = 0;
63             b = 0;
64         }
65
66     }
67     // Flush remaining data
68     if (a != b) {
69         buffer[b] = '\0';
70         LOG(LOG_INFO, tag, "%s", &buffer[a]);
71     }
72     status = 0xAAAA;
73     if (wait(&status) != -1) {  // Wait for child
74         if (WIFEXITED(status)) {
75             if (WEXITSTATUS(status) != 0) {
76                 LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
77                         WEXITSTATUS(status));
78             }
79             return WEXITSTATUS(status);
80         } else if (WIFSIGNALED(status))
81             LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
82                     WTERMSIG(status));
83         else if (WIFSTOPPED(status))
84             LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
85                     WSTOPSIG(status));
86     } else
87         LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
88                 strerror(errno), errno);
89     return -EAGAIN;
90 }
91
92 void child(int argc, const char**argv) {
93     // create null terminated argv_child array
94     char* argv_child[argc + 1];
95     memcpy(argv_child, argv, argc * sizeof(char *));
96     argv_child[argc] = NULL;
97
98     // XXX: PROTECT FROM VIKING KILLER
99     if (execv(argv_child[0], argv_child)) {
100         LOG(LOG_ERROR, "logwrapper",
101             "executing %s failed: %s", argv_child[0], strerror(errno));
102         exit(-1);
103     }
104 }
105
106 int logwrap(int argc, const char* argv[], int background)
107 {
108     pid_t pid;
109
110     int parent_ptty;
111     int child_ptty;
112     char *child_devname = NULL;
113
114     /* Use ptty instead of socketpair so that STDOUT is not buffered */
115     parent_ptty = open("/dev/ptmx", O_RDWR);
116     if (parent_ptty < 0) {
117         LOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty");
118         return -errno;
119     }
120
121     if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
122             ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
123         close(parent_ptty);
124         LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx");
125         return -1;
126     }
127
128     pid = fork();
129     if (pid < 0) {
130         close(parent_ptty);
131         LOG(LOG_ERROR, "logwrapper", "Failed to fork");
132         return -errno;
133     } else if (pid == 0) {
134         /*
135          * Child
136          */
137         child_ptty = open(child_devname, O_RDWR);
138         if (child_ptty < 0) {
139             close(parent_ptty);
140             LOG(LOG_ERROR, "logwrapper", "Problem with child ptty");
141             return -errno;
142         }
143
144         // redirect stdout and stderr
145         close(parent_ptty);
146         dup2(child_ptty, 1);
147         dup2(child_ptty, 2);
148         close(child_ptty);
149
150         if (background) {
151             int fd = open("/dev/cpuctl/bg_non_interactive/tasks", O_WRONLY);
152             if (fd >= 0) {
153                 char text[64];
154                 sprintf(text, "%d", getpid());
155                 if (write(fd, text, strlen(text)) < 0) {
156                     LOG(LOG_WARN, "logwrapper",
157                         "Unable to background process (%s)", strerror(errno));
158                 }
159                 close(fd);
160             } else {
161                 LOG(LOG_WARN, "logwrapper",
162                     "Unable to background process (%s)", strerror(errno));
163             }
164         }
165
166         child(argc, argv);
167     } else {
168         /*
169          * Parent
170          */
171         int rc = parent(argv[0], parent_ptty);
172         close(parent_ptty);
173         return rc;
174     }
175
176     return 0;
177 }