1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "exit-status.h"
9 #include "parse-util.h"
11 #include "string-util.h"
13 const ExitStatusMapping exit_status_mappings
[256] = {
14 /* Exit status ranges:
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)
21 * 200…244 │ systemd's private error codes (might be extended to 254 in future development)
22 * 245…254 │ (Currently unmapped, but see above)
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.)
29 [EXIT_SUCCESS
] = { "SUCCESS", EXIT_STATUS_LIBC
},
30 [EXIT_FAILURE
] = { "FAILURE", EXIT_STATUS_LIBC
},
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
},
73 [EXIT_CREDENTIALS
] = { "CREDENTIALS", EXIT_STATUS_SYSTEMD
},
74 [EXIT_BPF
] = { "BPF", EXIT_STATUS_SYSTEMD
},
75 [EXIT_KSM
] = { "KSM", EXIT_STATUS_SYSTEMD
},
77 [EXIT_EXCEPTION
] = { "EXCEPTION", EXIT_STATUS_SYSTEMD
},
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
},
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
},
103 const char* exit_status_to_string(int code
, ExitStatusClass
class) {
104 if (code
< 0 || (size_t) code
>= ELEMENTSOF(exit_status_mappings
))
106 return class & exit_status_mappings
[code
].class ? exit_status_mappings
[code
].name
: NULL
;
109 const char* exit_status_class(int code
) {
110 if (code
< 0 || (size_t) code
>= ELEMENTSOF(exit_status_mappings
))
113 switch (exit_status_mappings
[code
].class) {
114 case EXIT_STATUS_LIBC
:
116 case EXIT_STATUS_SYSTEMD
:
118 case EXIT_STATUS_LSB
:
120 case EXIT_STATUS_BSD
:
122 default: return NULL
;
126 int exit_status_from_string(const char *s
) {
130 for (size_t i
= 0; i
< ELEMENTSOF(exit_status_mappings
); i
++)
131 if (streq_ptr(s
, exit_status_mappings
[i
].name
))
134 r
= safe_atou8(s
, &val
);
141 bool is_clean_exit(int code
, int status
, ExitClean clean
, const ExitStatusSet
*success_status
) {
142 if (code
== CLD_EXITED
)
143 return status
== 0 ||
145 bitmap_isset(&success_status
->status
, status
));
147 /* If a daemon does not implement handlers for some of the signals, we do not consider this an
148 * unclean shutdown */
149 if (code
== CLD_KILLED
)
150 return (clean
== EXIT_CLEAN_DAEMON
&& IN_SET(status
, SIGHUP
, SIGINT
, SIGTERM
, SIGPIPE
)) ||
152 bitmap_isset(&success_status
->signal
, status
));
157 void exit_status_set_free(ExitStatusSet
*x
) {
160 bitmap_clear(&x
->status
);
161 bitmap_clear(&x
->signal
);
164 bool exit_status_set_is_empty(const ExitStatusSet
*x
) {
168 return bitmap_isclear(&x
->status
) && bitmap_isclear(&x
->signal
);
171 bool exit_status_set_test(const ExitStatusSet
*x
, int code
, int status
) {
172 if (code
== CLD_EXITED
&& bitmap_isset(&x
->status
, status
))
175 if (IN_SET(code
, CLD_KILLED
, CLD_DUMPED
) && bitmap_isset(&x
->signal
, status
))