]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
1afbdcb0 | 2 | |
c43516e0 | 3 | #include <signal.h> |
cf0fbc49 | 4 | #include <stdlib.h> |
0a233ba1 | 5 | #include <sysexits.h> |
1afbdcb0 LP |
6 | |
7 | #include "exit-status.h" | |
96342de6 | 8 | #include "macro.h" |
cf0fbc49 | 9 | #include "set.h" |
1afbdcb0 | 10 | |
65e3fd83 | 11 | const char* exit_status_to_string(int status, ExitStatusLevel level) { |
1afbdcb0 | 12 | |
0a233ba1 LP |
13 | /* Exit status ranges: |
14 | * | |
15 | * 0…1 │ ISO C, EXIT_SUCCESS + EXIT_FAILURE | |
16 | * 2…7 │ LSB exit codes for init scripts | |
17 | * 8…63 │ (Currently unmapped) | |
18 | * 64…78 │ BSD defined exit codes | |
19 | * 79…199 │ (Currently unmapped) | |
20 | * 200…241 │ systemd's private error codes (might be extended to 254 in future development) | |
21 | * 242…254 │ (Currently unmapped, but see above) | |
3584d3ca LP |
22 | * |
23 | * 255 │ EXIT_EXCEPTION (We use this to propagate exit-by-signal events. It's frequently used by others apps (like bash) | |
24 | * │ to indicate exit reason that cannot really be expressed in a single exit status value — such as a propagated | |
25 | * │ signal or such, and we follow that logic here.) | |
0a233ba1 LP |
26 | */ |
27 | ||
28 | switch (status) { /* We always cover the ISO C ones */ | |
1afbdcb0 LP |
29 | |
30 | case EXIT_SUCCESS: | |
31 | return "SUCCESS"; | |
32 | ||
33 | case EXIT_FAILURE: | |
34 | return "FAILURE"; | |
35 | } | |
36 | ||
0a233ba1 LP |
37 | if (IN_SET(level, EXIT_STATUS_SYSTEMD, EXIT_STATUS_LSB, EXIT_STATUS_FULL)) { |
38 | switch (status) { /* Optionally we cover our own ones */ | |
1afbdcb0 LP |
39 | |
40 | case EXIT_CHDIR: | |
41 | return "CHDIR"; | |
42 | ||
43 | case EXIT_NICE: | |
44 | return "NICE"; | |
45 | ||
46 | case EXIT_FDS: | |
47 | return "FDS"; | |
48 | ||
49 | case EXIT_EXEC: | |
50 | return "EXEC"; | |
51 | ||
52 | case EXIT_MEMORY: | |
53 | return "MEMORY"; | |
54 | ||
55 | case EXIT_LIMITS: | |
56 | return "LIMITS"; | |
57 | ||
58 | case EXIT_OOM_ADJUST: | |
59 | return "OOM_ADJUST"; | |
60 | ||
61 | case EXIT_SIGNAL_MASK: | |
62 | return "SIGNAL_MASK"; | |
63 | ||
64 | case EXIT_STDIN: | |
65 | return "STDIN"; | |
66 | ||
67 | case EXIT_STDOUT: | |
68 | return "STDOUT"; | |
69 | ||
70 | case EXIT_CHROOT: | |
71 | return "CHROOT"; | |
72 | ||
73 | case EXIT_IOPRIO: | |
74 | return "IOPRIO"; | |
75 | ||
76 | case EXIT_TIMERSLACK: | |
77 | return "TIMERSLACK"; | |
78 | ||
79 | case EXIT_SECUREBITS: | |
80 | return "SECUREBITS"; | |
81 | ||
82 | case EXIT_SETSCHEDULER: | |
83 | return "SETSCHEDULER"; | |
84 | ||
85 | case EXIT_CPUAFFINITY: | |
86 | return "CPUAFFINITY"; | |
87 | ||
88 | case EXIT_GROUP: | |
89 | return "GROUP"; | |
90 | ||
91 | case EXIT_USER: | |
92 | return "USER"; | |
93 | ||
94 | case EXIT_CAPABILITIES: | |
95 | return "CAPABILITIES"; | |
96 | ||
97 | case EXIT_CGROUP: | |
98 | return "CGROUP"; | |
99 | ||
100 | case EXIT_SETSID: | |
101 | return "SETSID"; | |
102 | ||
103 | case EXIT_CONFIRM: | |
104 | return "CONFIRM"; | |
105 | ||
106 | case EXIT_STDERR: | |
107 | return "STDERR"; | |
108 | ||
1afbdcb0 LP |
109 | case EXIT_PAM: |
110 | return "PAM"; | |
ff01d048 LP |
111 | |
112 | case EXIT_NETWORK: | |
113 | return "NETWORK"; | |
4c2630eb MS |
114 | |
115 | case EXIT_NAMESPACE: | |
116 | return "NAMESPACE"; | |
8351ceae LP |
117 | |
118 | case EXIT_NO_NEW_PRIVILEGES: | |
119 | return "NO_NEW_PRIVILEGES"; | |
120 | ||
121 | case EXIT_SECCOMP: | |
122 | return "SECCOMP"; | |
7b52a628 MS |
123 | |
124 | case EXIT_SELINUX_CONTEXT: | |
125 | return "SELINUX_CONTEXT"; | |
ac45f971 LP |
126 | |
127 | case EXIT_PERSONALITY: | |
128 | return "PERSONALITY"; | |
eef65bf3 MS |
129 | |
130 | case EXIT_APPARMOR_PROFILE: | |
131 | return "APPARMOR"; | |
4298d0b5 LP |
132 | |
133 | case EXIT_ADDRESS_FAMILIES: | |
134 | return "ADDRESS_FAMILIES"; | |
e66cf1a3 LP |
135 | |
136 | case EXIT_RUNTIME_DIRECTORY: | |
137 | return "RUNTIME_DIRECTORY"; | |
3900e5fd | 138 | |
56ecbcc0 LP |
139 | case EXIT_CHOWN: |
140 | return "CHOWN"; | |
141 | ||
94b573bd SY |
142 | case EXIT_SMACK_PROCESS_LABEL: |
143 | return "SMACK_PROCESS_LABEL"; | |
74dd6b51 LP |
144 | |
145 | case EXIT_KEYRING: | |
146 | return "KEYRING"; | |
3536f49e YW |
147 | |
148 | case EXIT_STATE_DIRECTORY: | |
149 | return "STATE_DIRECTORY"; | |
150 | ||
151 | case EXIT_CACHE_DIRECTORY: | |
152 | return "CACHE_DIRECTORY"; | |
153 | ||
154 | case EXIT_LOGS_DIRECTORY: | |
155 | return "LOGS_DIRECTORY"; | |
156 | ||
157 | case EXIT_CONFIGURATION_DIRECTORY: | |
158 | return "CONFIGURATION_DIRECTORY"; | |
3584d3ca LP |
159 | |
160 | case EXIT_EXCEPTION: | |
161 | return "EXCEPTION"; | |
1afbdcb0 LP |
162 | } |
163 | } | |
164 | ||
0a233ba1 LP |
165 | if (IN_SET(level, EXIT_STATUS_LSB, EXIT_STATUS_FULL)) { |
166 | switch (status) { /* Optionally we support LSB ones */ | |
1afbdcb0 LP |
167 | |
168 | case EXIT_INVALIDARGUMENT: | |
169 | return "INVALIDARGUMENT"; | |
170 | ||
171 | case EXIT_NOTIMPLEMENTED: | |
172 | return "NOTIMPLEMENTED"; | |
173 | ||
174 | case EXIT_NOPERMISSION: | |
175 | return "NOPERMISSION"; | |
176 | ||
177 | case EXIT_NOTINSTALLED: | |
9f8f87e3 | 178 | return "NOTINSTALLED"; |
1afbdcb0 LP |
179 | |
180 | case EXIT_NOTCONFIGURED: | |
181 | return "NOTCONFIGURED"; | |
182 | ||
183 | case EXIT_NOTRUNNING: | |
184 | return "NOTRUNNING"; | |
185 | } | |
186 | } | |
187 | ||
0a233ba1 LP |
188 | if (level == EXIT_STATUS_FULL) { |
189 | switch (status) { /* Optionally, we support BSD exit statusses */ | |
190 | ||
191 | case EX_USAGE: | |
192 | return "USAGE"; | |
193 | ||
194 | case EX_DATAERR: | |
195 | return "DATAERR"; | |
196 | ||
197 | case EX_NOINPUT: | |
198 | return "NOINPUT"; | |
199 | ||
200 | case EX_NOUSER: | |
201 | return "NOUSER"; | |
202 | ||
203 | case EX_NOHOST: | |
204 | return "NOHOST"; | |
205 | ||
206 | case EX_UNAVAILABLE: | |
207 | return "UNAVAILABLE"; | |
208 | ||
209 | case EX_SOFTWARE: | |
210 | return "SOFTWARE"; | |
211 | ||
212 | case EX_OSERR: | |
213 | return "OSERR"; | |
214 | ||
215 | case EX_OSFILE: | |
216 | return "OSFILE"; | |
217 | ||
218 | case EX_CANTCREAT: | |
219 | return "CANTCREAT"; | |
220 | ||
221 | case EX_IOERR: | |
222 | return "IOERR"; | |
223 | ||
224 | case EX_TEMPFAIL: | |
225 | return "TEMPFAIL"; | |
226 | ||
227 | case EX_PROTOCOL: | |
228 | return "PROTOCOL"; | |
229 | ||
230 | case EX_NOPERM: | |
231 | return "NOPERM"; | |
232 | ||
233 | case EX_CONFIG: | |
234 | return "CONFIG"; | |
235 | } | |
236 | } | |
237 | ||
1afbdcb0 LP |
238 | return NULL; |
239 | } | |
9a57c629 | 240 | |
1f0958f6 | 241 | bool is_clean_exit(int code, int status, ExitClean clean, ExitStatusSet *success_status) { |
9a57c629 LP |
242 | |
243 | if (code == CLD_EXITED) | |
96342de6 LN |
244 | return status == 0 || |
245 | (success_status && | |
6a2b82a7 | 246 | set_contains(success_status->status, INT_TO_PTR(status))); |
9a57c629 | 247 | |
1f0958f6 | 248 | /* If a daemon does not implement handlers for some of the signals that's not considered an unclean shutdown */ |
9a57c629 | 249 | if (code == CLD_KILLED) |
1f0958f6 LP |
250 | return |
251 | (clean == EXIT_CLEAN_DAEMON && IN_SET(status, SIGHUP, SIGINT, SIGTERM, SIGPIPE)) || | |
96342de6 | 252 | (success_status && |
5f94b4e6 | 253 | set_contains(success_status->signal, INT_TO_PTR(status))); |
9a57c629 LP |
254 | |
255 | return false; | |
256 | } | |
257 | ||
37520c1b LP |
258 | void exit_status_set_free(ExitStatusSet *x) { |
259 | assert(x); | |
260 | ||
5f94b4e6 LP |
261 | x->status = set_free(x->status); |
262 | x->signal = set_free(x->signal); | |
37520c1b | 263 | } |
55ebf98c LP |
264 | |
265 | bool exit_status_set_is_empty(ExitStatusSet *x) { | |
266 | if (!x) | |
267 | return true; | |
268 | ||
269 | return set_isempty(x->status) && set_isempty(x->signal); | |
270 | } | |
597466f4 LP |
271 | |
272 | bool exit_status_set_test(ExitStatusSet *x, int code, int status) { | |
273 | ||
274 | if (exit_status_set_is_empty(x)) | |
275 | return false; | |
276 | ||
277 | if (code == CLD_EXITED && set_contains(x->status, INT_TO_PTR(status))) | |
278 | return true; | |
279 | ||
280 | if (IN_SET(code, CLD_KILLED, CLD_DUMPED) && set_contains(x->signal, INT_TO_PTR(status))) | |
281 | return true; | |
282 | ||
283 | return false; | |
284 | } |