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 "bus-error.h"
29 #include "clean-ipc.h"
30 #include "conf-parser.h"
34 #include "formats-util.h"
37 #include "logind-user.h"
39 #include "path-util.h"
41 #include "smack-util.h"
43 #include "unit-name.h"
46 User
* user_new(Manager
*m
, uid_t uid
, gid_t gid
, const char *name
) {
56 u
->name
= strdup(name
);
60 if (asprintf(&u
->state_file
, "/run/systemd/users/"UID_FMT
, uid
) < 0)
63 if (hashmap_put(m
->users
, UID_TO_PTR(uid
), u
) < 0)
80 void user_free(User
*u
) {
84 LIST_REMOVE(gc_queue
, u
->manager
->user_gc_queue
, u
);
87 session_free(u
->sessions
);
90 hashmap_remove(u
->manager
->user_units
, u
->slice
);
95 hashmap_remove(u
->manager
->user_units
, u
->service
);
100 free(u
->service_job
);
102 free(u
->runtime_path
);
104 hashmap_remove(u
->manager
->users
, UID_TO_PTR(u
->uid
));
111 static int user_save_internal(User
*u
) {
112 _cleanup_free_
char *temp_path
= NULL
;
113 _cleanup_fclose_
FILE *f
= NULL
;
117 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
);
246 r
= fflush_and_check(f
);
250 if (rename(temp_path
, u
->state_file
) < 0) {
258 (void) unlink(u
->state_file
);
261 (void) unlink(temp_path
);
263 return log_error_errno(r
, "Failed to save user data %s: %m", u
->state_file
);
266 int user_save(User
*u
) {
272 return user_save_internal (u
);
275 int user_load(User
*u
) {
276 _cleanup_free_
char *display
= NULL
, *realtime
= NULL
, *monotonic
= NULL
;
282 r
= parse_env_file(u
->state_file
, NEWLINE
,
283 "RUNTIME", &u
->runtime_path
,
284 "SERVICE", &u
->service
,
285 "SERVICE_JOB", &u
->service_job
,
287 "SLICE_JOB", &u
->slice_job
,
289 "REALTIME", &realtime
,
290 "MONOTONIC", &monotonic
,
296 log_error_errno(r
, "Failed to read %s: %m", u
->state_file
);
301 s
= hashmap_get(u
->manager
->sessions
, display
);
303 if (s
&& s
->display
&& display_is_local(s
->display
))
307 unsigned long long l
;
308 if (sscanf(realtime
, "%llu", &l
) > 0)
309 u
->timestamp
.realtime
= l
;
313 unsigned long long l
;
314 if (sscanf(monotonic
, "%llu", &l
) > 0)
315 u
->timestamp
.monotonic
= l
;
321 static int user_mkdir_runtime_path(User
*u
) {
327 r
= mkdir_safe_label("/run/user", 0755, 0, 0);
329 return log_error_errno(r
, "Failed to create /run/user: %m");
331 if (!u
->runtime_path
) {
332 if (asprintf(&p
, "/run/user/" UID_FMT
, u
->uid
) < 0)
337 if (path_is_mount_point(p
, 0) <= 0) {
338 _cleanup_free_
char *t
= NULL
;
340 (void) mkdir_label(p
, 0700);
343 r
= asprintf(&t
, "mode=0700,smackfsroot=*,uid=" UID_FMT
",gid=" GID_FMT
",size=%zu", u
->uid
, u
->gid
, u
->manager
->runtime_dir_size
);
345 r
= asprintf(&t
, "mode=0700,uid=" UID_FMT
",gid=" GID_FMT
",size=%zu", u
->uid
, u
->gid
, u
->manager
->runtime_dir_size
);
351 r
= mount("tmpfs", p
, "tmpfs", MS_NODEV
|MS_NOSUID
, t
);
353 if (errno
!= EPERM
) {
354 r
= log_error_errno(errno
, "Failed to mount per-user tmpfs directory %s: %m", p
);
358 /* Lacking permissions, maybe
359 * CAP_SYS_ADMIN-less container? In this case,
360 * just use a normal directory. */
362 r
= chmod_and_chown(p
, 0700, u
->uid
, u
->gid
);
364 log_error_errno(r
, "Failed to change runtime directory ownership and mode: %m");
369 r
= label_fix(p
, false, false);
371 log_warning_errno(r
, "Failed to fix label of '%s', ignoring: %m", p
);
379 /* Try to clean up, but ignore errors */
384 u
->runtime_path
= NULL
;
388 static int user_start_slice(User
*u
) {
395 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
396 char lu
[DECIMAL_STR_MAX(uid_t
) + 1], *slice
;
397 sprintf(lu
, UID_FMT
, u
->uid
);
399 r
= slice_build_subslice(SPECIAL_USER_SLICE
, lu
, &slice
);
403 r
= manager_start_unit(u
->manager
, slice
, &error
, &job
);
405 log_error("Failed to start user slice: %s", bus_error_message(&error
, r
));
416 hashmap_put(u
->manager
->user_units
, u
->slice
, u
);
421 static int user_start_service(User
*u
) {
422 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
429 char lu
[DECIMAL_STR_MAX(uid_t
) + 1], *service
;
430 sprintf(lu
, UID_FMT
, u
->uid
);
432 r
= unit_name_build("user", lu
, ".service", &service
);
434 return log_error_errno(r
, "Failed to build service name: %m");
436 r
= manager_start_unit(u
->manager
, service
, &error
, &job
);
438 log_error("Failed to start user service: %s", bus_error_message(&error
, r
));
441 u
->service
= service
;
443 free(u
->service_job
);
444 u
->service_job
= job
;
449 hashmap_put(u
->manager
->user_units
, u
->service
, u
);
454 int user_start(User
*u
) {
462 log_debug("New user %s logged in.", u
->name
);
464 /* Make XDG_RUNTIME_DIR */
465 r
= user_mkdir_runtime_path(u
);
470 r
= user_start_slice(u
);
474 /* Save the user data so far, because pam_systemd will read the
475 * XDG_RUNTIME_DIR out of it while starting up systemd --user.
476 * We need to do user_save_internal() because we have not
477 * "officially" started yet. */
478 user_save_internal(u
);
480 /* Spawn user systemd */
481 r
= user_start_service(u
);
485 if (!dual_timestamp_is_set(&u
->timestamp
))
486 dual_timestamp_get(&u
->timestamp
);
490 /* Save new user data */
493 user_send_signal(u
, true);
498 static int user_stop_slice(User
*u
) {
499 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
508 r
= manager_stop_unit(u
->manager
, u
->slice
, &error
, &job
);
510 log_error("Failed to stop user slice: %s", bus_error_message(&error
, r
));
520 static int user_stop_service(User
*u
) {
521 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
530 r
= manager_stop_unit(u
->manager
, u
->service
, &error
, &job
);
532 log_error("Failed to stop user service: %s", bus_error_message(&error
, r
));
536 free(u
->service_job
);
537 u
->service_job
= job
;
542 static int user_remove_runtime_path(User
*u
) {
547 if (!u
->runtime_path
)
550 r
= rm_rf(u
->runtime_path
, 0);
552 log_error_errno(r
, "Failed to remove runtime directory %s: %m", u
->runtime_path
);
554 /* Ignore cases where the directory isn't mounted, as that's
555 * quite possible, if we lacked the permissions to mount
557 r
= umount2(u
->runtime_path
, MNT_DETACH
);
558 if (r
< 0 && errno
!= EINVAL
&& errno
!= ENOENT
)
559 log_error_errno(errno
, "Failed to unmount user runtime directory %s: %m", u
->runtime_path
);
561 r
= rm_rf(u
->runtime_path
, REMOVE_ROOT
);
563 log_error_errno(r
, "Failed to remove runtime directory %s: %m", u
->runtime_path
);
565 u
->runtime_path
= mfree(u
->runtime_path
);
570 int user_stop(User
*u
, bool force
) {
575 /* Stop jobs have already been queued */
581 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
582 k
= session_stop(s
, force
);
588 k
= user_stop_service(u
);
593 k
= user_stop_slice(u
);
604 int user_finalize(User
*u
) {
611 log_debug("User %s logged out.", u
->name
);
613 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
614 k
= session_finalize(s
);
619 /* Kill XDG_RUNTIME_DIR */
620 k
= user_remove_runtime_path(u
);
624 /* Clean SysV + POSIX IPC objects */
625 if (u
->manager
->remove_ipc
) {
626 k
= clean_ipc(u
->uid
);
631 unlink(u
->state_file
);
632 user_add_to_gc_queue(u
);
635 user_send_signal(u
, false);
642 int user_get_idle_hint(User
*u
, dual_timestamp
*t
) {
644 bool idle_hint
= true;
645 dual_timestamp ts
= DUAL_TIMESTAMP_NULL
;
649 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
653 ih
= session_get_idle_hint(s
, &k
);
659 if (k
.monotonic
< ts
.monotonic
)
665 } else if (idle_hint
) {
667 if (k
.monotonic
> ts
.monotonic
)
678 int user_check_linger_file(User
*u
) {
679 _cleanup_free_
char *cc
= NULL
;
682 cc
= cescape(u
->name
);
686 p
= strjoina("/var/lib/systemd/linger/", cc
);
688 return access(p
, F_OK
) >= 0;
691 bool user_check_gc(User
*u
, bool drop_not_started
) {
694 if (drop_not_started
&& !u
->started
)
700 if (user_check_linger_file(u
) > 0)
703 if (u
->slice_job
&& manager_job_is_active(u
->manager
, u
->slice_job
))
706 if (u
->service_job
&& manager_job_is_active(u
->manager
, u
->service_job
))
712 void user_add_to_gc_queue(User
*u
) {
718 LIST_PREPEND(gc_queue
, u
->manager
->user_gc_queue
, u
);
719 u
->in_gc_queue
= true;
722 UserState
user_get_state(User
*u
) {
730 if (!u
->started
|| u
->slice_job
|| u
->service_job
)
734 bool all_closing
= true;
736 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
739 state
= session_get_state(i
);
740 if (state
== SESSION_ACTIVE
)
742 if (state
!= SESSION_CLOSING
)
746 return all_closing
? USER_CLOSING
: USER_ONLINE
;
749 if (user_check_linger_file(u
) > 0)
750 return USER_LINGERING
;
755 int user_kill(User
*u
, int signo
) {
761 return manager_kill_unit(u
->manager
, u
->slice
, KILL_ALL
, signo
, NULL
);
764 static bool elect_display_filter(Session
*s
) {
765 /* Return true if the session is a candidate for the user’s ‘primary
766 * session’ or ‘display’. */
769 return (s
->class == SESSION_USER
&& !s
->stopping
);
772 static int elect_display_compare(Session
*s1
, Session
*s2
) {
773 /* Indexed by SessionType. Lower numbers mean more preferred. */
774 const int type_ranks
[_SESSION_TYPE_MAX
] = {
775 [SESSION_UNSPECIFIED
] = 0,
778 [SESSION_WAYLAND
] = -3,
783 /* Calculate the partial order relationship between s1 and s2,
784 * returning < 0 if s1 is preferred as the user’s ‘primary session’,
785 * 0 if s1 and s2 are equally preferred or incomparable, or > 0 if s2
788 * s1 or s2 may be NULL. */
792 if ((s1
== NULL
) != (s2
== NULL
))
793 return (s1
== NULL
) - (s2
== NULL
);
795 if (s1
->stopping
!= s2
->stopping
)
796 return s1
->stopping
- s2
->stopping
;
798 if ((s1
->class != SESSION_USER
) != (s2
->class != SESSION_USER
))
799 return (s1
->class != SESSION_USER
) - (s2
->class != SESSION_USER
);
801 if ((s1
->type
== _SESSION_TYPE_INVALID
) != (s2
->type
== _SESSION_TYPE_INVALID
))
802 return (s1
->type
== _SESSION_TYPE_INVALID
) - (s2
->type
== _SESSION_TYPE_INVALID
);
804 if (s1
->type
!= s2
->type
)
805 return type_ranks
[s1
->type
] - type_ranks
[s2
->type
];
810 void user_elect_display(User
*u
) {
815 /* This elects a primary session for each user, which we call
816 * the "display". We try to keep the assignment stable, but we
817 * "upgrade" to better choices. */
818 log_debug("Electing new display for user %s", u
->name
);
820 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
821 if (!elect_display_filter(s
)) {
822 log_debug("Ignoring session %s", s
->id
);
826 if (elect_display_compare(s
, u
->display
) < 0) {
827 log_debug("Choosing session %s in preference to %s", s
->id
, u
->display
? u
->display
->id
: "-");
833 static const char* const user_state_table
[_USER_STATE_MAX
] = {
834 [USER_OFFLINE
] = "offline",
835 [USER_OPENING
] = "opening",
836 [USER_LINGERING
] = "lingering",
837 [USER_ONLINE
] = "online",
838 [USER_ACTIVE
] = "active",
839 [USER_CLOSING
] = "closing"
842 DEFINE_STRING_TABLE_LOOKUP(user_state
, UserState
);
844 int config_parse_tmpfs_size(
846 const char *filename
,
849 unsigned section_line
,
865 e
= endswith(rvalue
, "%");
871 ul
= strtoul(rvalue
, &f
, 10);
872 if (errno
!= 0 || f
!= e
) {
873 log_syntax(unit
, LOG_ERR
, filename
, line
, errno
, "Failed to parse percentage value, ignoring: %s", rvalue
);
877 if (ul
<= 0 || ul
>= 100) {
878 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Percentage value out of range, ignoring: %s", rvalue
);
882 *sz
= PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul
) / (uint64_t) 100));
886 r
= parse_size(rvalue
, 1024, &k
);
887 if (r
< 0 || (uint64_t) (size_t) k
!= k
) {
888 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
892 *sz
= PAGE_ALIGN((size_t) k
);