build: add target to run cppcheck.
[oweals/dinit.git] / src / proc-service.cc
1 #include <sys/un.h>
2 #include <sys/socket.h>
3
4 #include "dinit.h"
5 #include "dinit-socket.h"
6 #include "dinit-util.h"
7 #include "dinit-log.h"
8 #include "proc-service.h"
9
10 /*
11  * Most of the implementation for process-based services (process, scripted, bgprocess) is here.
12  *
13  * See proc-service.h header for interface details.
14  */
15
16 // Given a string and a list of pairs of (start,end) indices for each argument in that string,
17 // store a null terminator for the argument. Return a `char *` vector containing the beginning
18 // of each argument and a trailing nullptr. (The returned array is invalidated if the string is later modified).
19 std::vector<const char *> separate_args(std::string &s, std::list<std::pair<unsigned,unsigned>> &arg_indices)
20 {
21     std::vector<const char *> r;
22     r.reserve(arg_indices.size() + 1);
23
24     // First store nul terminator for each part:
25     for (auto index_pair : arg_indices) {
26         if (index_pair.second < s.length()) {
27             s[index_pair.second] = 0;
28         }
29     }
30
31     // Now we can get the C string (c_str) and store offsets into it:
32     const char * cstr = s.c_str();
33     for (auto index_pair : arg_indices) {
34         r.push_back(cstr + index_pair.first);
35     }
36     r.push_back(nullptr);
37     return r;
38 }
39
40 void process_service::exec_succeeded() noexcept
41 {
42     // This could be a smooth recovery (state already STARTED). Even more, the process
43     // might be stopped (and killed via a signal) during smooth recovery.  We don't to
44     // process startup again in either case, so we check for state STARTING:
45     if (get_state() == service_state_t::STARTING) {
46         started();
47     }
48     else if (get_state() == service_state_t::STOPPING) {
49         // stopping, but smooth recovery was in process. That's now over so we can
50         // commence normal stop. Note that if pid == -1 the process already stopped(!),
51         // that's handled below.
52         if (pid != -1 && stop_check_dependents()) {
53             bring_down();
54         }
55     }
56 }
57
58 void scripted_service::exec_succeeded() noexcept
59 {
60         // For a scripted service, this means nothing other than that the start/stop
61         // script will now begin.
62 }
63
64 rearm exec_status_pipe_watcher::fd_event(eventloop_t &loop, int fd, int flags) noexcept
65 {
66     base_process_service *sr = service;
67     sr->waiting_for_execstat = false;
68
69     int exec_status;
70     int r = read(get_watched_fd(), &exec_status, sizeof(int));
71     deregister(loop);
72     close(get_watched_fd());
73
74     if (r > 0) {
75         // We read an errno code; exec() failed, and the service startup failed.
76         if (sr->pid != -1) {
77             sr->child_listener.deregister(event_loop, sr->pid);
78             sr->reserved_child_watch = false;
79             if (sr->stop_timer_armed) {
80                 sr->restart_timer.stop_timer(loop);
81                 sr->stop_timer_armed = false;
82             }
83         }
84         sr->pid = -1;
85         sr->exec_failed(exec_status);
86     }
87     else {
88         sr->exec_succeeded();
89
90         if (sr->pid == -1) {
91             // Somehow the process managed to complete before we even saw the exec() status.
92             sr->handle_exit_status(sr->exit_status);
93         }
94     }
95
96     sr->services->process_queues();
97
98     return rearm::REMOVED;
99 }
100
101 dasynq::rearm service_child_watcher::status_change(eventloop_t &loop, pid_t child, int status) noexcept
102 {
103     base_process_service *sr = service;
104
105     sr->pid = -1;
106     sr->exit_status = bp_sys::exit_status(status);
107
108     // Ok, for a process service, any process death which we didn't rig
109     // ourselves is a bit... unexpected. Probably, the child died because
110     // we asked it to (sr->service_state == STOPPING). But even if
111     // we didn't, there's not much we can do.
112
113     if (sr->waiting_for_execstat) {
114         // We still don't have an exec() status from the forked child, wait for that
115         // before doing any further processing.
116         return dasynq::rearm::NOOP; // hold watch reservation
117     }
118
119     // Must stop watch now since handle_exit_status might result in re-launch:
120     // (stop_watch instead of deregister, so that we hold watch reservation).
121     stop_watch(loop);
122
123     if (sr->stop_timer_armed) {
124         sr->restart_timer.stop_timer(loop);
125         sr->stop_timer_armed = false;
126     }
127
128     sr->handle_exit_status(bp_sys::exit_status(status));
129     return dasynq::rearm::NOOP;
130 }
131
132 void process_service::handle_exit_status(bp_sys::exit_status exit_status) noexcept
133 {
134     bool did_exit = exit_status.did_exit();
135     bool was_signalled = exit_status.was_signalled();
136     restarting = false;
137     auto service_state = get_state();
138
139     if (exit_status.did_exit_clean() && service_state != service_state_t::STOPPING) {
140         if (did_exit) {
141             log(loglevel_t::ERROR, "Service ", get_name(), " process terminated with exit code ",
142                     exit_status.get_exit_status());
143         }
144         else if (was_signalled) {
145             log(loglevel_t::ERROR, "Service ", get_name(), " terminated due to signal ",
146                     exit_status.get_term_sig());
147         }
148     }
149
150     if (service_state == service_state_t::STARTING) {
151         if (exit_status.did_exit_clean()) {
152             started();
153         }
154         else {
155             stop_reason = stopped_reason_t::FAILED;
156             failed_to_start();
157         }
158     }
159     else if (service_state == service_state_t::STOPPING) {
160         // We won't log a non-zero exit status or termination due to signal here -
161         // we assume that the process died because we signalled it.
162         if (stop_timer_armed) {
163             restart_timer.stop_timer(event_loop);
164         }
165         stopped();
166     }
167     else if (smooth_recovery && service_state == service_state_t::STARTED
168             && get_target_state() == service_state_t::STARTED) {
169         do_smooth_recovery();
170         return;
171     }
172     else {
173         stop_reason = stopped_reason_t::TERMINATED;
174         emergency_stop();
175     }
176     services->process_queues();
177 }
178
179 void process_service::exec_failed(int errcode) noexcept
180 {
181     log(loglevel_t::ERROR, get_name(), ": execution failed: ", strerror(errcode));
182     if (get_state() == service_state_t::STARTING) {
183         stop_reason = stopped_reason_t::EXECFAILED;
184         failed_to_start();
185     }
186     else {
187         // Process service in smooth recovery:
188         stop_reason = stopped_reason_t::TERMINATED;
189         emergency_stop();
190     }
191 }
192
193 void bgproc_service::handle_exit_status(bp_sys::exit_status exit_status) noexcept
194 {
195     begin:
196     bool did_exit = exit_status.did_exit();
197     bool was_signalled = exit_status.was_signalled();
198     auto service_state = get_state();
199
200     if (!exit_status.did_exit_clean() && service_state != service_state_t::STOPPING) {
201         if (did_exit) {
202             log(loglevel_t::ERROR, "Service ", get_name(), " process terminated with exit code ",
203                     exit_status.get_exit_status());
204         }
205         else if (was_signalled) {
206             log(loglevel_t::ERROR, "Service ", get_name(), " terminated due to signal ",
207                     exit_status.get_term_sig());
208         }
209     }
210
211     // This may be a "smooth recovery" where we are restarting the process while leaving the
212     // service in the STARTED state.
213     if (restarting && service_state == service_state_t::STARTED) {
214         restarting = false;
215         bool need_stop = false;
216         if ((did_exit && exit_status.get_exit_status() != 0) || was_signalled) {
217             need_stop = true;
218         }
219         else {
220             // We need to re-read the PID, since it has now changed.
221             if (pid_file.length() != 0) {
222                 auto pid_result = read_pid_file(&exit_status);
223                 switch (pid_result) {
224                     case pid_result_t::FAILED:
225                         // Failed startup: no auto-restart.
226                         need_stop = true;
227                         break;
228                     case pid_result_t::TERMINATED:
229                         goto begin;
230                     case pid_result_t::OK:
231                         break;
232                 }
233             }
234         }
235
236         if (need_stop) {
237             // Failed startup: no auto-restart.
238             stop_reason = stopped_reason_t::TERMINATED;
239             emergency_stop();
240             services->process_queues();
241         }
242
243         return;
244     }
245
246     restarting = false;
247     if (service_state == service_state_t::STARTING) {
248         // POSIX requires that if the process exited clearly with a status code of 0,
249         // the exit status value will be 0:
250         if (exit_status.did_exit_clean()) {
251             auto pid_result = read_pid_file(&exit_status);
252             switch (pid_result) {
253                 case pid_result_t::FAILED:
254                     // Failed startup: no auto-restart.
255                     stop_reason = stopped_reason_t::FAILED;
256                     failed_to_start();
257                     break;
258                 case pid_result_t::TERMINATED:
259                     // started, but immediately terminated
260                     started();
261                     goto begin;
262                 case pid_result_t::OK:
263                     started();
264                     break;
265             }
266         }
267         else {
268             stop_reason = stopped_reason_t::FAILED;
269             failed_to_start();
270         }
271     }
272     else if (service_state == service_state_t::STOPPING) {
273         // We won't log a non-zero exit status or termination due to signal here -
274         // we assume that the process died because we signalled it.
275         stopped();
276     }
277     else {
278         // we must be STARTED
279         if (smooth_recovery && get_target_state() == service_state_t::STARTED) {
280             do_smooth_recovery();
281             return;
282         }
283         if (! do_auto_restart() && start_explicit) {
284             start_explicit = false;
285             release(false);
286         }
287         stop_reason = stopped_reason_t::TERMINATED;
288         forced_stop();
289         stop_dependents();
290         stopped();
291     }
292     services->process_queues();
293 }
294
295 void bgproc_service::exec_failed(int errcode) noexcept
296 {
297     log(loglevel_t::ERROR, get_name(), ": execution failed: ", strerror(errcode));
298     // Only time we execute is for startup:
299     stop_reason = stopped_reason_t::EXECFAILED;
300     failed_to_start();
301 }
302
303 void scripted_service::handle_exit_status(bp_sys::exit_status exit_status) noexcept
304 {
305     bool did_exit = exit_status.did_exit();
306     bool was_signalled = exit_status.was_signalled();
307     auto service_state = get_state();
308
309     // For a scripted service, a termination occurs in one of three main cases:
310     // - the start script completed (or failed), when service was STARTING
311     // - the start script was interrupted to cancel startup; state is STOPPING
312     // - the stop script complete (or failed), state is STOPPING
313
314     if (service_state == service_state_t::STOPPING) {
315         // We might be running the stop script, or we might be running the start script and have issued
316         // a cancel order via SIGINT:
317         if (interrupting_start) {
318             // We issued a start interrupt, so we expected this failure:
319             if (did_exit && exit_status.get_exit_status() != 0) {
320                 log(loglevel_t::INFO, "Service ", get_name(), " start cancelled; exit code ",
321                         exit_status.get_exit_status());
322                 // Assume that a command terminating normally requires no cleanup:
323                 stopped();
324             }
325             else {
326                 if (was_signalled) {
327                     log(loglevel_t::INFO, "Service ", get_name(), " start cancelled from signal ",
328                             exit_status.get_term_sig());
329                 }
330                 // If the start script completed successfully, or was interrupted via our signal,
331                 // we want to run the stop script to clean up:
332                 bring_down();
333             }
334             interrupting_start = false;
335         }
336         else if (exit_status.did_exit_clean()) {
337             // We were running the stop script and finished successfully
338             stopped();
339         }
340         else {
341             // ??? failed to stop! Let's log it as warning:
342             if (did_exit) {
343                 log(loglevel_t::WARN, "Service ", get_name(), " stop command failed with exit code ",
344                         exit_status.get_exit_status());
345             }
346             else if (was_signalled) {
347                 log(loglevel_t::WARN, "Service ", get_name(), " stop command terminated due to signal ",
348                         exit_status.get_term_sig());
349             }
350             // Even if the stop script failed, assume that service is now stopped, so that any dependencies
351             // can be stopped. There's not really any other useful course of action here.
352             stopped();
353         }
354         services->process_queues();
355     }
356     else { // STARTING
357         if (exit_status.did_exit_clean()) {
358             started();
359         }
360         else if (was_signalled && exit_status.get_term_sig() == SIGINT && onstart_flags.skippable) {
361             // A skippable service can be skipped by interrupting (eg by ^C if the service
362             // starts on the console).
363             start_skipped = true;
364             started();
365         }
366         else {
367             // failed to start
368             if (did_exit) {
369                 log(loglevel_t::ERROR, "Service ", get_name(), " command failed with exit code ",
370                         exit_status.get_exit_status());
371             }
372             else if (was_signalled) {
373                 log(loglevel_t::ERROR, "Service ", get_name(), " command terminated due to signal ",
374                         exit_status.get_term_sig());
375             }
376             stop_reason = stopped_reason_t::FAILED;
377             failed_to_start();
378         }
379         services->process_queues();
380     }
381 }
382
383 void scripted_service::exec_failed(int errcode) noexcept
384 {
385     log(loglevel_t::ERROR, get_name(), ": execution failed: ", strerror(errcode));
386     auto service_state = get_state();
387     if (service_state == service_state_t::STARTING) {
388         stop_reason = stopped_reason_t::EXECFAILED;
389         failed_to_start();
390     }
391     else if (service_state == service_state_t::STOPPING) {
392         // We've logged the failure, but it's probably better not to leave the service in
393         // STOPPING state:
394         stopped();
395     }
396 }
397
398 bgproc_service::pid_result_t
399 bgproc_service::read_pid_file(bp_sys::exit_status *exit_status) noexcept
400 {
401     const char *pid_file_c = pid_file.c_str();
402     int fd = open(pid_file_c, O_CLOEXEC);
403     if (fd == -1) {
404         log(loglevel_t::ERROR, get_name(), ": read pid file: ", strerror(errno));
405         return pid_result_t::FAILED;
406     }
407
408     char pidbuf[21]; // just enough to hold any 64-bit integer
409     int r = ss_read(fd, pidbuf, 20);
410     if (r < 0) {
411         // Could not read from PID file
412         log(loglevel_t::ERROR, get_name(), ": could not read from pidfile; ", strerror(errno));
413         close(fd);
414         return pid_result_t::FAILED;
415     }
416
417     close(fd);
418     pidbuf[r] = 0; // store nul terminator
419
420     bool valid_pid = false;
421     try {
422         unsigned long long v = std::stoull(pidbuf, nullptr, 0);
423         if (v <= std::numeric_limits<pid_t>::max()) {
424             pid = (pid_t) v;
425             valid_pid = true;
426         }
427     }
428     catch (std::out_of_range &exc) {
429         // Too large?
430     }
431     catch (std::invalid_argument &exc) {
432         // Ok, so it doesn't look like a number: proceed...
433     }
434
435     if (valid_pid) {
436         pid_t wait_r = waitpid(pid, exit_status, WNOHANG);
437         if (wait_r == -1 && errno == ECHILD) {
438             // We can't track this child - check process exists:
439             if (kill(pid, 0) == 0 || errno != ESRCH) {
440                 tracking_child = false;
441                 return pid_result_t::OK;
442             }
443             else {
444                 log(loglevel_t::ERROR, get_name(), ": pid read from pidfile (", pid, ") is not valid");
445                 pid = -1;
446                 return pid_result_t::FAILED;
447             }
448         }
449         else if (wait_r == pid) {
450             pid = -1;
451             return pid_result_t::TERMINATED;
452         }
453         else if (wait_r == 0) {
454             // We can track the child
455             child_listener.add_reserved(event_loop, pid, dasynq::DEFAULT_PRIORITY - 10);
456             tracking_child = true;
457             reserved_child_watch = true;
458             return pid_result_t::OK;
459         }
460     }
461
462     log(loglevel_t::ERROR, get_name(), ": pid read from pidfile (", pid, ") is not valid");
463     pid = -1;
464     return pid_result_t::FAILED;
465 }
466
467 void process_service::bring_down() noexcept
468 {
469     if (waiting_for_execstat) {
470         // The process is still starting. This should be uncommon, but can occur during
471         // smooth recovery. We can't do much now; we have to wait until we get the
472         // status, and then act appropriately.
473         return;
474     }
475     else if (pid != -1) {
476         // The process is still kicking on - must actually kill it. We signal the process
477         // group (-pid) rather than just the process as there's less risk then of creating
478         // an orphaned process group:
479         if (! onstart_flags.no_sigterm) {
480             kill_pg(SIGTERM);
481         }
482         if (term_signal != -1) {
483             kill_pg(term_signal);
484         }
485
486         // If there's a stop timeout, arm the timer now:
487         if (stop_timeout != time_val(0,0)) {
488             restart_timer.arm_timer_rel(event_loop, stop_timeout);
489             stop_timer_armed = true;
490         }
491
492         // The rest is done in handle_exit_status.
493     }
494     else {
495         // The process is already dead.
496         stopped();
497     }
498 }
499
500 void bgproc_service::bring_down() noexcept
501 {
502     if (pid != -1) {
503         // The process is still kicking on - must actually kill it. We signal the process
504         // group (-pid) rather than just the process as there's less risk then of creating
505         // an orphaned process group:
506         if (! onstart_flags.no_sigterm) {
507             kill_pg(SIGTERM);
508         }
509         if (term_signal != -1) {
510             kill_pg(term_signal);
511         }
512
513         // In most cases, the rest is done in handle_exit_status.
514         // If we are a BGPROCESS and the process is not our immediate child, however, that
515         // won't work - check for this now:
516         if (! tracking_child) {
517             stopped();
518         }
519         else if (stop_timeout != time_val(0,0)) {
520             restart_timer.arm_timer_rel(event_loop, stop_timeout);
521             stop_timer_armed = true;
522         }
523     }
524     else {
525         // The process is already dead.
526         stopped();
527     }
528 }
529
530 void scripted_service::bring_down() noexcept
531 {
532         if (pid != -1) {
533                 // We're already running the stop script; nothing to do.
534                 return;
535         }
536
537     if (stop_command.length() == 0) {
538         stopped();
539     }
540     else if (! start_ps_process(stop_arg_parts, false)) {
541         // Couldn't execute stop script, but there's not much we can do:
542         stopped();
543     }
544     else {
545         // successfully started stop script: start kill timer:
546         if (stop_timeout != time_val(0,0)) {
547             restart_timer.arm_timer_rel(event_loop, stop_timeout);
548             stop_timer_armed = true;
549         }
550     }
551 }
552
553 dasynq::rearm process_restart_timer::timer_expiry(eventloop_t &, int expiry_count)
554 {
555     service->timer_expired();
556
557     // Leave the timer disabled, or, if it has been reset by any processing above, leave it armed:
558     return dasynq::rearm::NOOP;
559 }