mirror of
https://github.com/systemd/systemd.git
synced 2025-01-21 22:04:01 +03:00
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.
This commit is contained in:
parent
358712f3de
commit
fb6becb443
16
TODO
16
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
|
||||
|
@ -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"
|
||||
|
@ -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_cgroup(m, cgroup, &session);
|
||||
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;
|
||||
|
||||
/* Session already exists, client is probably
|
||||
* something like "su" which changes uid but is still
|
||||
* the same 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;
|
||||
}
|
||||
m->create_message = dbus_message_ref(message);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
*_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");
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
dbus_error_init(&error);
|
||||
|
||||
if (!m->cgroup_path) {
|
||||
_cleanup_free_ char *escaped = NULL, *slice = NULL;
|
||||
char *name;
|
||||
if (!m->scope) {
|
||||
_cleanup_free_ char *escaped = NULL;
|
||||
|
||||
name = strappenda(m->name, ".machine");
|
||||
|
||||
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)
|
||||
dbus_error_init(&error);
|
||||
|
||||
if (!m->scope)
|
||||
return 0;
|
||||
|
||||
cg_trim(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, false);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
hashmap_remove(m->manager->machine_cgroups, m->cgroup_path);
|
||||
|
||||
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;
|
||||
MachineState machine_get_state(Machine *s) {
|
||||
assert(s);
|
||||
|
||||
if (s->scope_job)
|
||||
return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
|
||||
|
||||
return MACHINE_RUNNING;
|
||||
}
|
||||
|
||||
int machine_kill(Machine *m, KillWho who, int signo) {
|
||||
assert(m);
|
||||
|
||||
if (!m->cgroup_path)
|
||||
if (!m->scope)
|
||||
return -ESRCH;
|
||||
|
||||
if (m->leader <= 0 && who == KILL_LEADER)
|
||||
return -ESRCH;
|
||||
|
||||
if (m->leader > 0)
|
||||
if (kill(m->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 (m->leader > 0) {
|
||||
q = set_put(pid_set, LONG_TO_PTR(m->leader));
|
||||
if (q < 0)
|
||||
r = q;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -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_;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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->cgroup_path);
|
||||
strv_free(s->controllers);
|
||||
free(s->scope_job);
|
||||
|
||||
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;
|
||||
dbus_error_init(&error);
|
||||
|
||||
if (!s->scope) {
|
||||
s->scope = strjoin("session.", s->id, ".scope", NULL);
|
||||
if (!s->scope)
|
||||
return log_oom();
|
||||
|
||||
r = hashmap_put(s->manager->session_units, s->scope, s);
|
||||
if (r < 0)
|
||||
log_warning("Failed to create mapping between unit and session");
|
||||
}
|
||||
|
||||
description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
|
||||
|
||||
r = manager_start_scope(s->manager, s->scope, s->leader, s->user->slice, description, &error, &job);
|
||||
if (r < 0) {
|
||||
r = cg_create(controller, path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
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 = 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();
|
||||
|
||||
escaped = cg_escape(name);
|
||||
if (!escaped)
|
||||
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);
|
||||
if (r < 0)
|
||||
log_warning("Failed to create %s:%s: %s", *k, s->cgroup_path, strerror(-r));
|
||||
}
|
||||
|
||||
STRV_FOREACH(k, s->manager->controllers) {
|
||||
|
||||
if (strv_contains(s->reset_controllers, *k) ||
|
||||
strv_contains(s->manager->reset_controllers, *k) ||
|
||||
strv_contains(s->controllers, *k))
|
||||
continue;
|
||||
|
||||
r = session_create_one_group(s, *k, 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) {
|
||||
|
||||
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 = 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)
|
||||
dbus_error_init(&error);
|
||||
|
||||
if (!s->scope)
|
||||
return 0;
|
||||
|
||||
cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
|
||||
|
||||
if (session_shall_kill(s)) {
|
||||
|
||||
r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
|
||||
if (r < 0)
|
||||
log_error("Failed to kill session cgroup: %s", strerror(-r));
|
||||
|
||||
} else {
|
||||
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 */
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if (!s->scope)
|
||||
return -ESRCH;
|
||||
|
||||
if (s->leader <= 0 && who == KILL_LEADER)
|
||||
return -ESRCH;
|
||||
|
||||
if (s->leader > 0)
|
||||
if (kill(s->leader, signo) < 0)
|
||||
r = -errno;
|
||||
|
||||
if (who == KILL_ALL) {
|
||||
int q;
|
||||
|
||||
pid_set = set_new(trivial_hash_func, trivial_compare_func);
|
||||
if (!pid_set)
|
||||
return 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"
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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 },
|
||||
|
@ -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);
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
if (!u->slice) {
|
||||
u->slice = strdup(SPECIAL_USER_SLICE);
|
||||
if (!u->slice)
|
||||
return log_oom();
|
||||
}
|
||||
char lu[DECIMAL_STR_MAX(unsigned long) + 1];
|
||||
sprintf(lu, "%lu", (unsigned long) u->uid);
|
||||
|
||||
if (!u->cgroup_path) {
|
||||
_cleanup_free_ char *name = NULL, *escaped = NULL, *slice = NULL;
|
||||
|
||||
if (asprintf(&name, "%lu.user", (unsigned long) u->uid) < 0)
|
||||
return log_oom();
|
||||
|
||||
escaped = cg_escape(name);
|
||||
if (!escaped)
|
||||
return log_oom();
|
||||
|
||||
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 = cg_create(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
|
||||
if (r < 0) {
|
||||
log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", u->cgroup_path, strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
STRV_FOREACH(k, u->manager->controllers) {
|
||||
|
||||
if (strv_contains(u->manager->reset_controllers, *k))
|
||||
continue;
|
||||
|
||||
r = cg_create(*k, u->cgroup_path);
|
||||
r = hashmap_put(u->manager->user_units, u->slice, u);
|
||||
if (r < 0)
|
||||
log_warning("Failed to create cgroup %s:%s: %s", *k, u->cgroup_path, strerror(-r));
|
||||
log_warning("Failed to create mapping between unit and user");
|
||||
}
|
||||
|
||||
r = hashmap_put(u->manager->user_cgroups, u->cgroup_path, u);
|
||||
if (r < 0)
|
||||
log_warning("Failed to create mapping between cgroup and user");
|
||||
r = manager_start_unit(u->manager, u->slice, &error, &job);
|
||||
if (r < 0) {
|
||||
log_error("Failed to start user slice: %s", bus_error(&error, r));
|
||||
dbus_error_free(&error);
|
||||
}
|
||||
|
||||
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,70 +434,71 @@ int user_start(User *u) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int user_stop_service(User *u) {
|
||||
static int user_stop_slice(User *u) {
|
||||
DBusError error;
|
||||
char *job;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
free(u->slice_job);
|
||||
u->slice_job = job;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int user_stop_service(User *u) {
|
||||
DBusError error;
|
||||
char *job;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
if (!u->service)
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int user_shall_kill(User *u) {
|
||||
assert(u);
|
||||
|
||||
if (!u->manager->kill_user_processes)
|
||||
return false;
|
||||
|
||||
if (strv_contains(u->manager->kill_exclude_users, u->name))
|
||||
return false;
|
||||
|
||||
if (strv_isempty(u->manager->kill_only_users))
|
||||
return true;
|
||||
|
||||
return strv_contains(u->manager->kill_only_users, u->name);
|
||||
}
|
||||
|
||||
static int user_terminate_cgroup(User *u) {
|
||||
int r;
|
||||
char **k;
|
||||
|
||||
assert(u);
|
||||
|
||||
if (!u->cgroup_path)
|
||||
return 0;
|
||||
|
||||
cg_trim(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false);
|
||||
|
||||
if (user_shall_kill(u)) {
|
||||
|
||||
r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
|
||||
if (r < 0)
|
||||
log_error("Failed to kill user cgroup: %s", strerror(-r));
|
||||
} else {
|
||||
|
||||
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
|
||||
if (r < 0)
|
||||
log_error("Failed to check user cgroup: %s", strerror(-r));
|
||||
else if (r > 0) {
|
||||
r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
|
||||
if (r < 0)
|
||||
log_error("Failed to delete user cgroup: %s", strerror(-r));
|
||||
} else
|
||||
r = -EBUSY;
|
||||
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;
|
||||
}
|
||||
|
||||
STRV_FOREACH(k, u->manager->controllers)
|
||||
cg_trim(*k, u->cgroup_path, true);
|
||||
|
||||
hashmap_remove(u->manager->user_cgroups, u->cgroup_path);
|
||||
|
||||
free(u->cgroup_path);
|
||||
u->cgroup_path = NULL;
|
||||
free(u->service_job);
|
||||
u->service_job = job;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* static int user_shall_kill(User *u) { */
|
||||
/* assert(u); */
|
||||
|
||||
/* if (!u->manager->kill_user_processes) */
|
||||
/* return false; */
|
||||
|
||||
/* if (strv_contains(u->manager->kill_exclude_users, u->name)) */
|
||||
/* return false; */
|
||||
|
||||
/* if (strv_isempty(u->manager->kill_only_users)) */
|
||||
/* return true; */
|
||||
|
||||
/* return strv_contains(u->manager->kill_only_users, u->name); */
|
||||
/* } */
|
||||
|
||||
static int user_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",
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
mm = hashmap_get(m->machine_units, unit);
|
||||
if (!mm)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
@ -13,8 +13,6 @@
|
||||
#KillUserProcesses=no
|
||||
#KillOnlyUsers=
|
||||
#KillExcludeUsers=root
|
||||
#Controllers=
|
||||
#ResetControllers=cpu
|
||||
#InhibitDelayMaxSec=5
|
||||
#HandlePowerKey=poweroff
|
||||
#HandleSuspendKey=suspend
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user