chiark / gitweb /
bus: use STR_IN_SET
[elogind.git] / src / core / dbus-unit.c
index d2f8ebf7602e75da1543462fa7981dbab9716baf..2d1862cfc687417e366aaf946d2d2ce3522a2db4 100644 (file)
   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 "bus-errors.h"
+#include "dbus.h"
+#include "dbus-manager.h"
+#include "dbus-unit.h"
 
-const char bus_unit_interface[] _introspect_("Unit") = 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;
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction);
+
+static int property_get_names(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Unit *u = userdata;
+        Iterator i;
+        const char *t;
+        int r;
 
-        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,
+                void *userdata,
+                sd_bus_error *error) {
 
-        assert(i);
-        assert(property);
+        Unit *u = userdata, *f;
+
+        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_dependencies(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u;
+static int property_get_dependencies(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        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,
+                void *userdata,
+                sd_bus_error *error) {
 
-        assert(i);
-        assert(property);
-        assert(u);
+        Unit *u = userdata;
 
-        d = unit_description(u);
-
-        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,
+                void *userdata,
+                sd_bus_error *error) {
 
-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;
+static int property_get_sub_state(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
 
-        assert(i);
-        assert(property);
-        assert(u);
+        Unit *u = userdata;
 
-        state = unit_sub_state_to_string(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_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;
-
-        assert(i);
-        assert(property);
-        assert(u);
+static int property_get_unit_file_state(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
 
-        state = strempty(unit_file_state_to_string(unit_get_unit_file_state(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_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,
+                void *userdata,
+                sd_bus_error *error) {
 
-        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,
+                void *userdata,
+                sd_bus_error *error) {
 
-        assert(i);
-        assert(property);
+        Unit *u = userdata;
+
+        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,
+                void *userdata,
+                sd_bus_error *error) {
 
-        assert(i);
-        assert(property);
-        assert(u);
+        Unit *u = userdata;
 
-        b = unit_can_reload(u);
-
-        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;
-
-        assert(i);
-        assert(property);
-        assert(u);
+static int property_get_can_isolate(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
 
-        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,
+                void *userdata,
+                sd_bus_error *error) {
+
         _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) {
-
-                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;
+        if (!u->job)
+                return sd_bus_message_append(reply, "(uo)", 0, "/");
 
-                /* No job, so let's fill in some placeholder
-                 * data. Since we need to fill in a valid path we
-                 * simple point to ourselves. */
-
-                p = unit_dbus_path(u);
-                if (!p)
-                        return -ENOMEM;
-
-                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &id) ||
-                    !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p))
-                        return -ENOMEM;
-        }
-
-        if (!dbus_message_iter_close_container(i, &sub))
+        p = job_dbus_path(u->job);
+        if (!p)
                 return -ENOMEM;
 
-        return 0;
+        return sd_bus_message_append(reply, "(uo)", u->job->id, p);
 }
 
-static int bus_unit_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        char *t;
-        CGroupBonding *cgb;
-        bool success;
-
-        assert(i);
-        assert(property);
-        assert(u);
-
-        cgb = unit_get_default_cgroup(u);
-        if (cgb) {
-                t = cgroup_bonding_to_string(cgb);
-                if (!t)
-                        return -ENOMEM;
-        } else
-                t = (char*) "";
+static int property_get_need_daemon_reload(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
 
-        success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
+        Unit *u = userdata;
 
-        if (cgb)
-                free(t);
+        assert(bus);
+        assert(reply);
+        assert(u);
 
-        return success ? 0 : -ENOMEM;
+        return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u));
 }
 
-static int bus_unit_append_cgroups(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        CGroupBonding *cgb;
-        DBusMessageIter sub;
+static int property_get_conditions(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Unit *u = userdata;
+        Condition *c;
+        int r;
 
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
-                return -ENOMEM;
+        assert(bus);
+        assert(reply);
+        assert(u);
 
-        LIST_FOREACH(by_unit, cgb, u->cgroup_bondings) {
-                char _cleanup_free_ *t = NULL;
-                bool success;
+        r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
+        if (r < 0)
+                return r;
 
-                t = cgroup_bonding_to_string(cgb);
-                if (!t)
-                        return -ENOMEM;
+        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;
 
-                success = dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t);
-                if (!success)
-                        return -ENOMEM;
         }
 
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
+        return sd_bus_message_close_container(reply);
 }
 
-static int bus_unit_append_cgroup_attrs(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        CGroupAttribute *a;
-        DBusMessageIter sub, sub2;
-
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sss)", &sub))
-                return -ENOMEM;
-
-        LIST_FOREACH(by_unit, a, u->cgroup_attributes) {
-                char _cleanup_free_ *v = NULL;
-                bool success;
-
-                if (a->map_callback)
-                        a->map_callback(a->controller, a->name, a->value, &v);
-
-                success =
-                        dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) &&
-                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->controller) &&
-                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->name) &&
-                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, v ? &v : &a->value) &&
-                        dbus_message_iter_close_container(&sub, &sub2);
-                if (!success)
-                        return -ENOMEM;
-        }
-
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
-
-        return 0;
-}
+static int property_get_load_error(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
 
-static int bus_unit_append_need_daemon_reload(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        dbus_bool_t b;
+        _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
+        Unit *u = userdata;
 
-        assert(i);
-        assert(property);
+        assert(bus);
+        assert(reply);
         assert(u);
 
-        b = unit_need_daemon_reload(u);
+        if (u->load_error != 0)
+                sd_bus_error_set_errno(&e, u->load_error);
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
-                return -ENOMEM;
-
-        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, sd_bus_error *error) {
+        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 r;
 
-        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_error_setf(error, 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, error);
 }
 
-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;
-
-        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);
-                }
-
-                if (signo <= 0 || signo >= _NSIG)
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
-
-                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.Unit", "ResetFailed")) {
-
-                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 (streq_ptr(dbus_message_get_member(message), "SetControlGroups")) {
-                DBusMessageIter iter;
-
-                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
-
-                if (!dbus_message_iter_init(message, &iter))
-                        goto oom;
-
-                r = bus_unit_cgroup_set(u, &iter);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, NULL, r);
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-        } else if (streq_ptr(dbus_message_get_member(message), "UnsetControlGroups")) {
-                DBusMessageIter iter;
-
-                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
+static int method_start(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return bus_unit_method_start_generic(bus, message, userdata, JOB_START, false, error);
+}
 
-                if (!dbus_message_iter_init(message, &iter))
-                        goto oom;
+static int method_stop(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return bus_unit_method_start_generic(bus, message, userdata, JOB_STOP, false, error);
+}
 
-                r = bus_unit_cgroup_set(u, &iter);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, NULL, r);
+static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return bus_unit_method_start_generic(bus, message, userdata, JOB_RELOAD, false, error);
+}
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-        } else if (streq_ptr(dbus_message_get_member(message), "GetControlGroupAttributes")) {
-                DBusMessageIter iter;
-                _cleanup_strv_free_ char **list = NULL;
+static int method_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, false, error);
+}
 
