1 | /* |
2 | * Copyright (c) Facebook, Inc. and its affiliates. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #ifndef _GNU_SOURCE |
18 | #define _GNU_SOURCE |
19 | #endif |
20 | |
21 | #include <folly/Subprocess.h> |
22 | |
23 | #if defined(__linux__) |
24 | #include <sys/prctl.h> |
25 | #endif |
26 | #include <fcntl.h> |
27 | |
28 | #include <algorithm> |
29 | #include <array> |
30 | #include <system_error> |
31 | #include <thread> |
32 | |
33 | #include <boost/container/flat_set.hpp> |
34 | #include <boost/range/adaptors.hpp> |
35 | |
36 | #include <glog/logging.h> |
37 | |
38 | #include <folly/Conv.h> |
39 | #include <folly/Exception.h> |
40 | #include <folly/ScopeGuard.h> |
41 | #include <folly/String.h> |
42 | #include <folly/io/Cursor.h> |
43 | #include <folly/lang/Assume.h> |
44 | #include <folly/portability/Sockets.h> |
45 | #include <folly/portability/Stdlib.h> |
46 | #include <folly/portability/SysSyscall.h> |
47 | #include <folly/portability/Unistd.h> |
48 | #include <folly/system/Shell.h> |
49 | |
50 | constexpr int kExecFailure = 127; |
51 | constexpr int kChildFailure = 126; |
52 | |
53 | namespace folly { |
54 | |
55 | ProcessReturnCode ProcessReturnCode::make(int status) { |
56 | if (!WIFEXITED(status) && !WIFSIGNALED(status)) { |
57 | throw std::runtime_error( |
58 | to<std::string>("Invalid ProcessReturnCode: " , status)); |
59 | } |
60 | return ProcessReturnCode(status); |
61 | } |
62 | |
63 | ProcessReturnCode::ProcessReturnCode(ProcessReturnCode&& p) noexcept |
64 | : rawStatus_(p.rawStatus_) { |
65 | p.rawStatus_ = ProcessReturnCode::RV_NOT_STARTED; |
66 | } |
67 | |
68 | ProcessReturnCode& ProcessReturnCode::operator=( |
69 | ProcessReturnCode&& p) noexcept { |
70 | rawStatus_ = p.rawStatus_; |
71 | p.rawStatus_ = ProcessReturnCode::RV_NOT_STARTED; |
72 | return *this; |
73 | } |
74 | |
75 | ProcessReturnCode::State ProcessReturnCode::state() const { |
76 | if (rawStatus_ == RV_NOT_STARTED) { |
77 | return NOT_STARTED; |
78 | } |
79 | if (rawStatus_ == RV_RUNNING) { |
80 | return RUNNING; |
81 | } |
82 | if (WIFEXITED(rawStatus_)) { |
83 | return EXITED; |
84 | } |
85 | if (WIFSIGNALED(rawStatus_)) { |
86 | return KILLED; |
87 | } |
88 | assume_unreachable(); |
89 | } |
90 | |
91 | void ProcessReturnCode::enforce(State expected) const { |
92 | State s = state(); |
93 | if (s != expected) { |
94 | throw std::logic_error(to<std::string>( |
95 | "Bad use of ProcessReturnCode; state is " , s, " expected " , expected)); |
96 | } |
97 | } |
98 | |
99 | int ProcessReturnCode::exitStatus() const { |
100 | enforce(EXITED); |
101 | return WEXITSTATUS(rawStatus_); |
102 | } |
103 | |
104 | int ProcessReturnCode::killSignal() const { |
105 | enforce(KILLED); |
106 | return WTERMSIG(rawStatus_); |
107 | } |
108 | |
109 | bool ProcessReturnCode::coreDumped() const { |
110 | enforce(KILLED); |
111 | return WCOREDUMP(rawStatus_); |
112 | } |
113 | |
114 | std::string ProcessReturnCode::str() const { |
115 | switch (state()) { |
116 | case NOT_STARTED: |
117 | return "not started" ; |
118 | case RUNNING: |
119 | return "running" ; |
120 | case EXITED: |
121 | return to<std::string>("exited with status " , exitStatus()); |
122 | case KILLED: |
123 | return to<std::string>( |
124 | "killed by signal " , |
125 | killSignal(), |
126 | (coreDumped() ? " (core dumped)" : "" )); |
127 | } |
128 | assume_unreachable(); |
129 | } |
130 | |
131 | CalledProcessError::CalledProcessError(ProcessReturnCode rc) |
132 | : SubprocessError(rc.str()), returnCode_(rc) {} |
133 | |
134 | static inline std::string toSubprocessSpawnErrorMessage( |
135 | char const* executable, |
136 | int errCode, |
137 | int errnoValue) { |
138 | auto prefix = errCode == kExecFailure ? "failed to execute " |
139 | : "error preparing to execute " ; |
140 | return to<std::string>(prefix, executable, ": " , errnoStr(errnoValue)); |
141 | } |
142 | |
143 | SubprocessSpawnError::SubprocessSpawnError( |
144 | const char* executable, |
145 | int errCode, |
146 | int errnoValue) |
147 | : SubprocessError( |
148 | toSubprocessSpawnErrorMessage(executable, errCode, errnoValue)), |
149 | errnoValue_(errnoValue) {} |
150 | |
151 | namespace { |
152 | |
153 | // Copy pointers to the given strings in a format suitable for posix_spawn |
154 | std::unique_ptr<const char* []> cloneStrings( |
155 | const std::vector<std::string>& s) { |
156 | std::unique_ptr<const char*[]> d(new const char*[s.size() + 1]); |
157 | for (size_t i = 0; i < s.size(); i++) { |
158 | d[i] = s[i].c_str(); |
159 | } |
160 | d[s.size()] = nullptr; |
161 | return d; |
162 | } |
163 | |
164 | // Check a wait() status, throw on non-successful |
165 | void checkStatus(ProcessReturnCode returnCode) { |
166 | if (returnCode.state() != ProcessReturnCode::EXITED || |
167 | returnCode.exitStatus() != 0) { |
168 | throw CalledProcessError(returnCode); |
169 | } |
170 | } |
171 | |
172 | } // namespace |
173 | |
174 | Subprocess::Options& Subprocess::Options::fd(int fd, int action) { |
175 | if (action == Subprocess::PIPE) { |
176 | if (fd == 0) { |
177 | action = Subprocess::PIPE_IN; |
178 | } else if (fd == 1 || fd == 2) { |
179 | action = Subprocess::PIPE_OUT; |
180 | } else { |
181 | throw std::invalid_argument( |
182 | to<std::string>("Only fds 0, 1, 2 are valid for action=PIPE: " , fd)); |
183 | } |
184 | } |
185 | fdActions_[fd] = action; |
186 | return *this; |
187 | } |
188 | |
189 | Subprocess::Subprocess() = default; |
190 | |
191 | Subprocess::Subprocess( |
192 | const std::vector<std::string>& argv, |
193 | const Options& options, |
194 | const char* executable, |
195 | const std::vector<std::string>* env) { |
196 | if (argv.empty()) { |
197 | throw std::invalid_argument("argv must not be empty" ); |
198 | } |
199 | if (!executable) { |
200 | executable = argv[0].c_str(); |
201 | } |
202 | spawn(cloneStrings(argv), executable, options, env); |
203 | } |
204 | |
205 | Subprocess::Subprocess( |
206 | const std::string& cmd, |
207 | const Options& options, |
208 | const std::vector<std::string>* env) { |
209 | if (options.usePath_) { |
210 | throw std::invalid_argument("usePath() not allowed when running in shell" ); |
211 | } |
212 | |
213 | std::vector<std::string> argv = {"/bin/sh" , "-c" , cmd}; |
214 | spawn(cloneStrings(argv), argv[0].c_str(), options, env); |
215 | } |
216 | |
217 | Subprocess::~Subprocess() { |
218 | CHECK_NE(returnCode_.state(), ProcessReturnCode::RUNNING) |
219 | << "Subprocess destroyed without reaping child" ; |
220 | } |
221 | |
222 | namespace { |
223 | |
224 | struct ChildErrorInfo { |
225 | int errCode; |
226 | int errnoValue; |
227 | }; |
228 | |
229 | [[noreturn]] void childError(int errFd, int errCode, int errnoValue) { |
230 | ChildErrorInfo info = {errCode, errnoValue}; |
231 | // Write the error information over the pipe to our parent process. |
232 | // We can't really do anything else if this write call fails. |
233 | writeNoInt(errFd, &info, sizeof(info)); |
234 | // exit |
235 | _exit(errCode); |
236 | } |
237 | |
238 | } // namespace |
239 | |
240 | void Subprocess::setAllNonBlocking() { |
241 | for (auto& p : pipes_) { |
242 | int fd = p.pipe.fd(); |
243 | int flags = ::fcntl(fd, F_GETFL); |
244 | checkUnixError(flags, "fcntl" ); |
245 | int r = ::fcntl(fd, F_SETFL, flags | O_NONBLOCK); |
246 | checkUnixError(r, "fcntl" ); |
247 | } |
248 | } |
249 | |
250 | void Subprocess::spawn( |
251 | std::unique_ptr<const char*[]> argv, |
252 | const char* executable, |
253 | const Options& optionsIn, |
254 | const std::vector<std::string>* env) { |
255 | if (optionsIn.usePath_ && env) { |
256 | throw std::invalid_argument( |
257 | "usePath() not allowed when overriding environment" ); |
258 | } |
259 | |
260 | // Make a copy, we'll mutate options |
261 | Options options(optionsIn); |
262 | |
263 | // On error, close all pipes_ (ignoring errors, but that seems fine here). |
264 | auto pipesGuard = makeGuard([this] { pipes_.clear(); }); |
265 | |
266 | // Create a pipe to use to receive error information from the child, |
267 | // in case it fails before calling exec() |
268 | int errFds[2]; |
269 | #if FOLLY_HAVE_PIPE2 |
270 | checkUnixError(::pipe2(errFds, O_CLOEXEC), "pipe2" ); |
271 | #else |
272 | checkUnixError(::pipe(errFds), "pipe" ); |
273 | #endif |
274 | SCOPE_EXIT { |
275 | CHECK_ERR(::close(errFds[0])); |
276 | if (errFds[1] >= 0) { |
277 | CHECK_ERR(::close(errFds[1])); |
278 | } |
279 | }; |
280 | |
281 | #if !FOLLY_HAVE_PIPE2 |
282 | // Ask the child to close the read end of the error pipe. |
283 | checkUnixError(fcntl(errFds[0], F_SETFD, FD_CLOEXEC), "set FD_CLOEXEC" ); |
284 | // Set the close-on-exec flag on the write side of the pipe. |
285 | // This way the pipe will be closed automatically in the child if execve() |
286 | // succeeds. If the exec fails the child can write error information to the |
287 | // pipe. |
288 | checkUnixError(fcntl(errFds[1], F_SETFD, FD_CLOEXEC), "set FD_CLOEXEC" ); |
289 | #endif |
290 | |
291 | // Perform the actual work of setting up pipes then forking and |
292 | // executing the child. |
293 | spawnInternal(std::move(argv), executable, options, env, errFds[1]); |
294 | |
295 | // After spawnInternal() returns the child is alive. We have to be very |
296 | // careful about throwing after this point. We are inside the constructor, |
297 | // so if we throw the Subprocess object will have never existed, and the |
298 | // destructor will never be called. |
299 | // |
300 | // We should only throw if we got an error via the errFd, and we know the |
301 | // child has exited and can be immediately waited for. In all other cases, |
302 | // we have no way of cleaning up the child. |
303 | |
304 | // Close writable side of the errFd pipe in the parent process |
305 | CHECK_ERR(::close(errFds[1])); |
306 | errFds[1] = -1; |
307 | |
308 | // Read from the errFd pipe, to tell if the child ran into any errors before |
309 | // calling exec() |
310 | readChildErrorPipe(errFds[0], executable); |
311 | |
312 | // If we spawned a detached child, wait on the intermediate child process. |
313 | // It always exits immediately. |
314 | if (options.detach_) { |
315 | wait(); |
316 | } |
317 | |
318 | // We have fully succeeded now, so release the guard on pipes_ |
319 | pipesGuard.dismiss(); |
320 | } |
321 | |
322 | // With -Wclobbered, gcc complains about vfork potentially cloberring the |
323 | // childDir variable, even though we only use it on the child side of the |
324 | // vfork. |
325 | |
326 | FOLLY_PUSH_WARNING |
327 | FOLLY_GCC_DISABLE_WARNING("-Wclobbered" ) |
328 | void Subprocess::spawnInternal( |
329 | std::unique_ptr<const char*[]> argv, |
330 | const char* executable, |
331 | Options& options, |
332 | const std::vector<std::string>* env, |
333 | int errFd) { |
334 | // Parent work, pre-fork: create pipes |
335 | std::vector<int> childFds; |
336 | // Close all of the childFds as we leave this scope |
337 | SCOPE_EXIT { |
338 | // These are only pipes, closing them shouldn't fail |
339 | for (int cfd : childFds) { |
340 | CHECK_ERR(::close(cfd)); |
341 | } |
342 | }; |
343 | |
344 | int r; |
345 | for (auto& p : options.fdActions_) { |
346 | if (p.second == PIPE_IN || p.second == PIPE_OUT) { |
347 | int fds[2]; |
348 | // We're setting both ends of the pipe as close-on-exec. The child |
349 | // doesn't need to reset the flag on its end, as we always dup2() the fd, |
350 | // and dup2() fds don't share the close-on-exec flag. |
351 | #if FOLLY_HAVE_PIPE2 |
352 | // If possible, set close-on-exec atomically. Otherwise, a concurrent |
353 | // Subprocess invocation can fork() between "pipe" and "fnctl", |
354 | // causing FDs to leak. |
355 | r = ::pipe2(fds, O_CLOEXEC); |
356 | checkUnixError(r, "pipe2" ); |
357 | #else |
358 | r = ::pipe(fds); |
359 | checkUnixError(r, "pipe" ); |
360 | r = fcntl(fds[0], F_SETFD, FD_CLOEXEC); |
361 | checkUnixError(r, "set FD_CLOEXEC" ); |
362 | r = fcntl(fds[1], F_SETFD, FD_CLOEXEC); |
363 | checkUnixError(r, "set FD_CLOEXEC" ); |
364 | #endif |
365 | pipes_.emplace_back(); |
366 | Pipe& pipe = pipes_.back(); |
367 | pipe.direction = p.second; |
368 | int cfd; |
369 | if (p.second == PIPE_IN) { |
370 | // Child gets reading end |
371 | pipe.pipe = folly::File(fds[1], /*ownsFd=*/true); |
372 | cfd = fds[0]; |
373 | } else { |
374 | pipe.pipe = folly::File(fds[0], /*ownsFd=*/true); |
375 | cfd = fds[1]; |
376 | } |
377 | p.second = cfd; // ensure it gets dup2()ed |
378 | pipe.childFd = p.first; |
379 | childFds.push_back(cfd); |
380 | } |
381 | } |
382 | |
383 | // This should already be sorted, as options.fdActions_ is |
384 | DCHECK(std::is_sorted(pipes_.begin(), pipes_.end())); |
385 | |
386 | // Note that the const casts below are legit, per |
387 | // http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html |
388 | |
389 | auto argVec = const_cast<char**>(argv.get()); |
390 | |
391 | // Set up environment |
392 | std::unique_ptr<const char*[]> envHolder; |
393 | char** envVec; |
394 | if (env) { |
395 | envHolder = cloneStrings(*env); |
396 | envVec = const_cast<char**>(envHolder.get()); |
397 | } else { |
398 | envVec = environ; |
399 | } |
400 | |
401 | // Block all signals around vfork; see http://ewontfix.com/7/. |
402 | // |
403 | // As the child may run in the same address space as the parent until |
404 | // the actual execve() system call, any (custom) signal handlers that |
405 | // the parent has might alter parent's memory if invoked in the child, |
406 | // with undefined results. So we block all signals in the parent before |
407 | // vfork(), which will cause them to be blocked in the child as well (we |
408 | // rely on the fact that Linux, just like all sane implementations, only |
409 | // clones the calling thread). Then, in the child, we reset all signals |
410 | // to their default dispositions (while still blocked), and unblock them |
411 | // (so the exec()ed process inherits the parent's signal mask) |
412 | // |
413 | // The parent also unblocks all signals as soon as vfork() returns. |
414 | sigset_t allBlocked; |
415 | r = sigfillset(&allBlocked); |
416 | checkUnixError(r, "sigfillset" ); |
417 | sigset_t oldSignals; |
418 | |
419 | r = pthread_sigmask(SIG_SETMASK, &allBlocked, &oldSignals); |
420 | checkPosixError(r, "pthread_sigmask" ); |
421 | SCOPE_EXIT { |
422 | // Restore signal mask |
423 | r = pthread_sigmask(SIG_SETMASK, &oldSignals, nullptr); |
424 | CHECK_EQ(r, 0) << "pthread_sigmask: " << errnoStr(r); // shouldn't fail |
425 | }; |
426 | |
427 | // Call c_str() here, as it's not necessarily safe after fork. |
428 | const char* childDir = |
429 | options.childDir_.empty() ? nullptr : options.childDir_.c_str(); |
430 | |
431 | pid_t pid; |
432 | #ifdef __linux__ |
433 | if (options.cloneFlags_) { |
434 | pid = syscall(SYS_clone, *options.cloneFlags_, 0, nullptr, nullptr); |
435 | } else { |
436 | #endif |
437 | if (options.detach_) { |
438 | // If we are detaching we must use fork() instead of vfork() for the first |
439 | // fork, since we aren't going to simply call exec() in the child. |
440 | pid = fork(); |
441 | } else { |
442 | pid = vfork(); |
443 | } |
444 | #ifdef __linux__ |
445 | } |
446 | #endif |
447 | checkUnixError(pid, errno, "failed to fork" ); |
448 | if (pid == 0) { |
449 | // Fork a second time if detach_ was requested. |
450 | // This must be done before signals are restored in prepareChild() |
451 | if (options.detach_) { |
452 | #ifdef __linux__ |
453 | if (options.cloneFlags_) { |
454 | pid = syscall(SYS_clone, *options.cloneFlags_, 0, nullptr, nullptr); |
455 | } else { |
456 | #endif |
457 | pid = vfork(); |
458 | #ifdef __linux__ |
459 | } |
460 | #endif |
461 | if (pid == -1) { |
462 | // Inform our parent process of the error so it can throw in the parent. |
463 | childError(errFd, kChildFailure, errno); |
464 | } else if (pid != 0) { |
465 | // We are the intermediate process. Exit immediately. |
466 | // Our child will still inform the original parent of success/failure |
467 | // through errFd. The pid of the grandchild process never gets |
468 | // propagated back up to the original parent. In the future we could |
469 | // potentially send it back using errFd if we needed to. |
470 | _exit(0); |
471 | } |
472 | } |
473 | |
474 | int errnoValue = prepareChild(options, &oldSignals, childDir); |
475 | if (errnoValue != 0) { |
476 | childError(errFd, kChildFailure, errnoValue); |
477 | } |
478 | |
479 | errnoValue = runChild(executable, argVec, envVec, options); |
480 | // If we get here, exec() failed. |
481 | childError(errFd, kExecFailure, errnoValue); |
482 | } |
483 | |
484 | // Child is alive. We have to be very careful about throwing after this |
485 | // point. We are inside the constructor, so if we throw the Subprocess |
486 | // object will have never existed, and the destructor will never be called. |
487 | // |
488 | // We should only throw if we got an error via the errFd, and we know the |
489 | // child has exited and can be immediately waited for. In all other cases, |
490 | // we have no way of cleaning up the child. |
491 | pid_ = pid; |
492 | returnCode_ = ProcessReturnCode::makeRunning(); |
493 | } |
494 | FOLLY_POP_WARNING |
495 | |
496 | int Subprocess::prepareChild( |
497 | const Options& options, |
498 | const sigset_t* sigmask, |
499 | const char* childDir) const { |
500 | // While all signals are blocked, we must reset their |
501 | // dispositions to default. |
502 | for (int sig = 1; sig < NSIG; ++sig) { |
503 | ::signal(sig, SIG_DFL); |
504 | } |
505 | |
506 | { |
507 | // Unblock signals; restore signal mask. |
508 | int r = pthread_sigmask(SIG_SETMASK, sigmask, nullptr); |
509 | if (r != 0) { |
510 | return r; // pthread_sigmask() returns an errno value |
511 | } |
512 | } |
513 | |
514 | // Change the working directory, if one is given |
515 | if (childDir) { |
516 | if (::chdir(childDir) == -1) { |
517 | return errno; |
518 | } |
519 | } |
520 | |
521 | // We don't have to explicitly close the parent's end of all pipes, |
522 | // as they all have the FD_CLOEXEC flag set and will be closed at |
523 | // exec time. |
524 | |
525 | // Close all fds that we're supposed to close. |
526 | for (auto& p : options.fdActions_) { |
527 | if (p.second == CLOSE) { |
528 | if (::close(p.first) == -1) { |
529 | return errno; |
530 | } |
531 | } else if (p.second != p.first) { |
532 | if (::dup2(p.second, p.first) == -1) { |
533 | return errno; |
534 | } |
535 | } |
536 | } |
537 | |
538 | // If requested, close all other file descriptors. Don't close |
539 | // any fds in options.fdActions_, and don't touch stdin, stdout, stderr. |
540 | // Ignore errors. |
541 | if (options.closeOtherFds_) { |
542 | for (int fd = getdtablesize() - 1; fd >= 3; --fd) { |
543 | if (options.fdActions_.count(fd) == 0) { |
544 | ::close(fd); |
545 | } |
546 | } |
547 | } |
548 | |
549 | #if defined(__linux__) |
550 | // Opt to receive signal on parent death, if requested |
551 | if (options.parentDeathSignal_ != 0) { |
552 | const auto parentDeathSignal = |
553 | static_cast<unsigned long>(options.parentDeathSignal_); |
554 | if (prctl(PR_SET_PDEATHSIG, parentDeathSignal, 0, 0, 0) == -1) { |
555 | return errno; |
556 | } |
557 | } |
558 | #endif |
559 | |
560 | if (options.processGroupLeader_) { |
561 | #if !defined(__FreeBSD__) |
562 | if (setpgrp() == -1) { |
563 | #else |
564 | if (setpgrp(getpid(), getpgrp()) == -1) { |
565 | #endif |
566 | return errno; |
567 | } |
568 | } |
569 | |
570 | // The user callback comes last, so that the child is otherwise all set up. |
571 | if (options.dangerousPostForkPreExecCallback_) { |
572 | if (int error = (*options.dangerousPostForkPreExecCallback_)()) { |
573 | return error; |
574 | } |
575 | } |
576 | |
577 | return 0; |
578 | } |
579 | |
580 | int Subprocess::runChild( |
581 | const char* executable, |
582 | char** argv, |
583 | char** env, |
584 | const Options& options) const { |
585 | // Now, finally, exec. |
586 | if (options.usePath_) { |
587 | ::execvp(executable, argv); |
588 | } else { |
589 | ::execve(executable, argv, env); |
590 | } |
591 | return errno; |
592 | } |
593 | |
594 | void Subprocess::readChildErrorPipe(int pfd, const char* executable) { |
595 | ChildErrorInfo info; |
596 | auto rc = readNoInt(pfd, &info, sizeof(info)); |
597 | if (rc == 0) { |
598 | // No data means the child executed successfully, and the pipe |
599 | // was closed due to the close-on-exec flag being set. |
600 | return; |
601 | } else if (rc != sizeof(ChildErrorInfo)) { |
602 | // An error occurred trying to read from the pipe, or we got a partial read. |
603 | // Neither of these cases should really occur in practice. |
604 | // |
605 | // We can't get any error data from the child in this case, and we don't |
606 | // know if it is successfully running or not. All we can do is to return |
607 | // normally, as if the child executed successfully. If something bad |
608 | // happened the caller should at least get a non-normal exit status from |
609 | // the child. |
610 | LOG(ERROR) << "unexpected error trying to read from child error pipe " |
611 | << "rc=" << rc << ", errno=" << errno; |
612 | return; |
613 | } |
614 | |
615 | // We got error data from the child. The child should exit immediately in |
616 | // this case, so wait on it to clean up. |
617 | wait(); |
618 | |
619 | // Throw to signal the error |
620 | throw SubprocessSpawnError(executable, info.errCode, info.errnoValue); |
621 | } |
622 | |
623 | ProcessReturnCode Subprocess::poll(struct rusage* ru) { |
624 | returnCode_.enforce(ProcessReturnCode::RUNNING); |
625 | DCHECK_GT(pid_, 0); |
626 | int status; |
627 | pid_t found = ::wait4(pid_, &status, WNOHANG, ru); |
628 | // The spec guarantees that EINTR does not occur with WNOHANG, so the only |
629 | // two remaining errors are ECHILD (other code reaped the child?), or |
630 | // EINVAL (cosmic rays?), both of which merit an abort: |
631 | PCHECK(found != -1) << "waitpid(" << pid_ << ", &status, WNOHANG)" ; |
632 | if (found != 0) { |
633 | // Though the child process had quit, this call does not close the pipes |
634 | // since its descendants may still be using them. |
635 | returnCode_ = ProcessReturnCode::make(status); |
636 | pid_ = -1; |
637 | } |
638 | return returnCode_; |
639 | } |
640 | |
641 | bool Subprocess::pollChecked() { |
642 | if (poll().state() == ProcessReturnCode::RUNNING) { |
643 | return false; |
644 | } |
645 | checkStatus(returnCode_); |
646 | return true; |
647 | } |
648 | |
649 | ProcessReturnCode Subprocess::wait() { |
650 | returnCode_.enforce(ProcessReturnCode::RUNNING); |
651 | DCHECK_GT(pid_, 0); |
652 | int status; |
653 | pid_t found; |
654 | do { |
655 | found = ::waitpid(pid_, &status, 0); |
656 | } while (found == -1 && errno == EINTR); |
657 | // The only two remaining errors are ECHILD (other code reaped the |
658 | // child?), or EINVAL (cosmic rays?), and both merit an abort: |
659 | PCHECK(found != -1) << "waitpid(" << pid_ << ", &status, 0)" ; |
660 | // Though the child process had quit, this call does not close the pipes |
661 | // since its descendants may still be using them. |
662 | DCHECK_EQ(found, pid_); |
663 | returnCode_ = ProcessReturnCode::make(status); |
664 | pid_ = -1; |
665 | return returnCode_; |
666 | } |
667 | |
668 | void Subprocess::waitChecked() { |
669 | wait(); |
670 | checkStatus(returnCode_); |
671 | } |
672 | |
673 | ProcessReturnCode Subprocess::waitTimeout(TimeoutDuration timeout) { |
674 | returnCode_.enforce(ProcessReturnCode::RUNNING); |
675 | DCHECK_GT(pid_, 0) << "The subprocess has been waited already" ; |
676 | |
677 | auto pollUntil = std::chrono::steady_clock::now() + timeout; |
678 | auto sleepDuration = std::chrono::milliseconds{2}; |
679 | constexpr auto maximumSleepDuration = std::chrono::milliseconds{100}; |
680 | |
681 | for (;;) { |
682 | // Always call waitpid once after the full timeout has elapsed. |
683 | auto now = std::chrono::steady_clock::now(); |
684 | |
685 | int status; |
686 | pid_t found; |
687 | do { |
688 | found = ::waitpid(pid_, &status, WNOHANG); |
689 | } while (found == -1 && errno == EINTR); |
690 | PCHECK(found != -1) << "waitpid(" << pid_ << ", &status, WNOHANG)" ; |
691 | if (found) { |
692 | // Just on the safe side, make sure it's the actual pid we are waiting. |
693 | DCHECK_EQ(found, pid_); |
694 | returnCode_ = ProcessReturnCode::make(status); |
695 | // Change pid_ to -1 to detect programming error like calling |
696 | // this method multiple times. |
697 | pid_ = -1; |
698 | return returnCode_; |
699 | } |
700 | if (now > pollUntil) { |
701 | // Timed out: still running(). |
702 | return returnCode_; |
703 | } |
704 | // The subprocess is still running, sleep for increasing periods of time. |
705 | std::this_thread::sleep_for(sleepDuration); |
706 | sleepDuration = |
707 | std::min(maximumSleepDuration, sleepDuration + sleepDuration); |
708 | } |
709 | } |
710 | |
711 | void Subprocess::sendSignal(int signal) { |
712 | returnCode_.enforce(ProcessReturnCode::RUNNING); |
713 | int r = ::kill(pid_, signal); |
714 | checkUnixError(r, "kill" ); |
715 | } |
716 | |
717 | ProcessReturnCode Subprocess::waitOrTerminateOrKill( |
718 | TimeoutDuration waitTimeout, |
719 | TimeoutDuration sigtermTimeout) { |
720 | returnCode_.enforce(ProcessReturnCode::RUNNING); |
721 | DCHECK_GT(pid_, 0) << "The subprocess has been waited already" ; |
722 | |
723 | this->waitTimeout(waitTimeout); |
724 | |
725 | if (returnCode_.running()) { |
726 | return terminateOrKill(sigtermTimeout); |
727 | } |
728 | return returnCode_; |
729 | } |
730 | |
731 | ProcessReturnCode Subprocess::terminateOrKill(TimeoutDuration sigtermTimeout) { |
732 | returnCode_.enforce(ProcessReturnCode::RUNNING); |
733 | DCHECK_GT(pid_, 0) << "The subprocess has been waited already" ; |
734 | // 1. Send SIGTERM to kill the process |
735 | terminate(); |
736 | // 2. check whether subprocess has terminated using non-blocking waitpid |
737 | waitTimeout(sigtermTimeout); |
738 | if (!returnCode_.running()) { |
739 | return returnCode_; |
740 | } |
741 | // 3. If we are at this point, we have waited enough time after |
742 | // sending SIGTERM, we have to use nuclear option SIGKILL to kill |
743 | // the subprocess. |
744 | LOG(INFO) << "Send SIGKILL to " << pid_; |
745 | kill(); |
746 | // 4. SIGKILL should kill the process otherwise there must be |
747 | // something seriously wrong, just use blocking wait to wait for the |
748 | // subprocess to finish. |
749 | return wait(); |
750 | } |
751 | |
752 | pid_t Subprocess::pid() const { |
753 | return pid_; |
754 | } |
755 | |
756 | namespace { |
757 | |
758 | ByteRange queueFront(const IOBufQueue& queue) { |
759 | auto* p = queue.front(); |
760 | if (!p) { |
761 | return ByteRange{}; |
762 | } |
763 | return io::Cursor(p).peekBytes(); |
764 | } |
765 | |
766 | // fd write |
767 | bool handleWrite(int fd, IOBufQueue& queue) { |
768 | for (;;) { |
769 | auto b = queueFront(queue); |
770 | if (b.empty()) { |
771 | return true; // EOF |
772 | } |
773 | |
774 | ssize_t n = writeNoInt(fd, b.data(), b.size()); |
775 | if (n == -1 && errno == EAGAIN) { |
776 | return false; |
777 | } |
778 | checkUnixError(n, "write" ); |
779 | queue.trimStart(n); |
780 | } |
781 | } |
782 | |
783 | // fd read |
784 | bool handleRead(int fd, IOBufQueue& queue) { |
785 | for (;;) { |
786 | auto p = queue.preallocate(100, 65000); |
787 | ssize_t n = readNoInt(fd, p.first, p.second); |
788 | if (n == -1 && errno == EAGAIN) { |
789 | return false; |
790 | } |
791 | checkUnixError(n, "read" ); |
792 | if (n == 0) { |
793 | return true; |
794 | } |
795 | queue.postallocate(n); |
796 | } |
797 | } |
798 | |
799 | bool discardRead(int fd) { |
800 | static const size_t bufSize = 65000; |
801 | // Thread unsafe, but it doesn't matter. |
802 | static std::unique_ptr<char[]> buf(new char[bufSize]); |
803 | |
804 | for (;;) { |
805 | ssize_t n = readNoInt(fd, buf.get(), bufSize); |
806 | if (n == -1 && errno == EAGAIN) { |
807 | return false; |
808 | } |
809 | checkUnixError(n, "read" ); |
810 | if (n == 0) { |
811 | return true; |
812 | } |
813 | } |
814 | } |
815 | |
816 | } // namespace |
817 | |
818 | std::pair<std::string, std::string> Subprocess::communicate(StringPiece input) { |
819 | IOBufQueue inputQueue; |
820 | inputQueue.wrapBuffer(input.data(), input.size()); |
821 | |
822 | auto outQueues = communicateIOBuf(std::move(inputQueue)); |
823 | auto outBufs = |
824 | std::make_pair(outQueues.first.move(), outQueues.second.move()); |
825 | std::pair<std::string, std::string> out; |
826 | if (outBufs.first) { |
827 | outBufs.first->coalesce(); |
828 | out.first.assign( |
829 | reinterpret_cast<const char*>(outBufs.first->data()), |
830 | outBufs.first->length()); |
831 | } |
832 | if (outBufs.second) { |
833 | outBufs.second->coalesce(); |
834 | out.second.assign( |
835 | reinterpret_cast<const char*>(outBufs.second->data()), |
836 | outBufs.second->length()); |
837 | } |
838 | return out; |
839 | } |
840 | |
841 | std::pair<IOBufQueue, IOBufQueue> Subprocess::communicateIOBuf( |
842 | IOBufQueue input) { |
843 | // If the user supplied a non-empty input buffer, make sure |
844 | // that stdin is a pipe so we can write the data. |
845 | if (!input.empty()) { |
846 | // findByChildFd() will throw std::invalid_argument if no pipe for |
847 | // STDIN_FILENO exists |
848 | findByChildFd(STDIN_FILENO); |
849 | } |
850 | |
851 | std::pair<IOBufQueue, IOBufQueue> out; |
852 | |
853 | auto readCallback = [&](int pfd, int cfd) -> bool { |
854 | if (cfd == STDOUT_FILENO) { |
855 | return handleRead(pfd, out.first); |
856 | } else if (cfd == STDERR_FILENO) { |
857 | return handleRead(pfd, out.second); |
858 | } else { |
859 | // Don't close the file descriptor, the child might not like SIGPIPE, |
860 | // just read and throw the data away. |
861 | return discardRead(pfd); |
862 | } |
863 | }; |
864 | |
865 | auto writeCallback = [&](int pfd, int cfd) -> bool { |
866 | if (cfd == STDIN_FILENO) { |
867 | return handleWrite(pfd, input); |
868 | } else { |
869 | // If we don't want to write to this fd, just close it. |
870 | return true; |
871 | } |
872 | }; |
873 | |
874 | communicate(std::move(readCallback), std::move(writeCallback)); |
875 | |
876 | return out; |
877 | } |
878 | |
879 | void Subprocess::communicate( |
880 | FdCallback readCallback, |
881 | FdCallback writeCallback) { |
882 | // This serves to prevent wait() followed by communicate(), but if you |
883 | // legitimately need that, send a patch to delete this line. |
884 | returnCode_.enforce(ProcessReturnCode::RUNNING); |
885 | setAllNonBlocking(); |
886 | |
887 | std::vector<pollfd> fds; |
888 | fds.reserve(pipes_.size()); |
889 | std::vector<size_t> toClose; // indexes into pipes_ |
890 | toClose.reserve(pipes_.size()); |
891 | |
892 | while (!pipes_.empty()) { |
893 | fds.clear(); |
894 | toClose.clear(); |
895 | |
896 | for (auto& p : pipes_) { |
897 | pollfd pfd; |
898 | pfd.fd = p.pipe.fd(); |
899 | // Yes, backwards, PIPE_IN / PIPE_OUT are defined from the |
900 | // child's point of view. |
901 | if (!p.enabled) { |
902 | // Still keeping fd in watched set so we get notified of POLLHUP / |
903 | // POLLERR |
904 | pfd.events = 0; |
905 | } else if (p.direction == PIPE_IN) { |
906 | pfd.events = POLLOUT; |
907 | } else { |
908 | pfd.events = POLLIN; |
909 | } |
910 | fds.push_back(pfd); |
911 | } |
912 | |
913 | int r; |
914 | do { |
915 | r = ::poll(fds.data(), fds.size(), -1); |
916 | } while (r == -1 && errno == EINTR); |
917 | checkUnixError(r, "poll" ); |
918 | |
919 | for (size_t i = 0; i < pipes_.size(); ++i) { |
920 | auto& p = pipes_[i]; |
921 | auto parentFd = p.pipe.fd(); |
922 | DCHECK_EQ(fds[i].fd, parentFd); |
923 | short events = fds[i].revents; |
924 | |
925 | bool closed = false; |
926 | if (events & POLLOUT) { |
927 | DCHECK(!(events & POLLIN)); |
928 | if (writeCallback(parentFd, p.childFd)) { |
929 | toClose.push_back(i); |
930 | closed = true; |
931 | } |
932 | } |
933 | |
934 | // Call read callback on POLLHUP, to give it a chance to read (and act |
935 | // on) end of file |
936 | if (events & (POLLIN | POLLHUP)) { |
937 | DCHECK(!(events & POLLOUT)); |
938 | if (readCallback(parentFd, p.childFd)) { |
939 | toClose.push_back(i); |
940 | closed = true; |
941 | } |
942 | } |
943 | |
944 | if ((events & (POLLHUP | POLLERR)) && !closed) { |
945 | toClose.push_back(i); |
946 | closed = true; |
947 | } |
948 | } |
949 | |
950 | // Close the fds in reverse order so the indexes hold after erase() |
951 | for (int idx : boost::adaptors::reverse(toClose)) { |
952 | auto pos = pipes_.begin() + idx; |
953 | pos->pipe.close(); // Throws on error |
954 | pipes_.erase(pos); |
955 | } |
956 | } |
957 | } |
958 | |
959 | void Subprocess::enableNotifications(int childFd, bool enabled) { |
960 | pipes_[findByChildFd(childFd)].enabled = enabled; |
961 | } |
962 | |
963 | bool Subprocess::notificationsEnabled(int childFd) const { |
964 | return pipes_[findByChildFd(childFd)].enabled; |
965 | } |
966 | |
967 | size_t Subprocess::findByChildFd(int childFd) const { |
968 | auto pos = std::lower_bound( |
969 | pipes_.begin(), pipes_.end(), childFd, [](const Pipe& pipe, int fd) { |
970 | return pipe.childFd < fd; |
971 | }); |
972 | if (pos == pipes_.end() || pos->childFd != childFd) { |
973 | throw std::invalid_argument( |
974 | folly::to<std::string>("child fd not found " , childFd)); |
975 | } |
976 | return pos - pipes_.begin(); |
977 | } |
978 | |
979 | void Subprocess::closeParentFd(int childFd) { |
980 | int idx = findByChildFd(childFd); |
981 | pipes_[idx].pipe.close(); // May throw |
982 | pipes_.erase(pipes_.begin() + idx); |
983 | } |
984 | |
985 | std::vector<Subprocess::ChildPipe> Subprocess::takeOwnershipOfPipes() { |
986 | std::vector<Subprocess::ChildPipe> pipes; |
987 | for (auto& p : pipes_) { |
988 | pipes.emplace_back(p.childFd, std::move(p.pipe)); |
989 | } |
990 | // release memory |
991 | std::vector<Pipe>().swap(pipes_); |
992 | return pipes; |
993 | } |
994 | |
995 | namespace { |
996 | |
997 | class Initializer { |
998 | public: |
999 | Initializer() { |
1000 | // We like EPIPE, thanks. |
1001 | ::signal(SIGPIPE, SIG_IGN); |
1002 | } |
1003 | }; |
1004 | |
1005 | Initializer initializer; |
1006 | |
1007 | } // namespace |
1008 | |
1009 | } // namespace folly |
1010 | |