]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/exit-status.c
pkgconfig: define variables relative to ${prefix}/${rootprefix}/${sysconfdir}
[thirdparty/systemd.git] / src / basic / exit-status.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <signal.h>
4 #include <stdlib.h>
5 #include <sysexits.h>
6
7 #include "exit-status.h"
8 #include "macro.h"
9 #include "set.h"
10
11 const char* exit_status_to_string(int status, ExitStatusLevel level) {
12
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 */
28
29 case EXIT_SUCCESS:
30 return "SUCCESS";
31
32 case EXIT_FAILURE:
33 return "FAILURE";
34 }
35
36 if (IN_SET(level, EXIT_STATUS_SYSTEMD, EXIT_STATUS_LSB, EXIT_STATUS_FULL)) {
37 switch (status) { /* Optionally we cover our own ones */
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
108 case EXIT_PAM:
109 return "PAM";
110
111 case EXIT_NETWORK:
112 return "NETWORK";
113
114 case EXIT_NAMESPACE:
115 return "NAMESPACE";
116
117 case EXIT_NO_NEW_PRIVILEGES:
118 return "NO_NEW_PRIVILEGES";
119
120 case EXIT_SECCOMP:
121 return "SECCOMP";
122
123 case EXIT_SELINUX_CONTEXT:
124 return "SELINUX_CONTEXT";
125
126 case EXIT_PERSONALITY:
127 return "PERSONALITY";
128
129 case EXIT_APPARMOR_PROFILE:
130 return "APPARMOR";
131
132 case EXIT_ADDRESS_FAMILIES:
133 return "ADDRESS_FAMILIES";
134
135 case EXIT_RUNTIME_DIRECTORY:
136 return "RUNTIME_DIRECTORY";
137
138 case EXIT_CHOWN:
139 return "CHOWN";
140
141 case EXIT_SMACK_PROCESS_LABEL:
142 return "SMACK_PROCESS_LABEL";
143
144 case EXIT_KEYRING:
145 return "KEYRING";
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";
158 }
159 }
160
161 if (IN_SET(level, EXIT_STATUS_LSB, EXIT_STATUS_FULL)) {
162 switch (status) { /* Optionally we support LSB ones */
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:
174 return "NOTINSTALLED";
175
176 case EXIT_NOTCONFIGURED:
177 return "NOTCONFIGURED";
178
179 case EXIT_NOTRUNNING:
180 return "NOTRUNNING";
181 }
182 }
183
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
234 return NULL;
235 }
236
237 bool is_clean_exit(int code, int status, ExitClean clean, ExitStatusSet *success_status) {
238
239 if (code == CLD_EXITED)
240 return status == 0 ||
241 (success_status &&
242 set_contains(success_status->status, INT_TO_PTR(status)));
243
244 /* If a daemon does not implement handlers for some of the signals that's not considered an unclean shutdown */
245 if (code == CLD_KILLED)
246 return
247 (clean == EXIT_CLEAN_DAEMON && IN_SET(status, SIGHUP, SIGINT, SIGTERM, SIGPIPE)) ||
248 (success_status &&
249 set_contains(success_status->signal, INT_TO_PTR(status)));
250
251 return false;
252 }
253
254 void exit_status_set_free(ExitStatusSet *x) {
255 assert(x);
256
257 x->status = set_free(x->status);
258 x->signal = set_free(x->signal);
259 }
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 }
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 }