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