Moves the subprocess function to a library
Test: run on gce
Bug: 79170615
Change-Id: I83ef0092e1a74930d98b35c4a5b359fa98a7b14a
Merged-In: I83ef0092e1a74930d98b35c4a5b359fa98a7b14a
(cherry picked from commit 6a9d629814eef712ff00438cb0e9f139b5cc74e3)
diff --git a/common/libs/Android.bp b/common/libs/Android.bp
index fff0a84..17a4c9d 100644
--- a/common/libs/Android.bp
+++ b/common/libs/Android.bp
@@ -21,4 +21,5 @@
"tcp_socket",
"threads",
"time",
+ "utils",
]
diff --git a/common/libs/utils/Android.bp b/common/libs/utils/Android.bp
new file mode 100644
index 0000000..3b6992c
--- /dev/null
+++ b/common/libs/utils/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2018 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.
+
+cc_library_shared {
+ name: "libcuttlefish_utils",
+ srcs: [
+ "subprocess.cpp",
+ ],
+ header_libs: [
+ "cuttlefish_glog",
+ ],
+ shared_libs: [
+ "libbase",
+ ],
+ defaults: ["cuttlefish_host_and_guest"],
+}
diff --git a/common/libs/utils/subprocess.cpp b/common/libs/utils/subprocess.cpp
new file mode 100644
index 0000000..593c421
--- /dev/null
+++ b/common/libs/utils/subprocess.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2018 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 "common/libs//utils/subprocess.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <glog/logging.h>
+namespace {
+pid_t subprocess_impl(const char* const* command, const char* const* envp) {
+ pid_t pid = fork();
+ if (!pid) {
+ int rval;
+ // If envp is NULL, the current process's environment is used as the
+ // environment of the child process. To force an empty emvironment for
+ // the child process pass the address of a pointer to NULL
+ if (envp == NULL) {
+ rval = execv(command[0], const_cast<char* const*>(command));
+ } else {
+ rval = execve(command[0],
+ const_cast<char* const*>(command),
+ const_cast<char* const*>(envp));
+ }
+ // No need for an if: if exec worked it wouldn't have returned
+ LOG(ERROR) << "exec of " << command[0] << " failed (" << strerror(errno)
+ << ")";
+ exit(rval);
+ }
+ if (pid == -1) {
+ LOG(ERROR) << "fork failed (" << strerror(errno) << ")";
+ }
+ LOG(INFO) << "Started " << command[0] << ", pid: " << pid;
+ return pid;
+}
+
+int execute_impl(const char* const* command, const char* const* envp) {
+ pid_t pid = subprocess_impl(command, envp);
+ if (pid == -1) {
+ return -1;
+ }
+ int wstatus = 0;
+ waitpid(pid, &wstatus, 0);
+ int retval = 0;
+ if (WIFEXITED(wstatus)) {
+ retval = WEXITSTATUS(wstatus);
+ if (retval) {
+ LOG(ERROR) << "Command " << command[0]
+ << " exited with error code: " << retval;
+ }
+ } else if (WIFSIGNALED(wstatus)) {
+ LOG(ERROR) << "Command " << command[0]
+ << " was interrupted by a signal: " << WTERMSIG(wstatus);
+ retval = -1;
+ }
+ return retval;
+}
+
+std::vector<const char*> ToCharPointers(
+ const std::vector<std::string>& vect) {
+ std::vector<const char*> ret = {};
+ for (const auto& str : vect) {
+ ret.push_back(str.c_str());
+ }
+ ret.push_back(NULL);
+ return ret;
+}
+} // namespace
+namespace cvd {
+pid_t subprocess(const std::vector<std::string>& command,
+ const std::vector<std::string>& env) {
+ auto cmd = ToCharPointers(command);
+ auto envp = ToCharPointers(env);
+
+ return subprocess_impl(cmd.data(), &envp[0]);
+}
+pid_t subprocess(const std::vector<std::string>& command) {
+ auto cmd = ToCharPointers(command);
+
+ return subprocess_impl(cmd.data(), NULL);
+}
+int execute(const std::vector<std::string>& command,
+ const std::vector<std::string>& env) {
+ auto cmd = ToCharPointers(command);
+ auto envp = ToCharPointers(env);
+
+ return execute_impl(cmd.data(), &envp[0]);
+}
+int execute(const std::vector<std::string>& command) {
+ auto cmd = ToCharPointers(command);
+
+ return execute_impl(cmd.data(), NULL);
+}
+} // namespace cvd
diff --git a/common/libs/utils/subprocess.h b/common/libs/utils/subprocess.h
new file mode 100644
index 0000000..cbb61f1
--- /dev/null
+++ b/common/libs/utils/subprocess.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+#pragma once
+
+#include <sys/types.h>
+
+#include <vector>
+
+namespace cvd {
+
+// Starts a new child process with the given parameters. Returns the pid of the
+// started process or -1 if failed. The function with no environment arguments
+// launches the subprocess with the same environment as the parent, to have an
+// empty environment just pass an empty vector as second argument.
+pid_t subprocess(const std::vector<std::string>& command,
+ const std::vector<std::string>& env);
+pid_t subprocess(const std::vector<std::string>& command);
+
+// Same as subprocess, but it waits for the child process before returning.
+// Returns zero if the process completed successfully, non zero otherwise.
+int execute(const std::vector<std::string>& command,
+ const std::vector<std::string>& env);
+int execute(const std::vector<std::string>& command);
+
+} // namespace cvd
diff --git a/host/commands/launch/Android.bp b/host/commands/launch/Android.bp
index 650ccb9..2100e52 100644
--- a/host/commands/launch/Android.bp
+++ b/host/commands/launch/Android.bp
@@ -28,6 +28,7 @@
"vsoc_lib",
"libcuttlefish_fs",
"libcuttlefish_strings",
+ "libcuttlefish_utils",
"cuttlefish_auto_resources",
"libicuuc",
"libbase",
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index 8f05e09..e37b98c 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -37,6 +37,7 @@
#include "common/libs/fs/shared_fd.h"
#include "common/libs/fs/shared_select.h"
#include "common/libs/strings/str_split.h"
+#include "common/libs/utils/subprocess.h"
#include "common/vsoc/lib/vsoc_memory.h"
#include "common/vsoc/shm/screen_layout.h"
#include "host/commands/launch/pre_launch_initializers.h"
@@ -262,39 +263,6 @@
KernelLogMonitor& operator=(const KernelLogMonitor&) = delete;
};
-void subprocess(const char* const* command,
- const char* const* envp,
- bool wait_for_child = true) {
- pid_t pid = fork();
- if (!pid) {
- int rval;
- // If envp is NULL, the current process's environment is used as the
- // environment of the child process. To force an empty emvironment for the
- // child process pass the address of a pointer to NULL
- if (envp == NULL) {
- rval = execv(command[0], const_cast<char* const*>(command));
- } else {
- rval = execve(command[0], const_cast<char* const*>(command),
- const_cast<char* const*>(envp));
- }
- // No need for an if: if exec worked it wouldn't have returned
- LOG(ERROR) << "exec of " << command[0] << " failed (" << strerror(errno)
- << ")";
- exit(rval);
- }
- if (pid == -1) {
- LOG(ERROR) << "fork of " << command[0] << " failed (" << strerror(errno)
- << ")";
- }
- if (pid > 0) {
- if (wait_for_child) {
- waitpid(pid, 0, 0);
- } else {
- LOG(INFO) << "Started " << command[0] << ", pid: " << pid;
- }
- }
-}
-
bool DirExists(const char* path) {
struct stat st;
if (stat(path, &st) == -1)
@@ -320,20 +288,13 @@
of += image;
std::string count = "count=";
count += std::to_string(image_mb);
- const char* dd_command[]{
- "/bin/dd", "if=/dev/zero", of.c_str(), "bs=1M", count.c_str(), NULL};
- subprocess(dd_command, NULL);
- const char* mkfs_command[]{
- "/sbin/mkfs", "-t", image_fmt.c_str(), image.c_str(), NULL};
- const char* envp[]{"PATH=/sbin", NULL};
- subprocess(mkfs_command, envp);
+ cvd::execute({"/bin/dd", "if=/dev/zero", of, "bs=1M", count});
+ cvd::execute({"/sbin/mkfs", "-t", image_fmt, image}, {"PATH=/sbin"});
}
void RemoveFile(const std::string& file) {
LOG(INFO) << "Removing " << file;
- const char* rm_command[]{
- "/bin/rm", "-f", file.c_str(), NULL};
- subprocess(rm_command, NULL);
+ cvd::execute({"/bin/rm", "-f", file});
}
bool ApplyDataImagePolicy(const char* data_image) {
@@ -380,24 +341,20 @@
return true;
}
-bool EnsureDirExists(const char* dir) {
- if (!DirExists(dir)) {
+bool EnsureDirExists(const std::string& dir) {
+ if (!DirExists(dir.c_str())) {
LOG(INFO) << "Setting up " << dir;
- if (mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0) {
+ if (mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0) {
if (errno == EACCES) {
// TODO(79170615) Don't use sudo once libvirt is replaced
LOG(WARNING) << "Not enough permission to create " << dir
<< " retrying with sudo";
- const char* mkdir_command[]{"/usr/bin/sudo", "/bin/mkdir", "-m",
- "0775", dir, NULL};
- subprocess(mkdir_command, NULL);
+ cvd::execute({"/usr/bin/sudo", "/bin/mkdir", "-m", "0775", dir});
// When created with sudo the owner and group is root.
std::string user_group = getenv("USER");
user_group += ":libvirt-qemu";
- const char* chown_cmd[] = {"/usr/bin/sudo", "/bin/chown",
- user_group.c_str(), dir, NULL};
- subprocess(chown_cmd, NULL);
+ cvd::execute({"/usr/bin/sudo", "/bin/chown", user_group, dir});
} else {
LOG(FATAL) << "Unable to create " << dir << ". Error: " << errno;
return false;
@@ -443,18 +400,10 @@
void LaunchSocketForwardProxyIfEnabled() {
if (AdbTunnelEnabled()) {
- auto guest_port_arg = GetGuestPortArg();
- auto host_port_arg = GetHostPortArg();
- auto config_arg = GetConfigFileArg();
-
- const char* const socket_proxy[] = {
- FLAGS_socket_forward_proxy_binary.c_str(),
- guest_port_arg.c_str(),
- host_port_arg.c_str(),
- config_arg.c_str(),
- NULL
- };
- subprocess(socket_proxy, nullptr, false);
+ cvd::subprocess({FLAGS_socket_forward_proxy_binary,
+ GetGuestPortArg(),
+ GetHostPortArg(),
+ GetConfigFileArg()});
}
}
@@ -462,30 +411,16 @@
if (FLAGS_start_vnc_server) {
// Launch the vnc server, don't wait for it to complete
auto port_options = "-port=" + std::to_string(FLAGS_vnc_server_port);
- auto config_arg = GetConfigFileArg();
- const char* vnc_command[] = {
- FLAGS_vnc_server_binary.c_str(),
- port_options.c_str(),
- config_arg.c_str(),
- NULL
- };
- subprocess(vnc_command, NULL, false);
+ cvd::subprocess(
+ {FLAGS_vnc_server_binary, port_options, GetConfigFileArg()});
}
}
void LaunchWifiRelayIfEnabled() {
if (FLAGS_start_wifi_relay) {
// Launch the wifi relay, don't wait for it to complete
- auto config_arg = GetConfigFileArg();
- const char* relay_command[] = {
- "/usr/bin/sudo",
- "-E",
- FLAGS_wifi_relay_binary.c_str(),
- config_arg.c_str(),
- NULL
- };
-
- subprocess(relay_command, NULL /* envp */, false /* wait_for_child */);
+ cvd::subprocess(
+ {"/usr/bin/sudo", "-E", FLAGS_wifi_relay_binary, GetConfigFileArg()});
}
}
bool ResolveInstanceFiles() {
@@ -554,7 +489,7 @@
auto config = vsoc::CuttlefishConfig::Get();
// Set this first so that calls to PerInstancePath below are correct
config->set_instance_dir(FLAGS_instance_dir);
- if (!EnsureDirExists(FLAGS_instance_dir.c_str())) {
+ if (!EnsureDirExists(FLAGS_instance_dir)) {
return false;
}
diff --git a/host/libs/vm_manager/Android.bp b/host/libs/vm_manager/Android.bp
index 1c23f0a..a4bfc66 100644
--- a/host/libs/vm_manager/Android.bp
+++ b/host/libs/vm_manager/Android.bp
@@ -23,6 +23,7 @@
],
shared_libs: [
"libcuttlefish_fs",
+ "libcuttlefish_utils",
"cuttlefish_auto_resources",
"libbase",
"libicuuc",