1 // Copyright 2015 The Kyua Authors. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // * Neither the name of Google Inc. nor the names of its contributors 14 // may be used to endorse or promote products derived from this software 15 // without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #include "utils/process/executor.ipp" 30 31 #if defined(HAVE_CONFIG_H) 32 #include "config.h" 33 #endif 34 35 extern "C" { 36 #include <sys/types.h> 37 #include <sys/wait.h> 38 39 #include <signal.h> 40 } 41 42 #include <fstream> 43 #include <map> 44 #include <memory> 45 #include <stdexcept> 46 47 #include "utils/datetime.hpp" 48 #include "utils/format/macros.hpp" 49 #include "utils/fs/auto_cleaners.hpp" 50 #include "utils/fs/exceptions.hpp" 51 #include "utils/fs/operations.hpp" 52 #include "utils/fs/path.hpp" 53 #include "utils/logging/macros.hpp" 54 #include "utils/logging/operations.hpp" 55 #include "utils/noncopyable.hpp" 56 #include "utils/optional.ipp" 57 #include "utils/passwd.hpp" 58 #include "utils/process/child.ipp" 59 #include "utils/process/deadline_killer.hpp" 60 #include "utils/process/isolation.hpp" 61 #include "utils/process/operations.hpp" 62 #include "utils/process/status.hpp" 63 #include "utils/sanity.hpp" 64 #include "utils/signals/interrupts.hpp" 65 #include "utils/signals/timer.hpp" 66 67 namespace datetime = utils::datetime; 68 namespace executor = utils::process::executor; 69 namespace fs = utils::fs; 70 namespace logging = utils::logging; 71 namespace passwd = utils::passwd; 72 namespace process = utils::process; 73 namespace signals = utils::signals; 74 75 using utils::none; 76 using utils::optional; 77 78 79 namespace { 80 81 82 /// Template for temporary directories created by the executor. 83 static const char* work_directory_template = PACKAGE_TARNAME ".XXXXXX"; 84 85 86 /// Mapping of active subprocess PIDs to their execution data. 87 typedef std::map< int, executor::exec_handle > exec_handles_map; 88 89 90 } // anonymous namespace 91 92 93 /// Basename of the file containing the stdout of the subprocess. 94 const char* utils::process::executor::detail::stdout_name = "stdout.txt"; 95 96 97 /// Basename of the file containing the stderr of the subprocess. 98 const char* utils::process::executor::detail::stderr_name = "stderr.txt"; 99 100 101 /// Basename of the subdirectory in which the subprocess is actually executed. 102 /// 103 /// This is a subdirectory of the "unique work directory" generated for the 104 /// subprocess so that our code can create control files on disk and not 105 /// get them clobbered by the subprocess's activity. 106 const char* utils::process::executor::detail::work_subdir = "work"; 107 108 109 /// Prepares a subprocess to run a user-provided hook in a controlled manner. 110 /// 111 /// \param unprivileged_user User to switch to if not none. 112 /// \param control_directory Path to the subprocess-specific control directory. 113 /// \param work_directory Path to the subprocess-specific work directory. 114 void 115 utils::process::executor::detail::setup_child( 116 const optional< passwd::user > unprivileged_user, 117 const fs::path& control_directory, 118 const fs::path& work_directory) 119 { 120 logging::set_inmemory(); 121 process::isolate_path(unprivileged_user, control_directory); 122 process::isolate_child(unprivileged_user, work_directory); 123 } 124 125 126 /// Internal implementation for the exit_handle class. 127 struct utils::process::executor::exec_handle::impl : utils::noncopyable { 128 /// PID of the process being run. 129 int pid; 130 131 /// Path to the subprocess-specific work directory. 132 fs::path control_directory; 133 134 /// Path to the subprocess's stdout file. 135 const fs::path stdout_file; 136 137 /// Path to the subprocess's stderr file. 138 const fs::path stderr_file; 139 140 /// Start time. 141 datetime::timestamp start_time; 142 143 /// User the subprocess is running as if different than the current one. 144 const optional< passwd::user > unprivileged_user; 145 146 /// Timer to kill the subprocess on activation. 147 process::deadline_killer timer; 148 149 /// Number of owners of the on-disk state. 150 executor::detail::refcnt_t state_owners; 151 152 /// Constructor. 153 /// 154 /// \param pid_ PID of the forked process. 155 /// \param control_directory_ Path to the subprocess-specific work 156 /// directory. 157 /// \param stdout_file_ Path to the subprocess's stdout file. 158 /// \param stderr_file_ Path to the subprocess's stderr file. 159 /// \param start_time_ Timestamp of when this object was constructed. 160 /// \param timeout Maximum amount of time the subprocess can run for. 161 /// \param unprivileged_user_ User the subprocess is running as if 162 /// different than the current one. 163 /// \param [in,out] state_owners_ Number of owners of the on-disk state. 164 /// For first-time processes, this should be a new counter set to 0; 165 /// for followup processes, this should point to the same counter used 166 /// by the preceding process. 167 impl(const int pid_, 168 const fs::path& control_directory_, 169 const fs::path& stdout_file_, 170 const fs::path& stderr_file_, 171 const datetime::timestamp& start_time_, 172 const datetime::delta& timeout, 173 const optional< passwd::user > unprivileged_user_, 174 executor::detail::refcnt_t state_owners_) : 175 pid(pid_), 176 control_directory(control_directory_), 177 stdout_file(stdout_file_), 178 stderr_file(stderr_file_), 179 start_time(start_time_), 180 unprivileged_user(unprivileged_user_), 181 timer(timeout, pid_), 182 state_owners(state_owners_) 183 { 184 (*state_owners)++; 185 POST(*state_owners > 0); 186 } 187 }; 188 189 190 /// Constructor. 191 /// 192 /// \param pimpl Constructed internal implementation. 193 executor::exec_handle::exec_handle(std::shared_ptr< impl > pimpl) : 194 _pimpl(pimpl) 195 { 196 } 197 198 199 /// Destructor. 200 executor::exec_handle::~exec_handle(void) 201 { 202 } 203 204 205 /// Returns the PID of the process being run. 206 /// 207 /// \return A PID. 208 int 209 executor::exec_handle::pid(void) const 210 { 211 return _pimpl->pid; 212 } 213 214 215 /// Returns the path to the subprocess-specific control directory. 216 /// 217 /// This is where the executor may store control files. 218 /// 219 /// \return The path to a directory that exists until cleanup() is called. 220 fs::path 221 executor::exec_handle::control_directory(void) const 222 { 223 return _pimpl->control_directory; 224 } 225 226 227 /// Returns the path to the subprocess-specific work directory. 228 /// 229 /// This is guaranteed to be clear of files created by the executor. 230 /// 231 /// \return The path to a directory that exists until cleanup() is called. 232 fs::path 233 executor::exec_handle::work_directory(void) const 234 { 235 return _pimpl->control_directory / detail::work_subdir; 236 } 237 238 239 /// Returns the path to the subprocess's stdout file. 240 /// 241 /// \return The path to a file that exists until cleanup() is called. 242 const fs::path& 243 executor::exec_handle::stdout_file(void) const 244 { 245 return _pimpl->stdout_file; 246 } 247 248 249 /// Returns the path to the subprocess's stderr file. 250 /// 251 /// \return The path to a file that exists until cleanup() is called. 252 const fs::path& 253 executor::exec_handle::stderr_file(void) const 254 { 255 return _pimpl->stderr_file; 256 } 257 258 259 /// Internal implementation for the exit_handle class. 260 struct utils::process::executor::exit_handle::impl : utils::noncopyable { 261 /// Original PID of the terminated subprocess. 262 /// 263 /// Note that this PID is no longer valid and cannot be used on system 264 /// tables! 265 const int original_pid; 266 267 /// Termination status of the subprocess, or none if it timed out. 268 const optional< process::status > status; 269 270 /// The user the process ran as, if different than the current one. 271 const optional< passwd::user > unprivileged_user; 272 273 /// Timestamp of when the subprocess was spawned. 274 const datetime::timestamp start_time; 275 276 /// Timestamp of when wait() or wait_any() returned this object. 277 const datetime::timestamp end_time; 278 279 /// Path to the subprocess-specific work directory. 280 const fs::path control_directory; 281 282 /// Path to the subprocess's stdout file. 283 const fs::path stdout_file; 284 285 /// Path to the subprocess's stderr file. 286 const fs::path stderr_file; 287 288 /// Number of owners of the on-disk state. 289 /// 290 /// This will be 1 if this exit_handle is the last holder of the on-disk 291 /// state, in which case cleanup() invocations will wipe the disk state. 292 /// For all other cases, this will hold a higher value. 293 detail::refcnt_t state_owners; 294 295 /// Mutable pointer to the corresponding executor state. 296 /// 297 /// This object references a member of the executor_handle that yielded this 298 /// exit_handle instance. We need this direct access to clean up after 299 /// ourselves when the handle is destroyed. 300 exec_handles_map& all_exec_handles; 301 302 /// Whether the subprocess state has been cleaned yet or not. 303 /// 304 /// Used to keep track of explicit calls to the public cleanup(). 305 bool cleaned; 306 307 /// Constructor. 308 /// 309 /// \param original_pid_ Original PID of the terminated subprocess. 310 /// \param status_ Termination status of the subprocess, or none if 311 /// timed out. 312 /// \param unprivileged_user_ The user the process ran as, if different than 313 /// the current one. 314 /// \param start_time_ Timestamp of when the subprocess was spawned. 315 /// \param end_time_ Timestamp of when wait() or wait_any() returned this 316 /// object. 317 /// \param control_directory_ Path to the subprocess-specific work 318 /// directory. 319 /// \param stdout_file_ Path to the subprocess's stdout file. 320 /// \param stderr_file_ Path to the subprocess's stderr file. 321 /// \param [in,out] state_owners_ Number of owners of the on-disk state. 322 /// \param [in,out] all_exec_handles_ Global object keeping track of all 323 /// active executions for an executor. This is a pointer to a member of 324 /// the executor_handle object. 325 impl(const int original_pid_, 326 const optional< process::status > status_, 327 const optional< passwd::user > unprivileged_user_, 328 const datetime::timestamp& start_time_, 329 const datetime::timestamp& end_time_, 330 const fs::path& control_directory_, 331 const fs::path& stdout_file_, 332 const fs::path& stderr_file_, 333 detail::refcnt_t state_owners_, 334 exec_handles_map& all_exec_handles_) : 335 original_pid(original_pid_), status(status_), 336 unprivileged_user(unprivileged_user_), 337 start_time(start_time_), end_time(end_time_), 338 control_directory(control_directory_), 339 stdout_file(stdout_file_), stderr_file(stderr_file_), 340 state_owners(state_owners_), 341 all_exec_handles(all_exec_handles_), cleaned(false) 342 { 343 } 344 345 /// Destructor. 346 ~impl(void) 347 { 348 if (!cleaned) { 349 LW(F("Implicitly cleaning up exit_handle for exec_handle %s; " 350 "ignoring errors!") % original_pid); 351 try { 352 cleanup(); 353 } catch (const std::runtime_error& error) { 354 LE(F("Subprocess cleanup failed: %s") % error.what()); 355 } 356 } 357 } 358 359 /// Cleans up the subprocess on-disk state. 360 /// 361 /// \throw engine::error If the cleanup fails, especially due to the 362 /// inability to remove the work directory. 363 void 364 cleanup(void) 365 { 366 PRE(*state_owners > 0); 367 if (*state_owners == 1) { 368 LI(F("Cleaning up exit_handle for exec_handle %s") % original_pid); 369 fs::rm_r(control_directory); 370 } else { 371 LI(F("Not cleaning up exit_handle for exec_handle %s; " 372 "%s owners left") % original_pid % (*state_owners - 1)); 373 } 374 // We must decrease our reference only after we have successfully 375 // cleaned up the control directory. Otherwise, the rm_r call would 376 // throw an exception, which would in turn invoke the implicit cleanup 377 // from the destructor, which would make us crash due to an invalid 378 // reference count. 379 (*state_owners)--; 380 // Marking this object as clean here, even if we did not do actually the 381 // cleaning above, is fine (albeit a bit confusing). Note that "another 382 // owner" refers to a handle for a different PID, so that handle will be 383 // the one issuing the cleanup. 384 all_exec_handles.erase(original_pid); 385 cleaned = true; 386 } 387 }; 388 389 390 /// Constructor. 391 /// 392 /// \param pimpl Constructed internal implementation. 393 executor::exit_handle::exit_handle(std::shared_ptr< impl > pimpl) : 394 _pimpl(pimpl) 395 { 396 } 397 398 399 /// Destructor. 400 executor::exit_handle::~exit_handle(void) 401 { 402 } 403 404 405 /// Cleans up the subprocess status. 406 /// 407 /// This function should be called explicitly as it provides the means to 408 /// control any exceptions raised during cleanup. Do not rely on the destructor 409 /// to clean things up. 410 /// 411 /// \throw engine::error If the cleanup fails, especially due to the inability 412 /// to remove the work directory. 413 void 414 executor::exit_handle::cleanup(void) 415 { 416 PRE(!_pimpl->cleaned); 417 _pimpl->cleanup(); 418 POST(_pimpl->cleaned); 419 } 420 421 422 /// Gets the current number of owners of the on-disk data. 423 /// 424 /// \return A shared reference counter. Even though this function is marked as 425 /// const, the return value is intentionally mutable because we need to update 426 /// reference counts from different but related processes. This is why this 427 /// method is not public. 428 std::shared_ptr< std::size_t > 429 executor::exit_handle::state_owners(void) const 430 { 431 return _pimpl->state_owners; 432 } 433 434 435 /// Returns the original PID corresponding to the terminated subprocess. 436 /// 437 /// \return An exec_handle. 438 int 439 executor::exit_handle::original_pid(void) const 440 { 441 return _pimpl->original_pid; 442 } 443 444 445 /// Returns the process termination status of the subprocess. 446 /// 447 /// \return A process termination status, or none if the subprocess timed out. 448 const optional< process::status >& 449 executor::exit_handle::status(void) const 450 { 451 return _pimpl->status; 452 } 453 454 455 /// Returns the user the process ran as if different than the current one. 456 /// 457 /// \return None if the credentials of the process were the same as the current 458 /// one, or else a user. 459 const optional< passwd::user >& 460 executor::exit_handle::unprivileged_user(void) const 461 { 462 return _pimpl->unprivileged_user; 463 } 464 465 466 /// Returns the timestamp of when the subprocess was spawned. 467 /// 468 /// \return A timestamp. 469 const datetime::timestamp& 470 executor::exit_handle::start_time(void) const 471 { 472 return _pimpl->start_time; 473 } 474 475 476 /// Returns the timestamp of when wait() or wait_any() returned this object. 477 /// 478 /// \return A timestamp. 479 const datetime::timestamp& 480 executor::exit_handle::end_time(void) const 481 { 482 return _pimpl->end_time; 483 } 484 485 486 /// Returns the path to the subprocess-specific control directory. 487 /// 488 /// This is where the executor may store control files. 489 /// 490 /// \return The path to a directory that exists until cleanup() is called. 491 fs::path 492 executor::exit_handle::control_directory(void) const 493 { 494 return _pimpl->control_directory; 495 } 496 497 498 /// Returns the path to the subprocess-specific work directory. 499 /// 500 /// This is guaranteed to be clear of files created by the executor. 501 /// 502 /// \return The path to a directory that exists until cleanup() is called. 503 fs::path 504 executor::exit_handle::work_directory(void) const 505 { 506 return _pimpl->control_directory / detail::work_subdir; 507 } 508 509 510 /// Returns the path to the subprocess's stdout file. 511 /// 512 /// \return The path to a file that exists until cleanup() is called. 513 const fs::path& 514 executor::exit_handle::stdout_file(void) const 515 { 516 return _pimpl->stdout_file; 517 } 518 519 520 /// Returns the path to the subprocess's stderr file. 521 /// 522 /// \return The path to a file that exists until cleanup() is called. 523 const fs::path& 524 executor::exit_handle::stderr_file(void) const 525 { 526 return _pimpl->stderr_file; 527 } 528 529 530 /// Internal implementation for the executor_handle. 531 /// 532 /// Because the executor is a singleton, these essentially is a container for 533 /// global variables. 534 struct utils::process::executor::executor_handle::impl : utils::noncopyable { 535 /// Numeric counter of executed subprocesses. 536 /// 537 /// This is used to generate a unique identifier for each subprocess as an 538 /// easy mechanism to discern their unique work directories. 539 size_t last_subprocess; 540 541 /// Interrupts handler. 542 std::auto_ptr< signals::interrupts_handler > interrupts_handler; 543 544 /// Root work directory for all executed subprocesses. 545 std::auto_ptr< fs::auto_directory > root_work_directory; 546 547 /// Mapping of PIDs to the data required at run time. 548 exec_handles_map all_exec_handles; 549 550 /// Whether the executor state has been cleaned yet or not. 551 /// 552 /// Used to keep track of explicit calls to the public cleanup(). 553 bool cleaned; 554 555 /// Constructor. 556 impl(void) : 557 last_subprocess(0), 558 interrupts_handler(new signals::interrupts_handler()), 559 root_work_directory(new fs::auto_directory( 560 fs::auto_directory::mkdtemp_public(work_directory_template))), 561 cleaned(false) 562 { 563 } 564 565 /// Destructor. 566 ~impl(void) 567 { 568 if (!cleaned) { 569 LW("Implicitly cleaning up executor; ignoring errors!"); 570 try { 571 cleanup(); 572 cleaned = true; 573 } catch (const std::runtime_error& error) { 574 LE(F("Executor global cleanup failed: %s") % error.what()); 575 } 576 } 577 } 578 579 /// Cleans up the executor state. 580 void 581 cleanup(void) 582 { 583 PRE(!cleaned); 584 585 for (exec_handles_map::const_iterator iter = all_exec_handles.begin(); 586 iter != all_exec_handles.end(); ++iter) { 587 const int& pid = (*iter).first; 588 const exec_handle& data = (*iter).second; 589 590 process::terminate_group(pid); 591 int status; 592 if (::waitpid(pid, &status, 0) == -1) { 593 // Should not happen. 594 LW(F("Failed to wait for PID %s") % pid); 595 } 596 597 try { 598 fs::rm_r(data.control_directory()); 599 } catch (const fs::error& e) { 600 LE(F("Failed to clean up subprocess work directory %s: %s") % 601 data.control_directory() % e.what()); 602 } 603 } 604 all_exec_handles.clear(); 605 606 try { 607 // The following only causes the work directory to be deleted, not 608 // any of its contents, so we expect this to always succeed. This 609 // *should* be sufficient because, in the loop above, we have 610 // individually wiped the subdirectories of any still-unclean 611 // subprocesses. 612 root_work_directory->cleanup(); 613 } catch (const fs::error& e) { 614 LE(F("Failed to clean up executor work directory %s: %s; this is " 615 "an internal error") % root_work_directory->directory() 616 % e.what()); 617 } 618 root_work_directory.reset(NULL); 619 620 interrupts_handler->unprogram(); 621 interrupts_handler.reset(NULL); 622 } 623 624 /// Common code to run after any of the wait calls. 625 /// 626 /// \param original_pid The PID of the terminated subprocess. 627 /// \param status The exit status of the terminated subprocess. 628 /// 629 /// \return A pointer to an object describing the waited-for subprocess. 630 executor::exit_handle 631 post_wait(const int original_pid, const process::status& status) 632 { 633 PRE(original_pid == status.dead_pid()); 634 LI(F("Waited for subprocess with exec_handle %s") % original_pid); 635 636 process::terminate_group(status.dead_pid()); 637 638 const exec_handles_map::iterator iter = all_exec_handles.find( 639 original_pid); 640 exec_handle& data = (*iter).second; 641 data._pimpl->timer.unprogram(); 642 643 // It is tempting to assert here (and old code did) that, if the timer 644 // has fired, the process has been forcibly killed by us. This is not 645 // always the case though: for short-lived processes and with very short 646 // timeouts (think 1ms), it is possible for scheduling decisions to 647 // allow the subprocess to finish while at the same time cause the timer 648 // to fire. So we do not assert this any longer and just rely on the 649 // timer expiration to check if the process timed out or not. If the 650 // process did finish but the timer expired... oh well, we do not detect 651 // this correctly but we don't care because this should not really 652 // happen. 653 654 if (!fs::exists(data.stdout_file())) { 655 std::ofstream new_stdout(data.stdout_file().c_str()); 656 } 657 if (!fs::exists(data.stderr_file())) { 658 std::ofstream new_stderr(data.stderr_file().c_str()); 659 } 660 661 return exit_handle(std::shared_ptr< exit_handle::impl >( 662 new exit_handle::impl( 663 data.pid(), 664 data._pimpl->timer.fired() ? 665 none : utils::make_optional(status), 666 data._pimpl->unprivileged_user, 667 data._pimpl->start_time, datetime::timestamp::now(), 668 data.control_directory(), 669 data.stdout_file(), 670 data.stderr_file(), 671 data._pimpl->state_owners, 672 all_exec_handles))); 673 } 674 }; 675 676 677 /// Constructor. 678 executor::executor_handle::executor_handle(void) throw() : _pimpl(new impl()) 679 { 680 } 681 682 683 /// Destructor. 684 executor::executor_handle::~executor_handle(void) 685 { 686 } 687 688 689 /// Queries the path to the root of the work directory for all subprocesses. 690 /// 691 /// \return A path. 692 const fs::path& 693 executor::executor_handle::root_work_directory(void) const 694 { 695 return _pimpl->root_work_directory->directory(); 696 } 697 698 699 /// Cleans up the executor state. 700 /// 701 /// This function should be called explicitly as it provides the means to 702 /// control any exceptions raised during cleanup. Do not rely on the destructor 703 /// to clean things up. 704 /// 705 /// \throw engine::error If there are problems cleaning up the executor. 706 void 707 executor::executor_handle::cleanup(void) 708 { 709 PRE(!_pimpl->cleaned); 710 _pimpl->cleanup(); 711 _pimpl->cleaned = true; 712 } 713 714 715 /// Initializes the executor. 716 /// 717 /// \pre This function can only be called if there is no other executor_handle 718 /// object alive. 719 /// 720 /// \return A handle to the operations of the executor. 721 executor::executor_handle 722 executor::setup(void) 723 { 724 return executor_handle(); 725 } 726 727 728 /// Pre-helper for the spawn() method. 729 /// 730 /// \return The created control directory for the subprocess. 731 fs::path 732 executor::executor_handle::spawn_pre(void) 733 { 734 signals::check_interrupt(); 735 736 ++_pimpl->last_subprocess; 737 738 const fs::path control_directory = 739 _pimpl->root_work_directory->directory() / 740 (F("%s") % _pimpl->last_subprocess); 741 fs::mkdir_p(control_directory / detail::work_subdir, 0755); 742 743 return control_directory; 744 } 745 746 747 /// Post-helper for the spawn() method. 748 /// 749 /// \param control_directory Control directory as returned by spawn_pre(). 750 /// \param stdout_file Path to the subprocess' stdout. 751 /// \param stderr_file Path to the subprocess' stderr. 752 /// \param timeout Maximum amount of time the subprocess can run for. 753 /// \param unprivileged_user If not none, user to switch to before execution. 754 /// \param child The process created by spawn(). 755 /// 756 /// \return The execution handle of the started subprocess. 757 executor::exec_handle 758 executor::executor_handle::spawn_post( 759 const fs::path& control_directory, 760 const fs::path& stdout_file, 761 const fs::path& stderr_file, 762 const datetime::delta& timeout, 763 const optional< passwd::user > unprivileged_user, 764 std::auto_ptr< process::child > child) 765 { 766 const exec_handle handle(std::shared_ptr< exec_handle::impl >( 767 new exec_handle::impl( 768 child->pid(), 769 control_directory, 770 stdout_file, 771 stderr_file, 772 datetime::timestamp::now(), 773 timeout, 774 unprivileged_user, 775 detail::refcnt_t(new detail::refcnt_t::element_type(0))))); 776 INV_MSG(_pimpl->all_exec_handles.find(handle.pid()) == 777 _pimpl->all_exec_handles.end(), 778 F("PID %s already in all_exec_handles; not properly cleaned " 779 "up or reused too fast") % handle.pid());; 780 _pimpl->all_exec_handles.insert(exec_handles_map::value_type( 781 handle.pid(), handle)); 782 LI(F("Spawned subprocess with exec_handle %s") % handle.pid()); 783 return handle; 784 } 785 786 787 /// Pre-helper for the spawn_followup() method. 788 void 789 executor::executor_handle::spawn_followup_pre(void) 790 { 791 signals::check_interrupt(); 792 } 793 794 795 /// Post-helper for the spawn_followup() method. 796 /// 797 /// \param base Exit handle of the subprocess to use as context. 798 /// \param timeout Maximum amount of time the subprocess can run for. 799 /// \param child The process created by spawn_followup(). 800 /// 801 /// \return The execution handle of the started subprocess. 802 executor::exec_handle 803 executor::executor_handle::spawn_followup_post( 804 const exit_handle& base, 805 const datetime::delta& timeout, 806 std::auto_ptr< process::child > child) 807 { 808 INV(*base.state_owners() > 0); 809 const exec_handle handle(std::shared_ptr< exec_handle::impl >( 810 new exec_handle::impl( 811 child->pid(), 812 base.control_directory(), 813 base.stdout_file(), 814 base.stderr_file(), 815 datetime::timestamp::now(), 816 timeout, 817 base.unprivileged_user(), 818 base.state_owners()))); 819 INV_MSG(_pimpl->all_exec_handles.find(handle.pid()) == 820 _pimpl->all_exec_handles.end(), 821 F("PID %s already in all_exec_handles; not properly cleaned " 822 "up or reused too fast") % handle.pid());; 823 _pimpl->all_exec_handles.insert(exec_handles_map::value_type( 824 handle.pid(), handle)); 825 LI(F("Spawned subprocess with exec_handle %s") % handle.pid()); 826 return handle; 827 } 828 829 830 /// Waits for completion of any forked process. 831 /// 832 /// \param exec_handle The handle of the process to wait for. 833 /// 834 /// \return A pointer to an object describing the waited-for subprocess. 835 executor::exit_handle 836 executor::executor_handle::wait(const exec_handle exec_handle) 837 { 838 signals::check_interrupt(); 839 const process::status status = process::wait(exec_handle.pid()); 840 return _pimpl->post_wait(exec_handle.pid(), status); 841 } 842 843 844 /// Waits for completion of any forked process. 845 /// 846 /// \return A pointer to an object describing the waited-for subprocess. 847 executor::exit_handle 848 executor::executor_handle::wait_any(void) 849 { 850 signals::check_interrupt(); 851 const process::status status = process::wait_any(); 852 return _pimpl->post_wait(status.dead_pid(), status); 853 } 854 855 856 /// Checks if an interrupt has fired. 857 /// 858 /// Calls to this function should be sprinkled in strategic places through the 859 /// code protected by an interrupts_handler object. 860 /// 861 /// This is just a wrapper over signals::check_interrupt() to avoid leaking this 862 /// dependency to the caller. 863 /// 864 /// \throw signals::interrupted_error If there has been an interrupt. 865 void 866 executor::executor_handle::check_interrupt(void) const 867 { 868 signals::check_interrupt(); 869 } 870