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 "logind-user.h"
40 #include "smack-util.h"
41 #include "formats-util.h"
43 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
53 u->name = strdup(name);
57 if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
60 if (hashmap_put(m->users, UID_TO_PTR(uid), u) < 0)
77 void user_free(User *u) {
81 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
84 session_free(u->sessions);
87 hashmap_remove(u->manager->user_units, u->slice);
92 hashmap_remove(u->manager->user_units, u->service);
99 free(u->runtime_path);
101 hashmap_remove(u->manager->users, UID_TO_PTR(u->uid));
108 int user_save(User *u) {
109 _cleanup_free_ char *temp_path = NULL;
110 _cleanup_fclose_ FILE *f = NULL;
114 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_load(User *u) {
267 _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
273 r = parse_env_file(u->state_file, NEWLINE,
274 "RUNTIME", &u->runtime_path,
275 "SERVICE", &u->service,
276 "SERVICE_JOB", &u->service_job,
278 "SLICE_JOB", &u->slice_job,
280 "REALTIME", &realtime,
281 "MONOTONIC", &monotonic,
287 log_error_errno(r, "Failed to read %s: %m", u->state_file);
292 s = hashmap_get(u->manager->sessions, display);
294 if (s && s->display && display_is_local(s->display))
298 unsigned long long l;
299 if (sscanf(realtime, "%llu", &l) > 0)
300 u->timestamp.realtime = l;
304 unsigned long long l;
305 if (sscanf(monotonic, "%llu", &l) > 0)
306 u->timestamp.monotonic = l;
312 static int user_mkdir_runtime_path(User *u) {
318 r = mkdir_safe_label("/run/user", 0755, 0, 0);
320 return log_error_errno(r, "Failed to create /run/user: %m");
322 if (!u->runtime_path) {
323 if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
328 if (path_is_mount_point(p, false) <= 0) {
329 _cleanup_free_ char *t = NULL;
331 (void) mkdir(p, 0700);
334 r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
336 r = asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
342 r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
344 if (errno != EPERM) {
345 r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", p);
349 /* Lacking permissions, maybe
350 * CAP_SYS_ADMIN-less container? In this case,
351 * just use a normal directory. */
353 r = chmod_and_chown(p, 0700, u->uid, u->gid);
355 log_error_errno(r, "Failed to change runtime directory ownership and mode: %m");
366 /* Try to clean up, but ignore errors */
371 u->runtime_path = NULL;
375 static int user_start_slice(User *u) {
382 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
383 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
384 sprintf(lu, UID_FMT, u->uid);
386 r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &slice);
390 r = manager_start_unit(u->manager, slice, &error, &job);
392 log_error("Failed to start user slice: %s", bus_error_message(&error, r));
403 hashmap_put(u->manager->user_units, u->slice, u);
408 static int user_start_service(User *u) {
409 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
416 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
417 sprintf(lu, UID_FMT, u->uid);
419 r = unit_name_build("user", lu, ".service", &service);
421 return log_error_errno(r, "Failed to build service name: %m");
423 r = manager_start_unit(u->manager, service, &error, &job);
425 log_error("Failed to start user service: %s", bus_error_message(&error, r));
428 u->service = service;
430 free(u->service_job);
431 u->service_job = job;
436 hashmap_put(u->manager->user_units, u->service, u);
441 int user_start(User *u) {
449 log_debug("New user %s logged in.", u->name);
451 /* Make XDG_RUNTIME_DIR */
452 r = user_mkdir_runtime_path(u);
457 r = user_start_slice(u);
461 /* Spawn user systemd */
462 r = user_start_service(u);
466 if (!dual_timestamp_is_set(&u->timestamp))
467 dual_timestamp_get(&u->timestamp);
471 /* Save new user data */
474 user_send_signal(u, true);
479 static int user_stop_slice(User *u) {
480 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
489 r = manager_stop_unit(u->manager, u->slice, &error, &job);
491 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
501 static int user_stop_service(User *u) {
502 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
511 r = manager_stop_unit(u->manager, u->service, &error, &job);
513 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
517 free(u->service_job);
518 u->service_job = job;
523 static int user_remove_runtime_path(User *u) {
528 if (!u->runtime_path)
531 r = rm_rf(u->runtime_path, 0);
533 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
535 /* Ignore cases where the directory isn't mounted, as that's
536 * quite possible, if we lacked the permissions to mount
538 r = umount2(u->runtime_path, MNT_DETACH);
539 if (r < 0 && errno != EINVAL && errno != ENOENT)
540 log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
542 r = rm_rf(u->runtime_path, REMOVE_ROOT);
544 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
546 free(u->runtime_path);
547 u->runtime_path = NULL;
552 int user_stop(User *u, bool force) {
557 /* Stop jobs have already been queued */
563 LIST_FOREACH(sessions_by_user, s, u->sessions) {
564 k = session_stop(s, force);
570 k = user_stop_service(u);
575 k = user_stop_slice(u);
586 int user_finalize(User *u) {
593 log_debug("User %s logged out.", u->name);
595 LIST_FOREACH(sessions_by_user, s, u->sessions) {
596 k = session_finalize(s);
601 /* Kill XDG_RUNTIME_DIR */
602 k = user_remove_runtime_path(u);
606 /* Clean SysV + POSIX IPC objects */
607 if (u->manager->remove_ipc) {
608 k = clean_ipc(u->uid);
613 unlink(u->state_file);
614 user_add_to_gc_queue(u);
617 user_send_signal(u, false);
624 int user_get_idle_hint(User *u, dual_timestamp *t) {
626 bool idle_hint = true;
627 dual_timestamp ts = { 0, 0 };
631 LIST_FOREACH(sessions_by_user, s, u->sessions) {
635 ih = session_get_idle_hint(s, &k);
641 if (k.monotonic < ts.monotonic)
647 } else if (idle_hint) {
649 if (k.monotonic > ts.monotonic)
660 int user_check_linger_file(User *u) {
661 _cleanup_free_ char *cc = NULL;
664 cc = cescape(u->name);
668 p = strjoina("/var/lib/systemd/linger/", cc);
670 return access(p, F_OK) >= 0;
673 bool user_check_gc(User *u, bool drop_not_started) {
676 if (drop_not_started && !u->started)
682 if (user_check_linger_file(u) > 0)
685 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
688 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
694 void user_add_to_gc_queue(User *u) {
700 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
701 u->in_gc_queue = true;
704 UserState user_get_state(User *u) {
712 if (u->slice_job || u->service_job)
716 bool all_closing = true;
718 LIST_FOREACH(sessions_by_user, i, u->sessions) {
721 state = session_get_state(i);
722 if (state == SESSION_ACTIVE)
724 if (state != SESSION_CLOSING)
728 return all_closing ? USER_CLOSING : USER_ONLINE;
731 if (user_check_linger_file(u) > 0)
732 return USER_LINGERING;
737 int user_kill(User *u, int signo) {
743 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
746 void user_elect_display(User *u) {
747 Session *graphical = NULL, *text = NULL, *other = NULL, *s;
751 /* This elects a primary session for each user, which we call
752 * the "display". We try to keep the assignment stable, but we
753 * "upgrade" to better choices. */
755 LIST_FOREACH(sessions_by_user, s, u->sessions) {
757 if (s->class != SESSION_USER)
763 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
765 else if (s->type == SESSION_TTY)
773 u->display->class != SESSION_USER ||
774 u->display->stopping ||
775 !SESSION_TYPE_IS_GRAPHICAL(u->display->type))) {
776 u->display = graphical;
782 u->display->class != SESSION_USER ||
783 u->display->stopping ||
784 u->display->type != SESSION_TTY)) {
791 u->display->class != SESSION_USER ||
792 u->display->stopping))
796 static const char* const user_state_table[_USER_STATE_MAX] = {
797 [USER_OFFLINE] = "offline",
798 [USER_OPENING] = "opening",
799 [USER_LINGERING] = "lingering",
800 [USER_ONLINE] = "online",
801 [USER_ACTIVE] = "active",
802 [USER_CLOSING] = "closing"
805 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
807 int config_parse_tmpfs_size(
809 const char *filename,
812 unsigned section_line,
828 e = endswith(rvalue, "%");
834 ul = strtoul(rvalue, &f, 10);
835 if (errno != 0 || f != e) {
836 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
840 if (ul <= 0 || ul >= 100) {
841 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
845 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
849 r = parse_size(rvalue, 1024, &o);
850 if (r < 0 || (off_t) (size_t) o != o) {
851 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
855 *sz = PAGE_ALIGN((size_t) o);