3 #include "baseproc-sys.h"
6 // This header defines base_proc_service (base process service) and several derivatives, as well as some
7 // utility functions and classes. See service.h for full details of services.
9 // Given a string and a list of pairs of (start,end) indices for each argument in that string,
10 // store a null terminator for the argument. Return a `char *` vector containing the beginning
11 // of each argument and a trailing nullptr. (The returned array is invalidated if the string is later
13 std::vector<const char *> separate_args(std::string &s,
14 const std::list<std::pair<unsigned,unsigned>> &arg_indices);
16 class base_process_service;
18 // A timer for process restarting. Used to ensure a minimum delay between process restarts (and
19 // also for timing service stop before the SIGKILL hammer is used).
20 class process_restart_timer : public eventloop_t::timer_impl<process_restart_timer>
23 base_process_service * service;
25 explicit process_restart_timer(base_process_service *service_p)
30 dasynq::rearm timer_expiry(eventloop_t &, int expiry_count);
33 // Watcher for the pipe used to receive exec() failure status errno
34 class exec_status_pipe_watcher : public eventloop_t::fd_watcher_impl<exec_status_pipe_watcher>
37 base_process_service * service;
38 dasynq::rearm fd_event(eventloop_t &eloop, int fd, int flags) noexcept;
40 exec_status_pipe_watcher(base_process_service * sr) noexcept : service(sr) { }
42 exec_status_pipe_watcher(const exec_status_pipe_watcher &) = delete;
43 void operator=(exec_status_pipe_watcher &) = delete;
46 class service_child_watcher : public eventloop_t::child_proc_watcher_impl<service_child_watcher>
49 base_process_service * service;
50 dasynq::rearm status_change(eventloop_t &eloop, pid_t child, int status) noexcept;
52 service_child_watcher(base_process_service * sr) noexcept : service(sr) { }
54 service_child_watcher(const service_child_watcher &) = delete;
55 void operator=(const service_child_watcher &) = delete;
58 // Base class for process-based services.
59 class base_process_service : public service_record
61 friend class service_child_watcher;
62 friend class exec_status_pipe_watcher;
63 friend class base_process_service_test;
67 void do_restart() noexcept;
70 string program_name; // storage for program/script and arguments
71 // pointer to each argument/part of the program_name, and nullptr:
72 std::vector<const char *> exec_arg_parts;
74 string stop_command; // storage for stop program/script and arguments
75 // pointer to each argument/part of the stop_command, and nullptr:
76 std::vector<const char *> stop_arg_parts;
78 string working_dir; // working directory (or empty)
80 service_child_watcher child_listener;
81 exec_status_pipe_watcher child_status_listener;
82 process_restart_timer restart_timer;
83 time_val last_start_time;
85 // Restart interval time and restart count are used to track the number of automatic restarts
86 // over an interval. Too many restarts over an interval will inhibit further restarts.
87 time_val restart_interval_time; // current restart interval
88 int restart_interval_count; // count of restarts within current interval
90 time_val restart_interval; // maximum restart interval
91 int max_restart_interval_count; // number of restarts allowed over maximum interval
92 time_val restart_delay; // delay between restarts
94 // Time allowed for service stop, after which SIGKILL is sent. 0 to disable.
95 time_val stop_timeout = {10, 0}; // default of 10 seconds
97 // Time allowed for service start, after which SIGINT is sent (and then SIGKILL after
98 // <stop_timeout>). 0 to disable.
99 time_val start_timeout = {60, 0}; // default of 1 minute
101 uid_t run_as_uid = -1;
102 gid_t run_as_gid = -1;
104 pid_t pid = -1; // PID of the process. If state is STARTING or STOPPING,
105 // this is PID of the service script; otherwise it is the
106 // PID of the process itself (process service).
107 bp_sys::exit_status exit_status; // Exit status, if the process has exited (pid == -1).
108 int socket_fd = -1; // For socket-activation services, this is the file
109 // descriptor for the socket.
111 bool waiting_restart_timer : 1;
112 bool stop_timer_armed : 1;
113 bool reserved_child_watch : 1;
114 bool tracking_child : 1; // whether we expect to see child process status
116 // Launch the process with the given arguments, return true on success
117 bool start_ps_process(const std::vector<const char *> &args, bool on_console) noexcept;
119 // Restart the process (due to start failure or unexpected termination). Restarts will be
121 bool restart_ps_process() noexcept;
123 // Perform smooth recovery process
124 void do_smooth_recovery() noexcept;
126 // Start the process, return true on success
127 virtual bool bring_up() noexcept override;
129 // Called when the process exits. The exit_status is the status value yielded by
130 // the "wait" system call.
131 virtual void handle_exit_status(bp_sys::exit_status exit_status) noexcept = 0;
133 // Called if an exec fails.
134 virtual void exec_failed(int errcode) noexcept = 0;
136 // Called if exec succeeds.
137 virtual void exec_succeeded() noexcept { };
139 virtual bool can_interrupt_start() noexcept override
141 return waiting_restart_timer || onstart_flags.start_interruptible
142 || service_record::can_interrupt_start();
145 virtual bool can_proceed_to_start() noexcept override
147 return ! waiting_restart_timer;
150 virtual bool interrupt_start() noexcept override;
152 void becoming_inactive() noexcept override;
155 void kill_with_fire() noexcept;
157 // Signal the process group of the service process
158 void kill_pg(int signo) noexcept;
161 void emergency_stop() noexcept;
163 // Open the activation socket, return false on failure
164 bool open_socket() noexcept;
167 // Constructor for a base_process_service. Note that the various parameters not specified here must in
168 // general be set separately (using the appropriate set_xxx function for each).
169 base_process_service(service_set *sset, string name, service_type_t record_type_p, string &&command,
170 const std::list<std::pair<unsigned,unsigned>> &command_offsets,
171 const std::list<prelim_dep> &deplist_p);
173 ~base_process_service() noexcept
175 if (reserved_child_watch) {
176 child_listener.unreserve(event_loop);
178 restart_timer.deregister(event_loop);
181 // Set the stop command and arguments (may throw std::bad_alloc)
182 void set_stop_command(const std::string &command,
183 std::list<std::pair<unsigned,unsigned>> &stop_command_offsets)
185 stop_command = command;
186 stop_arg_parts = separate_args(stop_command, stop_command_offsets);
189 void set_restart_interval(timespec interval, int max_restarts) noexcept
191 restart_interval = interval;
192 max_restart_interval_count = max_restarts;
195 void set_restart_delay(timespec delay) noexcept
197 restart_delay = delay;
200 void set_stop_timeout(timespec timeout) noexcept
202 stop_timeout = timeout;
205 void set_start_timeout(timespec timeout) noexcept
207 start_timeout = timeout;
210 // Set an additional signal (other than SIGTERM) to be used to terminate the process
211 void set_extra_termination_signal(int signo) noexcept
213 this->term_signal = signo;
216 // Set the uid/gid that the service process will be run as
217 void set_run_as_uid_gid(uid_t uid, gid_t gid) noexcept
223 // Set the working directory
224 void set_workding_dir(const string &working_dir_p)
226 working_dir = working_dir_p;
229 // The restart/stop timer expired.
230 void timer_expired() noexcept;
232 // Accessor for testing:
233 const std::vector<const char *> & get_exec_arg_parts() noexcept
235 return exec_arg_parts;
238 pid_t get_pid() override
243 int get_exit_status() override
245 return exit_status.as_int();
249 // Standard process service.
250 class process_service : public base_process_service
252 virtual void handle_exit_status(bp_sys::exit_status exit_status) noexcept override;
253 virtual void exec_failed(int errcode) noexcept override;
254 virtual void exec_succeeded() noexcept override;
255 virtual void bring_down() noexcept override;
258 process_service(service_set *sset, const string &name, string &&command,
259 std::list<std::pair<unsigned,unsigned>> &command_offsets,
260 const std::list<prelim_dep> &depends_p)
261 : base_process_service(sset, name, service_type_t::PROCESS, std::move(command), command_offsets,
266 ~process_service() noexcept
271 // Bgproc (self-"backgrounding", i.e. double-forking) process service
272 class bgproc_service : public base_process_service
274 virtual void handle_exit_status(bp_sys::exit_status exit_status) noexcept override;
275 virtual void exec_failed(int errcode) noexcept override;
276 virtual void bring_down() noexcept override;
278 enum class pid_result_t {
280 FAILED, // failed to read pid or read invalid pid
281 TERMINATED // read pid successfully, but the process already terminated
284 // Read the pid-file, return false on failure
285 pid_result_t read_pid_file(bp_sys::exit_status *exit_status) noexcept;
288 bgproc_service(service_set *sset, const string &name, string &&command,
289 std::list<std::pair<unsigned,unsigned>> &command_offsets,
290 const std::list<prelim_dep> &depends_p)
291 : base_process_service(sset, name, service_type_t::BGPROCESS, std::move(command), command_offsets,
296 ~bgproc_service() noexcept
301 // Service which is started and stopped via separate commands
302 class scripted_service : public base_process_service
304 virtual void handle_exit_status(bp_sys::exit_status exit_status) noexcept override;
305 virtual void exec_succeeded() noexcept override;
306 virtual void exec_failed(int errcode) noexcept override;
307 virtual void bring_down() noexcept override;
309 virtual bool interrupt_start() noexcept override
311 // if base::interrupt_start() returns false, then start hasn't been fully interrupted, but an
312 // interrupt has been issued:
313 interrupting_start = ! base_process_service::interrupt_start();
314 return ! interrupting_start;
317 bool interrupting_start : 1; // running start script (true) or stop script (false)
320 scripted_service(service_set *sset, const string &name, string &&command,
321 std::list<std::pair<unsigned,unsigned>> &command_offsets,
322 const std::list<prelim_dep> &depends_p)
323 : base_process_service(sset, name, service_type_t::SCRIPTED, std::move(command), command_offsets,
324 depends_p), interrupting_start(false)
328 ~scripted_service() noexcept