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