chiark / gitweb /
logind: use new udev_enumerate_add_match_parent() where applicable
[elogind.git] / src / logind-dbus.c
index 69e6b189aaf0a75b33b5c5357abd1c4a342c29da..4321ffd90043906f4736f0de0790a7e35e569083 100644 (file)
         "  <method name=\"ActivateSession\">\n"                         \
         "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
         "  </method>\n"                                                 \
+        "  <method name=\"LockSession\">\n"                             \
+        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
+        "  </method>\n"                                                 \
+        "  <method name=\"UnlockSession\">\n"                           \
+        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
+        "  </method>\n"                                                 \
+        "  <method name=\"KillSession\">\n"                             \
+        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
+        "   <arg name=\"who\" type=\"s\"/>\n"                           \
+        "   <arg name=\"signal\" type=\"s\"/>\n"                        \
+        "  </method>\n"                                                 \
+        "  <method name=\"KillUser\">\n"                                \
+        "   <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"          \
+        "   <arg name=\"signal\" type=\"s\"/>\n"                        \
+        "  </method>\n"                                                 \
         "  <method name=\"TerminateSession\">\n"                        \
         "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
         "  </method>\n"                                                 \
         "   <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n"        \
         "   <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n"  \
         "  </method>\n"                                                 \
+        "  <method name=\"FlushDevices\">\n"                            \
+        "   <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n"  \
+        "  </method>\n"                                                 \
         "  <signal name=\"SessionNew\">\n"                              \
         "   <arg name=\"id\" type=\"s\"/>\n"                            \
         "   <arg name=\"path\" type=\"o\"/>\n"                          \
@@ -316,7 +334,8 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
         if (r < 0)
                 return -EINVAL;
 