-                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
+static int method_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, false, error);
+}
 
-                if (!dbus_message_iter_init(message, &iter))
-                        goto oom;
+static int method_reload_or_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, true, error);
+}
 
-                r = bus_unit_cgroup_attribute_get(u, &iter, &list);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, NULL, r);
+static int method_reload_or_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, true, error);
+}
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Unit *u = userdata;
+        const char *swho;
+        int32_t signo;
+        KillWho who;
+        int r;
 
-                dbus_message_iter_init_append(reply, &iter);
-                if (bus_append_strv_iter(&iter, list) < 0)
-                        goto oom;
+        assert(bus);
+        assert(message);
+        assert(u);
 
-        } else if (streq_ptr(dbus_message_get_member(message), "SetControlGroupAttributes")) {
-                DBusMessageIter iter;
+        r = bus_verify_manage_unit_async_for_kill(u->manager, message, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
+        r = sd_bus_message_read(message, "si", &swho, &signo);
+        if (r < 0)
+                return r;
 
-                if (!dbus_message_iter_init(message, &iter))
-                        goto oom;
+        if (isempty(swho))
+                who = KILL_ALL;
+        else {
+                who = kill_who_from_string(swho);
+                if (who < 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
+        }
 
-                r = bus_unit_cgroup_attribute_set(u, &iter);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, NULL, r);
+        if (signo <= 0 || signo >= _NSIG)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
 
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
+        r = mac_selinux_unit_access_check(u, message, "stop", error);
+        if (r < 0)
+                return r;
 
-        } else if (streq_ptr(dbus_message_get_member(message), "UnsetControlGroupAttributes")) {
-                DBusMessageIter iter;
+        r = unit_kill(u, who, signo, error);
+        if (r < 0)
+                return r;
 
-                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
+        return sd_bus_reply_method_return(message, NULL);
+}
 
-                if (!dbus_message_iter_init(message, &iter))
-                        goto oom;
+int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Unit *u = userdata;
+        int r;
 
-                r = bus_unit_cgroup_attribute_unset(u, &iter);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, NULL, 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);
-                }
+        assert(bus);
+        assert(message);
+        assert(u);
 
