]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/exit-status.c
build(deps): bump pkg/debian from `f550017` to `50b20e2`
[thirdparty/systemd.git] / src / shared / exit-status.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
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"
f0d67dcd 9#include "parse-util.h"
cf0fbc49 10#include "set.h"
f0d67dcd 11#include "string-util.h"
1afbdcb0 12
e1714f02 13const ExitStatusMapping exit_status_mappings[256] = {
0a233ba1
LP
14 /* Exit status ranges:
15 *
16 * 0…1 │ ISO C, EXIT_SUCCESS + EXIT_FAILURE
17 * 2…7 │ LSB exit codes for init scripts
18 * 8…63 │ (Currently unmapped)
19 * 64…78 │ BSD defined exit codes
20 * 79…199 │ (Currently unmapped)
d13b60d8
ILG
21 * 200…244 │ systemd's private error codes (might be extended to 254 in future development)
22 * 245…254 │ (Currently unmapped, but see above)
3584d3ca
LP
23 *
24 * 255 │ EXIT_EXCEPTION (We use this to propagate exit-by-signal events. It's frequently used by others apps (like bash)
25 * │ to indicate exit reason that cannot really be expressed in a single exit status value — such as a propagated
26 * │ signal or such, and we follow that logic here.)
0a233ba1
LP
27 */
28
e04ed6db
LP
29 [EXIT_SUCCESS] = { "SUCCESS", EXIT_STATUS_LIBC },
30 [EXIT_FAILURE] = { "FAILURE", EXIT_STATUS_LIBC },
e1714f02
ZJS
31
32 [EXIT_CHDIR] = { "CHDIR", EXIT_STATUS_SYSTEMD },
33 [EXIT_NICE] = { "NICE", EXIT_STATUS_SYSTEMD },
34 [EXIT_FDS] = { "FDS", EXIT_STATUS_SYSTEMD },
35 [EXIT_EXEC] = { "EXEC", EXIT_STATUS_SYSTEMD },
36 [EXIT_MEMORY] = { "MEMORY", EXIT_STATUS_SYSTEMD },
37 [EXIT_LIMITS] = { "LIMITS", EXIT_STATUS_SYSTEMD },
38 [EXIT_OOM_ADJUST] = { "OOM_ADJUST", EXIT_STATUS_SYSTEMD },
39 [EXIT_SIGNAL_MASK] = { "SIGNAL_MASK", EXIT_STATUS_SYSTEMD },
40 [EXIT_STDIN] = { "STDIN", EXIT_STATUS_SYSTEMD },
41 [EXIT_STDOUT] = { "STDOUT", EXIT_STATUS_SYSTEMD },
42 [EXIT_CHROOT] = { "CHROOT", EXIT_STATUS_SYSTEMD },
43 [EXIT_IOPRIO] = { "IOPRIO", EXIT_STATUS_SYSTEMD },
44 [EXIT_TIMERSLACK] = { "TIMERSLACK", EXIT_STATUS_SYSTEMD },
45 [EXIT_SECUREBITS] = { "SECUREBITS", EXIT_STATUS_SYSTEMD },
46 [EXIT_SETSCHEDULER] = { "SETSCHEDULER", EXIT_STATUS_SYSTEMD },
47 [EXIT_CPUAFFINITY] = { "CPUAFFINITY", EXIT_STATUS_SYSTEMD },
48 [EXIT_GROUP] = { "GROUP", EXIT_STATUS_SYSTEMD },
49 [EXIT_USER] = { "USER", EXIT_STATUS_SYSTEMD },
50 [EXIT_CAPABILITIES] = { "CAPABILITIES", EXIT_STATUS_SYSTEMD },
51 [EXIT_CGROUP] = { "CGROUP", EXIT_STATUS_SYSTEMD },
52 [EXIT_SETSID] = { "SETSID", EXIT_STATUS_SYSTEMD },
53 [EXIT_CONFIRM] = { "CONFIRM", EXIT_STATUS_SYSTEMD },
54 [EXIT_STDERR] = { "STDERR", EXIT_STATUS_SYSTEMD },
55 [EXIT_PAM] = { "PAM", EXIT_STATUS_SYSTEMD },
56 [EXIT_NETWORK] = { "NETWORK", EXIT_STATUS_SYSTEMD },
57 [EXIT_NAMESPACE] = { "NAMESPACE", EXIT_STATUS_SYSTEMD },
58 [EXIT_NO_NEW_PRIVILEGES] = { "NO_NEW_PRIVILEGES", EXIT_STATUS_SYSTEMD },
59 [EXIT_SECCOMP] = { "SECCOMP", EXIT_STATUS_SYSTEMD },
60 [EXIT_SELINUX_CONTEXT] = { "SELINUX_CONTEXT", EXIT_STATUS_SYSTEMD },
61 [EXIT_PERSONALITY] = { "PERSONALITY", EXIT_STATUS_SYSTEMD },
62 [EXIT_APPARMOR_PROFILE] = { "APPARMOR", EXIT_STATUS_SYSTEMD },
63 [EXIT_ADDRESS_FAMILIES] = { "ADDRESS_FAMILIES", EXIT_STATUS_SYSTEMD },
64 [EXIT_RUNTIME_DIRECTORY] = { "RUNTIME_DIRECTORY", EXIT_STATUS_SYSTEMD },
65 [EXIT_CHOWN] = { "CHOWN", EXIT_STATUS_SYSTEMD },
66 [EXIT_SMACK_PROCESS_LABEL] = { "SMACK_PROCESS_LABEL", EXIT_STATUS_SYSTEMD },
67 [EXIT_KEYRING] = { "KEYRING", EXIT_STATUS_SYSTEMD },
68 [EXIT_STATE_DIRECTORY] = { "STATE_DIRECTORY", EXIT_STATUS_SYSTEMD },
69 [EXIT_CACHE_DIRECTORY] = { "CACHE_DIRECTORY", EXIT_STATUS_SYSTEMD },
70 [EXIT_LOGS_DIRECTORY] = { "LOGS_DIRECTORY", EXIT_STATUS_SYSTEMD },
71 [EXIT_CONFIGURATION_DIRECTORY] = { "CONFIGURATION_DIRECTORY", EXIT_STATUS_SYSTEMD },
72 [EXIT_NUMA_POLICY] = { "NUMA_POLICY", EXIT_STATUS_SYSTEMD },
bb0c0d6f 73 [EXIT_CREDENTIALS] = { "CREDENTIALS", EXIT_STATUS_SYSTEMD },
d13b60d8 74 [EXIT_BPF] = { "BPF", EXIT_STATUS_SYSTEMD },
85614c6e 75 [EXIT_KSM] = { "KSM", EXIT_STATUS_SYSTEMD },
bb0c0d6f 76
e1714f02
ZJS
77 [EXIT_EXCEPTION] = { "EXCEPTION", EXIT_STATUS_SYSTEMD },
78
79 [EXIT_INVALIDARGUMENT] = { "INVALIDARGUMENT", EXIT_STATUS_LSB },
80 [EXIT_NOTIMPLEMENTED] = { "NOTIMPLEMENTED", EXIT_STATUS_LSB },
81 [EXIT_NOPERMISSION] = { "NOPERMISSION", EXIT_STATUS_LSB },
82 [EXIT_NOTINSTALLED] = { "NOTINSTALLED", EXIT_STATUS_LSB },
83 [EXIT_NOTCONFIGURED] = { "NOTCONFIGURED", EXIT_STATUS_LSB },
84 [EXIT_NOTRUNNING] = { "NOTRUNNING", EXIT_STATUS_LSB },
85
86 [EX_USAGE] = { "USAGE", EXIT_STATUS_BSD },
87 [EX_DATAERR] = { "DATAERR", EXIT_STATUS_BSD },
88 [EX_NOINPUT] = { "NOINPUT", EXIT_STATUS_BSD },
89 [EX_NOUSER] = { "NOUSER", EXIT_STATUS_BSD },
90 [EX_NOHOST] = { "NOHOST", EXIT_STATUS_BSD },
91 [EX_UNAVAILABLE] = { "UNAVAILABLE", EXIT_STATUS_BSD },
92 [EX_SOFTWARE] = { "SOFTWARE", EXIT_STATUS_BSD },
93 [EX_OSERR] = { "OSERR", EXIT_STATUS_BSD },
94 [EX_OSFILE] = { "OSFILE", EXIT_STATUS_BSD },
95 [EX_CANTCREAT] = { "CANTCREAT", EXIT_STATUS_BSD },
96 [EX_IOERR] = { "IOERR", EXIT_STATUS_BSD },
97 [EX_TEMPFAIL] = { "TEMPFAIL", EXIT_STATUS_BSD },
98 [EX_PROTOCOL] = { "PROTOCOL", EXIT_STATUS_BSD },
99 [EX_NOPERM] = { "NOPERM", EXIT_STATUS_BSD },
100 [EX_CONFIG] = { "CONFIG", EXIT_STATUS_BSD },
101};
102
103const char* exit_status_to_string(int code, ExitStatusClass class) {
104 if (code < 0 || (size_t) code >= ELEMENTSOF(exit_status_mappings))
105 return NULL;
00d27e5d 106 return class & exit_status_mappings[code].class ? exit_status_mappings[code].name : NULL;
e1714f02 107}
0a233ba1 108
e1714f02
ZJS
109const char* exit_status_class(int code) {
110 if (code < 0 || (size_t) code >= ELEMENTSOF(exit_status_mappings))
111 return NULL;
112
113 switch (exit_status_mappings[code].class) {
e04ed6db
LP
114 case EXIT_STATUS_LIBC:
115 return "libc";
e1714f02
ZJS
116 case EXIT_STATUS_SYSTEMD:
117 return "systemd";
118 case EXIT_STATUS_LSB:
119 return "LSB";
120 case EXIT_STATUS_BSD:
121 return "BSD";
122 default: return NULL;
0a233ba1 123 }
1afbdcb0 124}
9a57c629 125
f0d67dcd
ZJS
126int exit_status_from_string(const char *s) {
127 uint8_t val;
128 int r;
129
130 for (size_t i = 0; i < ELEMENTSOF(exit_status_mappings); i++)
131 if (streq_ptr(s, exit_status_mappings[i].name))
132 return i;
133
134 r = safe_atou8(s, &val);
135 if (r < 0)
136 return r;
137
138 return val;
139}
140
23d5dd16 141bool is_clean_exit(int code, int status, ExitClean clean, const ExitStatusSet *success_status) {
9a57c629 142 if (code == CLD_EXITED)
96342de6
LN
143 return status == 0 ||
144 (success_status &&
23d5dd16 145 bitmap_isset(&success_status->status, status));
9a57c629 146
23d5dd16 147 /* If a daemon does not implement handlers for some of the signals, we do not consider this an
a8425c53 148 * unclean shutdown */
9a57c629 149 if (code == CLD_KILLED)
a8425c53
ZJS
150 return (clean == EXIT_CLEAN_DAEMON && IN_SET(status, SIGHUP, SIGINT, SIGTERM, SIGPIPE)) ||
151 (success_status &&
152 bitmap_isset(&success_status->signal, status));
9a57c629
LP
153
154 return false;
155}
156
37520c1b
LP
157void exit_status_set_free(ExitStatusSet *x) {
158 assert(x);
159
23d5dd16
ZJS
160 bitmap_clear(&x->status);
161 bitmap_clear(&x->signal);
37520c1b 162}
55ebf98c 163
23d5dd16 164bool exit_status_set_is_empty(const ExitStatusSet *x) {
55ebf98c
LP
165 if (!x)
166 return true;
167
23d5dd16 168 return bitmap_isclear(&x->status) && bitmap_isclear(&x->signal);
55ebf98c 169}
597466f4 170
23d5dd16
ZJS
171bool exit_status_set_test(const ExitStatusSet *x, int code, int status) {
172 if (code == CLD_EXITED && bitmap_isset(&x->status, status))
597466f4
LP
173 return true;
174
23d5dd16 175 if (IN_SET(code, CLD_KILLED, CLD_DUMPED) && bitmap_isset(&x->signal, status))
597466f4
LP
176 return true;
177
178 return false;
179}