chiark / gitweb /
logind: port over to use scopes+slices for all cgroup stuff
authorLennart Poettering <lennart@poettering.net>
Mon, 1 Jul 2013 23:46:30 +0000 (01:46 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 1 Jul 2013 23:48:55 +0000 (01:48 +0200)
In order to prepare things for the single-writer cgroup scheme, let's
make logind use systemd's own primitives for cgroup management.

Every login user now gets his own private slice unit, in which his sessions
live in a scope unit each. Also, add user@$UID.service to the same
slice, and implicitly start it on first login.

21 files changed:
TODO
src/core/bus-errors.h
src/login/logind-dbus.c
src/login/logind-gperf.gperf
src/login/logind-machine-dbus.c
src/login/logind-machine.c
src/login/logind-machine.h
src/login/logind-session-dbus.c
src/login/logind-session.c
src/login/logind-session.h
src/login/logind-user-dbus.c
src/login/logind-user.c
src/login/logind-user.h
src/login/logind.c
src/login/logind.conf
src/login/logind.h
src/login/pam-module.c
src/shared/unit-name.c
src/shared/unit-name.h
src/systemctl/systemctl.c
units/user@.service.in

diff --git a/TODO b/TODO
index e8afa5f..cde2ced 100644 (file)
--- a/TODO
+++ b/TODO
@@ -28,6 +28,22 @@ Fedora 19:
 
 Features:
 
+* libsystemd-logind: recognize new session/user/machine units
+
+* logind: implement session kill exceptions
+
+* fix machine regstration to forward property array
+
+* fix loginctl cgroup enumeration
+
+* move "systemctl dump" to systemd-analyze
+
+* introduce "mainpid" for scopes
+
+* add a fixed dbus path for "my own unit", "my own session", ... to PID1, logind, ...
+
+* add implicit slice for instantiated services
+
 * service_coldplug() appears to reinstall the wrong stop timeout watch?
 
 * transient units: allow creating auxiliary units with the same call
index 7a4084e..9368d68 100644 (file)
@@ -40,3 +40,4 @@
 #define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic"
 #define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown"
 #define BUS_ERROR_NO_SUCH_PROCESS "org.freedesktop.systemd1.NoSuchProcess"
+#define BUS_ERROR_JOB_FAILED "org.freedesktop.systemd1.JobFailed"
index 6310069..d8d25b0 100644 (file)
@@ -38,6 +38,8 @@
 #include "label.h"
 #include "utf8.h"
 #include "unit-name.h"
+#include "bus-errors.h"
+#include "virt.h"
 
 #define BUS_MANAGER_INTERFACE                                           \
         " <interface name=\"org.freedesktop.login1.Manager\">\n"        \
@@ -94,9 +96,7 @@
         "   <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=\"scope_properties\" type=\"a(sv)\" 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=\"service\" type=\"s\" direction=\"in\"/>\n"      \
         "   <arg name=\"class\" type=\"s\" direction=\"in\"/>\n"        \
         "   <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n"       \
-        "   <arg name=\"slice\" type=\"s\" direction=\"in\"/>\n"        \
         "   <arg name=\"root_directory\" type=\"s\" direction=\"in\"/>\n" \
+        "   <arg name=\"scope_properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
         "   <arg name=\"path\" type=\"o\" direction=\"out\"/>\n"        \
         "  </method>\n"                                                 \
         "  <method name=\"ActivateSession\">\n"                         \
@@ -345,27 +345,24 @@ static int bus_manager_append_preparing(DBusMessageIter *i, const char *property
         return 0;
 }
 
-static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
+static int bus_manager_create_session(Manager *m, DBusMessage *message) {
+
         const char *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *service;
         uint32_t uid, leader, audit_id = 0;
-        dbus_bool_t remote, kill_processes, exists;
-        _cleanup_strv_free_ char **controllers = NULL, **reset_controllers = NULL;
-        _cleanup_free_ char *cgroup = NULL, *id = NULL, *p = NULL;
-        SessionType t;
-        SessionClass c;
-        DBusMessageIter iter;
-        int r;
-        uint32_t vtnr = 0;
-        _cleanup_close_ int fifo_fd = -1;
-        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+        _cleanup_free_ char *id = NULL;
         Session *session = NULL;
         User *user = NULL;
         Seat *seat = NULL;
+        DBusMessageIter iter;
+        dbus_bool_t remote;
+        uint32_t vtnr = 0;
+        SessionType t;
+        SessionClass c;
         bool b;
+        int r;
 
         assert(m);
         assert(message);
-        assert(_reply);
 
         if (!dbus_message_iter_init(message, &iter) ||
             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
@@ -515,67 +512,37 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
 
         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 (!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 (!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);
-
         if (leader <= 0) {
                 leader = bus_get_unix_process_id(m->bus, dbus_message_get_sender(message), NULL);
                 if (leader == 0)
                         return -EINVAL;
         }
 
-        r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, leader, &cgroup);
-        if (r < 0)
-                goto fail;
+        r = manager_get_session_by_pid(m, leader, &session);
+        if (session) {
+                _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+                _cleanup_free_ char *path = NULL;
+                _cleanup_close_ int fifo_fd = -1;
+                bool exists;
 
-        r = manager_get_session_by_cgroup(m, cgroup, &session);
-        if (r < 0)
-                goto fail;
+                /* Session already exists, client is probably
+                 * something like "su" which changes uid but is still
+                 * the same session */
 
-        if (session) {
                 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) {
+                path = session_bus_path(session);
+                if (!path) {
                         r = -ENOMEM;
                         goto fail;
                 }
 
-                p = session_bus_path(session);
-                if (!p) {
+                reply = dbus_message_new_method_return(message);
+                if (!reply) {
                         r = -ENOMEM;
                         goto fail;
                 }
@@ -587,7 +554,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
                 b = dbus_message_append_args(
                                 reply,
                                 DBUS_TYPE_STRING, &session->id,
-                                DBUS_TYPE_OBJECT_PATH, &p,
+                                DBUS_TYPE_OBJECT_PATH, &path,
                                 DBUS_TYPE_STRING, &session->user->runtime_path,
                                 DBUS_TYPE_UNIX_FD, &fifo_fd,
                                 DBUS_TYPE_STRING, &cseat,
@@ -599,8 +566,10 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
                         goto fail;
                 }
 
-                *_reply = reply;
-                reply = NULL;
+                if (!dbus_connection_send(m->bus, reply, NULL)) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
 
                 return 0;
         }
@@ -654,13 +623,8 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
         session->type = t;
         session->class = c;
         session->remote = remote;
-        session->kill_processes = kill_processes;
         session->vtnr = vtnr;
 
-        session->controllers = cg_shorten_controllers(controllers);
-        session->reset_controllers = cg_shorten_controllers(reset_controllers);
-        controllers = reset_controllers = NULL;
-
         if (!isempty(tty)) {
                 session->tty = strdup(tty);
                 if (!session->tty) {
@@ -701,12 +665,6 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
                 }
         }
 
-        fifo_fd = session_create_fifo(session);
-        if (fifo_fd < 0) {
-                r = fifo_fd;
-                goto fail;
-        }
-
         if (seat) {
                 r = seat_attach_session(seat, session);
                 if (r < 0)
@@ -717,38 +675,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
         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;
-        }
-
-        cseat = seat ? seat->id : "";
-        exists = false;
-        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, &cseat,
-                        DBUS_TYPE_UINT32, &vtnr,
-                        DBUS_TYPE_BOOLEAN, &exists,
-                        DBUS_TYPE_INVALID);
-
-        if (!b) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        *_reply = reply;
-        reply = NULL;
+        session->create_message = dbus_message_ref(message);
 
         return 0;
 
@@ -779,26 +706,20 @@ static bool valid_machine_name(const char *p) {
         return true;
 }
 
-static int bus_manager_create_machine(
-                Manager *manager,
-                DBusMessage *message,
-                DBusMessage **_reply) {
+static int bus_manager_create_machine(Manager *manager, DBusMessage *message) {
 
         const char *name, *service, *class, *slice, *root_directory;
-        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
         _cleanup_free_ char *p = NULL;
         DBusMessageIter iter, sub;
         MachineClass c;
         uint32_t leader;
         sd_id128_t id;
-        dbus_bool_t b;
         Machine *m;
         int n, r;
         void *v;
 
         assert(manager);
         assert(message);
-        assert(_reply);
 
         if (!dbus_message_iter_init(message, &iter) ||
             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
@@ -887,14 +808,6 @@ static int bus_manager_create_machine(
                 }
         }
 
-        if (!isempty(slice)) {
-                m->slice = strdup(slice);
-                if (!m->slice) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-        }
-
         if (!isempty(root_directory)) {
                 m->root_directory = strdup(root_directory);
                 if (!m->root_directory) {
@@ -907,29 +820,8 @@ static int bus_manager_create_machine(
         if (r < 0)
                 goto fail;
 
-        reply = dbus_message_new_method_return(message);
-        if (!reply) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        p = machine_bus_path(m);
-        if (!p) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        b = dbus_message_append_args(
-                        reply,
-                        DBUS_TYPE_OBJECT_PATH, &p,
-                        DBUS_TYPE_INVALID);
-        if (!b) {
-                r = -ENOMEM;
-                goto fail;
-        }
+        m->create_message = dbus_message_ref(message);
 
-        *_reply = reply;
-        reply = NULL;
         return 0;
 
 fail:
@@ -1608,8 +1500,6 @@ static int bus_manager_do_shutdown_or_sleep(
 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
 
 static const BusProperty bus_login_manager_properties[] = {
-        { "Controllers",            bus_property_append_strv,           "as", offsetof(Manager, controllers),        true },
-        { "ResetControllers",       bus_property_append_strv,           "as", offsetof(Manager, reset_controllers),  true },
         { "NAutoVTs",               bus_property_append_unsigned,       "u",  offsetof(Manager, n_autovts)           },
         { "KillOnlyUsers",          bus_property_append_strv,           "as", offsetof(Manager, kill_only_users),    true },
         { "KillExcludeUsers",       bus_property_append_strv,           "as", offsetof(Manager, kill_exclude_users), true },
@@ -2109,7 +1999,7 @@ static DBusHandlerResult manager_message_handler(
 
         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
 
-                r = bus_manager_create_session(m, message, &reply);
+                r = bus_manager_create_session(m, message);
 
                 /* Don't delay the work on OOM here, since it might be
                  * triggered by a low RLIMIT_NOFILE here (since we
@@ -2118,9 +2008,10 @@ static DBusHandlerResult manager_message_handler(
 
                 if (r < 0)
                         return bus_send_error_reply(connection, message, NULL, r);
+
         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateMachine")) {
 
-                r = bus_manager_create_machine(m, message, &reply);
+                r = bus_manager_create_machine(m, message);
                 if (r < 0)
                         return bus_send_error_reply(connection, message, NULL, r);
 
@@ -2753,7 +2644,7 @@ static DBusHandlerResult manager_message_handler(
 
         if (reply) {
                 if (!bus_maybe_send_reply(connection, message, reply))
-                                goto oom;
+                        goto oom;
         }
 
         return DBUS_HANDLER_RESULT_HANDLED;
@@ -2782,29 +2673,23 @@ DBusHandlerResult bus_message_filter(
 
         dbus_error_init(&error);
 
-        if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
-                const char *cgroup;
+        log_debug("Got message: %s %s %s", strna(dbus_message_get_sender(message)), strna(dbus_message_get_interface(message)), strna(dbus_message_get_member(message)));
 
-                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);
-
-        } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
-                uint32_t id;
+        if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
                 const char *path, *result, *unit;
+                uint32_t id;
 
                 if (!dbus_message_get_args(message, &error,
                                            DBUS_TYPE_UINT32, &id,
                                            DBUS_TYPE_OBJECT_PATH, &path,
                                            DBUS_TYPE_STRING, &unit,
                                            DBUS_TYPE_STRING, &result,
-                                           DBUS_TYPE_INVALID))
+                                           DBUS_TYPE_INVALID)) {
                         log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
+                        goto finish;
+                }
 
-                else if (m->action_job && streq(m->action_job, path)) {
+                if (m->action_job && streq(m->action_job, path)) {
                         log_info("Operation finished.");
 
                         /* Tell people that they now may take a lock again */
@@ -2814,9 +2699,97 @@ DBusHandlerResult bus_message_filter(
                         m->action_job = NULL;
                         m->action_unit = NULL;
                         m->action_what = 0;
+
+                } else {
+                        Machine *mm;
+                        Session *s;
+                        User *u;
+
+                        s = hashmap_get(m->session_units, unit);
+                        if (s) {
+                                if (streq_ptr(path, s->scope_job)) {
+                                        free(s->scope_job);
+                                        s->scope_job = NULL;
+
+                                        if (s->started) {
+                                                if (streq(result, "done"))
+                                                        session_send_create_reply(s, NULL);
+                                                else {
+                                                        dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
+                                                        session_send_create_reply(s, &error);
+                                                }
+                                        }
+                                }
+
+                                session_add_to_gc_queue(s);
+                        }
+
+                        u = hashmap_get(m->user_units, unit);
+                        if (u) {
+                                if (streq_ptr(path, u->service_job)) {
+                                        free(u->service_job);
+                                        u->service_job = NULL;
+                                }
+
+                                if (streq_ptr(path, u->slice_job)) {
+                                        free(u->slice_job);
+                                        u->slice_job = NULL;
+                                }
+
+                                user_add_to_gc_queue(u);
+                        }
+
+                        mm = hashmap_get(m->machine_units, unit);
+                        if (mm) {
+                                if (streq_ptr(path, mm->scope_job)) {
+                                        free(mm->scope_job);
+                                        mm->scope_job = NULL;
+
+                                        if (mm->started) {
+                                                if (streq(result, "done"))
+                                                        machine_send_create_reply(mm, NULL);
+                                                else {
+                                                        dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
+                                                        machine_send_create_reply(mm, &error);
+                                                }
+                                        }
+                                }
+
+                                machine_add_to_gc_queue(mm);
+                        }
+                }
+
+        } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
+
+                _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+                _cleanup_free_ char *unit = NULL;
+                const char *path;
+
+                path = dbus_message_get_path(message);
+                if (!path)
+                        goto finish;
+
+                unit_name_from_dbus_path(path, &unit);
+                if (unit) {
+                        Machine *mm;
+                        Session *s;
+                        User *u;
+
+                        s = hashmap_get(m->session_units, unit);
+                        if (s)
+                                session_add_to_gc_queue(s);
+
+                        u = hashmap_get(m->user_units, unit);
+                        if (u)
+                                user_add_to_gc_queue(u);
+
+                        mm = hashmap_get(m->machine_units, unit);
+                        if (mm)
+                                machine_add_to_gc_queue(mm);
                 }
         }
 
+finish:
         dbus_error_free(&error);
 
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -2871,3 +2844,288 @@ int manager_dispatch_delayed(Manager *manager) {
 
         return 1;
 }
+
+int manager_start_scope(
+                Manager *manager,
+                const char *scope,
+                pid_t pid,
+                const char *slice,
+                const char *description,
+                DBusError *error,
+                char **job) {
+
+        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
+        DBusMessageIter iter, sub, sub2, sub3, sub4;
+        const char *timeout_stop_property = "TimeoutStopUSec";
+        const char *pids_property = "PIDs";
+        uint64_t timeout = 500 * USEC_PER_MSEC;
+        const char *fail = "fail";
+        uint32_t u;
+
+        assert(manager);
+        assert(scope);
+        assert(pid > 1);
+
+        if (!slice)
+                slice = "";
+
+        m = dbus_message_new_method_call(
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "StartTransientUnit");
+        if (!m)
+                return log_oom();
+
+        dbus_message_iter_init_append(m, &iter);
+
+        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &scope) ||
+            !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &fail) ||
+            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
+                return log_oom();
+
+        if (!isempty(slice)) {
+                const char *slice_property = "Slice";
+
+                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &slice_property) ||
+                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
+                    !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &slice) ||
+                    !dbus_message_iter_close_container(&sub2, &sub3) ||
+                    !dbus_message_iter_close_container(&sub, &sub2))
+                        return log_oom();
+        }
+
+        if (!isempty(description)) {
+                const char *description_property = "Description";
+
+                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description_property) ||
+                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
+                    !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &description) ||
+                    !dbus_message_iter_close_container(&sub2, &sub3) ||
+                    !dbus_message_iter_close_container(&sub, &sub2))
+                        return log_oom();
+        }
+
+        /* cgroup empty notification is not available in containers
+         * currently. To make this less problematic, let's shorten the
+         * stop timeout for sessions, so that we don't wait
+         * forever. */
+
+        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &timeout_stop_property) ||
+            !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "t", &sub3) ||
+            !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &timeout) ||
+            !dbus_message_iter_close_container(&sub2, &sub3) ||
+            !dbus_message_iter_close_container(&sub, &sub2))
+                return log_oom();
+
+        u = pid;
+        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &pids_property) ||
+            !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "au", &sub3) ||
+            !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "u", &sub4) ||
+            !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_UINT32, &u) ||
+            !dbus_message_iter_close_container(&sub3, &sub4) ||
+            !dbus_message_iter_close_container(&sub2, &sub3) ||
+            !dbus_message_iter_close_container(&sub, &sub2) ||
+            !dbus_message_iter_close_container(&iter, &sub))
+                return log_oom();
+
+        reply = dbus_connection_send_with_reply_and_block(manager->bus, m, -1, error);
+        if (!reply)
+                return -EIO;
+
+        if (job) {
+                const char *j;
+                char *copy;
+
+                if (!dbus_message_get_args(reply, error, DBUS_TYPE_OBJECT_PATH, &j, DBUS_TYPE_INVALID))
+                        return -EIO;
+
+                copy = strdup(j);
+                if (!copy)
+                        return -ENOMEM;
+
+                *job = copy;
+        }
+
+        return 0;
+}
+
+int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
+        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+        const char *fail = "fail";
+        int r;
+
+        assert(manager);
+        assert(unit);
+
+        r = bus_method_call_with_reply(
+                        manager->bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "StartUnit",
+                        &reply,
+                        error,
+                        DBUS_TYPE_STRING, &unit,
+                        DBUS_TYPE_STRING, &fail,
+                        DBUS_TYPE_INVALID);
+        if (r < 0) {
+                log_error("Failed to start unit %s: %s", unit, bus_error(error, r));
+                return r;
+        }
+
+        if (job) {
+                const char *j;
+                char *copy;
+
+                if (!dbus_message_get_args(reply, error,
+                                           DBUS_TYPE_OBJECT_PATH, &j,
+                                           DBUS_TYPE_INVALID)) {
+                        log_error("Failed to parse reply.");
+                        return -EIO;
+                }
+
+                copy = strdup(j);
+                if (!copy)
+                        return -ENOMEM;
+
+                *job = copy;
+        }
+
+        return 0;
+}
+
+int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
+        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+        const char *fail = "fail";
+        int r;
+
+        assert(manager);
+        assert(unit);
+
+        r = bus_method_call_with_reply(
+                        manager->bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "StopUnit",
+                        &reply,
+                        error,
+                        DBUS_TYPE_STRING, &unit,
+                        DBUS_TYPE_STRING, &fail,
+                        DBUS_TYPE_INVALID);
+        if (r < 0) {
+                log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
+                return r;
+        }
+
+        if (job) {
+                const char *j;
+                char *copy;
+
+                if (!dbus_message_get_args(reply, error,
+                                           DBUS_TYPE_OBJECT_PATH, &j,
+                                           DBUS_TYPE_INVALID)) {
+                        log_error("Failed to parse reply.");
+                        return -EIO;
+                }
+
+                copy = strdup(j);
+                if (!copy)
+                        return -ENOMEM;
+
+                *job = copy;
+        }
+
+        return 0;
+}
+
+int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
+        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+        const char *w;
+        int r;
+
+        assert(manager);
+        assert(unit);
+
+        w = who == KILL_LEADER ? "process" : "cgroup";
+        assert_cc(sizeof(signo) == sizeof(int32_t));
+
+        r = bus_method_call_with_reply(
+                        manager->bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "KillUnit",
+                        &reply,
+                        error,
+                        DBUS_TYPE_STRING, &unit,
+                        DBUS_TYPE_STRING, &w,
+                        DBUS_TYPE_INT32, &signo,
+                        DBUS_TYPE_INVALID);
+        if (r < 0) {
+                log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
+                return r;
+        }
+
+        return 0;
+}
+
+int manager_unit_is_active(Manager *manager, const char *unit) {
+
+        const char *interface = "org.freedesktop.systemd1.Unit";
+        const char *property = "ActiveState";
+        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+        _cleanup_free_ char *path = NULL;
+        DBusMessageIter iter, sub;
+        const char *state;
+        DBusError error;
+        int r;
+
+        assert(manager);
+        assert(unit);
+
+        dbus_error_init(&error);
+
+        path = unit_dbus_path_from_name(unit);
+        if (!path)
+                return -ENOMEM;
+
+        r = bus_method_call_with_reply(
+                        manager->bus,
+                        "org.freedesktop.systemd1",
+                        path,
+                        "org.freedesktop.DBus.Properties",
+                        "Get",
+                        &reply,
+                        &error,
+                        DBUS_TYPE_STRING, &interface,
+                        DBUS_TYPE_STRING, &property,
+                        DBUS_TYPE_INVALID);
+
+        if (r < 0) {
+                log_error("Failed to query ActiveState: %s", bus_error(&error, r));
+                dbus_error_free(&error);
+                return r;
+        }
+
+        if (!dbus_message_iter_init(reply, &iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
+                log_error("Failed to parse reply.");
+                return -EINVAL;
+        }
+
+        dbus_message_iter_recurse(&iter, &sub);
+        if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
+                log_error("Failed to parse reply.");
+                return -EINVAL;
+        }
+
+        dbus_message_iter_get_basic(&sub, &state);
+
+        return !streq(state, "inactive") && !streq(state, "failed");
+}
index 735d2db..845302a 100644 (file)
@@ -19,8 +19,6 @@ Login.ReserveVT,                   config_parse_unsigned,      0, offsetof(Manag
 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)
 Login.InhibitDelayMaxSec,          config_parse_sec,           0, offsetof(Manager, inhibit_delay_max)
 Login.HandlePowerKey,              config_parse_handle_action, 0, offsetof(Manager, handle_power_key)
 Login.HandleSuspendKey,            config_parse_handle_action, 0, offsetof(Manager, handle_suspend_key)
