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 p = strappend("/run/user/", u->name);
265 log_error("Out of memory");
271 r = mkdir_safe_label(p, 0700, u->uid, u->gid);
273 log_error("Failed to create runtime directory %s: %s", p, strerror(-r));
275 u->runtime_path = NULL;
283 static int user_create_cgroup(User *u) {
290 if (!u->cgroup_path) {
291 if (asprintf(&p, "%s/%s", u->manager->cgroup_path, u->name) < 0) {
292 log_error("Out of memory");
298 r = cg_create(SYSTEMD_CGROUP_CONTROLLER, p);
300 log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
302 u->cgroup_path = NULL;
308 STRV_FOREACH(k, u->manager->controllers) {
310 if (strv_contains(u->manager->reset_controllers, *k))
313 r = cg_create(*k, p);
315 log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r));
318 hashmap_put(u->manager->user_cgroups, u->cgroup_path, u);
323 static int user_start_service(User *u) {
326 /* FIXME: Fill me in later ... */
331 int user_start(User *u) {
339 log_debug("New user %s logged in.", u->name);
341 /* Make XDG_RUNTIME_DIR */
342 r = user_mkdir_runtime_path(u);
347 r = user_create_cgroup(u);
351 /* Spawn user systemd */
352 r = user_start_service(u);
356 dual_timestamp_get(&u->timestamp);
360 /* Save new user data */
363 user_send_signal(u, true);
368 static int user_stop_service(User *u) {
377 static int user_shall_kill(User *u) {
380 if (!u->manager->kill_user_processes)
383 if (strv_contains(u->manager->kill_exclude_users, u->name))
386 if (strv_isempty(u->manager->kill_only_users))
389 return strv_contains(u->manager->kill_only_users, u->name);
392 static int user_terminate_cgroup(User *u) {
401 cg_trim(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false);
403 if (user_shall_kill(u)) {
405 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
407 log_error("Failed to kill user cgroup: %s", strerror(-r));
410 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
412 log_error("Failed to check user cgroup: %s", strerror(-r));
414 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
416 log_error("Failed to delete user cgroup: %s", strerror(-r));
421 STRV_FOREACH(k, u->manager->controllers)
422 cg_trim(*k, u->cgroup_path, true);
424 hashmap_remove(u->manager->user_cgroups, u->cgroup_path);
426 free(u->cgroup_path);
427 u->cgroup_path = NULL;
432 static int user_remove_runtime_path(User *u) {
437 if (!u->runtime_path)
440 r = rm_rf(u->runtime_path, false, true, false);
442 log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
444 free(u->runtime_path);
445 u->runtime_path = NULL;
450 int user_stop(User *u) {
456 log_debug("User %s logged out.", u->name);
458 LIST_FOREACH(sessions_by_user, s, u->sessions) {
465 k = user_stop_service(u);
470 k = user_terminate_cgroup(u);
474 /* Kill XDG_RUNTIME_DIR */
475 k = user_remove_runtime_path(u);
479 unlink(u->state_file);
480 user_add_to_gc_queue(u);
483 user_send_signal(u, false);
490 int user_get_idle_hint(User *u, dual_timestamp *t) {
492 bool idle_hint = true;
493 dual_timestamp ts = { 0, 0 };
497 LIST_FOREACH(sessions_by_user, s, u->sessions) {
501 ih = session_get_idle_hint(s, &k);
507 if (k.monotonic < ts.monotonic)
513 } else if (idle_hint) {
515 if (k.monotonic > ts.monotonic)
526 static int user_check_linger_file(User *u) {
530 if (asprintf(&p, "/var/lib/systemd/linger/%s", u->name) < 0)
533 r = access(p, F_OK) >= 0;
539 int user_check_gc(User *u, bool drop_not_started) {
544 if (drop_not_started && !u->started)
550 if (user_check_linger_file(u) > 0)
553 if (u->cgroup_path) {
554 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false);
565 void user_add_to_gc_queue(User *u) {
571 LIST_PREPEND(User, gc_queue, u->manager->user_gc_queue, u);
572 u->in_gc_queue = true;
575 UserState user_get_state(User *u) {
580 LIST_FOREACH(sessions_by_user, i, u->sessions)
581 if (session_is_active(i))
587 if (user_check_linger_file(u) > 0)
588 return USER_LINGERING;
593 int user_kill(User *u, int signo) {
602 pid_set = set_new(trivial_hash_func, trivial_compare_func);
606 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
608 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
617 static const char* const user_state_table[_USER_STATE_MAX] = {
618 [USER_OFFLINE] = "offline",
619 [USER_LINGERING] = "lingering",
620 [USER_ONLINE] = "online",
621 [USER_ACTIVE] = "active",
622 [USER_CLOSING] = "closing"
625 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);