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 
Command(const string & prog)32 Command::Command(const string& prog)
33     :prog(prog)
34 {
35 }
36 
~Command()37 Command::~Command()
38 {
39 }
40 
41 void
AddArg(const string & arg)42 Command::AddArg(const string& arg)
43 {
44     args.push_back(arg);
45 }
46 
47 void
AddEnv(const string & name,const string & value)48 Command::AddEnv(const string& name, const string& value)
49 {
50     env[name] = value;
51 }
52 
53 const char*
GetProg() const54 Command::GetProg() const
55 {
56     return prog.c_str();
57 }
58 
59 char *const *
GetArgv() const60 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 *
GetEnv() const73 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
get_command_output(const Command & command,int * err,bool quiet)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
run_command(const Command & command)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
exec_with_path_search(const char * prog,char const * const * argv,char const * const * envp)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