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 <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 69 namespace datetime = utils::datetime; 70 namespace executor = utils::process::executor; 71 namespace fs = utils::fs; 72 namespace logging = utils::logging; 73 namespace passwd = utils::passwd; 74 namespace process = utils::process; 75 namespace signals = utils::signals; 76 77 using utils::none; 78 using utils::optional; 79 80 81 namespace { 82 83 84 /// Template for temporary directories created by the executor. 85 static const char* work_directory_template = PACKAGE_TARNAME ".XXXXXX"; 86 87 88 /// Mapping of active subprocess PIDs to their execution data. 89 typedef 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. 96 const char* utils::process::executor::detail::stdout_name = "stdout.txt"; 97 98 99 /// Basename of the file containing the stderr of the subprocess. 100 const 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. 108 const 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. 116 void 117 utils::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. 129 struct 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. 195 executor::exec_handle::exec_handle(std::shared_ptr< impl > pimpl) : 196 _pimpl(pimpl) 197 { 198 } 199 200 201 /// Destructor. 202 executor::exec_handle::~exec_handle(void) 203 { 204 } 205 206 207 /// Returns the PID of the process being run. 208 /// 209 /// \return A PID. 210 int 211 executor::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. 222 fs::path 223 executor::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. 234 fs::path 235 executor::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. 244 const fs::path& 245 executor::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. 254 const fs::path& 255 executor::exec_handle::stderr_file(void) const 256 { 257 return _pimpl->stderr_file; 258 } 259 260 261 /// Internal implementation for the exit_handle class. 262 struct 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. 395 executor::exit_handle::exit_handle(std::shared_ptr< impl > pimpl) : 396 _pimpl(pimpl) 397 { 398 } 399 400 401 /// Destructor. 402 executor::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. 415 void 416 executor::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. 430 std::shared_ptr< std::size_t > 431 executor::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. 440 int 441 executor::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. 450 const optional< process::status >& 451 executor::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. 461 const optional< passwd::user >& 462 executor::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. 471 const datetime::timestamp& 472 executor::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. 481 const datetime::timestamp& 482 executor::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. 493 fs::path 494 executor::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. 505 fs::path 506 executor::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. 515 const fs::path& 516 executor::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. 525 const fs::path& 526 executor::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. 536 struct 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. 696 executor::executor_handle::executor_handle(void) throw() : _pimpl(new impl()) 697 { 698 } 699 700 701 /// Destructor. 702 executor::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. 710 const fs::path& 711 executor::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. 724 void 725 executor::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. 739 executor::executor_handle 740 executor::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. 749 fs::path 750 executor::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. 775 executor::exec_handle 776 executor::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. 810 void 811 executor::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. 824 executor::exec_handle 825 executor::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. 861 executor::exit_handle 862 executor::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. 873 executor::exit_handle 874 executor::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. 891 void 892 executor::executor_handle::check_interrupt(void) const 893 { 894 signals::check_interrupt(); 895 } 896