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