--- src/subprocess-posix.cc.orig 2022-05-15 10:08:10.000000000 -0500 +++ src/subprocess-posix.cc 2022-05-18 04:18:56.000000000 -0500 @@ -22,7 +22,6 @@ #include #include #include -#include #if defined(USE_PPOLL) #include @@ -30,7 +29,6 @@ #include #endif -extern char** environ; #include "util.h" @@ -61,74 +59,61 @@ #endif // !USE_PPOLL SetCloseOnExec(fd_); - posix_spawn_file_actions_t action; - int err = posix_spawn_file_actions_init(&action); - if (err != 0) - Fatal("posix_spawn_file_actions_init: %s", strerror(err)); - - err = posix_spawn_file_actions_addclose(&action, output_pipe[0]); - if (err != 0) - Fatal("posix_spawn_file_actions_addclose: %s", strerror(err)); - - posix_spawnattr_t attr; - err = posix_spawnattr_init(&attr); - if (err != 0) - Fatal("posix_spawnattr_init: %s", strerror(err)); - - short flags = 0; - - flags |= POSIX_SPAWN_SETSIGMASK; - err = posix_spawnattr_setsigmask(&attr, &set->old_mask_); - if (err != 0) - Fatal("posix_spawnattr_setsigmask: %s", strerror(err)); - // Signals which are set to be caught in the calling process image are set to - // default action in the new process image, so no explicit - // POSIX_SPAWN_SETSIGDEF parameter is needed. - - if (!use_console_) { - // Put the child in its own process group, so ctrl-c won't reach it. - flags |= POSIX_SPAWN_SETPGROUP; - // No need to posix_spawnattr_setpgroup(&attr, 0), it's the default. - - // Open /dev/null over stdin. - err = posix_spawn_file_actions_addopen(&action, 0, "/dev/null", O_RDONLY, - 0); - if (err != 0) { - Fatal("posix_spawn_file_actions_addopen: %s", strerror(err)); - } + pid_ = fork(); + if (pid_ < 0) + Fatal("fork: %s", strerror(errno)); + + if (pid_ == 0) { + close(output_pipe[0]); + + // Track which fd we use to report errors on. + int error_pipe = output_pipe[1]; + do { + if (sigaction(SIGINT, &set->old_int_act_, 0) < 0) + break; + if (sigaction(SIGTERM, &set->old_term_act_, 0) < 0) + break; + if (sigaction(SIGHUP, &set->old_hup_act_, 0) < 0) + break; + if (sigprocmask(SIG_SETMASK, &set->old_mask_, 0) < 0) + break; + + if (!use_console_) { + // Put the child in its own process group, so ctrl-c won't reach it. + if (setpgid(0, 0) < 0) + break; + + // Open /dev/null over stdin. + int devnull = open("/dev/null", O_RDONLY); + if (devnull < 0) + break; + if (dup2(devnull, 0) < 0) + break; + close(devnull); + + if (dup2(output_pipe[1], 1) < 0 || + dup2(output_pipe[1], 2) < 0) + break; + + // Now can use stderr for errors. + error_pipe = 2; + close(output_pipe[1]); + } + // In the console case, output_pipe is still inherited by the child and + // closed when the subprocess finishes, which then notifies ninja. - err = posix_spawn_file_actions_adddup2(&action, output_pipe[1], 1); - if (err != 0) - Fatal("posix_spawn_file_actions_adddup2: %s", strerror(err)); - err = posix_spawn_file_actions_adddup2(&action, output_pipe[1], 2); - if (err != 0) - Fatal("posix_spawn_file_actions_adddup2: %s", strerror(err)); - err = posix_spawn_file_actions_addclose(&action, output_pipe[1]); - if (err != 0) - Fatal("posix_spawn_file_actions_addclose: %s", strerror(err)); - // In the console case, output_pipe is still inherited by the child and - // closed when the subprocess finishes, which then notifies ninja. - } -#ifdef POSIX_SPAWN_USEVFORK - flags |= POSIX_SPAWN_USEVFORK; -#endif + execl("/bin/sh", "/bin/sh", "-c", command.c_str(), (char *) NULL); + } while (false); - err = posix_spawnattr_setflags(&attr, flags); - if (err != 0) - Fatal("posix_spawnattr_setflags: %s", strerror(err)); - - const char* spawned_args[] = { "/bin/sh", "-c", command.c_str(), NULL }; - err = posix_spawn(&pid_, "/bin/sh", &action, &attr, - const_cast(spawned_args), environ); - if (err != 0) - Fatal("posix_spawn: %s", strerror(err)); - - err = posix_spawnattr_destroy(&attr); - if (err != 0) - Fatal("posix_spawnattr_destroy: %s", strerror(err)); - err = posix_spawn_file_actions_destroy(&action); - if (err != 0) - Fatal("posix_spawn_file_actions_destroy: %s", strerror(err)); + // If we get here, something went wrong; the execl should have + // replaced us. + char* err = strerror(errno); + if (write(error_pipe, err, strlen(err)) < 0) { + // If the write fails, there's nothing we can do. + // But this block seems necessary to silence the warning. + } + _exit(1); + } close(output_pipe[1]); return true; --- src/subprocess_test.cc.orig 2022-05-15 10:08:10.000000000 -0500 +++ src/subprocess_test.cc 2022-05-18 04:18:56.000000000 -0500 @@ -226,8 +226,7 @@ rlimit rlim; ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlim)); if (rlim.rlim_cur < kNumProcs) { - printf("Raise [ulimit -n] above %u (currently %lu) to make this test go\n", - kNumProcs, rlim.rlim_cur); + printf("Raise [ulimit -n] well above %u (currently %lu) to make this test go\n", kNumProcs, rlim.rlim_cur); return; }