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/>.
24 #include <sys/mount.h>
27 #include "alloc-util.h"
28 #include "bus-common-errors.h"
29 #include "bus-error.h"
31 #include "clean-ipc.h"
32 #include "conf-parser.h"
36 #include "formats-util.h"
40 #include "logind-user.h"
42 #include "mount-util.h"
43 #include "parse-util.h"
44 #include "path-util.h"
46 #include "smack-util.h"
47 //#include "special.h"
48 #include "stdio-util.h"
49 #include "string-table.h"
50 #include "unit-name.h"
51 #include "user-util.h"
54 int user_new(User **out, Manager *m, uid_t uid, gid_t gid, const char *name) {
55 _cleanup_(user_freep) User *u = NULL;
56 char lu[DECIMAL_STR_MAX(uid_t) + 1];
70 xsprintf(lu, UID_FMT, uid);
72 u->name = strdup(name);
76 if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
79 if (asprintf(&u->runtime_path, "/run/user/"UID_FMT, uid) < 0)
82 r = slice_build_subslice("user.slice", lu, &u->slice);
86 r = unit_name_build("user", lu, ".service", &u->service);
90 r = hashmap_put(m->users, UID_TO_PTR(uid), u);
94 r = hashmap_put(m->user_units, u->slice, u);
98 r = hashmap_put(m->user_units, u->service, u);
107 User *user_free(User *u) {
112 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
115 session_free(u->sessions);
118 hashmap_remove_value(u->manager->user_units, u->service, u);
121 hashmap_remove_value(u->manager->user_units, u->slice, u);
123 hashmap_remove_value(u->manager->users, UID_TO_PTR(u->uid), u);
125 #if 0 /// elogind neither supports slice nor service jobs.
126 u->slice_job = mfree(u->slice_job);
127 u->service_job = mfree(u->service_job);
129 u->service = mfree(u->service);
130 u->slice = mfree(u->slice);
131 u->runtime_path = mfree(u->runtime_path);
132 u->state_file = mfree(u->state_file);
133 u->name = mfree(u->name);
138 static int user_save_internal(User *u) {
139 _cleanup_free_ char *temp_path = NULL;
140 _cleanup_fclose_ FILE *f = NULL;
144 assert(u->state_file);
146 r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
150 r = fopen_temporary(u->state_file, &f, &temp_path);
154 fchmod(fileno(f), 0644);
157 "# This is private data. Do not parse.\n"
161 user_state_to_string(user_get_state(u)));
163 /* LEGACY: no-one reads RUNTIME= anymore, drop it at some point */
165 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
167 #if 0 /// elogind neither supports service nor slice jobs
169 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
172 fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
176 fprintf(f, "DISPLAY=%s\n", u->display->id);
178 if (dual_timestamp_is_set(&u->timestamp))
180 "REALTIME="USEC_FMT"\n"
181 "MONOTONIC="USEC_FMT"\n",
182 u->timestamp.realtime,
183 u->timestamp.monotonic);
189 fputs("SESSIONS=", f);
191 LIST_FOREACH(sessions_by_user, i, u->sessions) {
200 fputs("\nSEATS=", f);
202 LIST_FOREACH(sessions_by_user, i, u->sessions) {
211 fputs(i->seat->id, f);
214 fputs("\nACTIVE_SESSIONS=", f);
216 LIST_FOREACH(sessions_by_user, i, u->sessions) {
217 if (!session_is_active(i))
228 fputs("\nONLINE_SESSIONS=", f);
230 LIST_FOREACH(sessions_by_user, i, u->sessions) {
231 if (session_get_state(i) == SESSION_CLOSING)
242 fputs("\nACTIVE_SEATS=", f);
244 LIST_FOREACH(sessions_by_user, i, u->sessions) {
245 if (!session_is_active(i) || !i->seat)
253 fputs(i->seat->id, f);
256 fputs("\nONLINE_SEATS=", f);
258 LIST_FOREACH(sessions_by_user, i, u->sessions) {
259 if (session_get_state(i) == SESSION_CLOSING || !i->seat)
267 fputs(i->seat->id, f);
272 r = fflush_and_check(f);
276 if (rename(temp_path, u->state_file) < 0) {
284 (void) unlink(u->state_file);
287 (void) unlink(temp_path);
289 return log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
292 int user_save(User *u) {
298 return user_save_internal (u);
301 int user_load(User *u) {
302 _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
308 r = parse_env_file(u->state_file, NEWLINE,
309 #if 0 /// elogind neither supports service nor slice jobs
310 "SERVICE_JOB", &u->service_job,
311 "SLICE_JOB", &u->slice_job,
314 "REALTIME", &realtime,
315 "MONOTONIC", &monotonic,
321 log_error_errno(r, "Failed to read %s: %m", u->state_file);
326 s = hashmap_get(u->manager->sessions, display);
328 if (s && s->display && display_is_local(s->display))
332 unsigned long long l;
333 if (sscanf(realtime, "%llu", &l) > 0)
334 u->timestamp.realtime = l;
338 unsigned long long l;
339 if (sscanf(monotonic, "%llu", &l) > 0)
340 u->timestamp.monotonic = l;
346 static int user_mkdir_runtime_path(User *u) {
351 r = mkdir_safe_label("/run/user", 0755, 0, 0);
353 return log_error_errno(r, "Failed to create /run/user: %m");
355 if (path_is_mount_point(u->runtime_path, 0) <= 0) {
356 _cleanup_free_ char *t = NULL;
358 (void) mkdir_label(u->runtime_path, 0700);
361 r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
363 r = asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
369 r = mount("tmpfs", u->runtime_path, "tmpfs", MS_NODEV|MS_NOSUID, t);
371 if (errno != EPERM) {
372 r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", u->runtime_path);
376 /* Lacking permissions, maybe
377 * CAP_SYS_ADMIN-less container? In this case,
378 * just use a normal directory. */
380 r = chmod_and_chown(u->runtime_path, 0700, u->uid, u->gid);
382 log_error_errno(r, "Failed to change runtime directory ownership and mode: %m");
387 r = label_fix(u->runtime_path, false, false);
389 log_warning_errno(r, "Failed to fix label of '%s', ignoring: %m", u->runtime_path);
395 /* Try to clean up, but ignore errors */
396 (void) rmdir(u->runtime_path);
400 static int user_start_slice(User *u) {
401 #if 0 /// elogind can not ask systemd via dbus to start user services
402 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
403 const char *description;
409 u->slice_job = mfree(u->slice_job);
410 description = strjoina("User Slice of ", u->name);
412 r = manager_start_slice(
416 "systemd-logind.service",
417 "systemd-user-sessions.service",
418 u->manager->user_tasks_max,
422 /* we don't fail due to this, let's try to continue */
423 if (!sd_bus_error_has_name(&error, BUS_ERROR_UNIT_EXISTS))
424 log_error_errno(r, "Failed to start user slice %s, ignoring: %s (%s)", u->slice, bus_error_message(&error, r), error.name);
431 hashmap_put(u->manager->user_units, u->slice, u);
437 static int user_start_service(User *u) {
438 #if 0 /// elogind can not ask systemd via dbus to start user services
439 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
445 u->service_job = mfree(u->service_job);
447 r = manager_start_unit(
453 /* we don't fail due to this, let's try to continue */
454 log_error_errno(r, "Failed to start user service, ignoring: %s", bus_error_message(&error, r));
456 u->service_job = job;
461 hashmap_put(u->manager->user_units, u->service, u);
467 int user_start(User *u) {
472 if (u->started && !u->stopping)
476 * If u->stopping is set, the user is marked for removal and the slice
477 * and service stop-jobs are queued. We have to clear that flag before
478 * queing the start-jobs again. If they succeed, the user object can be
479 * re-used just fine (pid1 takes care of job-ordering and proper
480 * restart), but if they fail, we want to force another user_stop() so
481 * possibly pending units are stopped.
482 * Note that we don't clear u->started, as we have no clue what state
483 * the user is in on failure here. Hence, we pretend the user is
484 * running so it will be properly taken down by GC. However, we clearly
485 * return an error from user_start() in that case, so no further
486 * reference to the user is taken.
491 log_debug("New user %s logged in.", u->name);
493 /* Make XDG_RUNTIME_DIR */
494 r = user_mkdir_runtime_path(u);
500 r = user_start_slice(u);
504 /* Save the user data so far, because pam_systemd will read the
505 * XDG_RUNTIME_DIR out of it while starting up systemd --user.
506 * We need to do user_save_internal() because we have not
507 * "officially" started yet. */
508 user_save_internal(u);
510 /* Spawn user systemd */
511 r = user_start_service(u);
516 if (!dual_timestamp_is_set(&u->timestamp))
517 dual_timestamp_get(&u->timestamp);
518 user_send_signal(u, true);
522 /* Save new user data */
528 #if 0 /// UNNEEDED by elogind
529 static int user_stop_slice(User *u) {
530 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
536 r = manager_stop_unit(u->manager, u->slice, &error, &job);
538 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
548 static int user_stop_service(User *u) {
549 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
555 r = manager_stop_unit(u->manager, u->service, &error, &job);
557 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
561 free(u->service_job);
562 u->service_job = job;
568 static int user_remove_runtime_path(User *u) {
573 r = rm_rf(u->runtime_path, 0);
575 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
577 /* Ignore cases where the directory isn't mounted, as that's
578 * quite possible, if we lacked the permissions to mount
580 r = umount2(u->runtime_path, MNT_DETACH);
581 if (r < 0 && errno != EINVAL && errno != ENOENT)
582 log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
584 r = rm_rf(u->runtime_path, REMOVE_ROOT);
586 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
591 int user_stop(User *u, bool force) {
596 /* Stop jobs have already been queued */
602 LIST_FOREACH(sessions_by_user, s, u->sessions) {
603 k = session_stop(s, force);
609 #if 0 /// elogind does not support service or slice jobs
610 k = user_stop_service(u);
615 k = user_stop_slice(u);
627 int user_finalize(User *u) {
634 log_debug("User %s logged out.", u->name);
636 LIST_FOREACH(sessions_by_user, s, u->sessions) {
637 k = session_finalize(s);
642 /* Kill XDG_RUNTIME_DIR */
643 k = user_remove_runtime_path(u);
647 /* Clean SysV + POSIX IPC objects */
648 if (u->manager->remove_ipc) {
649 k = clean_ipc(u->uid);
654 unlink(u->state_file);
655 user_add_to_gc_queue(u);
658 user_send_signal(u, false);
665 int user_get_idle_hint(User *u, dual_timestamp *t) {
667 bool idle_hint = true;
668 dual_timestamp ts = DUAL_TIMESTAMP_NULL;
672 LIST_FOREACH(sessions_by_user, s, u->sessions) {
676 ih = session_get_idle_hint(s, &k);
682 if (k.monotonic < ts.monotonic)
688 } else if (idle_hint) {
690 if (k.monotonic > ts.monotonic)
701 int user_check_linger_file(User *u) {
702 _cleanup_free_ char *cc = NULL;
705 cc = cescape(u->name);
709 p = strjoina("/var/lib/systemd/linger/", cc);
711 return access(p, F_OK) >= 0;
714 bool user_check_gc(User *u, bool drop_not_started) {
717 if (drop_not_started && !u->started)
723 if (user_check_linger_file(u) > 0)
726 #if 0 /// elogind neither supports service nor slice jobs
727 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
730 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
737 void user_add_to_gc_queue(User *u) {
743 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
744 u->in_gc_queue = true;
747 UserState user_get_state(User *u) {
755 #if 0 /// elogind neither supports service nor slice jobs.
756 if (!u->started || u->slice_job || u->service_job)
763 bool all_closing = true;
765 LIST_FOREACH(sessions_by_user, i, u->sessions) {
768 state = session_get_state(i);
769 if (state == SESSION_ACTIVE)
771 if (state != SESSION_CLOSING)
775 return all_closing ? USER_CLOSING : USER_ONLINE;
778 if (user_check_linger_file(u) > 0)
779 return USER_LINGERING;
784 int user_kill(User *u, int signo) {
785 #if 0 /// Without systemd unit support, elogind has to rely on its session system
788 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
795 LIST_FOREACH(sessions_by_user, s, u->sessions) {
796 int r = session_kill(s, KILL_ALL, signo);
797 if (res == 0 && r < 0)
805 static bool elect_display_filter(Session *s) {
806 /* Return true if the session is a candidate for the user’s ‘primary
807 * session’ or ‘display’. */
810 return (s->class == SESSION_USER && !s->stopping);
813 static int elect_display_compare(Session *s1, Session *s2) {
814 /* Indexed by SessionType. Lower numbers mean more preferred. */
815 const int type_ranks[_SESSION_TYPE_MAX] = {
816 [SESSION_UNSPECIFIED] = 0,
819 [SESSION_WAYLAND] = -3,
824 /* Calculate the partial order relationship between s1 and s2,
825 * returning < 0 if s1 is preferred as the user’s ‘primary session’,
826 * 0 if s1 and s2 are equally preferred or incomparable, or > 0 if s2
829 * s1 or s2 may be NULL. */
833 if ((s1 == NULL) != (s2 == NULL))
834 return (s1 == NULL) - (s2 == NULL);
836 if (s1->stopping != s2->stopping)
837 return s1->stopping - s2->stopping;
839 if ((s1->class != SESSION_USER) != (s2->class != SESSION_USER))
840 return (s1->class != SESSION_USER) - (s2->class != SESSION_USER);
842 if ((s1->type == _SESSION_TYPE_INVALID) != (s2->type == _SESSION_TYPE_INVALID))
843 return (s1->type == _SESSION_TYPE_INVALID) - (s2->type == _SESSION_TYPE_INVALID);
845 if (s1->type != s2->type)
846 return type_ranks[s1->type] - type_ranks[s2->type];
851 void user_elect_display(User *u) {
856 /* This elects a primary session for each user, which we call
857 * the "display". We try to keep the assignment stable, but we
858 * "upgrade" to better choices. */
859 log_debug("Electing new display for user %s", u->name);
861 LIST_FOREACH(sessions_by_user, s, u->sessions) {
862 if (!elect_display_filter(s)) {
863 log_debug("Ignoring session %s", s->id);
867 if (elect_display_compare(s, u->display) < 0) {
868 log_debug("Choosing session %s in preference to %s", s->id, u->display ? u->display->id : "-");
874 static const char* const user_state_table[_USER_STATE_MAX] = {
875 [USER_OFFLINE] = "offline",
876 [USER_OPENING] = "opening",
877 [USER_LINGERING] = "lingering",
878 [USER_ONLINE] = "online",
879 [USER_ACTIVE] = "active",
880 [USER_CLOSING] = "closing"
883 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
885 int config_parse_tmpfs_size(
887 const char *filename,
890 unsigned section_line,
906 e = endswith(rvalue, "%");
912 ul = strtoul(rvalue, &f, 10);
913 if (errno != 0 || f != e) {
914 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse percentage value, ignoring: %s", rvalue);
918 if (ul <= 0 || ul >= 100) {
919 log_syntax(unit, LOG_ERR, filename, line, 0, "Percentage value out of range, ignoring: %s", rvalue);
923 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
927 r = parse_size(rvalue, 1024, &k);
928 if (r < 0 || (uint64_t) (size_t) k != k) {
929 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
933 *sz = PAGE_ALIGN((size_t) k);