summaryrefslogtreecommitdiff
path: root/tools/bit/command.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/bit/command.cpp')
-rw-r--r--tools/bit/command.cpp183
1 files changed, 183 insertions, 0 deletions
diff --git a/tools/bit/command.cpp b/tools/bit/command.cpp
new file mode 100644
index 000000000000..c5c12b4fad72
--- /dev/null
+++ b/tools/bit/command.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "command.h"
+
+#include "print.h"
+#include "util.h"
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+Command::Command(const string& prog)
+ :prog(prog)
+{
+}
+
+Command::~Command()
+{
+}
+
+void
+Command::AddArg(const string& arg)
+{
+ args.push_back(arg);
+}
+
+void
+Command::AddEnv(const string& name, const string& value)
+{
+ env[name] = value;
+}
+
+const char*
+Command::GetProg() const
+{
+ return prog.c_str();
+}
+
+char *const *
+Command::GetArgv() const
+{
+ const int N = args.size();
+ char** result = (char**)malloc(sizeof(char*)*(N+2));
+ result[0] = strdup(prog.c_str());
+ for (int i=0; i<N; i++) {
+ result[i+1] = strdup(args[i].c_str());
+ }
+ result[N+1] = 0;
+ return result;
+}
+
+char *const *
+Command::GetEnv() const
+{
+ map<string,string> copy;
+ for (const char** p=(const char**)environ; *p != NULL; p++) {
+ char* name = strdup(*p);
+ char* value = strchr(name, '=');
+ *value = '\0';
+ value++;
+ copy[name] = value;
+ free(name);
+ }
+ for (map<string,string>::const_iterator it=env.begin(); it!=env.end(); it++) {
+ copy[it->first] = it->second;
+ }
+ char** result = (char**)malloc(sizeof(char*)*(copy.size()+1));
+ char** row = result;
+ for (map<string,string>::const_iterator it=copy.begin(); it!=copy.end(); it++) {
+ *row = (char*)malloc(it->first.size() + it->second.size() + 2);
+ strcpy(*row, it->first.c_str());
+ strcat(*row, "=");
+ strcat(*row, it->second.c_str());
+ row++;
+ }
+ *row = NULL;
+ return result;
+}
+
+string
+get_command_output(const Command& command, int* err, bool quiet)
+{
+ if (!quiet) {
+ print_command(command);
+ }
+
+ int fds[2];
+ pipe(fds);
+
+ pid_t pid = fork();
+
+ if (pid == -1) {
+ // fork error
+ *err = errno;
+ return string();
+ } else if (pid == 0) {
+ // child
+ while ((dup2(fds[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
+ close(fds[1]);
+ close(fds[0]);
+ const char* prog = command.GetProg();
+ char* const* argv = command.GetArgv();
+ char* const* env = command.GetEnv();
+ execvpe(prog, argv, env);
+ if (!quiet) {
+ print_error("Unable to run command: %s", prog);
+ }
+ exit(1);
+ } else {
+ // parent
+ close(fds[1]);
+ string result;
+ const int size = 16*1024;
+ char* buf = (char*)malloc(size);
+ while (true) {
+ ssize_t amt = read(fds[0], buf, size);
+ if (amt <= 0) {
+ break;
+ } else if (amt > 0) {
+ result.append(buf, amt);
+ }
+ }
+ free(buf);
+ int status;
+ waitpid(pid, &status, 0);
+ if (WIFEXITED(status)) {
+ *err = WEXITSTATUS(status);
+ return result;
+ } else {
+ *err = -1;
+ return string();
+ }
+ }
+}
+
+
+int
+run_command(const Command& command)
+{
+ print_command(command);
+
+ pid_t pid = fork();
+
+ if (pid == -1) {
+ // fork error
+ return errno;
+ } else if (pid == 0) {
+ // child
+ const char* prog = command.GetProg();
+ char* const* argv = command.GetArgv();
+ char* const* env = command.GetEnv();
+ execvpe(prog, argv, env);
+ print_error("Unable to run command: %s", prog);
+ exit(1);
+ } else {
+ // parent
+ int status;
+ waitpid(pid, &status, 0);
+ if (WIFEXITED(status)) {
+ return WEXITSTATUS(status);
+ } else {
+ return -1;
+ }
+ }
+}
+