X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fbus-util.c;h=30ee67e85050ab63d96f31653b9b6272e6db6fbc;hp=bd005262ebc9d0cb082c7f68b6ad58dac445b541;hb=9f97c93671554dd3c46588b7c31031d26440ba34;hpb=537220d9102a12aa4a65d5479130ac2cdb323fff diff --git a/src/libsystemd-bus/bus-util.c b/src/libsystemd-bus/bus-util.c index bd005262e..30ee67e85 100644 --- a/src/libsystemd-bus/bus-util.c +++ b/src/libsystemd-bus/bus-util.c @@ -35,30 +35,48 @@ #include "bus-util.h" #include "bus-internal.h" -static int quit_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { +static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { sd_event *e = userdata; assert(bus); assert(m); assert(e); - sd_event_request_quit(e); + sd_event_exit(e, 0); return 1; } -int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name) { +int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) { _cleanup_free_ char *match = NULL; + const char *unique; int r; assert(e); assert(bus); assert(name); - r = asprintf(&match, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameLost',arg0='%s'", name); + /* We unregister the name here and then wait for the + * NameOwnerChanged signal for this event to arrive before we + * quit. We do this in order to make sure that any queued + * requests are still processed before we really exit. */ + + r = sd_bus_get_unique_name(bus, &unique); if (r < 0) return r; - r = sd_bus_add_match(bus, match, quit_callback, e); + r = asprintf(&match, + "sender='org.freedesktop.DBus'," + "type='signal'," + "interface='org.freedesktop.DBus'," + "member='NameOwnerChanged'," + "path='/org/freedesktop/DBus'," + "arg0='%s'," + "arg1='%s'," + "arg2=''", name, unique); + if (r < 0) + return -ENOMEM; + + r = sd_bus_add_match(bus, match, name_owner_change_callback, e); if (r < 0) return r; @@ -66,15 +84,12 @@ int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name) { if (r < 0) return r; - if (r != SD_BUS_NAME_RELEASED) - return -EIO; - return 0; } int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout) { bool exiting = false; - int r; + int r, code; assert(e); assert(bus); @@ -93,7 +108,7 @@ int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t return r; if (r == 0 && !exiting) { - r = bus_async_unregister_and_quit(e, bus, name); + r = bus_async_unregister_and_exit(e, bus, name); if (r < 0) return r; @@ -101,7 +116,11 @@ int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t } } - return 0; + r = sd_event_get_exit_code(e, &code); + if (r < 0) + return r; + + return code; } int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) { @@ -439,21 +458,43 @@ int bus_open_system_systemd(sd_bus **_bus) { if (geteuid() != 0) return sd_bus_open_system(_bus); - /* If we are root, then let's talk directly to the system - * instance, instead of going via the bus */ + /* If we are root and kdbus is not available, then let's talk + * directly to the system instance, instead of going via the + * bus */ +#ifdef ENABLE_KDBUS r = sd_bus_new(&bus); if (r < 0) return r; - r = sd_bus_set_address(bus, "unix:path=/run/systemd/private"); + r = sd_bus_set_address(bus, "kernel:path=/dev/kdbus/0-system/bus"); if (r < 0) return r; + bus->bus_client = true; + r = sd_bus_start(bus); + if (r >= 0) { + *_bus = bus; + bus = NULL; + return 0; + } + + bus = sd_bus_unref(bus); +#endif + + r = sd_bus_new(&bus); if (r < 0) return r; + r = sd_bus_set_address(bus, "unix:path=/run/systemd/private"); + if (r < 0) + return r; + + r = sd_bus_start(bus); + if (r < 0) + return sd_bus_open_system(_bus); + r = bus_check_peercred(bus); if (r < 0) return r; @@ -466,34 +507,53 @@ int bus_open_system_systemd(sd_bus **_bus) { int bus_open_user_systemd(sd_bus **_bus) { _cleanup_bus_unref_ sd_bus *bus = NULL; - _cleanup_free_ char *p = NULL; + _cleanup_free_ char *ee = NULL; const char *e; int r; - /* If we are supposed to talk to the instance, try via - * XDG_RUNTIME_DIR first, then fallback to normal bus - * access */ + /* Try via kdbus first, and then directly */ assert(_bus); +#ifdef ENABLE_KDBUS + r = sd_bus_new(&bus); + if (r < 0) + return r; + + if (asprintf(&bus->address, "kernel:path=/dev/kdbus/%lu-user/bus", (unsigned long) getuid()) < 0) + return -ENOMEM; + + bus->bus_client = true; + + r = sd_bus_start(bus); + if (r >= 0) { + *_bus = bus; + bus = NULL; + return 0; + } + + bus = sd_bus_unref(bus); +#endif + e = secure_getenv("XDG_RUNTIME_DIR"); if (!e) - return sd_bus_open_user(_bus); + return sd_bus_open_system(_bus); - if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0) + ee = bus_address_escape(e); + if (!ee) return -ENOMEM; r = sd_bus_new(&bus); if (r < 0) return r; - r = sd_bus_set_address(bus, p); - if (r < 0) - return r; + bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL); + if (!bus->address) + return -ENOMEM; r = sd_bus_start(bus); if (r < 0) - return r; + return sd_bus_open_system(_bus); r = bus_check_peercred(bus); if (r < 0) @@ -890,7 +950,8 @@ int bus_map_all_properties(sd_bus *bus, assert(path); assert(map); - r = sd_bus_call_method( bus, + r = sd_bus_call_method( + bus, destination, path, "org.freedesktop.DBus.Properties",