summaryrefslogtreecommitdiff
path: root/src/execute.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/execute.cc')
-rw-r--r--src/execute.cc87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/execute.cc b/src/execute.cc
new file mode 100644
index 0000000..bc4cd5f
--- /dev/null
+++ b/src/execute.cc
@@ -0,0 +1,87 @@
+#include "execute.h"
+
+#include <unistd.h>
+#include <cstring>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <spawn.h>
+#include <iostream>
+
+/*
+https://blog.famzah.net/2009/11/20/a-much-faster-popen-and-system-implementation-for-linux/
+https://github.com/famzah/popen-noshell/commit/1f9eaf4eeef348d1efe0f3c7fe8ab670653cfbb1
+https://blog.famzah.net/2018/12/19/posix_spawn-performance-benchmarks-and-usage-examples/
+https://stackoverflow.com/questions/4259629/what-is-the-difference-between-fork-and-vfork/5207945#5207945
+ */
+
+
+namespace
+{
+int parent_waitpid(pid_t pid)
+{
+ int status;
+
+ if(waitpid(pid, &status, 0) != pid)
+ {
+ return 1;
+ }
+
+ return status;
+}
+} // namespace ::
+
+int execute(const std::string& command,
+ const std::vector<std::string>& args,
+ bool verbose)
+{
+ std::vector<const char*> argv;
+ argv.push_back(command.data());
+ for(const auto& arg : args)
+ {
+ argv.push_back(arg.data());
+ }
+ argv.push_back(nullptr);
+
+ if(verbose)
+ {
+ std::string cmd;
+ for(const auto& arg : argv)
+ {
+ if(arg == nullptr)
+ {
+ break;
+ }
+ if(!cmd.empty())
+ {
+ cmd += " ";
+ }
+ cmd += arg;
+ }
+
+ std::cout << cmd << "\n";
+ }
+
+#if 1
+ auto pid = vfork();
+ if(pid == 0)
+ {
+ execv(command.data(), (char**)argv.data());
+ std::cout << "Could not execute " << command << ": " <<
+ strerror(errno) << "\n";
+ _exit(1); // execv only returns if an error occurred
+ }
+ auto ret = parent_waitpid(pid);
+#elif 0
+ pid_t pid;
+ if(posix_spawn(&pid, command.data(), nullptr, nullptr,
+ (char**)argv.data(), nullptr))
+ {
+ return 1;
+ }
+ auto ret = parent_waitpid(pid);
+#else
+ auto ret = system(cmd.data());
+#endif
+
+ return ret;
+}