-                return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
-        }
+        r = bus_verify_manage_unit_async(u->manager, message, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-        if (reply)
-                if (!dbus_connection_send(connection, reply, NULL))
-                        goto oom;
+        r = mac_selinux_unit_access_check(u, message, "reload", error);
+        if (r < 0)
+                return r;
 
-        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(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, sd_bus_error *error) {
+        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 = bus_verify_manage_unit_async(u->manager, message, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-                SELINUX_ACCESS_CHECK(connection, message, "status");
+        r = sd_bus_message_read(message, "b", &runtime);
+        if (r < 0)
+                return r;
 
-                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 = mac_selinux_unit_access_check(u, message, "start", error);
+        if (r < 0)
+                return r;
 
-                        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 r;
 
-                        /* 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(message, NULL);
+}
 
-                        f = open_memstream(&introspection, &size);
-                        if (!f)
-                                goto oom;
+const sd_bus_vtable bus_unit_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+
+        SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
+        SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
+        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), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
+        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, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        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), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
+        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, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
+
+        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(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-                              "<node>\n", f);
+static int property_get_slice(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
 
-                        fputs(BUS_INTROSPECTABLE_INTERFACE, f);
-                        fputs(BUS_PEER_INTERFACE, f);
+        Unit *u = userdata;
 
-                        HASHMAP_FOREACH_KEY(u, k, m->units, i) {
-                                char *p;
+        assert(bus);
+        assert(reply);
+        assert(u);
 
-                                if (k != u->id)
-                                        continue;
+        return sd_bus_message_append(reply, "s", unit_slice_name(u));
+}
 
-                                p = bus_path_escape(k);
-                                if (!p) {
-                                        fclose(f);
-                                        free(introspection);
-                                        goto oom;
-                                }
+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
+};
 
-                                fprintf(f, "<node name=\"%s\"/>", p);
-                                free(p);
-                        }
+static int send_new_signal(sd_bus *bus, void *userdata) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        _cleanup_free_ char *p = NULL;
+        Unit *u = userdata;
+        int r;
 
-                        fputs("</node>\n", f);
+        assert(bus);
+        assert(u);
 
-                        if (ferror(f)) {
-                                fclose(f);
-                                free(introspection);
-                                goto oom;
-                        }
+        p = unit_dbus_path(u);
+        if (!u)
+                return -ENOMEM;
 
-                        fclose(f);
+        r = sd_bus_message_new_signal(
+                        bus,
+                        &m,
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "UnitNew");
+        if (r < 0)
+                return r;
 
-                        if (!introspection)
-                                goto oom;
+        r = sd_bus_message_append(m, "so", u->id, p);
+        if (r < 0)
+                return r;
 
-                        if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
-                                free(introspection);
-                                goto oom;
-                        }
+        return sd_bus_send(bus, m, NULL);
+}
 
-                        free(introspection);
+static int send_changed_signal(sd_bus *bus, void *userdata) {
+        _cleanup_free_ char *p = NULL;
+        Unit *u = userdata;
+        int r;
 
-                        if (!dbus_connection_send(connection, reply, NULL))
-                                goto oom;
+        assert(bus);
+        assert(u);
 
-                        return DBUS_HANDLER_RESULT_HANDLED;
-                }
+        p = unit_dbus_path(u);
+        if (!p)
+                return -ENOMEM;
 
-                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-        }
+        /* 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. */
 
-        r = manager_load_unit_from_dbus_path(m, dbus_message_get_path(message), &error, &u);
-        if (r == -ENOMEM)
-                goto oom;
+        r = sd_bus_emit_properties_changed_strv(
+                        bus, p,
+                        UNIT_VTABLE(u)->bus_interface,
+                        NULL);
         if (r < 0)
-                return bus_send_error_reply(connection, message, &error, r);
-
-        return bus_unit_message_dispatch(u, connection, message);
-
-oom:
-        dbus_error_free(&error);
+                return r;
 
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+        return sd_bus_emit_properties_changed_strv(
+                        bus, p,
+                        "org.freedesktop.systemd1.Unit",
+                        NULL);
 }
 
-const DBusObjectPathVTable bus_unit_vtable = {
-        .message_function = bus_unit_message_handler
-};
-
 void bus_unit_send_change_signal(Unit *u) {
-        _cleanup_free_ char *p = NULL;
-        _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
-
+        int r;
         assert(u);
 
         if (u->in_dbus_queue) {
-                LIST_REMOVE(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
+                LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
                 u->in_dbus_queue = false;
         }
 
         if (!u->id)
                 return;
 
-        if (!bus_has_subscriber(u->manager)) {
-                u->sent_dbus_new_signal = true;
-                return;
-        }
-
-        p = unit_dbus_path(u);
-        if (!p)
-                goto oom;
-
-        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)
-                                goto oom;
+        r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
+        if (r < 0)
+                log_debug("Failed to send unit change signal for %s: %s", u->id, strerror(-r));
 
-                        if (bus_broadcast(u->manager, m) < 0)
-                                goto oom;
+        u->sent_dbus_new_signal = true;
+}
 
-                        dbus_message_unref(m);
-                }
+static int send_removed_signal(sd_bus *bus, void *userdata) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        _cleanup_free_ char *p = NULL;
+        Unit *u = userdata;
+        int r;
 
-                m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Unit",
-                                               INVALIDATING_PROPERTIES);
-                if (!m)
-                        goto oom;
-
-        } else {
-                /* Send a new signal */
-
-                m = dbus_message_new_signal("/org/freedesktop/systemd1",
-                                            "org.freedesktop.systemd1.Manager",
-                                            "UnitNew");
-                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;
-        }
+        assert(bus);
+        assert(u);
 
