chiark / gitweb /
logind: implement D-Bus properties
authorLennart Poettering <lennart@poettering.net>
Thu, 26 May 2011 00:21:16 +0000 (02:21 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 21 Jun 2011 17:29:44 +0000 (19:29 +0200)
15 files changed:
Makefile.am
src/70-uaccess.rules [new file with mode: 0644]
src/71-seat.rules [new file with mode: 0644]
src/logind-dbus.c [new file with mode: 0644]
src/logind-device.c
src/logind-seat-dbus.c [new file with mode: 0644]
src/logind-seat.c
src/logind-seat.h
src/logind-session-dbus.c [new file with mode: 0644]
src/logind-session.c
src/logind-session.h
src/logind-user-dbus.c [new file with mode: 0644]
src/logind-user.h
src/logind.c
src/logind.h

index f455f2110957fa443ca952693f0ae332f920d310..0bc51692d1b83c08e36aa22169972139880d602f 100644 (file)
@@ -810,10 +810,14 @@ systemd_hostnamed_LDADD = \
 
 systemd_logind_SOURCES = \
        src/logind.c \
 
 systemd_logind_SOURCES = \
        src/logind.c \
+       src/logind-dbus.c \
         src/logind-device.c \
         src/logind-seat.c \
         src/logind-device.c \
         src/logind-seat.c \
+        src/logind-seat-dbus.c \
         src/logind-session.c \
         src/logind-session.c \
+        src/logind-session-dbus.c \
         src/logind-user.c \
         src/logind-user.c \
+        src/logind-user-dbus.c \
         src/logind-acl.c \
         src/dbus-common.c \
         src/dbus-loop.c \
         src/logind-acl.c \
         src/dbus-common.c \
         src/dbus-loop.c \
diff --git a/src/70-uaccess.rules b/src/70-uaccess.rules
new file mode 100644 (file)
index 0000000..6932492
--- /dev/null
@@ -0,0 +1,72 @@
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+
+ACTION=="remove", GOTO="uaccess_end"
+ENV{MAJOR}=="", GOTO="uaccess_end"
+
+# PTP/MTP protocol devices, cameras, portable media players
+SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="", ENV{DEVTYPE}=="usb_device", IMPORT{program}="usb_id --export %p"
+SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="*:060101:*", TAG+="uaccess"
+
+# Digicams with proprietary protocol
+ENV{ID_GPHOTO2}=="*?", TAG+="uaccess"
+
+# SCSI and USB scanners
+ENV{libsane_matched}=="yes", TAG+="uaccess"
+
+# HPLIP devices (necessary for ink level check and HP tool maintenance)
+ENV{ID_HPLIP}=="1", TAG+="uaccess"
+
+# optical drives
+SUBSYSTEM=="block", ENV{ID_CDROM}=="1", TAG+="uaccess"
+SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="4|5", TAG+="uaccess"
+
+# Sound devices
+SUBSYSTEM=="sound", TAG+="uaccess"
+
+# ffado is an userspace driver for firewire sound cards
+SUBSYSTEM=="firewire", ENV{ID_FFADO}=="1", TAG+="uaccess"
+
+# Webcams, frame grabber, TV cards
+SUBSYSTEM=="video4linux", TAG+="uaccess"
+SUBSYSTEM=="dvb", TAG+="uaccess"
+
+# IIDC devices: industrial cameras and some webcams
+SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x00010*",  TAG+="uaccess"
+SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*",  TAG+="uaccess"
+# AV/C devices: camcorders, set-top boxes, TV sets, audio devices, and more
+SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="uaccess"
+SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess"
+
+# DRI video devices
+SUBSYSTEM=="drm", KERNEL=="card*", TAG+="uaccess"
+
+# KVM
+SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess"
+
+# smart-card readers
+ENV{ID_SMARTCARD_READER}=="*?", TAG+="uaccess"
+
+# PDA devices
+ENV{ID_PDA}=="*?", TAG+="uaccess"
+
+# Programmable remote control
+ENV{ID_REMOTE_CONTROL}=="1", TAG+="uaccess"
+
+# joysticks
+SUBSYSTEM=="input", ENV{ID_INPUT_JOYSTICK}=="?*", TAG+="uaccess"
+
+# color measurement devices
+ENV{COLOR_MEASUREMENT_DEVICE}=="*?", TAG+="uaccess"
+
+# DDC/CI device, usually high-end monitors such as the DreamColor
+ENV{DDC_DEVICE}=="*?", TAG+="uaccess"
+
+# media player raw devices (for user-mode drivers, Android SDK, etc.)
+SUBSYSTEM=="usb", ENV{ID_MEDIA_PLAYER}=="?*", TAG+="uaccess"
+
+LABEL="uaccess_end"
diff --git a/src/71-seat.rules b/src/71-seat.rules
new file mode 100644 (file)
index 0000000..3969837
--- /dev/null
@@ -0,0 +1,20 @@
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+
+ACTION=="remove", GOTO="seat_end"
+
+TAG=="uaccess", TAG+="seat"
+SUBSYSTEM=="input", TAG+="seat"
+SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", TAG+="seat"
+SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat"
+SUBSYSTEM=="usb", ATTR{idVendor}=="2230", ATTR{idProduct}=="0001", ENV{ID_AUTOSEAT}="1"
+
+IMPORT{parent}="ID_SEAT"
+ENV{ID_AUTOSEAT}=="1", ENV{ID_SEAT}=="", ENV{ID_SEAT}="seat-foo"
+ENV{ID_SEAT}!="", TAG+="seat-foo"
+
+LABEL="seat_end"
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
new file mode 100644 (file)
index 0000000..90db941
--- /dev/null
@@ -0,0 +1,235 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2011 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "logind.h"
+#include "dbus-common.h"
+
+#define BUS_MANAGER_INTERFACE                                           \
+        " <interface name=\"org.freedesktop.login1.Manager\">\n"        \
+        "  <method name=\"GetSeat\">\n"                                 \
+        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
+        "   <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n"        \
+        "  </method>\n"                                                 \
+        "  <method name=\"GetUser\">\n"                                 \
+        "   <arg name=\"uid\" type=\"t\" direction=\"in\"/>\n"          \
+        "   <arg name=\"user\" type=\"o\" direction=\"out\"/>\n"        \
+        "  </method>\n"                                                 \
+        "  <method name=\"GetSession\">\n"                              \
+        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
+        "   <arg name=\"session\" type=\"o\" direction=\"out\"/>\n"     \
+        "  </method>\n"                                                 \
+        "  <method name=\"ListSeats\">\n"                               \
+        "   <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n"   \
+        "  </method>\n"                                                 \
+        "  <method name=\"ListUsers\">\n"                               \
+        "   <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n"  \
+        "  </method>\n"                                                 \
+        "  <method name=\"ListSessions\">\n"                            \
+        "   <arg name=\"users\" type=\"a(sussso)\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"CreateSession\">\n"                           \
+        "   <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"          \
+        "   <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n"       \
+        "   <arg name=\"type\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n"          \
+        "   <arg name=\"display\" type=\"s\" direction=\"in\"/>\n"      \
+        "   <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n"       \
+        "   <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n"  \
+        "   <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n"  \
+        "   <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
+        "   <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
+        "   <arg name=\"kill_processes\" type=\"as\" direction=\"in\"/>\n" \
+        "   <arg name=\"id\" type=\"s\" direction=\"out\"/>\n"          \
+        "   <arg name=\"path\" type=\"o\" direction=\"out\"/>\n"        \
+        "   <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n"          \
+        "  </method>\n"                                                 \
+        "  <method name=\"TerminateSession\">\n"                        \
+        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
+        "  </method>\n"                                                 \
+        "  <method name=\"TerminateUser\">\n"                           \
+        "   <arg name=\"uid\" type=\"t\" direction=\"in\"/>\n"          \
+        "  </method>\n"                                                 \
+        "  <method name=\"TerminateSeat\">\n"                           \
+        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
+        "  </method>\n"                                                 \
+        "  <signal name=\"SessionNew\">\n"                              \
+        "   <arg name=\"id\" type=\"s\"/>\n"                            \
+        "   <arg name=\"path\" type=\"o\"/>\n"                          \
+        "  </signal>\n"                                                 \
+        "  <signal name=\"SessionRemoved\">\n"                          \
+        "   <arg name=\"id\" type=\"s\"/>\n"                            \
+        "   <arg name=\"path\" type=\"o\"/>\n"                          \
+        "  </signal>\n"                                                 \
+        "  <signal name=\"UserNew\">\n"                                 \
+        "   <arg name=\"uid\" type=\"u\"/>\n"                           \
+        "   <arg name=\"path\" type=\"o\"/>\n"                          \
+        "  </signal>\n"                                                 \
+        "  <signal name=\"UserRemoved\">\n"                             \
+        "   <arg name=\"uid\" type=\"u\"/>\n"                           \
+        "   <arg name=\"path\" type=\"o\"/>\n"                          \
+        "  </signal>\n"                                                 \
+        "  <signal name=\"SeatNew\">\n"                                 \
+        "   <arg name=\"id\" type=\"s\"/>\n"                            \
+        "   <arg name=\"path\" type=\"o\"/>\n"                          \
+        "  </signal>\n"                                                 \
+        "  <signal name=\"SeatRemoved\">\n"                             \
+        "   <arg name=\"id\" type=\"s\"/>\n"                            \
+        "   <arg name=\"path\" type=\"o\"/>\n"                          \
+        "  </signal>\n"                                                 \
+        "  <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
+        " </interface>\n"
+
+#define INTROSPECTION_BEGIN                                             \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_MANAGER_INTERFACE                                           \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE
+
+#define INTROSPECTION_END                                               \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_GENERIC_INTERFACES_LIST                  \
+        "org.freedesktop.login1.Manager\0"
+
+static DBusHandlerResult manager_message_handler(
+                DBusConnection *connection,
+                DBusMessage *message,
+                void *userdata) {
+
+        Manager *m = userdata;
+
+        const BusProperty properties[] = {
+                { "org.freedesktop.login1.Manager", "ControlGroupHierarchy", bus_property_append_string,   "s",  m->cgroup_path          },
+                { "org.freedesktop.login1.Manager", "Controllers",           bus_property_append_strv,     "as", m->controllers          },
+                { "org.freedesktop.login1.Manager", "ResetControllers",      bus_property_append_strv,     "as", m->reset_controllers    },
+                { "org.freedesktop.login1.Manager", "NAutoVTs",              bus_property_append_unsigned, "u",  &m->n_autovts           },
+                { "org.freedesktop.login1.Manager", "KillOnlyUsers",         bus_property_append_strv,     "as", m->kill_only_users      },
+                { "org.freedesktop.login1.Manager", "KillExcludeUsers",      bus_property_append_strv,     "as", m->kill_exclude_users   },
+                { "org.freedesktop.login1.Manager", "KillUserProcesses",     bus_property_append_bool,     "b",  &m->kill_user_processes },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        DBusError error;
+        DBusMessage *reply = NULL;
+
+        assert(connection);
+        assert(message);
+        assert(m);
+
+        dbus_error_init(&error);
+
+        if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+                char *introspection = NULL;
+                FILE *f;
+                Iterator i;
+                Session *session;
+                Seat *seat;
+                User *user;
+                size_t size;
+                char *p;
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                /* We roll our own introspection code here, instead of
+                 * relying on bus_default_message_handler() because we
+                 * need to generate our introspection string
+                 * dynamically. */
+
+                if (!(f = open_memstream(&introspection, &size)))
+                        goto oom;
+
+                fputs(INTROSPECTION_BEGIN, f);
+
+                HASHMAP_FOREACH(seat, m->seats, i) {
+                        p = bus_path_escape(seat->id);
+
+                        if (p) {
+                                fprintf(f, "<node name=\"seat/%s\"/>", p);
+                                free(p);
+                        }
+                }
+
+                HASHMAP_FOREACH(user, m->users, i)
+                        fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
+
+                HASHMAP_FOREACH(session, m->sessions, i) {
+                        p = bus_path_escape(session->id);
+
+                        if (p) {
+                                fprintf(f, "<node name=\"session/%s\"/>", p);
+                                free(p);
+                        }
+                }
+
+                fputs(INTROSPECTION_END, f);
+
+                if (ferror(f)) {
+                        fclose(f);
+                        free(introspection);
+                        goto oom;
+                }
+
+                fclose(f);
+
+                if (!introspection)
+                        goto oom;
+
+                if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
+                        free(introspection);
+                        goto oom;
+                }
+
+                free(introspection);
+        } else
+                return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, properties);
+
+        if (reply) {
+                if (!dbus_connection_send(connection, reply, NULL))
+                        goto oom;
+
+                dbus_message_unref(reply);
+        }
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+const DBusObjectPathVTable bus_manager_vtable = {
+        .message_function = manager_message_handler
+};
index 4e076c20b63c7728e278aca8d31457cc69c3b35c..31afa4ff2a776cb420bda0ca119142b877654b9f 100644 (file)
@@ -80,6 +80,6 @@ void device_attach(Device *d, Seat *s) {
         if (d->seat)
                 device_detach(d);
 
         if (d->seat)
                 device_detach(d);
 
-        LIST_PREPEND(Device, devices, d->seat->devices, d);
         d->seat = s;
         d->seat = s;
+        LIST_PREPEND(Device, devices, s->devices, d);
 }
 }
