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 static int user_save_internal(User
*u
) {
110 _cleanup_free_
char *temp_path
= NULL
;
111 _cleanup_fclose_
FILE *f
= NULL
;
115 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
);
244 r
= fflush_and_check(f
);
248 if (rename(temp_path
, u
->state_file
) < 0) {
256 (void) unlink(u
->state_file
);
259 (void) unlink(temp_path
);
261 return log_error_errno(r
, "Failed to save user data %s: %m", u
->state_file
);
264 int user_save(User
*u
) {
270 return user_save_internal (u
);
273 int user_load(User
*u
) {
274 _cleanup_free_
char *display
= NULL
, *realtime
= NULL
, *monotonic
= NULL
;
280 r
= parse_env_file(u
->state_file
, NEWLINE
,
281 "RUNTIME", &u
->runtime_path
,
282 "SERVICE", &u
->service
,
283 "SERVICE_JOB", &u
->service_job
,
285 "SLICE_JOB", &u
->slice_job
,
287 "REALTIME", &realtime
,
288 "MONOTONIC", &monotonic
,
294 log_error_errno(r
, "Failed to read %s: %m", u
->state_file
);
299 s
= hashmap_get(u
->manager
->sessions
, display
);
301 if (s
&& s
->display
&& display_is_local(s
->display
))
305 unsigned long long l
;
306 if (sscanf(realtime
, "%llu", &l
) > 0)
307 u
->timestamp
.realtime
= l
;
311 unsigned long long l
;
312 if (sscanf(monotonic
, "%llu", &l
) > 0)
313 u
->timestamp
.monotonic
= l
;
319 static int user_mkdir_runtime_path(User
*u
) {
325 r
= mkdir_safe_label("/run/user", 0755, 0, 0);
327 return log_error_errno(r
, "Failed to create /run/user: %m");
329 if (!u
->runtime_path
) {
330 if (asprintf(&p
, "/run/user/" UID_FMT
, u
->uid
) < 0)
335 if (path_is_mount_point(p
, 0) <= 0) {
336 _cleanup_free_
char *t
= NULL
;
338 (void) mkdir_label(p
, 0700);
341 r
= asprintf(&t
, "mode=0700,smackfsroot=*,uid=" UID_FMT
",gid=" GID_FMT
",size=%zu", u
->uid
, u
->gid
, u
->manager
->runtime_dir_size
);
343 r
= asprintf(&t
, "mode=0700,uid=" UID_FMT
",gid=" GID_FMT
",size=%zu", u
->uid
, u
->gid
, u
->manager
->runtime_dir_size
);
349 r
= mount("tmpfs", p
, "tmpfs", MS_NODEV
|MS_NOSUID
, t
);
351 if (errno
!= EPERM
) {
352 r
= log_error_errno(errno
, "Failed to mount per-user tmpfs directory %s: %m", p
);
356 /* Lacking permissions, maybe
357 * CAP_SYS_ADMIN-less container? In this case,
358 * just use a normal directory. */
360 r
= chmod_and_chown(p
, 0700, u
->uid
, u
->gid
);
362 log_error_errno(r
, "Failed to change runtime directory ownership and mode: %m");
367 r
= label_fix(p
, false, false);
369 log_warning_errno(r
, "Failed to fix label of '%s', ignoring: %m", p
);
377 /* Try to clean up, but ignore errors */
382 u
->runtime_path
= NULL
;
386 static int user_start_slice(User
*u
) {
393 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
394 char lu
[DECIMAL_STR_MAX(uid_t
) + 1], *slice
;
395 sprintf(lu
, UID_FMT
, u
->uid
);
397 r
= slice_build_subslice(SPECIAL_USER_SLICE
, lu
, &slice
);
401 r
= manager_start_unit(u
->manager
, slice
, &error
, &job
);
403 log_error("Failed to start user slice: %s", bus_error_message(&error
, r
));
414 hashmap_put(u
->manager
->user_units
, u
->slice
, u
);
419 static int user_start_service(User
*u
) {
420 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
427 char lu
[DECIMAL_STR_MAX(uid_t
) + 1], *service
;
428 sprintf(lu
, UID_FMT
, u
->uid
);
430 r
= unit_name_build("user", lu
, ".service", &service
);
432 return log_error_errno(r
, "Failed to build service name: %m");
434 r
= manager_start_unit(u
->manager
, service
, &error
, &job
);
436 log_error("Failed to start user service: %s", bus_error_message(&error
, r
));
439 u
->service
= service
;
441 free(u
->service_job
);
442 u
->service_job
= job
;
447 hashmap_put(u
->manager
->user_units
, u
->service
, u
);
452 int user_start(User
*u
) {
460 log_debug("New user %s logged in.", u
->name
);
462 /* Make XDG_RUNTIME_DIR */
463 r
= user_mkdir_runtime_path(u
);
468 r
= user_start_slice(u
);
472 /* Save the user data so far, because pam_systemd will read the
473 * XDG_RUNTIME_DIR out of it while starting up systemd --user.
474 * We need to do user_save_internal() because we have not
475 * "officially" started yet. */
476 user_save_internal(u
);
478 /* Spawn user systemd */
479 r
= user_start_service(u
);
483 if (!dual_timestamp_is_set(&u
->timestamp
))
484 dual_timestamp_get(&u
->timestamp
);
488 /* Save new user data */
491 user_send_signal(u
, true);
496 static int user_stop_slice(User
*u
) {
497 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
506 r
= manager_stop_unit(u
->manager
, u
->slice
, &error
, &job
);
508 log_error("Failed to stop user slice: %s", bus_error_message(&error
, r
));
518 static int user_stop_service(User
*u
) {
519 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
528 r
= manager_stop_unit(u
->manager
, u
->service
, &error
, &job
);
530 log_error("Failed to stop user service: %s", bus_error_message(&error
, r
));
534 free(u
->service_job
);
535 u
->service_job
= job
;
540 static int user_remove_runtime_path(User
*u
) {
545 if (!u
->runtime_path
)
548 r
= rm_rf(u
->runtime_path
, 0);
550 log_error_errno(r
, "Failed to remove runtime directory %s: %m", u
->runtime_path
);
552 /* Ignore cases where the directory isn't mounted, as that's
553 * quite possible, if we lacked the permissions to mount
555 r
= umount2(u
->runtime_path
, MNT_DETACH
);
556 if (r
< 0 && errno
!= EINVAL
&& errno
!= ENOENT
)
557 log_error_errno(errno
, "Failed to unmount user runtime directory %s: %m", u
->runtime_path
);
559 r
= rm_rf(u
->runtime_path
, REMOVE_ROOT
);
561 log_error_errno(r
, "Failed to remove runtime directory %s: %m", u
->runtime_path
);
563 free(u
->runtime_path
);
564 u
->runtime_path
= NULL
;
569 int user_stop(User
*u
, bool force
) {
574 /* Stop jobs have already been queued */
580 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
581 k
= session_stop(s
, force
);
587 k
= user_stop_service(u
);
592 k
= user_stop_slice(u
);
603 int user_finalize(User
*u
) {
610 log_debug("User %s logged out.", u
->name
);
612 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
613 k
= session_finalize(s
);
618 /* Kill XDG_RUNTIME_DIR */
619 k
= user_remove_runtime_path(u
);
623 /* Clean SysV + POSIX IPC objects */
624 if (u
->manager
->remove_ipc
) {
625 k
= clean_ipc(u
->uid
);
630 unlink(u
->state_file
);
631 user_add_to_gc_queue(u
);
634 user_send_signal(u
, false);
641 int user_get_idle_hint(User
*u
, dual_timestamp
*t
) {
643 bool idle_hint
= true;
644 dual_timestamp ts
= DUAL_TIMESTAMP_NULL
;
648 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
652 ih
= session_get_idle_hint(s
, &k
);
658 if (k
.monotonic
< ts
.monotonic
)
664 } else if (idle_hint
) {
666 if (k
.monotonic
> ts
.monotonic
)
677 int user_check_linger_file(User
*u
) {
678 _cleanup_free_
char *cc
= NULL
;
681 cc
= cescape(u
->name
);
685 p
= strjoina("/var/lib/systemd/linger/", cc
);
687 return access(p
, F_OK
) >= 0;
690 bool user_check_gc(User
*u
, bool drop_not_started
) {
693 if (drop_not_started
&& !u
->started
)
699 if (user_check_linger_file(u
) > 0)
702 if (u
->slice_job
&& manager_job_is_active(u
->manager
, u
->slice_job
))
705 if (u
->service_job
&& manager_job_is_active(u
->manager
, u
->service_job
))
711 void user_add_to_gc_queue(User
*u
) {
717 LIST_PREPEND(gc_queue
, u
->manager
->user_gc_queue
, u
);
718 u
->in_gc_queue
= true;
721 UserState
user_get_state(User
*u
) {
729 if (!u
->started
|| u
->slice_job
|| u
->service_job
)
733 bool all_closing
= true;
735 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
738 state
= session_get_state(i
);
739 if (state
== SESSION_ACTIVE
)
741 if (state
!= SESSION_CLOSING
)
745 return all_closing
? USER_CLOSING
: USER_ONLINE
;
748 if (user_check_linger_file(u
) > 0)
749 return USER_LINGERING
;
754 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
? errno
: EINVAL
, "Failed to parse percentage value, ignoring: %s", rvalue
);
876 if (ul
<= 0 || ul
>= 100) {
877 log_syntax(unit
, LOG_ERR
, filename
, line
, errno
? errno
: EINVAL
, "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, &o
);
886 if (r
< 0 || (off_t
) (size_t) o
!= o
) {
887 log_syntax(unit
, LOG_ERR
, filename
, line
, r
< 0 ? -r
: ERANGE
, "Failed to parse size value, ignoring: %s", rvalue
);
891 *sz
= PAGE_ALIGN((size_t) o
);