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, ULONG_TO_PTR((unsigned long) 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, ULONG_TO_PTR((unsigned long) 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);
337 r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
339 log_error_errno(r, "Failed to mount per-user tmpfs directory %s: %m", p);
349 u->runtime_path = NULL;
353 static int user_start_slice(User *u) {
360 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
361 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
362 sprintf(lu, UID_FMT, u->uid);
364 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
368 r = manager_start_unit(u->manager, slice, &error, &job);
370 log_error("Failed to start user slice: %s", bus_error_message(&error, r));
381 hashmap_put(u->manager->user_units, u->slice, u);
386 static int user_start_service(User *u) {
387 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
394 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
395 sprintf(lu, UID_FMT, u->uid);
397 service = unit_name_build("user", lu, ".service");
401 r = manager_start_unit(u->manager, service, &error, &job);
403 log_error("Failed to start user service: %s", bus_error_message(&error, r));
406 u->service = service;
408 free(u->service_job);
409 u->service_job = job;
414 hashmap_put(u->manager->user_units, u->service, u);
419 int user_start(User *u) {
427 log_debug("New user %s logged in.", u->name);
429 /* Make XDG_RUNTIME_DIR */
430 r = user_mkdir_runtime_path(u);
435 r = user_start_slice(u);
439 /* Spawn user systemd */
440 r = user_start_service(u);
444 if (!dual_timestamp_is_set(&u->timestamp))
445 dual_timestamp_get(&u->timestamp);
449 /* Save new user data */
452 user_send_signal(u, true);
457 static int user_stop_slice(User *u) {
458 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
467 r = manager_stop_unit(u->manager, u->slice, &error, &job);
469 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
479 static int user_stop_service(User *u) {
480 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
489 r = manager_stop_unit(u->manager, u->service, &error, &job);
491 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
495 free(u->service_job);
496 u->service_job = job;
501 static int user_remove_runtime_path(User *u) {
506 if (!u->runtime_path)
509 r = rm_rf(u->runtime_path, false, false, false);
511 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
513 if (umount2(u->runtime_path, MNT_DETACH) < 0)
514 log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
516 r = rm_rf(u->runtime_path, false, true, false);
518 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
520 free(u->runtime_path);
521 u->runtime_path = NULL;
526 int user_stop(User *u, bool force) {
531 /* Stop jobs have already been queued */
537 LIST_FOREACH(sessions_by_user, s, u->sessions) {
538 k = session_stop(s, force);
544 k = user_stop_service(u);
549 k = user_stop_slice(u);
560 int user_finalize(User *u) {
567 log_debug("User %s logged out.", u->name);
569 LIST_FOREACH(sessions_by_user, s, u->sessions) {
570 k = session_finalize(s);
575 /* Kill XDG_RUNTIME_DIR */
576 k = user_remove_runtime_path(u);
580 /* Clean SysV + POSIX IPC objects */
581 if (u->manager->remove_ipc) {
582 k = clean_ipc(u->uid);
587 unlink(u->state_file);
588 user_add_to_gc_queue(u);
591 user_send_signal(u, false);
598 int user_get_idle_hint(User *u, dual_timestamp *t) {
600 bool idle_hint = true;
601 dual_timestamp ts = { 0, 0 };
605 LIST_FOREACH(sessions_by_user, s, u->sessions) {
609 ih = session_get_idle_hint(s, &k);
615 if (k.monotonic < ts.monotonic)
621 } else if (idle_hint) {
623 if (k.monotonic > ts.monotonic)
634 int user_check_linger_file(User *u) {
635 _cleanup_free_ char *cc = NULL;
638 cc = cescape(u->name);
642 p = strappenda("/var/lib/systemd/linger/", cc);
644 return access(p, F_OK) >= 0;
647 bool user_check_gc(User *u, bool drop_not_started) {
650 if (drop_not_started && !u->started)
656 if (user_check_linger_file(u) > 0)
659 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
662 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
668 void user_add_to_gc_queue(User *u) {
674 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
675 u->in_gc_queue = true;
678 UserState user_get_state(User *u) {
686 if (u->slice_job || u->service_job)
690 bool all_closing = true;
692 LIST_FOREACH(sessions_by_user, i, u->sessions) {
695 state = session_get_state(i);
696 if (state == SESSION_ACTIVE)
698 if (state != SESSION_CLOSING)
702 return all_closing ? USER_CLOSING : USER_ONLINE;
705 if (user_check_linger_file(u) > 0)
706 return USER_LINGERING;
711 int user_kill(User *u, int signo) {
717 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
720 void user_elect_display(User *u) {
721 Session *graphical = NULL, *text = NULL, *other = NULL, *s;
725 /* This elects a primary session for each user, which we call
726 * the "display". We try to keep the assignment stable, but we
727 * "upgrade" to better choices. */
729 LIST_FOREACH(sessions_by_user, s, u->sessions) {
731 if (s->class != SESSION_USER)
737 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
739 else if (s->type == SESSION_TTY)
747 u->display->class != SESSION_USER ||
748 u->display->stopping ||
749 !SESSION_TYPE_IS_GRAPHICAL(u->display->type))) {
750 u->display = graphical;
756 u->display->class != SESSION_USER ||
757 u->display->stopping ||
758 u->display->type != SESSION_TTY)) {
765 u->display->class != SESSION_USER ||
766 u->display->stopping))
770 static const char* const user_state_table[_USER_STATE_MAX] = {
771 [USER_OFFLINE] = "offline",
772 [USER_OPENING] = "opening",
773 [USER_LINGERING] = "lingering",
774 [USER_ONLINE] = "online",
775 [USER_ACTIVE] = "active",
776 [USER_CLOSING] = "closing"
779 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
781 int config_parse_tmpfs_size(
783 const char *filename,
786 unsigned section_line,
802 e = endswith(rvalue, "%");
808 ul = strtoul(rvalue, &f, 10);
809 if (errno != 0 || f != e) {
810 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
814 if (ul <= 0 || ul >= 100) {
815 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
819 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
823 r = parse_size(rvalue, 1024, &o);
824 if (r < 0 || (off_t) (size_t) o != o) {
825 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
829 *sz = PAGE_ALIGN((size_t) o);