index 7feea2e..ae8c5d7 100644 (file)
         "  <property name=\"Id\" type=\"ay\" access=\"read\"/>\n"        \
         "  <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"Service\" type=\"s\" access=\"read\"/>\n"   \
-        "  <property name=\"Slice\" type=\"s\" access=\"read\"/>\n"     \
+        "  <property name=\"Scope\" type=\"s\" access=\"read\"/>\n"     \
         "  <property name=\"Leader\" type=\"u\" access=\"read\"/>\n"    \
         "  <property name=\"Class\" type=\"s\" access=\"read\"/>\n"     \
+        "  <property name=\"State\" type=\"s\" access=\"read\"/>\n"     \
         "  <property name=\"RootDirectory\" type=\"s\" access=\"read\"/>\n" \
         " </interface>\n"
 
         BUS_GENERIC_INTERFACES_LIST                  \
         "org.freedesktop.login1.Machine\0"
 
-static int bus_machine_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
-        _cleanup_free_ char *t = NULL;
-        Machine *m = data;
-        int r;
-        bool success;
-
-        assert(i);
-        assert(property);
-        assert(m);
-
-        r = cg_join_spec(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &t);
-        if (r < 0)
-                return r;
-
-        success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
-        return success ? 0 : -ENOMEM;
-}
-
 static int bus_machine_append_id(DBusMessageIter *i, const char *property, void *data) {
         DBusMessageIter sub;
         Machine *m = data;
@@ -100,6 +82,22 @@ static int bus_machine_append_id(DBusMessageIter *i, const char *property, void
         return 0;
 }
 
+static int bus_machine_append_state(DBusMessageIter *i, const char *property, void *data) {
+        Machine *m = data;
+        const char *state;
+
+        assert(i);
+        assert(property);
+        assert(m);
+
+        state = machine_state_to_string(machine_get_state(m));
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
+                return -ENOMEM;
+
+        return 0;
+}
+
 static int get_machine_for_path(Manager *m, const char *path, Machine **_machine) {
         _cleanup_free_ char *e = NULL;
         Machine *machine;
@@ -130,11 +128,11 @@ static const BusProperty bus_login_machine_properties[] = {
         { "Id",                     bus_machine_append_id,            "ay", 0 },
         { "Timestamp",              bus_property_append_usec,          "t", offsetof(Machine, timestamp.realtime)  },
         { "TimestampMonotonic",     bus_property_append_usec,          "t", offsetof(Machine, timestamp.monotonic) },
-        { "DefaultControlGroup",    bus_machine_append_default_cgroup, "s", 0 },
         { "Service",                bus_property_append_string,        "s", offsetof(Machine, service),            true },
-        { "Slice",                  bus_property_append_string,        "s", offsetof(Machine, slice),              true },
+        { "Scope",                  bus_property_append_string,        "s", offsetof(Machine, scope),              true },
         { "Leader",                 bus_property_append_pid,           "u", offsetof(Session, leader)              },
         { "Class",                  bus_machine_append_class,          "s", offsetof(Machine, class)               },
+        { "State",                  bus_machine_append_state,          "s", 0                                      },
         { "RootDirectory",          bus_property_append_string,        "s", offsetof(Machine, root_directory),     true },
         { NULL, }
 };
@@ -313,3 +311,50 @@ int machine_send_changed(Machine *m, const char *properties) {
 
         return 0;
 }
+
+int machine_send_create_reply(Machine *m, DBusError *error) {
+        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+
+        assert(m);
+
+        if (!m->create_message)
+                return 0;
+
+        if (error) {
+                DBusError buffer;
+
+                dbus_error_init(&buffer);
+
+                if (!error || !dbus_error_is_set(error)) {
+                        dbus_set_error_const(&buffer, DBUS_ERROR_INVALID_ARGS, "Invalid Arguments");
+                        error = &buffer;
+                }
+
+                reply = dbus_message_new_error(m->create_message, error->name, error->message);
+                dbus_error_free(&buffer);
+
+                if (!reply)
+                        return log_oom();
+        } else {
+                _cleanup_free_ char *p = NULL;
+
+                p = machine_bus_path(m);
+                if (!p)
+                        return log_oom();
+
+                reply = dbus_message_new_method_return(m->create_message);
+                if (!reply)
+                        return log_oom();
+
+                if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &p, DBUS_TYPE_INVALID))
+                        return log_oom();
+        }
+
+        if (!dbus_connection_send(m->manager->bus, reply, NULL))
+                return log_oom();
+
+        dbus_message_unref(m->create_message);
+        m->create_message = NULL;
+
+        return 0;
+}
index 0b35a9e..e4edd40 100644 (file)
@@ -23,7 +23,8 @@
 #include <unistd.h>
 #include <errno.h>
 
