proc-service.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #include <sys/types.h>
  2. #include "baseproc-sys.h"
  3. #include "service.h"
  4. // This header defines base_proc_service (base process service) and several derivatives, as well as some
  5. // utility functions and classes. See service.h for full details of services.
  6. // Given a string and a list of pairs of (start,end) indices for each argument in that string,
  7. // store a null terminator for the argument. Return a `char *` vector containing the beginning
  8. // of each argument and a trailing nullptr. (The returned array is invalidated if the string is later modified).
  9. std::vector<const char *> separate_args(std::string &s,
  10. const std::list<std::pair<unsigned,unsigned>> &arg_indices);
  11. class base_process_service;
  12. // A timer for process restarting. Used to ensure a minimum delay between process restarts (and
  13. // also for timing service stop before the SIGKILL hammer is used).
  14. class process_restart_timer : public eventloop_t::timer_impl<process_restart_timer>
  15. {
  16. public:
  17. base_process_service * service;
  18. explicit process_restart_timer(base_process_service *service_p)
  19. : service(service_p)
  20. {
  21. }
  22. dasynq::rearm timer_expiry(eventloop_t &, int expiry_count);
  23. };
  24. // Base class for process-based services.
  25. class base_process_service : public service_record
  26. {
  27. friend class service_child_watcher;
  28. friend class exec_status_pipe_watcher;
  29. friend class base_process_service_test;
  30. private:
  31. // Re-launch process
  32. void do_restart() noexcept;
  33. protected:
  34. string program_name; // storage for program/script and arguments
  35. std::vector<const char *> exec_arg_parts; // pointer to each argument/part of the program_name, and nullptr
  36. string stop_command; // storage for stop program/script and arguments
  37. std::vector<const char *> stop_arg_parts; // pointer to each argument/part of the stop_command, and nullptr
  38. string working_dir; // working directory (or empty)
  39. service_child_watcher child_listener;
  40. exec_status_pipe_watcher child_status_listener;
  41. process_restart_timer restart_timer;
  42. time_val last_start_time;
  43. // Restart interval time and restart count are used to track the number of automatic restarts
  44. // over an interval. Too many restarts over an interval will inhibit further restarts.
  45. time_val restart_interval_time; // current restart interval
  46. int restart_interval_count; // count of restarts within current interval
  47. time_val restart_interval; // maximum restart interval
  48. int max_restart_interval_count; // number of restarts allowed over maximum interval
  49. time_val restart_delay; // delay between restarts
  50. // Time allowed for service stop, after which SIGKILL is sent. 0 to disable.
  51. time_val stop_timeout = {10, 0}; // default of 10 seconds
  52. // Time allowed for service start, after which SIGINT is sent (and then SIGKILL after
  53. // <stop_timeout>). 0 to disable.
  54. time_val start_timeout = {60, 0}; // default of 1 minute
  55. uid_t run_as_uid = -1;
  56. gid_t run_as_gid = -1;
  57. pid_t pid = -1; // PID of the process. If state is STARTING or STOPPING,
  58. // this is PID of the service script; otherwise it is the
  59. // PID of the process itself (process service).
  60. bp_sys::exit_status exit_status; // Exit status, if the process has exited (pid == -1).
  61. int socket_fd = -1; // For socket-activation services, this is the file
  62. // descriptor for the socket.
  63. bool waiting_restart_timer : 1;
  64. bool stop_timer_armed : 1;
  65. bool reserved_child_watch : 1;
  66. bool tracking_child : 1; // whether we expect to see child process status
  67. // Launch the process with the given arguments, return true on success
  68. bool start_ps_process(const std::vector<const char *> &args, bool on_console) noexcept;
  69. // Restart the process (due to start failure or unexpected termination). Restarts will be
  70. // rate-limited.
  71. bool restart_ps_process() noexcept;
  72. // Perform smooth recovery process
  73. void do_smooth_recovery() noexcept;
  74. // Start the process, return true on success
  75. virtual bool bring_up() noexcept override;
  76. // Called when the process exits. The exit_status is the status value yielded by
  77. // the "wait" system call.
  78. virtual void handle_exit_status(bp_sys::exit_status exit_status) noexcept = 0;
  79. // Called if an exec fails.
  80. virtual void exec_failed(int errcode) noexcept = 0;
  81. // Called if exec succeeds.
  82. virtual void exec_succeeded() noexcept { };
  83. virtual bool can_interrupt_start() noexcept override
  84. {
  85. return waiting_restart_timer || onstart_flags.start_interruptible
  86. || service_record::can_interrupt_start();
  87. }
  88. virtual bool can_proceed_to_start() noexcept override
  89. {
  90. return ! waiting_restart_timer;
  91. }
  92. virtual bool interrupt_start() noexcept override;
  93. void becoming_inactive() noexcept override;
  94. // Kill with SIGKILL
  95. void kill_with_fire() noexcept;
  96. // Signal the process group of the service process
  97. void kill_pg(int signo) noexcept;
  98. // stop immediately
  99. void emergency_stop() noexcept;
  100. // Open the activation socket, return false on failure
  101. bool open_socket() noexcept;
  102. public:
  103. // Constructor for a base_process_service. Note that the various parameters not specified here must in
  104. // general be set separately (using the appropriate set_xxx function for each).
  105. base_process_service(service_set *sset, string name, service_type_t record_type_p, string &&command,
  106. const std::list<std::pair<unsigned,unsigned>> &command_offsets,
  107. const std::list<prelim_dep> &deplist_p);
  108. ~base_process_service() noexcept
  109. {
  110. if (reserved_child_watch) {
  111. child_listener.unreserve(event_loop);
  112. }
  113. restart_timer.deregister(event_loop);
  114. }
  115. // Set the stop command and arguments (may throw std::bad_alloc)
  116. void set_stop_command(const std::string &command,
  117. std::list<std::pair<unsigned,unsigned>> &stop_command_offsets)
  118. {
  119. stop_command = command;
  120. stop_arg_parts = separate_args(stop_command, stop_command_offsets);
  121. }
  122. void set_restart_interval(timespec interval, int max_restarts) noexcept
  123. {
  124. restart_interval = interval;
  125. max_restart_interval_count = max_restarts;
  126. }
  127. void set_restart_delay(timespec delay) noexcept
  128. {
  129. restart_delay = delay;
  130. }
  131. void set_stop_timeout(timespec timeout) noexcept
  132. {
  133. stop_timeout = timeout;
  134. }
  135. void set_start_timeout(timespec timeout) noexcept
  136. {
  137. start_timeout = timeout;
  138. }
  139. // Set an additional signal (other than SIGTERM) to be used to terminate the process
  140. void set_extra_termination_signal(int signo) noexcept
  141. {
  142. this->term_signal = signo;
  143. }
  144. // Set the uid/gid that the service process will be run as
  145. void set_run_as_uid_gid(uid_t uid, gid_t gid) noexcept
  146. {
  147. run_as_uid = uid;
  148. run_as_gid = gid;
  149. }
  150. // Set the working directory
  151. void set_workding_dir(const string &working_dir_p)
  152. {
  153. working_dir = working_dir_p;
  154. }
  155. // The restart/stop timer expired.
  156. void timer_expired() noexcept;
  157. // Accessor for testing:
  158. const std::vector<const char *> & get_exec_arg_parts() noexcept
  159. {
  160. return exec_arg_parts;
  161. }
  162. pid_t get_pid() override
  163. {
  164. return pid;
  165. }
  166. int get_exit_status() override
  167. {
  168. return exit_status.as_int();
  169. }
  170. };
  171. // Standard process service.
  172. class process_service : public base_process_service
  173. {
  174. virtual void handle_exit_status(bp_sys::exit_status exit_status) noexcept override;
  175. virtual void exec_failed(int errcode) noexcept override;
  176. virtual void exec_succeeded() noexcept override;
  177. virtual void bring_down() noexcept override;
  178. public:
  179. process_service(service_set *sset, const string &name, string &&command,
  180. std::list<std::pair<unsigned,unsigned>> &command_offsets,
  181. const std::list<prelim_dep> &depends_p)
  182. : base_process_service(sset, name, service_type_t::PROCESS, std::move(command), command_offsets,
  183. depends_p)
  184. {
  185. }
  186. ~process_service() noexcept
  187. {
  188. }
  189. };
  190. // Bgproc (self-"backgrounding", i.e. double-forking) process service
  191. class bgproc_service : public base_process_service
  192. {
  193. virtual void handle_exit_status(bp_sys::exit_status exit_status) noexcept override;
  194. virtual void exec_failed(int errcode) noexcept override;
  195. virtual void bring_down() noexcept override;
  196. enum class pid_result_t {
  197. OK,
  198. FAILED, // failed to read pid or read invalid pid
  199. TERMINATED // read pid successfully, but the process already terminated
  200. };
  201. // Read the pid-file, return false on failure
  202. pid_result_t read_pid_file(bp_sys::exit_status *exit_status) noexcept;
  203. public:
  204. bgproc_service(service_set *sset, const string &name, string &&command,
  205. std::list<std::pair<unsigned,unsigned>> &command_offsets,
  206. const std::list<prelim_dep> &depends_p)
  207. : base_process_service(sset, name, service_type_t::BGPROCESS, std::move(command), command_offsets,
  208. depends_p)
  209. {
  210. }
  211. ~bgproc_service() noexcept
  212. {
  213. }
  214. };
  215. // Service which is started and stopped via separate commands
  216. class scripted_service : public base_process_service
  217. {
  218. virtual void handle_exit_status(bp_sys::exit_status exit_status) noexcept override;
  219. virtual void exec_succeeded() noexcept override;
  220. virtual void exec_failed(int errcode) noexcept override;
  221. virtual void bring_down() noexcept override;
  222. virtual bool interrupt_start() noexcept override
  223. {
  224. // if base::interrupt_start() returns false, then start hasn't been fully interrupted, but an
  225. // interrupt has been issued:
  226. interrupting_start = ! base_process_service::interrupt_start();
  227. return ! interrupting_start;
  228. }
  229. bool interrupting_start : 1; // running start script (true) or stop script (false)
  230. public:
  231. scripted_service(service_set *sset, const string &name, string &&command,
  232. std::list<std::pair<unsigned,unsigned>> &command_offsets,
  233. const std::list<prelim_dep> &depends_p)
  234. : base_process_service(sset, name, service_type_t::SCRIPTED, std::move(command), command_offsets,
  235. depends_p), interrupting_start(false)
  236. {
  237. }
  238. ~scripted_service() noexcept
  239. {
  240. }
  241. };