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 "mount-util.h"
40 #include "parse-util.h"
41 #include "path-util.h"
43 #include "smack-util.h"
45 #include "unit-name.h"
48 User
* user_new(Manager
*m
, uid_t uid
, gid_t gid
, const char *name
) {
58 u
->name
= strdup(name
);
62 if (asprintf(&u
->state_file
, "/run/systemd/users/"UID_FMT
, uid
) < 0)
65 if (hashmap_put(m
->users
, UID_TO_PTR(uid
), u
) < 0)
82 void user_free(User
*u
) {
86 LIST_REMOVE(gc_queue
, u
->manager
->user_gc_queue
, u
);
89 session_free(u
->sessions
);
92 hashmap_remove(u
->manager
->user_units
, u
->slice
);
97 hashmap_remove(u
->manager
->user_units
, u
->service
);
102 free(u
->service_job
);
104 free(u
->runtime_path
);
106 hashmap_remove(u
->manager
->users
, UID_TO_PTR(u
->uid
));
113 static int user_save_internal(User
*u
) {
114 _cleanup_free_
char *temp_path
= NULL
;
115 _cleanup_fclose_
FILE *f
= NULL
;
119 assert(u
->state_file
);
121 r
= mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
125 r
= fopen_temporary(u
->state_file
, &f
, &temp_path
);
129 fchmod(fileno(f
), 0644);
132 "# This is private data. Do not parse.\n"
136 user_state_to_string(user_get_state(u
)));
139 fprintf(f
, "RUNTIME=%s\n", u
->runtime_path
);
142 fprintf(f
, "SERVICE=%s\n", u
->service
);
144 fprintf(f
, "SERVICE_JOB=%s\n", u
->service_job
);
147 fprintf(f
, "SLICE=%s\n", u
->slice
);
149 fprintf(f
, "SLICE_JOB=%s\n", u
->slice_job
);
152 fprintf(f
, "DISPLAY=%s\n", u
->display
->id
);
154 if (dual_timestamp_is_set(&u
->timestamp
))
156 "REALTIME="USEC_FMT
"\n"
157 "MONOTONIC="USEC_FMT
"\n",
158 u
->timestamp
.realtime
,
159 u
->timestamp
.monotonic
);
165 fputs("SESSIONS=", f
);
167 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
176 fputs("\nSEATS=", f
);
178 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
187 fputs(i
->seat
->id
, f
);
190 fputs("\nACTIVE_SESSIONS=", f
);
192 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
193 if (!session_is_active(i
))
204 fputs("\nONLINE_SESSIONS=", f
);
206 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
207 if (session_get_state(i
) == SESSION_CLOSING
)
218 fputs("\nACTIVE_SEATS=", f
);
220 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
221 if (!session_is_active(i
) || !i
->seat
)
229 fputs(i
->seat
->id
, f
);
232 fputs("\nONLINE_SEATS=", f
);
234 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
235 if (session_get_state(i
) == SESSION_CLOSING
|| !i
->seat
)
243 fputs(i
->seat
->id
, f
);
248 r
= fflush_and_check(f
);
252 if (rename(temp_path
, u
->state_file
) < 0) {
260 (void) unlink(u
->state_file
);
263 (void) unlink(temp_path
);
265 return log_error_errno(r
, "Failed to save user data %s: %m", u
->state_file
);
268 int user_save(User
*u
) {
274 return user_save_internal (u
);
277 int user_load(User
*u
) {
278 _cleanup_free_
char *display
= NULL
, *realtime
= NULL
, *monotonic
= NULL
;
284 r
= parse_env_file(u
->state_file
, NEWLINE
,
285 "RUNTIME", &u
->runtime_path
,
286 "SERVICE", &u
->service
,
287 "SERVICE_JOB", &u
->service_job
,
289 "SLICE_JOB", &u
->slice_job
,
291 "REALTIME", &realtime
,
292 "MONOTONIC", &monotonic
,
298 log_error_errno(r
, "Failed to read %s: %m", u
->state_file
);
303 s
= hashmap_get(u
->manager
->sessions
, display
);
305 if (s
&& s
->display
&& display_is_local(s
->display
))
309 unsigned long long l
;
310 if (sscanf(realtime
, "%llu", &l
) > 0)
311 u
->timestamp
.realtime
= l
;
315 unsigned long long l
;
316 if (sscanf(monotonic
, "%llu", &l
) > 0)
317 u
->timestamp
.monotonic
= l
;
323 static int user_mkdir_runtime_path(User
*u
) {
329 r
= mkdir_safe_label("/run/user", 0755, 0, 0);
331 return log_error_errno(r
, "Failed to create /run/user: %m");
333 if (!u
->runtime_path
) {
334 if (asprintf(&p
, "/run/user/" UID_FMT
, u
->uid
) < 0)
339 if (path_is_mount_point(p
, 0) <= 0) {
340 _cleanup_free_
char *t
= NULL
;
342 (void) mkdir_label(p
, 0700);
345 r
= asprintf(&t
, "mode=0700,smackfsroot=*,uid=" UID_FMT
",gid=" GID_FMT
",size=%zu", u
->uid
, u
->gid
, u
->manager
->runtime_dir_size
);
347 r
= asprintf(&t
, "mode=0700,uid=" UID_FMT
",gid=" GID_FMT
",size=%zu", u
->uid
, u
->gid
, u
->manager
->runtime_dir_size
);
353 r
= mount("tmpfs", p
, "tmpfs", MS_NODEV
|MS_NOSUID
, t
);
355 if (errno
!= EPERM
) {
356 r
= log_error_errno(errno
, "Failed to mount per-user tmpfs directory %s: %m", p
);
360 /* Lacking permissions, maybe
361 * CAP_SYS_ADMIN-less container? In this case,
362 * just use a normal directory. */
364 r
= chmod_and_chown(p
, 0700, u
->uid
, u
->gid
);
366 log_error_errno(r
, "Failed to change runtime directory ownership and mode: %m");
371 r
= label_fix(p
, false, false);
373 log_warning_errno(r
, "Failed to fix label of '%s', ignoring: %m", p
);
381 /* Try to clean up, but ignore errors */
386 u
->runtime_path
= NULL
;
390 static int user_start_slice(User
*u
) {
397 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
398 char lu
[DECIMAL_STR_MAX(uid_t
) + 1], *slice
;
399 sprintf(lu
, UID_FMT
, u
->uid
);
401 r
= slice_build_subslice(SPECIAL_USER_SLICE
, lu
, &slice
);
405 r
= manager_start_unit(u
->manager
, slice
, &error
, &job
);
407 log_error("Failed to start user slice: %s", bus_error_message(&error
, r
));
418 hashmap_put(u
->manager
->user_units
, u
->slice
, u
);
423 static int user_start_service(User
*u
) {
424 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
431 char lu
[DECIMAL_STR_MAX(uid_t
) + 1], *service
;
432 sprintf(lu
, UID_FMT
, u
->uid
);
434 r
= unit_name_build("user", lu
, ".service", &service
);
436 return log_error_errno(r
, "Failed to build service name: %m");
438 r
= manager_start_unit(u
->manager
, service
, &error
, &job
);
440 log_error("Failed to start user service: %s", bus_error_message(&error
, r
));
443 u
->service
= service
;
445 free(u
->service_job
);
446 u
->service_job
= job
;
451 hashmap_put(u
->manager
->user_units
, u
->service
, u
);
456 int user_start(User
*u
) {
464 log_debug("New user %s logged in.", u
->name
);
466 /* Make XDG_RUNTIME_DIR */
467 r
= user_mkdir_runtime_path(u
);
472 r
= user_start_slice(u
);
476 /* Save the user data so far, because pam_systemd will read the
477 * XDG_RUNTIME_DIR out of it while starting up systemd --user.
478 * We need to do user_save_internal() because we have not
479 * "officially" started yet. */
480 user_save_internal(u
);
482 /* Spawn user systemd */
483 r
= user_start_service(u
);
487 if (!dual_timestamp_is_set(&u
->timestamp
))
488 dual_timestamp_get(&u
->timestamp
);
492 /* Save new user data */
495 user_send_signal(u
, true);
500 static int user_stop_slice(User
*u
) {
501 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
510 r
= manager_stop_unit(u
->manager
, u
->slice
, &error
, &job
);
512 log_error("Failed to stop user slice: %s", bus_error_message(&error
, r
));
522 static int user_stop_service(User
*u
) {
523 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
532 r
= manager_stop_unit(u
->manager
, u
->service
, &error
, &job
);
534 log_error("Failed to stop user service: %s", bus_error_message(&error
, r
));
538 free(u
->service_job
);
539 u
->service_job
= job
;
544 static int user_remove_runtime_path(User
*u
) {
549 if (!u
->runtime_path
)
552 r
= rm_rf(u
->runtime_path
, 0);
554 log_error_errno(r
, "Failed to remove runtime directory %s: %m", u
->runtime_path
);
556 /* Ignore cases where the directory isn't mounted, as that's
557 * quite possible, if we lacked the permissions to mount
559 r
= umount2(u
->runtime_path
, MNT_DETACH
);
560 if (r
< 0 && errno
!= EINVAL
&& errno
!= ENOENT
)
561 log_error_errno(errno
, "Failed to unmount user runtime directory %s: %m", u
->runtime_path
);
563 r
= rm_rf(u
->runtime_path
, REMOVE_ROOT
);
565 log_error_errno(r
, "Failed to remove runtime directory %s: %m", u
->runtime_path
);
567 u
->runtime_path
= mfree(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
) {
763 return manager_kill_unit(u
->manager
, u
->slice
, KILL_ALL
, signo
, NULL
);
766 static bool elect_display_filter(Session
*s
) {
767 /* Return true if the session is a candidate for the user’s ‘primary
768 * session’ or ‘display’. */
771 return (s
->class == SESSION_USER
&& !s
->stopping
);
774 static int elect_display_compare(Session
*s1
, Session
*s2
) {
775 /* Indexed by SessionType. Lower numbers mean more preferred. */
776 const int type_ranks
[_SESSION_TYPE_MAX
] = {
777 [SESSION_UNSPECIFIED
] = 0,
780 [SESSION_WAYLAND
] = -3,
785 /* Calculate the partial order relationship between s1 and s2,
786 * returning < 0 if s1 is preferred as the user’s ‘primary session’,
787 * 0 if s1 and s2 are equally preferred or incomparable, or > 0 if s2
790 * s1 or s2 may be NULL. */
794 if ((s1
== NULL
) != (s2
== NULL
))
795 return (s1
== NULL
) - (s2
== NULL
);
797 if (s1
->stopping
!= s2
->stopping
)
798 return s1
->stopping
- s2
->stopping
;
800 if ((s1
->class != SESSION_USER
) != (s2
->class != SESSION_USER
))
801 return (s1
->class != SESSION_USER
) - (s2
->class != SESSION_USER
);
803 if ((s1
->type
== _SESSION_TYPE_INVALID
) != (s2
->type
== _SESSION_TYPE_INVALID
))
804 return (s1
->type
== _SESSION_TYPE_INVALID
) - (s2
->type
== _SESSION_TYPE_INVALID
);
806 if (s1
->type
!= s2
->type
)
807 return type_ranks
[s1
->type
] - type_ranks
[s2
->type
];
812 void user_elect_display(User
*u
) {
817 /* This elects a primary session for each user, which we call
818 * the "display". We try to keep the assignment stable, but we
819 * "upgrade" to better choices. */
820 log_debug("Electing new display for user %s", u
->name
);
822 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
823 if (!elect_display_filter(s
)) {
824 log_debug("Ignoring session %s", s
->id
);
828 if (elect_display_compare(s
, u
->display
) < 0) {
829 log_debug("Choosing session %s in preference to %s", s
->id
, u
->display
? u
->display
->id
: "-");
835 static const char* const user_state_table
[_USER_STATE_MAX
] = {
836 [USER_OFFLINE
] = "offline",
837 [USER_OPENING
] = "opening",
838 [USER_LINGERING
] = "lingering",
839 [USER_ONLINE
] = "online",
840 [USER_ACTIVE
] = "active",
841 [USER_CLOSING
] = "closing"
844 DEFINE_STRING_TABLE_LOOKUP(user_state
, UserState
);
846 int config_parse_tmpfs_size(
848 const char *filename
,
851 unsigned section_line
,
867 e
= endswith(rvalue
, "%");
873 ul
= strtoul(rvalue
, &f
, 10);
874 if (errno
!= 0 || f
!= e
) {
875 log_syntax(unit
, LOG_ERR
, filename
, line
, errno
, "Failed to parse percentage value, ignoring: %s", rvalue
);
879 if (ul
<= 0 || ul
>= 100) {
880 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Percentage value out of range, ignoring: %s", rvalue
);
884 *sz
= PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul
) / (uint64_t) 100));
888 r
= parse_size(rvalue
, 1024, &k
);
889 if (r
< 0 || (uint64_t) (size_t) k
!= k
) {
890 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
894 *sz
= PAGE_ALIGN((size_t) k
);