handle_exit.c (2458B) download
1#include "service.h"
2
3#include <errno.h>
4#include <limits.h>
5#include <stdarg.h>
6#include <stdio.h>
7#include <string.h>
8#include <sys/stat.h>
9#include <unistd.h>
10
11
12static void do_finish(struct service* s) {
13 struct stat st;
14
15 if (fstatat(s->dir, "finish", &st, 0) != -1 && st.st_mode & S_IXUSR) {
16 if ((s->pid = fork_dup_cd_exec(s->dir, "./finish", null_fd, null_fd, null_fd)) == -1) {
17 fprint(1, "error: cannot execute ./finish: %r\n");
18 service_update_state(s, STATE_INACTIVE);
19 } else {
20 service_update_state(s, STATE_FINISHING);
21 }
22 } else if (s->fail_count == SV_FAIL_MAX) {
23 service_update_state(s, STATE_ERROR);
24 print("%s died\n", s->name);
25 } else {
26 service_update_state(s, s->restart == S_ONCE ? STATE_DONE : STATE_INACTIVE);
27 }
28}
29
30
31void service_handle_exit(struct service* s, bool signaled, int return_code) {
32 struct stat st;
33
34 s->pid = 0;
35 s->stop_timeout = 0;
36
37 if (s->restart == S_ONCE)
38 s->restart = S_DOWN;
39
40 switch (s->state) {
41 case STATE_SETUP:
42 service_run(s);
43 break;
44 case STATE_ACTIVE_FOREGROUND:
45 if (signaled) {
46 s->last_exit = EXIT_SIGNALED;
47 s->return_code = return_code;
48 s->fail_count++;
49
50 print("%s killed thought signal %d\n", s->name, s->return_code);
51 } else {
52 s->last_exit = EXIT_NORMAL;
53 s->return_code = return_code;
54 if (s->return_code > 0)
55 s->fail_count++;
56 else
57 s->fail_count = 0;
58
59 print("%s exited with code %d\n", s->name, s->return_code);
60 }
61
62 do_finish(s);
63
64 break;
65 case STATE_ACTIVE_DUMMY:
66 case STATE_ACTIVE_BACKGROUND:
67 case STATE_STOPPING:
68 do_finish(s);
69 break;
70
71 case STATE_FINISHING:
72 if (s->fail_count == SV_FAIL_MAX) {
73 service_update_state(s, STATE_ERROR);
74 print("%s died\n", s->name);
75 } else {
76 service_update_state(s, s->restart == S_ONCE ? STATE_DONE : STATE_INACTIVE);
77 }
78 break;
79 case STATE_STARTING:
80 if (!signaled && return_code == 0) {
81 if (fstatat(s->dir, "stop", &st, 0) != -1 && st.st_mode & S_IXUSR) {
82 service_update_state(s, STATE_ACTIVE_BACKGROUND);
83 } else {
84 do_finish(s);
85 }
86 } else if (!signaled) {
87 s->last_exit = EXIT_NORMAL;
88 s->return_code = return_code;
89
90 do_finish(s);
91 } else { // signaled
92 s->last_exit = EXIT_SIGNALED;
93 s->return_code = return_code;
94
95 do_finish(s);
96 }
97 break;
98
99 case STATE_ERROR:
100 case STATE_INACTIVE:
101 case STATE_DONE:
102 print("unexpected error: %s died but it's inactive\n", s->name);
103 }
104}