blob: c5c12b4fad723e8576babd18afe0d8acbc49e219 [file] [log] [blame]
Joe Onorato0578cbc2016-10-19 17:03:06 -07001/*
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 <unistd.h>
26#include <sys/types.h>
27#include <sys/wait.h>
28
29Command::Command(const string& prog)
30 :prog(prog)
31{
32}
33
34Command::~Command()
35{
36}
37
38void
39Command::AddArg(const string& arg)
40{
41 args.push_back(arg);
42}
43
44void
45Command::AddEnv(const string& name, const string& value)
46{
47 env[name] = value;
48}
49
50const char*
51Command::GetProg() const
52{
53 return prog.c_str();
54}
55
56char *const *
57Command::GetArgv() const
58{
59 const int N = args.size();
60 char** result = (char**)malloc(sizeof(char*)*(N+2));
61 result[0] = strdup(prog.c_str());
62 for (int i=0; i<N; i++) {
63 result[i+1] = strdup(args[i].c_str());
64 }
65 result[N+1] = 0;
66 return result;
67}
68
69char *const *
70Command::GetEnv() const
71{
72 map<string,string> copy;
73 for (const char** p=(const char**)environ; *p != NULL; p++) {
74 char* name = strdup(*p);
75 char* value = strchr(name, '=');
76 *value = '\0';
77 value++;
78 copy[name] = value;
79 free(name);
80 }
81 for (map<string,string>::const_iterator it=env.begin(); it!=env.end(); it++) {
82 copy[it->first] = it->second;
83 }
84 char** result = (char**)malloc(sizeof(char*)*(copy.size()+1));
85 char** row = result;
86 for (map<string,string>::const_iterator it=copy.begin(); it!=copy.end(); it++) {
87 *row = (char*)malloc(it->first.size() + it->second.size() + 2);
88 strcpy(*row, it->first.c_str());
89 strcat(*row, "=");
90 strcat(*row, it->second.c_str());
91 row++;
92 }
93 *row = NULL;
94 return result;
95}
96
97string
98get_command_output(const Command& command, int* err, bool quiet)
99{
100 if (!quiet) {
101 print_command(command);
102 }
103
104 int fds[2];
105 pipe(fds);
106
107 pid_t pid = fork();
108
109 if (pid == -1) {
110 // fork error
111 *err = errno;
112 return string();
113 } else if (pid == 0) {
114 // child
115 while ((dup2(fds[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
116 close(fds[1]);
117 close(fds[0]);
118 const char* prog = command.GetProg();
119 char* const* argv = command.GetArgv();
120 char* const* env = command.GetEnv();
121 execvpe(prog, argv, env);
122 if (!quiet) {
123 print_error("Unable to run command: %s", prog);
124 }
125 exit(1);
126 } else {
127 // parent
128 close(fds[1]);
129 string result;
130 const int size = 16*1024;
131 char* buf = (char*)malloc(size);
132 while (true) {
133 ssize_t amt = read(fds[0], buf, size);
134 if (amt <= 0) {
135 break;
136 } else if (amt > 0) {
137 result.append(buf, amt);
138 }
139 }
140 free(buf);
141 int status;
142 waitpid(pid, &status, 0);
143 if (WIFEXITED(status)) {
144 *err = WEXITSTATUS(status);
145 return result;
146 } else {
147 *err = -1;
148 return string();
149 }
150 }
151}
152
153
154int
155run_command(const Command& command)
156{
157 print_command(command);
158
159 pid_t pid = fork();
160
161 if (pid == -1) {
162 // fork error
163 return errno;
164 } else if (pid == 0) {
165 // child
166 const char* prog = command.GetProg();
167 char* const* argv = command.GetArgv();
168 char* const* env = command.GetEnv();
169 execvpe(prog, argv, env);
170 print_error("Unable to run command: %s", prog);
171 exit(1);
172 } else {
173 // parent
174 int status;
175 waitpid(pid, &status, 0);
176 if (WIFEXITED(status)) {
177 return WEXITSTATUS(status);
178 } else {
179 return -1;
180 }
181 }
182}
183