mirror of
https://github.com/systemd/systemd.git
synced 2025-01-09 01:18:19 +03:00
Merge pull request #4337 from poettering/exit-code
Fix for #4275 and more
This commit is contained in:
commit
ec72b96366
2
TODO
2
TODO
@ -32,6 +32,8 @@ Janitorial Clean-ups:
|
||||
|
||||
Features:
|
||||
|
||||
* on cgroupsv2 add DelegateControllers=, to pick the precise cgroup controllers to delegate
|
||||
|
||||
* in networkd, when matching device types, fix up DEVTYPE rubbish the kernel passes to us
|
||||
|
||||
* enable LockMLOCK to take a percentage value relative to physical memory
|
||||
|
@ -24,12 +24,12 @@
|
||||
#include "macro.h"
|
||||
#include "set.h"
|
||||
|
||||
const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
|
||||
const char* exit_status_to_string(int status, ExitStatusLevel level) {
|
||||
|
||||
/* We cast to int here, so that -Wenum doesn't complain that
|
||||
* EXIT_SUCCESS/EXIT_FAILURE aren't in the enum */
|
||||
|
||||
switch ((int) status) {
|
||||
switch (status) {
|
||||
|
||||
case EXIT_SUCCESS:
|
||||
return "SUCCESS";
|
||||
@ -39,7 +39,7 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
|
||||
}
|
||||
|
||||
if (IN_SET(level, EXIT_STATUS_SYSTEMD, EXIT_STATUS_LSB)) {
|
||||
switch ((int) status) {
|
||||
switch (status) {
|
||||
|
||||
case EXIT_CHDIR:
|
||||
return "CHDIR";
|
||||
@ -140,19 +140,19 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
|
||||
case EXIT_RUNTIME_DIRECTORY:
|
||||
return "RUNTIME_DIRECTORY";
|
||||
|
||||
case EXIT_CHOWN:
|
||||
return "CHOWN";
|
||||
|
||||
case EXIT_MAKE_STARTER:
|
||||
return "MAKE_STARTER";
|
||||
|
||||
case EXIT_CHOWN:
|
||||
return "CHOWN";
|
||||
|
||||
case EXIT_SMACK_PROCESS_LABEL:
|
||||
return "SMACK_PROCESS_LABEL";
|
||||
}
|
||||
}
|
||||
|
||||
if (level == EXIT_STATUS_LSB) {
|
||||
switch ((int) status) {
|
||||
switch (status) {
|
||||
|
||||
case EXIT_INVALIDARGUMENT:
|
||||
return "INVALIDARGUMENT";
|
||||
@ -177,34 +177,23 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool is_clean_exit(int code, int status, ExitStatusSet *success_status) {
|
||||
bool is_clean_exit(int code, int status, ExitClean clean, ExitStatusSet *success_status) {
|
||||
|
||||
if (code == CLD_EXITED)
|
||||
return status == 0 ||
|
||||
(success_status &&
|
||||
set_contains(success_status->status, INT_TO_PTR(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 that's not considered an unclean shutdown */
|
||||
if (code == CLD_KILLED)
|
||||
return IN_SET(status, SIGHUP, SIGINT, SIGTERM, SIGPIPE) ||
|
||||
return
|
||||
(clean == EXIT_CLEAN_DAEMON && IN_SET(status, SIGHUP, SIGINT, SIGTERM, SIGPIPE)) ||
|
||||
(success_status &&
|
||||
set_contains(success_status->signal, INT_TO_PTR(status)));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status) {
|
||||
|
||||
if (is_clean_exit(code, status, success_status))
|
||||
return true;
|
||||
|
||||
return
|
||||
code == CLD_EXITED &&
|
||||
IN_SET(status, EXIT_NOTINSTALLED, EXIT_NOTCONFIGURED);
|
||||
}
|
||||
|
||||
void exit_status_set_free(ExitStatusSet *x) {
|
||||
assert(x);
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
* https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
|
||||
*/
|
||||
|
||||
typedef enum ExitStatus {
|
||||
enum {
|
||||
/* EXIT_SUCCESS defined by libc */
|
||||
/* EXIT_FAILURE defined by libc */
|
||||
EXIT_INVALIDARGUMENT = 2,
|
||||
@ -82,7 +82,7 @@ typedef enum ExitStatus {
|
||||
EXIT_MAKE_STARTER,
|
||||
EXIT_CHOWN,
|
||||
EXIT_SMACK_PROCESS_LABEL,
|
||||
} ExitStatus;
|
||||
};
|
||||
|
||||
typedef enum ExitStatusLevel {
|
||||
EXIT_STATUS_MINIMAL, /* only cover libc EXIT_STATUS/EXIT_FAILURE */
|
||||
@ -96,10 +96,14 @@ typedef struct ExitStatusSet {
|
||||
Set *signal;
|
||||
} ExitStatusSet;
|
||||
|
||||
const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) _const_;
|
||||
const char* exit_status_to_string(int status, ExitStatusLevel level) _const_;
|
||||
|
||||
bool is_clean_exit(int code, int status, ExitStatusSet *success_status);
|
||||
bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status);
|
||||
typedef enum ExitClean {
|
||||
EXIT_CLEAN_DAEMON,
|
||||
EXIT_CLEAN_COMMAND,
|
||||
} ExitClean;
|
||||
|
||||
bool is_clean_exit(int code, int status, ExitClean clean, ExitStatusSet *success_status);
|
||||
|
||||
void exit_status_set_free(ExitStatusSet *x);
|
||||
bool exit_status_set_is_empty(ExitStatusSet *x);
|
||||
|
@ -868,7 +868,7 @@ static void busname_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
|
||||
n->control_pid = 0;
|
||||
|
||||
if (is_clean_exit(code, status, NULL))
|
||||
if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
|
||||
f = BUSNAME_SUCCESS;
|
||||
else if (code == CLD_EXITED)
|
||||
f = BUSNAME_FAILURE_EXIT_CODE;
|
||||
|
@ -203,7 +203,7 @@ noreturn static void crash(int sig) {
|
||||
pid, sigchld_code_to_string(status.si_code),
|
||||
status.si_status,
|
||||
strna(status.si_code == CLD_EXITED
|
||||
? exit_status_to_string(status.si_status, EXIT_STATUS_FULL)
|
||||
? exit_status_to_string(status.si_status, EXIT_STATUS_MINIMAL)
|
||||
: signal_to_string(status.si_status)));
|
||||
else
|
||||
log_emergency("Caught <%s>, dumped core as pid "PID_FMT".", signal_to_string(sig), pid);
|
||||
|
@ -830,7 +830,7 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
|
||||
fail:
|
||||
log_unit_warning_errno(UNIT(m), r, "Failed to kill processes: %m");
|
||||
|
||||
if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
|
||||
if (IN_SET(state, MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL))
|
||||
mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
|
||||
else
|
||||
mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
|
||||
@ -986,18 +986,19 @@ static int mount_start(Unit *u) {
|
||||
|
||||
/* We cannot fulfill this request right now, try again later
|
||||
* please! */
|
||||
if (m->state == MOUNT_UNMOUNTING ||
|
||||
m->state == MOUNT_UNMOUNTING_SIGTERM ||
|
||||
m->state == MOUNT_UNMOUNTING_SIGKILL ||
|
||||
m->state == MOUNT_MOUNTING_SIGTERM ||
|
||||
m->state == MOUNT_MOUNTING_SIGKILL)
|
||||
if (IN_SET(m->state,
|
||||
MOUNT_UNMOUNTING,
|
||||
MOUNT_UNMOUNTING_SIGTERM,
|
||||
MOUNT_UNMOUNTING_SIGKILL,
|
||||
MOUNT_MOUNTING_SIGTERM,
|
||||
MOUNT_MOUNTING_SIGKILL))
|
||||
return -EAGAIN;
|
||||
|
||||
/* Already on it! */
|
||||
if (m->state == MOUNT_MOUNTING)
|
||||
return 0;
|
||||
|
||||
assert(m->state == MOUNT_DEAD || m->state == MOUNT_FAILED);
|
||||
assert(IN_SET(m->state, MOUNT_DEAD, MOUNT_FAILED));
|
||||
|
||||
r = unit_start_limit_test(u);
|
||||
if (r < 0) {
|
||||
@ -1019,19 +1020,21 @@ static int mount_stop(Unit *u) {
|
||||
assert(m);
|
||||
|
||||
/* Already on it */
|
||||
if (m->state == MOUNT_UNMOUNTING ||
|
||||
m->state == MOUNT_UNMOUNTING_SIGKILL ||
|
||||
m->state == MOUNT_UNMOUNTING_SIGTERM ||
|
||||
m->state == MOUNT_MOUNTING_SIGTERM ||
|
||||
m->state == MOUNT_MOUNTING_SIGKILL)
|
||||
if (IN_SET(m->state,
|
||||
MOUNT_UNMOUNTING,
|
||||
MOUNT_UNMOUNTING_SIGKILL,
|
||||
MOUNT_UNMOUNTING_SIGTERM,
|
||||
MOUNT_MOUNTING_SIGTERM,
|
||||
MOUNT_MOUNTING_SIGKILL))
|
||||
return 0;
|
||||
|
||||
assert(m->state == MOUNT_MOUNTING ||
|
||||
m->state == MOUNT_MOUNTING_DONE ||
|
||||
m->state == MOUNT_MOUNTED ||
|
||||
m->state == MOUNT_REMOUNTING ||
|
||||
m->state == MOUNT_REMOUNTING_SIGTERM ||
|
||||
m->state == MOUNT_REMOUNTING_SIGKILL);
|
||||
assert(IN_SET(m->state,
|
||||
MOUNT_MOUNTING,
|
||||
MOUNT_MOUNTING_DONE,
|
||||
MOUNT_MOUNTED,
|
||||
MOUNT_REMOUNTING,
|
||||
MOUNT_REMOUNTING_SIGTERM,
|
||||
MOUNT_REMOUNTING_SIGKILL));
|
||||
|
||||
mount_enter_unmounting(m);
|
||||
return 1;
|
||||
@ -1159,7 +1162,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
|
||||
m->control_pid = 0;
|
||||
|
||||
if (is_clean_exit(code, status, NULL))
|
||||
if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
|
||||
f = MOUNT_SUCCESS;
|
||||
else if (code == CLD_EXITED)
|
||||
f = MOUNT_FAILURE_EXIT_CODE;
|
||||
@ -1197,9 +1200,10 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
case MOUNT_MOUNTING_SIGKILL:
|
||||
case MOUNT_MOUNTING_SIGTERM:
|
||||
|
||||
if (f == MOUNT_SUCCESS)
|
||||
mount_enter_mounted(m, f);
|
||||
else if (m->from_proc_self_mountinfo)
|
||||
if (f == MOUNT_SUCCESS || m->from_proc_self_mountinfo)
|
||||
/* If /bin/mount returned success, or if we see the mount point in /proc/self/mountinfo we are
|
||||
* happy. If we see the first condition first, we should see the the second condition
|
||||
* immediately after – or /bin/mount lies to us and is broken. */
|
||||
mount_enter_mounted(m, f);
|
||||
else
|
||||
mount_enter_dead(m, f);
|
||||
|
@ -2600,8 +2600,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
assert(s);
|
||||
assert(pid >= 0);
|
||||
|
||||
if (UNIT(s)->fragment_path ? is_clean_exit(code, status, &s->success_status) :
|
||||
is_clean_exit_lsb(code, status, &s->success_status))
|
||||
if (is_clean_exit(code, status, s->type == SERVICE_ONESHOT ? EXIT_CLEAN_COMMAND : EXIT_CLEAN_DAEMON, &s->success_status))
|
||||
f = SERVICE_SUCCESS;
|
||||
else if (code == CLD_EXITED)
|
||||
f = SERVICE_FAILURE_EXIT_CODE;
|
||||
|
@ -2743,7 +2743,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
|
||||
s->control_pid = 0;
|
||||
|
||||
if (is_clean_exit(code, status, NULL))
|
||||
if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
|
||||
f = SOCKET_SUCCESS;
|
||||
else if (code == CLD_EXITED)
|
||||
f = SOCKET_FAILURE_EXIT_CODE;
|
||||
|
@ -988,7 +988,7 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
|
||||
s->control_pid = 0;
|
||||
|
||||
if (is_clean_exit(code, status, NULL))
|
||||
if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
|
||||
f = SWAP_SUCCESS;
|
||||
else if (code == CLD_EXITED)
|
||||
f = SWAP_FAILURE_EXIT_CODE;
|
||||
|
@ -137,7 +137,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
s = hashmap_remove(pids, PID_TO_PTR(si.si_pid));
|
||||
if (s) {
|
||||
if (!is_clean_exit(si.si_code, si.si_status, NULL)) {
|
||||
if (!is_clean_exit(si.si_code, si.si_status, EXIT_CLEAN_COMMAND, NULL)) {
|
||||
if (si.si_code == CLD_EXITED)
|
||||
log_error(MOUNT_PATH " for %s exited with exit status %i.", s, si.si_status);
|
||||
else
|
||||
|
@ -1020,7 +1020,7 @@ static int config_parse_alias(
|
||||
type = unit_name_to_type(name);
|
||||
if (!unit_type_may_alias(type))
|
||||
return log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||
"Aliases are not allowed for %s units, ignoring.",
|
||||
"Alias= is not allowed for %s units, ignoring.",
|
||||
unit_type_to_string(type));
|
||||
|
||||
return config_parse_strv(unit, filename, line, section, section_line,
|
||||
@ -1098,7 +1098,7 @@ static int config_parse_default_instance(
|
||||
return 0;
|
||||
if (!unit_name_is_valid(name, UNIT_NAME_TEMPLATE))
|
||||
return log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||
"DefaultInstance only makes sense for template units, ignoring.");
|
||||
"DefaultInstance= only makes sense for template units, ignoring.");
|
||||
|
||||
r = install_full_printf(i, rvalue, &printed);
|
||||
if (r < 0)
|
||||
|
@ -3936,7 +3936,7 @@ static void print_status_info(
|
||||
argv = strv_join(p->argv, " ");
|
||||
printf(" Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
|
||||
|
||||
good = is_clean_exit_lsb(p->code, p->status, NULL);
|
||||
good = is_clean_exit(p->code, p->status, EXIT_CLEAN_DAEMON, NULL);
|
||||
if (!good) {
|
||||
on = ansi_highlight_red();
|
||||
off = ansi_normal();
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dirent-util.h"
|
||||
#include "exit-status.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "hashmap.h"
|
||||
@ -199,6 +200,13 @@ static int generate_unit_file(SysvStub *s) {
|
||||
if (s->pid_file)
|
||||
fprintf(f, "PIDFile=%s\n", s->pid_file);
|
||||
|
||||
/* Consider two special LSB exit codes a clean exit */
|
||||
if (s->has_lsb)
|
||||
fprintf(f,
|
||||
"SuccessExitStatus=%i %i\n",
|
||||
EXIT_NOTINSTALLED,
|
||||
EXIT_NOTCONFIGURED);
|
||||
|
||||
fprintf(f,
|
||||
"ExecStart=%s start\n"
|
||||
"ExecStop=%s stop\n",
|
||||
|
@ -827,7 +827,7 @@ static int ask_on_consoles(int argc, char *argv[]) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_clean_exit(status.si_code, status.si_status, NULL))
|
||||
if (!is_clean_exit(status.si_code, status.si_status, EXIT_CLEAN_DAEMON, NULL))
|
||||
log_error("Password agent failed with: %d", status.si_status);
|
||||
|
||||
terminate_agents(pids);
|
||||
|
Loading…
Reference in New Issue
Block a user