diff --git a/command.cpp b/command.cpp index 5004c46..ab4e77b 100644 --- a/command.cpp +++ b/command.cpp @@ -19,6 +19,42 @@ extern volatile int control_c; + +void launch_mpw(const Environment &env, const std::vector &argv, const fdmask &fds) { + + std::vector cargv; + cargv.reserve(argv.size() + 3); + + + cargv.push_back((char *)"mpw"); + //cargv.push_back((char *)"--shell"); + + unsigned offset = cargv.size(); + + + std::transform(argv.begin(), argv.end(), std::back_inserter(cargv), + [](const std::string &s) { return strdup(s.c_str()); } + ); + cargv.push_back(nullptr); + + + // export environment... + + for (const auto &kv : env) { + if (kv.second) { // exported + std::string name = "mpw$" + kv.first; + setenv(name.c_str(), kv.second.c_str(), 1); + } + } + + // handle any indirection... + fds.dup(); + + execvp(cargv.front(), cargv.data()); + perror("execvp: "); + exit(EX_OSERR); // raise a signal? +} + namespace { std::string &lowercase(std::string &s) { @@ -40,26 +76,15 @@ namespace { + + int execute_external(const Environment &env, const std::vector &argv, const fdmask &fds) { - std::vector cargv; - cargv.reserve(argv.size() + 3); + int status; int pid; - cargv.push_back((char *)"mpw"); - //cargv.push_back((char *)"--shell"); - - unsigned offset = cargv.size(); - - - std::transform(argv.begin(), argv.end(), std::back_inserter(cargv), - [](const std::string &s) { return strdup(s.c_str()); } - ); - - cargv.push_back(nullptr); - pid = fork(); if (pid < 0) { @@ -69,26 +94,9 @@ namespace { if (pid == 0) { - - // export environment... - - for (const auto &kv : env) { - if (kv.second) { // exported - std::string name = "mpw$" + kv.first; - setenv(name.c_str(), kv.second.c_str(), 1); - } - } - - // handle any indirection... - fds.dup(); - - execvp(cargv.front(), cargv.data()); - perror("execvp: "); - exit(EX_OSERR); + launch_mpw(env, argv, fds); } - std::for_each(cargv.begin()+offset, cargv.end(), free); - for(;;) { int status; pid_t ok; diff --git a/fdset.h b/fdset.h index edf5046..8bbcfc3 100644 --- a/fdset.h +++ b/fdset.h @@ -25,6 +25,9 @@ class fdmask { fdmask(const std::array &rhs) : _fds(rhs) {} + fdmask(int a, int b, int c) : _fds{{ a, b, c }} + {} + #if 0 fdmask(std::initializer_list rhs) : _fds(rhs) {} diff --git a/mpw-shell.cpp b/mpw-shell.cpp index 4c54f86..cbd99f5 100644 --- a/mpw-shell.cpp +++ b/mpw-shell.cpp @@ -98,6 +98,71 @@ int read_fd(phase1 &p, int fd) { return 0; } +void launch_mpw(const Environment &env, const std::vector &argv, const fdmask &fds); + +int read_make(phase1 &p1, phase2 &p2, Environment &env, const std::vector &argv) { + + int out[2]; + int ok; + + + env.set("echo", "1"); + env.set("exit", "1"); + + ok = pipe(out); + if (ok < 0) { + perror("pipe"); + exit(EX_OSERR); + } + fcntl(out[0], F_SETFD, FD_CLOEXEC); + fcntl(out[1], F_SETFD, FD_CLOEXEC); + + int child = fork(); + if (child < 0) { + perror("fork"); + exit(EX_OSERR); + } + if (child == 0) { + // child. + fdmask fds = {-1, out[1], -1}; + + launch_mpw(env, argv, fds); + + exit(EX_OSERR); + } + + close(out[1]); + int rv = read_fd(p1, out[0]); + close(out[0]); + p2.finish(); + + // check for make errors. + for(;;) { + int status; + int ok = waitpid(child, &status, 0); + if (ok < 0) { + if (errno == EINTR) continue; + perror("waitpid: "); + exit(EX_OSERR); + } + + if (WIFEXITED(status)) { + ok = WEXITSTATUS(status); + env.status(ok, false); + break; + } + if (WIFSIGNALED(status)) { + env.status(-9, false); + break; + } + + fprintf(stderr, "waitpid - unexpected result\n"); + exit(EX_OSERR); + } + + return env.status(); +} + volatile int control_c = 0; void control_c_handler(int signal, siginfo_t *sinfo, void *context) { @@ -193,7 +258,83 @@ void define(Environment &env, const std::string &s) { } +std::string basename(const char *cp) { + std::string tmp(cp); + auto pos = tmp.rfind('/'); + if (pos == tmp.npos) return tmp; + return tmp.substr(pos+1); + +} + +void make_help() { + +} + +int make(int argc, char **argv) { + + Environment e; + init(e); + + std::vector args; + args.reserve(argc+1); + bool __ = false; + + args.emplace_back("make"); + + for (auto iter = argv; *iter; ++iter) { + std::string tmp(*iter); + + if (!__) { + if (tmp == "--") + { __ = true; continue; } + + if (tmp == "--help") + { make_help(); exit(0); } + + if (tmp == "--test" || tmp == "--dry-run") + { e.set("test", "1"); continue; } + } + args.emplace_back(std::move(tmp)); + + } + + phase1 p1; + phase2 p2; + + p1 >>= [&p2](std::string &&s) { + if (s.empty()) p2.finish(); + else p2(std::move(s)); + }; + + p2 >>= [&e](command_ptr_vector &&v) { + + for (auto iter = v.begin(); iter != v.end(); ++iter) { + auto &ptr = *iter; + fdmask fds; + try { + ptr->execute(e, fds); + } catch (execution_of_input_terminated &ex) { + control_c = 0; + if (!(ptr->terminal() && ++iter == v.end())) { + fprintf(stderr, "%s\n", ex.what()); + } + e.status(ex.status(), false); + return; + } + } + }; + + + return read_make(p1, p2, e, args); + +} + int main(int argc, char **argv) { + + + std::string self = basename(argv[0]); + if (self == "mpw-make") return make(argc - 1, argv + 1); + if (self == "mpw-shell" && argc > 1 && !strcmp(argv[1],"make")) return make(argc - 2, argv + 2); Environment e; init(e);