executable.cc 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. // The definition of the Base_executable and Binary classes. The former
  2. // provides functionality common to all derived types, the latter executes
  3. // external programs.
  4. //
  5. // Copyright (C) 2005-2019 Samuel Newbold
  6. #include <list>
  7. #include <map>
  8. #include <set>
  9. #include <string>
  10. #include <sys/time.h>
  11. #include <unistd.h>
  12. #include <vector>
  13. #include "rwsh_stream.h"
  14. #include "variable_map.h"
  15. #include "argm.h"
  16. #include "call_stack.h"
  17. #include "clock.h"
  18. #include "executable.h"
  19. #include "executable_map.h"
  20. #include "plumber.h"
  21. void Base_executable::operator() (const Argm& argm,
  22. Error_list& parent_exceptions) {
  23. if (global_stack.global_nesting > global_stack.max_nesting+1)
  24. parent_exceptions.add_error(Exception(Argm::Excessive_nesting));
  25. if (global_stack.unwind_stack()) return;
  26. else ++executable_nesting, ++global_stack.global_nesting;
  27. Error_list children;
  28. struct timeval start_time;
  29. gettimeofday(&start_time, rwsh_clock.no_timezone);
  30. try {execute(argm, children);}
  31. catch (Exception error) {children.add_error(error);}
  32. struct timeval end_time;
  33. gettimeofday(&end_time, rwsh_clock.no_timezone);
  34. last_execution_time_v = Clock::timeval_sub(end_time, start_time);
  35. Clock::timeval_add(total_execution_time_v, last_execution_time_v);
  36. ++execution_count_v;
  37. --global_stack.global_nesting;
  38. if (global_stack.caught_signal) {
  39. Exception focus(global_stack.caught_signal);
  40. global_stack.caught_signal = Argm::No_exception;
  41. executable_map.run(focus, children);}
  42. if (children.size()) {
  43. last_exception_v = "";
  44. for (auto j = children.begin(); j != children.end();) {
  45. last_exception_v += j->str() + " " + argm.str();
  46. j->push_back(argm[0]);
  47. parent_exceptions.push_back(*j);
  48. if (++j != children.end()) last_exception_v += "; ";}}
  49. --executable_nesting;
  50. if (del_on_term && !executable_nesting) delete this;}
  51. Binary::Binary(const std::string& impl) : implementation(impl) {}
  52. // run the given binary
  53. void Binary::execute(const Argm& argm_i, Error_list& exceptions) {
  54. int ret,
  55. input = argm_i.input.fd(),
  56. output = argm_i.output.fd(),
  57. error = argm_i.error.fd();
  58. if (!fork()) {
  59. plumber.after_fork();
  60. if (dup2(input, 0) < 0) argm_i.error <<"dup2 didn't like changing input\n";
  61. if (dup2(output, 1) < 0)
  62. argm_i.error <<"dup2 didn't like changing output\n";
  63. if (dup2(error, 2) < 0) argm_i.error <<"dup2 didn't like changing error\n";
  64. Old_argv argv(argm_i.subrange(0));
  65. std::vector<char *>env;
  66. argm_i.export_env(env);
  67. ret = execve(implementation.c_str(), argv.argv(), &env[0]);
  68. exceptions.add_error(Exception(Argm::Binary_does_not_exist, argm_i[0]));
  69. global_stack.exception_handler(exceptions);
  70. executable_map.unused_var_check_at_exit();
  71. exit(ret);}
  72. else plumber.wait(&ret);
  73. if (WIFEXITED(ret) && WEXITSTATUS(ret))
  74. exceptions.add_error(Exception(Argm::Return_code, WEXITSTATUS(ret)));}