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