]>
Commit | Line | Data |
---|---|---|
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 | 13 | const 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 | ||
103 | const 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 |
109 | const 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 |
126 | int 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 | 141 | bool 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 |
157 | void 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 | 164 | bool 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 |
171 | bool 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 | } |