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     pipe(fds);
    109 
    110     pid_t pid = fork();
    111 
    112     if (pid == -1) {
    113         // fork error
    114         *err = errno;
    115         return string();
    116     } else if (pid == 0) {
    117         // child
    118         while ((dup2(fds[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
    119         close(fds[1]);
    120         close(fds[0]);
    121         const char* prog = command.GetProg();
    122         char* const* argv = command.GetArgv();
    123         char* const* env = command.GetEnv();
    124         exec_with_path_search(prog, argv, env);
    125         if (!quiet) {
    126             print_error("Unable to run command: %s", prog);
    127         }
    128         exit(1);
    129     } else {
    130         // parent
    131         close(fds[1]);
    132         string result;
    133         const int size = 16*1024;
    134         char* buf = (char*)malloc(size);
    135         while (true) {
    136             ssize_t amt = read(fds[0], buf, size);
    137             if (amt <= 0) {
    138                 break;
    139             } else if (amt > 0) {
    140                 result.append(buf, amt);
    141             }
    142         }
    143         free(buf);
    144         int status;
    145         waitpid(pid, &status, 0);
    146         if (WIFEXITED(status)) {
    147             *err = WEXITSTATUS(status);
    148             return result;
    149         } else {
    150             *err = -1;
    151             return string();
    152         }
    153     }
    154 }
    155 
    156 
    157 int
    158 run_command(const Command& command)
    159 {
    160     print_command(command);
    161 
    162     pid_t pid = fork();
    163 
    164     if (pid == -1) {
    165         // fork error
    166         return errno;
    167     } else if (pid == 0) {
    168         // child
    169         const char* prog = command.GetProg();
    170         char* const* argv = command.GetArgv();
    171         char* const* env = command.GetEnv();
    172         exec_with_path_search(prog, argv, env);
    173         print_error("Unable to run command: %s", prog);
    174         exit(1);
    175     } else {
    176         // parent
    177         int status;
    178         waitpid(pid, &status, 0);
    179         if (WIFEXITED(status)) {
    180             return WEXITSTATUS(status);
    181         } else {
    182             return -1;
    183         }
    184     }
    185 }
    186 
    187 int
    188 exec_with_path_search(const char* prog, char const* const* argv, char const* const* envp)
    189 {
    190     if (prog[0] == '/') {
    191         return execve(prog, (char*const*)argv, (char*const*)envp);
    192     } else {
    193         char* pathEnv = strdup(getenv("PATH"));
    194         if (pathEnv == NULL) {
    195             return 1;
    196         }
    197         char* dir = pathEnv;
    198         while (dir) {
    199             char* next = strchr(dir, ':');
    200             if (next != NULL) {
    201                 *next = '\0';
    202                 next++;
    203             }
    204             if (dir[0] == '/') {
    205                 struct stat st;
    206                 string executable = string(dir) + "/" + prog;
    207                 if (stat(executable.c_str(), &st) == 0) {
    208                     execve(executable.c_str(), (char*const*)argv, (char*const*)envp);
    209                 }
    210             }
    211             dir = next;
    212         }
    213         free(pathEnv);
    214         return 1;
    215     }
    216 }
    217 
    218