[systemd-commits] 3 commits - .gitignore Makefile.am src/.gitignore src/libsystemd-login.sym src/login src/loginctl.c src/logind-acl.c src/logind-acl.h src/logind-dbus.c src/logind-device.c src/logind-device.h src/logind-gperf.gperf src/logind-seat-dbus.c src/logind-seat.c src/logind-seat.h src/logind-session-dbus.c src/logind-session.c src/logind-session.h src/logind-user-dbus.c src/logind-user.c src/logind-user.h src/logind.c src/logind.h src/org.freedesktop.login1.conf src/org.freedesktop.login1.policy.in src/org.freedesktop.login1.service src/sd-login.c src/sd-login.h src/systemd-logind.conf src/test-login.c src/uaccess.c

Lennart Poettering lennart at kemper.freedesktop.org
Fri Dec 30 18:24:43 PST 2011


 .gitignore                                 |    1 
 Makefile.am                                |   62 
 src/.gitignore                             |    1 
 src/libsystemd-login.sym                   |   35 
 src/login/.gitignore                       |    1 
 src/login/Makefile                         |    1 
 src/login/libsystemd-login.sym             |   35 
 src/login/loginctl.c                       | 1914 +++++++++++++++++++++++++++++
 src/login/logind-acl.c                     |  248 +++
 src/login/logind-acl.h                     |   60 
 src/login/logind-dbus.c                    | 1504 ++++++++++++++++++++++
 src/login/logind-device.c                  |   86 +
 src/login/logind-device.h                  |   48 
 src/login/logind-gperf.gperf               |   22 
 src/login/logind-seat-dbus.c               |  403 ++++++
 src/login/logind-seat.c                    |  499 +++++++
 src/login/logind-seat.h                    |   82 +
 src/login/logind-session-dbus.c            |  515 +++++++
 src/login/logind-session.c                 |  945 ++++++++++++++
 src/login/logind-session.h                 |  124 +
 src/login/logind-user-dbus.c               |  411 ++++++
 src/login/logind-user.c                    |  587 ++++++++
 src/login/logind-user.h                    |   86 +
 src/login/logind.c                         | 1228 ++++++++++++++++++
 src/login/logind.h                         |  128 +
 src/login/org.freedesktop.login1.conf      |   86 +
 src/login/org.freedesktop.login1.policy.in |   89 +
 src/login/org.freedesktop.login1.service   |   12 
 src/login/sd-login.c                       |  726 +++++++++++
 src/login/sd-login.h                       |  121 +
 src/login/systemd-logind.conf              |   16 
 src/login/test-login.c                     |  170 ++
 src/login/uaccess.c                        |   90 +
 src/loginctl.c                             | 1914 -----------------------------
 src/logind-acl.c                           |  248 ---
 src/logind-acl.h                           |   60 
 src/logind-dbus.c                          | 1504 ----------------------
 src/logind-device.c                        |   86 -
 src/logind-device.h                        |   48 
 src/logind-gperf.gperf                     |   22 
 src/logind-seat-dbus.c                     |  403 ------
 src/logind-seat.c                          |  499 -------
 src/logind-seat.h                          |   82 -
 src/logind-session-dbus.c                  |  515 -------
 src/logind-session.c                       |  945 --------------
 src/logind-session.h                       |  124 -
 src/logind-user-dbus.c                     |  411 ------
 src/logind-user.c                          |  587 --------
 src/logind-user.h                          |   86 -
 src/logind.c                               | 1228 ------------------
 src/logind.h                               |  128 -
 src/org.freedesktop.login1.conf            |   86 -
 src/org.freedesktop.login1.policy.in       |   89 -
 src/org.freedesktop.login1.service         |   12 
 src/sd-login.c                             |  726 -----------
 src/sd-login.h                             |  121 -
 src/systemd-logind.conf                    |   16 
 src/test-login.c                           |  170 --
 src/uaccess.c                              |   90 -
 59 files changed, 10269 insertions(+), 10267 deletions(-)

New commits:
commit 4deba285591ad2a388496d9c017da25e68db6f30
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Dec 31 03:24:31 2011 +0100

    logind: move more files into subdirectory

diff --git a/Makefile.am b/Makefile.am
index f8735de..da2e980 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -258,11 +258,11 @@ endif
 dist_pkgsysconf_DATA = \
 	src/system.conf \
         src/user.conf \
-        src/systemd-logind.conf
+        src/login/systemd-logind.conf
 
 dist_dbuspolicy_DATA = \
 	src/org.freedesktop.systemd1.conf \
-        src/org.freedesktop.login1.conf
+        src/login/org.freedesktop.login1.conf
 
 if ENABLE_HOSTNAMED
 dist_dbuspolicy_DATA += \
@@ -281,7 +281,7 @@ endif
 
 dist_dbussystemservice_DATA = \
 	src/org.freedesktop.systemd1.service \
-        src/org.freedesktop.login1.service
+        src/login/org.freedesktop.login1.service
 
 if ENABLE_HOSTNAMED
 dist_dbussystemservice_DATA += \
@@ -520,7 +520,7 @@ EXTRA_DIST = \
         libsystemd-id128.pc.in \
         libsystemd-journal.pc.in \
 	src/libsystemd-daemon.sym \
-	src/libsystemd-login.sym \
+	src/login/libsystemd-login.sym \
 	src/libsystemd-id128.sym \
 	src/libsystemd-journal.sym \
 	introspect.awk \
@@ -627,7 +627,7 @@ pkgconfiglib_DATA = \
 
 # Passed through intltool only
 polkitpolicy_in_files = \
-        src/org.freedesktop.login1.policy.in
+        src/login/org.freedesktop.login1.policy.in
 
 if ENABLE_HOSTNAMED
 polkitpolicy_in_files += \
@@ -1730,7 +1730,7 @@ libsystemd_login_la_CFLAGS = \
 libsystemd_login_la_LDFLAGS = \
         -shared \
         -version-info $(LIBSYSTEMD_LOGIN_CURRENT):$(LIBSYSTEMD_LOGIN_REVISION):$(LIBSYSTEMD_LOGIN_AGE) \
-        -Wl,--version-script=$(top_srcdir)/src/libsystemd-login.sym
+        -Wl,--version-script=$(top_srcdir)/src/login/libsystemd-login.sym
 
 libsystemd_login_la_LIBADD = \
 	libsystemd-basic.la
diff --git a/src/.gitignore b/src/.gitignore
index a3fd20b..ff2737b 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,7 +1,6 @@
 load-fragment-gperf-nulstr.c
 load-fragment-gperf.c
 load-fragment-gperf.gperf
-logind-gperf.c
 org.freedesktop.systemd1.policy.in
 99-systemd.rules
 org.freedesktop.hostname1.policy
diff --git a/src/libsystemd-login.sym b/src/libsystemd-login.sym
deleted file mode 100644
index 0d51fa7..0000000
--- a/src/libsystemd-login.sym
+++ /dev/null
@@ -1,35 +0,0 @@
-/***
-  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.
-***/
-
-/* Original symbols from systemd v31 */
-
-LIBSYSTEMD_LOGIN_31 {
-global:
-        sd_get_seats;
-        sd_get_sessions;
-        sd_get_uids;
-        sd_login_monitor_flush;
-        sd_login_monitor_get_fd;
-        sd_login_monitor_new;
-        sd_login_monitor_unref;
-        sd_pid_get_owner_uid;
-        sd_pid_get_session;
-        sd_seat_can_multi_session;
-        sd_seat_get_active;
-        sd_seat_get_sessions;
-        sd_session_get_seat;
-        sd_session_get_uid;
-        sd_session_is_active;
-        sd_uid_get_seats;
-        sd_uid_get_sessions;
-        sd_uid_get_state;
-        sd_uid_is_on_seat;
-local:
-        *;
-};
diff --git a/src/login/.gitignore b/src/login/.gitignore
new file mode 100644
index 0000000..7c420cb
--- /dev/null
+++ b/src/login/.gitignore
@@ -0,0 +1 @@
+logind-gperf.c
diff --git a/src/login/libsystemd-login.sym b/src/login/libsystemd-login.sym
new file mode 100644
index 0000000..0d51fa7
--- /dev/null
+++ b/src/login/libsystemd-login.sym
@@ -0,0 +1,35 @@
+/***
+  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.
+***/
+
+/* Original symbols from systemd v31 */
+
+LIBSYSTEMD_LOGIN_31 {
+global:
+        sd_get_seats;
+        sd_get_sessions;
+        sd_get_uids;
+        sd_login_monitor_flush;
+        sd_login_monitor_get_fd;
+        sd_login_monitor_new;
+        sd_login_monitor_unref;
+        sd_pid_get_owner_uid;
+        sd_pid_get_session;
+        sd_seat_can_multi_session;
+        sd_seat_get_active;
+        sd_seat_get_sessions;
+        sd_session_get_seat;
+        sd_session_get_uid;
+        sd_session_is_active;
+        sd_uid_get_seats;
+        sd_uid_get_sessions;
+        sd_uid_get_state;
+        sd_uid_is_on_seat;
+local:
+        *;
+};
diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf
new file mode 100644
index 0000000..c423ef5
--- /dev/null
+++ b/src/login/org.freedesktop.login1.conf
@@ -0,0 +1,86 @@
+<?xml version="1.0"?> <!--*-nxml-*-->
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+        "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+
+<!--
+  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.
+-->
+
+<busconfig>
+
+        <policy user="root">
+                <allow own="org.freedesktop.login1"/>
+                <allow send_destination="org.freedesktop.login1"/>
+                <allow receive_sender="org.freedesktop.login1"/>
+        </policy>
+
+        <policy context="default">
+                <deny send_destination="org.freedesktop.login1"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.DBus.Introspectable"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.DBus.Peer"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.DBus.Properties"
+                       send_member="Get"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.DBus.Properties"
+                       send_member="GetAll"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="GetSession"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="GetUser"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="GetSeat"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="ListSessions"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="ListUsers"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="ListSeats"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="SetUserLinger"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="ActivateSession"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Seat"
+                       send_member="ActivateSession"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Session"
+                       send_member="Activate"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Session"
+                       send_member="SetIdleHint"/>
+
+                <allow receive_sender="org.freedesktop.login1"/>
+        </policy>
+
+</busconfig>
diff --git a/src/login/org.freedesktop.login1.policy.in b/src/login/org.freedesktop.login1.policy.in
new file mode 100644
index 0000000..adc9048
--- /dev/null
+++ b/src/login/org.freedesktop.login1.policy.in
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
+<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+        "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
+
+<!--
+  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.
+-->
+
+<policyconfig>
+
+        <vendor>The systemd Project</vendor>
+        <vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url>
+
+        <action id="org.freedesktop.login1.set-user-linger">
+                <_description>Allow non-logged-in users to run programs</_description>
+                <_message>Authentication is required to allow a non-logged-in user to run programs</_message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+        </action>
+
+        <action id="org.freedesktop.login1.attach-device">
+                <_description>Allow attaching devices to seats</_description>
+                <_message>Authentication is required to allow attaching a device to a seat</_message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+        </action>
+
+        <action id="org.freedesktop.login1.flush-devices">
+                <_description>Flush device to seat attachments</_description>
+                <_message>Authentication is required to allow resetting how devices are attached to seats</_message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+        </action>
+
+        <action id="org.freedesktop.login1.power-off">
+                <_description>Power off the system</_description>
+                <_message>Authentication is required to allow powering off the system</_message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>yes</allow_active>
+                </defaults>
+        </action>
+
+        <action id="org.freedesktop.login1.power-off-multiple-sessions">
+                <_description>Power off the system when other users are logged in</_description>
+                <_message>Authentication is required to allow powering off the system while other users are logged in</_message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+        </action>
+
+        <action id="org.freedesktop.login1.reboot">
+                <_description>Reboot the system</_description>
+                <_message>Authentication is required to allow rebooting the system</_message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>yes</allow_active>
+                </defaults>
+        </action>
+
+        <action id="org.freedesktop.login1.reboot-multiple-sessions">
+                <_description>Reboot the system when other users are logged in</_description>
+                <_message>Authentication is required to allow rebooting the system while other users are logged in</_message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+        </action>
+
+</policyconfig>
diff --git a/src/login/org.freedesktop.login1.service b/src/login/org.freedesktop.login1.service
new file mode 100644
index 0000000..4a64177
--- /dev/null
+++ b/src/login/org.freedesktop.login1.service
@@ -0,0 +1,12 @@
+#  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.
+
+[D-BUS Service]
+Name=org.freedesktop.login1
+Exec=/bin/false
+User=root
+SystemdService=dbus-org.freedesktop.login1.service
diff --git a/src/login/systemd-logind.conf b/src/login/systemd-logind.conf
new file mode 100644
index 0000000..9909804
--- /dev/null
+++ b/src/login/systemd-logind.conf
@@ -0,0 +1,16 @@
+#  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.
+#
+# See system-logind.conf(5) for details
+
+[Login]
+#NAutoVTs=6
+#KillUserProcesses=no
+#KillOnlyUsers=
+#KillExcludeUsers=root
+#Controllers=
+#ResetControllers=cpu
diff --git a/src/org.freedesktop.login1.conf b/src/org.freedesktop.login1.conf
deleted file mode 100644
index c423ef5..0000000
--- a/src/org.freedesktop.login1.conf
+++ /dev/null
@@ -1,86 +0,0 @@
-<?xml version="1.0"?> <!--*-nxml-*-->
-<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
-        "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-
-<!--
-  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.
--->
-
-<busconfig>
-
-        <policy user="root">
-                <allow own="org.freedesktop.login1"/>
-                <allow send_destination="org.freedesktop.login1"/>
-                <allow receive_sender="org.freedesktop.login1"/>
-        </policy>
-
-        <policy context="default">
-                <deny send_destination="org.freedesktop.login1"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.DBus.Introspectable"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.DBus.Peer"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.DBus.Properties"
-                       send_member="Get"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.DBus.Properties"
-                       send_member="GetAll"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.login1.Manager"
-                       send_member="GetSession"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.login1.Manager"
-                       send_member="GetUser"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.login1.Manager"
-                       send_member="GetSeat"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.login1.Manager"
-                       send_member="ListSessions"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.login1.Manager"
-                       send_member="ListUsers"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.login1.Manager"
-                       send_member="ListSeats"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.login1.Manager"
-                       send_member="SetUserLinger"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.login1.Manager"
-                       send_member="ActivateSession"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.login1.Seat"
-                       send_member="ActivateSession"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.login1.Session"
-                       send_member="Activate"/>
-
-                <allow send_destination="org.freedesktop.login1"
-                       send_interface="org.freedesktop.login1.Session"
-                       send_member="SetIdleHint"/>
-
-                <allow receive_sender="org.freedesktop.login1"/>
-        </policy>
-
-</busconfig>
diff --git a/src/org.freedesktop.login1.policy.in b/src/org.freedesktop.login1.policy.in
deleted file mode 100644
index adc9048..0000000
--- a/src/org.freedesktop.login1.policy.in
+++ /dev/null
@@ -1,89 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
-<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
-        "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
-
-<!--
-  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.
--->
-
-<policyconfig>
-
-        <vendor>The systemd Project</vendor>
-        <vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url>
-
-        <action id="org.freedesktop.login1.set-user-linger">
-                <_description>Allow non-logged-in users to run programs</_description>
-                <_message>Authentication is required to allow a non-logged-in user to run programs</_message>
-                <defaults>
-                        <allow_any>auth_admin_keep</allow_any>
-                        <allow_inactive>auth_admin_keep</allow_inactive>
-                        <allow_active>auth_admin_keep</allow_active>
-                </defaults>
-        </action>
-
-        <action id="org.freedesktop.login1.attach-device">
-                <_description>Allow attaching devices to seats</_description>
-                <_message>Authentication is required to allow attaching a device to a seat</_message>
-                <defaults>
-                        <allow_any>auth_admin_keep</allow_any>
-                        <allow_inactive>auth_admin_keep</allow_inactive>
-                        <allow_active>auth_admin_keep</allow_active>
-                </defaults>
-        </action>
-
-        <action id="org.freedesktop.login1.flush-devices">
-                <_description>Flush device to seat attachments</_description>
-                <_message>Authentication is required to allow resetting how devices are attached to seats</_message>
-                <defaults>
-                        <allow_any>auth_admin_keep</allow_any>
-                        <allow_inactive>auth_admin_keep</allow_inactive>
-                        <allow_active>auth_admin_keep</allow_active>
-                </defaults>
-        </action>
-
-        <action id="org.freedesktop.login1.power-off">
-                <_description>Power off the system</_description>
-                <_message>Authentication is required to allow powering off the system</_message>
-                <defaults>
-                        <allow_any>auth_admin_keep</allow_any>
-                        <allow_inactive>auth_admin_keep</allow_inactive>
-                        <allow_active>yes</allow_active>
-                </defaults>
-        </action>
-
-        <action id="org.freedesktop.login1.power-off-multiple-sessions">
-                <_description>Power off the system when other users are logged in</_description>
-                <_message>Authentication is required to allow powering off the system while other users are logged in</_message>
-                <defaults>
-                        <allow_any>auth_admin_keep</allow_any>
-                        <allow_inactive>auth_admin_keep</allow_inactive>
-                        <allow_active>auth_admin_keep</allow_active>
-                </defaults>
-        </action>
-
-        <action id="org.freedesktop.login1.reboot">
-                <_description>Reboot the system</_description>
-                <_message>Authentication is required to allow rebooting the system</_message>
-                <defaults>
-                        <allow_any>auth_admin_keep</allow_any>
-                        <allow_inactive>auth_admin_keep</allow_inactive>
-                        <allow_active>yes</allow_active>
-                </defaults>
-        </action>
-
-        <action id="org.freedesktop.login1.reboot-multiple-sessions">
-                <_description>Reboot the system when other users are logged in</_description>
-                <_message>Authentication is required to allow rebooting the system while other users are logged in</_message>
-                <defaults>
-                        <allow_any>auth_admin_keep</allow_any>
-                        <allow_inactive>auth_admin_keep</allow_inactive>
-                        <allow_active>auth_admin_keep</allow_active>
-                </defaults>
-        </action>
-
-</policyconfig>
diff --git a/src/org.freedesktop.login1.service b/src/org.freedesktop.login1.service
deleted file mode 100644
index 4a64177..0000000
--- a/src/org.freedesktop.login1.service
+++ /dev/null
@@ -1,12 +0,0 @@
-#  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.
-
-[D-BUS Service]
-Name=org.freedesktop.login1
-Exec=/bin/false
-User=root
-SystemdService=dbus-org.freedesktop.login1.service
diff --git a/src/systemd-logind.conf b/src/systemd-logind.conf
deleted file mode 100644
index 9909804..0000000
--- a/src/systemd-logind.conf
+++ /dev/null
@@ -1,16 +0,0 @@
-#  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.
-#
-# See system-logind.conf(5) for details
-
-[Login]
-#NAutoVTs=6
-#KillUserProcesses=no
-#KillOnlyUsers=
-#KillExcludeUsers=root
-#Controllers=
-#ResetControllers=cpu

commit 4bba9156da3e1df2cee24d10d7cd88c776ef4179
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Dec 31 03:16:08 2011 +0100

    logind: move logind into its own subdirectory

diff --git a/Makefile.am b/Makefile.am
index 6629d91..f8735de 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -231,7 +231,7 @@ lib_LTLIBRARIES = \
 
 pkginclude_HEADERS = \
 	src/sd-daemon.h \
-	src/sd-login.h \
+	src/login/sd-login.h \
         src/sd-id128.h \
         src/journal/sd-journal.h
 
@@ -792,12 +792,12 @@ EXTRA_DIST += \
         src/pager.h \
         src/sysfs-show.h \
         src/polkit.h \
-        src/logind.h \
-        src/logind-device.h \
-        src/logind-seat.h \
-        src/logind-session.h \
-        src/logind-user.h \
-        src/logind-acl.h \
+        src/login/logind.h \
+        src/login/logind-device.h \
+        src/login/logind-seat.h \
+        src/login/logind-session.h \
+        src/login/logind-user.h \
+        src/login/logind-acl.h \
         src/dbus-loop.h \
         src/spawn-agent.h \
         src/journal/journal-def.h \
@@ -1018,7 +1018,7 @@ test_strv_LDADD = \
 	libsystemd-basic.la
 
 test_login_SOURCES = \
-	src/test-login.c
+	src/login/test-login.c
 
 test_login_CFLAGS = \
 	$(AM_CFLAGS)
@@ -1230,25 +1230,25 @@ systemd_timedated_LDADD = \
 	$(DBUS_LIBS)
 
 systemd_logind_SOURCES = \
-	src/logind.c \
-	src/logind-dbus.c \
-        src/logind-device.c \
-        src/logind-seat.c \
-        src/logind-seat-dbus.c \
-        src/logind-session.c \
-        src/logind-session-dbus.c \
-        src/logind-user.c \
-        src/logind-user-dbus.c \
+	src/login/logind.c \
+	src/login/logind-dbus.c \
+        src/login/logind-device.c \
+        src/login/logind-seat.c \
+        src/login/logind-seat-dbus.c \
+        src/login/logind-session.c \
+        src/login/logind-session-dbus.c \
+        src/login/logind-user.c \
+        src/login/logind-user-dbus.c \
         src/dbus-common.c \
         src/dbus-loop.c \
         src/cgroup-util.c \
         src/polkit.c
 
 nodist_systemd_logind_SOURCES = \
-        src/logind-gperf.c
+        src/login/logind-gperf.c
 
 EXTRA_DIST += \
-        src/logind-gperf.gperf
+        src/login/logind-gperf.gperf
 
 systemd_logind_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -1264,15 +1264,15 @@ systemd_logind_LDADD = \
         $(ACL_LIBS)
 
 systemd_uaccess_SOURCES = \
-	src/uaccess.c
+	src/login/uaccess.c
 
 if HAVE_ACL
 systemd_logind_SOURCES += \
-	src/logind-acl.c \
+	src/login/logind-acl.c \
         src/acl-util.c
 
 systemd_uaccess_SOURCES += \
-	src/logind-acl.c \
+	src/login/logind-acl.c \
         src/acl-util.c
 endif
 
@@ -1519,7 +1519,7 @@ systemctl_LDADD = \
 	$(DBUS_LIBS)
 
 systemd_loginctl_SOURCES = \
-	src/loginctl.c \
+	src/login/loginctl.c \
 	src/dbus-common.c \
 	src/cgroup-show.c \
 	src/cgroup-util.c \
@@ -1720,7 +1720,7 @@ libsystemd-daemon-uninstall-hook:
 	rm -f $(DESTDIR)$(rootlibdir)/libsystemd-daemon.so*
 
 libsystemd_login_la_SOURCES = \
-        src/sd-login.c \
+        src/login/sd-login.c \
         src/cgroup-util.c
 
 libsystemd_login_la_CFLAGS = \
@@ -1886,7 +1886,7 @@ CLEANFILES = \
         src/load-fragment-gperf.gperf \
         src/load-fragment-gperf.c \
         src/load-fragment-gperf-nulstr.c \
-        src/logind-gperf.c
+        src/login/logind-gperf.c
 
 if HAVE_VALAC
 CLEANFILES += \
diff --git a/src/login/Makefile b/src/login/Makefile
new file mode 120000
index 0000000..d0b0e8e
--- /dev/null
+++ b/src/login/Makefile
@@ -0,0 +1 @@
+../Makefile
\ No newline at end of file
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
new file mode 100644
index 0000000..1be47c8
--- /dev/null
+++ b/src/login/loginctl.c
@@ -0,0 +1,1914 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU 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 <dbus/dbus.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+#include <pwd.h>
+
+#include "log.h"
+#include "util.h"
+#include "macro.h"
+#include "pager.h"
+#include "dbus-common.h"
+#include "build.h"
+#include "strv.h"
+#include "cgroup-show.h"
+#include "sysfs-show.h"
+
+static char **arg_property = NULL;
+static bool arg_all = false;
+static bool arg_no_pager = false;
+static const char *arg_kill_who = NULL;
+static int arg_signal = SIGTERM;
+static enum transport {
+        TRANSPORT_NORMAL,
+        TRANSPORT_SSH,
+        TRANSPORT_POLKIT
+} arg_transport = TRANSPORT_NORMAL;
+static const char *arg_host = NULL;
+
+static bool on_tty(void) {
+        static int t = -1;
+
+        /* Note that this is invoked relatively early, before we start
+         * the pager. That means the value we return reflects whether
+         * we originally were started on a tty, not if we currently
+         * are. But this is intended, since we want colour and so on
+         * when run in our own pager. */
+
+        if (_unlikely_(t < 0))
+                t = isatty(STDOUT_FILENO) > 0;
+
+        return t;
+}
+
+static void pager_open_if_enabled(void) {
+
+        /* Cache result before we open the pager */
+        on_tty();
+
+        if (!arg_no_pager)
+                pager_open();
+}
+
+static int list_sessions(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL, *reply = NULL;
+        DBusError error;
+        int r;
+        DBusMessageIter iter, sub, sub2;
+        unsigned k = 0;
+
+        dbus_error_init(&error);
+
+        assert(bus);
+
+        pager_open_if_enabled();
+
+        m = dbus_message_new_method_call(
+                        "org.freedesktop.login1",
+                        "/org/freedesktop/login1",
+                        "org.freedesktop.login1.Manager",
+                        "ListSessions");
+        if (!m) {
+                log_error("Could not allocate message.");
+                return -ENOMEM;
+        }
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+        if (!reply) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
+                r = -EIO;
+                goto finish;
+        }
+
+        if (!dbus_message_iter_init(reply, &iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
+                log_error("Failed to parse reply.");
+                r = -EIO;
+                goto finish;
+        }
+
+        dbus_message_iter_recurse(&iter, &sub);
+
+        if (on_tty())
+                printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
+
+        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                const char *id, *user, *seat, *object;
+                uint32_t uid;
+
+                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_recurse(&sub, &sub2);
+
+                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
+                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
+                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &user, true) < 0 ||
+                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &seat, true) < 0 ||
+                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
+
+                k++;
+
+                dbus_message_iter_next(&sub);
+        }
+
+        if (on_tty())
+                printf("\n%u sessions listed.\n", k);
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return r;
+}
+
+static int list_users(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL, *reply = NULL;
+        DBusError error;
+        int r;
+        DBusMessageIter iter, sub, sub2;
+        unsigned k = 0;
+
+        dbus_error_init(&error);
+
+        assert(bus);
+
+        pager_open_if_enabled();
+
+        m = dbus_message_new_method_call(
+                        "org.freedesktop.login1",
+                        "/org/freedesktop/login1",
+                        "org.freedesktop.login1.Manager",
+                        "ListUsers");
+        if (!m) {
+                log_error("Could not allocate message.");
+                return -ENOMEM;
+        }
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+        if (!reply) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
+                r = -EIO;
+                goto finish;
+        }
+
+        if (!dbus_message_iter_init(reply, &iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
+                log_error("Failed to parse reply.");
+                r = -EIO;
+                goto finish;
+        }
+
+        dbus_message_iter_recurse(&iter, &sub);
+
+        if (on_tty())
+                printf("%10s %-16s\n", "UID", "USER");
+
+        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                const char *user, *object;
+                uint32_t uid;
+
+                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_recurse(&sub, &sub2);
+
+                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
+                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &user, true) < 0 ||
+                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                printf("%10u %-16s\n", (unsigned) uid, user);
+
+                k++;
+
+                dbus_message_iter_next(&sub);
+        }
+
+        if (on_tty())
+                printf("\n%u users listed.\n", k);
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return r;
+}
+
+static int list_seats(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL, *reply = NULL;
+        DBusError error;
+        int r;
+        DBusMessageIter iter, sub, sub2;
+        unsigned k = 0;
+
+        dbus_error_init(&error);
+
+        assert(bus);
+
+        pager_open_if_enabled();
+
+        m = dbus_message_new_method_call(
+                        "org.freedesktop.login1",
+                        "/org/freedesktop/login1",
+                        "org.freedesktop.login1.Manager",
+                        "ListSeats");
+        if (!m) {
+                log_error("Could not allocate message.");
+                return -ENOMEM;
+        }
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+        if (!reply) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
+                r = -EIO;
+                goto finish;
+        }
+
+        if (!dbus_message_iter_init(reply, &iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
+                log_error("Failed to parse reply.");
+                r = -EIO;
+                goto finish;
+        }
+
+        dbus_message_iter_recurse(&iter, &sub);
+
+        if (on_tty())
+                printf("%-16s\n", "SEAT");
+
+        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                const char *seat, *object;
+
+                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_recurse(&sub, &sub2);
+
+                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &seat, true) < 0 ||
+                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                printf("%-16s\n", seat);
+
+                k++;
+
+                dbus_message_iter_next(&sub);
+        }
+
+        if (on_tty())
+                printf("\n%u seats listed.\n", k);
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return r;
+}
+
+typedef struct SessionStatusInfo {
+        const char *id;
+        uid_t uid;
+        const char *name;
+        usec_t timestamp;
+        const char *control_group;
+        int vtnr;
+        const char *seat;
+        const char *tty;
+        const char *display;
+        bool remote;
+        const char *remote_host;
+        const char *remote_user;
+        const char *service;
+        pid_t leader;
+        const char *type;
+        bool active;
+} SessionStatusInfo;
+
+typedef struct UserStatusInfo {
+        uid_t uid;
+        const char *name;
+        usec_t timestamp;
+        const char *control_group;
+        const char *state;
+        char **sessions;
+        const char *display;
+} UserStatusInfo;
+
+typedef struct SeatStatusInfo {
+        const char *id;
+        const char *active_session;
+        char **sessions;
+} SeatStatusInfo;
+
+static void print_session_status_info(SessionStatusInfo *i) {
+        char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
+        char since2[FORMAT_TIMESTAMP_MAX], *s2;
+        assert(i);
+
+        printf("%s - ", strna(i->id));
+
+        if (i->name)
+                printf("%s (%u)\n", i->name, (unsigned) i->uid);
+        else
+                printf("%u\n", (unsigned) i->uid);
+
+        s1 = format_timestamp_pretty(since1, sizeof(since1), i->timestamp);
+        s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
+
+        if (s1)
+                printf("\t   Since: %s; %s\n", s2, s1);
+        else if (s2)
+                printf("\t   Since: %s\n", s2);
+
+        if (i->leader > 0) {
+                char *t = NULL;
+
+                printf("\t  Leader: %u", (unsigned) i->leader);
+
+                get_process_comm(i->leader, &t);
+                if (t) {
+                        printf(" (%s)", t);
+                        free(t);
+                }
+
+                printf("\n");
+        }
+
+        if (i->seat) {
+                printf("\t    Seat: %s", i->seat);
+
+                if (i->vtnr > 0)
+                        printf("; vc%i", i->vtnr);
+
+                printf("\n");
+        }
+
+        if (i->tty)
+                printf("\t     TTY: %s\n", i->tty);
+        else if (i->display)
+                printf("\t Display: %s\n", i->display);
+
+        if (i->remote_host && i->remote_user)
+                printf("\t  Remote: %s@%s\n", i->remote_user, i->remote_host);
+        else if (i->remote_host)
+                printf("\t  Remote: %s\n", i->remote_host);
+        else if (i->remote_user)
+                printf("\t  Remote: user %s\n", i->remote_user);
+        else if (i->remote)
+                printf("\t  Remote: Yes\n");
+
+        if (i->service) {
+                printf("\t Service: %s", i->service);
+
+                if (i->type)
+                        printf("; type %s", i->type);
+
+                printf("\n");
+        } else if (i->type)
+                printf("\t    Type: %s\n", i->type);
+
+        printf("\t  Active: %s\n", yes_no(i->active));
+
+        if (i->control_group) {
+                unsigned c;
+
+                printf("\t  CGroup: %s\n", i->control_group);
+
+                if (arg_transport != TRANSPORT_SSH) {
+                        c = columns();
+                        if (c > 18)
+                                c -= 18;
+                        else
+                                c = 0;
+
+                        show_cgroup_by_path(i->control_group, "\t\t  ", c);
+                }
+        }
+}
+
+static void print_user_status_info(UserStatusInfo *i) {
+        char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
+        char since2[FORMAT_TIMESTAMP_MAX], *s2;
+        assert(i);
+
+        if (i->name)
+                printf("%s (%u)\n", i->name, (unsigned) i->uid);
+        else
+                printf("%u\n", (unsigned) i->uid);
+
+        s1 = format_timestamp_pretty(since1, sizeof(since1), i->timestamp);
+        s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
+
+        if (s1)
+                printf("\t   Since: %s; %s\n", s2, s1);
+        else if (s2)
+                printf("\t   Since: %s\n", s2);
+
+        if (!isempty(i->state))
+                printf("\t   State: %s\n", i->state);
+
+        if (!strv_isempty(i->sessions)) {
+                char **l;
+                printf("\tSessions:");
+
+                STRV_FOREACH(l, i->sessions) {
+                        if (streq_ptr(*l, i->display))
+                                printf(" *%s", *l);
+                        else
+                                printf(" %s", *l);
+                }
+
+                printf("\n");
+        }
+
+        if (i->control_group) {
+                unsigned c;
+
+                printf("\t  CGroup: %s\n", i->control_group);
+
+                if (arg_transport != TRANSPORT_SSH) {
+                        c = columns();
+                        if (c > 18)
+                                c -= 18;
+                        else
+                                c = 0;
+
+                        show_cgroup_by_path(i->control_group, "\t\t  ", c);
+                }
+        }
+}
+
+static void print_seat_status_info(SeatStatusInfo *i) {
+        assert(i);
+
+        printf("%s\n", strna(i->id));
+
+        if (!strv_isempty(i->sessions)) {
+                char **l;
+                printf("\tSessions:");
+
+                STRV_FOREACH(l, i->sessions) {
+                        if (streq_ptr(*l, i->active_session))
+                                printf(" *%s", *l);
+                        else
+                                printf(" %s", *l);
+                }
+
+                printf("\n");
+        }
+
+        if (arg_transport != TRANSPORT_SSH) {
+                unsigned c;
+
+                c = columns();
+                if (c > 21)
+                        c -= 21;
+                else
+                        c = 0;
+
+                printf("\t Devices:\n");
+
+                show_sysfs(i->id, "\t\t  ", c);
+        }
+}
+
+static int status_property_session(const char *name, DBusMessageIter *iter, SessionStatusInfo *i) {
+        assert(name);
+        assert(iter);
+        assert(i);
+
+        switch (dbus_message_iter_get_arg_type(iter)) {
+
+        case DBUS_TYPE_STRING: {
+                const char *s;
+
+                dbus_message_iter_get_basic(iter, &s);
+
+                if (!isempty(s)) {
+                        if (streq(name, "Id"))
+                                i->id = s;
+                        else if (streq(name, "Name"))
+                                i->name = s;
+                        else if (streq(name, "ControlGroupPath"))
+                                i->control_group = s;
+                        else if (streq(name, "TTY"))
+                                i->tty = s;
+                        else if (streq(name, "Display"))
+                                i->display = s;
+                        else if (streq(name, "RemoteHost"))
+                                i->remote_host = s;
+                        else if (streq(name, "RemoteUser"))
+                                i->remote_user = s;
+                        else if (streq(name, "Service"))
+                                i->service = s;
+                        else if (streq(name, "Type"))
+                                i->type = s;
+                }
+                break;
+        }
+
+        case DBUS_TYPE_UINT32: {
+                uint32_t u;
+
+                dbus_message_iter_get_basic(iter, &u);
+
+                if (streq(name, "VTNr"))
+                        i->vtnr = (int) u;
+                else if (streq(name, "Leader"))
+                        i->leader = (pid_t) u;
+
+                break;
+        }
+
+        case DBUS_TYPE_BOOLEAN: {
+                dbus_bool_t b;
+
+                dbus_message_iter_get_basic(iter, &b);
+
+                if (streq(name, "Remote"))
+                        i->remote = b;
+                else if (streq(name, "Active"))
+                        i->active = b;
+
+                break;
+        }
+
+        case DBUS_TYPE_UINT64: {
+                uint64_t u;
+
+                dbus_message_iter_get_basic(iter, &u);
+
+                if (streq(name, "Timestamp"))
+                        i->timestamp = (usec_t) u;
+
+                break;
+        }
+
+        case DBUS_TYPE_STRUCT: {
+                DBusMessageIter sub;
+
+                dbus_message_iter_recurse(iter, &sub);
+
+                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "User")) {
+                        uint32_t u;
+
+                        dbus_message_iter_get_basic(&sub, &u);
+                        i->uid = (uid_t) u;
+
+                } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Seat")) {
+                        const char *s;
+
+                        dbus_message_iter_get_basic(&sub, &s);
+
+                        if (!isempty(s))
+                                i->seat = s;
+                }
+
+                break;
+        }
+        }
+
+        return 0;
+}
+
+static int status_property_user(const char *name, DBusMessageIter *iter, UserStatusInfo *i) {
+        assert(name);
+        assert(iter);
+        assert(i);
+
+        switch (dbus_message_iter_get_arg_type(iter)) {
+
+        case DBUS_TYPE_STRING: {
+                const char *s;
+
+                dbus_message_iter_get_basic(iter, &s);
+
+                if (!isempty(s)) {
+                        if (streq(name, "Name"))
+                                i->name = s;
+                        else if (streq(name, "ControlGroupPath"))
+                                i->control_group = s;
+                        else if (streq(name, "State"))
+                                i->state = s;
+                }
+                break;
+        }
+
+        case DBUS_TYPE_UINT32: {
+                uint32_t u;
+
+                dbus_message_iter_get_basic(iter, &u);
+
+                if (streq(name, "UID"))
+                        i->uid = (uid_t) u;
+
+                break;
+        }
+
+        case DBUS_TYPE_UINT64: {
+                uint64_t u;
+
+                dbus_message_iter_get_basic(iter, &u);
+
+                if (streq(name, "Timestamp"))
+                        i->timestamp = (usec_t) u;
+
+                break;
+        }
+
+        case DBUS_TYPE_STRUCT: {
+                DBusMessageIter sub;
+
+                dbus_message_iter_recurse(iter, &sub);
+
+                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Display")) {
+                        const char *s;
+
+                        dbus_message_iter_get_basic(&sub, &s);
+
+                        if (!isempty(s))
+                                i->display = s;
+                }
+
+                break;
+        }
+
+        case DBUS_TYPE_ARRAY: {
+
+                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
+                        DBusMessageIter sub, sub2;
+
+                        dbus_message_iter_recurse(iter, &sub);
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                                const char *id;
+                                const char *path;
+
+                                dbus_message_iter_recurse(&sub, &sub2);
+
+                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
+                                        char **l;
+
+                                        l = strv_append(i->sessions, id);
+                                        if (!l)
+                                                return -ENOMEM;
+
+                                        strv_free(i->sessions);
+                                        i->sessions = l;
+                                }
+
+                                dbus_message_iter_next(&sub);
+                        }
+
+                        return 0;
+                }
+        }
+        }
+
+        return 0;
+}
+
+static int status_property_seat(const char *name, DBusMessageIter *iter, SeatStatusInfo *i) {
+        assert(name);
+        assert(iter);
+        assert(i);
+
+        switch (dbus_message_iter_get_arg_type(iter)) {
+
+        case DBUS_TYPE_STRING: {
+                const char *s;
+
+                dbus_message_iter_get_basic(iter, &s);
+
+                if (!isempty(s)) {
+                        if (streq(name, "Id"))
+                                i->id = s;
+                }
+                break;
+        }
+
+        case DBUS_TYPE_STRUCT: {
+                DBusMessageIter sub;
+
+                dbus_message_iter_recurse(iter, &sub);
+
+                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "ActiveSession")) {
+                        const char *s;
+
+                        dbus_message_iter_get_basic(&sub, &s);
+
+                        if (!isempty(s))
+                                i->active_session = s;
+                }
+
+                break;
+        }
+
+        case DBUS_TYPE_ARRAY: {
+
+                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
+                        DBusMessageIter sub, sub2;
+
+                        dbus_message_iter_recurse(iter, &sub);
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                                const char *id;
+                                const char *path;
+
+                                dbus_message_iter_recurse(&sub, &sub2);
+
+                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
+                                        char **l;
+
+                                        l = strv_append(i->sessions, id);
+                                        if (!l)
+                                                return -ENOMEM;
+
+                                        strv_free(i->sessions);
+                                        i->sessions = l;
+                                }
+
+                                dbus_message_iter_next(&sub);
+                        }
+
+                        return 0;
+                }
+        }
+        }
+
+        return 0;
+}
+
+static int print_property(const char *name, DBusMessageIter *iter) {
+        assert(name);
+        assert(iter);
+
+        if (arg_property && !strv_find(arg_property, name))
+                return 0;
+
+        switch (dbus_message_iter_get_arg_type(iter)) {
+
+        case DBUS_TYPE_STRUCT: {
+                DBusMessageIter sub;
+
+                dbus_message_iter_recurse(iter, &sub);
+
+                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING &&
+                    (streq(name, "Display") || streq(name, "ActiveSession"))) {
+                        const char *s;
+
+                        dbus_message_iter_get_basic(&sub, &s);
+
+                        if (arg_all || !isempty(s))
+                                printf("%s=%s\n", name, s);
+                        return 0;
+                }
+                break;
+        }
+
+        case DBUS_TYPE_ARRAY:
+
+                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
+                        DBusMessageIter sub, sub2;
+                        bool found = false;
+
+                        dbus_message_iter_recurse(iter, &sub);
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                                const char *id;
+                                const char *path;
+
+                                dbus_message_iter_recurse(&sub, &sub2);
+
+                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
+                                        if (found)
+                                                printf(" %s", id);
+                                        else {
+                                                printf("%s=%s", name, id);
+                                                found = true;
+                                        }
+                                }
+
+                                dbus_message_iter_next(&sub);
+                        }
+
+                        if (!found && arg_all)
+                                printf("%s=\n", name);
+                        else if (found)
+                                printf("\n");
+
+                        return 0;
+                }
+
+                break;
+        }
+
+        if (generic_print_property(name, iter, arg_all) > 0)
+                return 0;
+
+        if (arg_all)
+                printf("%s=[unprintable]\n", name);
+
+        return 0;
+}
+
+static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
+        DBusMessage *m = NULL, *reply = NULL;
+        const char *interface = "";
+        int r;
+        DBusError error;
+        DBusMessageIter iter, sub, sub2, sub3;
+        SessionStatusInfo session_info;
+        UserStatusInfo user_info;
+        SeatStatusInfo seat_info;
+
+        assert(bus);
+        assert(path);
+        assert(new_line);
+
+        zero(session_info);
+        zero(user_info);
+        zero(seat_info);
+
+        dbus_error_init(&error);
+
+        m = dbus_message_new_method_call(
+                        "org.freedesktop.login1",
+                        path,
+                        "org.freedesktop.DBus.Properties",
+                        "GetAll");
+        if (!m) {
+                log_error("Could not allocate message.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_STRING, &interface,
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Could not append arguments to message.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+        if (!reply) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
+                r = -EIO;
+                goto finish;
+        }
+
+        if (!dbus_message_iter_init(reply, &iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
+                log_error("Failed to parse reply.");
+                r = -EIO;
+                goto finish;
+        }
+
+        dbus_message_iter_recurse(&iter, &sub);
+
+        if (*new_line)
+                printf("\n");
+
+        *new_line = true;
+
+        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                const char *name;
+
+                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_recurse(&sub, &sub2);
+
+                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_recurse(&sub2, &sub3);
+
+                if (show_properties)
+                        r = print_property(name, &sub3);
+                else if (strstr(verb, "session"))
+                        r = status_property_session(name, &sub3, &session_info);
+                else if (strstr(verb, "user"))
+                        r = status_property_user(name, &sub3, &user_info);
+                else
+                        r = status_property_seat(name, &sub3, &seat_info);
+
+                if (r < 0) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_next(&sub);
+        }
+
+        if (!show_properties) {
+                if (strstr(verb, "session"))
+                        print_session_status_info(&session_info);
+                else if (strstr(verb, "user"))
+                        print_user_status_info(&user_info);
+                else
+                        print_seat_status_info(&seat_info);
+        }
+
+        strv_free(seat_info.sessions);
+        strv_free(user_info.sessions);
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return r;
+}
+
+static int show(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL, *reply = NULL;
+        int r, ret = 0;
+        DBusError error;
+        unsigned i;
+        bool show_properties, new_line = false;
+
+        assert(bus);
+        assert(args);
+
+        dbus_error_init(&error);
+
+        show_properties = !strstr(args[0], "status");
+
+        if (show_properties)
+                pager_open_if_enabled();
+
+        if (show_properties && n <= 1) {
+                /* If not argument is specified inspect the manager
+                 * itself */
+
+                ret = show_one(args[0], bus, "/org/freedesktop/login1", show_properties, &new_line);
+                goto finish;
+        }
+
+        for (i = 1; i < n; i++) {
+                const char *path = NULL;
+
+                if (strstr(args[0], "session")) {
+
+                        m = dbus_message_new_method_call(
+                                        "org.freedesktop.login1",
+                                        "/org/freedesktop/login1",
+                                        "org.freedesktop.login1.Manager",
+                                        "GetSession");
+                        if (!m) {
+                                log_error("Could not allocate message.");
+                                ret = -ENOMEM;
+                                goto finish;
+                        }
+
+                        if (!dbus_message_append_args(m,
+                                                      DBUS_TYPE_STRING, &args[i],
+                                                      DBUS_TYPE_INVALID)) {
+                                log_error("Could not append arguments to message.");
+                                ret = -ENOMEM;
+                                goto finish;
+                        }
+
+                } else if (strstr(args[0], "user")) {
+                        uid_t uid;
+                        uint32_t u;
+
+                        ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
+                        if (ret < 0) {
+                                log_error("User %s unknown.", args[i]);
+                                goto finish;
+                        }
+
+                        m = dbus_message_new_method_call(
+                                        "org.freedesktop.login1",
+                                        "/org/freedesktop/login1",
+                                        "org.freedesktop.login1.Manager",
+                                        "GetUser");
+                        if (!m) {
+                                log_error("Could not allocate message.");
+                                ret = -ENOMEM;
+                                goto finish;
+                        }
+
+                        u = (uint32_t) uid;
+                        if (!dbus_message_append_args(m,
+                                                      DBUS_TYPE_UINT32, &u,
+                                                      DBUS_TYPE_INVALID)) {
+                                log_error("Could not append arguments to message.");
+                                ret = -ENOMEM;
+                                goto finish;
+                        }
+                } else {
+
+                        m = dbus_message_new_method_call(
+                                        "org.freedesktop.login1",
+                                        "/org/freedesktop/login1",
+                                        "org.freedesktop.login1.Manager",
+                                        "GetSeat");
+                        if (!m) {
+                                log_error("Could not allocate message.");
+                                ret = -ENOMEM;
+                                goto finish;
+                        }
+
+                        if (!dbus_message_append_args(m,
+                                                      DBUS_TYPE_STRING, &args[i],
+                                                      DBUS_TYPE_INVALID)) {
+                                log_error("Could not append arguments to message.");
+                                ret = -ENOMEM;
+                                goto finish;
+                        }
+                }
+
+                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+                if (!reply) {
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
+                        ret = -EIO;
+                        goto finish;
+                }
+
+                if (!dbus_message_get_args(reply, &error,
+                                           DBUS_TYPE_OBJECT_PATH, &path,
+                                           DBUS_TYPE_INVALID)) {
+                        log_error("Failed to parse reply: %s", bus_error_message(&error));
+                        ret = -EIO;
+                        goto finish;
+                }
+
+                r = show_one(args[0], bus, path, show_properties, &new_line);
+                if (r != 0)
+                        ret = r;
+
+                dbus_message_unref(m);
+                dbus_message_unref(reply);
+                m = reply = NULL;
+        }
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return ret;
+}
+
+static int activate(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL;
+        int ret = 0;
+        DBusError error;
+        unsigned i;
+
+        assert(bus);
+        assert(args);
+
+        dbus_error_init(&error);
+
+        for (i = 1; i < n; i++) {
+                DBusMessage *reply;
+
+                m = dbus_message_new_method_call(
+                                "org.freedesktop.login1",
+                                "/org/freedesktop/login1",
+                                "org.freedesktop.login1.Manager",
+                                streq(args[0], "lock-session")      ? "LockSession" :
+                                streq(args[0], "unlock-session")    ? "UnlockSession" :
+                                streq(args[0], "terminate-session") ? "TerminateSession" :
+                                                                      "ActivateSession");
+                if (!m) {
+                        log_error("Could not allocate message.");
+                        ret = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!dbus_message_append_args(m,
+                                              DBUS_TYPE_STRING, &args[i],
+                                              DBUS_TYPE_INVALID)) {
+                        log_error("Could not append arguments to message.");
+                        ret = -ENOMEM;
+                        goto finish;
+                }
+
+                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+                if (!reply) {
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
+                        ret = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_unref(m);
+                dbus_message_unref(reply);
+                m = reply = NULL;
+        }
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        dbus_error_free(&error);
+
+        return ret;
+}
+
+static int kill_session(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL;
+        int ret = 0;
+        DBusError error;
+        unsigned i;
+
+        assert(bus);
+        assert(args);
+
+        dbus_error_init(&error);
+
+        if (!arg_kill_who)
+                arg_kill_who = "all";
+
+        for (i = 1; i < n; i++) {
+                DBusMessage *reply;
+
+                m = dbus_message_new_method_call(
+                                "org.freedesktop.login1",
+                                "/org/freedesktop/login1",
+                                "org.freedesktop.login1.Manager",
+                                "KillSession");
+                if (!m) {
+                        log_error("Could not allocate message.");
+                        ret = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!dbus_message_append_args(m,
+                                              DBUS_TYPE_STRING, &args[i],
+                                              DBUS_TYPE_STRING, &arg_kill_who,
+                                              DBUS_TYPE_INT32, arg_signal,
+                                              DBUS_TYPE_INVALID)) {
+                        log_error("Could not append arguments to message.");
+                        ret = -ENOMEM;
+                        goto finish;
+                }
+
+                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+                if (!reply) {
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
+                        ret = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_unref(m);
+                dbus_message_unref(reply);
+                m = reply = NULL;
+        }
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        dbus_error_free(&error);
+
+        return ret;
+}
+
+static int enable_linger(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL;
+        int ret = 0;
+        DBusError error;
+        unsigned i;
+        dbus_bool_t b, interactive = true;
+
+        assert(bus);
+        assert(args);
+
+        dbus_error_init(&error);
+
+        b = streq(args[0], "enable-linger");
+
+        for (i = 1; i < n; i++) {
+                DBusMessage *reply;
+                uint32_t u;
+                uid_t uid;
+
+                m = dbus_message_new_method_call(
+                                "org.freedesktop.login1",
+                                "/org/freedesktop/login1",
+                                "org.freedesktop.login1.Manager",
+                                "SetUserLinger");
+                if (!m) {
+                        log_error("Could not allocate message.");
+                        ret = -ENOMEM;
+                        goto finish;
+                }
+
+                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
+                if (ret < 0) {
+                        log_error("Failed to resolve user %s: %s", args[i], strerror(-ret));
+                        goto finish;
+                }
+
+                u = (uint32_t) uid;
+                if (!dbus_message_append_args(m,
+                                              DBUS_TYPE_UINT32, &u,
+                                              DBUS_TYPE_BOOLEAN, &b,
+                                              DBUS_TYPE_BOOLEAN, &interactive,
+                                              DBUS_TYPE_INVALID)) {
+                        log_error("Could not append arguments to message.");
+                        ret = -ENOMEM;
+                        goto finish;
+                }
+
+                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+                if (!reply) {
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
+                        ret = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_unref(m);
+                dbus_message_unref(reply);
+                m = reply = NULL;
+        }
+
+        ret = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        dbus_error_free(&error);
+
+        return ret;
+}
+
+static int terminate_user(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL;
+        int ret = 0;
+        DBusError error;
+        unsigned i;
+
+        assert(bus);
+        assert(args);
+
+        dbus_error_init(&error);
+
+        for (i = 1; i < n; i++) {
+                uint32_t u;
+                uid_t uid;
+                DBusMessage *reply;
+
+                m = dbus_message_new_method_call(
+                                "org.freedesktop.login1",
+                                "/org/freedesktop/login1",
+                                "org.freedesktop.login1.Manager",
+                                "TerminateUser");
+                if (!m) {
+                        log_error("Could not allocate message.");
+                        ret = -ENOMEM;
+                        goto finish;
+                }
+
+                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
+                if (ret < 0) {
+                        log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
+                        goto finish;
+                }
+
+                u = (uint32_t) uid;
+                if (!dbus_message_append_args(m,
+                                              DBUS_TYPE_UINT32, &u,
+                                              DBUS_TYPE_INVALID)) {
+                        log_error("Could not append arguments to message.");
+                        ret = -ENOMEM;
+                        goto finish;
+                }
+
+                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+                if (!reply) {
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
+                        ret = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_unref(m);
+                dbus_message_unref(reply);
+                m = reply = NULL;
+        }
+
+        ret = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        dbus_error_free(&error);
+
+        return ret;
+}
+
+static int kill_user(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL;
+        int ret = 0;
+        DBusError error;
+        unsigned i;
+
+        assert(bus);
+        assert(args);
+
+        dbus_error_init(&error);
+
+        if (!arg_kill_who)
+                arg_kill_who = "all";
+
+        for (i = 1; i < n; i++) {
+                DBusMessage *reply;
+                uid_t uid;
+                uint32_t u;
+
+                m = dbus_message_new_method_call(
+                                "org.freedesktop.login1",
+                                "/org/freedesktop/login1",
+                                "org.freedesktop.login1.Manager",
+                                "KillUser");
+                if (!m) {
+                        log_error("Could not allocate message.");
+                        ret = -ENOMEM;
+                        goto finish;
+                }
+
+                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
+                if (ret < 0) {
+                        log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
+                        goto finish;
+                }
+
+                u = (uint32_t) uid;
+                if (!dbus_message_append_args(m,
+                                              DBUS_TYPE_UINT32, &u,
+                                              DBUS_TYPE_INT32, arg_signal,
+                                              DBUS_TYPE_INVALID)) {
+                        log_error("Could not append arguments to message.");
+                        ret = -ENOMEM;
+                        goto finish;
+                }
+
+                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+                if (!reply) {
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
+                        ret = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_unref(m);
+                dbus_message_unref(reply);
+                m = reply = NULL;
+        }
+
+        ret = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        dbus_error_free(&error);
+
+        return ret;
+}
+
+static int attach(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL;
+        int ret = 0;
+        DBusError error;
+        unsigned i;
+        dbus_bool_t interactive = true;
+
+        assert(bus);
+        assert(args);
+
+        dbus_error_init(&error);
+
+        for (i = 2; i < n; i++) {
+                DBusMessage *reply;
+
+                m = dbus_message_new_method_call(
+                                "org.freedesktop.login1",
+                                "/org/freedesktop/login1",
+                                "org.freedesktop.login1.Manager",
+                                "AttachDevice");
+                if (!m) {
+                        log_error("Could not allocate message.");
+                        ret = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!dbus_message_append_args(m,
+                                              DBUS_TYPE_STRING, &args[1],
+                                              DBUS_TYPE_STRING, &args[i],
+                                              DBUS_TYPE_BOOLEAN, &interactive,
+                                              DBUS_TYPE_INVALID)) {
+                        log_error("Could not append arguments to message.");
+                        ret = -ENOMEM;
+                        goto finish;
+                }
+
+                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+                if (!reply) {
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
+                        ret = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_unref(m);
+                dbus_message_unref(reply);
+                m = reply = NULL;
+        }
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        dbus_error_free(&error);
+
+        return ret;
+}
+
+static int flush_devices(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL, *reply = NULL;
+        int ret = 0;
+        DBusError error;
+        dbus_bool_t interactive = true;
+
+        assert(bus);
+        assert(args);
+
+        dbus_error_init(&error);
+
+        m = dbus_message_new_method_call(
+                        "org.freedesktop.login1",
+                        "/org/freedesktop/login1",
+                        "org.freedesktop.login1.Manager",
+                        "FlushDevices");
+        if (!m) {
+                log_error("Could not allocate message.");
+                ret = -ENOMEM;
+                goto finish;
+        }
+
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_BOOLEAN, &interactive,
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Could not append arguments to message.");
+                ret = -ENOMEM;
+                goto finish;
+        }
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+        if (!reply) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
+                ret = -EIO;
+                goto finish;
+        }
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return ret;
+}
+
+static int terminate_seat(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL;
+        int ret = 0;
+        DBusError error;
+        unsigned i;
+
+        assert(bus);
+        assert(args);
+
+        dbus_error_init(&error);
+
+        for (i = 1; i < n; i++) {
+                DBusMessage *reply;
+
+                m = dbus_message_new_method_call(
+                                "org.freedesktop.login1",
+                                "/org/freedesktop/login1",
+                                "org.freedesktop.login1.Manager",
+                                "TerminateSeat");
+                if (!m) {
+                        log_error("Could not allocate message.");
+                        ret = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!dbus_message_append_args(m,
+                                              DBUS_TYPE_STRING, &args[i],
+                                              DBUS_TYPE_INVALID)) {
+                        log_error("Could not append arguments to message.");
+                        ret = -ENOMEM;
+                        goto finish;
+                }
+
+                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+                if (!reply) {
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
+                        ret = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_unref(m);
+                dbus_message_unref(reply);
+                m = reply = NULL;
+        }
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        dbus_error_free(&error);
+
+        return ret;
+}
+
+static int help(void) {
+
+        printf("%s [OPTIONS...] {COMMAND} ...\n\n"
+               "Send control commands to or query the login manager.\n\n"
+               "  -h --help           Show this help\n"
+               "     --version        Show package version\n"
+               "  -p --property=NAME  Show only properties by this name\n"
+               "  -a --all            Show all properties, including empty ones\n"
+               "     --kill-who=WHO   Who to send signal to\n"
+               "  -s --signal=SIGNAL  Which signal to send\n"
+               "  -H --host=[USER@]HOST\n"
+               "                      Show information for remote host\n"
+               "  -P --privileged     Acquire privileges before execution\n"
+               "     --no-pager       Do not pipe output into a pager\n\n"
+               "Commands:\n"
+               "  list-sessions                   List sessions\n"
+               "  session-status [ID...]          Show session status\n"
+               "  show-session [ID...]            Show properties of one or more sessions\n"
+               "  activate [ID]                   Activate a session\n"
+               "  lock-session [ID...]            Screen lock one or more sessions\n"
+               "  unlock-session [ID...]          Screen unlock one or more sessions\n"
+               "  terminate-session [ID...]       Terminate one or more sessions\n"
+               "  kill-session [ID...]            Send signal to processes of a session\n"
+               "  list-users                      List users\n"
+               "  user-status [USER...]           Show user status\n"
+               "  show-user [USER...]             Show properties of one or more users\n"
+               "  enable-linger [USER...]         Enable linger state of one or more users\n"
+               "  disable-linger [USER...]        Disable linger state of one or more users\n"
+               "  terminate-user [USER...]        Terminate all sessions of one or more users\n"
+               "  kill-user [USER...]             Send signal to processes of a user\n"
+               "  list-seats                      List seats\n"
+               "  seat-status [NAME...]           Show seat status\n"
+               "  show-seat [NAME...]             Show properties of one or more seats\n"
+               "  attach [NAME] [DEVICE...]       Attach one or more devices to a seat\n"
+               "  flush-devices                   Flush all device associations\n"
+               "  terminate-seat [NAME...]        Terminate all sessions on one or more seats\n",
+               program_invocation_short_name);
+
+        return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+        enum {
+                ARG_VERSION = 0x100,
+                ARG_NO_PAGER,
+                ARG_KILL_WHO
+        };
+
+        static const struct option options[] = {
+                { "help",      no_argument,       NULL, 'h'           },
+                { "version",   no_argument,       NULL, ARG_VERSION   },
+                { "property",  required_argument, NULL, 'p'           },
+                { "all",       no_argument,       NULL, 'a'           },
+                { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
+                { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
+                { "signal",    required_argument, NULL, 's'           },
+                { "host",      required_argument, NULL, 'H'           },
+                { "privileged",no_argument,       NULL, 'P'           },
+                { NULL,        0,                 NULL, 0             }
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "hp:as:H:P", options, NULL)) >= 0) {
+
+                switch (c) {
+
+                case 'h':
+                        help();
+                        return 0;
+
+                case ARG_VERSION:
+                        puts(PACKAGE_STRING);
+                        puts(DISTRIBUTION);
+                        puts(SYSTEMD_FEATURES);
+                        return 0;
+
+                case 'p': {
+                        char **l;
+
+                        l = strv_append(arg_property, optarg);
+                        if (!l)
+                                return -ENOMEM;
+
+                        strv_free(arg_property);
+                        arg_property = l;
+
+                        /* If the user asked for a particular
+                         * property, show it to him, even if it is
+                         * empty. */
+                        arg_all = true;
+                        break;
+                }
+
+                case 'a':
+                        arg_all = true;
+                        break;
+
+                case ARG_NO_PAGER:
+                        arg_no_pager = true;
+                        break;
+
+                case ARG_KILL_WHO:
+                        arg_kill_who = optarg;
+                        break;
+
+                case 's':
+                        arg_signal = signal_from_string_try_harder(optarg);
+                        if (arg_signal < 0) {
+                                log_error("Failed to parse signal string %s.", optarg);
+                                return -EINVAL;
+                        }
+                        break;
+
+                case 'P':
+                        arg_transport = TRANSPORT_POLKIT;
+                        break;
+
+                case 'H':
+                        arg_transport = TRANSPORT_SSH;
+                        arg_host = optarg;
+                        break;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        log_error("Unknown option code %c", c);
+                        return -EINVAL;
+                }
+        }
+
+        return 1;
+}
+
+static int loginctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
+
+        static const struct {
+                const char* verb;
+                const enum {
+                        MORE,
+                        LESS,
+                        EQUAL
+                } argc_cmp;
+                const int argc;
+                int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
+        } verbs[] = {
+                { "list-sessions",         LESS,   1, list_sessions    },
+                { "session-status",        MORE,   2, show             },
+                { "show-session",          MORE,   1, show             },
+                { "activate",              EQUAL,  2, activate         },
+                { "lock-session",          MORE,   2, activate         },
+                { "unlock-session",        MORE,   2, activate         },
+                { "terminate-session",     MORE,   2, activate         },
+                { "kill-session",          MORE,   2, kill_session     },
+                { "list-users",            EQUAL,  1, list_users       },
+                { "user-status",           MORE,   2, show             },
+                { "show-user",             MORE,   1, show             },
+                { "enable-linger",         MORE,   2, enable_linger    },
+                { "disable-linger",        MORE,   2, enable_linger    },
+                { "terminate-user",        MORE,   2, terminate_user   },
+                { "kill-user",             MORE,   2, kill_user        },
+                { "list-seats",            EQUAL,  1, list_seats       },
+                { "seat-status",           MORE,   2, show             },
+                { "show-seat",             MORE,   1, show             },
+                { "attach",                MORE,   3, attach           },
+                { "flush-devices",         EQUAL,  1, flush_devices    },
+                { "terminate-seat",        MORE,   2, terminate_seat   },
+        };
+
+        int left;
+        unsigned i;
+
+        assert(argc >= 0);
+        assert(argv);
+        assert(error);
+
+        left = argc - optind;
+
+        if (left <= 0)
+                /* Special rule: no arguments means "list-sessions" */
+                i = 0;
+        else {
+                if (streq(argv[optind], "help")) {
+                        help();
+                        return 0;
+                }
+
+                for (i = 0; i < ELEMENTSOF(verbs); i++)
+                        if (streq(argv[optind], verbs[i].verb))
+                                break;
+
+                if (i >= ELEMENTSOF(verbs)) {
+                        log_error("Unknown operation %s", argv[optind]);
+                        return -EINVAL;
+                }
+        }
+
+        switch (verbs[i].argc_cmp) {
+
+        case EQUAL:
+                if (left != verbs[i].argc) {
+                        log_error("Invalid number of arguments.");
+                        return -EINVAL;
+                }
+
+                break;
+
+        case MORE:
+                if (left < verbs[i].argc) {
+                        log_error("Too few arguments.");
+                        return -EINVAL;
+                }
+
+                break;
+
+        case LESS:
+                if (left > verbs[i].argc) {
+                        log_error("Too many arguments.");
+                        return -EINVAL;
+                }
+
+                break;
+
+        default:
+                assert_not_reached("Unknown comparison operator.");
+        }
+
+        if (!bus) {
+                log_error("Failed to get D-Bus connection: %s", error->message);
+                return -EIO;
+        }
+
+        return verbs[i].dispatch(bus, argv + optind, left);
+}
+
+int main(int argc, char*argv[]) {
+        int r, retval = EXIT_FAILURE;
+        DBusConnection *bus = NULL;
+        DBusError error;
+
+        dbus_error_init(&error);
+
+        log_parse_environment();
+        log_open();
+
+        r = parse_argv(argc, argv);
+        if (r < 0)
+                goto finish;
+        else if (r == 0) {
+                retval = EXIT_SUCCESS;
+                goto finish;
+        }
+
+        if (arg_transport == TRANSPORT_NORMAL)
+                bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
+        else if (arg_transport == TRANSPORT_POLKIT)
+                bus_connect_system_polkit(&bus, &error);
+        else if (arg_transport == TRANSPORT_SSH)
+                bus_connect_system_ssh(NULL, arg_host, &bus, &error);
+        else
+                assert_not_reached("Uh, invalid transport...");
+
+        r = loginctl_main(bus, argc, argv, &error);
+        retval = r < 0 ? EXIT_FAILURE : r;
+
+finish:
+        if (bus) {
+                dbus_connection_flush(bus);
+                dbus_connection_close(bus);
+                dbus_connection_unref(bus);
+        }
+
+        dbus_error_free(&error);
+        dbus_shutdown();
+
+        strv_free(arg_property);
+
+        pager_close();
+
+        return retval;
+}
diff --git a/src/login/logind-acl.c b/src/login/logind-acl.c
new file mode 100644
index 0000000..eb8a48d
--- /dev/null
+++ b/src/login/logind-acl.c
@@ -0,0 +1,248 @@
+/*-*- 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 <assert.h>
+#include <sys/acl.h>
+#include <acl/libacl.h>
+#include <errno.h>
+#include <string.h>
+
+#include "logind-acl.h"
+#include "util.h"
+#include "acl-util.h"
+
+static int flush_acl(acl_t acl) {
+        acl_entry_t i;
+        int found;
+        bool changed = false;
+
+        assert(acl);
+
+        for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
+             found > 0;
+             found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
+
+                acl_tag_t tag;
+
+                if (acl_get_tag_type(i, &tag) < 0)
+                        return -errno;
+
+                if (tag != ACL_USER)
+                        continue;
+
+                if (acl_delete_entry(acl, i) < 0)
+                        return -errno;
+
+                changed = true;
+        }
+
+        if (found < 0)
+                return -errno;
+
+        return changed;
+}
+
+int devnode_acl(const char *path,
+                bool flush,
+                bool del, uid_t old_uid,
+                bool add, uid_t new_uid) {
+
+        acl_t acl;
+        int r = 0;
+        bool changed = false;
+
+        assert(path);
+
+        acl = acl_get_file(path, ACL_TYPE_ACCESS);
+        if (!acl)
+                return -errno;
+
+        if (flush) {
+
+                r = flush_acl(acl);
+                if (r < 0)
+                        goto finish;
+                if (r > 0)
+                        changed = true;
+
+        } else if (del && old_uid > 0) {
+                acl_entry_t entry;
+
+                r = acl_find_uid(acl, old_uid, &entry);
+                if (r < 0)
+                        goto finish;
+
+                if (r > 0) {
+                        if (acl_delete_entry(acl, entry) < 0) {
+                                r = -errno;
+                                goto finish;
+                        }
+
+                        changed = true;
+                }
+        }
+
+        if (add && new_uid > 0) {
+                acl_entry_t entry;
+                acl_permset_t permset;
+                int rd, wt;
+
+                r = acl_find_uid(acl, new_uid, &entry);
+                if (r < 0)
+                        goto finish;
+
+                if (r == 0) {
+                        if (acl_create_entry(&acl, &entry) < 0) {
+                                r = -errno;
+                                goto finish;
+                        }
+
+                        if (acl_set_tag_type(entry, ACL_USER) < 0 ||
+                            acl_set_qualifier(entry, &new_uid) < 0) {
+                                r = -errno;
+                                goto finish;
+                        }
+                }
+
+                if (acl_get_permset(entry, &permset) < 0) {
+                        r = -errno;
+                        goto finish;
+                }
+
+                rd = acl_get_perm(permset, ACL_READ);
+                if (rd < 0) {
+                        r = -errno;
+                        goto finish;
+                }
+
+                wt = acl_get_perm(permset, ACL_WRITE);
+                if (wt < 0) {
+                        r = -errno;
+                        goto finish;
+                }
+
+                if (!rd || !wt) {
+
+                        if (acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) {
+                                r = -errno;
+                                goto finish;
+                        }
+
+                        changed = true;
+                }
+        }
+
+        if (!changed)
+                goto finish;
+
+        if (acl_calc_mask(&acl) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        if (acl_set_file(path, ACL_TYPE_ACCESS, acl) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        r = 0;
+
+finish:
+        acl_free(acl);
+
+        return r;
+}
+
+int devnode_acl_all(struct udev *udev,
+                    const char *seat,
+                    bool flush,
+                    bool del, uid_t old_uid,
+                    bool add, uid_t new_uid) {
+
+        struct udev_list_entry *item = NULL, *first = NULL;
+        struct udev_enumerate *e;
+        int r;
+
+        assert(udev);
+
+        if (isempty(seat))
+                seat = "seat0";
+
+        e = udev_enumerate_new(udev);
+        if (!e)
+                return -ENOMEM;
+
+        /* We can only match by one tag in libudev. We choose
+         * "uaccess" for that. If we could match for two tags here we
+         * could add the seat name as second match tag, but this would
+         * be hardly optimizable in libudev, and hence checking the
+         * second tag manually in our loop is a good solution. */
+
+        r = udev_enumerate_add_match_tag(e, "uaccess");
+        if (r < 0)
+                goto finish;
+
+        r = udev_enumerate_scan_devices(e);
+        if (r < 0)
+                goto finish;
+
+        first = udev_enumerate_get_list_entry(e);
+        udev_list_entry_foreach(item, first) {
+                struct udev_device *d;
+                const char *node, *sn;
+
+                d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
+                if (!d) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                sn = udev_device_get_property_value(d, "ID_SEAT");
+                if (isempty(sn))
+                        sn = "seat0";
+
+                if (!streq(seat, sn)) {
+                        udev_device_unref(d);
+                        continue;
+                }
+
+                node = udev_device_get_devnode(d);
+                if (!node) {
+                        /* In case people mistag devices with nodes, we need to ignore this */
+                        udev_device_unref(d);
+                        continue;
+                }
+
+                log_debug("Fixing up %s for seat %s...", node, sn);
+
+                r = devnode_acl(node, flush, del, old_uid, add, new_uid);
+                udev_device_unref(d);
+
+                if (r < 0)
+                        goto finish;
+        }
+
+finish:
+        if (e)
+                udev_enumerate_unref(e);
+
+        return r;
+}
diff --git a/src/login/logind-acl.h b/src/login/logind-acl.h
new file mode 100644
index 0000000..72740f5
--- /dev/null
+++ b/src/login/logind-acl.h
@@ -0,0 +1,60 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologindaclhfoo
+#define foologindaclhfoo
+
+/***
+  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 <sys/types.h>
+#include <stdbool.h>
+#include <libudev.h>
+
+#ifdef HAVE_ACL
+
+int devnode_acl(const char *path,
+                bool flush,
+                bool del, uid_t old_uid,
+                bool add, uid_t new_uid);
+
+int devnode_acl_all(struct udev *udev,
+                    const char *seat,
+                    bool flush,
+                    bool del, uid_t old_uid,
+                    bool add, uid_t new_uid);
+#else
+
+static inline int devnode_acl(const char *path,
+                bool flush,
+                bool del, uid_t old_uid,
+                bool add, uid_t new_uid) {
+        return 0;
+}
+
+static inline int devnode_acl_all(struct udev *udev,
+                                  const char *seat,
+                                  bool flush,
+                                  bool del, uid_t old_uid,
+                                  bool add, uid_t new_uid) {
+        return 0;
+}
+
+#endif
+
+#endif
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
new file mode 100644
index 0000000..0550d1b
--- /dev/null
+++ b/src/login/logind-dbus.c
@@ -0,0 +1,1504 @@
+/*-*- 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 <string.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#include "logind.h"
+#include "dbus-common.h"
+#include "strv.h"
+#include "polkit.h"
+#include "special.h"
+
+#define BUS_MANAGER_INTERFACE                                           \
+        " <interface name=\"org.freedesktop.login1.Manager\">\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=\"GetUser\">\n"                                 \
+        "   <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"          \
+        "   <arg name=\"user\" type=\"o\" direction=\"out\"/>\n"        \
+        "  </method>\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=\"ListSessions\">\n"                            \
+        "   <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"ListUsers\">\n"                               \
+        "   <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n"  \
+        "  </method>\n"                                                 \
+        "  <method name=\"ListSeats\">\n"                               \
+        "   <arg name=\"seats\" type=\"a(so)\" 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=\"sevice\" type=\"s\" direction=\"in\"/>\n"       \
+        "   <arg name=\"type\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"vtnr\" type=\"u\" 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=\"b\" direction=\"in\"/>\n" \
+        "   <arg name=\"id\" type=\"s\" direction=\"out\"/>\n"          \
+        "   <arg name=\"path\" type=\"o\" direction=\"out\"/>\n"        \
+        "   <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
+        "   <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n"          \
+        "   <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n"        \
+        "   <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n"        \
+        "  </method>\n"                                                 \
+        "  <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"                                                 \
+        "  <method name=\"TerminateUser\">\n"                           \
+        "   <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"          \
+        "  </method>\n"                                                 \
+        "  <method name=\"TerminateSeat\">\n"                           \
+        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
+        "  </method>\n"                                                 \
+        "  <method name=\"SetUserLinger\">\n"                           \
+        "   <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"          \
+        "   <arg name=\"b\" type=\"b\" direction=\"in\"/>\n"            \
+        "   <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n"  \
+        "  </method>\n"                                                 \
+        "  <method name=\"AttachDevice\">\n"                            \
+        "   <arg name=\"seat\" type=\"s\" direction=\"in\"/>\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"                                                 \
+        "  <method name=\"PowerOff\">\n"                                \
+        "   <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n"  \
+        "  </method>\n"                                                 \
+        "  <method name=\"Reboot\">\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"                          \
+        "  </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" \
+        "  <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n"  \
+        "  <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"IdleSinceHintMonotonic\" type=\"t\" 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 int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
+        Manager *m = data;
+        dbus_bool_t b;
+
+        assert(i);
+        assert(property);
+        assert(m);
+
+        b = manager_get_idle_hint(m, NULL) > 0;
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
+        Manager *m = data;
+        dual_timestamp t;
+        uint64_t u;
+
+        assert(i);
+        assert(property);
+        assert(m);
+
+        manager_get_idle_hint(m, &t);
+        u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
+        Session *session = NULL;
+        User *user = NULL;
+        const char *type, *seat, *tty, *display, *remote_user, *remote_host, *service;
+        uint32_t uid, leader, audit_id = 0;
+        dbus_bool_t remote, kill_processes;
+        char **controllers = NULL, **reset_controllers = NULL;
+        SessionType t;
+        Seat *s;
+        DBusMessageIter iter;
+        int r;
+        char *id = NULL, *p;
+        uint32_t vtnr = 0;
+        int fifo_fd = -1;
+        DBusMessage *reply = NULL;
+        bool b;
+
+        assert(m);
+        assert(message);
+        assert(_reply);
+
+        if (!dbus_message_iter_init(message, &iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
+                return -EINVAL;
+
+        dbus_message_iter_get_basic(&iter, &uid);
+
+        if (!dbus_message_iter_next(&iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
+                return -EINVAL;
+
+        dbus_message_iter_get_basic(&iter, &leader);
+
+        if (leader <= 0 ||
+            !dbus_message_iter_next(&iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+                return -EINVAL;
+
+        dbus_message_iter_get_basic(&iter, &service);
+
+        if (!dbus_message_iter_next(&iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+                return -EINVAL;
+
+        dbus_message_iter_get_basic(&iter, &type);
+        t = session_type_from_string(type);
+
+        if (t < 0 ||
+            !dbus_message_iter_next(&iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+                return -EINVAL;
+
+        dbus_message_iter_get_basic(&iter, &seat);
+
+        if (isempty(seat))
+                s = NULL;
+        else {
+                s = hashmap_get(m->seats, seat);
+                if (!s)
+                        return -ENOENT;
+        }
+
+        if (!dbus_message_iter_next(&iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
+                return -EINVAL;
+
+        dbus_message_iter_get_basic(&iter, &vtnr);
+
+        if (!dbus_message_iter_next(&iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+                return -EINVAL;
+
+        dbus_message_iter_get_basic(&iter, &tty);
+
+        if (tty_is_vc(tty)) {
+                int v;
+
+                if (!s)
+                        s = m->vtconsole;
+                else if (s != m->vtconsole)
+                        return -EINVAL;
+
+                v = vtnr_from_tty(tty);
+
+                if (v <= 0)
+                        return v < 0 ? v : -EINVAL;
+
+                if (vtnr <= 0)
+                        vtnr = (uint32_t) v;
+                else if (vtnr != (uint32_t) v)
+                        return -EINVAL;
+
+        } else if (!isempty(tty) && s && seat_is_vtconsole(s))
+                return -EINVAL;
+
+        if (s) {
+                if (seat_is_vtconsole(s)) {
+                        if (vtnr <= 0 || vtnr > 63)
+                                return -EINVAL;
+                } else {
+                        if (vtnr > 0)
+                                return -EINVAL;
+                }
+        }
+
+        if (!dbus_message_iter_next(&iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+                return -EINVAL;
+
+        dbus_message_iter_get_basic(&iter, &display);
+
+        if (!dbus_message_iter_next(&iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
+                return -EINVAL;
+
+        dbus_message_iter_get_basic(&iter, &remote);
+
+        if (!dbus_message_iter_next(&iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+                return -EINVAL;
+
+        dbus_message_iter_get_basic(&iter, &remote_user);
+
+        if (!dbus_message_iter_next(&iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+                return -EINVAL;
+
+        dbus_message_iter_get_basic(&iter, &remote_host);
+
+        if (!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)
+                return -EINVAL;
+
+        r = bus_parse_strv_iter(&iter, &controllers);
+        if (r < 0)
+                return -EINVAL;
+
+        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;
+                goto fail;
+        }
+
+        r = bus_parse_strv_iter(&iter, &reset_controllers);
+        if (r < 0)
+                goto fail;
+
+        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;
+        }
+
+        dbus_message_iter_get_basic(&iter, &kill_processes);
+
+        r = manager_add_user_by_uid(m, uid, &user);
+        if (r < 0)
+                goto fail;
+
+        audit_session_from_pid(leader, &audit_id);
+
+        if (audit_id > 0) {
+                asprintf(&id, "%lu", (unsigned long) audit_id);
+
+                if (!id) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                session = hashmap_get(m->sessions, id);
+
+                if (session) {
+                        free(id);
+
+                        fifo_fd = session_create_fifo(session);
+                        if (fifo_fd < 0) {
+                                r = fifo_fd;
+                                goto fail;
+                        }
+
+                        /* Session already exists, client is probably
+                         * something like "su" which changes uid but
+                         * is still the same audit session */
+
+                        reply = dbus_message_new_method_return(message);
+                        if (!reply) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        p = session_bus_path(session);
+                        if (!p) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        seat = session->seat ? session->seat->id : "";
+                        vtnr = session->vtnr;
+                        b = dbus_message_append_args(
+                                        reply,
+                                        DBUS_TYPE_STRING, &session->id,
+                                        DBUS_TYPE_OBJECT_PATH, &p,
+                                        DBUS_TYPE_STRING, &session->user->runtime_path,
+                                        DBUS_TYPE_UNIX_FD, &fifo_fd,
+                                        DBUS_TYPE_STRING, &seat,
+                                        DBUS_TYPE_UINT32, &vtnr,
+                                        DBUS_TYPE_INVALID);
+                        free(p);
+
+                        if (!b) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        close_nointr_nofail(fifo_fd);
+                        *_reply = reply;
+
+                        strv_free(controllers);
+                        strv_free(reset_controllers);
+
+                        return 0;
+                }
+
+        } else {
+                do {
+                        free(id);
+                        asprintf(&id, "c%lu", ++m->session_counter);
+
+                        if (!id) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                } while (hashmap_get(m->sessions, id));
+        }
+
+        r = manager_add_session(m, user, id, &session);
+        free(id);
+        if (r < 0)
+                goto fail;
+
+        session->leader = leader;
+        session->audit_id = audit_id;
+        session->type = t;
+        session->remote = remote;
+        session->controllers = controllers;
+        session->reset_controllers = reset_controllers;
+        session->kill_processes = kill_processes;
+        session->vtnr = vtnr;
+
+        controllers = reset_controllers = NULL;
+
+        if (!isempty(tty)) {
+                session->tty = strdup(tty);
+                if (!session->tty) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        }
+
+        if (!isempty(display)) {
+                session->display = strdup(display);
+                if (!session->display) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        }
+
+        if (!isempty(remote_user)) {
+                session->remote_user = strdup(remote_user);
+                if (!session->remote_user) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        }
+
+        if (!isempty(remote_host)) {
+                session->remote_host = strdup(remote_host);
+                if (!session->remote_host) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        }
+
+        if (!isempty(service)) {
+                session->service = strdup(service);
+                if (!session->service) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        }
+
+        fifo_fd = session_create_fifo(session);
+        if (fifo_fd < 0) {
+                r = fifo_fd;
+                goto fail;
+        }
+
+        if (s) {
+                r = seat_attach_session(s, session);
+                if (r < 0)
+                        goto fail;
+        }
+
+        r = session_start(session);
+        if (r < 0)
+                goto fail;
+
+        reply = dbus_message_new_method_return(message);
+        if (!reply) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        p = session_bus_path(session);
+        if (!p) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        seat = s ? s->id : "";
+        b = dbus_message_append_args(
+                        reply,
+                        DBUS_TYPE_STRING, &session->id,
+                        DBUS_TYPE_OBJECT_PATH, &p,
+                        DBUS_TYPE_STRING, &session->user->runtime_path,
+                        DBUS_TYPE_UNIX_FD, &fifo_fd,
+                        DBUS_TYPE_STRING, &seat,
+                        DBUS_TYPE_UINT32, &vtnr,
+                        DBUS_TYPE_INVALID);
+        free(p);
+
+        if (!b) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        close_nointr_nofail(fifo_fd);
+        *_reply = reply;
+
+        return 0;
+
+fail:
+        strv_free(controllers);
+        strv_free(reset_controllers);
+
+        if (session)
+                session_add_to_gc_queue(session);
+
+        if (user)
+                user_add_to_gc_queue(user);
+
+        if (fifo_fd >= 0)
+                close_nointr_nofail(fifo_fd);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        return r;
+}
+
+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;
+        }
+
+        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);
+
+                t = strappend(p, "/uevent");
+                if (!t) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                write_one_line_file(t, "change");
+                free(t);
+        }
+
+        r = 0;
+
+finish:
+        if (e)
+                udev_enumerate_unref(e);
+
+        return r;
+}
+
+static int attach_device(Manager *m, const char *seat, const char *sysfs) {
+        struct udev_device *d;
+        char *rule = NULL, *file = NULL;
+        const char *id_for_seat;
+        int r;
+
+        assert(m);
+        assert(seat);
+        assert(sysfs);
+
+        d = udev_device_new_from_syspath(m->udev, sysfs);
+        if (!d)
+                return -ENODEV;
+
+        if (!udev_device_has_tag(d, "seat")) {
+                r = -ENODEV;
+                goto finish;
+        }
+
+        id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
+        if (!id_for_seat) {
+                r = -ENODEV;
+                goto finish;
+        }
+
+        if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        mkdir_p("/etc/udev/rules.d", 0755);
+        r = write_one_line_file_atomic(file, rule);
+        if (r < 0)
+                goto finish;
+
+        r = trigger_device(m, d);
+
+finish:
+        free(rule);
+        free(file);
+
+        if (d)
+                udev_device_unref(d);
+
+        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,
+                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 },
+                { "org.freedesktop.login1.Manager", "IdleHint",               bus_manager_append_idle_hint, "b",  m                       },
+                { "org.freedesktop.login1.Manager", "IdleSinceHint",          bus_manager_append_idle_hint_since, "t", m                  },
+                { "org.freedesktop.login1.Manager", "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", m                  },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        DBusError error;
+        DBusMessage *reply = NULL;
+        int r;
+
+        assert(connection);
+        assert(message);
+        assert(m);
+
+        dbus_error_init(&error);
+
+        if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
+                const char *name;
+                char *p;
+                Session *session;
+                bool b;
+
+                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);
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+                p = session_bus_path(session);
+                if (!p)
+                        goto oom;
+
+                b = dbus_message_append_args(
+                                reply,
+                                DBUS_TYPE_OBJECT_PATH, &p,
+                                DBUS_TYPE_INVALID);
+                free(p);
+
+                if (!b)
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
+                uint32_t uid;
+                char *p;
+                User *user;
+                bool b;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_UINT32, &uid,
+                                    DBUS_TYPE_INVALID))
+                        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);
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+                p = user_bus_path(user);
+                if (!p)
+                        goto oom;
+
+                b = dbus_message_append_args(
+                                reply,
+                                DBUS_TYPE_OBJECT_PATH, &p,
+                                DBUS_TYPE_INVALID);
+                free(p);
+
+                if (!b)
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
+                const char *name;
+                char *p;
+                Seat *seat;
+                bool b;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &name,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                seat = hashmap_get(m->seats, name);
+                if (!seat)
+                        return bus_send_error_reply(connection, message, &error, -ENOENT);
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+                p = seat_bus_path(seat);
+                if (!p)
+                        goto oom;
+
+                b = dbus_message_append_args(
+                                reply,
+                                DBUS_TYPE_OBJECT_PATH, &p,
+                                DBUS_TYPE_INVALID);
+                free(p);
+
+                if (!b)
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
+                char *p;
+                Session *session;
+                Iterator i;
+                DBusMessageIter iter, sub;
+                const char *empty = "";
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+                dbus_message_iter_init_append(reply, &iter);
+
+                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
+                        goto oom;
+
+                HASHMAP_FOREACH(session, m->sessions, i) {
+                        DBusMessageIter sub2;
+                        uint32_t uid;
+
+                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+                                goto oom;
+
+                        uid = session->user->uid;
+
+                        p = session_bus_path(session);
+                        if (!p)
+                                goto oom;
+
+                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
+                                free(p);
+                                goto oom;
+                        }
+
+                        free(p);
+
+                        if (!dbus_message_iter_close_container(&sub, &sub2))
+                                goto oom;
+                }
+
+                if (!dbus_message_iter_close_container(&iter, &sub))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
+                char *p;
+                User *user;
+                Iterator i;
+                DBusMessageIter iter, sub;
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+                dbus_message_iter_init_append(reply, &iter);
+
+                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
+                        goto oom;
+
+                HASHMAP_FOREACH(user, m->users, i) {
+                        DBusMessageIter sub2;
+                        uint32_t uid;
+
+                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+                                goto oom;
+
+                        uid = user->uid;
+
+                        p = user_bus_path(user);
+                        if (!p)
+                                goto oom;
+
+                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
+                                free(p);
+                                goto oom;
+                        }
+
+                        free(p);
+
+                        if (!dbus_message_iter_close_container(&sub, &sub2))
+                                goto oom;
+                }
+
+                if (!dbus_message_iter_close_container(&iter, &sub))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
+                char *p;
+                Seat *seat;
+                Iterator i;
+                DBusMessageIter iter, sub;
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+                dbus_message_iter_init_append(reply, &iter);
+
+                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
+                        goto oom;
+
+                HASHMAP_FOREACH(seat, m->seats, i) {
+                        DBusMessageIter sub2;
+
+                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+                                goto oom;
+
+                        p = seat_bus_path(seat);
+                        if (!p)
+                                goto oom;
+
+                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
+                                free(p);
+                                goto oom;
+                        }
+
+                        free(p);
+
+                        if (!dbus_message_iter_close_container(&sub, &sub2))
+                                goto oom;
+                }
+
+                if (!dbus_message_iter_close_container(&iter, &sub))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
+
+                r = bus_manager_create_session(m, message, &reply);
+
+                /* Don't delay the work on OOM here, since it might be
+                 * triggered by a low RLIMIT_NOFILE here (since we
+                 * send a dupped fd to the client), and we'd rather
+                 * see this fail quickly then be retried later */
+
+                if (r < 0)
+                        return bus_send_error_reply(connection, message, &error, r);
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
+                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);
+
+                r = session_activate(session);
+                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", "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;
+
+                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);
+
+                r = session_stop(session);
+                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", "TerminateUser")) {
+                uint32_t uid;
+                User *user;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_UINT32, &uid,
+                                    DBUS_TYPE_INVALID))
+                        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_stop(user);
+                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", "TerminateSeat")) {
+                const char *name;
+                Seat *seat;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &name,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                seat = hashmap_get(m->seats, name);
+                if (!seat)
+                        return bus_send_error_reply(connection, message, &error, -ENOENT);
+
+                r = seat_stop_sessions(seat);
+                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", "SetUserLinger")) {
+                uint32_t uid;
+                struct passwd *pw;
+                dbus_bool_t b, interactive;
+                char *path;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_UINT32, &uid,
+                                    DBUS_TYPE_BOOLEAN, &b,
+                                    DBUS_TYPE_BOOLEAN, &interactive,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                errno = 0;
+                pw = getpwuid(uid);
+                if (!pw)
+                        return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
+
+                r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, &error);
+                if (r < 0)
+                        return bus_send_error_reply(connection, message, &error, r);
+
+                r = safe_mkdir("/var/lib/systemd/linger", 0755, 0, 0);
+                if (r < 0)
+                        return bus_send_error_reply(connection, message, &error, r);
+
+                path = strappend("/var/lib/systemd/linger/", pw->pw_name);
+                if (!path)
+                        goto oom;
+
+                if (b) {
+                        User *u;
+
+                        r = touch(path);
+                        free(path);
+
+                        if (r < 0)
+                                return bus_send_error_reply(connection, message, &error, r);
+
+                        if (manager_add_user_by_uid(m, uid, &u) >= 0)
+                                user_start(u);
+
+                } else {
+                        User *u;
+
+                        r = unlink(path);
+                        free(path);
+
+                        if (r < 0 && errno != ENOENT)
+                                return bus_send_error_reply(connection, message, &error, -errno);
+
+                        u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
+                        if (u)
+                                user_add_to_gc_queue(u);
+                }
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
+                const char *sysfs, *seat;
+                dbus_bool_t interactive;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &seat,
+                                    DBUS_TYPE_STRING, &sysfs,
+                                    DBUS_TYPE_BOOLEAN, &interactive,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
+                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
+
+                r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, &error);
+                if (r < 0)
+                        return bus_send_error_reply(connection, message, &error, r);
+
+                r = attach_device(m, seat, sysfs);
+                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.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.login1.Manager", "PowerOff") ||
+                   dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
+                dbus_bool_t interactive;
+                bool multiple_sessions;
+                DBusMessage *forward, *freply;
+                const char *name;
+                const char *mode = "replace";
+                const char *action;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_BOOLEAN, &interactive,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                multiple_sessions = hashmap_size(m->sessions) > 1;
+
+                if (!multiple_sessions) {
+                        Session *s;
+
+                        /* Hmm, there's only one session, but let's
+                         * make sure it actually belongs to the user
+                         * who is asking. If not, better be safe than
+                         * sorry. */
+
+                        s = hashmap_first(m->sessions);
+                        if (s) {
+                                unsigned long ul;
+
+                                ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
+                                if (ul == (unsigned long) -1)
+                                        return bus_send_error_reply(connection, message, &error, -EIO);
+
+                                multiple_sessions = s->user->uid != ul;
+                        }
+                }
+
+                if (streq(dbus_message_get_member(message), "PowerOff")) {
+                        if (multiple_sessions)
+                                action = "org.freedesktop.login1.power-off-multiple-sessions";
+                        else
+                                action = "org.freedesktop.login1.power-off";
+
+                        name = SPECIAL_POWEROFF_TARGET;
+                } else {
+                        if (multiple_sessions)
+                                action = "org.freedesktop.login1.reboot-multiple-sessions";
+                        else
+                                action = "org.freedesktop.login1.reboot";
+
+                        name = SPECIAL_REBOOT_TARGET;
+                }
+
+                r = verify_polkit(connection, message, action, interactive, &error);
+                if (r < 0)
+                        return bus_send_error_reply(connection, message, &error, r);
+
+                forward = dbus_message_new_method_call(
+                              "org.freedesktop.systemd1",
+                              "/org/freedesktop/systemd1",
+                              "org.freedesktop.systemd1.Manager",
+                              "StartUnit");
+                if (!forward)
+                        return bus_send_error_reply(connection, message, NULL, -ENOMEM);
+
+                if (!dbus_message_append_args(forward,
+                                              DBUS_TYPE_STRING, &name,
+                                              DBUS_TYPE_STRING, &mode,
+                                              DBUS_TYPE_INVALID)) {
+                        dbus_message_unref(forward);
+                        return bus_send_error_reply(connection, message, NULL, -ENOMEM);
+                }
+
+                freply = dbus_connection_send_with_reply_and_block(connection, forward, -1, &error);
+                dbus_message_unref(forward);
+
+                if (!freply)
+                        return bus_send_error_reply(connection, message, &error, -EIO);
+
+                dbus_message_unref(freply);
+
+                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;
+                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
+};
+
+DBusHandlerResult bus_message_filter(
+                DBusConnection *connection,
+                DBusMessage *message,
+                void *userdata) {
+
+        Manager *m = userdata;
+        DBusError error;
+
+        assert(m);
+        assert(connection);
+        assert(message);
+
+        dbus_error_init(&error);
+
+        if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
+                const char *cgroup;
+
+                if (!dbus_message_get_args(message, &error,
+                                           DBUS_TYPE_STRING, &cgroup,
+                                           DBUS_TYPE_INVALID))
+                        log_error("Failed to parse Released message: %s", bus_error_message(&error));
+                else
+                        manager_cgroup_notify_empty(m, cgroup);
+        }
+
+        dbus_error_free(&error);
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+int manager_send_changed(Manager *manager, const char *properties) {
+        DBusMessage *m;
+        int r = -ENOMEM;
+
+        assert(manager);
+
+        m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
+        if (!m)
+                goto finish;
+
+        if (!dbus_connection_send(manager->bus, m, NULL))
+                goto finish;
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        return r;
+}
diff --git a/src/login/logind-device.c b/src/login/logind-device.c
new file mode 100644
index 0000000..bbd370f
--- /dev/null
+++ b/src/login/logind-device.c
@@ -0,0 +1,86 @@
+/*-*- 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 <assert.h>
+#include <string.h>
+
+#include "logind-device.h"
+#include "util.h"
+
+Device* device_new(Manager *m, const char *sysfs) {
+        Device *d;
+
+        assert(m);
+        assert(sysfs);
+
+        d = new0(Device, 1);
+        if (!d)
+                return NULL;
+
+        d->sysfs = strdup(sysfs);
+        if (!d->sysfs) {
+                free(d);
+                return NULL;
+        }
+
+        if (hashmap_put(m->devices, d->sysfs, d) < 0) {
+                free(d->sysfs);
+                free(d);
+                return NULL;
+        }
+
+        d->manager = m;
+        dual_timestamp_get(&d->timestamp);
+
+        return d;
+}
+
+void device_free(Device *d) {
+        assert(d);
+
+        device_detach(d);
+
+        hashmap_remove(d->manager->devices, d->sysfs);
+
+        free(d->sysfs);
+        free(d);
+}
+
+void device_detach(Device *d) {
+        assert(d);
+
+        if (d->seat)
+                LIST_REMOVE(Device, devices, d->seat->devices, d);
+
+        seat_add_to_gc_queue(d->seat);
+        d->seat = NULL;
+}
+
+void device_attach(Device *d, Seat *s) {
+        assert(d);
+        assert(s);
+
+        if (d->seat)
+                device_detach(d);
+
+        d->seat = s;
+        LIST_PREPEND(Device, devices, s->devices, d);
+}
diff --git a/src/login/logind-device.h b/src/login/logind-device.h
new file mode 100644
index 0000000..e25a534
--- /dev/null
+++ b/src/login/logind-device.h
@@ -0,0 +1,48 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologinddevicehfoo
+#define foologinddevicehfoo
+
+/***
+  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/>.
+***/
+
+typedef struct Device Device;
+
+#include "list.h"
+#include "util.h"
+#include "logind.h"
+#include "logind-seat.h"
+
+struct Device {
+        Manager *manager;
+
+        char *sysfs;
+        Seat *seat;
+
+        dual_timestamp timestamp;
+
+        LIST_FIELDS(struct Device, devices);
+};
+
+Device* device_new(Manager *m, const char *sysfs);
+void device_free(Device *d);
+void device_attach(Device *d, Seat *s);
+void device_detach(Device *d);
+
+#endif
diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf
new file mode 100644
index 0000000..940fe10
--- /dev/null
+++ b/src/login/logind-gperf.gperf
@@ -0,0 +1,22 @@
+%{
+#include <stddef.h>
+#include "conf-parser.h"
+#include "logind.h"
+%}
+struct ConfigPerfItem;
+%null_strings
+%language=ANSI-C
+%define slot-name section_and_lvalue
+%define hash-function-name logind_gperf_hash
+%define lookup-function-name logind_gperf_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+Login.NAutoVTs,          config_parse_unsigned, 0, offsetof(Manager, n_autovts)
+Login.KillUserProcesses, config_parse_bool,     0, offsetof(Manager, kill_user_processes)
+Login.KillOnlyUsers,     config_parse_strv,     0, offsetof(Manager, kill_only_users)
+Login.KillExcludeUsers,  config_parse_strv,     0, offsetof(Manager, kill_exclude_users)
+Login.Controllers,       config_parse_strv,     0, offsetof(Manager, controllers)
+Login.ResetControllers,  config_parse_strv,     0, offsetof(Manager, reset_controllers)
diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c
new file mode 100644
index 0000000..3a916ee
--- /dev/null
+++ b/src/login/logind-seat-dbus.c
@@ -0,0 +1,403 @@
+/*-*- 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 <string.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"                              \
+        "  <method name=\"ActivateSession\">\n"                         \
+        "   <arg name=\"id\" type=\"s\"/>\n"                            \
+        "  </method>\n"                                                 \
+        "  <property name=\"Id\" type=\"s\" access=\"read\"/>\n"        \
+        "  <property name=\"ActiveSession\" type=\"so\" access=\"read\"/>\n" \
+        "  <property name=\"CanMultiSession\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
+        "  <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n"  \
+        "  <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"IdleSinceHintMonotonic\" type=\"t\" 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 bus_seat_append_multi_session(DBusMessageIter *i, const char *property, void *data) {
+        Seat *s = data;
+        dbus_bool_t b;
+
+        assert(i);
+        assert(property);
+        assert(s);
+
+        b = seat_is_vtconsole(s);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_seat_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
+        Seat *s = data;
+        dbus_bool_t b;
+
+        assert(i);
+        assert(property);
+        assert(s);
+
+        b = seat_get_idle_hint(s, NULL) > 0;
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_seat_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
+        Seat *s = data;
+        dual_timestamp t;
+        uint64_t k;
+
+        assert(i);
+        assert(property);
+        assert(s);
+
+        seat_get_idle_hint(s, &t);
+        k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k))
+                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", "ActiveSession",          bus_seat_append_active,          "(so)",  s     },
+                { "org.freedesktop.login1.Seat", "CanMultiSession",        bus_seat_append_multi_session,   "b",     s     },
+                { "org.freedesktop.login1.Seat", "Sessions",               bus_seat_append_sessions,        "a(so)", s     },
+                { "org.freedesktop.login1.Seat", "IdleHint",               bus_seat_append_idle_hint,       "b",     s     },
+                { "org.freedesktop.login1.Seat", "IdleSinceHint",          bus_seat_append_idle_hint_since, "t",     s     },
+                { "org.freedesktop.login1.Seat", "IdleSinceHintMonotonic", bus_seat_append_idle_hint_since, "t",     s     },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        DBusError error;
+        DBusMessage *reply = NULL;
+        int r;
+
+        assert(s);
+        assert(connection);
+        assert(message);
+
+        dbus_error_init(&error);
+
+        if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "Terminate")) {
+
+                r = seat_stop_sessions(s);
+                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.Seat", "ActivateSession")) {
+                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(s->manager->sessions, name);
+                if (!session || session->seat != s)
+                        return bus_send_error_reply(connection, message, &error, -ENOENT);
+
+                r = session_activate(session);
+                if (r < 0)
+                        return bus_send_error_reply(connection, message, NULL, r);
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+        } else
+                return bus_default_message_handler(connection, message, INTROSPECTION, 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;
+}
+
+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;
+}
+
+int seat_send_signal(Seat *s, bool new_seat) {
+        DBusMessage *m;
+        int r = -ENOMEM;
+        char *p = NULL;
+
+        assert(s);
+
+        m = dbus_message_new_signal("/org/freedesktop/login1",
+                                    "org.freedesktop.login1.Manager",
+                                    new_seat ? "SeatNew" : "SeatRemoved");
+
+        if (!m)
+                return -ENOMEM;
+
+        p = seat_bus_path(s);
+        if (!p)
+                goto finish;
+
+        if (!dbus_message_append_args(
+                            m,
+                            DBUS_TYPE_STRING, &s->id,
+                            DBUS_TYPE_OBJECT_PATH, &p,
+                            DBUS_TYPE_INVALID))
+                goto finish;
+
+        if (!dbus_connection_send(s->manager->bus, m, NULL))
+                goto finish;
+
+        r = 0;
+
+finish:
+        dbus_message_unref(m);
+        free(p);
+
+        return r;
+}
+
+int seat_send_changed(Seat *s, const char *properties) {
+        DBusMessage *m;
+        int r = -ENOMEM;
+        char *p = NULL;
+
+        assert(s);
+
+        if (!s->started)
+                return 0;
+
+        p = seat_bus_path(s);
+        if (!p)
+                return -ENOMEM;
+
+        m = bus_properties_changed_new(p, "org.freedesktop.login1.Seat", properties);
+        if (!m)
+                goto finish;
+
+        if (!dbus_connection_send(s->manager->bus, m, NULL))
+                goto finish;
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+        free(p);
+
+        return r;
+}
diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c
new file mode 100644
index 0000000..3cf3958
--- /dev/null
+++ b/src/login/logind-seat.c
@@ -0,0 +1,499 @@
+/*-*- 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 <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/vt.h>
+#include <string.h>
+
+#include "logind-seat.h"
+#include "logind-acl.h"
+#include "util.h"
+
+Seat *seat_new(Manager *m, const char *id) {
+        Seat *s;
+
+        assert(m);
+        assert(id);
+
+        s = new0(Seat, 1);
+        if (!s)
+                return NULL;
+
+        s->state_file = strappend("/run/systemd/seats/", id);
+        if (!s->state_file) {
+                free(s);
+                return NULL;
+        }
+
+        s->id = file_name_from_path(s->state_file);
+        s->manager = m;
+
+        if (hashmap_put(m->seats, s->id, s) < 0) {
+                free(s->state_file);
+                free(s);
+                return NULL;
+        }
+
+        return s;
+}
+
+void seat_free(Seat *s) {
+        assert(s);
+
+        if (s->in_gc_queue)
+                LIST_REMOVE(Seat, gc_queue, s->manager->seat_gc_queue, s);
+
+        while (s->sessions)
+                session_free(s->sessions);
+
+        assert(!s->active);
+
+        while (s->devices)
+                device_free(s->devices);
+
+        hashmap_remove(s->manager->seats, s->id);
+
+        free(s->state_file);
+        free(s);
+}
+
+int seat_save(Seat *s) {
+        int r;
+        FILE *f;
+        char *temp_path;
+
+        assert(s);
+
+        if (!s->started)
+                return 0;
+
+        r = safe_mkdir("/run/systemd/seats", 0755, 0, 0);
+        if (r < 0)
+                goto finish;
+
+        r = fopen_temporary(s->state_file, &f, &temp_path);
+        if (r < 0)
+                goto finish;
+
+        fchmod(fileno(f), 0644);
+
+        fprintf(f,
+                "# This is private data. Do not parse.\n"
+                "IS_VTCONSOLE=%i\n",
+                seat_is_vtconsole(s));
+
+        if (s->active) {
+                assert(s->active->user);
+
+                fprintf(f,
+                        "ACTIVE=%s\n"
+                        "ACTIVE_UID=%lu\n",
+                        s->active->id,
+                        (unsigned long) s->active->user->uid);
+        }
+
+        if (s->sessions) {
+                Session *i;
+
+                fputs("SESSIONS=", f);
+                LIST_FOREACH(sessions_by_seat, i, s->sessions) {
+                        fprintf(f,
+                                "%s%c",
+                                i->id,
+                                i->sessions_by_seat_next ? ' ' : '\n');
+                }
+
+                fputs("UIDS=", f);
+                LIST_FOREACH(sessions_by_seat, i, s->sessions)
+                        fprintf(f,
+                                "%lu%c",
+                                (unsigned long) i->user->uid,
+                                i->sessions_by_seat_next ? ' ' : '\n');
+        }
+
+        fflush(f);
+
+        if (ferror(f) || rename(temp_path, s->state_file) < 0) {
+                r = -errno;
+                unlink(s->state_file);
+                unlink(temp_path);
+        }
+
+        fclose(f);
+        free(temp_path);
+
+finish:
+        if (r < 0)
+                log_error("Failed to save seat data for %s: %s", s->id, strerror(-r));
+
+        return r;
+}
+
+int seat_load(Seat *s) {
+        assert(s);
+
+        /* There isn't actually anything to read here ... */
+
+        return 0;
+}
+
+static int vt_allocate(int vtnr) {
+        int fd, r;
+        char *p;
+
+        assert(vtnr >= 1);
+
+        if (asprintf(&p, "/dev/tty%i", vtnr) < 0)
+                return -ENOMEM;
+
+        fd = open_terminal(p, O_RDWR|O_NOCTTY|O_CLOEXEC);
+        free(p);
+
+        r = fd < 0 ? -errno : 0;
+
+        if (fd >= 0)
+                close_nointr_nofail(fd);
+
+        return r;
+}
+
+int seat_preallocate_vts(Seat *s) {
+        int r = 0;
+        unsigned i;
+
+        assert(s);
+        assert(s->manager);
+
+        log_debug("Preallocating VTs...");
+
+        if (s->manager->n_autovts <= 0)
+                return 0;
+
+        if (!seat_is_vtconsole(s))
+                return 0;
+
+        for (i = 1; i <= s->manager->n_autovts; i++) {
+                int q;
+
+                q = vt_allocate(i);
+                if (q < 0) {
+                        log_error("Failed to preallocate VT %i: %s", i, strerror(-q));
+                        r = q;
+                }
+        }
+
+        return r;
+}
+
+int seat_apply_acls(Seat *s, Session *old_active) {
+        int r;
+
+        assert(s);
+
+        r = devnode_acl_all(s->manager->udev,
+                            s->id,
+                            false,
+                            !!old_active, old_active ? old_active->user->uid : 0,
+                            !!s->active, s->active ? s->active->user->uid : 0);
+
+        if (r < 0)
+                log_error("Failed to apply ACLs: %s", strerror(-r));
+
+        return r;
+}
+
+int seat_set_active(Seat *s, Session *session) {
+        Session *old_active;
+
+        assert(s);
+        assert(!session || session->seat == s);
+
+        if (session == s->active)
+                return 0;
+
+        old_active = s->active;
+        s->active = session;
+
+        seat_apply_acls(s, old_active);
+
+        if (session && session->started)
+                session_send_changed(session, "Active\0");
+
+        if (!session || session->started)
+                seat_send_changed(s, "ActiveSession\0");
+
+        seat_save(s);
+
+        if (session) {
+                session_save(session);
+                user_save(session->user);
+        }
+
+        if (old_active) {
+                session_save(old_active);
+                user_save(old_active->user);
+        }
+
+        return 0;
+}
+
+int seat_active_vt_changed(Seat *s, int vtnr) {
+        Session *i, *new_active = NULL;
+        int r;
+
+        assert(s);
+        assert(vtnr >= 1);
+
+        if (!seat_is_vtconsole(s))
+                return -EINVAL;
+
+        log_debug("VT changed to %i", vtnr);
+
+        LIST_FOREACH(sessions_by_seat, i, s->sessions)
+                if (i->vtnr == vtnr) {
+                        new_active = i;
+                        break;
+                }
+
+        r = seat_set_active(s, new_active);
+        manager_spawn_autovt(s->manager, vtnr);
+
+        return r;
+}
+
+int seat_read_active_vt(Seat *s) {
+        char t[64];
+        ssize_t k;
+        int r, vtnr;
+
+        assert(s);
+
+        if (!seat_is_vtconsole(s))
+                return 0;
+
+        lseek(s->manager->console_active_fd, SEEK_SET, 0);
+
+        k = read(s->manager->console_active_fd, t, sizeof(t)-1);
+        if (k <= 0) {
+                log_error("Failed to read current console: %s", k < 0 ? strerror(-errno) : "EOF");
+                return k < 0 ? -errno : -EIO;
+        }
+
+        t[k] = 0;
+        truncate_nl(t);
+
+        if (!startswith(t, "tty")) {
+                log_error("Hm, /sys/class/tty/tty0/active is badly formatted.");
+                return -EIO;
+        }
+
+        r = safe_atoi(t+3, &vtnr);
+        if (r < 0) {
+                log_error("Failed to parse VT number %s", t+3);
+                return r;
+        }
+
+        if (vtnr <= 0) {
+                log_error("VT number invalid: %s", t+3);
+                return -EIO;
+        }
+
+        return seat_active_vt_changed(s, vtnr);
+}
+
+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);
+
+        /* Read current VT */
+        seat_read_active_vt(s);
+
+        s->started = true;
+
+        /* Save seat data */
+        seat_save(s);
+
+        seat_send_signal(s, true);
+
+        return 0;
+}
+
+int seat_stop(Seat *s) {
+        int r = 0;
+
+        assert(s);
+
+        if (s->started)
+                log_info("Removed seat %s.", s->id);
+
+        seat_stop_sessions(s);
+
+        unlink(s->state_file);
+        seat_add_to_gc_queue(s);
+
+        if (s->started)
+                seat_send_signal(s, false);
+
+        s->started = false;
+
+        return r;
+}
+
+int seat_stop_sessions(Seat *s) {
+        Session *session;
+        int r = 0, k;
+
+        assert(s);
+
+        LIST_FOREACH(sessions_by_seat, session, s->sessions) {
+                k = session_stop(session);
+                if (k < 0)
+                        r = k;
+        }
+
+        return r;
+}
+
+int seat_attach_session(Seat *s, Session *session) {
+        assert(s);
+        assert(session);
+        assert(!session->seat);
+
+        if (!seat_is_vtconsole(s) && s->sessions)
+                return -EEXIST;
+
+        session->seat = s;
+        LIST_PREPEND(Session, sessions_by_seat, s->sessions, session);
+
+        seat_send_changed(s, "Sessions\0");
+
+        if (!seat_is_vtconsole(s)) {
+                assert(!s->active);
+                seat_set_active(s, session);
+        }
+
+        return 0;
+}
+
+bool seat_is_vtconsole(Seat *s) {
+        assert(s);
+
+        return s->manager->vtconsole == s;
+}
+
+int seat_get_idle_hint(Seat *s, dual_timestamp *t) {
+        Session *session;
+        bool idle_hint = true;
+        dual_timestamp ts = { 0, 0 };
+
+        assert(s);
+
+        LIST_FOREACH(sessions_by_seat, session, s->sessions) {
+                dual_timestamp k;
+                int ih;
+
+                ih = session_get_idle_hint(session, &k);
+                if (ih < 0)
+                        return ih;
+
+                if (!ih) {
+                        if (!idle_hint) {
+                                if (k.monotonic < ts.monotonic)
+                                        ts = k;
+                        } else {
+                                idle_hint = false;
+                                ts = k;
+                        }
+                } else if (idle_hint) {
+
+                        if (k.monotonic > ts.monotonic)
+                                ts = k;
+                }
+        }
+
+        if (t)
+                *t = ts;
+
+        return idle_hint;
+}
+
+int seat_check_gc(Seat *s, bool drop_not_started) {
+        assert(s);
+
+        if (drop_not_started && !s->started)
+                return 0;
+
+        if (seat_is_vtconsole(s))
+                return 1;
+
+        return !!s->devices;
+}
+
+void seat_add_to_gc_queue(Seat *s) {
+        assert(s);
+
+        if (s->in_gc_queue)
+                return;
+
+        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;
+
+        if (strlen(name) > 255)
+                return false;
+
+        return true;
+}
diff --git a/src/login/logind-seat.h b/src/login/logind-seat.h
new file mode 100644
index 0000000..5bce143
--- /dev/null
+++ b/src/login/logind-seat.h
@@ -0,0 +1,82 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologindseathfoo
+#define foologindseathfoo
+
+/***
+  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/>.
+***/
+
+typedef struct Seat Seat;
+
+#include "list.h"
+#include "util.h"
+#include "logind.h"
+#include "logind-device.h"
+#include "logind-session.h"
+
+struct Seat {
+        Manager *manager;
+        char *id;
+
+        char *state_file;
+
+        LIST_HEAD(Device, devices);
+
+        Session *active;
+        LIST_HEAD(Session, sessions);
+
+        bool in_gc_queue:1;
+        bool started:1;
+
+        LIST_FIELDS(Seat, gc_queue);
+};
+
+Seat *seat_new(Manager *m, const char *id);
+void seat_free(Seat *s);
+
+int seat_save(Seat *s);
+int seat_load(Seat *s);
+
+int seat_apply_acls(Seat *s, Session *old_active);
+int seat_set_active(Seat *s, Session *session);
+int seat_active_vt_changed(Seat *s, int vtnr);
+int seat_read_active_vt(Seat *s);
+int seat_preallocate_vts(Seat *s);
+
+int seat_attach_session(Seat *s, Session *session);
+
+bool seat_is_vtconsole(Seat *s);
+int seat_get_idle_hint(Seat *s, dual_timestamp *t);
+
+int seat_start(Seat *s);
+int seat_stop(Seat *s);
+int seat_stop_sessions(Seat *s);
+
+int seat_check_gc(Seat *s, bool drop_not_started);
+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;
+
+int seat_send_signal(Seat *s, bool new_seat);
+int seat_send_changed(Seat *s, const char *properties);
+
+#endif
diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
new file mode 100644
index 0000000..dc0ef5b
--- /dev/null
+++ b/src/login/logind-session-dbus.c
@@ -0,0 +1,515 @@
+/*-*- 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 <string.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"                               \
+        "  <method name=\"Lock\"/>\n"                                   \
+        "  <method name=\"Unlock\"/>\n"                                 \
+        "  <method name=\"SetIdleHint\">\n"                             \
+        "   <arg name=\"b\" type=\"b\"/>\n"                             \
+        "  </method>\n"                                                 \
+        "  <method name=\"Kill\">\n"                                    \
+        "   <arg name=\"who\" type=\"s\"/>\n"                           \
+        "   <arg name=\"signal\" type=\"s\"/>\n"                        \
+        "  </method>\n"                                                 \
+        "  <property name=\"Id\" type=\"s\" access=\"read\"/>\n"        \
+        "  <property name=\"User\" type=\"(uo)\" access=\"read\"/>\n"   \
+        "  <property name=\"Name\" type=\"s\" access=\"read\"/>\n"      \
+        "  <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"TimestampMonotonic\" type=\"t\" 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=\"Service\" 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" \
+        "  <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n"  \
+        "  <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"IdleSinceHintMonotonic\" type=\"t\" 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;
+        dbus_bool_t 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 int bus_session_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
+        Session *s = data;
+        int b;
+
+        assert(i);
+        assert(property);
+        assert(s);
+
+        b = session_get_idle_hint(s, NULL) > 0;
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_session_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
+        Session *s = data;
+        dual_timestamp t;
+        uint64_t u;
+
+        assert(i);
+        assert(property);
+        assert(s);
+
+        session_get_idle_hint(s, &t);
+        u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
+                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", "Timestamp",          bus_property_append_usec,     "t",    &s->timestamp.realtime  },
+                { "org.freedesktop.login1.Session", "TimestampMonotonic", bus_property_append_usec,     "t",    &s->timestamp.monotonic },
+                { "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", "Service",            bus_property_append_string,   "s",    s->service              },
+                { "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      },
+                { "org.freedesktop.login1.Session", "IdleHint",           bus_session_append_idle_hint, "b",    s                       },
+                { "org.freedesktop.login1.Session", "IdleSinceHint",          bus_session_append_idle_hint_since, "t", s                },
+                { "org.freedesktop.login1.Session", "IdleSinceHintMonotonic", bus_session_append_idle_hint_since, "t", s                },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        DBusError error;
+        DBusMessage *reply = NULL;
+        int r;
+
+        assert(s);
+        assert(connection);
+        assert(message);
+
+        dbus_error_init(&error);
+
+        if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Terminate")) {
+
+                r = session_stop(s);
+                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.Session", "Activate")) {
+
+                r = session_activate(s);
+                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.Session", "Lock") ||
+                   dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Unlock")) {
+
+                if (session_send_signal(s, streq(dbus_message_get_member(message), "Lock")) < 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.Session", "SetIdleHint")) {
+                dbus_bool_t b;
+                unsigned long ul;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_BOOLEAN, &b,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
+                if (ul == (unsigned long) -1)
+                        return bus_send_error_reply(connection, message, &error, -EIO);
+
+                if (ul != 0 && ul != s->user->uid)
+                        return bus_send_error_reply(connection, message, NULL, -EPERM);
+
+                session_set_idle_hint(s, b);
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "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);
+
+                r = session_kill(s, 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
+                return bus_default_message_handler(connection, message, INTROSPECTION, 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;
+}
+
+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;
+}
+
+int session_send_signal(Session *s, bool new_session) {
+        DBusMessage *m;
+        int r = -ENOMEM;
+        char *p = NULL;
+
+        assert(s);
+
+        m = dbus_message_new_signal("/org/freedesktop/login1",
+                                    "org.freedesktop.login1.Manager",
+                                    new_session ? "SessionNew" : "SessionRemoved");
+
+        if (!m)
+                return -ENOMEM;
+
+        p = session_bus_path(s);
+        if (!p)
+                goto finish;
+
+        if (!dbus_message_append_args(
+                            m,
+                            DBUS_TYPE_STRING, &s->id,
+                            DBUS_TYPE_OBJECT_PATH, &p,
+                            DBUS_TYPE_INVALID))
+                goto finish;
+
+        if (!dbus_connection_send(s->manager->bus, m, NULL))
+                goto finish;
+
+        r = 0;
+
+finish:
+        dbus_message_unref(m);
+        free(p);
+
+        return r;
+}
+
+int session_send_changed(Session *s, const char *properties) {
+        DBusMessage *m;
+        int r = -ENOMEM;
+        char *p = NULL;
+
+        assert(s);
+
+        if (!s->started)
+                return 0;
+
+        p = session_bus_path(s);
+        if (!p)
+                return -ENOMEM;
+
+        m = bus_properties_changed_new(p, "org.freedesktop.login1.Session", properties);
+        if (!m)
+                goto finish;
+
+        if (!dbus_connection_send(s->manager->bus, m, NULL))
+                goto finish;
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+        free(p);
+
+        return r;
+}
+
+int session_send_lock(Session *s, bool lock) {
+        DBusMessage *m;
+        bool b;
+        char *p;
+
+        assert(s);
+
+        p = session_bus_path(s);
+        if (!p)
+                return -ENOMEM;
+
+        m = dbus_message_new_signal(p, "org.freedesktop.login1.Session", lock ? "Lock" : "Unlock");
+        free(p);
+
+        if (!m)
+                return -ENOMEM;
+
+        b = dbus_connection_send(s->manager->bus, m, NULL);
+        dbus_message_unref(m);
+
+        if (!b)
+                return -ENOMEM;
+
+        return 0;
+}
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
new file mode 100644
index 0000000..63ee758
--- /dev/null
+++ b/src/login/logind-session.c
@@ -0,0 +1,945 @@
+/*-*- 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 <string.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <fcntl.h>
+
+#include "logind-session.h"
+#include "strv.h"
+#include "util.h"
+#include "cgroup-util.h"
+
+#define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
+
+Session* session_new(Manager *m, User *u, const char *id) {
+        Session *s;
+
+        assert(m);
+        assert(id);
+
+        s = new0(Session, 1);
+        if (!s)
+                return NULL;
+
+        s->state_file = strappend("/run/systemd/sessions/", id);
+        if (!s->state_file) {
+                free(s);
+                return NULL;
+        }
+
+        s->id = file_name_from_path(s->state_file);
+
+        if (hashmap_put(m->sessions, s->id, s) < 0) {
+                free(s->id);
+                free(s);
+                return NULL;
+        }
+
+        s->manager = m;
+        s->fifo_fd = -1;
+        s->user = u;
+
+        LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
+
+        return s;
+}
+
+void session_free(Session *s) {
+        assert(s);
+
+        if (s->in_gc_queue)
+                LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
+
+        if (s->user) {
+                LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
+
+                if (s->user->display == s)
+                        s->user->display = NULL;
+        }
+
+        if (s->seat) {
+                if (s->seat->active == s)
+                        s->seat->active = NULL;
+
+                LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
+        }
+
+        if (s->cgroup_path)
+                hashmap_remove(s->manager->cgroups, s->cgroup_path);
+
+        free(s->cgroup_path);
+        strv_free(s->controllers);
+
+        free(s->tty);
+        free(s->display);
+        free(s->remote_host);
+        free(s->remote_user);
+        free(s->service);
+
+        hashmap_remove(s->manager->sessions, s->id);
+
+        session_remove_fifo(s);
+
+        free(s->state_file);
+        free(s);
+}
+
+int session_save(Session *s) {
+        FILE *f;
+        int r = 0;
+        char *temp_path;
+
+        assert(s);
+
+        if (!s->started)
+                return 0;
+
+        r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
+        if (r < 0)
+                goto finish;
+
+        r = fopen_temporary(s->state_file, &f, &temp_path);
+        if (r < 0)
+                goto finish;
+
+        assert(s->user);
+
+        fchmod(fileno(f), 0644);
+
+        fprintf(f,
+                "# This is private data. Do not parse.\n"
+                "UID=%lu\n"
+                "USER=%s\n"
+                "ACTIVE=%i\n"
+                "REMOTE=%i\n"
+                "KILL_PROCESSES=%i\n",
+                (unsigned long) s->user->uid,
+                s->user->name,
+                session_is_active(s),
+                s->remote,
+                s->kill_processes);
+
+        if (s->type >= 0)
+                fprintf(f,
+                        "TYPE=%s\n",
+                        session_type_to_string(s->type));
+
+        if (s->cgroup_path)
+                fprintf(f,
+                        "CGROUP=%s\n",
+                        s->cgroup_path);
+
+        if (s->fifo_path)
+                fprintf(f,
+                        "FIFO=%s\n",
+                        s->fifo_path);
+
+        if (s->seat)
+                fprintf(f,
+                        "SEAT=%s\n",
+                        s->seat->id);
+
+        if (s->tty)
+                fprintf(f,
+                        "TTY=%s\n",
+                        s->tty);
+
+        if (s->display)
+                fprintf(f,
+                        "DISPLAY=%s\n",
+                        s->display);
+
+        if (s->remote_host)
+                fprintf(f,
+                        "REMOTE_HOST=%s\n",
+                        s->remote_host);
+
+        if (s->remote_user)
+                fprintf(f,
+                        "REMOTE_USER=%s\n",
+                        s->remote_user);
+
+        if (s->service)
+                fprintf(f,
+                        "SERVICE=%s\n",
+                        s->service);
+
+        if (s->seat && seat_is_vtconsole(s->seat))
+                fprintf(f,
+                        "VTNR=%i\n",
+                        s->vtnr);
+
+        if (s->leader > 0)
+                fprintf(f,
+                        "LEADER=%lu\n",
+                        (unsigned long) s->leader);
+
+        if (s->audit_id > 0)
+                fprintf(f,
+                        "AUDIT=%llu\n",
+                        (unsigned long long) s->audit_id);
+
+        fflush(f);
+
+        if (ferror(f) || rename(temp_path, s->state_file) < 0) {
+                r = -errno;
+                unlink(s->state_file);
+                unlink(temp_path);
+        }
+
+        fclose(f);
+        free(temp_path);
+
+finish:
+        if (r < 0)
+                log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
+
+        return r;
+}
+
+int session_load(Session *s) {
+        char *remote = NULL,
+                *kill_processes = NULL,
+                *seat = NULL,
+                *vtnr = NULL,
+                *leader = NULL,
+                *audit_id = NULL,
+                *type = NULL;
+
+        int k, r;
+
+        assert(s);
+
+        r = parse_env_file(s->state_file, NEWLINE,
+                           "REMOTE",         &remote,
+                           "KILL_PROCESSES", &kill_processes,
+                           "CGROUP",         &s->cgroup_path,
+                           "FIFO",           &s->fifo_path,
+                           "SEAT",           &seat,
+                           "TTY",            &s->tty,
+                           "DISPLAY",        &s->display,
+                           "REMOTE_HOST",    &s->remote_host,
+                           "REMOTE_USER",    &s->remote_user,
+                           "SERVICE",        &s->service,
+                           "VTNR",           &vtnr,
+                           "LEADER",         &leader,
+                           "TYPE",           &type,
+                           NULL);
+
+        if (r < 0)
+                goto finish;
+
+        if (remote) {
+                k = parse_boolean(remote);
+                if (k >= 0)
+                        s->remote = k;
+        }
+
+        if (kill_processes) {
+                k = parse_boolean(kill_processes);
+                if (k >= 0)
+                        s->kill_processes = k;
+        }
+
+        if (seat && !s->seat) {
+                Seat *o;
+
+                o = hashmap_get(s->manager->seats, seat);
+                if (o)
+                        seat_attach_session(o, s);
+        }
+
+        if (vtnr && s->seat && seat_is_vtconsole(s->seat)) {
+                int v;
+
+                k = safe_atoi(vtnr, &v);
+                if (k >= 0 && v >= 1)
+                        s->vtnr = v;
+        }
+
+        if (leader) {
+                pid_t pid;
+
+                k = parse_pid(leader, &pid);
+                if (k >= 0 && pid >= 1) {
+                        s->leader = pid;
+
+                        audit_session_from_pid(pid, &s->audit_id);
+                }
+        }
+
+        if (type) {
+                SessionType t;
+
+                t = session_type_from_string(type);
+                if (t >= 0)
+                        s->type = t;
+        }
+
+        if (s->fifo_path) {
+                int fd;
+
+                /* If we open an unopened pipe for reading we will not
+                   get an EOF. to trigger an EOF we hence open it for
+                   reading, but close it right-away which then will
+                   trigger the EOF. */
+
+                fd = session_create_fifo(s);
+                if (fd >= 0)
+                        close_nointr_nofail(fd);
+        }
+
+
+finish:
+        free(remote);
+        free(kill_processes);
+        free(seat);
+        free(vtnr);
+        free(leader);
+        free(audit_id);
+
+        return r;
+}
+
+int session_activate(Session *s) {
+        int r;
+        Session *old_active;
+
+        assert(s);
+
+        if (s->vtnr < 0)
+                return -ENOTSUP;
+
+        if (!s->seat)
+                return -ENOTSUP;
+
+        if (s->seat->active == s)
+                return 0;
+
+        assert(seat_is_vtconsole(s->seat));
+
+        r = chvt(s->vtnr);
+        if (r < 0)
+                return r;
+
+        old_active = s->seat->active;
+        s->seat->active = s;
+
+        return seat_apply_acls(s->seat, old_active);
+}
+
+static int session_link_x11_socket(Session *s) {
+        char *t, *f, *c;
+        size_t k;
+
+        assert(s);
+        assert(s->user);
+        assert(s->user->runtime_path);
+
+        if (s->user->display)
+                return 0;
+
+        if (!s->display || !display_is_local(s->display))
+                return 0;
+
+        k = strspn(s->display+1, "0123456789");
+        f = new(char, sizeof("/tmp/.X11-unix/X") + k);
+        if (!f) {
+                log_error("Out of memory");
+                return -ENOMEM;
+        }
+
+        c = stpcpy(f, "/tmp/.X11-unix/X");
+        memcpy(c, s->display+1, k);
+        c[k] = 0;
+
+        if (access(f, F_OK) < 0) {
+                log_warning("Session %s has display %s with nonexisting socket %s.", s->id, s->display, f);
+                free(f);
+                return -ENOENT;
+        }
+
+        t = strappend(s->user->runtime_path, "/X11/display");
+        if (!t) {
+                log_error("Out of memory");
+                free(f);
+                return -ENOMEM;
+        }
+
+        mkdir_parents(t, 0755);
+
+        if (link(f, t) < 0) {
+                if (errno == EEXIST) {
+                        unlink(t);
+
+                        if (link(f, t) >= 0)
+                                goto done;
+                }
+
+                if (symlink(f, t) < 0) {
+
+                        if (errno == EEXIST) {
+                                unlink(t);
+
+                                if (symlink(f, t) >= 0)
+                                        goto done;
+                        }
+
+                        log_error("Failed to link %s to %s: %m", f, t);
+                        free(f);
+                        free(t);
+                        return -errno;
+                }
+        }
+
+done:
+        log_info("Linked %s to %s.", f, t);
+        free(f);
+        free(t);
+
+        s->user->display = s;
+
+        return 0;
+}
+
+static int session_create_one_group(Session *s, const char *controller, const char *path) {
+        int r;
+
+        assert(s);
+        assert(controller);
+        assert(path);
+
+        if (s->leader > 0) {
+                r = cg_create_and_attach(controller, path, s->leader);
+                if (r < 0)
+                        r = cg_create(controller, path);
+        } else
+                r = cg_create(controller, path);
+
+        if (r < 0)
+                return r;
+
+        r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid);
+        if (r >= 0)
+                r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
+
+        return r;
+}
+
+static int session_create_cgroup(Session *s) {
+        char **k;
+        char *p;
+        int r;
+
+        assert(s);
+        assert(s->user);
+        assert(s->user->cgroup_path);
+
+        if (!s->cgroup_path) {
+                if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0) {
+                        log_error("Out of memory");
+                        return -ENOMEM;
+                }
+        } else
+                p = s->cgroup_path;
+
+        r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
+        if (r < 0) {
+                log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
+                free(p);
+                s->cgroup_path = NULL;
+                return r;
+        }
+
+        s->cgroup_path = p;
+
+        STRV_FOREACH(k, s->controllers) {
+
+                if (strv_contains(s->reset_controllers, *k))
+                        continue;
+
+                r = session_create_one_group(s, *k, p);
+                if (r < 0)
+                        log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
+        }
+
+        STRV_FOREACH(k, s->manager->controllers) {
+
+                if (strv_contains(s->reset_controllers, *k) ||
+                    strv_contains(s->manager->reset_controllers, *k) ||
+                    strv_contains(s->controllers, *k))
+                        continue;
+
+                r = session_create_one_group(s, *k, p);
+                if (r < 0)
+                        log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
+        }
+
+        if (s->leader > 0) {
+
+                STRV_FOREACH(k, s->reset_controllers) {
+                        r = cg_attach(*k, "/", s->leader);
+                        if (r < 0)
+                                log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
+
+                }
+
+                STRV_FOREACH(k, s->manager->reset_controllers) {
+
+                        if (strv_contains(s->reset_controllers, *k) ||
+                            strv_contains(s->controllers, *k))
+                                continue;
+
+                        r = cg_attach(*k, "/", s->leader);
+                        if (r < 0)
+                                log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
+
+                }
+        }
+
+        hashmap_put(s->manager->cgroups, s->cgroup_path, s);
+
+        return 0;
+}
+
+int session_start(Session *s) {
+        int r;
+
+        assert(s);
+        assert(s->user);
+
+        if (s->started)
+                return 0;
+
+        r = user_start(s->user);
+        if (r < 0)
+                return r;
+
+        log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
+                 "New session %s of user %s.", s->id, s->user->name);
+
+        /* Create cgroup */
+        r = session_create_cgroup(s);
+        if (r < 0)
+                return r;
+
+        /* Create X11 symlink */
+        session_link_x11_socket(s);
+
+        dual_timestamp_get(&s->timestamp);
+
+        if (s->seat)
+                seat_read_active_vt(s->seat);
+
+        s->started = true;
+
+        /* Save session data */
+        session_save(s);
+        user_save(s->user);
+
+        session_send_signal(s, true);
+
+        if (s->seat) {
+                seat_save(s->seat);
+
+                if (s->seat->active == s)
+                        seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
+                else
+                        seat_send_changed(s->seat, "Sessions\0");
+        }
+
+        user_send_changed(s->user, "Sessions\0");
+
+        return 0;
+}
+
+static bool session_shall_kill(Session *s) {
+        assert(s);
+
+        if (!s->kill_processes)
+                return false;
+
+        if (strv_contains(s->manager->kill_exclude_users, s->user->name))
+                return false;
+
+        if (strv_isempty(s->manager->kill_only_users))
+                return true;
+
+        return strv_contains(s->manager->kill_only_users, s->user->name);
+}
+
+static int session_terminate_cgroup(Session *s) {
+        int r;
+        char **k;
+
+        assert(s);
+
+        if (!s->cgroup_path)
+                return 0;
+
+        cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
+
+        if (session_shall_kill(s)) {
+
+                r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
+                if (r < 0)
+                        log_error("Failed to kill session cgroup: %s", strerror(-r));
+
+        } else {
+                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
+                if (r < 0)
+                        log_error("Failed to check session cgroup: %s", strerror(-r));
+                else if (r > 0) {
+                        r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
+                        if (r < 0)
+                                log_error("Failed to delete session cgroup: %s", strerror(-r));
+                } else
+                        r = -EBUSY;
+        }
+
+        STRV_FOREACH(k, s->user->manager->controllers)
+                cg_trim(*k, s->cgroup_path, true);
+
+        hashmap_remove(s->manager->cgroups, s->cgroup_path);
+
+        free(s->cgroup_path);
+        s->cgroup_path = NULL;
+
+        return r;
+}
+
+static int session_unlink_x11_socket(Session *s) {
+        char *t;
+        int r;
+
+        assert(s);
+        assert(s->user);
+
+        if (s->user->display != s)
+                return 0;
+
+        s->user->display = NULL;
+
+        t = strappend(s->user->runtime_path, "/X11/display");
+        if (!t) {
+                log_error("Out of memory");
+                return -ENOMEM;
+        }
+
+        r = unlink(t);
+        free(t);
+
+        return r < 0 ? -errno : 0;
+}
+
+int session_stop(Session *s) {
+        int r = 0, k;
+
+        assert(s);
+
+        if (s->started)
+                log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
+                         "Removed session %s.", s->id);
+
+        /* Kill cgroup */
+        k = session_terminate_cgroup(s);
+        if (k < 0)
+                r = k;
+
+        /* Remove X11 symlink */
+        session_unlink_x11_socket(s);
+
+        unlink(s->state_file);
+        session_add_to_gc_queue(s);
+        user_add_to_gc_queue(s->user);
+
+        if (s->started)
+                session_send_signal(s, false);
+
+        if (s->seat) {
+                if (s->seat->active == s)
+                        seat_set_active(s->seat, NULL);
+
+                seat_send_changed(s->seat, "Sessions\0");
+        }
+
+        user_send_changed(s->user, "Sessions\0");
+
+        s->started = false;
+
+        return r;
+}
+
+bool session_is_active(Session *s) {
+        assert(s);
+
+        if (!s->seat)
+                return true;
+
+        return s->seat->active == s;
+}
+
+int session_get_idle_hint(Session *s, dual_timestamp *t) {
+        char *p;
+        struct stat st;
+        usec_t u, n;
+        bool b;
+        int k;
+
+        assert(s);
+
+        if (s->idle_hint) {
+                if (t)
+                        *t = s->idle_hint_timestamp;
+
+                return s->idle_hint;
+        }
+
+        if (isempty(s->tty))
+                goto dont_know;
+
+        if (s->tty[0] != '/') {
+                p = strappend("/dev/", s->tty);
+                if (!p)
+                        return -ENOMEM;
+        } else
+                p = NULL;
+
+        if (!startswith(p ? p : s->tty, "/dev/")) {
+                free(p);
+                goto dont_know;
+        }
+
+        k = lstat(p ? p : s->tty, &st);
+        free(p);
+
+        if (k < 0)
+                goto dont_know;
+
+        u = timespec_load(&st.st_atim);
+        n = now(CLOCK_REALTIME);
+        b = u + IDLE_THRESHOLD_USEC < n;
+
+        if (t)
+                dual_timestamp_from_realtime(t, u + b ? IDLE_THRESHOLD_USEC : 0);
+
+        return b;
+
+dont_know:
+        if (t)
+                *t = s->idle_hint_timestamp;
+
+        return 0;
+}
+
+void session_set_idle_hint(Session *s, bool b) {
+        assert(s);
+
+        if (s->idle_hint == b)
+                return;
+
+        s->idle_hint = b;
+        dual_timestamp_get(&s->idle_hint_timestamp);
+
+        session_send_changed(s,
+                             "IdleHint\0"
+                             "IdleSinceHint\0"
+                             "IdleSinceHintMonotonic\0");
+
+        if (s->seat)
+                seat_send_changed(s->seat,
+                                  "IdleHint\0"
+                                  "IdleSinceHint\0"
+                                  "IdleSinceHintMonotonic\0");
+
+        user_send_changed(s->user,
+                          "IdleHint\0"
+                          "IdleSinceHint\0"
+                          "IdleSinceHintMonotonic\0");
+
+        manager_send_changed(s->manager,
+                             "IdleHint\0"
+                             "IdleSinceHint\0"
+                             "IdleSinceHintMonotonic\0");
+}
+
+int session_create_fifo(Session *s) {
+        int r;
+
+        assert(s);
+
+        /* Create FIFO */
+        if (!s->fifo_path) {
+                r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
+                if (r < 0)
+                        return r;
+
+                if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
+                        return -ENOMEM;
+
+                if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
+                        return -errno;
+        }
+
+        /* Open reading side */
+        if (s->fifo_fd < 0) {
+                struct epoll_event ev;
+
+                s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
+                if (s->fifo_fd < 0)
+                        return -errno;
+
+                r = hashmap_put(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1), s);
+                if (r < 0)
+                        return r;
+
+                zero(ev);
+                ev.events = 0;
+                ev.data.u32 = FD_FIFO_BASE + s->fifo_fd;
+
+                if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
+                        return -errno;
+        }
+
+        /* Open writing side */
+        r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
+        if (r < 0)
+                return -errno;
+
+        return r;
+}
+
+void session_remove_fifo(Session *s) {
+        assert(s);
+
+        if (s->fifo_fd >= 0) {
+                assert_se(hashmap_remove(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
+                assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
+                close_nointr_nofail(s->fifo_fd);
+                s->fifo_fd = -1;
+        }
+
+        if (s->fifo_path) {
+                unlink(s->fifo_path);
+                free(s->fifo_path);
+                s->fifo_path = NULL;
+        }
+}
+
+int session_check_gc(Session *s, bool drop_not_started) {
+        int r;
+
+        assert(s);
+
+        if (drop_not_started && !s->started)
+                return 0;
+
+        if (s->fifo_fd >= 0) {
+
+                r = pipe_eof(s->fifo_fd);
+                if (r < 0)
+                        return r;
+
+                if (r == 0)
+                        return 1;
+        }
+
+        if (s->cgroup_path) {
+
+                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
+                if (r < 0)
+                        return r;
+
+                if (r <= 0)
+                        return 1;
+        }
+
+        return 0;
+}
+
+void session_add_to_gc_queue(Session *s) {
+        assert(s);
+
+        if (s->in_gc_queue)
+                return;
+
+        LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
+        s->in_gc_queue = true;
+}
+
+int session_kill(Session *s, KillWho who, int signo) {
+        int r = 0;
+        Set *pid_set = NULL;
+
+        assert(s);
+
+        if (!s->cgroup_path)
+                return -ESRCH;
+
+        if (s->leader <= 0 && who == KILL_LEADER)
+                return -ESRCH;
+
+        if (s->leader > 0)
+                if (kill(s->leader, signo) < 0)
+                        r = -errno;
+
+        if (who == KILL_ALL) {
+                int q;
+
+                pid_set = set_new(trivial_hash_func, trivial_compare_func);
+                if (!pid_set)
+                        return -ENOMEM;
+
+                if (s->leader > 0) {
+                        q = set_put(pid_set, LONG_TO_PTR(s->leader));
+                        if (q < 0)
+                                r = q;
+                }
+
+                q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
+                if (q < 0)
+                        if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
+                                r = q;
+        }
+
+        if (pid_set)
+                set_free(pid_set);
+
+        return r;
+}
+
+static const char* const session_type_table[_SESSION_TYPE_MAX] = {
+        [SESSION_TTY] = "tty",
+        [SESSION_X11] = "x11",
+        [SESSION_UNSPECIFIED] = "unspecified"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
+
+static const char* const kill_who_table[_KILL_WHO_MAX] = {
+        [KILL_LEADER] = "leader",
+        [KILL_ALL] = "all"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
new file mode 100644
index 0000000..8e394ac
--- /dev/null
+++ b/src/login/logind-session.h
@@ -0,0 +1,124 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologindsessionhfoo
+#define foologindsessionhfoo
+
+/***
+  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/>.
+***/
+
+typedef struct Session Session;
+
+#include "list.h"
+#include "util.h"
+#include "logind.h"
+#include "logind-seat.h"
+#include "logind-user.h"
+
+typedef enum SessionType {
+        SESSION_UNSPECIFIED,
+        SESSION_TTY,
+        SESSION_X11,
+        _SESSION_TYPE_MAX,
+        _SESSION_TYPE_INVALID = -1
+} SessionType;
+
+typedef enum KillWho {
+        KILL_LEADER,
+        KILL_ALL,
+        _KILL_WHO_MAX,
+        _KILL_WHO_INVALID = -1
+} KillWho;
+
+struct Session {
+        Manager *manager;
+
+        char *id;
+        SessionType type;
+
+        char *state_file;
+
+        User *user;
+
+        dual_timestamp timestamp;
+
+        char *tty;
+        char *display;
+
+        bool remote;
+        char *remote_user;
+        char *remote_host;
+
+        char *service;
+
+        int vtnr;
+        Seat *seat;
+
+        pid_t leader;
+        uint32_t audit_id;
+
+        int fifo_fd;
+        char *fifo_path;
+
+        char *cgroup_path;
+        char **controllers, **reset_controllers;
+
+        bool idle_hint;
+        dual_timestamp idle_hint_timestamp;
+
+        bool kill_processes;
+        bool in_gc_queue:1;
+        bool started:1;
+
+        LIST_FIELDS(Session, sessions_by_user);
+        LIST_FIELDS(Session, sessions_by_seat);
+
+        LIST_FIELDS(Session, gc_queue);
+};
+
+Session *session_new(Manager *m, User *u, const char *id);
+void session_free(Session *s);
+int session_check_gc(Session *s, bool drop_not_started);
+void session_add_to_gc_queue(Session *s);
+int session_activate(Session *s);
+bool session_is_active(Session *s);
+int session_get_idle_hint(Session *s, dual_timestamp *t);
+void session_set_idle_hint(Session *s, bool b);
+int session_create_fifo(Session *s);
+void session_remove_fifo(Session *s);
+int session_start(Session *s);
+int session_stop(Session *s);
+int session_save(Session *s);
+int session_load(Session *s);
+int session_kill(Session *s, KillWho who, int signo);
+
+char *session_bus_path(Session *s);
+
+extern const DBusObjectPathVTable bus_session_vtable;
+
+int session_send_signal(Session *s, bool new_session);
+int session_send_changed(Session *s, const char *properties);
+int session_send_lock(Session *s, bool lock);
+
+const char* session_type_to_string(SessionType t);
+SessionType session_type_from_string(const char *s);
+
+const char *kill_who_to_string(KillWho k);
+KillWho kill_who_from_string(const char *s);
+
+#endif
diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c
new file mode 100644
index 0000000..3673a28
--- /dev/null
+++ b/src/login/logind-user-dbus.c
@@ -0,0 +1,411 @@
+/*-*- 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 <string.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"                              \
+        "  <method name=\"Kill\">\n"                                    \
+        "   <arg name=\"signal\" type=\"s\"/>\n"                        \
+        "  </method>\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=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"RuntimePath\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"ControlGroupPath\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"Service\" 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" \
+        "  <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n"  \
+        "  <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"IdleSinceHintMonotonic\" type=\"t\" 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 bus_user_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
+        User *u = data;
+        dbus_bool_t b;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        b = user_get_idle_hint(u, NULL) > 0;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_user_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
+        User *u = data;
+        dual_timestamp t;
+        uint64_t k;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        user_get_idle_hint(u, &t);
+        k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k))
+                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", "Timestamp",          bus_property_append_usec,   "t",     &u->timestamp.realtime  },
+                { "org.freedesktop.login1.User", "TimestampMonotonic", bus_property_append_usec,   "t",     &u->timestamp.monotonic },
+                { "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                       },
+                { "org.freedesktop.login1.User", "IdleHint",           bus_user_append_idle_hint,  "b",     u                       },
+                { "org.freedesktop.login1.User", "IdleSinceHint",          bus_user_append_idle_hint_since, "t", u                  },
+                { "org.freedesktop.login1.User", "IdleSinceHintMonotonic", bus_user_append_idle_hint_since, "t", u                  },
+                { NULL, NULL, NULL, NULL, NULL }
+        };
+
+        DBusError error;
+        DBusMessage *reply = NULL;
+        int r;
+
+        assert(u);
+        assert(connection);
+        assert(message);
+
+        if (dbus_message_is_method_call(message, "org.freedesktop.login1.User", "Terminate")) {
+
+                r = user_stop(u);
+                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.User", "Kill")) {
+                int32_t signo;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    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);
+
+                r = user_kill(u, 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
+                return bus_default_message_handler(connection, message, INTROSPECTION, 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;
+}
+
+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;
+}
+
+int user_send_signal(User *u, bool new_user) {
+        DBusMessage *m;
+        int r = -ENOMEM;
+        char *p = NULL;
+        uint32_t uid;
+
+        assert(u);
+
+        m = dbus_message_new_signal("/org/freedesktop/login1",
+                                    "org.freedesktop.login1.Manager",
+                                    new_user ? "UserNew" : "UserRemoved");
+
+        if (!m)
+                return -ENOMEM;
+
+        p = user_bus_path(u);
+        if (!p)
+                goto finish;
+
+        uid = u->uid;
+
+        if (!dbus_message_append_args(
+                            m,
+                            DBUS_TYPE_UINT32, &uid,
+                            DBUS_TYPE_OBJECT_PATH, &p,
+                            DBUS_TYPE_INVALID))
+                goto finish;
+
+        if (!dbus_connection_send(u->manager->bus, m, NULL))
+                goto finish;
+
+        r = 0;
+
+finish:
+        dbus_message_unref(m);
+        free(p);
+
+        return r;
+}
+
+int user_send_changed(User *u, const char *properties) {
+        DBusMessage *m;
+        int r = -ENOMEM;
+        char *p = NULL;
+
+        assert(u);
+
+        if (!u->started)
+                return 0;
+
+        p = user_bus_path(u);
+        if (!p)
+                return -ENOMEM;
+
+        m = bus_properties_changed_new(p, "org.freedesktop.login1.User", properties);
+        if (!m)
+                goto finish;
+
+        if (!dbus_connection_send(u->manager->bus, m, NULL))
+                goto finish;
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+        free(p);
+
+        return r;
+}
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
new file mode 100644
index 0000000..56c7de4
--- /dev/null
+++ b/src/login/logind-user.c
@@ -0,0 +1,587 @@
+/*-*- 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 <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "logind-user.h"
+#include "util.h"
+#include "cgroup-util.h"
+#include "hashmap.h"
+#include "strv.h"
+
+User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
+        User *u;
+
+        assert(m);
+        assert(name);
+
+        u = new0(User, 1);
+        if (!u)
+                return NULL;
+
+        u->name = strdup(name);
+        if (!u->name) {
+                free(u);
+                return NULL;
+        }
+
+        if (asprintf(&u->state_file, "/run/systemd/users/%lu", (unsigned long) uid) < 0) {
+                free(u->name);
+                free(u);
+                return NULL;
+        }
+
+        if (hashmap_put(m->users, ULONG_TO_PTR((unsigned long) uid), u) < 0) {
+                free(u->state_file);
+                free(u->name);
+                free(u);
+                return NULL;
+        }
+
+        u->manager = m;
+        u->uid = uid;
+        u->gid = gid;
+
+        return u;
+}
+
+void user_free(User *u) {
+        assert(u);
+
+        if (u->in_gc_queue)
+                LIST_REMOVE(User, gc_queue, u->manager->user_gc_queue, u);
+
+        while (u->sessions)
+                session_free(u->sessions);
+
+        free(u->cgroup_path);
+
+        free(u->service);
+        free(u->runtime_path);
+
+        hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid));
+
+        free(u->name);
+        free(u->state_file);
+        free(u);
+}
+
+int user_save(User *u) {
+        FILE *f;
+        int r;
+        char *temp_path;
+
+        assert(u);
+        assert(u->state_file);
+
+        if (!u->started)
+                return 0;
+
+        r = safe_mkdir("/run/systemd/users", 0755, 0, 0);
+        if (r < 0)
+                goto finish;
+
+        r = fopen_temporary(u->state_file, &f, &temp_path);
+        if (r < 0)
+                goto finish;
+
+        fchmod(fileno(f), 0644);
+
+        fprintf(f,
+                "# This is private data. Do not parse.\n"
+                "NAME=%s\n"
+                "STATE=%s\n",
+                u->name,
+                user_state_to_string(user_get_state(u)));
+
+        if (u->cgroup_path)
+                fprintf(f,
+                        "CGROUP=%s\n",
+                        u->cgroup_path);
+
+        if (u->runtime_path)
+                fprintf(f,
+                        "RUNTIME=%s\n",
+                        u->runtime_path);
+
+        if (u->service)
+                fprintf(f,
+                        "SERVICE=%s\n",
+                        u->service);
+
+        if (u->display)
+                fprintf(f,
+                        "DISPLAY=%s\n",
+                        u->display->id);
+
+        if (u->sessions) {
+                Session *i;
+
+                fputs("SESSIONS=", f);
+                LIST_FOREACH(sessions_by_user, i, u->sessions) {
+                        fprintf(f,
+                                "%s%c",
+                                i->id,
+                                i->sessions_by_user_next ? ' ' : '\n');
+                }
+
+                fputs("SEATS=", f);
+                LIST_FOREACH(sessions_by_user, i, u->sessions) {
+                        if (i->seat)
+                                fprintf(f,
+                                        "%s%c",
+                                        i->seat->id,
+                                        i->sessions_by_user_next ? ' ' : '\n');
+                }
+
+                fputs("ACTIVE_SESSIONS=", f);
+                LIST_FOREACH(sessions_by_user, i, u->sessions)
+                        if (session_is_active(i))
+                                fprintf(f,
+                                        "%lu%c",
+                                        (unsigned long) i->user->uid,
+                                        i->sessions_by_user_next ? ' ' : '\n');
+
+                fputs("ACTIVE_SEATS=", f);
+                LIST_FOREACH(sessions_by_user, i, u->sessions) {
+                        if (session_is_active(i) && i->seat)
+                                fprintf(f,
+                                        "%s%c",
+                                        i->seat->id,
+                                        i->sessions_by_user_next ? ' ' : '\n');
+                }
+        }
+
+        fflush(f);
+
+        if (ferror(f) || rename(temp_path, u->state_file) < 0) {
+                r = -errno;
+                unlink(u->state_file);
+                unlink(temp_path);
+        }
+
+        fclose(f);
+        free(temp_path);
+
+finish:
+        if (r < 0)
+                log_error("Failed to save user data for %s: %s", u->name, strerror(-r));
+
+        return r;
+}
+
+int user_load(User *u) {
+        int r;
+        char *display = NULL;
+        Session *s = NULL;
+
+        assert(u);
+
+        r = parse_env_file(u->state_file, NEWLINE,
+                           "CGROUP", &u->cgroup_path,
+                           "RUNTIME", &u->runtime_path,
+                           "SERVICE", &u->service,
+                           "DISPLAY", &display,
+                           NULL);
+        if (r < 0) {
+                free(display);
+
+                if (r == -ENOENT)
+                        return 0;
+
+                log_error("Failed to read %s: %s", u->state_file, strerror(-r));
+                return r;
+        }
+
+        if (display) {
+                s = hashmap_get(u->manager->sessions, display);
+                free(display);
+        }
+
+        if (s && s->display && display_is_local(s->display))
+                u->display = s;
+
+        return r;
+}
+
+static int user_mkdir_runtime_path(User *u) {
+        char *p;
+        int r;
+
+        assert(u);
+
+        r = safe_mkdir("/run/user", 0755, 0, 0);
+        if (r < 0) {
+                log_error("Failed to create /run/user: %s", strerror(-r));
+                return r;
+        }
+
+        if (!u->runtime_path) {
+                p = strappend("/run/user/", u->name);
+
+                if (!p) {
+                        log_error("Out of memory");
+                        return -ENOMEM;
+                }
+        } else
+                p = u->runtime_path;
+
+        r = safe_mkdir(p, 0700, u->uid, u->gid);
+        if (r < 0) {
+                log_error("Failed to create runtime directory %s: %s", p, strerror(-r));
+                free(p);
+                u->runtime_path = NULL;
+                return r;
+        }
+
+        u->runtime_path = p;
+        return 0;
+}
+
+static int user_create_cgroup(User *u) {
+        char **k;
+        char *p;
+        int r;
+
+        assert(u);
+
+        if (!u->cgroup_path) {
+                if (asprintf(&p, "%s/%s", u->manager->cgroup_path, u->name) < 0) {
+                        log_error("Out of memory");
+                        return -ENOMEM;
+                }
+        } else
+                p = u->cgroup_path;
+
+        r = cg_create(SYSTEMD_CGROUP_CONTROLLER, p);
+        if (r < 0) {
+                log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
+                free(p);
+                u->cgroup_path = NULL;
+                return r;
+        }
+
+        u->cgroup_path = p;
+
+        STRV_FOREACH(k, u->manager->controllers) {
+
+                if (strv_contains(u->manager->reset_controllers, *k))
+                        continue;
+
+                r = cg_create(*k, p);
+                if (r < 0)
+                        log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r));
+        }
+
+        return 0;
+}
+
+static int user_start_service(User *u) {
+        assert(u);
+
+        return 0;
+}
+
+int user_start(User *u) {
+        int r;
+
+        assert(u);
+
+        if (u->started)
+                return 0;
+
+        log_info("New user %s logged in.", u->name);
+
+        /* Make XDG_RUNTIME_DIR */
+        r = user_mkdir_runtime_path(u);
+        if (r < 0)
+                return r;
+
+        /* Create cgroup */
+        r = user_create_cgroup(u);
+        if (r < 0)
+                return r;
+
+        /* Spawn user systemd */
+        r = user_start_service(u);
+        if (r < 0)
+                return r;
+
+        dual_timestamp_get(&u->timestamp);
+
+        u->started = true;
+
+        /* Save new user data */
+        user_save(u);
+
+        user_send_signal(u, true);
+
+        return 0;
+}
+
+static int user_stop_service(User *u) {
+        assert(u);
+
+        if (!u->service)
+                return 0;
+
+        return 0;
+}
+
+static int user_shall_kill(User *u) {
+        assert(u);
+
+        if (!u->manager->kill_user_processes)
+                return false;
+
+        if (strv_contains(u->manager->kill_exclude_users, u->name))
+                return false;
+
+        if (strv_isempty(u->manager->kill_only_users))
+                return true;
+
+        return strv_contains(u->manager->kill_only_users, u->name);
+}
+
+static int user_terminate_cgroup(User *u) {
+        int r;
+        char **k;
+
+        assert(u);
+
+        if (!u->cgroup_path)
+                return 0;
+
+        cg_trim(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false);
+
+        if (user_shall_kill(u)) {
+
+                r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
+                if (r < 0)
+                        log_error("Failed to kill user cgroup: %s", strerror(-r));
+        } else {
+
+                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
+                if (r < 0)
+                        log_error("Failed to check user cgroup: %s", strerror(-r));
+                else if (r > 0) {
+                        r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
+                        if (r < 0)
+                                log_error("Failed to delete user cgroup: %s", strerror(-r));
+                } else
+                        r = -EBUSY;
+        }
+
+        STRV_FOREACH(k, u->manager->controllers)
+                cg_trim(*k, u->cgroup_path, true);
+
+        free(u->cgroup_path);
+        u->cgroup_path = NULL;
+
+        return r;
+}
+
+static int user_remove_runtime_path(User *u) {
+        int r;
+
+        assert(u);
+
+        if (!u->runtime_path)
+                return 0;
+
+        r = rm_rf(u->runtime_path, false, true, false);
+        if (r < 0)
+                log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
+
+        free(u->runtime_path);
+        u->runtime_path = NULL;
+
+        return r;
+}
+
+int user_stop(User *u) {
+        Session *s;
+        int r = 0, k;
+        assert(u);
+
+        if (u->started)
+                log_info("User %s logged out.", u->name);
+
+        LIST_FOREACH(sessions_by_user, s, u->sessions) {
+                k = session_stop(s);
+                if (k < 0)
+                        r = k;
+        }
+
+        /* Kill systemd */
+        k = user_stop_service(u);
+        if (k < 0)
+                r = k;
+
+        /* Kill cgroup */
+        k = user_terminate_cgroup(u);
+        if (k < 0)
+                r = k;
+
+        /* Kill XDG_RUNTIME_DIR */
+        k = user_remove_runtime_path(u);
+        if (k < 0)
+                r = k;
+
+        unlink(u->state_file);
+        user_add_to_gc_queue(u);
+
+        if (u->started)
+                user_send_signal(u, false);
+
+        u->started = false;
+
+        return r;
+}
+
+int user_get_idle_hint(User *u, dual_timestamp *t) {
+        Session *s;
+        bool idle_hint = true;
+        dual_timestamp ts = { 0, 0 };
+
+        assert(u);
+
+        LIST_FOREACH(sessions_by_user, s, u->sessions) {
+                dual_timestamp k;
+                int ih;
+
+                ih = session_get_idle_hint(s, &k);
+                if (ih < 0)
+                        return ih;
+
+                if (!ih) {
+                        if (!idle_hint) {
+                                if (k.monotonic < ts.monotonic)
+                                        ts = k;
+                        } else {
+                                idle_hint = false;
+                                ts = k;
+                        }
+                } else if (idle_hint) {
+
+                        if (k.monotonic > ts.monotonic)
+                                ts = k;
+                }
+        }
+
+        if (t)
+                *t = ts;
+
+        return idle_hint;
+}
+
+int user_check_gc(User *u, bool drop_not_started) {
+        int r;
+        char *p;
+
+        assert(u);
+
+        if (drop_not_started && !u->started)
+                return 0;
+
+        if (u->sessions)
+                return 1;
+
+        if (asprintf(&p, "/var/lib/systemd/linger/%s", u->name) < 0)
+                return -ENOMEM;
+
+        r = access(p, F_OK) >= 0;
+        free(p);
+
+        if (r > 0)
+                return 1;
+
+        if (u->cgroup_path) {
+                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false);
+                if (r < 0)
+                        return r;
+
+                if (r <= 0)
+                        return 1;
+        }
+
+        return 0;
+}
+
+void user_add_to_gc_queue(User *u) {
+        assert(u);
+
+        if (u->in_gc_queue)
+                return;
+
+        LIST_PREPEND(User, gc_queue, u->manager->user_gc_queue, u);
+        u->in_gc_queue = true;
+}
+
+UserState user_get_state(User *u) {
+        Session *i;
+
+        assert(u);
+
+        if (!u->sessions)
+                return USER_LINGERING;
+
+        LIST_FOREACH(sessions_by_user, i, u->sessions)
+                if (session_is_active(i))
+                        return USER_ACTIVE;
+
+        return USER_ONLINE;
+}
+
+int user_kill(User *u, int signo) {
+        int r = 0, q;
+        Set *pid_set = NULL;
+
+        assert(u);
+
+        if (!u->cgroup_path)
+                return -ESRCH;
+
+        pid_set = set_new(trivial_hash_func, trivial_compare_func);
+        if (!pid_set)
+                return -ENOMEM;
+
+        q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
+        if (q < 0)
+                if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
+                        r = q;
+
+        if (pid_set)
+                set_free(pid_set);
+
+        return r;
+}
+
+static const char* const user_state_table[_USER_STATE_MAX] = {
+        [USER_OFFLINE] = "offline",
+        [USER_LINGERING] = "lingering",
+        [USER_ONLINE] = "online",
+        [USER_ACTIVE] = "active"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
diff --git a/src/login/logind-user.h b/src/login/logind-user.h
new file mode 100644
index 0000000..db9a5f6
--- /dev/null
+++ b/src/login/logind-user.h
@@ -0,0 +1,86 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologinduserhfoo
+#define foologinduserhfoo
+
+/***
+  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/>.
+***/
+
+typedef struct User User;
+
+#include "list.h"
+#include "util.h"
+#include "logind.h"
+#include "logind-session.h"
+
+typedef enum UserState {
+        USER_OFFLINE,
+        USER_LINGERING,
+        USER_ONLINE,
+        USER_ACTIVE,
+        _USER_STATE_MAX,
+        _USER_STATE_INVALID = -1
+} UserState;
+
+struct User {
+        Manager *manager;
+
+        uid_t uid;
+        gid_t gid;
+        char *name;
+
+        char *state_file;
+        char *runtime_path;
+        char *service;
+        char *cgroup_path;
+
+        Session *display;
+
+        dual_timestamp timestamp;
+
+        bool in_gc_queue:1;
+        bool started:1;
+
+        LIST_HEAD(Session, sessions);
+        LIST_FIELDS(User, gc_queue);
+};
+
+User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name);
+void user_free(User *u);
+int user_check_gc(User *u, bool drop_not_started);
+void user_add_to_gc_queue(User *u);
+int user_start(User *u);
+int user_stop(User *u);
+UserState user_get_state(User *u);
+int user_get_idle_hint(User *u, dual_timestamp *t);
+int user_save(User *u);
+int user_load(User *u);
+int user_kill(User *u, int signo);
+
+char *user_bus_path(User *s);
+
+extern const DBusObjectPathVTable bus_user_vtable;
+
+int user_send_signal(User *u, bool new_user);
+int user_send_changed(User *u, const char *properties);
+
+const char* user_state_to_string(UserState s);
+UserState user_state_from_string(const char *s);
+
+#endif
diff --git a/src/login/logind.c b/src/login/logind.c
new file mode 100644
index 0000000..4633a5e
--- /dev/null
+++ b/src/login/logind.c
@@ -0,0 +1,1228 @@
+/*-*- 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 <pwd.h>
+#include <libudev.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/ioctl.h>
+#include <linux/vt.h>
+
+#include "logind.h"
+#include "dbus-common.h"
+#include "dbus-loop.h"
+#include "strv.h"
+#include "conf-parser.h"
+
+Manager *manager_new(void) {
+        Manager *m;
+
+        m = new0(Manager, 1);
+        if (!m)
+                return NULL;
+
+        m->console_active_fd = -1;
+        m->bus_fd = -1;
+        m->udev_seat_fd = -1;
+        m->udev_vcsa_fd = -1;
+        m->epoll_fd = -1;
+        m->n_autovts = 6;
+
+        m->devices = hashmap_new(string_hash_func, string_compare_func);
+        m->seats = hashmap_new(string_hash_func, string_compare_func);
+        m->sessions = hashmap_new(string_hash_func, string_compare_func);
+        m->users = hashmap_new(trivial_hash_func, trivial_compare_func);
+        m->cgroups = hashmap_new(string_hash_func, string_compare_func);
+        m->fifo_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
+
+        if (!m->devices || !m->seats || !m->sessions || !m->users || !m->cgroups || !m->fifo_fds) {
+                manager_free(m);
+                return NULL;
+        }
+
+        m->reset_controllers = strv_new("cpu", NULL);
+        m->kill_exclude_users = strv_new("root", NULL);
+        if (!m->reset_controllers || !m->kill_exclude_users) {
+                manager_free(m);
+                return NULL;
+        }
+
+        m->udev = udev_new();
+        if (!m->udev) {
+                manager_free(m);
+                return NULL;
+        }
+
+        if (cg_get_user_path(&m->cgroup_path) < 0) {
+                manager_free(m);
+                return NULL;
+        }
+
+        return m;
+}
+
+void manager_free(Manager *m) {
+        Session *session;
+        User *u;
+        Device *d;
+        Seat *s;
+
+        assert(m);
+
+        while ((session = hashmap_first(m->sessions)))
+                session_free(session);
+
+        while ((u = hashmap_first(m->users)))
+                user_free(u);
+
+        while ((d = hashmap_first(m->devices)))
+                device_free(d);
+
+        while ((s = hashmap_first(m->seats)))
+                seat_free(s);
+
+        hashmap_free(m->sessions);
+        hashmap_free(m->users);
+        hashmap_free(m->devices);
+        hashmap_free(m->seats);
+        hashmap_free(m->cgroups);
+        hashmap_free(m->fifo_fds);
+
+        if (m->console_active_fd >= 0)
+                close_nointr_nofail(m->console_active_fd);
+
+        if (m->udev_seat_monitor)
+                udev_monitor_unref(m->udev_seat_monitor);
+
+        if (m->udev_vcsa_monitor)
+                udev_monitor_unref(m->udev_vcsa_monitor);
+
+        if (m->udev)
+                udev_unref(m->udev);
+
+        if (m->bus) {
+                dbus_connection_flush(m->bus);
+                dbus_connection_close(m->bus);
+                dbus_connection_unref(m->bus);
+        }
+
+        if (m->bus_fd >= 0)
+                close_nointr_nofail(m->bus_fd);
+
+        if (m->epoll_fd >= 0)
+                close_nointr_nofail(m->epoll_fd);
+
+        strv_free(m->controllers);
+        strv_free(m->reset_controllers);
+        strv_free(m->kill_only_users);
+        strv_free(m->kill_exclude_users);
+
+        free(m->cgroup_path);
+        free(m);
+}
+
+int manager_add_device(Manager *m, const char *sysfs, Device **_device) {
+        Device *d;
+
+        assert(m);
+        assert(sysfs);
+
+        d = hashmap_get(m->devices, sysfs);
+        if (d) {
+                if (_device)
+                        *_device = d;
+
+                return 0;
+        }
+
+        d = device_new(m, sysfs);
+        if (!d)
+                return -ENOMEM;
+
+        if (_device)
+                *_device = d;
+
+        return 0;
+}
+
+int manager_add_seat(Manager *m, const char *id, Seat **_seat) {
+        Seat *s;
+
+        assert(m);
+        assert(id);
+
+        s = hashmap_get(m->seats, id);
+        if (s) {
+                if (_seat)
+                        *_seat = s;
+
+                return 0;
+        }
+
+        s = seat_new(m, id);
+        if (!s)
+                return -ENOMEM;
+
+        if (_seat)
+                *_seat = s;
+
+        return 0;
+}
+
+int manager_add_session(Manager *m, User *u, const char *id, Session **_session) {
+        Session *s;
+
+        assert(m);
+        assert(id);
+
+        s = hashmap_get(m->sessions, id);
+        if (s) {
+                if (_session)
+                        *_session = s;
+
+                return 0;
+        }
+
+        s = session_new(m, u, id);
+        if (!s)
+                return -ENOMEM;
+
+        if (_session)
+                *_session = s;
+
+        return 0;
+}
+
+int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
+        User *u;
+
+        assert(m);
+        assert(name);
+
+        u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
+        if (u) {
+                if (_user)
+                        *_user = u;
+
+                return 0;
+        }
+
+        u = user_new(m, uid, gid, name);
+        if (!u)
+                return -ENOMEM;
+
+        if (_user)
+                *_user = u;
+
+        return 0;
+}
+
+int manager_add_user_by_name(Manager *m, const char *name, User **_user) {
+        uid_t uid;
+        gid_t gid;
+        int r;
+
+        assert(m);
+        assert(name);
+
+        r = get_user_creds(&name, &uid, &gid, NULL);
+        if (r < 0)
+                return r;
+
+        return manager_add_user(m, uid, gid, name, _user);
+}
+
+int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
+        struct passwd *p;
+
+        assert(m);
+
+        errno = 0;
+        p = getpwuid(uid);
+        if (!p)
+                return errno ? -errno : -ENOENT;
+
+        return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
+}
+
+int manager_process_seat_device(Manager *m, struct udev_device *d) {
+        Device *device;
+        int r;
+
+        assert(m);
+
+        if (streq_ptr(udev_device_get_action(d), "remove")) {
+
+                device = hashmap_get(m->devices, udev_device_get_syspath(d));
+                if (!device)
+                        return 0;
+
+                seat_add_to_gc_queue(device->seat);
+                device_free(device);
+
+        } else {
+                const char *sn;
+                Seat *seat;
+
+                sn = udev_device_get_property_value(d, "ID_SEAT");
+                if (isempty(sn))
+                        sn = "seat0";
+
+                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);
+                if (r < 0)
+                        return r;
+
+                r = manager_add_seat(m, sn, &seat);
+                if (r < 0) {
+                        if (!device->seat)
+                                device_free(device);
+
+                        return r;
+                }
+
+                device_attach(device, seat);
+                seat_start(seat);
+        }
+
+        return 0;
+}
+
+int manager_enumerate_devices(Manager *m) {
+        struct udev_list_entry *item = NULL, *first = NULL;
+        struct udev_enumerate *e;
+        int r;
+
+        assert(m);
+
+        /* Loads devices from udev and creates seats for them as
+         * necessary */
+
+        e = udev_enumerate_new(m->udev);
+        if (!e) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        r = udev_enumerate_add_match_subsystem(e, "graphics");
+        if (r < 0)
+                goto finish;
+
+        r = udev_enumerate_add_match_tag(e, "seat");
+        if (r < 0)
+                goto finish;
+
+        r = udev_enumerate_scan_devices(e);
+        if (r < 0)
+                goto finish;
+
+        first = udev_enumerate_get_list_entry(e);
+        udev_list_entry_foreach(item, first) {
+                struct udev_device *d;
+                int k;
+
+                d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
+                if (!d) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                k = manager_process_seat_device(m, d);
+                udev_device_unref(d);
+
+                if (k < 0)
+                        r = k;
+        }
+
+finish:
+        if (e)
+                udev_enumerate_unref(e);
+
+        return r;
+}
+
+int manager_enumerate_seats(Manager *m) {
+        DIR *d;
+        struct dirent *de;
+        int r = 0;
+
+        assert(m);
+
+        /* This loads data about seats stored on disk, but does not
+         * actually create any seats. Removes data of seats that no
+         * longer exist. */
+
+        d = opendir("/run/systemd/seats");
+        if (!d) {
+                if (errno == ENOENT)
+                        return 0;
+
+                log_error("Failed to open /run/systemd/seats: %m");
+                return -errno;
+        }
+
+        while ((de = readdir(d))) {
+                Seat *s;
+                int k;
+
+                if (!dirent_is_file(de))
+                        continue;
+
+                s = hashmap_get(m->seats, de->d_name);
+                if (!s) {
+                        unlinkat(dirfd(d), de->d_name, 0);
+                        continue;
+                }
+
+                k = seat_load(s);
+                if (k < 0)
+                        r = k;
+        }
+
+        closedir(d);
+
+        return r;
+}
+
+static int manager_enumerate_users_from_cgroup(Manager *m) {
+        int r = 0;
+        char *name;
+        DIR *d;
+        int k;
+
+        r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &d);
+        if (r < 0) {
+                if (r == -ENOENT)
+                        return 0;
+
+                log_error("Failed to open %s: %s", m->cgroup_path, strerror(-r));
+                return r;
+        }
+
+        while ((k = cg_read_subgroup(d, &name)) > 0) {
+                User *user;
+
+                k = manager_add_user_by_name(m, name, &user);
+                if (k < 0) {
+                        free(name);
+                        r = k;
+                        continue;
+                }
+
+                user_add_to_gc_queue(user);
+
+                if (!user->cgroup_path)
+                        if (asprintf(&user->cgroup_path, "%s/%s", m->cgroup_path, name) < 0) {
+                                r = -ENOMEM;
+                                free(name);
+                                break;
+                        }
+
+                free(name);
+        }
+
+        if (r >= 0 && k < 0)
+                r = k;
+
+        closedir(d);
+
+        return r;
+}
+
+static int manager_enumerate_linger_users(Manager *m) {
+        DIR *d;
+        struct dirent *de;
+        int r = 0;
+
+        d = opendir("/var/lib/systemd/linger");
+        if (!d) {
+                if (errno == ENOENT)
+                        return 0;
+
+                log_error("Failed to open /var/lib/systemd/linger/: %m");
+                return -errno;
+        }
+
+        while ((de = readdir(d))) {
+                int k;
+
+                if (!dirent_is_file(de))
+                        continue;
+
+                k = manager_add_user_by_name(m, de->d_name, NULL);
+                if (k < 0) {
+                        log_notice("Couldn't add lingering user %s: %s", de->d_name, strerror(-k));
+                        r = k;
+                }
+        }
+
+        closedir(d);
+
+        return r;
+}
+
+int manager_enumerate_users(Manager *m) {
+        DIR *d;
+        struct dirent *de;
+        int r, k;
+
+        assert(m);
+
+        /* First, enumerate user cgroups */
+        r = manager_enumerate_users_from_cgroup(m);
+
+        /* Second, add lingering users on top */
+        k = manager_enumerate_linger_users(m);
+        if (k < 0)
+                r = k;
+
+        /* Third, read in user data stored on disk */
+        d = opendir("/run/systemd/users");
+        if (!d) {
+                if (errno == ENOENT)
+                        return 0;
+
+                log_error("Failed to open /run/systemd/users: %m");
+                return -errno;
+        }
+
+        while ((de = readdir(d))) {
+                uid_t uid;
+                User *u;
+
+                if (!dirent_is_file(de))
+                        continue;
+
+                k = parse_uid(de->d_name, &uid);
+                if (k < 0) {
+                        log_error("Failed to parse file name %s: %s", de->d_name, strerror(-k));
+                        continue;
+                }
+
+                u = hashmap_get(m->users, ULONG_TO_PTR(uid));
+                if (!u) {
+                        unlinkat(dirfd(d), de->d_name, 0);
+                        continue;
+                }
+
+                k = user_load(u);
+                if (k < 0)
+                        r = k;
+        }
+
+        closedir(d);
+
+        return r;
+}
+
+static int manager_enumerate_sessions_from_cgroup(Manager *m) {
+        User *u;
+        Iterator i;
+        int r = 0;
+
+        HASHMAP_FOREACH(u, m->users, i) {
+                DIR *d;
+                char *name;
+                int k;
+
+                if (!u->cgroup_path)
+                        continue;
+
+                k = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &d);
+                if (k < 0) {
+                        if (k == -ENOENT)
+                                continue;
+
+                        log_error("Failed to open %s: %s", u->cgroup_path, strerror(-k));
+                        r = k;
+                        continue;
+                }
+
+                while ((k = cg_read_subgroup(d, &name)) > 0) {
+                        Session *session;
+
+                        if (streq(name, "shared"))
+                                continue;
+
+                        k = manager_add_session(m, u, name, &session);
+                        if (k < 0) {
+                                free(name);
+                                break;
+                        }
+
+                        session_add_to_gc_queue(session);
+
+                        if (!session->cgroup_path)
+                                if (asprintf(&session->cgroup_path, "%s/%s", u->cgroup_path, name) < 0) {
+                                        k = -ENOMEM;
+                                        free(name);
+                                        break;
+                                }
+
+                        free(name);
+                }
+
+                closedir(d);
+
+                if (k < 0)
+                        r = k;
+        }
+
+        return r;
+}
+
+int manager_enumerate_sessions(Manager *m) {
+        DIR *d;
+        struct dirent *de;
+        int r = 0;
+
+        assert(m);
+
+        /* First enumerate session cgroups */
+        r = manager_enumerate_sessions_from_cgroup(m);
+
+        /* Second, read in session data stored on disk */
+        d = opendir("/run/systemd/sessions");
+        if (!d) {
+                if (errno == ENOENT)
+                        return 0;
+
+                log_error("Failed to open /run/systemd/sessions: %m");
+                return -errno;
+        }
+
+        while ((de = readdir(d))) {
+                struct Session *s;
+                int k;
+
+                if (!dirent_is_file(de))
+                        continue;
+
+                s = hashmap_get(m->sessions, de->d_name);
+                if (!s) {
+                        unlinkat(dirfd(d), de->d_name, 0);
+                        continue;
+                }
+
+                k = session_load(s);
+                if (k < 0)
+                        r = k;
+        }
+
+        closedir(d);
+
+        return r;
+}
+
+int manager_dispatch_seat_udev(Manager *m) {
+        struct udev_device *d;
+        int r;
+
+        assert(m);
+
+        d = udev_monitor_receive_device(m->udev_seat_monitor);
+        if (!d)
+                return -ENOMEM;
+
+        r = manager_process_seat_device(m, d);
+        udev_device_unref(d);
+
+        return r;
+}
+
+
+int manager_dispatch_vcsa_udev(Manager *m) {
+        struct udev_device *d;
+        int r = 0;
+        const char *name;
+
+        assert(m);
+
+        d = udev_monitor_receive_device(m->udev_vcsa_monitor);
+        if (!d)
+                return -ENOMEM;
+
+        name = udev_device_get_sysname(d);
+
+        /* Whenever a VCSA device is removed try to reallocate our
+         * VTs, to make sure our auto VTs never go away. */
+
+        if (name && startswith(name, "vcsa") && streq_ptr(udev_device_get_action(d), "remove"))
+                r = seat_preallocate_vts(m->vtconsole);
+
+        udev_device_unref(d);
+
+        return r;
+}
+
+int manager_dispatch_console(Manager *m) {
+        assert(m);
+
+        if (m->vtconsole)
+                seat_read_active_vt(m->vtconsole);
+
+        return 0;
+}
+
+static int vt_is_busy(int vtnr) {
+        struct vt_stat vt_stat;
+        int r = 0, fd;
+
+        assert(vtnr >= 1);
+
+        /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
+         * we'd open the latter we'd open the foreground tty which
+         * hence would be unconditionally busy. By opening /dev/tty1
+         * we avoid this. Since tty1 is special and needs to be an
+         * explicitly loaded getty or DM this is safe. */
+
+        fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+
+        if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
+                r = -errno;
+        else
+                r = !!(vt_stat.v_state & (1 << vtnr));
+
+        close_nointr_nofail(fd);
+
+        return r;
+}
+
+int manager_spawn_autovt(Manager *m, int vtnr) {
+        int r;
+        DBusMessage *message = NULL, *reply = NULL;
+        char *name = NULL;
+        const char *mode = "fail";
+        DBusError error;
+
+        assert(m);
+        assert(vtnr >= 1);
+
+        dbus_error_init(&error);
+
+        if ((unsigned) vtnr > m->n_autovts)
+                return 0;
+
+        r = vt_is_busy(vtnr);
+        if (r < 0)
+                return r;
+        else if (r > 0)
+                return -EBUSY;
+
+        message = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit");
+        if (!message) {
+                log_error("Could not allocate message.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (asprintf(&name, "autovt at tty%i.service", vtnr) < 0) {
+                log_error("Could not allocate service name.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (!dbus_message_append_args(message,
+                                      DBUS_TYPE_STRING, &name,
+                                      DBUS_TYPE_STRING, &mode,
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Could not attach target and flag information to message.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        reply = dbus_connection_send_with_reply_and_block(m->bus, message, -1, &error);
+        if (!reply) {
+                log_error("Failed to start unit: %s", bus_error_message(&error));
+                goto finish;
+        }
+
+        r = 0;
+
+finish:
+        free(name);
+
+        if (message)
+                dbus_message_unref(message);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return r;
+}
+
+void manager_cgroup_notify_empty(Manager *m, const char *cgroup) {
+        Session *s;
+        char *p;
+
+        assert(m);
+        assert(cgroup);
+
+        p = strdup(cgroup);
+        if (!p) {
+                log_error("Out of memory.");
+                return;
+        }
+
+        for (;;) {
+                char *e;
+
+                if (isempty(p) || streq(p, "/"))
+                        break;
+
+                s = hashmap_get(m->cgroups, p);
+                if (s)
+                        session_add_to_gc_queue(s);
+
+                assert_se(e = strrchr(p, '/'));
+                *e = 0;
+        }
+
+        free(p);
+}
+
+static void manager_pipe_notify_eof(Manager *m, int fd) {
+        Session *s;
+
+        assert_se(m);
+        assert_se(fd >= 0);
+
+        assert_se(s = hashmap_get(m->fifo_fds, INT_TO_PTR(fd + 1)));
+        assert(s->fifo_fd == fd);
+        session_remove_fifo(s);
+
+        session_stop(s);
+}
+
+static int manager_connect_bus(Manager *m) {
+        DBusError error;
+        int r;
+        struct epoll_event ev;
+
+        assert(m);
+        assert(!m->bus);
+        assert(m->bus_fd < 0);
+
+        dbus_error_init(&error);
+
+        m->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
+        if (!m->bus) {
+                log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error));
+                r = -ECONNREFUSED;
+                goto fail;
+        }
+
+        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, bus_message_filter, m, NULL)) {
+                log_error("Not enough memory");
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        dbus_bus_add_match(m->bus,
+                           "type='signal',"
+                           "interface='org.freedesktop.systemd1.Agent',"
+                           "member='Released',"
+                           "path='/org/freedesktop/systemd1/agent'",
+                           &error);
+
+        if (dbus_error_is_set(&error)) {
+                log_error("Failed to register match: %s", bus_error_message(&error));
+                r = -EIO;
+                goto fail;
+        }
+
+        r = dbus_bus_request_name(m->bus, "org.freedesktop.login1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
+        if (dbus_error_is_set(&error)) {
+                log_error("Failed to register name on bus: %s", bus_error_message(&error));
+                r = -EIO;
+                goto fail;
+        }
+
+        if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)  {
+                log_error("Failed to acquire name.");
+                r = -EEXIST;
+                goto fail;
+        }
+
+        m->bus_fd = bus_loop_open(m->bus);
+        if (m->bus_fd < 0) {
+                r = m->bus_fd;
+                goto fail;
+        }
+
+        zero(ev);
+        ev.events = EPOLLIN;
+        ev.data.u32 = FD_BUS;
+
+        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0)
+                goto fail;
+
+        return 0;
+
+fail:
+        dbus_error_free(&error);
+
+        return r;
+}
+
+static int manager_connect_console(Manager *m) {
+        struct epoll_event ev;
+
+        assert(m);
+        assert(m->console_active_fd < 0);
+
+        m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC);
+        if (m->console_active_fd < 0) {
+                log_error("Failed to open /sys/class/tty/tty0/active: %m");
+                return -errno;
+        }
+
+        zero(ev);
+        ev.events = 0;
+        ev.data.u32 = FD_CONSOLE;
+
+        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->console_active_fd, &ev) < 0)
+                return -errno;
+
+        return 0;
+}
+
+static int manager_connect_udev(Manager *m) {
+        struct epoll_event ev;
+        int r;
+
+        assert(m);
+        assert(!m->udev_seat_monitor);
+        assert(!m->udev_vcsa_monitor);
+
+        m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
+        if (!m->udev_seat_monitor)
+                return -ENOMEM;
+
+        r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "seat");
+        if (r < 0)
+                return r;
+
+        r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_seat_monitor, "graphics", NULL);
+        if (r < 0)
+                return r;
+
+        r = udev_monitor_enable_receiving(m->udev_seat_monitor);
+        if (r < 0)
+                return r;
+
+        m->udev_seat_fd = udev_monitor_get_fd(m->udev_seat_monitor);
+
+        zero(ev);
+        ev.events = EPOLLIN;
+        ev.data.u32 = FD_SEAT_UDEV;
+
+        if (m->n_autovts <= 0)
+                return 0;
+
+        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_seat_fd, &ev) < 0)
+                return -errno;
+
+        m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
+        if (!m->udev_vcsa_monitor)
+                return -ENOMEM;
+
+        r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL);
+        if (r < 0)
+                return r;
+
+        r = udev_monitor_enable_receiving(m->udev_vcsa_monitor);
+        if (r < 0)
+                return r;
+
+        m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor);
+
+        zero(ev);
+        ev.events = EPOLLIN;
+        ev.data.u32 = FD_VCSA_UDEV;
+
+        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_vcsa_fd, &ev) < 0)
+                return -errno;
+
+        return 0;
+}
+
+void manager_gc(Manager *m, bool drop_not_started) {
+        Seat *seat;
+        Session *session;
+        User *user;
+
+        assert(m);
+
+        while ((seat = m->seat_gc_queue)) {
+                LIST_REMOVE(Seat, gc_queue, m->seat_gc_queue, seat);
+                seat->in_gc_queue = false;
+
+                if (seat_check_gc(seat, drop_not_started) == 0) {
+                        seat_stop(seat);
+                        seat_free(seat);
+                }
+        }
+
+        while ((session = m->session_gc_queue)) {
+                LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session);
+                session->in_gc_queue = false;
+
+                if (session_check_gc(session, drop_not_started) == 0) {
+                        session_stop(session);
+                        session_free(session);
+                }
+        }
+
+        while ((user = m->user_gc_queue)) {
+                LIST_REMOVE(User, gc_queue, m->user_gc_queue, user);
+                user->in_gc_queue = false;
+
+                if (user_check_gc(user, drop_not_started) == 0) {
+                        user_stop(user);
+                        user_free(user);
+                }
+        }
+}
+
+int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
+        Session *s;
+        bool idle_hint = true;
+        dual_timestamp ts = { 0, 0 };
+        Iterator i;
+
+        assert(m);
+
+        HASHMAP_FOREACH(s, m->sessions, i) {
+                dual_timestamp k;
+                int ih;
+
+                ih = session_get_idle_hint(s, &k);
+                if (ih < 0)
+                        return ih;
+
+                if (!ih) {
+                        if (!idle_hint) {
+                                if (k.monotonic < ts.monotonic)
+                                        ts = k;
+                        } else {
+                                idle_hint = false;
+                                ts = k;
+                        }
+                } else if (idle_hint) {
+
+                        if (k.monotonic > ts.monotonic)
+                                ts = k;
+                }
+        }
+
+        if (t)
+                *t = ts;
+
+        return idle_hint;
+}
+
+int manager_startup(Manager *m) {
+        int r;
+        Seat *seat;
+        Session *session;
+        User *user;
+        Iterator i;
+
+        assert(m);
+        assert(m->epoll_fd <= 0);
+
+        m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+        if (m->epoll_fd < 0)
+                return -errno;
+
+        /* Connect to udev */
+        r = manager_connect_udev(m);
+        if (r < 0)
+                return r;
+
+        /* Connect to console */
+        r = manager_connect_console(m);
+        if (r < 0)
+                return r;
+
+        /* Connect to the bus */
+        r = manager_connect_bus(m);
+        if (r < 0)
+                return r;
+
+        /* Instantiate magic seat 0 */
+        r = manager_add_seat(m, "seat0", &m->vtconsole);
+        if (r < 0)
+                return r;
+
+        /* Deserialize state */
+        manager_enumerate_devices(m);
+        manager_enumerate_seats(m);
+        manager_enumerate_users(m);
+        manager_enumerate_sessions(m);
+
+        /* Remove stale objects before we start them */
+        manager_gc(m, false);
+
+        /* And start everything */
+        HASHMAP_FOREACH(seat, m->seats, i)
+                seat_start(seat);
+
+        HASHMAP_FOREACH(user, m->users, i)
+                user_start(user);
+
+        HASHMAP_FOREACH(session, m->sessions, i)
+                session_start(session);
+
+        return 0;
+}
+
+int manager_run(Manager *m) {
+        assert(m);
+
+        for (;;) {
+                struct epoll_event event;
+                int n;
+
+                manager_gc(m, true);
+
+                if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
+                        continue;
+
+                manager_gc(m, true);
+
+                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;
+                }
+
+                switch (event.data.u32) {
+
+                case FD_SEAT_UDEV:
+                        manager_dispatch_seat_udev(m);
+                        break;
+
+                case FD_VCSA_UDEV:
+                        manager_dispatch_vcsa_udev(m);
+                        break;
+
+                case FD_CONSOLE:
+                        manager_dispatch_console(m);
+                        break;
+
+                case FD_BUS:
+                        bus_loop_dispatch(m->bus_fd);
+                        break;
+
+                default:
+                        if (event.data.u32 >= FD_FIFO_BASE)
+                                manager_pipe_notify_eof(m, event.data.u32 - FD_FIFO_BASE);
+                }
+        }
+
+        return 0;
+}
+
+static int manager_parse_config_file(Manager *m) {
+        FILE *f;
+        const char *fn;
+        int r;
+
+        assert(m);
+
+        fn = "/etc/systemd/systemd-logind.conf";
+        f = fopen(fn, "re");
+        if (!f) {
+                if (errno == ENOENT)
+                        return 0;
+
+                log_warning("Failed to open configuration file %s: %m", fn);
+                return -errno;
+        }
+
+        r = config_parse(fn, f, "Login\0", config_item_perf_lookup, (void*) logind_gperf_lookup, false, m);
+        if (r < 0)
+                log_warning("Failed to parse configuration file: %s", strerror(-r));
+
+        fclose(f);
+
+        return r;
+}
+
+int main(int argc, char *argv[]) {
+        Manager *m = NULL;
+        int r;
+
+        log_set_target(LOG_TARGET_AUTO);
+        log_parse_environment();
+        log_open();
+
+        umask(0022);
+
+        if (argc != 1) {
+                log_error("This program takes no arguments.");
+                r = -EINVAL;
+                goto finish;
+        }
+
+        m = manager_new();
+        if (!m) {
+                log_error("Out of memory");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        manager_parse_config_file(m);
+
+        r = manager_startup(m);
+        if (r < 0) {
+                log_error("Failed to fully start up daemon: %s", strerror(-r));
+                goto finish;
+        }
+
+        r = manager_run(m);
+
+finish:
+        if (m)
+                manager_free(m);
+
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/login/logind.h b/src/login/logind.h
new file mode 100644
index 0000000..fd668a2
--- /dev/null
+++ b/src/login/logind.h
@@ -0,0 +1,128 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologindhfoo
+#define foologindhfoo
+
+/***
+  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 <stdbool.h>
+#include <inttypes.h>
+#include <dbus/dbus.h>
+#include <libudev.h>
+
+#include "util.h"
+#include "list.h"
+#include "hashmap.h"
+#include "cgroup-util.h"
+
+typedef struct Manager Manager;
+
+#include "logind-device.h"
+#include "logind-seat.h"
+#include "logind-session.h"
+#include "logind-user.h"
+
+struct Manager {
+        DBusConnection *bus;
+
+        Hashmap *devices;
+        Hashmap *seats;
+        Hashmap *sessions;
+        Hashmap *users;
+
+        LIST_HEAD(Seat, seat_gc_queue);
+        LIST_HEAD(Session, session_gc_queue);
+        LIST_HEAD(User, user_gc_queue);
+
+        struct udev *udev;
+        struct udev_monitor *udev_seat_monitor, *udev_vcsa_monitor;
+
+        int udev_seat_fd;
+        int udev_vcsa_fd;
+
+        int console_active_fd;
+        int bus_fd;
+        int epoll_fd;
+
+        unsigned n_autovts;
+
+        Seat *vtconsole;
+
+        char *cgroup_path;
+        char **controllers, **reset_controllers;
+
+        char **kill_only_users, **kill_exclude_users;
+
+        bool kill_user_processes;
+
+        unsigned long session_counter;
+
+        Hashmap *cgroups;
+        Hashmap *fifo_fds;
+};
+
+enum {
+        FD_SEAT_UDEV,
+        FD_VCSA_UDEV,
+        FD_CONSOLE,
+        FD_BUS,
+        FD_FIFO_BASE
+};
+
+Manager *manager_new(void);
+void manager_free(Manager *m);
+
+int manager_add_device(Manager *m, const char *sysfs, Device **_device);
+int manager_add_seat(Manager *m, const char *id, Seat **_seat);
+int manager_add_session(Manager *m, User *u, const char *id, Session **_session);
+int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user);
+int manager_add_user_by_name(Manager *m, const char *name, User **_user);
+int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user);
+
+int manager_process_seat_device(Manager *m, struct udev_device *d);
+int manager_dispatch_seat_udev(Manager *m);
+int manager_dispatch_vcsa_udev(Manager *m);
+int manager_dispatch_console(Manager *m);
+
+int manager_enumerate_devices(Manager *m);
+int manager_enumerate_seats(Manager *m);
+int manager_enumerate_sessions(Manager *m);
+int manager_enumerate_users(Manager *m);
+
+int manager_startup(Manager *m);
+int manager_run(Manager *m);
+int manager_spawn_autovt(Manager *m, int vtnr);
+
+void manager_cgroup_notify_empty(Manager *m, const char *cgroup);
+
+void manager_gc(Manager *m, bool drop_not_started);
+
+int manager_get_idle_hint(Manager *m, dual_timestamp *t);
+
+extern const DBusObjectPathVTable bus_manager_vtable;
+
+DBusHandlerResult bus_message_filter(DBusConnection *c, DBusMessage *message, void *userdata);
+
+int manager_send_changed(Manager *manager, const char *properties);
+
+/* gperf lookup function */
+const struct ConfigPerfItem* logind_gperf_lookup(const char *key, unsigned length);
+
+#endif
diff --git a/src/login/sd-login.c b/src/login/sd-login.c
new file mode 100644
index 0000000..a0a56c4
--- /dev/null
+++ b/src/login/sd-login.c
@@ -0,0 +1,726 @@
+/*-*- 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 <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/inotify.h>
+
+#include "util.h"
+#include "cgroup-util.h"
+#include "macro.h"
+#include "sd-login.h"
+#include "strv.h"
+
+static int pid_get_cgroup(pid_t pid, char **root, char **cgroup) {
+        char *cg_process, *cg_init, *p;
+        int r;
+
+        if (pid == 0)
+                pid = getpid();
+
+        if (pid <= 0)
+                return -EINVAL;
+
+        r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &cg_process);
+        if (r < 0)
+                return r;
+
+        r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &cg_init);
+        if (r < 0) {
+                free(cg_process);
+                return r;
+        }
+
+        if (endswith(cg_init, "/system"))
+                cg_init[strlen(cg_init)-7] = 0;
+        else if (streq(cg_init, "/"))
+                cg_init[0] = 0;
+
+        if (startswith(cg_process, cg_init))
+                p = cg_process + strlen(cg_init);
+        else
+                p = cg_process;
+
+        free(cg_init);
+
+        if (cgroup) {
+                char* c;
+
+                c = strdup(p);
+                if (!c) {
+                        free(cg_process);
+                        return -ENOMEM;
+                }
+
+                *cgroup = c;
+        }
+
+        if (root) {
+                cg_process[p-cg_process] = 0;
+                *root = cg_process;
+        } else
+                free(cg_process);
+
+        return 0;
+}
+
+_public_ int sd_pid_get_session(pid_t pid, char **session) {
+        int r;
+        char *cgroup, *p;
+
+        if (!session)
+                return -EINVAL;
+
+        r = pid_get_cgroup(pid, NULL, &cgroup);
+        if (r < 0)
+                return r;
+
+        if (!startswith(cgroup, "/user/")) {
+                free(cgroup);
+                return -ENOENT;
+        }
+
+        p = strchr(cgroup + 6, '/');
+        if (!p) {
+                free(cgroup);
+                return -ENOENT;
+        }
+
+        p++;
+        if (startswith(p, "shared/") || streq(p, "shared")) {
+                free(cgroup);
+                return -ENOENT;
+        }
+
+        p = strndup(p, strcspn(p, "/"));
+        free(cgroup);
+
+        if (!p)
+                return -ENOMEM;
+
+        *session = p;
+        return 0;
+}
+
+_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
+        int r;
+        char *root, *cgroup, *p, *cc;
+        struct stat st;
+
+        if (!uid)
+                return -EINVAL;
+
+        r = pid_get_cgroup(pid, &root, &cgroup);
+        if (r < 0)
+                return r;
+
+        if (!startswith(cgroup, "/user/")) {
+                free(cgroup);
+                free(root);
+                return -ENOENT;
+        }
+
+        p = strchr(cgroup + 6, '/');
+        if (!p) {
+                free(cgroup);
+                return -ENOENT;
+        }
+
+        p++;
+        p += strcspn(p, "/");
+        *p = 0;
+
+        r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, cgroup, &cc);
+        free(root);
+        free(cgroup);
+
+        if (r < 0)
+                return -ENOMEM;
+
+        r = lstat(cc, &st);
+        free(cc);
+
+        if (r < 0)
+                return -errno;
+
+        if (!S_ISDIR(st.st_mode))
+                return -ENOTDIR;
+
+        *uid = st.st_uid;
+        return 0;
+}
+
+_public_ int sd_uid_get_state(uid_t uid, char**state) {
+        char *p, *s = NULL;
+        int r;
+
+        if (!state)
+                return -EINVAL;
+
+        if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
+        free(p);
+
+        if (r == -ENOENT) {
+                free(s);
+                s = strdup("offline");
+                if (!s)
+                        return -ENOMEM;
+
+                *state = s;
+                return 0;
+        } else if (r < 0) {
+                free(s);
+                return r;
+        } else if (!s)
+                return -EIO;
+
+        *state = s;
+        return 0;
+}
+
+_public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
+        char *p, *w, *t, *state, *s = NULL;
+        size_t l;
+        int r;
+        const char *variable;
+
+        if (!seat)
+                return -EINVAL;
+
+        variable = require_active ? "ACTIVE_UID" : "UIDS";
+
+        p = strappend("/run/systemd/seats/", seat);
+        if (!p)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE, variable, &s, NULL);
+        free(p);
+
+        if (r < 0) {
+                free(s);
+                return r;
+        }
+
+        if (!s)
+                return -EIO;
+
+        if (asprintf(&t, "%lu", (unsigned long) uid) < 0) {
+                free(s);
+                return -ENOMEM;
+        }
+
+        FOREACH_WORD(w, l, s, state) {
+                if (strncmp(t, w, l) == 0) {
+                        free(s);
+                        free(t);
+
+                        return 1;
+                }
+        }
+
+        free(s);
+        free(t);
+
+        return 0;
+}
+
+static int uid_get_array(uid_t uid, const char *variable, char ***array) {
+        char *p, *s = NULL;
+        char **a;
+        int r;
+
+        if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE,
+                           variable, &s,
+                           NULL);
+        free(p);
+
+        if (r < 0) {
+                free(s);
+
+                if (r == -ENOENT) {
+                        if (array)
+                                *array = NULL;
+                        return 0;
+                }
+
+                return r;
+        }
+
+        if (!s) {
+                if (array)
+                        *array = NULL;
+                return 0;
+        }
+
+        a = strv_split(s, " ");
+        free(s);
+
+        if (!a)
+                return -ENOMEM;
+
+        strv_uniq(a);
+        r = strv_length(a);
+
+        if (array)
+                *array = a;
+        else
+                strv_free(a);
+
+        return r;
+}
+
+_public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
+        return uid_get_array(uid, require_active ? "ACTIVE_SESSIONS" : "SESSIONS", sessions);
+}
+
+_public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
+        return uid_get_array(uid, require_active ? "ACTIVE_SEATS" : "SEATS", seats);
+}
+
+_public_ int sd_session_is_active(const char *session) {
+        int r;
+        char *p, *s = NULL;
+
+        if (!session)
+                return -EINVAL;
+
+        p = strappend("/run/systemd/sessions/", session);
+        if (!p)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
+        free(p);
+
+        if (r < 0) {
+                free(s);
+                return r;
+        }
+
+        if (!s)
+                return -EIO;
+
+        r = parse_boolean(s);
+        free(s);
+
+        return r;
+}
+
+_public_ int sd_session_get_uid(const char *session, uid_t *uid) {
+        int r;
+        char *p, *s = NULL;
+
+        if (!session)
+                return -EINVAL;
+        if (!uid)
+                return -EINVAL;
+
+        p = strappend("/run/systemd/sessions/", session);
+        if (!p)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
+        free(p);
+
+        if (r < 0) {
+                free(s);
+                return r;
+        }
+
+        if (!s)
+                return -EIO;
+
+        r = parse_uid(s, uid);
+        free(s);
+
+        return r;
+}
+
+_public_ int sd_session_get_seat(const char *session, char **seat) {
+        char *p, *s = NULL;
+        int r;
+
+        if (!session)
+                return -EINVAL;
+        if (!seat)
+                return -EINVAL;
+
+        p = strappend("/run/systemd/sessions/", session);
+        if (!p)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE, "SEAT", &s, NULL);
+        free(p);
+
+        if (r < 0) {
+                free(s);
+                return r;
+        }
+
+        if (isempty(s))
+                return -ENOENT;
+
+        *seat = s;
+        return 0;
+}
+
+_public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
+        char *p, *s = NULL, *t = NULL;
+        int r;
+
+        if (!seat)
+                return -EINVAL;
+        if (!session && !uid)
+                return -EINVAL;
+
+        p = strappend("/run/systemd/seats/", seat);
+        if (!p)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE,
+                           "ACTIVE", &s,
+                           "ACTIVE_UID", &t,
+                           NULL);
+        free(p);
+
+        if (r < 0) {
+                free(s);
+                free(t);
+                return r;
+        }
+
+        if (session && !s)  {
+                free(t);
+                return -ENOENT;
+        }
+
+        if (uid && !t) {
+                free(s);
+                return -ENOENT;
+        }
+
+        if (uid && t) {
+                r = parse_uid(t, uid);
+                if (r < 0) {
+                        free(t);
+                        free(s);
+                        return r;
+                }
+        }
+
+        free(t);
+
+        if (session && s)
+                *session = s;
+        else
+                free(s);
+
+        return 0;
+}
+
+_public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
+        char *p, *s = NULL, *t = NULL, **a = NULL;
+        uid_t *b = NULL;
+        unsigned n = 0;
+        int r;
+
+        if (!seat)
+                return -EINVAL;
+
+        p = strappend("/run/systemd/seats/", seat);
+        if (!p)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE,
+                           "SESSIONS", &s,
+                           "ACTIVE_SESSIONS", &t,
+                           NULL);
+        free(p);
+
+        if (r < 0) {
+                free(s);
+                free(t);
+                return r;
+        }
+
+        if (s) {
+                a = strv_split(s, " ");
+                if (!a) {
+                        free(s);
+                        free(t);
+                        return -ENOMEM;
+                }
+        }
+
+        free(s);
+
+        if (uids && t) {
+                char *w, *state;
+                size_t l;
+
+                FOREACH_WORD(w, l, t, state)
+                        n++;
+
+                if (n == 0)
+                        b = NULL;
+                else {
+                        unsigned i = 0;
+
+                        b = new(uid_t, n);
+                        if (!b) {
+                                strv_free(a);
+                                return -ENOMEM;
+                        }
+
+                        FOREACH_WORD(w, l, t, state) {
+                                char *k;
+
+                                k = strndup(w, l);
+                                if (!k) {
+                                        free(t);
+                                        free(b);
+                                        strv_free(a);
+                                        return -ENOMEM;
+                                }
+
+                                r = parse_uid(k, b + i);
+                                free(k);
+                                if (r < 0)
+                                        continue;
+
+                                i++;
+                        }
+                }
+        }
+
+        free(t);
+
+        r = strv_length(a);
+
+        if (sessions)
+                *sessions = a;
+        else
+                strv_free(a);
+
+        if (uids)
+                *uids = b;
+
+        if (n_uids)
+                *n_uids = n;
+
+        return r;
+}
+
+_public_ int sd_seat_can_multi_session(const char *seat) {
+        char *p, *s = NULL;
+        int r;
+
+        if (!seat)
+                return -EINVAL;
+
+        p = strappend("/run/systemd/seats/", seat);
+        if (!p)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE,
+                           "IS_VTCONSOLE", &s,
+                           NULL);
+        free(p);
+
+        if (r < 0) {
+                free(s);
+                return r;
+        }
+
+        if (s) {
+                r = parse_boolean(s);
+                free(s);
+        } else
+                r = 0;
+
+        return r;
+}
+
+_public_ int sd_get_seats(char ***seats) {
+        return get_files_in_directory("/run/systemd/seats/", seats);
+}
+
+_public_ int sd_get_sessions(char ***sessions) {
+        return get_files_in_directory("/run/systemd/sessions/", sessions);
+}
+
+_public_ int sd_get_uids(uid_t **users) {
+        DIR *d;
+        int r = 0;
+        unsigned n = 0;
+        uid_t *l = NULL;
+
+        d = opendir("/run/systemd/users/");
+        if (!d)
+                return -errno;
+
+        for (;;) {
+                struct dirent buffer, *de;
+                int k;
+                uid_t uid;
+
+                k = readdir_r(d, &buffer, &de);
+                if (k != 0) {
+                        r = -k;
+                        goto finish;
+                }
+
+                if (!de)
+                        break;
+
+                dirent_ensure_type(d, de);
+
+                if (!dirent_is_file(de))
+                        continue;
+
+                k = parse_uid(de->d_name, &uid);
+                if (k < 0)
+                        continue;
+
+                if (users) {
+                        if ((unsigned) r >= n) {
+                                uid_t *t;
+
+                                n = MAX(16, 2*r);
+                                t = realloc(l, sizeof(uid_t) * n);
+                                if (!t) {
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
+
+                                l = t;
+                        }
+
+                        assert((unsigned) r < n);
+                        l[r++] = uid;
+                } else
+                        r++;
+        }
+
+finish:
+        if (d)
+                closedir(d);
+
+        if (r >= 0) {
+                if (users)
+                        *users = l;
+        } else
+                free(l);
+
+        return r;
+}
+
+static inline int MONITOR_TO_FD(sd_login_monitor *m) {
+        return (int) (unsigned long) m - 1;
+}
+
+static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
+        return (sd_login_monitor*) (unsigned long) (fd + 1);
+}
+
+_public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
+        int fd, k;
+        bool good = false;
+
+        if (!m)
+                return -EINVAL;
+
+        fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
+        if (fd < 0)
+                return errno;
+
+        if (!category || streq(category, "seat")) {
+                k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
+                if (k < 0) {
+                        close_nointr_nofail(fd);
+                        return -errno;
+                }
+
+                good = true;
+        }
+
+        if (!category || streq(category, "session")) {
+                k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
+                if (k < 0) {
+                        close_nointr_nofail(fd);
+                        return -errno;
+                }
+
+                good = true;
+        }
+
+        if (!category || streq(category, "uid")) {
+                k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
+                if (k < 0) {
+                        close_nointr_nofail(fd);
+                        return -errno;
+                }
+
+                good = true;
+        }
+
+        if (!good) {
+                close_nointr(fd);
+                return -EINVAL;
+        }
+
+        *m = FD_TO_MONITOR(fd);
+        return 0;
+}
+
+_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
+        int fd;
+
+        if (!m)
+                return NULL;
+
+        fd = MONITOR_TO_FD(m);
+        close_nointr(fd);
+
+        return NULL;
+}
+
+_public_ int sd_login_monitor_flush(sd_login_monitor *m) {
+
+        if (!m)
+                return -EINVAL;
+
+        return flush_fd(MONITOR_TO_FD(m));
+}
+
+_public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
+
+        if (!m)
+                return -EINVAL;
+
+        return MONITOR_TO_FD(m);
+}
diff --git a/src/login/sd-login.h b/src/login/sd-login.h
new file mode 100644
index 0000000..0cb0bf0
--- /dev/null
+++ b/src/login/sd-login.h
@@ -0,0 +1,121 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foosdloginhfoo
+#define foosdloginhfoo
+
+/***
+  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 <sys/types.h>
+
+/*
+ * A few points:
+ *
+ * Instead of returning an empty string array or empty uid array, we
+ * may return NULL.
+ *
+ * Free the data we return with libc free().
+ *
+ * We return error codes as negative errno, kernel-style. 0 or
+ * positive on success.
+ *
+ * These functions access data in /proc, /sys/fs/cgroup and /run. All
+ * of these are virtual file systems, hence the accesses are
+ * relatively cheap.
+ */
+
+/* Get session from PID. Note that 'shared' processes of a user are
+ * not attached to a session, but only attached to a user. This will
+ * return an error for system processes and 'shared' processes of a
+ * user. */
+int sd_pid_get_session(pid_t pid, char **session);
+
+/* Get UID of the owner of the session of the PID (or in case the
+ * process is a 'shared' user process the UID of that user is
+ * returned). This will not return the UID of the process, but rather
+ * the UID of the owner of the cgroup the process is in. This will
+ * return an error for system processes. */
+int sd_pid_get_owner_uid(pid_t pid, uid_t *uid);
+
+/* Get state from uid. Possible states: offline, lingering, online, active */
+int sd_uid_get_state(uid_t uid, char**state);
+
+/* Return 1 if uid has session on seat. If require_active is true will
+ * look for active sessions only. */
+int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat);
+
+/* Return sessions of user. If require_active is true will look for
+ * active sessions only. Returns number of sessions as return
+ * value. If sessions is NULL will just return number of sessions. */
+int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions);
+
+/* Return seats of user is on. If require_active is true will look for
+ * active seats only.  Returns number of seats. If seats is NULL will
+ * just return number of seats.*/
+int sd_uid_get_seats(uid_t uid, int require_active, char ***seats);
+
+/* Return 1 if the session is a active */
+int sd_session_is_active(const char *session);
+
+/* Determine user id of session */
+int sd_session_get_uid(const char *session, uid_t *uid);
+
+/* Determine seat of session */
+int sd_session_get_seat(const char *session, char **seat);
+
+/* Return active session and user of seat */
+int sd_seat_get_active(const char *seat, char **session, uid_t *uid);
+
+/* Return sessions and users on seat. Returns number of sessions as
+ * return value. If sessions is NULL returns only the number of
+ * sessions. */
+int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uid, unsigned *n_uids);
+
+/* Return whether the seat is multi-session capable */
+int sd_seat_can_multi_session(const char *seat);
+
+/* Get all seats, store in *seats. Returns the number of seats. If
+ * seats is NULL only returns number of seats. */
+int sd_get_seats(char ***seats);
+
+/* Get all sessions, store in *sessions. Returns the number of
+ * sessions. If sessions is NULL only returns number of sessions. */
+int sd_get_sessions(char ***sessions);
+
+/* Get all logged in users, store in *users. Returns the number of
+ * users. If users is NULL only returns the number of users. */
+int sd_get_uids(uid_t **users);
+
+/* Monitor object */
+typedef struct sd_login_monitor sd_login_monitor;
+
+/* Create a new monitor. Category must be NULL, "seat", "session",
+ * "uid" to get monitor events for the specific category (or all). */
+int sd_login_monitor_new(const char *category, sd_login_monitor** ret);
+
+/* Destroys the passed monitor. Returns NULL. */
+sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m);
+
+/* Flushes the monitor */
+int sd_login_monitor_flush(sd_login_monitor *m);
+
+/* Get FD from monitor */
+int sd_login_monitor_get_fd(sd_login_monitor *m);
+
+#endif
diff --git a/src/login/test-login.c b/src/login/test-login.c
new file mode 100644
index 0000000..7d6f082
--- /dev/null
+++ b/src/login/test-login.c
@@ -0,0 +1,170 @@
+/*-*- 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 <sys/poll.h>
+#include <string.h>
+
+#include "sd-login.h"
+#include "util.h"
+#include "strv.h"
+
+int main(int argc, char* argv[]) {
+        int r, k;
+        uid_t u, u2;
+        char *seat;
+        char *session;
+        char *state;
+        char *session2;
+        char *t;
+        char **seats, **sessions;
+        uid_t *uids;
+        unsigned n;
+        struct pollfd pollfd;
+        sd_login_monitor *m;
+
+        assert_se(sd_pid_get_session(0, &session) == 0);
+        printf("session = %s\n", session);
+
+        assert_se(sd_pid_get_owner_uid(0, &u2) == 0);
+        printf("user = %lu\n", (unsigned long) u2);
+
+        r = sd_uid_get_sessions(u2, false, &sessions);
+        assert_se(r >= 0);
+        assert_se(r == (int) strv_length(sessions));
+        assert_se(t = strv_join(sessions, ", "));
+        strv_free(sessions);
+        printf("sessions = %s\n", t);
+        free(t);
+
+        assert_se(r == sd_uid_get_sessions(u2, false, NULL));
+
+        r = sd_uid_get_seats(u2, false, &seats);
+        assert_se(r >= 0);
+        assert_se(r == (int) strv_length(seats));
+        assert_se(t = strv_join(seats, ", "));
+        strv_free(seats);
+        printf("seats = %s\n", t);
+        free(t);
+
+        assert_se(r == sd_uid_get_seats(u2, false, NULL));
+
+        r = sd_session_is_active(session);
+        assert_se(r >= 0);
+        printf("active = %s\n", yes_no(r));
+
+        assert_se(sd_session_get_uid(session, &u) >= 0);
+        printf("uid = %lu\n", (unsigned long) u);
+        assert_se(u == u2);
+
+        assert_se(sd_session_get_seat(session, &seat) >= 0);
+        printf("seat = %s\n", seat);
+
+        r = sd_seat_can_multi_session(seat);
+        assert_se(r >= 0);
+        printf("can do multi session = %s\n", yes_no(r));
+
+        assert_se(sd_uid_get_state(u, &state) >= 0);
+        printf("state = %s\n", state);
+
+        assert_se(sd_uid_is_on_seat(u, 0, seat) > 0);
+
+        k = sd_uid_is_on_seat(u, 1, seat);
+        assert_se(k >= 0);
+        assert_se(!!r == !!r);
+
+        assert_se(sd_seat_get_active(seat, &session2, &u2) >= 0);
+        printf("session2 = %s\n", session2);
+        printf("uid2 = %lu\n", (unsigned long) u2);
+
+        r = sd_seat_get_sessions(seat, &sessions, &uids, &n);
+        assert_se(r >= 0);
+        printf("n_sessions = %i\n", r);
+        assert_se(r == (int) strv_length(sessions));
+        assert_se(t = strv_join(sessions, ", "));
+        strv_free(sessions);
+        printf("sessions = %s\n", t);
+        free(t);
+        printf("uids =");
+        for (k = 0; k < (int) n; k++)
+                printf(" %lu", (unsigned long) uids[k]);
+        printf("\n");
+        free(uids);
+
+        assert_se(sd_seat_get_sessions(seat, NULL, NULL, NULL) == r);
+
+        free(session);
+        free(state);
+        free(session2);
+        free(seat);
+
+        r = sd_get_seats(&seats);
+        assert_se(r >= 0);
+        assert_se(r == (int) strv_length(seats));
+        assert_se(t = strv_join(seats, ", "));
+        strv_free(seats);
+        printf("n_seats = %i\n", r);
+        printf("seats = %s\n", t);
+        free(t);
+
+        assert_se(sd_get_seats(NULL) == r);
+
+        r = sd_get_sessions(&sessions);
+        assert_se(r >= 0);
+        assert_se(r == (int) strv_length(sessions));
+        assert_se(t = strv_join(sessions, ", "));
+        strv_free(sessions);
+        printf("n_sessions = %i\n", r);
+        printf("sessions = %s\n", t);
+        free(t);
+
+        assert_se(sd_get_sessions(NULL) == r);
+
+        r = sd_get_uids(&uids);
+        assert_se(r >= 0);
+
+        printf("uids =");
+        for (k = 0; k < r; k++)
+                printf(" %lu", (unsigned long) uids[k]);
+        printf("\n");
+        free(uids);
+
+        printf("n_uids = %i\n", r);
+        assert_se(sd_get_uids(NULL) == r);
+
+        r = sd_login_monitor_new("session", &m);
+        assert_se(r >= 0);
+
+        zero(pollfd);
+        pollfd.fd = sd_login_monitor_get_fd(m);
+        pollfd.events = POLLIN;
+
+        for (n = 0; n < 5; n++) {
+                r = poll(&pollfd, 1, -1);
+                assert_se(r >= 0);
+
+                sd_login_monitor_flush(m);
+                printf("Wake!\n");
+        }
+
+        sd_login_monitor_unref(m);
+
+        return 0;
+}
diff --git a/src/login/uaccess.c b/src/login/uaccess.c
new file mode 100644
index 0000000..49ac4af
--- /dev/null
+++ b/src/login/uaccess.c
@@ -0,0 +1,90 @@
+/*-*- 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 <string.h>
+
+#include "logind-acl.h"
+#include "util.h"
+#include "log.h"
+#include "sd-daemon.h"
+#include "sd-login.h"
+
+int main(int argc, char *argv[]) {
+        int r;
+        const char *path = NULL, *seat;
+        bool changed_acl = false;
+        uid_t uid;
+
+        log_set_target(LOG_TARGET_AUTO);
+        log_parse_environment();
+        log_open();
+
+        umask(0022);
+
+        if (argc < 2 || argc > 3) {
+                log_error("This program expects one or two arguments.");
+                r = -EINVAL;
+                goto finish;
+        }
+
+        /* Make sure we don't muck around with ACLs the system is not
+         * running systemd. */
+        if (!sd_booted())
+                return 0;
+
+        path = argv[1];
+        seat = argc < 3 || isempty(argv[2]) ? "seat0" : argv[2];
+
+        r = sd_seat_get_active(seat, NULL, &uid);
+        if (r == -ENOENT) {
+                /* No active session on this seat */
+                r = 0;
+                goto finish;
+        } else if (r < 0) {
+                log_error("Failed to determine active user on seat %s.", seat);
+                goto finish;
+        }
+
+        r = devnode_acl(path, true, false, 0, true, uid);
+        if (r < 0) {
+                log_error("Failed to apply ACL on %s: %s", path, strerror(-r));
+                goto finish;
+        }
+
+        changed_acl = true;
+        r = 0;
+
+finish:
+        if (path && !changed_acl) {
+                int k;
+                /* Better be safe that sorry and reset ACL */
+
+                k = devnode_acl(path, true, false, 0, false, 0);
+                if (k < 0) {
+                        log_error("Failed to apply ACL on %s: %s", path, strerror(-k));
+                        if (r >= 0)
+                                r = k;
+                }
+        }
+
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/loginctl.c b/src/loginctl.c
deleted file mode 100644
index 1be47c8..0000000
--- a/src/loginctl.c
+++ /dev/null
@@ -1,1914 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU 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 <dbus/dbus.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <getopt.h>
-#include <pwd.h>
-
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-#include "pager.h"
-#include "dbus-common.h"
-#include "build.h"
-#include "strv.h"
-#include "cgroup-show.h"
-#include "sysfs-show.h"
-
-static char **arg_property = NULL;
-static bool arg_all = false;
-static bool arg_no_pager = false;
-static const char *arg_kill_who = NULL;
-static int arg_signal = SIGTERM;
-static enum transport {
-        TRANSPORT_NORMAL,
-        TRANSPORT_SSH,
-        TRANSPORT_POLKIT
-} arg_transport = TRANSPORT_NORMAL;
-static const char *arg_host = NULL;
-
-static bool on_tty(void) {
-        static int t = -1;
-
-        /* Note that this is invoked relatively early, before we start
-         * the pager. That means the value we return reflects whether
-         * we originally were started on a tty, not if we currently
-         * are. But this is intended, since we want colour and so on
-         * when run in our own pager. */
-
-        if (_unlikely_(t < 0))
-                t = isatty(STDOUT_FILENO) > 0;
-
-        return t;
-}
-
-static void pager_open_if_enabled(void) {
-
-        /* Cache result before we open the pager */
-        on_tty();
-
-        if (!arg_no_pager)
-                pager_open();
-}
-
-static int list_sessions(DBusConnection *bus, char **args, unsigned n) {
-        DBusMessage *m = NULL, *reply = NULL;
-        DBusError error;
-        int r;
-        DBusMessageIter iter, sub, sub2;
-        unsigned k = 0;
-
-        dbus_error_init(&error);
-
-        assert(bus);
-
-        pager_open_if_enabled();
-
-        m = dbus_message_new_method_call(
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "ListSessions");
-        if (!m) {
-                log_error("Could not allocate message.");
-                return -ENOMEM;
-        }
-
-        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-        if (!reply) {
-                log_error("Failed to issue method call: %s", bus_error_message(&error));
-                r = -EIO;
-                goto finish;
-        }
-
-        if (!dbus_message_iter_init(reply, &iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
-            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
-                log_error("Failed to parse reply.");
-                r = -EIO;
-                goto finish;
-        }
-
-        dbus_message_iter_recurse(&iter, &sub);
-
-        if (on_tty())
-                printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
-
-        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                const char *id, *user, *seat, *object;
-                uint32_t uid;
-
-                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
-                        log_error("Failed to parse reply.");
-                        r = -EIO;
-                        goto finish;
-                }
-
-                dbus_message_iter_recurse(&sub, &sub2);
-
-                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &user, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &seat, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
-                        log_error("Failed to parse reply.");
-                        r = -EIO;
-                        goto finish;
-                }
-
-                printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
-
-                k++;
-
-                dbus_message_iter_next(&sub);
-        }
-
-        if (on_tty())
-                printf("\n%u sessions listed.\n", k);
-
-        r = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return r;
-}
-
-static int list_users(DBusConnection *bus, char **args, unsigned n) {
-        DBusMessage *m = NULL, *reply = NULL;
-        DBusError error;
-        int r;
-        DBusMessageIter iter, sub, sub2;
-        unsigned k = 0;
-
-        dbus_error_init(&error);
-
-        assert(bus);
-
-        pager_open_if_enabled();
-
-        m = dbus_message_new_method_call(
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "ListUsers");
-        if (!m) {
-                log_error("Could not allocate message.");
-                return -ENOMEM;
-        }
-
-        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-        if (!reply) {
-                log_error("Failed to issue method call: %s", bus_error_message(&error));
-                r = -EIO;
-                goto finish;
-        }
-
-        if (!dbus_message_iter_init(reply, &iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
-            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
-                log_error("Failed to parse reply.");
-                r = -EIO;
-                goto finish;
-        }
-
-        dbus_message_iter_recurse(&iter, &sub);
-
-        if (on_tty())
-                printf("%10s %-16s\n", "UID", "USER");
-
-        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                const char *user, *object;
-                uint32_t uid;
-
-                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
-                        log_error("Failed to parse reply.");
-                        r = -EIO;
-                        goto finish;
-                }
-
-                dbus_message_iter_recurse(&sub, &sub2);
-
-                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &user, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
-                        log_error("Failed to parse reply.");
-                        r = -EIO;
-                        goto finish;
-                }
-
-                printf("%10u %-16s\n", (unsigned) uid, user);
-
-                k++;
-
-                dbus_message_iter_next(&sub);
-        }
-
-        if (on_tty())
-                printf("\n%u users listed.\n", k);
-
-        r = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return r;
-}
-
-static int list_seats(DBusConnection *bus, char **args, unsigned n) {
-        DBusMessage *m = NULL, *reply = NULL;
-        DBusError error;
-        int r;
-        DBusMessageIter iter, sub, sub2;
-        unsigned k = 0;
-
-        dbus_error_init(&error);
-
-        assert(bus);
-
-        pager_open_if_enabled();
-
-        m = dbus_message_new_method_call(
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "ListSeats");
-        if (!m) {
-                log_error("Could not allocate message.");
-                return -ENOMEM;
-        }
-
-        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-        if (!reply) {
-                log_error("Failed to issue method call: %s", bus_error_message(&error));
-                r = -EIO;
-                goto finish;
-        }
-
-        if (!dbus_message_iter_init(reply, &iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
-            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
-                log_error("Failed to parse reply.");
-                r = -EIO;
-                goto finish;
-        }
-
-        dbus_message_iter_recurse(&iter, &sub);
-
-        if (on_tty())
-                printf("%-16s\n", "SEAT");
-
-        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                const char *seat, *object;
-
-                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
-                        log_error("Failed to parse reply.");
-                        r = -EIO;
-                        goto finish;
-                }
-
-                dbus_message_iter_recurse(&sub, &sub2);
-
-                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &seat, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
-                        log_error("Failed to parse reply.");
-                        r = -EIO;
-                        goto finish;
-                }
-
-                printf("%-16s\n", seat);
-
-                k++;
-
-                dbus_message_iter_next(&sub);
-        }
-
-        if (on_tty())
-                printf("\n%u seats listed.\n", k);
-
-        r = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return r;
-}
-
-typedef struct SessionStatusInfo {
-        const char *id;
-        uid_t uid;
-        const char *name;
-        usec_t timestamp;
-        const char *control_group;
-        int vtnr;
-        const char *seat;
-        const char *tty;
-        const char *display;
-        bool remote;
-        const char *remote_host;
-        const char *remote_user;
-        const char *service;
-        pid_t leader;
-        const char *type;
-        bool active;
-} SessionStatusInfo;
-
-typedef struct UserStatusInfo {
-        uid_t uid;
-        const char *name;
-        usec_t timestamp;
-        const char *control_group;
-        const char *state;
-        char **sessions;
-        const char *display;
-} UserStatusInfo;
-
-typedef struct SeatStatusInfo {
-        const char *id;
-        const char *active_session;
-        char **sessions;
-} SeatStatusInfo;
-
-static void print_session_status_info(SessionStatusInfo *i) {
-        char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
-        char since2[FORMAT_TIMESTAMP_MAX], *s2;
-        assert(i);
-
-        printf("%s - ", strna(i->id));
-
-        if (i->name)
-                printf("%s (%u)\n", i->name, (unsigned) i->uid);
-        else
-                printf("%u\n", (unsigned) i->uid);
-
-        s1 = format_timestamp_pretty(since1, sizeof(since1), i->timestamp);
-        s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
-
-        if (s1)
-                printf("\t   Since: %s; %s\n", s2, s1);
-        else if (s2)
-                printf("\t   Since: %s\n", s2);
-
-        if (i->leader > 0) {
-                char *t = NULL;
-
-                printf("\t  Leader: %u", (unsigned) i->leader);
-
-                get_process_comm(i->leader, &t);
-                if (t) {
-                        printf(" (%s)", t);
-                        free(t);
-                }
-
-                printf("\n");
-        }
-
-        if (i->seat) {
-                printf("\t    Seat: %s", i->seat);
-
-                if (i->vtnr > 0)
-                        printf("; vc%i", i->vtnr);
-
-                printf("\n");
-        }
-
-        if (i->tty)
-                printf("\t     TTY: %s\n", i->tty);
-        else if (i->display)
-                printf("\t Display: %s\n", i->display);
-
-        if (i->remote_host && i->remote_user)
-                printf("\t  Remote: %s@%s\n", i->remote_user, i->remote_host);
-        else if (i->remote_host)
-                printf("\t  Remote: %s\n", i->remote_host);
-        else if (i->remote_user)
-                printf("\t  Remote: user %s\n", i->remote_user);
-        else if (i->remote)
-                printf("\t  Remote: Yes\n");
-
-        if (i->service) {
-                printf("\t Service: %s", i->service);
-
-                if (i->type)
-                        printf("; type %s", i->type);
-
-                printf("\n");
-        } else if (i->type)
-                printf("\t    Type: %s\n", i->type);
-
-        printf("\t  Active: %s\n", yes_no(i->active));
-
-        if (i->control_group) {
-                unsigned c;
-
-                printf("\t  CGroup: %s\n", i->control_group);
-
-                if (arg_transport != TRANSPORT_SSH) {
-                        c = columns();
-                        if (c > 18)
-                                c -= 18;
-                        else
-                                c = 0;
-
-                        show_cgroup_by_path(i->control_group, "\t\t  ", c);
-                }
-        }
-}
-
-static void print_user_status_info(UserStatusInfo *i) {
-        char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
-        char since2[FORMAT_TIMESTAMP_MAX], *s2;
-        assert(i);
-
-        if (i->name)
-                printf("%s (%u)\n", i->name, (unsigned) i->uid);
-        else
-                printf("%u\n", (unsigned) i->uid);
-
-        s1 = format_timestamp_pretty(since1, sizeof(since1), i->timestamp);
-        s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
-
-        if (s1)
-                printf("\t   Since: %s; %s\n", s2, s1);
-        else if (s2)
-                printf("\t   Since: %s\n", s2);
-
-        if (!isempty(i->state))
-                printf("\t   State: %s\n", i->state);
-
-        if (!strv_isempty(i->sessions)) {
-                char **l;
-                printf("\tSessions:");
-
-                STRV_FOREACH(l, i->sessions) {
-                        if (streq_ptr(*l, i->display))
-                                printf(" *%s", *l);
-                        else
-                                printf(" %s", *l);
-                }
-
-                printf("\n");
-        }
-
-        if (i->control_group) {
-                unsigned c;
-
-                printf("\t  CGroup: %s\n", i->control_group);
-
-                if (arg_transport != TRANSPORT_SSH) {
-                        c = columns();
-                        if (c > 18)
-                                c -= 18;
-                        else
-                                c = 0;
-
-                        show_cgroup_by_path(i->control_group, "\t\t  ", c);
-                }
-        }
-}
-
-static void print_seat_status_info(SeatStatusInfo *i) {
-        assert(i);
-
-        printf("%s\n", strna(i->id));
-
-        if (!strv_isempty(i->sessions)) {
-                char **l;
-                printf("\tSessions:");
-
-                STRV_FOREACH(l, i->sessions) {
-                        if (streq_ptr(*l, i->active_session))
-                                printf(" *%s", *l);
-                        else
-                                printf(" %s", *l);
-                }
-
-                printf("\n");
-        }
-
-        if (arg_transport != TRANSPORT_SSH) {
-                unsigned c;
-
-                c = columns();
-                if (c > 21)
-                        c -= 21;
-                else
-                        c = 0;
-
-                printf("\t Devices:\n");
-
-                show_sysfs(i->id, "\t\t  ", c);
-        }
-}
-
-static int status_property_session(const char *name, DBusMessageIter *iter, SessionStatusInfo *i) {
-        assert(name);
-        assert(iter);
-        assert(i);
-
-        switch (dbus_message_iter_get_arg_type(iter)) {
-
-        case DBUS_TYPE_STRING: {
-                const char *s;
-
-                dbus_message_iter_get_basic(iter, &s);
-
-                if (!isempty(s)) {
-                        if (streq(name, "Id"))
-                                i->id = s;
-                        else if (streq(name, "Name"))
-                                i->name = s;
-                        else if (streq(name, "ControlGroupPath"))
-                                i->control_group = s;
-                        else if (streq(name, "TTY"))
-                                i->tty = s;
-                        else if (streq(name, "Display"))
-                                i->display = s;
-                        else if (streq(name, "RemoteHost"))
-                                i->remote_host = s;
-                        else if (streq(name, "RemoteUser"))
-                                i->remote_user = s;
-                        else if (streq(name, "Service"))
-                                i->service = s;
-                        else if (streq(name, "Type"))
-                                i->type = s;
-                }
-                break;
-        }
-
-        case DBUS_TYPE_UINT32: {
-                uint32_t u;
-
-                dbus_message_iter_get_basic(iter, &u);
-
-                if (streq(name, "VTNr"))
-                        i->vtnr = (int) u;
-                else if (streq(name, "Leader"))
-                        i->leader = (pid_t) u;
-
-                break;
-        }
-
-        case DBUS_TYPE_BOOLEAN: {
-                dbus_bool_t b;
-
-                dbus_message_iter_get_basic(iter, &b);
-
-                if (streq(name, "Remote"))
-                        i->remote = b;
-                else if (streq(name, "Active"))
-                        i->active = b;
-
-                break;
-        }
-
-        case DBUS_TYPE_UINT64: {
-                uint64_t u;
-
-                dbus_message_iter_get_basic(iter, &u);
-
-                if (streq(name, "Timestamp"))
-                        i->timestamp = (usec_t) u;
-
-                break;
-        }
-
-        case DBUS_TYPE_STRUCT: {
-                DBusMessageIter sub;
-
-                dbus_message_iter_recurse(iter, &sub);
-
-                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "User")) {
-                        uint32_t u;
-
-                        dbus_message_iter_get_basic(&sub, &u);
-                        i->uid = (uid_t) u;
-
-                } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Seat")) {
-                        const char *s;
-
-                        dbus_message_iter_get_basic(&sub, &s);
-
-                        if (!isempty(s))
-                                i->seat = s;
-                }
-
-                break;
-        }
-        }
-
-        return 0;
-}
-
-static int status_property_user(const char *name, DBusMessageIter *iter, UserStatusInfo *i) {
-        assert(name);
-        assert(iter);
-        assert(i);
-
-        switch (dbus_message_iter_get_arg_type(iter)) {
-
-        case DBUS_TYPE_STRING: {
-                const char *s;
-
-                dbus_message_iter_get_basic(iter, &s);
-
-                if (!isempty(s)) {
-                        if (streq(name, "Name"))
-                                i->name = s;
-                        else if (streq(name, "ControlGroupPath"))
-                                i->control_group = s;
-                        else if (streq(name, "State"))
-                                i->state = s;
-                }
-                break;
-        }
-
-        case DBUS_TYPE_UINT32: {
-                uint32_t u;
-
-                dbus_message_iter_get_basic(iter, &u);
-
-                if (streq(name, "UID"))
-                        i->uid = (uid_t) u;
-
-                break;
-        }
-
-        case DBUS_TYPE_UINT64: {
-                uint64_t u;
-
-                dbus_message_iter_get_basic(iter, &u);
-
-                if (streq(name, "Timestamp"))
-                        i->timestamp = (usec_t) u;
-
-                break;
-        }
-
-        case DBUS_TYPE_STRUCT: {
-                DBusMessageIter sub;
-
-                dbus_message_iter_recurse(iter, &sub);
-
-                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Display")) {
-                        const char *s;
-
-                        dbus_message_iter_get_basic(&sub, &s);
-
-                        if (!isempty(s))
-                                i->display = s;
-                }
-
-                break;
-        }
-
-        case DBUS_TYPE_ARRAY: {
-
-                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
-                        DBusMessageIter sub, sub2;
-
-                        dbus_message_iter_recurse(iter, &sub);
-                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
-                                const char *id;
-                                const char *path;
-
-                                dbus_message_iter_recurse(&sub, &sub2);
-
-                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
-                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
-                                        char **l;
-
-                                        l = strv_append(i->sessions, id);
-                                        if (!l)
-                                                return -ENOMEM;
-
-                                        strv_free(i->sessions);
-                                        i->sessions = l;
-                                }
-
-                                dbus_message_iter_next(&sub);
-                        }
-
-                        return 0;
-                }
-        }
-        }
-
-        return 0;
-}
-
-static int status_property_seat(const char *name, DBusMessageIter *iter, SeatStatusInfo *i) {
-        assert(name);
-        assert(iter);
-        assert(i);
-
-        switch (dbus_message_iter_get_arg_type(iter)) {
-
-        case DBUS_TYPE_STRING: {
-                const char *s;
-
-                dbus_message_iter_get_basic(iter, &s);
-
-                if (!isempty(s)) {
-                        if (streq(name, "Id"))
-                                i->id = s;
-                }
-                break;
-        }
-
-        case DBUS_TYPE_STRUCT: {
-                DBusMessageIter sub;
-
-                dbus_message_iter_recurse(iter, &sub);
-
-                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "ActiveSession")) {
-                        const char *s;
-
-                        dbus_message_iter_get_basic(&sub, &s);
-
-                        if (!isempty(s))
-                                i->active_session = s;
-                }
-
-                break;
-        }
-
-        case DBUS_TYPE_ARRAY: {
-
-                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
-                        DBusMessageIter sub, sub2;
-
-                        dbus_message_iter_recurse(iter, &sub);
-                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
-                                const char *id;
-                                const char *path;
-
-                                dbus_message_iter_recurse(&sub, &sub2);
-
-                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
-                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
-                                        char **l;
-
-                                        l = strv_append(i->sessions, id);
-                                        if (!l)
-                                                return -ENOMEM;
-
-                                        strv_free(i->sessions);
-                                        i->sessions = l;
-                                }
-
-                                dbus_message_iter_next(&sub);
-                        }
-
-                        return 0;
-                }
-        }
-        }
-
-        return 0;
-}
-
-static int print_property(const char *name, DBusMessageIter *iter) {
-        assert(name);
-        assert(iter);
-
-        if (arg_property && !strv_find(arg_property, name))
-                return 0;
-
-        switch (dbus_message_iter_get_arg_type(iter)) {
-
-        case DBUS_TYPE_STRUCT: {
-                DBusMessageIter sub;
-
-                dbus_message_iter_recurse(iter, &sub);
-
-                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING &&
-                    (streq(name, "Display") || streq(name, "ActiveSession"))) {
-                        const char *s;
-
-                        dbus_message_iter_get_basic(&sub, &s);
-
-                        if (arg_all || !isempty(s))
-                                printf("%s=%s\n", name, s);
-                        return 0;
-                }
-                break;
-        }
-
-        case DBUS_TYPE_ARRAY:
-
-                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
-                        DBusMessageIter sub, sub2;
-                        bool found = false;
-
-                        dbus_message_iter_recurse(iter, &sub);
-                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
-                                const char *id;
-                                const char *path;
-
-                                dbus_message_iter_recurse(&sub, &sub2);
-
-                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
-                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
-                                        if (found)
-                                                printf(" %s", id);
-                                        else {
-                                                printf("%s=%s", name, id);
-                                                found = true;
-                                        }
-                                }
-
-                                dbus_message_iter_next(&sub);
-                        }
-
-                        if (!found && arg_all)
-                                printf("%s=\n", name);
-                        else if (found)
-                                printf("\n");
-
-                        return 0;
-                }
-
-                break;
-        }
-
-        if (generic_print_property(name, iter, arg_all) > 0)
-                return 0;
-
-        if (arg_all)
-                printf("%s=[unprintable]\n", name);
-
-        return 0;
-}
-
-static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
-        DBusMessage *m = NULL, *reply = NULL;
-        const char *interface = "";
-        int r;
-        DBusError error;
-        DBusMessageIter iter, sub, sub2, sub3;
-        SessionStatusInfo session_info;
-        UserStatusInfo user_info;
-        SeatStatusInfo seat_info;
-
-        assert(bus);
-        assert(path);
-        assert(new_line);
-
-        zero(session_info);
-        zero(user_info);
-        zero(seat_info);
-
-        dbus_error_init(&error);
-
-        m = dbus_message_new_method_call(
-                        "org.freedesktop.login1",
-                        path,
-                        "org.freedesktop.DBus.Properties",
-                        "GetAll");
-        if (!m) {
-                log_error("Could not allocate message.");
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (!dbus_message_append_args(m,
-                                      DBUS_TYPE_STRING, &interface,
-                                      DBUS_TYPE_INVALID)) {
-                log_error("Could not append arguments to message.");
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-        if (!reply) {
-                log_error("Failed to issue method call: %s", bus_error_message(&error));
-                r = -EIO;
-                goto finish;
-        }
-
-        if (!dbus_message_iter_init(reply, &iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
-            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
-                log_error("Failed to parse reply.");
-                r = -EIO;
-                goto finish;
-        }
-
-        dbus_message_iter_recurse(&iter, &sub);
-
-        if (*new_line)
-                printf("\n");
-
-        *new_line = true;
-
-        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                const char *name;
-
-                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
-                        log_error("Failed to parse reply.");
-                        r = -EIO;
-                        goto finish;
-                }
-
-                dbus_message_iter_recurse(&sub, &sub2);
-
-                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
-                        log_error("Failed to parse reply.");
-                        r = -EIO;
-                        goto finish;
-                }
-
-                if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
-                        log_error("Failed to parse reply.");
-                        r = -EIO;
-                        goto finish;
-                }
-
-                dbus_message_iter_recurse(&sub2, &sub3);
-
-                if (show_properties)
-                        r = print_property(name, &sub3);
-                else if (strstr(verb, "session"))
-                        r = status_property_session(name, &sub3, &session_info);
-                else if (strstr(verb, "user"))
-                        r = status_property_user(name, &sub3, &user_info);
-                else
-                        r = status_property_seat(name, &sub3, &seat_info);
-
-                if (r < 0) {
-                        log_error("Failed to parse reply.");
-                        r = -EIO;
-                        goto finish;
-                }
-
-                dbus_message_iter_next(&sub);
-        }
-
-        if (!show_properties) {
-                if (strstr(verb, "session"))
-                        print_session_status_info(&session_info);
-                else if (strstr(verb, "user"))
-                        print_user_status_info(&user_info);
-                else
-                        print_seat_status_info(&seat_info);
-        }
-
-        strv_free(seat_info.sessions);
-        strv_free(user_info.sessions);
-
-        r = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return r;
-}
-
-static int show(DBusConnection *bus, char **args, unsigned n) {
-        DBusMessage *m = NULL, *reply = NULL;
-        int r, ret = 0;
-        DBusError error;
-        unsigned i;
-        bool show_properties, new_line = false;
-
-        assert(bus);
-        assert(args);
-
-        dbus_error_init(&error);
-
-        show_properties = !strstr(args[0], "status");
-
-        if (show_properties)
-                pager_open_if_enabled();
-
-        if (show_properties && n <= 1) {
-                /* If not argument is specified inspect the manager
-                 * itself */
-
-                ret = show_one(args[0], bus, "/org/freedesktop/login1", show_properties, &new_line);
-                goto finish;
-        }
-
-        for (i = 1; i < n; i++) {
-                const char *path = NULL;
-
-                if (strstr(args[0], "session")) {
-
-                        m = dbus_message_new_method_call(
-                                        "org.freedesktop.login1",
-                                        "/org/freedesktop/login1",
-                                        "org.freedesktop.login1.Manager",
-                                        "GetSession");
-                        if (!m) {
-                                log_error("Could not allocate message.");
-                                ret = -ENOMEM;
-                                goto finish;
-                        }
-
-                        if (!dbus_message_append_args(m,
-                                                      DBUS_TYPE_STRING, &args[i],
-                                                      DBUS_TYPE_INVALID)) {
-                                log_error("Could not append arguments to message.");
-                                ret = -ENOMEM;
-                                goto finish;
-                        }
-
-                } else if (strstr(args[0], "user")) {
-                        uid_t uid;
-                        uint32_t u;
-
-                        ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
-                        if (ret < 0) {
-                                log_error("User %s unknown.", args[i]);
-                                goto finish;
-                        }
-
-                        m = dbus_message_new_method_call(
-                                        "org.freedesktop.login1",
-                                        "/org/freedesktop/login1",
-                                        "org.freedesktop.login1.Manager",
-                                        "GetUser");
-                        if (!m) {
-                                log_error("Could not allocate message.");
-                                ret = -ENOMEM;
-                                goto finish;
-                        }
-
-                        u = (uint32_t) uid;
-                        if (!dbus_message_append_args(m,
-                                                      DBUS_TYPE_UINT32, &u,
-                                                      DBUS_TYPE_INVALID)) {
-                                log_error("Could not append arguments to message.");
-                                ret = -ENOMEM;
-                                goto finish;
-                        }
-                } else {
-
-                        m = dbus_message_new_method_call(
-                                        "org.freedesktop.login1",
-                                        "/org/freedesktop/login1",
-                                        "org.freedesktop.login1.Manager",
-                                        "GetSeat");
-                        if (!m) {
-                                log_error("Could not allocate message.");
-                                ret = -ENOMEM;
-                                goto finish;
-                        }
-
-                        if (!dbus_message_append_args(m,
-                                                      DBUS_TYPE_STRING, &args[i],
-                                                      DBUS_TYPE_INVALID)) {
-                                log_error("Could not append arguments to message.");
-                                ret = -ENOMEM;
-                                goto finish;
-                        }
-                }
-
-                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-                if (!reply) {
-                        log_error("Failed to issue method call: %s", bus_error_message(&error));
-                        ret = -EIO;
-                        goto finish;
-                }
-
-                if (!dbus_message_get_args(reply, &error,
-                                           DBUS_TYPE_OBJECT_PATH, &path,
-                                           DBUS_TYPE_INVALID)) {
-                        log_error("Failed to parse reply: %s", bus_error_message(&error));
-                        ret = -EIO;
-                        goto finish;
-                }
-
-                r = show_one(args[0], bus, path, show_properties, &new_line);
-                if (r != 0)
-                        ret = r;
-
-                dbus_message_unref(m);
-                dbus_message_unref(reply);
-                m = reply = NULL;
-        }
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return ret;
-}
-
-static int activate(DBusConnection *bus, char **args, unsigned n) {
-        DBusMessage *m = NULL;
-        int ret = 0;
-        DBusError error;
-        unsigned i;
-
-        assert(bus);
-        assert(args);
-
-        dbus_error_init(&error);
-
-        for (i = 1; i < n; i++) {
-                DBusMessage *reply;
-
-                m = dbus_message_new_method_call(
-                                "org.freedesktop.login1",
-                                "/org/freedesktop/login1",
-                                "org.freedesktop.login1.Manager",
-                                streq(args[0], "lock-session")      ? "LockSession" :
-                                streq(args[0], "unlock-session")    ? "UnlockSession" :
-                                streq(args[0], "terminate-session") ? "TerminateSession" :
-                                                                      "ActivateSession");
-                if (!m) {
-                        log_error("Could not allocate message.");
-                        ret = -ENOMEM;
-                        goto finish;
-                }
-
-                if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_STRING, &args[i],
-                                              DBUS_TYPE_INVALID)) {
-                        log_error("Could not append arguments to message.");
-                        ret = -ENOMEM;
-                        goto finish;
-                }
-
-                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-                if (!reply) {
-                        log_error("Failed to issue method call: %s", bus_error_message(&error));
-                        ret = -EIO;
-                        goto finish;
-                }
-
-                dbus_message_unref(m);
-                dbus_message_unref(reply);
-                m = reply = NULL;
-        }
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        dbus_error_free(&error);
-
-        return ret;
-}
-
-static int kill_session(DBusConnection *bus, char **args, unsigned n) {
-        DBusMessage *m = NULL;
-        int ret = 0;
-        DBusError error;
-        unsigned i;
-
-        assert(bus);
-        assert(args);
-
-        dbus_error_init(&error);
-
-        if (!arg_kill_who)
-                arg_kill_who = "all";
-
-        for (i = 1; i < n; i++) {
-                DBusMessage *reply;
-
-                m = dbus_message_new_method_call(
-                                "org.freedesktop.login1",
-                                "/org/freedesktop/login1",
-                                "org.freedesktop.login1.Manager",
-                                "KillSession");
-                if (!m) {
-                        log_error("Could not allocate message.");
-                        ret = -ENOMEM;
-                        goto finish;
-                }
-
-                if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_STRING, &args[i],
-                                              DBUS_TYPE_STRING, &arg_kill_who,
-                                              DBUS_TYPE_INT32, arg_signal,
-                                              DBUS_TYPE_INVALID)) {
-                        log_error("Could not append arguments to message.");
-                        ret = -ENOMEM;
-                        goto finish;
-                }
-
-                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-                if (!reply) {
-                        log_error("Failed to issue method call: %s", bus_error_message(&error));
-                        ret = -EIO;
-                        goto finish;
-                }
-
-                dbus_message_unref(m);
-                dbus_message_unref(reply);
-                m = reply = NULL;
-        }
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        dbus_error_free(&error);
-
-        return ret;
-}
-
-static int enable_linger(DBusConnection *bus, char **args, unsigned n) {
-        DBusMessage *m = NULL;
-        int ret = 0;
-        DBusError error;
-        unsigned i;
-        dbus_bool_t b, interactive = true;
-
-        assert(bus);
-        assert(args);
-
-        dbus_error_init(&error);
-
-        b = streq(args[0], "enable-linger");
-
-        for (i = 1; i < n; i++) {
-                DBusMessage *reply;
-                uint32_t u;
-                uid_t uid;
-
-                m = dbus_message_new_method_call(
-                                "org.freedesktop.login1",
-                                "/org/freedesktop/login1",
-                                "org.freedesktop.login1.Manager",
-                                "SetUserLinger");
-                if (!m) {
-                        log_error("Could not allocate message.");
-                        ret = -ENOMEM;
-                        goto finish;
-                }
-
-                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
-                if (ret < 0) {
-                        log_error("Failed to resolve user %s: %s", args[i], strerror(-ret));
-                        goto finish;
-                }
-
-                u = (uint32_t) uid;
-                if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_UINT32, &u,
-                                              DBUS_TYPE_BOOLEAN, &b,
-                                              DBUS_TYPE_BOOLEAN, &interactive,
-                                              DBUS_TYPE_INVALID)) {
-                        log_error("Could not append arguments to message.");
-                        ret = -ENOMEM;
-                        goto finish;
-                }
-
-                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-                if (!reply) {
-                        log_error("Failed to issue method call: %s", bus_error_message(&error));
-                        ret = -EIO;
-                        goto finish;
-                }
-
-                dbus_message_unref(m);
-                dbus_message_unref(reply);
-                m = reply = NULL;
-        }
-
-        ret = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        dbus_error_free(&error);
-
-        return ret;
-}
-
-static int terminate_user(DBusConnection *bus, char **args, unsigned n) {
-        DBusMessage *m = NULL;
-        int ret = 0;
-        DBusError error;
-        unsigned i;
-
-        assert(bus);
-        assert(args);
-
-        dbus_error_init(&error);
-
-        for (i = 1; i < n; i++) {
-                uint32_t u;
-                uid_t uid;
-                DBusMessage *reply;
-
-                m = dbus_message_new_method_call(
-                                "org.freedesktop.login1",
-                                "/org/freedesktop/login1",
-                                "org.freedesktop.login1.Manager",
-                                "TerminateUser");
-                if (!m) {
-                        log_error("Could not allocate message.");
-                        ret = -ENOMEM;
-                        goto finish;
-                }
-
-                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
-                if (ret < 0) {
-                        log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
-                        goto finish;
-                }
-
-                u = (uint32_t) uid;
-                if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_UINT32, &u,
-                                              DBUS_TYPE_INVALID)) {
-                        log_error("Could not append arguments to message.");
-                        ret = -ENOMEM;
-                        goto finish;
-                }
-
-                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-                if (!reply) {
-                        log_error("Failed to issue method call: %s", bus_error_message(&error));
-                        ret = -EIO;
-                        goto finish;
-                }
-
-                dbus_message_unref(m);
-                dbus_message_unref(reply);
-                m = reply = NULL;
-        }
-
-        ret = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        dbus_error_free(&error);
-
-        return ret;
-}
-
-static int kill_user(DBusConnection *bus, char **args, unsigned n) {
-        DBusMessage *m = NULL;
-        int ret = 0;
-        DBusError error;
-        unsigned i;
-
-        assert(bus);
-        assert(args);
-
-        dbus_error_init(&error);
-
-        if (!arg_kill_who)
-                arg_kill_who = "all";
-
-        for (i = 1; i < n; i++) {
-                DBusMessage *reply;
-                uid_t uid;
-                uint32_t u;
-
-                m = dbus_message_new_method_call(
-                                "org.freedesktop.login1",
-                                "/org/freedesktop/login1",
-                                "org.freedesktop.login1.Manager",
-                                "KillUser");
-                if (!m) {
-                        log_error("Could not allocate message.");
-                        ret = -ENOMEM;
-                        goto finish;
-                }
-
-                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
-                if (ret < 0) {
-                        log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
-                        goto finish;
-                }
-
-                u = (uint32_t) uid;
-                if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_UINT32, &u,
-                                              DBUS_TYPE_INT32, arg_signal,
-                                              DBUS_TYPE_INVALID)) {
-                        log_error("Could not append arguments to message.");
-                        ret = -ENOMEM;
-                        goto finish;
-                }
-
-                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-                if (!reply) {
-                        log_error("Failed to issue method call: %s", bus_error_message(&error));
-                        ret = -EIO;
-                        goto finish;
-                }
-
-                dbus_message_unref(m);
-                dbus_message_unref(reply);
-                m = reply = NULL;
-        }
-
-        ret = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        dbus_error_free(&error);
-
-        return ret;
-}
-
-static int attach(DBusConnection *bus, char **args, unsigned n) {
-        DBusMessage *m = NULL;
-        int ret = 0;
-        DBusError error;
-        unsigned i;
-        dbus_bool_t interactive = true;
-
-        assert(bus);
-        assert(args);
-
-        dbus_error_init(&error);
-
-        for (i = 2; i < n; i++) {
-                DBusMessage *reply;
-
-                m = dbus_message_new_method_call(
-                                "org.freedesktop.login1",
-                                "/org/freedesktop/login1",
-                                "org.freedesktop.login1.Manager",
-                                "AttachDevice");
-                if (!m) {
-                        log_error("Could not allocate message.");
-                        ret = -ENOMEM;
-                        goto finish;
-                }
-
-                if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_STRING, &args[1],
-                                              DBUS_TYPE_STRING, &args[i],
-                                              DBUS_TYPE_BOOLEAN, &interactive,
-                                              DBUS_TYPE_INVALID)) {
-                        log_error("Could not append arguments to message.");
-                        ret = -ENOMEM;
-                        goto finish;
-                }
-
-                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-                if (!reply) {
-                        log_error("Failed to issue method call: %s", bus_error_message(&error));
-                        ret = -EIO;
-                        goto finish;
-                }
-
-                dbus_message_unref(m);
-                dbus_message_unref(reply);
-                m = reply = NULL;
-        }
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        dbus_error_free(&error);
-
-        return ret;
-}
-
-static int flush_devices(DBusConnection *bus, char **args, unsigned n) {
-        DBusMessage *m = NULL, *reply = NULL;
-        int ret = 0;
-        DBusError error;
-        dbus_bool_t interactive = true;
-
-        assert(bus);
-        assert(args);
-
-        dbus_error_init(&error);
-
-        m = dbus_message_new_method_call(
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "FlushDevices");
-        if (!m) {
-                log_error("Could not allocate message.");
-                ret = -ENOMEM;
-                goto finish;
-        }
-
-        if (!dbus_message_append_args(m,
-                                      DBUS_TYPE_BOOLEAN, &interactive,
-                                      DBUS_TYPE_INVALID)) {
-                log_error("Could not append arguments to message.");
-                ret = -ENOMEM;
-                goto finish;
-        }
-
-        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-        if (!reply) {
-                log_error("Failed to issue method call: %s", bus_error_message(&error));
-                ret = -EIO;
-                goto finish;
-        }
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return ret;
-}
-
-static int terminate_seat(DBusConnection *bus, char **args, unsigned n) {
-        DBusMessage *m = NULL;
-        int ret = 0;
-        DBusError error;
-        unsigned i;
-
-        assert(bus);
-        assert(args);
-
-        dbus_error_init(&error);
-
-        for (i = 1; i < n; i++) {
-                DBusMessage *reply;
-
-                m = dbus_message_new_method_call(
-                                "org.freedesktop.login1",
-                                "/org/freedesktop/login1",
-                                "org.freedesktop.login1.Manager",
-                                "TerminateSeat");
-                if (!m) {
-                        log_error("Could not allocate message.");
-                        ret = -ENOMEM;
-                        goto finish;
-                }
-
-                if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_STRING, &args[i],
-                                              DBUS_TYPE_INVALID)) {
-                        log_error("Could not append arguments to message.");
-                        ret = -ENOMEM;
-                        goto finish;
-                }
-
-                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-                if (!reply) {
-                        log_error("Failed to issue method call: %s", bus_error_message(&error));
-                        ret = -EIO;
-                        goto finish;
-                }
-
-                dbus_message_unref(m);
-                dbus_message_unref(reply);
-                m = reply = NULL;
-        }
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        dbus_error_free(&error);
-
-        return ret;
-}
-
-static int help(void) {
-
-        printf("%s [OPTIONS...] {COMMAND} ...\n\n"
-               "Send control commands to or query the login manager.\n\n"
-               "  -h --help           Show this help\n"
-               "     --version        Show package version\n"
-               "  -p --property=NAME  Show only properties by this name\n"
-               "  -a --all            Show all properties, including empty ones\n"
-               "     --kill-who=WHO   Who to send signal to\n"
-               "  -s --signal=SIGNAL  Which signal to send\n"
-               "  -H --host=[USER@]HOST\n"
-               "                      Show information for remote host\n"
-               "  -P --privileged     Acquire privileges before execution\n"
-               "     --no-pager       Do not pipe output into a pager\n\n"
-               "Commands:\n"
-               "  list-sessions                   List sessions\n"
-               "  session-status [ID...]          Show session status\n"
-               "  show-session [ID...]            Show properties of one or more sessions\n"
-               "  activate [ID]                   Activate a session\n"
-               "  lock-session [ID...]            Screen lock one or more sessions\n"
-               "  unlock-session [ID...]          Screen unlock one or more sessions\n"
-               "  terminate-session [ID...]       Terminate one or more sessions\n"
-               "  kill-session [ID...]            Send signal to processes of a session\n"
-               "  list-users                      List users\n"
-               "  user-status [USER...]           Show user status\n"
-               "  show-user [USER...]             Show properties of one or more users\n"
-               "  enable-linger [USER...]         Enable linger state of one or more users\n"
-               "  disable-linger [USER...]        Disable linger state of one or more users\n"
-               "  terminate-user [USER...]        Terminate all sessions of one or more users\n"
-               "  kill-user [USER...]             Send signal to processes of a user\n"
-               "  list-seats                      List seats\n"
-               "  seat-status [NAME...]           Show seat status\n"
-               "  show-seat [NAME...]             Show properties of one or more seats\n"
-               "  attach [NAME] [DEVICE...]       Attach one or more devices to a seat\n"
-               "  flush-devices                   Flush all device associations\n"
-               "  terminate-seat [NAME...]        Terminate all sessions on one or more seats\n",
-               program_invocation_short_name);
-
-        return 0;
-}
-
-static int parse_argv(int argc, char *argv[]) {
-
-        enum {
-                ARG_VERSION = 0x100,
-                ARG_NO_PAGER,
-                ARG_KILL_WHO
-        };
-
-        static const struct option options[] = {
-                { "help",      no_argument,       NULL, 'h'           },
-                { "version",   no_argument,       NULL, ARG_VERSION   },
-                { "property",  required_argument, NULL, 'p'           },
-                { "all",       no_argument,       NULL, 'a'           },
-                { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
-                { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
-                { "signal",    required_argument, NULL, 's'           },
-                { "host",      required_argument, NULL, 'H'           },
-                { "privileged",no_argument,       NULL, 'P'           },
-                { NULL,        0,                 NULL, 0             }
-        };
-
-        int c;
-
-        assert(argc >= 0);
-        assert(argv);
-
-        while ((c = getopt_long(argc, argv, "hp:as:H:P", options, NULL)) >= 0) {
-
-                switch (c) {
-
-                case 'h':
-                        help();
-                        return 0;
-
-                case ARG_VERSION:
-                        puts(PACKAGE_STRING);
-                        puts(DISTRIBUTION);
-                        puts(SYSTEMD_FEATURES);
-                        return 0;
-
-                case 'p': {
-                        char **l;
-
-                        l = strv_append(arg_property, optarg);
-                        if (!l)
-                                return -ENOMEM;
-
-                        strv_free(arg_property);
-                        arg_property = l;
-
-                        /* If the user asked for a particular
-                         * property, show it to him, even if it is
-                         * empty. */
-                        arg_all = true;
-                        break;
-                }
-
-                case 'a':
-                        arg_all = true;
-                        break;
-
-                case ARG_NO_PAGER:
-                        arg_no_pager = true;
-                        break;
-
-                case ARG_KILL_WHO:
-                        arg_kill_who = optarg;
-                        break;
-
-                case 's':
-                        arg_signal = signal_from_string_try_harder(optarg);
-                        if (arg_signal < 0) {
-                                log_error("Failed to parse signal string %s.", optarg);
-                                return -EINVAL;
-                        }
-                        break;
-
-                case 'P':
-                        arg_transport = TRANSPORT_POLKIT;
-                        break;
-
-                case 'H':
-                        arg_transport = TRANSPORT_SSH;
-                        arg_host = optarg;
-                        break;
-
-                case '?':
-                        return -EINVAL;
-
-                default:
-                        log_error("Unknown option code %c", c);
-                        return -EINVAL;
-                }
-        }
-
-        return 1;
-}
-
-static int loginctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
-
-        static const struct {
-                const char* verb;
-                const enum {
-                        MORE,
-                        LESS,
-                        EQUAL
-                } argc_cmp;
-                const int argc;
-                int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
-        } verbs[] = {
-                { "list-sessions",         LESS,   1, list_sessions    },
-                { "session-status",        MORE,   2, show             },
-                { "show-session",          MORE,   1, show             },
-                { "activate",              EQUAL,  2, activate         },
-                { "lock-session",          MORE,   2, activate         },
-                { "unlock-session",        MORE,   2, activate         },
-                { "terminate-session",     MORE,   2, activate         },
-                { "kill-session",          MORE,   2, kill_session     },
-                { "list-users",            EQUAL,  1, list_users       },
-                { "user-status",           MORE,   2, show             },
-                { "show-user",             MORE,   1, show             },
-                { "enable-linger",         MORE,   2, enable_linger    },
-                { "disable-linger",        MORE,   2, enable_linger    },
-                { "terminate-user",        MORE,   2, terminate_user   },
-                { "kill-user",             MORE,   2, kill_user        },
-                { "list-seats",            EQUAL,  1, list_seats       },
-                { "seat-status",           MORE,   2, show             },
-                { "show-seat",             MORE,   1, show             },
-                { "attach",                MORE,   3, attach           },
-                { "flush-devices",         EQUAL,  1, flush_devices    },
-                { "terminate-seat",        MORE,   2, terminate_seat   },
-        };
-
-        int left;
-        unsigned i;
-
-        assert(argc >= 0);
-        assert(argv);
-        assert(error);
-
-        left = argc - optind;
-
-        if (left <= 0)
-                /* Special rule: no arguments means "list-sessions" */
-                i = 0;
-        else {
-                if (streq(argv[optind], "help")) {
-                        help();
-                        return 0;
-                }
-
-                for (i = 0; i < ELEMENTSOF(verbs); i++)
-                        if (streq(argv[optind], verbs[i].verb))
-                                break;
-
-                if (i >= ELEMENTSOF(verbs)) {
-                        log_error("Unknown operation %s", argv[optind]);
-                        return -EINVAL;
-                }
-        }
-
-        switch (verbs[i].argc_cmp) {
-
-        case EQUAL:
-                if (left != verbs[i].argc) {
-                        log_error("Invalid number of arguments.");
-                        return -EINVAL;
-                }
-
-                break;
-
-        case MORE:
-                if (left < verbs[i].argc) {
-                        log_error("Too few arguments.");
-                        return -EINVAL;
-                }
-
-                break;
-
-        case LESS:
-                if (left > verbs[i].argc) {
-                        log_error("Too many arguments.");
-                        return -EINVAL;
-                }
-
-                break;
-
-        default:
-                assert_not_reached("Unknown comparison operator.");
-        }
-
-        if (!bus) {
-                log_error("Failed to get D-Bus connection: %s", error->message);
-                return -EIO;
-        }
-
-        return verbs[i].dispatch(bus, argv + optind, left);
-}
-
-int main(int argc, char*argv[]) {
-        int r, retval = EXIT_FAILURE;
-        DBusConnection *bus = NULL;
-        DBusError error;
-
-        dbus_error_init(&error);
-
-        log_parse_environment();
-        log_open();
-
-        r = parse_argv(argc, argv);
-        if (r < 0)
-                goto finish;
-        else if (r == 0) {
-                retval = EXIT_SUCCESS;
-                goto finish;
-        }
-
-        if (arg_transport == TRANSPORT_NORMAL)
-                bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
-        else if (arg_transport == TRANSPORT_POLKIT)
-                bus_connect_system_polkit(&bus, &error);
-        else if (arg_transport == TRANSPORT_SSH)
-                bus_connect_system_ssh(NULL, arg_host, &bus, &error);
-        else
-                assert_not_reached("Uh, invalid transport...");
-
-        r = loginctl_main(bus, argc, argv, &error);
-        retval = r < 0 ? EXIT_FAILURE : r;
-
-finish:
-        if (bus) {
-                dbus_connection_flush(bus);
-                dbus_connection_close(bus);
-                dbus_connection_unref(bus);
-        }
-
-        dbus_error_free(&error);
-        dbus_shutdown();
-
-        strv_free(arg_property);
-
-        pager_close();
-
-        return retval;
-}
diff --git a/src/logind-acl.c b/src/logind-acl.c
deleted file mode 100644
index eb8a48d..0000000
--- a/src/logind-acl.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/*-*- 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 <assert.h>
-#include <sys/acl.h>
-#include <acl/libacl.h>
-#include <errno.h>
-#include <string.h>
-
-#include "logind-acl.h"
-#include "util.h"
-#include "acl-util.h"
-
-static int flush_acl(acl_t acl) {
-        acl_entry_t i;
-        int found;
-        bool changed = false;
-
-        assert(acl);
-
-        for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
-             found > 0;
-             found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
-
-                acl_tag_t tag;
-
-                if (acl_get_tag_type(i, &tag) < 0)
-                        return -errno;
-
-                if (tag != ACL_USER)
-                        continue;
-
-                if (acl_delete_entry(acl, i) < 0)
-                        return -errno;
-
-                changed = true;
-        }
-
-        if (found < 0)
-                return -errno;
-
-        return changed;
-}
-
-int devnode_acl(const char *path,
-                bool flush,
-                bool del, uid_t old_uid,
-                bool add, uid_t new_uid) {
-
-        acl_t acl;
-        int r = 0;
-        bool changed = false;
-
-        assert(path);
-
-        acl = acl_get_file(path, ACL_TYPE_ACCESS);
-        if (!acl)
-                return -errno;
-
-        if (flush) {
-
-                r = flush_acl(acl);
-                if (r < 0)
-                        goto finish;
-                if (r > 0)
-                        changed = true;
-
-        } else if (del && old_uid > 0) {
-                acl_entry_t entry;
-
-                r = acl_find_uid(acl, old_uid, &entry);
-                if (r < 0)
-                        goto finish;
-
-                if (r > 0) {
-                        if (acl_delete_entry(acl, entry) < 0) {
-                                r = -errno;
-                                goto finish;
-                        }
-
-                        changed = true;
-                }
-        }
-
-        if (add && new_uid > 0) {
-                acl_entry_t entry;
-                acl_permset_t permset;
-                int rd, wt;
-
-                r = acl_find_uid(acl, new_uid, &entry);
-                if (r < 0)
-                        goto finish;
-
-                if (r == 0) {
-                        if (acl_create_entry(&acl, &entry) < 0) {
-                                r = -errno;
-                                goto finish;
-                        }
-
-                        if (acl_set_tag_type(entry, ACL_USER) < 0 ||
-                            acl_set_qualifier(entry, &new_uid) < 0) {
-                                r = -errno;
-                                goto finish;
-                        }
-                }
-
-                if (acl_get_permset(entry, &permset) < 0) {
-                        r = -errno;
-                        goto finish;
-                }
-
-                rd = acl_get_perm(permset, ACL_READ);
-                if (rd < 0) {
-                        r = -errno;
-                        goto finish;
-                }
-
-                wt = acl_get_perm(permset, ACL_WRITE);
-                if (wt < 0) {
-                        r = -errno;
-                        goto finish;
-                }
-
-                if (!rd || !wt) {
-
-                        if (acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) {
-                                r = -errno;
-                                goto finish;
-                        }
-
-                        changed = true;
-                }
-        }
-
-        if (!changed)
-                goto finish;
-
-        if (acl_calc_mask(&acl) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        if (acl_set_file(path, ACL_TYPE_ACCESS, acl) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        r = 0;
-
-finish:
-        acl_free(acl);
-
-        return r;
-}
-
-int devnode_acl_all(struct udev *udev,
-                    const char *seat,
-                    bool flush,
-                    bool del, uid_t old_uid,
-                    bool add, uid_t new_uid) {
-
-        struct udev_list_entry *item = NULL, *first = NULL;
-        struct udev_enumerate *e;
-        int r;
-
-        assert(udev);
-
-        if (isempty(seat))
-                seat = "seat0";
-
-        e = udev_enumerate_new(udev);
-        if (!e)
-                return -ENOMEM;
-
-        /* We can only match by one tag in libudev. We choose
-         * "uaccess" for that. If we could match for two tags here we
-         * could add the seat name as second match tag, but this would
-         * be hardly optimizable in libudev, and hence checking the
-         * second tag manually in our loop is a good solution. */
-
-        r = udev_enumerate_add_match_tag(e, "uaccess");
-        if (r < 0)
-                goto finish;
-
-        r = udev_enumerate_scan_devices(e);
-        if (r < 0)
-                goto finish;
-
-        first = udev_enumerate_get_list_entry(e);
-        udev_list_entry_foreach(item, first) {
-                struct udev_device *d;
-                const char *node, *sn;
-
-                d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
-                if (!d) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                sn = udev_device_get_property_value(d, "ID_SEAT");
-                if (isempty(sn))
-                        sn = "seat0";
-
-                if (!streq(seat, sn)) {
-                        udev_device_unref(d);
-                        continue;
-                }
-
-                node = udev_device_get_devnode(d);
-                if (!node) {
-                        /* In case people mistag devices with nodes, we need to ignore this */
-                        udev_device_unref(d);
-                        continue;
-                }
-
-                log_debug("Fixing up %s for seat %s...", node, sn);
-
-                r = devnode_acl(node, flush, del, old_uid, add, new_uid);
-                udev_device_unref(d);
-
-                if (r < 0)
-                        goto finish;
-        }
-
-finish:
-        if (e)
-                udev_enumerate_unref(e);
-
-        return r;
-}
diff --git a/src/logind-acl.h b/src/logind-acl.h
deleted file mode 100644
index 72740f5..0000000
--- a/src/logind-acl.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foologindaclhfoo
-#define foologindaclhfoo
-
-/***
-  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 <sys/types.h>
-#include <stdbool.h>
-#include <libudev.h>
-
-#ifdef HAVE_ACL
-
-int devnode_acl(const char *path,
-                bool flush,
-                bool del, uid_t old_uid,
-                bool add, uid_t new_uid);
-
-int devnode_acl_all(struct udev *udev,
-                    const char *seat,
-                    bool flush,
-                    bool del, uid_t old_uid,
-                    bool add, uid_t new_uid);
-#else
-
-static inline int devnode_acl(const char *path,
-                bool flush,
-                bool del, uid_t old_uid,
-                bool add, uid_t new_uid) {
-        return 0;
-}
-
-static inline int devnode_acl_all(struct udev *udev,
-                                  const char *seat,
-                                  bool flush,
-                                  bool del, uid_t old_uid,
-                                  bool add, uid_t new_uid) {
-        return 0;
-}
-
-#endif
-
-#endif
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
deleted file mode 100644
index 0550d1b..0000000
--- a/src/logind-dbus.c
+++ /dev/null
@@ -1,1504 +0,0 @@
-/*-*- 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 <string.h>
-#include <unistd.h>
-#include <pwd.h>
-
-#include "logind.h"
-#include "dbus-common.h"
-#include "strv.h"
-#include "polkit.h"
-#include "special.h"
-
-#define BUS_MANAGER_INTERFACE                                           \
-        " <interface name=\"org.freedesktop.login1.Manager\">\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=\"GetUser\">\n"                                 \
-        "   <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"          \
-        "   <arg name=\"user\" type=\"o\" direction=\"out\"/>\n"        \
-        "  </method>\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=\"ListSessions\">\n"                            \
-        "   <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"ListUsers\">\n"                               \
-        "   <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n"  \
-        "  </method>\n"                                                 \
-        "  <method name=\"ListSeats\">\n"                               \
-        "   <arg name=\"seats\" type=\"a(so)\" 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=\"sevice\" type=\"s\" direction=\"in\"/>\n"       \
-        "   <arg name=\"type\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"vtnr\" type=\"u\" 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=\"b\" direction=\"in\"/>\n" \
-        "   <arg name=\"id\" type=\"s\" direction=\"out\"/>\n"          \
-        "   <arg name=\"path\" type=\"o\" direction=\"out\"/>\n"        \
-        "   <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
-        "   <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n"          \
-        "   <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n"        \
-        "   <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n"        \
-        "  </method>\n"                                                 \
-        "  <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"                                                 \
-        "  <method name=\"TerminateUser\">\n"                           \
-        "   <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"          \
-        "  </method>\n"                                                 \
-        "  <method name=\"TerminateSeat\">\n"                           \
-        "   <arg name=\"id\" type=\"s\" direction=\"in\"/>\n"           \
-        "  </method>\n"                                                 \
-        "  <method name=\"SetUserLinger\">\n"                           \
-        "   <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"          \
-        "   <arg name=\"b\" type=\"b\" direction=\"in\"/>\n"            \
-        "   <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n"  \
-        "  </method>\n"                                                 \
-        "  <method name=\"AttachDevice\">\n"                            \
-        "   <arg name=\"seat\" type=\"s\" direction=\"in\"/>\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"                                                 \
-        "  <method name=\"PowerOff\">\n"                                \
-        "   <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n"  \
-        "  </method>\n"                                                 \
-        "  <method name=\"Reboot\">\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"                          \
-        "  </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" \
-        "  <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n"  \
-        "  <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"IdleSinceHintMonotonic\" type=\"t\" 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 int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
-        Manager *m = data;
-        dbus_bool_t b;
-
-        assert(i);
-        assert(property);
-        assert(m);
-
-        b = manager_get_idle_hint(m, NULL) > 0;
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
-        Manager *m = data;
-        dual_timestamp t;
-        uint64_t u;
-
-        assert(i);
-        assert(property);
-        assert(m);
-
-        manager_get_idle_hint(m, &t);
-        u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
-        Session *session = NULL;
-        User *user = NULL;
-        const char *type, *seat, *tty, *display, *remote_user, *remote_host, *service;
-        uint32_t uid, leader, audit_id = 0;
-        dbus_bool_t remote, kill_processes;
-        char **controllers = NULL, **reset_controllers = NULL;
-        SessionType t;
-        Seat *s;
-        DBusMessageIter iter;
-        int r;
-        char *id = NULL, *p;
-        uint32_t vtnr = 0;
-        int fifo_fd = -1;
-        DBusMessage *reply = NULL;
-        bool b;
-
-        assert(m);
-        assert(message);
-        assert(_reply);
-
-        if (!dbus_message_iter_init(message, &iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
-                return -EINVAL;
-
-        dbus_message_iter_get_basic(&iter, &uid);
-
-        if (!dbus_message_iter_next(&iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
-                return -EINVAL;
-
-        dbus_message_iter_get_basic(&iter, &leader);
-
-        if (leader <= 0 ||
-            !dbus_message_iter_next(&iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-                return -EINVAL;
-
-        dbus_message_iter_get_basic(&iter, &service);
-
-        if (!dbus_message_iter_next(&iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-                return -EINVAL;
-
-        dbus_message_iter_get_basic(&iter, &type);
-        t = session_type_from_string(type);
-
-        if (t < 0 ||
-            !dbus_message_iter_next(&iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-                return -EINVAL;
-
-        dbus_message_iter_get_basic(&iter, &seat);
-
-        if (isempty(seat))
-                s = NULL;
-        else {
-                s = hashmap_get(m->seats, seat);
-                if (!s)
-                        return -ENOENT;
-        }
-
-        if (!dbus_message_iter_next(&iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
-                return -EINVAL;
-
-        dbus_message_iter_get_basic(&iter, &vtnr);
-
-        if (!dbus_message_iter_next(&iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-                return -EINVAL;
-
-        dbus_message_iter_get_basic(&iter, &tty);
-
-        if (tty_is_vc(tty)) {
-                int v;
-
-                if (!s)
-                        s = m->vtconsole;
-                else if (s != m->vtconsole)
-                        return -EINVAL;
-
-                v = vtnr_from_tty(tty);
-
-                if (v <= 0)
-                        return v < 0 ? v : -EINVAL;
-
-                if (vtnr <= 0)
-                        vtnr = (uint32_t) v;
-                else if (vtnr != (uint32_t) v)
-                        return -EINVAL;
-
-        } else if (!isempty(tty) && s && seat_is_vtconsole(s))
-                return -EINVAL;
-
-        if (s) {
-                if (seat_is_vtconsole(s)) {
-                        if (vtnr <= 0 || vtnr > 63)
-                                return -EINVAL;
-                } else {
-                        if (vtnr > 0)
-                                return -EINVAL;
-                }
-        }
-
-        if (!dbus_message_iter_next(&iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-                return -EINVAL;
-
-        dbus_message_iter_get_basic(&iter, &display);
-
-        if (!dbus_message_iter_next(&iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
-                return -EINVAL;
-
-        dbus_message_iter_get_basic(&iter, &remote);
-
-        if (!dbus_message_iter_next(&iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-                return -EINVAL;
-
-        dbus_message_iter_get_basic(&iter, &remote_user);
-
-        if (!dbus_message_iter_next(&iter) ||
-            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-                return -EINVAL;
-
-        dbus_message_iter_get_basic(&iter, &remote_host);
-
-        if (!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)
-                return -EINVAL;
-
-        r = bus_parse_strv_iter(&iter, &controllers);
-        if (r < 0)
-                return -EINVAL;
-
-        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;
-                goto fail;
-        }
-
-        r = bus_parse_strv_iter(&iter, &reset_controllers);
-        if (r < 0)
-                goto fail;
-
-        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;
-        }
-
-        dbus_message_iter_get_basic(&iter, &kill_processes);
-
-        r = manager_add_user_by_uid(m, uid, &user);
-        if (r < 0)
-                goto fail;
-
-        audit_session_from_pid(leader, &audit_id);
-
-        if (audit_id > 0) {
-                asprintf(&id, "%lu", (unsigned long) audit_id);
-
-                if (!id) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                session = hashmap_get(m->sessions, id);
-
-                if (session) {
-                        free(id);
-
-                        fifo_fd = session_create_fifo(session);
-                        if (fifo_fd < 0) {
-                                r = fifo_fd;
-                                goto fail;
-                        }
-
-                        /* Session already exists, client is probably
-                         * something like "su" which changes uid but
-                         * is still the same audit session */
-
-                        reply = dbus_message_new_method_return(message);
-                        if (!reply) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        p = session_bus_path(session);
-                        if (!p) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        seat = session->seat ? session->seat->id : "";
-                        vtnr = session->vtnr;
-                        b = dbus_message_append_args(
-                                        reply,
-                                        DBUS_TYPE_STRING, &session->id,
-                                        DBUS_TYPE_OBJECT_PATH, &p,
-                                        DBUS_TYPE_STRING, &session->user->runtime_path,
-                                        DBUS_TYPE_UNIX_FD, &fifo_fd,
-                                        DBUS_TYPE_STRING, &seat,
-                                        DBUS_TYPE_UINT32, &vtnr,
-                                        DBUS_TYPE_INVALID);
-                        free(p);
-
-                        if (!b) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        close_nointr_nofail(fifo_fd);
-                        *_reply = reply;
-
-                        strv_free(controllers);
-                        strv_free(reset_controllers);
-
-                        return 0;
-                }
-
-        } else {
-                do {
-                        free(id);
-                        asprintf(&id, "c%lu", ++m->session_counter);
-
-                        if (!id) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                } while (hashmap_get(m->sessions, id));
-        }
-
-        r = manager_add_session(m, user, id, &session);
-        free(id);
-        if (r < 0)
-                goto fail;
-
-        session->leader = leader;
-        session->audit_id = audit_id;
-        session->type = t;
-        session->remote = remote;
-        session->controllers = controllers;
-        session->reset_controllers = reset_controllers;
-        session->kill_processes = kill_processes;
-        session->vtnr = vtnr;
-
-        controllers = reset_controllers = NULL;
-
-        if (!isempty(tty)) {
-                session->tty = strdup(tty);
-                if (!session->tty) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-        }
-
-        if (!isempty(display)) {
-                session->display = strdup(display);
-                if (!session->display) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-        }
-
-        if (!isempty(remote_user)) {
-                session->remote_user = strdup(remote_user);
-                if (!session->remote_user) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-        }
-
-        if (!isempty(remote_host)) {
-                session->remote_host = strdup(remote_host);
-                if (!session->remote_host) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-        }
-
-        if (!isempty(service)) {
-                session->service = strdup(service);
-                if (!session->service) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-        }
-
-        fifo_fd = session_create_fifo(session);
-        if (fifo_fd < 0) {
-                r = fifo_fd;
-                goto fail;
-        }
-
-        if (s) {
-                r = seat_attach_session(s, session);
-                if (r < 0)
-                        goto fail;
-        }
-
-        r = session_start(session);
-        if (r < 0)
-                goto fail;
-
-        reply = dbus_message_new_method_return(message);
-        if (!reply) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        p = session_bus_path(session);
-        if (!p) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        seat = s ? s->id : "";
-        b = dbus_message_append_args(
-                        reply,
-                        DBUS_TYPE_STRING, &session->id,
-                        DBUS_TYPE_OBJECT_PATH, &p,
-                        DBUS_TYPE_STRING, &session->user->runtime_path,
-                        DBUS_TYPE_UNIX_FD, &fifo_fd,
-                        DBUS_TYPE_STRING, &seat,
-                        DBUS_TYPE_UINT32, &vtnr,
-                        DBUS_TYPE_INVALID);
-        free(p);
-
-        if (!b) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        close_nointr_nofail(fifo_fd);
-        *_reply = reply;
-
-        return 0;
-
-fail:
-        strv_free(controllers);
-        strv_free(reset_controllers);
-
-        if (session)
-                session_add_to_gc_queue(session);
-
-        if (user)
-                user_add_to_gc_queue(user);
-
-        if (fifo_fd >= 0)
-                close_nointr_nofail(fifo_fd);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        return r;
-}
-
-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;
-        }
-
-        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);
-
-                t = strappend(p, "/uevent");
-                if (!t) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                write_one_line_file(t, "change");
-                free(t);
-        }
-
-        r = 0;
-
-finish:
-        if (e)
-                udev_enumerate_unref(e);
-
-        return r;
-}
-
-static int attach_device(Manager *m, const char *seat, const char *sysfs) {
-        struct udev_device *d;
-        char *rule = NULL, *file = NULL;
-        const char *id_for_seat;
-        int r;
-
-        assert(m);
-        assert(seat);
-        assert(sysfs);
-
-        d = udev_device_new_from_syspath(m->udev, sysfs);
-        if (!d)
-                return -ENODEV;
-
-        if (!udev_device_has_tag(d, "seat")) {
-                r = -ENODEV;
-                goto finish;
-        }
-
-        id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
-        if (!id_for_seat) {
-                r = -ENODEV;
-                goto finish;
-        }
-
-        if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        mkdir_p("/etc/udev/rules.d", 0755);
-        r = write_one_line_file_atomic(file, rule);
-        if (r < 0)
-                goto finish;
-
-        r = trigger_device(m, d);
-
-finish:
-        free(rule);
-        free(file);
-
-        if (d)
-                udev_device_unref(d);
-
-        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,
-                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 },
-                { "org.freedesktop.login1.Manager", "IdleHint",               bus_manager_append_idle_hint, "b",  m                       },
-                { "org.freedesktop.login1.Manager", "IdleSinceHint",          bus_manager_append_idle_hint_since, "t", m                  },
-                { "org.freedesktop.login1.Manager", "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", m                  },
-                { NULL, NULL, NULL, NULL, NULL }
-        };
-
-        DBusError error;
-        DBusMessage *reply = NULL;
-        int r;
-
-        assert(connection);
-        assert(message);
-        assert(m);
-
-        dbus_error_init(&error);
-
-        if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
-                const char *name;
-                char *p;
-                Session *session;
-                bool b;
-
-                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);
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                p = session_bus_path(session);
-                if (!p)
-                        goto oom;
-
-                b = dbus_message_append_args(
-                                reply,
-                                DBUS_TYPE_OBJECT_PATH, &p,
-                                DBUS_TYPE_INVALID);
-                free(p);
-
-                if (!b)
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
-                uint32_t uid;
-                char *p;
-                User *user;
-                bool b;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_UINT32, &uid,
-                                    DBUS_TYPE_INVALID))
-                        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);
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                p = user_bus_path(user);
-                if (!p)
-                        goto oom;
-
-                b = dbus_message_append_args(
-                                reply,
-                                DBUS_TYPE_OBJECT_PATH, &p,
-                                DBUS_TYPE_INVALID);
-                free(p);
-
-                if (!b)
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
-                const char *name;
-                char *p;
-                Seat *seat;
-                bool b;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                seat = hashmap_get(m->seats, name);
-                if (!seat)
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                p = seat_bus_path(seat);
-                if (!p)
-                        goto oom;
-
-                b = dbus_message_append_args(
-                                reply,
-                                DBUS_TYPE_OBJECT_PATH, &p,
-                                DBUS_TYPE_INVALID);
-                free(p);
-
-                if (!b)
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
-                char *p;
-                Session *session;
-                Iterator i;
-                DBusMessageIter iter, sub;
-                const char *empty = "";
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                dbus_message_iter_init_append(reply, &iter);
-
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
-                        goto oom;
-
-                HASHMAP_FOREACH(session, m->sessions, i) {
-                        DBusMessageIter sub2;
-                        uint32_t uid;
-
-                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
-                                goto oom;
-
-                        uid = session->user->uid;
-
-                        p = session_bus_path(session);
-                        if (!p)
-                                goto oom;
-
-                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
-                                free(p);
-                                goto oom;
-                        }
-
-                        free(p);
-
-                        if (!dbus_message_iter_close_container(&sub, &sub2))
-                                goto oom;
-                }
-
-                if (!dbus_message_iter_close_container(&iter, &sub))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
-                char *p;
-                User *user;
-                Iterator i;
-                DBusMessageIter iter, sub;
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                dbus_message_iter_init_append(reply, &iter);
-
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
-                        goto oom;
-
-                HASHMAP_FOREACH(user, m->users, i) {
-                        DBusMessageIter sub2;
-                        uint32_t uid;
-
-                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
-                                goto oom;
-
-                        uid = user->uid;
-
-                        p = user_bus_path(user);
-                        if (!p)
-                                goto oom;
-
-                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
-                                free(p);
-                                goto oom;
-                        }
-
-                        free(p);
-
-                        if (!dbus_message_iter_close_container(&sub, &sub2))
-                                goto oom;
-                }
-
-                if (!dbus_message_iter_close_container(&iter, &sub))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
-                char *p;
-                Seat *seat;
-                Iterator i;
-                DBusMessageIter iter, sub;
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-                dbus_message_iter_init_append(reply, &iter);
-
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
-                        goto oom;
-
-                HASHMAP_FOREACH(seat, m->seats, i) {
-                        DBusMessageIter sub2;
-
-                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
-                                goto oom;
-
-                        p = seat_bus_path(seat);
-                        if (!p)
-                                goto oom;
-
-                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
-                                free(p);
-                                goto oom;
-                        }
-
-                        free(p);
-
-                        if (!dbus_message_iter_close_container(&sub, &sub2))
-                                goto oom;
-                }
-
-                if (!dbus_message_iter_close_container(&iter, &sub))
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
-
-                r = bus_manager_create_session(m, message, &reply);
-
-                /* Don't delay the work on OOM here, since it might be
-                 * triggered by a low RLIMIT_NOFILE here (since we
-                 * send a dupped fd to the client), and we'd rather
-                 * see this fail quickly then be retried later */
-
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
-                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);
-
-                r = session_activate(session);
-                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", "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;
-
-                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);
-
-                r = session_stop(session);
-                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", "TerminateUser")) {
-                uint32_t uid;
-                User *user;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_UINT32, &uid,
-                                    DBUS_TYPE_INVALID))
-                        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_stop(user);
-                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", "TerminateSeat")) {
-                const char *name;
-                Seat *seat;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                seat = hashmap_get(m->seats, name);
-                if (!seat)
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-
-                r = seat_stop_sessions(seat);
-                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", "SetUserLinger")) {
-                uint32_t uid;
-                struct passwd *pw;
-                dbus_bool_t b, interactive;
-                char *path;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_UINT32, &uid,
-                                    DBUS_TYPE_BOOLEAN, &b,
-                                    DBUS_TYPE_BOOLEAN, &interactive,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                errno = 0;
-                pw = getpwuid(uid);
-                if (!pw)
-                        return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
-
-                r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, &error);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
-
-                r = safe_mkdir("/var/lib/systemd/linger", 0755, 0, 0);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
-
-                path = strappend("/var/lib/systemd/linger/", pw->pw_name);
-                if (!path)
-                        goto oom;
-
-                if (b) {
-                        User *u;
-
-                        r = touch(path);
-                        free(path);
-
-                        if (r < 0)
-                                return bus_send_error_reply(connection, message, &error, r);
-
-                        if (manager_add_user_by_uid(m, uid, &u) >= 0)
-                                user_start(u);
-
-                } else {
-                        User *u;
-
-                        r = unlink(path);
-                        free(path);
-
-                        if (r < 0 && errno != ENOENT)
-                                return bus_send_error_reply(connection, message, &error, -errno);
-
-                        u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
-                        if (u)
-                                user_add_to_gc_queue(u);
-                }
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
-                const char *sysfs, *seat;
-                dbus_bool_t interactive;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &seat,
-                                    DBUS_TYPE_STRING, &sysfs,
-                                    DBUS_TYPE_BOOLEAN, &interactive,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
-
-                r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, &error);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
-
-                r = attach_device(m, seat, sysfs);
-                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.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.login1.Manager", "PowerOff") ||
-                   dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
-                dbus_bool_t interactive;
-                bool multiple_sessions;
-                DBusMessage *forward, *freply;
-                const char *name;
-                const char *mode = "replace";
-                const char *action;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_BOOLEAN, &interactive,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                multiple_sessions = hashmap_size(m->sessions) > 1;
-
-                if (!multiple_sessions) {
-                        Session *s;
-
-                        /* Hmm, there's only one session, but let's
-                         * make sure it actually belongs to the user
-                         * who is asking. If not, better be safe than
-                         * sorry. */
-
-                        s = hashmap_first(m->sessions);
-                        if (s) {
-                                unsigned long ul;
-
-                                ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
-                                if (ul == (unsigned long) -1)
-                                        return bus_send_error_reply(connection, message, &error, -EIO);
-
-                                multiple_sessions = s->user->uid != ul;
-                        }
-                }
-
-                if (streq(dbus_message_get_member(message), "PowerOff")) {
-                        if (multiple_sessions)
-                                action = "org.freedesktop.login1.power-off-multiple-sessions";
-                        else
-                                action = "org.freedesktop.login1.power-off";
-
-                        name = SPECIAL_POWEROFF_TARGET;
-                } else {
-                        if (multiple_sessions)
-                                action = "org.freedesktop.login1.reboot-multiple-sessions";
-                        else
-                                action = "org.freedesktop.login1.reboot";
-
-                        name = SPECIAL_REBOOT_TARGET;
-                }
-
-                r = verify_polkit(connection, message, action, interactive, &error);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
-
-                forward = dbus_message_new_method_call(
-                              "org.freedesktop.systemd1",
-                              "/org/freedesktop/systemd1",
-                              "org.freedesktop.systemd1.Manager",
-                              "StartUnit");
-                if (!forward)
-                        return bus_send_error_reply(connection, message, NULL, -ENOMEM);
-
-                if (!dbus_message_append_args(forward,
-                                              DBUS_TYPE_STRING, &name,
-                                              DBUS_TYPE_STRING, &mode,
-                                              DBUS_TYPE_INVALID)) {
-                        dbus_message_unref(forward);
-                        return bus_send_error_reply(connection, message, NULL, -ENOMEM);
-                }
-
-                freply = dbus_connection_send_with_reply_and_block(connection, forward, -1, &error);
-                dbus_message_unref(forward);
-
-                if (!freply)
-                        return bus_send_error_reply(connection, message, &error, -EIO);
-
-                dbus_message_unref(freply);
-
-                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;
-                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
-};
-
-DBusHandlerResult bus_message_filter(
-                DBusConnection *connection,
-                DBusMessage *message,
-                void *userdata) {
-
-        Manager *m = userdata;
-        DBusError error;
-
-        assert(m);
-        assert(connection);
-        assert(message);
-
-        dbus_error_init(&error);
-
-        if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
-                const char *cgroup;
-
-                if (!dbus_message_get_args(message, &error,
-                                           DBUS_TYPE_STRING, &cgroup,
-                                           DBUS_TYPE_INVALID))
-                        log_error("Failed to parse Released message: %s", bus_error_message(&error));
-                else
-                        manager_cgroup_notify_empty(m, cgroup);
-        }
-
-        dbus_error_free(&error);
-
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-int manager_send_changed(Manager *manager, const char *properties) {
-        DBusMessage *m;
-        int r = -ENOMEM;
-
-        assert(manager);
-
-        m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
-        if (!m)
-                goto finish;
-
-        if (!dbus_connection_send(manager->bus, m, NULL))
-                goto finish;
-
-        r = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        return r;
-}
diff --git a/src/logind-device.c b/src/logind-device.c
deleted file mode 100644
index bbd370f..0000000
--- a/src/logind-device.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*-*- 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 <assert.h>
-#include <string.h>
-
-#include "logind-device.h"
-#include "util.h"
-
-Device* device_new(Manager *m, const char *sysfs) {
-        Device *d;
-
-        assert(m);
-        assert(sysfs);
-
-        d = new0(Device, 1);
-        if (!d)
-                return NULL;
-
-        d->sysfs = strdup(sysfs);
-        if (!d->sysfs) {
-                free(d);
-                return NULL;
-        }
-
-        if (hashmap_put(m->devices, d->sysfs, d) < 0) {
-                free(d->sysfs);
-                free(d);
-                return NULL;
-        }
-
-        d->manager = m;
-        dual_timestamp_get(&d->timestamp);
-
-        return d;
-}
-
-void device_free(Device *d) {
-        assert(d);
-
-        device_detach(d);
-
-        hashmap_remove(d->manager->devices, d->sysfs);
-
-        free(d->sysfs);
-        free(d);
-}
-
-void device_detach(Device *d) {
-        assert(d);
-
-        if (d->seat)
-                LIST_REMOVE(Device, devices, d->seat->devices, d);
-
-        seat_add_to_gc_queue(d->seat);
-        d->seat = NULL;
-}
-
-void device_attach(Device *d, Seat *s) {
-        assert(d);
-        assert(s);
-
-        if (d->seat)
-                device_detach(d);
-
-        d->seat = s;
-        LIST_PREPEND(Device, devices, s->devices, d);
-}
diff --git a/src/logind-device.h b/src/logind-device.h
deleted file mode 100644
index e25a534..0000000
--- a/src/logind-device.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foologinddevicehfoo
-#define foologinddevicehfoo
-
-/***
-  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/>.
-***/
-
-typedef struct Device Device;
-
-#include "list.h"
-#include "util.h"
-#include "logind.h"
-#include "logind-seat.h"
-
-struct Device {
-        Manager *manager;
-
-        char *sysfs;
-        Seat *seat;
-
-        dual_timestamp timestamp;
-
-        LIST_FIELDS(struct Device, devices);
-};
-
-Device* device_new(Manager *m, const char *sysfs);
-void device_free(Device *d);
-void device_attach(Device *d, Seat *s);
-void device_detach(Device *d);
-
-#endif
diff --git a/src/logind-gperf.gperf b/src/logind-gperf.gperf
deleted file mode 100644
index 940fe10..0000000
--- a/src/logind-gperf.gperf
+++ /dev/null
@@ -1,22 +0,0 @@
-%{
-#include <stddef.h>
-#include "conf-parser.h"
-#include "logind.h"
-%}
-struct ConfigPerfItem;
-%null_strings
-%language=ANSI-C
-%define slot-name section_and_lvalue
-%define hash-function-name logind_gperf_hash
-%define lookup-function-name logind_gperf_lookup
-%readonly-tables
-%omit-struct-type
-%struct-type
-%includes
-%%
-Login.NAutoVTs,          config_parse_unsigned, 0, offsetof(Manager, n_autovts)
-Login.KillUserProcesses, config_parse_bool,     0, offsetof(Manager, kill_user_processes)
-Login.KillOnlyUsers,     config_parse_strv,     0, offsetof(Manager, kill_only_users)
-Login.KillExcludeUsers,  config_parse_strv,     0, offsetof(Manager, kill_exclude_users)
-Login.Controllers,       config_parse_strv,     0, offsetof(Manager, controllers)
-Login.ResetControllers,  config_parse_strv,     0, offsetof(Manager, reset_controllers)
diff --git a/src/logind-seat-dbus.c b/src/logind-seat-dbus.c
deleted file mode 100644
index 3a916ee..0000000
--- a/src/logind-seat-dbus.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/*-*- 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 <string.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"                              \
-        "  <method name=\"ActivateSession\">\n"                         \
-        "   <arg name=\"id\" type=\"s\"/>\n"                            \
-        "  </method>\n"                                                 \
-        "  <property name=\"Id\" type=\"s\" access=\"read\"/>\n"        \
-        "  <property name=\"ActiveSession\" type=\"so\" access=\"read\"/>\n" \
-        "  <property name=\"CanMultiSession\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
-        "  <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n"  \
-        "  <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"IdleSinceHintMonotonic\" type=\"t\" 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 bus_seat_append_multi_session(DBusMessageIter *i, const char *property, void *data) {
-        Seat *s = data;
-        dbus_bool_t b;
-
-        assert(i);
-        assert(property);
-        assert(s);
-
-        b = seat_is_vtconsole(s);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_seat_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
-        Seat *s = data;
-        dbus_bool_t b;
-
-        assert(i);
-        assert(property);
-        assert(s);
-
-        b = seat_get_idle_hint(s, NULL) > 0;
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_seat_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
-        Seat *s = data;
-        dual_timestamp t;
-        uint64_t k;
-
-        assert(i);
-        assert(property);
-        assert(s);
-
-        seat_get_idle_hint(s, &t);
-        k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k))
-                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", "ActiveSession",          bus_seat_append_active,          "(so)",  s     },
-                { "org.freedesktop.login1.Seat", "CanMultiSession",        bus_seat_append_multi_session,   "b",     s     },
-                { "org.freedesktop.login1.Seat", "Sessions",               bus_seat_append_sessions,        "a(so)", s     },
-                { "org.freedesktop.login1.Seat", "IdleHint",               bus_seat_append_idle_hint,       "b",     s     },
-                { "org.freedesktop.login1.Seat", "IdleSinceHint",          bus_seat_append_idle_hint_since, "t",     s     },
-                { "org.freedesktop.login1.Seat", "IdleSinceHintMonotonic", bus_seat_append_idle_hint_since, "t",     s     },
-                { NULL, NULL, NULL, NULL, NULL }
-        };
-
-        DBusError error;
-        DBusMessage *reply = NULL;
-        int r;
-
-        assert(s);
-        assert(connection);
-        assert(message);
-
-        dbus_error_init(&error);
-
-        if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "Terminate")) {
-
-                r = seat_stop_sessions(s);
-                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.Seat", "ActivateSession")) {
-                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(s->manager->sessions, name);
-                if (!session || session->seat != s)
-                        return bus_send_error_reply(connection, message, &error, -ENOENT);
-
-                r = session_activate(session);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, NULL, r);
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-        } else
-                return bus_default_message_handler(connection, message, INTROSPECTION, 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;
-}
-
-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;
-}
-
-int seat_send_signal(Seat *s, bool new_seat) {
-        DBusMessage *m;
-        int r = -ENOMEM;
-        char *p = NULL;
-
-        assert(s);
-
-        m = dbus_message_new_signal("/org/freedesktop/login1",
-                                    "org.freedesktop.login1.Manager",
-                                    new_seat ? "SeatNew" : "SeatRemoved");
-
-        if (!m)
-                return -ENOMEM;
-
-        p = seat_bus_path(s);
-        if (!p)
-                goto finish;
-
-        if (!dbus_message_append_args(
-                            m,
-                            DBUS_TYPE_STRING, &s->id,
-                            DBUS_TYPE_OBJECT_PATH, &p,
-                            DBUS_TYPE_INVALID))
-                goto finish;
-
-        if (!dbus_connection_send(s->manager->bus, m, NULL))
-                goto finish;
-
-        r = 0;
-
-finish:
-        dbus_message_unref(m);
-        free(p);
-
-        return r;
-}
-
-int seat_send_changed(Seat *s, const char *properties) {
-        DBusMessage *m;
-        int r = -ENOMEM;
-        char *p = NULL;
-
-        assert(s);
-
-        if (!s->started)
-                return 0;
-
-        p = seat_bus_path(s);
-        if (!p)
-                return -ENOMEM;
-
-        m = bus_properties_changed_new(p, "org.freedesktop.login1.Seat", properties);
-        if (!m)
-                goto finish;
-
-        if (!dbus_connection_send(s->manager->bus, m, NULL))
-                goto finish;
-
-        r = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-        free(p);
-
-        return r;
-}
diff --git a/src/logind-seat.c b/src/logind-seat.c
deleted file mode 100644
index 3cf3958..0000000
--- a/src/logind-seat.c
+++ /dev/null
@@ -1,499 +0,0 @@
-/*-*- 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 <assert.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/vt.h>
-#include <string.h>
-
-#include "logind-seat.h"
-#include "logind-acl.h"
-#include "util.h"
-
-Seat *seat_new(Manager *m, const char *id) {
-        Seat *s;
-
-        assert(m);
-        assert(id);
-
-        s = new0(Seat, 1);
-        if (!s)
-                return NULL;
-
-        s->state_file = strappend("/run/systemd/seats/", id);
-        if (!s->state_file) {
-                free(s);
-                return NULL;
-        }
-
-        s->id = file_name_from_path(s->state_file);
-        s->manager = m;
-
-        if (hashmap_put(m->seats, s->id, s) < 0) {
-                free(s->state_file);
-                free(s);
-                return NULL;
-        }
-
-        return s;
-}
-
-void seat_free(Seat *s) {
-        assert(s);
-
-        if (s->in_gc_queue)
-                LIST_REMOVE(Seat, gc_queue, s->manager->seat_gc_queue, s);
-
-        while (s->sessions)
-                session_free(s->sessions);
-
-        assert(!s->active);
-
-        while (s->devices)
-                device_free(s->devices);
-
-        hashmap_remove(s->manager->seats, s->id);
-
-        free(s->state_file);
-        free(s);
-}
-
-int seat_save(Seat *s) {
-        int r;
-        FILE *f;
-        char *temp_path;
-
-        assert(s);
-
-        if (!s->started)
-                return 0;
-
-        r = safe_mkdir("/run/systemd/seats", 0755, 0, 0);
-        if (r < 0)
-                goto finish;
-
-        r = fopen_temporary(s->state_file, &f, &temp_path);
-        if (r < 0)
-                goto finish;
-
-        fchmod(fileno(f), 0644);
-
-        fprintf(f,
-                "# This is private data. Do not parse.\n"
-                "IS_VTCONSOLE=%i\n",
-                seat_is_vtconsole(s));
-
-        if (s->active) {
-                assert(s->active->user);
-
-                fprintf(f,
-                        "ACTIVE=%s\n"
-                        "ACTIVE_UID=%lu\n",
-                        s->active->id,
-                        (unsigned long) s->active->user->uid);
-        }
-
-        if (s->sessions) {
-                Session *i;
-
-                fputs("SESSIONS=", f);
-                LIST_FOREACH(sessions_by_seat, i, s->sessions) {
-                        fprintf(f,
-                                "%s%c",
-                                i->id,
-                                i->sessions_by_seat_next ? ' ' : '\n');
-                }
-
-                fputs("UIDS=", f);
-                LIST_FOREACH(sessions_by_seat, i, s->sessions)
-                        fprintf(f,
-                                "%lu%c",
-                                (unsigned long) i->user->uid,
-                                i->sessions_by_seat_next ? ' ' : '\n');
-        }
-
-        fflush(f);
-
-        if (ferror(f) || rename(temp_path, s->state_file) < 0) {
-                r = -errno;
-                unlink(s->state_file);
-                unlink(temp_path);
-        }
-
-        fclose(f);
-        free(temp_path);
-
-finish:
-        if (r < 0)
-                log_error("Failed to save seat data for %s: %s", s->id, strerror(-r));
-
-        return r;
-}
-
-int seat_load(Seat *s) {
-        assert(s);
-
-        /* There isn't actually anything to read here ... */
-
-        return 0;
-}
-
-static int vt_allocate(int vtnr) {
-        int fd, r;
-        char *p;
-
-        assert(vtnr >= 1);
-
-        if (asprintf(&p, "/dev/tty%i", vtnr) < 0)
-                return -ENOMEM;
-
-        fd = open_terminal(p, O_RDWR|O_NOCTTY|O_CLOEXEC);
-        free(p);
-
-        r = fd < 0 ? -errno : 0;
-
-        if (fd >= 0)
-                close_nointr_nofail(fd);
-
-        return r;
-}
-
-int seat_preallocate_vts(Seat *s) {
-        int r = 0;
-        unsigned i;
-
-        assert(s);
-        assert(s->manager);
-
-        log_debug("Preallocating VTs...");
-
-        if (s->manager->n_autovts <= 0)
-                return 0;
-
-        if (!seat_is_vtconsole(s))
-                return 0;
-
-        for (i = 1; i <= s->manager->n_autovts; i++) {
-                int q;
-
-                q = vt_allocate(i);
-                if (q < 0) {
-                        log_error("Failed to preallocate VT %i: %s", i, strerror(-q));
-                        r = q;
-                }
-        }
-
-        return r;
-}
-
-int seat_apply_acls(Seat *s, Session *old_active) {
-        int r;
-
-        assert(s);
-
-        r = devnode_acl_all(s->manager->udev,
-                            s->id,
-                            false,
-                            !!old_active, old_active ? old_active->user->uid : 0,
-                            !!s->active, s->active ? s->active->user->uid : 0);
-
-        if (r < 0)
-                log_error("Failed to apply ACLs: %s", strerror(-r));
-
-        return r;
-}
-
-int seat_set_active(Seat *s, Session *session) {
-        Session *old_active;
-
-        assert(s);
-        assert(!session || session->seat == s);
-
-        if (session == s->active)
-                return 0;
-
-        old_active = s->active;
-        s->active = session;
-
-        seat_apply_acls(s, old_active);
-
-        if (session && session->started)
-                session_send_changed(session, "Active\0");
-
-        if (!session || session->started)
-                seat_send_changed(s, "ActiveSession\0");
-
-        seat_save(s);
-
-        if (session) {
-                session_save(session);
-                user_save(session->user);
-        }
-
-        if (old_active) {
-                session_save(old_active);
-                user_save(old_active->user);
-        }
-
-        return 0;
-}
-
-int seat_active_vt_changed(Seat *s, int vtnr) {
-        Session *i, *new_active = NULL;
-        int r;
-
-        assert(s);
-        assert(vtnr >= 1);
-
-        if (!seat_is_vtconsole(s))
-                return -EINVAL;
-
-        log_debug("VT changed to %i", vtnr);
-
-        LIST_FOREACH(sessions_by_seat, i, s->sessions)
-                if (i->vtnr == vtnr) {
-                        new_active = i;
-                        break;
-                }
-
-        r = seat_set_active(s, new_active);
-        manager_spawn_autovt(s->manager, vtnr);
-
-        return r;
-}
-
-int seat_read_active_vt(Seat *s) {
-        char t[64];
-        ssize_t k;
-        int r, vtnr;
-
-        assert(s);
-
-        if (!seat_is_vtconsole(s))
-                return 0;
-
-        lseek(s->manager->console_active_fd, SEEK_SET, 0);
-
-        k = read(s->manager->console_active_fd, t, sizeof(t)-1);
-        if (k <= 0) {
-                log_error("Failed to read current console: %s", k < 0 ? strerror(-errno) : "EOF");
-                return k < 0 ? -errno : -EIO;
-        }
-
-        t[k] = 0;
-        truncate_nl(t);
-
-        if (!startswith(t, "tty")) {
-                log_error("Hm, /sys/class/tty/tty0/active is badly formatted.");
-                return -EIO;
-        }
-
-        r = safe_atoi(t+3, &vtnr);
-        if (r < 0) {
-                log_error("Failed to parse VT number %s", t+3);
-                return r;
-        }
-
-        if (vtnr <= 0) {
-                log_error("VT number invalid: %s", t+3);
-                return -EIO;
-        }
-
-        return seat_active_vt_changed(s, vtnr);
-}
-
-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);
-
-        /* Read current VT */
-        seat_read_active_vt(s);
-
-        s->started = true;
-
-        /* Save seat data */
-        seat_save(s);
-
-        seat_send_signal(s, true);
-
-        return 0;
-}
-
-int seat_stop(Seat *s) {
-        int r = 0;
-
-        assert(s);
-
-        if (s->started)
-                log_info("Removed seat %s.", s->id);
-
-        seat_stop_sessions(s);
-
-        unlink(s->state_file);
-        seat_add_to_gc_queue(s);
-
-        if (s->started)
-                seat_send_signal(s, false);
-
-        s->started = false;
-
-        return r;
-}
-
-int seat_stop_sessions(Seat *s) {
-        Session *session;
-        int r = 0, k;
-
-        assert(s);
-
-        LIST_FOREACH(sessions_by_seat, session, s->sessions) {
-                k = session_stop(session);
-                if (k < 0)
-                        r = k;
-        }
-
-        return r;
-}
-
-int seat_attach_session(Seat *s, Session *session) {
-        assert(s);
-        assert(session);
-        assert(!session->seat);
-
-        if (!seat_is_vtconsole(s) && s->sessions)
-                return -EEXIST;
-
-        session->seat = s;
-        LIST_PREPEND(Session, sessions_by_seat, s->sessions, session);
-
-        seat_send_changed(s, "Sessions\0");
-
-        if (!seat_is_vtconsole(s)) {
-                assert(!s->active);
-                seat_set_active(s, session);
-        }
-
-        return 0;
-}
-
-bool seat_is_vtconsole(Seat *s) {
-        assert(s);
-
-        return s->manager->vtconsole == s;
-}
-
-int seat_get_idle_hint(Seat *s, dual_timestamp *t) {
-        Session *session;
-        bool idle_hint = true;
-        dual_timestamp ts = { 0, 0 };
-
-        assert(s);
-
-        LIST_FOREACH(sessions_by_seat, session, s->sessions) {
-                dual_timestamp k;
-                int ih;
-
-                ih = session_get_idle_hint(session, &k);
-                if (ih < 0)
-                        return ih;
-
-                if (!ih) {
-                        if (!idle_hint) {
-                                if (k.monotonic < ts.monotonic)
-                                        ts = k;
-                        } else {
-                                idle_hint = false;
-                                ts = k;
-                        }
-                } else if (idle_hint) {
-
-                        if (k.monotonic > ts.monotonic)
-                                ts = k;
-                }
-        }
-
-        if (t)
-                *t = ts;
-
-        return idle_hint;
-}
-
-int seat_check_gc(Seat *s, bool drop_not_started) {
-        assert(s);
-
-        if (drop_not_started && !s->started)
-                return 0;
-
-        if (seat_is_vtconsole(s))
-                return 1;
-
-        return !!s->devices;
-}
-
-void seat_add_to_gc_queue(Seat *s) {
-        assert(s);
-
-        if (s->in_gc_queue)
-                return;
-
-        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;
-
-        if (strlen(name) > 255)
-                return false;
-
-        return true;
-}
diff --git a/src/logind-seat.h b/src/logind-seat.h
deleted file mode 100644
index 5bce143..0000000
--- a/src/logind-seat.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foologindseathfoo
-#define foologindseathfoo
-
-/***
-  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/>.
-***/
-
-typedef struct Seat Seat;
-
-#include "list.h"
-#include "util.h"
-#include "logind.h"
-#include "logind-device.h"
-#include "logind-session.h"
-
-struct Seat {
-        Manager *manager;
-        char *id;
-
-        char *state_file;
-
-        LIST_HEAD(Device, devices);
-
-        Session *active;
-        LIST_HEAD(Session, sessions);
-
-        bool in_gc_queue:1;
-        bool started:1;
-
-        LIST_FIELDS(Seat, gc_queue);
-};
-
-Seat *seat_new(Manager *m, const char *id);
-void seat_free(Seat *s);
-
-int seat_save(Seat *s);
-int seat_load(Seat *s);
-
-int seat_apply_acls(Seat *s, Session *old_active);
-int seat_set_active(Seat *s, Session *session);
-int seat_active_vt_changed(Seat *s, int vtnr);
-int seat_read_active_vt(Seat *s);
-int seat_preallocate_vts(Seat *s);
-
-int seat_attach_session(Seat *s, Session *session);
-
-bool seat_is_vtconsole(Seat *s);
-int seat_get_idle_hint(Seat *s, dual_timestamp *t);
-
-int seat_start(Seat *s);
-int seat_stop(Seat *s);
-int seat_stop_sessions(Seat *s);
-
-int seat_check_gc(Seat *s, bool drop_not_started);
-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;
-
-int seat_send_signal(Seat *s, bool new_seat);
-int seat_send_changed(Seat *s, const char *properties);
-
-#endif
diff --git a/src/logind-session-dbus.c b/src/logind-session-dbus.c
deleted file mode 100644
index dc0ef5b..0000000
--- a/src/logind-session-dbus.c
+++ /dev/null
@@ -1,515 +0,0 @@
-/*-*- 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 <string.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"                               \
-        "  <method name=\"Lock\"/>\n"                                   \
-        "  <method name=\"Unlock\"/>\n"                                 \
-        "  <method name=\"SetIdleHint\">\n"                             \
-        "   <arg name=\"b\" type=\"b\"/>\n"                             \
-        "  </method>\n"                                                 \
-        "  <method name=\"Kill\">\n"                                    \
-        "   <arg name=\"who\" type=\"s\"/>\n"                           \
-        "   <arg name=\"signal\" type=\"s\"/>\n"                        \
-        "  </method>\n"                                                 \
-        "  <property name=\"Id\" type=\"s\" access=\"read\"/>\n"        \
-        "  <property name=\"User\" type=\"(uo)\" access=\"read\"/>\n"   \
-        "  <property name=\"Name\" type=\"s\" access=\"read\"/>\n"      \
-        "  <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"TimestampMonotonic\" type=\"t\" 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=\"Service\" 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" \
-        "  <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n"  \
-        "  <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"IdleSinceHintMonotonic\" type=\"t\" 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;
-        dbus_bool_t 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 int bus_session_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
-        Session *s = data;
-        int b;
-
-        assert(i);
-        assert(property);
-        assert(s);
-
-        b = session_get_idle_hint(s, NULL) > 0;
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_session_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
-        Session *s = data;
-        dual_timestamp t;
-        uint64_t u;
-
-        assert(i);
-        assert(property);
-        assert(s);
-
-        session_get_idle_hint(s, &t);
-        u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
-                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", "Timestamp",          bus_property_append_usec,     "t",    &s->timestamp.realtime  },
-                { "org.freedesktop.login1.Session", "TimestampMonotonic", bus_property_append_usec,     "t",    &s->timestamp.monotonic },
-                { "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", "Service",            bus_property_append_string,   "s",    s->service              },
-                { "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      },
-                { "org.freedesktop.login1.Session", "IdleHint",           bus_session_append_idle_hint, "b",    s                       },
-                { "org.freedesktop.login1.Session", "IdleSinceHint",          bus_session_append_idle_hint_since, "t", s                },
-                { "org.freedesktop.login1.Session", "IdleSinceHintMonotonic", bus_session_append_idle_hint_since, "t", s                },
-                { NULL, NULL, NULL, NULL, NULL }
-        };
-
-        DBusError error;
-        DBusMessage *reply = NULL;
-        int r;
-
-        assert(s);
-        assert(connection);
-        assert(message);
-
-        dbus_error_init(&error);
-
-        if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Terminate")) {
-
-                r = session_stop(s);
-                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.Session", "Activate")) {
-
-                r = session_activate(s);
-                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.Session", "Lock") ||
-                   dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Unlock")) {
-
-                if (session_send_signal(s, streq(dbus_message_get_member(message), "Lock")) < 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.Session", "SetIdleHint")) {
-                dbus_bool_t b;
-                unsigned long ul;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_BOOLEAN, &b,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
-                if (ul == (unsigned long) -1)
-                        return bus_send_error_reply(connection, message, &error, -EIO);
-
-                if (ul != 0 && ul != s->user->uid)
-                        return bus_send_error_reply(connection, message, NULL, -EPERM);
-
-                session_set_idle_hint(s, b);
-
-                reply = dbus_message_new_method_return(message);
-                if (!reply)
-                        goto oom;
-
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "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);
-
-                r = session_kill(s, 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
-                return bus_default_message_handler(connection, message, INTROSPECTION, 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;
-}
-
-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;
-}
-
-int session_send_signal(Session *s, bool new_session) {
-        DBusMessage *m;
-        int r = -ENOMEM;
-        char *p = NULL;
-
-        assert(s);
-
-        m = dbus_message_new_signal("/org/freedesktop/login1",
-                                    "org.freedesktop.login1.Manager",
-                                    new_session ? "SessionNew" : "SessionRemoved");
-
-        if (!m)
-                return -ENOMEM;
-
-        p = session_bus_path(s);
-        if (!p)
-                goto finish;
-
-        if (!dbus_message_append_args(
-                            m,
-                            DBUS_TYPE_STRING, &s->id,
-                            DBUS_TYPE_OBJECT_PATH, &p,
-                            DBUS_TYPE_INVALID))
-                goto finish;
-
-        if (!dbus_connection_send(s->manager->bus, m, NULL))
-                goto finish;
-
-        r = 0;
-
-finish:
-        dbus_message_unref(m);
-        free(p);
-
-        return r;
-}
-
-int session_send_changed(Session *s, const char *properties) {
-        DBusMessage *m;
-        int r = -ENOMEM;
-        char *p = NULL;
-
-        assert(s);
-
-        if (!s->started)
-                return 0;
-
-        p = session_bus_path(s);
-        if (!p)
-                return -ENOMEM;
-
-        m = bus_properties_changed_new(p, "org.freedesktop.login1.Session", properties);
-        if (!m)
-                goto finish;
-
-        if (!dbus_connection_send(s->manager->bus, m, NULL))
-                goto finish;
-
-        r = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-        free(p);
-
-        return r;
-}
-
-int session_send_lock(Session *s, bool lock) {
-        DBusMessage *m;
-        bool b;
-        char *p;
-
-        assert(s);
-
-        p = session_bus_path(s);
-        if (!p)
-                return -ENOMEM;
-
-        m = dbus_message_new_signal(p, "org.freedesktop.login1.Session", lock ? "Lock" : "Unlock");
-        free(p);
-
-        if (!m)
-                return -ENOMEM;
-
-        b = dbus_connection_send(s->manager->bus, m, NULL);
-        dbus_message_unref(m);
-
-        if (!b)
-                return -ENOMEM;
-
-        return 0;
-}
diff --git a/src/logind-session.c b/src/logind-session.c
deleted file mode 100644
index 63ee758..0000000
--- a/src/logind-session.c
+++ /dev/null
@@ -1,945 +0,0 @@
-/*-*- 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 <string.h>
-#include <unistd.h>
-#include <sys/epoll.h>
-#include <fcntl.h>
-
-#include "logind-session.h"
-#include "strv.h"
-#include "util.h"
-#include "cgroup-util.h"
-
-#define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
-
-Session* session_new(Manager *m, User *u, const char *id) {
-        Session *s;
-
-        assert(m);
-        assert(id);
-
-        s = new0(Session, 1);
-        if (!s)
-                return NULL;
-
-        s->state_file = strappend("/run/systemd/sessions/", id);
-        if (!s->state_file) {
-                free(s);
-                return NULL;
-        }
-
-        s->id = file_name_from_path(s->state_file);
-
-        if (hashmap_put(m->sessions, s->id, s) < 0) {
-                free(s->id);
-                free(s);
-                return NULL;
-        }
-
-        s->manager = m;
-        s->fifo_fd = -1;
-        s->user = u;
-
-        LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
-
-        return s;
-}
-
-void session_free(Session *s) {
-        assert(s);
-
-        if (s->in_gc_queue)
-                LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
-
-        if (s->user) {
-                LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
-
-                if (s->user->display == s)
-                        s->user->display = NULL;
-        }
-
-        if (s->seat) {
-                if (s->seat->active == s)
-                        s->seat->active = NULL;
-
-                LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
-        }
-
-        if (s->cgroup_path)
-                hashmap_remove(s->manager->cgroups, s->cgroup_path);
-
-        free(s->cgroup_path);
-        strv_free(s->controllers);
-
-        free(s->tty);
-        free(s->display);
-        free(s->remote_host);
-        free(s->remote_user);
-        free(s->service);
-
-        hashmap_remove(s->manager->sessions, s->id);
-
-        session_remove_fifo(s);
-
-        free(s->state_file);
-        free(s);
-}
-
-int session_save(Session *s) {
-        FILE *f;
-        int r = 0;
-        char *temp_path;
-
-        assert(s);
-
-        if (!s->started)
-                return 0;
-
-        r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
-        if (r < 0)
-                goto finish;
-
-        r = fopen_temporary(s->state_file, &f, &temp_path);
-        if (r < 0)
-                goto finish;
-
-        assert(s->user);
-
-        fchmod(fileno(f), 0644);
-
-        fprintf(f,
-                "# This is private data. Do not parse.\n"
-                "UID=%lu\n"
-                "USER=%s\n"
-                "ACTIVE=%i\n"
-                "REMOTE=%i\n"
-                "KILL_PROCESSES=%i\n",
-                (unsigned long) s->user->uid,
-                s->user->name,
-                session_is_active(s),
-                s->remote,
-                s->kill_processes);
-
-        if (s->type >= 0)
-                fprintf(f,
-                        "TYPE=%s\n",
-                        session_type_to_string(s->type));
-
-        if (s->cgroup_path)
-                fprintf(f,
-                        "CGROUP=%s\n",
-                        s->cgroup_path);
-
-        if (s->fifo_path)
-                fprintf(f,
-                        "FIFO=%s\n",
-                        s->fifo_path);
-
-        if (s->seat)
-                fprintf(f,
-                        "SEAT=%s\n",
-                        s->seat->id);
-
-        if (s->tty)
-                fprintf(f,
-                        "TTY=%s\n",
-                        s->tty);
-
-        if (s->display)
-                fprintf(f,
-                        "DISPLAY=%s\n",
-                        s->display);
-
-        if (s->remote_host)
-                fprintf(f,
-                        "REMOTE_HOST=%s\n",
-                        s->remote_host);
-
-        if (s->remote_user)
-                fprintf(f,
-                        "REMOTE_USER=%s\n",
-                        s->remote_user);
-
-        if (s->service)
-                fprintf(f,
-                        "SERVICE=%s\n",
-                        s->service);
-
-        if (s->seat && seat_is_vtconsole(s->seat))
-                fprintf(f,
-                        "VTNR=%i\n",
-                        s->vtnr);
-
-        if (s->leader > 0)
-                fprintf(f,
-                        "LEADER=%lu\n",
-                        (unsigned long) s->leader);
-
-        if (s->audit_id > 0)
-                fprintf(f,
-                        "AUDIT=%llu\n",
-                        (unsigned long long) s->audit_id);
-
-        fflush(f);
-
-        if (ferror(f) || rename(temp_path, s->state_file) < 0) {
-                r = -errno;
-                unlink(s->state_file);
-                unlink(temp_path);
-        }
-
-        fclose(f);
-        free(temp_path);
-
-finish:
-        if (r < 0)
-                log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
-
-        return r;
-}
-
-int session_load(Session *s) {
-        char *remote = NULL,
-                *kill_processes = NULL,
-                *seat = NULL,
-                *vtnr = NULL,
-                *leader = NULL,
-                *audit_id = NULL,
-                *type = NULL;
-
-        int k, r;
-
-        assert(s);
-
-        r = parse_env_file(s->state_file, NEWLINE,
-                           "REMOTE",         &remote,
-                           "KILL_PROCESSES", &kill_processes,
-                           "CGROUP",         &s->cgroup_path,
-                           "FIFO",           &s->fifo_path,
-                           "SEAT",           &seat,
-                           "TTY",            &s->tty,
-                           "DISPLAY",        &s->display,
-                           "REMOTE_HOST",    &s->remote_host,
-                           "REMOTE_USER",    &s->remote_user,
-                           "SERVICE",        &s->service,
-                           "VTNR",           &vtnr,
-                           "LEADER",         &leader,
-                           "TYPE",           &type,
-                           NULL);
-
-        if (r < 0)
-                goto finish;
-
-        if (remote) {
-                k = parse_boolean(remote);
-                if (k >= 0)
-                        s->remote = k;
-        }
-
-        if (kill_processes) {
-                k = parse_boolean(kill_processes);
-                if (k >= 0)
-                        s->kill_processes = k;
-        }
-
-        if (seat && !s->seat) {
-                Seat *o;
-
-                o = hashmap_get(s->manager->seats, seat);
-                if (o)
-                        seat_attach_session(o, s);
-        }
-
-        if (vtnr && s->seat && seat_is_vtconsole(s->seat)) {
-                int v;
-
-                k = safe_atoi(vtnr, &v);
-                if (k >= 0 && v >= 1)
-                        s->vtnr = v;
-        }
-
-        if (leader) {
-                pid_t pid;
-
-                k = parse_pid(leader, &pid);
-                if (k >= 0 && pid >= 1) {
-                        s->leader = pid;
-
-                        audit_session_from_pid(pid, &s->audit_id);
-                }
-        }
-
-        if (type) {
-                SessionType t;
-
-                t = session_type_from_string(type);
-                if (t >= 0)
-                        s->type = t;
-        }
-
-        if (s->fifo_path) {
-                int fd;
-
-                /* If we open an unopened pipe for reading we will not
-                   get an EOF. to trigger an EOF we hence open it for
-                   reading, but close it right-away which then will
-                   trigger the EOF. */
-
-                fd = session_create_fifo(s);
-                if (fd >= 0)
-                        close_nointr_nofail(fd);
-        }
-
-
-finish:
-        free(remote);
-        free(kill_processes);
-        free(seat);
-        free(vtnr);
-        free(leader);
-        free(audit_id);
-
-        return r;
-}
-
-int session_activate(Session *s) {
-        int r;
-        Session *old_active;
-
-        assert(s);
-
-        if (s->vtnr < 0)
-                return -ENOTSUP;
-
-        if (!s->seat)
-                return -ENOTSUP;
-
-        if (s->seat->active == s)
-                return 0;
-
-        assert(seat_is_vtconsole(s->seat));
-
-        r = chvt(s->vtnr);
-        if (r < 0)
-                return r;
-
-        old_active = s->seat->active;
-        s->seat->active = s;
-
-        return seat_apply_acls(s->seat, old_active);
-}
-
-static int session_link_x11_socket(Session *s) {
-        char *t, *f, *c;
-        size_t k;
-
-        assert(s);
-        assert(s->user);
-        assert(s->user->runtime_path);
-
-        if (s->user->display)
-                return 0;
-
-        if (!s->display || !display_is_local(s->display))
-                return 0;
-
-        k = strspn(s->display+1, "0123456789");
-        f = new(char, sizeof("/tmp/.X11-unix/X") + k);
-        if (!f) {
-                log_error("Out of memory");
-                return -ENOMEM;
-        }
-
-        c = stpcpy(f, "/tmp/.X11-unix/X");
-        memcpy(c, s->display+1, k);
-        c[k] = 0;
-
-        if (access(f, F_OK) < 0) {
-                log_warning("Session %s has display %s with nonexisting socket %s.", s->id, s->display, f);
-                free(f);
-                return -ENOENT;
-        }
-
-        t = strappend(s->user->runtime_path, "/X11/display");
-        if (!t) {
-                log_error("Out of memory");
-                free(f);
-                return -ENOMEM;
-        }
-
-        mkdir_parents(t, 0755);
-
-        if (link(f, t) < 0) {
-                if (errno == EEXIST) {
-                        unlink(t);
-
-                        if (link(f, t) >= 0)
-                                goto done;
-                }
-
-                if (symlink(f, t) < 0) {
-
-                        if (errno == EEXIST) {
-                                unlink(t);
-
-                                if (symlink(f, t) >= 0)
-                                        goto done;
-                        }
-
-                        log_error("Failed to link %s to %s: %m", f, t);
-                        free(f);
-                        free(t);
-                        return -errno;
-                }
-        }
-
-done:
-        log_info("Linked %s to %s.", f, t);
-        free(f);
-        free(t);
-
-        s->user->display = s;
-
-        return 0;
-}
-
-static int session_create_one_group(Session *s, const char *controller, const char *path) {
-        int r;
-
-        assert(s);
-        assert(controller);
-        assert(path);
-
-        if (s->leader > 0) {
-                r = cg_create_and_attach(controller, path, s->leader);
-                if (r < 0)
-                        r = cg_create(controller, path);
-        } else
-                r = cg_create(controller, path);
-
-        if (r < 0)
-                return r;
-
-        r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid);
-        if (r >= 0)
-                r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
-
-        return r;
-}
-
-static int session_create_cgroup(Session *s) {
-        char **k;
-        char *p;
-        int r;
-
-        assert(s);
-        assert(s->user);
-        assert(s->user->cgroup_path);
-
-        if (!s->cgroup_path) {
-                if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0) {
-                        log_error("Out of memory");
-                        return -ENOMEM;
-                }
-        } else
-                p = s->cgroup_path;
-
-        r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
-        if (r < 0) {
-                log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
-                free(p);
-                s->cgroup_path = NULL;
-                return r;
-        }
-
-        s->cgroup_path = p;
-
-        STRV_FOREACH(k, s->controllers) {
-
-                if (strv_contains(s->reset_controllers, *k))
-                        continue;
-
-                r = session_create_one_group(s, *k, p);
-                if (r < 0)
-                        log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
-        }
-
-        STRV_FOREACH(k, s->manager->controllers) {
-
-                if (strv_contains(s->reset_controllers, *k) ||
-                    strv_contains(s->manager->reset_controllers, *k) ||
-                    strv_contains(s->controllers, *k))
-                        continue;
-
-                r = session_create_one_group(s, *k, p);
-                if (r < 0)
-                        log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
-        }
-
-        if (s->leader > 0) {
-
-                STRV_FOREACH(k, s->reset_controllers) {
-                        r = cg_attach(*k, "/", s->leader);
-                        if (r < 0)
-                                log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
-
-                }
-
-                STRV_FOREACH(k, s->manager->reset_controllers) {
-
-                        if (strv_contains(s->reset_controllers, *k) ||
-                            strv_contains(s->controllers, *k))
-                                continue;
-
-                        r = cg_attach(*k, "/", s->leader);
-                        if (r < 0)
-                                log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
-
-                }
-        }
-
-        hashmap_put(s->manager->cgroups, s->cgroup_path, s);
-
-        return 0;
-}
-
-int session_start(Session *s) {
-        int r;
-
-        assert(s);
-        assert(s->user);
-
-        if (s->started)
-                return 0;
-
-        r = user_start(s->user);
-        if (r < 0)
-                return r;
-
-        log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
-                 "New session %s of user %s.", s->id, s->user->name);
-
-        /* Create cgroup */
-        r = session_create_cgroup(s);
-        if (r < 0)
-                return r;
-
-        /* Create X11 symlink */
-        session_link_x11_socket(s);
-
-        dual_timestamp_get(&s->timestamp);
-
-        if (s->seat)
-                seat_read_active_vt(s->seat);
-
-        s->started = true;
-
-        /* Save session data */
-        session_save(s);
-        user_save(s->user);
-
-        session_send_signal(s, true);
-
-        if (s->seat) {
-                seat_save(s->seat);
-
-                if (s->seat->active == s)
-                        seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
-                else
-                        seat_send_changed(s->seat, "Sessions\0");
-        }
-
-        user_send_changed(s->user, "Sessions\0");
-
-        return 0;
-}
-
-static bool session_shall_kill(Session *s) {
-        assert(s);
-
-        if (!s->kill_processes)
-                return false;
-
-        if (strv_contains(s->manager->kill_exclude_users, s->user->name))
-                return false;
-
-        if (strv_isempty(s->manager->kill_only_users))
-                return true;
-
-        return strv_contains(s->manager->kill_only_users, s->user->name);
-}
-
-static int session_terminate_cgroup(Session *s) {
-        int r;
-        char **k;
-
-        assert(s);
-
-        if (!s->cgroup_path)
-                return 0;
-
-        cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
-
-        if (session_shall_kill(s)) {
-
-                r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
-                if (r < 0)
-                        log_error("Failed to kill session cgroup: %s", strerror(-r));
-
-        } else {
-                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
-                if (r < 0)
-                        log_error("Failed to check session cgroup: %s", strerror(-r));
-                else if (r > 0) {
-                        r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
-                        if (r < 0)
-                                log_error("Failed to delete session cgroup: %s", strerror(-r));
-                } else
-                        r = -EBUSY;
-        }
-
-        STRV_FOREACH(k, s->user->manager->controllers)
-                cg_trim(*k, s->cgroup_path, true);
-
-        hashmap_remove(s->manager->cgroups, s->cgroup_path);
-
-        free(s->cgroup_path);
-        s->cgroup_path = NULL;
-
-        return r;
-}
-
-static int session_unlink_x11_socket(Session *s) {
-        char *t;
-        int r;
-
-        assert(s);
-        assert(s->user);
-
-        if (s->user->display != s)
-                return 0;
-
-        s->user->display = NULL;
-
-        t = strappend(s->user->runtime_path, "/X11/display");
-        if (!t) {
-                log_error("Out of memory");
-                return -ENOMEM;
-        }
-
-        r = unlink(t);
-        free(t);
-
-        return r < 0 ? -errno : 0;
-}
-
-int session_stop(Session *s) {
-        int r = 0, k;
-
-        assert(s);
-
-        if (s->started)
-                log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
-                         "Removed session %s.", s->id);
-
-        /* Kill cgroup */
-        k = session_terminate_cgroup(s);
-        if (k < 0)
-                r = k;
-
-        /* Remove X11 symlink */
-        session_unlink_x11_socket(s);
-
-        unlink(s->state_file);
-        session_add_to_gc_queue(s);
-        user_add_to_gc_queue(s->user);
-
-        if (s->started)
-                session_send_signal(s, false);
-
-        if (s->seat) {
-                if (s->seat->active == s)
-                        seat_set_active(s->seat, NULL);
-
-                seat_send_changed(s->seat, "Sessions\0");
-        }
-
-        user_send_changed(s->user, "Sessions\0");
-
-        s->started = false;
-
-        return r;
-}
-
-bool session_is_active(Session *s) {
-        assert(s);
-
-        if (!s->seat)
-                return true;
-
-        return s->seat->active == s;
-}
-
-int session_get_idle_hint(Session *s, dual_timestamp *t) {
-        char *p;
-        struct stat st;
-        usec_t u, n;
-        bool b;
-        int k;
-
-        assert(s);
-
-        if (s->idle_hint) {
-                if (t)
-                        *t = s->idle_hint_timestamp;
-
-                return s->idle_hint;
-        }
-
-        if (isempty(s->tty))
-                goto dont_know;
-
-        if (s->tty[0] != '/') {
-                p = strappend("/dev/", s->tty);
-                if (!p)
-                        return -ENOMEM;
-        } else
-                p = NULL;
-
-        if (!startswith(p ? p : s->tty, "/dev/")) {
-                free(p);
-                goto dont_know;
-        }
-
-        k = lstat(p ? p : s->tty, &st);
-        free(p);
-
-        if (k < 0)
-                goto dont_know;
-
-        u = timespec_load(&st.st_atim);
-        n = now(CLOCK_REALTIME);
-        b = u + IDLE_THRESHOLD_USEC < n;
-
-        if (t)
-                dual_timestamp_from_realtime(t, u + b ? IDLE_THRESHOLD_USEC : 0);
-
-        return b;
-
-dont_know:
-        if (t)
-                *t = s->idle_hint_timestamp;
-
-        return 0;
-}
-
-void session_set_idle_hint(Session *s, bool b) {
-        assert(s);
-
-        if (s->idle_hint == b)
-                return;
-
-        s->idle_hint = b;
-        dual_timestamp_get(&s->idle_hint_timestamp);
-
-        session_send_changed(s,
-                             "IdleHint\0"
-                             "IdleSinceHint\0"
-                             "IdleSinceHintMonotonic\0");
-
-        if (s->seat)
-                seat_send_changed(s->seat,
-                                  "IdleHint\0"
-                                  "IdleSinceHint\0"
-                                  "IdleSinceHintMonotonic\0");
-
-        user_send_changed(s->user,
-                          "IdleHint\0"
-                          "IdleSinceHint\0"
-                          "IdleSinceHintMonotonic\0");
-
-        manager_send_changed(s->manager,
-                             "IdleHint\0"
-                             "IdleSinceHint\0"
-                             "IdleSinceHintMonotonic\0");
-}
-
-int session_create_fifo(Session *s) {
-        int r;
-
-        assert(s);
-
-        /* Create FIFO */
-        if (!s->fifo_path) {
-                r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
-                if (r < 0)
-                        return r;
-
-                if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
-                        return -ENOMEM;
-
-                if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
-                        return -errno;
-        }
-
-        /* Open reading side */
-        if (s->fifo_fd < 0) {
-                struct epoll_event ev;
-
-                s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
-                if (s->fifo_fd < 0)
-                        return -errno;
-
-                r = hashmap_put(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1), s);
-                if (r < 0)
-                        return r;
-
-                zero(ev);
-                ev.events = 0;
-                ev.data.u32 = FD_FIFO_BASE + s->fifo_fd;
-
-                if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
-                        return -errno;
-        }
-
-        /* Open writing side */
-        r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
-        if (r < 0)
-                return -errno;
-
-        return r;
-}
-
-void session_remove_fifo(Session *s) {
-        assert(s);
-
-        if (s->fifo_fd >= 0) {
-                assert_se(hashmap_remove(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
-                assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
-                close_nointr_nofail(s->fifo_fd);
-                s->fifo_fd = -1;
-        }
-
-        if (s->fifo_path) {
-                unlink(s->fifo_path);
-                free(s->fifo_path);
-                s->fifo_path = NULL;
-        }
-}
-
-int session_check_gc(Session *s, bool drop_not_started) {
-        int r;
-
-        assert(s);
-
-        if (drop_not_started && !s->started)
-                return 0;
-
-        if (s->fifo_fd >= 0) {
-
-                r = pipe_eof(s->fifo_fd);
-                if (r < 0)
-                        return r;
-
-                if (r == 0)
-                        return 1;
-        }
-
-        if (s->cgroup_path) {
-
-                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
-                if (r < 0)
-                        return r;
-
-                if (r <= 0)
-                        return 1;
-        }
-
-        return 0;
-}
-
-void session_add_to_gc_queue(Session *s) {
-        assert(s);
-
-        if (s->in_gc_queue)
-                return;
-
-        LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
-        s->in_gc_queue = true;
-}
-
-int session_kill(Session *s, KillWho who, int signo) {
-        int r = 0;
-        Set *pid_set = NULL;
-
-        assert(s);
-
-        if (!s->cgroup_path)
-                return -ESRCH;
-
-        if (s->leader <= 0 && who == KILL_LEADER)
-                return -ESRCH;
-
-        if (s->leader > 0)
-                if (kill(s->leader, signo) < 0)
-                        r = -errno;
-
-        if (who == KILL_ALL) {
-                int q;
-
-                pid_set = set_new(trivial_hash_func, trivial_compare_func);
-                if (!pid_set)
-                        return -ENOMEM;
-
-                if (s->leader > 0) {
-                        q = set_put(pid_set, LONG_TO_PTR(s->leader));
-                        if (q < 0)
-                                r = q;
-                }
-
-                q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
-                if (q < 0)
-                        if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
-                                r = q;
-        }
-
-        if (pid_set)
-                set_free(pid_set);
-
-        return r;
-}
-
-static const char* const session_type_table[_SESSION_TYPE_MAX] = {
-        [SESSION_TTY] = "tty",
-        [SESSION_X11] = "x11",
-        [SESSION_UNSPECIFIED] = "unspecified"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
-
-static const char* const kill_who_table[_KILL_WHO_MAX] = {
-        [KILL_LEADER] = "leader",
-        [KILL_ALL] = "all"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
diff --git a/src/logind-session.h b/src/logind-session.h
deleted file mode 100644
index 8e394ac..0000000
--- a/src/logind-session.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foologindsessionhfoo
-#define foologindsessionhfoo
-
-/***
-  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/>.
-***/
-
-typedef struct Session Session;
-
-#include "list.h"
-#include "util.h"
-#include "logind.h"
-#include "logind-seat.h"
-#include "logind-user.h"
-
-typedef enum SessionType {
-        SESSION_UNSPECIFIED,
-        SESSION_TTY,
-        SESSION_X11,
-        _SESSION_TYPE_MAX,
-        _SESSION_TYPE_INVALID = -1
-} SessionType;
-
-typedef enum KillWho {
-        KILL_LEADER,
-        KILL_ALL,
-        _KILL_WHO_MAX,
-        _KILL_WHO_INVALID = -1
-} KillWho;
-
-struct Session {
-        Manager *manager;
-
-        char *id;
-        SessionType type;
-
-        char *state_file;
-
-        User *user;
-
-        dual_timestamp timestamp;
-
-        char *tty;
-        char *display;
-
-        bool remote;
-        char *remote_user;
-        char *remote_host;
-
-        char *service;
-
-        int vtnr;
-        Seat *seat;
-
-        pid_t leader;
-        uint32_t audit_id;
-
-        int fifo_fd;
-        char *fifo_path;
-
-        char *cgroup_path;
-        char **controllers, **reset_controllers;
-
-        bool idle_hint;
-        dual_timestamp idle_hint_timestamp;
-
-        bool kill_processes;
-        bool in_gc_queue:1;
-        bool started:1;
-
-        LIST_FIELDS(Session, sessions_by_user);
-        LIST_FIELDS(Session, sessions_by_seat);
-
-        LIST_FIELDS(Session, gc_queue);
-};
-
-Session *session_new(Manager *m, User *u, const char *id);
-void session_free(Session *s);
-int session_check_gc(Session *s, bool drop_not_started);
-void session_add_to_gc_queue(Session *s);
-int session_activate(Session *s);
-bool session_is_active(Session *s);
-int session_get_idle_hint(Session *s, dual_timestamp *t);
-void session_set_idle_hint(Session *s, bool b);
-int session_create_fifo(Session *s);
-void session_remove_fifo(Session *s);
-int session_start(Session *s);
-int session_stop(Session *s);
-int session_save(Session *s);
-int session_load(Session *s);
-int session_kill(Session *s, KillWho who, int signo);
-
-char *session_bus_path(Session *s);
-
-extern const DBusObjectPathVTable bus_session_vtable;
-
-int session_send_signal(Session *s, bool new_session);
-int session_send_changed(Session *s, const char *properties);
-int session_send_lock(Session *s, bool lock);
-
-const char* session_type_to_string(SessionType t);
-SessionType session_type_from_string(const char *s);
-
-const char *kill_who_to_string(KillWho k);
-KillWho kill_who_from_string(const char *s);
-
-#endif
diff --git a/src/logind-user-dbus.c b/src/logind-user-dbus.c
deleted file mode 100644
index 3673a28..0000000
--- a/src/logind-user-dbus.c
+++ /dev/null
@@ -1,411 +0,0 @@
-/*-*- 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 <string.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"                              \
-        "  <method name=\"Kill\">\n"                                    \
-        "   <arg name=\"signal\" type=\"s\"/>\n"                        \
-        "  </method>\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=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"RuntimePath\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"ControlGroupPath\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"Service\" 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" \
-        "  <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n"  \
-        "  <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"IdleSinceHintMonotonic\" type=\"t\" 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 bus_user_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
-        User *u = data;
-        dbus_bool_t b;
-
-        assert(i);
-        assert(property);
-        assert(u);
-
-        b = user_get_idle_hint(u, NULL) > 0;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int bus_user_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
-        User *u = data;
-        dual_timestamp t;
-        uint64_t k;
-
-        assert(i);
-        assert(property);
-        assert(u);
-
-        user_get_idle_hint(u, &t);
-        k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k))
-                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", "Timestamp",          bus_property_append_usec,   "t",     &u->timestamp.realtime  },
-                { "org.freedesktop.login1.User", "TimestampMonotonic", bus_property_append_usec,   "t",     &u->timestamp.monotonic },
-                { "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                       },
-                { "org.freedesktop.login1.User", "IdleHint",           bus_user_append_idle_hint,  "b",     u                       },
-                { "org.freedesktop.login1.User", "IdleSinceHint",          bus_user_append_idle_hint_since, "t", u                  },
-                { "org.freedesktop.login1.User", "IdleSinceHintMonotonic", bus_user_append_idle_hint_since, "t", u                  },
-                { NULL, NULL, NULL, NULL, NULL }
-        };
-
-        DBusError error;
-        DBusMessage *reply = NULL;
-        int r;
-
-        assert(u);
-        assert(connection);
-        assert(message);
-
-        if (dbus_message_is_method_call(message, "org.freedesktop.login1.User", "Terminate")) {
-
-                r = user_stop(u);
-                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.User", "Kill")) {
-                int32_t signo;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    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);
-
-                r = user_kill(u, 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
-                return bus_default_message_handler(connection, message, INTROSPECTION, 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;
-}
-
-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;
-}
-
-int user_send_signal(User *u, bool new_user) {
-        DBusMessage *m;
-        int r = -ENOMEM;
-        char *p = NULL;
-        uint32_t uid;
-
-        assert(u);
-
-        m = dbus_message_new_signal("/org/freedesktop/login1",
-                                    "org.freedesktop.login1.Manager",
-                                    new_user ? "UserNew" : "UserRemoved");
-
-        if (!m)
-                return -ENOMEM;
-
-        p = user_bus_path(u);
-        if (!p)
-                goto finish;
-
-        uid = u->uid;
-
-        if (!dbus_message_append_args(
-                            m,
-                            DBUS_TYPE_UINT32, &uid,
-                            DBUS_TYPE_OBJECT_PATH, &p,
-                            DBUS_TYPE_INVALID))
-                goto finish;
-
-        if (!dbus_connection_send(u->manager->bus, m, NULL))
-                goto finish;
-
-        r = 0;
-
-finish:
-        dbus_message_unref(m);
-        free(p);
-
-        return r;
-}
-
-int user_send_changed(User *u, const char *properties) {
-        DBusMessage *m;
-        int r = -ENOMEM;
-        char *p = NULL;
-
-        assert(u);
-
-        if (!u->started)
-                return 0;
-
-        p = user_bus_path(u);
-        if (!p)
-                return -ENOMEM;
-
-        m = bus_properties_changed_new(p, "org.freedesktop.login1.User", properties);
-        if (!m)
-                goto finish;
-
-        if (!dbus_connection_send(u->manager->bus, m, NULL))
-                goto finish;
-
-        r = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-        free(p);
-
-        return r;
-}
diff --git a/src/logind-user.c b/src/logind-user.c
deleted file mode 100644
index 56c7de4..0000000
--- a/src/logind-user.c
+++ /dev/null
@@ -1,587 +0,0 @@
-/*-*- 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 <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include "logind-user.h"
-#include "util.h"
-#include "cgroup-util.h"
-#include "hashmap.h"
-#include "strv.h"
-
-User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
-        User *u;
-
-        assert(m);
-        assert(name);
-
-        u = new0(User, 1);
-        if (!u)
-                return NULL;
-
-        u->name = strdup(name);
-        if (!u->name) {
-                free(u);
-                return NULL;
-        }
-
-        if (asprintf(&u->state_file, "/run/systemd/users/%lu", (unsigned long) uid) < 0) {
-                free(u->name);
-                free(u);
-                return NULL;
-        }
-
-        if (hashmap_put(m->users, ULONG_TO_PTR((unsigned long) uid), u) < 0) {
-                free(u->state_file);
-                free(u->name);
-                free(u);
-                return NULL;
-        }
-
-        u->manager = m;
-        u->uid = uid;
-        u->gid = gid;
-
-        return u;
-}
-
-void user_free(User *u) {
-        assert(u);
-
-        if (u->in_gc_queue)
-                LIST_REMOVE(User, gc_queue, u->manager->user_gc_queue, u);
-
-        while (u->sessions)
-                session_free(u->sessions);
-
-        free(u->cgroup_path);
-
-        free(u->service);
-        free(u->runtime_path);
-
-        hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid));
-
-        free(u->name);
-        free(u->state_file);
-        free(u);
-}
-
-int user_save(User *u) {
-        FILE *f;
-        int r;
-        char *temp_path;
-
-        assert(u);
-        assert(u->state_file);
-
-        if (!u->started)
-                return 0;
-
-        r = safe_mkdir("/run/systemd/users", 0755, 0, 0);
-        if (r < 0)
-                goto finish;
-
-        r = fopen_temporary(u->state_file, &f, &temp_path);
-        if (r < 0)
-                goto finish;
-
-        fchmod(fileno(f), 0644);
-
-        fprintf(f,
-                "# This is private data. Do not parse.\n"
-                "NAME=%s\n"
-                "STATE=%s\n",
-                u->name,
-                user_state_to_string(user_get_state(u)));
-
-        if (u->cgroup_path)
-                fprintf(f,
-                        "CGROUP=%s\n",
-                        u->cgroup_path);
-
-        if (u->runtime_path)
-                fprintf(f,
-                        "RUNTIME=%s\n",
-                        u->runtime_path);
-
-        if (u->service)
-                fprintf(f,
-                        "SERVICE=%s\n",
-                        u->service);
-
-        if (u->display)
-                fprintf(f,
-                        "DISPLAY=%s\n",
-                        u->display->id);
-
-        if (u->sessions) {
-                Session *i;
-
-                fputs("SESSIONS=", f);
-                LIST_FOREACH(sessions_by_user, i, u->sessions) {
-                        fprintf(f,
-                                "%s%c",
-                                i->id,
-                                i->sessions_by_user_next ? ' ' : '\n');
-                }
-
-                fputs("SEATS=", f);
-                LIST_FOREACH(sessions_by_user, i, u->sessions) {
-                        if (i->seat)
-                                fprintf(f,
-                                        "%s%c",
-                                        i->seat->id,
-                                        i->sessions_by_user_next ? ' ' : '\n');
-                }
-
-                fputs("ACTIVE_SESSIONS=", f);
-                LIST_FOREACH(sessions_by_user, i, u->sessions)
-                        if (session_is_active(i))
-                                fprintf(f,
-                                        "%lu%c",
-                                        (unsigned long) i->user->uid,
-                                        i->sessions_by_user_next ? ' ' : '\n');
-
-                fputs("ACTIVE_SEATS=", f);
-                LIST_FOREACH(sessions_by_user, i, u->sessions) {
-                        if (session_is_active(i) && i->seat)
-                                fprintf(f,
-                                        "%s%c",
-                                        i->seat->id,
-                                        i->sessions_by_user_next ? ' ' : '\n');
-                }
-        }
-
-        fflush(f);
-
-        if (ferror(f) || rename(temp_path, u->state_file) < 0) {
-                r = -errno;
-                unlink(u->state_file);
-                unlink(temp_path);
-        }
-
-        fclose(f);
-        free(temp_path);
-
-finish:
-        if (r < 0)
-                log_error("Failed to save user data for %s: %s", u->name, strerror(-r));
-
-        return r;
-}
-
-int user_load(User *u) {
-        int r;
-        char *display = NULL;
-        Session *s = NULL;
-
-        assert(u);
-
-        r = parse_env_file(u->state_file, NEWLINE,
-                           "CGROUP", &u->cgroup_path,
-                           "RUNTIME", &u->runtime_path,
-                           "SERVICE", &u->service,
-                           "DISPLAY", &display,
-                           NULL);
-        if (r < 0) {
-                free(display);
-
-                if (r == -ENOENT)
-                        return 0;
-
-                log_error("Failed to read %s: %s", u->state_file, strerror(-r));
-                return r;
-        }
-
-        if (display) {
-                s = hashmap_get(u->manager->sessions, display);
-                free(display);
-        }
-
-        if (s && s->display && display_is_local(s->display))
-                u->display = s;
-
-        return r;
-}
-
-static int user_mkdir_runtime_path(User *u) {
-        char *p;
-        int r;
-
-        assert(u);
-
-        r = safe_mkdir("/run/user", 0755, 0, 0);
-        if (r < 0) {
-                log_error("Failed to create /run/user: %s", strerror(-r));
-                return r;
-        }
-
-        if (!u->runtime_path) {
-                p = strappend("/run/user/", u->name);
-
-                if (!p) {
-                        log_error("Out of memory");
-                        return -ENOMEM;
-                }
-        } else
-                p = u->runtime_path;
-
-        r = safe_mkdir(p, 0700, u->uid, u->gid);
-        if (r < 0) {
-                log_error("Failed to create runtime directory %s: %s", p, strerror(-r));
-                free(p);
-                u->runtime_path = NULL;
-                return r;
-        }
-
-        u->runtime_path = p;
-        return 0;
-}
-
-static int user_create_cgroup(User *u) {
-        char **k;
-        char *p;
-        int r;
-
-        assert(u);
-
-        if (!u->cgroup_path) {
-                if (asprintf(&p, "%s/%s", u->manager->cgroup_path, u->name) < 0) {
-                        log_error("Out of memory");
-                        return -ENOMEM;
-                }
-        } else
-                p = u->cgroup_path;
-
-        r = cg_create(SYSTEMD_CGROUP_CONTROLLER, p);
-        if (r < 0) {
-                log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
-                free(p);
-                u->cgroup_path = NULL;
-                return r;
-        }
-
-        u->cgroup_path = p;
-
-        STRV_FOREACH(k, u->manager->controllers) {
-
-                if (strv_contains(u->manager->reset_controllers, *k))
-                        continue;
-
-                r = cg_create(*k, p);
-                if (r < 0)
-                        log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r));
-        }
-
-        return 0;
-}
-
-static int user_start_service(User *u) {
-        assert(u);
-
-        return 0;
-}
-
-int user_start(User *u) {
-        int r;
-
-        assert(u);
-
-        if (u->started)
-                return 0;
-
-        log_info("New user %s logged in.", u->name);
-
-        /* Make XDG_RUNTIME_DIR */
-        r = user_mkdir_runtime_path(u);
-        if (r < 0)
-                return r;
-
-        /* Create cgroup */
-        r = user_create_cgroup(u);
-        if (r < 0)
-                return r;
-
-        /* Spawn user systemd */
-        r = user_start_service(u);
-        if (r < 0)
-                return r;
-
-        dual_timestamp_get(&u->timestamp);
-
-        u->started = true;
-
-        /* Save new user data */
-        user_save(u);
-
-        user_send_signal(u, true);
-
-        return 0;
-}
-
-static int user_stop_service(User *u) {
-        assert(u);
-
-        if (!u->service)
-                return 0;
-
-        return 0;
-}
-
-static int user_shall_kill(User *u) {
-        assert(u);
-
-        if (!u->manager->kill_user_processes)
-                return false;
-
-        if (strv_contains(u->manager->kill_exclude_users, u->name))
-                return false;
-
-        if (strv_isempty(u->manager->kill_only_users))
-                return true;
-
-        return strv_contains(u->manager->kill_only_users, u->name);
-}
-
-static int user_terminate_cgroup(User *u) {
-        int r;
-        char **k;
-
-        assert(u);
-
-        if (!u->cgroup_path)
-                return 0;
-
-        cg_trim(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false);
-
-        if (user_shall_kill(u)) {
-
-                r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
-                if (r < 0)
-                        log_error("Failed to kill user cgroup: %s", strerror(-r));
-        } else {
-
-                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
-                if (r < 0)
-                        log_error("Failed to check user cgroup: %s", strerror(-r));
-                else if (r > 0) {
-                        r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
-                        if (r < 0)
-                                log_error("Failed to delete user cgroup: %s", strerror(-r));
-                } else
-                        r = -EBUSY;
-        }
-
-        STRV_FOREACH(k, u->manager->controllers)
-                cg_trim(*k, u->cgroup_path, true);
-
-        free(u->cgroup_path);
-        u->cgroup_path = NULL;
-
-        return r;
-}
-
-static int user_remove_runtime_path(User *u) {
-        int r;
-
-        assert(u);
-
-        if (!u->runtime_path)
-                return 0;
-
-        r = rm_rf(u->runtime_path, false, true, false);
-        if (r < 0)
-                log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
-
-        free(u->runtime_path);
-        u->runtime_path = NULL;
-
-        return r;
-}
-
-int user_stop(User *u) {
-        Session *s;
-        int r = 0, k;
-        assert(u);
-
-        if (u->started)
-                log_info("User %s logged out.", u->name);
-
-        LIST_FOREACH(sessions_by_user, s, u->sessions) {
-                k = session_stop(s);
-                if (k < 0)
-                        r = k;
-        }
-
-        /* Kill systemd */
-        k = user_stop_service(u);
-        if (k < 0)
-                r = k;
-
-        /* Kill cgroup */
-        k = user_terminate_cgroup(u);
-        if (k < 0)
-                r = k;
-
-        /* Kill XDG_RUNTIME_DIR */
-        k = user_remove_runtime_path(u);
-        if (k < 0)
-                r = k;
-
-        unlink(u->state_file);
-        user_add_to_gc_queue(u);
-
-        if (u->started)
-                user_send_signal(u, false);
-
-        u->started = false;
-
-        return r;
-}
-
-int user_get_idle_hint(User *u, dual_timestamp *t) {
-        Session *s;
-        bool idle_hint = true;
-        dual_timestamp ts = { 0, 0 };
-
-        assert(u);
-
-        LIST_FOREACH(sessions_by_user, s, u->sessions) {
-                dual_timestamp k;
-                int ih;
-
-                ih = session_get_idle_hint(s, &k);
-                if (ih < 0)
-                        return ih;
-
-                if (!ih) {
-                        if (!idle_hint) {
-                                if (k.monotonic < ts.monotonic)
-                                        ts = k;
-                        } else {
-                                idle_hint = false;
-                                ts = k;
-                        }
-                } else if (idle_hint) {
-
-                        if (k.monotonic > ts.monotonic)
-                                ts = k;
-                }
-        }
-
-        if (t)
-                *t = ts;
-
-        return idle_hint;
-}
-
-int user_check_gc(User *u, bool drop_not_started) {
-        int r;
-        char *p;
-
-        assert(u);
-
-        if (drop_not_started && !u->started)
-                return 0;
-
-        if (u->sessions)
-                return 1;
-
-        if (asprintf(&p, "/var/lib/systemd/linger/%s", u->name) < 0)
-                return -ENOMEM;
-
-        r = access(p, F_OK) >= 0;
-        free(p);
-
-        if (r > 0)
-                return 1;
-
-        if (u->cgroup_path) {
-                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false);
-                if (r < 0)
-                        return r;
-
-                if (r <= 0)
-                        return 1;
-        }
-
-        return 0;
-}
-
-void user_add_to_gc_queue(User *u) {
-        assert(u);
-
-        if (u->in_gc_queue)
-                return;
-
-        LIST_PREPEND(User, gc_queue, u->manager->user_gc_queue, u);
-        u->in_gc_queue = true;
-}
-
-UserState user_get_state(User *u) {
-        Session *i;
-
-        assert(u);
-
-        if (!u->sessions)
-                return USER_LINGERING;
-
-        LIST_FOREACH(sessions_by_user, i, u->sessions)
-                if (session_is_active(i))
-                        return USER_ACTIVE;
-
-        return USER_ONLINE;
-}
-
-int user_kill(User *u, int signo) {
-        int r = 0, q;
-        Set *pid_set = NULL;
-
-        assert(u);
-
-        if (!u->cgroup_path)
-                return -ESRCH;
-
-        pid_set = set_new(trivial_hash_func, trivial_compare_func);
-        if (!pid_set)
-                return -ENOMEM;
-
-        q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
-        if (q < 0)
-                if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
-                        r = q;
-
-        if (pid_set)
-                set_free(pid_set);
-
-        return r;
-}
-
-static const char* const user_state_table[_USER_STATE_MAX] = {
-        [USER_OFFLINE] = "offline",
-        [USER_LINGERING] = "lingering",
-        [USER_ONLINE] = "online",
-        [USER_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
diff --git a/src/logind-user.h b/src/logind-user.h
deleted file mode 100644
index db9a5f6..0000000
--- a/src/logind-user.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foologinduserhfoo
-#define foologinduserhfoo
-
-/***
-  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/>.
-***/
-
-typedef struct User User;
-
-#include "list.h"
-#include "util.h"
-#include "logind.h"
-#include "logind-session.h"
-
-typedef enum UserState {
-        USER_OFFLINE,
-        USER_LINGERING,
-        USER_ONLINE,
-        USER_ACTIVE,
-        _USER_STATE_MAX,
-        _USER_STATE_INVALID = -1
-} UserState;
-
-struct User {
-        Manager *manager;
-
-        uid_t uid;
-        gid_t gid;
-        char *name;
-
-        char *state_file;
-        char *runtime_path;
-        char *service;
-        char *cgroup_path;
-
-        Session *display;
-
-        dual_timestamp timestamp;
-
-        bool in_gc_queue:1;
-        bool started:1;
-
-        LIST_HEAD(Session, sessions);
-        LIST_FIELDS(User, gc_queue);
-};
-
-User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name);
-void user_free(User *u);
-int user_check_gc(User *u, bool drop_not_started);
-void user_add_to_gc_queue(User *u);
-int user_start(User *u);
-int user_stop(User *u);
-UserState user_get_state(User *u);
-int user_get_idle_hint(User *u, dual_timestamp *t);
-int user_save(User *u);
-int user_load(User *u);
-int user_kill(User *u, int signo);
-
-char *user_bus_path(User *s);
-
-extern const DBusObjectPathVTable bus_user_vtable;
-
-int user_send_signal(User *u, bool new_user);
-int user_send_changed(User *u, const char *properties);
-
-const char* user_state_to_string(UserState s);
-UserState user_state_from_string(const char *s);
-
-#endif
diff --git a/src/logind.c b/src/logind.c
deleted file mode 100644
index 4633a5e..0000000
--- a/src/logind.c
+++ /dev/null
@@ -1,1228 +0,0 @@
-/*-*- 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 <pwd.h>
-#include <libudev.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/epoll.h>
-#include <sys/ioctl.h>
-#include <linux/vt.h>
-
-#include "logind.h"
-#include "dbus-common.h"
-#include "dbus-loop.h"
-#include "strv.h"
-#include "conf-parser.h"
-
-Manager *manager_new(void) {
-        Manager *m;
-
-        m = new0(Manager, 1);
-        if (!m)
-                return NULL;
-
-        m->console_active_fd = -1;
-        m->bus_fd = -1;
-        m->udev_seat_fd = -1;
-        m->udev_vcsa_fd = -1;
-        m->epoll_fd = -1;
-        m->n_autovts = 6;
-
-        m->devices = hashmap_new(string_hash_func, string_compare_func);
-        m->seats = hashmap_new(string_hash_func, string_compare_func);
-        m->sessions = hashmap_new(string_hash_func, string_compare_func);
-        m->users = hashmap_new(trivial_hash_func, trivial_compare_func);
-        m->cgroups = hashmap_new(string_hash_func, string_compare_func);
-        m->fifo_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
-
-        if (!m->devices || !m->seats || !m->sessions || !m->users || !m->cgroups || !m->fifo_fds) {
-                manager_free(m);
-                return NULL;
-        }
-
-        m->reset_controllers = strv_new("cpu", NULL);
-        m->kill_exclude_users = strv_new("root", NULL);
-        if (!m->reset_controllers || !m->kill_exclude_users) {
-                manager_free(m);
-                return NULL;
-        }
-
-        m->udev = udev_new();
-        if (!m->udev) {
-                manager_free(m);
-                return NULL;
-        }
-
-        if (cg_get_user_path(&m->cgroup_path) < 0) {
-                manager_free(m);
-                return NULL;
-        }
-
-        return m;
-}
-
-void manager_free(Manager *m) {
-        Session *session;
-        User *u;
-        Device *d;
-        Seat *s;
-
-        assert(m);
-
-        while ((session = hashmap_first(m->sessions)))
-                session_free(session);
-
-        while ((u = hashmap_first(m->users)))
-                user_free(u);
-
-        while ((d = hashmap_first(m->devices)))
-                device_free(d);
-
-        while ((s = hashmap_first(m->seats)))
-                seat_free(s);
-
-        hashmap_free(m->sessions);
-        hashmap_free(m->users);
-        hashmap_free(m->devices);
-        hashmap_free(m->seats);
-        hashmap_free(m->cgroups);
-        hashmap_free(m->fifo_fds);
-
-        if (m->console_active_fd >= 0)
-                close_nointr_nofail(m->console_active_fd);
-
-        if (m->udev_seat_monitor)
-                udev_monitor_unref(m->udev_seat_monitor);
-
-        if (m->udev_vcsa_monitor)
-                udev_monitor_unref(m->udev_vcsa_monitor);
-
-        if (m->udev)
-                udev_unref(m->udev);
-
-        if (m->bus) {
-                dbus_connection_flush(m->bus);
-                dbus_connection_close(m->bus);
-                dbus_connection_unref(m->bus);
-        }
-
-        if (m->bus_fd >= 0)
-                close_nointr_nofail(m->bus_fd);
-
-        if (m->epoll_fd >= 0)
-                close_nointr_nofail(m->epoll_fd);
-
-        strv_free(m->controllers);
-        strv_free(m->reset_controllers);
-        strv_free(m->kill_only_users);
-        strv_free(m->kill_exclude_users);
-
-        free(m->cgroup_path);
-        free(m);
-}
-
-int manager_add_device(Manager *m, const char *sysfs, Device **_device) {
-        Device *d;
-
-        assert(m);
-        assert(sysfs);
-
-        d = hashmap_get(m->devices, sysfs);
-        if (d) {
-                if (_device)
-                        *_device = d;
-
-                return 0;
-        }
-
-        d = device_new(m, sysfs);
-        if (!d)
-                return -ENOMEM;
-
-        if (_device)
-                *_device = d;
-
-        return 0;
-}
-
-int manager_add_seat(Manager *m, const char *id, Seat **_seat) {
-        Seat *s;
-
-        assert(m);
-        assert(id);
-
-        s = hashmap_get(m->seats, id);
-        if (s) {
-                if (_seat)
-                        *_seat = s;
-
-                return 0;
-        }
-
-        s = seat_new(m, id);
-        if (!s)
-                return -ENOMEM;
-
-        if (_seat)
-                *_seat = s;
-
-        return 0;
-}
-
-int manager_add_session(Manager *m, User *u, const char *id, Session **_session) {
-        Session *s;
-
-        assert(m);
-        assert(id);
-
-        s = hashmap_get(m->sessions, id);
-        if (s) {
-                if (_session)
-                        *_session = s;
-
-                return 0;
-        }
-
-        s = session_new(m, u, id);
-        if (!s)
-                return -ENOMEM;
-
-        if (_session)
-                *_session = s;
-
-        return 0;
-}
-
-int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
-        User *u;
-
-        assert(m);
-        assert(name);
-
-        u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
-        if (u) {
-                if (_user)
-                        *_user = u;
-
-                return 0;
-        }
-
-        u = user_new(m, uid, gid, name);
-        if (!u)
-                return -ENOMEM;
-
-        if (_user)
-                *_user = u;
-
-        return 0;
-}
-
-int manager_add_user_by_name(Manager *m, const char *name, User **_user) {
-        uid_t uid;
-        gid_t gid;
-        int r;
-
-        assert(m);
-        assert(name);
-
-        r = get_user_creds(&name, &uid, &gid, NULL);
-        if (r < 0)
-                return r;
-
-        return manager_add_user(m, uid, gid, name, _user);
-}
-
-int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
-        struct passwd *p;
-
-        assert(m);
-
-        errno = 0;
-        p = getpwuid(uid);
-        if (!p)
-                return errno ? -errno : -ENOENT;
-
-        return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
-}
-
-int manager_process_seat_device(Manager *m, struct udev_device *d) {
-        Device *device;
-        int r;
-
-        assert(m);
-
-        if (streq_ptr(udev_device_get_action(d), "remove")) {
-
-                device = hashmap_get(m->devices, udev_device_get_syspath(d));
-                if (!device)
-                        return 0;
-
-                seat_add_to_gc_queue(device->seat);
-                device_free(device);
-
-        } else {
-                const char *sn;
-                Seat *seat;
-
-                sn = udev_device_get_property_value(d, "ID_SEAT");
-                if (isempty(sn))
-                        sn = "seat0";
-
-                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);
-                if (r < 0)
-                        return r;
-
-                r = manager_add_seat(m, sn, &seat);
-                if (r < 0) {
-                        if (!device->seat)
-                                device_free(device);
-
-                        return r;
-                }
-
-                device_attach(device, seat);
-                seat_start(seat);
-        }
-
-        return 0;
-}
-
-int manager_enumerate_devices(Manager *m) {
-        struct udev_list_entry *item = NULL, *first = NULL;
-        struct udev_enumerate *e;
-        int r;
-
-        assert(m);
-
-        /* Loads devices from udev and creates seats for them as
-         * necessary */
-
-        e = udev_enumerate_new(m->udev);
-        if (!e) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        r = udev_enumerate_add_match_subsystem(e, "graphics");
-        if (r < 0)
-                goto finish;
-
-        r = udev_enumerate_add_match_tag(e, "seat");
-        if (r < 0)
-                goto finish;
-
-        r = udev_enumerate_scan_devices(e);
-        if (r < 0)
-                goto finish;
-
-        first = udev_enumerate_get_list_entry(e);
-        udev_list_entry_foreach(item, first) {
-                struct udev_device *d;
-                int k;
-
-                d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
-                if (!d) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                k = manager_process_seat_device(m, d);
-                udev_device_unref(d);
-
-                if (k < 0)
-                        r = k;
-        }
-
-finish:
-        if (e)
-                udev_enumerate_unref(e);
-
-        return r;
-}
-
-int manager_enumerate_seats(Manager *m) {
-        DIR *d;
-        struct dirent *de;
-        int r = 0;
-
-        assert(m);
-
-        /* This loads data about seats stored on disk, but does not
-         * actually create any seats. Removes data of seats that no
-         * longer exist. */
-
-        d = opendir("/run/systemd/seats");
-        if (!d) {
-                if (errno == ENOENT)
-                        return 0;
-
-                log_error("Failed to open /run/systemd/seats: %m");
-                return -errno;
-        }
-
-        while ((de = readdir(d))) {
-                Seat *s;
-                int k;
-
-                if (!dirent_is_file(de))
-                        continue;
-
-                s = hashmap_get(m->seats, de->d_name);
-                if (!s) {
-                        unlinkat(dirfd(d), de->d_name, 0);
-                        continue;
-                }
-
-                k = seat_load(s);
-                if (k < 0)
-                        r = k;
-        }
-
-        closedir(d);
-
-        return r;
-}
-
-static int manager_enumerate_users_from_cgroup(Manager *m) {
-        int r = 0;
-        char *name;
-        DIR *d;
-        int k;
-
-        r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &d);
-        if (r < 0) {
-                if (r == -ENOENT)
-                        return 0;
-
-                log_error("Failed to open %s: %s", m->cgroup_path, strerror(-r));
-                return r;
-        }
-
-        while ((k = cg_read_subgroup(d, &name)) > 0) {
-                User *user;
-
-                k = manager_add_user_by_name(m, name, &user);
-                if (k < 0) {
-                        free(name);
-                        r = k;
-                        continue;
-                }
-
-                user_add_to_gc_queue(user);
-
-                if (!user->cgroup_path)
-                        if (asprintf(&user->cgroup_path, "%s/%s", m->cgroup_path, name) < 0) {
-                                r = -ENOMEM;
-                                free(name);
-                                break;
-                        }
-
-                free(name);
-        }
-
-        if (r >= 0 && k < 0)
-                r = k;
-
-        closedir(d);
-
-        return r;
-}
-
-static int manager_enumerate_linger_users(Manager *m) {
-        DIR *d;
-        struct dirent *de;
-        int r = 0;
-
-        d = opendir("/var/lib/systemd/linger");
-        if (!d) {
-                if (errno == ENOENT)
-                        return 0;
-
-                log_error("Failed to open /var/lib/systemd/linger/: %m");
-                return -errno;
-        }
-
-        while ((de = readdir(d))) {
-                int k;
-
-                if (!dirent_is_file(de))
-                        continue;
-
-                k = manager_add_user_by_name(m, de->d_name, NULL);
-                if (k < 0) {
-                        log_notice("Couldn't add lingering user %s: %s", de->d_name, strerror(-k));
-                        r = k;
-                }
-        }
-
-        closedir(d);
-
-        return r;
-}
-
-int manager_enumerate_users(Manager *m) {
-        DIR *d;
-        struct dirent *de;
-        int r, k;
-
-        assert(m);
-
-        /* First, enumerate user cgroups */
-        r = manager_enumerate_users_from_cgroup(m);
-
-        /* Second, add lingering users on top */
-        k = manager_enumerate_linger_users(m);
-        if (k < 0)
-                r = k;
-
-        /* Third, read in user data stored on disk */
-        d = opendir("/run/systemd/users");
-        if (!d) {
-                if (errno == ENOENT)
-                        return 0;
-
-                log_error("Failed to open /run/systemd/users: %m");
-                return -errno;
-        }
-
-        while ((de = readdir(d))) {
-                uid_t uid;
-                User *u;
-
-                if (!dirent_is_file(de))
-                        continue;
-
-                k = parse_uid(de->d_name, &uid);
-                if (k < 0) {
-                        log_error("Failed to parse file name %s: %s", de->d_name, strerror(-k));
-                        continue;
-                }
-
-                u = hashmap_get(m->users, ULONG_TO_PTR(uid));
-                if (!u) {
-                        unlinkat(dirfd(d), de->d_name, 0);
-                        continue;
-                }
-
-                k = user_load(u);
-                if (k < 0)
-                        r = k;
-        }
-
-        closedir(d);
-
-        return r;
-}
-
-static int manager_enumerate_sessions_from_cgroup(Manager *m) {
-        User *u;
-        Iterator i;
-        int r = 0;
-
-        HASHMAP_FOREACH(u, m->users, i) {
-                DIR *d;
-                char *name;
-                int k;
-
-                if (!u->cgroup_path)
-                        continue;
-
-                k = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &d);
-                if (k < 0) {
-                        if (k == -ENOENT)
-                                continue;
-
-                        log_error("Failed to open %s: %s", u->cgroup_path, strerror(-k));
-                        r = k;
-                        continue;
-                }
-
-                while ((k = cg_read_subgroup(d, &name)) > 0) {
-                        Session *session;
-
-                        if (streq(name, "shared"))
-                                continue;
-
-                        k = manager_add_session(m, u, name, &session);
-                        if (k < 0) {
-                                free(name);
-                                break;
-                        }
-
-                        session_add_to_gc_queue(session);
-
-                        if (!session->cgroup_path)
-                                if (asprintf(&session->cgroup_path, "%s/%s", u->cgroup_path, name) < 0) {
-                                        k = -ENOMEM;
-                                        free(name);
-                                        break;
-                                }
-
-                        free(name);
-                }
-
-                closedir(d);
-
-                if (k < 0)
-                        r = k;
-        }
-
-        return r;
-}
-
-int manager_enumerate_sessions(Manager *m) {
-        DIR *d;
-        struct dirent *de;
-        int r = 0;
-
-        assert(m);
-
-        /* First enumerate session cgroups */
-        r = manager_enumerate_sessions_from_cgroup(m);
-
-        /* Second, read in session data stored on disk */
-        d = opendir("/run/systemd/sessions");
-        if (!d) {
-                if (errno == ENOENT)
-                        return 0;
-
-                log_error("Failed to open /run/systemd/sessions: %m");
-                return -errno;
-        }
-
-        while ((de = readdir(d))) {
-                struct Session *s;
-                int k;
-
-                if (!dirent_is_file(de))
-                        continue;
-
-                s = hashmap_get(m->sessions, de->d_name);
-                if (!s) {
-                        unlinkat(dirfd(d), de->d_name, 0);
-                        continue;
-                }
-
-                k = session_load(s);
-                if (k < 0)
-                        r = k;
-        }
-
-        closedir(d);
-
-        return r;
-}
-
-int manager_dispatch_seat_udev(Manager *m) {
-        struct udev_device *d;
-        int r;
-
-        assert(m);
-
-        d = udev_monitor_receive_device(m->udev_seat_monitor);
-        if (!d)
-                return -ENOMEM;
-
-        r = manager_process_seat_device(m, d);
-        udev_device_unref(d);
-
-        return r;
-}
-
-
-int manager_dispatch_vcsa_udev(Manager *m) {
-        struct udev_device *d;
-        int r = 0;
-        const char *name;
-
-        assert(m);
-
-        d = udev_monitor_receive_device(m->udev_vcsa_monitor);
-        if (!d)
-                return -ENOMEM;
-
-        name = udev_device_get_sysname(d);
-
-        /* Whenever a VCSA device is removed try to reallocate our
-         * VTs, to make sure our auto VTs never go away. */
-
-        if (name && startswith(name, "vcsa") && streq_ptr(udev_device_get_action(d), "remove"))
-                r = seat_preallocate_vts(m->vtconsole);
-
-        udev_device_unref(d);
-
-        return r;
-}
-
-int manager_dispatch_console(Manager *m) {
-        assert(m);
-
-        if (m->vtconsole)
-                seat_read_active_vt(m->vtconsole);
-
-        return 0;
-}
-
-static int vt_is_busy(int vtnr) {
-        struct vt_stat vt_stat;
-        int r = 0, fd;
-
-        assert(vtnr >= 1);
-
-        /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
-         * we'd open the latter we'd open the foreground tty which
-         * hence would be unconditionally busy. By opening /dev/tty1
-         * we avoid this. Since tty1 is special and needs to be an
-         * explicitly loaded getty or DM this is safe. */
-
-        fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
-                r = -errno;
-        else
-                r = !!(vt_stat.v_state & (1 << vtnr));
-
-        close_nointr_nofail(fd);
-
-        return r;
-}
-
-int manager_spawn_autovt(Manager *m, int vtnr) {
-        int r;
-        DBusMessage *message = NULL, *reply = NULL;
-        char *name = NULL;
-        const char *mode = "fail";
-        DBusError error;
-
-        assert(m);
-        assert(vtnr >= 1);
-
-        dbus_error_init(&error);
-
-        if ((unsigned) vtnr > m->n_autovts)
-                return 0;
-
-        r = vt_is_busy(vtnr);
-        if (r < 0)
-                return r;
-        else if (r > 0)
-                return -EBUSY;
-
-        message = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit");
-        if (!message) {
-                log_error("Could not allocate message.");
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (asprintf(&name, "autovt at tty%i.service", vtnr) < 0) {
-                log_error("Could not allocate service name.");
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (!dbus_message_append_args(message,
-                                      DBUS_TYPE_STRING, &name,
-                                      DBUS_TYPE_STRING, &mode,
-                                      DBUS_TYPE_INVALID)) {
-                log_error("Could not attach target and flag information to message.");
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        reply = dbus_connection_send_with_reply_and_block(m->bus, message, -1, &error);
-        if (!reply) {
-                log_error("Failed to start unit: %s", bus_error_message(&error));
-                goto finish;
-        }
-
-        r = 0;
-
-finish:
-        free(name);
-
-        if (message)
-                dbus_message_unref(message);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return r;
-}
-
-void manager_cgroup_notify_empty(Manager *m, const char *cgroup) {
-        Session *s;
-        char *p;
-
-        assert(m);
-        assert(cgroup);
-
-        p = strdup(cgroup);
-        if (!p) {
-                log_error("Out of memory.");
-                return;
-        }
-
-        for (;;) {
-                char *e;
-
-                if (isempty(p) || streq(p, "/"))
-                        break;
-
-                s = hashmap_get(m->cgroups, p);
-                if (s)
-                        session_add_to_gc_queue(s);
-
-                assert_se(e = strrchr(p, '/'));
-                *e = 0;
-        }
-
-        free(p);
-}
-
-static void manager_pipe_notify_eof(Manager *m, int fd) {
-        Session *s;
-
-        assert_se(m);
-        assert_se(fd >= 0);
-
-        assert_se(s = hashmap_get(m->fifo_fds, INT_TO_PTR(fd + 1)));
-        assert(s->fifo_fd == fd);
-        session_remove_fifo(s);
-
-        session_stop(s);
-}
-
-static int manager_connect_bus(Manager *m) {
-        DBusError error;
-        int r;
-        struct epoll_event ev;
-
-        assert(m);
-        assert(!m->bus);
-        assert(m->bus_fd < 0);
-
-        dbus_error_init(&error);
-
-        m->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
-        if (!m->bus) {
-                log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error));
-                r = -ECONNREFUSED;
-                goto fail;
-        }
-
-        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, bus_message_filter, m, NULL)) {
-                log_error("Not enough memory");
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        dbus_bus_add_match(m->bus,
-                           "type='signal',"
-                           "interface='org.freedesktop.systemd1.Agent',"
-                           "member='Released',"
-                           "path='/org/freedesktop/systemd1/agent'",
-                           &error);
-
-        if (dbus_error_is_set(&error)) {
-                log_error("Failed to register match: %s", bus_error_message(&error));
-                r = -EIO;
-                goto fail;
-        }
-
-        r = dbus_bus_request_name(m->bus, "org.freedesktop.login1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
-        if (dbus_error_is_set(&error)) {
-                log_error("Failed to register name on bus: %s", bus_error_message(&error));
-                r = -EIO;
-                goto fail;
-        }
-
-        if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)  {
-                log_error("Failed to acquire name.");
-                r = -EEXIST;
-                goto fail;
-        }
-
-        m->bus_fd = bus_loop_open(m->bus);
-        if (m->bus_fd < 0) {
-                r = m->bus_fd;
-                goto fail;
-        }
-
-        zero(ev);
-        ev.events = EPOLLIN;
-        ev.data.u32 = FD_BUS;
-
-        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0)
-                goto fail;
-
-        return 0;
-
-fail:
-        dbus_error_free(&error);
-
-        return r;
-}
-
-static int manager_connect_console(Manager *m) {
-        struct epoll_event ev;
-
-        assert(m);
-        assert(m->console_active_fd < 0);
-
-        m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC);
-        if (m->console_active_fd < 0) {
-                log_error("Failed to open /sys/class/tty/tty0/active: %m");
-                return -errno;
-        }
-
-        zero(ev);
-        ev.events = 0;
-        ev.data.u32 = FD_CONSOLE;
-
-        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->console_active_fd, &ev) < 0)
-                return -errno;
-
-        return 0;
-}
-
-static int manager_connect_udev(Manager *m) {
-        struct epoll_event ev;
-        int r;
-
-        assert(m);
-        assert(!m->udev_seat_monitor);
-        assert(!m->udev_vcsa_monitor);
-
-        m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
-        if (!m->udev_seat_monitor)
-                return -ENOMEM;
-
-        r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "seat");
-        if (r < 0)
-                return r;
-
-        r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_seat_monitor, "graphics", NULL);
-        if (r < 0)
-                return r;
-
-        r = udev_monitor_enable_receiving(m->udev_seat_monitor);
-        if (r < 0)
-                return r;
-
-        m->udev_seat_fd = udev_monitor_get_fd(m->udev_seat_monitor);
-
-        zero(ev);
-        ev.events = EPOLLIN;
-        ev.data.u32 = FD_SEAT_UDEV;
-
-        if (m->n_autovts <= 0)
-                return 0;
-
-        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_seat_fd, &ev) < 0)
-                return -errno;
-
-        m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
-        if (!m->udev_vcsa_monitor)
-                return -ENOMEM;
-
-        r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL);
-        if (r < 0)
-                return r;
-
-        r = udev_monitor_enable_receiving(m->udev_vcsa_monitor);
-        if (r < 0)
-                return r;
-
-        m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor);
-
-        zero(ev);
-        ev.events = EPOLLIN;
-        ev.data.u32 = FD_VCSA_UDEV;
-
-        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_vcsa_fd, &ev) < 0)
-                return -errno;
-
-        return 0;
-}
-
-void manager_gc(Manager *m, bool drop_not_started) {
-        Seat *seat;
-        Session *session;
-        User *user;
-
-        assert(m);
-
-        while ((seat = m->seat_gc_queue)) {
-                LIST_REMOVE(Seat, gc_queue, m->seat_gc_queue, seat);
-                seat->in_gc_queue = false;
-
-                if (seat_check_gc(seat, drop_not_started) == 0) {
-                        seat_stop(seat);
-                        seat_free(seat);
-                }
-        }
-
-        while ((session = m->session_gc_queue)) {
-                LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session);
-                session->in_gc_queue = false;
-
-                if (session_check_gc(session, drop_not_started) == 0) {
-                        session_stop(session);
-                        session_free(session);
-                }
-        }
-
-        while ((user = m->user_gc_queue)) {
-                LIST_REMOVE(User, gc_queue, m->user_gc_queue, user);
-                user->in_gc_queue = false;
-
-                if (user_check_gc(user, drop_not_started) == 0) {
-                        user_stop(user);
-                        user_free(user);
-                }
-        }
-}
-
-int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
-        Session *s;
-        bool idle_hint = true;
-        dual_timestamp ts = { 0, 0 };
-        Iterator i;
-
-        assert(m);
-
-        HASHMAP_FOREACH(s, m->sessions, i) {
-                dual_timestamp k;
-                int ih;
-
-                ih = session_get_idle_hint(s, &k);
-                if (ih < 0)
-                        return ih;
-
-                if (!ih) {
-                        if (!idle_hint) {
-                                if (k.monotonic < ts.monotonic)
-                                        ts = k;
-                        } else {
-                                idle_hint = false;
-                                ts = k;
-                        }
-                } else if (idle_hint) {
-
-                        if (k.monotonic > ts.monotonic)
-                                ts = k;
-                }
-        }
-
-        if (t)
-                *t = ts;
-
-        return idle_hint;
-}
-
-int manager_startup(Manager *m) {
-        int r;
-        Seat *seat;
-        Session *session;
-        User *user;
-        Iterator i;
-
-        assert(m);
-        assert(m->epoll_fd <= 0);
-
-        m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
-        if (m->epoll_fd < 0)
-                return -errno;
-
-        /* Connect to udev */
-        r = manager_connect_udev(m);
-        if (r < 0)
-                return r;
-
-        /* Connect to console */
-        r = manager_connect_console(m);
-        if (r < 0)
-                return r;
-
-        /* Connect to the bus */
-        r = manager_connect_bus(m);
-        if (r < 0)
-                return r;
-
-        /* Instantiate magic seat 0 */
-        r = manager_add_seat(m, "seat0", &m->vtconsole);
-        if (r < 0)
-                return r;
-
-        /* Deserialize state */
-        manager_enumerate_devices(m);
-        manager_enumerate_seats(m);
-        manager_enumerate_users(m);
-        manager_enumerate_sessions(m);
-
-        /* Remove stale objects before we start them */
-        manager_gc(m, false);
-
-        /* And start everything */
-        HASHMAP_FOREACH(seat, m->seats, i)
-                seat_start(seat);
-
-        HASHMAP_FOREACH(user, m->users, i)
-                user_start(user);
-
-        HASHMAP_FOREACH(session, m->sessions, i)
-                session_start(session);
-
-        return 0;
-}
-
-int manager_run(Manager *m) {
-        assert(m);
-
-        for (;;) {
-                struct epoll_event event;
-                int n;
-
-                manager_gc(m, true);
-
-                if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
-                        continue;
-
-                manager_gc(m, true);
-
-                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;
-                }
-
-                switch (event.data.u32) {
-
-                case FD_SEAT_UDEV:
-                        manager_dispatch_seat_udev(m);
-                        break;
-
-                case FD_VCSA_UDEV:
-                        manager_dispatch_vcsa_udev(m);
-                        break;
-
-                case FD_CONSOLE:
-                        manager_dispatch_console(m);
-                        break;
-
-                case FD_BUS:
-                        bus_loop_dispatch(m->bus_fd);
-                        break;
-
-                default:
-                        if (event.data.u32 >= FD_FIFO_BASE)
-                                manager_pipe_notify_eof(m, event.data.u32 - FD_FIFO_BASE);
-                }
-        }
-
-        return 0;
-}
-
-static int manager_parse_config_file(Manager *m) {
-        FILE *f;
-        const char *fn;
-        int r;
-
-        assert(m);
-
-        fn = "/etc/systemd/systemd-logind.conf";
-        f = fopen(fn, "re");
-        if (!f) {
-                if (errno == ENOENT)
-                        return 0;
-
-                log_warning("Failed to open configuration file %s: %m", fn);
-                return -errno;
-        }
-
-        r = config_parse(fn, f, "Login\0", config_item_perf_lookup, (void*) logind_gperf_lookup, false, m);
-        if (r < 0)
-                log_warning("Failed to parse configuration file: %s", strerror(-r));
-
-        fclose(f);
-
-        return r;
-}
-
-int main(int argc, char *argv[]) {
-        Manager *m = NULL;
-        int r;
-
-        log_set_target(LOG_TARGET_AUTO);
-        log_parse_environment();
-        log_open();
-
-        umask(0022);
-
-        if (argc != 1) {
-                log_error("This program takes no arguments.");
-                r = -EINVAL;
-                goto finish;
-        }
-
-        m = manager_new();
-        if (!m) {
-                log_error("Out of memory");
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        manager_parse_config_file(m);
-
-        r = manager_startup(m);
-        if (r < 0) {
-                log_error("Failed to fully start up daemon: %s", strerror(-r));
-                goto finish;
-        }
-
-        r = manager_run(m);
-
-finish:
-        if (m)
-                manager_free(m);
-
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/src/logind.h b/src/logind.h
deleted file mode 100644
index fd668a2..0000000
--- a/src/logind.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foologindhfoo
-#define foologindhfoo
-
-/***
-  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 <stdbool.h>
-#include <inttypes.h>
-#include <dbus/dbus.h>
-#include <libudev.h>
-
-#include "util.h"
-#include "list.h"
-#include "hashmap.h"
-#include "cgroup-util.h"
-
-typedef struct Manager Manager;
-
-#include "logind-device.h"
-#include "logind-seat.h"
-#include "logind-session.h"
-#include "logind-user.h"
-
-struct Manager {
-        DBusConnection *bus;
-
-        Hashmap *devices;
-        Hashmap *seats;
-        Hashmap *sessions;
-        Hashmap *users;
-
-        LIST_HEAD(Seat, seat_gc_queue);
-        LIST_HEAD(Session, session_gc_queue);
-        LIST_HEAD(User, user_gc_queue);
-
-        struct udev *udev;
-        struct udev_monitor *udev_seat_monitor, *udev_vcsa_monitor;
-
-        int udev_seat_fd;
-        int udev_vcsa_fd;
-
-        int console_active_fd;
-        int bus_fd;
-        int epoll_fd;
-
-        unsigned n_autovts;
-
-        Seat *vtconsole;
-
-        char *cgroup_path;
-        char **controllers, **reset_controllers;
-
-        char **kill_only_users, **kill_exclude_users;
-
-        bool kill_user_processes;
-
-        unsigned long session_counter;
-
-        Hashmap *cgroups;
-        Hashmap *fifo_fds;
-};
-
-enum {
-        FD_SEAT_UDEV,
-        FD_VCSA_UDEV,
-        FD_CONSOLE,
-        FD_BUS,
-        FD_FIFO_BASE
-};
-
-Manager *manager_new(void);
-void manager_free(Manager *m);
-
-int manager_add_device(Manager *m, const char *sysfs, Device **_device);
-int manager_add_seat(Manager *m, const char *id, Seat **_seat);
-int manager_add_session(Manager *m, User *u, const char *id, Session **_session);
-int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user);
-int manager_add_user_by_name(Manager *m, const char *name, User **_user);
-int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user);
-
-int manager_process_seat_device(Manager *m, struct udev_device *d);
-int manager_dispatch_seat_udev(Manager *m);
-int manager_dispatch_vcsa_udev(Manager *m);
-int manager_dispatch_console(Manager *m);
-
-int manager_enumerate_devices(Manager *m);
-int manager_enumerate_seats(Manager *m);
-int manager_enumerate_sessions(Manager *m);
-int manager_enumerate_users(Manager *m);
-
-int manager_startup(Manager *m);
-int manager_run(Manager *m);
-int manager_spawn_autovt(Manager *m, int vtnr);
-
-void manager_cgroup_notify_empty(Manager *m, const char *cgroup);
-
-void manager_gc(Manager *m, bool drop_not_started);
-
-int manager_get_idle_hint(Manager *m, dual_timestamp *t);
-
-extern const DBusObjectPathVTable bus_manager_vtable;
-
-DBusHandlerResult bus_message_filter(DBusConnection *c, DBusMessage *message, void *userdata);
-
-int manager_send_changed(Manager *manager, const char *properties);
-
-/* gperf lookup function */
-const struct ConfigPerfItem* logind_gperf_lookup(const char *key, unsigned length);
-
-#endif
diff --git a/src/sd-login.c b/src/sd-login.c
deleted file mode 100644
index a0a56c4..0000000
--- a/src/sd-login.c
+++ /dev/null
@@ -1,726 +0,0 @@
-/*-*- 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 <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/inotify.h>
-
-#include "util.h"
-#include "cgroup-util.h"
-#include "macro.h"
-#include "sd-login.h"
-#include "strv.h"
-
-static int pid_get_cgroup(pid_t pid, char **root, char **cgroup) {
-        char *cg_process, *cg_init, *p;
-        int r;
-
-        if (pid == 0)
-                pid = getpid();
-
-        if (pid <= 0)
-                return -EINVAL;
-
-        r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &cg_process);
-        if (r < 0)
-                return r;
-
-        r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &cg_init);
-        if (r < 0) {
-                free(cg_process);
-                return r;
-        }
-
-        if (endswith(cg_init, "/system"))
-                cg_init[strlen(cg_init)-7] = 0;
-        else if (streq(cg_init, "/"))
-                cg_init[0] = 0;
-
-        if (startswith(cg_process, cg_init))
-                p = cg_process + strlen(cg_init);
-        else
-                p = cg_process;
-
-        free(cg_init);
-
-        if (cgroup) {
-                char* c;
-
-                c = strdup(p);
-                if (!c) {
-                        free(cg_process);
-                        return -ENOMEM;
-                }
-
-                *cgroup = c;
-        }
-
-        if (root) {
-                cg_process[p-cg_process] = 0;
-                *root = cg_process;
-        } else
-                free(cg_process);
-
-        return 0;
-}
-
-_public_ int sd_pid_get_session(pid_t pid, char **session) {
-        int r;
-        char *cgroup, *p;
-
-        if (!session)
-                return -EINVAL;
-
-        r = pid_get_cgroup(pid, NULL, &cgroup);
-        if (r < 0)
-                return r;
-
-        if (!startswith(cgroup, "/user/")) {
-                free(cgroup);
-                return -ENOENT;
-        }
-
-        p = strchr(cgroup + 6, '/');
-        if (!p) {
-                free(cgroup);
-                return -ENOENT;
-        }
-
-        p++;
-        if (startswith(p, "shared/") || streq(p, "shared")) {
-                free(cgroup);
-                return -ENOENT;
-        }
-
-        p = strndup(p, strcspn(p, "/"));
-        free(cgroup);
-
-        if (!p)
-                return -ENOMEM;
-
-        *session = p;
-        return 0;
-}
-
-_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
-        int r;
-        char *root, *cgroup, *p, *cc;
-        struct stat st;
-
-        if (!uid)
-                return -EINVAL;
-
-        r = pid_get_cgroup(pid, &root, &cgroup);
-        if (r < 0)
-                return r;
-
-        if (!startswith(cgroup, "/user/")) {
-                free(cgroup);
-                free(root);
-                return -ENOENT;
-        }
-
-        p = strchr(cgroup + 6, '/');
-        if (!p) {
-                free(cgroup);
-                return -ENOENT;
-        }
-
-        p++;
-        p += strcspn(p, "/");
-        *p = 0;
-
-        r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, cgroup, &cc);
-        free(root);
-        free(cgroup);
-
-        if (r < 0)
-                return -ENOMEM;
-
-        r = lstat(cc, &st);
-        free(cc);
-
-        if (r < 0)
-                return -errno;
-
-        if (!S_ISDIR(st.st_mode))
-                return -ENOTDIR;
-
-        *uid = st.st_uid;
-        return 0;
-}
-
-_public_ int sd_uid_get_state(uid_t uid, char**state) {
-        char *p, *s = NULL;
-        int r;
-
-        if (!state)
-                return -EINVAL;
-
-        if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
-                return -ENOMEM;
-
-        r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
-        free(p);
-
-        if (r == -ENOENT) {
-                free(s);
-                s = strdup("offline");
-                if (!s)
-                        return -ENOMEM;
-
-                *state = s;
-                return 0;
-        } else if (r < 0) {
-                free(s);
-                return r;
-        } else if (!s)
-                return -EIO;
-
-        *state = s;
-        return 0;
-}
-
-_public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
-        char *p, *w, *t, *state, *s = NULL;
-        size_t l;
-        int r;
-        const char *variable;
-
-        if (!seat)
-                return -EINVAL;
-
-        variable = require_active ? "ACTIVE_UID" : "UIDS";
-
-        p = strappend("/run/systemd/seats/", seat);
-        if (!p)
-                return -ENOMEM;
-
-        r = parse_env_file(p, NEWLINE, variable, &s, NULL);
-        free(p);
-
-        if (r < 0) {
-                free(s);
-                return r;
-        }
-
-        if (!s)
-                return -EIO;
-
-        if (asprintf(&t, "%lu", (unsigned long) uid) < 0) {
-                free(s);
-                return -ENOMEM;
-        }
-
-        FOREACH_WORD(w, l, s, state) {
-                if (strncmp(t, w, l) == 0) {
-                        free(s);
-                        free(t);
-
-                        return 1;
-                }
-        }
-
-        free(s);
-        free(t);
-
-        return 0;
-}
-
-static int uid_get_array(uid_t uid, const char *variable, char ***array) {
-        char *p, *s = NULL;
-        char **a;
-        int r;
-
-        if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
-                return -ENOMEM;
-
-        r = parse_env_file(p, NEWLINE,
-                           variable, &s,
-                           NULL);
-        free(p);
-
-        if (r < 0) {
-                free(s);
-
-                if (r == -ENOENT) {
-                        if (array)
-                                *array = NULL;
-                        return 0;
-                }
-
-                return r;
-        }
-
-        if (!s) {
-                if (array)
-                        *array = NULL;
-                return 0;
-        }
-
-        a = strv_split(s, " ");
-        free(s);
-
-        if (!a)
-                return -ENOMEM;
-
-        strv_uniq(a);
-        r = strv_length(a);
-
-        if (array)
-                *array = a;
-        else
-                strv_free(a);
-
-        return r;
-}
-
-_public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
-        return uid_get_array(uid, require_active ? "ACTIVE_SESSIONS" : "SESSIONS", sessions);
-}
-
-_public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
-        return uid_get_array(uid, require_active ? "ACTIVE_SEATS" : "SEATS", seats);
-}
-
-_public_ int sd_session_is_active(const char *session) {
-        int r;
-        char *p, *s = NULL;
-
-        if (!session)
-                return -EINVAL;
-
-        p = strappend("/run/systemd/sessions/", session);
-        if (!p)
-                return -ENOMEM;
-
-        r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
-        free(p);
-
-        if (r < 0) {
-                free(s);
-                return r;
-        }
-
-        if (!s)
-                return -EIO;
-
-        r = parse_boolean(s);
-        free(s);
-
-        return r;
-}
-
-_public_ int sd_session_get_uid(const char *session, uid_t *uid) {
-        int r;
-        char *p, *s = NULL;
-
-        if (!session)
-                return -EINVAL;
-        if (!uid)
-                return -EINVAL;
-
-        p = strappend("/run/systemd/sessions/", session);
-        if (!p)
-                return -ENOMEM;
-
-        r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
-        free(p);
-
-        if (r < 0) {
-                free(s);
-                return r;
-        }
-
-        if (!s)
-                return -EIO;
-
-        r = parse_uid(s, uid);
-        free(s);
-
-        return r;
-}
-
-_public_ int sd_session_get_seat(const char *session, char **seat) {
-        char *p, *s = NULL;
-        int r;
-
-        if (!session)
-                return -EINVAL;
-        if (!seat)
-                return -EINVAL;
-
-        p = strappend("/run/systemd/sessions/", session);
-        if (!p)
-                return -ENOMEM;
-
-        r = parse_env_file(p, NEWLINE, "SEAT", &s, NULL);
-        free(p);
-
-        if (r < 0) {
-                free(s);
-                return r;
-        }
-
-        if (isempty(s))
-                return -ENOENT;
-
-        *seat = s;
-        return 0;
-}
-
-_public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
-        char *p, *s = NULL, *t = NULL;
-        int r;
-
-        if (!seat)
-                return -EINVAL;
-        if (!session && !uid)
-                return -EINVAL;
-
-        p = strappend("/run/systemd/seats/", seat);
-        if (!p)
-                return -ENOMEM;
-
-        r = parse_env_file(p, NEWLINE,
-                           "ACTIVE", &s,
-                           "ACTIVE_UID", &t,
-                           NULL);
-        free(p);
-
-        if (r < 0) {
-                free(s);
-                free(t);
-                return r;
-        }
-
-        if (session && !s)  {
-                free(t);
-                return -ENOENT;
-        }
-
-        if (uid && !t) {
-                free(s);
-                return -ENOENT;
-        }
-
-        if (uid && t) {
-                r = parse_uid(t, uid);
-                if (r < 0) {
-                        free(t);
-                        free(s);
-                        return r;
-                }
-        }
-
-        free(t);
-
-        if (session && s)
-                *session = s;
-        else
-                free(s);
-
-        return 0;
-}
-
-_public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
-        char *p, *s = NULL, *t = NULL, **a = NULL;
-        uid_t *b = NULL;
-        unsigned n = 0;
-        int r;
-
-        if (!seat)
-                return -EINVAL;
-
-        p = strappend("/run/systemd/seats/", seat);
-        if (!p)
-                return -ENOMEM;
-
-        r = parse_env_file(p, NEWLINE,
-                           "SESSIONS", &s,
-                           "ACTIVE_SESSIONS", &t,
-                           NULL);
-        free(p);
-
-        if (r < 0) {
-                free(s);
-                free(t);
-                return r;
-        }
-
-        if (s) {
-                a = strv_split(s, " ");
-                if (!a) {
-                        free(s);
-                        free(t);
-                        return -ENOMEM;
-                }
-        }
-
-        free(s);
-
-        if (uids && t) {
-                char *w, *state;
-                size_t l;
-
-                FOREACH_WORD(w, l, t, state)
-                        n++;
-
-                if (n == 0)
-                        b = NULL;
-                else {
-                        unsigned i = 0;
-
-                        b = new(uid_t, n);
-                        if (!b) {
-                                strv_free(a);
-                                return -ENOMEM;
-                        }
-
-                        FOREACH_WORD(w, l, t, state) {
-                                char *k;
-
-                                k = strndup(w, l);
-                                if (!k) {
-                                        free(t);
-                                        free(b);
-                                        strv_free(a);
-                                        return -ENOMEM;
-                                }
-
-                                r = parse_uid(k, b + i);
-                                free(k);
-                                if (r < 0)
-                                        continue;
-
-                                i++;
-                        }
-                }
-        }
-
-        free(t);
-
-        r = strv_length(a);
-
-        if (sessions)
-                *sessions = a;
-        else
-                strv_free(a);
-
-        if (uids)
-                *uids = b;
-
-        if (n_uids)
-                *n_uids = n;
-
-        return r;
-}
-
-_public_ int sd_seat_can_multi_session(const char *seat) {
-        char *p, *s = NULL;
-        int r;
-
-        if (!seat)
-                return -EINVAL;
-
-        p = strappend("/run/systemd/seats/", seat);
-        if (!p)
-                return -ENOMEM;
-
-        r = parse_env_file(p, NEWLINE,
-                           "IS_VTCONSOLE", &s,
-                           NULL);
-        free(p);
-
-        if (r < 0) {
-                free(s);
-                return r;
-        }
-
-        if (s) {
-                r = parse_boolean(s);
-                free(s);
-        } else
-                r = 0;
-
-        return r;
-}
-
-_public_ int sd_get_seats(char ***seats) {
-        return get_files_in_directory("/run/systemd/seats/", seats);
-}
-
-_public_ int sd_get_sessions(char ***sessions) {
-        return get_files_in_directory("/run/systemd/sessions/", sessions);
-}
-
-_public_ int sd_get_uids(uid_t **users) {
-        DIR *d;
-        int r = 0;
-        unsigned n = 0;
-        uid_t *l = NULL;
-
-        d = opendir("/run/systemd/users/");
-        if (!d)
-                return -errno;
-
-        for (;;) {
-                struct dirent buffer, *de;
-                int k;
-                uid_t uid;
-
-                k = readdir_r(d, &buffer, &de);
-                if (k != 0) {
-                        r = -k;
-                        goto finish;
-                }
-
-                if (!de)
-                        break;
-
-                dirent_ensure_type(d, de);
-
-                if (!dirent_is_file(de))
-                        continue;
-
-                k = parse_uid(de->d_name, &uid);
-                if (k < 0)
-                        continue;
-
-                if (users) {
-                        if ((unsigned) r >= n) {
-                                uid_t *t;
-
-                                n = MAX(16, 2*r);
-                                t = realloc(l, sizeof(uid_t) * n);
-                                if (!t) {
-                                        r = -ENOMEM;
-                                        goto finish;
-                                }
-
-                                l = t;
-                        }
-
-                        assert((unsigned) r < n);
-                        l[r++] = uid;
-                } else
-                        r++;
-        }
-
-finish:
-        if (d)
-                closedir(d);
-
-        if (r >= 0) {
-                if (users)
-                        *users = l;
-        } else
-                free(l);
-
-        return r;
-}
-
-static inline int MONITOR_TO_FD(sd_login_monitor *m) {
-        return (int) (unsigned long) m - 1;
-}
-
-static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
-        return (sd_login_monitor*) (unsigned long) (fd + 1);
-}
-
-_public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
-        int fd, k;
-        bool good = false;
-
-        if (!m)
-                return -EINVAL;
-
-        fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
-        if (fd < 0)
-                return errno;
-
-        if (!category || streq(category, "seat")) {
-                k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
-                if (k < 0) {
-                        close_nointr_nofail(fd);
-                        return -errno;
-                }
-
-                good = true;
-        }
-
-        if (!category || streq(category, "session")) {
-                k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
-                if (k < 0) {
-                        close_nointr_nofail(fd);
-                        return -errno;
-                }
-
-                good = true;
-        }
-
-        if (!category || streq(category, "uid")) {
-                k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
-                if (k < 0) {
-                        close_nointr_nofail(fd);
-                        return -errno;
-                }
-
-                good = true;
-        }
-
-        if (!good) {
-                close_nointr(fd);
-                return -EINVAL;
-        }
-
-        *m = FD_TO_MONITOR(fd);
-        return 0;
-}
-
-_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
-        int fd;
-
-        if (!m)
-                return NULL;
-
-        fd = MONITOR_TO_FD(m);
-        close_nointr(fd);
-
-        return NULL;
-}
-
-_public_ int sd_login_monitor_flush(sd_login_monitor *m) {
-
-        if (!m)
-                return -EINVAL;
-
-        return flush_fd(MONITOR_TO_FD(m));
-}
-
-_public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
-
-        if (!m)
-                return -EINVAL;
-
-        return MONITOR_TO_FD(m);
-}
diff --git a/src/sd-login.h b/src/sd-login.h
deleted file mode 100644
index 0cb0bf0..0000000
--- a/src/sd-login.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foosdloginhfoo
-#define foosdloginhfoo
-
-/***
-  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 <sys/types.h>
-
-/*
- * A few points:
- *
- * Instead of returning an empty string array or empty uid array, we
- * may return NULL.
- *
- * Free the data we return with libc free().
- *
- * We return error codes as negative errno, kernel-style. 0 or
- * positive on success.
- *
- * These functions access data in /proc, /sys/fs/cgroup and /run. All
- * of these are virtual file systems, hence the accesses are
- * relatively cheap.
- */
-
-/* Get session from PID. Note that 'shared' processes of a user are
- * not attached to a session, but only attached to a user. This will
- * return an error for system processes and 'shared' processes of a
- * user. */
-int sd_pid_get_session(pid_t pid, char **session);
-
-/* Get UID of the owner of the session of the PID (or in case the
- * process is a 'shared' user process the UID of that user is
- * returned). This will not return the UID of the process, but rather
- * the UID of the owner of the cgroup the process is in. This will
- * return an error for system processes. */
-int sd_pid_get_owner_uid(pid_t pid, uid_t *uid);
-
-/* Get state from uid. Possible states: offline, lingering, online, active */
-int sd_uid_get_state(uid_t uid, char**state);
-
-/* Return 1 if uid has session on seat. If require_active is true will
- * look for active sessions only. */
-int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat);
-
-/* Return sessions of user. If require_active is true will look for
- * active sessions only. Returns number of sessions as return
- * value. If sessions is NULL will just return number of sessions. */
-int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions);
-
-/* Return seats of user is on. If require_active is true will look for
- * active seats only.  Returns number of seats. If seats is NULL will
- * just return number of seats.*/
-int sd_uid_get_seats(uid_t uid, int require_active, char ***seats);
-
-/* Return 1 if the session is a active */
-int sd_session_is_active(const char *session);
-
-/* Determine user id of session */
-int sd_session_get_uid(const char *session, uid_t *uid);
-
-/* Determine seat of session */
-int sd_session_get_seat(const char *session, char **seat);
-
-/* Return active session and user of seat */
-int sd_seat_get_active(const char *seat, char **session, uid_t *uid);
-
-/* Return sessions and users on seat. Returns number of sessions as
- * return value. If sessions is NULL returns only the number of
- * sessions. */
-int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uid, unsigned *n_uids);
-
-/* Return whether the seat is multi-session capable */
-int sd_seat_can_multi_session(const char *seat);
-
-/* Get all seats, store in *seats. Returns the number of seats. If
- * seats is NULL only returns number of seats. */
-int sd_get_seats(char ***seats);
-
-/* Get all sessions, store in *sessions. Returns the number of
- * sessions. If sessions is NULL only returns number of sessions. */
-int sd_get_sessions(char ***sessions);
-
-/* Get all logged in users, store in *users. Returns the number of
- * users. If users is NULL only returns the number of users. */
-int sd_get_uids(uid_t **users);
-
-/* Monitor object */
-typedef struct sd_login_monitor sd_login_monitor;
-
-/* Create a new monitor. Category must be NULL, "seat", "session",
- * "uid" to get monitor events for the specific category (or all). */
-int sd_login_monitor_new(const char *category, sd_login_monitor** ret);
-
-/* Destroys the passed monitor. Returns NULL. */
-sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m);
-
-/* Flushes the monitor */
-int sd_login_monitor_flush(sd_login_monitor *m);
-
-/* Get FD from monitor */
-int sd_login_monitor_get_fd(sd_login_monitor *m);
-
-#endif
diff --git a/src/test-login.c b/src/test-login.c
deleted file mode 100644
index 7d6f082..0000000
--- a/src/test-login.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*-*- 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 <sys/poll.h>
-#include <string.h>
-
-#include "sd-login.h"
-#include "util.h"
-#include "strv.h"
-
-int main(int argc, char* argv[]) {
-        int r, k;
-        uid_t u, u2;
-        char *seat;
-        char *session;
-        char *state;
-        char *session2;
-        char *t;
-        char **seats, **sessions;
-        uid_t *uids;
-        unsigned n;
-        struct pollfd pollfd;
-        sd_login_monitor *m;
-
-        assert_se(sd_pid_get_session(0, &session) == 0);
-        printf("session = %s\n", session);
-
-        assert_se(sd_pid_get_owner_uid(0, &u2) == 0);
-        printf("user = %lu\n", (unsigned long) u2);
-
-        r = sd_uid_get_sessions(u2, false, &sessions);
-        assert_se(r >= 0);
-        assert_se(r == (int) strv_length(sessions));
-        assert_se(t = strv_join(sessions, ", "));
-        strv_free(sessions);
-        printf("sessions = %s\n", t);
-        free(t);
-
-        assert_se(r == sd_uid_get_sessions(u2, false, NULL));
-
-        r = sd_uid_get_seats(u2, false, &seats);
-        assert_se(r >= 0);
-        assert_se(r == (int) strv_length(seats));
-        assert_se(t = strv_join(seats, ", "));
-        strv_free(seats);
-        printf("seats = %s\n", t);
-        free(t);
-
-        assert_se(r == sd_uid_get_seats(u2, false, NULL));
-
-        r = sd_session_is_active(session);
-        assert_se(r >= 0);
-        printf("active = %s\n", yes_no(r));
-
-        assert_se(sd_session_get_uid(session, &u) >= 0);
-        printf("uid = %lu\n", (unsigned long) u);
-        assert_se(u == u2);
-
-        assert_se(sd_session_get_seat(session, &seat) >= 0);
-        printf("seat = %s\n", seat);
-
-        r = sd_seat_can_multi_session(seat);
-        assert_se(r >= 0);
-        printf("can do multi session = %s\n", yes_no(r));
-
-        assert_se(sd_uid_get_state(u, &state) >= 0);
-        printf("state = %s\n", state);
-
-        assert_se(sd_uid_is_on_seat(u, 0, seat) > 0);
-
-        k = sd_uid_is_on_seat(u, 1, seat);
-        assert_se(k >= 0);
-        assert_se(!!r == !!r);
-
-        assert_se(sd_seat_get_active(seat, &session2, &u2) >= 0);
-        printf("session2 = %s\n", session2);
-        printf("uid2 = %lu\n", (unsigned long) u2);
-
-        r = sd_seat_get_sessions(seat, &sessions, &uids, &n);
-        assert_se(r >= 0);
-        printf("n_sessions = %i\n", r);
-        assert_se(r == (int) strv_length(sessions));
-        assert_se(t = strv_join(sessions, ", "));
-        strv_free(sessions);
-        printf("sessions = %s\n", t);
-        free(t);
-        printf("uids =");
-        for (k = 0; k < (int) n; k++)
-                printf(" %lu", (unsigned long) uids[k]);
-        printf("\n");
-        free(uids);
-
-        assert_se(sd_seat_get_sessions(seat, NULL, NULL, NULL) == r);
-
-        free(session);
-        free(state);
-        free(session2);
-        free(seat);
-
-        r = sd_get_seats(&seats);
-        assert_se(r >= 0);
-        assert_se(r == (int) strv_length(seats));
-        assert_se(t = strv_join(seats, ", "));
-        strv_free(seats);
-        printf("n_seats = %i\n", r);
-        printf("seats = %s\n", t);
-        free(t);
-
-        assert_se(sd_get_seats(NULL) == r);
-
-        r = sd_get_sessions(&sessions);
-        assert_se(r >= 0);
-        assert_se(r == (int) strv_length(sessions));
-        assert_se(t = strv_join(sessions, ", "));
-        strv_free(sessions);
-        printf("n_sessions = %i\n", r);
-        printf("sessions = %s\n", t);
-        free(t);
-
-        assert_se(sd_get_sessions(NULL) == r);
-
-        r = sd_get_uids(&uids);
-        assert_se(r >= 0);
-
-        printf("uids =");
-        for (k = 0; k < r; k++)
-                printf(" %lu", (unsigned long) uids[k]);
-        printf("\n");
-        free(uids);
-
-        printf("n_uids = %i\n", r);
-        assert_se(sd_get_uids(NULL) == r);
-
-        r = sd_login_monitor_new("session", &m);
-        assert_se(r >= 0);
-
-        zero(pollfd);
-        pollfd.fd = sd_login_monitor_get_fd(m);
-        pollfd.events = POLLIN;
-
-        for (n = 0; n < 5; n++) {
-                r = poll(&pollfd, 1, -1);
-                assert_se(r >= 0);
-
-                sd_login_monitor_flush(m);
-                printf("Wake!\n");
-        }
-
-        sd_login_monitor_unref(m);
-
-        return 0;
-}
diff --git a/src/uaccess.c b/src/uaccess.c
deleted file mode 100644
index 49ac4af..0000000
--- a/src/uaccess.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*-*- 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 <string.h>
-
-#include "logind-acl.h"
-#include "util.h"
-#include "log.h"
-#include "sd-daemon.h"
-#include "sd-login.h"
-
-int main(int argc, char *argv[]) {
-        int r;
-        const char *path = NULL, *seat;
-        bool changed_acl = false;
-        uid_t uid;
-
-        log_set_target(LOG_TARGET_AUTO);
-        log_parse_environment();
-        log_open();
-
-        umask(0022);
-
-        if (argc < 2 || argc > 3) {
-                log_error("This program expects one or two arguments.");
-                r = -EINVAL;
-                goto finish;
-        }
-
-        /* Make sure we don't muck around with ACLs the system is not
-         * running systemd. */
-        if (!sd_booted())
-                return 0;
-
-        path = argv[1];
-        seat = argc < 3 || isempty(argv[2]) ? "seat0" : argv[2];
-
-        r = sd_seat_get_active(seat, NULL, &uid);
-        if (r == -ENOENT) {
-                /* No active session on this seat */
-                r = 0;
-                goto finish;
-        } else if (r < 0) {
-                log_error("Failed to determine active user on seat %s.", seat);
-                goto finish;
-        }
-
-        r = devnode_acl(path, true, false, 0, true, uid);
-        if (r < 0) {
-                log_error("Failed to apply ACL on %s: %s", path, strerror(-r));
-                goto finish;
-        }
-
-        changed_acl = true;
-        r = 0;
-
-finish:
-        if (path && !changed_acl) {
-                int k;
-                /* Better be safe that sorry and reset ACL */
-
-                k = devnode_acl(path, true, false, 0, false, 0);
-                if (k < 0) {
-                        log_error("Failed to apply ACL on %s: %s", path, strerror(-k));
-                        if (r >= 0)
-                                r = k;
-                }
-        }
-
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}

commit fc5e60ee0c64343d1bd08c343275fc1ceff445aa
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Dec 31 03:02:57 2011 +0100

    git: update gitignore

diff --git a/.gitignore b/.gitignore
index 28b40de..20e3ec1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+/systemd-rc-local-generator
 /libsystemd-journal.pc
 /libsystemd-id128.pc
 systemd-journalctl



More information about the systemd-commits mailing list