-        if (!dbus_message_iter_next(&iter) ||
+        if (strv_contains(controllers, "systemd") ||
+            !dbus_message_iter_next(&iter) ||
             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
                 r = -EINVAL;
@@ -327,7 +346,8 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
         if (r < 0)
                 goto fail;
 
-        if (!dbus_message_iter_next(&iter) ||
+        if (strv_contains(reset_controllers, "systemd") ||
+            !dbus_message_iter_next(&iter) ||
             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
                 r = -EINVAL;
                 goto fail;
@@ -530,20 +550,56 @@ fail:
         return r;
 }
 
-static bool device_has_tag(struct udev_device *d, const char *tag) {
+static int trigger_device(Manager *m, struct udev_device *d) {
+        struct udev_enumerate *e;
         struct udev_list_entry *first, *item;
+        int r;
+
+        assert(m);
+
+        e = udev_enumerate_new(m->udev);
+        if (!e) {
+                r = -ENOMEM;
+                goto finish;
+        }
 
-        assert(d);
-        assert(tag);
+        if (d) {
+                if (udev_enumerate_add_match_parent(e, d) < 0) {
+                        r = -EIO;
+                        goto finish;
+                }
+        }
+
+
+        if (udev_enumerate_scan_devices(e) < 0) {
+                r = -EIO;
+                goto finish;
+        }
+
+        first = udev_enumerate_get_list_entry(e);
+        udev_list_entry_foreach(item, first) {
+                char *t;
+                const char *p;
+
+                p = udev_list_entry_get_name(item);
 
-        udev_device_get_is_initialized(d);
+                t = strappend(p, "/uevent");
+                if (!t) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
 
-        first = udev_device_get_tags_list_entry(d);
-        udev_list_entry_foreach(item, first)
-                if (streq(udev_list_entry_get_name(item), tag))
-                        return true;
+                write_one_line_file(t, "change");
+                free(t);
+        }
 
-        return false;
+        r = 0;
+
+finish:
+        if (e)
+                udev_enumerate_unref(e);
+
+        return r;
 }
 
 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
@@ -551,8 +607,6 @@ static int attach_device(Manager *m, const char *seat, const char *sysfs) {
         char *rule = NULL, *file = NULL;
         const char *id_for_seat;
         int r;
-        struct udev_enumerate *e;
-        struct udev_list_entry *first, *item;
 
         assert(m);
         assert(seat);
@@ -562,7 +616,7 @@ static int attach_device(Manager *m, const char *seat, const char *sysfs) {
         if (!d)
                 return -ENODEV;
 
-        if (!device_has_tag(d, "seat")) {
+        if (!udev_device_has_tag(d, "seat")) {
                 r = -ENODEV;
                 goto finish;
         }
@@ -584,39 +638,11 @@ static int attach_device(Manager *m, const char *seat, const char *sysfs) {
         }
 
         mkdir_p("/etc/udev/rules.d", 0755);
-        r = write_one_line_file(file, rule);
+        r = write_one_line_file_atomic(file, rule);
         if (r < 0)
                 goto finish;
 
-        e = udev_enumerate_new(m->udev);
-        if (!e) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (udev_enumerate_scan_devices(e) < 0) {
-                r = -EIO;
-                goto finish;
-        }
-
-        first = udev_enumerate_get_list_entry(e);
-        udev_list_entry_foreach(item, first) {
-                char *t;
-                const char *p;
-
-                p = udev_list_entry_get_name(item);
-                if (!path_startswith(p, sysfs))
-                        continue;
-
-                t = strappend(p, "/uevent");
-                if (!t) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                write_one_line_file(t, "change");
-                free(t);
-        }
+        r = trigger_device(m, d);
 
 finish:
         free(rule);
@@ -625,12 +651,42 @@ finish:
         if (d)
                 udev_device_unref(d);
 
-        if (e)
-                udev_enumerate_unref(e);
-
         return r;
 }
 
+static int flush_devices(Manager *m) {
+        DIR *d;
+
+        assert(m);
+
+        d = opendir("/etc/udev/rules.d");
+        if (!d) {
+                if (errno != ENOENT)
+                        log_warning("Failed to open /etc/udev/rules.d: %m");
+        } else {
+                struct dirent *de;
+
+                while ((de = readdir(d))) {
+
+                        if (!dirent_is_file(de))
+                                continue;
+
+                        if (!startswith(de->d_name, "72-seat-"))
+                                continue;
+
+                        if (!endswith(de->d_name, ".rules"))
+                                continue;
+
+                        if (unlinkat(dirfd(d), de->d_name, 0) < 0)
+                                log_warning("Failed to unlink %s: %m", de->d_name);
+                }
+
+                closedir(d);
+        }
+
+        return trigger_device(m, NULL);
+}
+
 static DBusHandlerResult manager_message_handler(
                 DBusConnection *connection,
                 DBusMessage *message,
@@ -927,6 +983,96 @@ static DBusHandlerResult manager_message_handler(
                 if (!reply)
                         goto oom;
 
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
+                   dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
+                const char *name;
+                Session *session;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &name,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                session = hashmap_get(m->sessions, name);
+                if (!session)
+                        return bus_send_error_reply(connection, message, &error, -ENOENT);
+
+                if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
+                        goto oom;
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
+                const char *swho;
+                int32_t signo;
+                KillWho who;
+                const char *name;
+                Session *session;
+
+                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);
+                }
+
+                if (signo <= 0 || signo >= _NSIG)
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                session = hashmap_get(m->sessions, name);
+                if (!session)
+                        return bus_send_error_reply(connection, message, &error, -ENOENT);
+
+                r = session_kill(session, who, signo);
+                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 (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
+                uint32_t uid;
+                User *user;
+                int32_t signo;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_UINT32, &uid,
+                                    DBUS_TYPE_INT32, &signo,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                if (signo <= 0 || signo >= _NSIG)
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
+                if (!user)
+                        return bus_send_error_reply(connection, message, &error, -ENOENT);
+
+                r = user_kill(user, signo);
+                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 (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
                 const char *name;
                 Session *session;
@@ -1086,6 +1232,29 @@ static DBusHandlerResult manager_message_handler(
                 if (!reply)
                         goto oom;
 
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
+                dbus_bool_t interactive;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_BOOLEAN, &interactive,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, &error);
+                if (r < 0)
+                        return bus_send_error_reply(connection, message, &error, r);
+
+                r = flush_devices(m);
+                if (r < 0)
+                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
         } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
                 char *introspection = NULL;
                 FILE *f;