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