]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/exit-status.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / shared / 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 *
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.)
26 */
27
28 switch (status) { /* We always cover the ISO C ones */
29
30 case EXIT_SUCCESS:
31 return "SUCCESS";
32
33 case EXIT_FAILURE:
34 return "FAILURE";
35 }
36
37 if (IN_SET(level, EXIT_STATUS_SYSTEMD, EXIT_STATUS_LSB, EXIT_STATUS_FULL)) {
38 switch (status) { /* Optionally we cover our own ones */
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
109 case EXIT_PAM:
110 return "PAM";
111
112 case EXIT_NETWORK:
113 return "NETWORK";
114
115 case EXIT_NAMESPACE:
116 return "NAMESPACE";
117
118 case EXIT_NO_NEW_PRIVILEGES:
119 return "NO_NEW_PRIVILEGES";
120
121 case EXIT_SECCOMP:
122 return "SECCOMP";
123
124 case EXIT_SELINUX_CONTEXT:
125 return "SELINUX_CONTEXT";
126
127 case EXIT_PERSONALITY:
128 return "PERSONALITY";
129
130 case EXIT_APPARMOR_PROFILE:
131 return "APPARMOR";
132
133 case EXIT_ADDRESS_FAMILIES:
134 return "ADDRESS_FAMILIES";
135
136 case EXIT_RUNTIME_DIRECTORY:
137 return "RUNTIME_DIRECTORY";
138
139 case EXIT_CHOWN:
140 return "CHOWN";
141
142 case EXIT_SMACK_PROCESS_LABEL:
143 return "SMACK_PROCESS_LABEL";
144
145 case EXIT_KEYRING:
146 return "KEYRING";
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";
159
160 case EXIT_EXCEPTION:
161 return "EXCEPTION";
162 }
163 }
164
165 if (IN_SET(level, EXIT_STATUS_LSB, EXIT_STATUS_FULL)) {
166 switch (status) { /* Optionally we support LSB ones */
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:
178 return "NOTINSTALLED";
179
180 case EXIT_NOTCONFIGURED:
181 return "NOTCONFIGURED";
182
183 case EXIT_NOTRUNNING:
184 return "NOTRUNNING";
185 }
186 }
187
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
238 return NULL;
239 }
240
241 bool is_clean_exit(int code, int status, ExitClean clean, ExitStatusSet *success_status) {
242
243 if (code == CLD_EXITED)
244 return status == 0 ||
245 (success_status &&
246 set_contains(success_status->status, INT_TO_PTR(status)));
247
248 /* If a daemon does not implement handlers for some of the signals that's not considered an unclean shutdown */
249 if (code == CLD_KILLED)
250 return
251 (clean == EXIT_CLEAN_DAEMON && IN_SET(status, SIGHUP, SIGINT, SIGTERM, SIGPIPE)) ||
252 (success_status &&
253 set_contains(success_status->signal, INT_TO_PTR(status)));
254
255 return false;
256 }
257
258 void exit_status_set_free(ExitStatusSet *x) {
259 assert(x);
260
261 x->status = set_free(x->status);
262 x->signal = set_free(x->signal);
263 }
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 }
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 }