aboutsummaryrefslogtreecommitdiff
path: root/func.cc
diff options
context:
space:
mode:
authorShinichiro Hamaji <shinichiro.hamaji@gmail.com>2015-07-02 01:42:31 +0900
committerShinichiro Hamaji <shinichiro.hamaji@gmail.com>2015-07-03 14:16:46 +0900
commit62b16e7b9424f88e4907a6879d15ee832ef49477 (patch)
treea43a61c7a49218a59ddaa78e4eb2b66df8a9fa61 /func.cc
parente1113ebeb184e5f6f135a3b0aa43309cc636c336 (diff)
downloadkati-62b16e7b9424f88e4907a6879d15ee832ef49477.tar.gz
[C++] Use vfork and exec instead of popen for $(shell)
Diffstat (limited to 'func.cc')
-rw-r--r--func.cc51
1 files changed, 50 insertions, 1 deletions
diff --git a/func.cc b/func.cc
index d85f6f7..9309ed3 100644
--- a/func.cc
+++ b/func.cc
@@ -16,10 +16,14 @@
#include "func.h"
+#include <errno.h>
#include <glob.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
#include <algorithm>
#include <iterator>
@@ -426,6 +430,48 @@ static string SortWordsInString(StringPiece s) {
}
#endif
+static void RunCommand(const string& cmd, string* s) {
+ int pipefd[2];
+ if (pipe(pipefd) != 0)
+ PERROR("pipe failed");
+ int pid;
+ if ((pid = vfork())) {
+ close(pipefd[1]);
+ while (true) {
+ int status;
+ int result = waitpid(pid, &status, WNOHANG);
+ if (result < 0)
+ PERROR("waitpid failed");
+
+ while (true) {
+ char buf[4096];
+ ssize_t r = read(pipefd[0], buf, 4096);
+ if (r < 0)
+ PERROR("read failed");
+ if (r == 0)
+ break;
+ s->append(buf, buf+r);
+ }
+
+ if (result != 0) {
+ break;
+ }
+ }
+ close(pipefd[0]);
+ } else {
+ close(pipefd[0]);
+ if (dup2(pipefd[1], 1) < 0)
+ PERROR("dup2 failed");
+ close(pipefd[1]);
+
+ const char* argv[] = {
+ // TODO: Handle $(SHELL).
+ "/bin/sh", "-c", cmd.c_str(), NULL
+ };
+ execvp(argv[0], const_cast<char**>(argv));
+ }
+}
+
void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
shared_ptr<string> cmd = args[0]->Eval(ev);
if (ev->avoid_io()) {
@@ -448,9 +494,9 @@ void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
return;
#endif
-
COLLECT_STATS_WITH_SLOW_REPORT("func shell time", cmd->c_str());
string out;
+#if 0
// TODO: Handle $(SHELL).
FILE* fp = popen(cmd->c_str(), "r");
while (true) {
@@ -462,6 +508,9 @@ void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
break;
}
}
+#else
+ RunCommand(*cmd, &out);
+#endif
while (out[out.size()-1] == '\n')
out.pop_back();