diff options
author | Lennart Poettering <lennart@poettering.net> | 2013-11-19 21:12:59 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2013-11-20 20:52:36 +0100 |
commit | 718db96199eb307751264e4163555662c9a389fa (patch) | |
tree | 9ec8467596ba1acba76bb6273c7797baf68c1a00 | |
parent | 3febea3a0b0a968ea281e7959c1654cbaf95c9bf (diff) |
core: convert PID 1 to libsystemd-bus
This patch converts PID 1 to libsystemd-bus and thus drops the
dependency on libdbus. The only remaining code using libdbus is a test
case that validates our bus marshalling against libdbus' marshalling,
and this dependency can be turned off.
This patch also adds a couple of things to libsystem-bus, that are
necessary to make the port work:
- Synthesizing of "Disconnected" messages when bus connections are
severed.
- Support for attaching multiple vtables for the same interface on the
same path.
This patch also fixes the SetDefaultTarget() and GetDefaultTarget() bus
calls which used an inappropriate signature.
As a side effect we will now generate PropertiesChanged messages which
carry property contents, rather than just invalidation information.
106 files changed, 6153 insertions, 9243 deletions
diff --git a/Makefile.am b/Makefile.am index 82e46a98b5..f7fe96c35c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -662,16 +662,19 @@ libsystemd_shared_la_SOURCES = \ src/shared/linux/fanotify.h \ src/shared/linux/seccomp.h \ src/shared/linux/seccomp-bpf.h \ + src/shared/ioprio.h \ src/shared/missing.h \ src/shared/list.h \ src/shared/macro.h \ src/shared/def.h \ + src/shared/sparse-endian.h \ + src/shared/refcnt.h \ + src/shared/udev-util.h \ + src/shared/bus-errors.h \ src/shared/device-nodes.c \ src/shared/device-nodes.h \ - src/shared/sparse-endian.h \ src/shared/util.c \ src/shared/util.h \ - src/shared/udev-util.h \ src/shared/virt.c \ src/shared/virt.h \ src/shared/efivars.c \ @@ -712,7 +715,6 @@ libsystemd_shared_la_SOURCES = \ src/shared/gunicode.h \ src/shared/pager.c \ src/shared/pager.h \ - src/shared/ioprio.h \ src/shared/socket-util.c \ src/shared/socket-util.h \ src/shared/conf-files.c \ @@ -748,7 +750,6 @@ libsystemd_shared_la_SOURCES = \ src/shared/acpi-fpdt.c \ src/shared/boot-timestamps.h \ src/shared/boot-timestamps.c \ - src/shared/refcnt.h \ src/shared/mkdir.c \ src/shared/mkdir.h \ src/shared/smack-util.c \ @@ -762,21 +763,6 @@ libsystemd_shared_la_SOURCES = \ src/shared/net-util.c \ src/shared/net-util.h -#------------------------------------------------------------------------------- -noinst_LTLIBRARIES += \ - libsystemd-dbus.la - -libsystemd_dbus_la_SOURCES = \ - src/shared/dbus-common.c \ - src/shared/dbus-common.h - -libsystemd_dbus_la_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) - -libsystemd_dbus_la_LIBADD = \ - $(DBUS_LIBS) - # ------------------------------------------------------------------------------ noinst_LTLIBRARIES += \ libsystemd-units.la @@ -792,8 +778,7 @@ libsystemd_units_la_SOURCES = \ src/shared/specifier.h libsystemd_units_la_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) + $(AM_CFLAGS) # ------------------------------------------------------------------------------ noinst_LTLIBRARIES += \ @@ -953,6 +938,8 @@ libsystemd_core_la_SOURCES = \ src/core/dbus-kill.h \ src/core/dbus-cgroup.c \ src/core/dbus-cgroup.h \ + src/core/dbus-client-track.c \ + src/core/dbus-client-track.h \ src/core/cgroup.c \ src/core/cgroup.h \ src/core/selinux-access.c \ @@ -982,7 +969,6 @@ libsystemd_core_la_SOURCES = \ src/core/securebits.h \ src/core/initreq.h \ src/core/special.h \ - src/core/bus-errors.h \ src/core/build.h \ src/core/sysfs-show.h \ src/core/switch-root.h \ @@ -1010,7 +996,6 @@ nodist_libsystemd_core_la_SOURCES = \ libsystemd_core_la_CFLAGS = \ $(AM_CFLAGS) \ - $(DBUS_CFLAGS) \ $(LIBWRAP_CFLAGS) \ $(PAM_CFLAGS) \ $(AUDIT_CFLAGS) \ @@ -1021,13 +1006,13 @@ libsystemd_core_la_LIBADD = \ libsystemd-capability.la \ libsystemd-units.la \ libsystemd-label.la \ - libsystemd-dbus.la \ libsystemd-audit.la \ libsystemd-id128-internal.la \ libsystemd-daemon-internal.la \ libudev-internal.la \ libsystemd-shared.la \ libsystemd-rtnl.la \ + libsystemd-bus-internal.la \ $(LIBWRAP_LIBS) \ $(PAM_LIBS) \ $(AUDIT_LIBS) \ @@ -1072,10 +1057,6 @@ src/core/syscall-to-name.h: src/core/syscall-list.txt Makefile systemd_SOURCES = \ src/core/main.c -systemd_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) - systemd_LDADD = \ libsystemd-core.la \ $(RT_LIBS) @@ -1166,10 +1147,6 @@ test_device_nodes_LDADD = \ test_engine_SOURCES = \ src/test/test-engine.c -test_engine_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) - test_engine_LDADD = \ libsystemd-core.la \ $(RT_LIBS) @@ -1177,10 +1154,6 @@ test_engine_LDADD = \ test_job_type_SOURCES = \ src/test/test-job-type.c -test_job_type_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) - test_job_type_LDADD = \ libsystemd-core.la \ $(RT_LIBS) @@ -1191,10 +1164,6 @@ test_ns_SOURCES = \ test_ns_LDADD = \ libsystemd-core.la -test_ns_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) - test_loopback_SOURCES = \ src/test/test-loopback.c @@ -1221,10 +1190,6 @@ endif test_unit_name_SOURCES = \ src/test/test-unit-name.c -test_unit_name_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) - test_unit_name_LDADD = \ libsystemd-core.la \ $(RT_LIBS) @@ -1232,10 +1197,6 @@ test_unit_name_LDADD = \ test_unit_file_SOURCES = \ src/test/test-unit-file.c -test_unit_file_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) - test_unit_file_LDADD = \ libsystemd-core.la \ $(RT_LIBS) @@ -1274,10 +1235,6 @@ test_tables_SOURCES = \ src/test/test-tables.c \ src/shared/test-tables.h -test_tables_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) - test_tables_LDADD = \ libsystemd-logs.la \ libsystemd-journal-internal.la \ @@ -1401,10 +1358,6 @@ test_strxcpyx_LDADD = \ test_install_SOURCES = \ src/test/test-install.c -test_install_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) - test_install_LDADD = \ libsystemd-units.la \ libsystemd-label.la \ @@ -1422,7 +1375,6 @@ test_sched_prio_SOURCES = \ test_sched_prio_CFLAGS = \ $(AM_CFLAGS) \ - $(DBUS_CFLAGS) \ -D"STR(s)=\#s" -D"TEST_DIR=STR($(abs_top_srcdir)/test/)" test_sched_prio_LDADD = \ @@ -2800,9 +2752,6 @@ mtd_probe_SOURCES = \ src/udev/mtd_probe/mtd_probe.h \ src/udev/mtd_probe/probe_smartmedia.c -mtd_probe_CPPFLAGS = \ - $(AM_CPPFLAGS) - dist_udevrules_DATA += \ rules/75-probe_mtd.rules @@ -3893,7 +3842,6 @@ systemd_logind_LDADD = \ libsystemd_logind_core_la_SOURCES = \ src/login/logind-core.c \ - src/login/logind-dbus.c \ src/login/logind-device.c \ src/login/logind-device.h \ src/login/logind-button.c \ @@ -3910,6 +3858,7 @@ libsystemd_logind_core_la_SOURCES = \ src/login/logind-user.h \ src/login/logind-inhibit.c \ src/login/logind-inhibit.h \ + src/login/logind-dbus.c \ src/login/logind-session-dbus.c \ src/login/logind-seat-dbus.c \ src/login/logind-user-dbus.c \ @@ -43,6 +43,53 @@ CGroup Rework Completion: Features: +* sd-event: allow multiple signal handlers per signal + +* timer: expose accuracy as unit setting + +* sd-event: do per-minute coalescing of timer events too + +* when we detect low battery and no AC on boot, show pretty splash and refuse boot + +* move libasyncns into systemd as libsystemd-asyncns + +* calendarspec: support value ranges with ".." notation. Example: 2013-4..8-1 + +* pid1 porting: + - restore selinux access control on properties + +* sd-bus: when triggering property change events, allow a NULL strv indicate that all properties listed as such are send out as changed + +* sd-bus: enforce signatures on response messages + +* sd-bus: make message handlers take an sd_bus_error and generate error replies automatically if they are set + +* sd-bus: when replying to a bus message we should not need to specify the bus again + +* sd-bus: see if we can drop more message validation on the sending side + +* sd-bus: introduce sd_bus_creds object and attach it to messages as well as allow querying it for names + +* sd-bus: support "const" properties as flag + +* sd-bus: add api call to escape bus path components + +* sd-event: when a handler returns an error, just turn off its event + source, but do not return anything up to the event loop + caller. Instead add parameter to sd_event_request_quit() to take + retval. This way errors rippling upwards are the option, not the + default + +* sd-event: child pid handling: first invoke waitid(WNOHANG) and call event handler, only afterwards reap the process + +* sd-event: native support for watchdog stuff + +* machined, localed: when we try to kill an empty cgroup, generate an ESRCH call over the bus + +* sd-bus: SD_BUS_COMMENT() macro for inclusion in vtables, syntax inspired by gdbus + +* libsystemd-journal, libsystemd-login, libudev: add calls to easily attach these objects to sd-event event loops + * be more careful what we export on the bus as (usec_t) 0 and (usec_t) -1 * check :no-sender logic after PID 1 conversion diff --git a/src/core/automount.c b/src/core/automount.c index d1379e0913..49a64b124f 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -35,13 +35,13 @@ #include "load-fragment.h" #include "load-dropin.h" #include "unit-name.h" -#include "dbus-automount.h" -#include "bus-errors.h" #include "special.h" #include "label.h" #include "mkdir.h" #include "path-util.h" -#include "dbus-common.h" +#include "dbus-automount.h" +#include "bus-util.h" +#include "bus-error.h" static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = { [AUTOMOUNT_DEAD] = UNIT_INACTIVE, @@ -51,6 +51,7 @@ static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = { }; static int open_dev_autofs(Manager *m); +static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata); static void automount_init(Unit *u) { Automount *a = AUTOMOUNT(u); @@ -58,11 +59,8 @@ static void automount_init(Unit *u) { assert(u); assert(u->load_state == UNIT_STUB); - a->pipe_watch.fd = a->pipe_fd = -1; - a->pipe_watch.type = WATCH_INVALID; - + a->pipe_fd = -1; a->directory_mode = 0755; - UNIT(a)->ignore_on_isolate = true; } @@ -91,7 +89,8 @@ static void unmount_autofs(Automount *a) { automount_send_ready(a, -EHOSTDOWN); - unit_unwatch_fd(UNIT(a), &a->pipe_watch); + a->pipe_event_source = sd_event_source_unref(a->pipe_event_source); + close_nointr_nofail(a->pipe_fd); a->pipe_fd = -1; @@ -257,7 +256,7 @@ static int automount_coldplug(Unit *u) { assert(a->pipe_fd >= 0); - r = unit_watch_fd(UNIT(a), a->pipe_fd, EPOLLIN, &a->pipe_watch); + r = sd_event_add_io(u->manager->event, a->pipe_fd, EPOLLIN, automount_dispatch_io, u, &a->pipe_event_source); if (r < 0) return r; } @@ -532,7 +531,7 @@ static void automount_enter_waiting(Automount *a) { close_nointr_nofail(ioctl_fd); ioctl_fd = -1; - r = unit_watch_fd(UNIT(a), p[0], EPOLLIN, &a->pipe_watch); + r = sd_event_add_io(UNIT(a)->manager->event, p[0], EPOLLIN, automount_dispatch_io, a, &a->pipe_event_source); if (r < 0) goto fail; @@ -558,14 +557,12 @@ fail: } static void automount_enter_runnning(Automount *a) { - _cleanup_dbus_error_free_ DBusError error; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; struct stat st; int r; assert(a); - dbus_error_init(&error); - /* We don't take mount requests anymore if we are supposed to * shut down anyway */ if (unit_stop_pending(UNIT(a))) { @@ -593,7 +590,7 @@ static void automount_enter_runnning(Automount *a) { if (r < 0) { log_warning_unit(UNIT(a)->id, "%s failed to queue mount startup job: %s", - UNIT(a)->id, bus_error(&error, r)); + UNIT(a)->id, bus_error_message(&error, r)); goto fail; } } @@ -748,9 +745,9 @@ static bool automount_check_gc(Unit *u) { return UNIT_VTABLE(UNIT_TRIGGER(u))->check_gc(UNIT_TRIGGER(u)); } -static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { - Automount *a = AUTOMOUNT(u); +static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) { union autofs_v5_packet_union packet; + Automount *a = AUTOMOUNT(userdata); ssize_t l; int r; @@ -758,13 +755,13 @@ static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { assert(fd == a->pipe_fd); if (events != EPOLLIN) { - log_error_unit(u->id, "Got invalid poll event on pipe."); + log_error_unit(UNIT(a)->id, "Got invalid poll event on pipe."); goto fail; } l = loop_read(a->pipe_fd, &packet, sizeof(packet), true); if (l != sizeof(packet)) { - log_error_unit(u->id, "Invalid read from pipe: %s", l < 0 ? strerror(-l) : "short read"); + log_error_unit(UNIT(a)->id, "Invalid read from pipe: %s", l < 0 ? strerror(-l) : "short read"); goto fail; } @@ -776,21 +773,21 @@ static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { _cleanup_free_ char *p = NULL; get_process_comm(packet.v5_packet.pid, &p); - log_debug_unit(u->id, + log_debug_unit(UNIT(a)->id, "Got direct mount request on %s, triggered by %lu (%s)", a->where, (unsigned long) packet.v5_packet.pid, strna(p)); } else - log_debug_unit(u->id, "Got direct mount request on %s", a->where); + log_debug_unit(UNIT(a)->id, "Got direct mount request on %s", a->where); r = set_ensure_allocated(&a->tokens, trivial_hash_func, trivial_compare_func); if (r < 0) { - log_error_unit(u->id, "Failed to allocate token set."); + log_error_unit(UNIT(a)->id, "Failed to allocate token set."); goto fail; } r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token)); if (r < 0) { - log_error_unit(u->id, "Failed to remember token: %s", strerror(-r)); + log_error_unit(UNIT(a)->id, "Failed to remember token: %s", strerror(-r)); goto fail; } @@ -798,14 +795,15 @@ static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { break; default: - log_error_unit(u->id, "Received unknown automount request %i", packet.hdr.type); + log_error_unit(UNIT(a)->id, "Received unknown automount request %i", packet.hdr.type); break; } - return; + return 0; fail: automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES); + return 0; } static void automount_shutdown(Manager *m) { @@ -844,6 +842,7 @@ DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult); const UnitVTable automount_vtable = { .object_size = sizeof(Automount), + .sections = "Unit\0" "Automount\0" @@ -871,13 +870,11 @@ const UnitVTable automount_vtable = { .check_gc = automount_check_gc, - .fd_event = automount_fd_event, - .reset_failed = automount_reset_failed, .bus_interface = "org.freedesktop.systemd1.Automount", - .bus_message_handler = bus_automount_message_handler, - .bus_invalidating_properties = bus_automount_invalidating_properties, + .bus_vtable = bus_automount_vtable, + .bus_changing_properties = bus_automount_changing_properties, .shutdown = automount_shutdown, diff --git a/src/core/automount.h b/src/core/automount.h index a7a25d34e0..60f5522389 100644 --- a/src/core/automount.h +++ b/src/core/automount.h @@ -49,8 +49,8 @@ struct Automount { char *where; int pipe_fd; + sd_event_source *pipe_event_source; mode_t directory_mode; - Watch pipe_watch; dev_t dev_id; Set *tokens; diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c index 720f9ba6d1..420cfaa331 100644 --- a/src/core/dbus-automount.c +++ b/src/core/dbus-automount.c @@ -19,57 +19,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> - +#include "unit.h" +#include "automount.h" #include "dbus-unit.h" #include "dbus-automount.h" -#include "dbus-common.h" -#include "selinux-access.h" - -#define BUS_AUTOMOUNT_INTERFACE \ - " <interface name=\"org.freedesktop.systemd1.Automount\">\n" \ - " <property name=\"Where\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \ - " </interface>\n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "<node>\n" \ - BUS_UNIT_INTERFACE \ - BUS_AUTOMOUNT_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "</node>\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Automount\0" - -const char bus_automount_interface[] = BUS_AUTOMOUNT_INTERFACE; +#include "bus-util.h" -const char bus_automount_invalidating_properties[] = - "Result\0"; +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, automount_result, AutomountResult); -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_automount_append_automount_result, automount_result, AutomountResult); - -static const BusProperty bus_automount_properties[] = { - { "Where", bus_property_append_string, "s", offsetof(Automount, where), true }, - { "DirectoryMode", bus_property_append_mode, "u", offsetof(Automount, directory_mode) }, - { "Result", bus_automount_append_automount_result, "s", offsetof(Automount, result) }, - { NULL, } +const sd_bus_vtable bus_automount_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Where", "s", NULL, offsetof(Automount, where), 0), + SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Automount, directory_mode), 0), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Automount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_VTABLE_END }; -DBusHandlerResult bus_automount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - Automount *am = AUTOMOUNT(u); - const BusBoundProperties bps[] = { - { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, - { "org.freedesktop.systemd1.Automount", bus_automount_properties, am }, - { NULL, } - }; - - SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status"); - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps); -} +const char* const bus_automount_changing_properties[] = { + "Result", + NULL +}; diff --git a/src/core/dbus-automount.h b/src/core/dbus-automount.h index b338e25fc1..0b9618368e 100644 --- a/src/core/dbus-automount.h +++ b/src/core/dbus-automount.h @@ -21,11 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> +#include "sd-bus.h" -#include "unit.h" - -DBusHandlerResult bus_automount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_automount_interface[]; -extern const char bus_automount_invalidating_properties[]; +extern const sd_bus_vtable bus_automount_vtable[]; +extern const char* const bus_automount_changing_properties[]; diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index f198357637..4dbb83a769 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -19,147 +19,159 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> - +#include "bus-util.h" #include "path-util.h" +#include "cgroup-util.h" +#include "cgroup.h" #include "dbus-cgroup.h" -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_cgroup_append_device_policy, cgroup_device_policy, CGroupDevicePolicy); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy); + +static int property_get_blockio_device_weight( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { -static int bus_cgroup_append_device_weights(DBusMessageIter *i, const char *property, void *data) { - DBusMessageIter sub, sub2; - CGroupContext *c = data; + CGroupContext *c = userdata; CGroupBlockIODeviceWeight *w; + int r; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(c); - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(st)", &sub)) - return -ENOMEM; + r = sd_bus_message_open_container(reply, 'a', "(st)"); + if (r < 0) + return r; LIST_FOREACH(device_weights, w, c->blockio_device_weights) { - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &w->path) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &w->weight) || - !dbus_message_iter_close_container(&sub, &sub2)) - return -ENOMEM; + r = sd_bus_message_append(reply, "(st)", w->path, w->weight); + if (r < 0) + return r; } - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; + return sd_bus_message_close_container(reply); } -static int bus_cgroup_append_device_bandwidths(DBusMessageIter *i, const char *property, void *data) { - DBusMessageIter sub, sub2; - CGroupContext *c = data; +static int property_get_blockio_device_bandwidths( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + CGroupContext *c = userdata; CGroupBlockIODeviceBandwidth *b; + int r; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(c); - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(st)", &sub)) - return -ENOMEM; + r = sd_bus_message_open_container(reply, 'a', "(st)"); + if (r < 0) + return r; LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) { if (streq(property, "BlockIOReadBandwidth") != b->read) continue; - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &b->path) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &b->bandwidth) || - !dbus_message_iter_close_container(&sub, &sub2)) - return -ENOMEM; + r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth); + if (r < 0) + return r; } - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; + return sd_bus_message_close_container(reply); } -static int bus_cgroup_append_device_allow(DBusMessageIter *i, const char *property, void *data) { - DBusMessageIter sub, sub2; - CGroupContext *c = data; +static int property_get_device_allow( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + CGroupContext *c = userdata; CGroupDeviceAllow *a; + int r; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(c); - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &sub)) - return -ENOMEM; + r = sd_bus_message_open_container(reply, 'a', "(ss)"); + if (r < 0) + return r; LIST_FOREACH(device_allow, a, c->device_allow) { - const char *rwm; - char buf[4]; unsigned k = 0; + char rwm[4]; if (a->r) - buf[k++] = 'r'; + rwm[k++] = 'r'; if (a->w) - buf[k++] = 'w'; + rwm[k++] = 'w'; if (a->m) - buf[k++] = 'm'; + rwm[k++] = 'm'; - buf[k] = 0; - rwm = buf; + rwm[k] = 0; - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->path) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &rwm) || - !dbus_message_iter_close_container(&sub, &sub2)) - return -ENOMEM; + r = sd_bus_message_append(reply, "(ss)", a->path, rwm); + if (r < 0) + return r; } - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; + return sd_bus_message_close_container(reply); } -const BusProperty bus_cgroup_context_properties[] = { - { "CPUAccounting", bus_property_append_bool, "b", offsetof(CGroupContext, cpu_accounting) }, - { "CPUShares", bus_property_append_ul, "t", offsetof(CGroupContext, cpu_shares) }, - { "BlockIOAccounting", bus_property_append_bool, "b", offsetof(CGroupContext, blockio_accounting) }, - { "BlockIOWeight", bus_property_append_ul, "t", offsetof(CGroupContext, blockio_weight) }, - { "BlockIODeviceWeight", bus_cgroup_append_device_weights, "a(st)", 0 }, - { "BlockIOReadBandwidth", bus_cgroup_append_device_bandwidths, "a(st)", 0 }, - { "BlockIOWriteBandwidth", bus_cgroup_append_device_bandwidths, "a(st)", 0 }, - { "MemoryAccounting", bus_property_append_bool, "b", offsetof(CGroupContext, memory_accounting) }, - { "MemoryLimit", bus_property_append_uint64, "t", offsetof(CGroupContext, memory_limit) }, - { "DevicePolicy", bus_cgroup_append_device_policy, "s", offsetof(CGroupContext, device_policy) }, - { "DeviceAllow", bus_cgroup_append_device_allow, "a(ss)", 0 }, - {} +const sd_bus_vtable bus_cgroup_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0), + SD_BUS_PROPERTY("CPUShares", "t", bus_property_get_ulong, offsetof(CGroupContext, cpu_shares), 0), + SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0), + SD_BUS_PROPERTY("BlockIOWeight", "t", bus_property_get_ulong, offsetof(CGroupContext, blockio_weight), 0), + SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0), + SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), + SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), + SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0), + SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0), + SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0), + SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0), + SD_BUS_VTABLE_END }; int bus_cgroup_set_property( Unit *u, CGroupContext *c, const char *name, - DBusMessageIter *i, + sd_bus_message *message, UnitSetPropertiesMode mode, - DBusError *error) { + sd_bus_error *error) { + + int r; - assert(name); assert(u); assert(c); - assert(i); + assert(name); + assert(message); if (streq(name, "CPUAccounting")) { + int b; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN) - return -EINVAL; + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; if (mode != UNIT_CHECK) { - dbus_bool_t b; - dbus_message_iter_get_basic(i, &b); - c->cpu_accounting = b; unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no"); } @@ -170,14 +182,13 @@ int bus_cgroup_set_property( uint64_t u64; unsigned long ul; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64) - return -EINVAL; + r = sd_bus_message_read(message, "t", &u64); + if (r < 0) + return r; - dbus_message_iter_get_basic(i, &u64); ul = (unsigned long) u64; - - if (u64 <= 0 || u64 != (uint64_t) ul) - return -EINVAL; + if (ul <= 0 || (uint64_t) ul != u64) + return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range"); if (mode != UNIT_CHECK) { c->cpu_shares = ul; @@ -187,14 +198,13 @@ int bus_cgroup_set_property( return 1; } else if (streq(name, "BlockIOAccounting")) { + int b; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN) - return -EINVAL; + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; if (mode != UNIT_CHECK) { - dbus_bool_t b; - dbus_message_iter_get_basic(i, &b); - c->blockio_accounting = b; unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no"); } @@ -205,14 +215,13 @@ int bus_cgroup_set_property( uint64_t u64; unsigned long ul; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64) - return -EINVAL; + r = sd_bus_message_read(message, "t", &u64); + if (r < 0) + return r; - dbus_message_iter_get_basic(i, &u64); ul = (unsigned long) u64; - - if (u64 < 10 || u64 > 1000) - return -EINVAL; + if (ul < 10 || ul > 1000) + return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range"); if (mode != UNIT_CHECK) { c->blockio_weight = ul; @@ -222,42 +231,31 @@ int bus_cgroup_set_property( return 1; } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) { - DBusMessageIter sub; - unsigned n = 0; + const char *path; bool read = true; + unsigned n = 0; + uint64_t u64; if (streq(name, "BlockIOWriteBandwidth")) read = false; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT) - return -EINVAL; - - dbus_message_iter_recurse(i, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { - DBusMessageIter sub2; - const char *path; - uint64_t u64; + r = sd_bus_message_enter_container(message, 'a', "(st)"); + if (r < 0) + return r; - dbus_message_iter_recurse(&sub, &sub2); - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &u64, false) < 0) - return -EINVAL; + while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { if (mode != UNIT_CHECK) { - CGroupBlockIODeviceBandwidth *a = NULL; - CGroupBlockIODeviceBandwidth *b; - bool exist = false; + CGroupBlockIODeviceBandwidth *a = NULL, *b; LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) { if (path_equal(path, b->path) && read == b->read) { a = b; - exist = true; break; } } - if (!exist) { + if (!a) { a = new0(CGroupBlockIODeviceBandwidth, 1); if (!a) return -ENOMEM; @@ -268,23 +266,22 @@ int bus_cgroup_set_property( free(a); return -ENOMEM; } + + LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a); } a->bandwidth = u64; - - if (!exist) - LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a); } n++; - dbus_message_iter_next(&sub); } + if (r < 0) + return r; if (mode != UNIT_CHECK) { + CGroupBlockIODeviceBandwidth *a, *next; _cleanup_free_ char *buf = NULL; _cleanup_fclose_ FILE *f = NULL; - CGroupBlockIODeviceBandwidth *a; - CGroupBlockIODeviceBandwidth *next; size_t size = 0; if (n == 0) { @@ -316,44 +313,32 @@ int bus_cgroup_set_property( return 1; } else if (streq(name, "BlockIODeviceWeight")) { - DBusMessageIter sub; + const char *path; + uint64_t u64; unsigned n = 0; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT) - return -EINVAL; + r = sd_bus_message_enter_container(message, 'a', "(st)"); + if (r < 0) + return r; - dbus_message_iter_recurse(i, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { - DBusMessageIter sub2; - const char *path; - uint64_t u64; + while (( r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { unsigned long ul; - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &u64, false) < 0) - return -EINVAL; - ul = (unsigned long) u64; if (ul < 10 || ul > 1000) - return -EINVAL; + return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range"); if (mode != UNIT_CHECK) { - CGroupBlockIODeviceWeight *a = NULL; - CGroupBlockIODeviceWeight *b; - bool exist = false; + CGroupBlockIODeviceWeight *a = NULL, *b; LIST_FOREACH(device_weights, b, c->blockio_device_weights) { if (path_equal(b->path, path)) { a = b; - exist = true; break; } } - if (!exist) { + if (!a) { a = new0(CGroupBlockIODeviceWeight, 1); if (!a) return -ENOMEM; @@ -363,16 +348,13 @@ int bus_cgroup_set_property( free(a); return -ENOMEM; } + LIST_PREPEND(device_weights,c->blockio_device_weights, a); } a->weight = ul; - - if (!exist) - LIST_PREPEND(device_weights,c->blockio_device_weights, a); } n++; - dbus_message_iter_next(&sub); } if (mode != UNIT_CHECK) { @@ -401,14 +383,13 @@ int bus_cgroup_set_property( return 1; } else if (streq(name, "MemoryAccounting")) { + int b; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN) - return -EINVAL; + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; if (mode != UNIT_CHECK) { - dbus_bool_t b; - dbus_message_iter_get_basic(i, &b); - c->memory_accounting = b; unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no"); } @@ -416,14 +397,13 @@ int bus_cgroup_set_property( return 1; } else if (streq(name, "MemoryLimit")) { + uint64_t limit; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64) - return -EINVAL; + r = sd_bus_message_read(message, "t", &limit); + if (r < 0) + return r; if (mode != UNIT_CHECK) { - uint64_t limit; - dbus_message_iter_get_basic(i, &limit); - c->memory_limit = limit; unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit); } @@ -434,10 +414,10 @@ int bus_cgroup_set_property( const char *policy; CGroupDevicePolicy p; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) - return -EINVAL; + r = sd_bus_message_read(message, "s", &policy); + if (r < 0) + return r; - dbus_message_iter_get_basic(i, &policy); p = cgroup_device_policy_from_string(policy); if (p < 0) return -EINVAL; @@ -454,51 +434,35 @@ int bus_cgroup_set_property( return 1; } else if (streq(name, "DeviceAllow")) { - DBusMessageIter sub; + const char *path, *rwm; unsigned n = 0; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT) - return -EINVAL; - - dbus_message_iter_recurse(i, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { - DBusMessageIter sub2; - const char *path, *rwm; + r = sd_bus_message_enter_container(message, 'a', "(ss)"); + if (r < 0) + return r; - dbus_message_iter_recurse(&sub, &sub2); + while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) { - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &rwm, false) < 0) - return -EINVAL; - - if (!path_startswith(path, "/dev")) { - dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node"); - return -EINVAL; - } + if (!path_startswith(path, "/dev")) + return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node"); if (isempty(rwm)) rwm = "rwm"; - if (!in_charset(rwm, "rwm")) { - dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags"); - return -EINVAL; - } + if (!in_charset(rwm, "rwm")) + return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags"); if (mode != UNIT_CHECK) { - CGroupDeviceAllow *a = NULL; - CGroupDeviceAllow *b; - bool exist = false; + CGroupDeviceAllow *a = NULL, *b; LIST_FOREACH(device_allow, b, c->device_allow) { if (path_equal(b->path, path)) { a = b; - exist = true; break; } } - if (!exist) { + if (!a) { a = new0(CGroupDeviceAllow, 1); if (!a) return -ENOMEM; @@ -508,18 +472,17 @@ int bus_cgroup_set_property( free(a); return -ENOMEM; } + + LIST_PREPEND(device_allow, c->device_allow, a); } a->r = !!strchr(rwm, 'r'); a->w = !!strchr(rwm, 'w'); a->m = !!strchr(rwm, 'm'); - if (!exist) - LIST_PREPEND(device_allow, c->device_allow, a); } n++; - dbus_message_iter_next(&sub); } if (mode != UNIT_CHECK) { diff --git a/src/core/dbus-cgroup.h b/src/core/dbus-cgroup.h index e5ac4c3af7..c2a3910f3d 100644 --- a/src/core/dbus-cgroup.h +++ b/src/core/dbus-cgroup.h @@ -21,25 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> - -#include "manager.h" -#include "dbus-common.h" +#include "sd-bus.h" #include "cgroup.h" -#define BUS_CGROUP_CONTEXT_INTERFACE \ - " <property name=\"CPUAccounting\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"CPUShares\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"BlockIOAccounting\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"BlockIOWeight\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"BlockIODeviceWeight\" type=\"a(st)\" access=\"read\"/>\n" \ - " <property name=\"BlockIOReadBandwidth=\" type=\"a(st)\" access=\"read\"/>\n" \ - " <property name=\"BlockIOWriteBandwidth=\" type=\"a(st)\" access=\"read\"/>\n" \ - " <property name=\"MemoryAccounting\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"MemoryLimit\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"DevicePolicy\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"DeviceAllow\" type=\"a(ss)\" access=\"read\"/>\n" - -extern const BusProperty bus_cgroup_context_properties[]; - -int bus_cgroup_set_property(Unit *u, CGroupContext *c, const char *name, DBusMessageIter *i, UnitSetPropertiesMode mode, DBusError *error); +extern const sd_bus_vtable bus_cgroup_vtable[]; + +int bus_cgroup_set_property(Unit *u, CGroupContext *c, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); diff --git a/src/core/dbus-client-track.c b/src/core/dbus-client-track.c new file mode 100644 index 0000000000..ce514b577c --- /dev/null +++ b/src/core/dbus-client-track.c @@ -0,0 +1,250 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "dbus-client-track.h" + +static unsigned tracked_client_hash(const void *a) { + const BusTrackedClient *x = a; + + return string_hash_func(x->name) ^ PTR_TO_UINT(x->bus); +} + +static int tracked_client_compare(const void *a, const void *b) { + const BusTrackedClient *x = a, *y = b; + int r; + + r = strcmp(x->name, y->name); + if (r != 0) + return r; + + if (x->bus < y->bus) + return -1; + if (x->bus > y->bus) + return 1; + + return 0; +} + +static int on_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata) { + BusTrackedClient *c = userdata; + const char *name, *old, *new; + int r; + + assert(bus); + assert(message); + + r = sd_bus_message_read(message, "sss", &name, &old, &new); + if (r < 0) { + log_debug("Failed to parse NameOwnerChanged message."); + return 0; + } + + bus_client_untrack(c->set, bus, name); + return 0; +} + +static char *build_match(const char *name) { + + return strjoin("type='signal'," + "sender='org.freedesktop.DBus'," + "path='/org/freedesktop/DBus'," + "interface='org.freedesktop.DBus'," + "member='NameOwnerChanged'," + "arg0='", name, "'", NULL); +} + +int bus_client_track(Set **s, sd_bus *bus, const char *name) { + BusTrackedClient *c, *found; + size_t l; + int r; + + assert(s); + assert(bus); + + r = set_ensure_allocated(s, tracked_client_hash, tracked_client_compare); + if (r < 0) + return r; + + name = strempty(name); + + l = strlen(name); + + c = alloca(offsetof(BusTrackedClient, name) + l + 1); + c->set = *s; + c->bus = bus; + strcpy(c->name, name); + + found = set_get(*s, c); + if (found) + return 0; + + c = memdup(c, offsetof(BusTrackedClient, name) + l + 1); + if (!c) + return -ENOMEM; + + r = set_put(*s, c); + if (r < 0) { + free(c); + return r; + } + + if (!isempty(name)) { + _cleanup_free_ char *match = NULL; + + match = build_match(name); + if (!match) { + set_remove(*s, c); + free(c); + return -ENOMEM; + } + + r = sd_bus_add_match(bus, match, on_name_owner_changed, c); + if (r < 0) { + set_remove(*s, c); + free(c); + return r; + } + } + + sd_bus_ref(c->bus); + return 1; +} + +static void bus_client_free_one(Set *s, BusTrackedClient *c) { + assert(s); + assert(c); + + if (!isempty(c->name)) { + _cleanup_free_ char *match = NULL; + + match = build_match(c->name); + if (match) + sd_bus_remove_match(c->bus, match, on_name_owner_changed, c); + } + + sd_bus_unref(c->bus); + set_remove(s, c); + free(c); +} + +int bus_client_untrack(Set *s, sd_bus *bus, const char *name) { + BusTrackedClient *c, *found; + size_t l; + + assert(bus); + assert(s); + assert(name); + + name = strempty(name); + + l = strlen(name); + + c = alloca(offsetof(BusTrackedClient, name) + l + 1); + c->bus = bus; + strcpy(c->name, name); + + found = set_get(s, c); + if (!found) + return 0; + + bus_client_free_one(s, found); + return 1; +} + +void bus_client_track_free(Set *s) { + BusTrackedClient *c; + + while ((c = set_first(s))) + bus_client_free_one(s, c); + + set_free(s); +} + +int bus_client_untrack_bus(Set *s, sd_bus *bus) { + BusTrackedClient *c; + Iterator i; + int r = 0; + + SET_FOREACH(c, s, i) + if (c->bus == bus) { + bus_client_free_one(s, c); + r++; + } + + return r; +} + +void bus_client_track_serialize(Manager *m, FILE *f, Set *s) { + BusTrackedClient *c; + Iterator i; + + assert(m); + assert(f); + + SET_FOREACH(c, s, i) { + if (c->bus == m->api_bus) + fprintf(f, "subscribed=%s", isempty(c->name) ? "*" : c->name); + else + fprintf(f, "subscribed=%p %s", c->bus, isempty(c->name) ? "*" : c->name); + } +} + +int bus_client_track_deserialize_item(Manager *m, Set **s, const char *line) { + const char *e, *q, *name; + sd_bus *bus; + void *p; + int r; + + e = startswith(line, "subscribed="); + if (!e) + return 0; + + q = strpbrk(e, WHITESPACE); + if (!q) { + if (m->api_bus) { + bus = m->api_bus; + name = e; + goto finish; + } + + return 1; + } + + if (sscanf(e, "%p", &p) != 1) { + log_debug("Failed to parse subscription pointer."); + return -EINVAL; + } + + bus = set_get(m->private_buses, p); + if (!bus) + return 1; + + name = q + strspn(q, WHITESPACE); + +finish: + r = bus_client_track(s, bus, streq(name, "*") ? NULL : name); + if (r < 0) { + log_debug("Failed to deserialize client subscription: %s", strerror(-r)); + return r; + } + + return 1; +} diff --git a/src/core/dbus-client-track.h b/src/core/dbus-client-track.h new file mode 100644 index 0000000000..01676479b0 --- /dev/null +++ b/src/core/dbus-client-track.h @@ -0,0 +1,42 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "sd-bus.h" +#include "set.h" +#include "manager.h" + +typedef struct BusTrackedClient { + Set *set; + sd_bus *bus; + char name[0]; +} BusTrackedClient; + +int bus_client_track(Set **s, sd_bus *bus, const char *name); + +int bus_client_untrack(Set *s, sd_bus *bus, const char *name); +int bus_client_untrack_bus(Set *s, sd_bus *bus); + +void bus_client_track_free(Set *s); + +void bus_client_track_serialize(Manager *m, FILE *f, Set *s); +int bus_client_track_deserialize_item(Manager *m, Set **s, const char *line); diff --git a/src/core/dbus-device.c b/src/core/dbus-device.c index ef484a86b7..621bab0426 100644 --- a/src/core/dbus-device.c +++ b/src/core/dbus-device.c @@ -19,50 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "unit.h" +#include "device.h" #include "dbus-unit.h" #include "dbus-device.h" -#include "dbus-common.h" -#include "selinux-access.h" -#define BUS_DEVICE_INTERFACE \ - " <interface name=\"org.freedesktop.systemd1.Device\">\n" \ - " <property name=\"SysFSPath\" type=\"s\" access=\"read\"/>\n" \ - " </interface>\n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "<node>\n" \ - BUS_UNIT_INTERFACE \ - BUS_DEVICE_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "</node>\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Device\0" - -const char bus_device_interface[] = BUS_DEVICE_INTERFACE; - -const char bus_device_invalidating_properties[] = - "SysFSPath\0"; - -static const BusProperty bus_device_properties[] = { - { "SysFSPath", bus_property_append_string, "s", offsetof(Device, sysfs), true }, - { NULL, } +const sd_bus_vtable bus_device_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("SysFSPath", "s", NULL, offsetof(Device, sysfs), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_VTABLE_END }; - -DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - Device *d = DEVICE(u); - const BusBoundProperties bps[] = { - { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, - { "org.freedesktop.systemd1.Device", bus_device_properties, d }, - { NULL, } - }; - - SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status"); - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps); -} +const char* const bus_device_changing_properties[] = { + "SysFSPath", + NULL +}; diff --git a/src/core/dbus-device.h b/src/core/dbus-device.h index 311e0685d1..f248c28db3 100644 --- a/src/core/dbus-device.h +++ b/src/core/dbus-device.h @@ -21,11 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> - +#include "sd-bus.h" #include "unit.h" -DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_device_interface[]; -extern const char bus_device_invalidating_properties[]; +extern const sd_bus_vtable bus_device_vtable[]; +extern const char* const bus_device_changing_properties[]; diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 2402e8c34d..ca7ee5c10b 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -19,59 +19,102 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> -#include <dbus/dbus.h> #include <sys/prctl.h> -#include "dbus-execute.h" +#include "bus-util.h" #include "missing.h" #include "ioprio.h" #include "strv.h" -#include "dbus-common.h" #include "syscall-list.h" #include "fileio.h" +#include "execute.h" +#include "dbus-execute.h" -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput); -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput); +BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput); -static int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data) { - char **env_files = data, **j; - DBusMessageIter sub, sub2; +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput); - assert(i); - assert(property); +static int property_get_environment_files( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sb)", &sub)) - return -ENOMEM; + ExecContext *c = userdata; + char **j; + int r; - STRV_FOREACH(j, env_files) { - dbus_bool_t b = false; - char *fn = *j; + assert(bus); + assert(reply); + assert(c); + + r = sd_bus_message_open_container(reply, 'a', "(sb)"); + if (r < 0) + return r; - if (fn[0] == '-') { - b = true; - fn++; - } + STRV_FOREACH(j, c->environment_files) { + const char *fn = *j; - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &fn) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) || - !dbus_message_iter_close_container(&sub, &sub2)) - return -ENOMEM; + r = sd_bus_message_append(reply, "(sb)", fn[0] == '-' ? fn + 1 : fn, fn[0] == '-'); + if (r < 0) + return r; } - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; + return sd_bus_message_close_container(reply); +} + +static int property_get_rlimit( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + struct rlimit *rl; + uint64_t u; + + assert(bus); + assert(reply); + assert(userdata); - return 0; + rl = *(struct rlimit**) userdata; + if (rl) + u = (uint64_t) rl->rlim_max; + else { + struct rlimit buf = {}; + int z; + + z = rlimit_from_string(property); + assert(z >= 0); + + getrlimit(z, &buf); + + u = (uint64_t) buf.rlim_max; + } + + return sd_bus_message_append(reply, "t", u); } -static int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; +static int property_get_oom_score_adjust( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + + ExecContext *c = userdata; int32_t n; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(c); if (c->oom_score_adjust_set) @@ -80,80 +123,111 @@ static int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *p _cleanup_free_ char *t = NULL; n = 0; - if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0) { + if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0) safe_atoi(t, &n); - } } - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n)) - return -ENOMEM; - - return 0; + return sd_bus_message_append(reply, "i", n); } -static int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; +static int property_get_nice( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + + ExecContext *c = userdata; int32_t n; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(c); if (c->nice_set) n = c->nice; - else + else { + errno = 0; n = getpriority(PRIO_PROCESS, 0); + if (errno != 0) + n = 0; + } - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n)) - return -ENOMEM; - - return 0; + return sd_bus_message_append(reply, "i", n); } -static int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; +static int property_get_ioprio( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + + ExecContext *c = userdata; int32_t n; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(c); if (c->ioprio_set) n = c->ioprio; - else + else { n = ioprio_get(IOPRIO_WHO_PROCESS, 0); + if (n < 0) + n = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4); + } - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n)) - return -ENOMEM; - - return 0; + return sd_bus_message_append(reply, "i", n); } -static int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; +static int property_get_cpu_sched_policy( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + ExecContext *c = userdata; int32_t n; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(c); if (c->cpu_sched_set) n = c->cpu_sched_policy; - else + else { n = sched_getscheduler(0); + if (n < 0) + n = SCHED_OTHER; + } - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n)) - return -ENOMEM; - - return 0; + return sd_bus_message_append(reply, "i", n); } -static int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; +static int property_get_cpu_sched_priority( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + ExecContext *c = userdata; int32_t n; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(c); if (c->cpu_sched_set) @@ -167,44 +241,44 @@ static int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char n = 0; } - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n)) - return -ENOMEM; - - return 0; + return sd_bus_message_append(reply, "i", n); } -static int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; - dbus_bool_t b; - DBusMessageIter sub; +static int property_get_cpu_affinity( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - assert(i); - assert(property); - assert(c); + ExecContext *c = userdata; - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub)) - return -ENOMEM; + assert(bus); + assert(reply); + assert(c); if (c->cpuset) - b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus)); + return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus)); else - b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, 0); - - if (!b) - return -ENOMEM; - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; + return sd_bus_message_append_array(reply, 'y', NULL, 0); } -static int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; +static int property_get_timer_slack_nsec( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + ExecContext *c = userdata; uint64_t u; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(c); if (c->timer_slack_nsec != (nsec_t) -1) @@ -212,37 +286,45 @@ static int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *p else u = (uint64_t) prctl(PR_GET_TIMERSLACK); - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) - return -ENOMEM; - - return 0; + return sd_bus_message_append(reply, "t", u); } -static int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; - uint64_t normal, inverted; +static int property_get_capability_bounding_set( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - assert(i); - assert(property); + ExecContext *c = userdata; + + assert(bus); + assert(reply); assert(c); /* We store this negated internally, to match the kernel, but * we expose it normalized. */ - - normal = *(uint64_t*) data; - inverted = ~normal; - - return bus_property_append_uint64(i, property, &inverted); + return sd_bus_message_append(reply, "t", ~c->capability_bounding_set_drop); } -static int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; +static int property_get_capabilities( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + ExecContext *c = userdata; char *t = NULL; const char *s; - dbus_bool_t b; + int r; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(c); if (c->capabilities) @@ -253,184 +335,150 @@ static int bus_execute_append_capabilities(DBusMessageIter *i, const char *prope if (!s) return -ENOMEM; - b = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &s); + r = sd_bus_message_append(reply, "s", s); if (t) cap_free(t); - if (!b) - return -ENOMEM; - - return 0; + return r; } -static int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; - int r; - uint64_t u; - - assert(i); - assert(property); - assert(c); - - assert_se((r = rlimit_from_string(property)) >= 0); +static int property_get_syscall_filter( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - if (c->rlimit[r]) - u = (uint64_t) c->rlimit[r]->rlim_max; - else { - struct rlimit rl = {}; + ExecContext *c = userdata; - getrlimit(r, &rl); + assert(bus); + assert(reply); + assert(c); - u = (uint64_t) rl.rlim_max; - } + if (c->syscall_filter) + return sd_bus_message_append_array(reply, 'u', c->syscall_filter, (syscall_max() + 31) >> 4); + else + return sd_bus_message_append_array(reply, 'u', NULL, 0); +} - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) - return -ENOMEM; +const sd_bus_vtable bus_exec_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), 0), + SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, 0), + SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), 0), + SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), 0), + SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), 0), + SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), 0), + SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), 0), + SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), 0), + SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), 0), + SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), 0), + SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), 0), + SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), 0), + SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), 0), + SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), 0), + SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), 0), + SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), 0), + SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), 0), + SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), 0), + SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), 0), + SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), 0), + SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), 0), + SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, 0), + SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, 0), + SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, 0), + SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, 0), + SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, 0), + SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, 0), + SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, 0), + SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), 0), + SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), 0), + SD_BUS_PROPERTY("StandardInput", "s", property_get_exec_input, offsetof(ExecContext, std_input), 0), + SD_BUS_PROPERTY("StandardOutput", "s", bus_property_get_exec_output, offsetof(ExecContext, std_output), 0), + SD_BUS_PROPERTY("StandardError", "s", bus_property_get_exec_output, offsetof(ExecContext, std_error), 0), + SD_BUS_PROPERTY("TTYPath", "s", NULL, offsetof(ExecContext, tty_path), 0), + SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), 0), + SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), 0), + SD_BUS_PROPERTY("TTYVTDisallocate", "b", bus_property_get_bool, offsetof(ExecContext, tty_vt_disallocate), 0), + SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), 0), + SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), 0), + SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), 0), + SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, 0), + SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), 0), + SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, 0), + SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), 0), + SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), 0), + SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), 0), + SD_BUS_PROPERTY("TCPWrapName", "s", NULL, offsetof(ExecContext, tcpwrap_name), 0), + SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), 0), + SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_dirs), 0), + SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_dirs), 0), + SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_dirs), 0), + SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), 0), + SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), 0), + SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), 0), + SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), 0), + SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), 0), + SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), 0), + SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), 0), + SD_BUS_PROPERTY("SystemCallFilter", "au", property_get_syscall_filter, 0, 0), + SD_BUS_VTABLE_END +}; - return 0; -} +int bus_property_get_exec_command( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { -int bus_execute_append_command(DBusMessageIter *i, const char *property, void *data) { - ExecCommand *c = data; - DBusMessageIter sub, sub2, sub3; + ExecCommand *c = *(ExecCommand**) userdata; + int r; - assert(i); - assert(property); + assert(bus); + assert(reply); - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sasbttttuii)", &sub)) - return -ENOMEM; + r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)"); + if (r < 0) + return r; LIST_FOREACH(command, c, c) { - char **l; - uint32_t pid; - int32_t code, status; - dbus_bool_t b; - if (!c->path) continue; - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &c->path) || - !dbus_message_iter_open_container(&sub2, DBUS_TYPE_ARRAY, "s", &sub3)) - return -ENOMEM; - - STRV_FOREACH(l, c->argv) - if (!dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, l)) - return -ENOMEM; - - pid = (uint32_t) c->exec_status.pid; - code = (int32_t) c->exec_status.code; - status = (int32_t) c->exec_status.status; - - b = !!c->ignore; - - if (!dbus_message_iter_close_container(&sub2, &sub3) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.realtime) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.monotonic) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.realtime) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.monotonic) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &code) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &status)) - return -ENOMEM; - - if (!dbus_message_iter_close_container(&sub, &sub2)) - return -ENOMEM; + r = sd_bus_message_open_container(reply, 'r', "sasbttttuii"); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "s", c->path); + if (r < 0) + return r; + + r = sd_bus_message_append_strv(reply, c->argv); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "bttttuii", + c->ignore, + c->exec_status.start_timestamp.realtime, + c->exec_status.start_timestamp.monotonic, + c->exec_status.exit_timestamp.realtime, + c->exec_status.exit_timestamp.monotonic, + (uint32_t) c->exec_status.pid, + (int32_t) c->exec_status.code, + (int32_t) c->exec_status.status); + if (r < 0) + return r; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; } - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -static int bus_execute_append_syscall_filter(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; - dbus_bool_t b; - DBusMessageIter sub; - - assert(i); - assert(property); - assert(c); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "u", &sub)) - return -ENOMEM; - - if (c->syscall_filter) - b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_UINT32, &c->syscall_filter, (syscall_max() + 31) >> 4); - else - b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_UINT32, &c->syscall_filter, 0); - - if (!b) - return -ENOMEM; - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; + return sd_bus_message_close_container(reply); } - -const BusProperty bus_exec_context_properties[] = { - { "Environment", bus_property_append_strv, "as", offsetof(ExecContext, environment), true }, - { "EnvironmentFiles", bus_execute_append_env_files, "a(sb)", offsetof(ExecContext, environment_files), true }, - { "UMask", bus_property_append_mode, "u", offsetof(ExecContext, umask) }, - { "LimitCPU", bus_execute_append_rlimits, "t", 0 }, - { "LimitFSIZE", bus_execute_append_rlimits, "t", 0 }, - { "LimitDATA", bus_execute_append_rlimits, "t", 0 }, - { "LimitSTACK", bus_execute_append_rlimits, "t", 0 }, - { "LimitCORE", bus_execute_append_rlimits, "t", 0 }, - { "LimitRSS", bus_execute_append_rlimits, "t", 0 }, - { "LimitNOFILE", bus_execute_append_rlimits, "t", 0 }, - { "LimitAS", bus_execute_append_rlimits, "t", 0 }, - { "LimitNPROC", bus_execute_append_rlimits, "t", 0 }, - { "LimitMEMLOCK", bus_execute_append_rlimits, "t", 0 }, - { "LimitLOCKS", bus_execute_append_rlimits, "t", 0 }, - { "LimitSIGPENDING", bus_execute_append_rlimits, "t", 0 }, - { "LimitMSGQUEUE", bus_execute_append_rlimits, "t", 0 }, - { "LimitNICE", bus_execute_append_rlimits, "t", 0 }, - { "LimitRTPRIO", bus_execute_append_rlimits, "t", 0 }, - { "LimitRTTIME", bus_execute_append_rlimits, "t", 0 }, - { "WorkingDirectory", bus_property_append_string, "s", offsetof(ExecContext, working_directory), true }, - { "RootDirectory", bus_property_append_string, "s", offsetof(ExecContext, root_directory), true }, - { "OOMScoreAdjust", bus_execute_append_oom_score_adjust, "i", 0 }, - { "Nice", bus_execute_append_nice, "i", 0 }, - { "IOScheduling", bus_execute_append_ioprio, "i", 0 }, - { "CPUSchedulingPolicy", bus_execute_append_cpu_sched_policy, "i", 0 }, - { "CPUSchedulingPriority", bus_execute_append_cpu_sched_priority, "i", 0 }, - { "CPUAffinity", bus_execute_append_affinity, "ay", 0 }, - { "TimerSlackNSec", bus_execute_append_timer_slack_nsec, "t", 0 }, - { "CPUSchedulingResetOnFork", bus_property_append_bool, "b", offsetof(ExecContext, cpu_sched_reset_on_fork) }, - { "NonBlocking", bus_property_append_bool, "b", offsetof(ExecContext, non_blocking) }, - { "StandardInput", bus_execute_append_input, "s", offsetof(ExecContext, std_input) }, - { "StandardOutput", bus_execute_append_output, "s", offsetof(ExecContext, std_output) }, - { "StandardError", bus_execute_append_output, "s", offsetof(ExecContext, std_error) }, - { "TTYPath", bus_property_append_string, "s", offsetof(ExecContext, tty_path), true }, - { "TTYReset", bus_property_append_bool, "b", offsetof(ExecContext, tty_reset) }, - { "TTYVHangup", bus_property_append_bool, "b", offsetof(ExecContext, tty_vhangup) }, - { "TTYVTDisallocate", bus_property_append_bool, "b", offsetof(ExecContext, tty_vt_disallocate) }, - { "SyslogPriority", bus_property_append_int, "i", offsetof(ExecContext, syslog_priority) }, - { "SyslogIdentifier", bus_property_append_string, "s", offsetof(ExecContext, syslog_identifier), true }, - { "SyslogLevelPrefix", bus_property_append_bool, "b", offsetof(ExecContext, syslog_level_prefix) }, - { "Capabilities", bus_execute_append_capabilities, "s", 0 }, - { "SecureBits", bus_property_append_int, "i", offsetof(ExecContext, secure_bits) }, - { "CapabilityBoundingSet", bus_execute_append_capability_bs, "t", offsetof(ExecContext, capability_bounding_set_drop) }, - { "User", bus_property_append_string, "s", offsetof(ExecContext, user), true }, - { "Group", bus_property_append_string, "s", offsetof(ExecContext, group), true }, - { "SupplementaryGroups", bus_property_append_strv, "as", offsetof(ExecContext, supplementary_groups), true }, - { "TCPWrapName", bus_property_append_string, "s", offsetof(ExecContext, tcpwrap_name), true }, - { "PAMName", bus_property_append_string, "s", offsetof(ExecContext, pam_name), true }, - { "ReadWriteDirectories", bus_property_append_strv, "as", offsetof(ExecContext, read_write_dirs), true }, - { "ReadOnlyDirectories", bus_property_append_strv, "as", offsetof(ExecContext, read_only_dirs), true }, - { "InaccessibleDirectories", bus_property_append_strv, "as", offsetof(ExecContext, inaccessible_dirs), true }, - { "MountFlags", bus_property_append_ul, "t", offsetof(ExecContext, mount_flags) }, - { "PrivateTmp", bus_property_append_bool, "b", offsetof(ExecContext, private_tmp) }, - { "PrivateNetwork", bus_property_append_bool, "b", offsetof(ExecContext, private_network) }, - { "SameProcessGroup", bus_property_append_bool, "b", offsetof(ExecContext, same_pgrp) }, - { "UtmpIdentifier", bus_property_append_string, "s", offsetof(ExecContext, utmp_id), true }, - { "IgnoreSIGPIPE", bus_property_append_bool, "b", offsetof(ExecContext, ignore_sigpipe) }, - { "NoNewPrivileges", bus_property_append_bool, "b", offsetof(ExecContext, no_new_privileges) }, - { "SystemCallFilter", bus_execute_append_syscall_filter, "au", 0 }, - {} -}; diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h index 79bf30838a..957742beee 100644 --- a/src/core/dbus-execute.h +++ b/src/core/dbus-execute.h @@ -21,87 +21,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> +#include "sd-bus.h" +#include "execute.h" -#include "manager.h" -#include "dbus-common.h" +#define BUS_EXEC_STATUS_VTABLE(prefix, offset, flags) \ + BUS_PROPERTY_DUAL_TIMESTAMP(prefix "StartTimestamp", (offset) + offsetof(ExecStatus, start_timestamp), flags), \ + BUS_PROPERTY_DUAL_TIMESTAMP(prefix "ExitTimestamp", (offset) + offsetof(ExecStatus, exit_timestamp), flags), \ + SD_BUS_PROPERTY(prefix "PID", "u", bus_property_get_pid, (offset) + offsetof(ExecStatus, pid), flags), \ + SD_BUS_PROPERTY(prefix "Code", "i", bus_property_get_int, (offset) + offsetof(ExecStatus, code), flags), \ + SD_BUS_PROPERTY(prefix "Status", "i", bus_property_get_int, (offset) + offsetof(ExecStatus, status), flags) -#define BUS_EXEC_STATUS_INTERFACE(prefix) \ - " <property name=\"" prefix "StartTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"" prefix "StartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"" prefix "ExitTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"" prefix "ExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"" prefix "PID\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"" prefix "Code\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"" prefix "Status\" type=\"i\" access=\"read\"/>\n" +#define BUS_EXEC_COMMAND_VTABLE(name, offset, flags) \ + SD_BUS_PROPERTY(name, "a(sasbttttuii)", bus_property_get_exec_command, offset, flags) -#define BUS_EXEC_CONTEXT_INTERFACE \ - " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"EnvironmentFiles\" type=\"a(sb)\" access=\"read\"/>\n" \ - " <property name=\"UMask\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"LimitCPU\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitFSIZE\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitDATA\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitSTACK\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitCORE\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitRSS\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitNOFILE\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitAS\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitNPROC\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitMEMLOCK\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitLOCKS\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitSIGPENDING\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitMSGQUEUE\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitNICE\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitRTPRIO\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LimitRTTIME\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"WorkingDirectory\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"RootDirectory\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"OOMScoreAdjust\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"Nice\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"IOScheduling\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"CPUSchedulingPolicy\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"CPUSchedulingPriority\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"CPUAffinity\" type=\"ay\" access=\"read\"/>\n" \ - " <property name=\"TimerSlackNSec\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"CPUSchedulingResetOnFork\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"NonBlocking\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"StandardInput\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"StandardOutput\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"StandardError\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"TTYPath\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"TTYReset\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"TTYVHangup\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"TTYVTDisallocate\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"SyslogPriority\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"SyslogIdentifier\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"SyslogLevelPrefix\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"Capabilities\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"SecureBits\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"CapabilityBoundingSet\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"User\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"Group\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"SupplementaryGroups\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"TCPWrapName\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"PAMName\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"ReadWriteDirectories\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"ReadOnlyDirectories\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"InaccessibleDirectories\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"MountFlags\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"PrivateTmp\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"PrivateNetwork\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"SameProcessGroup\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"UtmpIdentifier\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"IgnoreSIGPIPE\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"NoNewPrivileges\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"SystemCallFilter\" type=\"au\" access=\"read\"/>\n" +extern const sd_bus_vtable bus_exec_vtable[]; -#define BUS_EXEC_COMMAND_INTERFACE(name) \ - " <property name=\"" name "\" type=\"a(sasbttuii)\" access=\"read\"/>\n" - -extern const BusProperty bus_exec_context_properties[]; - -#define BUS_EXEC_COMMAND_PROPERTY(name, command, indirect) \ - { name, bus_execute_append_command, "a(sasbttttuii)", (command), (indirect), NULL } - -int bus_execute_append_command(DBusMessageIter *u, const char *property, void *data); +int bus_property_get_exec_output(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata); +int bus_property_get_exec_command(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata); diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c index e1d7504e85..e774383793 100644 --- a/src/core/dbus-job.c +++ b/src/core/dbus-job.c @@ -19,303 +19,145 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> - -#include "dbus.h" #include "log.h" -#include "dbus-job.h" -#include "dbus-common.h" +#include "sd-bus.h" #include "selinux-access.h" +#include "job.h" +#include "dbus-job.h" +#include "dbus-client-track.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, job_type, JobType); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_state, job_state, JobState); + +static int property_get_unit( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { -#define BUS_JOB_INTERFACE \ - " <interface name=\"org.freedesktop.systemd1.Job\">\n" \ - " <method name=\"Cancel\"/>\n" \ - " <property name=\"Id\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"Unit\" type=\"(so)\" access=\"read\"/>\n" \ - " <property name=\"JobType\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"State\" type=\"s\" access=\"read\"/>\n" \ - " </interface>\n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "<node>\n" \ - BUS_JOB_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "</node>\n" - -const char bus_job_interface[] = BUS_JOB_INTERFACE; - -#define INTERFACES_LIST \ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.systemd1.Job\0" - -#define INVALIDATING_PROPERTIES \ - "State\0" - -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_state, job_state, JobState); -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_type, job_type, JobType); - -static int bus_job_append_unit(DBusMessageIter *i, const char *property, void *data) { - Job *j = data; - DBusMessageIter sub; _cleanup_free_ char *p = NULL; + Job *j = userdata; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(j); - if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub)) - return -ENOMEM; - p = unit_dbus_path(j->unit); if (!p) return -ENOMEM; - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &j->unit->id) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) { - return -ENOMEM; - } - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; + return sd_bus_message_append(reply, "(so)", j->unit->id, p); } -static const BusProperty bus_job_properties[] = { - { "Id", bus_property_append_uint32, "u", offsetof(Job, id) }, - { "State", bus_job_append_state, "s", offsetof(Job, state) }, - { "JobType", bus_job_append_type, "s", offsetof(Job, type) }, - { "Unit", bus_job_append_unit, "(so)", 0 }, - { NULL, } -}; - -static DBusHandlerResult bus_job_message_dispatch(Job *j, DBusConnection *connection, DBusMessage *message) { - _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; - - if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Job", "Cancel")) { - - SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop"); - job_finish_and_invalidate(j, JOB_CANCELED, true); - - reply = dbus_message_new_method_return(message); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } else { - const BusBoundProperties bps[] = { - { "org.freedesktop.systemd1.Job", bus_job_properties, j }, - { NULL, } - }; - - SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status"); - return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps); - } - - if (!bus_maybe_send_reply(connection, message, reply)) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - return DBUS_HANDLER_RESULT_HANDLED; -} - -static DBusHandlerResult bus_job_message_handler(DBusConnection *connection, DBusMessage *message, void *data) { - Manager *m = data; - Job *j; - int r; - _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; +static int method_cancel(sd_bus *bus, sd_bus_message *message, void *userdata) { + Job *j = userdata; - assert(connection); + assert(bus); assert(message); - assert(m); - - if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/job")) { - /* Be nice to gdbus and return introspection data for our mid-level paths */ - - if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { - _cleanup_free_ char *introspection = NULL; - FILE *f; - Iterator i; - size_t size; - - SELINUX_ACCESS_CHECK(connection, message, "status"); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - /* We roll our own introspection code here, instead of - * relying on bus_default_message_handler() because we - * need to generate our introspection string - * dynamically. */ - - f = open_memstream(&introspection, &size); - if (!f) - goto oom; - - fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE - "<node>\n", f); - - fputs(BUS_INTROSPECTABLE_INTERFACE, f); - fputs(BUS_PEER_INTERFACE, f); - - HASHMAP_FOREACH(j, m->jobs, i) - fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id); - - fputs("</node>\n", f); - - if (ferror(f)) { - fclose(f); - goto oom; - } - - fclose(f); - - if (!introspection) - goto oom; - - if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) { - goto oom; - } - - if (!bus_maybe_send_reply(connection, message, reply)) - goto oom; - - return DBUS_HANDLER_RESULT_HANDLED; - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - - r = manager_get_job_from_dbus_path(m, dbus_message_get_path(message), &j); - if (r == -ENOMEM) - goto oom; - if (r == -ENOENT) { - DBusError e; - - dbus_error_init(&e); - dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown job"); - return bus_send_error_reply(connection, message, &e, r); - } - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); + assert(j); - return bus_job_message_dispatch(j, connection, message); + SELINUX_UNIT_ACCESS_CHECK(j->unit, bus, message, "stop"); + job_finish_and_invalidate(j, JOB_CANCELED, true); -oom: - return DBUS_HANDLER_RESULT_NEED_MEMORY; + return sd_bus_reply_method_return(bus, message, NULL); } -const DBusObjectPathVTable bus_job_vtable = { - .message_function = bus_job_message_handler +const sd_bus_vtable bus_job_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("Cancel", NULL, NULL, method_cancel, 0), + SD_BUS_PROPERTY("Id", "u", NULL, offsetof(Job, id), 0), + SD_BUS_PROPERTY("Unit", "(so)", property_get_unit, 0, 0), + SD_BUS_PROPERTY("JobType", "s", property_get_type, offsetof(Job, type), 0), + SD_BUS_PROPERTY("State", "s", property_get_state, offsetof(Job, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_VTABLE_END }; -static int job_send_message(Job *j, DBusMessage* (*new_message)(Job *j)) { - _cleanup_dbus_message_unref_ DBusMessage *m = NULL; +static int foreach_client(Job *j, int (*send_message)(sd_bus *bus, const char *name, Job *j)) { + BusTrackedClient *one_destination = NULL; + Iterator i; + sd_bus *b; + unsigned n, m; int r; assert(j); - assert(new_message); + assert(send_message); - if (bus_has_subscriber(j->manager) || j->forgot_bus_clients) { - m = new_message(j); - if (!m) - return -ENOMEM; + n = set_size(j->manager->subscribed); + m = set_size(j->subscribed); - r = bus_broadcast(j->manager, m); - if (r < 0) - return r; - - } else { - /* If nobody is subscribed, we just send the message - * to the client(s) which created the job */ - JobBusClient *cl; - assert(j->bus_client_list); - - LIST_FOREACH(client, cl, j->bus_client_list) { - assert(cl->bus); + if (n <= 0 && m <= 0) + return 0; - m = new_message(j); - if (!m) - return -ENOMEM; + if (n == 1 && m == 0) + one_destination = set_first(j->manager->subscribed); + else if (n == 0 && m == 1) + one_destination = set_first(j->subscribed); + else + one_destination = NULL; - if (!dbus_message_set_destination(m, cl->name)) - return -ENOMEM; + if (one_destination) + return send_message(one_destination->bus, isempty(one_destination->name) ? NULL : one_destination->name, j); - if (!dbus_connection_send(cl->bus, m, NULL)) - return -ENOMEM; - - dbus_message_unref(m); - m = NULL; - } + /* Send to everybody */ + SET_FOREACH(b, j->manager->private_buses, i) { + r = send_message(b, NULL, j); + if (r < 0) + return r; } + if (j->manager->api_bus) + return send_message(j->manager->api_bus, NULL, j); + return 0; } -static DBusMessage* new_change_signal_message(Job *j) { +static int send_new_signal(sd_bus *bus, const char *destination, Job *j) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; _cleanup_free_ char *p = NULL; - DBusMessage *m; + int r; + + assert(bus); + assert(j); p = job_dbus_path(j); if (!p) - return NULL; - - if (j->sent_dbus_new_signal) { - /* Send a properties changed signal */ - m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Job", INVALIDATING_PROPERTIES); - if (!m) - return NULL; - - } else { - /* Send a new signal */ - - m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobNew"); - if (!m) - return NULL; - - if (!dbus_message_append_args(m, - DBUS_TYPE_UINT32, &j->id, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_STRING, &j->unit->id, - DBUS_TYPE_INVALID)) { - dbus_message_unref(m); - return NULL; - } - } + return -ENOMEM; - return m; + r = sd_bus_message_new_signal( + bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "JobNew", + &m); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "uos", j->id, p, j->unit->id); + if (r < 0) + return r; + + return sd_bus_send_to(bus, m, destination, NULL); } -static DBusMessage* new_removed_signal_message(Job *j) { +static int send_changed_signal(sd_bus *bus, const char *destination, Job *j) { _cleanup_free_ char *p = NULL; - DBusMessage *m; - const char *r; + + assert(bus); + assert(j); p = job_dbus_path(j); if (!p) - return NULL; - - m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobRemoved"); - if (!m) - return NULL; - - r = job_result_to_string(j->result); - - if (!dbus_message_append_args(m, - DBUS_TYPE_UINT32, &j->id, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_STRING, &j->unit->id, - DBUS_TYPE_STRING, &r, - DBUS_TYPE_INVALID)) { - dbus_message_unref(m); - return NULL; - } + return -ENOMEM; - return m; + return sd_bus_emit_properties_changed(bus, p, "org.freedesktop.systemd1.Job", "State", NULL); } void bus_job_send_change_signal(Job *j) { + int r; + assert(j); if (j->in_dbus_queue) { @@ -323,36 +165,52 @@ void bus_job_send_change_signal(Job *j) { j->in_dbus_queue = false; } - if (!bus_has_subscriber(j->manager) && !j->bus_client_list && !j->forgot_bus_clients) { - j->sent_dbus_new_signal = true; - return; - } - - if (job_send_message(j, new_change_signal_message) < 0) - goto oom; + r = foreach_client(j, j->sent_dbus_new_signal ? send_changed_signal : send_new_signal); + if (r < 0) + log_warning("Failed to send job change signal for %u/%s: %s", j->id, j->unit->id, strerror(-r)); j->sent_dbus_new_signal = true; +} + +static int send_removed_signal(sd_bus *bus, const char *destination, Job *j) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_free_ char *p = NULL; + int r; + + assert(bus); + assert(j); + + p = job_dbus_path(j); + if (!p) + return -ENOMEM; - return; -oom: - log_error("Failed to allocate job change signal."); + r = sd_bus_message_new_signal( + bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "JobRemoved", + &m); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "uoss", j->id, p, j->unit->id, job_result_to_string(j->result)); + if (r < 0) + return r; + + return sd_bus_send_to(bus, m, destination, NULL); } void bus_job_send_removed_signal(Job *j) { - assert(j); + int r; - if (!bus_has_subscriber(j->manager) && !j->bus_client_list && !j->forgot_bus_clients) - return; + assert(j); if (!j->sent_dbus_new_signal) bus_job_send_change_signal(j); - if (job_send_message(j, new_removed_signal_message) < 0) - goto oom; - - return; - -oom: - log_error("Failed to allocate job remove signal."); + r = foreach_client(j, send_removed_signal); + if (r < 0) + log_warning("Failed to send job removal signal for %u/%s: %s", j->id, j->unit->id, strerror(-r)); + return; } diff --git a/src/core/dbus-job.h b/src/core/dbus-job.h index a1b928fb16..d1d0f6ddf0 100644 --- a/src/core/dbus-job.h +++ b/src/core/dbus-job.h @@ -21,13 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> - +#include "sd-bus.h" #include "job.h" +extern const sd_bus_vtable bus_job_vtable[]; + void bus_job_send_change_signal(Job *j); void bus_job_send_removed_signal(Job *j); - -extern const DBusObjectPathVTable bus_job_vtable; - -extern const char bus_job_interface[]; diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c index 811adb1b5a..42488b1f54 100644 --- a/src/core/dbus-kill.c +++ b/src/core/dbus-kill.c @@ -19,43 +19,44 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> -#include <dbus/dbus.h> - +#include "bus-util.h" +#include "kill.h" #include "dbus-kill.h" -#include "dbus-common.h" +#include "bus-util.h" -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_kill_append_mode, kill_mode, KillMode); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_kill_mode, kill_mode, KillMode); -const BusProperty bus_kill_context_properties[] = { - { "KillMode", bus_kill_append_mode, "s", offsetof(KillContext, kill_mode) }, - { "KillSignal", bus_property_append_int, "i", offsetof(KillContext, kill_signal) }, - { "SendSIGKILL", bus_property_append_bool, "b", offsetof(KillContext, send_sigkill) }, - { "SendSIGHUP", bus_property_append_bool, "b", offsetof(KillContext, send_sighup) }, - {} +const sd_bus_vtable bus_kill_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("KillMode", "s", property_get_kill_mode, offsetof(KillContext, kill_mode), 0), + SD_BUS_PROPERTY("KillSignal", "i", bus_property_get_int, offsetof(KillContext, kill_signal), 0), + SD_BUS_PROPERTY("SendSIGKILL", "b", bus_property_get_bool, offsetof(KillContext, send_sigkill), 0), + SD_BUS_PROPERTY("SendSIGHUP", "b", bus_property_get_bool, offsetof(KillContext, send_sighup), 0), + SD_BUS_VTABLE_END }; int bus_kill_context_set_transient_property( Unit *u, KillContext *c, const char *name, - DBusMessageIter *i, + sd_bus_message *message, UnitSetPropertiesMode mode, - DBusError *error) { + sd_bus_error *error) { + + int r; assert(u); assert(c); assert(name); - assert(i); + assert(message); if (streq(name, "KillMode")) { const char *m; KillMode k; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) - return -EINVAL; - - dbus_message_iter_get_basic(i, &m); + r = sd_bus_message_read(message, "s", &m); + if (r < 0) + return r; k = kill_mode_from_string(m); if (k < 0) @@ -70,14 +71,13 @@ int bus_kill_context_set_transient_property( return 1; } else if (streq(name, "SendSIGHUP")) { + int b; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN) - return -EINVAL; + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; if (mode != UNIT_CHECK) { - dbus_bool_t b; - - dbus_message_iter_get_basic(i, &b); c->send_sighup = b; unit_write_drop_in_private_format(u, mode, name, "SendSIGHUP=%s\n", yes_no(b)); @@ -86,14 +86,13 @@ int bus_kill_context_set_transient_property( return 1; } else if (streq(name, "SendSIGKILL")) { + int b; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN) - return -EINVAL; + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; if (mode != UNIT_CHECK) { - dbus_bool_t b; - - dbus_message_iter_get_basic(i, &b); c->send_sigkill = b; unit_write_drop_in_private_format(u, mode, name, "SendSIGKILL=%s\n", yes_no(b)); diff --git a/src/core/dbus-kill.h b/src/core/dbus-kill.h index 7676d98e91..7c15f3a90b 100644 --- a/src/core/dbus-kill.h +++ b/src/core/dbus-kill.h @@ -21,17 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> +#include "sd-bus.h" +#include "unit.h" +#include "kill.h" -#include "manager.h" -#include "dbus-common.h" +extern const sd_bus_vtable bus_kill_vtable[]; -#define BUS_KILL_CONTEXT_INTERFACE \ - " <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"KillSignal\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"SendSIGKILL\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"SendSIGHUP\" type=\"b\" access=\"read\"/>\n" - -extern const BusProperty bus_kill_context_properties[]; - -int bus_kill_context_set_transient_property(Unit *u, KillContext *c, const char *name, DBusMessageIter *i, UnitSetPropertiesMode mode, DBusError *error); +int bus_kill_context_set_transient_property(Unit *u, KillContext *c, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 747bcfcb91..2e4de2e431 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -22,320 +22,88 @@ #include <errno.h> #include <unistd.h> -#include "dbus.h" #include "log.h" -#include "dbus-manager.h" #include "strv.h" -#include "bus-errors.h" #include "build.h" -#include "dbus-common.h" #include "install.h" #include "selinux-access.h" #include "watchdog.h" #include "hwclock.h" #include "path-util.h" -#include "dbus-unit.h" #include "virt.h" #include "env-util.h" +#include "dbus.h" +#include "dbus-manager.h" +#include "dbus-unit.h" +#include "dbus-snapshot.h" +#include "dbus-client-track.h" +#include "dbus-execute.h" +#include "bus-errors.h" -#define BUS_MANAGER_INTERFACE_BEGIN \ - " <interface name=\"org.freedesktop.systemd1.Manager\">\n" - -#define BUS_MANAGER_INTERFACE_METHODS \ - " <method name=\"GetUnit\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"GetUnitByPID\">\n" \ - " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \ - " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"LoadUnit\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"StartUnit\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"StartUnitReplace\">\n" \ - " <arg name=\"old_unit\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"new_unit\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"StopUnit\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"ReloadUnit\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"RestartUnit\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"TryRestartUnit\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"ReloadOrRestartUnit\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"ReloadOrTryRestartUnit\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"KillUnit\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n" \ - " </method>\n" \ - " <method name=\"ResetFailedUnit\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " </method>\n" \ - " <method name=\"GetJob\">\n" \ - " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"CancelJob\">\n" \ - " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \ - " </method>\n" \ - " <method name=\"ClearJobs\"/>\n" \ - " <method name=\"ResetFailed\"/>\n" \ - " <method name=\"ListUnits\">\n" \ - " <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"ListJobs\">\n" \ - " <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"Subscribe\"/>\n" \ - " <method name=\"Unsubscribe\"/>\n" \ - " <method name=\"Dump\">\n" \ - " <arg name=\"dump\" type=\"s\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"CreateSnapshot\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"RemoveSnapshot\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " </method>\n" \ - " <method name=\"Reload\"/>\n" \ - " <method name=\"Reexecute\"/>\n" \ - " <method name=\"Exit\"/>\n" \ - " <method name=\"Reboot\"/>\n" \ - " <method name=\"PowerOff\"/>\n" \ - " <method name=\"Halt\"/>\n" \ - " <method name=\"KExec\"/>\n" \ - " <method name=\"SwitchRoot\">\n" \ - " <arg name=\"new_root\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"init\" type=\"s\" direction=\"in\"/>\n" \ - " </method>\n" \ - " <method name=\"SetEnvironment\">\n" \ - " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \ - " </method>\n" \ - " <method name=\"UnsetEnvironment\">\n" \ - " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \ - " </method>\n" \ - " <method name=\"UnsetAndSetEnvironment\">\n" \ - " <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n" \ - " <arg name=\"set\" type=\"as\" direction=\"in\"/>\n" \ - " </method>\n" \ - " <method name=\"ListUnitFiles\">\n" \ - " <arg name=\"files\" type=\"a(ss)\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"GetUnitFileState\">\n" \ - " <arg name=\"file\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"state\" type=\"s\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"EnableUnitFiles\">\n" \ - " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \ - " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \ - " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"DisableUnitFiles\">\n" \ - " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \ - " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"ReenableUnitFiles\">\n" \ - " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \ - " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \ - " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"LinkUnitFiles\">\n" \ - " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \ - " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"PresetUnitFiles\">\n" \ - " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \ - " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \ - " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"MaskUnitFiles\">\n" \ - " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \ - " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"UnmaskUnitFiles\">\n" \ - " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \ - " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"SetDefaultTarget\">\n" \ - " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \ - " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"GetDefaultTarget\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"SetUnitProperties\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"properties\" type=\"a(sv)\" direction=\"in\"/>\n" \ - " </method>\n" \ - " <method name=\"StartTransientUnit\">\n" \ - " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"properties\" type=\"a(sv)\" direction=\"in\"/>\n" \ - " <arg name=\"aux\" type=\"a(sa(sv))\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" - -#define BUS_MANAGER_INTERFACE_SIGNALS \ - " <signal name=\"UnitNew\">\n" \ - " <arg name=\"id\" type=\"s\"/>\n" \ - " <arg name=\"unit\" type=\"o\"/>\n" \ - " </signal>\n" \ - " <signal name=\"UnitRemoved\">\n" \ - " <arg name=\"id\" type=\"s\"/>\n" \ - " <arg name=\"unit\" type=\"o\"/>\n" \ - " </signal>\n" \ - " <signal name=\"JobNew\">\n" \ - " <arg name=\"id\" type=\"u\"/>\n" \ - " <arg name=\"job\" type=\"o\"/>\n" \ - " <arg name=\"unit\" type=\"s\"/>\n" \ - " </signal>\n" \ - " <signal name=\"JobRemoved\">\n" \ - " <arg name=\"id\" type=\"u\"/>\n" \ - " <arg name=\"job\" type=\"o\"/>\n" \ - " <arg name=\"unit\" type=\"s\"/>\n" \ - " <arg name=\"result\" type=\"s\"/>\n" \ - " </signal>" \ - " <signal name=\"StartupFinished\">\n" \ - " <arg name=\"firmware\" type=\"t\"/>\n" \ - " <arg name=\"loader\" type=\"t\"/>\n" \ - " <arg name=\"kernel\" type=\"t\"/>\n" \ - " <arg name=\"initrd\" type=\"t\"/>\n" \ - " <arg name=\"userspace\" type=\"t\"/>\n" \ - " <arg name=\"total\" type=\"t\"/>\n" \ - " </signal>" \ - " <signal name=\"UnitFilesChanged\"/>\n" \ - " <signal name=\"Reloading\">\n" \ - " <arg name=\"active\" type=\"b\"/>\n" \ - " </signal>" - -#define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \ - " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"FirmwareTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"FirmwareTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LoaderTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LoaderTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"KernelTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"KernelTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"SecurityStartTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"SecurityStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"SecurityFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"SecurityFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"GeneratorsStartTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"GeneratorsStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"GeneratorsFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"GeneratorsFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"UnitsLoadStartTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"UnitsLoadStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"UnitsLoadFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"UnitsLoadFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \ - " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \ - " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \ - " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"RuntimeWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \ - " <property name=\"ShutdownWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \ - " <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n" - -#define BUS_MANAGER_INTERFACE_END \ - " </interface>\n" - -#define BUS_MANAGER_INTERFACE \ - BUS_MANAGER_INTERFACE_BEGIN \ - BUS_MANAGER_INTERFACE_METHODS \ - BUS_MANAGER_INTERFACE_SIGNALS \ - BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \ - BUS_MANAGER_INTERFACE_END - -#define INTROSPECTION_BEGIN \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "<node>\n" \ - BUS_MANAGER_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE - -#define INTROSPECTION_END \ - "</node>\n" - -#define INTERFACES_LIST \ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.systemd1.Manager\0" - -const char bus_manager_interface[] = BUS_MANAGER_INTERFACE; - -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput); - -static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) { - const char *t; - Manager *m = data; - char buf[LINE_MAX] = "", *e = buf, *p = NULL; +static int property_get_version( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + assert(bus); + assert(reply); + + return sd_bus_message_append(reply, "s", PACKAGE_VERSION); +} - assert(i); - assert(property); +static int property_get_features( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + assert(bus); + assert(reply); + + return sd_bus_message_append(reply, "s", SYSTEMD_FEATURES); +} + +static int property_get_virtualization( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + const char *id = NULL; + + assert(bus); + assert(reply); + + detect_virtualization(&id); + + return sd_bus_message_append(reply, "s", id); +} + +static int property_get_tainted( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + char buf[LINE_MAX] = "", *e = buf; + _cleanup_free_ char *p = NULL; + Manager *m = userdata; + + assert(bus); + assert(reply); assert(m); if (m->taint_usr) @@ -343,8 +111,6 @@ static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, if (readlink_malloc("/etc/mtab", &p) < 0) e = stpcpy(e, "mtab-not-symlink:"); - else - free(p); if (access("/proc/cgroups", F_OK) < 0) e = stpcpy(e, "cgroups-missing:"); @@ -356,105 +122,140 @@ static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, if (e != buf) e[-1] = 0; - t = buf; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t)) - return -ENOMEM; - - return 0; + return sd_bus_message_append(reply, "s", buf); } -static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) { - const char *t; - - assert(i); - assert(property); - - t = log_target_to_string(log_get_target()); +static int property_get_log_target( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t)) - return -ENOMEM; + assert(bus); + assert(reply); - return 0; + return sd_bus_message_append(reply, "s", log_target_to_string(log_get_target())); } -static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) { +static int property_set_log_target( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *value, + sd_bus_error *error, + void *userdata) { + const char *t; + int r; - assert(i); - assert(property); + assert(bus); + assert(value); - dbus_message_iter_get_basic(i, &t); + r = sd_bus_message_read(value, "s", &t); + if (r < 0) + return r; return log_set_target_from_string(t); } -static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) { +static int property_get_log_level( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + _cleanup_free_ char *t = NULL; int r; - assert(i); - assert(property); + assert(bus); + assert(reply); r = log_level_to_string_alloc(log_get_max_level(), &t); if (r < 0) return r; - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t)) - r = -ENOMEM; - - return r; + return sd_bus_message_append(reply, "s", t); } -static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) { +static int property_set_log_level( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *value, + sd_bus_error *error, + void *userdata) { + const char *t; + int r; - assert(i); - assert(property); + assert(bus); + assert(value); - dbus_message_iter_get_basic(i, &t); + r = sd_bus_message_read(value, "s", &t); + if (r < 0) + return r; return log_set_max_level_from_string(t); } -static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) { - Manager *m = data; - uint32_t u; +static int property_get_n_names( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - assert(i); - assert(property); - assert(m); + Manager *m = userdata; - u = hashmap_size(m->units); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u)) - return -ENOMEM; + assert(bus); + assert(reply); + assert(m); - return 0; + return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->units)); } -static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) { - Manager *m = data; - uint32_t u; +static int property_get_n_jobs( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - assert(i); - assert(property); - assert(m); + Manager *m = userdata; - u = hashmap_size(m->jobs); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u)) - return -ENOMEM; + assert(bus); + assert(reply); + assert(m); - return 0; + return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->jobs)); } -static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) { +static int property_get_progress( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + Manager *m = userdata; double d; - Manager *m = data; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(m); if (dual_timestamp_is_set(&m->finish_timestamp)) @@ -462,1416 +263,1375 @@ static int bus_manager_append_progress(DBusMessageIter *i, const char *property, else d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs); - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d)) - return -ENOMEM; + return sd_bus_message_append(reply, "d", d); +} + +static int property_set_runtime_watchdog( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *value, + sd_bus_error *error, + void *userdata) { - return 0; + usec_t *t = userdata; + int r; + + assert(bus); + assert(value); + + assert_cc(sizeof(usec_t) == sizeof(uint64_t)); + + r = sd_bus_message_read(value, "t", t); + if (r < 0) + return r; + + return watchdog_set_timeout(t); } -static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) { - Manager *m = data; - const char *id = NULL; +static int method_get_unit(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_free_ char *path = NULL; + Manager *m = userdata; + const char *name; + Unit *u; + int r; - assert(i); - assert(property); + assert(bus); + assert(message); assert(m); - detect_virtualization(&id); + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - if (!id) - id = ""; - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id)) - return -ENOMEM; + u = manager_get_unit(m, name); + if (!u) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", name); - return 0; -} + SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "status"); -static DBusMessage *message_from_file_changes( - DBusMessage *m, - UnitFileChange *changes, - unsigned n_changes, - int carries_install_info) { + path = unit_dbus_path(u); + if (!path) + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); - DBusMessageIter iter, sub, sub2; - DBusMessage *reply; - unsigned i; + return sd_bus_reply_method_return(bus, message, "o", path); +} - reply = dbus_message_new_method_return(m); - if (!reply) - return NULL; +static int method_get_unit_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_free_ char *path = NULL; + Manager *m = userdata; + pid_t pid; + Unit *u; + int r; - dbus_message_iter_init_append(reply, &iter); + assert(bus); + assert(message); + assert(m); - if (carries_install_info >= 0) { - dbus_bool_t b; + assert_cc(sizeof(pid_t) == sizeof(uint32_t)); - b = !!carries_install_info; - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) - goto oom; + r = sd_bus_message_read(message, "u", &pid); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + if (pid == 0) { + r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); } - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub)) - goto oom; + u = manager_get_unit_by_pid(m, pid); + if (!u) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_UNIT_FOR_PID, "PID %u does not belong to any loaded unit.", pid); - for (i = 0; i < n_changes; i++) { - const char *type, *path, *source; - - type = unit_file_change_type_to_string(changes[i].type); - path = strempty(changes[i].path); - source = strempty(changes[i].source); - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) || - !dbus_message_iter_close_container(&sub, &sub2)) - goto oom; - } + SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "status"); + + path = unit_dbus_path(u); + if (!path) + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); + + return sd_bus_reply_method_return(bus, message, "o", path); +} + +static int method_load_unit(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *path = NULL; + Manager *m = userdata; + const char *name; + Unit *u; + int r; - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - return reply; + r = manager_load_unit(m, name, NULL, &error, &u); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, &error); + + SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "status"); -oom: - dbus_message_unref(reply); - return NULL; + path = unit_dbus_path(u); + if (!path) + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); + + return sd_bus_reply_method_return(bus, message, "o", path); } -static int bus_manager_send_unit_files_changed(Manager *m) { - DBusMessage *s; +static int method_start_unit_generic(sd_bus *bus, sd_bus_message *message, Manager *m, JobType job_type, bool reload_if_possible) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *name; + Unit *u; int r; - s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged"); - if (!s) - return -ENOMEM; + assert(bus); + assert(message); + assert(m); - r = bus_broadcast(m, s); - dbus_message_unref(s); + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - return r; + r = manager_load_unit(m, name, NULL, &error, &u); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, &error); + + return bus_unit_method_start_generic(bus, message, u, job_type, reload_if_possible); } -static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) { - uint64_t *t = data; +static int method_start_unit(sd_bus *bus, sd_bus_message *message, void *userdata) { + return method_start_unit_generic(bus, message, userdata, JOB_START, false); +} - assert(i); - assert(property); +static int method_stop_unit(sd_bus *bus, sd_bus_message *message, void *userdata) { + return method_start_unit_generic(bus, message, userdata, JOB_STOP, false); +} - dbus_message_iter_get_basic(i, t); +static int method_reload_unit(sd_bus *bus, sd_bus_message *message, void *userdata) { + return method_start_unit_generic(bus, message, userdata, JOB_RELOAD, false); +} - return watchdog_set_timeout(t); +static int method_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata) { + return method_start_unit_generic(bus, message, userdata, JOB_RESTART, false); } -static const char systemd_property_string[] = - PACKAGE_STRING "\0" - SYSTEMD_FEATURES; +static int method_try_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata) { + return method_start_unit_generic(bus, message, userdata, JOB_TRY_RESTART, false); +} -static const BusProperty bus_systemd_properties[] = { - { "Version", bus_property_append_string, "s", 0 }, - { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) }, - { NULL, } -}; +static int method_reload_or_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata) { + return method_start_unit_generic(bus, message, userdata, JOB_RESTART, true); +} -static const BusProperty bus_manager_properties[] = { - { "Tainted", bus_manager_append_tainted, "s", 0 }, - { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) }, - { "FirmwareTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.monotonic) }, - { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) }, - { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) }, - { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) }, - { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) }, - { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) }, - { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) }, - { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime) }, - { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) }, - { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) }, - { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) }, - { "SecurityStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, security_start_timestamp.realtime) }, - { "SecurityStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, security_start_timestamp.monotonic) }, - { "SecurityFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, security_finish_timestamp.realtime) }, - { "SecurityFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, security_finish_timestamp.monotonic) }, - { "GeneratorsStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.realtime) }, - { "GeneratorsStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.monotonic) }, - { "GeneratorsFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.realtime) }, - { "GeneratorsFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.monotonic) }, - { "UnitsLoadStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.realtime) }, - { "UnitsLoadStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.monotonic) }, - { "UnitsLoadFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.realtime) }, - { "UnitsLoadFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.monotonic) }, - { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level }, - { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target }, - { "NNames", bus_manager_append_n_names, "u", 0 }, - { "NJobs", bus_manager_append_n_jobs, "u", 0 }, - { "NInstalledJobs", bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) }, - { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) }, - { "Progress", bus_manager_append_progress, "d", 0 }, - { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true }, - { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) }, - { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) }, - { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true }, - { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) }, - { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) }, - { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec }, - { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec }, - { "Virtualization", bus_manager_append_virt, "s", 0, }, - { NULL, } -}; +static int method_reload_or_try_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata) { + return method_start_unit_generic(bus, message, userdata, JOB_TRY_RESTART, true); +} -static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) { - _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; - _cleanup_free_ char * path = NULL; - Manager *m = data; +static int method_start_unit_replace(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; + const char *old_name; + Unit *u; int r; - DBusError error; - JobType job_type = _JOB_TYPE_INVALID; - bool reload_if_possible = false; - const char *member; - assert(connection); + assert(bus); assert(message); assert(m); - dbus_error_init(&error); + r = sd_bus_message_read(message, "s", &old_name); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - member = dbus_message_get_member(message); + u = manager_get_unit(m, old_name); + if (!u || !u->job || u->job->type != JOB_START) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name); - if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) { - const char *name; - Unit *u; + return method_start_unit_generic(bus, message, m, JOB_START, false); +} - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); +static int method_kill_unit(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; + const char *name; + Unit *u; + int r; - u = manager_get_unit(m, name); - if (!u) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } + assert(bus); + assert(message); + assert(m); - SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status"); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - path = unit_dbus_path(u); - if (!path) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto oom; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) { - Unit *u; - uint32_t pid; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_UINT32, &pid, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - u = manager_get_unit_by_pid(m, (pid_t) pid); - if (!u) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status"); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - path = unit_dbus_path(u); - if (!path) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto oom; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) { - const char *name; - Unit *u; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - r = manager_load_unit(m, name, NULL, &error, &u); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status"); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - path = unit_dbus_path(u); - if (!path) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit")) - job_type = JOB_START; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace")) - job_type = JOB_START; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit")) - job_type = JOB_STOP; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit")) - job_type = JOB_RELOAD; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit")) - job_type = JOB_RESTART; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit")) - job_type = JOB_TRY_RESTART; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) { - reload_if_possible = true; - job_type = JOB_RESTART; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) { - reload_if_possible = true; - job_type = JOB_TRY_RESTART; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) { - const char *name, *swho; - int32_t signo; - Unit *u; - KillWho who; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &swho, - DBUS_TYPE_INT32, &signo, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (isempty(swho)) - who = KILL_ALL; - else { - who = kill_who_from_string(swho); - if (who < 0) - return bus_send_error_reply(connection, message, &error, -EINVAL); - } + u = manager_get_unit(m, name); + if (!u) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); - if (signo <= 0 || signo >= _NSIG) - return bus_send_error_reply(connection, message, &error, -EINVAL); + return bus_unit_method_kill(bus, message, u); +} - u = manager_get_unit(m, name); - if (!u) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } +static int method_reset_failed_unit(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; + const char *name; + Unit *u; + int r; - SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop"); + assert(bus); + assert(message); + assert(m); - r = unit_kill(u, who, signo, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) { - uint32_t id; - Job *j; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_UINT32, &id, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - j = manager_get_job(m, id); - if (!j) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status"); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - path = job_dbus_path(j); - if (!path) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) { - uint32_t id; - Job *j; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_UINT32, &id, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - j = manager_get_job(m, id); - if (!j) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } + u = manager_get_unit(m, name); + if (!u) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); - SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop"); - job_finish_and_invalidate(j, JOB_CANCELED, true); + return bus_unit_method_reset_failed(bus, message, u); +} - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; +static int method_set_unit_properties(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; + const char *name; + Unit *u; + int r; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) { + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + u = manager_get_unit(m, name); + if (!u) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); - SELINUX_ACCESS_CHECK(connection, message, "reboot"); - manager_clear_jobs(m); + return bus_unit_method_set_properties(bus, message, u); +} + +static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *name, *smode; + Manager *m = userdata; + JobMode mode; + UnitType t; + Unit *u; + int r; - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; + assert(bus); + assert(message); + assert(m); - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) { + r = sd_bus_message_read(message, "ss", &name, &smode); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - SELINUX_ACCESS_CHECK(connection, message, "reload"); + t = unit_name_to_type(name); + if (t < 0) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit type."); - manager_reset_failed(m); + if (!unit_vtable[t]->can_transient) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units."); - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; + mode = job_mode_from_string(smode); + if (mode < 0) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s is invalid.", smode); - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) { - const char *name; - Unit *u; + r = manager_load_unit(m, name, NULL, &error, &u); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, &error); - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); + SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "start"); - u = manager_get_unit(m, name); - if (!u) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } + if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name); - SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload"); - - unit_reset_failed(u); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) { - DBusMessageIter iter, sub; - Iterator i; - Unit *u; - const char *k; - - SELINUX_ACCESS_CHECK(connection, message, "status"); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub)) - goto oom; - - HASHMAP_FOREACH_KEY(u, k, m->units, i) { - char *u_path, *j_path; - const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following; - DBusMessageIter sub2; - uint32_t job_id; - Unit *f; - - if (k != u->id) - continue; - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2)) - goto oom; - - description = unit_description(u); - load_state = unit_load_state_to_string(u->load_state); - active_state = unit_active_state_to_string(unit_active_state(u)); - sub_state = unit_sub_state_to_string(u); - - f = unit_following(u); - following = f ? f->id : ""; - - u_path = unit_dbus_path(u); - if (!u_path) - goto oom; - - if (u->job) { - job_id = (uint32_t) u->job->id; - - if (!(j_path = job_dbus_path(u->job))) { - free(u_path); - goto oom; - } - - sjob_type = job_type_to_string(u->job->type); - } else { - job_id = 0; - j_path = u_path; - sjob_type = ""; - } - - if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) { - free(u_path); - if (u->job) - free(j_path); - goto oom; - } - - free(u_path); - if (u->job) - free(j_path); - - if (!dbus_message_iter_close_container(&sub, &sub2)) - goto oom; - } + /* OK, the unit failed to load and is unreferenced, now let's + * fill in the transient data instead */ + r = unit_make_transient(u); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; + /* Set our properties */ + r = bus_unit_set_properties(u, message, UNIT_RUNTIME, false, &error); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, &error); - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) { - DBusMessageIter iter, sub; - Iterator i; - Job *j; + /* And load this stub fully */ + r = unit_load(u); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, &error); - SELINUX_ACCESS_CHECK(connection, message, "status"); + manager_dispatch_load_queue(m); - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; + /* Finally, start it */ + return bus_unit_queue_job(bus, message, u, JOB_START, mode, false); +} - dbus_message_iter_init_append(reply, &iter); +static int method_get_job(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_free_ char *path = NULL; + Manager *m = userdata; + uint32_t id; + Job *j; + int r; - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub)) - goto oom; + assert(bus); + assert(message); + assert(m); - HASHMAP_FOREACH(j, m->jobs, i) { - char *u_path, *j_path; - const char *state, *type; - uint32_t id; - DBusMessageIter sub2; + r = sd_bus_message_read(message, "u", &id); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2)) - goto oom; + j = manager_get_job(m, id); + if (!j) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id); - id = (uint32_t) j->id; - state = job_state_to_string(j->state); - type = job_type_to_string(j->type); + SELINUX_UNIT_ACCESS_CHECK(j->unit, bus, message, "status"); - j_path = job_dbus_path(j); - if (!j_path) - goto oom; + path = job_dbus_path(j); + if (!path) + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); - u_path = unit_dbus_path(j->unit); - if (!u_path) { - free(j_path); - goto oom; - } + return sd_bus_reply_method_return(bus, message, "o", path); +} - if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) { - free(j_path); - free(u_path); - goto oom; - } +static int method_cancel_job(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; + uint32_t id; + Job *j; + int r; - free(j_path); - free(u_path); + assert(bus); + assert(message); + assert(m); - if (!dbus_message_iter_close_container(&sub, &sub2)) - goto oom; - } + r = sd_bus_message_read(message, "u", &id); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; + j = manager_get_job(m, id); + if (!j) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id); - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) { - char *client; - Set *s; + SELINUX_UNIT_ACCESS_CHECK(j->unit, bus, message, "stop"); - SELINUX_ACCESS_CHECK(connection, message, "status"); + job_finish_and_invalidate(j, JOB_CANCELED, true); - s = bus_acquire_subscribed(m, connection); - if (!s) - goto oom; + return sd_bus_reply_method_return(bus, message, NULL); +} - client = strdup(bus_message_get_sender_with_fallback(message)); - if (!client) - goto oom; +static int method_clear_jobs(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; - r = set_consume(s, client); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); + assert(bus); + assert(message); + assert(m); - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; + SELINUX_ACCESS_CHECK(bus, message, "reboot"); + manager_clear_jobs(m); - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) { - char *client; + return sd_bus_reply_method_return(bus, message, NULL); +} - SELINUX_ACCESS_CHECK(connection, message, "status"); +static int method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; - client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message)); - if (!client) { - dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed."); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } + assert(bus); + assert(message); + assert(m); + + SELINUX_ACCESS_CHECK(bus, message, "reload"); + manager_reset_failed(m); - free(client); + return sd_bus_reply_method_return(bus, message, NULL); +} - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; +static int method_list_units(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; + const char *k; + Iterator i; + Unit *u; + int r; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) { - FILE *f; - char *dump = NULL; - size_t size; + assert(bus); + assert(message); + assert(m); - SELINUX_ACCESS_CHECK(connection, message, "status"); + SELINUX_ACCESS_CHECK(bus, message, "status"); - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; + r = sd_bus_message_new_method_return(bus, message, &reply); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - f = open_memstream(&dump, &size); - if (!f) - goto oom; + r = sd_bus_message_open_container(reply, 'a', "(ssssssouso)"); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - manager_dump_units(m, f, NULL); - manager_dump_jobs(m, f, NULL); + HASHMAP_FOREACH_KEY(u, k, m->units, i) { + _cleanup_free_ char *unit_path = NULL, *job_path = NULL; + Unit *following; - if (ferror(f)) { - fclose(f); - free(dump); - goto oom; - } + if (k != u->id) + continue; - fclose(f); + following = unit_following(u); - if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) { - free(dump); - goto oom; + unit_path = unit_dbus_path(u); + if (!unit_path) + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); + + if (u->job) { + job_path = job_dbus_path(u->job); + if (!job_path) + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); } - free(dump); - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) { - const char *name; - dbus_bool_t cleanup; - Snapshot *s; + r = sd_bus_message_append( + reply, "(ssssssouso)", + u->id, + unit_description(u), + unit_load_state_to_string(u->load_state), + unit_active_state_to_string(unit_active_state(u)), + unit_sub_state_to_string(u), + following ? following->id : "", + unit_path, + u->job ? u->job->id : 0, + u->job ? job_type_to_string(u->job->type) : "", + job_path ? job_path : "/"); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + } - SELINUX_ACCESS_CHECK(connection, message, "start"); + r = sd_bus_message_close_container(reply); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_BOOLEAN, &cleanup, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); + return sd_bus_send(bus, reply, NULL); +} - if (isempty(name)) - name = NULL; +static int method_list_jobs(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; + Iterator i; + Job *j; + int r; - r = snapshot_create(m, name, cleanup, &error, &s); + assert(bus); + assert(message); + assert(m); + + SELINUX_ACCESS_CHECK(bus, message, "status"); + + r = sd_bus_message_new_method_return(bus, message, &reply); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + r = sd_bus_message_open_container(reply, 'a', "(usssoo)"); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + HASHMAP_FOREACH(j, m->jobs, i) { + _cleanup_free_ char *unit_path = NULL, *job_path = NULL; + + job_path = job_dbus_path(j); + if (!job_path) + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); + + unit_path = unit_dbus_path(j->unit); + if (!unit_path) + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); + + r = sd_bus_message_append( + reply, "(usssoo)", + j->id, + job_state_to_string(j->state), + job_type_to_string(j->type), + job_path, + unit_path); if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - path = unit_dbus_path(UNIT(s)); - if (!path) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) { - const char *name; - Unit *u; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - u = manager_get_unit(m, name); - if (!u) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } + return sd_bus_reply_method_errno(bus, message, r, NULL); + } - if (u->type != UNIT_SNAPSHOT) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } + r = sd_bus_message_close_container(reply); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop"); - snapshot_remove(SNAPSHOT(u)); + return sd_bus_send(bus, reply, NULL); +} - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; +static int method_subscribe(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; + int r; - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { - _cleanup_free_ char *introspection = NULL; - FILE *f; - Iterator i; - Unit *u; - Job *j; - const char *k; - size_t size; + assert(bus); + assert(message); + assert(m); - SELINUX_ACCESS_CHECK(connection, message, "status"); + SELINUX_ACCESS_CHECK(bus, message, "status"); - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; + r = bus_client_track(&m->subscribed, bus, sd_bus_message_get_sender(message)); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + if (r == 0) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_ALREADY_SUBSCRIBED, "Client is already subscribed."); - /* We roll our own introspection code here, instead of - * relying on bus_default_message_handler() because we - * need to generate our introspection string - * dynamically. */ + return sd_bus_reply_method_return(bus, message, NULL); +} - f = open_memstream(&introspection, &size); - if (!f) - goto oom; +static int method_unsubscribe(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; + int r; - fputs(INTROSPECTION_BEGIN, f); + assert(bus); + assert(message); + assert(m); - HASHMAP_FOREACH_KEY(u, k, m->units, i) { - _cleanup_free_ char *p = NULL; + SELINUX_ACCESS_CHECK(bus, message, "status"); - if (k != u->id) - continue; + r = bus_client_untrack(m->subscribed, bus, sd_bus_message_get_sender(message)); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + if (r == 0) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed."); - p = bus_path_escape(k); - if (!p) { - fclose(f); - goto oom; - } + return sd_bus_reply_method_return(bus, message, NULL); +} - fprintf(f, "<node name=\"unit/%s\"/>", p); - } +static int method_dump(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_free_ char *dump = NULL; + _cleanup_fclose_ FILE *f = NULL; + Manager *m = userdata; + size_t size; - HASHMAP_FOREACH(j, m->jobs, i) - fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id); + assert(bus); + assert(message); + assert(m); - fputs(INTROSPECTION_END, f); + SELINUX_ACCESS_CHECK(bus, message, "status"); - if (ferror(f)) { - fclose(f); - goto oom; - } + f = open_memstream(&dump, &size); + if (!f) + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); - fclose(f); + manager_dump_units(m, f, NULL); + manager_dump_jobs(m, f, NULL); - if (!introspection) - goto oom; + fflush(f); - if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) { - goto oom; - } - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) { + if (ferror(f)) + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); - SELINUX_ACCESS_CHECK(connection, message, "reload"); + return sd_bus_reply_method_return(bus, message, "s", dump); +} - assert(!m->queued_message); +static int method_create_snapshot(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *path = NULL; + Manager *m = userdata; + const char *name; + int cleanup; + Snapshot *s; + int r; - /* Instead of sending the reply back right away, we - * just remember that we need to and then send it - * after the reload is finished. That way the caller - * knows when the reload finished. */ + assert(bus); + assert(message); + assert(m); - m->queued_message = dbus_message_new_method_return(message); - if (!m->queued_message) - goto oom; + SELINUX_ACCESS_CHECK(bus, message, "start"); - m->queued_message_connection = connection; - m->exit_code = MANAGER_RELOAD; + r = sd_bus_message_read(message, "sb", &name, &cleanup); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) { + if (isempty(name)) + name = NULL; - SELINUX_ACCESS_CHECK(connection, message, "reload"); + r = snapshot_create(m, name, cleanup, &error, &s); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, &error); - /* We don't send a reply back here, the client should - * just wait for us disconnecting. */ + path = unit_dbus_path(UNIT(s)); + if (!path) + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); - m->exit_code = MANAGER_REEXECUTE; + return sd_bus_reply_method_return(bus, message, "o", path); +} - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) { +static int method_remove_snapshot(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; + const char *name; + Unit *u; + int r; - SELINUX_ACCESS_CHECK(connection, message, "halt"); + assert(bus); + assert(message); + assert(m); - if (m->running_as == SYSTEMD_SYSTEM) { - dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers."); - return bus_send_error_reply(connection, message, &error, -ENOTSUP); - } + SELINUX_ACCESS_CHECK(bus, message, "start"); - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - m->exit_code = MANAGER_EXIT; + u = manager_get_unit(m, name); + if (!u) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name); - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) { + if (u->type != UNIT_SNAPSHOT) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot", name); - SELINUX_ACCESS_CHECK(connection, message, "reboot"); + return bus_snapshot_method_remove(bus, message, u); +} - if (m->running_as != SYSTEMD_SYSTEM) { - dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers."); - return bus_send_error_reply(connection, message, &error, -ENOTSUP); - } +static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; + int r; - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; + assert(bus); + assert(message); + assert(m); - m->exit_code = MANAGER_REBOOT; + SELINUX_ACCESS_CHECK(bus, message, "reload"); - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) { + /* Instead of sending the reply back right away, we just + * remember that we need to and then send it after the reload + * is finished. That way the caller knows when the reload + * finished. */ - SELINUX_ACCESS_CHECK(connection, message, "halt"); + assert(!m->queued_message); + r = sd_bus_message_new_method_return(bus, message, &m->queued_message); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - if (m->running_as != SYSTEMD_SYSTEM) { - dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers."); - return bus_send_error_reply(connection, message, &error, -ENOTSUP); - } + m->queued_message_bus = sd_bus_ref(bus); + m->exit_code = MANAGER_RELOAD; - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; + return 1; +} - m->exit_code = MANAGER_POWEROFF; +static int method_reexecute(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) { + assert(bus); + assert(message); + assert(m); - SELINUX_ACCESS_CHECK(connection, message, "halt"); + SELINUX_ACCESS_CHECK(bus, message, "reload"); - if (m->running_as != SYSTEMD_SYSTEM) { - dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers."); - return bus_send_error_reply(connection, message, &error, -ENOTSUP); - } + /* We don't send a reply back here, the client should + * just wait for us disconnecting. */ - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; + m->exit_code = MANAGER_REEXECUTE; + return 1; +} - m->exit_code = MANAGER_HALT; +static int method_exit(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) { + assert(bus); + assert(message); + assert(m); - SELINUX_ACCESS_CHECK(connection, message, "reboot"); + SELINUX_ACCESS_CHECK(bus, message, "halt"); - if (m->running_as != SYSTEMD_SYSTEM) { - dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers."); - return bus_send_error_reply(connection, message, &error, -ENOTSUP); - } + if (m->running_as == SYSTEMD_SYSTEM) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers."); - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; + m->exit_code = MANAGER_EXIT; - m->exit_code = MANAGER_KEXEC; + return sd_bus_reply_method_return(bus, message, NULL); +} - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) { - const char *switch_root, *switch_root_init; - char *u, *v; - bool good; +static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; - SELINUX_ACCESS_CHECK(connection, message, "reboot"); + assert(bus); + assert(message); + assert(m); - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &switch_root, - DBUS_TYPE_STRING, &switch_root_init, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); + SELINUX_ACCESS_CHECK(bus, message, "reboot"); - if (path_equal(switch_root, "/") || !path_is_absolute(switch_root)) - return bus_send_error_reply(connection, message, NULL, -EINVAL); + if (m->running_as != SYSTEMD_SYSTEM) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers."); - if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init)) - return bus_send_error_reply(connection, message, NULL, -EINVAL); + m->exit_code = MANAGER_REBOOT; - if (m->running_as != SYSTEMD_SYSTEM) { - dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers."); - return bus_send_error_reply(connection, message, &error, -ENOTSUP); - } + return sd_bus_reply_method_return(bus, message, NULL); +} - /* Safety check */ - if (isempty(switch_root_init)) { - good = path_is_os_tree(switch_root); - if (!good) - log_error("Not switching root: %s does not seem to be an OS tree. /etc/os-release is missing.", switch_root); - } - else { - _cleanup_free_ char *p = NULL; - p = strjoin(switch_root, "/", switch_root_init, NULL); - if (!p) - goto oom; +static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; - good = access(p, X_OK) >= 0; - if (!good) - log_error("Not switching root: cannot execute new init %s", p); - } - if (!good) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - u = strdup(switch_root); - if (!u) - goto oom; - - if (!isempty(switch_root_init)) { - v = strdup(switch_root_init); - if (!v) { - free(u); - goto oom; - } - } else - v = NULL; - - free(m->switch_root); - free(m->switch_root_init); - m->switch_root = u; - m->switch_root_init = v; - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - m->exit_code = MANAGER_SWITCH_ROOT; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) { - _cleanup_strv_free_ char **l = NULL; - char **e = NULL; - - SELINUX_ACCESS_CHECK(connection, message, "reload"); - - r = bus_parse_strv(message, &l); - if (r == -ENOMEM) - goto oom; - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - if (!strv_env_is_valid(l)) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - e = strv_env_merge(2, m->environment, l); - if (!e) - goto oom; - - reply = dbus_message_new_method_return(message); - if (!reply) { - strv_free(e); - goto oom; - } + assert(bus); + assert(message); + assert(m); - strv_free(m->environment); - m->environment = e; + SELINUX_ACCESS_CHECK(bus, message, "halt"); - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) { - _cleanup_strv_free_ char **l = NULL; - char **e = NULL; + if (m->running_as != SYSTEMD_SYSTEM) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers."); - SELINUX_ACCESS_CHECK(connection, message, "reload"); + m->exit_code = MANAGER_POWEROFF; - r = bus_parse_strv(message, &l); - if (r == -ENOMEM) - goto oom; - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - if (!strv_env_name_or_assignment_is_valid(l)) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - e = strv_env_delete(m->environment, 1, l); - if (!e) - goto oom; - - reply = dbus_message_new_method_return(message); - if (!reply) { - strv_free(e); - goto oom; - } + return sd_bus_reply_method_return(bus, message, NULL); +} - strv_free(m->environment); - m->environment = e; +static int method_halt(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) { - _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL; - char **f = NULL; - DBusMessageIter iter; + assert(bus); + assert(message); + assert(m); - SELINUX_ACCESS_CHECK(connection, message, "reload"); + SELINUX_ACCESS_CHECK(bus, message, "halt"); - if (!dbus_message_iter_init(message, &iter)) - goto oom; + if (m->running_as != SYSTEMD_SYSTEM) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "Halt is only supported for system managers."); - r = bus_parse_strv_iter(&iter, &l_unset); - if (r == -ENOMEM) - goto oom; - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - if (!strv_env_name_or_assignment_is_valid(l_unset)) - return bus_send_error_reply(connection, message, NULL, -EINVAL); + m->exit_code = MANAGER_HALT; - if (!dbus_message_iter_next(&iter)) - return bus_send_error_reply(connection, message, NULL, -EINVAL); + return sd_bus_reply_method_return(bus, message, NULL); +} - r = bus_parse_strv_iter(&iter, &l_set); - if (r == -ENOMEM) - goto oom; - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - if (!strv_env_is_valid(l_set)) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - e = strv_env_delete(m->environment, 1, l_unset); - if (!e) - goto oom; - - f = strv_env_merge(2, e, l_set); - if (!f) - goto oom; - - reply = dbus_message_new_method_return(message); - if (!reply) { - strv_free(f); - goto oom; - } +static int method_kexec(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; - strv_free(m->environment); - m->environment = f; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) { - DBusMessageIter iter, sub, sub2; - Hashmap *h; - Iterator i; - UnitFileList *item; + assert(bus); + assert(message); + assert(m); - SELINUX_ACCESS_CHECK(connection, message, "status"); + SELINUX_ACCESS_CHECK(bus, message, "reboot"); - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; + if (m->running_as != SYSTEMD_SYSTEM) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers."); - h = hashmap_new(string_hash_func, string_compare_func); - if (!h) - goto oom; + m->exit_code = MANAGER_KEXEC; - r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h); - if (r < 0) { - unit_file_list_free(h); - return bus_send_error_reply(connection, message, NULL, r); - } + return sd_bus_reply_method_return(bus, message, NULL); +} - dbus_message_iter_init_append(reply, &iter); +static int method_switch_root(sd_bus *bus, sd_bus_message *message, void *userdata) { + char *ri = NULL, *rt = NULL; + const char *root, *init; + Manager *m = userdata; + int r; - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) { - unit_file_list_free(h); - goto oom; - } + assert(bus); + assert(message); + assert(m); - HASHMAP_FOREACH(item, h, i) { - const char *state; + SELINUX_ACCESS_CHECK(bus, message, "reboot"); - state = unit_file_state_to_string(item->state); - assert(state); + if (m->running_as != SYSTEMD_SYSTEM) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers."); - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) || - !dbus_message_iter_close_container(&sub, &sub2)) { - unit_file_list_free(h); - goto oom; - } - } + r = sd_bus_message_read(message, "ss", &root, &init); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - unit_file_list_free(h); - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) { - const char *name; - UnitFileState state; - const char *s; - - SELINUX_ACCESS_CHECK(connection, message, "status"); - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name); - if (state < 0) - return bus_send_error_reply(connection, message, NULL, state); - - s = unit_file_state_to_string(state); - assert(s); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_STRING, &s, - DBUS_TYPE_INVALID)) - goto oom; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") || - dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") || - dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") || - dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") || - dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") || - dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) { - - char **l = NULL; - DBusMessageIter iter; - UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; - UnitFileChange *changes = NULL; - unsigned n_changes = 0; - dbus_bool_t runtime, force; - int carries_install_info = -1; - - SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable"); - - if (!dbus_message_iter_init(message, &iter)) - goto oom; - - r = bus_parse_strv_iter(&iter, &l); - if (r < 0) { - if (r == -ENOMEM) - goto oom; + if (path_equal(root, "/") || !path_is_absolute(root)) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid switch root path %s", root); - return bus_send_error_reply(connection, message, NULL, r); - } + /* Safety check */ + if (isempty(init)) { + if (! path_is_os_tree(root)) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Specified switch root path %s does not seem to be an OS tree. /etc/os-release is missing.", root); + } else { + _cleanup_free_ char *p = NULL; - if (!dbus_message_iter_next(&iter) || - bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 || - bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) { - strv_free(l); - return bus_send_error_reply(connection, message, NULL, -EIO); - } + if (!path_is_absolute(init)) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid init path %s", init); - if (streq(member, "EnableUnitFiles")) { - r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes); - carries_install_info = r; - } else if (streq(member, "ReenableUnitFiles")) { - r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes); - carries_install_info = r; - } else if (streq(member, "LinkUnitFiles")) - r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes); - else if (streq(member, "PresetUnitFiles")) { - r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes); - carries_install_info = r; - } else if (streq(member, "MaskUnitFiles")) - r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes); - else if (streq(member, "SetDefaultTarget")) - r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes); - else - assert_not_reached("Uh? Wrong method"); - - strv_free(l); - bus_manager_send_unit_files_changed(m); + p = strappend(root, init); + if (!p) + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); - if (r < 0) { - unit_file_changes_free(changes, n_changes); - return bus_send_error_reply(connection, message, NULL, r); + if (access(p, X_OK) < 0) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Specified init binary %s does not exist.", p); + } + + rt = strdup(root); + if (!rt) + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); + + if (!isempty(init)) { + ri = strdup(init); + if (!ri) { + free(ri); + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); } + } - reply = message_from_file_changes(message, changes, n_changes, carries_install_info); - unit_file_changes_free(changes, n_changes); + free(m->switch_root); + m->switch_root = rt; - if (!reply) - goto oom; + free(m->switch_root_init); + m->switch_root_init = ri; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") || - dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) { + return sd_bus_reply_method_return(bus, message, NULL); +} - char **l = NULL; - DBusMessageIter iter; - UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; - UnitFileChange *changes = NULL; - unsigned n_changes = 0; - dbus_bool_t runtime; +static int method_set_environment(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_strv_free_ char **plus = NULL; + Manager *m = userdata; + int r; - SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable"); + assert(bus); + assert(message); + assert(m); - if (!dbus_message_iter_init(message, &iter)) - goto oom; + SELINUX_ACCESS_CHECK(bus, message, "reload"); - r = bus_parse_strv_iter(&iter, &l); - if (r < 0) { - if (r == -ENOMEM) - goto oom; + r = sd_bus_message_read_strv(message, &plus); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + if (!strv_env_is_valid(plus)) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments"); - return bus_send_error_reply(connection, message, NULL, r); - } + r = manager_environment_add(m, NULL, plus); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - if (!dbus_message_iter_next(&iter) || - bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) { - strv_free(l); - return bus_send_error_reply(connection, message, NULL, -EIO); - } + return sd_bus_reply_method_return(bus, message, NULL); +} + +static int method_unset_environment(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_strv_free_ char **minus = NULL; + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + SELINUX_ACCESS_CHECK(bus, message, "reload"); - if (streq(member, "DisableUnitFiles")) - r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes); - else if (streq(member, "UnmaskUnitFiles")) - r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes); - else - assert_not_reached("Uh? Wrong method"); + r = sd_bus_message_read_strv(message, &minus); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + if (!strv_env_name_or_assignment_is_valid(minus)) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments"); + + r = manager_environment_add(m, minus, NULL); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + return sd_bus_reply_method_return(bus, message, NULL); +} + +static int method_unset_and_set_environment(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_strv_free_ char **minus = NULL, **plus = NULL; + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + SELINUX_ACCESS_CHECK(bus, message, "reload"); + + r = sd_bus_message_read_strv(message, &plus); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + r = sd_bus_message_read_strv(message, &minus); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + if (!strv_env_is_valid(plus)) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments"); + if (!strv_env_name_or_assignment_is_valid(minus)) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments"); + + r = manager_environment_add(m, minus, plus); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + return sd_bus_reply_method_return(bus, message, NULL); +} + +static int method_list_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; + UnitFileList *item; + Hashmap *h; + Iterator i; + int r; + + assert(bus); + assert(message); + assert(m); + + SELINUX_ACCESS_CHECK(bus, message, "status"); + + r = sd_bus_message_new_method_return(bus, message, &reply); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - strv_free(l); - bus_manager_send_unit_files_changed(m); + h = hashmap_new(string_hash_func, string_compare_func); + if (!h) + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); + r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h); + if (r < 0) { + r = sd_bus_reply_method_errno(bus, message, r, NULL); + goto fail; + } + + r = sd_bus_message_open_container(reply, 'a', "(ss)"); + if (r < 0) { + r = sd_bus_reply_method_errno(bus, message, r, NULL); + goto fail; + } + + HASHMAP_FOREACH(item, h, i) { + + r = sd_bus_message_append(reply, "(ss)", item->path, unit_file_state_to_string(item->state)); if (r < 0) { - unit_file_changes_free(changes, n_changes); - return bus_send_error_reply(connection, message, NULL, r); + r = sd_bus_reply_method_errno(bus, message, r, NULL); + goto fail; } + } - reply = message_from_file_changes(message, changes, n_changes, -1); - unit_file_changes_free(changes, n_changes); + unit_file_list_free(h); - if (!reply) - goto oom; + r = sd_bus_message_close_container(reply); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) { - UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; - _cleanup_free_ char *default_target = NULL; + return sd_bus_send(bus, reply, NULL); - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; +fail: + unit_file_list_free(h); + return r; +} - r = unit_file_get_default(scope, NULL, &default_target); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); +static int method_get_unit_file_state(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; + const char *name; + UnitFileState state; + UnitFileScope scope; + int r; - if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_target, DBUS_TYPE_INVALID)) { - goto oom; - } + assert(bus); + assert(message); + assert(m); - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitProperties")) { - DBusMessageIter iter; - dbus_bool_t runtime; - const char *name; - Unit *u; + SELINUX_ACCESS_CHECK(bus, message, "status"); - if (!dbus_message_iter_init(message, &iter)) - goto oom; + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 || - bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0) - return bus_send_error_reply(connection, message, NULL, -EINVAL); + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; - u = manager_get_unit(m, name); - if (!u) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } + state = unit_file_get_state(scope, NULL, name); + if (state < 0) + return sd_bus_reply_method_errno(bus, message, state, NULL); - SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start"); + return sd_bus_reply_method_return(bus, message, "s", unit_file_state_to_string(state)); +} - r = bus_unit_set_properties(u, &iter, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartTransientUnit")) { - const char *name, *smode; - DBusMessageIter iter; - JobMode mode; - UnitType t; - Unit *u; - - if (!dbus_message_iter_init(message, &iter)) - goto oom; - - if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 || - bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &smode, true) < 0) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - t = unit_name_to_type(name); - if (t < 0) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - if (!unit_vtable[t]->can_transient) { - dbus_set_error(&error, DBUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t)); - return bus_send_error_reply(connection, message, &error, -EINVAL); - } +static int method_get_default_target(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_free_ char *default_target = NULL; + Manager *m = userdata; + UnitFileScope scope; + int r; - mode = job_mode_from_string(smode); - if (mode < 0) { - dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode); - return bus_send_error_reply(connection, message, &error, -EINVAL); - } + assert(bus); + assert(message); + assert(m); - r = manager_load_unit(m, name, NULL, NULL, &u); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); + SELINUX_ACCESS_CHECK(bus, message, "status"); - SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start"); + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; - if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) { - dbus_set_error(&error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name); - return bus_send_error_reply(connection, message, &error, -EEXIST); - } + r = unit_file_get_default(scope, NULL, &default_target); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - /* OK, the unit failed to load and is unreferenced, - * now let's fill in the transient data instead */ - r = unit_make_transient(u); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); + return sd_bus_reply_method_return(bus, message, "s", default_target); +} - /* Set our properties */ - r = bus_unit_set_properties(u, &iter, UNIT_RUNTIME, false, &error); +static int send_unit_files_changed(sd_bus *bus, const char *destination, void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *message = NULL; + int r; + + assert(bus); + + r = sd_bus_message_new_signal(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged", &message); + if (r < 0) + return r; + + return sd_bus_send_to(bus, message, destination, NULL); +} + +static int reply_unit_file_changes_and_free( + Manager *m, + sd_bus *bus, + sd_bus_message *message, + int carries_install_info, + UnitFileChange *changes, + unsigned n_changes) { + + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + unsigned i; + int r; + + if (n_changes > 0) + bus_manager_foreach_client(m, send_unit_files_changed, NULL); + + r = sd_bus_message_new_method_return(bus, message, &reply); + if (r < 0) + goto fail; + + if (carries_install_info >= 0) { + r = sd_bus_message_append(reply, "b", carries_install_info); if (r < 0) - return bus_send_error_reply(connection, message, &error, r); + goto fail; + } + + r = sd_bus_message_open_container(reply, 'a', "(sss)"); + if (r < 0) + goto fail; - /* And load this stub fully */ - r = unit_load(u); + for (i = 0; i < n_changes; i++) { + r = sd_bus_message_append( + message, "(sss)", + unit_file_change_type_to_string(changes[i].type), + changes[i].path, + changes[i].source); if (r < 0) - return bus_send_error_reply(connection, message, &error, r); + goto fail; + } - manager_dispatch_load_queue(m); + r = sd_bus_message_close_container(reply); + if (r < 0) + goto fail; - /* Finally, start it */ - return bus_unit_queue_job(connection, message, u, JOB_START, mode, false); + return sd_bus_send(bus, message, NULL); - } else { - const BusBoundProperties bps[] = { - { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string }, - { "org.freedesktop.systemd1.Manager", bus_manager_properties, m }, - { NULL, } - }; +fail: + unit_file_changes_free(changes, n_changes); + return sd_bus_reply_method_errno(bus, message, r, NULL); +} - SELINUX_ACCESS_CHECK(connection, message, "status"); +static int method_enable_unit_files_generic( + sd_bus *bus, + sd_bus_message *message, + Manager *m, const + char *verb, + int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes), + bool carries_install_info) { + + _cleanup_strv_free_ char **l = NULL; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + UnitFileScope scope; + int runtime, force, r; + + assert(bus); + assert(message); + assert(m); - return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps); - } + SELINUX_ACCESS_CHECK(bus, message, verb); - if (job_type != _JOB_TYPE_INVALID) { - const char *name, *smode, *old_name = NULL; - JobMode mode; - Unit *u; - dbus_bool_t b; - - if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace")) - b = dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &old_name, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &smode, - DBUS_TYPE_INVALID); - else - b = dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &smode, - DBUS_TYPE_INVALID); - if (!b) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (old_name) { - u = manager_get_unit(m, old_name); - if (!u || !u->job || u->job->type != JOB_START) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } - } + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - mode = job_mode_from_string(smode); - if (mode < 0) { - dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode); - return bus_send_error_reply(connection, message, &error, -EINVAL); - } + r = sd_bus_message_read(message, "bb", &runtime, &force); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - r = manager_load_unit(m, name, NULL, &error, &u); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; - return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible); - } + r = call(scope, runtime, NULL, l, force, &changes, &n_changes); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + return reply_unit_file_changes_and_free(m, bus, message, carries_install_info ? r : -1, changes, n_changes); +} - if (reply) - if (!bus_maybe_send_reply(connection, message, reply)) - goto oom; +static int method_enable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) { + return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_enable, true); +} - return DBUS_HANDLER_RESULT_HANDLED; +static int method_reenable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) { + return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_reenable, true); +} + +static int method_link_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) { + return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_link, false); +} + +static int method_preset_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) { + return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_preset, true); +} + +static int method_mask_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) { + return method_enable_unit_files_generic(bus, message, userdata, "disable", unit_file_mask, false); +} -oom: - dbus_error_free(&error); +static int method_disable_unit_files_generic( + sd_bus *bus, + sd_bus_message *message, + Manager *m, const + char *verb, + int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes)) { + + _cleanup_strv_free_ char **l = NULL; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + UnitFileScope scope; + int r, runtime; + + assert(bus); + assert(message); + assert(m); + + SELINUX_ACCESS_CHECK(bus, message, verb); + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + r = sd_bus_message_read(message, "b", &runtime); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + + r = call(scope, runtime, NULL, l, &changes, &n_changes); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes); +} - return DBUS_HANDLER_RESULT_NEED_MEMORY; +static int method_disable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) { + return method_disable_unit_files_generic(bus, message, userdata, "disable", unit_file_disable); } -const DBusObjectPathVTable bus_manager_vtable = { - .message_function = bus_manager_message_handler +static int method_unmask_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) { + return method_disable_unit_files_generic(bus, message, userdata, "enable", unit_file_unmask); +} + +static int method_set_default_target(sd_bus *bus, sd_bus_message *message, void *userdata) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + Manager *m = userdata; + UnitFileScope scope; + const char *name; + int force, r; + + assert(bus); + assert(message); + assert(m); + + SELINUX_ACCESS_CHECK(bus, message, "enable"); + + r = sd_bus_message_read(message, "sb", &name, &force); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + + r = unit_file_set_default(scope, NULL, name, force, &changes, &n_changes); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes); +} + +const sd_bus_vtable bus_manager_vtable[] = { + SD_BUS_VTABLE_START(0), + + SD_BUS_PROPERTY("Version", "s", property_get_version, 0, 0), + SD_BUS_PROPERTY("Features", "s", property_get_features, 0, 0), + SD_BUS_PROPERTY("Virtualization", "s", property_get_virtualization, 0, 0), + SD_BUS_PROPERTY("Tainted", "s", property_get_tainted, 0, 0), + BUS_PROPERTY_DUAL_TIMESTAMP("FirmwareTimestamp", offsetof(Manager, firmware_timestamp), 0), + BUS_PROPERTY_DUAL_TIMESTAMP("LoaderTimestamp", offsetof(Manager, loader_timestamp), 0), + BUS_PROPERTY_DUAL_TIMESTAMP("KernelTimestamp", offsetof(Manager, firmware_timestamp), 0), + BUS_PROPERTY_DUAL_TIMESTAMP("InitRDTimestamp", offsetof(Manager, initrd_timestamp), 0), + BUS_PROPERTY_DUAL_TIMESTAMP("UserspaceTimestamp", offsetof(Manager, userspace_timestamp), 0), + BUS_PROPERTY_DUAL_TIMESTAMP("FinishTimestamp", offsetof(Manager, finish_timestamp), 0), + BUS_PROPERTY_DUAL_TIMESTAMP("SecurityStartTimestamp", offsetof(Manager, security_start_timestamp), 0), + BUS_PROPERTY_DUAL_TIMESTAMP("SecurityFinishTimestamp", offsetof(Manager, security_finish_timestamp), 0), + BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsStartTimestamp", offsetof(Manager, generators_start_timestamp), 0), + BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsFinishTimestamp", offsetof(Manager, generators_finish_timestamp), 0), + BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadStartTimestamp", offsetof(Manager, units_load_start_timestamp), 0), + BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadFinishTimestamp", offsetof(Manager, units_load_finish_timestamp), 0), + SD_BUS_WRITABLE_PROPERTY("LogLevel", "s", property_get_log_level, property_set_log_level, 0, 0), + SD_BUS_WRITABLE_PROPERTY("LogTarget", "s", property_get_log_target, property_set_log_target, 0, 0), + SD_BUS_PROPERTY("NNames", "u", property_get_n_names, 0, 0), + SD_BUS_PROPERTY("NJobs", "u", property_get_n_jobs, 0, 0), + SD_BUS_PROPERTY("NInstalledJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_installed_jobs), 0), + SD_BUS_PROPERTY("NFailedJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_failed_jobs), 0), + SD_BUS_PROPERTY("Progress", "d", property_get_progress, 0, 0), + SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(Manager, environment), 0), + SD_BUS_PROPERTY("ConfirmSpawn", "b", bus_property_get_bool, offsetof(Manager, confirm_spawn), 0), + SD_BUS_PROPERTY("ShowStatus", "b", bus_property_get_bool, offsetof(Manager, show_status), 0), + SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.unit_path), 0), + SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), 0), + SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), 0), + SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), 0), + SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), 0), + + SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, 0), + SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, 0), + SD_BUS_METHOD("LoadUnit", "s", "o", method_load_unit, 0), + SD_BUS_METHOD("StartUnit", "ss", "o", method_start_unit, 0), + SD_BUS_METHOD("StartUnitReplace", "sss", "o", method_start_unit_replace, 0), + SD_BUS_METHOD("StopUnit", "ss", "o", method_stop_unit, 0), + SD_BUS_METHOD("ReloadUnit", "ss", "o", method_reload_unit, 0), + SD_BUS_METHOD("RestartUnit", "ss", "o", method_restart_unit, 0), + SD_BUS_METHOD("TryRestartUnit", "ss", "o", method_try_restart_unit, 0), + SD_BUS_METHOD("ReloadOrRestartUnit", "ss", "o", method_reload_or_restart_unit, 0), + SD_BUS_METHOD("ReloadOrTryRestartUnit", "ss", "o", method_reload_or_try_restart_unit, 0), + SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, 0), + SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, 0), + SD_BUS_METHOD("SetUnitProperties", "sb", "a(sv)", method_set_unit_properties, 0), + SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, 0), + SD_BUS_METHOD("GetJob", "u", "o", method_get_job, 0), + SD_BUS_METHOD("CancelJob", "u", NULL, method_cancel_job, 0), + SD_BUS_METHOD("ClearJobs", NULL, NULL, method_clear_jobs, 0), + SD_BUS_METHOD("ResetFailed", NULL, NULL, method_reset_failed, 0), + SD_BUS_METHOD("ListUnits", NULL, "a(ssssssouso)", method_list_units, 0), + SD_BUS_METHOD("ListJobs", NULL, "a(usssoo)", method_list_jobs, 0), + SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, 0), + SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, 0), + SD_BUS_METHOD("Dump", NULL, "s", method_dump, 0), + SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_create_snapshot, 0), + SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, 0), + SD_BUS_METHOD("Reload", NULL, NULL, method_reload, 0), + SD_BUS_METHOD("Reexecute", NULL, NULL, method_reexecute, 0), + SD_BUS_METHOD("Exit", NULL, NULL, method_exit, 0), + SD_BUS_METHOD("Reboot", NULL, NULL, method_reboot, 0), + SD_BUS_METHOD("PowerOff", NULL, NULL, method_poweroff, 0), + SD_BUS_METHOD("Halt", NULL, NULL, method_halt, 0), + SD_BUS_METHOD("KExec", NULL, NULL, method_kexec, 0), + SD_BUS_METHOD("SwitchRoot", "ss", NULL, method_switch_root, 0), + SD_BUS_METHOD("SetEnvironment", "as", NULL, method_set_environment, 0), + SD_BUS_METHOD("UnsetEnvironment", "as", NULL, method_unset_environment, 0), + SD_BUS_METHOD("UnsetAndSetEnvironment", "asas", NULL, method_unset_and_set_environment, 0), + SD_BUS_METHOD("ListUnitFiles", NULL, "a(ss)", method_list_unit_files, 0), + SD_BUS_METHOD("GetUnitFileState", "s", "s", method_get_unit_file_state, 0), + SD_BUS_METHOD("EnableUnitFiles", "asbb", "ba(sss)", method_enable_unit_files, 0), + SD_BUS_METHOD("DisableUnitFiles", "asb", "a(sss)", method_disable_unit_files, 0), + SD_BUS_METHOD("ReenableUnitFiles", "asbb", "ba(sss)", method_reenable_unit_files, 0), + SD_BUS_METHOD("LinkUnitFiles", "asbb", "a(sss)", method_link_unit_files, 0), + SD_BUS_METHOD("PresetUnitFiles", "asbb", "ba(sss)", method_preset_unit_files, 0), + SD_BUS_METHOD("MaskUnitFiles", "asbb", "a(sss)", method_mask_unit_files, 0), + SD_BUS_METHOD("UnmaskUnitFiles", "asb", "a(sss)", method_unmask_unit_files, 0), + SD_BUS_METHOD("SetDefaultTarget", "sb", "a(sss)", method_set_default_target, 0), + SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, 0), + + SD_BUS_SIGNAL("UnitNew", "so", 0), + SD_BUS_SIGNAL("UnitRemoved", "so", 0), + SD_BUS_SIGNAL("JobNew", "uos", 0), + SD_BUS_SIGNAL("JobRemoved", "uoss", 0), + SD_BUS_SIGNAL("StartupFinished", "tttttt", 0), + SD_BUS_SIGNAL("UnitFilesChanged", NULL, 0), + SD_BUS_SIGNAL("Reloading", "b", 0), + + SD_BUS_VTABLE_END }; + +int bus_manager_foreach_client(Manager *m, int (*send_message)(sd_bus *bus, const char *destination, void *userdata), void *userdata) { + Iterator i; + sd_bus *b; + unsigned n; + int r; + + n = set_size(m->subscribed); + if (n <= 0) + return 0; + if (n == 1) { + BusTrackedClient *d; + + assert_se(d = set_first(m->subscribed)); + return send_message(d->bus, isempty(d->name) ? NULL : d->name, userdata); + } + + /* Send to everybody */ + SET_FOREACH(b, m->private_buses, i) { + r = send_message(b, NULL, userdata); + if (r < 0) + return r; + } + + if (m->api_bus) + return send_message(m->api_bus, NULL, userdata); + + return 0; +} + +static int send_finished(sd_bus *bus, const char *destination, void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *message = NULL; + usec_t *times = userdata; + int r; + + assert(bus); + assert(times); + + r = sd_bus_message_new_signal(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished", &message); + if (r < 0) + return r; + + r = sd_bus_message_append(message, "tttttt", times[0], times[1], times[2], times[3], times[4], times[5]); + if (r < 0) + return r; + + return sd_bus_send_to(bus, message, destination, NULL); +} + +int bus_manager_send_finished( + Manager *m, + usec_t firmware_usec, + usec_t loader_usec, + usec_t kernel_usec, + usec_t initrd_usec, + usec_t userspace_usec, + usec_t total_usec) { + + assert(m); + + return bus_manager_foreach_client(m, send_finished, + (usec_t[6]) { firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec }); +} + +static int send_reloading(sd_bus *bus, const char *destination, void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *message = NULL; + int r; + + assert(bus); + + r = sd_bus_message_new_signal(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "Reloading", &message); + if (r < 0) + return r; + + r = sd_bus_message_append(message, "b", PTR_TO_INT(userdata)); + if (r < 0) + return r; + + return sd_bus_send_to(bus, message, destination, NULL); +} + +int bus_manager_send_reloading(Manager *m, bool active) { + assert(m); + + return bus_manager_foreach_client(m, send_reloading, INT_TO_PTR(active)); +} diff --git a/src/core/dbus-manager.h b/src/core/dbus-manager.h index f0dce5a2e9..ad451eb6fd 100644 --- a/src/core/dbus-manager.h +++ b/src/core/dbus-manager.h @@ -21,8 +21,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> +#include "sd-bus.h" +#include "manager.h" -extern const DBusObjectPathVTable bus_manager_vtable; +extern const sd_bus_vtable bus_manager_vtable[]; -extern const char bus_manager_interface[]; +int bus_manager_foreach_client(Manager *m, int (*send_message)(sd_bus *bus, const char *destination, void *userdata), void *userdata); + +int bus_manager_send_finished(Manager *m, usec_t firmware_usec, usec_t loader_usec, usec_t kernel_usec, usec_t initrd_usec, usec_t userspace_usec, usec_t total_usec); +int bus_manager_send_reloading(Manager *m, bool active); diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c index 70b2d48330..2056eab11e 100644 --- a/src/core/dbus-mount.c +++ b/src/core/dbus-mount.c @@ -19,67 +19,29 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> - +#include "unit.h" +#include "mount.h" #include "dbus-unit.h" #include "dbus-execute.h" #include "dbus-kill.h" #include "dbus-cgroup.h" -#include "dbus-common.h" -#include "selinux-access.h" #include "dbus-mount.h" - -#define BUS_MOUNT_INTERFACE \ - " <interface name=\"org.freedesktop.systemd1.Mount\">\n" \ - " <property name=\"Where\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"What\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"Options\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \ - BUS_UNIT_CGROUP_INTERFACE \ - BUS_EXEC_COMMAND_INTERFACE("ExecMount") \ - BUS_EXEC_COMMAND_INTERFACE("ExecUnmount") \ - BUS_EXEC_COMMAND_INTERFACE("ExecRemount") \ - BUS_EXEC_CONTEXT_INTERFACE \ - BUS_KILL_CONTEXT_INTERFACE \ - BUS_CGROUP_CONTEXT_INTERFACE \ - " <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \ - " </interface>\n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "<node>\n" \ - BUS_UNIT_INTERFACE \ - BUS_MOUNT_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "</node>\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Mount\0" - -const char bus_mount_interface[] = BUS_MOUNT_INTERFACE; - -const char bus_mount_invalidating_properties[] = - "What\0" - "Options\0" - "Type\0" - "ExecMount\0" - "ExecUnmount\0" - "ExecRemount\0" - "ControlPID\0" - "Result\0"; - -static int bus_mount_append_what(DBusMessageIter *i, const char *property, void *data) { - Mount *m = data; +#include "bus-util.h" + +static int property_get_what( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + Mount *m = userdata; const char *d; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(m); if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.what) @@ -89,18 +51,23 @@ static int bus_mount_append_what(DBusMessageIter *i, const char *property, void else d = ""; - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d)) - return -ENOMEM; - - return 0; + return sd_bus_message_append(reply, "s", d); } -static int bus_mount_append_options(DBusMessageIter *i, const char *property, void *data) { - Mount *m = data; +static int property_get_options( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + Mount *m = userdata; const char *d; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(m); if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.options) @@ -110,18 +77,23 @@ static int bus_mount_append_options(DBusMessageIter *i, const char *property, vo else d = ""; - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d)) - return -ENOMEM; - - return 0; + return sd_bus_message_append(reply, "s", d); } -static int bus_mount_append_type(DBusMessageIter *i, const char *property, void *data) { - Mount *m = data; +static int property_get_type( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + Mount *m = userdata; const char *d; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(m); if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.fstype) @@ -131,66 +103,50 @@ static int bus_mount_append_type(DBusMessageIter *i, const char *property, void else d = ""; - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d)) - return -ENOMEM; - - return 0; + return sd_bus_message_append(reply, "s", d); } -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_mount_append_mount_result, mount_result, MountResult); - -static const BusProperty bus_mount_properties[] = { - { "Where", bus_property_append_string, "s", offsetof(Mount, where), true }, - { "What", bus_mount_append_what, "s", 0 }, - { "Options", bus_mount_append_options, "s", 0 }, - { "Type", bus_mount_append_type, "s", 0 }, - { "TimeoutUSec", bus_property_append_usec, "t", offsetof(Mount, timeout_usec) }, - BUS_EXEC_COMMAND_PROPERTY("ExecMount", offsetof(Mount, exec_command[MOUNT_EXEC_MOUNT]), false), - BUS_EXEC_COMMAND_PROPERTY("ExecUnmount", offsetof(Mount, exec_command[MOUNT_EXEC_UNMOUNT]), false), - BUS_EXEC_COMMAND_PROPERTY("ExecRemount", offsetof(Mount, exec_command[MOUNT_EXEC_REMOUNT]), false), - { "ControlPID", bus_property_append_pid, "u", offsetof(Mount, control_pid) }, - { "DirectoryMode", bus_property_append_mode, "u", offsetof(Mount, directory_mode) }, - { "Result", bus_mount_append_mount_result, "s", offsetof(Mount, result) }, - { NULL, } +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, mount_result, MountResult); + +const sd_bus_vtable bus_mount_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Where", "s", NULL, offsetof(Mount, where), 0), + SD_BUS_PROPERTY("What", "s", property_get_what, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Options","s", property_get_options, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Type", "s", property_get_type, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("TimeoutUSec", "t", bus_property_get_usec, offsetof(Mount, timeout_usec), 0), + SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Mount, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Mount, directory_mode), 0), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Mount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_EXEC_COMMAND_VTABLE("ExecMount", offsetof(Mount, exec_command[MOUNT_EXEC_MOUNT]), 0), + BUS_EXEC_COMMAND_VTABLE("ExecUnmount", offsetof(Mount, exec_command[MOUNT_EXEC_UNMOUNT]), 0), + BUS_EXEC_COMMAND_VTABLE("ExecRemount", offsetof(Mount, exec_command[MOUNT_EXEC_REMOUNT]), 0), + SD_BUS_VTABLE_END }; -DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - Mount *m = MOUNT(u); - - const BusBoundProperties bps[] = { - { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, - { "org.freedesktop.systemd1.Mount", bus_unit_cgroup_properties, u }, - { "org.freedesktop.systemd1.Mount", bus_mount_properties, m }, - { "org.freedesktop.systemd1.Mount", bus_exec_context_properties, &m->exec_context }, - { "org.freedesktop.systemd1.Mount", bus_kill_context_properties, &m->kill_context }, - { "org.freedesktop.systemd1.Mount", bus_cgroup_context_properties, &m->cgroup_context }, - { NULL, } - }; - - SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status"); - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps ); -} +const char * const bus_mount_changing_properties[] = { + "What", + "Options", + "Type", + "ControlPID", + "Result", + NULL +}; int bus_mount_set_property( Unit *u, const char *name, - DBusMessageIter *i, + sd_bus_message *message, UnitSetPropertiesMode mode, - DBusError *error) { + sd_bus_error *error) { Mount *m = MOUNT(u); - int r; + assert(m); assert(name); - assert(u); - assert(i); + assert(message); - r = bus_cgroup_set_property(u, &m->cgroup_context, name, i, mode, error); - if (r != 0) - return r; - - return 0; + return bus_cgroup_set_property(u, &m->cgroup_context, name, message, mode, error); } int bus_mount_commit_properties(Unit *u) { diff --git a/src/core/dbus-mount.h b/src/core/dbus-mount.h index f4ec8b1625..4bb5d2ddee 100644 --- a/src/core/dbus-mount.h +++ b/src/core/dbus-mount.h @@ -21,14 +21,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> - +#include "sd-bus.h" #include "unit.h" -DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); +extern const sd_bus_vtable bus_mount_vtable[]; +extern const char * const bus_mount_changing_properties[]; -int bus_mount_set_property(Unit *u, const char *name, DBusMessageIter *i, UnitSetPropertiesMode mode, DBusError *error); +int bus_mount_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); int bus_mount_commit_properties(Unit *u); - -extern const char bus_mount_interface[]; -extern const char bus_mount_invalidating_properties[]; diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c index a523b81446..a206f49020 100644 --- a/src/core/dbus-path.c +++ b/src/core/dbus-path.c @@ -19,104 +19,75 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> - +#include "unit.h" +#include "path.h" #include "dbus-unit.h" #include "dbus-path.h" -#include "dbus-execute.h" -#include "dbus-common.h" -#include "selinux-access.h" - -#define BUS_PATH_INTERFACE \ - " <interface name=\"org.freedesktop.systemd1.Path\">\n" \ - " <property name=\"Unit\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"Paths\" type=\"a(ss)\" access=\"read\"/>\n" \ - " <property name=\"MakeDirectory\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \ - " </interface>\n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "<node>\n" \ - BUS_UNIT_INTERFACE \ - BUS_PATH_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "</node>\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Path\0" - -const char bus_path_interface[] = BUS_PATH_INTERFACE; - -const char bus_path_invalidating_properties[] = - "Result\0"; - -static int bus_path_append_paths(DBusMessageIter *i, const char *property, void *data) { - Path *p = data; - DBusMessageIter sub, sub2; +#include "bus-util.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, path_result, PathResult); + +static int property_get_paths( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + Path *p = userdata; PathSpec *k; + int r; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(p); - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &sub)) - return -ENOMEM; + r = sd_bus_message_open_container(reply, 'a', "(ss)"); + if (r < 0) + return r; LIST_FOREACH(spec, k, p->specs) { - const char *t = path_type_to_string(k->type); - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &t) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &k->path) || - !dbus_message_iter_close_container(&sub, &sub2)) - return -ENOMEM; + r = sd_bus_message_append(reply, "(ss)", path_type_to_string(k->type), k->path); + if (r < 0) + return r; } - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; + return sd_bus_message_close_container(reply); } -static int bus_path_append_unit(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data, *trigger; - const char *t; +static int property_get_unit( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - assert(i); - assert(property); - assert(u); + Unit *p = userdata, *trigger; - trigger = UNIT_TRIGGER(u); - t = trigger ? trigger->id : ""; + assert(bus); + assert(reply); + assert(p); - return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM; -} + trigger = UNIT_TRIGGER(p); -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_path_append_path_result, path_result, PathResult); + return sd_bus_message_append(reply, "s", trigger ? trigger->id : ""); +} -static const BusProperty bus_path_properties[] = { - { "Unit", bus_path_append_unit, "s", 0 }, - { "Paths", bus_path_append_paths, "a(ss)", 0 }, - { "MakeDirectory", bus_property_append_bool, "b", offsetof(Path, make_directory) }, - { "DirectoryMode", bus_property_append_mode, "u", offsetof(Path, directory_mode) }, - { "Result", bus_path_append_path_result, "s", offsetof(Path, result) }, - { NULL, } +const sd_bus_vtable bus_path_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Unit", "s", property_get_unit, 0, 0), + SD_BUS_PROPERTY("Paths", "a(ss)", property_get_paths, 0, 0), + SD_BUS_PROPERTY("MakeDirectory", "b", bus_property_get_bool, offsetof(Path, make_directory), 0), + SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Path, directory_mode), 0), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Path, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_VTABLE_END }; -DBusHandlerResult bus_path_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - Path *p = PATH(u); - const BusBoundProperties bps[] = { - { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, - { "org.freedesktop.systemd1.Path", bus_path_properties, p }, - { NULL, } - }; - - SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status"); - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps); -} +const char* const bus_path_changing_properties[] = { + "Result", + NULL +}; diff --git a/src/core/dbus-path.h b/src/core/dbus-path.h index c945f7d588..e9558f81b5 100644 --- a/src/core/dbus-path.h +++ b/src/core/dbus-path.h @@ -21,12 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> -#include "unit.h" +#include "sd-bus.h" -DBusHandlerResult bus_path_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_path_interface[]; - -extern const char bus_path_invalidating_properties[]; +extern const sd_bus_vtable bus_path_vtable[]; +extern const char* const bus_path_changing_properties[]; diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c index c790d26cfe..13ff49d62f 100644 --- a/src/core/dbus-scope.c +++ b/src/core/dbus-scope.c @@ -19,95 +19,54 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> - +#include "unit.h" +#include "scope.h" #include "dbus-unit.h" -#include "dbus-common.h" #include "dbus-cgroup.h" #include "dbus-kill.h" -#include "selinux-access.h" #include "dbus-scope.h" +#include "bus-util.h" -#define BUS_SCOPE_INTERFACE \ - " <interface name=\"org.freedesktop.systemd1.Scope\">\n" \ - BUS_UNIT_CGROUP_INTERFACE \ - " <property name=\"TimeoutStopUSec\" type=\"t\" access=\"read\"/>\n" \ - BUS_KILL_CONTEXT_INTERFACE \ - BUS_CGROUP_CONTEXT_INTERFACE \ - " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \ - " </interface>\n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "<node>\n" \ - BUS_UNIT_INTERFACE \ - BUS_SCOPE_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "</node>\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Scope\0" - -const char bus_scope_interface[] = BUS_SCOPE_INTERFACE; - -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_scope_append_scope_result, scope_result, ScopeResult); - -static const BusProperty bus_scope_properties[] = { - { "TimeoutStopUSec", bus_property_append_usec, "t", offsetof(Scope, timeout_stop_usec) }, - { "Result", bus_scope_append_scope_result, "s", offsetof(Scope, result) }, - {} -}; - -DBusHandlerResult bus_scope_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - Scope *s = SCOPE(u); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, scope_result, ScopeResult); - const BusBoundProperties bps[] = { - { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, - { "org.freedesktop.systemd1.Scope", bus_unit_cgroup_properties, u }, - { "org.freedesktop.systemd1.Scope", bus_scope_properties, s }, - { "org.freedesktop.systemd1.Scope", bus_cgroup_context_properties, &s->cgroup_context }, - { "org.freedesktop.systemd1.Scope", bus_kill_context_properties, &s->kill_context }, - {} - }; - - SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status"); +const sd_bus_vtable bus_scope_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Scope, timeout_stop_usec), 0), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Scope, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_VTABLE_END +}; - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps); -} +const char* const bus_scope_changing_properties[] = { + "Result", + NULL +}; static int bus_scope_set_transient_property( Scope *s, const char *name, - DBusMessageIter *i, + sd_bus_message *message, UnitSetPropertiesMode mode, - DBusError *error) { + sd_bus_error *error) { int r; - assert(name); assert(s); - assert(i); + assert(name); + assert(message); if (streq(name, "PIDs")) { - DBusMessageIter sub; unsigned n = 0; - - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(i) != DBUS_TYPE_UINT32) - return -EINVAL; + uint32_t pid; r = set_ensure_allocated(&s->pids, trivial_hash_func, trivial_compare_func); if (r < 0) return r; - dbus_message_iter_recurse(i, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32) { - uint32_t pid; + r = sd_bus_message_enter_container(message, 'a', "u"); + if (r < 0) + return r; - dbus_message_iter_get_basic(&sub, &pid); + while ((r = sd_bus_message_read(message, "u", &pid)) > 0) { if (pid <= 1) return -EINVAL; @@ -118,9 +77,14 @@ static int bus_scope_set_transient_property( return r; } - dbus_message_iter_next(&sub); n++; } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; if (n <= 0) return -EINVAL; @@ -129,17 +93,16 @@ static int bus_scope_set_transient_property( } else if (streq(name, "TimeoutStopUSec")) { - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64) - return -EINVAL; - if (mode != UNIT_CHECK) { - uint64_t t; - - dbus_message_iter_get_basic(i, &t); - - s->timeout_stop_usec = t; - - unit_write_drop_in_format(UNIT(s), mode, name, "[Scope]\nTimeoutStopSec=%lluus\n", (unsigned long long) t); + r = sd_bus_message_read(message, "t", &s->timeout_stop_usec); + if (r < 0) + return r; + + unit_write_drop_in_format(UNIT(s), mode, name, "[Scope]\nTimeoutStopSec=%lluus\n", (unsigned long long) s->timeout_stop_usec); + } else { + r = sd_bus_message_skip(message, "t"); + if (r < 0) + return r; } return 1; @@ -151,29 +114,29 @@ static int bus_scope_set_transient_property( int bus_scope_set_property( Unit *u, const char *name, - DBusMessageIter *i, + sd_bus_message *message, UnitSetPropertiesMode mode, - DBusError *error) { + sd_bus_error *error) { Scope *s = SCOPE(u); int r; + assert(s); assert(name); - assert(u); - assert(i); + assert(message); - r = bus_cgroup_set_property(u, &s->cgroup_context, name, i, mode, error); + r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error); if (r != 0) return r; if (u->load_state == UNIT_STUB) { /* While we are created we still accept PIDs */ - r = bus_scope_set_transient_property(s, name, i, mode, error); + r = bus_scope_set_transient_property(s, name, message, mode, error); if (r != 0) return r; - r = bus_kill_context_set_transient_property(u, &s->kill_context, name, i, mode, error); + r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error); if (r != 0) return r; } diff --git a/src/core/dbus-scope.h b/src/core/dbus-scope.h index e6836f13f0..30c5e1e0a7 100644 --- a/src/core/dbus-scope.h +++ b/src/core/dbus-scope.h @@ -21,13 +21,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> - +#include "sd-bus.h" #include "unit.h" -DBusHandlerResult bus_scope_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); +extern const sd_bus_vtable bus_scope_vtable[]; +extern const char* const bus_scope_changing_properties[]; -int bus_scope_set_property(Unit *u, const char *name, DBusMessageIter *i, UnitSetPropertiesMode mode, DBusError *error); +int bus_scope_set_property(Unit *u, const char *name, sd_bus_message *i, UnitSetPropertiesMode mode, sd_bus_error *error); int bus_scope_commit_properties(Unit *u); - -extern const char bus_scope_interface[]; diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index c888570c4b..c4bfa2c38f 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -19,176 +19,92 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> - #include "strv.h" #include "path-util.h" +#include "unit.h" +#include "service.h" #include "dbus-unit.h" #include "dbus-execute.h" #include "dbus-kill.h" #include "dbus-cgroup.h" -#include "dbus-common.h" -#include "selinux-access.h" #include "dbus-service.h" - -#define BUS_SERVICE_INTERFACE \ - " <interface name=\"org.freedesktop.systemd1.Service\">\n" \ - " <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"Restart\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"PIDFile\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"NotifyAccess\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"RestartUSec\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"TimeoutStartUSec\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"TimeoutStopUSec\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"WatchdogUSec\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"WatchdogTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"WatchdogTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"StartLimitInterval\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"StartLimitBurst\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"StartLimitAction\" type=\"s\" access=\"readwrite\"/>\n" \ - BUS_UNIT_CGROUP_INTERFACE \ - BUS_EXEC_COMMAND_INTERFACE("ExecStartPre") \ - BUS_EXEC_COMMAND_INTERFACE("ExecStart") \ - BUS_EXEC_COMMAND_INTERFACE("ExecStartPost") \ - BUS_EXEC_COMMAND_INTERFACE("ExecReload") \ - BUS_EXEC_COMMAND_INTERFACE("ExecStop") \ - BUS_EXEC_COMMAND_INTERFACE("ExecStopPost") \ - BUS_EXEC_CONTEXT_INTERFACE \ - BUS_KILL_CONTEXT_INTERFACE \ - BUS_CGROUP_CONTEXT_INTERFACE \ - " <property name=\"PermissionsStartOnly\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"RootDirectoryStartOnly\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"RemainAfterExit\" type=\"b\" access=\"read\"/>\n" \ - BUS_EXEC_STATUS_INTERFACE("ExecMain") \ - " <property name=\"MainPID\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"BusName\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"StatusText\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \ - " </interface>\n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "<node>\n" \ - BUS_UNIT_INTERFACE \ - BUS_SERVICE_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "</node>\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Service\0" - -const char bus_service_interface[] = BUS_SERVICE_INTERFACE; - -const char bus_service_invalidating_properties[] = - "ExecStartPre\0" - "ExecStart\0" - "ExecStartPost\0" - "ExecReload\0" - "ExecStop\0" - "ExecStopPost\0" - "ExecMain\0" - "WatchdogTimestamp\0" - "WatchdogTimestampMonotonic\0" - "MainPID\0" - "ControlPID\0" - "StatusText\0" - "Result\0"; - -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_type, service_type, ServiceType); -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_restart, service_restart, ServiceRestart); -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_notify_access, notify_access, NotifyAccess); -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_service_result, service_result, ServiceResult); -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_start_limit_action, start_limit_action, StartLimitAction); -static DEFINE_BUS_PROPERTY_SET_ENUM(bus_service_set_start_limit_action, start_limit_action, StartLimitAction); - -static const BusProperty bus_exec_main_status_properties[] = { - { "ExecMainStartTimestamp", bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.realtime) }, - { "ExecMainStartTimestampMonotonic",bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.monotonic) }, - { "ExecMainExitTimestamp", bus_property_append_usec, "t", offsetof(ExecStatus, exit_timestamp.realtime) }, - { "ExecMainExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(ExecStatus, exit_timestamp.monotonic) }, - { "ExecMainPID", bus_property_append_pid, "u", offsetof(ExecStatus, pid) }, - { "ExecMainCode", bus_property_append_int, "i", offsetof(ExecStatus, code) }, - { "ExecMainStatus", bus_property_append_int, "i", offsetof(ExecStatus, status) }, - {} +#include "bus-util.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart, service_restart, ServiceRestart); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_notify_access, notify_access, NotifyAccess); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_start_limit_action, start_limit_action, StartLimitAction); + +const sd_bus_vtable bus_service_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Service, type), 0), + SD_BUS_PROPERTY("Restart", "s", property_get_restart, offsetof(Service, restart), 0), + SD_BUS_PROPERTY("PIDFile", "s", NULL, offsetof(Service, pid_file), 0), + SD_BUS_PROPERTY("NotifyAccess", "s", property_get_notify_access, offsetof(Service, notify_access), 0), + SD_BUS_PROPERTY("RestartUSec", "t", bus_property_get_usec, offsetof(Service, restart_usec), 0), + SD_BUS_PROPERTY("TimeoutStartUSec", "t", bus_property_get_usec, offsetof(Service, timeout_start_usec), 0), + SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Service, timeout_stop_usec), 0), + SD_BUS_PROPERTY("WatchdogUSec", "t", bus_property_get_usec, offsetof(Service, watchdog_usec), 0), + BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0), + SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Service, start_limit.interval), 0), + SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Service, start_limit.burst), 0), + SD_BUS_PROPERTY("StartLimitAction", "s", property_get_start_limit_action, offsetof(Service, start_limit_action), 0), + SD_BUS_PROPERTY("PermissionsStartOnly", "b", bus_property_get_bool, offsetof(Service, permissions_start_only), 0), + SD_BUS_PROPERTY("RootDirectoryStartOnly", "b", bus_property_get_bool, offsetof(Service, root_directory_start_only), 0), + SD_BUS_PROPERTY("RemainAfterExit", "b", bus_property_get_bool, offsetof(Service, remain_after_exit), 0), + SD_BUS_PROPERTY("GuessMainPID", "b", bus_property_get_bool, offsetof(Service, guess_main_pid), 0), + SD_BUS_PROPERTY("MainPID", "u", bus_property_get_pid, offsetof(Service, main_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Service, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), 0), + SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_EXEC_COMMAND_VTABLE("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), 0), + BUS_EXEC_COMMAND_VTABLE("ExecStart", offsetof(Service, exec_command[SERVICE_EXEC_START]), 0), + BUS_EXEC_COMMAND_VTABLE("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), 0), + BUS_EXEC_COMMAND_VTABLE("ExecReload", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]), 0), + BUS_EXEC_COMMAND_VTABLE("ExecStop", offsetof(Service, exec_command[SERVICE_EXEC_STOP]), 0), + BUS_EXEC_COMMAND_VTABLE("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), 0), + SD_BUS_VTABLE_END }; -static const BusProperty bus_service_properties[] = { - { "Type", bus_service_append_type, "s", offsetof(Service, type) }, - { "Restart", bus_service_append_restart, "s", offsetof(Service, restart) }, - { "PIDFile", bus_property_append_string, "s", offsetof(Service, pid_file), true }, - { "NotifyAccess", bus_service_append_notify_access, "s", offsetof(Service, notify_access) }, - { "RestartUSec", bus_property_append_usec, "t", offsetof(Service, restart_usec) }, - { "TimeoutStartUSec", bus_property_append_usec, "t", offsetof(Service, timeout_start_usec) }, - { "TimeoutStopUSec", bus_property_append_usec, "t", offsetof(Service, timeout_stop_usec) }, - { "WatchdogUSec", bus_property_append_usec, "t", offsetof(Service, watchdog_usec) }, - { "WatchdogTimestamp", bus_property_append_usec, "t", offsetof(Service, watchdog_timestamp.realtime) }, - { "WatchdogTimestampMonotonic",bus_property_append_usec, "t", offsetof(Service, watchdog_timestamp.monotonic) }, - { "StartLimitInterval", bus_property_append_usec, "t", offsetof(Service, start_limit.interval) }, - { "StartLimitBurst", bus_property_append_uint32, "u", offsetof(Service, start_limit.burst) }, - { "StartLimitAction", bus_service_append_start_limit_action,"s", offsetof(Service, start_limit_action), false, bus_service_set_start_limit_action}, - BUS_EXEC_COMMAND_PROPERTY("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), true ), - BUS_EXEC_COMMAND_PROPERTY("ExecStart", offsetof(Service, exec_command[SERVICE_EXEC_START]), true ), - BUS_EXEC_COMMAND_PROPERTY("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), true ), - BUS_EXEC_COMMAND_PROPERTY("ExecReload", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]), true ), - BUS_EXEC_COMMAND_PROPERTY("ExecStop", offsetof(Service, exec_command[SERVICE_EXEC_STOP]), true ), - BUS_EXEC_COMMAND_PROPERTY("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), true ), - { "PermissionsStartOnly", bus_property_append_bool, "b", offsetof(Service, permissions_start_only) }, - { "RootDirectoryStartOnly", bus_property_append_bool, "b", offsetof(Service, root_directory_start_only) }, - { "RemainAfterExit", bus_property_append_bool, "b", offsetof(Service, remain_after_exit) }, - { "GuessMainPID", bus_property_append_bool, "b", offsetof(Service, guess_main_pid) }, - { "MainPID", bus_property_append_pid, "u", offsetof(Service, main_pid) }, - { "ControlPID", bus_property_append_pid, "u", offsetof(Service, control_pid) }, - { "BusName", bus_property_append_string, "s", offsetof(Service, bus_name), true }, - { "StatusText", bus_property_append_string, "s", offsetof(Service, status_text), true }, - { "Result", bus_service_append_service_result,"s", offsetof(Service, result) }, - {} +const char* const bus_service_changing_properties[] = { + "ExecMainStartTimestamp", + "ExecMainStartTimestampMonotonic", + "ExecMainExitTimestamp", + "ExecMainExitTimestampMonotonic", + "ExecMainPID", + "ExecMainCode", + "ExecMainStatus", + "MainPID", + "ControlPID", + "StatusText", + "Result", + NULL }; -DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connection, DBusMessage *message) { - Service *s = SERVICE(u); - - const BusBoundProperties bps[] = { - { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, - { "org.freedesktop.systemd1.Service", bus_unit_cgroup_properties, u }, - { "org.freedesktop.systemd1.Service", bus_service_properties, s }, - { "org.freedesktop.systemd1.Service", bus_exec_context_properties, &s->exec_context }, - { "org.freedesktop.systemd1.Service", bus_kill_context_properties, &s->kill_context }, - { "org.freedesktop.systemd1.Service", bus_cgroup_context_properties, &s->cgroup_context }, - { "org.freedesktop.systemd1.Service", bus_exec_main_status_properties, &s->main_exec_status }, - {} - }; - - SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status"); - - return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps); -} - static int bus_service_set_transient_property( Service *s, const char *name, - DBusMessageIter *i, + sd_bus_message *message, UnitSetPropertiesMode mode, - DBusError *error) { + sd_bus_error *error) { int r; - assert(name); assert(s); - assert(i); + assert(name); + assert(message); if (streq(name, "RemainAfterExit")) { - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_BOOLEAN) - return -EINVAL; + int b; - if (mode != UNIT_CHECK) { - dbus_bool_t b; - - dbus_message_iter_get_basic(i, &b); + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + if (mode != UNIT_CHECK) { s->remain_after_exit = b; unit_write_drop_in_private_format(UNIT(s), mode, name, "RemainAfterExit=%s\n", yes_no(b)); } @@ -196,38 +112,35 @@ static int bus_service_set_transient_property( return 1; } else if (streq(name, "ExecStart")) { - DBusMessageIter sub; unsigned n = 0; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRUCT) - return -EINVAL; + r = sd_bus_message_enter_container(message, 'a', "(sasb)"); + if (r < 0) + return r; - dbus_message_iter_recurse(i, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { + while ((r = sd_bus_message_enter_container(message, 'r', "sasb")) > 0) { _cleanup_strv_free_ char **argv = NULL; - DBusMessageIter sub2; - dbus_bool_t ignore; const char *path; + int b; - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0) - return -EINVAL; + r = sd_bus_message_read(message, "s", &path); + if (r < 0) + return r; - if (!path_is_absolute(path)) { - dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path); - return -EINVAL; - } + if (!path_is_absolute(path)) + return sd_bus_error_set_errnof(error, EINVAL, "Path %s is not absolute.", path); - r = bus_parse_strv_iter(&sub2, &argv); + r = sd_bus_message_read_strv(message, &argv); if (r < 0) return r; - dbus_message_iter_next(&sub2); + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) < 0) - return -EINVAL; + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; if (mode != UNIT_CHECK) { ExecCommand *c; @@ -245,15 +158,16 @@ static int bus_service_set_transient_property( c->argv = argv; argv = NULL; - c->ignore = ignore; + c->ignore = b; path_kill_slashes(c->path); exec_command_append_list(&s->exec_command[SERVICE_EXEC_START], c); } n++; - dbus_message_iter_next(&sub); } + if (r < 0) + return r; if (mode != UNIT_CHECK) { _cleanup_free_ char *buf = NULL; @@ -298,29 +212,29 @@ static int bus_service_set_transient_property( int bus_service_set_property( Unit *u, const char *name, - DBusMessageIter *i, + sd_bus_message *message, UnitSetPropertiesMode mode, - DBusError *error) { + sd_bus_error *error) { Service *s = SERVICE(u); int r; + assert(s); assert(name); - assert(u); - assert(i); + assert(message); - r = bus_cgroup_set_property(u, &s->cgroup_context, name, i, mode, error); + r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error); if (r != 0) return r; if (u->transient && u->load_state == UNIT_STUB) { /* This is a transient unit, let's load a little more */ - r = bus_service_set_transient_property(s, name, i, mode, error); + r = bus_service_set_transient_property(s, name, message, mode, error); if (r != 0) return r; - r = bus_kill_context_set_transient_property(u, &s->kill_context, name, i, mode, error); + r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error); if (r != 0) return r; } diff --git a/src/core/dbus-service.h b/src/core/dbus-service.h index 9b9f13701c..5fa9b2f139 100644 --- a/src/core/dbus-service.h +++ b/src/core/dbus-service.h @@ -21,14 +21,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> - +#include "sd-bus.h" #include "unit.h" -DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); +extern const sd_bus_vtable bus_service_vtable[]; +extern const char* const bus_service_changing_properties[]; -int bus_service_set_property(Unit *u, const char *name, DBusMessageIter *i, UnitSetPropertiesMode mode, DBusError *error); +int bus_service_set_property(Unit *u, const char *name, sd_bus_message *i, UnitSetPropertiesMode mode, sd_bus_error *error); int bus_service_commit_properties(Unit *u); - -extern const char bus_service_interface[]; -extern const char bus_service_invalidating_properties[]; diff --git a/src/core/dbus-slice.c b/src/core/dbus-slice.c index eeefcdbcd6..2a48ea455e 100644 --- a/src/core/dbus-slice.c +++ b/src/core/dbus-slice.c @@ -19,70 +19,30 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> - +#include "unit.h" +#include "slice.h" #include "dbus-unit.h" -#include "dbus-common.h" #include "dbus-cgroup.h" -#include "selinux-access.h" #include "dbus-slice.h" -#define BUS_SLICE_INTERFACE \ - " <interface name=\"org.freedesktop.systemd1.Slice\">\n" \ - BUS_UNIT_CGROUP_INTERFACE \ - BUS_CGROUP_CONTEXT_INTERFACE \ - " </interface>\n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "<node>\n" \ - BUS_UNIT_INTERFACE \ - BUS_SLICE_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "</node>\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Slice\0" - -const char bus_slice_interface[] = BUS_SLICE_INTERFACE; - -DBusHandlerResult bus_slice_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - Slice *s = SLICE(u); - - const BusBoundProperties bps[] = { - { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, - { "org.freedesktop.systemd1.Slice", bus_unit_cgroup_properties, u }, - { "org.freedesktop.systemd1.Slice", bus_cgroup_context_properties, &s->cgroup_context }, - {} - }; - - SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status"); - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps); -} +const sd_bus_vtable bus_slice_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_VTABLE_END +}; int bus_slice_set_property( Unit *u, const char *name, - DBusMessageIter *i, + sd_bus_message *message, UnitSetPropertiesMode mode, - DBusError *error) { + sd_bus_error *error) { Slice *s = SLICE(u); - int r; assert(name); assert(u); - assert(i); - - r = bus_cgroup_set_property(u, &s->cgroup_context, name, i, mode, error); - if (r != 0) - return r; - return 0; + return bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error); } int bus_slice_commit_properties(Unit *u) { diff --git a/src/core/dbus-slice.h b/src/core/dbus-slice.h index c5ac473763..eadc3b1a9c 100644 --- a/src/core/dbus-slice.h +++ b/src/core/dbus-slice.h @@ -21,13 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> - +#include "sd-bus.h" #include "unit.h" -DBusHandlerResult bus_slice_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); +extern const sd_bus_vtable bus_slice_vtable[]; -int bus_slice_set_property(Unit *u, const char *name, DBusMessageIter *i, UnitSetPropertiesMode mode, DBusError *error); +int bus_slice_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); int bus_slice_commit_properties(Unit *u); - -extern const char bus_slice_interface[]; diff --git a/src/core/dbus-snapshot.c b/src/core/dbus-snapshot.c index 9978df6022..a4ba588a1d 100644 --- a/src/core/dbus-snapshot.c +++ b/src/core/dbus-snapshot.c @@ -19,66 +19,29 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "selinux-access.h" +#include "unit.h" +#include "snapshot.h" #include "dbus-unit.h" #include "dbus-snapshot.h" -#include "dbus-common.h" -#include "selinux-access.h" - -#define BUS_SNAPSHOT_INTERFACE \ - " <interface name=\"org.freedesktop.systemd1.Snapshot\">\n" \ - " <method name=\"Remove\"/>\n" \ - " <property name=\"Cleanup\" type=\"b\" access=\"read\"/>\n" \ - " </interface>\n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "<node>\n" \ - BUS_UNIT_INTERFACE \ - BUS_SNAPSHOT_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "</node>\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Snapshot\0" - -const char bus_snapshot_interface[] = BUS_SNAPSHOT_INTERFACE; - -static const BusProperty bus_snapshot_properties[] = { - { "Cleanup", bus_property_append_bool, "b", offsetof(Snapshot, cleanup) }, - { NULL, } -}; -DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - Snapshot *s = SNAPSHOT(u); - _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; +int bus_snapshot_method_remove(sd_bus *bus, sd_bus_message *message, void *userdata) { + Snapshot *s = userdata; - if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Snapshot", "Remove")) { + assert(bus); + assert(message); + assert(s); - SELINUX_UNIT_ACCESS_CHECK(u, c, message, "stop"); + SELINUX_UNIT_ACCESS_CHECK(UNIT(s), bus, message, "stop"); - reply = dbus_message_new_method_return(message); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; + snapshot_remove(s); - snapshot_remove(SNAPSHOT(u)); - - } else { - const BusBoundProperties bps[] = { - { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, - { "org.freedesktop.systemd1.Snapshot", bus_snapshot_properties, s }, - { NULL, } - }; - - SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status"); - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps); - } - - if (!bus_maybe_send_reply(c, message, reply)) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - return DBUS_HANDLER_RESULT_HANDLED; + return sd_bus_reply_method_return(bus, message, NULL); } + +const sd_bus_vtable bus_snapshot_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("Remove", NULL, NULL, bus_snapshot_method_remove, 0), + SD_BUS_PROPERTY("Cleanup", "b", bus_property_get_bool, offsetof(Snapshot, cleanup), 0), + SD_BUS_VTABLE_END +}; diff --git a/src/core/dbus-snapshot.h b/src/core/dbus-snapshot.h index 1208aafff6..f6f432240d 100644 --- a/src/core/dbus-snapshot.h +++ b/src/core/dbus-snapshot.h @@ -21,10 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> +#include "sd-bus.h" -#include "unit.h" +extern const sd_bus_vtable bus_snapshot_vtable[]; -DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_snapshot_interface[]; +int bus_snapshot_method_remove(sd_bus *bus, sd_bus_message *message, void *userdata); diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 60a8d0501c..e9fa24d1a3 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -19,122 +19,50 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> - +#include "unit.h" +#include "socket.h" #include "dbus-unit.h" #include "dbus-execute.h" #include "dbus-kill.h" #include "dbus-cgroup.h" -#include "dbus-common.h" -#include "selinux-access.h" #include "dbus-socket.h" +#include "bus-util.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, socket_result, SocketResult); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only); + +static int property_get_listen( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { -#define BUS_SOCKET_INTERFACE \ - " <interface name=\"org.freedesktop.systemd1.Socket\">\n" \ - " <property name=\"BindIPv6Only\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"Backlog\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \ - BUS_UNIT_CGROUP_INTERFACE \ - BUS_EXEC_COMMAND_INTERFACE("ExecStartPre") \ - BUS_EXEC_COMMAND_INTERFACE("ExecStartPost") \ - BUS_EXEC_COMMAND_INTERFACE("ExecStopPre") \ - BUS_EXEC_COMMAND_INTERFACE("ExecStopPost") \ - BUS_EXEC_CONTEXT_INTERFACE \ - BUS_KILL_CONTEXT_INTERFACE \ - BUS_CGROUP_CONTEXT_INTERFACE \ - " <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"BindToDevice\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"SocketMode\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"Accept\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"KeepAlive\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"Priority\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"ReceiveBuffer\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"SendBuffer\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"IPTOS\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"IPTTL\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"PipeSize\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"FreeBind\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"Transparent\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"Broadcast\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"PassCredentials\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"PassSecurity\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"Mark\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"MaxConnections\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"NAccepted\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"NConnections\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"MessageQueueMaxMessages\" type=\"x\" access=\"read\"/>\n" \ - " <property name=\"MessageQueueMessageSize\" type=\"x\" access=\"read\"/>\n" \ - " <property name=\"Listen\" type=\"a(ss)\" access=\"read\"/>\n" \ - " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"ReusePort\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"SmackLabel\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"SmackLabelIPIn\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"SmackLabelIPOut\" type=\"s\" access=\"read\"/>\n" \ - " </interface>\n" \ - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "<node>\n" \ - BUS_UNIT_INTERFACE \ - BUS_SOCKET_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "</node>\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Socket\0" - -const char bus_socket_interface[] = BUS_SOCKET_INTERFACE; - -const char bus_socket_invalidating_properties[] = - "ExecStartPre\0" - "ExecStartPost\0" - "ExecStopPre\0" - "ExecStopPost\0" - "ControlPID\0" - "NAccepted\0" - "NConnections\0" - "Result\0"; - -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_socket_append_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only); -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_socket_append_socket_result, socket_result, SocketResult); - -static int bus_socket_append_listen(DBusMessageIter *i, const char *property, void *data) { - - Socket *s = SOCKET(data); + + Socket *s = SOCKET(userdata); SocketPort *p; - DBusMessageIter array, stru; + int r; - assert(data); - assert(property); + assert(bus); + assert(reply); assert(s); - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &array)) - return log_oom(); + r = sd_bus_message_open_container(reply, 'a', "(ss)"); + if (r < 0) + return r; LIST_FOREACH(port, p, s->ports) { - const char *type = socket_port_type_to_string(p); _cleanup_free_ char *address = NULL; const char *a; - if (!dbus_message_iter_open_container(&array, DBUS_TYPE_STRUCT, NULL, &stru)) - return log_oom(); - - if (!dbus_message_iter_append_basic(&stru, DBUS_TYPE_STRING, &type)) - return log_oom(); - switch (p->type) { case SOCKET_SOCKET: { - int r; - r = socket_address_print(&p->address, &address); - if (r) { - log_error("socket_address_print failed: %s", strerror(-r)); + if (r) return r; - } + a = address; break; } @@ -146,98 +74,80 @@ static int bus_socket_append_listen(DBusMessageIter *i, const char *property, vo break; default: - a = type; + assert_not_reached("Unknown socket type"); } - if (!dbus_message_iter_append_basic(&stru, DBUS_TYPE_STRING, &a)) - return -ENOMEM; - - if (!dbus_message_iter_close_container(&array, &stru)) - return -ENOMEM; + r = sd_bus_message_append(reply, "(ss)", socket_port_type_to_string(p), a); + if (r < 0) + return r; } - if (!dbus_message_iter_close_container(i, &array)) - return -ENOMEM; - - return 0; + return sd_bus_message_close_container(reply); } -static const BusProperty bus_socket_properties[] = { - { "BindIPv6Only", bus_socket_append_bind_ipv6_only, "s", offsetof(Socket, bind_ipv6_only) }, - { "Backlog", bus_property_append_unsigned, "u", offsetof(Socket, backlog) }, - { "TimeoutUSec", bus_property_append_usec, "t", offsetof(Socket, timeout_usec) }, - BUS_EXEC_COMMAND_PROPERTY("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), true ), - BUS_EXEC_COMMAND_PROPERTY("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), true ), - BUS_EXEC_COMMAND_PROPERTY("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), true ), - BUS_EXEC_COMMAND_PROPERTY("ExecStopPost", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_POST]), true ), - { "ControlPID", bus_property_append_pid, "u", offsetof(Socket, control_pid) }, - { "BindToDevice", bus_property_append_string, "s", offsetof(Socket, bind_to_device), true }, - { "DirectoryMode", bus_property_append_mode, "u", offsetof(Socket, directory_mode) }, - { "SocketMode", bus_property_append_mode, "u", offsetof(Socket, socket_mode) }, - { "Accept", bus_property_append_bool, "b", offsetof(Socket, accept) }, - { "KeepAlive", bus_property_append_bool, "b", offsetof(Socket, keep_alive) }, - { "Priority", bus_property_append_int, "i", offsetof(Socket, priority) }, - { "ReceiveBuffer", bus_property_append_size, "t", offsetof(Socket, receive_buffer) }, - { "SendBuffer", bus_property_append_size, "t", offsetof(Socket, send_buffer) }, - { "IPTOS", bus_property_append_int, "i", offsetof(Socket, ip_tos) }, - { "IPTTL", bus_property_append_int, "i", offsetof(Socket, ip_ttl) }, - { "PipeSize", bus_property_append_size, "t", offsetof(Socket, pipe_size) }, - { "FreeBind", bus_property_append_bool, "b", offsetof(Socket, free_bind) }, - { "Transparent", bus_property_append_bool, "b", offsetof(Socket, transparent) }, - { "Broadcast", bus_property_append_bool, "b", offsetof(Socket, broadcast) }, - { "PassCredentials",bus_property_append_bool, "b", offsetof(Socket, pass_cred) }, - { "PassSecurity", bus_property_append_bool, "b", offsetof(Socket, pass_sec) }, - { "Listen", bus_socket_append_listen, "a(ss)", 0, }, - { "Mark", bus_property_append_int, "i", offsetof(Socket, mark) }, - { "MaxConnections", bus_property_append_unsigned, "u", offsetof(Socket, max_connections) }, - { "NConnections", bus_property_append_unsigned, "u", offsetof(Socket, n_connections) }, - { "NAccepted", bus_property_append_unsigned, "u", offsetof(Socket, n_accepted) }, - { "MessageQueueMaxMessages", bus_property_append_long, "x", offsetof(Socket, mq_maxmsg) }, - { "MessageQueueMessageSize", bus_property_append_long, "x", offsetof(Socket, mq_msgsize) }, - { "Result", bus_socket_append_socket_result, "s", offsetof(Socket, result) }, - { "ReusePort", bus_property_append_bool, "b", offsetof(Socket, reuseport) }, - { "SmackLabel", bus_property_append_string, "s", offsetof(Socket, smack), true }, - { "SmackLabelIPIn", bus_property_append_string, "s", offsetof(Socket, smack_ip_in), true }, - { "SmackLabelIPOut",bus_property_append_string, "s", offsetof(Socket, smack_ip_out), true }, - {} +const sd_bus_vtable bus_socket_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("BindIPv6Only", "s", property_get_bind_ipv6_only, offsetof(Socket, bind_ipv6_only), 0), + SD_BUS_PROPERTY("Backlog", "u", bus_property_get_unsigned, offsetof(Socket, backlog), 0), + SD_BUS_PROPERTY("TimeoutUSec", "t", bus_property_get_usec, offsetof(Socket, timeout_usec), 0), + SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Socket, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("BindToDevice", "s", NULL, offsetof(Socket, bind_to_device), 0), + SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Socket, directory_mode), 0), + SD_BUS_PROPERTY("SocketMode", "u", bus_property_get_mode, offsetof(Socket, socket_mode), 0), + SD_BUS_PROPERTY("Accept", "b", bus_property_get_bool, offsetof(Socket, accept), 0), + SD_BUS_PROPERTY("KeepAlive", "b", bus_property_get_bool, offsetof(Socket, keep_alive), 0), + SD_BUS_PROPERTY("Priority", "i", bus_property_get_int, offsetof(Socket, priority), 0), + SD_BUS_PROPERTY("ReceiveBuffer", "t", bus_property_get_size, offsetof(Socket, receive_buffer), 0), + SD_BUS_PROPERTY("SendBuffer", "t", bus_property_get_size, offsetof(Socket, send_buffer), 0), + SD_BUS_PROPERTY("IPTOS", "i", bus_property_get_int, offsetof(Socket, ip_tos), 0), + SD_BUS_PROPERTY("IPTTL", "i", bus_property_get_int, offsetof(Socket, ip_ttl), 0), + SD_BUS_PROPERTY("PipeSize", "t", bus_property_get_size, offsetof(Socket, pipe_size), 0), + SD_BUS_PROPERTY("FreeBind", "b", bus_property_get_bool, offsetof(Socket, free_bind), 0), + SD_BUS_PROPERTY("Transparent", "b", bus_property_get_bool, offsetof(Socket, transparent), 0), + SD_BUS_PROPERTY("Broadcast", "b", bus_property_get_bool, offsetof(Socket, broadcast), 0), + SD_BUS_PROPERTY("PassCredentials", "b", bus_property_get_bool, offsetof(Socket, pass_cred), 0), + SD_BUS_PROPERTY("PassSecurity", "b", bus_property_get_bool, offsetof(Socket, pass_sec), 0), + SD_BUS_PROPERTY("Listen", "a(ss)", property_get_listen, 0, 0), + SD_BUS_PROPERTY("Mark", "i", bus_property_get_int, offsetof(Socket, mark), 0), + SD_BUS_PROPERTY("MaxConnections", "u", bus_property_get_unsigned, offsetof(Socket, max_connections), 0), + SD_BUS_PROPERTY("NConnections", "u", bus_property_get_unsigned, offsetof(Socket, n_connections), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("MessageQueueMaxMessages", "x", bus_property_get_long, offsetof(Socket, mq_maxmsg), 0), + SD_BUS_PROPERTY("MessageQueueMessageSize", "x", bus_property_get_long, offsetof(Socket, mq_msgsize), 0), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Socket, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("ReusePort", "b", bus_property_get_bool, offsetof(Socket, reuse_port), 0), + SD_BUS_PROPERTY("SmackLabel", "s", NULL, offsetof(Socket, smack), 0), + SD_BUS_PROPERTY("SmackLabelIPIn", "s", NULL, offsetof(Socket, smack_ip_in), 0), + SD_BUS_PROPERTY("SmackLabelIPOut", "s", NULL, offsetof(Socket, smack_ip_out), 0), + BUS_EXEC_COMMAND_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), 0), + BUS_EXEC_COMMAND_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), 0), + BUS_EXEC_COMMAND_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), 0), + BUS_EXEC_COMMAND_VTABLE("ExecStopPost", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_POST]), 0), + SD_BUS_VTABLE_END }; -DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - Socket *s = SOCKET(u); - const BusBoundProperties bps[] = { - { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, - { "org.freedesktop.systemd1.Socket", bus_unit_cgroup_properties, u }, - { "org.freedesktop.systemd1.Socket", bus_socket_properties, s }, - { "org.freedesktop.systemd1.Socket", bus_exec_context_properties, &s->exec_context }, - { "org.freedesktop.systemd1.Socket", bus_kill_context_properties, &s->kill_context }, - { "org.freedesktop.systemd1.Socket", bus_cgroup_context_properties, &s->cgroup_context }, - {} - }; - - SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status"); - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps); -} +const char* const bus_socket_changing_properties[] = { + "ControlPID", + "NAccepted", + "NConnections", + "Result", + NULL +}; int bus_socket_set_property( Unit *u, const char *name, - DBusMessageIter *i, + sd_bus_message *message, UnitSetPropertiesMode mode, - DBusError *error) { + sd_bus_error *error) { Socket *s = SOCKET(u); - int r; + assert(s); assert(name); - assert(u); - assert(i); + assert(message); - r = bus_cgroup_set_property(u, &s->cgroup_context, name, i, mode, error); - if (r != 0) - return r; - - return 0; + return bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error); } int bus_socket_commit_properties(Unit *u) { diff --git a/src/core/dbus-socket.h b/src/core/dbus-socket.h index eb035c1a94..8808fa2355 100644 --- a/src/core/dbus-socket.h +++ b/src/core/dbus-socket.h @@ -21,14 +21,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> - +#include "sd-bus.h" #include "unit.h" -DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); +extern const sd_bus_vtable bus_socket_vtable[]; +extern const char* const bus_socket_changing_properties[]; -int bus_socket_set_property(Unit *u, const char *name, DBusMessageIter *i, UnitSetPropertiesMode mode, DBusError *error); +int bus_socket_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); int bus_socket_commit_properties(Unit *u); - -extern const char bus_socket_interface[]; -extern const char bus_socket_invalidating_properties[]; diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c index 0da86bd6fa..15292cd192 100644 --- a/src/core/dbus-swap.c +++ b/src/core/dbus-swap.c @@ -20,125 +20,77 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> - +#include "unit.h" +#include "swap.h" #include "dbus-unit.h" #include "dbus-execute.h" #include "dbus-kill.h" #include "dbus-cgroup.h" -#include "dbus-common.h" -#include "selinux-access.h" #include "dbus-swap.h" - -#define BUS_SWAP_INTERFACE \ - " <interface name=\"org.freedesktop.systemd1.Swap\">\n" \ - " <property name=\"What\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"Priority\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \ - BUS_UNIT_CGROUP_INTERFACE \ - BUS_EXEC_COMMAND_INTERFACE("ExecActivate") \ - BUS_EXEC_COMMAND_INTERFACE("ExecDeactivate") \ - BUS_EXEC_CONTEXT_INTERFACE \ - BUS_KILL_CONTEXT_INTERFACE \ - BUS_CGROUP_CONTEXT_INTERFACE \ - " <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \ - " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \ - " </interface>\n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "<node>\n" \ - BUS_UNIT_INTERFACE \ - BUS_SWAP_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "</node>\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Swap\0" - -const char bus_swap_interface[] = BUS_SWAP_INTERFACE; - -const char bus_swap_invalidating_properties[] = - "What\0" - "Priority\0" - "ExecActivate\0" - "ExecDeactivate\0" - "ControlPID\0" - "Result\0"; - -static int bus_swap_append_priority(DBusMessageIter *i, const char *property, void *data) { - Swap *s = data; - dbus_int32_t j; - - assert(i); - assert(property); +#include "bus-util.h" + +static int property_get_priority( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + Swap *s = SWAP(userdata); + int p; + + assert(bus); + assert(reply); assert(s); if (s->from_proc_swaps) - j = s->parameters_proc_swaps.priority; + p = s->parameters_proc_swaps.priority; else if (s->from_fragment) - j = s->parameters_fragment.priority; + p = s->parameters_fragment.priority; else - j = -1; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &j)) - return -ENOMEM; + p = -1; - return 0; + return sd_bus_message_append(reply, "i", p); } -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_swap_append_swap_result, swap_result, SwapResult); - -static const BusProperty bus_swap_properties[] = { - { "What", bus_property_append_string, "s", offsetof(Swap, what), true }, - { "Priority", bus_swap_append_priority, "i", 0 }, - { "TimeoutUSec",bus_property_append_usec, "t", offsetof(Swap, timeout_usec)}, - BUS_EXEC_COMMAND_PROPERTY("ExecActivate", offsetof(Swap, exec_command[SWAP_EXEC_ACTIVATE]), false), - BUS_EXEC_COMMAND_PROPERTY("ExecDeactivate", offsetof(Swap, exec_command[SWAP_EXEC_DEACTIVATE]), false), - { "ControlPID", bus_property_append_pid, "u", offsetof(Swap, control_pid) }, - { "Result", bus_swap_append_swap_result,"s", offsetof(Swap, result) }, - { NULL, } +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, swap_result, SwapResult); + +const sd_bus_vtable bus_swap_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("What", "s", NULL, offsetof(Swap, what), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Priority", "i", property_get_priority, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("TimeoutUSec", "t", bus_property_get_usec, offsetof(Swap, timeout_usec), 0), + SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Swap, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Swap, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_EXEC_COMMAND_VTABLE("ExecActivate", offsetof(Swap, exec_command[SWAP_EXEC_ACTIVATE]), 0), + BUS_EXEC_COMMAND_VTABLE("ExecDeactivate", offsetof(Swap, exec_command[SWAP_EXEC_DEACTIVATE]), 0), + SD_BUS_VTABLE_END }; -DBusHandlerResult bus_swap_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - Swap *s = SWAP(u); - const BusBoundProperties bps[] = { - { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, - { "org.freedesktop.systemd1.Swap", bus_unit_cgroup_properties, u }, - { "org.freedesktop.systemd1.Swap", bus_swap_properties, s }, - { "org.freedesktop.systemd1.Swap", bus_exec_context_properties, &s->exec_context }, - { "org.freedesktop.systemd1.Swap", bus_kill_context_properties, &s->kill_context }, - { "org.freedesktop.systemd1.Swap", bus_cgroup_context_properties, &s->cgroup_context }, - { NULL, } - }; - - SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status"); - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps); -} +const char* const bus_swap_changing_properties[] = { + "What", + "Priority", + "ControlPID", + "Result", + NULL +}; int bus_swap_set_property( Unit *u, const char *name, - DBusMessageIter *i, + sd_bus_message *message, UnitSetPropertiesMode mode, - DBusError *error) { + sd_bus_error *error) { Swap *s = SWAP(u); - int r; + assert(s); assert(name); - assert(u); - assert(i); + assert(message); - r = bus_cgroup_set_property(u, &s->cgroup_context, name, i, mode, error); - if (r != 0) - return r; - - return 0; + return bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error); } int bus_swap_commit_properties(Unit *u) { diff --git a/src/core/dbus-swap.h b/src/core/dbus-swap.h index 9b586a1ad2..5d357377cd 100644 --- a/src/core/dbus-swap.h +++ b/src/core/dbus-swap.h @@ -22,14 +22,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> - +#include "sd-bus.h" #include "unit.h" -DBusHandlerResult bus_swap_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); +extern const sd_bus_vtable bus_swap_vtable[]; +extern const char* const bus_swap_changing_properties[]; -int bus_swap_set_property(Unit *u, const char *name, DBusMessageIter *i, UnitSetPropertiesMode mode, DBusError *error); +int bus_swap_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); int bus_swap_commit_properties(Unit *u); - -extern const char bus_swap_interface[]; -extern const char bus_swap_invalidating_properties[]; diff --git a/src/core/dbus-target.c b/src/core/dbus-target.c index f143d897fa..205d1c4a88 100644 --- a/src/core/dbus-target.c +++ b/src/core/dbus-target.c @@ -19,40 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> - +#include "unit.h" +#include "target.h" #include "dbus-unit.h" #include "dbus-target.h" -#include "dbus-common.h" -#include "selinux-access.h" - -#define BUS_TARGET_INTERFACE \ - " <interface name=\"org.freedesktop.systemd1.Target\">\n" \ - " </interface>\n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "<node>\n" \ - BUS_UNIT_INTERFACE \ - BUS_TARGET_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "</node>\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Target\0" - -const char bus_target_interface[] = BUS_TARGET_INTERFACE; - -DBusHandlerResult bus_target_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - const BusBoundProperties bps[] = { - { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, - { NULL, } - }; - - SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status"); - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps); -} +const sd_bus_vtable bus_target_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_VTABLE_END +}; diff --git a/src/core/dbus-target.h b/src/core/dbus-target.h index a8a0304c75..6be9c9f708 100644 --- a/src/core/dbus-target.h +++ b/src/core/dbus-target.h @@ -21,10 +21,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> +#include "sd-bus.h" -#include "unit.h" - -DBusHandlerResult bus_target_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_target_interface[]; +extern const sd_bus_vtable bus_target_vtable[]; diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c index c6f1dd9b7f..113c63faa0 100644 --- a/src/core/dbus-timer.c +++ b/src/core/dbus-timer.c @@ -19,173 +19,136 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> - +#include "unit.h" +#include "timer.h" #include "dbus-unit.h" #include "dbus-timer.h" -#include "dbus-execute.h" -#include "dbus-common.h" -#include "selinux-access.h" - -#define BUS_TIMER_INTERFACE \ - " <interface name=\"org.freedesktop.systemd1.Timer\">\n" \ - " <property name=\"Unit\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"TimersMonotonic\" type=\"a(stt)\" access=\"read\"/>\n" \ - " <property name=\"TimersCalendar\" type=\"a(sst)\" access=\"read\"/>\n" \ - " <property name=\"NextElapseUSecRealtime\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"NextElapseUSecMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \ - " </interface>\n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "<node>\n" \ - BUS_UNIT_INTERFACE \ - BUS_TIMER_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "</node>\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Timer\0" - -const char bus_timer_interface[] = BUS_TIMER_INTERFACE; - -const char bus_timer_invalidating_properties[] = - "TimersMonotonic\0" - "TimersRealtime\0" - "NextElapseUSecRealtime\0" - "NextElapseUSecMonotonic\0" - "Result\0"; - -static int bus_timer_append_monotonic_timers(DBusMessageIter *i, const char *property, void *data) { - Timer *p = data; - DBusMessageIter sub, sub2; - TimerValue *k; - - assert(i); - assert(property); - assert(p); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(stt)", &sub)) - return -ENOMEM; - - LIST_FOREACH(value, k, p->values) { +#include "bus-util.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult); + +static int property_get_monotonic_timers( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + Timer *t = userdata; + TimerValue *v; + int r; + + assert(bus); + assert(reply); + assert(t); + + r = sd_bus_message_open_container(reply, 'a', "(stt)"); + if (r < 0) + return r; + + LIST_FOREACH(value, v, t->values) { _cleanup_free_ char *buf = NULL; - const char *t; + const char *s; size_t l; - bool b; - if (k->base == TIMER_CALENDAR) + if (v->base == TIMER_CALENDAR) continue; - t = timer_base_to_string(k->base); - assert(endswith(t, "Sec")); + s = timer_base_to_string(v->base); + assert(endswith(s, "Sec")); /* s/Sec/USec/ */ - l = strlen(t); + l = strlen(s); buf = new(char, l+2); if (!buf) return -ENOMEM; - memcpy(buf, t, l-3); + memcpy(buf, s, l-3); memcpy(buf+l-3, "USec", 5); - b = dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) && - dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &buf) && - dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->value) && - dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->next_elapse) && - dbus_message_iter_close_container(&sub, &sub2); - - if (!b) - return -ENOMEM; + r = sd_bus_message_append(reply, "(stt)", buf, v->value, v->next_elapse); + if (r < 0) + return r; } - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; + return sd_bus_message_close_container(reply); } -static int bus_timer_append_calendar_timers(DBusMessageIter *i, const char *property, void *data) { - Timer *p = data; - DBusMessageIter sub, sub2; - TimerValue *k; +static int property_get_calendar_timers( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - assert(i); - assert(property); - assert(p); + Timer *t = userdata; + TimerValue *v; + int r; - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sst)", &sub)) - return -ENOMEM; + assert(bus); + assert(reply); + assert(t); - LIST_FOREACH(value, k, p->values) { + r = sd_bus_message_open_container(reply, 'a', "(sst)"); + if (r < 0) + return r; + + LIST_FOREACH(value, v, t->values) { _cleanup_free_ char *buf = NULL; - const char *t; - bool b; - int j; - if (k->base != TIMER_CALENDAR) + if (v->base != TIMER_CALENDAR) continue; - t = timer_base_to_string(k->base); - j = calendar_spec_to_string(k->calendar_spec, &buf); - if (j < 0) - return j; - - b = dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) && - dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &t) && - dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &buf) && - dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->next_elapse) && - dbus_message_iter_close_container(&sub, &sub2); + r = calendar_spec_to_string(v->calendar_spec, &buf); + if (r < 0) + return r; - if (!b) - return -ENOMEM; + r = sd_bus_message_append(reply, "(sst)", timer_base_to_string(v->base), buf, v->next_elapse); + if (r < 0) + return r; } - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; + return sd_bus_message_close_container(reply); } -static int bus_timer_append_unit(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data, *trigger; - const char *t; +static int property_get_unit( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + Unit *u = userdata, *trigger; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(u); trigger = UNIT_TRIGGER(u); - t = trigger ? trigger->id : ""; - return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM; + return sd_bus_message_append(reply, "s", trigger ? trigger->id : ""); } -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_timer_append_timer_result, timer_result, TimerResult); - -static const BusProperty bus_timer_properties[] = { - { "Unit", bus_timer_append_unit, "s", 0 }, - { "TimersMonotonic", bus_timer_append_monotonic_timers, "a(stt)", 0 }, - { "TimersCalendar", bus_timer_append_calendar_timers, "a(sst)", 0 }, - { "NextElapseUSecMonotonic", bus_property_append_usec, "t", offsetof(Timer, next_elapse_monotonic) }, - { "NextElapseUSecRealtime", bus_property_append_usec, "t", offsetof(Timer, next_elapse_realtime) }, - { "Result", bus_timer_append_timer_result, "s", offsetof(Timer, result) }, - { NULL, } +const sd_bus_vtable bus_timer_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Unit", "s", property_get_unit, 0, 0), + SD_BUS_PROPERTY("TimersMonotonic", "a(stt)", property_get_monotonic_timers, 0, 0), + SD_BUS_PROPERTY("TimersCalendar", "a(sst)", property_get_calendar_timers, 0, 0), + SD_BUS_PROPERTY("NextElapseUSecRealtime", "t", bus_property_get_usec, offsetof(Timer, next_elapse_monotonic), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("NextElapseUSecMonotonic", "t", bus_property_get_usec, offsetof(Timer, next_elapse_realtime), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_VTABLE_END }; -DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - Timer *t = TIMER(u); - const BusBoundProperties bps[] = { - { "org.freedesktop.systemd1.Unit", bus_unit_properties, u }, - { "org.freedesktop.systemd1.Timer", bus_timer_properties, t }, - { NULL, } - }; - - SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status"); - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps); -} +const char* const bus_timer_changing_properties[] = { + "NextElapseUSecRealtime", + "NextElapseUSecMonotonic", + "Result", + NULL +}; diff --git a/src/core/dbus-timer.h b/src/core/dbus-timer.h index 9ac30501d1..ddd311c626 100644 --- a/src/core/dbus-timer.h +++ b/src/core/dbus-timer.h @@ -21,11 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> +#include "sd-bus.h" -#include "unit.h" - -DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_timer_interface[]; -extern const char bus_timer_invalidating_properties[]; +extern const sd_bus_vtable bus_timer_vtable[]; +extern const char* const bus_timer_changing_properties[]; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 032915d14e..49054781c0 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -19,609 +19,645 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> - -#include "dbus.h" +#include "sd-bus.h" #include "log.h" -#include "dbus-unit.h" -#include "bus-errors.h" -#include "dbus-common.h" #include "selinux-access.h" #include "cgroup-util.h" #include "strv.h" #include "path-util.h" #include "fileio.h" +#include "dbus-unit.h" +#include "dbus-manager.h" +#include "bus-errors.h" +#include "dbus-client-track.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState); + +static int property_get_names( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + Unit *u = userdata; + Iterator i; + const char *t; + int r; -const char bus_unit_interface[] = BUS_UNIT_INTERFACE; - -#define INVALIDATING_PROPERTIES \ - "LoadState\0" \ - "ActiveState\0" \ - "SubState\0" \ - "InactiveExitTimestamp\0" \ - "ActiveEnterTimestamp\0" \ - "ActiveExitTimestamp\0" \ - "InactiveEnterTimestamp\0" \ - "Job\0" \ - "NeedDaemonReload\0" - -static int bus_unit_append_names(DBusMessageIter *i, const char *property, void *data) { - char *t; - Iterator j; - DBusMessageIter sub; - Unit *u = data; - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub)) - return -ENOMEM; + assert(bus); + assert(reply); + assert(u); - SET_FOREACH(t, u->names, j) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t)) - return -ENOMEM; + r = sd_bus_message_open_container(reply, 'a', "s"); + if (r < 0) + return r; - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; + SET_FOREACH(t, u->names, i) { + r = sd_bus_message_append(reply, "s", t); + if (r < 0) + return r; + } - return 0; + return sd_bus_message_close_container(reply); } -static int bus_unit_append_following(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data, *f; - const char *d; +static int property_get_following( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + Unit *u = userdata, *f; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(u); f = unit_following(u); - d = f ? f->id : ""; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d)) - return -ENOMEM; - - return 0; + return sd_bus_message_append(reply, "s", f ? f->id : ""); } -static int bus_unit_append_slice(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - const char *d; - - assert(i); - assert(property); - assert(u); - - d = strempty(unit_slice_name(u)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d)) - return -ENOMEM; +static int property_get_dependencies( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - return 0; -} - -static int bus_unit_append_dependencies(DBusMessageIter *i, const char *property, void *data) { - Unit *u; + Set *s = *(Set**) userdata; Iterator j; - DBusMessageIter sub; - Set *s = data; + Unit *u; + int r; - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub)) - return -ENOMEM; + assert(bus); + assert(reply); - SET_FOREACH(u, s, j) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &u->id)) - return -ENOMEM; + r = sd_bus_message_open_container(reply, 'a', "s"); + if (r < 0) + return r; - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; + SET_FOREACH(u, s, j) { + r = sd_bus_message_append(reply, "s", u->id); + if (r < 0) + return r; + } - return 0; + return sd_bus_message_close_container(reply); } -static int bus_unit_append_description(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - const char *d; +static int property_get_description( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - assert(i); - assert(property); - assert(u); - - d = unit_description(u); + Unit *u = userdata; - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d)) - return -ENOMEM; + assert(bus); + assert(reply); + assert(u); - return 0; + return sd_bus_message_append(reply, "s", unit_description(u)); } -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_load_state, unit_load_state, UnitLoadState); +static int property_get_active_state( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { -static int bus_unit_append_active_state(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - const char *state; + Unit *u = userdata; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(u); - state = unit_active_state_to_string(unit_active_state(u)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state)) - return -ENOMEM; - - return 0; + return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u))); } -static int bus_unit_append_sub_state(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - const char *state; - - assert(i); - assert(property); - assert(u); +static int property_get_sub_state( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - state = unit_sub_state_to_string(u); + Unit *u = userdata; - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state)) - return -ENOMEM; + assert(bus); + assert(reply); + assert(u); - return 0; + return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u)); } -static int bus_unit_append_file_state(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - const char *state; +static int property_get_unit_file_state( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - assert(i); - assert(property); - assert(u); + Unit *u = userdata; - state = strempty(unit_file_state_to_string(unit_get_unit_file_state(u))); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state)) - return -ENOMEM; + assert(bus); + assert(reply); + assert(u); - return 0; + return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u))); } -static int bus_unit_append_can_start(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - dbus_bool_t b; - - assert(i); - assert(property); - assert(u); +static int property_get_can_start( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - b = unit_can_start(u) && - !u->refuse_manual_start; + Unit *u = userdata; - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; + assert(bus); + assert(reply); + assert(u); - return 0; + return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start); } -static int bus_unit_append_can_stop(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - dbus_bool_t b; +static int property_get_can_stop( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + Unit *u = userdata; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(u); /* On the lower levels we assume that every unit we can start * we can also stop */ - b = unit_can_start(u) && - !u->refuse_manual_stop; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; - - return 0; + return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_stop); } -static int bus_unit_append_can_reload(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - dbus_bool_t b; +static int property_get_can_reload( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - assert(i); - assert(property); - assert(u); - - b = unit_can_reload(u); + Unit *u = userdata; - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; + assert(bus); + assert(reply); + assert(u); - return 0; + return sd_bus_message_append(reply, "b", unit_can_reload(u)); } -static int bus_unit_append_can_isolate(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - dbus_bool_t b; +static int property_get_can_isolate( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - assert(i); - assert(property); - assert(u); - - b = unit_can_isolate(u) && - !u->refuse_manual_start; + Unit *u = userdata; - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; + assert(bus); + assert(reply); + assert(u); - return 0; + return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start); } -static int bus_unit_append_job(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - DBusMessageIter sub; +static int property_get_job( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + _cleanup_free_ char *p = NULL; + Unit *u = userdata; - assert(i); - assert(property); + assert(bus); + assert(reply); assert(u); - if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub)) - return -ENOMEM; - - if (u->job) { + if (!u->job) + return sd_bus_message_append(reply, "(uo)", 0, "/"); - p = job_dbus_path(u->job); - if (!p) - return -ENOMEM; - - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->job->id) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) - return -ENOMEM; - } else { - uint32_t id = 0; + p = job_dbus_path(u->job); + if (!p) + return -ENOMEM; - /* No job, so let's fill in some placeholder - * data. Since we need to fill in a valid path we - * simple point to ourselves. */ + return sd_bus_message_append(reply, "(uo)", u->job->id, p); +} - p = unit_dbus_path(u); - if (!p) - return -ENOMEM; +static int property_get_need_daemon_reload( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &id) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) - return -ENOMEM; - } + Unit *u = userdata; - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; + assert(bus); + assert(reply); + assert(u); - return 0; + return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u)); } -static int bus_unit_append_need_daemon_reload(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - dbus_bool_t b; +static int property_get_conditions( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - assert(i); - assert(property); - assert(u); + Unit *u = userdata; + Condition *c; + int r; - b = unit_need_daemon_reload(u); + assert(bus); + assert(reply); + assert(u); - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; + r = sd_bus_message_open_container(reply, 'a', "(sbbsi)"); + if (r < 0) + return r; - return 0; -} + LIST_FOREACH(conditions, c, u->conditions) { + r = sd_bus_message_append(reply, "sbbsi", condition_type_to_string(c->type), c->trigger, c->negate, c->parameter, c->state); + if (r < 0) + return r; -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; - dbus_int32_t state; - DBusMessageIter sub; - - assert(i); - assert(property); - assert(cp); - - c = *cp; - assert(c); - - name = condition_type_to_string(c->type); - param = c->parameter; - trigger = c->trigger; - negate = c->negate; - state = c->state; - - 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_append_basic(&sub, DBUS_TYPE_INT32, &state) || - !dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; + } - return 0; + return sd_bus_message_close_container(reply); } -static int bus_property_append_condition_list(DBusMessageIter *i, const char *property, void *data) { - Condition **first = data, *c; - DBusMessageIter sub; - - assert(i); - assert(data); +static int property_get_load_error( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sbbsi)", &sub)) - return -ENOMEM; + _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL; + Unit *u = userdata; - LIST_FOREACH(conditions, c, *first) - bus_property_append_condition(&sub, property, &c); + assert(bus); + assert(reply); + assert(u); - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; + if (u->load_error != 0) + sd_bus_error_set_errno(&e, u->load_error); - return 0; + return sd_bus_message_append(reply, "(ss)", e.name, e.message); } -static int bus_unit_append_load_error(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - const char *name, *message; - DBusMessageIter sub; +int bus_unit_method_start_generic(sd_bus *bus, sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible) { + const char *smode; + JobMode mode; + int r; - assert(i); - assert(property); + assert(bus); + assert(message); assert(u); + assert(job_type >= 0 && job_type < _JOB_TYPE_MAX); - if (u->load_error != 0) { - name = bus_errno_to_dbus(u->load_error); - message = strempty(strerror(-u->load_error)); - } else - name = message = ""; + r = sd_bus_message_read(message, "s", &smode); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - 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_STRING, &message) || - !dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; + mode = job_mode_from_string(smode); + if (mode < 0) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode); - return 0; + return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible); } -static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *connection, DBusMessage *message) { - _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; - DBusError error; - JobType job_type = _JOB_TYPE_INVALID; - bool reload_if_possible = false; - int r; +static int method_start(sd_bus *bus, sd_bus_message *message, void *userdata) { + return bus_unit_method_start_generic(bus, message, userdata, JOB_START, false); +} - dbus_error_init(&error); - - if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Start")) - job_type = JOB_START; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Stop")) - job_type = JOB_STOP; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Reload")) - job_type = JOB_RELOAD; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Restart")) - job_type = JOB_RESTART; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "TryRestart")) - job_type = JOB_TRY_RESTART; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ReloadOrRestart")) { - reload_if_possible = true; - job_type = JOB_RESTART; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ReloadOrTryRestart")) { - reload_if_possible = true; - job_type = JOB_TRY_RESTART; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Kill")) { - const char *swho; - int32_t signo; - KillWho who; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &swho, - DBUS_TYPE_INT32, &signo, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (isempty(swho)) - who = KILL_ALL; - else { - who = kill_who_from_string(swho); - if (who < 0) - return bus_send_error_reply(connection, message, &error, -EINVAL); - } +static int method_stop(sd_bus *bus, sd_bus_message *message, void *userdata) { + return bus_unit_method_start_generic(bus, message, userdata, JOB_STOP, false); +} + +static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata) { + return bus_unit_method_start_generic(bus, message, userdata, JOB_RELOAD, false); +} - if (signo <= 0 || signo >= _NSIG) - return bus_send_error_reply(connection, message, &error, -EINVAL); +static int method_restart(sd_bus *bus, sd_bus_message *message, void *userdata) { + return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, false); +} - SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop"); +static int method_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata) { + return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, false); +} - r = unit_kill(u, who, signo, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); +static int method_reload_or_restart(sd_bus *bus, sd_bus_message *message, void *userdata) { + return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, true); +} - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; +static int method_reload_or_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata) { + return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, true); +} - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ResetFailed")) { +int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + Unit *u = userdata; + const char *swho; + int32_t signo; + KillWho who; + int r; - SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload"); + assert(bus); + assert(message); + assert(u); - unit_reset_failed(u); + r = sd_bus_message_read(message, "si", &swho, &signo); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); + + if (isempty(swho)) + who = KILL_ALL; + else { + who = kill_who_from_string(swho); + if (who < 0) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho); + } - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "SetProperties")) { - DBusMessageIter iter; - dbus_bool_t runtime; + if (signo <= 0 || signo >= _NSIG) + return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range."); - if (!dbus_message_iter_init(message, &iter)) - goto oom; + SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "stop"); - if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0) - return bus_send_error_reply(connection, message, NULL, -EINVAL); + r = unit_kill(u, who, signo, &error); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, &error); - SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start"); + return sd_bus_reply_method_return(bus, message, NULL); +} - r = bus_unit_set_properties(u, &iter, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (UNIT_VTABLE(u)->bus_message_handler) - return UNIT_VTABLE(u)->bus_message_handler(u, connection, message); - else - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (job_type != _JOB_TYPE_INVALID) { - const char *smode; - JobMode mode; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &smode, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - mode = job_mode_from_string(smode); - if (mode < 0) { - dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode); - return bus_send_error_reply(connection, message, &error, -EINVAL); - } +int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata) { + Unit *u = userdata; - return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible); - } + assert(bus); + assert(message); + assert(u); - if (reply) - if (!bus_maybe_send_reply(connection, message, reply)) - goto oom; + SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "reload"); - return DBUS_HANDLER_RESULT_HANDLED; + unit_reset_failed(u); -oom: - dbus_error_free(&error); - return DBUS_HANDLER_RESULT_NEED_MEMORY; + return sd_bus_reply_method_return(bus, message, NULL); } -static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DBusMessage *message, void *data) { - Manager *m = data; - Unit *u; - int r; - _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; - DBusError error; +int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + Unit *u = userdata; + int runtime, r; - assert(connection); + assert(bus); assert(message); - assert(m); - - dbus_error_init(&error); + assert(u); - if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/unit")) { - /* Be nice to gdbus and return introspection data for our mid-level paths */ + r = sd_bus_message_read(message, "b", &runtime); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - SELINUX_ACCESS_CHECK(connection, message, "status"); + SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "start"); - if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { - char *introspection = NULL; - FILE *f; - Iterator i; - const char *k; - size_t size; + r = sd_bus_message_enter_container(message, 'a', "(sv)"); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; + r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, &error); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, &error); - /* We roll our own introspection code here, instead of - * relying on bus_default_message_handler() because we - * need to generate our introspection string - * dynamically. */ + r = sd_bus_message_exit_container(message); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); - f = open_memstream(&introspection, &size); - if (!f) - goto oom; + return sd_bus_reply_method_return(bus, message, NULL); +} - fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE - "<node>\n", f); +const sd_bus_vtable bus_unit_vtable[] = { + SD_BUS_VTABLE_START(0), + + SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), 0), + SD_BUS_PROPERTY("Names", "as", property_get_names, 0, 0), + SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0), + SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), 0), + SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), 0), + SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), 0), + SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), 0), + SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), 0), + SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), 0), + SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), 0), + SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), 0), + SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), 0), + SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), 0), + SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), 0), + SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), 0), + SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), 0), + SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), 0), + SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), 0), + SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), 0), + SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), 0), + SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), 0), + SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), 0), + SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), 0), + SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), 0), + SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), 0), + SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), 0), + SD_BUS_PROPERTY("Description", "s", property_get_description, 0, 0), + SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), 0), + SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), 0), + SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), 0), + SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), 0), + SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0), + BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, 0), + SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, 0), + SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, 0), + SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, 0), + SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), 0), + SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), 0), + SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), 0), + SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), 0), + SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), 0), + SD_BUS_PROPERTY("OnFailureIsolate", "b", bus_property_get_bool, offsetof(Unit, on_failure_isolate), 0), + SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), 0), + SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), 0), + SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, 0), + SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), 0), + SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_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), + SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, 0), + SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), 0), + + SD_BUS_METHOD("Start", "s", "o", method_start, 0), + SD_BUS_METHOD("Stop", "s", "o", method_stop, 0), + SD_BUS_METHOD("Reload", "s", "o", method_reload, 0), + SD_BUS_METHOD("Restart", "s", "o", method_restart, 0), + SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, 0), + SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, 0), + SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, 0), + SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, 0), + SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, 0), + SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, 0), + + SD_BUS_VTABLE_END +}; - fputs(BUS_INTROSPECTABLE_INTERFACE, f); - fputs(BUS_PEER_INTERFACE, f); +static int property_get_slice( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { - HASHMAP_FOREACH_KEY(u, k, m->units, i) { - char *p; + Unit *u = userdata; - if (k != u->id) - continue; + assert(bus); + assert(reply); + assert(u); - p = bus_path_escape(k); - if (!p) { - fclose(f); - free(introspection); - goto oom; - } + return sd_bus_message_append(reply, "s", unit_slice_name(u)); +} - fprintf(f, "<node name=\"%s\"/>", p); - free(p); - } +const sd_bus_vtable bus_unit_cgroup_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0), + SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0), + SD_BUS_VTABLE_END +}; - fputs("</node>\n", f); +static int send_new_signal(sd_bus *bus, const char *destination, void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_free_ char *p = NULL; + Unit *u = userdata; + int r; - if (ferror(f)) { - fclose(f); - free(introspection); - goto oom; - } + assert(bus); + assert(u); - fclose(f); + p = unit_dbus_path(u); + if (!u) + return -ENOMEM; - if (!introspection) - goto oom; + r = sd_bus_message_new_signal( + bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "UnitNew", + &m); + if (r < 0) + return r; - if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) { - free(introspection); - goto oom; - } + r = sd_bus_message_append(m, "so", u->id, p); + if (r < 0) + return r; - free(introspection); + return sd_bus_send_to(bus, m, destination, NULL); +} - if (!bus_maybe_send_reply(connection, message, reply)) - goto oom; +static int send_changed_signal(sd_bus *bus, const char *destination, void *userdata) { + _cleanup_free_ char *p = NULL; + Unit *u = userdata; + int r; - return DBUS_HANDLER_RESULT_HANDLED; - } + assert(bus); + assert(u); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } + p = unit_dbus_path(u); + if (!u) + return -ENOMEM; - r = manager_load_unit_from_dbus_path(m, dbus_message_get_path(message), &error, &u); - if (r == -ENOMEM) - goto oom; - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); + /* Send a properties changed signal. First for the specific + * type, then for the generic unit. The clients may rely on + * this order to get atomic behavior if needed. */ - return bus_unit_message_dispatch(u, connection, message); + if (UNIT_VTABLE(u)->bus_changing_properties) { -oom: - dbus_error_free(&error); + r = sd_bus_emit_properties_changed_strv( + bus, p, + UNIT_VTABLE(u)->bus_interface, + (char**) UNIT_VTABLE(u)->bus_changing_properties); + if (r < 0) + return r; + } - return DBUS_HANDLER_RESULT_NEED_MEMORY; + return sd_bus_emit_properties_changed( + bus, p, + "org.freedesktop.systemd1.Unit", + "ActiveState", + "SubState", + "InactiveExitTimestamp", + "ActiveEnterTimestamp", + "ActiveExitTimestamp", + "InactiveEnterTimestamp", + "Job", + "ConditionResult", + "ConditionTimestamp", + NULL); } -const DBusObjectPathVTable bus_unit_vtable = { - .message_function = bus_unit_message_handler -}; - void bus_unit_send_change_signal(Unit *u) { - _cleanup_dbus_message_unref_ DBusMessage *m = NULL; - _cleanup_free_ char *p = NULL; int r; assert(u); @@ -634,141 +670,77 @@ void bus_unit_send_change_signal(Unit *u) { if (!u->id) return; - if (!bus_has_subscriber(u->manager)) { - u->sent_dbus_new_signal = true; - return; - } - - p = unit_dbus_path(u); - if (!p) { - log_oom(); - return; - } - - if (u->sent_dbus_new_signal) { - /* Send a properties changed signal. First for the - * specific type, then for the generic unit. The - * clients may rely on this order to get atomic - * behavior if needed. */ - - if (UNIT_VTABLE(u)->bus_invalidating_properties) { - - m = bus_properties_changed_new(p, - UNIT_VTABLE(u)->bus_interface, - UNIT_VTABLE(u)->bus_invalidating_properties); - if (!m) { - log_oom(); - return; - } - - r = bus_broadcast(u->manager, m); - if (r < 0) { - log_error("Failed to broadcast change message: %s", strerror(-r)); - return; - } + r = bus_manager_foreach_client(u->manager, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u); + if (r < 0) + log_warning("Failed to send unit change signal for %s: %s", u->id, strerror(-r)); - dbus_message_unref(m); - } + u->sent_dbus_new_signal = true; +} - m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Unit", - INVALIDATING_PROPERTIES); - if (!m) { - log_oom(); - return; - } +static int send_removed_signal(sd_bus *bus, const char *destination, void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_free_ char *p = NULL; + Unit *u = userdata; + int r; - } else { - /* Send a new signal */ + assert(bus); + assert(u); - m = dbus_message_new_signal("/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "UnitNew"); - if (!m) { - log_oom(); - return; - } + p = unit_dbus_path(u); + if (!u) + return -ENOMEM; - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &u->id, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_INVALID)) { - log_oom(); - return; - } - } + r = sd_bus_message_new_signal( + bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "UnitRemoved", + &m); + if (r < 0) + return r; - r = bus_broadcast(u->manager, m); - if (r < 0) { - log_error("Failed to broadcast UnitNew/PropertiesChanged message."); - return; - } + r = sd_bus_message_append(m, "so", u->id, p); + if (r < 0) + return r; - u->sent_dbus_new_signal = true; + return sd_bus_send_to(bus, m, destination, NULL); } void bus_unit_send_removed_signal(Unit *u) { - _cleanup_free_ char *p = NULL; - _cleanup_dbus_message_unref_ DBusMessage *m = NULL; + int r; assert(u); - if (!bus_has_subscriber(u->manager)) - return; - if (!u->sent_dbus_new_signal) bus_unit_send_change_signal(u); if (!u->id) return; - p = unit_dbus_path(u); - if (!p) - goto oom; - - m = dbus_message_new_signal("/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "UnitRemoved"); - if (!m) - goto oom; - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &u->id, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_INVALID)) - goto oom; - - if (bus_broadcast(u->manager, m) < 0) - goto oom; - - return; - -oom: - log_oom(); + r = bus_manager_foreach_client(u->manager, send_removed_signal, u); + if (r < 0) + log_warning("Failed to send unit change signal for %s: %s", u->id, strerror(-r)); } -DBusHandlerResult bus_unit_queue_job( - DBusConnection *connection, - DBusMessage *message, +int bus_unit_queue_job( + sd_bus *bus, + sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible) { - _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *path = NULL; Job *j; - JobBusClient *cl; - DBusError error; int r; - assert(connection); + assert(bus); assert(message); assert(u); assert(type >= 0 && type < _JOB_TYPE_MAX); assert(mode >= 0 && mode < _JOB_MODE_MAX); - dbus_error_init(&error); - if (reload_if_possible && unit_can_reload(u)) { if (type == JOB_RESTART) type = JOB_RELOAD_OR_START; @@ -776,85 +748,61 @@ DBusHandlerResult bus_unit_queue_job( type = JOB_RELOAD; } - SELINUX_UNIT_ACCESS_CHECK(u, connection, message, + SELINUX_UNIT_ACCESS_CHECK(u, bus, message, (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" : type == JOB_STOP ? "stop" : "reload"); - if (type == JOB_STOP && (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) && unit_active_state(u) == UNIT_INACTIVE) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id); - return bus_send_error_reply(connection, message, &error, -EPERM); - } + if (type == JOB_STOP && + (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) && + unit_active_state(u) == UNIT_INACTIVE) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id); if ((type == JOB_START && u->refuse_manual_start) || (type == JOB_STOP && u->refuse_manual_stop) || - ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop))) { - dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, - "Operation refused, unit %s may be requested by dependency only.", u->id); - return bus_send_error_reply(connection, message, &error, -EPERM); - } + ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop))) + return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id); r = manager_add_job(u->manager, type, u, mode, true, &error, &j); if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - cl = job_bus_client_new(connection, bus_message_get_sender_with_fallback(message)); - if (!cl) - goto oom; - - LIST_PREPEND(client, j->bus_client_list, cl); + return sd_bus_reply_method_errno(bus, message, r, &error); - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; + r = bus_client_track(&j->subscribed, bus, sd_bus_message_get_sender(message)); + if (r < 0) + return sd_bus_reply_method_errno(bus, message, r, NULL); path = job_dbus_path(j); if (!path) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto oom; - - if (!bus_maybe_send_reply(connection, message, reply)) - goto oom; - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - dbus_error_free(&error); + return sd_bus_reply_method_errno(bus, message, r, NULL); - return DBUS_HANDLER_RESULT_NEED_MEMORY; + return sd_bus_reply_method_return(bus, message, "o", path); } static int bus_unit_set_transient_property( Unit *u, const char *name, - DBusMessageIter *i, + sd_bus_message *message, UnitSetPropertiesMode mode, - DBusError *error) { + sd_bus_error *error) { int r; assert(u); assert(name); - assert(i); + assert(message); if (streq(name, "Description")) { - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) - return -EINVAL; - - if (mode != UNIT_CHECK) { - const char *description; + const char *d; - dbus_message_iter_get_basic(i, &description); + r = sd_bus_message_read(message, "s", &d); + if (r < 0) + return r; - r = unit_set_description(u, description); + if (mode != UNIT_CHECK) { + r = unit_set_description(u, d); if (r < 0) return r; - unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", description); + unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d); } return 1; @@ -862,10 +810,12 @@ static int bus_unit_set_transient_property( } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) { const char *s; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) - return -EINVAL; + r = sd_bus_message_read(message, "s", &s); + if (r < 0) + return r; - dbus_message_iter_get_basic(i, &s); + if (!unit_name_is_valid(s, false) || !endswith(s, ".slice")) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s); if (isempty(s)) { if (mode != UNIT_CHECK) { @@ -905,24 +855,19 @@ static int bus_unit_set_transient_property( streq(name, "PartOf")) { UnitDependency d; - DBusMessageIter sub; + const char *other; d = unit_dependency_from_string(name); if (d < 0) return -EINVAL; - if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRING) - return -EINVAL; - - dbus_message_iter_recurse(i, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) { - const char *other; - - dbus_message_iter_get_basic(&sub, &other); + r = sd_bus_message_enter_container(message, 'a', "s"); + if (r < 0) + return r; + while ((r = sd_bus_message_read(message, "s", &other)) > 0) { if (!unit_name_is_valid(other, false)) - return -EINVAL; + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other); if (mode != UNIT_CHECK) { _cleanup_free_ char *label = NULL; @@ -938,8 +883,9 @@ static int bus_unit_set_transient_property( unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other); } - dbus_message_iter_next(&sub); } + if (r < 0) + return r; return 1; } @@ -949,18 +895,17 @@ static int bus_unit_set_transient_property( int bus_unit_set_properties( Unit *u, - DBusMessageIter *iter, + sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, - DBusError *error) { + sd_bus_error *error) { bool for_real = false; - DBusMessageIter sub; unsigned n = 0; int r; assert(u); - assert(iter); + assert(message); if (u->transient) mode &= UNIT_RUNTIME; @@ -970,52 +915,54 @@ int bus_unit_set_properties( * it. This is to implement transaction-like behaviour without * actually providing full transactions. */ - if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRUCT) - return -EINVAL; + r = sd_bus_message_enter_container(message, 'a', "(sv)"); + if (r < 0) + return r; - dbus_message_iter_recurse(iter, &sub); for (;;) { - DBusMessageIter sub2, sub3; const char *name; - if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_INVALID) { - + r = sd_bus_message_enter_container(message, 'r', "sv"); + if (r < 0) + return r; + if (r == 0) { if (for_real || mode == UNIT_CHECK) break; /* Reached EOF. Let's try again, and this time for realz... */ - dbus_message_iter_recurse(iter, &sub); + r = sd_bus_message_rewind(message, false); + if (r < 0) + return r; for_real = true; continue; } - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) - return -EINVAL; - - dbus_message_iter_recurse(&sub, &sub2); + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 || - dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) - return -EINVAL; + if (!UNIT_VTABLE(u)->bus_set_property) + return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties."); - if (!UNIT_VTABLE(u)->bus_set_property) { - dbus_set_error(error, DBUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties."); - return -ENOENT; - } + r = sd_bus_message_enter_container(message, 'v', NULL); + if (r < 0) + return r; - dbus_message_iter_recurse(&sub2, &sub3); - r = UNIT_VTABLE(u)->bus_set_property(u, name, &sub3, for_real ? mode : UNIT_CHECK, error); + r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error); if (r == 0 && u->transient && u->load_state == UNIT_STUB) - r = bus_unit_set_transient_property(u, name, &sub3, for_real ? mode : UNIT_CHECK, error); + r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error); + if (r < 0) + return r; + if (r == 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name); + + r = sd_bus_message_exit_container(message); if (r < 0) return r; - if (r == 0) { - dbus_set_error(error, DBUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name); - return -ENOENT; - } - dbus_message_iter_next(&sub); + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; n += for_real; } @@ -1025,76 +972,3 @@ int bus_unit_set_properties( return n; } - -const BusProperty bus_unit_properties[] = { - { "Id", bus_property_append_string, "s", offsetof(Unit, id), true }, - { "Names", bus_unit_append_names, "as", 0 }, - { "Following", bus_unit_append_following, "s", 0 }, - { "Requires", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRES]), true }, - { "RequiresOverridable", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), true }, - { "Requisite", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUISITE]), true }, - { "RequisiteOverridable", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), true }, - { "Wants", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_WANTS]), true }, - { "BindsTo", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_BINDS_TO]), true }, - { "PartOf", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PART_OF]), true }, - { "RequiredBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), true }, - { "RequiredByOverridable", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), true }, - { "WantedBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_WANTED_BY]), true }, - { "BoundBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_BOUND_BY]), true }, - { "ConsistsOf", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), true }, - { "Conflicts", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_CONFLICTS]), true }, - { "ConflictedBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), true }, - { "Before", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_BEFORE]), true }, - { "After", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_AFTER]), true }, - { "OnFailure", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_ON_FAILURE]), true }, - { "Triggers", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_TRIGGERS]), true }, - { "TriggeredBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), true }, - { "PropagatesReloadTo", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), true }, - { "ReloadPropagatedFrom", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), true }, - { "RequiresMountsFor", bus_property_append_strv, "as", offsetof(Unit, requires_mounts_for), true }, - { "Documentation", bus_property_append_strv, "as", offsetof(Unit, documentation), true }, - { "Description", bus_unit_append_description, "s", 0 }, - { "LoadState", bus_unit_append_load_state, "s", offsetof(Unit, load_state) }, - { "ActiveState", bus_unit_append_active_state, "s", 0 }, - { "SubState", bus_unit_append_sub_state, "s", 0 }, - { "FragmentPath", bus_property_append_string, "s", offsetof(Unit, fragment_path), true }, - { "SourcePath", bus_property_append_string, "s", offsetof(Unit, source_path), true }, - { "DropInPaths", bus_property_append_strv, "as", offsetof(Unit, dropin_paths), true }, - { "UnitFileState", bus_unit_append_file_state, "s", 0 }, - { "InactiveExitTimestamp", bus_property_append_usec, "t", offsetof(Unit, inactive_exit_timestamp.realtime) }, - { "InactiveExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, inactive_exit_timestamp.monotonic) }, - { "ActiveEnterTimestamp", bus_property_append_usec, "t", offsetof(Unit, active_enter_timestamp.realtime) }, - { "ActiveEnterTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, active_enter_timestamp.monotonic) }, - { "ActiveExitTimestamp", bus_property_append_usec, "t", offsetof(Unit, active_exit_timestamp.realtime) }, - { "ActiveExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, active_exit_timestamp.monotonic) }, - { "InactiveEnterTimestamp", bus_property_append_usec, "t", offsetof(Unit, inactive_enter_timestamp.realtime) }, - { "InactiveEnterTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, inactive_enter_timestamp.monotonic) }, - { "CanStart", bus_unit_append_can_start, "b", 0 }, - { "CanStop", bus_unit_append_can_stop, "b", 0 }, - { "CanReload", bus_unit_append_can_reload, "b", 0 }, - { "CanIsolate", bus_unit_append_can_isolate, "b", 0 }, - { "Job", bus_unit_append_job, "(uo)", 0 }, - { "StopWhenUnneeded", bus_property_append_bool, "b", offsetof(Unit, stop_when_unneeded) }, - { "RefuseManualStart", bus_property_append_bool, "b", offsetof(Unit, refuse_manual_start) }, - { "RefuseManualStop", bus_property_append_bool, "b", offsetof(Unit, refuse_manual_stop) }, - { "AllowIsolate", bus_property_append_bool, "b", offsetof(Unit, allow_isolate) }, - { "DefaultDependencies", bus_property_append_bool, "b", offsetof(Unit, default_dependencies) }, - { "OnFailureIsolate", bus_property_append_bool, "b", offsetof(Unit, on_failure_isolate) }, - { "IgnoreOnIsolate", bus_property_append_bool, "b", offsetof(Unit, ignore_on_isolate) }, - { "IgnoreOnSnapshot", bus_property_append_bool, "b", offsetof(Unit, ignore_on_snapshot) }, - { "NeedDaemonReload", bus_unit_append_need_daemon_reload, "b", 0 }, - { "JobTimeoutUSec", bus_property_append_usec, "t", offsetof(Unit, job_timeout) }, - { "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) }, - { "Conditions", bus_property_append_condition_list, "a(sbbsi)", offsetof(Unit, conditions) }, - { "LoadError", bus_unit_append_load_error, "(ss)", 0 }, - { "Transient", bus_property_append_bool, "b", offsetof(Unit, transient) }, - {} -}; - -const BusProperty bus_unit_cgroup_properties[] = { - { "Slice", bus_unit_append_slice, "s", 0 }, - { "ControlGroup", bus_property_append_string, "s", offsetof(Unit, cgroup_path), true }, - {} -}; diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h index 3064cd552a..859de102b6 100644 --- a/src/core/dbus-unit.h +++ b/src/core/dbus-unit.h @@ -21,133 +21,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> +#include "sd-bus.h" +#include "unit.h" -#include "manager.h" -#include "dbus-common.h" - -#define BUS_UNIT_INTERFACE \ - " <interface name=\"org.freedesktop.systemd1.Unit\">\n" \ - " <method name=\"Start\">\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"Stop\">\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"Reload\">\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"Restart\">\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"TryRestart\">\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"ReloadOrRestart\">\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"ReloadOrTryRestart\">\n" \ - " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ - " </method>\n" \ - " <method name=\"Kill\">\n" \ - " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \ - " <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n" \ - " </method>\n" \ - " <method name=\"ResetFailed\"/>\n" \ - " <method name=\"SetProperties\">\n" \ - " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \ - " <arg name=\"properties\" type=\"a(sv)\" direction=\"in\"/>\n" \ - " </method>\n" \ - " <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"Names\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"Following\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"Requires\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"RequiresOverridable\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"Requisite\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"RequisiteOverridable\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"Wants\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"BindsTo\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"PartOf\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"RequiredBy\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"RequiredByOverridable\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"WantedBy\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"BoundBy\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"ConsistsOf\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"Conflicts\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"ConflictedBy\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"Before\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"After\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"OnFailure\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"Triggers\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"TriggeredBy\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"PropagatesReloadTo\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"ReloadPropagatedFrom\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"RequiresMountsFor\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"Description\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"SourcePath\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"DropInPaths\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"Documentation\" type=\"as\" access=\"read\"/>\n" \ - " <property name=\"LoadState\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"ActiveState\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"SubState\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"FragmentPath\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"UnitFileState\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"InactiveExitTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"InactiveExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"ActiveEnterTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"ActiveEnterTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"ActiveExitTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"ActiveExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"InactiveEnterTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"InactiveEnterTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"CanStart\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"CanStop\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"CanReload\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"CanIsolate\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"Job\" type=\"(uo)\" access=\"read\"/>\n" \ - " <property name=\"StopWhenUnneeded\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"RefuseManualStart\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"RefuseManualStop\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"AllowIsolate\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"DefaultDependencies\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"OnFailureIsolate\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"IgnoreOnIsolate\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"IgnoreOnSnapshot\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"NeedDaemonReload\" type=\"b\" access=\"read\"/>\n" \ - " <property name=\"JobTimeoutUSec\" type=\"t\" access=\"read\"/>\n" \ - " <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=\"Conditions\" type=\"a(sbbsi)\" access=\"read\"/>\n" \ - " <property name=\"LoadError\" type=\"(ss)\" access=\"read\"/>\n" \ - " <property name=\"Transient\" type=\"b\" access=\"read\"/>\n" \ - " </interface>\n" - -#define BUS_UNIT_CGROUP_INTERFACE \ - " <property name=\"Slice\" type=\"s\" access=\"read\"/>\n" \ - " <property name=\"ControlGroup\" type=\"s\" access=\"read\"/>\n" - -#define BUS_UNIT_INTERFACES_LIST \ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.systemd1.Unit\0" - -extern const BusProperty bus_unit_properties[]; -extern const BusProperty bus_unit_cgroup_properties[]; +extern const sd_bus_vtable bus_unit_vtable[]; +extern const sd_bus_vtable bus_unit_cgroup_vtable[]; void bus_unit_send_change_signal(Unit *u); void bus_unit_send_removed_signal(Unit *u); -DBusHandlerResult bus_unit_queue_job(DBusConnection *connection, DBusMessage *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible); - -int bus_unit_set_properties(Unit *u, DBusMessageIter *i, UnitSetPropertiesMode mode, bool commit, DBusError *error); - -extern const DBusObjectPathVTable bus_unit_vtable; +int bus_unit_method_start_generic(sd_bus *bus, sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible); +int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata); +int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata); -extern const char bus_unit_interface[]; +int bus_unit_queue_job(sd_bus *bus, sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible); +int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error); +int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata); diff --git a/src/core/dbus.c b/src/core/dbus.c index b0ae3e1ae7..35d185a601 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -23,9 +23,8 @@ #include <sys/timerfd.h> #include <errno.h> #include <unistd.h> -#include <dbus/dbus.h> -#include "dbus.h" +#include "sd-bus.h" #include "log.h" #include "strv.h" #include "mkdir.h" @@ -33,1034 +32,851 @@ #include "dbus-unit.h" #include "dbus-job.h" #include "dbus-manager.h" -#include "dbus-service.h" -#include "dbus-socket.h" -#include "dbus-target.h" -#include "dbus-device.h" -#include "dbus-mount.h" -#include "dbus-automount.h" -#include "dbus-snapshot.h" -#include "dbus-swap.h" -#include "dbus-timer.h" -#include "dbus-path.h" -#include "bus-errors.h" +#include "dbus-execute.h" +#include "dbus-kill.h" +#include "dbus-cgroup.h" #include "special.h" -#include "dbus-common.h" +#include "dbus.h" +#include "bus-util.h" +#include "bus-error.h" +#include "bus-errors.h" +#include "strxcpyx.h" +#include "dbus-client-track.h" #define CONNECTIONS_MAX 512 -/* Well-known address (http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-types) */ -#define DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "unix:path=/var/run/dbus/system_bus_socket" -/* Only used as a fallback */ -#define DBUS_SESSION_BUS_DEFAULT_ADDRESS "autolaunch:" - -static const char bus_properties_interface[] = BUS_PROPERTIES_INTERFACE; -static const char bus_introspectable_interface[] = BUS_INTROSPECTABLE_INTERFACE; - -const char *const bus_interface_table[] = { - "org.freedesktop.DBus.Properties", bus_properties_interface, - "org.freedesktop.DBus.Introspectable", bus_introspectable_interface, - "org.freedesktop.systemd1.Manager", bus_manager_interface, - "org.freedesktop.systemd1.Job", bus_job_interface, - "org.freedesktop.systemd1.Unit", bus_unit_interface, - "org.freedesktop.systemd1.Service", bus_service_interface, - "org.freedesktop.systemd1.Socket", bus_socket_interface, - "org.freedesktop.systemd1.Target", bus_target_interface, - "org.freedesktop.systemd1.Device", bus_device_interface, - "org.freedesktop.systemd1.Mount", bus_mount_interface, - "org.freedesktop.systemd1.Automount", bus_automount_interface, - "org.freedesktop.systemd1.Snapshot", bus_snapshot_interface, - "org.freedesktop.systemd1.Swap", bus_swap_interface, - "org.freedesktop.systemd1.Timer", bus_timer_interface, - "org.freedesktop.systemd1.Path", bus_path_interface, - NULL -}; - -static void bus_done_api(Manager *m); -static void bus_done_system(Manager *m); -static void bus_done_private(Manager *m); -static void shutdown_connection(Manager *m, DBusConnection *c); - -static void bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data) { - Manager *m = data; +static void destroy_bus(Manager *m, sd_bus **bus); + +int bus_send_queued_message(Manager *m) { + int r; - assert(bus); assert(m); - /* We maintain two sets, one for those connections where we - * requested a dispatch, and another where we didn't. And then, - * we move the connections between the two sets. */ + if (!m->queued_message) + return 0; - if (status == DBUS_DISPATCH_COMPLETE) - set_move_one(m->bus_connections, m->bus_connections_for_dispatch, bus); - else - set_move_one(m->bus_connections_for_dispatch, m->bus_connections, bus); -} + assert(m->queued_message_bus); -void bus_watch_event(Manager *m, Watch *w, int events) { - assert(m); - assert(w); + /* If we cannot get rid of this message we won't dispatch any + * D-Bus messages, so that we won't end up wanting to queue + * another message. */ - /* This is called by the event loop whenever there is - * something happening on D-Bus' file handles. */ + r = sd_bus_send(m->queued_message_bus, m->queued_message, NULL); + if (r < 0) + log_warning("Failed to send queued message: %s", strerror(-r)); - if (!dbus_watch_get_enabled(w->data.bus_watch)) - return; + m->queued_message = sd_bus_message_unref(m->queued_message); + m->queued_message_bus = sd_bus_unref(m->queued_message_bus); - dbus_watch_handle(w->data.bus_watch, bus_events_to_flags(events)); + return 0; } -static dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) { - Manager *m = data; - Watch *w; - struct epoll_event ev; +static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; + const char *cgroup; + int r; - assert(bus_watch); + assert(bus); + assert(message); assert(m); - if (!(w = new0(Watch, 1))) - return FALSE; - - w->fd = dbus_watch_get_unix_fd(bus_watch); - w->type = WATCH_DBUS_WATCH; - w->data.bus_watch = bus_watch; + r = sd_bus_message_read(message, "s", &cgroup); + if (r < 0) { + bus_log_parse_error(r); + return 0; + } - zero(ev); - ev.events = bus_flags_to_events(bus_watch); - ev.data.ptr = w; + manager_notify_cgroup_empty(m, cgroup); - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) { + if (m->running_as == SYSTEMD_SYSTEM && m->system_bus) { + /* If we are running as system manager, forward the + * message to the system bus */ - if (errno != EEXIST) { - free(w); - return FALSE; - } + r = sd_bus_send(m->system_bus, message, NULL); + if (r < 0) + log_warning("Failed to forward Released message: %s", strerror(-r)); + } - /* Hmm, bloody D-Bus creates multiple watches on the - * same fd. epoll() does not like that. As a dirty - * hack we simply dup() the fd and hence get a second - * one we can safely add to the epoll(). */ + return 0; +} - if ((w->fd = dup(w->fd)) < 0) { - free(w); - return FALSE; - } +static int signal_disconnected(sd_bus *bus, sd_bus_message *message, void *userdata) { + Manager *m = userdata; - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) { - close_nointr_nofail(w->fd); - free(w); - return FALSE; - } + assert(bus); + assert(message); + assert(m); - w->fd_is_dupped = true; + if (bus == m->api_bus) + destroy_bus(m, &m->api_bus); + if (bus == m->system_bus) + destroy_bus(m, &m->system_bus); + if (set_remove(m->private_buses, bus)) { + log_debug("Got disconnect on private connection."); + destroy_bus(m, &bus); } - dbus_watch_set_data(bus_watch, w, NULL); - - return TRUE; + return 0; } -static void bus_remove_watch(DBusWatch *bus_watch, void *data) { - Manager *m = data; - Watch *w; +static int signal_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata) { + const char *name, *old_owner, *new_owner; + Manager *m = userdata; + int r; - assert(bus_watch); + assert(bus); + assert(message); assert(m); - w = dbus_watch_get_data(bus_watch); - if (!w) - return; - - assert(w->type == WATCH_DBUS_WATCH); - assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0); + r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner); + if (r < 0) { + bus_log_parse_error(r); + return 0; + } - if (w->fd_is_dupped) - close_nointr_nofail(w->fd); + manager_dispatch_bus_name_owner_changed( + m, name, + isempty(old_owner) ? NULL : old_owner, + isempty(new_owner) ? NULL : new_owner); - free(w); + return 0; } -static void bus_toggle_watch(DBusWatch *bus_watch, void *data) { - Manager *m = data; - Watch *w; - struct epoll_event ev; +static int signal_activation_request(sd_bus *bus, sd_bus_message *message, void *userdata) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; + const char *name; + Unit *u; + int r; - assert(bus_watch); + assert(bus); + assert(message); assert(m); - w = dbus_watch_get_data(bus_watch); - if (!w) - return; - - assert(w->type == WATCH_DBUS_WATCH); - - zero(ev); - ev.events = bus_flags_to_events(bus_watch); - ev.data.ptr = w; - - assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_MOD, w->fd, &ev) == 0); -} + r = sd_bus_message_read(message, "s", &name); + if (r < 0) { + bus_log_parse_error(r); + return 0; + } -static int bus_timeout_arm(Manager *m, Watch *w) { - struct itimerspec its = {}; + if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE) || + manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET)) { + r = sd_bus_error_setf(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down."); + goto failed; + } - assert(m); - assert(w); + r = manager_load_unit(m, name, NULL, &error, &u); + if (r < 0) + goto failed; - if (dbus_timeout_get_enabled(w->data.bus_timeout)) { - timespec_store(&its.it_value, dbus_timeout_get_interval(w->data.bus_timeout) * USEC_PER_MSEC); - its.it_interval = its.it_value; + if (u->refuse_manual_start) { + r = sd_bus_error_setf(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, %u may be requested by dependency only.", u->id); + goto failed; } - if (timerfd_settime(w->fd, 0, &its, NULL) < 0) - return -errno; + r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL); + if (r < 0) + goto failed; + /* Successfully queued, that's it for us */ return 0; -} -void bus_timeout_event(Manager *m, Watch *w, int events) { - assert(m); - assert(w); +failed: + if (!sd_bus_error_is_set(&error)) + sd_bus_error_set_errno(&error, r); - /* This is called by the event loop whenever there is - * something happening on D-Bus' file handles. */ + log_debug("D-Bus activation failed for %s: %s", name, bus_error_message(&error, r)); - if (!(dbus_timeout_get_enabled(w->data.bus_timeout))) - return; + r = sd_bus_message_new_signal(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure", &reply); + if (r < 0) { + bus_log_create_error(r); + return 0; + } - dbus_timeout_handle(w->data.bus_timeout); + r = sd_bus_message_append(reply, "sss", error.name, error.message); + if (r < 0) { + bus_log_create_error(r); + return 0; + } + + r = sd_bus_send_to(bus, reply, "org.freedesktop.DBus", NULL); + if (r < 0) { + log_error("Failed to respond with to bus activation request: %s", strerror(-r)); + return r; + } + + return 0; } -static dbus_bool_t bus_add_timeout(DBusTimeout *timeout, void *data) { - Manager *m = data; - Watch *w; - struct epoll_event ev; +static int bus_job_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) { + Manager *m = userdata; + Job *j; + int r; - assert(timeout); + assert(bus); + assert(path); + assert(interface); + assert(found); assert(m); - if (!(w = new0(Watch, 1))) - return FALSE; - - if ((w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) - goto fail; + r = manager_get_job_from_dbus_path(m, path, &j); + if (r < 0) + return 0; - w->type = WATCH_DBUS_TIMEOUT; - w->data.bus_timeout = timeout; + *found = j; + return 1; +} - if (bus_timeout_arm(m, w) < 0) - goto fail; +static Unit *find_unit(Manager *m, sd_bus *bus, const char *path) { + Unit *u; + int r; - zero(ev); - ev.events = EPOLLIN; - ev.data.ptr = w; + assert(m); + assert(bus); + assert(path); - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) - goto fail; + if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) { + sd_bus_message *message; + pid_t pid; - dbus_timeout_set_data(timeout, w, NULL); + message = sd_bus_get_current(bus); + if (!message) + return NULL; - return TRUE; + r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid); + if (r < 0) + return NULL; -fail: - if (w->fd >= 0) - close_nointr_nofail(w->fd); + u = manager_get_unit_by_pid(m, pid); + } else { + r = manager_load_unit_from_dbus_path(m, path, NULL, &u); + if (r < 0) + return NULL; + } - free(w); - return FALSE; + return u; } -static void bus_remove_timeout(DBusTimeout *timeout, void *data) { - Manager *m = data; - Watch *w; +static int bus_unit_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) { + Manager *m = userdata; + Unit *u; - assert(timeout); + assert(bus); + assert(path); + assert(interface); + assert(found); assert(m); - w = dbus_timeout_get_data(timeout); - if (!w) - return; - - assert(w->type == WATCH_DBUS_TIMEOUT); + u = find_unit(m, bus, path); + if (!u) + return 0; - assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0); - close_nointr_nofail(w->fd); - free(w); + *found = u; + return 1; } -static void bus_toggle_timeout(DBusTimeout *timeout, void *data) { - Manager *m = data; - Watch *w; - int r; +static int bus_unit_interface_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) { + Manager *m = userdata; + Unit *u; - assert(timeout); + assert(bus); + assert(path); + assert(interface); + assert(found); assert(m); - w = dbus_timeout_get_data(timeout); - if (!w) - return; + u = find_unit(m, bus, path); + if (!u) + return 0; - assert(w->type == WATCH_DBUS_TIMEOUT); + if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + return 0; - if ((r = bus_timeout_arm(m, w)) < 0) - log_error("Failed to rearm timer: %s", strerror(-r)); + *found = u; + return 1; } -static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) { - Manager *m = data; - DBusError error; - DBusMessage *reply = NULL; +static int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) { + Manager *m = userdata; + Unit *u; - assert(connection); - assert(message); + assert(bus); + assert(path); + assert(interface); + assert(found); assert(m); - dbus_error_init(&error); - - if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL || - dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) - log_debug("Got D-Bus request: %s.%s() on %s", - dbus_message_get_interface(message), - dbus_message_get_member(message), - dbus_message_get_path(message)); - - if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { - log_debug("API D-Bus connection terminated."); - bus_done_api(m); - - } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { - const char *name, *old_owner, *new_owner; - - if (!dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &old_owner, - DBUS_TYPE_STRING, &new_owner, - DBUS_TYPE_INVALID)) - log_error("Failed to parse NameOwnerChanged message: %s", bus_error_message(&error)); - else { - if (set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) name)) - log_debug("Subscription client vanished: %s (left: %u)", name, set_size(BUS_CONNECTION_SUBSCRIBED(m, connection))); - - if (old_owner[0] == 0) - old_owner = NULL; + u = find_unit(m, bus, path); + if (!u) + return 0; - if (new_owner[0] == 0) - new_owner = NULL; + if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + return 0; - manager_dispatch_bus_name_owner_changed(m, name, old_owner, new_owner); - } - } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Activator", "ActivationRequest")) { - const char *name; - - if (!dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - log_error("Failed to parse ActivationRequest message: %s", bus_error_message(&error)); - else { - int r; - Unit *u; - - log_debug("Got D-Bus activation request for %s", name); - - if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE) || - manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET)) { - r = -EADDRNOTAVAIL; - dbus_set_error(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down."); - } else { - r = manager_load_unit(m, name, NULL, &error, &u); - - if (r >= 0 && u->refuse_manual_start) - r = -EPERM; - - if (r >= 0) - r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL); - } + if (!unit_get_cgroup_context(u)) + return 0; - if (r < 0) { - const char *id, *text; + *found = u; + return 1; +} - log_debug("D-Bus activation failed for %s: %s", name, strerror(-r)); +static int bus_cgroup_context_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) { + Manager *m = userdata; + CGroupContext *c; + Unit *u; - if (!(reply = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure"))) - goto oom; + assert(bus); + assert(path); + assert(interface); + assert(found); + assert(m); - id = error.name ? error.name : bus_errno_to_dbus(r); - text = bus_error(&error, r); + u = find_unit(m, bus, path); + if (!u) + return 0; - if (!dbus_message_set_destination(reply, DBUS_SERVICE_DBUS) || - !dbus_message_append_args(reply, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &id, - DBUS_TYPE_STRING, &text, - DBUS_TYPE_INVALID)) - goto oom; - } + if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + return 0; - /* On success we don't do anything, the service will be spawned now */ - } - } + c = unit_get_cgroup_context(u); + if (!c) + return 0; - dbus_error_free(&error); + *found = c; + return 1; +} - if (reply) { - if (!bus_maybe_send_reply(connection, message, reply)) - goto oom; +static int bus_exec_context_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) { + Manager *m = userdata; + ExecContext *c; + Unit *u; - dbus_message_unref(reply); - } + assert(bus); + assert(path); + assert(interface); + assert(found); + assert(m); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + u = find_unit(m, bus, path); + if (!u) + return 0; -oom: - if (reply) - dbus_message_unref(reply); + if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + return 0; - dbus_error_free(&error); + c = unit_get_exec_context(u); + if (!c) + return 0; - return DBUS_HANDLER_RESULT_NEED_MEMORY; + *found = c; + return 1; } -static DBusHandlerResult system_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) { - Manager *m = data; - DBusError error; +static int bus_kill_context_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) { + Manager *m = userdata; + KillContext *c; + Unit *u; - assert(connection); - assert(message); + assert(bus); + assert(path); + assert(interface); + assert(found); assert(m); - dbus_error_init(&error); - - if (m->api_bus != m->system_bus && - (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL || - dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)) - log_debug("Got D-Bus request on system bus: %s.%s() on %s", - dbus_message_get_interface(message), - dbus_message_get_member(message), - dbus_message_get_path(message)); + u = find_unit(m, bus, path); + if (!u) + return 0; - if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { - log_debug("System D-Bus connection terminated."); - bus_done_system(m); + if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + return 0; - } else if (m->running_as != SYSTEMD_SYSTEM && - dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) { + c = unit_get_kill_context(u); + if (!c) + return 0; - const char *cgroup; + *found = c; + return 1; +} - if (!dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &cgroup, - DBUS_TYPE_INVALID)) - log_error("Failed to parse Released message: %s", bus_error_message(&error)); - else - manager_notify_cgroup_empty(m, cgroup); - } +static int bus_job_enumerate(sd_bus *bus, const char *path, char ***nodes, void *userdata) { + _cleanup_free_ char **l = NULL; + Manager *m = userdata; + unsigned k = 0; + Iterator i; + Job *j; - dbus_error_free(&error); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} + l = new0(char*, hashmap_size(m->jobs)+1); + if (!l) + return -ENOMEM; -static DBusHandlerResult private_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) { - Manager *m = data; - DBusError error; + HASHMAP_FOREACH(j, m->jobs, i) { + l[k] = job_dbus_path(j); + if (!l[k]) + return -ENOMEM; - assert(connection); - assert(message); - assert(m); + k++; + } - dbus_error_init(&error); + assert(hashmap_size(m->jobs) == k); - if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL || - dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) - log_debug("Got D-Bus request: %s.%s() on %s", - dbus_message_get_interface(message), - dbus_message_get_member(message), - dbus_message_get_path(message)); + *nodes = l; + l = NULL; - if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) - shutdown_connection(m, connection); - else if (m->running_as == SYSTEMD_SYSTEM && - dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) { + return k; +} - const char *cgroup; +static int bus_unit_enumerate(sd_bus *bus, const char *path, char ***nodes, void *userdata) { + _cleanup_free_ char **l = NULL; + Manager *m = userdata; + unsigned k = 0; + Iterator i; + Unit *u; - if (!dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &cgroup, - DBUS_TYPE_INVALID)) - log_error("Failed to parse Released message: %s", bus_error_message(&error)); - else - manager_notify_cgroup_empty(m, cgroup); + l = new0(char*, hashmap_size(m->units)+1); + if (!l) + return -ENOMEM; - /* Forward the message to the system bus, so that user - * instances are notified as well */ + HASHMAP_FOREACH(u, m->units, i) { + l[k] = unit_dbus_path(u); + if (!l[k]) + return -ENOMEM; - if (m->system_bus) - dbus_connection_send(m->system_bus, message, NULL); + k++; } - dbus_error_free(&error); + *nodes = l; + l = NULL; - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + return k; } -unsigned bus_dispatch(Manager *m) { - DBusConnection *c; +static int bus_setup_api_vtables(Manager *m, sd_bus *bus) { + UnitType t; + int r; assert(m); + assert(bus); - if (m->queued_message) { - /* If we cannot get rid of this message we won't - * dispatch any D-Bus messages, so that we won't end - * up wanting to queue another message. */ - - if (m->queued_message_connection) - if (!dbus_connection_send(m->queued_message_connection, m->queued_message, NULL)) - return 0; - - dbus_message_unref(m->queued_message); - m->queued_message = NULL; - m->queued_message_connection = NULL; + r = sd_bus_add_object_vtable(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m); + if (r < 0) { + log_error("Failed to register Manager vtable: %s", strerror(-r)); + return r; } - if ((c = set_first(m->bus_connections_for_dispatch))) { - if (dbus_connection_dispatch(c) == DBUS_DISPATCH_COMPLETE) - set_move_one(m->bus_connections, m->bus_connections_for_dispatch, c); - - return 1; + r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m); + if (r < 0) { + log_error("Failed to register Job vtable: %s", strerror(-r)); + return r; } - return 0; -} - -static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) { - DBusMessage *reply; - DBusError error; - - dbus_error_init(&error); - - assert_se(reply = dbus_pending_call_steal_reply(pending)); + r = sd_bus_add_node_enumerator(bus, "/org/freedesktop/systemd1/job", bus_job_enumerate, m); + if (r < 0) { + log_error("Failed to add job enumerator: %s", strerror(-r)); + return r; + } - switch (dbus_message_get_type(reply)) { + r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m); + if (r < 0) { + log_error("Failed to register Unit vtable: %s", strerror(-r)); + return r; + } - case DBUS_MESSAGE_TYPE_ERROR: + r = sd_bus_add_node_enumerator(bus, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m); + if (r < 0) { + log_error("Failed to add job enumerator: %s", strerror(-r)); + return r; + } - assert_se(dbus_set_error_from_message(&error, reply)); - log_warning("RequestName() failed: %s", bus_error_message(&error)); - break; + for (t = 0; t < _UNIT_TYPE_MAX; t++) { + r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m); + if (r < 0) { + log_error("Failed to register type specific vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r)); + return r; + } - case DBUS_MESSAGE_TYPE_METHOD_RETURN: { - uint32_t r; + if (unit_vtable[t]->cgroup_context_offset > 0) { + r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m); + if (r < 0) { + log_error("Failed to register control group unit vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r)); + return r; + } - if (!dbus_message_get_args(reply, - &error, - DBUS_TYPE_UINT32, &r, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse RequestName() reply: %s", bus_error_message(&error)); - break; + r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_cgroup_vtable, bus_cgroup_context_find, m); + if (r < 0) { + log_error("Failed to register control group vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r)); + return r; + } } - if (r == 1) - log_debug("Successfully acquired name."); - else - log_error("Name already owned."); - - break; - } + if (unit_vtable[t]->exec_context_offset > 0) { + r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_exec_vtable, bus_exec_context_find, m); + if (r < 0) { + log_error("Failed to register execute vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r)); + return r; + } + } - default: - assert_not_reached("Invalid reply message"); + if (unit_vtable[t]->kill_context_offset > 0) { + r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_kill_vtable, bus_kill_context_find, m); + if (r < 0) { + log_error("Failed to register kill vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r)); + return r; + } + } } - dbus_message_unref(reply); - dbus_error_free(&error); + return 0; } -static int request_name(Manager *m) { - const char *name = "org.freedesktop.systemd1"; - /* Allow replacing of our name, to ease implementation of - * reexecution, where we keep the old connection open until - * after the new connection is set up and the name installed - * to allow clients to synchronously wait for reexecution to - * finish */ - uint32_t flags = DBUS_NAME_FLAG_ALLOW_REPLACEMENT|DBUS_NAME_FLAG_REPLACE_EXISTING; - DBusMessage *message = NULL; - DBusPendingCall *pending = NULL; - - if (!(message = dbus_message_new_method_call( - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "RequestName"))) - goto oom; - - if (!dbus_message_append_args( - message, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_UINT32, &flags, - DBUS_TYPE_INVALID)) - goto oom; - - if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1)) - goto oom; - - if (!dbus_pending_call_set_notify(pending, request_name_pending_cb, m, NULL)) - goto oom; +static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) { + int r; - dbus_message_unref(message); - dbus_pending_call_unref(pending); + assert(m); + assert(bus); - /* We simple ask for the name and don't wait for it. Sooner or - * later we'll have it. */ + r = sd_bus_add_match( + bus, + "type='signal'," + "path='/org/freedesktop/DBus/Local'," + "interface='org.freedesktop.DBus.Local'," + "member='Disconnected'", + signal_disconnected, m); - return 0; - -oom: - if (pending) { - dbus_pending_call_cancel(pending); - dbus_pending_call_unref(pending); + if (r < 0) { + log_error("Failed to register match for Disconnected message: %s", strerror(-r)); + return r; } - if (message) - dbus_message_unref(message); - - return -ENOMEM; + return 0; } -static void query_name_list_pending_cb(DBusPendingCall *pending, void *userdata) { - DBusMessage *reply; - DBusError error; +static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_close_ int nfd = -1; Manager *m = userdata; + sd_id128_t id; + int r; + assert(s); assert(m); - dbus_error_init(&error); - - assert_se(reply = dbus_pending_call_steal_reply(pending)); - - switch (dbus_message_get_type(reply)) { - - case DBUS_MESSAGE_TYPE_ERROR: - - assert_se(dbus_set_error_from_message(&error, reply)); - log_warning("ListNames() failed: %s", bus_error_message(&error)); - break; - - case DBUS_MESSAGE_TYPE_METHOD_RETURN: { - int r; - char **l; - - if ((r = bus_parse_strv(reply, &l)) < 0) - log_warning("Failed to parse ListNames() reply: %s", strerror(-r)); - else { - char **t; - - STRV_FOREACH(t, l) - /* This is a bit hacky, we say the - * owner of the name is the name - * itself, because we don't want the - * extra traffic to figure out the - * real owner. */ - manager_dispatch_bus_name_owner_changed(m, *t, NULL, *t); - - strv_free(l); - } - - break; + nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); + if (nfd < 0) { + log_warning("Failed to accept private connection, ignoring: %m"); + return 0; } - default: - assert_not_reached("Invalid reply message"); + if (set_size(m->private_buses) >= CONNECTIONS_MAX) { + log_warning("Too many concurrent connections, refusing"); + return 0; } - dbus_message_unref(reply); - dbus_error_free(&error); -} - -static int query_name_list(Manager *m) { - DBusMessage *message = NULL; - DBusPendingCall *pending = NULL; + r = set_ensure_allocated(&m->private_buses, trivial_hash_func, trivial_compare_func); + if (r < 0) { + log_oom(); + return 0; + } - /* Asks for the currently installed bus names */ + r = sd_bus_new(&bus); + if (r < 0) { + log_warning("Failed to allocate new private connection bus: %s", strerror(-r)); + return 0; + } - if (!(message = dbus_message_new_method_call( - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "ListNames"))) - goto oom; + r = sd_bus_set_fd(bus, nfd, nfd); + if (r < 0) { + log_warning("Failed to set fd on new connection bus: %s", strerror(-r)); + return 0; + } - if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1)) - goto oom; + nfd = -1; - if (!dbus_pending_call_set_notify(pending, query_name_list_pending_cb, m, NULL)) - goto oom; + r = bus_check_peercred(bus); + if (r < 0) { + log_warning("Incoming private connection from unprivileged client, refusing: %s", strerror(-r)); + return 0; + } - dbus_message_unref(message); - dbus_pending_call_unref(pending); + assert_se(sd_id128_randomize(&id) >= 0); - /* We simple ask for the list and don't wait for it. Sooner or - * later we'll get it. */ + r = sd_bus_set_server(bus, 1, id); + if (r < 0) { + log_warning("Failed to enable server support for new connection bus: %s", strerror(-r)); + return 0; + } - return 0; + r = sd_bus_start(bus); + if (r < 0) { + log_warning("Failed to start new connection bus: %s", strerror(-r)); + return 0; + } -oom: - if (pending) { - dbus_pending_call_cancel(pending); - dbus_pending_call_unref(pending); + r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL); + if (r < 0) { + log_warning("Failed to attach new connection bus to event loop: %s", strerror(-r)); + return 0; } - if (message) - dbus_message_unref(message); + if (m->running_as == SYSTEMD_SYSTEM) { + /* When we run as system instance we get the Released + * signal via a direct connection */ + + r = sd_bus_add_match( + bus, + "type='signal'," + "interface='org.freedesktop.systemd1.Agent'," + "member='Released'," + "path='/org/freedesktop/systemd1/agent'", + signal_agent_released, m); + + if (r < 0) { + log_warning("Failed to register Released match on new connection bus: %s", strerror(-r)); + return 0; + } + } - return -ENOMEM; -} + r = bus_setup_disconnected_match(m, bus); + if (r < 0) + return 0; -static int bus_setup_loop(Manager *m, DBusConnection *bus) { - assert(m); - assert(bus); + r = bus_setup_api_vtables(m, bus); + if (r < 0) { + log_warning("Failed to set up API vtables on new connection bus: %s", strerror(-r)); + return 0; + } - dbus_connection_set_exit_on_disconnect(bus, FALSE); + r = set_put(m->private_buses, bus); + if (r < 0) { + log_warning("Failed to add new conenction bus to set: %s", strerror(-r)); + return 0; + } - if (!dbus_connection_set_watch_functions(bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) || - !dbus_connection_set_timeout_functions(bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL)) - return log_oom(); + bus = NULL; - if (set_put(m->bus_connections_for_dispatch, bus) < 0) - return log_oom(); + log_debug("Accepted new private connection."); - dbus_connection_set_dispatch_status_function(bus, bus_dispatch_status, m, NULL); return 0; } -static dbus_bool_t allow_only_same_user(DBusConnection *connection, unsigned long uid, void *data) { - return uid == 0 || uid == geteuid(); -} - -static void bus_new_connection( - DBusServer *server, - DBusConnection *new_connection, - void *data) { - - Manager *m = data; +static int bus_list_names(Manager *m, sd_bus *bus) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char *name; + int r; assert(m); + assert(bus); - if (set_size(m->bus_connections) >= CONNECTIONS_MAX) { - log_error("Too many concurrent connections."); - return; + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "ListNames", + &error, &reply, + NULL); + if (r < 0) { + log_error("Failed to get initial list of names: %s", bus_error_message(&error, r)); + return r; } - dbus_connection_set_unix_user_function(new_connection, allow_only_same_user, NULL, NULL); - - if (bus_setup_loop(m, new_connection) < 0) - return; + r = sd_bus_message_enter_container(reply, 'a', "s"); + if (r < 0) + return bus_log_parse_error(r); - if (!dbus_connection_register_object_path(new_connection, "/org/freedesktop/systemd1", &bus_manager_vtable, m) || - !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) || - !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) || - !dbus_connection_add_filter(new_connection, private_bus_message_filter, m, NULL)) { - log_oom(); - return; - } + /* This is a bit hacky, we say the owner of the name is the + * name itself, because we don't want the extra traffic to + * figure out the real owner. */ + while ((r = sd_bus_message_read(reply, "s", &name)) > 0) + manager_dispatch_bus_name_owner_changed(m, name, NULL, name); + if (r < 0) + return bus_log_parse_error(r); - log_debug("Accepted connection on private bus."); + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); - dbus_connection_ref(new_connection); + return 0; } -static int init_registered_system_bus(Manager *m) { - char *id = NULL; +static int bus_setup_api(Manager *m, sd_bus *bus) { + int r; - if (!dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL)) - return log_oom(); + assert(m); + assert(bus); - if (m->running_as != SYSTEMD_SYSTEM) { - DBusError error; + r = bus_setup_api_vtables(m, bus); + if (r < 0) + return r; - dbus_error_init(&error); + r = sd_bus_add_match( + bus, + "type='signal'," + "sender='org.freedesktop.DBus'," + "path='/org/freedesktop/DBus'," + "interface='org.freedesktop.DBus'," + "member='NameOwnerChanged'", + signal_name_owner_changed, m); + if (r < 0) + log_warning("Failed to subscribe to NameOwnerChanged signal: %s", strerror(-r)); + + r = sd_bus_add_match( + bus, + "type='signal'," + "sender='org.freedesktop.DBus'," + "path='/org/freedesktop/DBus'," + "interface='org.freedesktop.systemd1.Activator'," + "member='ActivationRequest'", + signal_activation_request, m); + if (r < 0) + log_warning("Failed to subscribe to activation signal: %s", strerror(-r)); - dbus_bus_add_match(m->system_bus, - "type='signal'," - "interface='org.freedesktop.systemd1.Agent'," - "member='Released'," - "path='/org/freedesktop/systemd1/agent'", - &error); + /* Allow replacing of our name, to ease implementation of + * reexecution, where we keep the old connection open until + * after the new connection is set up and the name installed + * to allow clients to synchronously wait for reexecution to + * finish */ + r = sd_bus_request_name(bus,"org.freedesktop.systemd1", SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING); + if (r < 0) { + log_error("Failed to register name: %s", strerror(-r)); + return r; + } - if (dbus_error_is_set(&error)) { - log_error("Failed to register match: %s", bus_error_message(&error)); - dbus_error_free(&error); - return -1; - } + if (r != SD_BUS_NAME_PRIMARY_OWNER) { + log_error("Failed to acquire name."); + return -EEXIST; } - log_debug("Successfully connected to system D-Bus bus %s as %s", - strnull((id = dbus_connection_get_server_id(m->system_bus))), - strnull(dbus_bus_get_unique_name(m->system_bus))); - dbus_free(id); + bus_list_names(m, bus); + log_debug("Successfully connected to API bus."); return 0; } -static int init_registered_api_bus(Manager *m) { +static int bus_init_api(Manager *m) { + _cleanup_bus_unref_ sd_bus *bus = NULL; int r; - if (!dbus_connection_register_object_path(m->api_bus, "/org/freedesktop/systemd1", &bus_manager_vtable, m) || - !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) || - !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) || - !dbus_connection_add_filter(m->api_bus, api_bus_message_filter, m, NULL)) - return log_oom(); - - /* Get NameOwnerChange messages */ - dbus_bus_add_match(m->api_bus, - "type='signal'," - "sender='"DBUS_SERVICE_DBUS"'," - "interface='"DBUS_INTERFACE_DBUS"'," - "member='NameOwnerChanged'," - "path='"DBUS_PATH_DBUS"'", - NULL); - - /* Get activation requests */ - dbus_bus_add_match(m->api_bus, - "type='signal'," - "sender='"DBUS_SERVICE_DBUS"'," - "interface='org.freedesktop.systemd1.Activator'," - "member='ActivationRequest'," - "path='"DBUS_PATH_DBUS"'", - NULL); - - r = request_name(m); - if (r < 0) - return r; - - r = query_name_list(m); - if (r < 0) - return r; - - if (m->running_as == SYSTEMD_USER) { - char *id = NULL; - - log_debug("Successfully connected to API D-Bus bus %s as %s", - strnull((id = dbus_connection_get_server_id(m->api_bus))), - strnull(dbus_bus_get_unique_name(m->api_bus))); - dbus_free(id); - } else - log_debug("Successfully initialized API on the system bus"); + if (m->api_bus) + return 0; - return 0; -} + /* The API and system bus is the same if we are running in system mode */ + if (m->running_as == SYSTEMD_SYSTEM && m->system_bus) + bus = sd_bus_ref(m->system_bus); + else { + if (m->running_as == SYSTEMD_SYSTEM) + r = sd_bus_open_system(&bus); + else + r = sd_bus_open_user(&bus); -static void bus_register_cb(DBusPendingCall *pending, void *userdata) { - Manager *m = userdata; - DBusConnection **conn; - DBusMessage *reply; - DBusError error; - const char *name; - int r = 0; - - dbus_error_init(&error); - - conn = dbus_pending_call_get_data(pending, m->conn_data_slot); - assert(conn == &m->system_bus || conn == &m->api_bus); - - reply = dbus_pending_call_steal_reply(pending); - - switch (dbus_message_get_type(reply)) { - case DBUS_MESSAGE_TYPE_ERROR: - assert_se(dbus_set_error_from_message(&error, reply)); - log_warning("Failed to register to bus: %s", bus_error_message(&error)); - r = -1; - break; - case DBUS_MESSAGE_TYPE_METHOD_RETURN: - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse Hello reply: %s", bus_error_message(&error)); - r = -1; - break; + if (r < 0) { + log_debug("Failed to connect to API bus, retrying later..."); + return 0; } - log_debug("Received name %s in reply to Hello", name); - if (!dbus_bus_set_unique_name(*conn, name)) { - log_error("Failed to set unique name"); - r = -1; - break; + r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL); + if (r < 0) { + log_error("Failed to attach API bus to event loop: %s", strerror(-r)); + return 0; } - if (conn == &m->system_bus) { - r = init_registered_system_bus(m); - if (r == 0 && m->running_as == SYSTEMD_SYSTEM) - r = init_registered_api_bus(m); - } else - r = init_registered_api_bus(m); - - break; - default: - assert_not_reached("Invalid reply message"); + r = bus_setup_disconnected_match(m, bus); + if (r < 0) + return 0; } - dbus_message_unref(reply); - dbus_error_free(&error); - + r = bus_setup_api(m, bus); if (r < 0) { - if (conn == &m->system_bus) { - log_debug("Failed setting up the system bus"); - bus_done_system(m); - } else { - log_debug("Failed setting up the API bus"); - bus_done_api(m); - } + log_error("Failed to set up API bus: %s", strerror(-r)); + return 0; } -} - -static int manager_bus_async_register(Manager *m, DBusConnection **conn) { - DBusMessage *message = NULL; - DBusPendingCall *pending = NULL; - - message = dbus_message_new_method_call(DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "Hello"); - if (!message) - goto oom; - if (!dbus_connection_send_with_reply(*conn, message, &pending, -1)) - goto oom; - - if (!dbus_pending_call_set_data(pending, m->conn_data_slot, conn, NULL)) - goto oom; - - if (!dbus_pending_call_set_notify(pending, bus_register_cb, m, NULL)) - goto oom; - - dbus_message_unref(message); - dbus_pending_call_unref(pending); + m->api_bus = bus; + bus = NULL; return 0; -oom: - if (pending) { - dbus_pending_call_cancel(pending); - dbus_pending_call_unref(pending); - } - - if (message) - dbus_message_unref(message); - - return -ENOMEM; } -static DBusConnection* manager_bus_connect_private(Manager *m, DBusBusType type) { - const char *address; - DBusConnection *connection; - DBusError error; - - switch (type) { - case DBUS_BUS_SYSTEM: - address = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS"); - if (!address || !address[0]) - address = DBUS_SYSTEM_BUS_DEFAULT_ADDRESS; - break; - case DBUS_BUS_SESSION: - address = secure_getenv("DBUS_SESSION_BUS_ADDRESS"); - if (!address || !address[0]) - address = DBUS_SESSION_BUS_DEFAULT_ADDRESS; - break; - default: - assert_not_reached("Invalid bus type"); - } +static int bus_setup_system(Manager *m, sd_bus *bus) { + int r; - dbus_error_init(&error); + assert(m); + assert(bus); - connection = dbus_connection_open_private(address, &error); - if (!connection) { - log_warning("Failed to open private bus connection: %s", bus_error_message(&error)); - goto fail; - } + if (m->running_as == SYSTEMD_SYSTEM) + return 0; + + /* If we are a user instance we get the Released message via + * the system bus */ + r = sd_bus_add_match( + bus, + "type='signal'," + "interface='org.freedesktop.systemd1.Agent'," + "member='Released'," + "path='/org/freedesktop/systemd1/agent'", + signal_agent_released, m); - return connection; + if (r < 0) + log_warning("Failed to register Released match on system bus: %s", strerror(-r)); -fail: - dbus_error_free(&error); - return NULL; + log_debug("Successfully connected to system bus."); + return 0; } static int bus_init_system(Manager *m) { + _cleanup_bus_unref_ sd_bus *bus = NULL; int r; if (m->system_bus) return 0; - m->system_bus = manager_bus_connect_private(m, DBUS_BUS_SYSTEM); - if (!m->system_bus) { - log_debug("Failed to connect to system D-Bus, retrying later"); - r = 0; - goto fail; + /* The API and system bus is the same if we are running in system mode */ + if (m->running_as == SYSTEMD_SYSTEM && m->api_bus) { + m->system_bus = sd_bus_ref(m->api_bus); + return 0; } - r = bus_setup_loop(m, m->system_bus); - if (r < 0) - goto fail; + r = sd_bus_open_system(&bus); + if (r < 0) { + log_debug("Failed to connect to system bus, retrying later..."); + return 0; + } - r = manager_bus_async_register(m, &m->system_bus); + r = bus_setup_disconnected_match(m, bus); if (r < 0) - goto fail; - - return 0; -fail: - bus_done_system(m); - - return r; -} - -static int bus_init_api(Manager *m) { - int r; - - if (m->api_bus) return 0; - if (m->running_as == SYSTEMD_SYSTEM) { - m->api_bus = m->system_bus; - /* In this mode there is no distinct connection to the API bus, - * the API is published on the system bus. - * bus_register_cb() is aware of that and will init the API - * when the system bus gets registered. - * No need to setup anything here. */ + r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL); + if (r < 0) { + log_error("Failed to attach system bus to event loop: %s", strerror(-r)); return 0; } - m->api_bus = manager_bus_connect_private(m, DBUS_BUS_SESSION); - if (!m->api_bus) { - log_debug("Failed to connect to API D-Bus, retrying later"); - r = 0; - goto fail; + r = bus_setup_system(m, bus); + if (r < 0) { + log_error("Fauiled to set up system bus: %s", strerror(-r)); + return 0; } - r = bus_setup_loop(m, m->api_bus); - if (r < 0) - goto fail; - - r = manager_bus_async_register(m, &m->api_bus); - if (r < 0) - goto fail; + m->system_bus = bus; + bus = NULL; return 0; -fail: - bus_done_api(m); - - return r; } static int bus_init_private(Manager *m) { - DBusError error; - int r; - static const char *const external_only[] = { - "EXTERNAL", - NULL + _cleanup_close_ int fd = -1; + union sockaddr_union sa = { + .un.sun_family = AF_UNIX }; + sd_event_source *s; + socklen_t salen; + int r; assert(m); - dbus_error_init(&error); - - if (m->private_bus) + if (m->private_listen_fd >= 0) return 0; if (m->running_as == SYSTEMD_SYSTEM) { @@ -1069,90 +885,72 @@ static int bus_init_private(Manager *m) { if (getpid() != 1) return 0; - unlink("/run/systemd/private"); - m->private_bus = dbus_server_listen("unix:path=/run/systemd/private", &error); + strcpy(sa.un.sun_path, "/run/systemd/private"); + salen = offsetof(union sockaddr_union, un.sun_path) + sizeof("/run/systemd/private") - 1; } else { + size_t left = sizeof(sa.un.sun_path); + char *p = sa.un.sun_path; const char *e; - char *p; - char *escaped; e = secure_getenv("XDG_RUNTIME_DIR"); - if (!e) - return 0; - - if (asprintf(&p, "%s/systemd/private", e) < 0) { - r = log_oom(); - goto fail; + if (!e) { + log_error("Failed to determine XDG_RUNTIME_DIR"); + return -EHOSTDOWN; } - mkdir_parents_label(p, 0755); - unlink(p); - free(p); + left = strpcpy(&p, left, e); + left = strpcpy(&p, left, "/systemd/private"); - escaped = dbus_address_escape_value(e); - if (!escaped) { - r = log_oom(); - goto fail; - } - if (asprintf(&p, "unix:path=%s/systemd/private", escaped) < 0) { - dbus_free(escaped); - r = log_oom(); - goto fail; - } - dbus_free(escaped); + salen = sizeof(sa.un) - left; + + mkdir_parents_label(sa.un.sun_path, 0755); + } + + unlink(sa.un.sun_path); - m->private_bus = dbus_server_listen(p, &error); - free(p); + fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (fd < 0) { + log_error("Failed to allocate private socket: %m"); + return -errno; } - if (!m->private_bus) { - log_error("Failed to create private D-Bus server: %s", bus_error_message(&error)); - r = -EIO; - goto fail; + r = bind(fd, &sa.sa, salen); + if (r < 0) { + log_error("Failed to bind private socket: %m"); + return -errno; } - if (!dbus_server_set_auth_mechanisms(m->private_bus, (const char**) external_only) || - !dbus_server_set_watch_functions(m->private_bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) || - !dbus_server_set_timeout_functions(m->private_bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL)) { - r = log_oom(); - goto fail; + r = listen(fd, SOMAXCONN); + if (r < 0) { + log_error("Failed to make private socket listening: %m"); + return -errno; } - dbus_server_set_new_connection_function(m->private_bus, bus_new_connection, m, NULL); + r = sd_event_add_io(m->event, fd, EPOLLIN, bus_on_connection, m, &s); + if (r < 0) { + log_error("Failed to allocate event source: %s", strerror(-r)); + return r; + } + + m->private_listen_fd = fd; + m->private_listen_event_source = s; + fd = -1; log_debug("Successfully created private D-Bus server."); return 0; - -fail: - bus_done_private(m); - dbus_error_free(&error); - - return r; } int bus_init(Manager *m, bool try_bus_connect) { int r; - if (set_ensure_allocated(&m->bus_connections, trivial_hash_func, trivial_compare_func) < 0 || - set_ensure_allocated(&m->bus_connections_for_dispatch, trivial_hash_func, trivial_compare_func) < 0) - return log_oom(); - - if (m->name_data_slot < 0) - if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot)) - return log_oom(); - - if (m->conn_data_slot < 0) - if (!dbus_pending_call_allocate_data_slot(&m->conn_data_slot)) - return log_oom(); - - if (m->subscribed_data_slot < 0) - if (!dbus_connection_allocate_data_slot(&m->subscribed_data_slot)) - return log_oom(); - if (try_bus_connect) { - if ((r = bus_init_system(m)) < 0 || - (r = bus_init_api(m)) < 0) + r = bus_init_system(m); + if (r < 0) + return r; + + r = bus_init_api(m); + if (r < 0) return r; } @@ -1163,415 +961,113 @@ int bus_init(Manager *m, bool try_bus_connect) { return 0; } -static void shutdown_connection(Manager *m, DBusConnection *c) { - Job *j; +static void destroy_bus(Manager *m, sd_bus **bus) { Iterator i; + Job *j; - HASHMAP_FOREACH(j, m->jobs, i) { - JobBusClient *cl, *nextcl; - LIST_FOREACH_SAFE(client, cl, nextcl, j->bus_client_list) { - if (cl->bus == c) { - LIST_REMOVE(client, j->bus_client_list, cl); - free(cl); - } - } - } - - set_remove(m->bus_connections, c); - set_remove(m->bus_connections_for_dispatch, c); - set_free_free(BUS_CONNECTION_SUBSCRIBED(m, c)); - - if (m->queued_message_connection == c) { - m->queued_message_connection = NULL; - - if (m->queued_message) { - dbus_message_unref(m->queued_message); - m->queued_message = NULL; - } - } - - dbus_connection_set_dispatch_status_function(c, NULL, NULL, NULL); - /* system manager cannot afford to block on DBus */ - if (m->running_as != SYSTEMD_SYSTEM) - dbus_connection_flush(c); - dbus_connection_close(c); - dbus_connection_unref(c); -} + assert(m); + assert(bus); -static void bus_done_api(Manager *m) { - if (!m->api_bus) + if (!*bus) return; - if (m->running_as == SYSTEMD_USER) - shutdown_connection(m, m->api_bus); + /* Get rid of tracked clients on this bus */ + bus_client_untrack_bus(m->subscribed, *bus); + HASHMAP_FOREACH(j, m->jobs, i) + bus_client_untrack_bus(j->subscribed, *bus); - m->api_bus = NULL; + /* Get rid of queued message on this bus */ + if (m->queued_message_bus == *bus) { + m->queued_message_bus = sd_bus_unref(m->queued_message_bus); - if (m->queued_message) { - dbus_message_unref(m->queued_message); - m->queued_message = NULL; + if (m->queued_message) + m->queued_message = sd_bus_message_unref(m->queued_message); } -} -static void bus_done_system(Manager *m) { - if (!m->system_bus) - return; - - if (m->running_as == SYSTEMD_SYSTEM) - bus_done_api(m); - - shutdown_connection(m, m->system_bus); - m->system_bus = NULL; -} - -static void bus_done_private(Manager *m) { - if (!m->private_bus) - return; + /* Possibly flush unwritten data, but only if we are + * unprivileged, since we don't want to sync here */ + if (m->running_as != SYSTEMD_SYSTEM) + sd_bus_flush(*bus); - dbus_server_disconnect(m->private_bus); - dbus_server_unref(m->private_bus); - m->private_bus = NULL; + /* And destroy the object */ + sd_bus_close(*bus); + *bus = sd_bus_unref(*bus); } void bus_done(Manager *m) { - DBusConnection *c; - - bus_done_api(m); - bus_done_system(m); - bus_done_private(m); - - while ((c = set_steal_first(m->bus_connections))) - shutdown_connection(m, c); - - while ((c = set_steal_first(m->bus_connections_for_dispatch))) - shutdown_connection(m, c); - - set_free(m->bus_connections); - set_free(m->bus_connections_for_dispatch); - - if (m->name_data_slot >= 0) - dbus_pending_call_free_data_slot(&m->name_data_slot); - - if (m->conn_data_slot >= 0) - dbus_pending_call_free_data_slot(&m->conn_data_slot); - - if (m->subscribed_data_slot >= 0) - dbus_connection_free_data_slot(&m->subscribed_data_slot); -} - -static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) { - Manager *m = userdata; - DBusMessage *reply; - DBusError error; - const char *name; - - dbus_error_init(&error); - - assert_se(name = BUS_PENDING_CALL_NAME(m, pending)); - assert_se(reply = dbus_pending_call_steal_reply(pending)); - - switch (dbus_message_get_type(reply)) { - - case DBUS_MESSAGE_TYPE_ERROR: - - assert_se(dbus_set_error_from_message(&error, reply)); - log_warning("GetConnectionUnixProcessID() failed: %s", bus_error_message(&error)); - break; - - case DBUS_MESSAGE_TYPE_METHOD_RETURN: { - uint32_t r; - - if (!dbus_message_get_args(reply, - &error, - DBUS_TYPE_UINT32, &r, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse GetConnectionUnixProcessID() reply: %s", bus_error_message(&error)); - break; - } - - manager_dispatch_bus_query_pid_done(m, name, (pid_t) r); - break; - } - - default: - assert_not_reached("Invalid reply message"); - } - - dbus_message_unref(reply); - dbus_error_free(&error); -} - -int bus_query_pid(Manager *m, const char *name) { - DBusMessage *message = NULL; - DBusPendingCall *pending = NULL; - char *n = NULL; + sd_bus *b; assert(m); - assert(name); - - if (!(message = dbus_message_new_method_call( - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetConnectionUnixProcessID"))) - goto oom; - - if (!(dbus_message_append_args( - message, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID))) - goto oom; - - if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1)) - goto oom; - - if (!(n = strdup(name))) - goto oom; - - if (!dbus_pending_call_set_data(pending, m->name_data_slot, n, free)) - goto oom; - - n = NULL; - - if (!dbus_pending_call_set_notify(pending, query_pid_pending_cb, m, NULL)) - goto oom; - dbus_message_unref(message); - dbus_pending_call_unref(pending); + if (m->api_bus) + destroy_bus(m, &m->api_bus); + if (m->system_bus) + destroy_bus(m, &m->system_bus); + while ((b = set_steal_first(m->private_buses))) + destroy_bus(m, &b); - return 0; + set_free(m->private_buses); + set_free(m->subscribed); -oom: - free(n); + if (m->private_listen_event_source) + m->private_listen_event_source = sd_event_source_unref(m->private_listen_event_source); - if (pending) { - dbus_pending_call_cancel(pending); - dbus_pending_call_unref(pending); + if (m->private_listen_fd >= 0) { + close_nointr_nofail(m->private_listen_fd); + m->private_listen_fd = -1; } - - if (message) - dbus_message_unref(message); - - return -ENOMEM; -} - -int bus_broadcast(Manager *m, DBusMessage *message) { - bool oom = false; - Iterator i; - DBusConnection *c; - - assert(m); - assert(message); - - SET_FOREACH(c, m->bus_connections_for_dispatch, i) - if (c != m->system_bus || m->running_as == SYSTEMD_SYSTEM) - oom = !dbus_connection_send(c, message, NULL); - - SET_FOREACH(c, m->bus_connections, i) - if (c != m->system_bus || m->running_as == SYSTEMD_SYSTEM) - oom = !dbus_connection_send(c, message, NULL); - - return oom ? -ENOMEM : 0; -} - -bool bus_has_subscriber(Manager *m) { - Iterator i; - DBusConnection *c; - - assert(m); - - /* If we are reloading then we might not have deserialized the - subscribers yet, hence let's assume that there are some */ - - if (m->n_reloading > 0) - return true; - - SET_FOREACH(c, m->bus_connections_for_dispatch, i) - if (bus_connection_has_subscriber(m, c)) - return true; - - SET_FOREACH(c, m->bus_connections, i) - if (bus_connection_has_subscriber(m, c)) - return true; - - return false; -} - -bool bus_connection_has_subscriber(Manager *m, DBusConnection *c) { - assert(m); - assert(c); - - return !set_isempty(BUS_CONNECTION_SUBSCRIBED(m, c)); } int bus_fdset_add_all(Manager *m, FDSet *fds) { Iterator i; - DBusConnection *c; + sd_bus *b; + int fd; assert(m); assert(fds); /* When we are about to reexecute we add all D-Bus fds to the * set to pass over to the newly executed systemd. They won't - * be used there however, except that they are closed at the + * be used there however, except thatt they are closed at the * very end of deserialization, those making it possible for * clients to synchronously wait for systemd to reexec by * simply waiting for disconnection */ - SET_FOREACH(c, m->bus_connections_for_dispatch, i) { - int fd; - - if (dbus_connection_get_unix_fd(c, &fd)) { + if (m->api_bus) { + fd = sd_bus_get_fd(m->api_bus); + if (fd >= 0) { fd = fdset_put_dup(fds, fd); - if (fd < 0) return fd; } } - SET_FOREACH(c, m->bus_connections, i) { - int fd; - - if (dbus_connection_get_unix_fd(c, &fd)) { + SET_FOREACH(b, m->private_buses, i) { + fd = sd_bus_get_fd(b); + if (fd >= 0) { fd = fdset_put_dup(fds, fd); - if (fd < 0) return fd; } } - return 0; -} - -void bus_broadcast_finished( - Manager *m, - usec_t firmware_usec, - usec_t loader_usec, - usec_t kernel_usec, - usec_t initrd_usec, - usec_t userspace_usec, - usec_t total_usec) { - - _cleanup_dbus_message_unref_ DBusMessage *message = NULL; - - assert(m); - - message = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished"); - if (!message) { - log_oom(); - return; - } - - assert_cc(sizeof(usec_t) == sizeof(uint64_t)); - if (!dbus_message_append_args(message, - DBUS_TYPE_UINT64, &firmware_usec, - DBUS_TYPE_UINT64, &loader_usec, - DBUS_TYPE_UINT64, &kernel_usec, - DBUS_TYPE_UINT64, &initrd_usec, - DBUS_TYPE_UINT64, &userspace_usec, - DBUS_TYPE_UINT64, &total_usec, - DBUS_TYPE_INVALID)) { - log_oom(); - return; - } - - - if (bus_broadcast(m, message) < 0) { - log_oom(); - return; - } -} - -void bus_broadcast_reloading(Manager *m, bool active) { - - _cleanup_dbus_message_unref_ DBusMessage *message = NULL; - dbus_bool_t b = active; - - assert(m); - - message = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "Reloading"); - if (!message) { - log_oom(); - return; - } - - assert_cc(sizeof(usec_t) == sizeof(uint64_t)); - if (!dbus_message_append_args(message, - DBUS_TYPE_BOOLEAN, &b, - DBUS_TYPE_INVALID)) { - log_oom(); - return; - } - - - if (bus_broadcast(m, message) < 0) { - log_oom(); - return; - } -} - -Set *bus_acquire_subscribed(Manager *m, DBusConnection *c) { - Set *s; - - assert(m); - assert(c); - - s = BUS_CONNECTION_SUBSCRIBED(m, c); - if (s) - return s; - - s = set_new(string_hash_func, string_compare_func); - if (!s) - return NULL; - - if (!dbus_connection_set_data(c, m->subscribed_data_slot, s, NULL)) { - set_free(s); - return NULL; - } + /* We don't offer any APIs on the system bus (well, unless it + * is the same as the API bus) hence we don't bother with it + * here */ - return s; + return 0; } void bus_serialize(Manager *m, FILE *f) { - char *client; - Iterator i; - Set *s; - assert(m); assert(f); - if (!m->api_bus) - return; - - s = BUS_CONNECTION_SUBSCRIBED(m, m->api_bus); - SET_FOREACH(client, s, i) - fprintf(f, "subscribed=%s\n", client); + bus_client_track_serialize(m, f, m->subscribed); } int bus_deserialize_item(Manager *m, const char *line) { - const char *e; - char *b; - Set *s; - assert(m); assert(line); - if (!m->api_bus) - return 0; - - e = startswith(line, "subscribed="); - if (!e) - return 0; - - s = bus_acquire_subscribed(m, m->api_bus); - if (!s) - return -ENOMEM; - - b = strdup(e); - if (!b) - return -ENOMEM; - - set_consume(s, b); - - return 1; + return bus_client_track_deserialize_item(m, &m->subscribed, line); } diff --git a/src/core/dbus.h b/src/core/dbus.h index 6500cd7455..a3bef47d5d 100644 --- a/src/core/dbus.h +++ b/src/core/dbus.h @@ -21,36 +21,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> - #include "manager.h" +int bus_send_queued_message(Manager *m); + int bus_init(Manager *m, bool try_bus_connect); void bus_done(Manager *m); -unsigned bus_dispatch(Manager *m); - -void bus_watch_event(Manager *m, Watch *w, int events); -void bus_timeout_event(Manager *m, Watch *w, int events); - -int bus_query_pid(Manager *m, const char *name); - -int bus_broadcast(Manager *m, DBusMessage *message); - -bool bus_has_subscriber(Manager *m); -bool bus_connection_has_subscriber(Manager *m, DBusConnection *c); - int bus_fdset_add_all(Manager *m, FDSet *fds); -void bus_broadcast_finished(Manager *m, usec_t firmware_usec, usec_t loader_usec, usec_t kernel_usec, usec_t initrd_usec, usec_t userspace_usec, usec_t total_usec); -void bus_broadcast_reloading(Manager *m, bool active); - -Set *bus_acquire_subscribed(Manager *m, DBusConnection *c); - void bus_serialize(Manager *m, FILE *f); int bus_deserialize_item(Manager *m, const char *line); - -#define BUS_CONNECTION_SUBSCRIBED(m, c) dbus_connection_get_data((c), (m)->subscribed_data_slot) -#define BUS_PENDING_CALL_NAME(m, p) dbus_pending_call_get_data((p), (m)->name_data_slot) - -extern const char * const bus_interface_table[]; diff --git a/src/core/device.c b/src/core/device.c index 6fc4c95ea0..91e37e09db 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -31,12 +31,15 @@ #include "dbus-device.h" #include "def.h" #include "path-util.h" +#include "udev-util.h" static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = { [DEVICE_DEAD] = UNIT_INACTIVE, [DEVICE_PLUGGED] = UNIT_ACTIVE }; +static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); + static void device_unset_sysfs(Device *d) { Device *first; @@ -137,7 +140,7 @@ _pure_ static const char *device_sub_state_to_string(Unit *u) { } static int device_add_escaped_name(Unit *u, const char *dn) { - char *e; + _cleanup_free_ char *e = NULL; int r; assert(u); @@ -149,8 +152,6 @@ static int device_add_escaped_name(Unit *u, const char *dn) { return -ENOMEM; r = unit_add_name(u, e); - free(e); - if (r < 0 && r != -EEXIST) return r; @@ -158,7 +159,7 @@ static int device_add_escaped_name(Unit *u, const char *dn) { } static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) { - char *e; + _cleanup_free_ char *e = NULL; Unit *u; assert(m); @@ -171,8 +172,6 @@ static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) { return -ENOMEM; u = manager_get_unit(m, e); - free(e); - if (u) { *_u = u; return 1; @@ -222,16 +221,15 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p if (!DEVICE(u)->sysfs) { Device *first; - if (!(DEVICE(u)->sysfs = strdup(sysfs))) { + DEVICE(u)->sysfs = strdup(sysfs); + if (!DEVICE(u)->sysfs) { r = -ENOMEM; goto fail; } - if (!m->devices_by_sysfs) - if (!(m->devices_by_sysfs = hashmap_new(string_hash_func, string_compare_func))) { - r = -ENOMEM; - goto fail; - } + r = hashmap_ensure_allocated(&m->devices_by_sysfs, string_hash_func, string_compare_func); + if (r < 0) + goto fail; first = hashmap_get(m->devices_by_sysfs, sysfs); LIST_PREPEND(same_sysfs, first, DEVICE(u)); @@ -242,15 +240,12 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p } if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) || - (model = udev_device_get_property_value(dev, "ID_MODEL"))) { + (model = udev_device_get_property_value(dev, "ID_MODEL"))) r = unit_set_description(u, model); - if (r < 0) - goto fail; - } else { + else r = unit_set_description(u, path); - if (r < 0) - goto fail; - } + if (r < 0) + goto fail; if (main) { /* The additional systemd udev properties we only @@ -278,7 +273,7 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p } } - wants = udev_device_get_property_value(dev, "SYSTEMD_WANTS"); + wants = udev_device_get_property_value(dev, m->running_as == SYSTEMD_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS"); if (wants) { char *state, *w; size_t l; @@ -324,7 +319,8 @@ static int device_process_new_device(Manager *m, struct udev_device *dev, bool u assert(m); - if (!(sysfs = udev_device_get_syspath(dev))) + sysfs = udev_device_get_syspath(dev); + if (!sysfs) return -ENOMEM; /* Add the main unit named after the sysfs path */ @@ -384,7 +380,8 @@ static int device_process_path(Manager *m, const char *path, bool update_state) assert(m); assert(path); - if (!(dev = udev_device_new_from_syspath(m->udev, path))) { + dev = udev_device_new_from_syspath(m->udev, path); + if (!dev) { log_warning("Failed to get udev device object from udev for path %s.", path); return -ENOMEM; } @@ -473,6 +470,8 @@ fail: static void device_shutdown(Manager *m) { assert(m); + m->udev_event_source = sd_event_source_unref(m->udev_event_source); + if (m->udev_monitor) { udev_monitor_unref(m->udev_monitor); m->udev_monitor = NULL; @@ -488,19 +487,19 @@ static void device_shutdown(Manager *m) { } static int device_enumerate(Manager *m) { - int r; - struct udev_enumerate *e = NULL; + _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; struct udev_list_entry *item = NULL, *first = NULL; + int r; assert(m); if (!m->udev) { - struct epoll_event ev; - - if (!(m->udev = udev_new())) + m->udev = udev_new(); + if (!m->udev) return -ENOMEM; - if (!(m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"))) { + m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); + if (!m->udev_monitor) { r = -ENOMEM; goto fail; } @@ -510,101 +509,88 @@ static int device_enumerate(Manager *m) { * during boot. */ udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024); - if (udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd") < 0) { - r = -ENOMEM; + r = udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd"); + if (r < 0) goto fail; - } - if (udev_monitor_enable_receiving(m->udev_monitor) < 0) { - r = -EIO; + r = udev_monitor_enable_receiving(m->udev_monitor); + if (r < 0) goto fail; - } - - m->udev_watch.type = WATCH_UDEV; - m->udev_watch.fd = udev_monitor_get_fd(m->udev_monitor); - - zero(ev); - ev.events = EPOLLIN; - ev.data.ptr = &m->udev_watch; - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_watch.fd, &ev) < 0) - return -errno; + r = sd_event_add_io(m->event, udev_monitor_get_fd(m->udev_monitor), EPOLLIN, device_dispatch_io, m, &m->udev_event_source); + if (r < 0) + goto fail; } - if (!(e = udev_enumerate_new(m->udev))) { + e = udev_enumerate_new(m->udev); + if (!e) { r = -ENOMEM; goto fail; } - if (udev_enumerate_add_match_tag(e, "systemd") < 0) { - r = -EIO; + + r = udev_enumerate_add_match_tag(e, "systemd"); + if (r < 0) goto fail; - } - if (udev_enumerate_scan_devices(e) < 0) { - r = -EIO; + r = udev_enumerate_scan_devices(e); + if (r < 0) goto fail; - } first = udev_enumerate_get_list_entry(e); udev_list_entry_foreach(item, first) device_process_path(m, udev_list_entry_get_name(item), false); - udev_enumerate_unref(e); return 0; fail: - if (e) - udev_enumerate_unref(e); - device_shutdown(m); return r; } -void device_fd_event(Manager *m, int events) { - struct udev_device *dev; - int r; +static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + _cleanup_udev_device_unref_ struct udev_device *dev = NULL; const char *action, *ready; + Manager *m = userdata; + int r; assert(m); - if (events != EPOLLIN) { + if (revents != EPOLLIN) { static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5); if (!ratelimit_test(&limit)) log_error("Failed to get udev event: %m"); - if (!(events & EPOLLIN)) - return; + if (!(revents & EPOLLIN)) + return 0; } - if (!(dev = udev_monitor_receive_device(m->udev_monitor))) { - /* - * libudev might filter-out devices which pass the bloom filter, - * so getting NULL here is not necessarily an error - */ - return; - } + /* + * libudev might filter-out devices which pass the bloom + * filter, so getting NULL here is not necessarily an error. + */ + dev = udev_monitor_receive_device(m->udev_monitor); + if (!dev) + return 0; - if (!(action = udev_device_get_action(dev))) { + action = udev_device_get_action(dev); + if (!action) { log_error("Failed to get udev action string."); - goto fail; + return 0; } ready = udev_device_get_property_value(dev, "SYSTEMD_READY"); if (streq(action, "remove") || (ready && parse_boolean(ready) == 0)) { - if ((r = device_process_removed_device(m, dev)) < 0) { + r = device_process_removed_device(m, dev); + if (r < 0) log_error("Failed to process udev device event: %s", strerror(-r)); - goto fail; - } } else { - if ((r = device_process_new_device(m, dev, true)) < 0) { + r = device_process_new_device(m, dev, true); + if (r < 0) log_error("Failed to process udev device event: %s", strerror(-r)); - goto fail; - } } -fail: - udev_device_unref(dev); + return 0; } static const char* const device_state_table[_DEVICE_STATE_MAX] = { @@ -624,9 +610,9 @@ const UnitVTable device_vtable = { .no_instances = true, .init = device_init, - - .load = unit_load_fragment_and_dropin_optional, .done = device_done, + .load = unit_load_fragment_and_dropin_optional, + .coldplug = device_coldplug, .dump = device_dump, @@ -635,8 +621,8 @@ const UnitVTable device_vtable = { .sub_state_to_string = device_sub_state_to_string, .bus_interface = "org.freedesktop.systemd1.Device", - .bus_message_handler = bus_device_message_handler, - .bus_invalidating_properties = bus_device_invalidating_properties, + .bus_changing_properties = bus_device_changing_properties, + .bus_vtable = bus_device_vtable, .following = device_following, .following_set = device_following_set, diff --git a/src/core/device.h b/src/core/device.h index 41e8de9703..bb7ae07834 100644 --- a/src/core/device.h +++ b/src/core/device.h @@ -50,7 +50,5 @@ struct Device { extern const UnitVTable device_vtable; -void device_fd_event(Manager *m, int events); - const char* device_state_to_string(DeviceState i) _const_; DeviceState device_state_from_string(const char *s) _pure_; diff --git a/src/core/job.c b/src/core/job.c index 0dd161c1c5..f053d57349 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -24,8 +24,8 @@ #include <sys/timerfd.h> #include <sys/epoll.h> -#include "systemd/sd-id128.h" -#include "systemd/sd-messages.h" +#include "sd-id128.h" +#include "sd-messages.h" #include "set.h" #include "unit.h" #include "macro.h" @@ -37,20 +37,7 @@ #include "special.h" #include "async.h" #include "virt.h" - -JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name) { - JobBusClient *cl; - size_t name_len; - - name_len = strlen(name); - cl = malloc0(sizeof(JobBusClient) + name_len + 1); - if (!cl) - return NULL; - - cl->bus = connection; - memcpy(cl->name, name, name_len + 1); - return cl; -} +#include "dbus-client-track.h" Job* job_new_raw(Unit *unit) { Job *j; @@ -66,7 +53,6 @@ Job* job_new_raw(Unit *unit) { j->manager = unit->manager; j->unit = unit; j->type = _JOB_TYPE_INVALID; - j->timer_watch.type = WATCH_INVALID; return j; } @@ -89,8 +75,6 @@ Job* job_new(Unit *unit, JobType type) { } void job_free(Job *j) { - JobBusClient *cl; - assert(j); assert(!j->installed); assert(!j->transaction_prev); @@ -104,19 +88,10 @@ void job_free(Job *j) { if (j->in_dbus_queue) LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j); - if (j->timer_watch.type != WATCH_INVALID) { - assert(j->timer_watch.type == WATCH_JOB_TIMER); - assert(j->timer_watch.data.job == j); - assert(j->timer_watch.fd >= 0); + sd_event_source_unref(j->timer_event_source); - assert_se(epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_DEL, j->timer_watch.fd, NULL) >= 0); - close_nointr_nofail(j->timer_watch.fd); - } + bus_client_track_free(j->subscribed); - while ((cl = j->bus_client_list)) { - LIST_REMOVE(client, j->bus_client_list, cl); - free(cl); - } free(j); } @@ -859,48 +834,32 @@ finish: return 0; } -int job_start_timer(Job *j) { - struct itimerspec its = {}; - struct epoll_event ev = { - .data.ptr = &j->timer_watch, - .events = EPOLLIN, - }; - int fd, r; - - if (j->unit->job_timeout <= 0 || - j->timer_watch.type == WATCH_JOB_TIMER) - return 0; +static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *userdata) { + Job *j = userdata; - assert(j->timer_watch.type == WATCH_INVALID); - - if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) { - r = -errno; - goto fail; - } + assert(j); + assert(s == j->timer_event_source); - timespec_store(&its.it_value, j->unit->job_timeout); + log_warning_unit(j->unit->id, "Job %s/%s timed out.", + j->unit->id, job_type_to_string(j->type)); - if (timerfd_settime(fd, 0, &its, NULL) < 0) { - r = -errno; - goto fail; - } + job_finish_and_invalidate(j, JOB_TIMEOUT, true); + return 0; +} - if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { - r = -errno; - goto fail; - } +int job_start_timer(Job *j) { + int r; - j->timer_watch.type = WATCH_JOB_TIMER; - j->timer_watch.fd = fd; - j->timer_watch.data.job = j; + if (j->unit->job_timeout <= 0 || j->timer_event_source) + return 0; - return 0; + j->begin_usec = now(CLOCK_MONOTONIC); -fail: - if (fd >= 0) - close_nointr_nofail(fd); + r = sd_event_add_monotonic(j->manager->event, j->begin_usec + j->unit->job_timeout, 0, job_dispatch_timer, j, &j->timer_event_source); + if (r < 0) + return r; - return r; + return 0; } void job_add_to_run_queue(Job *j) { @@ -940,15 +899,6 @@ char *job_dbus_path(Job *j) { return p; } -void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) { - assert(j); - assert(w == &j->timer_watch); - - log_warning_unit(j->unit->id, "Job %s/%s timed out.", - j->unit->id, job_type_to_string(j->type)); - job_finish_and_invalidate(j, JOB_TIMEOUT, true); -} - int job_serialize(Job *j, FILE *f, FDSet *fds) { fprintf(f, "job-id=%u\n", j->id); fprintf(f, "job-type=%s\n", job_type_to_string(j->type)); @@ -957,16 +907,11 @@ int job_serialize(Job *j, FILE *f, FDSet *fds) { fprintf(f, "job-irreversible=%s\n", yes_no(j->irreversible)); fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal)); fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order)); - /* Cannot save bus clients. Just note the fact that we're losing - * them. job_send_message() will fallback to broadcasting. */ - fprintf(f, "job-forgot-bus-clients=%s\n", - yes_no(j->forgot_bus_clients || j->bus_client_list)); - if (j->timer_watch.type == WATCH_JOB_TIMER) { - int copy = fdset_put_dup(fds, j->timer_watch.fd); - if (copy < 0) - return copy; - fprintf(f, "job-timer-watch-fd=%d\n", copy); - } + + if (j->begin_usec > 0) + fprintf(f, "job-begin=%llu", (unsigned long long) j->begin_usec); + + bus_client_track_serialize(j->manager, f, j->subscribed); /* End marker */ fputc('\n', f); @@ -974,6 +919,8 @@ int job_serialize(Job *j, FILE *f, FDSet *fds) { } int job_deserialize(Job *j, FILE *f, FDSet *fds) { + assert(j); + for (;;) { char line[LINE_MAX], *l, *v; size_t k; @@ -1000,81 +947,101 @@ int job_deserialize(Job *j, FILE *f, FDSet *fds) { v = l+k; if (streq(l, "job-id")) { + if (safe_atou32(v, &j->id) < 0) log_debug("Failed to parse job id value %s", v); + } else if (streq(l, "job-type")) { - JobType t = job_type_from_string(v); + JobType t; + + t = job_type_from_string(v); if (t < 0) log_debug("Failed to parse job type %s", v); else if (t >= _JOB_TYPE_MAX_IN_TRANSACTION) log_debug("Cannot deserialize job of type %s", v); else j->type = t; + } else if (streq(l, "job-state")) { - JobState s = job_state_from_string(v); + JobState s; + + s = job_state_from_string(v); if (s < 0) log_debug("Failed to parse job state %s", v); else j->state = s; + } else if (streq(l, "job-override")) { - int b = parse_boolean(v); + int b; + + b = parse_boolean(v); if (b < 0) log_debug("Failed to parse job override flag %s", v); else j->override = j->override || b; + } else if (streq(l, "job-irreversible")) { - int b = parse_boolean(v); + int b; + + b = parse_boolean(v); if (b < 0) log_debug("Failed to parse job irreversible flag %s", v); else j->irreversible = j->irreversible || b; + } else if (streq(l, "job-sent-dbus-new-signal")) { - int b = parse_boolean(v); + int b; + + b = parse_boolean(v); if (b < 0) log_debug("Failed to parse job sent_dbus_new_signal flag %s", v); else j->sent_dbus_new_signal = j->sent_dbus_new_signal || b; + } else if (streq(l, "job-ignore-order")) { - int b = parse_boolean(v); + int b; + + b = parse_boolean(v); if (b < 0) log_debug("Failed to parse job ignore_order flag %s", v); else j->ignore_order = j->ignore_order || b; - } else if (streq(l, "job-forgot-bus-clients")) { - int b = parse_boolean(v); - if (b < 0) - log_debug("Failed to parse job forgot_bus_clients flag %s", v); + + } else if (streq(l, "job-begin")) { + unsigned long long ull; + + if (sscanf(v, "%llu", &ull) != 1) + log_debug("Failed to parse job-begin value %s", v); else - j->forgot_bus_clients = j->forgot_bus_clients || b; - } else if (streq(l, "job-timer-watch-fd")) { - int fd; - if (safe_atoi(v, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) - log_debug("Failed to parse job-timer-watch-fd value %s", v); - else { - if (j->timer_watch.type == WATCH_JOB_TIMER) - close_nointr_nofail(j->timer_watch.fd); - - j->timer_watch.type = WATCH_JOB_TIMER; - j->timer_watch.fd = fdset_remove(fds, fd); - j->timer_watch.data.job = j; - } + j->begin_usec = ull; + + } else { + char t[strlen(l) + 1 + strlen(v) + 1]; + + strcpy(stpcpy(stpcpy(t, l), "="), v); + + if (bus_client_track_deserialize_item(j->manager, &j->subscribed, t) == 0) + log_debug("Unknown deserialization key '%s'", l); } } } int job_coldplug(Job *j) { - struct epoll_event ev = { - .data.ptr = &j->timer_watch, - .events = EPOLLIN, - }; + int r; + + assert(j); - if (j->timer_watch.type != WATCH_JOB_TIMER) + if (j->begin_usec <= 0) return 0; - if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, j->timer_watch.fd, &ev) < 0) - return -errno; + if (j->timer_event_source) + j->timer_event_source = sd_event_source_unref(j->timer_event_source); - return 0; + r = sd_event_add_monotonic(j->manager->event, j->begin_usec + j->unit->job_timeout, 0, job_dispatch_timer, j, &j->timer_event_source); + if (r < 0) + log_debug("Failed to restart timeout for job: %s", strerror(-r)); + + return r; } void job_shutdown_magic(Job *j) { diff --git a/src/core/job.h b/src/core/job.h index be9d278b0c..60bb87d75a 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -27,7 +27,6 @@ typedef struct Job Job; typedef struct JobDependency JobDependency; -typedef struct JobBusClient JobBusClient; typedef enum JobType JobType; typedef enum JobState JobState; typedef enum JobMode JobMode; @@ -102,6 +101,7 @@ enum JobResult { _JOB_RESULT_INVALID = -1 }; +#include "sd-event.h" #include "manager.h" #include "unit.h" #include "hashmap.h" @@ -120,13 +120,6 @@ struct JobDependency { bool conflicts; }; -struct JobBusClient { - LIST_FIELDS(JobBusClient, client); - /* Note that this bus object is not ref counted here. */ - DBusConnection *bus; - char name[0]; -}; - struct Job { Manager *manager; Unit *unit; @@ -147,10 +140,11 @@ struct Job { JobType type; JobState state; - Watch timer_watch; + sd_event_source *timer_event_source; + usec_t begin_usec; /* There can be more than one client, because of job merging. */ - LIST_HEAD(JobBusClient, bus_client_list); + Set *subscribed; JobResult result; @@ -165,8 +159,6 @@ struct Job { bool irreversible:1; }; -JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name); - Job* job_new(Unit *unit, JobType type); Job* job_new_raw(Unit *unit); void job_free(Job *job); @@ -210,7 +202,6 @@ void job_add_to_run_queue(Job *j); void job_add_to_dbus_queue(Job *j); int job_start_timer(Job *j); -void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w); int job_run_and_invalidate(Job *j); int job_finish_and_invalidate(Job *j, JobResult result, bool recursive); diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index b64fdc9dcb..22dc536ee1 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -210,7 +210,7 @@ Socket.Broadcast, config_parse_bool, 0, Socket.PassCredentials, config_parse_bool, 0, offsetof(Socket, pass_cred) Socket.PassSecurity, config_parse_bool, 0, offsetof(Socket, pass_sec) Socket.TCPCongestion, config_parse_string, 0, offsetof(Socket, tcp_congestion) -Socket.ReusePort, config_parse_bool, 0, offsetof(Socket, reuseport) +Socket.ReusePort, config_parse_bool, 0, offsetof(Socket, reuse_port) Socket.MessageQueueMaxMessages, config_parse_long, 0, offsetof(Socket, mq_maxmsg) Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize) Socket.Service, config_parse_socket_service, 0, 0 diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 72c46371e4..de612f05cb 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -45,12 +45,13 @@ #include "missing.h" #include "unit-name.h" #include "unit-printf.h" -#include "dbus-common.h" #include "utf8.h" #include "path-util.h" #include "syscall-list.h" #include "env-util.h" #include "cgroup.h" +#include "bus-util.h" +#include "bus-error.h" #ifndef HAVE_SYSV_COMPAT int config_parse_warn_compat(const char *unit, @@ -1288,6 +1289,7 @@ int config_parse_path_spec(const char *unit, if (!s) return log_oom(); + s->unit = UNIT(p); s->path = path_kill_slashes(k); k = NULL; s->type = b; @@ -1308,9 +1310,9 @@ int config_parse_socket_service(const char *unit, void *data, void *userdata) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; Socket *s = data; int r; - DBusError error; Unit *x; _cleanup_free_ char *p = NULL; @@ -1319,25 +1321,18 @@ int config_parse_socket_service(const char *unit, assert(rvalue); assert(data); - dbus_error_init(&error); - r = unit_name_printf(UNIT(s), rvalue, &p); if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue); if (!endswith(p ?: rvalue, ".service")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Unit must be of type service, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue); return 0; } r = manager_load_unit(UNIT(s)->manager, p ?: rvalue, NULL, &error, &x); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Failed to load unit %s, ignoring: %s", - rvalue, bus_error(&error, r)); - dbus_error_free(&error); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r)); return 0; } diff --git a/src/core/main.c b/src/core/main.c index c89c12343e..f342cdd289 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -19,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus/dbus.h> - #include <stdio.h> #include <errno.h> #include <string.h> @@ -34,13 +32,15 @@ #include <sys/prctl.h> #include <sys/mount.h> +#include "sd-daemon.h" +#include "sd-messages.h" +#include "sd-bus.h" #include "manager.h" #include "log.h" #include "load-fragment.h" #include "fdset.h" #include "special.h" #include "conf-parser.h" -#include "dbus-common.h" #include "missing.h" #include "label.h" #include "build.h" @@ -54,20 +54,21 @@ #include "killall.h" #include "env-util.h" #include "hwclock.h" -#include "sd-daemon.h" -#include "sd-messages.h" +#include "fileio.h" +#include "dbus-manager.h" +#include "bus-error.h" +#include "bus-util.h" #include "mount-setup.h" #include "loopback-setup.h" -#ifdef HAVE_KMOD -#include "kmod-setup.h" -#endif #include "hostname-setup.h" #include "machine-id-setup.h" #include "selinux-setup.h" #include "ima-setup.h" -#include "fileio.h" #include "smack-setup.h" +#ifdef HAVE_KMOD +#include "kmod-setup.h" +#endif static enum { ACTION_RUN, @@ -1039,7 +1040,7 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching /* Make sure nothing is really destructed when we shut down */ m->n_reloading ++; - bus_broadcast_reloading(m, true); + bus_manager_send_reloading(m, true); fds = fdset_new(); if (!fds) { @@ -1442,9 +1443,6 @@ int main(int argc, char *argv[]) { /* Move out of the way, so that we won't block unmounts */ assert_se(chdir("/") == 0); - /* Make sure D-Bus doesn't fiddle with the SIGPIPE handlers */ - dbus_connection_set_change_sigpipe(FALSE); - /* Reset the console, but only if this is really init and we * are freshly booted */ if (arg_running_as == SYSTEMD_SYSTEM && arg_action == ACTION_RUN) @@ -1551,7 +1549,7 @@ int main(int argc, char *argv[]) { manager_set_default_rlimits(m, arg_default_rlimit); if (arg_default_environment) - manager_environment_add(m, arg_default_environment); + manager_environment_add(m, NULL, arg_default_environment); manager_set_show_status(m, arg_show_status); @@ -1575,19 +1573,16 @@ int main(int argc, char *argv[]) { } if (queue_default_job) { - DBusError error; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; Unit *target = NULL; Job *default_unit_job; - dbus_error_init(&error); - log_debug("Activating default unit: %s", arg_default_unit); r = manager_load_unit(m, arg_default_unit, NULL, &error, &target); - if (r < 0) { - log_error("Failed to load default target: %s", bus_error(&error, r)); - dbus_error_free(&error); - } else if (target->load_state == UNIT_ERROR || target->load_state == UNIT_NOT_FOUND) + if (r < 0) + log_error("Failed to load default target: %s", bus_error_message(&error, r)); + else if (target->load_state == UNIT_ERROR || target->load_state == UNIT_NOT_FOUND) log_error("Failed to load default target: %s", strerror(-target->load_error)); else if (target->load_state == UNIT_MASKED) log_error("Default target masked."); @@ -1597,8 +1592,7 @@ int main(int argc, char *argv[]) { r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &error, &target); if (r < 0) { - log_error("Failed to load rescue target: %s", bus_error(&error, r)); - dbus_error_free(&error); + log_error("Failed to load rescue target: %s", bus_error_message(&error, r)); goto finish; } else if (target->load_state == UNIT_ERROR || target->load_state == UNIT_NOT_FOUND) { log_error("Failed to load rescue target: %s", strerror(-target->load_error)); @@ -1618,18 +1612,15 @@ int main(int argc, char *argv[]) { r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, false, &error, &default_unit_job); if (r == -EPERM) { - log_debug("Default target could not be isolated, starting instead: %s", bus_error(&error, r)); - dbus_error_free(&error); + log_debug("Default target could not be isolated, starting instead: %s", bus_error_message(&error, r)); r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &error, &default_unit_job); if (r < 0) { - log_error("Failed to start default target: %s", bus_error(&error, r)); - dbus_error_free(&error); + log_error("Failed to start default target: %s", bus_error_message(&error, r)); goto finish; } } else if (r < 0) { - log_error("Failed to isolate default target: %s", bus_error(&error, r)); - dbus_error_free(&error); + log_error("Failed to isolate default target: %s", bus_error_message(&error, r)); goto finish; } @@ -1725,7 +1716,6 @@ finish: free(arg_default_unit); free_join_controllers(); - dbus_shutdown(); label_finish(); if (reexecute) { diff --git a/src/core/manager.c b/src/core/manager.c index c99a022cd5..86de0e3fbf 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -42,9 +42,9 @@ #include <libaudit.h> #endif -#include "systemd/sd-daemon.h" -#include "systemd/sd-id128.h" -#include "systemd/sd-messages.h" +#include "sd-daemon.h" +#include "sd-id128.h" +#include "sd-messages.h" #include "manager.h" #include "transaction.h" @@ -58,12 +58,9 @@ #include "locale-setup.h" #include "mount-setup.h" #include "unit-name.h" -#include "dbus-unit.h" -#include "dbus-job.h" #include "missing.h" #include "path-lookup.h" #include "special.h" -#include "bus-errors.h" #include "exit-status.h" #include "virt.h" #include "watchdog.h" @@ -72,6 +69,13 @@ #include "audit-fd.h" #include "boot-timestamps.h" #include "env-util.h" +#include "bus-errors.h" +#include "bus-error.h" +#include "bus-util.h" +#include "dbus.h" +#include "dbus-unit.h" +#include "dbus-job.h" +#include "dbus-manager.h" /* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */ #define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC) @@ -86,6 +90,12 @@ #define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) +static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); +static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); +static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); +static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); +static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata); + static int manager_setup_notify(Manager *m) { union { struct sockaddr sa; @@ -93,15 +103,10 @@ static int manager_setup_notify(Manager *m) { } sa = { .sa.sa_family = AF_UNIX, }; - struct epoll_event ev = { - .events = EPOLLIN, - .data.ptr = &m->notify_watch, - }; int one = 1, r; - m->notify_watch.type = WATCH_NOTIFY; - m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (m->notify_watch.fd < 0) { + m->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (m->notify_fd < 0) { log_error("Failed to allocate notification socket: %m"); return -errno; } @@ -110,25 +115,23 @@ static int manager_setup_notify(Manager *m) { snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET "/%llu", random_ull()); else strncpy(sa.un.sun_path, NOTIFY_SOCKET, sizeof(sa.un.sun_path)); - sa.un.sun_path[0] = 0; - r = bind(m->notify_watch.fd, &sa.sa, - offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)); + r = bind(m->notify_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)); if (r < 0) { log_error("bind() failed: %m"); return -errno; } - r = setsockopt(m->notify_watch.fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); + r = setsockopt(m->notify_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); if (r < 0) { log_error("SO_PASSCRED failed: %m"); return -errno; } - r = epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev); + r = sd_event_add_io(m->event, m->notify_fd, EPOLLIN, manager_dispatch_notify_fd, m, &m->notify_event_source); if (r < 0) { - log_error("Failed to add notification socket fd to epoll: %m"); + log_error("Failed to allocate notify event source: %s", strerror(-r)); return -errno; } @@ -142,75 +145,17 @@ static int manager_setup_notify(Manager *m) { return 0; } -static int manager_jobs_in_progress_mod_timer(Manager *m) { - struct itimerspec its = { - .it_value.tv_sec = JOBS_IN_PROGRESS_WAIT_SEC, - .it_interval.tv_sec = JOBS_IN_PROGRESS_PERIOD_SEC, - }; - - if (m->jobs_in_progress_watch.type != WATCH_JOBS_IN_PROGRESS) - return 0; - - if (timerfd_settime(m->jobs_in_progress_watch.fd, 0, &its, NULL) < 0) - return -errno; - - return 0; -} - static int manager_watch_jobs_in_progress(Manager *m) { - struct epoll_event ev = { - .events = EPOLLIN, - .data.ptr = &m->jobs_in_progress_watch, - }; - int r; + assert(m); - if (m->jobs_in_progress_watch.type != WATCH_INVALID) + if (m->jobs_in_progress_event_source) return 0; - m->jobs_in_progress_watch.type = WATCH_JOBS_IN_PROGRESS; - m->jobs_in_progress_watch.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC); - if (m->jobs_in_progress_watch.fd < 0) { - log_error("Failed to create timerfd: %m"); - r = -errno; - goto err; - } - - r = manager_jobs_in_progress_mod_timer(m); - if (r < 0) { - log_error("Failed to set up timer for jobs progress watch: %s", strerror(-r)); - goto err; - } - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->jobs_in_progress_watch.fd, &ev) < 0) { - log_error("Failed to add jobs progress timer fd to epoll: %m"); - r = -errno; - goto err; - } - - log_debug("Set up jobs progress timerfd."); - - return 0; - -err: - if (m->jobs_in_progress_watch.fd >= 0) - close_nointr_nofail(m->jobs_in_progress_watch.fd); - watch_init(&m->jobs_in_progress_watch); - return r; + return sd_event_add_monotonic(m->event, JOBS_IN_PROGRESS_WAIT_SEC, 0, manager_dispatch_jobs_in_progress, m, &m->jobs_in_progress_event_source); } -static void manager_unwatch_jobs_in_progress(Manager *m) { - if (m->jobs_in_progress_watch.type != WATCH_JOBS_IN_PROGRESS) - return; - - assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, m->jobs_in_progress_watch.fd, NULL) >= 0); - close_nointr_nofail(m->jobs_in_progress_watch.fd); - watch_init(&m->jobs_in_progress_watch); - m->jobs_in_progress_iteration = 0; - - log_debug("Closed jobs progress timerfd."); -} +#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED_ON)-1) + sizeof(ANSI_HIGHLIGHT_RED_ON)-1 + 2*(sizeof(ANSI_HIGHLIGHT_OFF)-1)) -#define CYLON_BUFFER_EXTRA (2*strlen(ANSI_RED_ON) + strlen(ANSI_HIGHLIGHT_RED_ON) + 2*strlen(ANSI_HIGHLIGHT_OFF)) static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) { char *p = buffer; @@ -241,13 +186,15 @@ static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned po } static void manager_print_jobs_in_progress(Manager *m) { + _cleanup_free_ char *job_of_n = NULL; Iterator i; Job *j; - char *job_of_n = NULL; unsigned counter = 0, print_nr; char cylon[6 + CYLON_BUFFER_EXTRA + 1]; unsigned cylon_pos; + assert(m); + print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs; HASHMAP_FOREACH(j, m->jobs, i) @@ -270,94 +217,69 @@ static void manager_print_jobs_in_progress(Manager *m) { manager_status_printf(m, true, cylon, "%sA %s job is running for %s", strempty(job_of_n), job_type_to_string(j->type), unit_description(j->unit)); - free(job_of_n); m->jobs_in_progress_iteration++; } static int manager_watch_idle_pipe(Manager *m) { - struct epoll_event ev = { - .events = EPOLLIN, - .data.ptr = &m->idle_pipe_watch, - }; int r; - if (m->idle_pipe_watch.type != WATCH_INVALID) + assert(m); + + if (m->idle_pipe_event_source) return 0; if (m->idle_pipe[2] < 0) return 0; - m->idle_pipe_watch.type = WATCH_IDLE_PIPE; - m->idle_pipe_watch.fd = m->idle_pipe[2]; - if (m->idle_pipe_watch.fd < 0) { - log_error("Failed to create timerfd: %m"); - r = -errno; - goto err; - } - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->idle_pipe_watch.fd, &ev) < 0) { - log_error("Failed to add idle_pipe fd to epoll: %m"); - r = -errno; - goto err; + r = sd_event_add_io(m->event, m->idle_pipe[2], EPOLLIN, manager_dispatch_idle_pipe_fd, m, &m->idle_pipe_event_source); + if (r < 0) { + log_error("Failed to watch idle pipe: %s", strerror(-r)); + return r; } - log_debug("Set up idle_pipe watch."); - return 0; - -err: - if (m->idle_pipe_watch.fd >= 0) - close_nointr_nofail(m->idle_pipe_watch.fd); - watch_init(&m->idle_pipe_watch); - return r; } -static void manager_unwatch_idle_pipe(Manager *m) { - if (m->idle_pipe_watch.type != WATCH_IDLE_PIPE) - return; - - assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, m->idle_pipe_watch.fd, NULL) >= 0); - watch_init(&m->idle_pipe_watch); +static void manager_close_idle_pipe(Manager *m) { + assert(m); - log_debug("Closed idle_pipe watch."); + close_pipe(m->idle_pipe); + close_pipe(m->idle_pipe + 2); } static int manager_setup_time_change(Manager *m) { - struct epoll_event ev = { - .events = EPOLLIN, - .data.ptr = &m->time_change_watch, - }; + int r; /* We only care for the cancellation event, hence we set the * timeout to the latest possible value. */ struct itimerspec its = { .it_value.tv_sec = TIME_T_MAX, }; - assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX)); - assert(m->time_change_watch.type == WATCH_INVALID); + assert(m); + assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX)); /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever * CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */ - m->time_change_watch.type = WATCH_TIME_CHANGE; - m->time_change_watch.fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC); - if (m->time_change_watch.fd < 0) { + m->time_change_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC); + if (m->time_change_fd < 0) { log_error("Failed to create timerfd: %m"); return -errno; } - if (timerfd_settime(m->time_change_watch.fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) { + if (timerfd_settime(m->time_change_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) { log_debug("Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m"); - close_nointr_nofail(m->time_change_watch.fd); - watch_init(&m->time_change_watch); + close_nointr_nofail(m->time_change_fd); + m->time_change_fd = -1; return 0; } - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->time_change_watch.fd, &ev) < 0) { - log_error("Failed to add timer change fd to epoll: %m"); - return -errno; + r = sd_event_add_io(m->event, m->time_change_fd, EPOLLIN, manager_dispatch_time_change_fd, m, &m->time_change_event_source); + if (r < 0) { + log_error("Failed to create time change event source: %s", strerror(-r)); + return r; } log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd."); @@ -366,7 +288,7 @@ static int manager_setup_time_change(Manager *m) { } static int enable_special_signals(Manager *m) { - int fd; + _cleanup_close_ int fd = -1; assert(m); @@ -385,23 +307,18 @@ static int enable_special_signals(Manager *m) { /* Enable that we get SIGWINCH on kbrequest */ if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0) log_warning("Failed to enable kbrequest handling: %s", strerror(errno)); - - close_nointr_nofail(fd); } return 0; } static int manager_setup_signals(Manager *m) { - sigset_t mask; - struct epoll_event ev = { - .events = EPOLLIN, - .data.ptr = &m->signal_watch, - }; struct sigaction sa = { .sa_handler = SIG_DFL, .sa_flags = SA_NOCLDSTOP|SA_RESTART, }; + sigset_t mask; + int r; assert(m); @@ -442,13 +359,13 @@ static int manager_setup_signals(Manager *m) { -1); assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); - m->signal_watch.type = WATCH_SIGNAL; - m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); - if (m->signal_watch.fd < 0) + m->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); + if (m->signal_fd < 0) return -errno; - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0) - return -errno; + r = sd_event_add_io(m->event, m->signal_fd, EPOLLIN, manager_dispatch_signal_fd, m, &m->signal_event_source); + if (r < 0) + return r; if (m->running_as == SYSTEMD_SYSTEM) return enable_special_signals(m); @@ -502,44 +419,39 @@ int manager_new(SystemdRunningAs running_as, bool reexecuting, Manager **_m) { #endif m->running_as = running_as; - m->name_data_slot = m->conn_data_slot = m->subscribed_data_slot = -1; m->exit_code = _MANAGER_EXIT_CODE_INVALID; - m->pin_cgroupfs_fd = -1; - m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1; - watch_init(&m->signal_watch); - watch_init(&m->mount_watch); - watch_init(&m->swap_watch); - watch_init(&m->udev_watch); - watch_init(&m->time_change_watch); - watch_init(&m->jobs_in_progress_watch); + m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1; - m->epoll_fd = m->dev_autofs_fd = -1; + m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = -1; m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */ r = manager_default_environment(m); if (r < 0) goto fail; - if (!(m->units = hashmap_new(string_hash_func, string_compare_func))) + r = hashmap_ensure_allocated(&m->units, string_hash_func, string_compare_func); + if (r < 0) goto fail; - if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func))) + r = hashmap_ensure_allocated(&m->jobs, trivial_hash_func, trivial_compare_func); + if (r < 0) goto fail; - if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func))) + r = hashmap_ensure_allocated(&m->cgroup_unit, string_hash_func, string_compare_func); + if (r < 0) goto fail; - m->cgroup_unit = hashmap_new(string_hash_func, string_compare_func); - if (!m->cgroup_unit) + r = hashmap_ensure_allocated(&m->watch_pids, trivial_hash_func, trivial_compare_func); + if (r < 0) goto fail; - m->watch_bus = hashmap_new(string_hash_func, string_compare_func); - if (!m->watch_bus) + r = hashmap_ensure_allocated(&m->watch_bus, string_hash_func, string_compare_func); + if (r < 0) goto fail; - m->epoll_fd = epoll_create1(EPOLL_CLOEXEC); - if (m->epoll_fd < 0) + r = sd_event_default(&m->event); + if (r < 0) goto fail; r = manager_setup_signals(m); @@ -718,11 +630,6 @@ static void manager_clear_jobs_and_units(Manager *m) { m->n_running_jobs = 0; } -static void close_idle_pipe(Manager *m) { - close_pipe(m->idle_pipe); - close_pipe(m->idle_pipe + 2); -} - void manager_free(Manager *m) { UnitType c; int i; @@ -748,16 +655,22 @@ void manager_free(Manager *m) { hashmap_free(m->watch_pids); hashmap_free(m->watch_bus); - if (m->epoll_fd >= 0) - close_nointr_nofail(m->epoll_fd); - if (m->signal_watch.fd >= 0) - close_nointr_nofail(m->signal_watch.fd); - if (m->notify_watch.fd >= 0) - close_nointr_nofail(m->notify_watch.fd); - if (m->time_change_watch.fd >= 0) - close_nointr_nofail(m->time_change_watch.fd); - if (m->jobs_in_progress_watch.fd >= 0) - close_nointr_nofail(m->jobs_in_progress_watch.fd); + sd_event_source_unref(m->signal_event_source); + sd_event_source_unref(m->notify_event_source); + sd_event_source_unref(m->time_change_event_source); + sd_event_source_unref(m->jobs_in_progress_event_source); + sd_event_source_unref(m->idle_pipe_event_source); + + if (m->signal_fd >= 0) + close_nointr_nofail(m->signal_fd); + if (m->notify_fd >= 0) + close_nointr_nofail(m->notify_fd); + if (m->time_change_fd >= 0) + close_nointr_nofail(m->time_change_fd); + + manager_close_idle_pipe(m); + + sd_event_unref(m->event); free(m->notify_socket); @@ -767,8 +680,6 @@ void manager_free(Manager *m) { hashmap_free(m->cgroup_unit); set_free_free(m->unit_path_cache); - close_idle_pipe(m); - free(m->switch_root); free(m->switch_root_init); @@ -929,9 +840,9 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { m->n_reloading ++; /* First, enumerate what we can from all config files */ - dual_timestamp_get(&m->unitsload_start_timestamp); + dual_timestamp_get(&m->units_load_start_timestamp); r = manager_enumerate(m); - dual_timestamp_get(&m->unitsload_finish_timestamp); + dual_timestamp_get(&m->units_load_finish_timestamp); /* Second, deserialize if there is something to deserialize */ if (serialization) { @@ -968,7 +879,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { return r; } -int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, DBusError *e, Job **_ret) { +int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, sd_bus_error *e, Job **_ret) { int r; Transaction *tr; @@ -978,12 +889,12 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove assert(mode < _JOB_MODE_MAX); if (mode == JOB_ISOLATE && type != JOB_START) { - dbus_set_error(e, BUS_ERROR_INVALID_JOB_MODE, "Isolate is only valid for start."); + sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start."); return -EINVAL; } if (mode == JOB_ISOLATE && !unit->allow_isolate) { - dbus_set_error(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated."); + sd_bus_error_setf(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated."); return -EPERM; } @@ -1029,7 +940,7 @@ tr_abort: return r; } -int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, DBusError *e, Job **_ret) { +int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, sd_bus_error *e, Job **_ret) { Unit *unit; int r; @@ -1088,7 +999,7 @@ int manager_load_unit_prepare( Manager *m, const char *name, const char *path, - DBusError *e, + sd_bus_error *e, Unit **_ret) { Unit *ret; @@ -1101,20 +1012,16 @@ int manager_load_unit_prepare( /* This will prepare the unit for loading, but not actually * load anything from disk. */ - if (path && !is_path(path)) { - dbus_set_error(e, BUS_ERROR_INVALID_PATH, "Path %s is not absolute.", path); - return -EINVAL; - } + if (path && !is_path(path)) + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path); if (!name) name = path_get_file_name(path); t = unit_name_to_type(name); - if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, false)) { - dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name); - return -EINVAL; - } + if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, false)) + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name); ret = manager_get_unit(m, name); if (ret) { @@ -1154,7 +1061,7 @@ int manager_load_unit( Manager *m, const char *name, const char *path, - DBusError *e, + sd_bus_error *e, Unit **_ret) { int r; @@ -1269,16 +1176,26 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) { if (m->send_reloading_done) { m->send_reloading_done = false; - bus_broadcast_reloading(m, false); + bus_manager_send_reloading(m, false); } + if (m->queued_message) + bus_send_queued_message(m); + return n; } -static int manager_process_notify_fd(Manager *m) { +static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; ssize_t n; assert(m); + assert(m->notify_fd == fd); + + if (revents != EPOLLIN) { + log_warning("Got unexpected poll event for notify fd."); + return 0; + } for (;;) { char buf[4096]; @@ -1302,7 +1219,7 @@ static int manager_process_notify_fd(Manager *m) { Unit *u; _cleanup_strv_free_ char **tags = NULL; - n = recvmsg(m->notify_watch.fd, &msghdr, MSG_DONTWAIT); + n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT); if (n <= 0) { if (n == 0) return -EIO; @@ -1383,7 +1300,7 @@ static int manager_dispatch_sigchld(Manager *m) { * have queued for us. This ensures that the process * still exists in /proc so that we can figure out * which cgroup and hence unit it belongs to. */ - r = manager_process_notify_fd(m); + r = manager_dispatch_notify_fd(m->notify_event_source, m->notify_fd, EPOLLIN, m); if (r < 0) return r; @@ -1425,32 +1342,34 @@ static int manager_dispatch_sigchld(Manager *m) { } static int manager_start_target(Manager *m, const char *name, JobMode mode) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; int r; - DBusError error; - - dbus_error_init(&error); log_debug_unit(name, "Activating special unit %s", name); r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL); if (r < 0) - log_error_unit(name, - "Failed to enqueue %s job: %s", name, bus_error(&error, r)); - - dbus_error_free(&error); + log_error_unit(name, "Failed to enqueue %s job: %s", name, bus_error_message(&error, r)); return r; } -static int manager_process_signal_fd(Manager *m) { +static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; ssize_t n; struct signalfd_siginfo sfsi; bool sigchld = false; assert(m); + assert(m->signal_fd == fd); + + if (revents != EPOLLIN) { + log_warning("Got unexpected events from signal file descriptor."); + return 0; + } for (;;) { - n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi)); + n = read(m->signal_fd, &sfsi, sizeof(sfsi)); if (n != sizeof(sfsi)) { if (n >= 0) @@ -1537,11 +1456,12 @@ static int manager_process_signal_fd(Manager *m) { } case SIGUSR2: { - FILE *f; - char *dump = NULL; + _cleanup_free_ char *dump = NULL; + _cleanup_fclose_ FILE *f = NULL; size_t size; - if (!(f = open_memstream(&dump, &size))) { + f = open_memstream(&dump, &size); + if (!f) { log_warning("Failed to allocate memory stream."); break; } @@ -1550,16 +1470,11 @@ static int manager_process_signal_fd(Manager *m) { manager_dump_jobs(m, f, "\t"); if (ferror(f)) { - fclose(f); - free(dump); log_warning("Failed to write status stream"); break; } - fclose(f); log_dump(LOG_INFO, dump); - free(dump); - break; } @@ -1666,141 +1581,54 @@ static int manager_process_signal_fd(Manager *m) { return 0; } -static int process_event(Manager *m, struct epoll_event *ev) { - int r; - Watch *w; +static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; + Iterator i; + Unit *u; assert(m); - assert(ev); - - assert_se(w = ev->data.ptr); - - if (w->type == WATCH_INVALID) - return 0; - - switch (w->type) { - - case WATCH_SIGNAL: - - /* An incoming signal? */ - if (ev->events != EPOLLIN) - return -EINVAL; - - if ((r = manager_process_signal_fd(m)) < 0) - return r; - - break; - - case WATCH_NOTIFY: - - /* An incoming daemon notification event? */ - if (ev->events != EPOLLIN) - return -EINVAL; - - if ((r = manager_process_notify_fd(m)) < 0) - return r; - - break; - - case WATCH_FD: - - /* Some fd event, to be dispatched to the units */ - UNIT_VTABLE(w->data.unit)->fd_event(w->data.unit, w->fd, ev->events, w); - break; - - case WATCH_UNIT_TIMER: - case WATCH_JOB_TIMER: { - uint64_t v; - ssize_t k; - - /* Some timer event, to be dispatched to the units */ - k = read(w->fd, &v, sizeof(v)); - if (k != sizeof(v)) { + assert(m->time_change_fd == fd); - if (k < 0 && (errno == EINTR || errno == EAGAIN)) - break; - - log_error("Failed to read timer event counter: %s", k < 0 ? strerror(-k) : "Short read"); - return k < 0 ? -errno : -EIO; - } + log_struct(LOG_INFO, + MESSAGE_ID(SD_MESSAGE_TIME_CHANGE), + "MESSAGE=Time has been changed", + NULL); - if (w->type == WATCH_UNIT_TIMER) - UNIT_VTABLE(w->data.unit)->timer_event(w->data.unit, v, w); - else - job_timer_event(w->data.job, v, w); - break; - } + /* Restart the watch */ + m->time_change_event_source = sd_event_source_unref(m->time_change_event_source); - case WATCH_MOUNT: - /* Some mount table change, intended for the mount subsystem */ - mount_fd_event(m, ev->events); - break; + close_nointr_nofail(m->time_change_fd); + m->time_change_fd = -1; - case WATCH_SWAP: - /* Some swap table change, intended for the swap subsystem */ - swap_fd_event(m, ev->events); - break; + manager_setup_time_change(m); - case WATCH_UDEV: - /* Some notification from udev, intended for the device subsystem */ - device_fd_event(m, ev->events); - break; - - case WATCH_DBUS_WATCH: - bus_watch_event(m, w, ev->events); - break; + HASHMAP_FOREACH(u, m->units, i) + if (UNIT_VTABLE(u)->time_change) + UNIT_VTABLE(u)->time_change(u); - case WATCH_DBUS_TIMEOUT: - bus_timeout_event(m, w, ev->events); - break; + return 0; +} - case WATCH_TIME_CHANGE: { - Unit *u; - Iterator i; - - log_struct(LOG_INFO, - MESSAGE_ID(SD_MESSAGE_TIME_CHANGE), - "MESSAGE=Time has been changed", - NULL); - - /* Restart the watch */ - epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, m->time_change_watch.fd, - NULL); - close_nointr_nofail(m->time_change_watch.fd); - watch_init(&m->time_change_watch); - manager_setup_time_change(m); - - HASHMAP_FOREACH(u, m->units, i) { - if (UNIT_VTABLE(u)->time_change) - UNIT_VTABLE(u)->time_change(u); - } +static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; - break; - } + assert(m); + assert(m->idle_pipe[2] == fd); - case WATCH_JOBS_IN_PROGRESS: { - uint64_t v; + m->no_console_output = m->n_on_console > 0; - /* not interested in the data */ - read(w->fd, &v, sizeof(v)); + m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source); + manager_close_idle_pipe(m); - manager_print_jobs_in_progress(m); - break; - } - - case WATCH_IDLE_PIPE: { - m->no_console_output = m->n_on_console > 0; + return 0; +} - manager_unwatch_idle_pipe(m); - close_idle_pipe(m); - break; - } +static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata) { + Manager *m = userdata; - default: - log_error("event type=%i", w->type); - assert_not_reached("Unknown epoll event type."); - } + assert(m); + manager_print_jobs_in_progress(m); return 0; } @@ -1825,9 +1653,7 @@ int manager_loop(Manager *m) { return r; while (m->exit_code == MANAGER_RUNNING) { - struct epoll_event event; - int n; - int wait_msec = -1; + usec_t wait_usec; if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM) watchdog_ping(); @@ -1854,44 +1680,28 @@ int manager_loop(Manager *m) { if (manager_dispatch_run_queue(m) > 0) continue; - if (bus_dispatch(m) > 0) - continue; - if (manager_dispatch_dbus_queue(m) > 0) continue; - if (swap_dispatch_reload(m) > 0) - continue; - /* Sleep for half the watchdog time */ if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM) { - wait_msec = (int) (m->runtime_watchdog / 2 / USEC_PER_MSEC); - if (wait_msec <= 0) - wait_msec = 1; + wait_usec = m->runtime_watchdog / 2; + if (wait_usec <= 0) + wait_usec = 1; } else - wait_msec = -1; - - n = epoll_wait(m->epoll_fd, &event, 1, wait_msec); - if (n < 0) { + wait_usec = (usec_t) -1; - if (errno == EINTR) - continue; - - return -errno; - } else if (n == 0) - continue; - - assert(n == 1); - - r = process_event(m, &event); - if (r < 0) + r = sd_event_run(m->event, wait_usec); + if (r < 0) { + log_error("Failed to run event loop: %s", strerror(-r)); return r; + } } return m->exit_code; } -int manager_load_unit_from_dbus_path(Manager *m, const char *s, DBusError *e, Unit **_u) { +int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u) { _cleanup_free_ char *n = NULL; Unit *u; int r; @@ -1914,18 +1724,20 @@ int manager_load_unit_from_dbus_path(Manager *m, const char *s, DBusError *e, Un } int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) { - Job *j; + const char *p; unsigned id; + Job *j; int r; assert(m); assert(s); assert(_j); - if (!startswith(s, "/org/freedesktop/systemd1/job/")) + p = startswith(s, "/org/freedesktop/systemd1/job/"); + if (!p) return -EINVAL; - r = safe_atou(s + 30, &id); + r = safe_atou(p, &id); if (r < 0) return r; @@ -2060,29 +1872,13 @@ void manager_dispatch_bus_name_owner_changed( assert(m); assert(name); - if (!(u = hashmap_get(m->watch_bus, name))) + u = hashmap_get(m->watch_bus, name); + if (!u) return; UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner); } -void manager_dispatch_bus_query_pid_done( - Manager *m, - const char *name, - pid_t pid) { - - Unit *u; - - assert(m); - assert(name); - assert(pid >= 1); - - if (!(u = hashmap_get(m->watch_bus, name))) - return; - - UNIT_VTABLE(u)->bus_query_pid_done(u, name, pid); -} - int manager_open_serialization(Manager *m, FILE **_f) { char *path = NULL; int fd = -1; @@ -2140,13 +1936,19 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) { fprintf(f, "n-failed-jobs=%u\n", m->n_failed_jobs); dual_timestamp_serialize(f, "firmware-timestamp", &m->firmware_timestamp); - dual_timestamp_serialize(f, "kernel-timestamp", &m->kernel_timestamp); dual_timestamp_serialize(f, "loader-timestamp", &m->loader_timestamp); + dual_timestamp_serialize(f, "kernel-timestamp", &m->kernel_timestamp); dual_timestamp_serialize(f, "initrd-timestamp", &m->initrd_timestamp); if (!in_initrd()) { dual_timestamp_serialize(f, "userspace-timestamp", &m->userspace_timestamp); dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp); + dual_timestamp_serialize(f, "security-start-timestamp", &m->security_start_timestamp); + dual_timestamp_serialize(f, "security-finish-timestamp", &m->security_finish_timestamp); + dual_timestamp_serialize(f, "generators-start-timestamp", &m->generators_start_timestamp); + dual_timestamp_serialize(f, "generators-finish-timestamp", &m->generators_finish_timestamp); + dual_timestamp_serialize(f, "units-load-start-timestamp", &m->units_load_start_timestamp); + dual_timestamp_serialize(f, "units-load-finish-timestamp", &m->units_load_finish_timestamp); } if (!switching_root) { @@ -2229,6 +2031,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { log_debug("Failed to parse current job id value %s", l+15); else m->current_job_id = MAX(m->current_job_id, id); + } else if (startswith(l, "n-installed-jobs=")) { uint32_t n; @@ -2236,6 +2039,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { log_debug("Failed to parse installed jobs counter %s", l+17); else m->n_installed_jobs += n; + } else if (startswith(l, "n-failed-jobs=")) { uint32_t n; @@ -2243,6 +2047,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { log_debug("Failed to parse failed jobs counter %s", l+14); else m->n_failed_jobs += n; + } else if (startswith(l, "taint-usr=")) { int b; @@ -2250,6 +2055,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { log_debug("Failed to parse taint /usr flag %s", l+10); else m->taint_usr = m->taint_usr || b; + } else if (startswith(l, "firmware-timestamp=")) dual_timestamp_deserialize(l+19, &m->firmware_timestamp); else if (startswith(l, "loader-timestamp=")) @@ -2262,6 +2068,18 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { dual_timestamp_deserialize(l+20, &m->userspace_timestamp); else if (startswith(l, "finish-timestamp=")) dual_timestamp_deserialize(l+17, &m->finish_timestamp); + else if (startswith(l, "security-start-timestamp=")) + dual_timestamp_deserialize(l+25, &m->security_start_timestamp); + else if (startswith(l, "security-finish-timestamp=")) + dual_timestamp_deserialize(l+26, &m->security_finish_timestamp); + else if (startswith(l, "generators-start-timestamp=")) + dual_timestamp_deserialize(l+27, &m->generators_start_timestamp); + else if (startswith(l, "generators-finish-timestamp=")) + dual_timestamp_deserialize(l+28, &m->generators_finish_timestamp); + else if (startswith(l, "units-load-start-timestamp=")) + dual_timestamp_deserialize(l+27, &m->units_load_start_timestamp); + else if (startswith(l, "units-load-finish-timestamp=")) + dual_timestamp_deserialize(l+28, &m->units_load_finish_timestamp); else if (startswith(l, "env=")) { _cleanup_free_ char *uce = NULL; char **e; @@ -2333,7 +2151,7 @@ int manager_reload(Manager *m) { return r; m->n_reloading ++; - bus_broadcast_reloading(m, true); + bus_manager_send_reloading(m, true); fds = fdset_new(); if (!fds) { @@ -2450,16 +2268,16 @@ void manager_check_finished(Manager *m) { assert(m); if (m->n_running_jobs == 0) - manager_unwatch_jobs_in_progress(m); + m->jobs_in_progress_event_source = sd_event_source_unref(m->jobs_in_progress_event_source); - if (hashmap_size(m->jobs) > 0) { - manager_jobs_in_progress_mod_timer(m); + if (hashmap_size(m->jobs) > 0 && m->jobs_in_progress_event_source) { + sd_event_source_set_time(m->jobs_in_progress_event_source, JOBS_IN_PROGRESS_PERIOD_SEC); return; } /* Notify Type=idle units that we are done now */ - manager_unwatch_idle_pipe(m); - close_idle_pipe(m); + m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source); + manager_close_idle_pipe(m); /* Turn off confirm spawn now */ m->confirm_spawn = false; @@ -2526,7 +2344,7 @@ void manager_check_finished(Manager *m) { NULL); } - bus_broadcast_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec); + bus_manager_send_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec); sd_notifyf(false, "READY=1\nSTATUS=Startup finished in %s.", @@ -2590,7 +2408,7 @@ static void trim_generator_dir(Manager *m, char **generator) { } void manager_run_generators(Manager *m) { - DIR *d = NULL; + _cleanup_closedir_ DIR *d = NULL; const char *generator_path; const char *argv[5]; int r; @@ -2626,17 +2444,13 @@ void manager_run_generators(Manager *m) { argv[3] = m->generator_unit_path_late; argv[4] = NULL; - RUN_WITH_UMASK(0022) { + RUN_WITH_UMASK(0022) execute_directory(generator_path, d, (char**) argv); - } +finish: trim_generator_dir(m, &m->generator_unit_path); trim_generator_dir(m, &m->generator_unit_path_early); trim_generator_dir(m, &m->generator_unit_path_late); - -finish: - if (d) - closedir(d); } static void remove_generator_dir(Manager *m, char **generator) { @@ -2661,17 +2475,36 @@ void manager_undo_generators(Manager *m) { remove_generator_dir(m, &m->generator_unit_path_late); } -int manager_environment_add(Manager *m, char **environment) { - char **e = NULL; +int manager_environment_add(Manager *m, char **minus, char **plus) { + char **a = NULL, **b = NULL, **l; assert(m); - e = strv_env_merge(2, m->environment, environment); - if (!e) - return -ENOMEM; + l = m->environment; - strv_free(m->environment); - m->environment = e; + if (!strv_isempty(minus)) { + a = strv_env_delete(l, 1, minus); + if (!a) + return -ENOMEM; + + l = a; + } + + if (!strv_isempty(plus)) { + b = strv_env_merge(2, l, plus); + if (!b) + return -ENOMEM; + l = b; + } + + if (m->environment != l) + strv_free(m->environment); + if (a != l) + strv_free(a); + if (b != l) + strv_free(b); + + m->environment = l; return 0; } @@ -2802,10 +2635,3 @@ Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) { return hashmap_get(m->units_requiring_mounts_for, streq(p, "/") ? "" : p); } - -void watch_init(Watch *w) { - assert(w); - - w->type = WATCH_INVALID; - w->fd = -1; -} diff --git a/src/core/manager.h b/src/core/manager.h index b043970340..9eddef20dc 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -24,8 +24,9 @@ #include <stdbool.h> #include <inttypes.h> #include <stdio.h> -#include <dbus/dbus.h> +#include "sd-bus.h" +#include "sd-event.h" #include "fdset.h" #include "cgroup-util.h" @@ -33,8 +34,6 @@ #define MANAGER_MAX_NAMES 131072 /* 128K */ typedef struct Manager Manager; -typedef enum WatchType WatchType; -typedef struct Watch Watch; typedef enum ManagerExitCode { MANAGER_RUNNING, @@ -50,42 +49,11 @@ typedef enum ManagerExitCode { _MANAGER_EXIT_CODE_INVALID = -1 } ManagerExitCode; -enum WatchType { - WATCH_INVALID, - WATCH_SIGNAL, - WATCH_NOTIFY, - WATCH_FD, - WATCH_UNIT_TIMER, - WATCH_JOB_TIMER, - WATCH_MOUNT, - WATCH_SWAP, - WATCH_UDEV, - WATCH_DBUS_WATCH, - WATCH_DBUS_TIMEOUT, - WATCH_TIME_CHANGE, - WATCH_JOBS_IN_PROGRESS, - WATCH_IDLE_PIPE, -}; - -struct Watch { - int fd; - WatchType type; - union { - struct Unit *unit; - struct Job *job; - DBusWatch *bus_watch; - DBusTimeout *bus_timeout; - } data; - bool fd_is_dupped:1; - bool socket_accept:1; -}; - #include "unit.h" #include "job.h" #include "hashmap.h" #include "list.h" #include "set.h" -#include "dbus.h" #include "path-lookup.h" #include "execute.h" #include "unit-name.h" @@ -125,17 +93,21 @@ struct Manager { /* Units that should be realized */ LIST_HEAD(Unit, cgroup_queue); + sd_event *event; + Hashmap *watch_pids; /* pid => Unit object n:1 */ char *notify_socket; + int notify_fd; + sd_event_source *notify_event_source; + + int signal_fd; + sd_event_source *signal_event_source; - Watch notify_watch; - Watch signal_watch; - Watch time_change_watch; - Watch jobs_in_progress_watch; - Watch idle_pipe_watch; + int time_change_fd; + sd_event_source *time_change_event_source; - int epoll_fd; + sd_event_source *jobs_in_progress_event_source; unsigned n_snapshots; @@ -157,8 +129,8 @@ struct Manager { dual_timestamp security_finish_timestamp; dual_timestamp generators_start_timestamp; dual_timestamp generators_finish_timestamp; - dual_timestamp unitsload_start_timestamp; - dual_timestamp unitsload_finish_timestamp; + dual_timestamp units_load_start_timestamp; + dual_timestamp units_load_finish_timestamp; char *generator_unit_path; char *generator_unit_path_early; @@ -167,34 +139,33 @@ struct Manager { /* Data specific to the device subsystem */ struct udev* udev; struct udev_monitor* udev_monitor; - Watch udev_watch; + sd_event_source *udev_event_source; Hashmap *devices_by_sysfs; /* Data specific to the mount subsystem */ FILE *proc_self_mountinfo; - Watch mount_watch; + sd_event_source *mount_event_source; /* Data specific to the swap filesystem */ FILE *proc_swaps; + sd_event_source *swap_event_source; Hashmap *swaps_by_proc_swaps; bool request_reload; - Watch swap_watch; /* Data specific to the D-Bus subsystem */ - DBusConnection *api_bus, *system_bus; - DBusServer *private_bus; - Set *bus_connections, *bus_connections_for_dispatch; + sd_bus *api_bus, *system_bus; + Set *private_buses; + int private_listen_fd; + sd_event_source *private_listen_event_source; + Set *subscribed; - DBusMessage *queued_message; /* This is used during reloading: + sd_bus_message *queued_message; /* This is used during reloading: * before the reload we queue the * reply message here, and * afterwards we send it */ - DBusConnection *queued_message_connection; /* The connection to send the queued message on */ + sd_bus *queued_message_bus; /* The connection to send the queued message on */ Hashmap *watch_bus; /* D-Bus names => Unit object n:1 */ - int32_t name_data_slot; - int32_t conn_data_slot; - int32_t subscribed_data_slot; bool send_reloading_done; @@ -253,6 +224,7 @@ struct Manager { /* Type=idle pipes */ int idle_pipe[4]; + sd_event_source *idle_pipe_event_source; char *switch_root; char *switch_root_init; @@ -276,12 +248,12 @@ int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, U int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j); -int manager_load_unit_prepare(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret); -int manager_load_unit(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret); -int manager_load_unit_from_dbus_path(Manager *m, const char *s, DBusError *e, Unit **_u); +int manager_load_unit_prepare(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret); +int manager_load_unit(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret); +int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u); -int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, DBusError *e, Job **_ret); -int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, DBusError *e, Job **_ret); +int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, sd_bus_error *e, Job **_ret); +int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, sd_bus_error *e, Job **_ret); void manager_dump_units(Manager *s, FILE *f, const char *prefix); void manager_dump_jobs(Manager *s, FILE *f, const char *prefix); @@ -290,13 +262,12 @@ void manager_clear_jobs(Manager *m); unsigned manager_dispatch_load_queue(Manager *m); -int manager_environment_add(Manager *m, char **environment); +int manager_environment_add(Manager *m, char **minus, char **plus); int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit); int manager_loop(Manager *m); void manager_dispatch_bus_name_owner_changed(Manager *m, const char *name, const char* old_owner, const char *new_owner); -void manager_dispatch_bus_query_pid_done(Manager *m, const char *name, pid_t pid); int manager_open_serialization(Manager *m, FILE **_f); @@ -325,5 +296,3 @@ void manager_set_show_status(Manager *m, bool b); void manager_status_printf(Manager *m, bool ephemeral, const char *status, const char *format, ...) _printf_(4,5); Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path); - -void watch_init(Watch *w); diff --git a/src/core/mount.c b/src/core/mount.c index 0c15b99f94..99e7cedc45 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -59,6 +59,9 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = { [MOUNT_FAILED] = UNIT_FAILED }; +static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); +static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); + static char* mount_test_option(const char *haystack, const char *needle) { struct mntent me = { .mnt_opts = (char*) haystack }; @@ -156,13 +159,32 @@ static void mount_init(Unit *u) { * already trying to comply its last one. */ m->exec_context.same_pgrp = true; - m->timer_watch.type = WATCH_INVALID; - m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; UNIT(m)->ignore_on_isolate = true; } +static int mount_arm_timer(Mount *m) { + int r; + + assert(m); + + if (m->timeout_usec <= 0) { + m->timer_event_source = sd_event_source_unref(m->timer_event_source); + return 0; + } + + if (m->timer_event_source) { + r = sd_event_source_set_time(m->timer_event_source, now(CLOCK_MONOTONIC) + m->timeout_usec); + if (r < 0) + return r; + + return sd_event_source_set_enabled(m->timer_event_source, SD_EVENT_ONESHOT); + } + + return sd_event_add_monotonic(UNIT(m)->manager->event, now(CLOCK_MONOTONIC) + m->timeout_usec, 0, mount_dispatch_timer, m, &m->timer_event_source); +} + static void mount_unwatch_control_pid(Mount *m) { assert(m); @@ -201,7 +223,7 @@ static void mount_done(Unit *u) { mount_unwatch_control_pid(m); - unit_unwatch_timer(u, &m->timer_watch); + m->timer_event_source = sd_event_source_unref(m->timer_event_source); } _pure_ static MountParameters* get_mount_parameters_fragment(Mount *m) { @@ -626,7 +648,7 @@ static void mount_set_state(Mount *m, MountState state) { state != MOUNT_UNMOUNTING_SIGKILL && state != MOUNT_REMOUNTING_SIGTERM && state != MOUNT_REMOUNTING_SIGKILL) { - unit_unwatch_timer(UNIT(m), &m->timer_watch); + m->timer_event_source = sd_event_source_unref(m->timer_event_source); mount_unwatch_control_pid(m); m->control_command = NULL; m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; @@ -692,7 +714,7 @@ static int mount_coldplug(Unit *u) { if (r < 0) return r; - r = unit_watch_timer(UNIT(m), CLOCK_MONOTONIC, true, m->timeout_usec, &m->timer_watch); + r = mount_arm_timer(m); if (r < 0) return r; } @@ -751,7 +773,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { unit_realize_cgroup(UNIT(m)); - r = unit_watch_timer(UNIT(m), CLOCK_MONOTONIC, true, m->timeout_usec, &m->timer_watch); + r = mount_arm_timer(m); if (r < 0) goto fail; @@ -782,7 +804,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { return 0; fail: - unit_unwatch_timer(UNIT(m), &m->timer_watch); + m->timer_event_source = sd_event_source_unref(m->timer_event_source); return r; } @@ -825,7 +847,7 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) { goto fail; if (r > 0) { - r = unit_watch_timer(UNIT(m), CLOCK_MONOTONIC, true, m->timeout_usec, &m->timer_watch); + r = mount_arm_timer(m); if (r < 0) goto fail; @@ -959,17 +981,11 @@ static void mount_enter_remounting(Mount *m) { m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT; if (m->from_fragment) { - char *buf = NULL; const char *o; - if (m->parameters_fragment.options) { - if (!(buf = strappend("remount,", m->parameters_fragment.options))) { - r = -ENOMEM; - goto fail; - } - - o = buf; - } else + if (m->parameters_fragment.options) + o = strappenda("remount,", m->parameters_fragment.options); + else o = "remount"; r = exec_command_set( @@ -980,8 +996,6 @@ static void mount_enter_remounting(Mount *m) { "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto", "-o", o, NULL); - - free(buf); } else r = -ENOENT; @@ -990,7 +1004,8 @@ static void mount_enter_remounting(Mount *m) { mount_unwatch_control_pid(m); - if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0) + r = mount_spawn(m, m->control_command, &m->control_pid); + if (r < 0) goto fail; mount_set_state(m, MOUNT_REMOUNTING); @@ -1279,44 +1294,43 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { unit_add_to_dbus_queue(u); } -static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) { - Mount *m = MOUNT(u); +static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) { + Mount *m = MOUNT(userdata); assert(m); - assert(elapsed == 1); - assert(w == &m->timer_watch); + assert(m->timer_event_source == source); switch (m->state) { case MOUNT_MOUNTING: case MOUNT_MOUNTING_DONE: - log_warning_unit(u->id, - "%s mounting timed out. Stopping.", u->id); + log_warning_unit(UNIT(m)->id, + "%s mounting timed out. Stopping.", UNIT(m)->id); mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT); break; case MOUNT_REMOUNTING: - log_warning_unit(u->id, - "%s remounting timed out. Stopping.", u->id); + log_warning_unit(UNIT(m)->id, + "%s remounting timed out. Stopping.", UNIT(m)->id); m->reload_result = MOUNT_FAILURE_TIMEOUT; mount_enter_mounted(m, MOUNT_SUCCESS); break; case MOUNT_UNMOUNTING: - log_warning_unit(u->id, - "%s unmounting timed out. Stopping.", u->id); + log_warning_unit(UNIT(m)->id, + "%s unmounting timed out. Stopping.", UNIT(m)->id); mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT); break; case MOUNT_MOUNTING_SIGTERM: if (m->kill_context.send_sigkill) { - log_warning_unit(u->id, - "%s mounting timed out. Killing.", u->id); + log_warning_unit(UNIT(m)->id, + "%s mounting timed out. Killing.", UNIT(m)->id); mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT); } else { - log_warning_unit(u->id, + log_warning_unit(UNIT(m)->id, "%s mounting timed out. Skipping SIGKILL. Ignoring.", - u->id); + UNIT(m)->id); if (m->from_proc_self_mountinfo) mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT); @@ -1327,13 +1341,13 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) { case MOUNT_REMOUNTING_SIGTERM: if (m->kill_context.send_sigkill) { - log_warning_unit(u->id, - "%s remounting timed out. Killing.", u->id); + log_warning_unit(UNIT(m)->id, + "%s remounting timed out. Killing.", UNIT(m)->id); mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT); } else { - log_warning_unit(u->id, + log_warning_unit(UNIT(m)->id, "%s remounting timed out. Skipping SIGKILL. Ignoring.", - u->id); + UNIT(m)->id); if (m->from_proc_self_mountinfo) mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT); @@ -1344,13 +1358,13 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) { case MOUNT_UNMOUNTING_SIGTERM: if (m->kill_context.send_sigkill) { - log_warning_unit(u->id, - "%s unmounting timed out. Killing.", u->id); + log_warning_unit(UNIT(m)->id, + "%s unmounting timed out. Killing.", UNIT(m)->id); mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT); } else { - log_warning_unit(u->id, + log_warning_unit(UNIT(m)->id, "%s unmounting timed out. Skipping SIGKILL. Ignoring.", - u->id); + UNIT(m)->id); if (m->from_proc_self_mountinfo) mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT); @@ -1362,9 +1376,9 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) { case MOUNT_MOUNTING_SIGKILL: case MOUNT_REMOUNTING_SIGKILL: case MOUNT_UNMOUNTING_SIGKILL: - log_warning_unit(u->id, + log_warning_unit(UNIT(m)->id, "%s mount process still around after SIGKILL. Ignoring.", - u->id); + UNIT(m)->id); if (m->from_proc_self_mountinfo) mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT); @@ -1375,6 +1389,8 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) { default: assert_not_reached("Timeout at wrong time."); } + + return 0; } static int mount_add_one( @@ -1582,6 +1598,8 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { static void mount_shutdown(Manager *m) { assert(m); + m->mount_event_source = sd_event_source_unref(m->mount_event_source); + if (m->proc_self_mountinfo) { fclose(m->proc_self_mountinfo); m->proc_self_mountinfo = NULL; @@ -1593,20 +1611,13 @@ static int mount_enumerate(Manager *m) { assert(m); if (!m->proc_self_mountinfo) { - struct epoll_event ev = { - .events = EPOLLPRI, - .data.ptr = &m->mount_watch, - }; - m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); if (!m->proc_self_mountinfo) return -errno; - m->mount_watch.type = WATCH_MOUNT; - m->mount_watch.fd = fileno(m->proc_self_mountinfo); - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->mount_watch.fd, &ev) < 0) - return -errno; + r = sd_event_add_io(m->event, fileno(m->proc_self_mountinfo), EPOLLPRI, mount_dispatch_io, m, &m->mount_event_source); + if (r < 0) + goto fail; } r = mount_load_proc_self_mountinfo(m, false); @@ -1620,12 +1631,13 @@ fail: return r; } -void mount_fd_event(Manager *m, int events) { +static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; Unit *u; int r; assert(m); - assert(events & EPOLLPRI); + assert(revents & EPOLLPRI); /* The manager calls this for every fd event happening on the * /proc/self/mountinfo file, which informs us about mounting @@ -1642,7 +1654,7 @@ void mount_fd_event(Manager *m, int events) { mount->is_mounted = mount->just_mounted = mount->just_changed = false; } - return; + return 0; } manager_dispatch_load_queue(m); @@ -1696,6 +1708,8 @@ void mount_fd_event(Manager *m, int events) { /* Reset the flags for later calls */ mount->is_mounted = mount->just_mounted = mount->just_changed = false; } + + return 0; } static void mount_reset_failed(Unit *u) { @@ -1710,7 +1724,7 @@ static void mount_reset_failed(Unit *u) { m->reload_result = MOUNT_SUCCESS; } -static int mount_kill(Unit *u, KillWho who, int signo, DBusError *error) { +static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error); } @@ -1753,15 +1767,15 @@ DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult); const UnitVTable mount_vtable = { .object_size = sizeof(Mount), + .exec_context_offset = offsetof(Mount, exec_context), + .cgroup_context_offset = offsetof(Mount, cgroup_context), + .kill_context_offset = offsetof(Mount, kill_context), .sections = "Unit\0" "Mount\0" "Install\0", - .private_section = "Mount", - .exec_context_offset = offsetof(Mount, exec_context), - .cgroup_context_offset = offsetof(Mount, cgroup_context), .no_alias = true, .no_instances = true, @@ -1789,13 +1803,12 @@ const UnitVTable mount_vtable = { .check_gc = mount_check_gc, .sigchld_event = mount_sigchld_event, - .timer_event = mount_timer_event, .reset_failed = mount_reset_failed, .bus_interface = "org.freedesktop.systemd1.Mount", - .bus_message_handler = bus_mount_message_handler, - .bus_invalidating_properties = bus_mount_invalidating_properties, + .bus_vtable = bus_mount_vtable, + .bus_changing_properties = bus_mount_changing_properties, .bus_set_property = bus_mount_set_property, .bus_commit_properties = bus_mount_commit_properties, diff --git a/src/core/mount.h b/src/core/mount.h index a9550697e5..2edb75eb54 100644 --- a/src/core/mount.h +++ b/src/core/mount.h @@ -107,7 +107,7 @@ struct Mount { MountExecCommand control_command_id; pid_t control_pid; - Watch timer_watch; + sd_event_source *timer_event_source; }; extern const UnitVTable mount_vtable; diff --git a/src/core/path.c b/src/core/path.c index 10df80f695..51e8d1dbcc 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -31,9 +31,10 @@ #include "mkdir.h" #include "dbus-path.h" #include "special.h" -#include "dbus-common.h" #include "path-util.h" #include "macro.h" +#include "bus-util.h" +#include "bus-error.h" static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = { [PATH_DEAD] = UNIT_INACTIVE, @@ -42,7 +43,9 @@ static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = { [PATH_FAILED] = UNIT_FAILED }; -int path_spec_watch(PathSpec *s, Unit *u) { +static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); + +int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) { static const int flags_table[_PATH_TYPE_MAX] = { [PATH_EXISTS] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB, @@ -56,10 +59,11 @@ int path_spec_watch(PathSpec *s, Unit *u) { char *slash, *oldslash = NULL; int r; - assert(u); assert(s); + assert(s->unit); + assert(handler); - path_spec_unwatch(s, u); + path_spec_unwatch(s); s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); if (s->inotify_fd < 0) { @@ -67,7 +71,7 @@ int path_spec_watch(PathSpec *s, Unit *u) { goto fail; } - r = unit_watch_fd(u, s->inotify_fd, EPOLLIN, &s->watch); + r = sd_event_add_io(s->unit->manager->event, s->inotify_fd, EPOLLIN, handler, s, &s->event_source); if (r < 0) goto fail; @@ -140,29 +144,29 @@ int path_spec_watch(PathSpec *s, Unit *u) { return 0; fail: - path_spec_unwatch(s, u); + path_spec_unwatch(s); return r; } -void path_spec_unwatch(PathSpec *s, Unit *u) { - - if (s->inotify_fd < 0) - return; +void path_spec_unwatch(PathSpec *s) { + assert(s); - unit_unwatch_fd(u, &s->watch); + s->event_source = sd_event_source_unref(s->event_source); - close_nointr_nofail(s->inotify_fd); - s->inotify_fd = -1; + if (s->inotify_fd >= 0) { + close_nointr_nofail(s->inotify_fd); + s->inotify_fd = -1; + } } -int path_spec_fd_event(PathSpec *s, uint32_t events) { +int path_spec_fd_event(PathSpec *s, uint32_t revents) { _cleanup_free_ uint8_t *buf = NULL; struct inotify_event *e; ssize_t k; int l; int r = 0; - if (events != EPOLLIN) { + if (revents != EPOLLIN) { log_error("Got invalid poll event on inotify."); return -EINVAL; } @@ -282,7 +286,7 @@ void path_free_specs(Path *p) { assert(p); while ((s = p->specs)) { - path_spec_unwatch(s, UNIT(p)); + path_spec_unwatch(s); LIST_REMOVE(spec, p->specs, s); path_spec_done(s); free(s); @@ -419,7 +423,7 @@ static void path_unwatch(Path *p) { assert(p); LIST_FOREACH(spec, s, p->specs) - path_spec_unwatch(s, UNIT(p)); + path_spec_unwatch(s); } static int path_watch(Path *p) { @@ -429,7 +433,7 @@ static int path_watch(Path *p) { assert(p); LIST_FOREACH(spec, s, p->specs) { - r = path_spec_watch(s, UNIT(p)); + r = path_spec_watch(s, path_dispatch_io); if (r < 0) return r; } @@ -487,13 +491,11 @@ static void path_enter_dead(Path *p, PathResult f) { } static void path_enter_running(Path *p) { - _cleanup_dbus_error_free_ DBusError error; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(p); - dbus_error_init(&error); - /* Don't start job if we are supposed to go down */ if (unit_stop_pending(UNIT(p))) return; @@ -514,7 +516,7 @@ static void path_enter_running(Path *p) { fail: log_warning("%s failed to queue unit startup job: %s", - UNIT(p)->id, bus_error(&error, r)); + UNIT(p)->id, bus_error_message(&error, r)); path_enter_dead(p, PATH_FAILURE_RESOURCES); } @@ -664,17 +666,20 @@ _pure_ static const char *path_sub_state_to_string(Unit *u) { return path_state_to_string(PATH(u)->state); } -static void path_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { - Path *p = PATH(u); - PathSpec *s; +static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + PathSpec *s = userdata; + Path *p; int changed; - assert(p); + assert(s); + assert(s->unit); assert(fd >= 0); + p = PATH(s->unit); + if (p->state != PATH_WAITING && p->state != PATH_RUNNING) - return; + return 0; /* log_debug("inotify wakeup on %s.", u->id); */ @@ -687,7 +692,7 @@ static void path_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { goto fail; } - changed = path_spec_fd_event(s, events); + changed = path_spec_fd_event(s, revents); if (changed < 0) goto fail; @@ -701,10 +706,11 @@ static void path_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { else path_enter_waiting(p, false, true); - return; + return 0; fail: path_enter_dead(p, PATH_FAILURE_RESOURCES); + return 0; } static void path_trigger_notify(Unit *u, Unit *other) { @@ -771,6 +777,7 @@ DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult); const UnitVTable path_vtable = { .object_size = sizeof(Path), + .sections = "Unit\0" "Path\0" @@ -793,13 +800,11 @@ const UnitVTable path_vtable = { .active_state = path_active_state, .sub_state_to_string = path_sub_state_to_string, - .fd_event = path_fd_event, - .trigger_notify = path_trigger_notify, .reset_failed = path_reset_failed, .bus_interface = "org.freedesktop.systemd1.Path", - .bus_message_handler = bus_path_message_handler, - .bus_invalidating_properties = bus_path_invalidating_properties + .bus_vtable = bus_path_vtable, + .bus_changing_properties = bus_path_changing_properties }; diff --git a/src/core/path.h b/src/core/path.h index dec3df7035..d2e91d7d71 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -46,9 +46,11 @@ typedef enum PathType { } PathType; typedef struct PathSpec { + Unit *unit; + char *path; - Watch watch; + sd_event_source *event_source; LIST_FIELDS(struct PathSpec, spec); @@ -59,8 +61,8 @@ typedef struct PathSpec { bool previous_exists; } PathSpec; -int path_spec_watch(PathSpec *s, Unit *u); -void path_spec_unwatch(PathSpec *s, Unit *u); +int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler); +void path_spec_unwatch(PathSpec *s); int path_spec_fd_event(PathSpec *s, uint32_t events); void path_spec_done(PathSpec *s); diff --git a/src/core/scope.c b/src/core/scope.c index 41da3b9378..a3c94794b1 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -40,6 +40,8 @@ static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = { [SCOPE_FAILED] = UNIT_FAILED }; +static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); + static void scope_init(Unit *u) { Scope *s = SCOPE(u); @@ -48,8 +50,6 @@ static void scope_init(Unit *u) { s->timeout_stop_usec = u->manager->default_timeout_stop_usec; - watch_init(&s->timer_watch); - cgroup_context_init(&s->cgroup_context); kill_context_init(&s->kill_context); @@ -67,7 +67,28 @@ static void scope_done(Unit *u) { set_free(s->pids); s->pids = NULL; - unit_unwatch_timer(u, &s->timer_watch); + s->timer_event_source = sd_event_source_unref(s->timer_event_source); +} + +static int scope_arm_timer(Scope *s) { + int r; + + assert(s); + + if (s->timeout_stop_usec <= 0) { + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + return 0; + } + + if (s->timer_event_source) { + r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_stop_usec); + if (r < 0) + return r; + + return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT); + } + + return sd_event_add_monotonic(UNIT(s)->manager->event, now(CLOCK_MONOTONIC) + s->timeout_stop_usec, 0, scope_dispatch_timer, s, &s->timer_event_source); } static void scope_set_state(Scope *s, ScopeState state) { @@ -79,7 +100,7 @@ static void scope_set_state(Scope *s, ScopeState state) { if (state != SCOPE_STOP_SIGTERM && state != SCOPE_STOP_SIGKILL) - unit_unwatch_timer(UNIT(s), &s->timer_watch); + s->timer_event_source = sd_event_source_unref(s->timer_event_source); if (state != old_state) log_debug("%s changed %s -> %s", @@ -158,11 +179,9 @@ static int scope_coldplug(Unit *u) { if (s->deserialized_state != s->state) { - if ((s->deserialized_state == SCOPE_STOP_SIGKILL || s->deserialized_state == SCOPE_STOP_SIGTERM) - && s->timeout_stop_usec > 0) { - r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_stop_usec, &s->timer_watch); + if (s->deserialized_state == SCOPE_STOP_SIGKILL || s->deserialized_state == SCOPE_STOP_SIGTERM) { + r = scope_arm_timer(s); if (r < 0) - return r; } @@ -214,11 +233,9 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) { goto fail; if (r > 0) { - if (s->timeout_stop_usec > 0) { - r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_stop_usec, &s->timer_watch); - if (r < 0) - goto fail; - } + r = scope_arm_timer(s); + if (r < 0) + goto fail; scope_set_state(s, state); } else @@ -297,7 +314,7 @@ static void scope_reset_failed(Unit *u) { s->result = SCOPE_SUCCESS; } -static int scope_kill(Unit *u, KillWho who, int signo, DBusError *error) { +static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, -1, -1, error); } @@ -353,34 +370,35 @@ static bool scope_check_gc(Unit *u) { return false; } -static void scope_timer_event(Unit *u, uint64_t elapsed, Watch*w) { - Scope *s = SCOPE(u); +static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) { + Scope *s = SCOPE(userdata); assert(s); - assert(elapsed == 1); - assert(w == &s->timer_watch); + assert(s->timer_event_source == source); switch (s->state) { case SCOPE_STOP_SIGTERM: if (s->kill_context.send_sigkill) { - log_warning_unit(u->id, "%s stopping timed out. Killing.", u->id); + log_warning_unit(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id); scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT); } else { - log_warning_unit(u->id, "%s stopping timed out. Skipping SIGKILL.", u->id); + log_warning_unit(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL.", UNIT(s)->id); scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT); } break; case SCOPE_STOP_SIGKILL: - log_warning_unit(u->id, "%s still around after SIGKILL. Ignoring.", u->id); + log_warning_unit(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id); scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT); break; default: assert_not_reached("Timeout at wrong time."); } + + return 0; } static void scope_notify_cgroup_empty_event(Unit *u) { @@ -435,13 +453,14 @@ DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult); const UnitVTable scope_vtable = { .object_size = sizeof(Scope), + .cgroup_context_offset = offsetof(Scope, cgroup_context), + .kill_context_offset = offsetof(Scope, kill_context), + .sections = "Unit\0" "Scope\0" "Install\0", - .private_section = "Scope", - .cgroup_context_offset = offsetof(Scope, cgroup_context), .no_alias = true, .no_instances = true, @@ -467,14 +486,13 @@ const UnitVTable scope_vtable = { .check_gc = scope_check_gc, - .timer_event = scope_timer_event, - .reset_failed = scope_reset_failed, .notify_cgroup_empty = scope_notify_cgroup_empty_event, .bus_interface = "org.freedesktop.systemd1.Scope", - .bus_message_handler = bus_scope_message_handler, + .bus_vtable = bus_scope_vtable, + .bus_changing_properties = bus_scope_changing_properties, .bus_set_property = bus_scope_set_property, .bus_commit_properties = bus_scope_commit_properties, diff --git a/src/core/scope.h b/src/core/scope.h index 2a3dcb73d7..4d8a1714bc 100644 --- a/src/core/scope.h +++ b/src/core/scope.h @@ -57,7 +57,7 @@ struct Scope { Set *pids; - Watch timer_watch; + sd_event_source *timer_event_source; }; extern const UnitVTable scope_vtable; diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index c7e951cde6..0ecbdf0be6 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -32,12 +32,11 @@ #ifdef HAVE_AUDIT #include <libaudit.h> #endif -#include <dbus.h> +#include "sd-bus.h" +#include "bus-util.h" #include "util.h" #include "log.h" -#include "bus-errors.h" -#include "dbus-common.h" #include "audit.h" #include "selinux-util.h" #include "audit-fd.h" @@ -53,72 +52,59 @@ struct auditstruct { }; static int bus_get_selinux_security_context( - DBusConnection *connection, + sd_bus *bus, const char *name, - char **scon, - DBusError *error) { + sd_bus_error *error, + char **ret) { - _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; - DBusMessageIter iter, sub; - const char *bytes; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + const void *p; + size_t sz; char *b; - int nbytes; - - m = dbus_message_new_method_call( - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetConnectionSELinuxSecurityContext"); - if (!m) { - dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); - return -ENOMEM; - } - - if (!dbus_message_append_args( - m, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) { - dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); - return -ENOMEM; - } - - reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error); - if (!reply) - return -EIO; - - if (dbus_set_error_from_message(error, reply)) - return -EIO; - - if (!dbus_message_iter_init(reply, &iter)) - return -EIO; + int r; - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) - return -EIO; + assert(bus); + assert(name); + assert(ret); + + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetConnectionSELinuxSecurityContext", + error, &m, + "s", name); + if (r < 0) + return r; - dbus_message_iter_recurse(&iter, &sub); - dbus_message_iter_get_fixed_array(&sub, &bytes, &nbytes); + r = sd_bus_message_read_array(m, 'y', &p, &sz); + if (r < 0) + return r; - b = strndup(bytes, nbytes); + b = strndup(p, sz); if (!b) return -ENOMEM; - *scon = b; - + *ret = b; return 0; } static int bus_get_audit_data( - DBusConnection *connection, + sd_bus *bus, const char *name, - struct auditstruct *audit, - DBusError *error) { + struct auditstruct *audit) { pid_t pid; int r; - pid = bus_get_unix_process_id(connection, name, error); - if (pid <= 0) - return -EIO; + assert(bus); + assert(name); + assert(audit); + + r = sd_bus_get_owner_pid(bus, name, &pid); + if (r < 0) + return r; r = audit_loginuid_from_pid(pid, &audit->loginuid); if (r < 0) @@ -207,7 +193,7 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) { If you want to cleanup memory you should need to call selinux_access_finish. */ static int access_init(void) { - int r; + int r = 0; if (avc_open(NULL, 0)) { log_error("avc_open() failed: %m"); @@ -217,34 +203,33 @@ static int access_init(void) { selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback); selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback); - if (security_getenforce() >= 0) - return 0; - - r = -errno; - avc_destroy(); + if (security_getenforce() < 0){ + r = -errno; + avc_destroy(); + } return r; } -static int selinux_access_init(DBusError *error) { +static int selinux_access_init(sd_bus_error *error) { int r; if (initialized) return 0; - if (use_selinux()) { - r = access_init(); - if (r < 0) { - dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "Failed to initialize SELinux."); - return r; - } - } + if (!use_selinux()) + return 0; + + r = access_init(); + if (r < 0) + return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to initialize SELinux."); initialized = true; return 0; } void selinux_access_free(void) { + if (!initialized) return; @@ -253,28 +238,27 @@ void selinux_access_free(void) { } static int get_audit_data( - DBusConnection *connection, - DBusMessage *message, - struct auditstruct *audit, - DBusError *error) { + sd_bus *bus, + sd_bus_message *message, + struct auditstruct *audit) { + struct ucred ucred; const char *sender; + socklen_t len; int r, fd; - struct ucred ucred; - socklen_t len = sizeof(ucred); - sender = dbus_message_get_sender(message); + sender = sd_bus_message_get_sender(message); if (sender) - return bus_get_audit_data(connection, sender, audit, error); + return bus_get_audit_data(bus, sender, audit); - if (!dbus_connection_get_unix_fd(connection, &fd)) - return -EINVAL; + fd = sd_bus_get_fd(bus); + if (fd < 0) + return fd; + len = sizeof(ucred); r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len); - if (r < 0) { - log_error("Failed to determine peer credentials: %m"); + if (r < 0) return -errno; - } audit->uid = ucred.uid; audit->gid = ucred.gid; @@ -295,40 +279,30 @@ static int get_audit_data( connections. Whether it is on the bus or a local connection. */ static int get_calling_context( - DBusConnection *connection, - DBusMessage *message, - security_context_t *scon, - DBusError *error) { + sd_bus *bus, + sd_bus_message *message, + sd_bus_error *error, + security_context_t *ret) { const char *sender; - int r; - int fd; + int r, fd; /* If sender exists then if sender is NULL this indicates a local connection. Grab the fd from dbus and do an getpeercon to peers process context */ - sender = dbus_message_get_sender(message); - if (sender) { - r = bus_get_selinux_security_context(connection, sender, scon, error); - if (r >= 0) - return r; - - log_error("bus_get_selinux_security_context failed: %m"); - return r; - } + sender = sd_bus_message_get_sender(message); + if (sender) + return bus_get_selinux_security_context(bus, sender, error, ret); - if (!dbus_connection_get_unix_fd(connection, &fd)) { - log_error("bus_connection_get_unix_fd failed %m"); - return -EINVAL; - } + fd = sd_bus_get_fd(bus); + if (fd < 0) + return fd; - r = getpeercon(fd, scon); - if (r < 0) { - log_error("getpeercon failed %m"); + r = getpeercon(fd, ret); + if (r < 0) return -errno; - } return 0; } @@ -340,18 +314,18 @@ static int get_calling_context( still be generated if the access would be denied in enforcing mode. */ int selinux_access_check( - DBusConnection *connection, - DBusMessage *message, + sd_bus *bus, + sd_bus_message *message, const char *path, const char *permission, - DBusError *error) { + sd_bus_error *error) { security_context_t scon = NULL, fcon = NULL; - int r = 0; const char *tclass = NULL; struct auditstruct audit; + int r = 0; - assert(connection); + assert(bus); assert(message); assert(permission); assert(error); @@ -368,43 +342,36 @@ int selinux_access_check( audit.cmdline = NULL; audit.path = path; - r = get_calling_context(connection, message, &scon, error); - if (r < 0) { - log_error("Failed to get caller's security context on: %m"); + r = get_calling_context(bus, message, error, &scon); + if (r < 0) goto finish; - } if (path) { - tclass = "service"; - /* get the file context of the unit file */ + /* Get the file context of the unit file */ + r = getfilecon(path, &fcon); if (r < 0) { - dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path); - r = -errno; - log_error("Failed to get security context on %s: %m",path); + r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path); goto finish; } + tclass = "service"; } else { - tclass = "system"; r = getcon(&fcon); if (r < 0) { - dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "Failed to get current context."); - r = -errno; - log_error("Failed to get current process context on: %m"); + r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context."); goto finish; } + + tclass = "system"; } - (void) get_audit_data(connection, message, &audit, error); + get_audit_data(bus, message, &audit); errno = 0; r = selinux_check_access(scon, fcon, tclass, permission, &audit); - if (r < 0) { - dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "SELinux policy denies access."); - r = -errno; - log_error("SELinux policy denies access."); - } + if (r < 0) + r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access."); log_debug("SELinux access check scon=%s tcon=%s tclass=%s perm=%s path=%s cmdline=%s: %i", scon, fcon, tclass, permission, path, audit.cmdline, r); @@ -414,7 +381,7 @@ finish: freecon(fcon); if (r && security_getenforce() != 1) { - dbus_error_init(error); + sd_bus_error_free(error); r = 0; } @@ -424,11 +391,11 @@ finish: #else int selinux_access_check( - DBusConnection *connection, - DBusMessage *message, + sd_bus *bus, + sd_bus_message *message, const char *path, const char *permission, - DBusError *error) { + sd_bus_error *error) { return 0; } diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h index 2d7ac64c8f..0926a5eb09 100644 --- a/src/core/selinux-access.h +++ b/src/core/selinux-access.h @@ -21,42 +21,42 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dbus.h> +#include "sd-bus.h" +#include "bus-error.h" +#include "bus-util.h" void selinux_access_free(void); -int selinux_access_check(DBusConnection *connection, DBusMessage *message, const char *path, const char *permission, DBusError *error); +int selinux_access_check(sd_bus *bus, sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error); #ifdef HAVE_SELINUX -#define SELINUX_ACCESS_CHECK(connection, message, permission) \ +#define SELINUX_ACCESS_CHECK(bus, message, permission) \ do { \ - DBusError _error; \ + _cleanup_bus_error_free_ sd_bus_error _error = SD_BUS_ERROR_NULL; \ + sd_bus_message *_m = (message); \ + sd_bus *_b = (bus); \ int _r; \ - DBusConnection *_c = (connection); \ - DBusMessage *_m = (message); \ - dbus_error_init(&_error); \ - _r = selinux_access_check(_c, _m, NULL, (permission), &_error); \ + _r = selinux_access_check(_b, _m, NULL, (permission), &_error); \ if (_r < 0) \ - return bus_send_error_reply(_c, _m, &_error, _r); \ + return sd_bus_reply_method_errno(_b, _m, _r, &_error); \ } while (false) -#define SELINUX_UNIT_ACCESS_CHECK(unit, connection, message, permission) \ +#define SELINUX_UNIT_ACCESS_CHECK(unit, bus, message, permission) \ do { \ - DBusError _error; \ - int _r; \ - DBusConnection *_c = (connection); \ - DBusMessage *_m = (message); \ + _cleanup_bus_error_free_ sd_bus_error _error = SD_BUS_ERROR_NULL; \ + sd_bus_message *_m = (message); \ + sd_bus *_b = (bus); \ Unit *_u = (unit); \ - dbus_error_init(&_error); \ - _r = selinux_access_check(_c, _m, _u->source_path ?: _u->fragment_path, (permission), &_error); \ + int _r; \ + _r = selinux_access_check(_b, _m, _u->source_path ?: _u->fragment_path, (permission), &_error); \ if (_r < 0) \ - return bus_send_error_reply(_c, _m, &_error, _r); \ + return sd_bus_reply_method_errno(_b, _m, _r, &_error); \ } while (false) #else -#define SELINUX_ACCESS_CHECK(connection, message, permission) do { } while (false) -#define SELINUX_UNIT_ACCESS_CHECK(unit, connection, message, permission) do { } while (false) +#define SELINUX_ACCESS_CHECK(bus, message, permission) do { } while (false) +#define SELINUX_UNIT_ACCESS_CHECK(unit, bus, message, permission) do { } while (false) #endif diff --git a/src/core/service.c b/src/core/service.c index c0ee1140a8..d9e525e485 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -36,7 +36,6 @@ #include "unit-printf.h" #include "dbus-service.h" #include "special.h" -#include "dbus-common.h" #include "exit-status.h" #include "def.h" #include "path-util.h" @@ -44,6 +43,8 @@ #include "utf8.h" #include "env-util.h" #include "fileio.h" +#include "bus-error.h" +#include "bus-util.h" #ifdef HAVE_SYSV_COMPAT @@ -118,6 +119,10 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] = [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING }; +static int service_dispatch_io(sd_event_source *source, int fd, uint32_t events, void *userdata); +static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); +static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void *userdata); + static void service_init(Unit *u) { Service *s = SERVICE(u); @@ -129,9 +134,6 @@ static void service_init(Unit *u) { s->restart_usec = u->manager->default_restart_usec; s->type = _SERVICE_TYPE_INVALID; - watch_init(&s->watchdog_watch); - watch_init(&s->timer_watch); - #ifdef HAVE_SYSV_COMPAT s->sysv_start_priority = -1; s->sysv_start_priority_from_rcnd = -1; @@ -176,7 +178,7 @@ static void service_unwatch_pid_file(Service *s) { log_debug_unit(UNIT(s)->id, "Stopping watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path); - path_spec_unwatch(s->pid_file_pathspec, UNIT(s)); + path_spec_unwatch(s->pid_file_pathspec); path_spec_done(s->pid_file_pathspec); free(s->pid_file_pathspec); s->pid_file_pathspec = NULL; @@ -239,15 +241,14 @@ static void service_connection_unref(Service *s) { static void service_stop_watchdog(Service *s) { assert(s); - unit_unwatch_timer(UNIT(s), &s->watchdog_watch); - s->watchdog_timestamp.realtime = 0; - s->watchdog_timestamp.monotonic = 0; + s->watchdog_event_source = sd_event_source_unref(s->watchdog_event_source); + s->watchdog_timestamp = (struct dual_timestamp) { 0, 0 }; } static void service_enter_signal(Service *s, ServiceState state, ServiceResult f); static void service_handle_watchdog(Service *s) { - usec_t offset; + usec_t nw; int r; assert(s); @@ -255,14 +256,24 @@ static void service_handle_watchdog(Service *s) { if (s->watchdog_usec == 0) return; - offset = now(CLOCK_MONOTONIC) - s->watchdog_timestamp.monotonic; - if (offset >= s->watchdog_usec) { + nw = now(CLOCK_MONOTONIC); + if (nw >= s->watchdog_timestamp.monotonic + s->watchdog_usec) { log_error_unit(UNIT(s)->id, "%s watchdog timeout!", UNIT(s)->id); service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_WATCHDOG); return; } - r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->watchdog_usec - offset, &s->watchdog_watch); + if (s->watchdog_event_source) { + r = sd_event_source_set_time(s->watchdog_event_source, s->watchdog_timestamp.monotonic + s->watchdog_usec); + if (r < 0) { + log_warning_unit(UNIT(s)->id, "%s failed to reset watchdog timer: %s", UNIT(s)->id, strerror(-r)); + return; + } + + r = sd_event_source_set_enabled(s->watchdog_event_source, SD_EVENT_ON); + } else + r = sd_event_add_monotonic(UNIT(s)->manager->event, s->watchdog_timestamp.monotonic + s->watchdog_usec, 0, service_dispatch_watchdog, s, &s->watchdog_event_source); + if (r < 0) log_warning_unit(UNIT(s)->id, "%s failed to install watchdog timer: %s", @@ -327,7 +338,28 @@ static void service_done(Unit *u) { service_stop_watchdog(s); - unit_unwatch_timer(u, &s->timer_watch); + s->timer_event_source = sd_event_source_unref(s->timer_event_source); +} + +static int service_arm_timer(Service *s, usec_t usec) { + int r; + + assert(s); + + if (usec <= 0) { + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + return 0; + } + + if (s->timer_event_source) { + r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + usec); + if (r < 0) + return r; + + return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT); + } + + return sd_event_add_monotonic(UNIT(s)->manager->event, now(CLOCK_MONOTONIC) + usec, 0, service_dispatch_timer, s, &s->timer_event_source); } #ifdef HAVE_SYSV_COMPAT @@ -1214,9 +1246,11 @@ static int service_load(Unit *u) { return r; #endif - if (s->bus_name) - if ((r = unit_watch_bus_name(u, s->bus_name)) < 0) + if (s->bus_name) { + r = unit_watch_bus_name(u, s->bus_name); + if (r < 0) return r; + } if (s->type == SERVICE_NOTIFY && s->notify_access == NOTIFY_NONE) s->notify_access = NOTIFY_MAIN; @@ -1467,7 +1501,7 @@ static void service_set_state(Service *s, ServiceState state) { state != SERVICE_FINAL_SIGTERM && state != SERVICE_FINAL_SIGKILL && state != SERVICE_AUTO_RESTART) - unit_unwatch_timer(UNIT(s), &s->timer_watch); + s->timer_event_source = sd_event_source_unref(s->timer_event_source); if (state != SERVICE_START && state != SERVICE_START_POST && @@ -1567,11 +1601,12 @@ static int service_coldplug(Unit *u) { s->deserialized_state == SERVICE_AUTO_RESTART) { if (s->deserialized_state == SERVICE_AUTO_RESTART || s->timeout_start_usec > 0) { - usec_t k; - k = s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : s->timeout_start_usec; - - r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, k, &s->timer_watch); + r = service_arm_timer(s, + s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : + s->deserialized_state == SERVICE_START_PRE || s->deserialized_state == SERVICE_START || + s->deserialized_state == SERVICE_START_POST || s->deserialized_state == SERVICE_RELOAD ? s->timeout_start_usec : + s->timeout_stop_usec); if (r < 0) return r; } @@ -1728,13 +1763,9 @@ static int service_spawn( } } - if (timeout && s->timeout_start_usec) { - r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, - s->timeout_start_usec, &s->timer_watch); - if (r < 0) - goto fail; - } else - unit_unwatch_timer(UNIT(s), &s->timer_watch); + r = service_arm_timer(s, timeout ? s->timeout_start_usec : 0); + if (r < 0) + goto fail; r = unit_full_printf_strv(UNIT(s), c->argv, &argv); if (r < 0) @@ -1810,7 +1841,7 @@ static int service_spawn( fail: if (timeout) - unit_unwatch_timer(UNIT(s), &s->timer_watch); + s->timer_event_source = sd_event_source_unref(s->timer_event_source); return r; } @@ -1881,10 +1912,9 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) (s->result != SERVICE_FAILURE_EXIT_CODE || !set_contains(s->restart_ignore_status.code, INT_TO_PTR(s->main_exec_status.status))) && (s->result != SERVICE_FAILURE_SIGNAL || - !set_contains(s->restart_ignore_status.signal, INT_TO_PTR(s->main_exec_status.status))) - ) { + !set_contains(s->restart_ignore_status.signal, INT_TO_PTR(s->main_exec_status.status)))) { - r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->restart_usec, &s->timer_watch); + r = service_arm_timer(s, s->restart_usec); if (r < 0) goto fail; @@ -1971,8 +2001,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f if (r > 0) { if (s->timeout_stop_usec > 0) { - r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, - s->timeout_stop_usec, &s->timer_watch); + r = service_arm_timer(s, s->timeout_stop_usec); if (r < 0) goto fail; } @@ -2225,18 +2254,17 @@ fail: } static void service_enter_restart(Service *s) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; int r; - DBusError error; assert(s); - dbus_error_init(&error); if (UNIT(s)->job && UNIT(s)->job->type == JOB_STOP) { /* Don't restart things if we are going down anyway */ log_info_unit(UNIT(s)->id, "Stop job pending for unit, delaying automatic restart."); - r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->restart_usec, &s->timer_watch); + r = service_arm_timer(s, s->restart_usec); if (r < 0) goto fail; @@ -2262,10 +2290,8 @@ static void service_enter_restart(Service *s) { fail: log_warning_unit(UNIT(s)->id, "%s failed to schedule restart job: %s", - UNIT(s)->id, bus_error(&error, -r)); + UNIT(s)->id, bus_error_message(&error, -r)); service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false); - - dbus_error_free(&error); } static void service_enter_reload(Service *s) { @@ -2402,22 +2428,18 @@ static int service_start_limit_test(Service *s) { break; case SERVICE_START_LIMIT_REBOOT: { - DBusError error; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; int r; - dbus_error_init(&error); - log_warning_unit(UNIT(s)->id, "%s start request repeated too quickly, rebooting.", UNIT(s)->id); r = manager_add_job_by_name(UNIT(s)->manager, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL); - if (r < 0) { + if (r < 0) log_error_unit(UNIT(s)->id, - "Failed to reboot: %s.", bus_error(&error, r)); - dbus_error_free(&error); - } + "Failed to reboot: %s.", bus_error_message(&error, r)); break; } @@ -2837,7 +2859,7 @@ static int service_watch_pid_file(Service *s) { log_debug_unit(UNIT(s)->id, "Setting watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path); - r = path_spec_watch(s->pid_file_pathspec, UNIT(s)); + r = path_spec_watch(s->pid_file_pathspec, service_dispatch_io); if (r < 0) goto fail; @@ -2866,6 +2888,7 @@ static int service_demand_pid_file(Service *s) { if (!ps) return -ENOMEM; + ps->unit = UNIT(s); ps->path = strdup(s->pid_file); if (!ps->path) { free(ps); @@ -2884,8 +2907,8 @@ static int service_demand_pid_file(Service *s) { return service_watch_pid_file(s); } -static void service_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { - Service *s = SERVICE(u); +static int service_dispatch_io(sd_event_source *source, int fd, uint32_t events, void *userdata) { + Service *s = SERVICE(userdata); assert(s); assert(fd >= 0); @@ -2893,21 +2916,23 @@ static void service_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { assert(s->pid_file_pathspec); assert(path_spec_owns_inotify_fd(s->pid_file_pathspec, fd)); - log_debug_unit(u->id, "inotify event for %s", u->id); + log_debug_unit(UNIT(s)->id, "inotify event for %s", UNIT(s)->id); if (path_spec_fd_event(s->pid_file_pathspec, events) < 0) goto fail; if (service_retry_pid_file(s) == 0) - return; + return 0; if (service_watch_pid_file(s) < 0) goto fail; - return; + return 0; + fail: service_unwatch_pid_file(s); service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES); + return 0; } static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { @@ -3180,55 +3205,48 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { unit_add_to_dbus_queue(u); } -static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) { - Service *s = SERVICE(u); +static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) { + Service *s = SERVICE(userdata); assert(s); - assert(elapsed == 1); - - if (w == &s->watchdog_watch) { - service_handle_watchdog(s); - return; - } - - assert(w == &s->timer_watch); + assert(source == s->timer_event_source); switch (s->state) { case SERVICE_START_PRE: case SERVICE_START: - log_warning_unit(u->id, - "%s operation timed out. Terminating.", u->id); + log_warning_unit(UNIT(s)->id, + "%s operation timed out. Terminating.", UNIT(s)->id); service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT); break; case SERVICE_START_POST: - log_warning_unit(u->id, - "%s operation timed out. Stopping.", u->id); + log_warning_unit(UNIT(s)->id, + "%s operation timed out. Stopping.", UNIT(s)->id); service_enter_stop(s, SERVICE_FAILURE_TIMEOUT); break; case SERVICE_RELOAD: - log_warning_unit(u->id, - "%s operation timed out. Stopping.", u->id); + log_warning_unit(UNIT(s)->id, + "%s operation timed out. Stopping.", UNIT(s)->id); s->reload_result = SERVICE_FAILURE_TIMEOUT; service_enter_running(s, SERVICE_SUCCESS); break; case SERVICE_STOP: - log_warning_unit(u->id, - "%s stopping timed out. Terminating.", u->id); + log_warning_unit(UNIT(s)->id, + "%s stopping timed out. Terminating.", UNIT(s)->id); service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT); break; case SERVICE_STOP_SIGTERM: if (s->kill_context.send_sigkill) { - log_warning_unit(u->id, - "%s stopping timed out. Killing.", u->id); + log_warning_unit(UNIT(s)->id, + "%s stopping timed out. Killing.", UNIT(s)->id); service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT); } else { - log_warning_unit(u->id, - "%s stopping timed out. Skipping SIGKILL.", u->id); + log_warning_unit(UNIT(s)->id, + "%s stopping timed out. Skipping SIGKILL.", UNIT(s)->id); service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT); } @@ -3239,46 +3257,58 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) { * Must be something we cannot kill, so let's just be * weirded out and continue */ - log_warning_unit(u->id, - "%s still around after SIGKILL. Ignoring.", u->id); + log_warning_unit(UNIT(s)->id, + "%s still around after SIGKILL. Ignoring.", UNIT(s)->id); service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT); break; case SERVICE_STOP_POST: - log_warning_unit(u->id, - "%s stopping timed out (2). Terminating.", u->id); + log_warning_unit(UNIT(s)->id, + "%s stopping timed out (2). Terminating.", UNIT(s)->id); service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT); break; case SERVICE_FINAL_SIGTERM: if (s->kill_context.send_sigkill) { - log_warning_unit(u->id, - "%s stopping timed out (2). Killing.", u->id); + log_warning_unit(UNIT(s)->id, + "%s stopping timed out (2). Killing.", UNIT(s)->id); service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT); } else { - log_warning_unit(u->id, + log_warning_unit(UNIT(s)->id, "%s stopping timed out (2). Skipping SIGKILL. Entering failed mode.", - u->id); + UNIT(s)->id); service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false); } break; case SERVICE_FINAL_SIGKILL: - log_warning_unit(u->id, - "%s still around after SIGKILL (2). Entering failed mode.", u->id); + log_warning_unit(UNIT(s)->id, + "%s still around after SIGKILL (2). Entering failed mode.", UNIT(s)->id); service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, true); break; case SERVICE_AUTO_RESTART: - log_info_unit(u->id, - "%s holdoff time over, scheduling restart.", u->id); + log_info_unit(UNIT(s)->id, + "%s holdoff time over, scheduling restart.", UNIT(s)->id); service_enter_restart(s); break; default: assert_not_reached("Timeout at wrong time."); } + + return 0; +} + +static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void *userdata) { + Service *s = SERVICE(userdata); + + assert(s); + assert(source == s->watchdog_event_source); + + service_handle_watchdog(s); + return 0; } static void service_notify_cgroup_empty_event(Unit *u) { @@ -3606,6 +3636,7 @@ static void service_bus_name_owner_change( const char *new_owner) { Service *s = SERVICE(u); + int r; assert(s); assert(name); @@ -3644,35 +3675,17 @@ static void service_bus_name_owner_change( s->state == SERVICE_RUNNING || s->state == SERVICE_RELOAD)) { - /* Try to acquire PID from bus service */ - log_debug_unit(u->id, - "Trying to acquire PID from D-Bus name..."); - - bus_query_pid(u->manager, name); - } -} - -static void service_bus_query_pid_done( - Unit *u, - const char *name, - pid_t pid) { - - Service *s = SERVICE(u); + pid_t pid; - assert(s); - assert(name); + /* Try to acquire PID from bus service */ - log_debug_unit(u->id, - "%s's D-Bus name %s is now owned by process %u", - u->id, name, (unsigned) pid); + r = sd_bus_get_owner_pid(u->manager->api_bus, name, &pid); + if (r >= 0) { + log_debug_unit(u->id, "%s's D-Bus name %s is now owned by process %u", u->id, name, (unsigned) pid); - if (s->main_pid <= 0 && - (s->state == SERVICE_START || - s->state == SERVICE_START_POST || - s->state == SERVICE_RUNNING || - s->state == SERVICE_RELOAD)){ - service_set_main_pid(s, pid); - unit_watch_pid(UNIT(s), pid); + service_set_main_pid(s, pid); + unit_watch_pid(UNIT(s), pid); + } } } @@ -3716,7 +3729,7 @@ static void service_reset_failed(Unit *u) { RATELIMIT_RESET(s->start_limit); } -static int service_kill(Unit *u, KillWho who, int signo, DBusError *error) { +static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { Service *s = SERVICE(u); return unit_kill_common(u, who, signo, s->main_pid, s->control_pid, error); @@ -3806,15 +3819,15 @@ DEFINE_STRING_TABLE_LOOKUP(start_limit_action, StartLimitAction); const UnitVTable service_vtable = { .object_size = sizeof(Service), + .exec_context_offset = offsetof(Service, exec_context), + .cgroup_context_offset = offsetof(Service, cgroup_context), + .kill_context_offset = offsetof(Service, kill_context), .sections = "Unit\0" "Service\0" "Install\0", - .private_section = "Service", - .exec_context_offset = offsetof(Service, exec_context), - .cgroup_context_offset = offsetof(Service, cgroup_context), .init = service_init, .done = service_done, @@ -3842,8 +3855,6 @@ const UnitVTable service_vtable = { .check_snapshot = service_check_snapshot, .sigchld_event = service_sigchld_event, - .timer_event = service_timer_event, - .fd_event = service_fd_event, .reset_failed = service_reset_failed, @@ -3851,19 +3862,19 @@ const UnitVTable service_vtable = { .notify_message = service_notify_message, .bus_name_owner_change = service_bus_name_owner_change, - .bus_query_pid_done = service_bus_query_pid_done, .bus_interface = "org.freedesktop.systemd1.Service", - .bus_message_handler = bus_service_message_handler, - .bus_invalidating_properties = bus_service_invalidating_properties, + .bus_vtable = bus_service_vtable, + .bus_changing_properties = bus_service_changing_properties, .bus_set_property = bus_service_set_property, .bus_commit_properties = bus_service_commit_properties, - .can_transient = true, - #ifdef HAVE_SYSV_COMPAT .enumerate = service_enumerate, #endif + + .can_transient = true, + .status_message_formats = { .starting_stopping = { [0] = "Starting %s...", diff --git a/src/core/service.h b/src/core/service.h index 37fa6ff0fa..5c53791753 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -130,7 +130,7 @@ struct Service { dual_timestamp watchdog_timestamp; usec_t watchdog_usec; - Watch watchdog_watch; + sd_event_source *watchdog_event_source; ExecCommand* exec_command[_SERVICE_EXEC_COMMAND_MAX]; @@ -191,7 +191,7 @@ struct Service { UnitRef accept_socket; - Watch timer_watch; + sd_event_source *timer_event_source; PathSpec *pid_file_pathspec; NotifyAccess notify_access; diff --git a/src/core/slice.c b/src/core/slice.c index 40d416e35e..1e42df2b8b 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -216,7 +216,7 @@ static int slice_stop(Unit *u) { return 0; } -static int slice_kill(Unit *u, KillWho who, int signo, DBusError *error) { +static int slice_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, -1, -1, error); } @@ -275,13 +275,13 @@ DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState); const UnitVTable slice_vtable = { .object_size = sizeof(Slice), + .cgroup_context_offset = offsetof(Slice, cgroup_context), + .sections = "Unit\0" "Slice\0" "Install\0", - .private_section = "Slice", - .cgroup_context_offset = offsetof(Slice, cgroup_context), .no_alias = true, .no_instances = true, @@ -306,7 +306,7 @@ const UnitVTable slice_vtable = { .sub_state_to_string = slice_sub_state_to_string, .bus_interface = "org.freedesktop.systemd1.Slice", - .bus_message_handler = bus_slice_message_handler, + .bus_vtable = bus_slice_vtable, .bus_set_property = bus_slice_set_property, .bus_commit_properties = bus_slice_commit_properties, diff --git a/src/core/snapshot.c b/src/core/snapshot.c index d11239dff3..21e89ac996 100644 --- a/src/core/snapshot.c +++ b/src/core/snapshot.c @@ -189,7 +189,7 @@ _pure_ static const char *snapshot_sub_state_to_string(Unit *u) { return snapshot_state_to_string(SNAPSHOT(u)->state); } -int snapshot_create(Manager *m, const char *name, bool cleanup, DBusError *e, Snapshot **_s) { +int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **_s) { _cleanup_free_ char *n = NULL; Unit *other, *u = NULL; Iterator i; @@ -200,20 +200,14 @@ int snapshot_create(Manager *m, const char *name, bool cleanup, DBusError *e, Sn assert(_s); if (name) { - if (!unit_name_is_valid(name, false)) { - dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name); - return -EINVAL; - } + if (!unit_name_is_valid(name, false)) + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name); - if (unit_name_to_type(name) != UNIT_SNAPSHOT) { - dbus_set_error(e, BUS_ERROR_UNIT_TYPE_MISMATCH, "Unit name %s lacks snapshot suffix.", name); - return -EINVAL; - } + if (unit_name_to_type(name) != UNIT_SNAPSHOT) + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name); - if (manager_get_unit(m, name)) { - dbus_set_error(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name); - return -EEXIST; - } + if (manager_get_unit(m, name)) + sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name); } else { @@ -293,8 +287,8 @@ const UnitVTable snapshot_vtable = { .no_gc = true, .init = snapshot_init, - .load = snapshot_load, + .coldplug = snapshot_coldplug, .dump = snapshot_dump, @@ -309,5 +303,5 @@ const UnitVTable snapshot_vtable = { .sub_state_to_string = snapshot_sub_state_to_string, .bus_interface = "org.freedesktop.systemd1.Snapshot", - .bus_message_handler = bus_snapshot_message_handler + .bus_vtable = bus_snapshot_vtable }; diff --git a/src/core/snapshot.h b/src/core/snapshot.h index 2675b1b242..e6dc661060 100644 --- a/src/core/snapshot.h +++ b/src/core/snapshot.h @@ -42,7 +42,7 @@ struct Snapshot { extern const UnitVTable snapshot_vtable; -int snapshot_create(Manager *m, const char *name, bool cleanup, DBusError *e, Snapshot **s); +int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **s); void snapshot_remove(Snapshot *s); const char* snapshot_state_to_string(SnapshotState i) _const_; diff --git a/src/core/socket.c b/src/core/socket.c index 751f20bdca..eae9465788 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -27,14 +27,15 @@ #include <sys/epoll.h> #include <signal.h> #include <arpa/inet.h> +#include <netinet/tcp.h> #include <mqueue.h> #ifdef HAVE_XATTR #include <attr/xattr.h> #endif +#include "sd-event.h" #include "unit.h" #include "socket.h" -#include "netinet/tcp.h" #include "log.h" #include "load-dropin.h" #include "load-fragment.h" @@ -46,11 +47,12 @@ #include "dbus-socket.h" #include "missing.h" #include "special.h" -#include "dbus-common.h" #include "label.h" #include "exit-status.h" #include "def.h" #include "smack-util.h" +#include "bus-util.h" +#include "bus-error.h" static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { [SOCKET_DEAD] = UNIT_INACTIVE, @@ -67,6 +69,9 @@ static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { [SOCKET_FAILED] = UNIT_FAILED }; +static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); +static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); + static void socket_init(Unit *u) { Socket *s = SOCKET(u); @@ -112,10 +117,10 @@ void socket_free_ports(Socket *s) { while ((p = s->ports)) { LIST_REMOVE(port, s->ports, p); - if (p->fd >= 0) { - unit_unwatch_fd(UNIT(s), &p->fd_watch); + sd_event_source_unref(p->event_source); + + if (p->fd >= 0) close_nointr_nofail(p->fd); - } free(p->path); free(p); @@ -149,7 +154,28 @@ static void socket_done(Unit *u) { free(s->smack_ip_in); free(s->smack_ip_out); - unit_unwatch_timer(u, &s->timer_watch); + s->timer_event_source = sd_event_source_unref(s->timer_event_source); +} + +static int socket_arm_timer(Socket *s) { + int r; + + assert(s); + + if (s->timeout_usec <= 0) { + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + return 0; + } + + if (s->timer_event_source) { + r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec); + if (r < 0) + return r; + + return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT); + } + + return sd_event_add_monotonic(UNIT(s)->manager->event, now(CLOCK_MONOTONIC) + s->timeout_usec, 0, socket_dispatch_timer, s, &s->timer_event_source); } static int socket_instantiate_service(Socket *s) { @@ -508,10 +534,10 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { "%sMessageQueueMessageSize: %li\n", prefix, s->mq_msgsize); - if (s->reuseport) + if (s->reuse_port) fprintf(f, "%sReusePort: %s\n", - prefix, yes_no(s->reuseport)); + prefix, yes_no(s->reuse_port)); if (s->smack) fprintf(f, @@ -673,10 +699,12 @@ static void socket_close_fds(Socket *s) { assert(s); LIST_FOREACH(port, p, s->ports) { + + p->event_source = sd_event_source_unref(p->event_source); + if (p->fd < 0) continue; - unit_unwatch_fd(UNIT(s), &p->fd_watch); close_nointr_nofail(p->fd); /* One little note: we should never delete any sockets @@ -769,8 +797,8 @@ static void socket_apply_socket_options(Socket *s, int fd) { if (setsockopt(fd, SOL_TCP, TCP_CONGESTION, s->tcp_congestion, strlen(s->tcp_congestion)+1) < 0) log_warning_unit(UNIT(s)->id, "TCP_CONGESTION failed: %m"); - if (s->reuseport) { - int b = s->reuseport; + if (s->reuse_port) { + int b = s->reuse_port; if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &b, sizeof(b)) < 0) log_warning_unit(UNIT(s)->id, "SO_REUSEPORT failed: %m"); } @@ -1054,6 +1082,7 @@ rollback: static void socket_unwatch_fds(Socket *s) { SocketPort *p; + int r; assert(s); @@ -1061,7 +1090,11 @@ static void socket_unwatch_fds(Socket *s) { if (p->fd < 0) continue; - unit_unwatch_fd(UNIT(s), &p->fd_watch); + if (p->event_source) { + r = sd_event_source_set_enabled(p->event_source, SD_EVENT_OFF); + if (r < 0) + log_debug_unit(UNIT(s)->id, "Failed to disable event source."); + } } } @@ -1075,13 +1108,15 @@ static int socket_watch_fds(Socket *s) { if (p->fd < 0) continue; - p->fd_watch.socket_accept = - s->accept && - p->type == SOCKET_SOCKET && - socket_address_can_accept(&p->address); + if (p->event_source) + r = sd_event_source_set_enabled(p->event_source, SD_EVENT_ON); + else + r = sd_event_add_io(UNIT(s)->manager->event, p->fd, EPOLLIN, socket_dispatch_io, p, &p->event_source); - if ((r = unit_watch_fd(UNIT(s), p->fd, EPOLLIN, &p->fd_watch)) < 0) + if (r < 0) { + log_warning_unit(UNIT(s)->id, "Failed to watch listening fds: %s", strerror(-r)); goto fail; + } } return 0; @@ -1106,7 +1141,8 @@ static void socket_set_state(Socket *s, SocketState state) { state != SOCKET_STOP_POST && state != SOCKET_FINAL_SIGTERM && state != SOCKET_FINAL_SIGKILL) { - unit_unwatch_timer(UNIT(s), &s->timer_watch); + + s->timer_event_source = sd_event_source_unref(s->timer_event_source); socket_unwatch_control_pid(s); s->control_command = NULL; s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; @@ -1157,7 +1193,7 @@ static int socket_coldplug(Unit *u) { if (r < 0) return r; - r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_usec, &s->timer_watch); + r = socket_arm_timer(s); if (r < 0) return r; } @@ -1167,13 +1203,17 @@ static int socket_coldplug(Unit *u) { s->deserialized_state == SOCKET_RUNNING || s->deserialized_state == SOCKET_STOP_PRE || s->deserialized_state == SOCKET_STOP_PRE_SIGTERM || - s->deserialized_state == SOCKET_STOP_PRE_SIGKILL) - if ((r = socket_open_fds(s)) < 0) + s->deserialized_state == SOCKET_STOP_PRE_SIGKILL) { + r = socket_open_fds(s); + if (r < 0) return r; + } - if (s->deserialized_state == SOCKET_LISTENING) - if ((r = socket_watch_fds(s)) < 0) + if (s->deserialized_state == SOCKET_LISTENING) { + r = socket_watch_fds(s); + if (r < 0) return r; + } socket_set_state(s, s->deserialized_state); } @@ -1192,7 +1232,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { unit_realize_cgroup(UNIT(s)); - r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_usec, &s->timer_watch); + r = socket_arm_timer(s); if (r < 0) goto fail; @@ -1219,7 +1259,8 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { if (r < 0) goto fail; - if ((r = unit_watch_pid(UNIT(s), pid)) < 0) + r = unit_watch_pid(UNIT(s), pid); + if (r < 0) /* FIXME: we need to do something here */ goto fail; @@ -1228,7 +1269,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { return 0; fail: - unit_unwatch_timer(UNIT(s), &s->timer_watch); + s->timer_event_source = sd_event_source_unref(s->timer_event_source); return r; } @@ -1292,7 +1333,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) { goto fail; if (r > 0) { - r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_usec, &s->timer_watch); + r = socket_arm_timer(s); if (r < 0) goto fail; @@ -1423,11 +1464,10 @@ fail: } static void socket_enter_running(Socket *s, int cfd) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; int r; - DBusError error; assert(s); - dbus_error_init(&error); /* We don't take connections anymore if we are supposed to * shut down anyway */ @@ -1548,13 +1588,11 @@ fail: "%s failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s", UNIT(s)->id, cfd >= 0 ? "template" : "non-template", - bus_error(&error, r)); + bus_error_message(&error, r)); socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES); if (cfd >= 0) close_nointr_nofail(cfd); - - dbus_error_free(&error); } static void socket_run_next(Socket *s) { @@ -1952,20 +1990,39 @@ const char* socket_port_type_to_string(SocketPort *p) { assert(p); switch (p->type) { - case SOCKET_SOCKET: - switch (p->address.type) { - case SOCK_STREAM: return "Stream"; - case SOCK_DGRAM: return "Datagram"; - case SOCK_SEQPACKET: return "SequentialPacket"; - case SOCK_RAW: - if (socket_address_family(&p->address) == AF_NETLINK) - return "Netlink"; - default: return "Invalid"; - } - case SOCKET_SPECIAL: return "Special"; - case SOCKET_MQUEUE: return "MessageQueue"; - case SOCKET_FIFO: return "FIFO"; - default: return NULL; + + case SOCKET_SOCKET: + + switch (p->address.type) { + + case SOCK_STREAM: + return "Stream"; + + case SOCK_DGRAM: + return "Datagram"; + + case SOCK_SEQPACKET: + return "SequentialPacket"; + + case SOCK_RAW: + if (socket_address_family(&p->address) == AF_NETLINK) + return "Netlink"; + + default: + return NULL; + } + + case SOCKET_SPECIAL: + return "Special"; + + case SOCKET_MQUEUE: + return "MessageQueue"; + + case SOCKET_FIFO: + return "FIFO"; + + default: + return NULL; } } @@ -1977,33 +2034,36 @@ _pure_ static bool socket_check_gc(Unit *u) { return s->n_connections > 0; } -static void socket_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { - Socket *s = SOCKET(u); +static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + SocketPort *p = userdata; int cfd = -1; - assert(s); + assert(p); assert(fd >= 0); - if (s->state != SOCKET_LISTENING) - return; + if (p->socket->state != SOCKET_LISTENING) + return 0; - log_debug_unit(u->id, "Incoming traffic on %s", u->id); + log_debug_unit(UNIT(p->socket)->id, "Incoming traffic on %s", UNIT(p->socket)->id); - if (events != EPOLLIN) { + if (revents != EPOLLIN) { - if (events & EPOLLHUP) - log_error_unit(u->id, + if (revents & EPOLLHUP) + log_error_unit(UNIT(p->socket)->id, "%s: Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.", - u->id); + UNIT(p->socket)->id); else - log_error_unit(u->id, + log_error_unit(UNIT(p->socket)->id, "%s: Got unexpected poll event (0x%x) on socket.", - u->id, events); + UNIT(p->socket)->id, revents); goto fail; } - if (w->socket_accept) { + if (p->socket->accept && + p->type == SOCKET_SOCKET && + socket_address_can_accept(&p->address)) { + for (;;) { cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK); @@ -2012,7 +2072,7 @@ static void socket_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { if (errno == EINTR) continue; - log_error_unit(u->id, + log_error_unit(UNIT(p->socket)->id, "Failed to accept socket: %m"); goto fail; } @@ -2020,14 +2080,15 @@ static void socket_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { break; } - socket_apply_socket_options(s, cfd); + socket_apply_socket_options(p->socket, cfd); } - socket_enter_running(s, cfd); - return; + socket_enter_running(p->socket, cfd); + return 0; fail: - socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES); + socket_enter_stop_pre(p->socket, SOCKET_FAILURE_RESOURCES); + return 0; } static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) { @@ -2124,81 +2185,82 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) { unit_add_to_dbus_queue(u); } -static void socket_timer_event(Unit *u, uint64_t elapsed, Watch *w) { - Socket *s = SOCKET(u); +static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) { + Socket *s = SOCKET(userdata); assert(s); - assert(elapsed == 1); - assert(w == &s->timer_watch); + assert(s->timer_event_source == source); switch (s->state) { case SOCKET_START_PRE: - log_warning_unit(u->id, - "%s starting timed out. Terminating.", u->id); + log_warning_unit(UNIT(s)->id, + "%s starting timed out. Terminating.", UNIT(s)->id); socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT); break; case SOCKET_START_POST: - log_warning_unit(u->id, - "%s starting timed out. Stopping.", u->id); + log_warning_unit(UNIT(s)->id, + "%s starting timed out. Stopping.", UNIT(s)->id); socket_enter_stop_pre(s, SOCKET_FAILURE_TIMEOUT); break; case SOCKET_STOP_PRE: - log_warning_unit(u->id, - "%s stopping timed out. Terminating.", u->id); + log_warning_unit(UNIT(s)->id, + "%s stopping timed out. Terminating.", UNIT(s)->id); socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, SOCKET_FAILURE_TIMEOUT); break; case SOCKET_STOP_PRE_SIGTERM: if (s->kill_context.send_sigkill) { - log_warning_unit(u->id, - "%s stopping timed out. Killing.", u->id); + log_warning_unit(UNIT(s)->id, + "%s stopping timed out. Killing.", UNIT(s)->id); socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, SOCKET_FAILURE_TIMEOUT); } else { - log_warning_unit(u->id, + log_warning_unit(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL. Ignoring.", - u->id); + UNIT(s)->id); socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT); } break; case SOCKET_STOP_PRE_SIGKILL: - log_warning_unit(u->id, - "%s still around after SIGKILL. Ignoring.", u->id); + log_warning_unit(UNIT(s)->id, + "%s still around after SIGKILL. Ignoring.", UNIT(s)->id); socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT); break; case SOCKET_STOP_POST: - log_warning_unit(u->id, - "%s stopping timed out (2). Terminating.", u->id); + log_warning_unit(UNIT(s)->id, + "%s stopping timed out (2). Terminating.", UNIT(s)->id); socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT); break; case SOCKET_FINAL_SIGTERM: if (s->kill_context.send_sigkill) { - log_warning_unit(u->id, - "%s stopping timed out (2). Killing.", u->id); + log_warning_unit(UNIT(s)->id, + "%s stopping timed out (2). Killing.", UNIT(s)->id); socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_FAILURE_TIMEOUT); } else { - log_warning_unit(u->id, + log_warning_unit(UNIT(s)->id, "%s stopping timed out (2). Skipping SIGKILL. Ignoring.", - u->id); + UNIT(s)->id); socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT); } break; case SOCKET_FINAL_SIGKILL: - log_warning_unit(u->id, + log_warning_unit(UNIT(s)->id, "%s still around after SIGKILL (2). Entering failed mode.", - u->id); + UNIT(s)->id); socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT); break; default: assert_not_reached("Timeout at wrong time."); } + + return 0; } int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) { @@ -2319,7 +2381,7 @@ static void socket_trigger_notify(Unit *u, Unit *other) { socket_set_state(s, SOCKET_RUNNING); } -static int socket_kill(Unit *u, KillWho who, int signo, DBusError *error) { +static int socket_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, -1, SOCKET(u)->control_pid, error); } @@ -2363,22 +2425,20 @@ DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult); const UnitVTable socket_vtable = { .object_size = sizeof(Socket), + .exec_context_offset = offsetof(Socket, exec_context), + .cgroup_context_offset = offsetof(Socket, cgroup_context), + .kill_context_offset = offsetof(Socket, kill_context), .sections = "Unit\0" "Socket\0" "Install\0", - .private_section = "Socket", - .exec_context_offset = offsetof(Socket, exec_context), - .cgroup_context_offset = offsetof(Socket, cgroup_context), .init = socket_init, .done = socket_done, .load = socket_load, - .kill = socket_kill, - .coldplug = socket_coldplug, .dump = socket_dump, @@ -2386,6 +2446,8 @@ const UnitVTable socket_vtable = { .start = socket_start, .stop = socket_stop, + .kill = socket_kill, + .serialize = socket_serialize, .deserialize_item = socket_deserialize_item, .distribute_fds = socket_distribute_fds, @@ -2395,17 +2457,15 @@ const UnitVTable socket_vtable = { .check_gc = socket_check_gc, - .fd_event = socket_fd_event, .sigchld_event = socket_sigchld_event, - .timer_event = socket_timer_event, .trigger_notify = socket_trigger_notify, .reset_failed = socket_reset_failed, .bus_interface = "org.freedesktop.systemd1.Socket", - .bus_message_handler = bus_socket_message_handler, - .bus_invalidating_properties = bus_socket_invalidating_properties, + .bus_vtable = bus_socket_vtable, + .bus_changing_properties = bus_socket_changing_properties, .bus_set_property = bus_socket_set_property, .bus_commit_properties = bus_socket_commit_properties, diff --git a/src/core/socket.h b/src/core/socket.h index 3d7eadc9fe..db0796c4a3 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -77,12 +77,14 @@ typedef enum SocketResult { } SocketResult; typedef struct SocketPort { + Socket *socket; + SocketType type; int fd; SocketAddress address; char *path; - Watch fd_watch; + sd_event_source *event_source; LIST_FIELDS(struct SocketPort, port); } SocketPort; @@ -111,7 +113,7 @@ struct Socket { SocketState state, deserialized_state; - Watch timer_watch; + sd_event_source *timer_event_source; ExecCommand* control_command; SocketExecCommand control_command_id; @@ -144,7 +146,7 @@ struct Socket { size_t pipe_size; char *bind_to_device; char *tcp_congestion; - bool reuseport; + bool reuse_port; long mq_maxmsg; long mq_msgsize; diff --git a/src/core/swap.c b/src/core/swap.c index c48c0bd5f9..a798eca3f1 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -53,6 +53,9 @@ static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = { [SWAP_FAILED] = UNIT_FAILED }; +static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); +static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); + static void swap_unset_proc_swaps(Swap *s) { Swap *first; Hashmap *swaps; @@ -96,8 +99,6 @@ static void swap_init(Unit *u) { s->parameters_proc_swaps.priority = s->parameters_fragment.priority = -1; - s->timer_watch.type = WATCH_INVALID; - s->control_command_id = _SWAP_EXEC_COMMAND_INVALID; UNIT(s)->ignore_on_isolate = true; @@ -134,7 +135,28 @@ static void swap_done(Unit *u) { swap_unwatch_control_pid(s); - unit_unwatch_timer(u, &s->timer_watch); + s->timer_event_source = sd_event_source_unref(s->timer_event_source); +} + +static int swap_arm_timer(Swap *s) { + int r; + + assert(s); + + if (s->timeout_usec <= 0) { + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + return 0; + } + + if (s->timer_event_source) { + r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec); + if (r < 0) + return r; + + return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT); + } + + return sd_event_add_monotonic(UNIT(s)->manager->event, now(CLOCK_MONOTONIC) + s->timeout_usec, 0, swap_dispatch_timer, s, &s->timer_event_source); } static int swap_add_device_links(Swap *s) { @@ -465,7 +487,7 @@ static void swap_set_state(Swap *s, SwapState state) { state != SWAP_DEACTIVATING && state != SWAP_DEACTIVATING_SIGTERM && state != SWAP_DEACTIVATING_SIGKILL) { - unit_unwatch_timer(UNIT(s), &s->timer_watch); + s->timer_event_source = sd_event_source_unref(s->timer_event_source); swap_unwatch_control_pid(s); s->control_command = NULL; s->control_command_id = _SWAP_EXEC_COMMAND_INVALID; @@ -511,7 +533,7 @@ static int swap_coldplug(Unit *u) { if (r < 0) return r; - r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_usec, &s->timer_watch); + r = swap_arm_timer(s); if (r < 0) return r; } @@ -576,7 +598,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { unit_realize_cgroup(UNIT(s)); - r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_usec, &s->timer_watch); + r = swap_arm_timer(s); if (r < 0) goto fail; @@ -607,7 +629,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { return 0; fail: - unit_unwatch_timer(UNIT(s), &s->timer_watch); + s->timer_event_source = sd_event_source_unref(s->timer_event_source); return r; } @@ -650,7 +672,7 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) { goto fail; if (r > 0) { - r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_usec, &s->timer_watch); + r = swap_arm_timer(s); if (r < 0) goto fail; @@ -977,54 +999,55 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) { u->manager->request_reload = true; } -static void swap_timer_event(Unit *u, uint64_t elapsed, Watch *w) { - Swap *s = SWAP(u); +static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) { + Swap *s = SWAP(userdata); assert(s); - assert(elapsed == 1); - assert(w == &s->timer_watch); + assert(s->timer_event_source == source); switch (s->state) { case SWAP_ACTIVATING: - log_warning_unit(u->id, "%s activation timed out. Stopping.", u->id); + log_warning_unit(UNIT(s)->id, "%s activation timed out. Stopping.", UNIT(s)->id); swap_enter_signal(s, SWAP_ACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT); break; case SWAP_DEACTIVATING: - log_warning_unit(u->id, "%s deactivation timed out. Stopping.", u->id); + log_warning_unit(UNIT(s)->id, "%s deactivation timed out. Stopping.", UNIT(s)->id); swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT); break; case SWAP_ACTIVATING_SIGTERM: if (s->kill_context.send_sigkill) { - log_warning_unit(u->id, "%s activation timed out. Killing.", u->id); + log_warning_unit(UNIT(s)->id, "%s activation timed out. Killing.", UNIT(s)->id); swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT); } else { - log_warning_unit(u->id, "%s activation timed out. Skipping SIGKILL. Ignoring.", u->id); + log_warning_unit(UNIT(s)->id, "%s activation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id); swap_enter_dead(s, SWAP_FAILURE_TIMEOUT); } break; case SWAP_DEACTIVATING_SIGTERM: if (s->kill_context.send_sigkill) { - log_warning_unit(u->id, "%s deactivation timed out. Killing.", u->id); + log_warning_unit(UNIT(s)->id, "%s deactivation timed out. Killing.", UNIT(s)->id); swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT); } else { - log_warning_unit(u->id, "%s deactivation timed out. Skipping SIGKILL. Ignoring.", u->id); + log_warning_unit(UNIT(s)->id, "%s deactivation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id); swap_enter_dead(s, SWAP_FAILURE_TIMEOUT); } break; case SWAP_ACTIVATING_SIGKILL: case SWAP_DEACTIVATING_SIGKILL: - log_warning_unit(u->id, "%s swap process still around after SIGKILL. Ignoring.", u->id); + log_warning_unit(UNIT(s)->id, "%s swap process still around after SIGKILL. Ignoring.", UNIT(s)->id); swap_enter_dead(s, SWAP_FAILURE_TIMEOUT); break; default: assert_not_reached("Timeout at wrong time."); } + + return 0; } static int swap_load_proc_swaps(Manager *m, bool set_flags) { @@ -1068,23 +1091,13 @@ static int swap_load_proc_swaps(Manager *m, bool set_flags) { return r; } -int swap_dispatch_reload(Manager *m) { - /* This function should go as soon as the kernel properly notifies us */ - - if (_likely_(!m->request_reload)) - return 0; - - m->request_reload = false; - - return swap_fd_event(m, EPOLLPRI); -} - -int swap_fd_event(Manager *m, int events) { +static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; Unit *u; int r; assert(m); - assert(events & EPOLLPRI); + assert(revents & EPOLLPRI); r = swap_load_proc_swaps(m, true); if (r < 0) { @@ -1212,6 +1225,8 @@ fail: static void swap_shutdown(Manager *m) { assert(m); + m->swap_event_source = sd_event_source_unref(m->swap_event_source); + if (m->proc_swaps) { fclose(m->proc_swaps); m->proc_swaps = NULL; @@ -1226,26 +1241,23 @@ static int swap_enumerate(Manager *m) { assert(m); if (!m->proc_swaps) { - struct epoll_event ev = { - .events = EPOLLPRI, - .data.ptr = &m->swap_watch, - }; - m->proc_swaps = fopen("/proc/swaps", "re"); if (!m->proc_swaps) - return (errno == ENOENT) ? 0 : -errno; - - m->swap_watch.type = WATCH_SWAP; - m->swap_watch.fd = fileno(m->proc_swaps); + return errno == ENOENT ? 0 : -errno; - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->swap_watch.fd, &ev) < 0) - return -errno; + r = sd_event_add_io(m->event, fileno(m->proc_swaps), EPOLLPRI, swap_dispatch_io, m, &m->swap_event_source); + if (r < 0) + goto fail; } r = swap_load_proc_swaps(m, false); if (r < 0) - swap_shutdown(m); + goto fail; + + return 0; +fail: + swap_shutdown(m); return r; } @@ -1260,7 +1272,7 @@ static void swap_reset_failed(Unit *u) { s->result = SWAP_SUCCESS; } -static int swap_kill(Unit *u, KillWho who, int signo, DBusError *error) { +static int swap_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, -1, SWAP(u)->control_pid, error); } @@ -1298,15 +1310,15 @@ DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult); const UnitVTable swap_vtable = { .object_size = sizeof(Swap), + .exec_context_offset = offsetof(Swap, exec_context), + .cgroup_context_offset = offsetof(Swap, cgroup_context), + .kill_context_offset = offsetof(Swap, kill_context), .sections = "Unit\0" "Swap\0" "Install\0", - .private_section = "Swap", - .exec_context_offset = offsetof(Swap, exec_context), - .cgroup_context_offset = offsetof(Swap, cgroup_context), .no_alias = true, .no_instances = true, @@ -1333,13 +1345,12 @@ const UnitVTable swap_vtable = { .check_gc = swap_check_gc, .sigchld_event = swap_sigchld_event, - .timer_event = swap_timer_event, .reset_failed = swap_reset_failed, .bus_interface = "org.freedesktop.systemd1.Swap", - .bus_message_handler = bus_swap_message_handler, - .bus_invalidating_properties = bus_swap_invalidating_properties, + .bus_vtable = bus_swap_vtable, + .bus_changing_properties = bus_swap_changing_properties, .bus_set_property = bus_swap_set_property, .bus_commit_properties = bus_swap_commit_properties, diff --git a/src/core/swap.h b/src/core/swap.h index dd89535895..c51c55f839 100644 --- a/src/core/swap.h +++ b/src/core/swap.h @@ -96,7 +96,7 @@ struct Swap { SwapExecCommand control_command_id; pid_t control_pid; - Watch timer_watch; + sd_event_source *timer_event_source; /* In order to be able to distinguish dependencies on different device nodes we might end up creating multiple @@ -107,9 +107,6 @@ struct Swap { extern const UnitVTable swap_vtable; -int swap_dispatch_reload(Manager *m); -int swap_fd_event(Manager *m, int events); - const char* swap_state_to_string(SwapState i) _const_; SwapState swap_state_from_string(const char *s) _pure_; diff --git a/src/core/target.c b/src/core/target.c index 3fffa0d2f5..68be22b38d 100644 --- a/src/core/target.c +++ b/src/core/target.c @@ -205,6 +205,7 @@ DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState); const UnitVTable target_vtable = { .object_size = sizeof(Target), + .sections = "Unit\0" "Target\0" @@ -225,7 +226,7 @@ const UnitVTable target_vtable = { .sub_state_to_string = target_sub_state_to_string, .bus_interface = "org.freedesktop.systemd1.Target", - .bus_message_handler = bus_target_message_handler, + .bus_vtable = bus_target_vtable, .status_message_formats = { .finished_start_job = { diff --git a/src/core/timer.c b/src/core/timer.c index b90c85f823..5bc01a26ff 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -26,7 +26,8 @@ #include "timer.h" #include "dbus-timer.h" #include "special.h" -#include "dbus-common.h" +#include "bus-util.h" +#include "bus-error.h" static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = { [TIMER_DEAD] = UNIT_INACTIVE, @@ -36,6 +37,8 @@ static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = { [TIMER_FAILED] = UNIT_FAILED }; +static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata); + static void timer_init(Unit *u) { Timer *t = TIMER(u); @@ -44,8 +47,6 @@ static void timer_init(Unit *u) { t->next_elapse_monotonic = (usec_t) -1; t->next_elapse_realtime = (usec_t) -1; - watch_init(&t->monotonic_watch); - watch_init(&t->realtime_watch); } void timer_free_values(Timer *t) { @@ -70,8 +71,8 @@ static void timer_done(Unit *u) { timer_free_values(t); - unit_unwatch_timer(u, &t->monotonic_watch); - unit_unwatch_timer(u, &t->realtime_watch); + t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source); + t->realtime_event_source = sd_event_source_unref(t->realtime_event_source); } static int timer_verify(Timer *t) { @@ -189,8 +190,8 @@ static void timer_set_state(Timer *t, TimerState state) { t->state = state; if (state != TIMER_WAITING) { - unit_unwatch_timer(UNIT(t), &t->monotonic_watch); - unit_unwatch_timer(UNIT(t), &t->realtime_watch); + t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source); + t->realtime_event_source = sd_event_source_unref(t->realtime_event_source); } if (state != old_state) @@ -230,6 +231,7 @@ static void timer_enter_dead(Timer *t, TimerResult f) { timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD); } + static void timer_enter_waiting(Timer *t, bool initial) { TimerValue *v; usec_t base = 0; @@ -337,11 +339,24 @@ static void timer_enter_waiting(Timer *t, bool initial) { UNIT(t)->id, format_timespan(buf, sizeof(buf), t->next_elapse_monotonic > ts.monotonic ? t->next_elapse_monotonic - ts.monotonic : 0, 0)); - r = unit_watch_timer(UNIT(t), CLOCK_MONOTONIC, false, t->next_elapse_monotonic, &t->monotonic_watch); + if (t->monotonic_event_source) { + r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic); + if (r < 0) + goto fail; + + r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT); + } else + r = sd_event_add_monotonic(UNIT(t)->manager->event, t->next_elapse_monotonic, 0, timer_dispatch, t, &t->monotonic_event_source); + if (r < 0) goto fail; - } else - unit_unwatch_timer(UNIT(t), &t->monotonic_watch); + + } else if (t->monotonic_event_source) { + r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF); + + if (r < 0) + goto fail; + } if (found_realtime) { char buf[FORMAT_TIMESTAMP_MAX]; @@ -350,11 +365,24 @@ static void timer_enter_waiting(Timer *t, bool initial) { UNIT(t)->id, format_timestamp(buf, sizeof(buf), t->next_elapse_realtime)); - r = unit_watch_timer(UNIT(t), CLOCK_REALTIME, false, t->next_elapse_realtime, &t->realtime_watch); + if (t->realtime_event_source) { + r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime); + if (r < 0) + goto fail; + + r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT); + } else + r = sd_event_add_realtime(UNIT(t)->manager->event, t->next_elapse_realtime, 0, timer_dispatch, t, &t->realtime_event_source); + if (r < 0) goto fail; - } else - unit_unwatch_timer(UNIT(t), &t->realtime_watch); + + } else if (t->realtime_event_source) { + r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF); + + if (r < 0) + goto fail; + } timer_set_state(t, TIMER_WAITING); return; @@ -367,11 +395,10 @@ fail: } static void timer_enter_running(Timer *t) { - DBusError error; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(t); - dbus_error_init(&error); /* Don't start job if we are supposed to go down */ if (unit_stop_pending(UNIT(t))) @@ -390,10 +417,8 @@ static void timer_enter_running(Timer *t) { fail: log_warning_unit(UNIT(t)->id, "%s failed to queue unit startup job: %s", - UNIT(t)->id, bus_error(&error, r)); + UNIT(t)->id, bus_error_message(&error, r)); timer_enter_dead(t, TIMER_FAILURE_RESOURCES); - - dbus_error_free(&error); } static int timer_start(Unit *u) { @@ -476,17 +501,17 @@ _pure_ static const char *timer_sub_state_to_string(Unit *u) { return timer_state_to_string(TIMER(u)->state); } -static void timer_timer_event(Unit *u, uint64_t elapsed, Watch *w) { - Timer *t = TIMER(u); +static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) { + Timer *t = TIMER(userdata); assert(t); - assert(elapsed == 1); if (t->state != TIMER_WAITING) - return; + return 0; - log_debug_unit(u->id, "Timer elapsed on %s", u->id); + log_debug_unit(UNIT(t)->id, "Timer elapsed on %s", UNIT(t)->id); timer_enter_running(t); + return 0; } static void timer_trigger_notify(Unit *u, Unit *other) { @@ -587,6 +612,7 @@ DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult); const UnitVTable timer_vtable = { .object_size = sizeof(Timer), + .sections = "Unit\0" "Timer\0" @@ -609,14 +635,12 @@ const UnitVTable timer_vtable = { .active_state = timer_active_state, .sub_state_to_string = timer_sub_state_to_string, - .timer_event = timer_timer_event, - .trigger_notify = timer_trigger_notify, .reset_failed = timer_reset_failed, .time_change = timer_time_change, .bus_interface = "org.freedesktop.systemd1.Timer", - .bus_message_handler = bus_timer_message_handler, - .bus_invalidating_properties = bus_timer_invalidating_properties + .bus_vtable = bus_timer_vtable, + .bus_changing_properties = bus_timer_changing_properties, }; diff --git a/src/core/timer.h b/src/core/timer.h index 4168553e9d..b3722f0028 100644 --- a/src/core/timer.h +++ b/src/core/timer.h @@ -75,8 +75,8 @@ struct Timer { TimerState state, deserialized_state; - Watch monotonic_watch; - Watch realtime_watch; + sd_event_source *monotonic_event_source; + sd_event_source *realtime_event_source; TimerResult result; diff --git a/src/core/transaction.c b/src/core/transaction.c index ba7d8d9828..e2ff0bd1e5 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -22,9 +22,10 @@ #include <unistd.h> #include <fcntl.h> -#include "transaction.h" #include "bus-errors.h" -#include "dbus-common.h" +#include "bus-util.h" +#include "bus-error.h" +#include "transaction.h" static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies); @@ -231,7 +232,7 @@ static int delete_one_unmergeable_job(Transaction *tr, Job *j) { return -EINVAL; } -static int transaction_merge_jobs(Transaction *tr, DBusError *e) { +static int transaction_merge_jobs(Transaction *tr, sd_bus_error *e) { Job *j; Iterator i; int r; @@ -261,8 +262,9 @@ static int transaction_merge_jobs(Transaction *tr, DBusError *e) { return -EAGAIN; /* We couldn't merge anything. Failure */ - dbus_set_error(e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, "Transaction contains conflicting jobs '%s' and '%s' for %s. Probably contradicting requirement dependencies configured.", - job_type_to_string(t), job_type_to_string(k->type), k->unit->id); + sd_bus_error_setf( + e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, "Transaction contains conflicting jobs '%s' and '%s' for %s. Probably contradicting requirement dependencies configured.", + job_type_to_string(t), job_type_to_string(k->type), k->unit->id); return r; } } @@ -334,7 +336,7 @@ _pure_ static bool unit_matters_to_anchor(Unit *u, Job *j) { return false; } -static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, DBusError *e) { +static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) { Iterator i; Unit *u; int r; @@ -405,8 +407,8 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi log_error("Unable to break cycle"); - dbus_set_error(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, - "Transaction order is cyclic. See system logs for details."); + sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, + "Transaction order is cyclic. See system logs for details."); return -ENOEXEC; } @@ -445,7 +447,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi return 0; } -static int transaction_verify_order(Transaction *tr, unsigned *generation, DBusError *e) { +static int transaction_verify_order(Transaction *tr, unsigned *generation, sd_bus_error *e) { Job *j; int r; Iterator i; @@ -490,7 +492,7 @@ rescan: } } -static int transaction_is_destructive(Transaction *tr, JobMode mode, DBusError *e) { +static int transaction_is_destructive(Transaction *tr, JobMode mode, sd_bus_error *e) { Iterator i; Job *j; @@ -508,7 +510,7 @@ static int transaction_is_destructive(Transaction *tr, JobMode mode, DBusError * if (j->unit->job && (mode == JOB_FAIL || j->unit->job->irreversible) && !job_type_is_superset(j->type, j->unit->job->type)) { - dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive."); + sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive."); return -EEXIST; } } @@ -635,7 +637,7 @@ rollback: return r; } -int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e) { +int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e) { Iterator i; Job *j; int r; @@ -677,7 +679,7 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e break; if (r != -EAGAIN) { - log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error(e, r)); + log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error_message(e, r)); return r; } @@ -694,7 +696,7 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e break; if (r != -EAGAIN) { - log_warning("Requested transaction contains unmergeable jobs: %s", bus_error(e, r)); + log_warning("Requested transaction contains unmergeable jobs: %s", bus_error_message(e, r)); return r; } @@ -713,7 +715,7 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e /* Ninth step: check whether we can actually apply this */ r = transaction_is_destructive(tr, mode, e); if (r < 0) { - log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r)); + log_notice("Requested transaction contradicts existing jobs: %s", bus_error_message(e, r)); return r; } @@ -835,7 +837,7 @@ int transaction_add_job_and_dependencies( bool conflicts, bool ignore_requirements, bool ignore_order, - DBusError *e) { + sd_bus_error *e) { Job *ret; Iterator i; Unit *dep; @@ -856,12 +858,12 @@ int transaction_add_job_and_dependencies( unit->load_state != UNIT_ERROR && unit->load_state != UNIT_NOT_FOUND && unit->load_state != UNIT_MASKED) { - dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id); + sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id); return -EINVAL; } if (type != JOB_STOP && unit->load_state == UNIT_ERROR) { - dbus_set_error(e, BUS_ERROR_LOAD_FAILED, + sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s failed to load: %s. " "See system logs and 'systemctl status %s' for details.", unit->id, @@ -871,7 +873,7 @@ int transaction_add_job_and_dependencies( } if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND) { - dbus_set_error(e, BUS_ERROR_LOAD_FAILED, + sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s failed to load: %s.", unit->id, strerror(-unit->load_error)); @@ -879,12 +881,12 @@ int transaction_add_job_and_dependencies( } if (type != JOB_STOP && unit->load_state == UNIT_MASKED) { - dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->id); + sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED, "Unit %s is masked.", unit->id); return -EADDRNOTAVAIL; } if (!unit_job_is_applicable(unit, type)) { - dbus_set_error(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", job_type_to_string(type), unit->id); + sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", job_type_to_string(type), unit->id); return -EBADR; } @@ -916,10 +918,10 @@ int transaction_add_job_and_dependencies( if (r < 0) { log_warning_unit(dep->id, "Cannot add dependency job for unit %s, ignoring: %s", - dep->id, bus_error(e, r)); + dep->id, bus_error_message(e, r)); if (e) - dbus_error_free(e); + sd_bus_error_free(e); } } @@ -935,7 +937,7 @@ int transaction_add_job_and_dependencies( goto fail; if (e) - dbus_error_free(e); + sd_bus_error_free(e); } } @@ -946,7 +948,7 @@ int transaction_add_job_and_dependencies( goto fail; if (e) - dbus_error_free(e); + sd_bus_error_free(e); } } @@ -955,10 +957,10 @@ int transaction_add_job_and_dependencies( if (r < 0) { log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id, "Cannot add dependency job for unit %s, ignoring: %s", - dep->id, bus_error(e, r)); + dep->id, bus_error_message(e, r)); if (e) - dbus_error_free(e); + sd_bus_error_free(e); } } @@ -967,10 +969,10 @@ int transaction_add_job_and_dependencies( if (r < 0) { log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id, "Cannot add dependency job for unit %s, ignoring: %s", - dep->id, bus_error(e, r)); + dep->id, bus_error_message(e, r)); if (e) - dbus_error_free(e); + sd_bus_error_free(e); } } @@ -981,7 +983,7 @@ int transaction_add_job_and_dependencies( goto fail; if (e) - dbus_error_free(e); + sd_bus_error_free(e); } } @@ -990,10 +992,10 @@ int transaction_add_job_and_dependencies( if (r < 0) { log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id, "Cannot add dependency job for unit %s, ignoring: %s", - dep->id, bus_error(e, r)); + dep->id, bus_error_message(e, r)); if (e) - dbus_error_free(e); + sd_bus_error_free(e); } } @@ -1004,7 +1006,7 @@ int transaction_add_job_and_dependencies( goto fail; if (e) - dbus_error_free(e); + sd_bus_error_free(e); } } @@ -1013,10 +1015,10 @@ int transaction_add_job_and_dependencies( if (r < 0) { log_warning_unit(dep->id, "Cannot add dependency job for unit %s, ignoring: %s", - dep->id, bus_error(e, r)); + dep->id, bus_error_message(e, r)); if (e) - dbus_error_free(e); + sd_bus_error_free(e); } } @@ -1031,7 +1033,7 @@ int transaction_add_job_and_dependencies( goto fail; if (e) - dbus_error_free(e); + sd_bus_error_free(e); } } @@ -1042,7 +1044,7 @@ int transaction_add_job_and_dependencies( goto fail; if (e) - dbus_error_free(e); + sd_bus_error_free(e); } } @@ -1053,7 +1055,7 @@ int transaction_add_job_and_dependencies( goto fail; if (e) - dbus_error_free(e); + sd_bus_error_free(e); } } @@ -1066,10 +1068,10 @@ int transaction_add_job_and_dependencies( if (r < 0) { log_warning_unit(dep->id, "Cannot add dependency reload job for unit %s, ignoring: %s", - dep->id, bus_error(e, r)); + dep->id, bus_error_message(e, r)); if (e) - dbus_error_free(e); + sd_bus_error_free(e); } } } diff --git a/src/core/transaction.h b/src/core/transaction.h index b6ee237ef8..d949b21b8d 100644 --- a/src/core/transaction.h +++ b/src/core/transaction.h @@ -48,7 +48,7 @@ int transaction_add_job_and_dependencies( bool conflicts, bool ignore_requirements, bool ignore_order, - DBusError *e); -int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e); + sd_bus_error *e); +int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e); int transaction_add_isolate_jobs(Transaction *tr, Manager *m); void transaction_abort(Transaction *tr); diff --git a/src/core/unit.c b/src/core/unit.c index 7f463f311b..1173f0b160 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -29,8 +29,8 @@ #include <unistd.h> #include <sys/stat.h> -#include "systemd/sd-id128.h" -#include "systemd/sd-messages.h" +#include "sd-id128.h" +#include "sd-messages.h" #include "set.h" #include "unit.h" #include "macro.h" @@ -48,6 +48,7 @@ #include "label.h" #include "fileio-label.h" #include "bus-errors.h" +#include "dbus.h" const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = &service_vtable, @@ -326,7 +327,7 @@ void unit_add_to_dbus_queue(Unit *u) { return; /* Shortcut things if nobody cares */ - if (!bus_has_subscriber(u->manager)) { + if (set_isempty(u->manager->subscribed)) { u->sent_dbus_new_signal = true; return; } @@ -1658,46 +1659,6 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su unit_add_to_gc_queue(u); } -int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) { - struct epoll_event ev = { - .data.ptr = w, - .events = events, - }; - - assert(u); - assert(fd >= 0); - assert(w); - assert(w->type == WATCH_INVALID || (w->type == WATCH_FD && w->fd == fd && w->data.unit == u)); - - if (epoll_ctl(u->manager->epoll_fd, - w->type == WATCH_INVALID ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, - fd, - &ev) < 0) - return -errno; - - w->fd = fd; - w->type = WATCH_FD; - w->data.unit = u; - - return 0; -} - -void unit_unwatch_fd(Unit *u, Watch *w) { - assert(u); - assert(w); - - if (w->type == WATCH_INVALID) - return; - - assert(w->type == WATCH_FD); - assert(w->data.unit == u); - assert_se(epoll_ctl(u->manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0); - - w->fd = -1; - w->type = WATCH_INVALID; - w->data.unit = NULL; -} - int unit_watch_pid(Unit *u, pid_t pid) { assert(u); assert(pid >= 1); @@ -1715,90 +1676,6 @@ void unit_unwatch_pid(Unit *u, pid_t pid) { hashmap_remove_value(u->manager->watch_pids, LONG_TO_PTR(pid), u); } -int unit_watch_timer(Unit *u, clockid_t clock_id, bool relative, usec_t usec, Watch *w) { - struct itimerspec its = {}; - int flags, fd; - bool ours; - - assert(u); - assert(w); - assert(w->type == WATCH_INVALID || (w->type == WATCH_UNIT_TIMER && w->data.unit == u)); - - /* This will try to reuse the old timer if there is one */ - - if (w->type == WATCH_UNIT_TIMER) { - assert(w->data.unit == u); - assert(w->fd >= 0); - - ours = false; - fd = w->fd; - } else if (w->type == WATCH_INVALID) { - - ours = true; - fd = timerfd_create(clock_id, TFD_NONBLOCK|TFD_CLOEXEC); - if (fd < 0) - return -errno; - } else - assert_not_reached("Invalid watch type"); - - if (usec <= 0) { - /* Set absolute time in the past, but not 0, since we - * don't want to disarm the timer */ - its.it_value.tv_sec = 0; - its.it_value.tv_nsec = 1; - - flags = TFD_TIMER_ABSTIME; - } else { - timespec_store(&its.it_value, usec); - flags = relative ? 0 : TFD_TIMER_ABSTIME; - } - - /* This will also flush the elapse counter */ - if (timerfd_settime(fd, flags, &its, NULL) < 0) - goto fail; - - if (w->type == WATCH_INVALID) { - struct epoll_event ev = { - .data.ptr = w, - .events = EPOLLIN, - }; - - if (epoll_ctl(u->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) - goto fail; - } - - w->type = WATCH_UNIT_TIMER; - w->fd = fd; - w->data.unit = u; - - return 0; - -fail: - if (ours) - close_nointr_nofail(fd); - - return -errno; -} - -void unit_unwatch_timer(Unit *u, Watch *w) { - assert(u); - assert(w); - - if (w->type == WATCH_INVALID) - return; - - assert(w->type == WATCH_UNIT_TIMER); - assert(w->data.unit == u); - assert(w->fd >= 0); - - assert_se(epoll_ctl(u->manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0); - close_nointr_nofail(w->fd); - - w->fd = -1; - w->type = WATCH_INVALID; - w->data.unit = NULL; -} - bool unit_job_is_applicable(Unit *u, JobType j) { assert(u); assert(j >= 0 && j < _JOB_TYPE_MAX); @@ -2572,7 +2449,7 @@ bool unit_active_or_pending(Unit *u) { return false; } -int unit_kill(Unit *u, KillWho w, int signo, DBusError *error) { +int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error) { assert(u); assert(w >= 0 && w < _KILL_WHO_MAX); assert(signo > 0); @@ -2618,23 +2495,23 @@ int unit_kill_common( int signo, pid_t main_pid, pid_t control_pid, - DBusError *error) { + sd_bus_error *error) { int r = 0; if (who == KILL_MAIN && main_pid <= 0) { if (main_pid < 0) - dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type)); + sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type)); else - dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill"); + sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill"); return -ESRCH; } if (who == KILL_CONTROL && control_pid <= 0) { if (control_pid < 0) - dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type)); + sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type)); else - dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill"); + sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill"); return -ESRCH; } @@ -2746,6 +2623,17 @@ ExecContext *unit_get_exec_context(Unit *u) { return (ExecContext*) ((uint8_t*) u + offset); } +KillContext *unit_get_kill_context(Unit *u) { + size_t offset; + assert(u); + + offset = UNIT_VTABLE(u)->kill_context_offset; + if (offset <= 0) + return NULL; + + return (KillContext*) ((uint8_t*) u + offset); +} + CGroupContext *unit_get_cgroup_context(Unit *u) { size_t offset; diff --git a/src/core/unit.h b/src/core/unit.h index 1a558423f7..c58202bf0f 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -32,6 +32,7 @@ typedef enum UnitDependency UnitDependency; typedef struct UnitRef UnitRef; typedef struct UnitStatusMessageFormats UnitStatusMessageFormats; +#include "sd-event.h" #include "set.h" #include "util.h" #include "list.h" @@ -295,6 +296,10 @@ struct UnitVTable { * CGroupContext is found, if the unit type has that */ size_t cgroup_context_offset; + /* If greater than 0, the offset into the object where + * KillContext is found, if the unit type has that */ + size_t kill_context_offset; + /* The name of the configuration file section with the private settings of this unit*/ const char *private_section; @@ -327,7 +332,7 @@ struct UnitVTable { int (*stop)(Unit *u); int (*reload)(Unit *u); - int (*kill)(Unit *u, KillWho w, int signo, DBusError *error); + int (*kill)(Unit *u, KillWho w, int signo, sd_bus_error *error); bool (*can_reload)(Unit *u); @@ -359,9 +364,8 @@ struct UnitVTable { /* Return true when this unit is suitable for snapshotting */ bool (*check_snapshot)(Unit *u); - void (*fd_event)(Unit *u, int fd, uint32_t events, Watch *w); + /* Invoked on every child that died */ void (*sigchld_event)(Unit *u, pid_t pid, int code, int status); - void (*timer_event)(Unit *u, uint64_t n_elapsed, Watch *w); /* Reset failed state if we are in failed state */ void (*reset_failed)(Unit *u); @@ -377,14 +381,8 @@ struct UnitVTable { * goes away. */ void (*bus_name_owner_change)(Unit *u, const char *name, const char *old_owner, const char *new_owner); - /* Called whenever a bus PID lookup finishes */ - void (*bus_query_pid_done)(Unit *u, const char *name, pid_t pid); - - /* Called for each message received on the bus */ - DBusHandlerResult (*bus_message_handler)(Unit *u, DBusConnection *c, DBusMessage *message); - /* Called for each property that is being set */ - int (*bus_set_property)(Unit *u, const char *name, DBusMessageIter *i, UnitSetPropertiesMode mode, DBusError *error); + int (*bus_set_property)(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); /* Called after at least one property got changed to apply the necessary change */ int (*bus_commit_properties)(Unit *u); @@ -412,14 +410,16 @@ struct UnitVTable { /* Type specific cleanups. */ void (*shutdown)(Manager *m); - /* When sending out PropertiesChanged signal, which properties - * shall be invalidated? This is a NUL separated list of - * strings, to minimize relocations a little. */ - const char *bus_invalidating_properties; - /* The interface name */ const char *bus_interface; + /* The bus vtable */ + const sd_bus_vtable *bus_vtable; + + /* strv list of changing properties */ + const char * const * const bus_changing_properties; + + /* The strings to print in status messages */ UnitStatusMessageFormats status_message_formats; /* Can units of this type have multiple names? */ @@ -521,20 +521,14 @@ int unit_start(Unit *u); int unit_stop(Unit *u); int unit_reload(Unit *u); -int unit_kill(Unit *u, KillWho w, int signo, DBusError *error); -int unit_kill_common(Unit *u, KillWho who, int signo, pid_t main_pid, pid_t control_pid, DBusError *error); +int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error); +int unit_kill_common(Unit *u, KillWho who, int signo, pid_t main_pid, pid_t control_pid, sd_bus_error *error); void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success); -int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w); -void unit_unwatch_fd(Unit *u, Watch *w); - int unit_watch_pid(Unit *u, pid_t pid); void unit_unwatch_pid(Unit *u, pid_t pid); -int unit_watch_timer(Unit *u, clockid_t, bool relative, usec_t usec, Watch *w); -void unit_unwatch_timer(Unit *u, Watch *w); - int unit_watch_bus_name(Unit *u, const char *name); void unit_unwatch_bus_name(Unit *u, const char *name); @@ -590,6 +584,7 @@ void unit_ref_unset(UnitRef *ref); int unit_exec_context_defaults(Unit *u, ExecContext *c); ExecContext *unit_get_exec_context(Unit *u) _pure_; +KillContext *unit_get_kill_context(Unit *u) _pure_; CGroupContext *unit_get_cgroup_context(Unit *u) _pure_; int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data); diff --git a/src/libsystemd-bus/bus-error.h b/src/libsystemd-bus/bus-error.h index 5474c8c5ec..f442e953e0 100644 --- a/src/libsystemd-bus/bus-error.h +++ b/src/libsystemd-bus/bus-error.h @@ -21,6 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <stdbool.h> + #include "sd-bus.h" bool bus_error_is_dirty(sd_bus_error *e); diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h index faed183990..a1d60b1133 100644 --- a/src/libsystemd-bus/bus-internal.h +++ b/src/libsystemd-bus/bus-internal.h @@ -119,11 +119,12 @@ enum bus_state { BUS_AUTHENTICATING, BUS_HELLO, BUS_RUNNING, + BUS_CLOSING, BUS_CLOSED }; static inline bool BUS_IS_OPEN(enum bus_state state) { - return state > BUS_UNSET && state < BUS_CLOSED; + return state > BUS_UNSET && state < BUS_CLOSING; } enum bus_auth { @@ -155,7 +156,6 @@ struct sd_bus { bool anonymous_auth:1; bool prefer_readv:1; bool prefer_writev:1; - bool processing:1; bool match_callbacks_modified:1; bool filter_callbacks_modified:1; bool nodes_modified:1; diff --git a/src/libsystemd-bus/bus-introspect.c b/src/libsystemd-bus/bus-introspect.c index 9a49e431c0..4c6031729a 100644 --- a/src/libsystemd-bus/bus-introspect.c +++ b/src/libsystemd-bus/bus-introspect.c @@ -111,13 +111,10 @@ static int introspect_write_arguments(struct introspect *i, const char *signatur } } -int introspect_write_interface(struct introspect *i, const char *interface, const sd_bus_vtable *v) { +int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) { assert(i); - assert(interface); assert(v); - fprintf(i->f, " <interface name=\"%s\">\n", interface); - for (; v->type != _SD_BUS_VTABLE_END; v++) { switch (v->type) { @@ -155,7 +152,6 @@ int introspect_write_interface(struct introspect *i, const char *interface, cons } - fputs(" </interface>\n", i->f); return 0; } diff --git a/src/libsystemd-bus/bus-introspect.h b/src/libsystemd-bus/bus-introspect.h index 48c3885d94..0be12cffb9 100644 --- a/src/libsystemd-bus/bus-introspect.h +++ b/src/libsystemd-bus/bus-introspect.h @@ -36,6 +36,6 @@ struct introspect { int introspect_begin(struct introspect *i); int introspect_write_default_interfaces(struct introspect *i, bool object_manager); int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix); -int introspect_write_interface(struct introspect *i, const char *interface, const sd_bus_vtable *v); +int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v); int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply); void introspect_free(struct introspect *i); diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c index 4f21db56e2..666307cc6e 100644 --- a/src/libsystemd-bus/bus-message.c +++ b/src/libsystemd-bus/bus-message.c @@ -3294,6 +3294,7 @@ _public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) { return !isempty(c->signature); } + static int message_read_ap( sd_bus_message *m, const char *types, diff --git a/src/libsystemd-bus/bus-objects.c b/src/libsystemd-bus/bus-objects.c index 8369068bd0..a6e8b2de86 100644 --- a/src/libsystemd-bus/bus-objects.c +++ b/src/libsystemd-bus/bus-objects.c @@ -728,6 +728,7 @@ static int process_introspect( _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_set_free_free_ Set *s = NULL; + const char *previous_interface = NULL; struct introspect intro; struct node_vtable *c; bool empty; @@ -768,11 +769,24 @@ static int process_introspect( empty = false; - r = introspect_write_interface(&intro, c->interface, c->vtable); + if (!streq_ptr(previous_interface, c->interface)) { + + if (previous_interface) + fputs(" </interface>\n", intro.f); + + fprintf(intro.f, " <interface name=\"%s\">\n", c->interface); + } + + r = introspect_write_interface(&intro, c->vtable); if (r < 0) goto finish; + + previous_interface = c->interface; } + if (previous_interface) + fputs(" </interface>\n", intro.f); + if (empty) { /* Nothing?, let's see if we exist at all, and if not * refuse to do anything */ @@ -806,51 +820,6 @@ finish: return r; } -static int object_manager_serialize_vtable( - sd_bus *bus, - sd_bus_message *reply, - const char *path, - struct node_vtable *c, - sd_bus_error *error, - void *userdata) { - - int r; - - assert(bus); - assert(reply); - assert(path); - assert(c); - assert(error); - - r = sd_bus_message_open_container(reply, 'e', "sa{sv}"); - if (r < 0) - return r; - - r = sd_bus_message_append(reply, "s", c->interface); - if (r < 0) - return r; - - r = sd_bus_message_open_container(reply, 'a', "{sv}"); - if (r < 0) - return r; - - r = vtable_append_all_properties(bus, reply, path, c, userdata, error); - if (r < 0) - return r; - if (bus->nodes_modified) - return 0; - - r = sd_bus_message_close_container(reply); - if (r < 0) - return r; - - r = sd_bus_message_close_container(reply); - if (r < 0) - return r; - - return 0; -} - static int object_manager_serialize_path( sd_bus *bus, sd_bus_message *reply, @@ -859,9 +828,10 @@ static int object_manager_serialize_path( bool require_fallback, sd_bus_error *error) { + const char *previous_interface = NULL; + bool found_something = false; struct node_vtable *i; struct node *n; - bool found_something = false; int r; assert(bus); @@ -889,6 +859,9 @@ static int object_manager_serialize_path( continue; if (!found_something) { + + /* Open the object part */ + r = sd_bus_message_open_container(reply, 'e', "oa{sa{sv}}"); if (r < 0) return r; @@ -904,13 +877,54 @@ static int object_manager_serialize_path( found_something = true; } - r = object_manager_serialize_vtable(bus, reply, path, i, error, u); + if (!streq_ptr(previous_interface, i->interface)) { + + /* Maybe close the previous interface part */ + + if (previous_interface) { + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + } + + /* Open the new interface part */ + + r = sd_bus_message_open_container(reply, 'e', "sa{sv}"); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "s", i->interface); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "{sv}"); + if (r < 0) + return r; + } + + r = vtable_append_all_properties(bus, reply, path, i, u, error); if (r < 0) return r; if (sd_bus_error_is_set(error)) return 0; if (bus->nodes_modified) return 0; + + previous_interface = i->interface; + } + + if (previous_interface) { + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; } if (found_something) { @@ -1503,7 +1517,7 @@ static int add_object_vtable_internal( sd_bus_object_find_t find, void *userdata) { - struct node_vtable *c = NULL, *i; + struct node_vtable *c = NULL, *i, *existing = NULL; const sd_bus_vtable *v; struct node *n; int r; @@ -1515,6 +1529,10 @@ static int add_object_vtable_internal( assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL); assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!streq(interface, "org.freedesktop.DBus.Properties") && + !streq(interface, "org.freedesktop.DBus.Introspectable") && + !streq(interface, "org.freedesktop.DBus.Peer") && + !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL); r = hashmap_ensure_allocated(&bus->vtable_methods, vtable_member_hash_func, vtable_member_compare_func); if (r < 0) @@ -1529,15 +1547,20 @@ static int add_object_vtable_internal( return -ENOMEM; LIST_FOREACH(vtables, i, n->vtables) { - if (streq(i->interface, interface)) { - r = -EEXIST; - goto fail; - } - if (i->is_fallback != fallback) { r = -EPROTOTYPE; goto fail; } + + if (streq(i->interface, interface)) { + + if (i->vtable == vtable) { + r = -EEXIST; + goto fail; + } + + existing = i; + } } c = new0(struct node_vtable, 1); @@ -1654,7 +1677,7 @@ static int add_object_vtable_internal( } } - LIST_PREPEND(vtables, n->vtables, c); + LIST_INSERT_AFTER(vtables, n->vtables, existing, c); bus->nodes_modified = true; return 0; @@ -1671,7 +1694,10 @@ static int remove_object_vtable_internal( sd_bus *bus, const char *path, const char *interface, - bool fallback) { + const sd_bus_vtable *vtable, + bool fallback, + sd_bus_object_find_t find, + void *userdata) { struct node_vtable *c; struct node *n; @@ -1686,7 +1712,11 @@ static int remove_object_vtable_internal( return 0; LIST_FOREACH(vtables, c, n->vtables) - if (streq(c->interface, interface) && c->is_fallback == fallback) + if (streq(c->interface, interface) && + c->is_fallback == fallback && + c->vtable == vtable && + c->find == find && + c->userdata == userdata) break; if (!c) @@ -1715,9 +1745,11 @@ _public_ int sd_bus_add_object_vtable( _public_ int sd_bus_remove_object_vtable( sd_bus *bus, const char *path, - const char *interface) { + const char *interface, + const sd_bus_vtable *vtable, + void *userdata) { - return remove_object_vtable_internal(bus, path, interface, false); + return remove_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata); } _public_ int sd_bus_add_fallback_vtable( @@ -1734,9 +1766,12 @@ _public_ int sd_bus_add_fallback_vtable( _public_ int sd_bus_remove_fallback_vtable( sd_bus *bus, const char *path, - const char *interface) { + const char *interface, + const sd_bus_vtable *vtable, + sd_bus_object_find_t find, + void *userdata) { - return remove_object_vtable_internal(bus, path, interface, true); + return remove_object_vtable_internal(bus, path, interface, vtable, true, find, userdata); } _public_ int sd_bus_add_node_enumerator( @@ -1824,8 +1859,8 @@ static int emit_properties_changed_on_interface( char **names) { _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - bool has_invalidating = false; - struct vtable_member key; + bool has_invalidating = false, has_changing = false; + struct vtable_member key = {}; struct node_vtable *c; struct node *n; char **property; @@ -1841,23 +1876,6 @@ static int emit_properties_changed_on_interface( if (!n) return 0; - LIST_FOREACH(vtables, c, n->vtables) { - if (require_fallback && !c->is_fallback) - continue; - - if (streq(c->interface, interface)) - break; - } - - if (!c) - return 0; - - r = node_vtable_get_userdata(bus, path, c, &u); - if (r <= 0) - return r; - if (bus->nodes_modified) - return 0; - r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.Properties", "PropertiesChanged", &m); if (r < 0) return r; @@ -1873,52 +1891,78 @@ static int emit_properties_changed_on_interface( key.path = prefix; key.interface = interface; - STRV_FOREACH(property, names) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - struct vtable_member *v; - - assert_return(member_name_is_valid(*property), -EINVAL); - - key.member = *property; - v = hashmap_get(bus->vtable_properties, &key); - if (!v) - return -ENOENT; - - assert(c == v->parent); - assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE, -EDOM); + LIST_FOREACH(vtables, c, n->vtables) { + if (require_fallback && !c->is_fallback) + continue; - if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY) { - has_invalidating = true; + if (!streq(c->interface, interface)) continue; - } - r = sd_bus_message_open_container(m, 'e', "sv"); + r = node_vtable_get_userdata(bus, path, c, &u); if (r < 0) return r; + if (bus->nodes_modified) + return 0; + if (r == 0) + continue; - r = sd_bus_message_append(m, "s", *property); - if (r < 0) - return r; + STRV_FOREACH(property, names) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + struct vtable_member *v; - r = sd_bus_message_open_container(m, 'v', v->vtable->x.property.signature); - if (r < 0) - return r; + assert_return(member_name_is_valid(*property), -EINVAL); - r = invoke_property_get(bus, v->vtable, m->path, interface, *property, m, &error, vtable_property_convert_userdata(v->vtable, u)); - if (r < 0) - return r; - if (bus->nodes_modified) - return 0; + key.member = *property; + v = hashmap_get(bus->vtable_properties, &key); + if (!v) + return -ENOENT; + + /* If there are two vtables for the same + * interface, let's handle this property when + * we come to that vtable. */ + if (c != v->parent) + continue; - r = sd_bus_message_close_container(m); - if (r < 0) - return r; + assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE, -EDOM); - r = sd_bus_message_close_container(m); - if (r < 0) - return r; + if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY) { + has_invalidating = true; + continue; + } + + has_changing = true; + + r = sd_bus_message_open_container(m, 'e', "sv"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "s", *property); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'v', v->vtable->x.property.signature); + if (r < 0) + return r; + + r = invoke_property_get(bus, v->vtable, m->path, interface, *property, m, &error, vtable_property_convert_userdata(v->vtable, u)); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + } } + if (!has_invalidating && !has_changing) + return 0; + r = sd_bus_message_close_container(m); if (r < 0) return r; @@ -1928,19 +1972,35 @@ static int emit_properties_changed_on_interface( return r; if (has_invalidating) { - STRV_FOREACH(property, names) { - struct vtable_member *v; - - key.member = *property; - assert_se(v = hashmap_get(bus->vtable_properties, &key)); - assert(c == v->parent); + LIST_FOREACH(vtables, c, n->vtables) { + if (require_fallback && !c->is_fallback) + continue; - if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY)) + if (!streq(c->interface, interface)) continue; - r = sd_bus_message_append(m, "s", *property); + r = node_vtable_get_userdata(bus, path, c, &u); if (r < 0) return r; + if (bus->nodes_modified) + return 0; + if (r == 0) + continue; + + STRV_FOREACH(property, names) { + struct vtable_member *v; + + key.member = *property; + assert_se(v = hashmap_get(bus->vtable_properties, &key)); + assert(c == v->parent); + + if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY)) + continue; + + r = sd_bus_message_append(m, "s", *property); + if (r < 0) + return r; + } } } @@ -2028,6 +2088,7 @@ static int interfaces_added_append_one_prefix( bool require_fallback) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + bool found_interface = false; struct node_vtable *c; struct node *n; void *u = NULL; @@ -2047,38 +2108,43 @@ static int interfaces_added_append_one_prefix( if (require_fallback && !c->is_fallback) continue; - if (streq(c->interface, interface)) - break; - } + if (!streq(c->interface, interface)) + continue; - if (!c) - return 0; + r = node_vtable_get_userdata(bus, path, c, &u); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + if (r == 0) + continue; - r = node_vtable_get_userdata(bus, path, c, &u); - if (r <= 0) - return r; - if (bus->nodes_modified) - return 0; + if (!found_interface) { + r = sd_bus_message_append_basic(m, 's', interface); + if (r < 0) + return r; - r = sd_bus_message_append_basic(m, 's', interface); - if (r < 0) - return r; + r = sd_bus_message_open_container(m, 'a', "{sv}"); + if (r < 0) + return r; - r = sd_bus_message_open_container(m, 'a', "{sv}"); - if (r < 0) - return r; + found_interface = true; + } - r = vtable_append_all_properties(bus, m,path, c, u, &error); - if (r < 0) - return r; - if (bus->nodes_modified) - return 0; + r = vtable_append_all_properties(bus, m, path, c, u, &error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + } - r = sd_bus_message_close_container(m); - if (r < 0) - return r; + if (found_interface) { + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + } - return 1; + return found_interface; } static int interfaces_added_append_one( diff --git a/src/libsystemd-bus/bus-signature.c b/src/libsystemd-bus/bus-signature.c index 35c054baf6..1e5bf4821d 100644 --- a/src/libsystemd-bus/bus-signature.c +++ b/src/libsystemd-bus/bus-signature.c @@ -33,7 +33,10 @@ static int signature_element_length_internal( int r; - assert(s); + if (!s) + return -EINVAL; + + assert(l); if (bus_type_is_basic(*s) || *s == SD_BUS_TYPE_VARIANT) { *l = 1; @@ -114,7 +117,8 @@ bool signature_is_single(const char *s, bool allow_dict_entry) { int r; size_t t; - assert(s); + if (!s) + return false; r = signature_element_length_internal(s, allow_dict_entry, 0, 0, &t); if (r < 0) @@ -124,7 +128,9 @@ bool signature_is_single(const char *s, bool allow_dict_entry) { } bool signature_is_pair(const char *s) { - assert(s); + + if (!s) + return false; if (!bus_type_is_basic(*s)) return false; @@ -136,7 +142,8 @@ bool signature_is_valid(const char *s, bool allow_dict_entry) { const char *p; int r; - assert(s); + if (!s) + return false; p = s; while (*p) { diff --git a/src/libsystemd-bus/bus-util.c b/src/libsystemd-bus/bus-util.c index ed6fdc473a..65323d0081 100644 --- a/src/libsystemd-bus/bus-util.c +++ b/src/libsystemd-bus/bus-util.c @@ -383,7 +383,7 @@ void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) { #endif } -static int bus_check_peercred(sd_bus *c) { +int bus_check_peercred(sd_bus *c) { struct ucred ucred; socklen_t l; int fd; @@ -1014,7 +1014,8 @@ int bus_property_get_bool( return sd_bus_message_append_basic(reply, 'b', &b); } -int bus_property_get_uid( +#if __SIZEOF_SIZE_T__ != 8 +int bus_property_get_size( sd_bus *bus, const char *path, const char *interface, @@ -1023,12 +1024,41 @@ int bus_property_get_uid( sd_bus_error *error, void *userdata) { - assert_cc(sizeof(uint32_t) == sizeof(uid_t)); - assert_cc(sizeof(uint32_t) == sizeof(gid_t)); - assert_cc(sizeof(uint32_t) == sizeof(pid_t)); + uint64_t sz = *(size_t*) userdata; - return sd_bus_message_append_basic(reply, 'u', userdata); + return sd_bus_message_append_basic(reply, 't', &sz); } +#endif + +#if __SIZEOF_LONG__ != 8 +int bus_property_get_long( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + int64_t l = *(long*) userdata; + + return sd_bus_message_append_basic(reply, 'x', &l); +} + +int bus_property_get_ulong( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + sd_bus_error *error, + void *userdata) { + + uint64_t ul = *(unsigned long*) userdata; + + return sd_bus_message_append_basic(reply, 't', &ul); +} +#endif int bus_log_parse_error(int r) { log_error("Failed to parse message: %s", strerror(-r)); diff --git a/src/libsystemd-bus/bus-util.h b/src/libsystemd-bus/bus-util.h index 314c2f7867..c8d5dd982e 100644 --- a/src/libsystemd-bus/bus-util.h +++ b/src/libsystemd-bus/bus-util.h @@ -55,7 +55,8 @@ int bus_map_all_properties(sd_bus *bus, int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name); int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout); -int bus_property_get_tristate(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata); + +int bus_check_peercred(sd_bus *c); int bus_verify_polkit(sd_bus *bus, sd_bus_message *m, const char *action, bool interactive, bool *_challenge, sd_bus_error *e); @@ -71,11 +72,48 @@ int bus_open_transport_systemd(BusTransport transport, const char *host, bool us int bus_print_property(const char *name, sd_bus_message *property, bool all); int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all); +int bus_property_get_tristate(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata); int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata); -int bus_property_get_uid(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata); -#define bus_property_get_gid bus_property_get_uid -#define bus_property_get_pid bus_property_get_uid +#define bus_property_get_usec ((sd_bus_property_get_t) NULL) +#define bus_property_set_usec ((sd_bus_property_set_t) NULL) + +assert_cc(sizeof(int) == sizeof(int32_t)); +#define bus_property_get_int ((sd_bus_property_get_t) NULL) + +assert_cc(sizeof(unsigned) == sizeof(unsigned)); +#define bus_property_get_unsigned ((sd_bus_property_get_t) NULL) + +/* On 64bit machines we can use the default serializer for size_t and + * friends, otherwise we need to cast this manually */ +#if __SIZEOF_SIZE_T__ == 8 +#define bus_property_get_size ((sd_bus_property_get_t) NULL) +#else +int bus_property_get_size(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata); +#endif + +#if __SIZEOF_LONG__ == 8 +#define bus_property_get_long ((sd_bus_property_get_t) NULL) +#define bus_property_get_ulong ((sd_bus_property_get_t) NULL) +#else +int bus_property_get_long(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata); +int bus_property_get_ulong(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata); +#endif + +/* uid_t and friends on Linux 32 bit. This means we can just use the + * default serializer for 32bit unsigned, for serializing it, and map + * it to NULL here */ +assert_cc(sizeof(uid_t) == sizeof(uint32_t)); +#define bus_property_get_uid ((sd_bus_property_get_t) NULL) + +assert_cc(sizeof(gid_t) == sizeof(uint32_t)); +#define bus_property_get_gid ((sd_bus_property_get_t) NULL) + +assert_cc(sizeof(pid_t) == sizeof(uint32_t)); +#define bus_property_get_pid ((sd_bus_property_get_t) NULL) + +assert_cc(sizeof(mode_t) == sizeof(uint32_t)); +#define bus_property_get_mode ((sd_bus_property_get_t) NULL) int bus_log_parse_error(int r); int bus_log_create_error(int r); @@ -129,22 +167,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref); } \ struct __useless_struct_to_allow_trailing_semicolon__ -#define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit" -#define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed" -#define BUS_ERROR_JOB_FAILED "org.freedesktop.systemd1.JobFailed" - -#define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine" -#define BUS_ERROR_NO_MACHINE_FOR_PID "org.freedesktop.machine1.NoMachineForPID" -#define BUS_ERROR_MACHINE_EXISTS "org.freedesktop.machine1.MachineExists" - -#define BUS_ERROR_NO_SUCH_SESSION "org.freedesktop.login1.NoSuchSession" -#define BUS_ERROR_NO_SESSION_FOR_PID "org.freedesktop.login1.NoSessionForPID" -#define BUS_ERROR_NO_SUCH_USER "org.freedesktop.login1.NoSuchUser" -#define BUS_ERROR_NO_USER_FOR_PID "org.freedesktop.login1.NoUserForPID" -#define BUS_ERROR_NO_SUCH_SEAT "org.freedesktop.login1.NoSuchSeat" -#define BUS_ERROR_SESSION_NOT_ON_SEAT "org.freedesktop.login1.SessionNotOnSeat" -#define BUS_ERROR_NOT_IN_CONTROL "org.freedesktop.login1.NotInControl" -#define BUS_ERROR_DEVICE_IS_TAKEN "org.freedesktop.login1.DeviceIsTaken" -#define BUS_ERROR_DEVICE_NOT_TAKEN "org.freedesktop.login1.DeviceNotTaken" -#define BUS_ERROR_OPERATION_IN_PROGRESS "org.freedesktop.login1.OperationInProgress" -#define BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED "org.freedesktop.login1.SleepVerbNotSupported" +#define BUS_PROPERTY_DUAL_TIMESTAMP(name, offset, flags) \ + SD_BUS_PROPERTY(name, "t", bus_property_get_usec, offset + offsetof(struct dual_timestamp, realtime), flags), \ + SD_BUS_PROPERTY(name "Monotonic", "t", bus_property_get_usec, offset + offsetof(struct dual_timestamp, monotonic), flags) diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c index c8248e19aa..bc88ac977c 100644 --- a/src/libsystemd-bus/sd-bus.c +++ b/src/libsystemd-bus/sd-bus.c @@ -1204,6 +1204,18 @@ _public_ void sd_bus_close(sd_bus *bus) { * freed. */ } +static void bus_enter_closing(sd_bus *bus) { + assert(bus); + + if (bus->state != BUS_OPENING && + bus->state != BUS_AUTHENTICATING && + bus->state != BUS_HELLO && + bus->state != BUS_RUNNING) + return; + + bus->state = BUS_CLOSING; +} + _public_ sd_bus *sd_bus_ref(sd_bus *bus) { assert_return(bus, NULL); @@ -1282,6 +1294,20 @@ static int bus_seal_message(sd_bus *b, sd_bus_message *m) { return bus_message_seal(m, ++b->serial); } +static int bus_write_message(sd_bus *bus, sd_bus_message *message, size_t *idx) { + int r; + + assert(bus); + assert(message); + + if (bus->is_kernel) + r = bus_kernel_write_message(bus, message); + else + r = bus_socket_write_message(bus, message, idx); + + return r; +} + static int dispatch_wqueue(sd_bus *bus) { int r, ret = 0; @@ -1290,15 +1316,10 @@ static int dispatch_wqueue(sd_bus *bus) { while (bus->wqueue_size > 0) { - if (bus->is_kernel) - r = bus_kernel_write_message(bus, bus->wqueue[0]); - else - r = bus_socket_write_message(bus, bus->wqueue[0], &bus->windex); - - if (r < 0) { - sd_bus_close(bus); + r = bus_write_message(bus, bus->wqueue[0], &bus->windex); + if (r < 0) return r; - } else if (r == 0) + else if (r == 0) /* Didn't do anything this time */ return ret; else if (bus->is_kernel || bus->windex >= BUS_MESSAGE_SIZE(bus->wqueue[0])) { @@ -1324,6 +1345,20 @@ static int dispatch_wqueue(sd_bus *bus) { return ret; } +static int bus_read_message(sd_bus *bus, sd_bus_message **m) { + int r; + + assert(bus); + assert(m); + + if (bus->is_kernel) + r = bus_kernel_read_message(bus, m); + else + r = bus_socket_read_message(bus, m); + + return r; +} + static int dispatch_rqueue(sd_bus *bus, sd_bus_message **m) { sd_bus_message *z = NULL; int r, ret = 0; @@ -1343,15 +1378,9 @@ static int dispatch_rqueue(sd_bus *bus, sd_bus_message **m) { /* Try to read a new message */ do { - if (bus->is_kernel) - r = bus_kernel_read_message(bus, &z); - else - r = bus_socket_read_message(bus, &z); - - if (r < 0) { - sd_bus_close(bus); + r = bus_read_message(bus, &z); + if (r < 0) return r; - } if (r == 0) return ret; @@ -1395,15 +1424,10 @@ _public_ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial) { if ((bus->state == BUS_RUNNING || bus->state == BUS_HELLO) && bus->wqueue_size <= 0) { size_t idx = 0; - if (bus->is_kernel) - r = bus_kernel_write_message(bus, m); - else - r = bus_socket_write_message(bus, m, &idx); - - if (r < 0) { - sd_bus_close(bus); + r = bus_write_message(bus, m, &idx); + if (r < 0) return r; - } else if (!bus->is_kernel && idx < BUS_MESSAGE_SIZE(m)) { + else if (!bus->is_kernel && idx < BUS_MESSAGE_SIZE(m)) { /* Wasn't fully written. So let's remember how * much was written. Note that the first entry * of the wqueue array is always allocated so @@ -1573,7 +1597,7 @@ int bus_ensure_running(sd_bus *bus) { assert(bus); - if (bus->state == BUS_UNSET || bus->state == BUS_CLOSED) + if (bus->state == BUS_UNSET || bus->state == BUS_CLOSED || bus->state == BUS_CLOSING) return -ENOTCONN; if (bus->state == BUS_RUNNING) return 1; @@ -1644,12 +1668,10 @@ _public_ int sd_bus_call( room = true; } - if (bus->is_kernel) - r = bus_kernel_read_message(bus, &incoming); - else - r = bus_socket_read_message(bus, &incoming); + r = bus_read_message(bus, &incoming); if (r < 0) return r; + if (incoming) { if (incoming->reply_serial == serial) { @@ -1731,7 +1753,6 @@ _public_ int sd_bus_call( _public_ int sd_bus_get_fd(sd_bus *bus) { assert_return(bus, -EINVAL); - assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); assert_return(bus->input_fd == bus->output_fd, -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -1742,7 +1763,7 @@ _public_ int sd_bus_get_events(sd_bus *bus) { int flags = 0; assert_return(bus, -EINVAL); - assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(BUS_IS_OPEN(bus->state) || bus->state == BUS_CLOSING, -ENOTCONN); assert_return(!bus_pid_changed(bus), -ECHILD); if (bus->state == BUS_OPENING) @@ -1769,9 +1790,14 @@ _public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) { assert_return(bus, -EINVAL); assert_return(timeout_usec, -EINVAL); - assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(BUS_IS_OPEN(bus->state) || bus->state == BUS_CLOSING, -ENOTCONN); assert_return(!bus_pid_changed(bus), -ECHILD); + if (bus->state == BUS_CLOSING) { + *timeout_usec = 0; + return 1; + } + if (bus->state == BUS_AUTHENTICATING) { *timeout_usec = bus->auth_timeout; return 1; @@ -1821,12 +1847,21 @@ static int process_timeout(sd_bus *bus) { if (r < 0) return r; + r = bus_seal_message(bus, m); + if (r < 0) + return r; + assert_se(prioq_pop(bus->reply_callbacks_prioq) == c); hashmap_remove(bus->reply_callbacks, &c->serial); + bus->current = m; + bus->iteration_counter ++; + r = c->callback(bus, m, c->userdata); free(c); + bus->current = NULL; + return r < 0 ? r : 1; } @@ -1877,7 +1912,7 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) { r = c->callback(bus, m, c->userdata); free(c); - return r; + return r < 0 ? r : 1; } static int process_filter(sd_bus *bus, sd_bus_message *m) { @@ -2078,6 +2113,85 @@ null_message: return r; } +static int process_closing(sd_bus *bus, sd_bus_message **ret) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + struct reply_callback *c; + int r; + + assert(bus); + assert(bus->state == BUS_CLOSING); + + c = hashmap_first(bus->reply_callbacks); + if (c) { + /* First, fail all outstanding method calls */ + r = bus_message_new_synthetic_error( + bus, + c->serial, + &SD_BUS_ERROR_MAKE(SD_BUS_ERROR_NO_REPLY, "Connection terminated"), + &m); + if (r < 0) + return r; + + r = bus_seal_message(bus, m); + if (r < 0) + return r; + + if (c->timeout != 0) + prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx); + + hashmap_remove(bus->reply_callbacks, &c->serial); + + bus->current = m; + bus->iteration_counter++; + + r = c->callback(bus, m, c->userdata); + free(c); + + if (r >= 0) + r = 1; + + goto finish; + } + + /* Then, synthesize a Disconnected message */ + r = sd_bus_message_new_signal( + bus, + "/org/freedesktop/DBus/Local", + "org.freedesktop.DBus.Local", + "Disconnected", + &m); + if (r < 0) + return r; + + r = bus_seal_message(bus, m); + if (r < 0) + return r; + + sd_bus_close(bus); + + bus->current = m; + bus->iteration_counter++; + + r = process_filter(bus, m); + if (r != 0) + goto finish; + + r = process_match(bus, m); + if (r != 0) + goto finish; + + if (ret) { + *ret = m; + m = NULL; + } + + r = 1; + +finish: + bus->current = NULL; + return r; +} + _public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) { BUS_DONT_DESTROY(bus); int r; @@ -2091,7 +2205,7 @@ _public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) { assert_return(!bus_pid_changed(bus), -ECHILD); /* We don't allow recursively invoking sd_bus_process(). */ - assert_return(!bus->processing, -EBUSY); + assert_return(!bus->current, -EBUSY); switch (bus->state) { @@ -2101,29 +2215,43 @@ _public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) { case BUS_OPENING: r = bus_socket_process_opening(bus); - if (r < 0) + if (r == -ECONNRESET || r == -EPIPE) { + bus_enter_closing(bus); + r = 1; + } else if (r < 0) return r; if (ret) *ret = NULL; return r; case BUS_AUTHENTICATING: - r = bus_socket_process_authenticating(bus); - if (r < 0) + if (r == -ECONNRESET || r == -EPIPE) { + bus_enter_closing(bus); + r = 1; + } else if (r < 0) return r; + if (ret) *ret = NULL; + return r; case BUS_RUNNING: case BUS_HELLO: - - bus->processing = true; r = process_running(bus, ret); - bus->processing = false; + if (r == -ECONNRESET || r == -EPIPE) { + bus_enter_closing(bus); + r = 1; + + if (ret) + *ret = NULL; + } return r; + + case BUS_CLOSING: + return process_closing(bus, ret); } assert_not_reached("Unknown state"); @@ -2136,6 +2264,10 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { usec_t m = (usec_t) -1; assert(bus); + + if (bus->state == BUS_CLOSING) + return 1; + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); e = sd_bus_get_events(bus); @@ -2186,9 +2318,13 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { _public_ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) { assert_return(bus, -EINVAL); - assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); assert_return(!bus_pid_changed(bus), -ECHILD); + if (bus->state == BUS_CLOSING) + return 0; + + assert_return(BUS_IS_OPEN(bus->state) , -ENOTCONN); + if (bus->rqueue_size > 0) return 0; @@ -2199,9 +2335,13 @@ _public_ int sd_bus_flush(sd_bus *bus) { int r; assert_return(bus, -EINVAL); - assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); assert_return(!bus_pid_changed(bus), -ECHILD); + if (bus->state == BUS_CLOSING) + return 0; + + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + r = bus_ensure_running(bus); if (r < 0) return r; diff --git a/src/libsystemd-bus/sd-event.c b/src/libsystemd-bus/sd-event.c index d01e82d945..5cb3bccc5a 100644 --- a/src/libsystemd-bus/sd-event.c +++ b/src/libsystemd-bus/sd-event.c @@ -51,7 +51,7 @@ struct sd_event_source { sd_event *event; void *userdata; - sd_prepare_handler_t prepare; + sd_event_handler_t prepare; EventSourceType type:4; int enabled:3; @@ -65,34 +65,34 @@ struct sd_event_source { union { struct { - sd_io_handler_t callback; + sd_event_io_handler_t callback; int fd; uint32_t events; uint32_t revents; bool registered:1; } io; struct { - sd_time_handler_t callback; + sd_event_time_handler_t callback; usec_t next, accuracy; unsigned earliest_index; unsigned latest_index; } time; struct { - sd_signal_handler_t callback; + sd_event_signal_handler_t callback; struct signalfd_siginfo siginfo; int sig; } signal; struct { - sd_child_handler_t callback; + sd_event_child_handler_t callback; siginfo_t siginfo; pid_t pid; int options; } child; struct { - sd_defer_handler_t callback; + sd_event_handler_t callback; } defer; struct { - sd_quit_handler_t callback; + sd_event_handler_t callback; unsigned prioq_index; } quit; }; @@ -567,7 +567,7 @@ _public_ int sd_event_add_io( sd_event *e, int fd, uint32_t events, - sd_io_handler_t callback, + sd_event_io_handler_t callback, void *userdata, sd_event_source **ret) { @@ -655,7 +655,7 @@ static int event_add_time_internal( Prioq **latest, uint64_t usec, uint64_t accuracy, - sd_time_handler_t callback, + sd_event_time_handler_t callback, void *userdata, sd_event_source **ret) { @@ -722,7 +722,7 @@ fail: _public_ int sd_event_add_monotonic(sd_event *e, uint64_t usec, uint64_t accuracy, - sd_time_handler_t callback, + sd_event_time_handler_t callback, void *userdata, sd_event_source **ret) { @@ -732,7 +732,7 @@ _public_ int sd_event_add_monotonic(sd_event *e, _public_ int sd_event_add_realtime(sd_event *e, uint64_t usec, uint64_t accuracy, - sd_time_handler_t callback, + sd_event_time_handler_t callback, void *userdata, sd_event_source **ret) { @@ -774,7 +774,7 @@ static int event_update_signal_fd(sd_event *e) { _public_ int sd_event_add_signal( sd_event *e, int sig, - sd_signal_handler_t callback, + sd_event_signal_handler_t callback, void *userdata, sd_event_source **ret) { @@ -824,7 +824,7 @@ _public_ int sd_event_add_child( sd_event *e, pid_t pid, int options, - sd_child_handler_t callback, + sd_event_child_handler_t callback, void *userdata, sd_event_source **ret) { @@ -883,7 +883,7 @@ _public_ int sd_event_add_child( _public_ int sd_event_add_defer( sd_event *e, - sd_defer_handler_t callback, + sd_event_handler_t callback, void *userdata, sd_event_source **ret) { @@ -916,7 +916,7 @@ _public_ int sd_event_add_defer( _public_ int sd_event_add_quit( sd_event *e, - sd_quit_handler_t callback, + sd_event_handler_t callback, void *userdata, sd_event_source **ret) { @@ -1297,7 +1297,7 @@ _public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) { return 0; } -_public_ int sd_event_source_set_prepare(sd_event_source *s, sd_prepare_handler_t callback) { +_public_ int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback) { int r; assert_return(s, -EINVAL); diff --git a/src/libsystemd-bus/test-bus-introspect.c b/src/libsystemd-bus/test-bus-introspect.c index ae41618647..b9865349ac 100644 --- a/src/libsystemd-bus/test-bus-introspect.c +++ b/src/libsystemd-bus/test-bus-introspect.c @@ -52,7 +52,9 @@ int main(int argc, char *argv[]) { assert_se(introspect_begin(&intro) >= 0); - assert_se(introspect_write_interface(&intro, "org.foo", vtable) >= 0); + fprintf(intro.f, " <interface name=\"org.foo\">\n"); + assert_se(introspect_write_interface(&intro, vtable) >= 0); + fputs(" </interface>\n", intro.f); fflush(intro.f); fputs(intro.introspection, stdout); diff --git a/src/libsystemd-bus/test-bus-marshal.c b/src/libsystemd-bus/test-bus-marshal.c index cbf5e1a0fa..b7606d7708 100644 --- a/src/libsystemd-bus/test-bus-marshal.c +++ b/src/libsystemd-bus/test-bus-marshal.c @@ -28,7 +28,7 @@ #endif #ifdef HAVE_DBUS -#include <dbus.h> +#include <dbus/dbus.h> #endif #include "log.h" diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 0f25e2306f..7e6f6109dc 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -40,6 +40,7 @@ #include "bus-util.h" #include "bus-error.h" #include "logind.h" +#include "bus-errors.h" static int property_get_idle_hint( sd_bus *bus, @@ -184,7 +185,7 @@ static int method_get_session_by_pid(sd_bus *bus, sd_bus_message *message, void p = session_bus_path(session); if (!p) - return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL); + return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL); return sd_bus_reply_method_return(bus, message, "o", p); } diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index 26cce8d7fc..1b6f1362b3 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -304,7 +304,7 @@ int inhibitor_create_fifo(Inhibitor *i) { if (r < 0) return r; - r = sd_event_source_set_priority(i->event_source, SD_PRIORITY_IDLE); + r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE); if (r < 0) return r; } diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index c59dfd9338..53141a892e 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -25,6 +25,7 @@ #include "util.h" #include "bus-util.h" #include "strv.h" +#include "bus-errors.h" #include "logind.h" #include "logind-seat.h" diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index fa9c0039f4..4995391443 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -25,6 +25,7 @@ #include "util.h" #include "strv.h" #include "bus-util.h" +#include "bus-errors.h" #include "logind.h" #include "logind-session.h" diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 65cc6f3094..d3433731e5 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -864,7 +864,7 @@ int session_create_fifo(Session *s) { if (r < 0) return r; - r = sd_event_source_set_priority(s->fifo_event_source, SD_PRIORITY_IDLE); + r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE); if (r < 0) return r; } diff --git a/src/login/logind.c b/src/login/logind.c index 1d16eaa7b8..47b306b619 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -958,7 +958,7 @@ static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *us return r; } - r = sd_event_source_set_priority(m->idle_action_event_source, SD_PRIORITY_IDLE+10); + r = sd_event_source_set_priority(m->idle_action_event_source, SD_EVENT_PRIORITY_IDLE+10); if (r < 0) { log_error("Failed to set idle event source priority: %s", strerror(-r)); return r; diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 2b25f07525..be0dbe0097 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -36,6 +36,7 @@ #include "utf8.h" #include "unit-name.h" #include "bus-util.h" +#include "bus-errors.h" #include "time-util.h" #include "cgroup-util.h" #include "machined.h" diff --git a/src/shared/bus-errors.h b/src/shared/bus-errors.h new file mode 100644 index 0000000000..e9ab731bac --- /dev/null +++ b/src/shared/bus-errors.h @@ -0,0 +1,57 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit" +#define BUS_ERROR_NO_UNIT_FOR_PID "org.freedesktop.systemd1.NoUnitForPID" +#define BUS_ERROR_UNIT_EXISTS "org.freedesktop.systemd1.UnitExists" +#define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed" +#define BUS_ERROR_JOB_FAILED "org.freedesktop.systemd1.JobFailed" +#define BUS_ERROR_NO_SUCH_JOB "org.freedesktop.systemd1.NoSuchJob" +#define BUS_ERROR_NOT_SUBSCRIBED "org.freedesktop.systemd1.NotSubscribed" +#define BUS_ERROR_ALREADY_SUBSCRIBED "org.freedesktop.systemd1.AlreadySubscribed" +#define BUS_ERROR_ONLY_BY_DEPENDENCY "org.freedesktop.systemd1.OnlyByDependency" +#define BUS_ERROR_TRANSACTION_JOBS_CONFLICTING "org.freedesktop.systemd1.TransactionJobsConflicting" +#define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic" +#define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive" +#define BUS_ERROR_UNIT_MASKED "org.freedesktop.systemd1.UnitMasked" +#define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable" +#define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation" +#define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown" + +#define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine" +#define BUS_ERROR_NO_MACHINE_FOR_PID "org.freedesktop.machine1.NoMachineForPID" +#define BUS_ERROR_MACHINE_EXISTS "org.freedesktop.machine1.MachineExists" + +#define BUS_ERROR_NO_SUCH_SESSION "org.freedesktop.login1.NoSuchSession" +#define BUS_ERROR_NO_SESSION_FOR_PID "org.freedesktop.login1.NoSessionForPID" +#define BUS_ERROR_NO_SUCH_USER "org.freedesktop.login1.NoSuchUser" +#define BUS_ERROR_NO_USER_FOR_PID "org.freedesktop.login1.NoUserForPID" +#define BUS_ERROR_NO_SUCH_SEAT "org.freedesktop.login1.NoSuchSeat" +#define BUS_ERROR_SESSION_NOT_ON_SEAT "org.freedesktop.login1.SessionNotOnSeat" +#define BUS_ERROR_NOT_IN_CONTROL "org.freedesktop.login1.NotInControl" +#define BUS_ERROR_DEVICE_IS_TAKEN "org.freedesktop.login1.DeviceIsTaken" +#define BUS_ERROR_DEVICE_NOT_TAKEN "org.freedesktop.login1.DeviceNotTaken" +#define BUS_ERROR_OPERATION_IN_PROGRESS "org.freedesktop.login1.OperationInProgress" +#define BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED "org.freedesktop.login1.SleepVerbNotSupported" + +#define BUS_ERROR_NO_SUCH_PROCESS "org.freedesktop.systemd1.NoSuchProcess" diff --git a/src/shared/dbus-common.c b/src/shared/dbus-common.c deleted file mode 100644 index 3ba2d87c4d..0000000000 --- a/src/shared/dbus-common.c +++ /dev/null @@ -1,1430 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <assert.h> -#include <sys/socket.h> -#include <errno.h> -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <dbus/dbus.h> -#include <string.h> -#include <sys/epoll.h> - -#include "log.h" -#include "dbus-common.h" -#include "util.h" -#include "missing.h" -#include "def.h" -#include "strv.h" - -int bus_check_peercred(DBusConnection *c) { - int fd; - struct ucred ucred; - socklen_t l; - - assert(c); - - assert_se(dbus_connection_get_unix_fd(c, &fd)); - - l = sizeof(struct ucred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) { - log_error("SO_PEERCRED failed: %m"); - return -errno; - } - - if (l != sizeof(struct ucred)) { - log_error("SO_PEERCRED returned wrong size."); - return -E2BIG; - } - - if (ucred.uid != 0 && ucred.uid != geteuid()) - return -EPERM; - - return 1; -} - -static int sync_auth(DBusConnection *bus, DBusError *error) { - usec_t begin, tstamp; - - assert(bus); - - /* This complexity should probably move into D-Bus itself: - * - * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */ - - begin = tstamp = now(CLOCK_MONOTONIC); - for (;;) { - - if (tstamp > begin + DEFAULT_TIMEOUT_USEC) - break; - - if (dbus_connection_get_is_authenticated(bus)) - break; - - if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC)) - break; - - tstamp = now(CLOCK_MONOTONIC); - } - - if (!dbus_connection_get_is_connected(bus)) { - dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication."); - return -ECONNREFUSED; - } - - if (!dbus_connection_get_is_authenticated(bus)) { - dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time."); - return -EACCES; - } - - return 0; -} - -int bus_connect(DBusBusType t, DBusConnection **_bus, bool *_private, DBusError *error) { - DBusConnection *bus = NULL; - int r; - bool private = true; - - assert(_bus); - - if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) { - /* If we are root, then let's talk directly to the - * system instance, instead of going via the bus */ - - bus = dbus_connection_open_private("unix:path=/run/systemd/private", error); - if (!bus) - return -EIO; - - } else { - if (t == DBUS_BUS_SESSION) { - const char *e; - - /* If we are supposed to talk to the instance, - * try via XDG_RUNTIME_DIR first, then - * fallback to normal bus access */ - - e = secure_getenv("XDG_RUNTIME_DIR"); - if (e) { - char *p; - - if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0) - return -ENOMEM; - - bus = dbus_connection_open_private(p, NULL); - free(p); - } - } - - if (!bus) { - bus = dbus_bus_get_private(t, error); - if (!bus) - return -EIO; - - private = false; - } - } - - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - if (private) { - if (bus_check_peercred(bus) < 0) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - - dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus."); - return -EACCES; - } - } - - r = sync_auth(bus, error); - if (r < 0) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - if (_private) - *_private = private; - - *_bus = bus; - return 0; -} - -int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error) { - DBusConnection *bus; - char *p = NULL; - int r; - - assert(_bus); - assert(user || host); - - if (user && host) - asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s%%40%s,argv3=systemd-stdio-bridge", user, host); - else if (user) - asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s%%40localhost,argv3=systemd-stdio-bridge", user); - else if (host) - asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host); - - if (!p) { - dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); - return -ENOMEM; - } - - bus = dbus_connection_open_private(p, error); - free(p); - - if (!bus) - return -EIO; - - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - if ((r = sync_auth(bus, error)) < 0) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - if (!dbus_bus_register(bus, error)) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - *_bus = bus; - return 0; -} - -int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) { - DBusConnection *bus; - int r; - - assert(_bus); - - /* Don't bother with PolicyKit if we are root */ - if (geteuid() == 0) - return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error); - - bus = dbus_connection_open_private("unixexec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error); - if (!bus) - return -EIO; - - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - r = sync_auth(bus, error); - if (r < 0) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - if (!dbus_bus_register(bus, error)) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - *_bus = bus; - return 0; -} - -const char *bus_error_message(const DBusError *error) { - if (!error) - return NULL; - - /* Sometimes the D-Bus server is a little bit too verbose with - * its error messages, so let's override them here */ - if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED)) - return "Access denied"; - - return error->message; -} - -const char *bus_error(const DBusError *error, int err) { - if (error && dbus_error_is_set(error)) - return bus_error_message(error); - - return strerror(err < 0 ? -err : err); -} - -DBusHandlerResult bus_default_message_handler( - DBusConnection *c, - DBusMessage *message, - const char *introspection, - const char *interfaces, - const BusBoundProperties *bound_properties) { - - DBusError error; - _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; - int r; - - assert(c); - assert(message); - - dbus_error_init(&error); - - if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) { - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && bound_properties) { - const char *interface, *property; - const BusBoundProperties *bp; - const BusProperty *p; - void *data; - DBusMessageIter iter, sub; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_STRING, &property, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(c, message, &error, -EINVAL); - - for (bp = bound_properties; bp->interface; bp++) { - if (!streq(bp->interface, interface)) - continue; - - for (p = bp->properties; p->property; p++) - if (streq(p->property, property)) - goto get_prop; - } - - /* no match */ - if (!nulstr_contains(interfaces, interface)) - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - else - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); - - return bus_send_error_reply(c, message, &error, -EINVAL); - -get_prop: - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub)) - goto oom; - - data = (char*)bp->base + p->offset; - if (p->indirect) - data = *(void**)data; - - r = p->append(&sub, property, data); - if (r == -ENOMEM) - goto oom; - if (r < 0) - return bus_send_error_reply(c, message, NULL, r); - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && bound_properties) { - const char *interface; - const BusBoundProperties *bp; - const BusProperty *p; - DBusMessageIter iter, sub, sub2, sub3; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(c, message, &error, -EINVAL); - - if (interface[0] && !nulstr_contains(interfaces, interface)) { - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - return bus_send_error_reply(c, message, &error, -EINVAL); - } - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub)) - goto oom; - - for (bp = bound_properties; bp->interface; bp++) { - if (interface[0] && !streq(bp->interface, interface)) - continue; - - for (p = bp->properties; p->property; p++) { - void *data; - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) || - !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3)) - goto oom; - - data = (char*)bp->base + p->offset; - if (p->indirect) - data = *(void**)data; - r = p->append(&sub3, p->property, data); - if (r == -ENOMEM) - goto oom; - if (r < 0) - return bus_send_error_reply(c, message, NULL, r); - - if (!dbus_message_iter_close_container(&sub2, &sub3) || - !dbus_message_iter_close_container(&sub, &sub2)) - goto oom; - } - } - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && bound_properties) { - const char *interface, *property; - DBusMessageIter iter; - const BusBoundProperties *bp; - const BusProperty *p; - DBusMessageIter sub; - char *sig; - void *data; - DBusMessage *changed; - - if (!dbus_message_iter_init(message, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return bus_send_error_reply(c, message, NULL, -EINVAL); - - dbus_message_iter_get_basic(&iter, &interface); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return bus_send_error_reply(c, message, NULL, -EINVAL); - - dbus_message_iter_get_basic(&iter, &property); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT || - dbus_message_iter_has_next(&iter)) - return bus_send_error_reply(c, message, NULL, -EINVAL); - - for (bp = bound_properties; bp->interface; bp++) { - if (!streq(bp->interface, interface)) - continue; - - for (p = bp->properties; p->property; p++) - if (streq(p->property, property)) - goto set_prop; - } - - /* no match */ - if (!nulstr_contains(interfaces, interface)) - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - else - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); - - return bus_send_error_reply(c, message, &error, -EINVAL); - -set_prop: - if (!p->set) { - dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only"); - return bus_send_error_reply(c, message, &error, -EINVAL); - } - - dbus_message_iter_recurse(&iter, &sub); - - sig = dbus_message_iter_get_signature(&sub); - if (!sig) - goto oom; - - if (!streq(sig, p->signature)) { - dbus_free(sig); - return bus_send_error_reply(c, message, NULL, -EINVAL); - } - dbus_free(sig); - - data = (uint8_t*) bp->base + p->offset; - if (p->indirect) - data = *(void**)data; - - r = p->set(&sub, property, data); - if (r == -ENOMEM) - goto oom; - else if (r < 0) - return bus_send_error_reply(c, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - /* Send out a signal about this, but it doesn't really - * matter if this fails, so eat all errors */ - changed = bus_properties_changed_one_new( - dbus_message_get_path(message), - interface, - property); - if (changed) { - dbus_connection_send(c, changed, NULL); - dbus_message_unref(changed); - } - - - } else { - const char *interface = dbus_message_get_interface(message); - - if (!interface || !nulstr_contains(interfaces, interface)) { - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - return bus_send_error_reply(c, message, &error, -EINVAL); - } - } - - if (reply) { - if (!bus_maybe_send_reply(c, message, reply)) - goto oom; - - return DBUS_HANDLER_RESULT_HANDLED; - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - -oom: - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) { - const char *t = data; - - assert(i); - assert(property); - - if (!t) - t = ""; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) { - char **t = data; - - assert(i); - assert(property); - - return bus_append_strv_iter(i, t); -} - -int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) { - bool *b = data; - dbus_bool_t db; - - assert(i); - assert(property); - assert(b); - - db = *b; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) { - int *b = data; - dbus_bool_t db; - - assert(i); - assert(property); - assert(b); - - db = *b > 0; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) { - assert(i); - assert(property); - assert(data); - - /* Let's ensure that usec_t is actually 64bit, and hence this - * function can be used for usec_t */ - assert_cc(sizeof(uint64_t) == sizeof(usec_t)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) { - assert(i); - assert(property); - assert(data); - - /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually - * 32bit, and hence this function can be used for - * pid_t/mode_t/uid_t/gid_t */ - assert_cc(sizeof(uint32_t) == sizeof(pid_t)); - assert_cc(sizeof(uint32_t) == sizeof(mode_t)); - assert_cc(sizeof(uint32_t) == sizeof(unsigned)); - assert_cc(sizeof(uint32_t) == sizeof(uid_t)); - assert_cc(sizeof(uint32_t) == sizeof(gid_t)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) { - assert(i); - assert(property); - assert(data); - - assert_cc(sizeof(int32_t) == sizeof(int)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) { - uint64_t u; - - assert(i); - assert(property); - assert(data); - - u = (uint64_t) *(size_t*) data; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) { - uint64_t u; - - assert(i); - assert(property); - assert(data); - - u = (uint64_t) *(unsigned long*) data; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) { - int64_t l; - - assert(i); - assert(property); - assert(data); - - l = (int64_t) *(long*) data; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l)) - return -ENOMEM; - - return 0; -} - -int bus_property_set_uint64(DBusMessageIter *i, const char *property, void *data) { - uint64_t *t = data; - - assert(i); - assert(property); - - dbus_message_iter_get_basic(i, t); - return 0; -} - -const char *bus_errno_to_dbus(int error) { - - switch(error) { - - case -EINVAL: - return DBUS_ERROR_INVALID_ARGS; - - case -ENOMEM: - return DBUS_ERROR_NO_MEMORY; - - case -EPERM: - case -EACCES: - return DBUS_ERROR_ACCESS_DENIED; - - case -ESRCH: - return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN; - - case -ENOENT: - return DBUS_ERROR_FILE_NOT_FOUND; - - case -EEXIST: - return DBUS_ERROR_FILE_EXISTS; - - case -ETIMEDOUT: - case -ETIME: - return DBUS_ERROR_TIMEOUT; - - case -EIO: - return DBUS_ERROR_IO_ERROR; - - case -ENETRESET: - case -ECONNABORTED: - case -ECONNRESET: - return DBUS_ERROR_DISCONNECTED; - } - - return DBUS_ERROR_FAILED; -} - -dbus_bool_t bus_maybe_send_reply (DBusConnection *c, - DBusMessage *message, - DBusMessage *reply) -{ - /* Some parts of systemd "reply" to signals, which of course - * have the no-reply flag set. We will be defensive here and - * still send out a reply if we're passed a signal. - */ - if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL && - dbus_message_get_no_reply(message)) - return TRUE; - return dbus_connection_send(c, reply, NULL); -} - -DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) { - _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; - const char *name, *text; - - if (berror && dbus_error_is_set(berror)) { - name = berror->name; - text = berror->message; - } else { - name = bus_errno_to_dbus(error); - text = strerror(-error); - } - - reply = dbus_message_new_error(message, name, text); - if (!reply) - goto oom; - - if (!bus_maybe_send_reply(c, message, reply)) - goto oom; - - if (berror) - dbus_error_free(berror); - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - if (berror) - dbus_error_free(berror); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) { - DBusMessage *m; - DBusMessageIter iter, sub; - const char *i; - - assert(interface); - assert(properties); - - m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged"); - if (!m) - goto oom; - - dbus_message_iter_init_append(m, &iter); - - /* We won't send any property values, since they might be - * large and sometimes not cheap to generated */ - - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) || - !dbus_message_iter_close_container(&iter, &sub) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) - goto oom; - - NULSTR_FOREACH(i, properties) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i)) - goto oom; - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - return m; - -oom: - if (m) - dbus_message_unref(m); - - return NULL; -} - -DBusMessage* bus_properties_changed_one_new(const char *path, const char *interface, const char *property) { - DBusMessage *m; - DBusMessageIter iter, sub; - - assert(interface); - assert(property); - - m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged"); - if (!m) - goto oom; - - dbus_message_iter_init_append(m, &iter); - - /* We won't send any property values, since they might be - * large and sometimes not cheap to generated */ - - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) || - !dbus_message_iter_close_container(&iter, &sub) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) - goto oom; - - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &property)) - goto oom; - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - return m; - -oom: - if (m) - dbus_message_unref(m); - - return NULL; -} - -uint32_t bus_flags_to_events(DBusWatch *bus_watch) { - unsigned flags; - uint32_t events = 0; - - assert(bus_watch); - - /* no watch flags for disabled watches */ - if (!dbus_watch_get_enabled(bus_watch)) - return 0; - - flags = dbus_watch_get_flags(bus_watch); - - if (flags & DBUS_WATCH_READABLE) - events |= EPOLLIN; - if (flags & DBUS_WATCH_WRITABLE) - events |= EPOLLOUT; - - return events | EPOLLHUP | EPOLLERR; -} - -unsigned bus_events_to_flags(uint32_t events) { - unsigned flags = 0; - - if (events & EPOLLIN) - flags |= DBUS_WATCH_READABLE; - if (events & EPOLLOUT) - flags |= DBUS_WATCH_WRITABLE; - if (events & EPOLLHUP) - flags |= DBUS_WATCH_HANGUP; - if (events & EPOLLERR) - flags |= DBUS_WATCH_ERROR; - - return flags; -} - -int bus_parse_strv(DBusMessage *m, char ***_l) { - DBusMessageIter iter; - - assert(m); - assert(_l); - - if (!dbus_message_iter_init(m, &iter)) - return -EINVAL; - - return bus_parse_strv_iter(&iter, _l); -} - -int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) { - DBusMessageIter sub; - unsigned n = 0, i = 0; - char **l; - - assert(iter); - assert(_l); - - if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING) - return -EINVAL; - - dbus_message_iter_recurse(iter, &sub); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - n++; - dbus_message_iter_next(&sub); - } - - l = new(char*, n+1); - if (!l) - return -ENOMEM; - - dbus_message_iter_recurse(iter, &sub); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *s; - - assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING); - dbus_message_iter_get_basic(&sub, &s); - - if (!(l[i++] = strdup(s))) { - strv_free(l); - return -ENOMEM; - } - - dbus_message_iter_next(&sub); - } - - assert(i == n); - l[i] = NULL; - - if (_l) - *_l = l; - - return 0; -} - -int bus_parse_strv_pairs_iter(DBusMessageIter *iter, char ***_l) { - DBusMessageIter sub, sub2; - unsigned n = 0, i = 0; - _cleanup_strv_free_ char **l = NULL; - - assert(iter); - assert(_l); - - if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRUCT) - return -EINVAL; - - dbus_message_iter_recurse(iter, &sub); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - n++; - dbus_message_iter_next(&sub); - } - - l = new(char*, n*2+1); - if (!l) - return -ENOMEM; - l[0] = NULL; /* make sure that l is properly terminated at all times */ - - dbus_message_iter_recurse(iter, &sub); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *a, *b; - - assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT); - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &a, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &b, false) < 0) - return -EINVAL; - - l[i] = strdup(a); - if (!l[i]) - return -ENOMEM; - i++; - - l[i] = strdup(b); - if (!l[i]) - return -ENOMEM; - i++; - - dbus_message_iter_next(&sub); - } - - assert(i == n*2); - l[i] = NULL; - - if (_l) { - *_l = l; - l = NULL; /* avoid freeing */ - } - - return 0; -} - -int bus_parse_unit_info(DBusMessageIter *iter, struct unit_info *u) { - DBusMessageIter sub; - - assert(iter); - assert(u); - - if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) - return -EINVAL; - - dbus_message_iter_recurse(iter, &sub); - - if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->id, true) < 0 || - bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->description, true) < 0 || - bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->load_state, true) < 0 || - bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->active_state, true) < 0 || - bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->sub_state, true) < 0 || - bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->following, true) < 0 || - bus_iter_get_basic_and_next(&sub, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 || - bus_iter_get_basic_and_next(&sub, DBUS_TYPE_UINT32, &u->job_id, true) < 0 || - bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->job_type, true) < 0 || - bus_iter_get_basic_and_next(&sub, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) { - log_error("Failed to parse reply."); - return -EIO; - } - - return 0; -} - -int bus_append_strv_iter(DBusMessageIter *iter, char **l) { - DBusMessageIter sub; - - assert(iter); - - if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub)) - return -ENOMEM; - - STRV_FOREACH(l, l) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l)) - return -ENOMEM; - - if (!dbus_message_iter_close_container(iter, &sub)) - return -ENOMEM; - - return 0; -} - -int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) { - - assert(iter); - assert(data); - - if (dbus_message_iter_get_arg_type(iter) != type) - return -EIO; - - dbus_message_iter_get_basic(iter, data); - - if (!dbus_message_iter_next(iter) != !next) - return -EIO; - - return 0; -} - -int generic_print_property(const char *name, DBusMessageIter *iter, bool all) { - assert(name); - assert(iter); - - switch (dbus_message_iter_get_arg_type(iter)) { - - case DBUS_TYPE_STRING: { - const char *s; - dbus_message_iter_get_basic(iter, &s); - - if (all || !isempty(s)) - printf("%s=%s\n", name, s); - - return 1; - } - - case DBUS_TYPE_BOOLEAN: { - dbus_bool_t b; - - dbus_message_iter_get_basic(iter, &b); - printf("%s=%s\n", name, yes_no(b)); - - return 1; - } - - case DBUS_TYPE_UINT64: { - uint64_t u; - dbus_message_iter_get_basic(iter, &u); - - /* Yes, heuristics! But we can change this check - * should it turn out to not be sufficient */ - - if (endswith(name, "Timestamp")) { - char timestamp[FORMAT_TIMESTAMP_MAX], *t; - - t = format_timestamp(timestamp, sizeof(timestamp), u); - if (t || all) - printf("%s=%s\n", name, strempty(t)); - - } else if (strstr(name, "USec")) { - char timespan[FORMAT_TIMESPAN_MAX]; - - printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0)); - } else - printf("%s=%llu\n", name, (unsigned long long) u); - - return 1; - } - - case DBUS_TYPE_UINT32: { - uint32_t u; - dbus_message_iter_get_basic(iter, &u); - - if (strstr(name, "UMask") || strstr(name, "Mode")) - printf("%s=%04o\n", name, u); - else - printf("%s=%u\n", name, (unsigned) u); - - return 1; - } - - case DBUS_TYPE_INT32: { - int32_t i; - dbus_message_iter_get_basic(iter, &i); - - printf("%s=%i\n", name, (int) i); - return 1; - } - - case DBUS_TYPE_DOUBLE: { - double d; - dbus_message_iter_get_basic(iter, &d); - - printf("%s=%g\n", name, d); - return 1; - } - - case DBUS_TYPE_ARRAY: - - if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) { - DBusMessageIter sub; - bool space = false; - - dbus_message_iter_recurse(iter, &sub); - if (all || - dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - printf("%s=", name); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *s; - - assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING); - dbus_message_iter_get_basic(&sub, &s); - printf("%s%s", space ? " " : "", s); - - space = true; - dbus_message_iter_next(&sub); - } - - puts(""); - } - - return 1; - - } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) { - DBusMessageIter sub; - - dbus_message_iter_recurse(iter, &sub); - if (all || - dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - printf("%s=", name); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - uint8_t u; - - assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE); - dbus_message_iter_get_basic(&sub, &u); - printf("%02x", u); - - dbus_message_iter_next(&sub); - } - - puts(""); - } - - return 1; - - } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_UINT32) { - DBusMessageIter sub; - - dbus_message_iter_recurse(iter, &sub); - if (all || - dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - printf("%s=", name); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - uint32_t u; - - assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32); - dbus_message_iter_get_basic(&sub, &u); - printf("%08x", u); - - dbus_message_iter_next(&sub); - } - - puts(""); - } - - return 1; - } - - break; - } - - return 0; -} - -static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) { - DBusMessage *reply; - DBusConnection *bus = userdata; - - assert_se(reply = dbus_pending_call_steal_reply(pending)); - dbus_message_unref(reply); - - dbus_connection_close(bus); -} - -void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) { - _cleanup_dbus_message_unref_ DBusMessage *m = NULL; - DBusPendingCall *pending = NULL; - - assert(bus); - - /* We unregister the name here, but we continue to process - * requests, until we get the response for it, so that all - * requests are guaranteed to be processed. */ - - m = dbus_message_new_method_call( - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "ReleaseName"); - if (!m) - goto oom; - - if (!dbus_message_append_args( - m, - DBUS_TYPE_STRING, - &name, - DBUS_TYPE_INVALID)) - goto oom; - - if (!dbus_connection_send_with_reply(bus, m, &pending, -1)) - goto oom; - - if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL)) - goto oom; - - dbus_pending_call_unref(pending); - - return; - -oom: - log_oom(); - - if (pending) { - dbus_pending_call_cancel(pending); - dbus_pending_call_unref(pending); - } -} - -DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) { - usec_t *remain_until = userdata; - - assert(bus); - assert(m); - assert(remain_until); - - /* Every time we get a new message we reset out timeout */ - *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC; - - if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) - dbus_connection_close(bus); - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -/* This mimics dbus_bus_get_unix_user() */ -pid_t bus_get_unix_process_id( - DBusConnection *connection, - const char *name, - DBusError *error) { - - _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; - uint32_t pid = 0; - - m = dbus_message_new_method_call( - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetConnectionUnixProcessID"); - if (!m) { - dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); - return 0; - } - - if (!dbus_message_append_args( - m, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) { - dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); - return 0; - } - - reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error); - if (!reply) - return 0; - - if (dbus_set_error_from_message(error, reply)) - return 0; - - if (!dbus_message_get_args( - reply, error, - DBUS_TYPE_UINT32, &pid, - DBUS_TYPE_INVALID)) - return 0; - - return (pid_t) pid; -} - -bool bus_error_is_no_service(const DBusError *error) { - assert(error); - - if (!dbus_error_is_set(error)) - return false; - - if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER)) - return true; - - if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN)) - return true; - - return startswith(error->name, "org.freedesktop.DBus.Error.Spawn."); -} - -int bus_method_call_with_reply( - DBusConnection *bus, - const char *destination, - const char *path, - const char *interface, - const char *method, - DBusMessage **return_reply, - DBusError *return_error, - int first_arg_type, ...) { - - DBusError error; - _cleanup_dbus_message_unref_ DBusMessage *m = NULL; - DBusMessage *reply; - va_list ap; - int r = 0; - - dbus_error_init(&error); - assert(bus); - - m = dbus_message_new_method_call(destination, path, interface, method); - if (!m) { - r = log_oom(); - goto finish; - } - - va_start(ap, first_arg_type); - if (!dbus_message_append_args_valist(m, first_arg_type, ap)) { - va_end(ap); - r = log_oom(); - goto finish; - } - va_end(ap); - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - if (!return_error) - log_error("Failed to issue method call: %s", bus_error_message(&error)); - - if (bus_error_is_no_service(&error)) - r = -ENOENT; - else if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) - r = -EACCES; - else if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) - r = -ETIMEDOUT; - else if (dbus_error_has_name(&error, DBUS_ERROR_DISCONNECTED)) - r = -ECONNRESET; - else - r = -EIO; - goto finish; - } - - if (return_reply) - *return_reply = reply; - else - dbus_message_unref(reply); - -finish: - if (return_error) - *return_error = error; - else - dbus_error_free(&error); - - return r; -} - -void bus_message_unrefp(DBusMessage **reply) { - if (!reply) - return; - - if (!*reply) - return; - - dbus_message_unref(*reply); -} - -const char *bus_message_get_sender_with_fallback(DBusMessage *m) { - const char *s; - - assert(m); - - s = dbus_message_get_sender(m); - if (s) - return s; - - /* When the message came in from a direct connection the - * message will have no sender. We fix that here. */ - - return ":no-sender"; -} diff --git a/src/shared/dbus-common.h b/src/shared/dbus-common.h deleted file mode 100644 index 9752f08c05..0000000000 --- a/src/shared/dbus-common.h +++ /dev/null @@ -1,246 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <dbus/dbus.h> -#include <inttypes.h> -#include <sys/types.h> - -#include "macro.h" - -#ifndef DBUS_ERROR_UNKNOWN_OBJECT -#define DBUS_ERROR_UNKNOWN_OBJECT "org.freedesktop.DBus.Error.UnknownObject" -#endif - -#ifndef DBUS_ERROR_UNKNOWN_INTERFACE -#define DBUS_ERROR_UNKNOWN_INTERFACE "org.freedesktop.DBus.Error.UnknownInterface" -#endif - -#ifndef DBUS_ERROR_UNKNOWN_PROPERTY -#define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty" -#endif - -#ifndef DBUS_ERROR_PROPERTY_READ_ONLY -#define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly" -#endif - -#define BUS_PROPERTIES_INTERFACE \ - " <interface name=\"org.freedesktop.DBus.Properties\">\n" \ - " <method name=\"Get\">\n" \ - " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"value\" direction=\"out\" type=\"v\"/>\n" \ - " </method>\n" \ - " <method name=\"GetAll\">\n" \ - " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \ - " </method>\n" \ - " <method name=\"Set\">\n" \ - " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"value\" direction=\"in\" type=\"v\"/>\n" \ - " </method>\n" \ - " <signal name=\"PropertiesChanged\">\n" \ - " <arg type=\"s\" name=\"interface\"/>\n" \ - " <arg type=\"a{sv}\" name=\"changed_properties\"/>\n" \ - " <arg type=\"as\" name=\"invalidated_properties\"/>\n" \ - " </signal>\n" \ - " </interface>\n" - -#define BUS_INTROSPECTABLE_INTERFACE \ - " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" \ - " <method name=\"Introspect\">\n" \ - " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \ - " </method>\n" \ - " </interface>\n" - -#define BUS_PEER_INTERFACE \ - "<interface name=\"org.freedesktop.DBus.Peer\">\n" \ - " <method name=\"Ping\"/>\n" \ - " <method name=\"GetMachineId\">\n" \ - " <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \ - " </method>\n" \ - "</interface>\n" - -#define BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.DBus.Properties\0" \ - "org.freedesktop.DBus.Introspectable\0" \ - "org.freedesktop.DBus.Peer\0" - -int bus_check_peercred(DBusConnection *c); - -int bus_connect(DBusBusType t, DBusConnection **_bus, bool *private_bus, DBusError *error); - -int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error); -int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error); - -const char *bus_error_message(const DBusError *error); -const char *bus_error(const DBusError *e, int r); - -typedef int (*BusPropertyCallback)(DBusMessageIter *iter, const char *property, void *data); -typedef int (*BusPropertySetCallback)(DBusMessageIter *iter, const char *property, void *data); - -typedef struct BusProperty { - const char *property; /* name of the property */ - BusPropertyCallback append; /* Function that is called to serialize this property */ - const char *signature; - const uint16_t offset; /* Offset from BusBoundProperties::base address to the property data. - * uint16_t is sufficient, because we have no structs too big. - * -Werror=overflow will catch it if this does not hold. */ - bool indirect; /* data is indirect, ie. not base+offset, but *(base+offset) */ - BusPropertySetCallback set; /* Optional: Function that is called to set this property */ -} BusProperty; - -typedef struct BusBoundProperties { - const char *interface; /* interface of the properties */ - const BusProperty *properties; /* array of properties, ended by a NULL-filled element */ - const void *const base; /* base pointer to which the offset must be added to reach data */ -} BusBoundProperties; - -dbus_bool_t bus_maybe_send_reply (DBusConnection *c, - DBusMessage *message, - DBusMessage *reply); - -DBusHandlerResult bus_send_error_reply( - DBusConnection *c, - DBusMessage *message, - DBusError *bus_error, - int error); - -DBusHandlerResult bus_default_message_handler( - DBusConnection *c, - DBusMessage *message, - const char *introspection, - const char *interfaces, - const BusBoundProperties *bound_properties); - -int bus_property_append_string(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_size(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_long(DBusMessageIter *i, const char *property, void *data); - -#define bus_property_append_int bus_property_append_int32 -#define bus_property_append_pid bus_property_append_uint32 -#define bus_property_append_uid bus_property_append_uint32 -#define bus_property_append_gid bus_property_append_uint32 -#define bus_property_append_mode bus_property_append_uint32 -#define bus_property_append_unsigned bus_property_append_uint32 -#define bus_property_append_usec bus_property_append_uint64 - -int bus_property_set_uint64(DBusMessageIter *i, const char *property, void *data); -#define bus_property_set_usec bus_property_set_uint64 - -#define DEFINE_BUS_PROPERTY_APPEND_ENUM(function,name,type) \ - int function(DBusMessageIter *i, const char *property, void *data) { \ - const char *value; \ - type *field = data; \ - \ - assert(i); \ - assert(property); \ - \ - value = strempty(name##_to_string(*field)); \ - \ - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &value)) \ - return -ENOMEM; \ - \ - return 0; \ - } - -#define DEFINE_BUS_PROPERTY_SET_ENUM(function,name,type) \ - int function(DBusMessageIter *i, const char *property, void *data) { \ - const char *value; \ - type f, *field = data; \ - \ - assert(i); \ - assert(property); \ - \ - dbus_message_iter_get_basic(i, &value); \ - \ - f = name##_from_string(value); \ - if (f < 0) \ - return f; \ - \ - *field = f; \ - return 0; \ - } - -const char *bus_errno_to_dbus(int error) _const_; - -DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties); -DBusMessage* bus_properties_changed_one_new(const char *path, const char *interface, const char *property); - -uint32_t bus_flags_to_events(DBusWatch *bus_watch) _pure_; -unsigned bus_events_to_flags(uint32_t events) _const_; - -int bus_parse_strv(DBusMessage *m, char ***_l); -int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l); -int bus_parse_strv_pairs_iter(DBusMessageIter *iter, char ***_l); - -struct unit_info { - const char *id; - const char *description; - const char *load_state; - const char *active_state; - const char *sub_state; - const char *following; - const char *unit_path; - uint32_t job_id; - const char *job_type; - const char *job_path; -}; - -int bus_parse_unit_info(DBusMessageIter *iter, struct unit_info *u); - -int bus_append_strv_iter(DBusMessageIter *iter, char **l); - -int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next); - -int generic_print_property(const char *name, DBusMessageIter *iter, bool all); - -void bus_async_unregister_and_exit(DBusConnection *bus, const char *name); - -DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata); - -pid_t bus_get_unix_process_id(DBusConnection *connection, const char *name, DBusError *error); - -bool bus_error_is_no_service(const DBusError *error); -int bus_method_call_with_reply(DBusConnection *bus, - const char *destination, - const char *path, - const char *interface, - const char *method, - DBusMessage **return_reply, - DBusError *return_error, - int first_arg_type, ...); - -const char *bus_message_get_sender_with_fallback(DBusMessage *m); - -void bus_message_unrefp(DBusMessage **reply); - -#define _cleanup_dbus_message_unref_ __attribute__((cleanup(bus_message_unrefp))) -#define _cleanup_dbus_error_free_ __attribute__((cleanup(dbus_error_free))) diff --git a/src/shared/install.c b/src/shared/install.c index 2c119e2dca..16504eef0f 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1562,6 +1562,7 @@ int unit_file_set_default( UnitFileScope scope, const char *root_dir, const char *file, + bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -1599,7 +1600,7 @@ int unit_file_set_default( path = strappenda(config_path, "/" SPECIAL_DEFAULT_TARGET); - r = create_symlink(i->path, path, true, changes, n_changes); + r = create_symlink(i->path, path, force, changes, n_changes); if (r < 0) return r; diff --git a/src/shared/install.h b/src/shared/install.h index 3c2e162852..e87c57e48a 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -80,7 +80,7 @@ int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes); -int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char *file, UnitFileChange **changes, unsigned *n_changes); +int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char *file, bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_get_default(UnitFileScope scope, const char *root_dir, char **name); UnitFileState unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename); diff --git a/src/shared/prioq.c b/src/shared/prioq.c index 537befc623..8af4c51c2f 100644 --- a/src/shared/prioq.c +++ b/src/shared/prioq.c @@ -295,8 +295,8 @@ unsigned prioq_size(Prioq *q) { return 0; return q->n_items; - } + bool prioq_isempty(Prioq *q) { if (!q) diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 2e1863675f..84826a3829 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -70,6 +70,7 @@ #include "bus-util.h" #include "bus-message.h" #include "bus-error.h" +#include "bus-errors.h" static char **arg_types = NULL; static char **arg_states = NULL; @@ -194,7 +195,7 @@ static int translate_bus_error_to_exit_status(int r, const sd_bus_error *error) return EXIT_NOTINSTALLED; if (sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) || - sd_bus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED)) + sd_bus_error_has_name(error, SD_BUS_ERROR_NOT_SUPPORTED)) return EXIT_NOTIMPLEMENTED; if (sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) @@ -1400,6 +1401,100 @@ static int get_default(sd_bus *bus, char **args) { return 0; } +static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_changes) { + unsigned i; + + assert(changes || n_changes == 0); + + for (i = 0; i < n_changes; i++) { + if (changes[i].type == UNIT_FILE_SYMLINK) + log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path); + else + log_info("rm '%s'", changes[i].path); + } +} + +static int deserialize_and_dump_unit_file_changes(sd_bus_message *m) { + 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 (!arg_quiet) { + if (streq(type, "symlink")) + log_info("ln -s '%s' '%s'", source, path); + else + log_info("rm '%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; +} + +static int set_default(sd_bus *bus, char **args) { + _cleanup_free_ char *unit = NULL; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + int r; + + unit = unit_name_mangle_with_suffix(args[1], ".target"); + if (!unit) + return log_oom(); + + if (!bus || avoid_bus()) { + r = unit_file_set_default(arg_scope, arg_root, unit, arg_force, &changes, &n_changes); + if (r < 0) { + log_error("Failed to set default target: %s", strerror(-r)); + return r; + } + + if (!arg_quiet) + dump_unit_file_changes(changes, n_changes); + + r = 0; + } else { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "SetDefaultTarget", + &error, + &reply, + "sb", unit, arg_force); + if (r < 0) { + log_error("Failed to set default target: %s", bus_error_message(&error, -r)); + return r; + } + + r = deserialize_and_dump_unit_file_changes(reply); + if (r < 0) + return r; + + /* Try to reload if enabeld */ + if (!arg_no_reload) + r = daemon_reload(bus, args); + else + r = 0; + } + + unit_file_changes_free(changes, n_changes); + + return r; +} + struct job_info { uint32_t id; const char *name, *type, *state; @@ -4331,12 +4426,10 @@ static int mangle_names(char **original_names, char ***mangled_names) { } static int enable_unit(sd_bus *bus, char **args) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_strv_free_ char **mangled_names = NULL; const char *verb = args[0]; UnitFileChange *changes = NULL; - unsigned n_changes = 0, i; + unsigned n_changes = 0; int carries_install_info = -1; int r; @@ -4369,8 +4462,6 @@ static int enable_unit(sd_bus *bus, char **args) { r = unit_file_mask(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes); else if (streq(verb, "unmask")) r = unit_file_unmask(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes); - else if (streq(verb, "set-default")) - r = unit_file_set_default(arg_scope, arg_root, args[1], &changes, &n_changes); else assert_not_reached("Unknown verb"); @@ -4379,20 +4470,16 @@ static int enable_unit(sd_bus *bus, char **args) { goto finish; } - if (!arg_quiet) { - for (i = 0; i < n_changes; i++) { - if (changes[i].type == UNIT_FILE_SYMLINK) - log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path); - else - log_info("rm '%s'", changes[i].path); - } - } + if (!arg_quiet) + dump_unit_file_changes(changes, n_changes); r = 0; } else { - const char *method, *type, *path, *source; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; int expect_carries_install_info = false; bool send_force = true; + const char *method; if (streq(verb, "enable")) { method = "EnableUnitFiles"; @@ -4413,8 +4500,6 @@ static int enable_unit(sd_bus *bus, char **args) { else if (streq(verb, "unmask")) { method = "UnmaskUnitFiles"; send_force = false; - } else if (streq(verb, "set-default")) { - method = "SetDefaultTarget"; } else assert_not_reached("Unknown verb"); @@ -4454,24 +4539,9 @@ static int enable_unit(sd_bus *bus, char **args) { return bus_log_parse_error(r); } - r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(sss)"); - if (r < 0) - return bus_log_parse_error(r); - - while ((r = sd_bus_message_read(reply, "(sss)", &type, &path, &source)) > 0) { - if (!arg_quiet) { - if (streq(type, "symlink")) - log_info("ln -s '%s' '%s'", source, path); - else - log_info("rm '%s'", path); - } - } - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_message_exit_container(reply); + r = deserialize_and_dump_unit_file_changes(m); if (r < 0) - return bus_log_parse_error(r); + return r; /* Try to reload if enabeld */ if (!arg_no_reload) @@ -5649,8 +5719,8 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) { { "link", MORE, 2, enable_unit }, { "switch-root", MORE, 2, switch_root }, { "list-dependencies", LESS, 2, list_dependencies }, - { "set-default", EQUAL, 2, enable_unit }, - { "get-default", LESS, 1, get_default }, + { "set-default", EQUAL, 2, set_default }, + { "get-default", EQUAL, 1, get_default }, { "set-property", MORE, 3, set_property }, }; diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 072b54fa3a..a09b39f278 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -125,10 +125,10 @@ int sd_bus_add_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_ int sd_bus_remove_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata); int sd_bus_add_object_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata); -int sd_bus_remove_object_vtable(sd_bus *bus, const char *path, const char *interface); +int sd_bus_remove_object_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata); int sd_bus_add_fallback_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, sd_bus_object_find_t find, void *userdata); -int sd_bus_remove_fallback_vtable(sd_bus *bus, const char *path, const char *interface); +int sd_bus_remove_fallback_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, sd_bus_object_find_t find, void *userdata); int sd_bus_add_node_enumerator(sd_bus *bus, const char *path, sd_bus_node_enumerator_t callback, void *userdata); int sd_bus_remove_node_enumerator(sd_bus *bus, const char *path, sd_bus_node_enumerator_t callback, void *userdata); diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index 919b661d61..e7b6c9ec9b 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -59,18 +59,16 @@ enum { enum { /* And everything inbetween and outside is good too */ - SD_PRIORITY_IMPORTANT = -100, - SD_PRIORITY_NORMAL = 0, - SD_PRIORITY_IDLE = 100 + SD_EVENT_PRIORITY_IMPORTANT = -100, + SD_EVENT_PRIORITY_NORMAL = 0, + SD_EVENT_PRIORITY_IDLE = 100 }; -typedef int (*sd_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata); -typedef int (*sd_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata); -typedef int (*sd_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata); -typedef int (*sd_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata); -typedef int (*sd_defer_handler_t)(sd_event_source *s, void *userdata); -typedef int (*sd_prepare_handler_t)(sd_event_source *s, void *userdata); -typedef int (*sd_quit_handler_t)(sd_event_source *s, void *userdata); +typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata); +typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata); +typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata); +typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata); +typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata); int sd_event_default(sd_event **e); @@ -78,13 +76,13 @@ int sd_event_new(sd_event **e); sd_event* sd_event_ref(sd_event *e); sd_event* sd_event_unref(sd_event *e); -int sd_event_add_io(sd_event *e, int fd, uint32_t events, sd_io_handler_t callback, void *userdata, sd_event_source **s); -int sd_event_add_monotonic(sd_event *e, uint64_t usec, uint64_t accuracy, sd_time_handler_t callback, void *userdata, sd_event_source **s); -int sd_event_add_realtime(sd_event *e, uint64_t usec, uint64_t accuracy, sd_time_handler_t callback, void *userdata, sd_event_source **s); -int sd_event_add_signal(sd_event *e, int sig, sd_signal_handler_t callback, void *userdata, sd_event_source **s); -int sd_event_add_child(sd_event *e, pid_t pid, int options, sd_child_handler_t callback, void *userdata, sd_event_source **s); -int sd_event_add_defer(sd_event *e, sd_defer_handler_t callback, void *userdata, sd_event_source **s); -int sd_event_add_quit(sd_event *e, sd_quit_handler_t callback, void *userdata, sd_event_source **s); +int sd_event_add_io(sd_event *e, int fd, uint32_t events, sd_event_io_handler_t callback, void *userdata, sd_event_source **s); +int sd_event_add_monotonic(sd_event *e, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata, sd_event_source **s); +int sd_event_add_realtime(sd_event *e, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata, sd_event_source **s); +int sd_event_add_signal(sd_event *e, int sig, sd_event_signal_handler_t callback, void *userdata, sd_event_source **s); +int sd_event_add_child(sd_event *e, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata, sd_event_source **s); +int sd_event_add_defer(sd_event *e, sd_event_handler_t callback, void *userdata, sd_event_source **s); +int sd_event_add_quit(sd_event *e, sd_event_handler_t callback, void *userdata, sd_event_source **s); int sd_event_run(sd_event *e, uint64_t timeout); int sd_event_loop(sd_event *e); @@ -101,7 +99,7 @@ sd_event_source* sd_event_source_unref(sd_event_source *s); sd_event *sd_event_get(sd_event_source *s); -int sd_event_source_set_prepare(sd_event_source *s, sd_prepare_handler_t callback); +int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback); int sd_event_source_get_pending(sd_event_source *s); int sd_event_source_get_priority(sd_event_source *s, int *priority); int sd_event_source_set_priority(sd_event_source *s, int priority); |