Home | History | Annotate | Download | only in bit
      1 /*
      2  * Copyright (C) 2016 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 "command.h"
     18 
     19 #include "print.h"
     20 #include "util.h"
     21 
     22 #include <errno.h>
     23 #include <string.h>
     24 #include <stdlib.h>
     25 #include <sys/types.h>
     26 #include <sys/stat.h>
     27 #include <unistd.h>
     28 #include <sys/wait.h>
     29 
     30 extern char **environ;
     31 
     32 Command::Command(const string& prog)
     33     :prog(prog)
     34 {
     35 }
     36 
     37 Command::~Command()
     38 {
     39 }
     40 
     41 void
     42 Command::AddArg(const string& arg)
     43 {
     44     args.push_back(arg);
     45 }
     46 
     47 void
     48 Command::AddEnv(const string& name, const string& value)
     49 {
     50     env[name] = value;
     51 }
     52 
     53 const char*
     54 Command::GetProg() const
     55 {
     56     return prog.c_str();
     57 }
     58 
     59 char *const *
     60 Command::GetArgv() const
     61 {
     62     const int N = args.size();
     63     char** result = (char**)malloc(sizeof(char*)*(N+2));
     64     result[0] = strdup(prog.c_str());
     65     for (int i=0; i<N; i++) {
     66         result[i+1] = strdup(args[i].c_str());
     67     }
     68     result[N+1] = 0;
     69     return result;
     70 }
     71 
     72 char *const *
     73 Command::GetEnv() const
     74 {
     75     map<string,string> copy;
     76     for (const char** p=(const char**)environ; *p != NULL; p++) {
     77         char* name = strdup(*p);
     78         char* value = strchr(name, '=');
     79         *value = '\0';
     80         value++;
     81         copy[name] = value;
     82         free(name);
     83     }
     84     for (map<string,string>::const_iterator it=env.begin(); it!=env.end(); it++) {
     85         copy[it->first] = it->second;
     86     }
     87     char** result = (char**)malloc(sizeof(char*)*(copy.size()+1));
     88     char** row = result;
     89     for (map<string,string>::const_iterator it=copy.begin(); it!=copy.end(); it++) {
     90         *row = (char*)malloc(it->first.size() + it->second.size() + 2);
     91         strcpy(*row, it->first.c_str());
     92         strcat(*row, "=");
     93         strcat(*row, it->second.c_str());
     94         row++;
     95     }
     96     *row = NULL;
     97     return result;
     98 }
     99 
    100 string
    101 get_command_output(const Command& command, int* err, bool quiet)
    102 {
    103     if (!quiet) {
    104         print_command(command);
    105     }
    106 
    107     int fds[2];
    108     if (0 != pipe(fds)) {
    109         return string();
    110     }
    111 
    112     pid_t pid = fork();
    113 
    114     if (pid == -1) {
    115         // fork error
    116         *err = errno;
    117         return string();
    118     } else if (pid == 0) {
    119         // child
    120         while ((dup2(fds[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
    121         close(fds[1]);
    122         close(fds[0]);
    123         const char* prog = command.GetProg();
    124         char* const* argv = command.GetArgv();
    125         char* const* env = command.GetEnv();
    126         exec_with_path_search(prog, argv, env);
    127         if (!quiet) {
    128             print_error("Unable to run command: %s", prog);
    129         }
    130         exit(1);
    131     } else {
    132         // parent
    133         close(fds[1]);
    134         string result;
    135         const int size = 16*1024;
    136         char* buf = (char*)malloc(size);
    137         while (true) {
    138             ssize_t amt = read(fds[0], buf, size);
    139             if (amt <= 0) {
    140                 break;
    141             } else if (amt > 0) {
    142                 result.append(buf, amt);
    143             }
    144         }
    145         free(buf);
    146         int status;
    147         waitpid(pid, &status, 0);
    148         if (WIFEXITED(status)) {
    149             *err = WEXITSTATUS(status);
    150             return result;
    151         } else {
    152             *err = -1;
    153             return string();
    154         }
    155     }
    156 }
    157 
    158 
    159 int
    160 run_command(const Command& command)
    161 {
    162     print_command(command);
    163 
    164     pid_t pid = fork();
    165 
    166     if (pid == -1) {
    167         // fork error
    168         return errno;
    169     } else if (pid == 0) {
    170         // child
    171         const char* prog = command.GetProg();
    172         char* const* argv = command.GetArgv();
    173         char* const* env = command.GetEnv();
    174         exec_with_path_search(prog, argv, env);
    175         print_error("Unable to run command: %s", prog);
    176         exit(1);
    177     } else {
    178         // parent
    179         int status;
    180         waitpid(pid, &status, 0);
    181         if (WIFEXITED(status)) {
    182             return WEXITSTATUS(status);
    183         } else {
    184             return -1;
    185         }
    186     }
    187 }
    188 
    189 int
    190 exec_with_path_search(const char* prog, char const* const* argv, char const* const* envp)
    191 {
    192     if (strchr(prog, '/') != NULL) {
    193         return execve(prog, (char*const*)argv, (char*const*)envp);
    194     } else {
    195         char* pathEnv = strdup(getenv("PATH"));
    196         if (pathEnv == NULL) {
    197             return 1;
    198         }
    199         char* dir = pathEnv;
    200         while (dir) {
    201             char* next = strchr(dir, ':');
    202             if (next != NULL) {
    203                 *next = '\0';
    204                 next++;
    205             }
    206             if (dir[0] == '/') {
    207                 struct stat st;
    208                 string executable = string(dir) + "/" + prog;
    209                 if (stat(executable.c_str(), &st) == 0) {
    210                     execve(executable.c_str(), (char*const*)argv, (char*const*)envp);
    211                 }
    212             }
    213             dir = next;
    214         }
    215         free(pathEnv);
    216         return 1;
    217     }
    218 }
    219 
    220