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"
41 #include "formats-util.h"
43 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
53 u->name = strdup(name);
57 if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
60 if (hashmap_put(m->users, UID_TO_PTR(uid), u) < 0)
77 void user_free(User *u) {
81 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
84 session_free(u->sessions);
87 hashmap_remove(u->manager->user_units, u->slice);
92 hashmap_remove(u->manager->user_units, u->service);
99 free(u->runtime_path);
101 hashmap_remove(u->manager->users, UID_TO_PTR(u->uid));
108 int user_save(User *u) {
109 _cleanup_free_ char *temp_path = NULL;
110 _cleanup_fclose_ FILE *f = NULL;
114 assert(u->state_file);
119 r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
123 r = fopen_temporary(u->state_file, &f, &temp_path);
127 fchmod(fileno(f), 0644);
130 "# This is private data. Do not parse.\n"
134 user_state_to_string(user_get_state(u)));
137 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
140 fprintf(f, "SERVICE=%s\n", u->service);
142 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
145 fprintf(f, "SLICE=%s\n", u->slice);
147 fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
150 fprintf(f, "DISPLAY=%s\n", u->display->id);
152 if (dual_timestamp_is_set(&u->timestamp))
154 "REALTIME="USEC_FMT"\n"
155 "MONOTONIC="USEC_FMT"\n",
156 u->timestamp.realtime,
157 u->timestamp.monotonic);
163 fputs("SESSIONS=", f);
165 LIST_FOREACH(sessions_by_user, i, u->sessions) {
174 fputs("\nSEATS=", f);
176 LIST_FOREACH(sessions_by_user, i, u->sessions) {
185 fputs(i->seat->id, f);
188 fputs("\nACTIVE_SESSIONS=", f);
190 LIST_FOREACH(sessions_by_user, i, u->sessions) {
191 if (!session_is_active(i))
202 fputs("\nONLINE_SESSIONS=", f);
204 LIST_FOREACH(sessions_by_user, i, u->sessions) {
205 if (session_get_state(i) == SESSION_CLOSING)
216 fputs("\nACTIVE_SEATS=", f);
218 LIST_FOREACH(sessions_by_user, i, u->sessions) {
219 if (!session_is_active(i) || !i->seat)
227 fputs(i->seat->id, f);
230 fputs("\nONLINE_SEATS=", f);
232 LIST_FOREACH(sessions_by_user, i, u->sessions) {
233 if (session_get_state(i) == SESSION_CLOSING || !i->seat)
241 fputs(i->seat->id, f);
248 if (ferror(f) || rename(temp_path, u->state_file) < 0) {
250 unlink(u->state_file);
256 log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
261 int user_load(User *u) {
262 _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
268 r = parse_env_file(u->state_file, NEWLINE,
269 "RUNTIME", &u->runtime_path,
270 "SERVICE", &u->service,
271 "SERVICE_JOB", &u->service_job,
273 "SLICE_JOB", &u->slice_job,
275 "REALTIME", &realtime,
276 "MONOTONIC", &monotonic,
282 log_error_errno(r, "Failed to read %s: %m", u->state_file);
287 s = hashmap_get(u->manager->sessions, display);
289 if (s && s->display && display_is_local(s->display))
293 unsigned long long l;
294 if (sscanf(realtime, "%llu", &l) > 0)
295 u->timestamp.realtime = l;
299 unsigned long long l;
300 if (sscanf(monotonic, "%llu", &l) > 0)
301 u->timestamp.monotonic = l;
307 static int user_mkdir_runtime_path(User *u) {
313 r = mkdir_safe_label("/run/user", 0755, 0, 0);
315 return log_error_errno(r, "Failed to create /run/user: %m");
317 if (!u->runtime_path) {
318 if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
323 if (path_is_mount_point(p, 0) <= 0) {
324 _cleanup_free_ char *t = NULL;
326 (void) mkdir(p, 0700);
329 r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
331 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 if (errno != EPERM) {
340 r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", p);
344 /* Lacking permissions, maybe
345 * CAP_SYS_ADMIN-less container? In this case,
346 * just use a normal directory. */
348 r = chmod_and_chown(p, 0700, u->uid, u->gid);
350 log_error_errno(r, "Failed to change runtime directory ownership and mode: %m");
361 /* Try to clean up, but ignore errors */
366 u->runtime_path = NULL;
370 static int user_start_slice(User *u) {
377 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
378 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
379 sprintf(lu, UID_FMT, u->uid);
381 r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &slice);
385 r = manager_start_unit(u->manager, slice, &error, &job);
387 log_error("Failed to start user slice: %s", bus_error_message(&error, r));
398 hashmap_put(u->manager->user_units, u->slice, u);
403 static int user_start_service(User *u) {
404 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
411 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
412 sprintf(lu, UID_FMT, u->uid);
414 r = unit_name_build("user", lu, ".service", &service);
416 return log_error_errno(r, "Failed to build service name: %m");
418 r = manager_start_unit(u->manager, service, &error, &job);
420 log_error("Failed to start user service: %s", bus_error_message(&error, r));
423 u->service = service;
425 free(u->service_job);
426 u->service_job = job;
431 hashmap_put(u->manager->user_units, u->service, u);
436 int user_start(User *u) {
444 log_debug("New user %s logged in.", u->name);
446 /* Make XDG_RUNTIME_DIR */
447 r = user_mkdir_runtime_path(u);
452 r = user_start_slice(u);
456 /* Spawn user systemd */
457 r = user_start_service(u);
461 if (!dual_timestamp_is_set(&u->timestamp))
462 dual_timestamp_get(&u->timestamp);
466 /* Save new user data */
469 user_send_signal(u, true);
474 static int user_stop_slice(User *u) {
475 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
484 r = manager_stop_unit(u->manager, u->slice, &error, &job);
486 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
496 static int user_stop_service(User *u) {
497 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
506 r = manager_stop_unit(u->manager, u->service, &error, &job);
508 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
512 free(u->service_job);
513 u->service_job = job;
518 static int user_remove_runtime_path(User *u) {
523 if (!u->runtime_path)
526 r = rm_rf(u->runtime_path, 0);
528 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
530 /* Ignore cases where the directory isn't mounted, as that's
531 * quite possible, if we lacked the permissions to mount
533 r = umount2(u->runtime_path, MNT_DETACH);
534 if (r < 0 && errno != EINVAL && errno != ENOENT)
535 log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
537 r = rm_rf(u->runtime_path, REMOVE_ROOT);
539 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
541 free(u->runtime_path);
542 u->runtime_path = NULL;
547 int user_stop(User *u, bool force) {
552 /* Stop jobs have already been queued */
558 LIST_FOREACH(sessions_by_user, s, u->sessions) {
559 k = session_stop(s, force);
565 k = user_stop_service(u);
570 k = user_stop_slice(u);
581 int user_finalize(User *u) {
588 log_debug("User %s logged out.", u->name);
590 LIST_FOREACH(sessions_by_user, s, u->sessions) {
591 k = session_finalize(s);
596 /* Kill XDG_RUNTIME_DIR */
597 k = user_remove_runtime_path(u);
601 /* Clean SysV + POSIX IPC objects */
602 if (u->manager->remove_ipc) {
603 k = clean_ipc(u->uid);
608 unlink(u->state_file);
609 user_add_to_gc_queue(u);
612 user_send_signal(u, false);
619 int user_get_idle_hint(User *u, dual_timestamp *t) {
621 bool idle_hint = true;
622 dual_timestamp ts = { 0, 0 };
626 LIST_FOREACH(sessions_by_user, s, u->sessions) {
630 ih = session_get_idle_hint(s, &k);
636 if (k.monotonic < ts.monotonic)
642 } else if (idle_hint) {
644 if (k.monotonic > ts.monotonic)
655 int user_check_linger_file(User *u) {
656 _cleanup_free_ char *cc = NULL;
659 cc = cescape(u->name);
663 p = strjoina("/var/lib/systemd/linger/", cc);
665 return access(p, F_OK) >= 0;
668 bool user_check_gc(User *u, bool drop_not_started) {
671 if (drop_not_started && !u->started)
677 if (user_check_linger_file(u) > 0)
680 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
683 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
689 void user_add_to_gc_queue(User *u) {
695 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
696 u->in_gc_queue = true;
699 UserState user_get_state(User *u) {
707 if (u->slice_job || u->service_job)
711 bool all_closing = true;
713 LIST_FOREACH(sessions_by_user, i, u->sessions) {
716 state = session_get_state(i);
717 if (state == SESSION_ACTIVE)
719 if (state != SESSION_CLOSING)
723 return all_closing ? USER_CLOSING : USER_ONLINE;
726 if (user_check_linger_file(u) > 0)
727 return USER_LINGERING;
732 int user_kill(User *u, int signo) {
738 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
741 static bool elect_display_filter(Session *s) {
742 /* Return true if the session is a candidate for the user’s ‘primary
743 * session’ or ‘display’. */
746 return (s->class == SESSION_USER && !s->stopping);
749 static int elect_display_compare(Session *s1, Session *s2) {
750 /* Indexed by SessionType. Lower numbers mean more preferred. */
751 const int type_ranks[_SESSION_TYPE_MAX] = {
752 [SESSION_UNSPECIFIED] = 0,
755 [SESSION_WAYLAND] = -3,
760 /* Calculate the partial order relationship between s1 and s2,
761 * returning < 0 if s1 is preferred as the user’s ‘primary session’,
762 * 0 if s1 and s2 are equally preferred or incomparable, or > 0 if s2
765 * s1 or s2 may be NULL. */
769 if ((s1 == NULL) != (s2 == NULL))
770 return (s1 == NULL) - (s2 == NULL);
772 if (s1->stopping != s2->stopping)
773 return s1->stopping - s2->stopping;
775 if ((s1->class != SESSION_USER) != (s2->class != SESSION_USER))
776 return (s1->class != SESSION_USER) - (s2->class != SESSION_USER);
778 if ((s1->type == _SESSION_TYPE_INVALID) != (s2->type == _SESSION_TYPE_INVALID))
779 return (s1->type == _SESSION_TYPE_INVALID) - (s2->type == _SESSION_TYPE_INVALID);
781 if (s1->type != s2->type)
782 return type_ranks[s1->type] - type_ranks[s2->type];
787 void user_elect_display(User *u) {
792 /* This elects a primary session for each user, which we call
793 * the "display". We try to keep the assignment stable, but we
794 * "upgrade" to better choices. */
795 log_debug("Electing new display for user %s", u->name);
797 LIST_FOREACH(sessions_by_user, s, u->sessions) {
798 if (!elect_display_filter(s)) {
799 log_debug("Ignoring session %s", s->id);
803 if (elect_display_compare(s, u->display) < 0) {
804 log_debug("Choosing session %s in preference to %s", s->id, u->display ? u->display->id : "-");
810 static const char* const user_state_table[_USER_STATE_MAX] = {
811 [USER_OFFLINE] = "offline",
812 [USER_OPENING] = "opening",
813 [USER_LINGERING] = "lingering",
814 [USER_ONLINE] = "online",
815 [USER_ACTIVE] = "active",
816 [USER_CLOSING] = "closing"
819 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
821 int config_parse_tmpfs_size(
823 const char *filename,
826 unsigned section_line,
842 e = endswith(rvalue, "%");
848 ul = strtoul(rvalue, &f, 10);
849 if (errno != 0 || f != e) {
850 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
854 if (ul <= 0 || ul >= 100) {
855 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
859 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
863 r = parse_size(rvalue, 1024, &o);
864 if (r < 0 || (off_t) (size_t) o != o) {
865 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
869 *sz = PAGE_ALIGN((size_t) o);