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 "smack-util.h"
40 #include "formats-util.h"
42 #include "logind-user.h"
44 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
54 u->name = strdup(name);
58 if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
61 if (hashmap_put(m->users, UID_TO_PTR(uid), u) < 0)
78 void user_free(User *u) {
82 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
85 session_free(u->sessions);
88 hashmap_remove(u->manager->user_units, u->slice);
93 hashmap_remove(u->manager->user_units, u->service);
100 free(u->runtime_path);
102 hashmap_remove(u->manager->users, UID_TO_PTR(u->uid));
109 int user_save(User *u) {
110 _cleanup_free_ char *temp_path = NULL;
111 _cleanup_fclose_ FILE *f = NULL;
115 assert(u->state_file);
120 r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
124 r = fopen_temporary(u->state_file, &f, &temp_path);
128 fchmod(fileno(f), 0644);
131 "# This is private data. Do not parse.\n"
135 user_state_to_string(user_get_state(u)));
138 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
141 fprintf(f, "SERVICE=%s\n", u->service);
143 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
146 fprintf(f, "SLICE=%s\n", u->slice);
148 fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
151 fprintf(f, "DISPLAY=%s\n", u->display->id);
153 if (dual_timestamp_is_set(&u->timestamp))
155 "REALTIME="USEC_FMT"\n"
156 "MONOTONIC="USEC_FMT"\n",
157 u->timestamp.realtime,
158 u->timestamp.monotonic);
164 fputs("SESSIONS=", f);
166 LIST_FOREACH(sessions_by_user, i, u->sessions) {
175 fputs("\nSEATS=", f);
177 LIST_FOREACH(sessions_by_user, i, u->sessions) {
186 fputs(i->seat->id, f);
189 fputs("\nACTIVE_SESSIONS=", f);
191 LIST_FOREACH(sessions_by_user, i, u->sessions) {
192 if (!session_is_active(i))
203 fputs("\nONLINE_SESSIONS=", f);
205 LIST_FOREACH(sessions_by_user, i, u->sessions) {
206 if (session_get_state(i) == SESSION_CLOSING)
217 fputs("\nACTIVE_SEATS=", f);
219 LIST_FOREACH(sessions_by_user, i, u->sessions) {
220 if (!session_is_active(i) || !i->seat)
228 fputs(i->seat->id, f);
231 fputs("\nONLINE_SEATS=", f);
233 LIST_FOREACH(sessions_by_user, i, u->sessions) {
234 if (session_get_state(i) == SESSION_CLOSING || !i->seat)
242 fputs(i->seat->id, f);
249 if (ferror(f) || rename(temp_path, u->state_file) < 0) {
251 unlink(u->state_file);
257 log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
262 int user_load(User *u) {
263 _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
269 r = parse_env_file(u->state_file, NEWLINE,
270 "RUNTIME", &u->runtime_path,
271 "SERVICE", &u->service,
272 "SERVICE_JOB", &u->service_job,
274 "SLICE_JOB", &u->slice_job,
276 "REALTIME", &realtime,
277 "MONOTONIC", &monotonic,
283 log_error_errno(r, "Failed to read %s: %m", u->state_file);
288 s = hashmap_get(u->manager->sessions, display);
290 if (s && s->display && display_is_local(s->display))
294 unsigned long long l;
295 if (sscanf(realtime, "%llu", &l) > 0)
296 u->timestamp.realtime = l;
300 unsigned long long l;
301 if (sscanf(monotonic, "%llu", &l) > 0)
302 u->timestamp.monotonic = l;
308 static int user_mkdir_runtime_path(User *u) {
314 r = mkdir_safe_label("/run/user", 0755, 0, 0);
316 return log_error_errno(r, "Failed to create /run/user: %m");
318 if (!u->runtime_path) {
319 if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
324 if (path_is_mount_point(p, 0) <= 0) {
325 _cleanup_free_ char *t = NULL;
327 (void) mkdir_label(p, 0700);
330 r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
332 r = asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
338 r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
340 if (errno != EPERM) {
341 r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", p);
345 /* Lacking permissions, maybe
346 * CAP_SYS_ADMIN-less container? In this case,
347 * just use a normal directory. */
349 r = chmod_and_chown(p, 0700, u->uid, u->gid);
351 log_error_errno(r, "Failed to change runtime directory ownership and mode: %m");
356 r = label_fix(p, false, false);
358 log_warning_errno(r, "Failed to fix label of '%s', ignoring: %m", p);
366 /* Try to clean up, but ignore errors */
371 u->runtime_path = NULL;
375 static int user_start_slice(User *u) {
382 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
383 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
384 sprintf(lu, UID_FMT, u->uid);
386 r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &slice);
390 r = manager_start_unit(u->manager, slice, &error, &job);
392 log_error("Failed to start user slice: %s", bus_error_message(&error, r));
403 hashmap_put(u->manager->user_units, u->slice, u);
408 static int user_start_service(User *u) {
409 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
416 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
417 sprintf(lu, UID_FMT, u->uid);
419 r = unit_name_build("user", lu, ".service", &service);
421 return log_error_errno(r, "Failed to build service name: %m");
423 r = manager_start_unit(u->manager, service, &error, &job);
425 log_error("Failed to start user service: %s", bus_error_message(&error, r));
428 u->service = service;
430 free(u->service_job);
431 u->service_job = job;
436 hashmap_put(u->manager->user_units, u->service, u);
441 int user_start(User *u) {
449 log_debug("New user %s logged in.", u->name);
451 /* Make XDG_RUNTIME_DIR */
452 r = user_mkdir_runtime_path(u);
457 r = user_start_slice(u);
461 /* Spawn user systemd */
462 r = user_start_service(u);
466 if (!dual_timestamp_is_set(&u->timestamp))
467 dual_timestamp_get(&u->timestamp);
471 /* Save new user data */
474 user_send_signal(u, true);
479 static int user_stop_slice(User *u) {
480 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
489 r = manager_stop_unit(u->manager, u->slice, &error, &job);
491 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
501 static int user_stop_service(User *u) {
502 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
511 r = manager_stop_unit(u->manager, u->service, &error, &job);
513 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
517 free(u->service_job);
518 u->service_job = job;
523 static int user_remove_runtime_path(User *u) {
528 if (!u->runtime_path)
531 r = rm_rf(u->runtime_path, 0);
533 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
535 /* Ignore cases where the directory isn't mounted, as that's
536 * quite possible, if we lacked the permissions to mount
538 r = umount2(u->runtime_path, MNT_DETACH);
539 if (r < 0 && errno != EINVAL && errno != ENOENT)
540 log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
542 r = rm_rf(u->runtime_path, REMOVE_ROOT);
544 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
546 free(u->runtime_path);
547 u->runtime_path = NULL;
552 int user_stop(User *u, bool force) {
557 /* Stop jobs have already been queued */
563 LIST_FOREACH(sessions_by_user, s, u->sessions) {
564 k = session_stop(s, force);
570 k = user_stop_service(u);
575 k = user_stop_slice(u);
586 int user_finalize(User *u) {
593 log_debug("User %s logged out.", u->name);
595 LIST_FOREACH(sessions_by_user, s, u->sessions) {
596 k = session_finalize(s);
601 /* Kill XDG_RUNTIME_DIR */
602 k = user_remove_runtime_path(u);
606 /* Clean SysV + POSIX IPC objects */
607 if (u->manager->remove_ipc) {
608 k = clean_ipc(u->uid);
613 unlink(u->state_file);
614 user_add_to_gc_queue(u);
617 user_send_signal(u, false);
624 int user_get_idle_hint(User *u, dual_timestamp *t) {
626 bool idle_hint = true;
627 dual_timestamp ts = DUAL_TIMESTAMP_NULL;
631 LIST_FOREACH(sessions_by_user, s, u->sessions) {
635 ih = session_get_idle_hint(s, &k);
641 if (k.monotonic < ts.monotonic)
647 } else if (idle_hint) {
649 if (k.monotonic > ts.monotonic)
660 int user_check_linger_file(User *u) {
661 _cleanup_free_ char *cc = NULL;
664 cc = cescape(u->name);
668 p = strjoina("/var/lib/systemd/linger/", cc);
670 return access(p, F_OK) >= 0;
673 bool user_check_gc(User *u, bool drop_not_started) {
676 if (drop_not_started && !u->started)
682 if (user_check_linger_file(u) > 0)
685 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
688 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
694 void user_add_to_gc_queue(User *u) {
700 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
701 u->in_gc_queue = true;
704 UserState user_get_state(User *u) {
712 if (u->slice_job || u->service_job)
716 bool all_closing = true;
718 LIST_FOREACH(sessions_by_user, i, u->sessions) {
721 state = session_get_state(i);
722 if (state == SESSION_ACTIVE)
724 if (state != SESSION_CLOSING)
728 return all_closing ? USER_CLOSING : USER_ONLINE;
731 if (user_check_linger_file(u) > 0)
732 return USER_LINGERING;
737 int user_kill(User *u, int signo) {
743 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
746 static bool elect_display_filter(Session *s) {
747 /* Return true if the session is a candidate for the user’s ‘primary
748 * session’ or ‘display’. */
751 return (s->class == SESSION_USER && !s->stopping);
754 static int elect_display_compare(Session *s1, Session *s2) {
755 /* Indexed by SessionType. Lower numbers mean more preferred. */
756 const int type_ranks[_SESSION_TYPE_MAX] = {
757 [SESSION_UNSPECIFIED] = 0,
760 [SESSION_WAYLAND] = -3,
765 /* Calculate the partial order relationship between s1 and s2,
766 * returning < 0 if s1 is preferred as the user’s ‘primary session’,
767 * 0 if s1 and s2 are equally preferred or incomparable, or > 0 if s2
770 * s1 or s2 may be NULL. */
774 if ((s1 == NULL) != (s2 == NULL))
775 return (s1 == NULL) - (s2 == NULL);
777 if (s1->stopping != s2->stopping)
778 return s1->stopping - s2->stopping;
780 if ((s1->class != SESSION_USER) != (s2->class != SESSION_USER))
781 return (s1->class != SESSION_USER) - (s2->class != SESSION_USER);
783 if ((s1->type == _SESSION_TYPE_INVALID) != (s2->type == _SESSION_TYPE_INVALID))
784 return (s1->type == _SESSION_TYPE_INVALID) - (s2->type == _SESSION_TYPE_INVALID);
786 if (s1->type != s2->type)
787 return type_ranks[s1->type] - type_ranks[s2->type];
792 void user_elect_display(User *u) {
797 /* This elects a primary session for each user, which we call
798 * the "display". We try to keep the assignment stable, but we
799 * "upgrade" to better choices. */
800 log_debug("Electing new display for user %s", u->name);
802 LIST_FOREACH(sessions_by_user, s, u->sessions) {
803 if (!elect_display_filter(s)) {
804 log_debug("Ignoring session %s", s->id);
808 if (elect_display_compare(s, u->display) < 0) {
809 log_debug("Choosing session %s in preference to %s", s->id, u->display ? u->display->id : "-");
815 static const char* const user_state_table[_USER_STATE_MAX] = {
816 [USER_OFFLINE] = "offline",
817 [USER_OPENING] = "opening",
818 [USER_LINGERING] = "lingering",
819 [USER_ONLINE] = "online",
820 [USER_ACTIVE] = "active",
821 [USER_CLOSING] = "closing"
824 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
826 int config_parse_tmpfs_size(
828 const char *filename,
831 unsigned section_line,
847 e = endswith(rvalue, "%");
853 ul = strtoul(rvalue, &f, 10);
854 if (errno != 0 || f != e) {
855 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
859 if (ul <= 0 || ul >= 100) {
860 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
864 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
868 r = parse_size(rvalue, 1024, &o);
869 if (r < 0 || (off_t) (size_t) o != o) {
870 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
874 *sz = PAGE_ALIGN((size_t) o);