Merge pull request #13207 from keszybz/symbolic-exit-code-names
Symbolic exit code names
This commit is contained in:
+5
-12
@@ -12,12 +12,6 @@
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
|
||||
struct Bitmap {
|
||||
uint64_t *bitmaps;
|
||||
size_t n_bitmaps;
|
||||
size_t bitmaps_allocated;
|
||||
};
|
||||
|
||||
/* Bitmaps are only meant to store relatively small numbers
|
||||
* (corresponding to, say, an enum), so it is ok to limit
|
||||
* the max entry. 64k should be plenty. */
|
||||
@@ -117,7 +111,7 @@ void bitmap_unset(Bitmap *b, unsigned n) {
|
||||
b->bitmaps[offset] &= ~bitmask;
|
||||
}
|
||||
|
||||
bool bitmap_isset(Bitmap *b, unsigned n) {
|
||||
bool bitmap_isset(const Bitmap *b, unsigned n) {
|
||||
uint64_t bitmask;
|
||||
unsigned offset;
|
||||
|
||||
@@ -134,7 +128,7 @@ bool bitmap_isset(Bitmap *b, unsigned n) {
|
||||
return !!(b->bitmaps[offset] & bitmask);
|
||||
}
|
||||
|
||||
bool bitmap_isclear(Bitmap *b) {
|
||||
bool bitmap_isclear(const Bitmap *b) {
|
||||
unsigned i;
|
||||
|
||||
if (!b)
|
||||
@@ -148,7 +142,6 @@ bool bitmap_isclear(Bitmap *b) {
|
||||
}
|
||||
|
||||
void bitmap_clear(Bitmap *b) {
|
||||
|
||||
if (!b)
|
||||
return;
|
||||
|
||||
@@ -157,7 +150,7 @@ void bitmap_clear(Bitmap *b) {
|
||||
b->bitmaps_allocated = 0;
|
||||
}
|
||||
|
||||
bool bitmap_iterate(Bitmap *b, Iterator *i, unsigned *n) {
|
||||
bool bitmap_iterate(const Bitmap *b, Iterator *i, unsigned *n) {
|
||||
uint64_t bitmask;
|
||||
unsigned offset, rem;
|
||||
|
||||
@@ -192,9 +185,9 @@ bool bitmap_iterate(Bitmap *b, Iterator *i, unsigned *n) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bitmap_equal(Bitmap *a, Bitmap *b) {
|
||||
bool bitmap_equal(const Bitmap *a, const Bitmap *b) {
|
||||
size_t common_n_bitmaps;
|
||||
Bitmap *c;
|
||||
const Bitmap *c;
|
||||
unsigned i;
|
||||
|
||||
if (a == b)
|
||||
|
||||
+9
-5
@@ -6,7 +6,11 @@
|
||||
#include "hashmap.h"
|
||||
#include "macro.h"
|
||||
|
||||
typedef struct Bitmap Bitmap;
|
||||
typedef struct Bitmap {
|
||||
uint64_t *bitmaps;
|
||||
size_t n_bitmaps;
|
||||
size_t bitmaps_allocated;
|
||||
} Bitmap;
|
||||
|
||||
Bitmap *bitmap_new(void);
|
||||
Bitmap *bitmap_copy(Bitmap *b);
|
||||
@@ -15,13 +19,13 @@ void bitmap_free(Bitmap *b);
|
||||
|
||||
int bitmap_set(Bitmap *b, unsigned n);
|
||||
void bitmap_unset(Bitmap *b, unsigned n);
|
||||
bool bitmap_isset(Bitmap *b, unsigned n);
|
||||
bool bitmap_isclear(Bitmap *b);
|
||||
bool bitmap_isset(const Bitmap *b, unsigned n);
|
||||
bool bitmap_isclear(const Bitmap *b);
|
||||
void bitmap_clear(Bitmap *b);
|
||||
|
||||
bool bitmap_iterate(Bitmap *b, Iterator *i, unsigned *n);
|
||||
bool bitmap_iterate(const Bitmap *b, Iterator *i, unsigned *n);
|
||||
|
||||
bool bitmap_equal(Bitmap *a, Bitmap *b);
|
||||
bool bitmap_equal(const Bitmap *a, const Bitmap *b);
|
||||
|
||||
#define BITMAP_FOREACH(n, b, i) \
|
||||
for ((i).idx = 0; bitmap_iterate((b), &(i), (unsigned*)&(n)); )
|
||||
|
||||
+23
-17
@@ -10,6 +10,7 @@
|
||||
#include "cpu-set-util.h"
|
||||
#include "escape.h"
|
||||
#include "exec-util.h"
|
||||
#include "exit-status.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "hostname-util.h"
|
||||
#include "in-addr-util.h"
|
||||
@@ -1439,12 +1440,11 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con
|
||||
|
||||
if (STR_IN_SET(field, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
|
||||
_cleanup_free_ int *status = NULL, *signal = NULL;
|
||||
size_t sz_status = 0, sz_signal = 0;
|
||||
size_t n_status = 0, n_signal = 0;
|
||||
const char *p;
|
||||
|
||||
for (p = eq;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
int val;
|
||||
|
||||
r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
|
||||
if (r == 0)
|
||||
@@ -1454,24 +1454,30 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
|
||||
|
||||
r = safe_atoi(word, &val);
|
||||
if (r < 0) {
|
||||
val = signal_from_string(word);
|
||||
if (val < 0)
|
||||
return log_error_errno(r, "Invalid status or signal %s in %s: %m", word, field);
|
||||
/* We need to call exit_status_from_string() first, because we want
|
||||
* to parse numbers as exit statuses, not signals. */
|
||||
|
||||
signal = reallocarray(signal, sz_signal + 1, sizeof(int));
|
||||
if (!signal)
|
||||
return log_oom();
|
||||
r = exit_status_from_string(word);
|
||||
if (r >= 0) {
|
||||
assert(r >= 0 && r < 256);
|
||||
|
||||
signal[sz_signal++] = val;
|
||||
} else {
|
||||
status = reallocarray(status, sz_status + 1, sizeof(int));
|
||||
status = reallocarray(status, n_status + 1, sizeof(int));
|
||||
if (!status)
|
||||
return log_oom();
|
||||
|
||||
status[sz_status++] = val;
|
||||
}
|
||||
status[n_status++] = r;
|
||||
|
||||
} else if ((r = signal_from_string(word)) >= 0) {
|
||||
signal = reallocarray(signal, n_signal + 1, sizeof(int));
|
||||
if (!signal)
|
||||
return log_oom();
|
||||
|
||||
signal[n_signal++] = r;
|
||||
|
||||
} else
|
||||
/* original r from exit_status_to_string() */
|
||||
return log_error_errno(r, "Invalid status or signal %s in %s: %m",
|
||||
word, field);
|
||||
}
|
||||
|
||||
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
|
||||
@@ -1490,11 +1496,11 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append_array(m, 'i', status, sz_status);
|
||||
r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append_array(m, 'i', signal, sz_signal);
|
||||
r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
|
||||
@@ -1480,14 +1480,6 @@ int bus_property_get_ulong(
|
||||
}
|
||||
#endif
|
||||
|
||||
int bus_log_parse_error(int r) {
|
||||
return log_error_errno(r, "Failed to parse bus message: %m");
|
||||
}
|
||||
|
||||
int bus_log_create_error(int r) {
|
||||
return log_error_errno(r, "Failed to create bus message: %m");
|
||||
}
|
||||
|
||||
/**
|
||||
* bus_path_encode_unique() - encode unique object path
|
||||
* @b: bus connection or NULL
|
||||
|
||||
@@ -114,8 +114,11 @@ assert_cc(sizeof(pid_t) == sizeof(uint32_t));
|
||||
assert_cc(sizeof(mode_t) == sizeof(uint32_t));
|
||||
#define bus_property_get_mode ((sd_bus_property_get_t) NULL)
|
||||
|
||||
int bus_log_parse_error(int r);
|
||||
int bus_log_create_error(int r);
|
||||
#define bus_log_parse_error(r) \
|
||||
log_error_errno(r, "Failed to parse bus message: %m")
|
||||
|
||||
#define bus_log_create_error(r) \
|
||||
log_error_errno(r, "Failed to create bus message: %m")
|
||||
|
||||
#define BUS_DEFINE_PROPERTY_GET_GLOBAL(function, bus_type, val) \
|
||||
int function(sd_bus *bus, \
|
||||
|
||||
+120
-231
@@ -6,10 +6,11 @@
|
||||
|
||||
#include "exit-status.h"
|
||||
#include "macro.h"
|
||||
#include "parse-util.h"
|
||||
#include "set.h"
|
||||
#include "string-util.h"
|
||||
|
||||
const char* exit_status_to_string(int status, ExitStatusLevel level) {
|
||||
|
||||
const ExitStatusMapping exit_status_mappings[256] = {
|
||||
/* Exit status ranges:
|
||||
*
|
||||
* 0…1 │ ISO C, EXIT_SUCCESS + EXIT_FAILURE
|
||||
@@ -25,235 +26,127 @@ const char* exit_status_to_string(int status, ExitStatusLevel level) {
|
||||
* │ signal or such, and we follow that logic here.)
|
||||
*/
|
||||
|
||||
switch (status) { /* We always cover the ISO C ones */
|
||||
|
||||
case EXIT_SUCCESS:
|
||||
return "SUCCESS";
|
||||
|
||||
case EXIT_FAILURE:
|
||||
return "FAILURE";
|
||||
}
|
||||
|
||||
if (IN_SET(level, EXIT_STATUS_SYSTEMD, EXIT_STATUS_LSB, EXIT_STATUS_FULL)) {
|
||||
switch (status) { /* Optionally we cover our own ones */
|
||||
|
||||
case EXIT_CHDIR:
|
||||
return "CHDIR";
|
||||
|
||||
case EXIT_NICE:
|
||||
return "NICE";
|
||||
|
||||
case EXIT_FDS:
|
||||
return "FDS";
|
||||
|
||||
case EXIT_EXEC:
|
||||
return "EXEC";
|
||||
|
||||
case EXIT_MEMORY:
|
||||
return "MEMORY";
|
||||
|
||||
case EXIT_LIMITS:
|
||||
return "LIMITS";
|
||||
|
||||
case EXIT_OOM_ADJUST:
|
||||
return "OOM_ADJUST";
|
||||
|
||||
case EXIT_SIGNAL_MASK:
|
||||
return "SIGNAL_MASK";
|
||||
|
||||
case EXIT_STDIN:
|
||||
return "STDIN";
|
||||
|
||||
case EXIT_STDOUT:
|
||||
return "STDOUT";
|
||||
|
||||
case EXIT_CHROOT:
|
||||
return "CHROOT";
|
||||
|
||||
case EXIT_IOPRIO:
|
||||
return "IOPRIO";
|
||||
|
||||
case EXIT_TIMERSLACK:
|
||||
return "TIMERSLACK";
|
||||
|
||||
case EXIT_SECUREBITS:
|
||||
return "SECUREBITS";
|
||||
|
||||
case EXIT_SETSCHEDULER:
|
||||
return "SETSCHEDULER";
|
||||
|
||||
case EXIT_CPUAFFINITY:
|
||||
return "CPUAFFINITY";
|
||||
|
||||
case EXIT_GROUP:
|
||||
return "GROUP";
|
||||
|
||||
case EXIT_USER:
|
||||
return "USER";
|
||||
|
||||
case EXIT_CAPABILITIES:
|
||||
return "CAPABILITIES";
|
||||
|
||||
case EXIT_CGROUP:
|
||||
return "CGROUP";
|
||||
|
||||
case EXIT_SETSID:
|
||||
return "SETSID";
|
||||
|
||||
case EXIT_CONFIRM:
|
||||
return "CONFIRM";
|
||||
|
||||
case EXIT_STDERR:
|
||||
return "STDERR";
|
||||
|
||||
case EXIT_PAM:
|
||||
return "PAM";
|
||||
|
||||
case EXIT_NETWORK:
|
||||
return "NETWORK";
|
||||
|
||||
case EXIT_NAMESPACE:
|
||||
return "NAMESPACE";
|
||||
|
||||
case EXIT_NO_NEW_PRIVILEGES:
|
||||
return "NO_NEW_PRIVILEGES";
|
||||
|
||||
case EXIT_SECCOMP:
|
||||
return "SECCOMP";
|
||||
|
||||
case EXIT_SELINUX_CONTEXT:
|
||||
return "SELINUX_CONTEXT";
|
||||
|
||||
case EXIT_PERSONALITY:
|
||||
return "PERSONALITY";
|
||||
|
||||
case EXIT_APPARMOR_PROFILE:
|
||||
return "APPARMOR";
|
||||
|
||||
case EXIT_ADDRESS_FAMILIES:
|
||||
return "ADDRESS_FAMILIES";
|
||||
|
||||
case EXIT_RUNTIME_DIRECTORY:
|
||||
return "RUNTIME_DIRECTORY";
|
||||
|
||||
case EXIT_CHOWN:
|
||||
return "CHOWN";
|
||||
|
||||
case EXIT_SMACK_PROCESS_LABEL:
|
||||
return "SMACK_PROCESS_LABEL";
|
||||
|
||||
case EXIT_KEYRING:
|
||||
return "KEYRING";
|
||||
|
||||
case EXIT_STATE_DIRECTORY:
|
||||
return "STATE_DIRECTORY";
|
||||
|
||||
case EXIT_CACHE_DIRECTORY:
|
||||
return "CACHE_DIRECTORY";
|
||||
|
||||
case EXIT_LOGS_DIRECTORY:
|
||||
return "LOGS_DIRECTORY";
|
||||
|
||||
case EXIT_CONFIGURATION_DIRECTORY:
|
||||
return "CONFIGURATION_DIRECTORY";
|
||||
|
||||
case EXIT_NUMA_POLICY:
|
||||
return "NUMA_POLICY";
|
||||
|
||||
case EXIT_EXCEPTION:
|
||||
return "EXCEPTION";
|
||||
}
|
||||
}
|
||||
|
||||
if (IN_SET(level, EXIT_STATUS_LSB, EXIT_STATUS_FULL)) {
|
||||
switch (status) { /* Optionally we support LSB ones */
|
||||
|
||||
case EXIT_INVALIDARGUMENT:
|
||||
return "INVALIDARGUMENT";
|
||||
|
||||
case EXIT_NOTIMPLEMENTED:
|
||||
return "NOTIMPLEMENTED";
|
||||
|
||||
case EXIT_NOPERMISSION:
|
||||
return "NOPERMISSION";
|
||||
|
||||
case EXIT_NOTINSTALLED:
|
||||
return "NOTINSTALLED";
|
||||
|
||||
case EXIT_NOTCONFIGURED:
|
||||
return "NOTCONFIGURED";
|
||||
|
||||
case EXIT_NOTRUNNING:
|
||||
return "NOTRUNNING";
|
||||
}
|
||||
}
|
||||
|
||||
if (level == EXIT_STATUS_FULL) {
|
||||
switch (status) { /* Optionally, we support BSD exit statusses */
|
||||
|
||||
case EX_USAGE:
|
||||
return "USAGE";
|
||||
|
||||
case EX_DATAERR:
|
||||
return "DATAERR";
|
||||
|
||||
case EX_NOINPUT:
|
||||
return "NOINPUT";
|
||||
|
||||
case EX_NOUSER:
|
||||
return "NOUSER";
|
||||
|
||||
case EX_NOHOST:
|
||||
return "NOHOST";
|
||||
|
||||
case EX_UNAVAILABLE:
|
||||
return "UNAVAILABLE";
|
||||
|
||||
case EX_SOFTWARE:
|
||||
return "SOFTWARE";
|
||||
|
||||
case EX_OSERR:
|
||||
return "OSERR";
|
||||
|
||||
case EX_OSFILE:
|
||||
return "OSFILE";
|
||||
|
||||
case EX_CANTCREAT:
|
||||
return "CANTCREAT";
|
||||
|
||||
case EX_IOERR:
|
||||
return "IOERR";
|
||||
|
||||
case EX_TEMPFAIL:
|
||||
return "TEMPFAIL";
|
||||
|
||||
case EX_PROTOCOL:
|
||||
return "PROTOCOL";
|
||||
|
||||
case EX_NOPERM:
|
||||
return "NOPERM";
|
||||
|
||||
case EX_CONFIG:
|
||||
return "CONFIG";
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
[EXIT_SUCCESS] = { "SUCCESS", EXIT_STATUS_GLIBC },
|
||||
[EXIT_FAILURE] = { "FAILURE", EXIT_STATUS_GLIBC },
|
||||
|
||||
[EXIT_CHDIR] = { "CHDIR", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_NICE] = { "NICE", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_FDS] = { "FDS", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_EXEC] = { "EXEC", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_MEMORY] = { "MEMORY", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_LIMITS] = { "LIMITS", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_OOM_ADJUST] = { "OOM_ADJUST", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_SIGNAL_MASK] = { "SIGNAL_MASK", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_STDIN] = { "STDIN", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_STDOUT] = { "STDOUT", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_CHROOT] = { "CHROOT", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_IOPRIO] = { "IOPRIO", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_TIMERSLACK] = { "TIMERSLACK", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_SECUREBITS] = { "SECUREBITS", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_SETSCHEDULER] = { "SETSCHEDULER", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_CPUAFFINITY] = { "CPUAFFINITY", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_GROUP] = { "GROUP", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_USER] = { "USER", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_CAPABILITIES] = { "CAPABILITIES", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_CGROUP] = { "CGROUP", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_SETSID] = { "SETSID", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_CONFIRM] = { "CONFIRM", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_STDERR] = { "STDERR", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_PAM] = { "PAM", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_NETWORK] = { "NETWORK", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_NAMESPACE] = { "NAMESPACE", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_NO_NEW_PRIVILEGES] = { "NO_NEW_PRIVILEGES", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_SECCOMP] = { "SECCOMP", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_SELINUX_CONTEXT] = { "SELINUX_CONTEXT", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_PERSONALITY] = { "PERSONALITY", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_APPARMOR_PROFILE] = { "APPARMOR", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_ADDRESS_FAMILIES] = { "ADDRESS_FAMILIES", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_RUNTIME_DIRECTORY] = { "RUNTIME_DIRECTORY", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_CHOWN] = { "CHOWN", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_SMACK_PROCESS_LABEL] = { "SMACK_PROCESS_LABEL", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_KEYRING] = { "KEYRING", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_STATE_DIRECTORY] = { "STATE_DIRECTORY", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_CACHE_DIRECTORY] = { "CACHE_DIRECTORY", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_LOGS_DIRECTORY] = { "LOGS_DIRECTORY", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_CONFIGURATION_DIRECTORY] = { "CONFIGURATION_DIRECTORY", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_NUMA_POLICY] = { "NUMA_POLICY", EXIT_STATUS_SYSTEMD },
|
||||
[EXIT_EXCEPTION] = { "EXCEPTION", EXIT_STATUS_SYSTEMD },
|
||||
|
||||
[EXIT_INVALIDARGUMENT] = { "INVALIDARGUMENT", EXIT_STATUS_LSB },
|
||||
[EXIT_NOTIMPLEMENTED] = { "NOTIMPLEMENTED", EXIT_STATUS_LSB },
|
||||
[EXIT_NOPERMISSION] = { "NOPERMISSION", EXIT_STATUS_LSB },
|
||||
[EXIT_NOTINSTALLED] = { "NOTINSTALLED", EXIT_STATUS_LSB },
|
||||
[EXIT_NOTCONFIGURED] = { "NOTCONFIGURED", EXIT_STATUS_LSB },
|
||||
[EXIT_NOTRUNNING] = { "NOTRUNNING", EXIT_STATUS_LSB },
|
||||
|
||||
[EX_USAGE] = { "USAGE", EXIT_STATUS_BSD },
|
||||
[EX_DATAERR] = { "DATAERR", EXIT_STATUS_BSD },
|
||||
[EX_NOINPUT] = { "NOINPUT", EXIT_STATUS_BSD },
|
||||
[EX_NOUSER] = { "NOUSER", EXIT_STATUS_BSD },
|
||||
[EX_NOHOST] = { "NOHOST", EXIT_STATUS_BSD },
|
||||
[EX_UNAVAILABLE] = { "UNAVAILABLE", EXIT_STATUS_BSD },
|
||||
[EX_SOFTWARE] = { "SOFTWARE", EXIT_STATUS_BSD },
|
||||
[EX_OSERR] = { "OSERR", EXIT_STATUS_BSD },
|
||||
[EX_OSFILE] = { "OSFILE", EXIT_STATUS_BSD },
|
||||
[EX_CANTCREAT] = { "CANTCREAT", EXIT_STATUS_BSD },
|
||||
[EX_IOERR] = { "IOERR", EXIT_STATUS_BSD },
|
||||
[EX_TEMPFAIL] = { "TEMPFAIL", EXIT_STATUS_BSD },
|
||||
[EX_PROTOCOL] = { "PROTOCOL", EXIT_STATUS_BSD },
|
||||
[EX_NOPERM] = { "NOPERM", EXIT_STATUS_BSD },
|
||||
[EX_CONFIG] = { "CONFIG", EXIT_STATUS_BSD },
|
||||
};
|
||||
|
||||
const char* exit_status_to_string(int code, ExitStatusClass class) {
|
||||
if (code < 0 || (size_t) code >= ELEMENTSOF(exit_status_mappings))
|
||||
return NULL;
|
||||
return FLAGS_SET(exit_status_mappings[code].class, class) ? exit_status_mappings[code].name : NULL;
|
||||
}
|
||||
|
||||
bool is_clean_exit(int code, int status, ExitClean clean, ExitStatusSet *success_status) {
|
||||
const char* exit_status_class(int code) {
|
||||
if (code < 0 || (size_t) code >= ELEMENTSOF(exit_status_mappings))
|
||||
return NULL;
|
||||
|
||||
switch (exit_status_mappings[code].class) {
|
||||
case EXIT_STATUS_GLIBC:
|
||||
return "glibc";
|
||||
case EXIT_STATUS_SYSTEMD:
|
||||
return "systemd";
|
||||
case EXIT_STATUS_LSB:
|
||||
return "LSB";
|
||||
case EXIT_STATUS_BSD:
|
||||
return "BSD";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int exit_status_from_string(const char *s) {
|
||||
uint8_t val;
|
||||
int r;
|
||||
|
||||
for (size_t i = 0; i < ELEMENTSOF(exit_status_mappings); i++)
|
||||
if (streq_ptr(s, exit_status_mappings[i].name))
|
||||
return i;
|
||||
|
||||
r = safe_atou8(s, &val);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
bool is_clean_exit(int code, int status, ExitClean clean, const ExitStatusSet *success_status) {
|
||||
if (code == CLD_EXITED)
|
||||
return status == 0 ||
|
||||
(success_status &&
|
||||
set_contains(success_status->status, INT_TO_PTR(status)));
|
||||
bitmap_isset(&success_status->status, status));
|
||||
|
||||
/* If a daemon does not implement handlers for some of the signals that's not considered an unclean shutdown */
|
||||
/* If a daemon does not implement handlers for some of the signals, we do not consider this an
|
||||
unclean shutdown */
|
||||
if (code == CLD_KILLED)
|
||||
return
|
||||
(clean == EXIT_CLEAN_DAEMON && IN_SET(status, SIGHUP, SIGINT, SIGTERM, SIGPIPE)) ||
|
||||
(success_status &&
|
||||
set_contains(success_status->signal, INT_TO_PTR(status)));
|
||||
bitmap_isset(&success_status->signal, status));
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -261,26 +154,22 @@ bool is_clean_exit(int code, int status, ExitClean clean, ExitStatusSet *success
|
||||
void exit_status_set_free(ExitStatusSet *x) {
|
||||
assert(x);
|
||||
|
||||
x->status = set_free(x->status);
|
||||
x->signal = set_free(x->signal);
|
||||
bitmap_clear(&x->status);
|
||||
bitmap_clear(&x->signal);
|
||||
}
|
||||
|
||||
bool exit_status_set_is_empty(ExitStatusSet *x) {
|
||||
bool exit_status_set_is_empty(const ExitStatusSet *x) {
|
||||
if (!x)
|
||||
return true;
|
||||
|
||||
return set_isempty(x->status) && set_isempty(x->signal);
|
||||
return bitmap_isclear(&x->status) && bitmap_isclear(&x->signal);
|
||||
}
|
||||
|
||||
bool exit_status_set_test(ExitStatusSet *x, int code, int status) {
|
||||
|
||||
if (exit_status_set_is_empty(x))
|
||||
return false;
|
||||
|
||||
if (code == CLD_EXITED && set_contains(x->status, INT_TO_PTR(status)))
|
||||
bool exit_status_set_test(const ExitStatusSet *x, int code, int status) {
|
||||
if (code == CLD_EXITED && bitmap_isset(&x->status, status))
|
||||
return true;
|
||||
|
||||
if (IN_SET(code, CLD_KILLED, CLD_DUMPED) && set_contains(x->signal, INT_TO_PTR(status)))
|
||||
if (IN_SET(code, CLD_KILLED, CLD_DUMPED) && bitmap_isset(&x->signal, status))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
+27
-17
@@ -3,12 +3,12 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "bitmap.h"
|
||||
#include "hashmap.h"
|
||||
#include "macro.h"
|
||||
#include "set.h"
|
||||
|
||||
/* This defines pretty names for the LSB 'start' verb exit codes. Note that they shouldn't be confused with the LSB
|
||||
* 'status' verb exit codes which are defined very differently. For details see:
|
||||
/* This defines pretty names for the LSB 'start' verb exit codes. Note that they shouldn't be confused with
|
||||
* the LSB 'status' verb exit codes which are defined very differently. For details see:
|
||||
*
|
||||
* https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
|
||||
*/
|
||||
@@ -25,8 +25,8 @@ enum {
|
||||
|
||||
/* BSD's sysexits.h defines a couple EX_xyz exit codes in the range 64 … 78 */
|
||||
|
||||
/* The LSB suggests that error codes >= 200 are "reserved". We use them here under the assumption that they
|
||||
* hence are unused by init scripts. */
|
||||
/* The LSB suggests that error codes >= 200 are "reserved". We use them here under the assumption
|
||||
* that they hence are unused by init scripts. */
|
||||
EXIT_CHDIR = 200,
|
||||
EXIT_NICE,
|
||||
EXIT_FDS,
|
||||
@@ -74,27 +74,37 @@ enum {
|
||||
EXIT_EXCEPTION = 255, /* Whenever we want to propagate an abnormal/signal exit, in line with bash */
|
||||
};
|
||||
|
||||
typedef enum ExitStatusLevel {
|
||||
EXIT_STATUS_MINIMAL, /* only cover libc EXIT_STATUS/EXIT_FAILURE */
|
||||
EXIT_STATUS_SYSTEMD, /* cover libc and systemd's own exit codes */
|
||||
EXIT_STATUS_LSB, /* cover libc, systemd's own and LSB exit codes */
|
||||
EXIT_STATUS_FULL, /* cover libc, systemd's own, LSB and BSD (EX_xyz) exit codes */
|
||||
} ExitStatusLevel;
|
||||
typedef enum ExitStatusClass {
|
||||
EXIT_STATUS_GLIBC = 1 << 0, /* libc EXIT_STATUS/EXIT_FAILURE */
|
||||
EXIT_STATUS_SYSTEMD = 1 << 1, /* systemd's own exit codes */
|
||||
EXIT_STATUS_LSB = 1 << 2, /* LSB exit codes */
|
||||
EXIT_STATUS_BSD = 1 << 3, /* BSD (EX_xyz) exit codes */
|
||||
EXIT_STATUS_FULL = EXIT_STATUS_GLIBC | EXIT_STATUS_SYSTEMD | EXIT_STATUS_LSB | EXIT_STATUS_BSD,
|
||||
} ExitStatusClass;
|
||||
|
||||
typedef struct ExitStatusSet {
|
||||
Set *status;
|
||||
Set *signal;
|
||||
Bitmap status;
|
||||
Bitmap signal;
|
||||
} ExitStatusSet;
|
||||
|
||||
const char* exit_status_to_string(int status, ExitStatusLevel level) _const_;
|
||||
const char* exit_status_to_string(int code, ExitStatusClass class) _const_;
|
||||
const char* exit_status_class(int code) _const_;
|
||||
int exit_status_from_string(const char *s) _pure_;
|
||||
|
||||
typedef struct ExitStatusMapping {
|
||||
const char *name;
|
||||
ExitStatusClass class;
|
||||
} ExitStatusMapping;
|
||||
|
||||
extern const ExitStatusMapping exit_status_mappings[256];
|
||||
|
||||
typedef enum ExitClean {
|
||||
EXIT_CLEAN_DAEMON,
|
||||
EXIT_CLEAN_COMMAND,
|
||||
} ExitClean;
|
||||
|
||||
bool is_clean_exit(int code, int status, ExitClean clean, ExitStatusSet *success_status);
|
||||
bool is_clean_exit(int code, int status, ExitClean clean, const ExitStatusSet *success_status);
|
||||
|
||||
void exit_status_set_free(ExitStatusSet *x);
|
||||
bool exit_status_set_is_empty(ExitStatusSet *x);
|
||||
bool exit_status_set_test(ExitStatusSet *x, int code, int status);
|
||||
bool exit_status_set_is_empty(const ExitStatusSet *x);
|
||||
bool exit_status_set_test(const ExitStatusSet *x, int code, int status);
|
||||
|
||||
Reference in New Issue
Block a user