57 | | posix_spawn_file_actions_t action; |
58 | | int err = posix_spawn_file_actions_init(&action); |
59 | | if (err != 0) |
60 | | Fatal("posix_spawn_file_actions_init: %s", strerror(err)); |
61 | | |
62 | | err = posix_spawn_file_actions_addclose(&action, output_pipe[0]); |
63 | | if (err != 0) |
64 | | Fatal("posix_spawn_file_actions_addclose: %s", strerror(err)); |
65 | | |
66 | | posix_spawnattr_t attr; |
67 | | err = posix_spawnattr_init(&attr); |
68 | | if (err != 0) |
69 | | Fatal("posix_spawnattr_init: %s", strerror(err)); |
70 | | |
71 | | short flags = 0; |
72 | | |
73 | | flags |= POSIX_SPAWN_SETSIGMASK; |
74 | | err = posix_spawnattr_setsigmask(&attr, &set->old_mask_); |
75 | | if (err != 0) |
76 | | Fatal("posix_spawnattr_setsigmask: %s", strerror(err)); |
77 | | // Signals which are set to be caught in the calling process image are set to |
78 | | // default action in the new process image, so no explicit |
79 | | // POSIX_SPAWN_SETSIGDEF parameter is needed. |
80 | | |
81 | | if (!use_console_) { |
82 | | // Put the child in its own process group, so ctrl-c won't reach it. |
83 | | flags |= POSIX_SPAWN_SETPGROUP; |
84 | | // No need to posix_spawnattr_setpgroup(&attr, 0), it's the default. |
85 | | |
86 | | // Open /dev/null over stdin. |
87 | | err = posix_spawn_file_actions_addopen(&action, 0, "/dev/null", O_RDONLY, |
88 | | 0); |
89 | | if (err != 0) { |
90 | | Fatal("posix_spawn_file_actions_addopen: %s", strerror(err)); |
91 | | } |
| 54 | pid_ = fork(); |
| 55 | if (pid_ < 0) |
| 56 | Fatal("fork: %s", strerror(errno)); |
| 57 | |
| 58 | if (pid_ == 0) { |
| 59 | close(output_pipe[0]); |
| 60 | |
| 61 | // Track which fd we use to report errors on. |
| 62 | int error_pipe = output_pipe[1]; |
| 63 | do { |
| 64 | if (sigaction(SIGINT, &set->old_int_act_, 0) < 0) |
| 65 | break; |
| 66 | if (sigaction(SIGTERM, &set->old_term_act_, 0) < 0) |
| 67 | break; |
| 68 | if (sigaction(SIGHUP, &set->old_hup_act_, 0) < 0) |
| 69 | break; |
| 70 | if (sigprocmask(SIG_SETMASK, &set->old_mask_, 0) < 0) |
| 71 | break; |
| 72 | |
| 73 | if (!use_console_) { |
| 74 | // Put the child in its own process group, so ctrl-c won't reach it. |
| 75 | if (setpgid(0, 0) < 0) |
| 76 | break; |
| 77 | |
| 78 | // Open /dev/null over stdin. |
| 79 | int devnull = open("/dev/null", O_RDONLY); |
| 80 | if (devnull < 0) |
| 81 | break; |
| 82 | if (dup2(devnull, 0) < 0) |
| 83 | break; |
| 84 | close(devnull); |
| 85 | |
| 86 | if (dup2(output_pipe[1], 1) < 0 || |
| 87 | dup2(output_pipe[1], 2) < 0) |
| 88 | break; |
| 89 | |
| 90 | // Now can use stderr for errors. |
| 91 | error_pipe = 2; |
| 92 | close(output_pipe[1]); |
| 93 | } |
| 94 | // In the console case, output_pipe is still inherited by the child and |
| 95 | // closed when the subprocess finishes, which then notifies ninja. |
93 | | err = posix_spawn_file_actions_adddup2(&action, output_pipe[1], 1); |
94 | | if (err != 0) |
95 | | Fatal("posix_spawn_file_actions_adddup2: %s", strerror(err)); |
96 | | err = posix_spawn_file_actions_adddup2(&action, output_pipe[1], 2); |
97 | | if (err != 0) |
98 | | Fatal("posix_spawn_file_actions_adddup2: %s", strerror(err)); |
99 | | err = posix_spawn_file_actions_addclose(&action, output_pipe[1]); |
100 | | if (err != 0) |
101 | | Fatal("posix_spawn_file_actions_addclose: %s", strerror(err)); |
102 | | // In the console case, output_pipe is still inherited by the child and |
103 | | // closed when the subprocess finishes, which then notifies ninja. |
104 | | } |
105 | | #ifdef POSIX_SPAWN_USEVFORK |
106 | | flags |= POSIX_SPAWN_USEVFORK; |
107 | | #endif |
108 | | |
109 | | err = posix_spawnattr_setflags(&attr, flags); |
110 | | if (err != 0) |
111 | | Fatal("posix_spawnattr_setflags: %s", strerror(err)); |
112 | | |
113 | | const char* spawned_args[] = { "/bin/sh", "-c", command.c_str(), NULL }; |
114 | | err = posix_spawn(&pid_, "/bin/sh", &action, &attr, |
115 | | const_cast<char**>(spawned_args), environ); |
116 | | if (err != 0) |
117 | | Fatal("posix_spawn: %s", strerror(err)); |
118 | | |
119 | | err = posix_spawnattr_destroy(&attr); |
120 | | if (err != 0) |
121 | | Fatal("posix_spawnattr_destroy: %s", strerror(err)); |
122 | | err = posix_spawn_file_actions_destroy(&action); |
123 | | if (err != 0) |
124 | | Fatal("posix_spawn_file_actions_destroy: %s", strerror(err)); |
| 97 | execl("/bin/sh", "/bin/sh", "-c", command.c_str(), (char *) NULL); |
| 98 | } while (false); |
| 99 | |
| 100 | // If we get here, something went wrong; the execl should have |
| 101 | // replaced us. |
| 102 | char* err = strerror(errno); |
| 103 | if (write(error_pipe, err, strlen(err)) < 0) { |
| 104 | // If the write fails, there's nothing we can do. |
| 105 | // But this block seems necessary to silence the warning. |
| 106 | } |
| 107 | _exit(1); |
| 108 | } |