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>
31 #include "path-util.h"
33 #include "unit-name.h"
35 #include "bus-error.h"
36 #include "conf-parser.h"
37 #include "clean-ipc.h"
38 #include "logind-user.h"
39 #include "smack-util.h"
41 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
51 u->name = strdup(name);
55 if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
58 if (hashmap_put(m->users, UID_TO_PTR(uid), u) < 0)
75 void user_free(User *u) {
79 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
82 session_free(u->sessions);
85 hashmap_remove(u->manager->user_units, u->slice);
90 hashmap_remove(u->manager->user_units, u->service);
97 free(u->runtime_path);
99 hashmap_remove(u->manager->users, UID_TO_PTR(u->uid));
106 int user_save(User *u) {
107 _cleanup_free_ char *temp_path = NULL;
108 _cleanup_fclose_ FILE *f = NULL;
112 assert(u->state_file);
117 r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
121 r = fopen_temporary(u->state_file, &f, &temp_path);
125 fchmod(fileno(f), 0644);
128 "# This is private data. Do not parse.\n"
132 user_state_to_string(user_get_state(u)));
135 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
138 fprintf(f, "SERVICE=%s\n", u->service);
140 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
143 fprintf(f, "SLICE=%s\n", u->slice);
145 fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
148 fprintf(f, "DISPLAY=%s\n", u->display->id);
150 if (dual_timestamp_is_set(&u->timestamp))
152 "REALTIME="USEC_FMT"\n"
153 "MONOTONIC="USEC_FMT"\n",
154 u->timestamp.realtime,
155 u->timestamp.monotonic);
161 fputs("SESSIONS=", f);
163 LIST_FOREACH(sessions_by_user, i, u->sessions) {
172 fputs("\nSEATS=", f);
174 LIST_FOREACH(sessions_by_user, i, u->sessions) {
183 fputs(i->seat->id, f);
186 fputs("\nACTIVE_SESSIONS=", f);
188 LIST_FOREACH(sessions_by_user, i, u->sessions) {
189 if (!session_is_active(i))
200 fputs("\nONLINE_SESSIONS=", f);
202 LIST_FOREACH(sessions_by_user, i, u->sessions) {
203 if (session_get_state(i) == SESSION_CLOSING)
214 fputs("\nACTIVE_SEATS=", f);
216 LIST_FOREACH(sessions_by_user, i, u->sessions) {
217 if (!session_is_active(i) || !i->seat)
225 fputs(i->seat->id, f);
228 fputs("\nONLINE_SEATS=", f);
230 LIST_FOREACH(sessions_by_user, i, u->sessions) {
231 if (session_get_state(i) == SESSION_CLOSING || !i->seat)
239 fputs(i->seat->id, f);
246 if (ferror(f) || rename(temp_path, u->state_file) < 0) {
248 unlink(u->state_file);
254 log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
259 int user_load(User *u) {
260 _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
266 r = parse_env_file(u->state_file, NEWLINE,
267 "RUNTIME", &u->runtime_path,
268 "SERVICE", &u->service,
269 "SERVICE_JOB", &u->service_job,
271 "SLICE_JOB", &u->slice_job,
273 "REALTIME", &realtime,
274 "MONOTONIC", &monotonic,
280 log_error_errno(r, "Failed to read %s: %m", u->state_file);
285 s = hashmap_get(u->manager->sessions, display);
287 if (s && s->display && display_is_local(s->display))
291 unsigned long long l;
292 if (sscanf(realtime, "%llu", &l) > 0)
293 u->timestamp.realtime = l;
297 unsigned long long l;
298 if (sscanf(monotonic, "%llu", &l) > 0)
299 u->timestamp.monotonic = l;
305 static int user_mkdir_runtime_path(User *u) {
311 r = mkdir_safe_label("/run/user", 0755, 0, 0);
313 return log_error_errno(r, "Failed to create /run/user: %m");
315 if (!u->runtime_path) {
316 if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
321 if (path_is_mount_point(p, false) <= 0) {
322 _cleanup_free_ char *t = NULL;
324 (void) mkdir(p, 0700);
327 r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
329 r = asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
335 r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
337 if (errno != EPERM) {
338 r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", p);
342 /* Lacking permissions, maybe
343 * CAP_SYS_ADMIN-less container? In this case,
344 * just use a normal directory. */
346 r = chmod_and_chown(p, 0700, u->uid, u->gid);
348 log_error_errno(r, "Failed to change runtime directory ownership and mode: %m");
359 /* Try to clean up, but ignore errors */
364 u->runtime_path = NULL;
368 static int user_start_slice(User *u) {
375 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
376 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
377 sprintf(lu, UID_FMT, u->uid);
379 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
383 r = manager_start_unit(u->manager, slice, &error, &job);
385 log_error("Failed to start user slice: %s", bus_error_message(&error, r));
396 hashmap_put(u->manager->user_units, u->slice, u);
401 static int user_start_service(User *u) {
402 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
409 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
410 sprintf(lu, UID_FMT, u->uid);
412 service = unit_name_build("user", lu, ".service");
416 r = manager_start_unit(u->manager, service, &error, &job);
418 log_error("Failed to start user service: %s", bus_error_message(&error, r));
421 u->service = service;
423 free(u->service_job);
424 u->service_job = job;
429 hashmap_put(u->manager->user_units, u->service, u);
434 int user_start(User *u) {
442 log_debug("New user %s logged in.", u->name);
444 /* Make XDG_RUNTIME_DIR */
445 r = user_mkdir_runtime_path(u);
450 r = user_start_slice(u);
454 /* Spawn user systemd */
455 r = user_start_service(u);
459 if (!dual_timestamp_is_set(&u->timestamp))
460 dual_timestamp_get(&u->timestamp);
464 /* Save new user data */
467 user_send_signal(u, true);
472 static int user_stop_slice(User *u) {
473 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
482 r = manager_stop_unit(u->manager, u->slice, &error, &job);
484 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
494 static int user_stop_service(User *u) {
495 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
504 r = manager_stop_unit(u->manager, u->service, &error, &job);
506 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
510 free(u->service_job);
511 u->service_job = job;
516 static int user_remove_runtime_path(User *u) {
521 if (!u->runtime_path)
524 r = rm_rf(u->runtime_path, false, false, false);
526 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
528 /* Ignore cases where the directory isn't mounted, as that's
529 * quite possible, if we lacked the permissions to mount
531 r = umount2(u->runtime_path, MNT_DETACH);
532 if (r < 0 && errno != EINVAL && errno != ENOENT)
533 log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
535 r = rm_rf(u->runtime_path, false, true, false);
537 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
539 free(u->runtime_path);
540 u->runtime_path = NULL;
545 int user_stop(User *u, bool force) {
550 /* Stop jobs have already been queued */
556 LIST_FOREACH(sessions_by_user, s, u->sessions) {
557 k = session_stop(s, force);
563 k = user_stop_service(u);
568 k = user_stop_slice(u);
579 int user_finalize(User *u) {
586 log_debug("User %s logged out.", u->name);
588 LIST_FOREACH(sessions_by_user, s, u->sessions) {
589 k = session_finalize(s);
594 /* Kill XDG_RUNTIME_DIR */
595 k = user_remove_runtime_path(u);
599 /* Clean SysV + POSIX IPC objects */
600 if (u->manager->remove_ipc) {
601 k = clean_ipc(u->uid);
606 unlink(u->state_file);
607 user_add_to_gc_queue(u);
610 user_send_signal(u, false);
617 int user_get_idle_hint(User *u, dual_timestamp *t) {
619 bool idle_hint = true;
620 dual_timestamp ts = { 0, 0 };
624 LIST_FOREACH(sessions_by_user, s, u->sessions) {
628 ih = session_get_idle_hint(s, &k);
634 if (k.monotonic < ts.monotonic)
640 } else if (idle_hint) {
642 if (k.monotonic > ts.monotonic)
653 int user_check_linger_file(User *u) {
654 _cleanup_free_ char *cc = NULL;
657 cc = cescape(u->name);
661 p = strjoina("/var/lib/systemd/linger/", cc);
663 return access(p, F_OK) >= 0;
666 bool user_check_gc(User *u, bool drop_not_started) {
669 if (drop_not_started && !u->started)
675 if (user_check_linger_file(u) > 0)
678 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
681 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
687 void user_add_to_gc_queue(User *u) {
693 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
694 u->in_gc_queue = true;
697 UserState user_get_state(User *u) {
705 if (u->slice_job || u->service_job)
709 bool all_closing = true;
711 LIST_FOREACH(sessions_by_user, i, u->sessions) {
714 state = session_get_state(i);
715 if (state == SESSION_ACTIVE)
717 if (state != SESSION_CLOSING)
721 return all_closing ? USER_CLOSING : USER_ONLINE;
724 if (user_check_linger_file(u) > 0)
725 return USER_LINGERING;
730 int user_kill(User *u, int signo) {
736 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
739 void user_elect_display(User *u) {
740 Session *graphical = NULL, *text = NULL, *other = NULL, *s;
744 /* This elects a primary session for each user, which we call
745 * the "display". We try to keep the assignment stable, but we
746 * "upgrade" to better choices. */
748 LIST_FOREACH(sessions_by_user, s, u->sessions) {
750 if (s->class != SESSION_USER)
756 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
758 else if (s->type == SESSION_TTY)
766 u->display->class != SESSION_USER ||
767 u->display->stopping ||
768 !SESSION_TYPE_IS_GRAPHICAL(u->display->type))) {
769 u->display = graphical;
775 u->display->class != SESSION_USER ||
776 u->display->stopping ||
777 u->display->type != SESSION_TTY)) {
784 u->display->class != SESSION_USER ||
785 u->display->stopping))
789 static const char* const user_state_table[_USER_STATE_MAX] = {
790 [USER_OFFLINE] = "offline",
791 [USER_OPENING] = "opening",
792 [USER_LINGERING] = "lingering",
793 [USER_ONLINE] = "online",
794 [USER_ACTIVE] = "active",
795 [USER_CLOSING] = "closing"
798 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
800 int config_parse_tmpfs_size(
802 const char *filename,
805 unsigned section_line,
821 e = endswith(rvalue, "%");
827 ul = strtoul(rvalue, &f, 10);
828 if (errno != 0 || f != e) {
829 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
833 if (ul <= 0 || ul >= 100) {
834 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
838 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
842 r = parse_size(rvalue, 1024, &o);
843 if (r < 0 || (off_t) (size_t) o != o) {
844 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
848 *sz = PAGE_ALIGN((size_t) o);