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/>.
22 #include <sys/mount.h>
32 #include "path-util.h"
34 #include "unit-name.h"
36 #include "bus-error.h"
37 #include "conf-parser.h"
38 #include "clean-ipc.h"
39 #include "logind-user.h"
40 #include "smack-util.h"
42 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
52 u->name = strdup(name);
56 if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
59 if (hashmap_put(m->users, UID_TO_PTR(uid), u) < 0)
76 void user_free(User *u) {
80 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
83 session_free(u->sessions);
86 hashmap_remove(u->manager->user_units, u->slice);
91 hashmap_remove(u->manager->user_units, u->service);
98 free(u->runtime_path);
100 hashmap_remove(u->manager->users, UID_TO_PTR(u->uid));
107 int user_save(User *u) {
108 _cleanup_free_ char *temp_path = NULL;
109 _cleanup_fclose_ FILE *f = NULL;
113 assert(u->state_file);
118 r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
122 r = fopen_temporary(u->state_file, &f, &temp_path);
126 fchmod(fileno(f), 0644);
129 "# This is private data. Do not parse.\n"
133 user_state_to_string(user_get_state(u)));
136 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
139 fprintf(f, "SERVICE=%s\n", u->service);
141 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
144 fprintf(f, "SLICE=%s\n", u->slice);
146 fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
149 fprintf(f, "DISPLAY=%s\n", u->display->id);
151 if (dual_timestamp_is_set(&u->timestamp))
153 "REALTIME="USEC_FMT"\n"
154 "MONOTONIC="USEC_FMT"\n",
155 u->timestamp.realtime,
156 u->timestamp.monotonic);
162 fputs("SESSIONS=", f);
164 LIST_FOREACH(sessions_by_user, i, u->sessions) {
173 fputs("\nSEATS=", f);
175 LIST_FOREACH(sessions_by_user, i, u->sessions) {
184 fputs(i->seat->id, f);
187 fputs("\nACTIVE_SESSIONS=", f);
189 LIST_FOREACH(sessions_by_user, i, u->sessions) {
190 if (!session_is_active(i))
201 fputs("\nONLINE_SESSIONS=", f);
203 LIST_FOREACH(sessions_by_user, i, u->sessions) {
204 if (session_get_state(i) == SESSION_CLOSING)
215 fputs("\nACTIVE_SEATS=", f);
217 LIST_FOREACH(sessions_by_user, i, u->sessions) {
218 if (!session_is_active(i) || !i->seat)
226 fputs(i->seat->id, f);
229 fputs("\nONLINE_SEATS=", f);
231 LIST_FOREACH(sessions_by_user, i, u->sessions) {
232 if (session_get_state(i) == SESSION_CLOSING || !i->seat)
240 fputs(i->seat->id, f);
247 if (ferror(f) || rename(temp_path, u->state_file) < 0) {
249 unlink(u->state_file);
255 log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
260 int user_load(User *u) {
261 _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
267 r = parse_env_file(u->state_file, NEWLINE,
268 "RUNTIME", &u->runtime_path,
269 "SERVICE", &u->service,
270 "SERVICE_JOB", &u->service_job,
272 "SLICE_JOB", &u->slice_job,
274 "REALTIME", &realtime,
275 "MONOTONIC", &monotonic,
281 log_error_errno(r, "Failed to read %s: %m", u->state_file);
286 s = hashmap_get(u->manager->sessions, display);
288 if (s && s->display && display_is_local(s->display))
292 unsigned long long l;
293 if (sscanf(realtime, "%llu", &l) > 0)
294 u->timestamp.realtime = l;
298 unsigned long long l;
299 if (sscanf(monotonic, "%llu", &l) > 0)
300 u->timestamp.monotonic = l;
306 static int user_mkdir_runtime_path(User *u) {
312 r = mkdir_safe_label("/run/user", 0755, 0, 0);
314 return log_error_errno(r, "Failed to create /run/user: %m");
316 if (!u->runtime_path) {
317 if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
322 if (path_is_mount_point(p, false) <= 0) {
323 _cleanup_free_ char *t = NULL;
328 r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
330 r = asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
336 r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
338 r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", p);
348 /* Try to clean up, but ignore errors */
353 u->runtime_path = NULL;
357 static int user_start_slice(User *u) {
364 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
365 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
366 sprintf(lu, UID_FMT, u->uid);
368 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
372 r = manager_start_unit(u->manager, slice, &error, &job);
374 log_error("Failed to start user slice: %s", bus_error_message(&error, r));
385 hashmap_put(u->manager->user_units, u->slice, u);
390 static int user_start_service(User *u) {
391 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
398 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
399 sprintf(lu, UID_FMT, u->uid);
401 service = unit_name_build("user", lu, ".service");
405 r = manager_start_unit(u->manager, service, &error, &job);
407 log_error("Failed to start user service: %s", bus_error_message(&error, r));
410 u->service = service;
412 free(u->service_job);
413 u->service_job = job;
418 hashmap_put(u->manager->user_units, u->service, u);
423 int user_start(User *u) {
431 log_debug("New user %s logged in.", u->name);
433 /* Make XDG_RUNTIME_DIR */
434 r = user_mkdir_runtime_path(u);
439 r = user_start_slice(u);
443 /* Spawn user systemd */
444 r = user_start_service(u);
448 if (!dual_timestamp_is_set(&u->timestamp))
449 dual_timestamp_get(&u->timestamp);
453 /* Save new user data */
456 user_send_signal(u, true);
461 static int user_stop_slice(User *u) {
462 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
471 r = manager_stop_unit(u->manager, u->slice, &error, &job);
473 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
483 static int user_stop_service(User *u) {
484 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
493 r = manager_stop_unit(u->manager, u->service, &error, &job);
495 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
499 free(u->service_job);
500 u->service_job = job;
505 static int user_remove_runtime_path(User *u) {
510 if (!u->runtime_path)
513 r = rm_rf(u->runtime_path, false, false, false);
515 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
517 if (umount2(u->runtime_path, MNT_DETACH) < 0)
518 log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
520 r = rm_rf(u->runtime_path, false, true, false);
522 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
524 free(u->runtime_path);
525 u->runtime_path = NULL;
530 int user_stop(User *u, bool force) {
535 /* Stop jobs have already been queued */
541 LIST_FOREACH(sessions_by_user, s, u->sessions) {
542 k = session_stop(s, force);
548 k = user_stop_service(u);
553 k = user_stop_slice(u);
564 int user_finalize(User *u) {
571 log_debug("User %s logged out.", u->name);
573 LIST_FOREACH(sessions_by_user, s, u->sessions) {
574 k = session_finalize(s);
579 /* Kill XDG_RUNTIME_DIR */
580 k = user_remove_runtime_path(u);
584 /* Clean SysV + POSIX IPC objects */
585 if (u->manager->remove_ipc) {
586 k = clean_ipc(u->uid);
591 unlink(u->state_file);
592 user_add_to_gc_queue(u);
595 user_send_signal(u, false);
602 int user_get_idle_hint(User *u, dual_timestamp *t) {
604 bool idle_hint = true;
605 dual_timestamp ts = { 0, 0 };
609 LIST_FOREACH(sessions_by_user, s, u->sessions) {
613 ih = session_get_idle_hint(s, &k);
619 if (k.monotonic < ts.monotonic)
625 } else if (idle_hint) {
627 if (k.monotonic > ts.monotonic)
638 int user_check_linger_file(User *u) {
639 _cleanup_free_ char *cc = NULL;
642 cc = cescape(u->name);
646 p = strappenda("/var/lib/systemd/linger/", cc);
648 return access(p, F_OK) >= 0;
651 bool user_check_gc(User *u, bool drop_not_started) {
654 if (drop_not_started && !u->started)
660 if (user_check_linger_file(u) > 0)
663 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
666 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
672 void user_add_to_gc_queue(User *u) {
678 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
679 u->in_gc_queue = true;
682 UserState user_get_state(User *u) {
690 if (u->slice_job || u->service_job)
694 bool all_closing = true;
696 LIST_FOREACH(sessions_by_user, i, u->sessions) {
699 state = session_get_state(i);
700 if (state == SESSION_ACTIVE)
702 if (state != SESSION_CLOSING)
706 return all_closing ? USER_CLOSING : USER_ONLINE;
709 if (user_check_linger_file(u) > 0)
710 return USER_LINGERING;
715 int user_kill(User *u, int signo) {
721 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
724 void user_elect_display(User *u) {
725 Session *graphical = NULL, *text = NULL, *other = NULL, *s;
729 /* This elects a primary session for each user, which we call
730 * the "display". We try to keep the assignment stable, but we
731 * "upgrade" to better choices. */
733 LIST_FOREACH(sessions_by_user, s, u->sessions) {
735 if (s->class != SESSION_USER)
741 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
743 else if (s->type == SESSION_TTY)
751 u->display->class != SESSION_USER ||
752 u->display->stopping ||
753 !SESSION_TYPE_IS_GRAPHICAL(u->display->type))) {
754 u->display = graphical;
760 u->display->class != SESSION_USER ||
761 u->display->stopping ||
762 u->display->type != SESSION_TTY)) {
769 u->display->class != SESSION_USER ||
770 u->display->stopping))
774 static const char* const user_state_table[_USER_STATE_MAX] = {
775 [USER_OFFLINE] = "offline",
776 [USER_OPENING] = "opening",
777 [USER_LINGERING] = "lingering",
778 [USER_ONLINE] = "online",
779 [USER_ACTIVE] = "active",
780 [USER_CLOSING] = "closing"
783 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
785 int config_parse_tmpfs_size(
787 const char *filename,
790 unsigned section_line,
806 e = endswith(rvalue, "%");
812 ul = strtoul(rvalue, &f, 10);
813 if (errno != 0 || f != e) {
814 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
818 if (ul <= 0 || ul >= 100) {
819 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
823 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
827 r = parse_size(rvalue, 1024, &o);
828 if (r < 0 || (off_t) (size_t) o != o) {
829 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
833 *sz = PAGE_ALIGN((size_t) o);