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