From: Lennart Poettering Date: Mon, 1 Jul 2013 23:46:30 +0000 (+0200) Subject: logind: port over to use scopes+slices for all cgroup stuff X-Git-Tag: v205~34 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=fb6becb4436ae4078337011b2017ce294e7361cf logind: port over to use scopes+slices for all cgroup stuff 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. --- diff --git a/TODO b/TODO index e8afa5f3d..cde2ced31 100644 --- 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 diff --git a/src/core/bus-errors.h b/src/core/bus-errors.h index 7a4084ea1..9368d68e8 100644 --- a/src/core/bus-errors.h +++ b/src/core/bus-errors.h @@ -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" diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 631006924..d8d25b004 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -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 \ " \n" \ @@ -94,9 +96,7 @@ " \n" \ " \n" \ " \n" \ - " \n" \ - " \n" \ - " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -114,8 +114,8 @@ " \n" \ " \n" \ " \n" \ - " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \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"); +} diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf index 735d2dbc9..845302a54 100644 --- a/src/login/logind-gperf.gperf +++ b/src/login/logind-gperf.gperf @@ -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) diff --git a/src/login/logind-machine-dbus.c b/src/login/logind-machine-dbus.c index 7feea2e92..ae8c5d720 100644 --- a/src/login/logind-machine-dbus.c +++ b/src/login/logind-machine-dbus.c @@ -37,11 +37,11 @@ " \n" \ " \n" \ " \n" \ - " \n" \ " \n" \ - " \n" \ + " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" @@ -58,24 +58,6 @@ 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; +} diff --git a/src/login/logind-machine.c b/src/login/logind-machine.c index 0b35a9e2d..e4edd40db 100644 --- a/src/login/logind-machine.c +++ b/src/login/logind-machine.c @@ -23,7 +23,8 @@ #include #include -#include "logind-machine.h" +#include + #include "util.h" #include "mkdir.h" #include "cgroup-util.h" @@ -31,7 +32,9 @@ #include "strv.h" #include "fileio.h" #include "special.h" -#include +#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); diff --git a/src/login/logind-machine.h b/src/login/logind-machine.h index cd5174ff9..a09f07195 100644 --- a/src/login/logind-machine.h +++ b/src/login/logind-machine.h @@ -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_; diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index e306eabb3..7aba3477a 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -47,7 +47,6 @@ " \n" \ " \n" \ " \n" \ - " \n" \ " \n" \ " \n" \ " \n" \ @@ -56,15 +55,13 @@ " \n" \ " \n" \ " \n" \ - " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ - " \n" \ - " \n" \ " \n" \ " \n" \ " \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; +} diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 760425329..93e403723 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -25,15 +25,17 @@ #include #include -#include "systemd/sd-id128.h" -#include "systemd/sd-messages.h" +#include +#include + #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" diff --git a/src/login/logind-session.h b/src/login/logind-session.h index 60597c236..e2a46d590 100644 --- a/src/login/logind-session.h +++ b/src/login/logind-session.h @@ -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_; diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c index 2a2825308..fa2ecba53 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -38,7 +38,6 @@ " \n" \ " \n" \ " \n" \ - " \n" \ " \n" \ " \n" \ " \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 }, diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 9f7b924a2..316c4cd09 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -23,7 +23,6 @@ #include #include -#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", diff --git a/src/login/logind-user.h b/src/login/logind-user.h index 16d798541..889f828c4 100644 --- a/src/login/logind-user.h +++ b/src/login/logind-user.h @@ -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); diff --git a/src/login/logind.c b/src/login/logind.c index ea74254b2..7040ac9e8 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -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; diff --git a/src/login/logind.conf b/src/login/logind.conf index 0861d73e0..c0abf01b0 100644 --- a/src/login/logind.conf +++ b/src/login/logind.conf @@ -13,8 +13,6 @@ #KillUserProcesses=no #KillOnlyUsers= #KillExcludeUsers=root -#Controllers= -#ResetControllers=cpu #InhibitDelayMaxSec=5 #HandlePowerKey=poweroff #HandleSuspendKey=suspend diff --git a/src/login/logind.h b/src/login/logind.h index ce2521187..b7277af73 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -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); diff --git a/src/login/pam-module.c b/src/login/pam-module.c index 13290fd8e..8c5b3a10f 100644 --- a/src/login/pam-module.c +++ b/src/login/pam-module.c @@ -43,11 +43,6 @@ 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) { diff --git a/src/shared/unit-name.c b/src/shared/unit-name.c index 7733aae0e..1baa6eb7e 100644 --- a/src/shared/unit-name.c +++ b/src/shared/unit-name.c @@ -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; +} diff --git a/src/shared/unit-name.h b/src/shared/unit-name.h index 7f4ae5643..20138df08 100644 --- a/src/shared/unit-name.h +++ b/src/shared/unit-name.h @@ -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); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index fde3f43a1..7ecd8d2cf 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -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", diff --git a/units/user@.service.in b/units/user@.service.in index ece671d44..d2d24f10b 100644 --- a/units/user@.service.in +++ b/units/user@.service.in @@ -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