]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-user.c
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"
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(SPECIAL_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 u
->slice_job
= mfree(u
->slice_job
);
126 u
->service_job
= mfree(u
->service_job
);
128 u
->service
= mfree(u
->service
);
129 u
->slice
= mfree(u
->slice
);
130 u
->runtime_path
= mfree(u
->runtime_path
);
131 u
->state_file
= mfree(u
->state_file
);
132 u
->name
= mfree(u
->name
);
137 static int user_save_internal(User
*u
) {
138 _cleanup_free_
char *temp_path
= NULL
;
139 _cleanup_fclose_
FILE *f
= NULL
;
143 assert(u
->state_file
);
145 r
= mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
149 r
= fopen_temporary(u
->state_file
, &f
, &temp_path
);
153 fchmod(fileno(f
), 0644);
156 "# This is private data. Do not parse.\n"
160 user_state_to_string(user_get_state(u
)));
162 /* LEGACY: no-one reads RUNTIME= anymore, drop it at some point */
164 fprintf(f
, "RUNTIME=%s\n", u
->runtime_path
);
167 fprintf(f
, "SERVICE_JOB=%s\n", u
->service_job
);
170 fprintf(f
, "SLICE_JOB=%s\n", u
->slice_job
);
173 fprintf(f
, "DISPLAY=%s\n", u
->display
->id
);
175 if (dual_timestamp_is_set(&u
->timestamp
))
177 "REALTIME="USEC_FMT
"\n"
178 "MONOTONIC="USEC_FMT
"\n",
179 u
->timestamp
.realtime
,
180 u
->timestamp
.monotonic
);
186 fputs("SESSIONS=", f
);
188 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
197 fputs("\nSEATS=", f
);
199 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
208 fputs(i
->seat
->id
, f
);
211 fputs("\nACTIVE_SESSIONS=", f
);
213 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
214 if (!session_is_active(i
))
225 fputs("\nONLINE_SESSIONS=", f
);
227 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
228 if (session_get_state(i
) == SESSION_CLOSING
)
239 fputs("\nACTIVE_SEATS=", f
);
241 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
242 if (!session_is_active(i
) || !i
->seat
)
250 fputs(i
->seat
->id
, f
);
253 fputs("\nONLINE_SEATS=", f
);
255 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
256 if (session_get_state(i
) == SESSION_CLOSING
|| !i
->seat
)
264 fputs(i
->seat
->id
, f
);
269 r
= fflush_and_check(f
);
273 if (rename(temp_path
, u
->state_file
) < 0) {
281 (void) unlink(u
->state_file
);
284 (void) unlink(temp_path
);
286 return log_error_errno(r
, "Failed to save user data %s: %m", u
->state_file
);
289 int user_save(User
*u
) {
295 return user_save_internal (u
);
298 int user_load(User
*u
) {
299 _cleanup_free_
char *display
= NULL
, *realtime
= NULL
, *monotonic
= NULL
;
305 r
= parse_env_file(u
->state_file
, NEWLINE
,
306 "SERVICE_JOB", &u
->service_job
,
307 "SLICE_JOB", &u
->slice_job
,
309 "REALTIME", &realtime
,
310 "MONOTONIC", &monotonic
,
316 log_error_errno(r
, "Failed to read %s: %m", u
->state_file
);
321 s
= hashmap_get(u
->manager
->sessions
, display
);
323 if (s
&& s
->display
&& display_is_local(s
->display
))
327 unsigned long long l
;
328 if (sscanf(realtime
, "%llu", &l
) > 0)
329 u
->timestamp
.realtime
= l
;
333 unsigned long long l
;
334 if (sscanf(monotonic
, "%llu", &l
) > 0)
335 u
->timestamp
.monotonic
= l
;
341 static int user_mkdir_runtime_path(User
*u
) {
346 r
= mkdir_safe_label("/run/user", 0755, 0, 0);
348 return log_error_errno(r
, "Failed to create /run/user: %m");
350 if (path_is_mount_point(u
->runtime_path
, 0) <= 0) {
351 _cleanup_free_
char *t
= NULL
;
353 (void) mkdir_label(u
->runtime_path
, 0700);
356 r
= asprintf(&t
, "mode=0700,smackfsroot=*,uid=" UID_FMT
",gid=" GID_FMT
",size=%zu", u
->uid
, u
->gid
, u
->manager
->runtime_dir_size
);
358 r
= asprintf(&t
, "mode=0700,uid=" UID_FMT
",gid=" GID_FMT
",size=%zu", u
->uid
, u
->gid
, u
->manager
->runtime_dir_size
);
364 r
= mount("tmpfs", u
->runtime_path
, "tmpfs", MS_NODEV
|MS_NOSUID
, t
);
366 if (errno
!= EPERM
) {
367 r
= log_error_errno(errno
, "Failed to mount per-user tmpfs directory %s: %m", u
->runtime_path
);
371 /* Lacking permissions, maybe
372 * CAP_SYS_ADMIN-less container? In this case,
373 * just use a normal directory. */
375 r
= chmod_and_chown(u
->runtime_path
, 0700, u
->uid
, u
->gid
);
377 log_error_errno(r
, "Failed to change runtime directory ownership and mode: %m");
382 r
= label_fix(u
->runtime_path
, false, false);
384 log_warning_errno(r
, "Failed to fix label of '%s', ignoring: %m", u
->runtime_path
);
390 /* Try to clean up, but ignore errors */
391 (void) rmdir(u
->runtime_path
);
395 static int user_start_slice(User
*u
) {
396 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
397 const char *description
;
403 u
->slice_job
= mfree(u
->slice_job
);
404 description
= strjoina("User Slice of ", u
->name
);
406 r
= manager_start_slice(
410 "systemd-logind.service",
411 "systemd-user-sessions.service",
412 u
->manager
->user_tasks_max
,
416 /* we don't fail due to this, let's try to continue */
417 if (!sd_bus_error_has_name(&error
, BUS_ERROR_UNIT_EXISTS
))
418 log_error_errno(r
, "Failed to start user slice %s, ignoring: %s (%s)", u
->slice
, bus_error_message(&error
, r
), error
.name
);
426 static int user_start_service(User
*u
) {
427 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
433 u
->service_job
= mfree(u
->service_job
);
435 r
= manager_start_unit(
441 /* we don't fail due to this, let's try to continue */
442 log_error_errno(r
, "Failed to start user service, ignoring: %s", bus_error_message(&error
, r
));
444 u
->service_job
= job
;
450 int user_start(User
*u
) {
455 if (u
->started
&& !u
->stopping
)
459 * If u->stopping is set, the user is marked for removal and the slice
460 * and service stop-jobs are queued. We have to clear that flag before
461 * queing the start-jobs again. If they succeed, the user object can be
462 * re-used just fine (pid1 takes care of job-ordering and proper
463 * restart), but if they fail, we want to force another user_stop() so
464 * possibly pending units are stopped.
465 * Note that we don't clear u->started, as we have no clue what state
466 * the user is in on failure here. Hence, we pretend the user is
467 * running so it will be properly taken down by GC. However, we clearly
468 * return an error from user_start() in that case, so no further
469 * reference to the user is taken.
474 log_debug("New user %s logged in.", u
->name
);
476 /* Make XDG_RUNTIME_DIR */
477 r
= user_mkdir_runtime_path(u
);
483 r
= user_start_slice(u
);
487 /* Save the user data so far, because pam_systemd will read the
488 * XDG_RUNTIME_DIR out of it while starting up systemd --user.
489 * We need to do user_save_internal() because we have not
490 * "officially" started yet. */
491 user_save_internal(u
);
493 /* Spawn user systemd */
494 r
= user_start_service(u
);
499 if (!dual_timestamp_is_set(&u
->timestamp
))
500 dual_timestamp_get(&u
->timestamp
);
501 user_send_signal(u
, true);
505 /* Save new user data */
511 static int user_stop_slice(User
*u
) {
512 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
518 r
= manager_stop_unit(u
->manager
, u
->slice
, &error
, &job
);
520 log_error("Failed to stop user slice: %s", bus_error_message(&error
, r
));
530 static int user_stop_service(User
*u
) {
531 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
537 r
= manager_stop_unit(u
->manager
, u
->service
, &error
, &job
);
539 log_error("Failed to stop user service: %s", bus_error_message(&error
, r
));
543 free(u
->service_job
);
544 u
->service_job
= job
;
549 static int user_remove_runtime_path(User
*u
) {
554 r
= rm_rf(u
->runtime_path
, 0);
556 log_error_errno(r
, "Failed to remove runtime directory %s: %m", u
->runtime_path
);
558 /* Ignore cases where the directory isn't mounted, as that's
559 * quite possible, if we lacked the permissions to mount
561 r
= umount2(u
->runtime_path
, MNT_DETACH
);
562 if (r
< 0 && errno
!= EINVAL
&& errno
!= ENOENT
)
563 log_error_errno(errno
, "Failed to unmount user runtime directory %s: %m", u
->runtime_path
);
565 r
= rm_rf(u
->runtime_path
, REMOVE_ROOT
);
567 log_error_errno(r
, "Failed to remove runtime directory %s: %m", u
->runtime_path
);
572 int user_stop(User
*u
, bool force
) {
577 /* Stop jobs have already been queued */
583 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
584 k
= session_stop(s
, force
);
590 k
= user_stop_service(u
);
595 k
= user_stop_slice(u
);
606 int user_finalize(User
*u
) {
613 log_debug("User %s logged out.", u
->name
);
615 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
616 k
= session_finalize(s
);
621 /* Kill XDG_RUNTIME_DIR */
622 k
= user_remove_runtime_path(u
);
626 /* Clean SysV + POSIX IPC objects */
627 if (u
->manager
->remove_ipc
) {
628 k
= clean_ipc(u
->uid
);
633 unlink(u
->state_file
);
634 user_add_to_gc_queue(u
);
637 user_send_signal(u
, false);
644 int user_get_idle_hint(User
*u
, dual_timestamp
*t
) {
646 bool idle_hint
= true;
647 dual_timestamp ts
= DUAL_TIMESTAMP_NULL
;
651 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
655 ih
= session_get_idle_hint(s
, &k
);
661 if (k
.monotonic
< ts
.monotonic
)
667 } else if (idle_hint
) {
669 if (k
.monotonic
> ts
.monotonic
)
680 int user_check_linger_file(User
*u
) {
681 _cleanup_free_
char *cc
= NULL
;
684 cc
= cescape(u
->name
);
688 p
= strjoina("/var/lib/systemd/linger/", cc
);
690 return access(p
, F_OK
) >= 0;
693 bool user_check_gc(User
*u
, bool drop_not_started
) {
696 if (drop_not_started
&& !u
->started
)
702 if (user_check_linger_file(u
) > 0)
705 if (u
->slice_job
&& manager_job_is_active(u
->manager
, u
->slice_job
))
708 if (u
->service_job
&& manager_job_is_active(u
->manager
, u
->service_job
))
714 void user_add_to_gc_queue(User
*u
) {
720 LIST_PREPEND(gc_queue
, u
->manager
->user_gc_queue
, u
);
721 u
->in_gc_queue
= true;
724 UserState
user_get_state(User
*u
) {
732 if (!u
->started
|| u
->slice_job
|| u
->service_job
)
736 bool all_closing
= true;
738 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
741 state
= session_get_state(i
);
742 if (state
== SESSION_ACTIVE
)
744 if (state
!= SESSION_CLOSING
)
748 return all_closing
? USER_CLOSING
: USER_ONLINE
;
751 if (user_check_linger_file(u
) > 0)
752 return USER_LINGERING
;
757 int user_kill(User
*u
, int signo
) {
760 return manager_kill_unit(u
->manager
, u
->slice
, KILL_ALL
, signo
, NULL
);
763 static bool elect_display_filter(Session
*s
) {
764 /* Return true if the session is a candidate for the user’s ‘primary
765 * session’ or ‘display’. */
768 return (s
->class == SESSION_USER
&& !s
->stopping
);
771 static int elect_display_compare(Session
*s1
, Session
*s2
) {
772 /* Indexed by SessionType. Lower numbers mean more preferred. */
773 const int type_ranks
[_SESSION_TYPE_MAX
] = {
774 [SESSION_UNSPECIFIED
] = 0,
777 [SESSION_WAYLAND
] = -3,
782 /* Calculate the partial order relationship between s1 and s2,
783 * returning < 0 if s1 is preferred as the user’s ‘primary session’,
784 * 0 if s1 and s2 are equally preferred or incomparable, or > 0 if s2
787 * s1 or s2 may be NULL. */
791 if ((s1
== NULL
) != (s2
== NULL
))
792 return (s1
== NULL
) - (s2
== NULL
);
794 if (s1
->stopping
!= s2
->stopping
)
795 return s1
->stopping
- s2
->stopping
;
797 if ((s1
->class != SESSION_USER
) != (s2
->class != SESSION_USER
))
798 return (s1
->class != SESSION_USER
) - (s2
->class != SESSION_USER
);
800 if ((s1
->type
== _SESSION_TYPE_INVALID
) != (s2
->type
== _SESSION_TYPE_INVALID
))
801 return (s1
->type
== _SESSION_TYPE_INVALID
) - (s2
->type
== _SESSION_TYPE_INVALID
);
803 if (s1
->type
!= s2
->type
)
804 return type_ranks
[s1
->type
] - type_ranks
[s2
->type
];
809 void user_elect_display(User
*u
) {
814 /* This elects a primary session for each user, which we call
815 * the "display". We try to keep the assignment stable, but we
816 * "upgrade" to better choices. */
817 log_debug("Electing new display for user %s", u
->name
);
819 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
820 if (!elect_display_filter(s
)) {
821 log_debug("Ignoring session %s", s
->id
);
825 if (elect_display_compare(s
, u
->display
) < 0) {
826 log_debug("Choosing session %s in preference to %s", s
->id
, u
->display
? u
->display
->id
: "-");
832 static const char* const user_state_table
[_USER_STATE_MAX
] = {
833 [USER_OFFLINE
] = "offline",
834 [USER_OPENING
] = "opening",
835 [USER_LINGERING
] = "lingering",
836 [USER_ONLINE
] = "online",
837 [USER_ACTIVE
] = "active",
838 [USER_CLOSING
] = "closing"
841 DEFINE_STRING_TABLE_LOOKUP(user_state
, UserState
);
843 int config_parse_tmpfs_size(
845 const char *filename
,
848 unsigned section_line
,
864 e
= endswith(rvalue
, "%");
870 ul
= strtoul(rvalue
, &f
, 10);
871 if (errno
!= 0 || f
!= e
) {
872 log_syntax(unit
, LOG_ERR
, filename
, line
, errno
, "Failed to parse percentage value, ignoring: %s", rvalue
);
876 if (ul
<= 0 || ul
>= 100) {
877 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Percentage value out of range, ignoring: %s", rvalue
);
881 *sz
= PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul
) / (uint64_t) 100));
885 r
= parse_size(rvalue
, 1024, &k
);
886 if (r
< 0 || (uint64_t) (size_t) k
!= k
) {
887 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
891 *sz
= PAGE_ALIGN((size_t) k
);