]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/dbus-path.c
Merge pull request #17732 from yuwata/core-use-synthetic_errno
[thirdparty/systemd.git] / src / core / dbus-path.c
index a523b8144627b500307e19b6985dedde5a15dd7c..14e77d783dd929b25a17560907c4dcc48d2ae34f 100644 (file)
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
-/***
-  This file is part of systemd.
+#include "alloc-util.h"
+#include "bus-get-properties.h"
+#include "dbus-path.h"
+#include "dbus-util.h"
+#include "list.h"
+#include "path.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "unit.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,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Path *p = userdata;
+        PathSpec *k;
+        int r;
 
-  Copyright 2010 Lennart Poettering
+        assert(bus);
+        assert(reply);
+        assert(p);
 
-  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.
+        r = sd_bus_message_open_container(reply, 'a', "(ss)");
+        if (r < 0)
+                return r;
 
-  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.
+        LIST_FOREACH(spec, k, p->specs) {
+                r = sd_bus_message_append(reply, "(ss)", path_type_to_string(k->type), k->path);
+                if (r < 0)
+                        return r;
+        }
 
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+        return sd_bus_message_close_container(reply);
+}
 
-#include <errno.h>
+const sd_bus_vtable bus_path_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+        SD_BUS_PROPERTY("Unit", "s", bus_property_get_triggered_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Paths", "a(ss)", property_get_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("MakeDirectory", "b", bus_property_get_bool, offsetof(Path, make_directory), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Path, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Path, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_VTABLE_END
+};
 
-#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;
-        PathSpec *k;
+static int bus_path_set_transient_property(
+                Path *p,
+                const char *name,
+                sd_bus_message *message,
+                UnitWriteFlags flags,
+                sd_bus_error *error) {
+
+        Unit *u = UNIT(p);
+        int r;
 
-        assert(i);
-        assert(property);
         assert(p);
+        assert(name);
+        assert(message);
 
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &sub))
-                return -ENOMEM;
+        flags |= UNIT_PRIVATE;
 
-        LIST_FOREACH(spec, k, p->specs) {
-                const char *t = path_type_to_string(k->type);
+        if (streq(name, "MakeDirectory"))
+                return bus_set_transient_bool(u, name, &p->make_directory, message, flags, error);
 
-                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;
-        }
+        if (streq(name, "DirectoryMode"))
+                return bus_set_transient_mode_t(u, name, &p->directory_mode, message, flags, error);
 
-        if (!dbus_message_iter_close_container(i, &sub))
-                return -ENOMEM;
+        if (streq(name, "Paths")) {
+                const char *type_name, *path;
+                bool empty = true;
 
-        return 0;
-}
+                r = sd_bus_message_enter_container(message, 'a', "(ss)");
+                if (r < 0)
+                        return r;
 
-static int bus_path_append_unit(DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data, *trigger;
-        const char *t;
+                while ((r = sd_bus_message_read(message, "(ss)", &type_name, &path)) > 0) {
+                        PathType t;
 
-        assert(i);
-        assert(property);
-        assert(u);
+                        t = path_type_from_string(type_name);
+                        if (t < 0)
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown path type: %s", type_name);
 
-        trigger = UNIT_TRIGGER(u);
-        t = trigger ? trigger->id : "";
+                        if (isempty(path))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path in %s is empty", type_name);
 
-        return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM;
-}
+                        if (!path_is_absolute(path))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path in %s is not absolute: %s", type_name, path);
 
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_path_append_path_result, path_result, PathResult);
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                                _cleanup_free_ char *k;
+                                PathSpec *s;
 
-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, }
-};
+                                k = strdup(path);
+                                if (!k)
+                                        return -ENOMEM;
+
+                                path_simplify(k, false);
+
+                                s = new0(PathSpec, 1);
+                                if (!s)
+                                        return -ENOMEM;
+
+                                s->unit = u;
+                                s->path = TAKE_PTR(k);
+                                s->type = t;
+                                s->inotify_fd = -1;
+
+                                LIST_PREPEND(spec, p->specs, s);
+
+                                unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", type_name, path);
+                        }
+
+                        empty = false;
+                }
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_exit_container(message);
+                if (r < 0)
+                        return r;
+
+                if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
+                        path_free_specs(p);
+                        unit_write_settingf(u, flags, name, "PathExists=");
+                }
+
+                return 1;
+        }
+
+        return 0;
+}
+
+int bus_path_set_property(
+                Unit *u,
+                const char *name,
+                sd_bus_message *message,
+                UnitWriteFlags mode,
+                sd_bus_error *error) {
 
-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");
+        assert(p);
+        assert(name);
+        assert(message);
+
+        if (u->transient && u->load_state == UNIT_STUB)
+                return bus_path_set_transient_property(p, name, message, mode, error);
 
-        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
+        return 0;
 }