mirror of
https://github.com/systemd/systemd.git
synced 2025-01-12 13:18:14 +03:00
unit: handle nicely of certain unit types are not supported on specific systems
Containers do not really support .device, .automount or .swap units; Systems compiled without support for swap do not support .swap units; Systems without kdbus do not support .busname units. With this change attempts to start a unsupported unit types will result in an immediate "unsupported" job result, which is a lot more descriptive then before. Also, attempts to start device units in containers will now immediately fail instead of causing jobs to be enqueued that never go away.
This commit is contained in:
parent
17d1f37d0d
commit
0faacd470d
@ -807,6 +807,17 @@ static void automount_reset_failed(Unit *u) {
|
||||
a->result = AUTOMOUNT_SUCCESS;
|
||||
}
|
||||
|
||||
static bool automount_supported(Manager *m) {
|
||||
static int supported = -1;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (supported < 0)
|
||||
supported = access("/dev/autofs", F_OK) >= 0;
|
||||
|
||||
return supported;
|
||||
}
|
||||
|
||||
static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
|
||||
[AUTOMOUNT_DEAD] = "dead",
|
||||
[AUTOMOUNT_WAITING] = "waiting",
|
||||
@ -859,6 +870,7 @@ const UnitVTable automount_vtable = {
|
||||
.bus_vtable = bus_automount_vtable,
|
||||
|
||||
.shutdown = automount_shutdown,
|
||||
.supported = automount_supported,
|
||||
|
||||
.status_message_formats = {
|
||||
.finished_start_job = {
|
||||
|
@ -971,6 +971,16 @@ static int busname_get_timeout(Unit *u, uint64_t *timeout) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool busname_supported(Manager *m) {
|
||||
int supported = -1;
|
||||
assert(m);
|
||||
|
||||
if (supported < 0)
|
||||
supported = access("/sys/fs/kdbus", F_OK) >= 0;
|
||||
|
||||
return supported;
|
||||
}
|
||||
|
||||
static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
|
||||
[BUSNAME_DEAD] = "dead",
|
||||
[BUSNAME_MAKING] = "making",
|
||||
@ -1032,6 +1042,8 @@ const UnitVTable busname_vtable = {
|
||||
|
||||
.reset_failed = busname_reset_failed,
|
||||
|
||||
.supported = busname_supported,
|
||||
|
||||
.bus_interface = "org.freedesktop.systemd1.BusName",
|
||||
.bus_vtable = bus_busname_vtable,
|
||||
|
||||
|
@ -673,6 +673,19 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool device_supported(Manager *m) {
|
||||
static int read_only = -1;
|
||||
assert(m);
|
||||
|
||||
/* If /sys is read-only we don't support device units, and any
|
||||
* attempts to start one should fail immediately. */
|
||||
|
||||
if (read_only < 0)
|
||||
read_only = path_is_read_only_fs("/sys");
|
||||
|
||||
return read_only <= 0;
|
||||
}
|
||||
|
||||
static const char* const device_state_table[_DEVICE_STATE_MAX] = {
|
||||
[DEVICE_DEAD] = "dead",
|
||||
[DEVICE_PLUGGED] = "plugged"
|
||||
@ -708,6 +721,7 @@ const UnitVTable device_vtable = {
|
||||
|
||||
.enumerate = device_enumerate,
|
||||
.shutdown = device_shutdown,
|
||||
.supported = device_supported,
|
||||
|
||||
.status_message_formats = {
|
||||
.starting_stopping = {
|
||||
|
@ -547,6 +547,8 @@ int job_run_and_invalidate(Job *j) {
|
||||
r = job_finish_and_invalidate(j, JOB_INVALID, true);
|
||||
else if (r == -EPROTO)
|
||||
r = job_finish_and_invalidate(j, JOB_ASSERT, true);
|
||||
else if (r == -ENOTSUP)
|
||||
r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true);
|
||||
else if (r == -EAGAIN) {
|
||||
j->state = JOB_WAITING;
|
||||
m->n_running_jobs--;
|
||||
@ -591,12 +593,16 @@ _pure_ static const char *job_get_status_message_format_try_harder(Unit *u, JobT
|
||||
if (t == JOB_START) {
|
||||
if (result == JOB_DONE)
|
||||
return "Started %s.";
|
||||
else if (result == JOB_TIMEOUT)
|
||||
return "Timed out starting %s.";
|
||||
else if (result == JOB_FAILED)
|
||||
return "Failed to start %s.";
|
||||
else if (result == JOB_DEPENDENCY)
|
||||
return "Dependency failed for %s.";
|
||||
else if (result == JOB_TIMEOUT)
|
||||
return "Timed out starting %s.";
|
||||
else if (result == JOB_ASSERT)
|
||||
return "Assertion failed for %s.";
|
||||
else if (result == JOB_UNSUPPORTED)
|
||||
return "Starting of %s not supported.";
|
||||
} else if (t == JOB_STOP || t == JOB_RESTART) {
|
||||
if (result == JOB_DONE)
|
||||
return "Stopped %s.";
|
||||
@ -637,6 +643,11 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
|
||||
unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format);
|
||||
break;
|
||||
|
||||
case JOB_TIMEOUT:
|
||||
manager_flip_auto_status(u->manager, true);
|
||||
unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
|
||||
break;
|
||||
|
||||
case JOB_FAILED: {
|
||||
bool quotes;
|
||||
|
||||
@ -655,16 +666,16 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
|
||||
unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format);
|
||||
break;
|
||||
|
||||
case JOB_TIMEOUT:
|
||||
manager_flip_auto_status(u->manager, true);
|
||||
unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
|
||||
break;
|
||||
|
||||
case JOB_ASSERT:
|
||||
manager_flip_auto_status(u->manager, true);
|
||||
unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "ASSERT" ANSI_HIGHLIGHT_OFF, format);
|
||||
break;
|
||||
|
||||
case JOB_UNSUPPORTED:
|
||||
manager_flip_auto_status(u->manager, true);
|
||||
unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "UNSUPP" ANSI_HIGHLIGHT_OFF, format);
|
||||
break;
|
||||
|
||||
default:
|
||||
;
|
||||
}
|
||||
@ -1200,6 +1211,7 @@ static const char* const job_result_table[_JOB_RESULT_MAX] = {
|
||||
[JOB_SKIPPED] = "skipped",
|
||||
[JOB_INVALID] = "invalid",
|
||||
[JOB_ASSERT] = "assert",
|
||||
[JOB_UNSUPPORTED] = "unsupported",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);
|
||||
|
@ -96,12 +96,13 @@ enum JobMode {
|
||||
enum JobResult {
|
||||
JOB_DONE, /* Job completed successfully */
|
||||
JOB_CANCELED, /* Job canceled by a conflicting job installation or by explicit cancel request */
|
||||
JOB_TIMEOUT, /* JobTimeout elapsed */
|
||||
JOB_TIMEOUT, /* Job timeout elapsed */
|
||||
JOB_FAILED, /* Job failed */
|
||||
JOB_DEPENDENCY, /* A required dependency job did not result in JOB_DONE */
|
||||
JOB_SKIPPED, /* Negative result of JOB_VERIFY_ACTIVE */
|
||||
JOB_INVALID, /* JOB_RELOAD of inactive unit */
|
||||
JOB_ASSERT, /* Couldn't start a unit, because an assert didn't hold */
|
||||
JOB_UNSUPPORTED, /* Couldn't start a unit, because the unit type is not supported on the system */
|
||||
_JOB_RESULT_MAX,
|
||||
_JOB_RESULT_INVALID = -1
|
||||
};
|
||||
|
@ -946,20 +946,29 @@ Manager* manager_free(Manager *m) {
|
||||
}
|
||||
|
||||
int manager_enumerate(Manager *m) {
|
||||
int r = 0, q;
|
||||
int r = 0;
|
||||
UnitType c;
|
||||
|
||||
assert(m);
|
||||
|
||||
/* Let's ask every type to load all units from disk/kernel
|
||||
* that it might know */
|
||||
for (c = 0; c < _UNIT_TYPE_MAX; c++)
|
||||
if (unit_vtable[c]->enumerate) {
|
||||
q = unit_vtable[c]->enumerate(m);
|
||||
if (q < 0)
|
||||
r = q;
|
||||
for (c = 0; c < _UNIT_TYPE_MAX; c++) {
|
||||
int q;
|
||||
|
||||
if (unit_vtable[c]->supported && !unit_vtable[c]->supported(m)) {
|
||||
log_info("Unit type .%s is not supported on this system.", unit_type_to_string(c));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!unit_vtable[c]->enumerate)
|
||||
continue;
|
||||
|
||||
q = unit_vtable[c]->enumerate(m);
|
||||
if (q < 0)
|
||||
r = q;
|
||||
}
|
||||
|
||||
manager_dispatch_load_queue(m);
|
||||
return r;
|
||||
}
|
||||
|
@ -1447,7 +1447,6 @@ static int mount_add_one(
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if (m->running_as == SYSTEMD_SYSTEM) {
|
||||
const char* target;
|
||||
|
||||
|
@ -1453,6 +1453,21 @@ static int swap_get_timeout(Unit *u, uint64_t *timeout) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool swap_supported(Manager *m) {
|
||||
static int supported = -1;
|
||||
|
||||
/* If swap support is not available in the kernel, or we are
|
||||
* running in a container we don't support swap units, and any
|
||||
* attempts to starting one should fail immediately. */
|
||||
|
||||
if (supported < 0)
|
||||
supported =
|
||||
access("/proc/swaps", F_OK) >= 0 &&
|
||||
detect_container(NULL) <= 0;
|
||||
|
||||
return supported;
|
||||
}
|
||||
|
||||
static const char* const swap_state_table[_SWAP_STATE_MAX] = {
|
||||
[SWAP_DEAD] = "dead",
|
||||
[SWAP_ACTIVATING] = "activating",
|
||||
@ -1539,6 +1554,7 @@ const UnitVTable swap_vtable = {
|
||||
|
||||
.enumerate = swap_enumerate,
|
||||
.shutdown = swap_shutdown,
|
||||
.supported = swap_supported,
|
||||
|
||||
.status_message_formats = {
|
||||
.starting_stopping = {
|
||||
|
@ -1453,6 +1453,9 @@ int unit_start(Unit *u) {
|
||||
unit_status_log_starting_stopping_reloading(u, JOB_START);
|
||||
unit_status_print_starting_stopping(u, JOB_START);
|
||||
|
||||
if (UNIT_VTABLE(u)->supported && !UNIT_VTABLE(u)->supported(u->manager))
|
||||
return -ENOTSUP;
|
||||
|
||||
/* If it is stopped, but we cannot start it, then fail */
|
||||
if (!UNIT_VTABLE(u)->start)
|
||||
return -EBADR;
|
||||
@ -1496,9 +1499,9 @@ int unit_stop(Unit *u) {
|
||||
if (UNIT_IS_INACTIVE_OR_FAILED(state))
|
||||
return -EALREADY;
|
||||
|
||||
if ((following = unit_following(u))) {
|
||||
log_unit_debug(u->id, "Redirecting stop request from %s to %s.",
|
||||
u->id, following->id);
|
||||
following = unit_following(u);
|
||||
if (following) {
|
||||
log_unit_debug(u->id, "Redirecting stop request from %s to %s.", u->id, following->id);
|
||||
return unit_stop(following);
|
||||
}
|
||||
|
||||
@ -1535,15 +1538,13 @@ int unit_reload(Unit *u) {
|
||||
return -EALREADY;
|
||||
|
||||
if (state != UNIT_ACTIVE) {
|
||||
log_unit_warning(u->id, "Unit %s cannot be reloaded because it is inactive.",
|
||||
u->id);
|
||||
log_unit_warning(u->id, "Unit %s cannot be reloaded because it is inactive.", u->id);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
following = unit_following(u);
|
||||
if (following) {
|
||||
log_unit_debug(u->id, "Redirecting reload request from %s to %s.",
|
||||
u->id, following->id);
|
||||
log_unit_debug(u->id, "Redirecting reload request from %s to %s.", u->id, following->id);
|
||||
return unit_reload(following);
|
||||
}
|
||||
|
||||
|
@ -396,6 +396,10 @@ struct UnitVTable {
|
||||
/* Type specific cleanups. */
|
||||
void (*shutdown)(Manager *m);
|
||||
|
||||
/* If this function is set and return false all jobs for units
|
||||
* of this type will immediately fail. */
|
||||
bool (*supported)(Manager *m);
|
||||
|
||||
/* The interface name */
|
||||
const char *bus_interface;
|
||||
|
||||
|
@ -2380,12 +2380,18 @@ static int check_wait_response(WaitData *d) {
|
||||
assert(d->result);
|
||||
|
||||
if (!arg_quiet) {
|
||||
if (streq(d->result, "timeout"))
|
||||
log_error("Job for %s timed out.", strna(d->name));
|
||||
else if (streq(d->result, "canceled"))
|
||||
if (streq(d->result, "canceled"))
|
||||
log_error("Job for %s canceled.", strna(d->name));
|
||||
else if (streq(d->result, "timeout"))
|
||||
log_error("Job for %s timed out.", strna(d->name));
|
||||
else if (streq(d->result, "dependency"))
|
||||
log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
|
||||
else if (streq(d->result, "invalid"))
|
||||
log_error("Job for %s invalid.", strna(d->name));
|
||||
else if (streq(d->result, "assert"))
|
||||
log_error("Assertion failed on job for %s.", strna(d->name));
|
||||
else if (streq(d->result, "unsupported"))
|
||||
log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
|
||||
else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
|
||||
if (d->name) {
|
||||
bool quotes;
|
||||
@ -2400,12 +2406,18 @@ static int check_wait_response(WaitData *d) {
|
||||
}
|
||||
}
|
||||
|
||||
if (streq(d->result, "timeout"))
|
||||
r = -ETIME;
|
||||
else if (streq(d->result, "canceled"))
|
||||
if (streq(d->result, "canceled"))
|
||||
r = -ECANCELED;
|
||||
else if (streq(d->result, "timeout"))
|
||||
r = -ETIME;
|
||||
else if (streq(d->result, "dependency"))
|
||||
r = -EIO;
|
||||
else if (streq(d->result, "invalid"))
|
||||
r = -ENOEXEC;
|
||||
else if (streq(d->result, "assert"))
|
||||
r = -EPROTO;
|
||||
else if (streq(d->result, "unsupported"))
|
||||
r = -ENOTSUP;
|
||||
else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
|
||||
r = -EIO;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user