systemctl: show unit name when a job fails

https://bugzilla.redhat.com/show_bug.cgi?id=845028
https://bugzilla.redhat.com/show_bug.cgi?id=846483
This commit is contained in:
Lennart Poettering 2012-09-14 15:11:07 +02:00
parent 73836c5c43
commit 67f3c40265
4 changed files with 97 additions and 74 deletions

2
TODO
View file

@ -53,6 +53,8 @@ Bugfixes:
Features: Features:
* journald: warn if we drop messages we forward to the syslog socket
* does vasprintf advance the struct vaargs? http://pastie.org/pastes/4712773/text * does vasprintf advance the struct vaargs? http://pastie.org/pastes/4712773/text
* do shutdown audit/utmp msgs inside of PID 1, get rid of systemd-update-utmp-runlevel * do shutdown audit/utmp msgs inside of PID 1, get rid of systemd-update-utmp-runlevel

View file

@ -1253,14 +1253,16 @@ bool bus_error_is_no_service(const DBusError *error) {
return startswith(error->name, "org.freedesktop.DBus.Error.Spawn."); return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
} }
int bus_method_call_with_reply(DBusConnection *bus, int bus_method_call_with_reply(
const char *destination, DBusConnection *bus,
const char *path, const char *destination,
const char *interface, const char *path,
const char *method, const char *interface,
DBusMessage **return_reply, const char *method,
DBusError *return_error, DBusMessage **return_reply,
int first_arg_type, ...) { DBusError *return_error,
int first_arg_type, ...) {
DBusError error; DBusError error;
DBusMessage *m, *reply; DBusMessage *m, *reply;
va_list ap; va_list ap;
@ -1287,6 +1289,7 @@ int bus_method_call_with_reply(DBusConnection *bus,
if (!reply) { if (!reply) {
if (!return_error) if (!return_error)
log_error("Failed to issue method call: %s", bus_error_message(&error)); log_error("Failed to issue method call: %s", bus_error_message(&error));
if (bus_error_is_no_service(&error)) if (bus_error_is_no_service(&error))
r = -ENOENT; r = -ENOENT;
else if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) else if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED))

View file

@ -265,6 +265,8 @@ static void remove_entry(Hashmap *h, struct hashmap_entry *e) {
void hashmap_free(Hashmap*h) { void hashmap_free(Hashmap*h) {
/* Free the hashmap, but nothing in it */
if (!h) if (!h)
return; return;
@ -277,6 +279,10 @@ void hashmap_free(Hashmap*h) {
} }
void hashmap_free_free(Hashmap *h) { void hashmap_free_free(Hashmap *h) {
/* Free the hashmap and all data objects in it, but not the
* keys */
if (!h) if (!h)
return; return;
@ -371,8 +377,8 @@ void* hashmap_get(Hashmap *h, const void *key) {
return NULL; return NULL;
hash = h->hash_func(key) % NBUCKETS; hash = h->hash_func(key) % NBUCKETS;
e = hash_scan(h, hash, key);
if (!(e = hash_scan(h, hash, key))) if (!e)
return NULL; return NULL;
return e->value; return e->value;

View file

@ -1175,6 +1175,8 @@ finish:
typedef struct WaitData { typedef struct WaitData {
Set *set; Set *set;
char *name;
char *result; char *result;
} WaitData; } WaitData;
@ -1213,9 +1215,12 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me
p = set_remove(d->set, (char*) path); p = set_remove(d->set, (char*) path);
free(p); free(p);
if (*result) if (!isempty(result))
d->result = strdup(result); d->result = strdup(result);
if (!isempty(unit))
d->name = strdup(unit);
goto finish; goto finish;
} }
#ifndef LEGACY #ifndef LEGACY
@ -1297,7 +1302,7 @@ static int enable_wait_for_jobs(DBusConnection *bus) {
} }
static int wait_for_jobs(DBusConnection *bus, Set *s) { static int wait_for_jobs(DBusConnection *bus, Set *s) {
int r; int r = 0;
WaitData d; WaitData d;
assert(bus); assert(bus);
@ -1306,41 +1311,42 @@ static int wait_for_jobs(DBusConnection *bus, Set *s) {
zero(d); zero(d);
d.set = s; d.set = s;
if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) { if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
log_error("Failed to add filter."); return log_oom();
r = -ENOMEM;
goto finish; while (!set_isempty(s)) {
if (!dbus_connection_read_write_dispatch(bus, -1)) {
log_error("Disconnected from bus.");
return -ECONNREFUSED;
}
if (!arg_quiet && d.result) {
if (streq(d.result, "timeout"))
log_error("Job for %s timed out.", strna(d.name));
else if (streq(d.result, "canceled"))
log_error("Job for %s canceled.", strna(d.name));
else if (streq(d.result, "dependency"))
log_error("A dependency job for %s failed. See 'journalctl' for details.", strna(d.name));
else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl' for details.", strna(d.name), strna(d.name));
}
if (streq_ptr(d.result, "timeout"))
r = -ETIME;
else if (streq_ptr(d.result, "canceled"))
r = -ECANCELED;
else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
r = -EIO;
free(d.result);
d.result = NULL;
free(d.name);
d.name = NULL;
} }
while (!set_isempty(s) &&
dbus_connection_read_write_dispatch(bus, -1))
;
if (!arg_quiet && d.result) {
if (streq(d.result, "timeout"))
log_error("Job timed out.");
else if (streq(d.result, "canceled"))
log_error("Job canceled.");
else if (streq(d.result, "dependency"))
log_error("A dependency job failed. See system journal for details.");
else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
log_error("Job failed. See system journal and 'systemctl status' for details.");
}
if (streq_ptr(d.result, "timeout"))
r = -ETIME;
else if (streq_ptr(d.result, "canceled"))
r = -ECANCELED;
else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
r = -EIO;
else
r = 0;
free(d.result);
finish:
/* This is slightly dirty, since we don't undo the filter registration. */ /* This is slightly dirty, since we don't undo the filter registration. */
return r; return r;
} }
@ -1517,16 +1523,18 @@ static int start_unit_one(
DBusMessage *reply = NULL; DBusMessage *reply = NULL;
const char *path; const char *path;
int r; int r;
char *n; _cleanup_free_ char *n, *p = NULL;
assert(method); assert(method);
assert(name); assert(name);
assert(mode); assert(mode);
assert(error); assert(error);
assert(arg_no_block || s);
n = unit_name_mangle(name); n = unit_name_mangle(name);
r = bus_method_call_with_reply ( if (!n)
return log_oom();
r = bus_method_call_with_reply(
bus, bus,
"org.freedesktop.systemd1", "org.freedesktop.systemd1",
"/org/freedesktop/systemd1", "/org/freedesktop/systemd1",
@ -1534,17 +1542,17 @@ static int start_unit_one(
method, method,
&reply, &reply,
error, error,
DBUS_TYPE_STRING, n ? (const char **) &n : &name, DBUS_TYPE_STRING, &n,
DBUS_TYPE_STRING, &mode, DBUS_TYPE_STRING, &mode,
DBUS_TYPE_INVALID); DBUS_TYPE_INVALID);
free(n);
if (r) { if (r) {
if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL ) if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
/* There's always a fallback possible for /* There's always a fallback possible for
* legacy actions. */ * legacy actions. */
r = -EADDRNOTAVAIL; r = -EADDRNOTAVAIL;
else else
log_error("Failed to issue method call: %s", bus_error_message(error)); log_error("Failed to issue method call: %s", bus_error_message(error));
goto finish; goto finish;
} }
@ -1556,24 +1564,24 @@ static int start_unit_one(
goto finish; goto finish;
} }
if (need_daemon_reload(bus, name)) if (need_daemon_reload(bus, n))
log_warning("Warning: Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.", log_warning("Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended.",
arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user"); n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
if (!arg_no_block) { if (s) {
char *p; p = strdup(path);
if (!p) {
if (!(p = strdup(path))) { r = log_oom();
log_error("Failed to duplicate path.");
r = -ENOMEM;
goto finish; goto finish;
} }
if ((r = set_put(s, p)) < 0) { r = set_put(s, p);
free(p); if (r < 0) {
log_error("Failed to add path to set."); log_error("Failed to add path to set.");
goto finish; goto finish;
} }
p = NULL;
} }
/* When stopping a unit warn if it can still be triggered by /* When stopping a unit warn if it can still be triggered by
@ -1688,39 +1696,43 @@ static int start_unit(DBusConnection *bus, char **args) {
} }
if (!arg_no_block) { if (!arg_no_block) {
if ((ret = enable_wait_for_jobs(bus)) < 0) { ret = enable_wait_for_jobs(bus);
if (ret < 0) {
log_error("Could not watch jobs: %s", strerror(-ret)); log_error("Could not watch jobs: %s", strerror(-ret));
goto finish; goto finish;
} }
if (!(s = set_new(string_hash_func, string_compare_func))) { s = set_new(string_hash_func, string_compare_func);
log_error("Failed to allocate set."); if (!s) {
ret = -ENOMEM; ret = log_oom();
goto finish; goto finish;
} }
} }
if (one_name) { if (one_name) {
if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0) ret = start_unit_one(bus, method, one_name, mode, &error, s);
goto finish; if (ret < 0)
ret = translate_bus_error_to_exit_status(ret, &error);
} else { } else {
STRV_FOREACH(name, args+1) STRV_FOREACH(name, args+1) {
if ((r = start_unit_one(bus, method, *name, mode, &error, s)) != 0) { r = start_unit_one(bus, method, *name, mode, &error, s);
if (r < 0) {
ret = translate_bus_error_to_exit_status(r, &error); ret = translate_bus_error_to_exit_status(r, &error);
dbus_error_free(&error); dbus_error_free(&error);
} }
}
} }
if (!arg_no_block) if (!arg_no_block) {
if ((r = wait_for_jobs(bus, s)) < 0) { r = wait_for_jobs(bus, s);
if (r < 0) {
ret = r; ret = r;
goto finish; goto finish;
} }
}
finish: finish:
if (s) set_free_free(s);
set_free_free(s);
dbus_error_free(&error); dbus_error_free(&error);
return ret; return ret;