-        if (bus_broadcast(u->manager, m) < 0)
-                goto oom;
+        p = unit_dbus_path(u);
+        if (!u)
+                return -ENOMEM;
 
-        u->sent_dbus_new_signal = true;
+        r = sd_bus_message_new_signal(
+                        bus,
+                        &m,
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "UnitRemoved");
+        if (r < 0)
+                return r;
 
-        return;
+        r = sd_bus_message_append(m, "so", u->id, p);
+        if (r < 0)
+                return r;
 
-oom:
-        log_oom();
+        return sd_bus_send(bus, m, 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_foreach_bus(u->manager, NULL, send_removed_signal, u);
+        if (r < 0)
+                log_debug("Failed to send unit remove 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) {
+                bool reload_if_possible,
+                sd_bus_error *error) {
 
-        _cleanup_dbus_message_unref_ DBusMessage *reply = 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;
@@ -844,367 +757,240 @@ DBusHandlerResult bus_unit_queue_job(
                         type = JOB_RELOAD;
         }
 
-        SELINUX_UNIT_ACCESS_CHECK(u, connection, message,
-                                  (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
-                                  type == JOB_STOP ? "stop" : "reload");
+        r = mac_selinux_unit_access_check(
+                        u, message,
+                        (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
+                        type == JOB_STOP ? "stop" : "reload", error);
+        if (r < 0)
+                return r;
 
-        if (type == JOB_STOP && 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_error_setf(error, 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_error_setf(error, 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);
+        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;
+                return r;
 
-        LIST_PREPEND(JobBusClient, client, j->bus_client_list, cl);
+        if (bus == u->manager->api_bus) {
+                if (!j->clients) {
+                        r = sd_bus_track_new(bus, &j->clients, NULL, NULL);
+                        if (r < 0)
+                                return r;
+                }
 
-        reply = dbus_message_new_method_return(message);
-        if (!reply)
-                goto oom;
+                r = sd_bus_track_add_sender(j->clients, message);
+                if (r < 0)
+                        return r;
+        }
 
         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 (!dbus_connection_send(connection, reply, NULL))
-                goto oom;
-
-        return DBUS_HANDLER_RESULT_HANDLED;
-
-oom:
-        dbus_error_free(&error);
+                return -ENOMEM;
 
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+        return sd_bus_reply_method_return(message, "o", path);
 }
 
-int bus_unit_cgroup_set(Unit *u, DBusMessageIter *iter) {
+static int bus_unit_set_transient_property(
+                Unit *u,
+                const char *name,
+                sd_bus_message *message,
+                UnitSetPropertiesMode mode,
+                sd_bus_error *error) {
+
         int r;
-        _cleanup_strv_free_ char **a = NULL;
-        char **name;
 
         assert(u);
-        assert(iter);
-
-        if (!unit_get_exec_context(u))
-                return -EINVAL;
-
-        r = bus_parse_strv_iter(iter, &a);
-        if (r < 0)
-                return r;
-
-        STRV_FOREACH(name, a) {
-                _cleanup_free_ char *controller = NULL, *old_path = NULL, *new_path = NULL;
-                CGroupBonding *b;
-
-                r = cg_split_spec(*name, &controller, &new_path);
-                if (r < 0)
-                        return r;
+        assert(name);
+        assert(message);
 
-                b = cgroup_bonding_find_list(u->cgroup_bondings, controller);
-                if (b) {
-                        old_path = strdup(b->path);
-                        if (!old_path)
-                                return -ENOMEM;
-                }
+        if (streq(name, "Description")) {
+                const char *d;
 
-                r = unit_add_cgroup_from_text(u, *name, true, &b);
+                r = sd_bus_message_read(message, "s", &d);
                 if (r < 0)
                         return r;
 
-                if (r > 0) {
-                        /* Try to move things to the new place, and clean up the old place */
-                        cgroup_bonding_realize(b);
-                        cgroup_bonding_migrate(b, u->cgroup_bondings);
+                if (mode != UNIT_CHECK) {
+                        r = unit_set_description(u, d);
+                        if (r < 0)
+                                return r;
 
-                        if (old_path)
-                                cg_trim(controller, old_path, true);
+                        unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
                 }
-        }
 
-        return 0;
-}
-
-int bus_unit_cgroup_unset(Unit *u, DBusMessageIter *iter) {
-        _cleanup_strv_free_ char **a = NULL;
-        char **name;
-        int r;
-
-        assert(u);
-        assert(iter);
+                return 1;
 
-        if (!unit_get_exec_context(u))
-                return -EINVAL;
+        } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
+                const char *s;
 
-        r = bus_parse_strv_iter(iter, &a);
-        if (r < 0)
-                return r;
-
-        STRV_FOREACH(name, a) {
-                _cleanup_free_ char *controller = NULL, *path = NULL, *target = NULL;
-                CGroupBonding *b;
-
-                r = cg_split_spec(*name, &controller, &path);
+                r = sd_bus_message_read(message, "s", &s);
                 if (r < 0)
                         return r;
 
-                b = cgroup_bonding_find_list(u->cgroup_bondings, controller);
-                if (!b)
-                        continue;
-
-                if (path && !path_equal(path, b->path))
-                        continue;
-
-                if (b->essential)
-                        return -EINVAL;
-
-                /* Try to migrate the old group away */
-                if (cg_get_by_pid(controller, 0, &target) >= 0)
-                        cgroup_bonding_migrate_to(u->cgroup_bondings, target, false);
-
-                cgroup_bonding_free(b, true);
-        }
+                if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
 
-        return 0;
-}
+                if (isempty(s)) {
+                        if (mode != UNIT_CHECK) {
+                                unit_ref_unset(&u->slice);
+                                unit_remove_drop_in(u, mode, name);
+                        }
+                } else {
+                        Unit *slice;
 
-int bus_unit_cgroup_attribute_get(Unit *u, DBusMessageIter *iter, char ***_result) {
-        _cleanup_strv_free_ char **l = NULL, **result = NULL;
-        char **name;
-        int r;
+                        r = manager_load_unit(u->manager, s, NULL, error, &slice);
+                        if (r < 0)
+                                return r;
 
-        assert(u);
-        assert(iter);
-        assert(_result);
+                        if (slice->type != UNIT_SLICE)
+                                return -EINVAL;
 
-        if (!unit_get_exec_context(u))
-                return -EINVAL;
+                        if (mode != UNIT_CHECK) {
+                                unit_ref_set(&u->slice, slice);
+                                unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
+                        }
+                }
 
-        r = bus_parse_strv_iter(iter, &l);
-        if (r < 0)
-                return r;
+                return 1;
+        } else if (STR_IN_SET(name,
+                              "Requires", "RequiresOverridable",
+                              "Requisite", "RequisiteOverridable",
+                              "Wants",
+                              "BindsTo",
+                              "Conflicts",
+                              "Before", "After",
+                              "OnFailure",
+                              "PropagatesReloadTo", "ReloadPropagatedFrom",
+                              "PartOf")) {
+
+                UnitDependency d;
+                const char *other;
+
+                d = unit_dependency_from_string(name);
+                if (d < 0)
+                        return -EINVAL;
 
-        STRV_FOREACH(name, l) {
-                _cleanup_free_ char *controller = NULL;
-                const char *dot;
-                CGroupAttribute *a;
-                CGroupBonding *b;
-
-                dot = strchr(*name, '.');
-                if (dot) {
-                        controller = strndup(*name, dot - *name);
-                        if (!controller)
-                                return -ENOMEM;
-                }
+                r = sd_bus_message_enter_container(message, 'a', "s");
+                if (r < 0)
+                        return r;
 
-                /* First attempt, read the value from the kernel */
-                b = cgroup_bonding_find_list(u->cgroup_bondings, controller);
-                if (b) {
-                        _cleanup_free_ char *p = NULL, *v = NULL;
+                while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
+                        if (!unit_name_is_valid(other, TEMPLATE_INVALID))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
 
-                        r = cg_get_path(b->controller, b->path, *name, &p);
-                        if (r < 0)
-                                return r;
+                        if (mode != UNIT_CHECK) {
+                                _cleanup_free_ char *label = NULL;
 
-                        r = read_full_file(p, &v, NULL);
-                        if (r >= 0) {
-                                r = strv_extend(&result, v);
+                                r = unit_add_dependency_by_name(u, d, other, NULL, true);
                                 if (r < 0)
                                         return r;
 
-                                continue;
-                        } else if (r != -ENOENT)
-                                return r;
-                }
+                                label = strjoin(name, "-", other, NULL);
+                                if (!label)
+                                        return -ENOMEM;
 
-                /* If that didn't work, read our cached value */
-                a = cgroup_attribute_find_list(u->cgroup_attributes, NULL, *name);
-                if (a) {
-                        r = strv_extend(&result, a->value);
-                        if (r < 0)
-                                return r;
+                                unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
+                        }
 
-                        continue;
                 }
+                if (r < 0)
+                        return r;
 
-                return -ENOENT;
-        }
+                r = sd_bus_message_exit_container(message);
+                if (r < 0)
+                        return r;
 
-        *_result = result;
-        result = NULL;
+                return 1;
+        }
 
         return 0;
 }
 
-int bus_unit_cgroup_attribute_set(Unit *u, DBusMessageIter *iter) {
-        DBusMessageIter sub, sub2;
+int bus_unit_set_properties(
+                Unit *u,
+                sd_bus_message *message,
+                UnitSetPropertiesMode mode,
+                bool commit,
+                sd_bus_error *error) {
+
+        bool for_real = false;
+        unsigned n = 0;
         int r;
 
         assert(u);
-        assert(iter);
+        assert(message);
 
-        if (!unit_get_exec_context(u))
-                return -EINVAL;
+        /* We iterate through the array twice. First run we just check
+         * if all passed data is valid, second run actually applies
+         * 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 (;;) {
+                const char *name;
 
-        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                const char *name, *value;
-                CGroupAttribute *a;
+                r = sd_bus_message_enter_container(message, 'r', "sv");
+                if (r < 0)
+                        return r;
+                if (r == 0) {
+                        if (for_real || mode == UNIT_CHECK)
+                                break;
 
-                assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
+                        /* Reached EOF. Let's try again, and this time for realz... */
+                        r = sd_bus_message_rewind(message, false);
+                        if (r < 0)
+                                return r;
 
-                dbus_message_iter_recurse(&sub, &sub2);
+                        for_real = true;
+                        continue;
+                }
 
-                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) < 0)
-                        return -EINVAL;
+                r = sd_bus_message_read(message, "s", &name);
+                if (r < 0)
+                        return r;
 
-                dbus_message_iter_next(&sub);
+                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.");
 
-                r = unit_add_cgroup_attribute(u, NULL, name, value, NULL, &a);
+                r = sd_bus_message_enter_container(message, 'v', NULL);
                 if (r < 0)
                         return r;
 
-                if (r > 0) {
-                        CGroupBonding *b;
+                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, 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);
 
-                        b = cgroup_bonding_find_list(u->cgroup_bondings, a->controller);
-                        if (!b) {
-                                /* Doesn't exist yet? Then let's add it */
-                                r = unit_add_cgroup_from_text(u, a->controller, false, &b);
-                                if (r < 0)
-                                        return r;
+                r = sd_bus_message_exit_container(message);
+                if (r < 0)
+                        return r;
 
-                                if (r > 0) {
-                                        cgroup_bonding_realize(b);
-                                        cgroup_bonding_migrate(b, u->cgroup_bondings);
-                                }
-                        }
+                r = sd_bus_message_exit_container(message);
+                if (r < 0)
+                        return r;
 
-                        /* Make it count */
-                        cgroup_attribute_apply(a, u->cgroup_bondings);
-                }
+                n += for_real;
         }
 
-        return 0;
-}
-
-int bus_unit_cgroup_attribute_unset(Unit *u, DBusMessageIter *iter) {
-        _cleanup_strv_free_ char **l = NULL;
-        char **name;
-        int r;
-
-        assert(u);
-        assert(iter);
-
-        if (!unit_get_exec_context(u))
-                return -EINVAL;
-
-        r = bus_parse_strv_iter(iter, &l);
+        r = sd_bus_message_exit_container(message);
         if (r < 0)
                 return r;
 
-        STRV_FOREACH(name, l) {
-                CGroupAttribute *a;
-
-                a = cgroup_attribute_find_list(u->cgroup_attributes, NULL, *name);
-                if (a)
-                        cgroup_attribute_free(a);
-        }
+        if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
+                UNIT_VTABLE(u)->bus_commit_properties(u);
 
-        return 0;
+        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 },
-        { "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)                   },
-        { "LoadError",            bus_unit_append_load_error,      "(ss)", 0 },
-        { NULL, }
-};
-
-const BusProperty bus_unit_cgroup_properties[] = {
-        { "DefaultControlGroup",    bus_unit_append_default_cgroup,     "s", 0 },
-        { "ControlGroups",          bus_unit_append_cgroups,           "as", 0 },
-        { "ControlGroupAttributes", bus_unit_append_cgroup_attrs,  "a(sss)", 0 },
-        { NULL, }
-};