Home | History | Annotate | Download | only in vold
      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, &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, &buffer[a]);
     71     }
     72     status = 0xAAAA;
     73     if (wait(&status) != -1) {  // Wait for child
     74         if (WIFEXITED(status)) {
     75             LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
     76                     WEXITSTATUS(status));
     77             return WEXITSTATUS(status);
     78         } else if (WIFSIGNALED(status))
     79             LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
     80                     WTERMSIG(status));
     81         else if (WIFSTOPPED(status))
     82             LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
     83                     WSTOPSIG(status));
     84     } else
     85         LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
     86                 strerror(errno), errno);
     87     return -EAGAIN;
     88 }
     89 
     90 void child(int argc, const char**argv) {
     91     // create null terminated argv_child array
     92     char* argv_child[argc + 1];
     93     memcpy(argv_child, argv, argc * sizeof(char *));
     94     argv_child[argc] = NULL;
     95 
     96     // XXX: PROTECT FROM VIKING KILLER
     97     if (execv(argv_child[0], argv_child)) {
     98         LOG(LOG_ERROR, "logwrapper",
     99             "executing %s failed: %s", argv_child[0], strerror(errno));
    100         exit(-1);
    101     }
    102 }
    103 
    104 int logwrap(int argc, const char* argv[], int background)
    105 {
    106     pid_t pid;
    107 
    108     int parent_ptty;
    109     int child_ptty;
    110     char *child_devname = NULL;
    111 
    112     /* Use ptty instead of socketpair so that STDOUT is not buffered */
    113     parent_ptty = open("/dev/ptmx", O_RDWR);
    114     if (parent_ptty < 0) {
    115 	LOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty");
    116 	return -errno;
    117     }
    118 
    119     if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
    120             ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
    121 	LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx");
    122         close(parent_ptty);
    123 	return -1;
    124     }
    125 
    126     pid = fork();
    127     if (pid < 0) {
    128 	LOG(LOG_ERROR, "logwrapper", "Failed to fork");
    129         return -errno;
    130     } else if (pid == 0) {
    131         /*
    132          * Child
    133          */
    134         child_ptty = open(child_devname, O_RDWR);
    135         if (child_ptty < 0) {
    136 	    LOG(LOG_ERROR, "logwrapper", "Problem with child ptty");
    137             return -errno;
    138         }
    139 
    140         // redirect stdout and stderr
    141         close(parent_ptty);
    142         dup2(child_ptty, 1);
    143         dup2(child_ptty, 2);
    144         close(child_ptty);
    145 
    146         if (background) {
    147             int fd = open("/dev/cpuctl/bg_non_interactive/tasks", O_WRONLY);
    148 
    149             if (fd >=0 ) {
    150                 char text[64];
    151 
    152                 sprintf(text, "%d", getpid());
    153                 if (write(fd, text, strlen(text)) < 0) {
    154                     LOG(LOG_WARN, "logwrapper",
    155                         "Unable to background process (%s)", strerror(errno));
    156                     close(fd);
    157                 }
    158                 close(fd);
    159             } else {
    160                 LOG(LOG_WARN, "logwrapper",
    161                     "Unable to background process (%s)", strerror(errno));
    162             }
    163         }
    164 
    165         child(argc, argv);
    166     } else {
    167         /*
    168          * Parent
    169          */
    170         int rc = parent(argv[0], parent_ptty);
    171         close(parent_ptty);
    172         return rc;
    173     }
    174 
    175     return 0;
    176 }
    177