From 59fccdc587bc179c1638916ee16a24099f94f81f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 6 Nov 2014 13:43:45 +0100 Subject: core: introduce the concept of AssertXYZ= similar to ConditionXYZ=, but fatal for a start job if not met --- src/core/condition.c | 6 +- src/core/condition.h | 2 +- src/core/dbus-unit.c | 17 +++-- src/core/job.c | 8 +++ src/core/job.h | 1 + src/core/load-fragment-gperf.gperf.m4 | 57 ++++++++++----- src/core/load-fragment.c | 131 ++++++++++++++++------------------ src/core/unit.c | 53 ++++++++++++-- src/core/unit.h | 3 + 9 files changed, 174 insertions(+), 104 deletions(-) (limited to 'src/core') diff --git a/src/core/condition.c b/src/core/condition.c index 8475258679..c20c0f01e1 100644 --- a/src/core/condition.c +++ b/src/core/condition.c @@ -22,7 +22,7 @@ #include "condition.h" #include "unit.h" -bool condition_test_list(const char *unit, Condition *first) { +bool condition_test_list(const char *unit, Condition *first, const char *(*to_string)(ConditionType t)) { Condition *c; int triggered = -1; @@ -40,7 +40,7 @@ bool condition_test_list(const char *unit, Condition *first) { if (r < 0) log_warning_unit(unit, "Couldn't determine result for %s=%s%s%s for %s, assuming failed: %s", - condition_type_to_string(c->type), + to_string(c->type), c->trigger ? "|" : "", c->negate ? "!" : "", c->parameter, @@ -49,7 +49,7 @@ bool condition_test_list(const char *unit, Condition *first) { else log_debug_unit(unit, "%s=%s%s%s %s for %s.", - condition_type_to_string(c->type), + to_string(c->type), c->trigger ? "|" : "", c->negate ? "!" : "", c->parameter, diff --git a/src/core/condition.h b/src/core/condition.h index 6dd77bb658..a6a31edc7a 100644 --- a/src/core/condition.h +++ b/src/core/condition.h @@ -23,4 +23,4 @@ #include "condition-util.h" -bool condition_test_list(const char *unit, Condition *c); +bool condition_test_list(const char *unit, Condition *c, const char *(*to_string)(ConditionType t)); diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 3fa427198e..5dcde25a2d 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -315,19 +315,21 @@ static int property_get_conditions( void *userdata, sd_bus_error *error) { - Unit *u = userdata; - Condition *c; + const char *(*to_string)(ConditionType type) = NULL; + Condition **list = userdata, *c; int r; assert(bus); assert(reply); - assert(u); + assert(list); + + to_string = streq(property, "Asserts") ? assert_type_to_string : condition_type_to_string; r = sd_bus_message_open_container(reply, 'a', "(sbbsi)"); if (r < 0) return r; - LIST_FOREACH(conditions, c, u->conditions) { + LIST_FOREACH(conditions, c, *list) { int tristate; tristate = @@ -335,7 +337,7 @@ static int property_get_conditions( c->result == CONDITION_SUCCEEDED ? 1 : -1; r = sd_bus_message_append(reply, "(sbbsi)", - condition_type_to_string(c->type), + to_string(c->type), c->trigger, c->negate, c->parameter, tristate); if (r < 0) @@ -572,8 +574,11 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), - SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, 0, 0), + BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0), + SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0), SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/core/job.c b/src/core/job.c index eaa4bb17fc..51d15811b5 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -542,6 +542,8 @@ int job_run_and_invalidate(Job *j) { r = job_finish_and_invalidate(j, JOB_SKIPPED, true); else if (r == -ENOEXEC) 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 == -EAGAIN) { j->state = JOB_WAITING; m->n_running_jobs--; @@ -655,6 +657,11 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) { 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; + default: ; } @@ -1189,6 +1196,7 @@ static const char* const job_result_table[_JOB_RESULT_MAX] = { [JOB_DEPENDENCY] = "dependency", [JOB_SKIPPED] = "skipped", [JOB_INVALID] = "invalid", + [JOB_ASSERT] = "assert", }; DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult); diff --git a/src/core/job.h b/src/core/job.h index 1e7c61b04f..b7ebd8dc88 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -99,6 +99,7 @@ enum JobResult { 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_RESULT_MAX, _JOB_RESULT_INVALID = -1 }; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 5158a9f158..1d2debe70f 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -155,25 +155,44 @@ Unit.IgnoreOnSnapshot, config_parse_bool, 0, Unit.JobTimeoutSec, config_parse_sec, 0, offsetof(Unit, job_timeout) Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action) Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg) -Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, 0 -Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, 0 -Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, 0 -Unit.ConditionPathIsSymbolicLink,config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,0 -Unit.ConditionPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, 0 -Unit.ConditionPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, 0 -Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, 0 -Unit.ConditionFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, 0 -Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, 0 -Unit.ConditionNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, 0 -Unit.ConditionFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, 0 -Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, 0 -Unit.ConditionArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, 0 -Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, 0 -Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, 0 -Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, 0 -Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_HOST, 0 -Unit.ConditionACPower, config_parse_unit_condition_string, CONDITION_AC_POWER, 0 -Unit.ConditionNull, config_parse_unit_condition_null, 0, 0 +Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, conditions) +Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, conditions) +Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, offsetof(Unit, conditions) +Unit.ConditionPathIsSymbolicLink,config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,offsetof(Unit, conditions) +Unit.ConditionPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, offsetof(Unit, conditions) +Unit.ConditionPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, offsetof(Unit, conditions) +Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, offsetof(Unit, conditions) +Unit.ConditionFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, offsetof(Unit, conditions) +Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, offsetof(Unit, conditions) +Unit.ConditionNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, offsetof(Unit, conditions) +Unit.ConditionFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, offsetof(Unit, conditions) +Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, conditions) +Unit.ConditionArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, conditions) +Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, conditions) +Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, offsetof(Unit, conditions) +Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, offsetof(Unit, conditions) +Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_HOST, offsetof(Unit, conditions) +Unit.ConditionACPower, config_parse_unit_condition_string, CONDITION_AC_POWER, offsetof(Unit, conditions) +Unit.ConditionNull, config_parse_unit_condition_null, 0, offsetof(Unit, conditions) +Unit.AssertPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, asserts) +Unit.AssertPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, asserts) +Unit.AssertPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, offsetof(Unit, asserts) +Unit.AssertPathIsSymbolicLink, config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,offsetof(Unit, asserts) +Unit.AssertPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, offsetof(Unit, asserts) +Unit.AssertPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, offsetof(Unit, asserts) +Unit.AssertDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, offsetof(Unit, asserts) +Unit.AssertFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, offsetof(Unit, asserts) +Unit.AssertFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, offsetof(Unit, asserts) +Unit.AssertNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, offsetof(Unit, asserts) +Unit.AssertFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, offsetof(Unit, asserts) +Unit.AssertKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, asserts) +Unit.AssertArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, asserts) +Unit.AssertVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, asserts) +Unit.AssertSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, offsetof(Unit, asserts) +Unit.AssertCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, offsetof(Unit, asserts) +Unit.AssertHost, config_parse_unit_condition_string, CONDITION_HOST, offsetof(Unit, asserts) +Unit.AssertACPower, config_parse_unit_condition_string, CONDITION_AC_POWER, offsetof(Unit, asserts) +Unit.AssertNull, config_parse_unit_condition_null, 0, offsetof(Unit, asserts) m4_dnl Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file) Service.ExecStartPre, config_parse_exec, SERVICE_EXEC_START_PRE, offsetof(Service, exec_command) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index e193a67dcd..2ee16bdef9 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1955,22 +1955,23 @@ int config_parse_ip_tos(const char *unit, return 0; } -int config_parse_unit_condition_path(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_unit_condition_path( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { - ConditionType cond = ltype; - Unit *u = data; - bool trigger, negate; - Condition *c; _cleanup_free_ char *p = NULL; + Condition **list = data, *c; + ConditionType t = ltype; + bool trigger, negate; + Unit *u = userdata; int r; assert(filename); @@ -1980,8 +1981,8 @@ int config_parse_unit_condition_path(const char *unit, if (isempty(rvalue)) { /* Empty assignment resets the list */ - condition_free_list(u->conditions); - u->conditions = NULL; + condition_free_list(*list); + *list = NULL; return 0; } @@ -1994,45 +1995,41 @@ int config_parse_unit_condition_path(const char *unit, rvalue++; r = unit_full_printf(u, rvalue, &p); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", rvalue); - if (!p) { - p = strdup(rvalue); - if (!p) - return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue); + return 0; } if (!path_is_absolute(p)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Path in condition not absolute, ignoring: %s", p); + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p); return 0; } - c = condition_new(cond, p, trigger, negate); + c = condition_new(t, p, trigger, negate); if (!c) return log_oom(); - LIST_PREPEND(conditions, u->conditions, c); + LIST_PREPEND(conditions, *list, c); return 0; } -int config_parse_unit_condition_string(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_unit_condition_string( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { - ConditionType cond = ltype; - Unit *u = data; - bool trigger, negate; - Condition *c; _cleanup_free_ char *s = NULL; + Condition **list = data, *c; + ConditionType t = ltype; + bool trigger, negate; + Unit *u = userdata; int r; assert(filename); @@ -2042,8 +2039,8 @@ int config_parse_unit_condition_string(const char *unit, if (isempty(rvalue)) { /* Empty assignment resets the list */ - condition_free_list(u->conditions); - u->conditions = NULL; + condition_free_list(*list); + *list = NULL; return 0; } @@ -2056,36 +2053,32 @@ int config_parse_unit_condition_string(const char *unit, rvalue++; r = unit_full_printf(u, rvalue, &s); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", rvalue); - if (!s) { - s = strdup(rvalue); - if (!s) - return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue); + return 0; } - c = condition_new(cond, s, trigger, negate); + c = condition_new(t, s, trigger, negate); if (!c) return log_oom(); - LIST_PREPEND(conditions, u->conditions, c); + LIST_PREPEND(conditions, *list, c); return 0; } -int config_parse_unit_condition_null(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_unit_condition_null( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { - Unit *u = data; - Condition *c; + Condition **list = data, *c; bool trigger, negate; int b; @@ -2096,8 +2089,8 @@ int config_parse_unit_condition_null(const char *unit, if (isempty(rvalue)) { /* Empty assignment resets the list */ - condition_free_list(u->conditions); - u->conditions = NULL; + condition_free_list(*list); + *list = NULL; return 0; } @@ -2111,9 +2104,7 @@ int config_parse_unit_condition_null(const char *unit, b = parse_boolean(rvalue); if (b < 0) { - log_syntax(unit, LOG_ERR, filename, line, -b, - "Failed to parse boolean value in condition, ignoring: %s", - rvalue); + log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue); return 0; } @@ -2124,7 +2115,7 @@ int config_parse_unit_condition_null(const char *unit, if (!c) return log_oom(); - LIST_PREPEND(conditions, u->conditions, c); + LIST_PREPEND(conditions, *list, c); return 0; } diff --git a/src/core/unit.c b/src/core/unit.c index d5acc728ec..66f53ddc7c 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -527,6 +527,7 @@ void unit_free(Unit *u) { unit_unwatch_all_pids(u); condition_free_list(u->conditions); + condition_free_list(u->asserts); unit_ref_unset(&u->slice); @@ -929,7 +930,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { if (u->job_timeout_reboot_arg) fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg); - condition_dump_list(u->conditions, f, prefix); + condition_dump_list(u->conditions, f, prefix, condition_type_to_string); + condition_dump_list(u->asserts, f, prefix, assert_type_to_string); if (dual_timestamp_is_set(&u->condition_timestamp)) fprintf(f, @@ -938,6 +940,13 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->condition_timestamp.realtime)), prefix, yes_no(u->condition_result)); + if (dual_timestamp_is_set(&u->assert_timestamp)) + fprintf(f, + "%s\tAssert Timestamp: %s\n" + "%s\tAssert Result: %s\n", + prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->assert_timestamp.realtime)), + prefix, yes_no(u->assert_result)); + for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) { Unit *other; @@ -1240,11 +1249,20 @@ static bool unit_condition_test(Unit *u) { assert(u); dual_timestamp_get(&u->condition_timestamp); - u->condition_result = condition_test_list(u->id, u->conditions); + u->condition_result = condition_test_list(u->id, u->conditions, condition_type_to_string); return u->condition_result; } +static bool unit_assert_test(Unit *u) { + assert(u); + + dual_timestamp_get(&u->assert_timestamp); + u->assert_result = condition_test_list(u->id, u->asserts, assert_type_to_string); + + return u->assert_result; +} + _pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) { const UnitStatusMessageFormats *format_table; @@ -1341,6 +1359,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) { * -EALREADY: Unit is already started. * -EAGAIN: An operation is already in progress. Retry later. * -ECANCELED: Too many requests for now. + * -EPROTO: Assert failed */ int unit_start(Unit *u) { UnitActiveState state; @@ -1365,15 +1384,21 @@ int unit_start(Unit *u) { * but we don't want to recheck the condition in that case. */ if (state != UNIT_ACTIVATING && !unit_condition_test(u)) { - log_debug_unit(u->id, "Starting of %s requested but condition failed. Ignoring.", u->id); + log_debug_unit(u->id, "Starting of %s requested but condition failed. Not starting unit.", u->id); return -EALREADY; } + /* If the asserts failed, fail the entire job */ + if (state != UNIT_ACTIVATING && + !unit_assert_test(u)) { + log_debug_unit(u->id, "Starting of %s requested but asserts failed.", u->id); + return -EPROTO; + } + /* Forward to the main object, if we aren't it. */ following = unit_following(u); if (following) { - log_debug_unit(u->id, "Redirecting start request from %s to %s.", - u->id, following->id); + log_debug_unit(u->id, "Redirecting start request from %s to %s.", u->id, following->id); return unit_start(following); } @@ -2502,10 +2527,14 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { dual_timestamp_serialize(f, "active-exit-timestamp", &u->active_exit_timestamp); dual_timestamp_serialize(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp); dual_timestamp_serialize(f, "condition-timestamp", &u->condition_timestamp); + dual_timestamp_serialize(f, "assert-timestamp", &u->assert_timestamp); if (dual_timestamp_is_set(&u->condition_timestamp)) unit_serialize_item(u, f, "condition-result", yes_no(u->condition_result)); + if (dual_timestamp_is_set(&u->assert_timestamp)) + unit_serialize_item(u, f, "assert-result", yes_no(u->assert_result)); + unit_serialize_item(u, f, "transient", yes_no(u->transient)); if (u->cgroup_path) @@ -2645,6 +2674,9 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { } else if (streq(l, "condition-timestamp")) { dual_timestamp_deserialize(v, &u->condition_timestamp); continue; + } else if (streq(l, "assert-timestamp")) { + dual_timestamp_deserialize(v, &u->assert_timestamp); + continue; } else if (streq(l, "condition-result")) { int b; @@ -2656,6 +2688,17 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { continue; + } else if (streq(l, "assert-result")) { + int b; + + b = parse_boolean(v); + if (b < 0) + log_debug("Failed to parse assert result value %s", v); + else + u->assert_result = b; + + continue; + } else if (streq(l, "transient")) { int b; diff --git a/src/core/unit.h b/src/core/unit.h index 081ab18f10..8b24272245 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -129,8 +129,10 @@ struct Unit { /* Conditions to check */ LIST_HEAD(Condition, conditions); + LIST_HEAD(Condition, asserts); dual_timestamp condition_timestamp; + dual_timestamp assert_timestamp; dual_timestamp inactive_exit_timestamp; dual_timestamp active_enter_timestamp; @@ -212,6 +214,7 @@ struct Unit { /* Did the last condition check succeed? */ bool condition_result; + bool assert_result; /* Is this a transient unit? */ bool transient; -- cgit v1.2.3-54-g00ecf