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
setup_child(const optional<passwd::user> unprivileged_user,const fs::path & control_directory,const fs::path & work_directory)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.
implutils::process::executor::exec_handle::impl167     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.
exec_handle(std::shared_ptr<impl> pimpl)193 executor::exec_handle::exec_handle(std::shared_ptr< impl > pimpl) :
194     _pimpl(pimpl)
195 {
196 }
197 
198 
199 /// Destructor.
~exec_handle(void)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
pid(void) const209 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
control_directory(void) const221 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
work_directory(void) const233 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&
stdout_file(void) const243 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&
stderr_file(void) const253 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.
implutils::process::executor::exit_handle::impl325     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.
~implutils::process::executor::exit_handle::impl346     ~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
cleanuputils::process::executor::exit_handle::impl364     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.
exit_handle(std::shared_ptr<impl> pimpl)393 executor::exit_handle::exit_handle(std::shared_ptr< impl > pimpl) :
394     _pimpl(pimpl)
395 {
396 }
397 
398 
399 /// Destructor.
~exit_handle(void)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
cleanup(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 >
state_owners(void) const429 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
original_pid(void) const439 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 >&
status(void) const449 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 >&
unprivileged_user(void) const460 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&
start_time(void) const470 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&
end_time(void) const480 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
control_directory(void) const492 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
work_directory(void) const504 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&
stdout_file(void) const514 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&
stderr_file(void) const524 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.
implutils::process::executor::executor_handle::impl556     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.
~implutils::process::executor::executor_handle::impl566     ~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
cleanuputils::process::executor::executor_handle::impl581     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
post_waitutils::process::executor::executor_handle::impl631     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     executor::exit_handle
reaputils::process::executor::executor_handle::impl676     reap(const pid_t original_pid)
677     {
678         const exec_handles_map::iterator iter = all_exec_handles.find(
679             original_pid);
680         exec_handle& data = (*iter).second;
681         data._pimpl->timer.unprogram();
682 
683         if (!fs::exists(data.stdout_file())) {
684             std::ofstream new_stdout(data.stdout_file().c_str());
685         }
686         if (!fs::exists(data.stderr_file())) {
687             std::ofstream new_stderr(data.stderr_file().c_str());
688         }
689 
690         return exit_handle(std::shared_ptr< exit_handle::impl >(
691             new exit_handle::impl(
692                 data.pid(),
693                 none,
694                 data._pimpl->unprivileged_user,
695                 data._pimpl->start_time, datetime::timestamp::now(),
696                 data.control_directory(),
697                 data.stdout_file(),
698                 data.stderr_file(),
699                 data._pimpl->state_owners,
700                 all_exec_handles)));
701     }
702 };
703 
704 
705 /// Constructor.
executor_handle(void)706 executor::executor_handle::executor_handle(void) throw() : _pimpl(new impl())
707 {
708 }
709 
710 
711 /// Destructor.
~executor_handle(void)712 executor::executor_handle::~executor_handle(void)
713 {
714 }
715 
716 
717 /// Queries the path to the root of the work directory for all subprocesses.
718 ///
719 /// \return A path.
720 const fs::path&
root_work_directory(void) const721 executor::executor_handle::root_work_directory(void) const
722 {
723     return _pimpl->root_work_directory->directory();
724 }
725 
726 
727 /// Cleans up the executor state.
728 ///
729 /// This function should be called explicitly as it provides the means to
730 /// control any exceptions raised during cleanup.  Do not rely on the destructor
731 /// to clean things up.
732 ///
733 /// \throw engine::error If there are problems cleaning up the executor.
734 void
cleanup(void)735 executor::executor_handle::cleanup(void)
736 {
737     PRE(!_pimpl->cleaned);
738     _pimpl->cleanup();
739     _pimpl->cleaned = true;
740 }
741 
742 
743 /// Initializes the executor.
744 ///
745 /// \pre This function can only be called if there is no other executor_handle
746 /// object alive.
747 ///
748 /// \return A handle to the operations of the executor.
749 executor::executor_handle
setup(void)750 executor::setup(void)
751 {
752     return executor_handle();
753 }
754 
755 
756 /// Pre-helper for the spawn() method.
757 ///
758 /// \return The created control directory for the subprocess.
759 fs::path
spawn_pre(void)760 executor::executor_handle::spawn_pre(void)
761 {
762     signals::check_interrupt();
763 
764     ++_pimpl->last_subprocess;
765 
766     const fs::path control_directory =
767         _pimpl->root_work_directory->directory() /
768         (F("%s") % _pimpl->last_subprocess);
769     fs::mkdir_p(control_directory / detail::work_subdir, 0755);
770 
771     return control_directory;
772 }
773 
774 
775 /// Post-helper for the spawn() method.
776 ///
777 /// \param control_directory Control directory as returned by spawn_pre().
778 /// \param stdout_file Path to the subprocess' stdout.
779 /// \param stderr_file Path to the subprocess' stderr.
780 /// \param timeout Maximum amount of time the subprocess can run for.
781 /// \param unprivileged_user If not none, user to switch to before execution.
782 /// \param child The process created by spawn().
783 ///
784 /// \return The execution handle of the started subprocess.
785 executor::exec_handle
spawn_post(const fs::path & control_directory,const fs::path & stdout_file,const fs::path & stderr_file,const datetime::delta & timeout,const optional<passwd::user> unprivileged_user,std::auto_ptr<process::child> child)786 executor::executor_handle::spawn_post(
787     const fs::path& control_directory,
788     const fs::path& stdout_file,
789     const fs::path& stderr_file,
790     const datetime::delta& timeout,
791     const optional< passwd::user > unprivileged_user,
792     std::auto_ptr< process::child > child)
793 {
794     const exec_handle handle(std::shared_ptr< exec_handle::impl >(
795         new exec_handle::impl(
796             child->pid(),
797             control_directory,
798             stdout_file,
799             stderr_file,
800             datetime::timestamp::now(),
801             timeout,
802             unprivileged_user,
803             detail::refcnt_t(new detail::refcnt_t::element_type(0)))));
804     INV_MSG(_pimpl->all_exec_handles.find(handle.pid()) ==
805             _pimpl->all_exec_handles.end(),
806             F("PID %s already in all_exec_handles; not properly cleaned "
807               "up or reused too fast") % handle.pid());;
808     _pimpl->all_exec_handles.insert(exec_handles_map::value_type(
809         handle.pid(), handle));
810     LI(F("Spawned subprocess with exec_handle %s") % handle.pid());
811     return handle;
812 }
813 
814 
815 /// Pre-helper for the spawn_followup() method.
816 void
spawn_followup_pre(void)817 executor::executor_handle::spawn_followup_pre(void)
818 {
819     signals::check_interrupt();
820 }
821 
822 
823 /// Post-helper for the spawn_followup() method.
824 ///
825 /// \param base Exit handle of the subprocess to use as context.
826 /// \param timeout Maximum amount of time the subprocess can run for.
827 /// \param child The process created by spawn_followup().
828 ///
829 /// \return The execution handle of the started subprocess.
830 executor::exec_handle
spawn_followup_post(const exit_handle & base,const datetime::delta & timeout,std::auto_ptr<process::child> child)831 executor::executor_handle::spawn_followup_post(
832     const exit_handle& base,
833     const datetime::delta& timeout,
834     std::auto_ptr< process::child > child)
835 {
836     INV(*base.state_owners() > 0);
837     const exec_handle handle(std::shared_ptr< exec_handle::impl >(
838         new exec_handle::impl(
839             child->pid(),
840             base.control_directory(),
841             base.stdout_file(),
842             base.stderr_file(),
843             datetime::timestamp::now(),
844             timeout,
845             base.unprivileged_user(),
846             base.state_owners())));
847     INV_MSG(_pimpl->all_exec_handles.find(handle.pid()) ==
848             _pimpl->all_exec_handles.end(),
849             F("PID %s already in all_exec_handles; not properly cleaned "
850               "up or reused too fast") % handle.pid());;
851     _pimpl->all_exec_handles.insert(exec_handles_map::value_type(
852         handle.pid(), handle));
853     LI(F("Spawned subprocess with exec_handle %s") % handle.pid());
854     return handle;
855 }
856 
857 
858 /// Waits for completion of any forked process.
859 ///
860 /// \param exec_handle The handle of the process to wait for.
861 ///
862 /// \return A pointer to an object describing the waited-for subprocess.
863 executor::exit_handle
wait(const exec_handle exec_handle)864 executor::executor_handle::wait(const exec_handle exec_handle)
865 {
866     signals::check_interrupt();
867     const process::status status = process::wait(exec_handle.pid());
868     return _pimpl->post_wait(exec_handle.pid(), status);
869 }
870 
871 
872 /// Waits for completion of any forked process.
873 ///
874 /// \return A pointer to an object describing the waited-for subprocess.
875 executor::exit_handle
wait_any(void)876 executor::executor_handle::wait_any(void)
877 {
878     signals::check_interrupt();
879     const process::status status = process::wait_any();
880     return _pimpl->post_wait(status.dead_pid(), status);
881 }
882 
883 
884 /// Forms exit_handle for the given PID subprocess.
885 ///
886 /// Can be used in the cases when we want to do cleanup(s) of a killed test
887 /// subprocess, but we do not have exit handle as we usually do after normal
888 /// wait mechanism.
889 ///
890 /// \return A pointer to an object describing the subprocess.
891 executor::exit_handle
reap(const int pid)892 executor::executor_handle::reap(const int pid)
893 {
894     return _pimpl->reap(pid);
895 }
896 
897 
898 /// Checks if an interrupt has fired.
899 ///
900 /// Calls to this function should be sprinkled in strategic places through the
901 /// code protected by an interrupts_handler object.
902 ///
903 /// This is just a wrapper over signals::check_interrupt() to avoid leaking this
904 /// dependency to the caller.
905 ///
906 /// \throw signals::interrupted_error If there has been an interrupt.
907 void
check_interrupt(void) const908 executor::executor_handle::check_interrupt(void) const
909 {
910     signals::check_interrupt();
911 }
912