Add more missing includes for tests.
[oweals/dinit.git] / src / baseproc-service.cc
1 #include <cstring>
2
3 #include "dinit-log.h"
4 #include "dinit-socket.h"
5 #include "proc-service.h"
6
7 /*
8  * Base process implementation (base_process_service).
9  *
10  * See proc-service.h for interface documentation.
11  */
12
13 extern eventloop_t event_loop;
14
15 using clock_type = dasynq::clock_type;
16 using rearm = dasynq::rearm;
17 using time_val = dasynq::time_val;
18
19 void base_process_service::do_smooth_recovery() noexcept
20 {
21     if (! restart_ps_process()) {
22         emergency_stop();
23         services->process_queues();
24     }
25 }
26
27 bool base_process_service::bring_up() noexcept
28 {
29     if (restarting) {
30         if (pid == -1) {
31             return restart_ps_process();
32         }
33         return true;
34     }
35     else {
36         event_loop.get_time(restart_interval_time, clock_type::MONOTONIC);
37         restart_interval_count = 0;
38         if (start_ps_process(exec_arg_parts, onstart_flags.starts_on_console)) {
39             if (start_timeout != time_val(0,0)) {
40                 restart_timer.arm_timer_rel(event_loop, start_timeout);
41                 stop_timer_armed = true;
42             }
43             else if (stop_timer_armed) {
44                 restart_timer.stop_timer(event_loop);
45                 stop_timer_armed = false;
46             }
47             return true;
48         }
49         return false;
50     }
51 }
52
53 bool base_process_service::start_ps_process(const std::vector<const char *> &cmd, bool on_console) noexcept
54 {
55     // In general, you can't tell whether fork/exec is successful. We use a pipe to communicate
56     // success/failure from the child to the parent. The pipe is set CLOEXEC so a successful
57     // exec closes the pipe, and the parent sees EOF. If the exec is unsuccessful, the errno
58     // is written to the pipe, and the parent can read it.
59
60     event_loop.get_time(last_start_time, clock_type::MONOTONIC);
61
62     int pipefd[2];
63     if (dasynq::pipe2(pipefd, O_CLOEXEC)) {
64         log(loglevel_t::ERROR, get_name(), ": can't create status check pipe: ", strerror(errno));
65         return false;
66     }
67
68     const char * logfile = this->logfile.c_str();
69     if (*logfile == 0) {
70         logfile = "/dev/null";
71     }
72
73     bool child_status_registered = false;
74     control_conn_t *control_conn = nullptr;
75
76     int control_socket[2] = {-1, -1};
77     if (onstart_flags.pass_cs_fd) {
78         if (dinit_socketpair(AF_UNIX, SOCK_STREAM, /* protocol */ 0, control_socket, SOCK_NONBLOCK)) {
79             log(loglevel_t::ERROR, get_name(), ": can't create control socket: ", strerror(errno));
80             goto out_p;
81         }
82
83         // Make the server side socket close-on-exec:
84         int fdflags = fcntl(control_socket[0], F_GETFD);
85         fcntl(control_socket[0], F_SETFD, fdflags | FD_CLOEXEC);
86
87         try {
88             control_conn = new control_conn_t(event_loop, services, control_socket[0]);
89         }
90         catch (std::exception &exc) {
91             log(loglevel_t::ERROR, get_name(), ": can't launch process; out of memory");
92             goto out_cs;
93         }
94     }
95
96     // Set up complete, now fork and exec:
97
98     pid_t forkpid;
99
100     try {
101         child_status_listener.add_watch(event_loop, pipefd[0], dasynq::IN_EVENTS);
102         child_status_registered = true;
103
104         // We specify a high priority (i.e. low priority value) so that process termination is
105         // handled early. This means we have always recorded that the process is terminated by the
106         // time that we handle events that might otherwise cause us to signal the process, so we
107         // avoid sending a signal to an invalid (and possibly recycled) process ID.
108         forkpid = child_listener.fork(event_loop, reserved_child_watch, dasynq::DEFAULT_PRIORITY - 10);
109         reserved_child_watch = true;
110     }
111     catch (std::exception &e) {
112         log(loglevel_t::ERROR, get_name(), ": Could not fork: ", e.what());
113         goto out_cs_h;
114     }
115
116     if (forkpid == 0) {
117         run_child_proc(cmd.data(), logfile, on_console, pipefd[1], control_socket[1]);
118     }
119     else {
120         // Parent process
121         close(pipefd[1]); // close the 'other end' fd
122         if (control_socket[1] != -1) {
123             close(control_socket[1]);
124         }
125         pid = forkpid;
126
127         waiting_for_execstat = true;
128         return true;
129     }
130
131     // Failure exit:
132
133     out_cs_h:
134     if (child_status_registered) {
135         child_status_listener.deregister(event_loop);
136     }
137
138     if (onstart_flags.pass_cs_fd) {
139         delete control_conn;
140
141         out_cs:
142         close(control_socket[0]);
143         close(control_socket[1]);
144     }
145
146     out_p:
147     close(pipefd[0]);
148     close(pipefd[1]);
149
150     return false;
151 }
152
153 void base_process_service::bring_down() noexcept
154 {
155     waiting_for_deps = false;
156     if (pid != -1) {
157         // The process is still kicking on - must actually kill it. We signal the process
158         // group (-pid) rather than just the process as there's less risk then of creating
159         // an orphaned process group:
160         if (! onstart_flags.no_sigterm) {
161             kill_pg(SIGTERM);
162         }
163         if (term_signal != -1) {
164             kill_pg(term_signal);
165         }
166
167         // In most cases, the rest is done in handle_exit_status.
168         // If we are a BGPROCESS and the process is not our immediate child, however, that
169         // won't work - check for this now:
170         if (get_type() == service_type_t::BGPROCESS && ! tracking_child) {
171             stopped();
172         }
173         else if (stop_timeout != time_val(0,0)) {
174             restart_timer.arm_timer_rel(event_loop, stop_timeout);
175             stop_timer_armed = true;
176         }
177     }
178     else {
179         // The process is already dead.
180         stopped();
181     }
182 }
183
184 base_process_service::base_process_service(service_set *sset, string name,
185         service_type_t service_type_p, string &&command,
186         std::list<std::pair<unsigned,unsigned>> &command_offsets,
187         const std::list<prelim_dep> &deplist_p)
188      : service_record(sset, name, service_type_p, deplist_p), child_listener(this),
189        child_status_listener(this), restart_timer(this)
190 {
191     program_name = std::move(command);
192     exec_arg_parts = separate_args(program_name, command_offsets);
193
194     restart_interval_count = 0;
195     restart_interval_time = {0, 0};
196     restart_timer.service = this;
197     restart_timer.add_timer(event_loop);
198
199     // By default, allow a maximum of 3 restarts within 10.0 seconds:
200     restart_interval.seconds() = 10;
201     restart_interval.nseconds() = 0;
202     max_restart_interval_count = 3;
203
204     waiting_restart_timer = false;
205     reserved_child_watch = false;
206     tracking_child = false;
207     stop_timer_armed = false;
208     start_is_interruptible = false;
209 }
210
211 void base_process_service::do_restart() noexcept
212 {
213     waiting_restart_timer = false;
214     restart_interval_count++;
215     auto service_state = get_state();
216
217     // We may be STARTING (regular restart) or STARTED ("smooth recovery"). This affects whether
218     // the process should be granted access to the console:
219     bool on_console = service_state == service_state_t::STARTING
220             ? onstart_flags.starts_on_console : onstart_flags.runs_on_console;
221
222     if (service_state == service_state_t::STARTING) {
223         // for a smooth recovery, we want to check dependencies are available before actually
224         // starting:
225         if (! check_deps_started()) {
226             waiting_for_deps = true;
227             return;
228         }
229     }
230
231     if (! start_ps_process(exec_arg_parts, on_console)) {
232         restarting = false;
233         if (service_state == service_state_t::STARTING) {
234             failed_to_start();
235         }
236         else {
237             // desired_state = service_state_t::STOPPED;
238             forced_stop();
239         }
240         services->process_queues();
241     }
242 }
243
244 bool base_process_service::restart_ps_process() noexcept
245 {
246     using time_val = dasynq::time_val;
247
248     time_val current_time;
249     event_loop.get_time(current_time, clock_type::MONOTONIC);
250
251     if (max_restart_interval_count != 0) {
252         // Check whether we're still in the most recent restart check interval:
253         time_val int_diff = current_time - restart_interval_time;
254         if (int_diff < restart_interval) {
255             if (restart_interval_count >= max_restart_interval_count) {
256                 log(loglevel_t::ERROR, "Service ", get_name(), " restarting too quickly; stopping.");
257                 return false;
258             }
259         }
260         else {
261             restart_interval_time = current_time;
262             restart_interval_count = 0;
263         }
264     }
265
266     // Check if enough time has lapsed since the prevous restart. If not, start a timer:
267     time_val tdiff = current_time - last_start_time;
268     if (restart_delay <= tdiff) {
269         // > restart delay (normally 200ms)
270         do_restart();
271     }
272     else {
273         time_val timeout = restart_delay - tdiff;
274         restart_timer.arm_timer_rel(event_loop, timeout);
275         waiting_restart_timer = true;
276     }
277     return true;
278 }
279
280 bool base_process_service::interrupt_start() noexcept
281 {
282     if (waiting_restart_timer) {
283         restart_timer.stop_timer(event_loop);
284         waiting_restart_timer = false;
285         return service_record::interrupt_start();
286     }
287     else {
288         log(loglevel_t::WARN, "Interrupting start of service ", get_name(), " with pid ", pid, " (with SIGINT).");
289         kill_pg(SIGINT);
290         if (stop_timeout != time_val(0,0)) {
291             restart_timer.arm_timer_rel(event_loop, stop_timeout);
292             stop_timer_armed = true;
293         }
294         else if (stop_timer_armed) {
295             restart_timer.stop_timer(event_loop);
296             stop_timer_armed = false;
297         }
298         set_state(service_state_t::STOPPING);
299         notify_listeners(service_event_t::STARTCANCELLED);
300         return false;
301     }
302 }
303
304 void base_process_service::kill_with_fire() noexcept
305 {
306     if (pid != -1) {
307         log(loglevel_t::WARN, "Service ", get_name(), " with pid ", pid, " exceeded allowed stop time; killing.");
308         kill_pg(SIGKILL);
309     }
310 }
311
312 void base_process_service::kill_pg(int signo) noexcept
313 {
314     pid_t pgid = getpgid(pid);
315     if (pgid == -1) {
316         // only should happen if pid is invalid, which should never happen...
317         log(loglevel_t::ERROR, get_name(), ": can't signal process: ", strerror(errno));
318         return;
319     }
320     kill(-pgid, signo);
321 }