1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "logind-user.h"
29 #include "cgroup-util.h"
33 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
43 u->name = strdup(name);
49 if (asprintf(&u->state_file, "/run/systemd/users/%lu", (unsigned long) uid) < 0) {
55 if (hashmap_put(m->users, ULONG_TO_PTR((unsigned long) uid), u) < 0) {
69 void user_free(User *u) {
73 LIST_REMOVE(User, gc_queue, u->manager->user_gc_queue, u);
76 session_free(u->sessions);
79 hashmap_remove(u->manager->user_cgroups, u->cgroup_path);
83 free(u->runtime_path);
85 hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid));
92 int user_save(User *u) {
98 assert(u->state_file);
103 r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
107 r = fopen_temporary(u->state_file, &f, &temp_path);
111 fchmod(fileno(f), 0644);
114 "# This is private data. Do not parse.\n"
118 user_state_to_string(user_get_state(u)));
144 fputs("SESSIONS=", f);
146 LIST_FOREACH(sessions_by_user, i, u->sessions) {
155 fputs("\nSEATS=", f);
157 LIST_FOREACH(sessions_by_user, i, u->sessions) {
166 fputs(i->seat->id, f);
169 fputs("\nACTIVE_SESSIONS=", f);
171 LIST_FOREACH(sessions_by_user, i, u->sessions) {
172 if (!session_is_active(i))
183 fputs("\nACTIVE_SEATS=", f);
185 LIST_FOREACH(sessions_by_user, i, u->sessions) {
186 if (!session_is_active(i) || !i->seat)
192 fputs(i->seat->id, f);
199 if (ferror(f) || rename(temp_path, u->state_file) < 0) {
201 unlink(u->state_file);
210 log_error("Failed to save user data for %s: %s", u->name, strerror(-r));
215 int user_load(User *u) {
217 char *display = NULL;
222 r = parse_env_file(u->state_file, NEWLINE,
223 "CGROUP", &u->cgroup_path,
224 "RUNTIME", &u->runtime_path,
225 "SERVICE", &u->service,
234 log_error("Failed to read %s: %s", u->state_file, strerror(-r));
239 s = hashmap_get(u->manager->sessions, display);
243 if (s && s->display && display_is_local(s->display))
249 static int user_mkdir_runtime_path(User *u) {
255 r = mkdir_safe_label("/run/user", 0755, 0, 0);
257 log_error("Failed to create /run/user: %s", strerror(-r));
261 if (!u->runtime_path) {
262 if (asprintf(&p, "/run/user/%lu", (unsigned long) u->uid) < 0) {
263 log_error("Out of memory");
269 r = mkdir_safe_label(p, 0700, u->uid, u->gid);
271 log_error("Failed to create runtime directory %s: %s", p, strerror(-r));
273 u->runtime_path = NULL;
281 static int user_create_cgroup(User *u) {
288 if (!u->cgroup_path) {
289 if (asprintf(&p, "%s/%s", u->manager->cgroup_path, u->name) < 0) {
290 log_error("Out of memory");
296 r = cg_create(SYSTEMD_CGROUP_CONTROLLER, p);
298 log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
300 u->cgroup_path = NULL;
306 STRV_FOREACH(k, u->manager->controllers) {
308 if (strv_contains(u->manager->reset_controllers, *k))
311 r = cg_create(*k, p);
313 log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r));
316 hashmap_put(u->manager->user_cgroups, u->cgroup_path, u);
321 static int user_start_service(User *u) {
324 /* FIXME: Fill me in later ... */
329 int user_start(User *u) {
337 log_debug("New user %s logged in.", u->name);
339 /* Make XDG_RUNTIME_DIR */
340 r = user_mkdir_runtime_path(u);
345 r = user_create_cgroup(u);
349 /* Spawn user systemd */
350 r = user_start_service(u);
354 dual_timestamp_get(&u->timestamp);
358 /* Save new user data */
361 user_send_signal(u, true);
366 static int user_stop_service(User *u) {
375 static int user_shall_kill(User *u) {
378 if (!u->manager->kill_user_processes)
381 if (strv_contains(u->manager->kill_exclude_users, u->name))
384 if (strv_isempty(u->manager->kill_only_users))
387 return strv_contains(u->manager->kill_only_users, u->name);
390 static int user_terminate_cgroup(User *u) {
399 cg_trim(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false);
401 if (user_shall_kill(u)) {
403 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
405 log_error("Failed to kill user cgroup: %s", strerror(-r));
408 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
410 log_error("Failed to check user cgroup: %s", strerror(-r));
412 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
414 log_error("Failed to delete user cgroup: %s", strerror(-r));
419 STRV_FOREACH(k, u->manager->controllers)
420 cg_trim(*k, u->cgroup_path, true);
422 hashmap_remove(u->manager->user_cgroups, u->cgroup_path);
424 free(u->cgroup_path);
425 u->cgroup_path = NULL;
430 static int user_remove_runtime_path(User *u) {
435 if (!u->runtime_path)
438 r = rm_rf(u->runtime_path, false, true, false);
440 log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
442 free(u->runtime_path);
443 u->runtime_path = NULL;
448 int user_stop(User *u) {
454 log_debug("User %s logged out.", u->name);
456 LIST_FOREACH(sessions_by_user, s, u->sessions) {
463 k = user_stop_service(u);
468 k = user_terminate_cgroup(u);
472 /* Kill XDG_RUNTIME_DIR */
473 k = user_remove_runtime_path(u);
477 unlink(u->state_file);
478 user_add_to_gc_queue(u);
481 user_send_signal(u, false);
488 int user_get_idle_hint(User *u, dual_timestamp *t) {
490 bool idle_hint = true;
491 dual_timestamp ts = { 0, 0 };
495 LIST_FOREACH(sessions_by_user, s, u->sessions) {
499 ih = session_get_idle_hint(s, &k);
505 if (k.monotonic < ts.monotonic)
511 } else if (idle_hint) {
513 if (k.monotonic > ts.monotonic)
524 static int user_check_linger_file(User *u) {
528 if (asprintf(&p, "/var/lib/systemd/linger/%s", u->name) < 0)
531 r = access(p, F_OK) >= 0;
537 int user_check_gc(User *u, bool drop_not_started) {
542 if (drop_not_started && !u->started)
548 if (user_check_linger_file(u) > 0)
551 if (u->cgroup_path) {
552 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false);
563 void user_add_to_gc_queue(User *u) {
569 LIST_PREPEND(User, gc_queue, u->manager->user_gc_queue, u);
570 u->in_gc_queue = true;
573 UserState user_get_state(User *u) {
578 LIST_FOREACH(sessions_by_user, i, u->sessions)
579 if (session_is_active(i))
585 if (user_check_linger_file(u) > 0)
586 return USER_LINGERING;
591 int user_kill(User *u, int signo) {
600 pid_set = set_new(trivial_hash_func, trivial_compare_func);
604 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
606 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
615 static const char* const user_state_table[_USER_STATE_MAX] = {
616 [USER_OFFLINE] = "offline",
617 [USER_LINGERING] = "lingering",
618 [USER_ONLINE] = "online",
619 [USER_ACTIVE] = "active",
620 [USER_CLOSING] = "closing"
623 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);