diff --git a/src/logind-seat-dbus.c b/src/logind-seat-dbus.c
new file mode 100644 (file)
index 0000000..63b1bd5
--- /dev/null
@@ -0,0 +1,218 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2011 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "logind.h"
+#include "logind-seat.h"
+#include "dbus-common.h"
+#include "util.h"
+
+#define BUS_SEAT_INTERFACE \
+        " <interface name=\"org.freedesktop.login1.Seat\">\n"           \
+        "  <method name=\"Terminate\"/>\n"                              \
+        "  <property name=\"Id\" type=\"s\" access=\"read\"/>\n"        \
+        "  <property name=\"Active\" type=\"so\" access=\"read\"/>\n"   \
+        "  <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
+        " </interface>\n"                                               \
+
+#define INTROSPECTION                                                   \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_SEAT_INTERFACE                                              \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE                                    \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_GENERIC_INTERFACES_LIST                  \
+        "org.freedesktop.login1.Seat\0"
+
+static int bus_seat_append_active(DBusMessageIter *i, const char *property, void *data) {
+        DBusMessageIter sub;
+        Seat *s = data;
+        const char *id, *path;
+        char *p = NULL;
+
+        assert(i);
+        assert(property);
+        assert(s);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+                return -ENOMEM;
+
+        if (s->active) {
+                id = s->active->id;
+                path = p = session_bus_path(s->active);
+
+                if (!p)
+                        return -ENOMEM;
+        } else {
+                id = "";
+                path = "/";
+        }
+
+        if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
+            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
+                free(p);
+                return -ENOMEM;
+        }
+
+        free(p);
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_seat_append_sessions(DBusMessageIter *i, const char *property, void *data) {
+        DBusMessageIter sub, sub2;
+        Seat *s = data;
+        Session *session;
+
+        assert(i);
+        assert(property);
+        assert(s);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "so", &sub))
+                return -ENOMEM;
+
+        LIST_FOREACH(sessions_by_seat, session, s->sessions) {
+                char *p;
+
+                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+                        return -ENOMEM;
+
+                p = session_bus_path(session);
+                if (!p)
+                        return -ENOMEM;
+
+                if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
+                        free(p);
+                        return -ENOMEM;
+                }
+
+                free(p);
+
+                if (!dbus_message_iter_close_container(&sub, &sub2))
+                        return -ENOMEM;
+        }
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int get_seat_for_path(Manager *m, const char *path, Seat **_s) {
+        Seat *s;
+        char *id;
+
+        assert(m);
+        assert(path);
+        assert(_s);
+
+        if (!startswith(path, "/org/freedesktop/login1/seat/"))
+                return -EINVAL;
+
+        id = bus_path_unescape(path + 29);
+        if (!id)
+                return -ENOMEM;
+
+        s = hashmap_get(m->seats, id);
+        free(id);
+
+        if (!s)
+                return -ENOENT;
+
+        *_s = s;
+        return 0;
+}
+
+static DBusHandlerResult seat_message_dispatch(
+                Seat *s,
+                DBusConnection *connection,
+                DBusMessage *message) {
+
+        const BusProperty properties[] = {
+                { "org.freedesktop.login1.Seat", "Id",       bus_property_append_string, "s",     s->id },
+                { "org.freedesktop.login1.Seat", "Active",   bus_seat_append_active,     "(so)",  s     },
+                { "org.freedesktop.login1.Seat", "Sessions", bus_seat_append_sessions,   "a(so)", s     },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        assert(s);
+        assert(connection);
+        assert(message);
+
+        return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+}
+
+static DBusHandlerResult seat_message_handler(
+                DBusConnection *connection,
+                DBusMessage *message,
+                void *userdata) {
+
+        Manager *m = userdata;
+        Seat *s;
+        int r;
+
+        r = get_seat_for_path(m, dbus_message_get_path(message), &s);
+        if (r < 0) {
+
+                if (r == -ENOMEM)
+                        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+                if (r == -ENOENT) {
+                        DBusError e;
+
+                        dbus_error_init(&e);
+                        dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown seat");
+                        return bus_send_error_reply(connection, message, &e, r);
+                }
+
+                return bus_send_error_reply(connection, message, NULL, r);
+        }
+
+        return seat_message_dispatch(s, connection, message);
+}
+
+const DBusObjectPathVTable bus_seat_vtable = {
+        .message_function = seat_message_handler
+};
+
+char *seat_bus_path(Seat *s) {
+        char *t, *r;
+
+        assert(s);
+
+        t = bus_path_escape(s->id);
+        if (!t)
+                return NULL;
+
+        r = strappend("/org/freedesktop/login1/seat/", t);
+        free(t);
+
+        return r;
+}
index ae89ec9d8385440d3fd1efa698e5185e86affe2d..2ba3060be33940fb4a691778696898c43486e80d 100644 (file)
@@ -182,7 +182,8 @@ static int vt_allocate(int vtnr) {
 }
 
 static int seat_preallocate_vts(Seat *s) {
 }
 
 static int seat_preallocate_vts(Seat *s) {
-        int i, r = 0;
+        int r = 0;
+        unsigned i;
 
         assert(s);
         assert(s->manager);
 
         assert(s);
         assert(s->manager);
@@ -295,6 +296,11 @@ int seat_read_active_vt(Seat *s) {
 int seat_start(Seat *s) {
         assert(s);
 
 int seat_start(Seat *s) {
         assert(s);
 
+        if (s->started)
+                return 0;
+
+        log_info("New seat %s.", s->id);
+
         /* Initialize VT magic stuff */
         seat_preallocate_vts(s);
 
         /* Initialize VT magic stuff */
         seat_preallocate_vts(s);
 
@@ -304,6 +310,8 @@ int seat_start(Seat *s) {
         /* Save seat data */
         seat_save(s);
 
         /* Save seat data */
         seat_save(s);
 
+        s->started = true;
+
         return 0;
 }
 
         return 0;
 }
 
@@ -313,6 +321,11 @@ int seat_stop(Seat *s) {
 
         assert(s);
 
 
         assert(s);
 
+        if (!s->started)
+                return 0;
+
+        log_info("Removed seat %s.", s->id);
+
         LIST_FOREACH(sessions_by_seat, session, s->sessions) {
                 k = session_stop(session);
                 if (k < 0)
         LIST_FOREACH(sessions_by_seat, session, s->sessions) {
                 k = session_stop(session);
                 if (k < 0)
@@ -322,6 +335,8 @@ int seat_stop(Seat *s) {
         unlink(s->state_file);
         seat_add_to_gc_queue(s);
 
         unlink(s->state_file);
         seat_add_to_gc_queue(s);
 
+        s->started = false;
+
         return r;
 }
 
         return r;
 }
 
@@ -343,3 +358,30 @@ void seat_add_to_gc_queue(Seat *s) {
         LIST_PREPEND(Seat, gc_queue, s->manager->seat_gc_queue, s);
         s->in_gc_queue = true;
 }
         LIST_PREPEND(Seat, gc_queue, s->manager->seat_gc_queue, s);
         s->in_gc_queue = true;
 }
+
+static bool seat_name_valid_char(char c) {
+        return
+                (c >= 'a' && c <= 'z') ||
+                (c >= 'A' && c <= 'Z') ||
+                (c >= '0' && c <= '9') ||
+                c == '-' ||
+                c == '_';
+}
+
+bool seat_name_is_valid(const char *name) {
+        const char *p;
+
+        assert(name);
+
+        if (!startswith(name, "seat"))
+                return false;
+
+        if (!name[4])
+                return false;
+
+        for (p = name; *p; p++)
+                if (!seat_name_valid_char(*p))
+                        return false;
+
+        return true;
+}
index b1a8d619a249b31fe3d2501ef2d5c5aff5213a98..b045bde931ab0079ce24c38342657855d9cf40cb 100644 (file)
@@ -42,6 +42,7 @@ struct Seat {
         LIST_HEAD(Session, sessions);
 
         bool in_gc_queue:1;
         LIST_HEAD(Session, sessions);
 
         bool in_gc_queue:1;
+        bool started:1;
 
         LIST_FIELDS(Seat, gc_queue);
 };
 
         LIST_FIELDS(Seat, gc_queue);
 };
@@ -62,4 +63,9 @@ int seat_stop(Seat *s);
 int seat_check_gc(Seat *s);
 void seat_add_to_gc_queue(Seat *s);
 
 int seat_check_gc(Seat *s);
 void seat_add_to_gc_queue(Seat *s);
 
+bool seat_name_is_valid(const char *name);
+char *seat_bus_path(Seat *s);
+
+extern const DBusObjectPathVTable bus_seat_vtable;
+
 #endif
 #endif
diff --git a/src/logind-session-dbus.c b/src/logind-session-dbus.c
new file mode 100644 (file)
index 0000000..41af658
--- /dev/null
@@ -0,0 +1,256 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2011 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "logind.h"
+#include "logind-session.h"
+#include "dbus-common.h"
+#include "util.h"
+
+#define BUS_SESSION_INTERFACE \
+        " <interface name=\"org.freedesktop.login1.Session\">\n"        \
+        "  <method name=\"Terminate\"/>\n"                              \
+        "  <method name=\"Activate\"/>\n"                               \
+        "  <property name=\"Id\" type=\"u\" access=\"read\"/>\n"        \
+        "  <property name=\"User\" type=\"(uo)\" access=\"read\"/>\n"   \
+        "  <property name=\"Name\" type=\"s\" access=\"read\"/>\n"      \
+        "  <property name=\"ControlGroupPath\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"VTNr\" type=\"u\" access=\"read\"/>\n"      \
+        "  <property name=\"Seat\" type=\"(so)\" access=\"read\"/>\n"   \
+        "  <property name=\"TTY\" type=\"s\" access=\"read\"/>\n"       \
+        "  <property name=\"Display\" type=\"s\" access=\"read\"/>\n"   \
+        "  <property name=\"Remote\" type=\"b\" access=\"read\"/>\n"    \
+        "  <property name=\"RemoteHost\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"RemoteUser\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"Leader\" type=\"u\" access=\"read\"/>\n"    \
+        "  <property name=\"Audit\" type=\"u\" access=\"read\"/>\n"     \
+        "  <property name=\"Type\" type=\"s\" access=\"read\"/>\n"      \
+        "  <property name=\"Active\" type=\"b\" access=\"read\"/>\n"    \
+        "  <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"KillProcesses\" type=\"b\" access=\"read\"/>\n" \
+        " </interface>\n"
+
+#define INTROSPECTION                                                   \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_SESSION_INTERFACE                                           \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE                                    \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_GENERIC_INTERFACES_LIST                  \
+        "org.freedesktop.login1.Session\0"
+
+static int bus_session_append_seat(DBusMessageIter *i, const char *property, void *data) {
+        DBusMessageIter sub;
+        Session *s = data;
+        const char *id, *path;
+        char *p = NULL;
+
+        assert(i);
+        assert(property);
+        assert(s);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+                return -ENOMEM;
+
+        if (s->seat) {
+                id = s->seat->id;
+                path = p = seat_bus_path(s->seat);
+
+                if (!p)
+                        return -ENOMEM;
+        } else {
+                id = "";
+                path = "/";
+        }
+
+        if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
+            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
+                free(p);
+                return -ENOMEM;
+        }
+
+        free(p);
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_session_append_user(DBusMessageIter *i, const char *property, void *data) {
+        DBusMessageIter sub;
+        Session *s = data;
+        char *p = NULL;
+
+        assert(i);
+        assert(property);
+        assert(s);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+                return -ENOMEM;
+
+        p = user_bus_path(s->user);
+        if (!p)
+                return -ENOMEM;
+
+        if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &s->user->uid) ||
+            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
+                free(p);
+                return -ENOMEM;
+        }
+
+        free(p);
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_session_append_active(DBusMessageIter *i, const char *property, void *data) {
+        Session *s = data;
+        bool b;
+
+        assert(i);
+        assert(property);
+        assert(s);
+
+        b = session_is_active(s);
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
+
+static int get_session_for_path(Manager *m, const char *path, Session **_s) {
+        Session *s;
+        char *id;
+
+        assert(m);
+        assert(path);
+        assert(_s);
+
+        if (!startswith(path, "/org/freedesktop/login1/session/"))
+                return -EINVAL;
+
+        id = bus_path_unescape(path + 32);
+        if (!id)
+                return -ENOMEM;
+
+        s = hashmap_get(m->sessions, id);
+        free(id);
+
+        if (!s)
+                return -ENOENT;
+
+        *_s = s;
+        return 0;
+}
+
+static DBusHandlerResult session_message_dispatch(
+                Session *s,
+                DBusConnection *connection,
+                DBusMessage *message) {
+
+        const BusProperty properties[] = {
+                { "org.freedesktop.login1.Session", "Id",               bus_property_append_string, "s",    s->id                },
+                { "org.freedesktop.login1.Session", "User",             bus_session_append_user,    "(uo)", s                    },
+                { "org.freedesktop.login1.Session", "Name",             bus_property_append_string, "s",    s->user->name        },
+                { "org.freedesktop.login1.Session", "ControlGroupPath", bus_property_append_string, "s",    s->cgroup_path       },
+                { "org.freedesktop.login1.Session", "VTNr",             bus_property_append_uint32, "u",    &s->vtnr             },
+                { "org.freedesktop.login1.Session", "Seat",             bus_session_append_seat,    "(so)", s                    },
+                { "org.freedesktop.login1.Session", "TTY",              bus_property_append_string, "s",    s->tty               },
+                { "org.freedesktop.login1.Session", "Display",          bus_property_append_string, "s",    s->display           },
+                { "org.freedesktop.login1.Session", "Remote",           bus_property_append_bool,   "b",    &s->remote           },
+                { "org.freedesktop.login1.Session", "RemoteUser",       bus_property_append_string, "s",    s->remote_user       },
+                { "org.freedesktop.login1.Session", "RemoteHost",       bus_property_append_string, "s",    s->remote_host       },
+                { "org.freedesktop.login1.Session", "Leader",           bus_property_append_pid,    "u",    &s->leader           },
+                { "org.freedesktop.login1.Session", "Audit",            bus_property_append_uint32, "u",    &s->audit_id         },
+                { "org.freedesktop.login1.Session", "Type",             bus_session_append_type,    "s",    &s->type             },
+                { "org.freedesktop.login1.Session", "Active",           bus_session_append_active,  "b",    s                    },
+                { "org.freedesktop.login1.Session", "Controllers",      bus_property_append_strv,   "as",   s->controllers       },
+                { "org.freedesktop.login1.Session", "ResetControllers", bus_property_append_strv,   "as",   s->reset_controllers },
+                { "org.freedesktop.login1.Session", "KillProcesses",    bus_property_append_bool,   "b",    &s->kill_processes   },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        assert(s);
+        assert(connection);
+        assert(message);
+
+        return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+}
+
+static DBusHandlerResult session_message_handler(
+                DBusConnection *connection,
+                DBusMessage *message,
+                void *userdata) {
+
+        Manager *m = userdata;
+        Session *s;
+        int r;
+
+        r = get_session_for_path(m, dbus_message_get_path(message), &s);
+        if (r < 0) {
+
+                if (r == -ENOMEM)
+                        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+                if (r == -ENOENT) {
+                        DBusError e;
+
+                        dbus_error_init(&e);
+                        dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown session");
+                        return bus_send_error_reply(connection, message, &e, r);
+                }
+
+                return bus_send_error_reply(connection, message, NULL, r);
+        }
+
+        return session_message_dispatch(s, connection, message);
+}
+
+const DBusObjectPathVTable bus_session_vtable = {
+        .message_function = session_message_handler
+};
+
+char *session_bus_path(Session *s) {
+        char *t, *r;
+
+        assert(s);
+
+        t = bus_path_escape(s->id);
+        if (!t)
+                return NULL;
+
+        r = strappend("/org/freedesktop/login1/session/", t);
+        free(t);
+
+        return r;
+}
index 8f1280dbdca6a6fbaf16aef844309c48422e813c..6b3b277897544084b844aef1331e6b8c02ada2d0 100644 (file)
@@ -83,6 +83,7 @@ void session_free(Session *s) {
         free(s->tty);
         free(s->display);
         free(s->remote_host);
         free(s->tty);
         free(s->display);
         free(s->remote_host);
+        free(s->remote_user);
 
         hashmap_remove(s->manager->sessions, s->id);
 
 
         hashmap_remove(s->manager->sessions, s->id);
 
@@ -147,6 +148,11 @@ int session_save(Session *s) {
                         "REMOTE_HOST=%s\n",
                         s->remote_host);
 
                         "REMOTE_HOST=%s\n",
                         s->remote_host);
 
+        if (s->remote_user)
+                fprintf(f,
+                        "REMOTE_USER=%s\n",
+                        s->remote_user);
+
         if (s->seat && s->seat->manager->vtconsole == s->seat)
                 fprintf(f,
                         "VTNR=%i\n",
         if (s->seat && s->seat->manager->vtconsole == s->seat)
                 fprintf(f,
                         "VTNR=%i\n",
@@ -495,7 +501,7 @@ void session_add_to_gc_queue(Session *s) {
 }
 
 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
 }
 
 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
-        [SESSION_TERMINAL] = "terminal",
+        [SESSION_TTY] = "tty",
         [SESSION_X11] = "x11"
 };
 
         [SESSION_X11] = "x11"
 };
 
index 4c6e768f8f3eb30ced6c989e1331c196b87baeff..60ac1c54e603976739cb2cd1964fb9a8480a33f3 100644 (file)
@@ -31,7 +31,7 @@ typedef struct Session Session;
 #include "logind-user.h"
 
 typedef enum SessionType {
 #include "logind-user.h"
 
 typedef enum SessionType {
-        SESSION_TERMINAL,
+        SESSION_TTY,
         SESSION_X11,
         _SESSION_TYPE_MAX,
         _SESSION_TYPE_INVALID = -1
         SESSION_X11,
         _SESSION_TYPE_MAX,
         _SESSION_TYPE_INVALID = -1
@@ -53,20 +53,21 @@ struct Session {
         char *display;
 
         bool remote;
         char *display;
 
         bool remote;
+        char *remote_user;
         char *remote_host;
 
         int vtnr;
         Seat *seat;
 
         pid_t leader;
         char *remote_host;
 
         int vtnr;
         Seat *seat;
 
         pid_t leader;
-        uint64_t audit_id;
+        uint32_t audit_id;
 
         int pipe_fd;
 
         char *cgroup_path;
         char **controllers, **reset_controllers;
 
 
         int pipe_fd;
 
         char *cgroup_path;
         char **controllers, **reset_controllers;
 
-        bool kill_processes:1;
+        bool kill_processes;
         bool in_gc_queue:1;
 
         LIST_FIELDS(Session, sessions_by_user);
         bool in_gc_queue:1;
 
         LIST_FIELDS(Session, sessions_by_user);
@@ -86,6 +87,10 @@ int session_stop(Session *s);
 int session_save(Session *s);
 int session_load(Session *s);
 
 int session_save(Session *s);
 int session_load(Session *s);
 
+char *session_bus_path(Session *s);
+
+extern const DBusObjectPathVTable bus_session_vtable;
+
 const char* session_type_to_string(SessionType t);
 SessionType session_type_from_string(const char *s);
 
 const char* session_type_to_string(SessionType t);
 SessionType session_type_from_string(const char *s);
 
diff --git a/src/logind-user-dbus.c b/src/logind-user-dbus.c
new file mode 100644 (file)
index 0000000..7c8bb27
--- /dev/null
@@ -0,0 +1,240 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2011 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "logind.h"
+#include "logind-user.h"
+#include "dbus-common.h"
+
+#define BUS_USER_INTERFACE \
+        " <interface name=\"org.freedesktop.login1.User\">\n"           \
+        "  <method name=\"Terminate\"/>\n"                              \
+        "  <property name=\"UID\" type=\"u\" access=\"read\"/>\n"       \
+        "  <property name=\"GID\" type=\"u\" access=\"read\"/>\n"       \
+        "  <property name=\"Name\" type=\"s\" access=\"read\"/>\n"      \
+        "  <property name=\"RuntimePath\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"Service\" type=\"s\" access=\"read\"/>\n"   \
+        "  <property name=\"ControlGroupPath\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"Display\" type=\"(so)\" access=\"read\"/>\n" \
+        "  <property name=\"State\" type=\"s\" access=\"read\"/>\n"     \
+        "  <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
+        " </interface>\n"                                               \
+
+#define INTROSPECTION                                                   \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_USER_INTERFACE                                              \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE                                    \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_GENERIC_INTERFACES_LIST                  \
+        "org.freedesktop.login1.User\0"
+
+static int bus_user_append_display(DBusMessageIter *i, const char *property, void *data) {
+        DBusMessageIter sub;
+        User *u = data;
+        const char *id, *path;
+        char *p = NULL;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+                return -ENOMEM;
+
+        if (u->display) {
+                id = u->display->id;
+                path = p = session_bus_path(u->display);
+
+                if (!p)
+                        return -ENOMEM;
+        } else {
+                id = "";
+                path = "/";
+        }
+
+        if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
+            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
+                free(p);
+                return -ENOMEM;
+        }
+
+        free(p);
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_user_append_state(DBusMessageIter *i, const char *property, void *data) {
+        User *u = data;
+        const char *state;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        state = user_state_to_string(user_get_state(u));
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_user_append_sessions(DBusMessageIter *i, const char *property, void *data) {
+        DBusMessageIter sub, sub2;
+        User *u = data;
+        Session *session;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "so", &sub))
+                return -ENOMEM;
+
+        LIST_FOREACH(sessions_by_user, session, u->sessions) {
+                char *p;
+
+                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+                        return -ENOMEM;
+
+                p = session_bus_path(session);
+                if (!p)
+                        return -ENOMEM;
+
+                if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
+                        free(p);
+                        return -ENOMEM;
+                }
+
+                free(p);
+
+                if (!dbus_message_iter_close_container(&sub, &sub2))
+                        return -ENOMEM;
+        }
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int get_user_for_path(Manager *m, const char *path, User **_u) {
+        User *u;
+        unsigned long lu;
+        int r;
+
+        assert(m);
+        assert(path);
+        assert(_u);
+
+        if (!startswith(path, "/org/freedesktop/login1/user/"))
+                return -EINVAL;
+
+        r = safe_atolu(path + 29, &lu);
+        if (r < 0)
+                return r;
+
+        u = hashmap_get(m->users, ULONG_TO_PTR(lu));
+        if (!u)
+                return -ENOENT;
+
+        *_u = u;
+        return 0;
+}
+
+static DBusHandlerResult user_message_dispatch(
+                User *u,
+                DBusConnection *connection,
+                DBusMessage *message) {
+
+        const BusProperty properties[] = {
+                { "org.freedesktop.login1.User", "UID",              bus_property_append_uid,    "u",     &u->uid         },
+                { "org.freedesktop.login1.User", "GID",              bus_property_append_gid,    "u",     &u->gid         },
+                { "org.freedesktop.login1.User", "Name",             bus_property_append_string, "s",     u->name         },
+                { "org.freedesktop.login1.User", "RuntimePath",      bus_property_append_string, "s",     u->runtime_path },
+                { "org.freedesktop.login1.User", "ControlGroupPath", bus_property_append_string, "s",     u->cgroup_path  },
+                { "org.freedesktop.login1.User", "Service",          bus_property_append_string, "s",     u->service      },
+                { "org.freedesktop.login1.User", "Display",          bus_user_append_display,    "(so)",  u               },
+                { "org.freedesktop.login1.User", "State",            bus_user_append_state,      "s",     u               },
+                { "org.freedesktop.login1.User", "Sessions",         bus_user_append_sessions,   "a(so)", u               },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        assert(u);
+        assert(connection);
+        assert(message);
+
+        return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+}
+
+static DBusHandlerResult user_message_handler(
+                DBusConnection *connection,
+                DBusMessage *message,
+                void *userdata) {
+
+        Manager *m = userdata;
+        User *u;
+        int r;
+
+        r = get_user_for_path(m, dbus_message_get_path(message), &u);
+        if (r < 0) {
+
+                if (r == -ENOMEM)
+                        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+                if (r == -ENOENT) {
+                        DBusError e;
+
+                        dbus_error_init(&e);
+                        dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown user");
+                        return bus_send_error_reply(connection, message, &e, r);
+                }
+
+                return bus_send_error_reply(connection, message, NULL, r);
+        }
+
+        return user_message_dispatch(u, connection, message);
+}
+
+const DBusObjectPathVTable bus_user_vtable = {
+        .message_function = user_message_handler
+};
+
+char *user_bus_path(User *u) {
+        char *s;
+
+        assert(u);
+
+        if (asprintf(&s, "/org/freedesktop/login1/user/%llu", (unsigned long long) u->uid) < 0)
+                return NULL;
+
+        return s;
+}
index fc480594295e365c2efdb185b77d75aca15daae9..7f58aa2b0701a0986dffddc614181dba86556831 100644 (file)
@@ -70,6 +70,10 @@ UserState user_get_state(User *u);
 int user_save(User *u);
 int user_load(User *u);
 
 int user_save(User *u);
 int user_load(User *u);
 
+char *user_bus_path(User *s);
+
+extern const DBusObjectPathVTable bus_user_vtable;
+
 const char* user_state_to_string(UserState s);
 UserState user_state_from_string(const char *s);
 
 const char* user_state_to_string(UserState s);
 UserState user_state_from_string(const char *s);
 
index 5d5181a1bb38ff004a9aea4aba941bf9303710e7..a62802895c1feec12c54adc2fc7c9b0d1a1f9cec 100644 (file)
@@ -255,9 +255,15 @@ int manager_process_device(Manager *m, struct udev_device *d) {
 
         assert(m);
 
 
         assert(m);
 
+        /* FIXME: drop this check as soon as libudev's enum support
+         * honours tags and subsystem matches at the same time */
+        if (!streq_ptr(udev_device_get_subsystem(d), "graphics"))
+                return 0;
+
         if (streq_ptr(udev_device_get_action(d), "remove")) {
 
         if (streq_ptr(udev_device_get_action(d), "remove")) {
 
-                device = hashmap_get(m->devices, udev_device_get_syspath(d));
+                /* FIXME: use syspath instead of sysname here, as soon as fb driver is fixed */
+                device = hashmap_get(m->devices, udev_device_get_sysname(d));
                 if (!device)
                         return 0;
 
                 if (!device)
                         return 0;
 
@@ -268,14 +274,16 @@ int manager_process_device(Manager *m, struct udev_device *d) {
                 const char *sn;
                 Seat *seat;
 
                 const char *sn;
                 Seat *seat;
 
-                sn = udev_device_get_property_value(d, "SEAT");
+                sn = udev_device_get_property_value(d, "ID_SEAT");
                 if (!sn)
                         sn = "seat0";
 
                 if (!sn)
                         sn = "seat0";
 
-                if (!startswith(sn, "seat"))
-                        return -EINVAL;
+                if (!seat_name_is_valid(sn)) {
+                        log_warning("Device with invalid seat name %s found, ignoring.", sn);
+                        return 0;
+                }
 
 
-                r = manager_add_device(m, udev_device_get_syspath(d), &device);
+                r = manager_add_device(m, udev_device_get_sysname(d), &device);
                 if (r < 0)
                         return r;
 
                 if (r < 0)
                         return r;
 
@@ -288,6 +296,7 @@ int manager_process_device(Manager *m, struct udev_device *d) {
                 }
 
                 device_attach(device, seat);
                 }
 
                 device_attach(device, seat);
+                seat_start(seat);
         }
 
         return 0;
         }
 
         return 0;
@@ -373,9 +382,6 @@ int manager_enumerate_seats(Manager *m) {
                 if (!dirent_is_file(de))
                         continue;
 
                 if (!dirent_is_file(de))
                         continue;
 
-                if (!startswith(de->d_name, "seat"))
-                        continue;
-
                 s = hashmap_get(m->seats, de->d_name);
                 if (!s) {
                         unlinkat(dirfd(d), de->d_name, 0);
                 s = hashmap_get(m->seats, de->d_name);
                 if (!s) {
                         unlinkat(dirfd(d), de->d_name, 0);
@@ -676,27 +682,15 @@ int manager_spawn_autovt(Manager *m, int vtnr) {
         return 0;
 }
 
         return 0;
 }
 
-static DBusHandlerResult login_message_handler(
-                DBusConnection *connection,
-                DBusMessage *message,
-                void *userdata) {
-
-        return DBUS_HANDLER_RESULT_HANDLED;
-}
-
 static DBusHandlerResult login_message_filter(
                 DBusConnection *connection,
                 DBusMessage *message,
                 void *userdata) {
 
 static DBusHandlerResult login_message_filter(
                 DBusConnection *connection,
                 DBusMessage *message,
                 void *userdata) {
 
-        return DBUS_HANDLER_RESULT_HANDLED;
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
 static int manager_connect_bus(Manager *m) {
 }
 
 static int manager_connect_bus(Manager *m) {
-        const DBusObjectPathVTable login_vtable = {
-                .message_function = login_message_handler
-        };
-
         DBusError error;
         int r;
         struct epoll_event ev;
         DBusError error;
         int r;
         struct epoll_event ev;
@@ -714,13 +708,11 @@ static int manager_connect_bus(Manager *m) {
                 goto fail;
         }
 
                 goto fail;
         }
 
-        if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/login1", &login_vtable, NULL)) {
-                log_error("Not enough memory");
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        if (!dbus_connection_add_filter(m->bus, login_message_filter, m, NULL)) {
+        if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/login1", &bus_manager_vtable, m) ||
+            !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/seat", &bus_seat_vtable, m) ||
+            !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/session", &bus_session_vtable, m) ||
+            !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/user", &bus_user_vtable, m) ||
+            !dbus_connection_add_filter(m->bus, login_message_filter, m, NULL)) {
                 log_error("Not enough memory");
                 r = -ENOMEM;
                 goto fail;
                 log_error("Not enough memory");
                 r = -ENOMEM;
                 goto fail;
@@ -931,6 +923,9 @@ int manager_run(Manager *m) {
 
                 n = epoll_wait(m->epoll_fd, &event, 1, -1);
                 if (n < 0) {
 
                 n = epoll_wait(m->epoll_fd, &event, 1, -1);
                 if (n < 0) {
+                        if (errno == EINTR || errno == EAGAIN)
+                                continue;
+
                         log_error("epoll() failed: %m");
                         return -errno;
                 }
                         log_error("epoll() failed: %m");
                         return -errno;
                 }
index a8b387b05fe43767ad9dbab9fe33f1c32465017d..e4b7a3c4e03b5460d77694cd8180500ab4d4ae8f 100644 (file)
@@ -72,14 +72,14 @@ struct Manager {
         int bus_fd;
         int epoll_fd;
 
         int bus_fd;
         int epoll_fd;
 
-        int n_autovts;
+        unsigned n_autovts;
 
         Seat *vtconsole;
 
         char *cgroup_path;
         char **controllers, **reset_controllers;
 
 
         Seat *vtconsole;
 
         char *cgroup_path;
         char **controllers, **reset_controllers;
 
-        char **kill_only_users, **kill_exlude_users;
+        char **kill_only_users, **kill_exclude_users;
 
         bool kill_user_processes;
 };
 
         bool kill_user_processes;
 };
@@ -111,4 +111,6 @@ void manager_gc(Manager *m);
 
 bool x11_display_is_local(const char *display);
 
 
 bool x11_display_is_local(const char *display);
 
+extern const DBusObjectPathVTable bus_manager_vtable;
+
 #endif
 #endif