Move some data/functions from service_record to base_process_service.
[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 rearm exec_status_pipe_watcher::fd_event(eventloop_t &loop, int fd, int flags) noexcept
59 {
60     base_process_service *sr = service;
61     sr->waiting_for_execstat = false;
62
63     int exec_status;
64     int r = read(get_watched_fd(), &exec_status, sizeof(int));
65     deregister(loop);
66     close(get_watched_fd());
67
68     if (r > 0) {
69         // We read an errno code; exec() failed, and the service startup failed.
70         if (sr->pid != -1) {
71             sr->child_listener.deregister(event_loop, sr->pid);
72             sr->reserved_child_watch = false;
73             if (sr->stop_timer_armed) {
74                 sr->restart_timer.stop_timer(loop);
75                 sr->stop_timer_armed = false;
76             }
77         }
78         sr->pid = -1;
79         sr->exec_failed(exec_status);
80     }
81     else {
82         sr->exec_succeeded();
83
84         if (sr->pid == -1) {
85             // Somehow the process managed to complete before we even saw the exec() status.
86             sr->handle_exit_status(sr->exit_status);
87         }
88     }
89
90     sr->services->process_queues();
91
92     return rearm::REMOVED;
93 }
94
95 dasynq::rearm service_child_watcher::status_change(eventloop_t &loop, pid_t child, int status) noexcept
96 {
97     base_process_service *sr = service;
98
99     sr->pid = -1;
100     sr->exit_status = status;
101
102     // Ok, for a process service, any process death which we didn't rig
103     // ourselves is a bit... unexpected. Probably, the child died because
104     // we asked it to (sr->service_state == STOPPING). But even if
105     // we didn't, there's not much we can do.
106
107     if (sr->waiting_for_execstat) {
108         // We still don't have an exec() status from the forked child, wait for that
109         // before doing any further processing.
110         return dasynq::rearm::NOOP; // hold watch reservation
111     }
112
113     // Must stop watch now since handle_exit_status might result in re-launch:
114     // (stop_watch instead of deregister, so that we hold watch reservation).
115     stop_watch(loop);
116
117     if (sr->stop_timer_armed) {
118         sr->restart_timer.stop_timer(loop);
119         sr->stop_timer_armed = false;
120     }
121
122     sr->handle_exit_status(status);
123     return dasynq::rearm::NOOP;
124 }
125
126 void process_service::handle_exit_status(int exit_status) noexcept
127 {
128     bool did_exit = WIFEXITED(exit_status);
129     bool was_signalled = WIFSIGNALED(exit_status);
130     restarting = false;
131     auto service_state = get_state();
132
133     if (exit_status != 0 && service_state != service_state_t::STOPPING) {
134         if (did_exit) {
135             log(loglevel_t::ERROR, "Service ", get_name(), " process terminated with exit code ",
136                     WEXITSTATUS(exit_status));
137         }
138         else if (was_signalled) {
139             log(loglevel_t::ERROR, "Service ", get_name(), " terminated due to signal ",
140                     WTERMSIG(exit_status));
141         }
142     }
143
144     if (service_state == service_state_t::STARTING) {
145         if (did_exit && WEXITSTATUS(exit_status) == 0) {
146             started();
147         }
148         else {
149             failed_to_start();
150         }
151     }
152     else if (service_state == service_state_t::STOPPING) {
153         // We won't log a non-zero exit status or termination due to signal here -
154         // we assume that the process died because we signalled it.
155         stopped();
156     }
157     else if (smooth_recovery && service_state == service_state_t::STARTED
158             && get_target_state() == service_state_t::STARTED) {
159         do_smooth_recovery();
160         return;
161     }
162     else {
163         emergency_stop();
164     }
165     services->process_queues();
166 }
167
168 void process_service::exec_failed(int errcode) noexcept
169 {
170     log(loglevel_t::ERROR, get_name(), ": execution failed: ", strerror(errcode));
171     if (get_state() == service_state_t::STARTING) {
172         failed_to_start();
173     }
174     else {
175         // Process service in smooth recovery:
176         emergency_stop();
177     }
178 }
179
180 void bgproc_service::handle_exit_status(int exit_status) noexcept
181 {
182     begin:
183     bool did_exit = WIFEXITED(exit_status);
184     bool was_signalled = WIFSIGNALED(exit_status);
185     auto service_state = get_state();
186
187     if (exit_status != 0 && service_state != service_state_t::STOPPING) {
188         if (did_exit) {
189             log(loglevel_t::ERROR, "Service ", get_name(), " process terminated with exit code ",
190                     WEXITSTATUS(exit_status));
191         }
192         else if (was_signalled) {
193             log(loglevel_t::ERROR, "Service ", get_name(), " terminated due to signal ",
194                     WTERMSIG(exit_status));
195         }
196     }
197
198     // This may be a "smooth recovery" where we are restarting the process while leaving the
199     // service in the STARTED state.
200     if (restarting && service_state == service_state_t::STARTED) {
201         restarting = false;
202         bool need_stop = false;
203         if ((did_exit && WEXITSTATUS(exit_status) != 0) || was_signalled) {
204             need_stop = true;
205         }
206         else {
207             // We need to re-read the PID, since it has now changed.
208             if (pid_file.length() != 0) {
209                 auto pid_result = read_pid_file(&exit_status);
210                 switch (pid_result) {
211                     case pid_result_t::FAILED:
212                         // Failed startup: no auto-restart.
213                         need_stop = true;
214                         break;
215                     case pid_result_t::TERMINATED:
216                         goto begin;
217                     case pid_result_t::OK:
218                         break;
219                 }
220             }
221         }
222
223         if (need_stop) {
224             // Failed startup: no auto-restart.
225             emergency_stop();
226             services->process_queues();
227         }
228
229         return;
230     }
231
232     restarting = false;
233     if (service_state == service_state_t::STARTING) {
234         // POSIX requires that if the process exited clearly with a status code of 0,
235         // the exit status value will be 0:
236         if (exit_status == 0) {
237             auto pid_result = read_pid_file(&exit_status);
238             switch (pid_result) {
239                 case pid_result_t::FAILED:
240                     // Failed startup: no auto-restart.
241                     failed_to_start();
242                     break;
243                 case pid_result_t::TERMINATED:
244                     // started, but immediately terminated
245                     started();
246                     goto begin;
247                 case pid_result_t::OK:
248                     started();
249                     break;
250             }
251         }
252         else {
253             failed_to_start();
254         }
255     }
256     else if (service_state == service_state_t::STOPPING) {
257         // We won't log a non-zero exit status or termination due to signal here -
258         // we assume that the process died because we signalled it.
259         stopped();
260     }
261     else {
262         // we must be STARTED
263         if (smooth_recovery && get_target_state() == service_state_t::STARTED) {
264             do_smooth_recovery();
265             return;
266         }
267         if (! do_auto_restart() && start_explicit) {
268             start_explicit = false;
269             release();
270         }
271         forced_stop();
272         stop_dependents();
273         stopped();
274     }
275     services->process_queues();
276 }
277
278 void bgproc_service::exec_failed(int errcode) noexcept
279 {
280     log(loglevel_t::ERROR, get_name(), ": execution failed: ", strerror(errcode));
281     // Only time we execute is for startup:
282     failed_to_start();
283 }
284
285 void scripted_service::handle_exit_status(int exit_status) noexcept
286 {
287     bool did_exit = WIFEXITED(exit_status);
288     bool was_signalled = WIFSIGNALED(exit_status);
289     auto service_state = get_state();
290
291     // For a scripted service, a termination occurs in one of three main cases:
292     // - the start script completed (or failed), when service was STARTING
293     // - the start script was interrupted to cancel startup; state is STOPPING
294     // - the stop script complete (or failed), state is STOPPING
295
296     if (service_state == service_state_t::STOPPING) {
297         // We might be running the stop script, or we might be running the start script and have issued
298         // a cancel order via SIGINT:
299         if (did_exit && WEXITSTATUS(exit_status) == 0) {
300             if (interrupting_start) {
301                 interrupting_start = false;
302                 // launch stop script:
303                 bring_down();
304             }
305             else {
306                 // We were running the stop script and finished successfully
307                 stopped();
308             }
309         }
310         else {
311             if (interrupting_start) {
312                 // We issued a start interrupt, so we expected this failure:
313                 if (did_exit) {
314                     log(loglevel_t::INFO, "Service ", get_name(), " start cancelled; exit code ",
315                             WEXITSTATUS(exit_status));
316                 }
317                 else if (was_signalled) {
318                     log(loglevel_t::INFO, "Service ", get_name(), " start cancelled from signal ",
319                             WTERMSIG(exit_status));
320                 }
321             }
322             else {
323                 // ??? failed to stop! Let's log it as warning:
324                 if (did_exit) {
325                     log(loglevel_t::WARN, "Service ", get_name(), " stop command failed with exit code ",
326                             WEXITSTATUS(exit_status));
327                 }
328                 else if (was_signalled) {
329                     log(loglevel_t::WARN, "Service ", get_name(), " stop command terminated due to signal ",
330                             WTERMSIG(exit_status));
331                 }
332             }
333             // Even if the stop script failed, assume that service is now stopped, so that any dependencies
334             // can be stopped. There's not really any other useful course of action here.
335             interrupting_start = false;
336             stopped();
337         }
338         services->process_queues();
339     }
340     else { // STARTING
341         if (exit_status == 0) {
342             started();
343         }
344         else {
345             // failed to start
346             if (did_exit) {
347                 log(loglevel_t::ERROR, "Service ", get_name(), " command failed with exit code ",
348                         WEXITSTATUS(exit_status));
349             }
350             else if (was_signalled) {
351                 log(loglevel_t::ERROR, "Service ", get_name(), " command terminated due to signal ",
352                         WTERMSIG(exit_status));
353             }
354             failed_to_start();
355         }
356         services->process_queues();
357     }
358 }
359
360 void scripted_service::exec_failed(int errcode) noexcept
361 {
362     log(loglevel_t::ERROR, get_name(), ": execution failed: ", strerror(errcode));
363     auto service_state = get_state();
364     if (service_state == service_state_t::STARTING) {
365         failed_to_start();
366     }
367     else if (service_state == service_state_t::STOPPING) {
368         // We've logged the failure, but it's probably better not to leave the service in
369         // STOPPING state:
370         stopped();
371     }
372 }
373
374 bgproc_service::pid_result_t
375 bgproc_service::read_pid_file(int *exit_status) noexcept
376 {
377     const char *pid_file_c = pid_file.c_str();
378     int fd = open(pid_file_c, O_CLOEXEC);
379     if (fd == -1) {
380         log(loglevel_t::ERROR, get_name(), ": read pid file: ", strerror(errno));
381         return pid_result_t::FAILED;
382     }
383
384     char pidbuf[21]; // just enough to hold any 64-bit integer
385     int r = ss_read(fd, pidbuf, 20);
386     if (r < 0) {
387         // Could not read from PID file
388         log(loglevel_t::ERROR, get_name(), ": could not read from pidfile; ", strerror(errno));
389         close(fd);
390         return pid_result_t::FAILED;
391     }
392
393     close(fd);
394     pidbuf[r] = 0; // store nul terminator
395
396     bool valid_pid = false;
397     try {
398         unsigned long long v = std::stoull(pidbuf, nullptr, 0);
399         if (v <= std::numeric_limits<pid_t>::max()) {
400             pid = (pid_t) v;
401             valid_pid = true;
402         }
403     }
404     catch (std::out_of_range &exc) {
405         // Too large?
406     }
407     catch (std::invalid_argument &exc) {
408         // Ok, so it doesn't look like a number: proceed...
409     }
410
411     if (valid_pid) {
412         pid_t wait_r = waitpid(pid, exit_status, WNOHANG);
413         if (wait_r == -1 && errno == ECHILD) {
414             // We can't track this child - check process exists:
415             if (kill(pid, 0) == 0 || errno != ESRCH) {
416                 tracking_child = false;
417                 return pid_result_t::OK;
418             }
419             else {
420                 log(loglevel_t::ERROR, get_name(), ": pid read from pidfile (", pid, ") is not valid");
421                 pid = -1;
422                 return pid_result_t::FAILED;
423             }
424         }
425         else if (wait_r == pid) {
426             pid = -1;
427             return pid_result_t::TERMINATED;
428         }
429         else if (wait_r == 0) {
430             // We can track the child
431             child_listener.add_reserved(event_loop, pid, dasynq::DEFAULT_PRIORITY - 10);
432             tracking_child = true;
433             reserved_child_watch = true;
434             return pid_result_t::OK;
435         }
436     }
437
438     log(loglevel_t::ERROR, get_name(), ": pid read from pidfile (", pid, ") is not valid");
439     pid = -1;
440     return pid_result_t::FAILED;
441 }
442
443 void process_service::bring_down() noexcept
444 {
445     waiting_for_deps = false;
446     if (waiting_for_execstat) {
447         // The process is still starting. This should be uncommon, but can occur during
448         // smooth recovery. We can't do much now; we have to wait until we get the
449         // status, and then act appropriately.
450         return;
451     }
452     else if (pid != -1) {
453         // The process is still kicking on - must actually kill it. We signal the process
454         // group (-pid) rather than just the process as there's less risk then of creating
455         // an orphaned process group:
456         if (! onstart_flags.no_sigterm) {
457             kill_pg(SIGTERM);
458         }
459         if (term_signal != -1) {
460             kill_pg(term_signal);
461         }
462
463         // In most cases, the rest is done in handle_exit_status.
464         // If we are a BGPROCESS and the process is not our immediate child, however, that
465         // won't work - check for this now:
466         if (get_type() == service_type_t::BGPROCESS && ! tracking_child) {
467             stopped();
468         }
469         else if (stop_timeout != time_val(0,0)) {
470             restart_timer.arm_timer_rel(event_loop, stop_timeout);
471             stop_timer_armed = true;
472         }
473     }
474     else {
475         // The process is already dead.
476         stopped();
477     }
478 }
479
480 void scripted_service::bring_down() noexcept
481 {
482     waiting_for_deps = false;
483     if (stop_command.length() == 0) {
484         stopped();
485     }
486     else if (! start_ps_process(stop_arg_parts, false)) {
487         // Couldn't execute stop script, but there's not much we can do:
488         stopped();
489     }
490     else {
491         // successfully started stop script: start kill timer:
492         if (stop_timeout != time_val(0,0)) {
493             restart_timer.arm_timer_rel(event_loop, stop_timeout);
494             stop_timer_armed = true;
495         }
496     }
497 }
498
499 dasynq::rearm process_restart_timer::timer_expiry(eventloop_t &, int expiry_count)
500 {
501     service->timer_expired();
502
503     // Leave the timer disabled, or, if it has been reset by any processing above, leave it armed:
504     return dasynq::rearm::NOOP;
505 }