summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2013-07-02 01:46:30 +0200
committerLennart Poettering <lennart@poettering.net>2013-07-02 01:48:55 +0200
commitfb6becb4436ae4078337011b2017ce294e7361cf (patch)
tree5e80cea85b91f039563907c830cd1d38f19c375c
parent358712f3de33789b2d1293825f1add2c6f4b8e66 (diff)
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.
-rw-r--r--TODO16
-rw-r--r--src/core/bus-errors.h1
-rw-r--r--src/login/logind-dbus.c578
-rw-r--r--src/login/logind-gperf.gperf2
-rw-r--r--src/login/logind-machine-dbus.c89
-rw-r--r--src/login/logind-machine.c220
-rw-r--r--src/login/logind-machine.h23
-rw-r--r--src/login/logind-session-dbus.c99
-rw-r--r--src/login/logind-session.c334
-rw-r--r--src/login/logind-session.h16
-rw-r--r--src/login/logind-user-dbus.c20
-rw-r--r--src/login/logind-user.c240
-rw-r--r--src/login/logind-user.h8
-rw-r--r--src/login/logind.c231
-rw-r--r--src/login/logind.conf2
-rw-r--r--src/login/logind.h21
-rw-r--r--src/login/pam-module.c183
-rw-r--r--src/shared/unit-name.c27
-rw-r--r--src/shared/unit-name.h2
-rw-r--r--src/systemctl/systemctl.c2
-rw-r--r--units/user@.service.in6
21 files changed, 1010 insertions, 1110 deletions
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 \
" <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" \
@@ -114,8 +114,8 @@
" <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");
+}
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 @@
" <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"
@@ -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 <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);
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 @@
" <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" \
@@ -56,15 +55,13 @@
" <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;
+}
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 <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"
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 @@
" <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 },
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 <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",
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