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 #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