X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-bus%2Fbus-util.c;h=29520f95d217ab42597aa0cf9b2bd507a70617db;hp=b8559e9826955dc1aeb4f76c46a60dc21a2b7a49;hb=d8f52ed25a9edce75fda5251c977b7898e33887e;hpb=b911eb15602ad173b1b938f351e2116789bd2c71 diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c index b8559e982..29520f95d 100644 --- a/src/libsystemd/sd-bus/bus-util.c +++ b/src/libsystemd/sd-bus/bus-util.c @@ -20,18 +20,17 @@ ***/ #include -#include - -#include "systemd/sd-daemon.h" +#include "sd-daemon.h" +#include "sd-event.h" #include "util.h" #include "strv.h" #include "macro.h" #include "def.h" #include "path-util.h" #include "missing.h" +#include "set.h" -#include "sd-event.h" #include "sd-bus.h" #include "bus-error.h" #include "bus-message.h" @@ -382,6 +381,9 @@ int bus_verify_polkit_async( if (authorized) return 1; + if (challenge) + return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required."); + return -EACCES; } #endif @@ -518,7 +520,7 @@ int bus_open_system_systemd(sd_bus **_bus) { if (r < 0) return r; - r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_PATH); + r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_ADDRESS); if (r < 0) return r; @@ -571,7 +573,7 @@ int bus_open_user_systemd(sd_bus **_bus) { if (r < 0) return r; - if (asprintf(&bus->address, KERNEL_USER_BUS_FMT, getuid()) < 0) + if (asprintf(&bus->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()) < 0) return -ENOMEM; bus->bus_client = true; @@ -637,8 +639,15 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { if (r < 0) return r; - if (all || !isempty(s)) - printf("%s=%s\n", name, s); + if (all || !isempty(s)) { + _cleanup_free_ char *escaped = NULL; + + escaped = xescape(s, "\n"); + if (!escaped) + return -ENOMEM; + + printf("%s=%s\n", name, escaped); + } return 1; } @@ -729,10 +738,16 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { return r; while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) { + _cleanup_free_ char *escaped = NULL; + if (first) printf("%s=", name); - printf("%s%s", first ? "" : " ", str); + escaped = xescape(str, "\n "); + if (!escaped) + return -ENOMEM; + + printf("%s%s", first ? "" : " ", escaped); first = false; } @@ -1140,8 +1155,8 @@ int bus_open_transport(BusTransport transport, const char *host, bool user, sd_b r = sd_bus_open_system_remote(bus, host); break; - case BUS_TRANSPORT_CONTAINER: - r = sd_bus_open_system_container(bus, host); + case BUS_TRANSPORT_MACHINE: + r = sd_bus_open_system_machine(bus, host); break; default: @@ -1175,8 +1190,8 @@ int bus_open_transport_systemd(BusTransport transport, const char *host, bool us r = sd_bus_open_system_remote(bus, host); break; - case BUS_TRANSPORT_CONTAINER: - r = sd_bus_open_system_container(bus, host); + case BUS_TRANSPORT_MACHINE: + r = sd_bus_open_system_machine(bus, host); break; default: @@ -1247,13 +1262,11 @@ int bus_property_get_ulong( #endif int bus_log_parse_error(int r) { - log_error("Failed to parse bus message: %s", strerror(-r)); - return r; + return log_error_errno(r, "Failed to parse bus message: %m"); } int bus_log_create_error(int r) { - log_error("Failed to create bus message: %s", strerror(-r)); - return r; + return log_error_errno(r, "Failed to create bus message: %m"); } int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) { @@ -1358,7 +1371,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen if (STR_IN_SET(field, "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", - "SendSIGHUP", "SendSIGKILL")) { + "SendSIGHUP", "SendSIGKILL", + "WakeSystem")) { r = parse_boolean(eq); if (r < 0) { @@ -1519,6 +1533,17 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "i", sig); + } else if (streq(field, "AccuracySec")) { + usec_t u; + + r = parse_sec(eq, &u); + if (r < 0) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "t", u); + } else { log_error("Unknown assignment %s.", assignment); return -EINVAL; @@ -1529,3 +1554,251 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return 0; } + +typedef struct BusWaitForJobs { + sd_bus *bus; + Set *jobs; + + char *name; + char *result; + + sd_bus_slot *slot_job_removed; + sd_bus_slot *slot_disconnected; +} BusWaitForJobs; + +static int match_disconnected(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + assert(bus); + assert(m); + + log_error("Warning! D-Bus connection terminated."); + sd_bus_close(bus); + + return 0; +} + +static int match_job_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + const char *path, *unit, *result; + BusWaitForJobs *d = userdata; + uint32_t id; + char *found; + int r; + + assert(bus); + assert(m); + assert(d); + + r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result); + if (r < 0) { + bus_log_parse_error(r); + return 0; + } + + found = set_remove(d->jobs, (char*) path); + if (!found) + return 0; + + free(found); + + if (!isempty(result)) + d->result = strdup(result); + + if (!isempty(unit)) + d->name = strdup(unit); + + return 0; +} + +void bus_wait_for_jobs_free(BusWaitForJobs *d) { + if (!d) + return; + + set_free_free(d->jobs); + + sd_bus_slot_unref(d->slot_disconnected); + sd_bus_slot_unref(d->slot_job_removed); + + sd_bus_unref(d->bus); + + free(d->name); + free(d->result); + + free(d); +} + +int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) { + _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL; + int r; + + assert(bus); + assert(ret); + + d = new0(BusWaitForJobs, 1); + if (!d) + return -ENOMEM; + + d->bus = sd_bus_ref(bus); + + r = sd_bus_add_match( + bus, + &d->slot_job_removed, + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.systemd1.Manager'," + "member='JobRemoved'," + "path='/org/freedesktop/systemd1'", + match_job_removed, d); + if (r < 0) + return r; + + r = sd_bus_add_match( + bus, + &d->slot_disconnected, + "type='signal'," + "sender='org.freedesktop.DBus.Local'," + "interface='org.freedesktop.DBus.Local'," + "member='Disconnected'", + match_disconnected, d); + if (r < 0) + return r; + + *ret = d; + d = NULL; + + return 0; +} + +static int bus_process_wait(sd_bus *bus) { + int r; + + for (;;) { + r = sd_bus_process(bus, NULL); + if (r < 0) + return r; + if (r > 0) + return 0; + + r = sd_bus_wait(bus, (uint64_t) -1); + if (r < 0) + return r; + } +} + +static int check_wait_response(BusWaitForJobs *d, bool quiet) { + int r = 0; + + assert(d->result); + + if (!quiet) { + 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; + + quotes = chars_intersect(d->name, SHELL_NEED_QUOTES); + + log_error("Job for %s failed. See \"systemctl status %s%s%s\" and \"journalctl -xe\" for details.", + d->name, + quotes ? "'" : "", d->name, quotes ? "'" : ""); + } else + log_error("Job failed. See \"journalctl -xe\" for details."); + } + } + + 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; + + return r; +} + +int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet) { + int r = 0; + + assert(d); + + while (!set_isempty(d->jobs)) { + int q; + + q = bus_process_wait(d->bus); + if (q < 0) + return log_error_errno(q, "Failed to wait for response: %m"); + + if (d->result) { + q = check_wait_response(d, quiet); + /* Return the first error as it is most likely to be + * meaningful. */ + if (q < 0 && r == 0) + r = q; + + log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name)); + } + + free(d->name); + d->name = NULL; + + free(d->result); + d->result = NULL; + } + + return r; +} + +int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) { + int r; + + assert(d); + + r = set_ensure_allocated(&d->jobs, &string_hash_ops); + if (r < 0) + return r; + + return set_put_strdup(d->jobs, path); +} + +int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) { + const char *type, *path, *source; + int r; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) { + if (!quiet) { + if (streq(type, "symlink")) + log_info("Created symlink from %s to %s.", path, source); + else + log_info("Removed symlink %s.", path); + } + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + return 0; +}