-#include "logind-machine.h"
+#include <systemd/sd-messages.h>
+
 #include "util.h"
 #include "mkdir.h"
 #include "cgroup-util.h"
@@ -31,7 +32,9 @@
 #include "strv.h"
 #include "fileio.h"
 #include "special.h"
-#include <systemd/sd-messages.h>
+#include "unit-name.h"
+#include "dbus-common.h"
+#include "logind-machine.h"
 
 Machine* machine_new(Manager *manager, const char *name) {
         Machine *m;
@@ -73,17 +76,21 @@ void machine_free(Machine *m) {
         if (m->in_gc_queue)
                 LIST_REMOVE(Machine, gc_queue, m->manager->machine_gc_queue, m);
 
-        if (m->cgroup_path) {
-                hashmap_remove(m->manager->machine_cgroups, m->cgroup_path);
-                free(m->cgroup_path);
+        if (m->scope) {
+                hashmap_remove(m->manager->machine_units, m->scope);
+                free(m->scope);
         }
 
+        free(m->scope_job);
+
         hashmap_remove(m->manager->machines, m->name);
 
+        if (m->create_message)
+                dbus_message_unref(m->create_message);
+
         free(m->name);
         free(m->state_file);
         free(m->service);
-        free(m->slice);
         free(m->root_directory);
         free(m);
 }
@@ -114,15 +121,15 @@ int machine_save(Machine *m) {
                 "NAME=%s\n",
                 m->name);
 
-        if (m->cgroup_path)
-                fprintf(f, "CGROUP=%s\n", m->cgroup_path);
+        if (m->scope)
+                fprintf(f, "SCOPE=%s\n", m->scope);
+
+        if (m->scope_job)
+                fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
 
         if (m->service)
                 fprintf(f, "SERVICE=%s\n", m->service);
 
-        if (m->slice)
-                fprintf(f, "SLICE=%s\n", m->slice);
-
         if (m->root_directory)
                 fprintf(f, "ROOT=%s\n", m->root_directory);
 
@@ -164,9 +171,9 @@ int machine_load(Machine *m) {
         assert(m);
 
         r = parse_env_file(m->state_file, NEWLINE,
-                           "CGROUP",    &m->cgroup_path,
+                           "SCOPE",     &m->scope,
+                           "SCOPE_JOB", &m->scope_job,
                            "SERVICE",   &m->service,
-                           "SLICE",     &m->slice,
                            "ROOT",      &m->root_directory,
                            "ID",        &id,
                            "LEADER",    &leader,
@@ -211,86 +218,44 @@ int machine_load(Machine *m) {
         return r;
 }
 
-static int machine_create_one_group(Machine *m, const char *controller, const char *path) {
-        int r;
-
-        assert(m);
-        assert(path);
-
-        if (m->leader > 0)
-                r = cg_create_and_attach(controller, path, m->leader);
-        else
-                r = -EINVAL;
-
-        if (r < 0) {
-                r = cg_create(controller, path);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int machine_create_cgroup(Machine *m) {
-        char **k;
+static int machine_start_scope(Machine *m) {
+        _cleanup_free_ char *description = NULL;
+        DBusError error;
+        char *job;
         int r;
 
         assert(m);
 
-        if (!m->slice) {
-                m->slice = strdup(SPECIAL_MACHINE_SLICE);
-                if (!m->slice)
-                        return log_oom();
-        }
-
-        if (!m->cgroup_path) {
-                _cleanup_free_ char *escaped = NULL, *slice = NULL;
-                char *name;
+        dbus_error_init(&error);
 
-                name = strappenda(m->name, ".machine");
+        if (!m->scope) {
+                _cleanup_free_ char *escaped = NULL;
 
-                escaped = cg_escape(name);
+                escaped = unit_name_escape(m->name);
                 if (!escaped)
                         return log_oom();
 
-                r = cg_slice_to_path(m->slice, &slice);
-                if (r < 0)
-                        return r;
-
-                m->cgroup_path = strjoin(m->manager->cgroup_root, "/", slice, "/", escaped, NULL);
-                if (!m->cgroup_path)
+                m->scope = strjoin("machine.", m->name, ".scope", NULL);
+                if (!m->scope)
                         return log_oom();
-        }
 
-        r = machine_create_one_group(m, SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path);
-        if (r < 0) {
-                log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", m->cgroup_path, strerror(-r));
-                return r;
-        }
-
-        STRV_FOREACH(k, m->manager->controllers) {
-
-                if (strv_contains(m->manager->reset_controllers, *k))
-                        continue;
-
-                r = machine_create_one_group(m, *k, m->cgroup_path);
+                r = hashmap_put(m->manager->machine_units, m->scope, m);
                 if (r < 0)
-                        log_warning("Failed to create cgroup %s:%s: %s", *k, m->cgroup_path, strerror(-r));
+                        log_warning("Failed to create mapping between unit and machine");
         }
 
-        if (m->leader > 0) {
-                STRV_FOREACH(k, m->manager->reset_controllers) {
-                        r = cg_attach(*k, "/", m->leader);
-                        if (r < 0)
-                                log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
-                }
+        description = strappend(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
+
+        r = manager_start_scope(m->manager, m->scope, m->leader, SPECIAL_MACHINE_SLICE, description, &error, &job);
+        if (r < 0) {
+                log_error("Failed to start machine scope: %s", bus_error(&error, r));
+                dbus_error_free(&error);
         }
 
-        r = hashmap_put(m->manager->machine_cgroups, m->cgroup_path, m);
-        if (r < 0)
-                log_warning("Failed to create mapping between cgroup and machine");
+        free(m->scope_job);
+        m->scope_job = job;
 
-        return 0;
+        return r;
 }
 
 int machine_start(Machine *m) {
@@ -301,6 +266,11 @@ int machine_start(Machine *m) {
         if (m->started)
                 return 0;
 
+        /* Create cgroup */
+        r = machine_start_scope(m);
+        if (r < 0)
+                return r;
+
         log_struct(LOG_INFO,
                    MESSAGE_ID(SD_MESSAGE_MACHINE_START),
                    "NAME=%s", m->name,
@@ -308,11 +278,6 @@ int machine_start(Machine *m) {
                    "MESSAGE=New machine %s.", m->name,
                    NULL);
 
-        /* Create cgroup */
-        r = machine_create_cgroup(m);
-        if (r < 0)
-                return r;
-
         if (!dual_timestamp_is_set(&m->timestamp))
                 dual_timestamp_get(&m->timestamp);
 
@@ -326,28 +291,27 @@ int machine_start(Machine *m) {
         return 0;
 }
 
-static int machine_terminate_cgroup(Machine *m) {
+static int machine_stop_scope(Machine *m) {
+        DBusError error;
+        char *job;
         int r;
-        char **k;
 
         assert(m);
 
-        if (!m->cgroup_path)
-                return 0;
-
-        cg_trim(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, false);
+        dbus_error_init(&error);
 
-        r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, true);
-        if (r < 0)
-                log_error("Failed to kill machine cgroup: %s", strerror(-r));
-
-        STRV_FOREACH(k, m->manager->controllers)
-                cg_trim(*k, m->cgroup_path, true);
+        if (!m->scope)
+                return 0;
 
-        hashmap_remove(m->manager->machine_cgroups, m->cgroup_path);
+        r = manager_stop_unit(m->manager, m->scope, &error, &job);
+        if (r < 0) {
+                log_error("Failed to stop machine scope: %s", bus_error(&error, r));
+                dbus_error_free(&error);
+                return r;
+        }
 
-        free(m->cgroup_path);
-        m->cgroup_path = NULL;
+        free(m->scope_job);
+        m->scope_job = job;
 
         return r;
 }
@@ -365,7 +329,7 @@ int machine_stop(Machine *m) {
                            NULL);
 
         /* Kill cgroup */
-        k = machine_terminate_cgroup(m);
+        k = machine_stop_scope(m);
         if (k < 0)
                 r = k;
 
@@ -381,21 +345,16 @@ int machine_stop(Machine *m) {
 }
 
 int machine_check_gc(Machine *m, bool drop_not_started) {
-        int r;
-
         assert(m);
 
         if (drop_not_started && !m->started)
                 return 0;
 
-        if (m->cgroup_path) {
-                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, false);
-                if (r < 0)
-                        return r;
+        if (m->scope_job)
+                return 1;
 
-                if (r <= 0)
-                        return 1;
-        }
+        if (m->scope)
+                return manager_unit_is_active(m->manager, m->scope) != 0;
 
         return 0;
 }
@@ -410,41 +369,22 @@ void machine_add_to_gc_queue(Machine *m) {
         m->in_gc_queue = true;
 }
 
-int machine_kill(Machine *m, KillWho who, int signo) {
-        _cleanup_set_free_ Set *pid_set = NULL;
-        int r = 0;
-
-        assert(m);
-
-        if (!m->cgroup_path)
-                return -ESRCH;
-
-        if (m->leader <= 0 && who == KILL_LEADER)
-                return -ESRCH;
+MachineState machine_get_state(Machine *s) {
+        assert(s);
 
-        if (m->leader > 0)
-                if (kill(m->leader, signo) < 0)
-                        r = -errno;
+        if (s->scope_job)
+                return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
 
-        if (who == KILL_ALL) {
-                int q;
-
-                pid_set = set_new(trivial_hash_func, trivial_compare_func);
-                if (!pid_set)
-                        return log_oom();
+        return MACHINE_RUNNING;
+}
 
-                if (m->leader > 0) {
-                        q = set_put(pid_set, LONG_TO_PTR(m->leader));
-                        if (q < 0)
-                                r = q;
-                }
+int machine_kill(Machine *m, KillWho who, int signo) {
+        assert(m);
 
-                q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, signo, false, true, false, pid_set);
-                if (q < 0 && (q != -EAGAIN && q != -ESRCH && q != -ENOENT))
-                        r = q;
-        }
+        if (!m->scope)
+                return -ESRCH;
 
-        return r;
+        return manager_kill_unit(m->manager, m->scope, who, signo, NULL);
 }
 
 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
@@ -453,3 +393,11 @@ static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
 };
 
 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
+
+static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
+        [MACHINE_OPENING] = "opening",
+        [MACHINE_RUNNING] = "running",
+        [MACHINE_CLOSING] = "closing"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
index cd5174f..a09f071 100644 (file)
@@ -28,6 +28,14 @@ typedef struct Machine Machine;
 #include "logind.h"
 #include "logind-session.h"
 
+typedef enum MachineState {
+        MACHINE_OPENING,    /* Machine is being registered */
+        MACHINE_RUNNING,    /* Machine is running */
+        MACHINE_CLOSING,    /* Machine is terminating */
+        _MACHINE_STATE_MAX,
+        _MACHINE_STATE_INVALID = -1
+} MachineState;
+
 typedef enum MachineClass {
         MACHINE_CONTAINER,
         MACHINE_VM,
@@ -41,14 +49,16 @@ struct Machine {
         char *name;
         sd_id128_t id;
 
+        MachineState state;
         MachineClass class;
 
         char *state_file;
         char *service;
-        char *cgroup_path;
-        char *slice;
         char *root_directory;
 
+        char *scope;
+        char *scope_job;
+
         pid_t leader;
 
         dual_timestamp timestamp;
@@ -56,6 +66,8 @@ struct Machine {
         bool in_gc_queue:1;
         bool started:1;
 
+        DBusMessage *create_message;
+
         LIST_FIELDS(Machine, gc_queue);
 };
 
@@ -71,10 +83,17 @@ int machine_kill(Machine *m, KillWho who, int signo);
 
 char *machine_bus_path(Machine *s);
 
+MachineState machine_get_state(Machine *u);
+
 extern const DBusObjectPathVTable bus_machine_vtable;
 
 int machine_send_signal(Machine *m, bool new_machine);
 int machine_send_changed(Machine *m, const char *properties);
 
+int machine_send_create_reply(Machine *m, DBusError *error);
+
 const char* machine_class_to_string(MachineClass t) _const_;
 MachineClass machine_class_from_string(const char *s) _pure_;
+
+const char* machine_state_to_string(MachineState t) _const_;
+MachineState machine_state_from_string(const char *s) _pure_;
index e306eab..7aba347 100644 (file)
@@ -47,7 +47,6 @@
         "  <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=\"DefaultControlGroup\" 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=\"RemoteHost\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"RemoteUser\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"Service\" type=\"s\" access=\"read\"/>\n"   \
-        "  <property name=\"Slice\" type=\"s\" access=\"read\"/>\n"     \
+        "  <property name=\"Scope\" 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=\"Class\" type=\"s\" access=\"read\"/>\n"     \
         "  <property name=\"Active\" type=\"b\" access=\"read\"/>\n"    \
         "  <property name=\"State\" type=\"s\" 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" \
@@ -196,24 +193,6 @@ static int bus_session_append_idle_hint_since(DBusMessageIter *i, const char *pr
         return 0;
 }
 
-static int bus_session_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
-        Session *s = data;
-        _cleanup_free_ char *t = NULL;
-        int r;
-        bool success;
-
-        assert(i);
-        assert(property);
-        assert(s);
-
-        r = cg_join_spec(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &t);
-        if (r < 0)
-                return r;
-
-        success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
-        return success ? 0 : -ENOMEM;
-}
-
 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_class, session_class, SessionClass);
 
@@ -260,7 +239,6 @@ static const BusProperty bus_login_session_properties[] = {
         { "Id",                     bus_property_append_string,         "s", offsetof(Session, id),                 true },
         { "Timestamp",              bus_property_append_usec,           "t", offsetof(Session, timestamp.realtime)  },
         { "TimestampMonotonic",     bus_property_append_usec,           "t", offsetof(Session, timestamp.monotonic) },
-        { "DefaultControlGroup",    bus_session_append_default_cgroup,  "s", 0,                                     },
         { "VTNr",                   bus_property_append_uint32,         "u", offsetof(Session, vtnr)                },
         { "Seat",                   bus_session_append_seat,         "(so)", 0 },
         { "TTY",                    bus_property_append_string,         "s", offsetof(Session, tty),                true },
@@ -269,16 +247,13 @@ static const BusProperty bus_login_session_properties[] = {
         { "RemoteUser",             bus_property_append_string,         "s", offsetof(Session, remote_user),        true },
         { "RemoteHost",             bus_property_append_string,         "s", offsetof(Session, remote_host),        true },
         { "Service",                bus_property_append_string,         "s", offsetof(Session, service),            true },
-        { "Slice",                  bus_property_append_string,         "s", offsetof(Session, slice),              true },
+        { "Scope",                  bus_property_append_string,         "s", offsetof(Session, scope),              true },
         { "Leader",                 bus_property_append_pid,            "u", offsetof(Session, leader)              },
         { "Audit",                  bus_property_append_uint32,         "u", offsetof(Session, audit_id)            },
         { "Type",                   bus_session_append_type,            "s", offsetof(Session, type)                },
         { "Class",                  bus_session_append_class,           "s", offsetof(Session, class)               },
         { "Active",                 bus_session_append_active,          "b", 0 },
         { "State",                  bus_session_append_state,           "s", 0 },
-        { "Controllers",            bus_property_append_strv,          "as", offsetof(Session, controllers),        true },
-        { "ResetControllers",       bus_property_append_strv,          "as", offsetof(Session, reset_controllers),  true },
-        { "KillProcesses",          bus_property_append_bool,           "b", offsetof(Session, kill_processes)      },
         { "IdleHint",               bus_session_append_idle_hint,       "b", 0 },
         { "IdleSinceHint",          bus_session_append_idle_hint_since, "t", 0 },
         { "IdleSinceHintMonotonic", bus_session_append_idle_hint_since, "t", 0 },
@@ -552,3 +527,73 @@ int session_send_lock_all(Manager *m, bool lock) {
 
         return r;
 }
+
+int session_send_create_reply(Session *s, DBusError *error) {
+        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+
+        assert(s);
+
+        if (!s->create_message)
+                return 0;
+
+        if (error) {
+                DBusError buffer;
+
+                dbus_error_init(&buffer);
+
+                if (!dbus_error_is_set(error)) {
+                        dbus_set_error_const(&buffer, DBUS_ERROR_INVALID_ARGS, "Invalid Arguments");
+                        error = &buffer;
+                }
+
+                reply = dbus_message_new_error(s->create_message, error->name, error->message);
+                dbus_error_free(&buffer);
+
+                if (!reply)
+                        return log_oom();
+        } else {
+                _cleanup_close_ int fifo_fd = -1;
+                _cleanup_free_ char *path = NULL;
+                const char *cseat;
+                uint32_t vtnr;
+                dbus_bool_t exists;
+
+                fifo_fd = session_create_fifo(s);
+                if (fifo_fd < 0) {
+                        log_error("Failed to create fifo: %s", strerror(-fifo_fd));
+                        return fifo_fd;
+                }
+
+                path = session_bus_path(s);
+                if (!path)
+                        return log_oom();
+
+                reply = dbus_message_new_method_return(s->create_message);
+                if (!reply)
+                        return log_oom();
+
+                cseat = s->seat ? s->seat->id : "";
+                vtnr = s->vtnr;
+                exists = false;
+
+                if (!dbus_message_append_args(
+                                    reply,
+                                    DBUS_TYPE_STRING, &s->id,
+                                    DBUS_TYPE_OBJECT_PATH, &path,
+                                    DBUS_TYPE_STRING, &s->user->runtime_path,
+                                    DBUS_TYPE_UNIX_FD, &fifo_fd,
+                                    DBUS_TYPE_STRING, &cseat,
+                                    DBUS_TYPE_UINT32, &vtnr,
+                                    DBUS_TYPE_BOOLEAN, &exists,
+                                    DBUS_TYPE_INVALID))
+                        return log_oom();
+        }
+
+        if (!dbus_connection_send(s->manager->bus, reply, NULL))
+                return log_oom();
+
+        dbus_message_unref(s->create_message);
+        s->create_message = NULL;
+
+        return 0;
+}
index 7604253..93e4037 100644 (file)
 #include <sys/epoll.h>
 #include <fcntl.h>
 
-#include "systemd/sd-id128.h"
-#include "systemd/sd-messages.h"
+#include <systemd/sd-id128.h>
+#include <systemd/sd-messages.h>
+
 #include "strv.h"
 #include "util.h"
 #include "mkdir.h"
 #include "path-util.h"
 #include "cgroup-util.h"
-#include "logind-session.h"
 #include "fileio.h"
+#include "dbus-common.h"
+#include "logind-session.h"
 
 Session* session_new(Manager *m, const char *id) {
         Session *s;
@@ -85,18 +87,21 @@ void session_free(Session *s) {
                 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
         }
 
-        if (s->cgroup_path)
-                hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
+        if (s->scope) {
+                hashmap_remove(s->manager->session_units, s->scope);
+                free(s->scope);
+        }
+
+        free(s->scope_job);
 
-        free(s->cgroup_path);
-        strv_free(s->controllers);
+        if (s->create_message)
+                dbus_message_unref(s->create_message);
 
         free(s->tty);
         free(s->display);
         free(s->remote_host);
         free(s->remote_user);
         free(s->service);
-        free(s->slice);
 
         hashmap_remove(s->manager->sessions, s->id);
         session_remove_fifo(s);
@@ -144,14 +149,12 @@ int session_save(Session *s) {
                 "USER=%s\n"
                 "ACTIVE=%i\n"
                 "STATE=%s\n"
-                "REMOTE=%i\n"
-                "KILL_PROCESSES=%i\n",
+                "REMOTE=%i\n",
                 (unsigned long) s->user->uid,
                 s->user->name,
                 session_is_active(s),
                 session_state_to_string(session_get_state(s)),
-                s->remote,
-                s->kill_processes);
+                s->remote);
 
         if (s->type >= 0)
                 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
@@ -159,8 +162,11 @@ int session_save(Session *s) {
         if (s->class >= 0)
                 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
 
-        if (s->cgroup_path)
-                fprintf(f, "CGROUP=%s\n", s->cgroup_path);
+        if (s->scope)
+                fprintf(f, "SCOPE=%s\n", s->scope);
+
+        if (s->scope_job)
+                fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
 
         if (s->fifo_path)
                 fprintf(f, "FIFO=%s\n", s->fifo_path);
@@ -183,9 +189,6 @@ int session_save(Session *s) {
         if (s->service)
                 fprintf(f, "SERVICE=%s\n", s->service);
 
-        if (s->seat)
-                fprintf(f, "SLICE=%s\n", s->slice);
-
         if (s->seat && seat_can_multi_session(s->seat))
                 fprintf(f, "VTNR=%i\n", s->vtnr);
 
@@ -219,7 +222,6 @@ finish:
 
 int session_load(Session *s) {
         _cleanup_free_ char *remote = NULL,
-                *kill_processes = NULL,
                 *seat = NULL,
                 *vtnr = NULL,
                 *leader = NULL,
@@ -236,8 +238,8 @@ int session_load(Session *s) {
 
         r = parse_env_file(s->state_file, NEWLINE,
                            "REMOTE",         &remote,
-                           "KILL_PROCESSES", &kill_processes,
-                           "CGROUP",         &s->cgroup_path,
+                           "SCOPE",          &s->scope,
+                           "SCOPE_JOB",      &s->scope_job,
                            "FIFO",           &s->fifo_path,
                            "SEAT",           &seat,
                            "TTY",            &s->tty,
@@ -245,7 +247,6 @@ int session_load(Session *s) {
                            "REMOTE_HOST",    &s->remote_host,
                            "REMOTE_USER",    &s->remote_user,
                            "SERVICE",        &s->service,
-                           "SLICE",          &s->slice,
                            "VTNR",           &vtnr,
                            "LEADER",         &leader,
                            "TYPE",           &type,
@@ -290,12 +291,6 @@ int session_load(Session *s) {
                         s->remote = k;
         }
 
-        if (kill_processes) {
-                k = parse_boolean(kill_processes);
-                if (k >= 0)
-                        s->kill_processes = k;
-        }
-
         if (seat && !s->seat) {
                 Seat *o;
 
@@ -459,124 +454,39 @@ done:
         return 0;
 }
 
-static int session_create_one_group(Session *s, const char *controller, const char *path) {
+static int session_start_scope(Session *s) {
+        _cleanup_free_ char *description = NULL;
+        DBusError error;
+        char *job;
         int r;
 
         assert(s);
         assert(s->user);
-        assert(path);
+        assert(s->user->slice);
 
-        if (s->leader > 0)
-                r = cg_create_and_attach(controller, path, s->leader);
-        else
-                r = -EINVAL;
-
-        if (r < 0) {
-                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;
-        int r;
-
-        assert(s);
-        assert(s->user);
-        assert(s->user->cgroup_path);
-
-        if (!s->cgroup_path) {
-                _cleanup_free_ char *name = NULL, *escaped = NULL;
-
-                name = strappend(s->id, ".session");
-                if (!name)
-                        return log_oom();
+        dbus_error_init(&error);
 
-                escaped = cg_escape(name);
-                if (!escaped)
+        if (!s->scope) {
+                s->scope = strjoin("session.", s->id, ".scope", NULL);
+                if (!s->scope)
                         return log_oom();
 
-                if (s->slice) {
-                        _cleanup_free_ char *slice = NULL;
-
-                        r = cg_slice_to_path(s->slice, &slice);
-                        if (r < 0)
-                                return r;
-
-                        s->cgroup_path = strjoin(s->manager->cgroup_root, "/", slice, "/", escaped, NULL);
-                } else
-                        s->cgroup_path = strjoin(s->user->cgroup_path, "/", escaped, NULL);
-
-                if (!s->cgroup_path)
-                        return log_oom();
-        }
-
-        if (!s->slice) {
-                s->slice = strdup(s->user->slice);
-                if (!s->slice)
-                        return log_oom();
-        }
-
-        r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
-        if (r < 0) {
-                log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", s->cgroup_path, strerror(-r));
-                return r;
-        }
-
-        STRV_FOREACH(k, s->controllers) {
-
-                if (strv_contains(s->reset_controllers, *k))
-                        continue;
-
-                r = session_create_one_group(s, *k, s->cgroup_path);
+                r = hashmap_put(s->manager->session_units, s->scope, s);
                 if (r < 0)
-                        log_warning("Failed to create %s:%s: %s", *k, s->cgroup_path, strerror(-r));
+                        log_warning("Failed to create mapping between unit and session");
         }
 
-        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, s->cgroup_path);
-                if (r < 0)
-                        log_warning("Failed to create %s:%s: %s", *k, s->cgroup_path, 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) {
+        description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
 
-                        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));
-                }
+        r = manager_start_scope(s->manager, s->scope, s->leader, s->user->slice, description, &error, &job);
+        if (r < 0) {
+                log_error("Failed to start session scope: %s %s", bus_error(&error, r), error.name);
+                dbus_error_free(&error);
+        } else {
+                free(s->scope_job);
+                s->scope_job = job;
         }
 
-        r = hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
-        if (r < 0)
-                log_warning("Failed to create mapping between cgroup and session");
-
         return 0;
 }
 
@@ -595,6 +505,11 @@ int session_start(Session *s) {
         if (r < 0)
                 return r;
 
+        /* Create cgroup */
+        r = session_start_scope(s);
+        if (r < 0)
+                return r;
+
         log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
                    MESSAGE_ID(SD_MESSAGE_SESSION_START),
                    "SESSION_ID=%s", s->id,
@@ -603,11 +518,6 @@ int session_start(Session *s) {
                    "MESSAGE=New session %s of user %s.", s->id, s->user->name,
                    NULL);
 
-        /* Create cgroup */
-        r = session_create_cgroup(s);
-        if (r < 0)
-                return r;
-
         /* Create X11 symlink */
         session_link_x11_socket(s);
 
@@ -639,73 +549,42 @@ int session_start(Session *s) {
         return 0;
 }
 
-static bool session_shall_kill(Session *s) {
-        assert(s);
+/* static bool session_shall_kill(Session *s) { */
+/*         assert(s); */
 
-        if (!s->kill_processes)
-                return false;
+/*         if (!s->kill_processes) */
+/*                 return false; */
 
-        if (strv_contains(s->manager->kill_exclude_users, s->user->name))
-                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;
+/*         if (strv_isempty(s->manager->kill_only_users)) */
+/*                 return true; */
 
-        return strv_contains(s->manager->kill_only_users, s->user->name);
-}
+/*         return strv_contains(s->manager->kill_only_users, s->user->name); */
+/* } */
 
-static int session_terminate_cgroup(Session *s) {
+static int session_stop_scope(Session *s) {
+        DBusError error;
+        char *job;
         int r;
-        char **k;
 
         assert(s);
 
-        if (!s->cgroup_path)
-                return 0;
+        dbus_error_init(&error);
 
-        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 {
-                if (s->leader > 0) {
-                        Session *t;
-
-                        /* We still send a HUP to the leader process,
-                         * even if we are not supposed to kill the
-                         * whole cgroup. But let's first check the
-                         * leader still exists and belongs to our
-                         * session... */
-
-                        r = manager_get_session_by_pid(s->manager, s->leader, &t);
-                        if (r > 0 && t == s) {
-                                kill(s->leader, SIGTERM); /* for normal processes */
-                                kill(s->leader, SIGHUP);  /* for shells */
-                                kill(s->leader, SIGCONT); /* in case they are stopped */
-                        }
-                }
+        if (!s->scope)
+                return 0;
 
-                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));
-                }
+        r = manager_stop_unit(s->manager, s->scope, &error, &job);
+        if (r < 0) {
+                log_error("Failed to stop session scope: %s", bus_error(&error, r));
+                dbus_error_free(&error);
+                return r;
         }
 
-        STRV_FOREACH(k, s->user->manager->controllers)
-                cg_trim(*k, s->cgroup_path, true);
-
-        hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
-
-        free(s->cgroup_path);
-        s->cgroup_path = NULL;
+        free(s->scope_job);
+        s->scope_job = job;
 
         return 0;
 }
@@ -750,7 +629,7 @@ int session_stop(Session *s) {
                            NULL);
 
         /* Kill cgroup */
-        k = session_terminate_cgroup(s);
+        k = session_stop_scope(s);
         if (k < 0)
                 r = k;
 
@@ -861,28 +740,6 @@ int session_get_idle_hint(Session *s, dual_timestamp *t) {
                         goto found_atime;
         }
 
-        /* For other TTY sessions, let's find the most recent atime of
-         * the ttys of any of the processes of the session */
-        if (s->cgroup_path) {
-                _cleanup_fclose_ FILE *f = NULL;
-
-                if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &f) >= 0) {
-                        pid_t pid;
-
-                        atime = 0;
-                        while (cg_read_pid(f, &pid) > 0) {
-                                usec_t a;
-
-                                if (get_process_ctty_atime(pid, &a) >= 0)
-                                        if (atime == 0 || atime < a)
-                                                atime = a;
-                        }
-
-                        if (atime != 0)
-                                goto found_atime;
-                }
-        }
-
 dont_know:
         if (t)
                 *t = s->idle_hint_timestamp;
@@ -1018,15 +875,11 @@ int session_check_gc(Session *s, bool drop_not_started) {
                         return 1;
         }
 
-        if (s->cgroup_path) {
+        if (s->scope_job)
+                return 1;
 
-                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
-                if (r < 0)
-                        return r;
-
-                if (r <= 0)
-                        return 1;
-        }
+        if (s->scope)
+                return manager_unit_is_active(s->manager, s->scope) != 0;
 
         return 0;
 }
@@ -1044,6 +897,9 @@ void session_add_to_gc_queue(Session *s) {
 SessionState session_get_state(Session *s) {
         assert(s);
 
+        if (s->scope_job)
+                return s->started ? SESSION_OPENING : SESSION_CLOSING;
+
         if (s->fifo_fd < 0)
                 return SESSION_CLOSING;
 
@@ -1054,44 +910,16 @@ SessionState session_get_state(Session *s) {
 }
 
 int session_kill(Session *s, KillWho who, int signo) {
-        _cleanup_set_free_ Set *pid_set = NULL;
-        int r = 0;
-
         assert(s);
 
-        if (!s->cgroup_path)
-                return -ESRCH;
-
-        if (s->leader <= 0 && who == KILL_LEADER)
+        if (!s->scope)
                 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 log_oom();
-
-                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;
-        }
-
-        return r;
+        return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
 }
 
-static const char* const session_state_table[_SESSION_TYPE_MAX] = {
+static const char* const session_state_table[_SESSION_STATE_MAX] = {
+        [SESSION_OPENING] = "opening",
         [SESSION_ONLINE] = "online",
         [SESSION_ACTIVE] = "active",
         [SESSION_CLOSING] = "closing"
index 60597c2..e2a46d5 100644 (file)
@@ -31,9 +31,10 @@ typedef enum KillWho KillWho;
 #include "logind-user.h"
 
 typedef enum SessionState {
+        SESSION_OPENING,  /* Session scope is being created */
         SESSION_ONLINE,   /* Logged in */
         SESSION_ACTIVE,   /* Logged in and in the fg */
-        SESSION_CLOSING,  /* Logged out, but processes still remain */
+        SESSION_CLOSING,  /* Logged out, but scope is still there */
         _SESSION_STATE_MAX,
         _SESSION_STATE_INVALID = -1
 } SessionState;
@@ -81,9 +82,10 @@ struct Session {
         bool remote;
         char *remote_user;
         char *remote_host;
-
         char *service;
-        char *slice;
+
+        char *scope;
+        char *scope_job;
 
         int vtnr;
         Seat *seat;
@@ -94,16 +96,14 @@ struct Session {
         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;
 
+        DBusMessage *create_message;
+
         LIST_FIELDS(Session, sessions_by_user);
         LIST_FIELDS(Session, sessions_by_seat);
 
@@ -138,6 +138,8 @@ int session_send_changed(Session *s, const char *properties);
 int session_send_lock(Session *s, bool lock);
 int session_send_lock_all(Manager *m, bool lock);
 
+int session_send_create_reply(Session *s, DBusError *error);
+
 const char* session_state_to_string(SessionState t) _const_;
 SessionState session_state_from_string(const char *s) _pure_;
 
index 2a28253..fa2ecba 100644 (file)
@@ -38,7 +38,6 @@
         "  <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=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"Service\" type=\"s\" access=\"read\"/>\n"   \
         "  <property name=\"Slice\" type=\"s\" access=\"read\"/>\n"     \
         "  <property name=\"Display\" type=\"(so)\" access=\"read\"/>\n" \
@@ -186,24 +185,6 @@ static int bus_user_append_idle_hint_since(DBusMessageIter *i, const char *prope
         return 0;
 }
 
-static int bus_user_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
-        User *u = data;
-        _cleanup_free_ char *t = NULL;
-        int r;
-        bool success;
-
-        assert(i);
-        assert(property);
-        assert(u);
-
-        r = cg_join_spec(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &t);
-        if (r < 0)
-                return r;
-
-        success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
-        return success ? 0 : -ENOMEM;
-}
-
 static int get_user_for_path(Manager *m, const char *path, User **_u) {
         User *u;
         unsigned long lu;
@@ -235,7 +216,6 @@ static const BusProperty bus_login_user_properties[] = {
         { "Timestamp",              bus_property_append_usec,        "t", offsetof(User, timestamp.realtime)  },
         { "TimestampMonotonic",     bus_property_append_usec,        "t", offsetof(User, timestamp.monotonic) },
         { "RuntimePath",            bus_property_append_string,      "s", offsetof(User, runtime_path),       true },
-        { "DefaultControlGroup",    bus_user_append_default_cgroup,  "s", 0 },
         { "Service",                bus_property_append_string,      "s", offsetof(User, service),            true },
         { "Slice",                  bus_property_append_string,      "s", offsetof(User, slice),              true },
         { "Display",                bus_user_append_display,      "(so)", 0 },
index 9f7b924..316c4cd 100644 (file)
@@ -23,7 +23,6 @@
 #include <unistd.h>
 #include <errno.h>
 
-#include "logind-user.h"
 #include "util.h"
 #include "mkdir.h"
 #include "cgroup-util.h"
@@ -31,6 +30,9 @@
 #include "strv.h"
 #include "fileio.h"
 #include "special.h"
+#include "unit-name.h"
+#include "dbus-common.h"
+#include "logind-user.h"
 
 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
         User *u;
@@ -75,19 +77,25 @@ void user_free(User *u) {
         while (u->sessions)
                 session_free(u->sessions);
 
-        if (u->cgroup_path) {
-                hashmap_remove(u->manager->user_cgroups, u->cgroup_path);
-                free(u->cgroup_path);
+        if (u->slice) {
+                hashmap_remove(u->manager->user_units, u->slice);
+                free(u->slice);
         }
 
-        free(u->service);
+        if (u->service) {
+                hashmap_remove(u->manager->user_units, u->service);
+                free(u->service);
+        }
+
+        free(u->slice_job);
+        free(u->service_job);
+
         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->slice);
         free(u);
 }
 
@@ -119,17 +127,18 @@ int user_save(User *u) {
                 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->service_job)
+                fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
 
         if (u->slice)
                 fprintf(f, "SLICE=%s\n", u->slice);
+        if (u->slice_job)
+                fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
 
         if (u->display)
                 fprintf(f, "DISPLAY=%s\n", u->display->id);
@@ -251,13 +260,14 @@ int user_load(User *u) {
         assert(u);
 
         r = parse_env_file(u->state_file, NEWLINE,
-                           "CGROUP",    &u->cgroup_path,
-                           "RUNTIME",   &u->runtime_path,
-                           "SERVICE",   &u->service,
-                           "DISPLAY",   &display,
-                           "SLICE",     &u->slice,
-                           "REALTIME",  &realtime,
-                           "MONOTONIC", &monotonic,
+                           "RUNTIME",     &u->runtime_path,
+                           "SERVICE",     &u->service,
+                           "SERVICE_JOB", &u->service_job,
+                           "SLICE",       &u->slice,
+                           "SLICE_JOB",   &u->slice_job,
+                           "DISPLAY",     &display,
+                           "REALTIME",    &realtime,
+                           "MONOTONIC",   &monotonic,
                            NULL);
         if (r < 0) {
                 if (r == -ENOENT)
@@ -318,64 +328,70 @@ static int user_mkdir_runtime_path(User *u) {
         return 0;
 }
 
-static int user_create_cgroup(User *u) {
-        char **k;
+static int user_start_slice(User *u) {
+        DBusError error;
+        char *job;
         int r;
 
         assert(u);
 
-        if (!u->slice) {
-                u->slice = strdup(SPECIAL_USER_SLICE);
-                if (!u->slice)
-                        return log_oom();
-        }
-
-        if (!u->cgroup_path) {
-                _cleanup_free_ char *name = NULL, *escaped = NULL, *slice = NULL;
+        dbus_error_init(&error);
 
-                if (asprintf(&name, "%lu.user", (unsigned long) u->uid) < 0)
-                        return log_oom();
-
-                escaped = cg_escape(name);
-                if (!escaped)
-                        return log_oom();
+        if (!u->slice) {
+                char lu[DECIMAL_STR_MAX(unsigned long) + 1];
+                sprintf(lu, "%lu", (unsigned long) u->uid);
 
-                r = cg_slice_to_path(u->slice, &slice);
+                r = build_subslice(SPECIAL_USER_SLICE, lu, &u->slice);
                 if (r < 0)
                         return r;
 
-                u->cgroup_path = strjoin(u->manager->cgroup_root, "/", slice, "/", escaped, NULL);
-                if (!u->cgroup_path)
-                        return log_oom();
+                r = hashmap_put(u->manager->user_units, u->slice, u);
+                if (r < 0)
+                        log_warning("Failed to create mapping between unit and user");
         }
 
-        r = cg_create(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
+        r = manager_start_unit(u->manager, u->slice, &error, &job);
         if (r < 0) {
-                log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", u->cgroup_path, strerror(-r));
-                return r;
+                log_error("Failed to start user slice: %s", bus_error(&error, r));
+                dbus_error_free(&error);
         }
 
-        STRV_FOREACH(k, u->manager->controllers) {
-
-                if (strv_contains(u->manager->reset_controllers, *k))
-                        continue;
-
-                r = cg_create(*k, u->cgroup_path);
-                if (r < 0)
-                        log_warning("Failed to create cgroup %s:%s: %s", *k, u->cgroup_path, strerror(-r));
-        }
-
-        r = hashmap_put(u->manager->user_cgroups, u->cgroup_path, u);
-        if (r < 0)
-                log_warning("Failed to create mapping between cgroup and user");
+        free(u->slice_job);
+        u->slice_job = job;
 
         return 0;
 }
 
 static int user_start_service(User *u) {
+        DBusError error;
+        char *job;
+        int r;
+
         assert(u);
 
-        /* FIXME: Fill me in later ... */
+        dbus_error_init(&error);
+
+        if (!u->service) {
+                char lu[DECIMAL_STR_MAX(unsigned long) + 1];
+                sprintf(lu, "%lu", (unsigned long) u->uid);
+
+                u->service = unit_name_build("user", lu, ".service");
+                if (!u->service)
+                        return log_oom();
+
+                r = hashmap_put(u->manager->user_units, u->service, u);
+                if (r < 0)
+                        log_warning("Failed to create mapping between service and user");
+        }
+
+        r = manager_start_unit(u->manager, u->service, &error, &job);
+        if (r < 0) {
+                log_error("Failed to start user service: %s", bus_error(&error, r));
+                dbus_error_free(&error);
+        }
+
+        free(u->service_job);
+        u->service_job = job;
 
         return 0;
 }
@@ -396,7 +412,7 @@ int user_start(User *u) {
                 return r;
 
         /* Create cgroup */
-        r = user_create_cgroup(u);
+        r = user_start_slice(u);
         if (r < 0)
                 return r;
 
@@ -418,69 +434,70 @@ int user_start(User *u) {
         return 0;
 }
 
-static int user_stop_service(User *u) {
-        assert(u);
-
-        if (!u->service)
-                return 0;
-
-        return 0;
-}
+static int user_stop_slice(User *u) {
+        DBusError error;
+        char *job;
+        int r;
 
-static int user_shall_kill(User *u) {
         assert(u);
 
-        if (!u->manager->kill_user_processes)
-                return false;
+        dbus_error_init(&error);
 
-        if (strv_contains(u->manager->kill_exclude_users, u->name))
-                return false;
+        if (!u->slice)
+                return 0;
+
+        r = manager_stop_unit(u->manager, u->slice, &error, &job);
+        if (r < 0) {
+                log_error("Failed to stop user slice: %s", bus_error(&error, r));
+                dbus_error_free(&error);
+                return r;
+        }
 
-        if (strv_isempty(u->manager->kill_only_users))
-                return true;
+        free(u->slice_job);
+        u->slice_job = job;
 
-        return strv_contains(u->manager->kill_only_users, u->name);
+        return r;
 }
 
-static int user_terminate_cgroup(User *u) {
+static int user_stop_service(User *u) {
+        DBusError error;
+        char *job;
         int r;
-        char **k;
 
         assert(u);
 
-        if (!u->cgroup_path)
+        dbus_error_init(&error);
+
+        if (!u->service)
                 return 0;
 
-        cg_trim(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false);
+        r = manager_stop_unit(u->manager, u->service, &error, &job);
+        if (r < 0) {
+                log_error("Failed to stop user service: %s", bus_error(&error, r));
+                dbus_error_free(&error);
+                return r;
+        }
 
-        if (user_shall_kill(u)) {
+        free(u->service_job);
+        u->service_job = job;
 
-                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 {
+        return r;
+}
 
-                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;
-        }
+/* static int user_shall_kill(User *u) { */
+/*         assert(u); */
 
-        STRV_FOREACH(k, u->manager->controllers)
-                cg_trim(*k, u->cgroup_path, true);
+/*         if (!u->manager->kill_user_processes) */
+/*                 return false; */
 
-        hashmap_remove(u->manager->user_cgroups, u->cgroup_path);
+/*         if (strv_contains(u->manager->kill_exclude_users, u->name)) */
+/*                 return false; */
 
-        free(u->cgroup_path);
-        u->cgroup_path = NULL;
+/*         if (strv_isempty(u->manager->kill_only_users)) */
+/*                 return true; */
 
-        return r;
-}
+/*         return strv_contains(u->manager->kill_only_users, u->name); */
+/* } */
 
 static int user_remove_runtime_path(User *u) {
         int r;
@@ -520,7 +537,7 @@ int user_stop(User *u) {
                 r = k;
 
         /* Kill cgroup */
-        k = user_terminate_cgroup(u);
+        k = user_stop_slice(u);
         if (k < 0)
                 r = k;
 
@@ -590,8 +607,6 @@ static int user_check_linger_file(User *u) {
 }
 
 int user_check_gc(User *u, bool drop_not_started) {
-        int r;
-
         assert(u);
 
         if (drop_not_started && !u->started)
@@ -603,15 +618,6 @@ int user_check_gc(User *u, bool drop_not_started) {
         if (user_check_linger_file(u) > 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;
 }
 
@@ -631,6 +637,8 @@ UserState user_get_state(User *u) {
 
         assert(u);
 
+        if (u->slice_job || u->service_job)
+                return u->started ? USER_OPENING : USER_CLOSING;
 
         LIST_FOREACH(sessions_by_user, i, u->sessions) {
                 if (session_is_active(i))
@@ -649,27 +657,17 @@ UserState user_get_state(User *u) {
 }
 
 int user_kill(User *u, int signo) {
-        _cleanup_set_free_ Set *pid_set = NULL;
-        int r;
-
         assert(u);
 
-        if (!u->cgroup_path)
+        if (!u->slice)
                 return -ESRCH;
 
-        pid_set = set_new(trivial_hash_func, trivial_compare_func);
-        if (!pid_set)
-                return -ENOMEM;
-
-        r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
-        if (r < 0 && (r != -EAGAIN && r != -ESRCH && r != -ENOENT))
-                return r;
-
-        return 0;
+        return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
 }
 
 static const char* const user_state_table[_USER_STATE_MAX] = {
         [USER_OFFLINE] = "offline",
+        [USER_OPENING] = "opening",
         [USER_LINGERING] = "lingering",
         [USER_ONLINE] = "online",
         [USER_ACTIVE] = "active",
index 16d7985..889f828 100644 (file)
@@ -30,6 +30,7 @@ typedef struct User User;
 
 typedef enum UserState {
         USER_OFFLINE,    /* Not logged in at all */
+        USER_OPENING,    /* Is logging in */
         USER_LINGERING,  /* Lingering has been enabled by the admin for this user */
         USER_ONLINE,     /* User logged in */
         USER_ACTIVE,     /* User logged in and has a session in the fg */
@@ -47,16 +48,21 @@ struct User {
 
         char *state_file;
         char *runtime_path;
+
         char *service;
-        char *cgroup_path;
         char *slice;
 
+        char *service_job;
+        char *slice_job;
+
         Session *display;
 
         dual_timestamp timestamp;
 
         bool in_gc_queue:1;
         bool started:1;
+        bool slice_created:1;
+        bool service_created:1;
 
         LIST_HEAD(Session, sessions);
         LIST_FIELDS(User, gc_queue);
index ea74254..7040ac9 100644 (file)
@@ -76,24 +76,23 @@ Manager *manager_new(void) {
         m->buttons = hashmap_new(string_hash_func, string_compare_func);
         m->machines = hashmap_new(string_hash_func, string_compare_func);
 
-        m->user_cgroups = hashmap_new(string_hash_func, string_compare_func);
-        m->session_cgroups = hashmap_new(string_hash_func, string_compare_func);
-        m->machine_cgroups = hashmap_new(string_hash_func, string_compare_func);
+        m->user_units = hashmap_new(string_hash_func, string_compare_func);
+        m->session_units = hashmap_new(string_hash_func, string_compare_func);
+        m->machine_units = hashmap_new(string_hash_func, string_compare_func);
 
         m->session_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
         m->inhibitor_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
         m->button_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
 
         if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->machines ||
-            !m->user_cgroups || !m->session_cgroups || !m->machine_cgroups ||
+            !m->user_units || !m->session_units || !m->machine_units ||
             !m->session_fds || !m->inhibitor_fds || !m->button_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) {
+        if (!m->kill_exclude_users) {
                 manager_free(m);
                 return NULL;
         }
@@ -104,14 +103,6 @@ Manager *manager_new(void) {
                 return NULL;
         }
 
-        if (cg_get_root_path(&m->cgroup_root) < 0) {
-                manager_free(m);
-                return NULL;
-        }
-
-        if (streq(m->cgroup_root, "/"))
-                m->cgroup_root[0] = 0;
-
         return m;
 }
 
@@ -155,9 +146,9 @@ void manager_free(Manager *m) {
         hashmap_free(m->buttons);
         hashmap_free(m->machines);
 
-        hashmap_free(m->user_cgroups);
-        hashmap_free(m->session_cgroups);
-        hashmap_free(m->machine_cgroups);
+        hashmap_free(m->user_units);
+        hashmap_free(m->session_units);
+        hashmap_free(m->machine_units);
 
         hashmap_free(m->session_fds);
         hashmap_free(m->inhibitor_fds);
@@ -194,14 +185,10 @@ void manager_free(Manager *m) {
         if (m->idle_action_fd >= 0)
                 close_nointr_nofail(m->idle_action_fd);
 
-        strv_free(m->controllers);
-        strv_free(m->reset_controllers);
         strv_free(m->kill_only_users);
         strv_free(m->kill_exclude_users);
 
         free(m->action_job);
-
-        free(m->cgroup_root);
         free(m);
 }
 
@@ -989,177 +976,67 @@ static int manager_reserve_vt(Manager *m) {
         return 0;
 }
 
-int manager_get_session_by_cgroup(Manager *m, const char *cgroup, Session **session) {
-        Session *s;
-        char *p;
-
-        assert(m);
-        assert(cgroup);
-        assert(session);
-
-        s = hashmap_get(m->session_cgroups, cgroup);
-        if (s) {
-                *session = s;
-                return 1;
-        }
-
-        p = strdupa(cgroup);
-
-        for (;;) {
-                char *e;
-
-                e = strrchr(p, '/');
-                if (!e || e == p) {
-                        *session = NULL;
-                        return 0;
-                }
-
-                *e = 0;
-
-                s = hashmap_get(m->session_cgroups, p);
-                if (s) {
-                        *session = s;
-                        return 1;
-                }
-        }
-}
-
-int manager_get_user_by_cgroup(Manager *m, const char *cgroup, User **user) {
-        User *u;
-        char *p;
-
-        assert(m);
-        assert(cgroup);
-        assert(user);
-
-        u = hashmap_get(m->user_cgroups, cgroup);
-        if (u) {
-                *user = u;
-                return 1;
-        }
-
-        p = strdupa(cgroup);
-        if (!p)
-                return log_oom();
-
-        for (;;) {
-                char *e;
-
-                e = strrchr(p, '/');
-                if (!e || e == p) {
-                        *user = NULL;
-                        return 0;
-                }
-
-                *e = 0;
-
-                u = hashmap_get(m->user_cgroups, p);
-                if (u) {
-                        *user = u;
-                        return 1;
-                }
-        }
-}
-
-int manager_get_machine_by_cgroup(Manager *m, const char *cgroup, Machine **machine) {
-        Machine *u;
-        char *p;
-
-        assert(m);
-        assert(cgroup);
-        assert(machine);
-
-        u = hashmap_get(m->machine_cgroups, cgroup);
-        if (u) {
-                *machine = u;
-                return 1;
-        }
-
-        p = strdupa(cgroup);
-        if (!p)
-                return log_oom();
-
-        for (;;) {
-                char *e;
-
-                e = strrchr(p, '/');
-                if (!e || e == p) {
-                        *machine = NULL;
-                        return 0;
-                }
-
-                *e = 0;
-
-                u = hashmap_get(m->machine_cgroups, p);
-                if (u) {
-                        *machine = u;
-                        return 1;
-                }
-        }
-}
-
 int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) {
-        _cleanup_free_ char *p = NULL;
+        _cleanup_free_ char *unit = NULL;
+        Session *s;
         int r;
 
         assert(m);
         assert(pid >= 1);
         assert(session);
 
-        r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &p);
+        r = cg_pid_get_unit(pid, &unit);
         if (r < 0)
                 return r;
 
-        return manager_get_session_by_cgroup(m, p, session);
+        s = hashmap_get(m->session_units, unit);
+        if (!s)
+                return 0;
+
+        *session = s;
+        return 1;
 }
 
 int manager_get_user_by_pid(Manager *m, pid_t pid, User **user) {
-        _cleanup_free_ char *p = NULL;
+        _cleanup_free_ char *unit = NULL;
+        User *u;
         int r;
 
         assert(m);
         assert(pid >= 1);
         assert(user);
 
-        r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &p);
+        r = cg_pid_get_slice(pid, &unit);
         if (r < 0)
                 return r;
 
-        return manager_get_user_by_cgroup(m, p, user);
+        u = hashmap_get(m->user_units, unit);
+        if (!u)
+                return 0;
+
+        *user = u;
+        return 1;
 }
 
 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
-        _cleanup_free_ char *p = NULL;
+        _cleanup_free_ char *unit = NULL;
+        Machine *mm;
         int r;
 
         assert(m);
         assert(pid >= 1);
         assert(machine);
 
-        r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &p);
+        r = cg_pid_get_unit(pid, &unit);
         if (r < 0)
                 return r;
 
-        return manager_get_machine_by_cgroup(m, p, machine);
-}
-
-void manager_cgroup_notify_empty(Manager *m, const char *cgroup) {
-        Machine *machine;
-        Session *s;
-        User *u;
-        int r;
-
-        r = manager_get_session_by_cgroup(m, cgroup, &s);
-        if (r > 0)
-                session_add_to_gc_queue(s);
-
-        r = manager_get_user_by_cgroup(m, cgroup, &u);
-        if (r > 0)
-                user_add_to_gc_queue(u);
+        mm = hashmap_get(m->machine_units, unit);
+        if (!mm)
+                return 0;
 
-        r = manager_get_machine_by_cgroup(m, cgroup, &machine);
-        if (r > 0)
-                machine_add_to_gc_queue(machine);
+        *machine = mm;
+        return 1;
 }
 
 static void manager_dispatch_other(Manager *m, int fd) {
@@ -1229,15 +1106,40 @@ static int manager_connect_bus(Manager *m) {
 
         dbus_bus_add_match(m->bus,
                            "type='signal',"
-                           "interface='org.freedesktop.systemd1.Agent',"
-                           "member='Released',"
-                           "path='/org/freedesktop/systemd1/agent'",
+                           "sender='org.freedesktop.systemd1',"
+                           "interface='org.freedesktop.systemd1.Manager',"
+                           "member='JobRemoved',"
+                           "path='/org/freedesktop/systemd1'",
+                           &error);
+        if (dbus_error_is_set(&error)) {
+                log_error("Failed to add match for JobRemoved: %s", bus_error_message(&error));
+                dbus_error_free(&error);
+        }
+
+        dbus_bus_add_match(m->bus,
+                           "type='signal',"
+                           "sender='org.freedesktop.systemd1',"
+                           "interface='org.freedesktop.DBus.Properties',"
+                           "member='PropertiesChanged'",
                            &error);
 
         if (dbus_error_is_set(&error)) {
-                log_error("Failed to register match: %s", bus_error_message(&error));
-                r = -EIO;
-                goto fail;
+                log_error("Failed to add match for PropertiesChanged: %s", bus_error_message(&error));
+                dbus_error_free(&error);
+        }
+
+        r = bus_method_call_with_reply(
+                        m->bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "Subscribe",
+                        NULL,
+                        &error,
+                        DBUS_TYPE_INVALID);
+        if (r < 0) {
+                log_error("Failed to enable subscription: %s", bus_error(&error, r));
+                dbus_error_free(&error);
         }
 
         r = dbus_bus_request_name(m->bus, "org.freedesktop.login1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
@@ -1563,9 +1465,6 @@ int manager_startup(Manager *m) {
         assert(m);
         assert(m->epoll_fd <= 0);
 
-        cg_shorten_controllers(m->reset_controllers);
-        cg_shorten_controllers(m->controllers);
-
         m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
         if (m->epoll_fd < 0)
                 return -errno;
index 0861d73..c0abf01 100644 (file)
@@ -13,8 +13,6 @@
 #KillUserProcesses=no
 #KillOnlyUsers=
 #KillExcludeUsers=root
-#Controllers=
-#ResetControllers=cpu
 #InhibitDelayMaxSec=5
 #HandlePowerKey=poweroff
 #HandleSuspendKey=suspend
index ce25211..b7277af 100644 (file)
@@ -77,19 +77,15 @@ struct Manager {
 
         Seat *vtconsole;
 
-        char *cgroup_root;
-        char **controllers, **reset_controllers;
-
         char **kill_only_users, **kill_exclude_users;
-
         bool kill_user_processes;
 
         unsigned long session_counter;
         unsigned long inhibit_counter;
 
-        Hashmap *session_cgroups;
-        Hashmap *user_cgroups;
-        Hashmap *machine_cgroups;
+        Hashmap *session_units;
+        Hashmap *user_units;
+        Hashmap *machine_units;
 
         Hashmap *session_fds;
         Hashmap *inhibitor_fds;
@@ -171,17 +167,12 @@ 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);
 
-int manager_get_user_by_cgroup(Manager *m, const char *cgroup, User **user);
 int manager_get_user_by_pid(Manager *m, pid_t pid, User **user);
-int manager_get_session_by_cgroup(Manager *m, const char *cgroup, Session **session);
 int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session);
-int manager_get_machine_by_cgroup(Manager *m, const char *cgroup, Machine **machine);
 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine);
 
 extern const DBusObjectPathVTable bus_manager_vtable;
@@ -194,5 +185,11 @@ int manager_send_changed(Manager *manager, const char *properties);
 
 int manager_dispatch_delayed(Manager *manager);
 
+int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, DBusError *error, char **job);
+int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job);
+int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job);
+int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error);
+int manager_unit_is_active(Manager *manager, const char *unit);
+
 /* gperf lookup function */
 const struct ConfigPerfItem* logind_gperf_lookup(const char *key, unsigned length);
index 13290fd..8c5b3a1 100644 (file)
 
 static int parse_argv(pam_handle_t *handle,
                       int argc, const char **argv,
-                      char ***controllers,
-                      char ***reset_controllers,
-                      bool *kill_processes,
-                      char ***kill_only_users,
-                      char ***kill_exclude_users,
                       const char **class,
                       bool *debug) {
 
@@ -59,89 +54,15 @@ static int parse_argv(pam_handle_t *handle,
         for (i = 0; i < (unsigned) argc; i++) {
                 int k;
 
-                if (startswith(argv[i], "kill-session-processes=")) {
-                        if ((k = parse_boolean(argv[i] + 23)) < 0) {
-                                pam_syslog(handle, LOG_ERR, "Failed to parse kill-session-processes= argument.");
-                                return k;
-                        }
-
-                        if (kill_processes)
-                                *kill_processes = k;
-
-                } else if (startswith(argv[i], "kill-session=")) {
-                        /* As compatibility for old versions */
-
-                        if ((k = parse_boolean(argv[i] + 13)) < 0) {
-                                pam_syslog(handle, LOG_ERR, "Failed to parse kill-session= argument.");
-                                return k;
-                        }
-
-                        if (kill_processes)
-                                *kill_processes = k;
-
-                } else if (startswith(argv[i], "controllers=")) {
-
-                        if (controllers) {
-                                char **l;
-
-                                if (!(l = strv_split(argv[i] + 12, ","))) {
-                                        pam_syslog(handle, LOG_ERR, "Out of memory.");
-                                        return -ENOMEM;
-                                }
-
-                                strv_free(*controllers);
-                                *controllers = l;
-                        }
-
-                } else if (startswith(argv[i], "reset-controllers=")) {
-
-                        if (reset_controllers) {
-                                char **l;
-
-                                if (!(l = strv_split(argv[i] + 18, ","))) {
-                                        pam_syslog(handle, LOG_ERR, "Out of memory.");
-                                        return -ENOMEM;
-                                }
-
-                                strv_free(*reset_controllers);
-                                *reset_controllers = l;
-                        }
-
-                } else if (startswith(argv[i], "kill-only-users=")) {
-
-                        if (kill_only_users) {
-                                char **l;
-
-                                if (!(l = strv_split(argv[i] + 16, ","))) {
-                                        pam_syslog(handle, LOG_ERR, "Out of memory.");
-                                        return -ENOMEM;
-                                }
-
-                                strv_free(*kill_only_users);
-                                *kill_only_users = l;
-                        }
-
-                } else if (startswith(argv[i], "kill-exclude-users=")) {
-
-                        if (kill_exclude_users) {
-                                char **l;
-
-                                if (!(l = strv_split(argv[i] + 19, ","))) {
-                                        pam_syslog(handle, LOG_ERR, "Out of memory.");
-                                        return -ENOMEM;
-                                }
-
-                                strv_free(*kill_exclude_users);
-                                *kill_exclude_users = l;
-                        }
-
-                } else if (startswith(argv[i], "class=")) {
+                if (startswith(argv[i], "class=")) {
 
                         if (class)
                                 *class = argv[i] + 6;
 
                 } else if (startswith(argv[i], "debug=")) {
-                        if ((k = parse_boolean(argv[i] + 6)) < 0) {
+                        k = parse_boolean(argv[i] + 6);
+
+                        if (k < 0) {
                                 pam_syslog(handle, LOG_ERR, "Failed to parse debug= argument.");
                                 return k;
                         }
@@ -149,14 +70,9 @@ static int parse_argv(pam_handle_t *handle,
                         if (debug)
                                 *debug = k;
 
-                } else if (startswith(argv[i], "create-session=") ||
-                           startswith(argv[i], "kill-user=")) {
-
-                        pam_syslog(handle, LOG_WARNING, "Option %s not supported anymore, ignoring.", argv[i]);
-
                 } else {
-                        pam_syslog(handle, LOG_ERR, "Unknown parameter '%s'.", argv[i]);
-                        return -EINVAL;
+                        pam_syslog(handle, LOG_WARNING, "Unknown parameter '%s', ignoring", argv[i]);
+                        return 0;
                 }
         }
 
@@ -206,55 +122,6 @@ static int get_user_data(
         return PAM_SUCCESS;
 }
 
-static bool check_user_lists(
-                pam_handle_t *handle,
-                uid_t uid,
-                char **kill_only_users,
-                char **kill_exclude_users) {
-
-        const char *name = NULL;
-        char **l;
-
-        assert(handle);
-
-        if (uid == 0)
-                name = "root"; /* Avoid obvious NSS requests, to suppress network traffic */
-        else {
-                struct passwd *pw;
-
-                pw = pam_modutil_getpwuid(handle, uid);
-                if (pw)
-                        name = pw->pw_name;
-        }
-
-        STRV_FOREACH(l, kill_exclude_users) {
-                uid_t u;
-
-                if (parse_uid(*l, &u) >= 0)
-                        if (u == uid)
-                                return false;
-
-                if (name && streq(name, *l))
-                        return false;
-        }
-
-        if (strv_isempty(kill_only_users))
-                return true;
-
-        STRV_FOREACH(l, kill_only_users) {
-                uid_t u;
-
-                if (parse_uid(*l, &u) >= 0)
-                        if (u == uid)
-                                return true;
-
-                if (name && streq(name, *l))
-                        return true;
-        }
-
-        return false;
-}
-
 static int get_seat_from_display(const char *display, const char **seat, uint32_t *vtnr) {
         _cleanup_free_ char *p = NULL;
         int r;
@@ -316,13 +183,11 @@ _public_ PAM_EXTERN int pam_sm_open_session(
                 int argc, const char **argv) {
 
         struct passwd *pw;
-        bool kill_processes = false, debug = false;
+        bool debug = false;
         const char *username, *id, *object_path, *runtime_path, *service = NULL, *tty = NULL, *display = NULL, *remote_user = NULL, *remote_host = NULL, *seat = NULL, *type = NULL, *class = NULL, *class_pam = NULL, *cvtnr = NULL;
-        char **controllers = NULL, **reset_controllers = NULL, **kill_only_users = NULL, **kill_exclude_users = NULL;
         DBusError error;
         uint32_t uid, pid;
         DBusMessageIter iter;
-        dbus_bool_t kp;
         int session_fd = -1;
         DBusConnection *bus = NULL;
         DBusMessage *m = NULL, *reply = NULL;
@@ -342,9 +207,8 @@ _public_ PAM_EXTERN int pam_sm_open_session(
 
         if (parse_argv(handle,
                        argc, argv,
-                       &controllers, &reset_controllers,
-                       &kill_processes, &kill_only_users, &kill_exclude_users,
-                       &class_pam, &debug) < 0) {
+                       &class_pam,
+                       &debug) < 0) {
                 r = PAM_SESSION_ERR;
                 goto finish;
         }
@@ -393,9 +257,6 @@ _public_ PAM_EXTERN int pam_sm_open_session(
                 goto finish;
         }
 
-        if (kill_processes)
-                kill_processes = check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users);
-
         dbus_connection_set_change_sigpipe(FALSE);
 
         bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
@@ -510,27 +371,6 @@ _public_ PAM_EXTERN int pam_sm_open_session(
 
         dbus_message_iter_init_append(m, &iter);
 
-        r = bus_append_strv_iter(&iter, controllers);
-        if (r < 0) {
-                pam_syslog(handle, LOG_ERR, "Could not attach parameter to message.");
-                r = PAM_BUF_ERR;
-                goto finish;
-        }
-
-        r = bus_append_strv_iter(&iter, reset_controllers);
-        if (r < 0) {
-                pam_syslog(handle, LOG_ERR, "Could not attach parameter to message.");
-                r = PAM_BUF_ERR;
-                goto finish;
-        }
-
-        kp = kill_processes;
-        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &kp)) {
-                pam_syslog(handle, LOG_ERR, "Could not attach parameter to message.");
-                r = PAM_BUF_ERR;
-                goto finish;
-        }
-
         if (debug)
                 pam_syslog(handle, LOG_DEBUG, "Asking logind to create session: "
                            "uid=%u pid=%u service=%s type=%s class=%s seat=%s vtnr=%u tty=%s display=%s remote=%s remote_user=%s remote_host=%s",
@@ -613,11 +453,6 @@ _public_ PAM_EXTERN int pam_sm_open_session(
         r = PAM_SUCCESS;
 
 finish:
-        strv_free(controllers);
-        strv_free(reset_controllers);
-        strv_free(kill_only_users);
-        strv_free(kill_exclude_users);
-
         dbus_error_free(&error);
 
         if (bus) {
index 7733aae..1baa6eb 100644 (file)
@@ -565,3 +565,30 @@ UnitType unit_name_to_type(const char *n) {
 
         return unit_type_from_string(e + 1);
 }
+
+int build_subslice(const char *slice, const char*name, char **subslice) {
+        char *ret;
+
+        assert(slice);
+        assert(name);
+        assert(subslice);
+
+        if (streq(slice, "-.slice"))
+                ret = strappend(name, ".slice");
+        else {
+                char *e;
+
+                e = endswith(slice, ".slice");
+                if (!e)
+                        return -EINVAL;
+
+                ret = new(char, (e - slice) + 1 + strlen(name) + 6 + 1);
+                if (!ret)
+                        return -ENOMEM;
+
+                stpcpy(stpcpy(stpcpy(mempcpy(ret, slice, e - slice), "-"), name), ".slice");
+        }
+
+        *subslice = ret;
+        return 0;
+}
index 7f4ae56..20138df 100644 (file)
@@ -99,3 +99,5 @@ int unit_name_from_dbus_path(const char *path, char **name);
 
 char *unit_name_mangle(const char *name);
 char *unit_name_mangle_with_suffix(const char *name, const char *suffix);
+
+int build_subslice(const char *slice, const char*name, char **subslice);
index fde3f43..7ecd8d2 100644 (file)
@@ -3806,7 +3806,7 @@ static int snapshot(DBusConnection *bus, char **args) {
         if (!n)
                 return log_oom();
 
-        r = bus_method_call_with_reply (
+        r = bus_method_call_with_reply(
                         bus,
                         "org.freedesktop.systemd1",
                         "/org/freedesktop/systemd1",
index ece671d..d2d24f1 100644 (file)
@@ -12,12 +12,10 @@ After=systemd-user-sessions.service
 [Service]
 User=%I
 PAMName=systemd-shared
-# in order to allow MEM_CG features to work, add "memory:/" here
-ControlGroup=%R/user/%U.user/shared cpu:/
-ControlGroupModify=yes
 Type=notify
 ExecStart=-@rootlibexecdir@/systemd --user
-Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%U/dbus/user_bus_socket
+Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%I/dbus/user_bus_socket
+Slice=user-%i.slice
 
 [Install]
 Alias=user@%i.service