[systemd-devel] [PATCH 2/2] systemd, systemctl: export and show failing condition
Zbigniew Jędrzejewski-Szmek
zbyszek at in.waw.pl
Wed Jun 26 05:11:18 PDT 2013
$ systemctl --user status hoohoo
hoohoo.service
Loaded: loaded (/home/zbyszek/.config/systemd/user/hoohoo.service; static)
Active: inactive (dead)
start condition failed at Tue 2013-06-25 18:08:42 EDT; 1s ago
ConditionPathExists=/tmp/hoo was not met
---
TODO | 2 --
src/core/condition.c | 9 +++++++--
src/core/condition.h | 2 +-
src/core/dbus-unit.c | 34 +++++++++++++++++++++++++++++++
src/core/dbus-unit.h | 1 +
src/core/load-fragment.c | 17 ++++++++++------
src/core/unit.c | 12 +++++++----
src/core/unit.h | 4 ++++
src/systemctl/systemctl.c | 51 ++++++++++++++++++++++++++++++++++++++++++-----
9 files changed, 112 insertions(+), 20 deletions(-)
diff --git a/TODO b/TODO
index caba4e3..1aced8b 100644
--- a/TODO
+++ b/TODO
@@ -474,8 +474,6 @@ Features:
when done. That means clients don't get a successful method reply,
but much rather a disconnect on success.
-* remember which condition failed for services, not just the fact that something failed
-
* use opterr = 0 for all getopt tools
* properly handle loop back mounts via fstab, especially regards to fsck/passno
diff --git a/src/core/condition.c b/src/core/condition.c
index 3807398..cf1ea2e 100644
--- a/src/core/condition.c
+++ b/src/core/condition.c
@@ -334,10 +334,13 @@ bool condition_test(Condition *c) {
}
}
-bool condition_test_list(const char *unit, Condition *first) {
+bool condition_test_list(const char *unit, Condition *first, Condition **failing) {
Condition *c;
int triggered = -1;
+ assert(failing);
+ *failing = NULL;
+
/* If the condition list is empty, then it is true */
if (!first)
return true;
@@ -359,8 +362,10 @@ bool condition_test_list(const char *unit, Condition *first) {
b ? "succeeded" : "failed",
unit);
- if (!c->trigger && !b)
+ if (!c->trigger && !b) {
+ *failing = c;
return false;
+ }
if (c->trigger && triggered <= 0)
triggered = b;
diff --git a/src/core/condition.h b/src/core/condition.h
index 2ad7787..be8faf6 100644
--- a/src/core/condition.h
+++ b/src/core/condition.h
@@ -61,7 +61,7 @@ void condition_free(Condition *c);
void condition_free_list(Condition *c);
bool condition_test(Condition *c);
-bool condition_test_list(const char *unit, Condition *c);
+bool condition_test_list(const char *unit, Condition *c, Condition **failing);
void condition_dump(Condition *c, FILE *f, const char *prefix);
void condition_dump_list(Condition *c, FILE *f, const char *prefix);
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 8a7ab34..c3c7198 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -395,6 +395,39 @@ static int bus_unit_append_need_daemon_reload(DBusMessageIter *i, const char *pr
return 0;
}
+static int bus_property_append_condition(DBusMessageIter *i, const char *property, void *data) {
+ Condition **cp = data;
+ Condition *c;
+ const char *name, *param;
+ dbus_bool_t trigger, negate;
+ DBusMessageIter sub;
+
+ assert(i);
+ assert(property);
+ assert(cp);
+
+ c = *cp;
+ if (c) {
+ name = condition_type_to_string(c->type);
+ param = c->parameter;
+ trigger = c->trigger;
+ negate = c->negate;
+ } else {
+ name = param = "";
+ trigger = negate = false;
+ }
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &name) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &trigger) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &negate) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, ¶m) ||
+ !dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
static int bus_unit_append_load_error(DBusMessageIter *i, const char *property, void *data) {
Unit *u = data;
const char *name, *message;
@@ -1329,6 +1362,7 @@ const BusProperty bus_unit_properties[] = {
{ "ConditionTimestamp", bus_property_append_usec, "t", offsetof(Unit, condition_timestamp.realtime) },
{ "ConditionTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, condition_timestamp.monotonic) },
{ "ConditionResult", bus_property_append_bool, "b", offsetof(Unit, condition_result) },
+ { "ConditionFailed", bus_property_append_condition, "(sbbs)", offsetof(Unit, failed_condition) },
{ "LoadError", bus_unit_append_load_error, "(ss)", 0 },
{ NULL, }
};
diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h
index 83932c5..aa995da 100644
--- a/src/core/dbus-unit.h
+++ b/src/core/dbus-unit.h
@@ -122,6 +122,7 @@
" <property name=\"ConditionTimestamp\" type=\"t\" access=\"read\"/>\n" \
" <property name=\"ConditionTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
" <property name=\"ConditionResult\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"ConditionFailed\" type=\"(sbbs)\" access=\"read\"/>\n" \
" <property name=\"LoadError\" type=\"(ss)\" access=\"read\"/>\n" \
" </interface>\n"
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 15fabe8..9553472 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -1634,6 +1634,14 @@ int config_parse_ip_tos(const char *unit,
return 0;
}
+static void reset_conditions(Unit *u) {
+ assert(u);
+
+ condition_free_list(u->conditions);
+ u->conditions = NULL;
+ u->failed_condition = NULL;
+}
+
int config_parse_unit_condition_path(const char *unit,
const char *filename,
unsigned line,
@@ -1657,8 +1665,7 @@ 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;
+ reset_conditions(u);
return 0;
}
@@ -1711,8 +1718,7 @@ 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;
+ reset_conditions(u);
return 0;
}
@@ -1758,8 +1764,7 @@ 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;
+ reset_conditions(u);
return 0;
}
diff --git a/src/core/unit.c b/src/core/unit.c
index 8a00fea..60a1ef1 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -958,7 +958,8 @@ 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,
+ &u->failed_condition);
return u->condition_result;
}
@@ -1087,7 +1088,8 @@ int unit_start(Unit *u) {
}
/* Forward to the main object, if we aren't it. */
- if ((following = unit_following(u))) {
+ following = unit_following(u);
+ if (following) {
log_debug_unit(u->id, "Redirecting start request from %s to %s.",
u->id, following->id);
return unit_start(following);
@@ -2560,7 +2562,8 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
} else if (streq(l, "condition-result")) {
int b;
- if ((b = parse_boolean(v)) < 0)
+ b = parse_boolean(v);
+ if (b < 0)
log_debug("Failed to parse condition result value %s", v);
else
u->condition_result = b;
@@ -2568,7 +2571,8 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
continue;
}
- if ((r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds)) < 0)
+ r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
+ if (r < 0)
return r;
}
}
diff --git a/src/core/unit.h b/src/core/unit.h
index da52101..4539522 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -166,6 +166,10 @@ struct Unit {
/* Conditions to check */
LIST_HEAD(Condition, conditions);
+ /* Condition which prevented start */
+ Condition *failed_condition;
+
+ /* Condition check time */
dual_timestamp condition_timestamp;
dual_timestamp inactive_exit_timestamp;
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 24543ee..8f3fa64 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -2668,6 +2668,10 @@ typedef struct UnitStatusInfo {
usec_t condition_timestamp;
bool condition_result;
+ bool failed_condition_trigger:1;
+ bool failed_condition_negate:1;
+ const char *failed_condition;
+ const char *failed_condition_param;
/* Socket */
unsigned n_accepted;
@@ -2810,10 +2814,15 @@ static void print_status_info(UnitStatusInfo *i) {
s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
- if (s1)
- printf(" start condition failed at %s; %s\n", s2, s1);
- else if (s2)
- printf(" start condition failed at %s\n", s2);
+ printf(" start condition failed at %s%s%s\n",
+ s2, s1 ? "; " : "", s1 ? s1 : "");
+ if (i->failed_condition) {
+ printf(" %s=%s%s%s was not met\n",
+ i->failed_condition,
+ i->failed_condition_trigger ? "|" : "",
+ i->failed_condition_negate ? "!" : "",
+ i->failed_condition_param);
+ }
}
if (i->sysfs_path)
@@ -3172,7 +3181,8 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
return -ENOMEM;
}
- if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
+ r = exec_status_info_deserialize(&sub, info);
+ if (r < 0) {
free(info);
return r;
}
@@ -3255,6 +3265,37 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
if (!isempty(message))
i->load_error = message;
+
+ } else if (streq(name, "ConditionFailed")) {
+ DBusMessageIter sub;
+ const char *cond, *param;
+ dbus_bool_t trigger, negate;
+ int r;
+
+ dbus_message_iter_recurse(iter, &sub);
+
+ r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &cond, true);
+ if (r < 0)
+ return r;
+
+ r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_BOOLEAN, &trigger, true);
+ if (r < 0)
+ return r;
+
+ r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_BOOLEAN, &negate, true);
+ if (r < 0)
+ return r;
+
+ r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, ¶m, false);
+ if (r < 0)
+ return r;
+
+ if (!isempty(cond)) {
+ i->failed_condition = cond;
+ i->failed_condition_param = param;
+ i->failed_condition_trigger = trigger;
+ i->failed_condition_negate = negate;
+ }
}
break;
--
1.8.2.562.g931e949
More information about the systemd-devel
mailing list