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"
42 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
52 u->name = strdup(name);
56 if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
59 if (hashmap_put(m->users, UID_TO_PTR(uid), u) < 0)
76 void user_free(User *u) {
80 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
83 session_free(u->sessions);
86 hashmap_remove(u->manager->user_units, u->slice);
91 hashmap_remove(u->manager->user_units, u->service);
98 free(u->runtime_path);
100 hashmap_remove(u->manager->users, UID_TO_PTR(u->uid));
107 int user_save(User *u) {
108 _cleanup_free_ char *temp_path = NULL;
109 _cleanup_fclose_ FILE *f = NULL;
113 assert(u->state_file);
118 r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
122 r = fopen_temporary(u->state_file, &f, &temp_path);
126 fchmod(fileno(f), 0644);
129 "# This is private data. Do not parse.\n"
133 user_state_to_string(user_get_state(u)));
136 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
139 fprintf(f, "SERVICE=%s\n", u->service);
141 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
144 fprintf(f, "SLICE=%s\n", u->slice);
146 fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
149 fprintf(f, "DISPLAY=%s\n", u->display->id);
151 if (dual_timestamp_is_set(&u->timestamp))
153 "REALTIME="USEC_FMT"\n"
154 "MONOTONIC="USEC_FMT"\n",
155 u->timestamp.realtime,
156 u->timestamp.monotonic);
162 fputs("SESSIONS=", f);
164 LIST_FOREACH(sessions_by_user, i, u->sessions) {
173 fputs("\nSEATS=", f);
175 LIST_FOREACH(sessions_by_user, i, u->sessions) {
184 fputs(i->seat->id, f);
187 fputs("\nACTIVE_SESSIONS=", f);
189 LIST_FOREACH(sessions_by_user, i, u->sessions) {
190 if (!session_is_active(i))
201 fputs("\nONLINE_SESSIONS=", f);
203 LIST_FOREACH(sessions_by_user, i, u->sessions) {
204 if (session_get_state(i) == SESSION_CLOSING)
215 fputs("\nACTIVE_SEATS=", f);
217 LIST_FOREACH(sessions_by_user, i, u->sessions) {
218 if (!session_is_active(i) || !i->seat)
226 fputs(i->seat->id, f);
229 fputs("\nONLINE_SEATS=", f);
231 LIST_FOREACH(sessions_by_user, i, u->sessions) {
232 if (session_get_state(i) == SESSION_CLOSING || !i->seat)
240 fputs(i->seat->id, f);
247 if (ferror(f) || rename(temp_path, u->state_file) < 0) {
249 unlink(u->state_file);
255 log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
260 int user_load(User *u) {
261 _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
267 r = parse_env_file(u->state_file, NEWLINE,
268 "RUNTIME", &u->runtime_path,
269 "SERVICE", &u->service,
270 "SERVICE_JOB", &u->service_job,
272 "SLICE_JOB", &u->slice_job,
274 "REALTIME", &realtime,
275 "MONOTONIC", &monotonic,
281 log_error_errno(r, "Failed to read %s: %m", u->state_file);
286 s = hashmap_get(u->manager->sessions, display);
288 if (s && s->display && display_is_local(s->display))
292 unsigned long long l;
293 if (sscanf(realtime, "%llu", &l) > 0)
294 u->timestamp.realtime = l;
298 unsigned long long l;
299 if (sscanf(monotonic, "%llu", &l) > 0)
300 u->timestamp.monotonic = l;
306 static int user_mkdir_runtime_path(User *u) {
312 r = mkdir_safe_label("/run/user", 0755, 0, 0);
314 return log_error_errno(r, "Failed to create /run/user: %m");
316 if (!u->runtime_path) {
317 if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
322 if (path_is_mount_point(p, false) <= 0) {
323 _cleanup_free_ char *t = NULL;
325 (void) mkdir(p, 0700);
328 r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
330 r = asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
336 r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
338 if (errno != EPERM) {
339 r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", p);
343 /* Lacking permissions, maybe
344 * CAP_SYS_ADMIN-less container? In this case,
345 * just use a normal directory. */
347 r = chmod_and_chown(p, 0700, u->uid, u->gid);
349 log_error_errno(r, "Failed to change runtime directory ownership and mode: %m");
360 /* Try to clean up, but ignore errors */
365 u->runtime_path = NULL;
369 static int user_start_slice(User *u) {
376 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
377 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
378 sprintf(lu, UID_FMT, u->uid);
380 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
384 r = manager_start_unit(u->manager, slice, &error, &job);
386 log_error("Failed to start user slice: %s", bus_error_message(&error, r));
397 hashmap_put(u->manager->user_units, u->slice, u);
402 static int user_start_service(User *u) {
403 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
410 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
411 sprintf(lu, UID_FMT, u->uid);
413 service = unit_name_build("user", lu, ".service");
417 r = manager_start_unit(u->manager, service, &error, &job);
419 log_error("Failed to start user service: %s", bus_error_message(&error, r));
422 u->service = service;
424 free(u->service_job);
425 u->service_job = job;
430 hashmap_put(u->manager->user_units, u->service, u);
435 int user_start(User *u) {
443 log_debug("New user %s logged in.", u->name);
445 /* Make XDG_RUNTIME_DIR */
446 r = user_mkdir_runtime_path(u);
451 r = user_start_slice(u);
455 /* Spawn user systemd */
456 r = user_start_service(u);
460 if (!dual_timestamp_is_set(&u->timestamp))
461 dual_timestamp_get(&u->timestamp);
465 /* Save new user data */
468 user_send_signal(u, true);
473 static int user_stop_slice(User *u) {
474 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
483 r = manager_stop_unit(u->manager, u->slice, &error, &job);
485 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
495 static int user_stop_service(User *u) {
496 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
505 r = manager_stop_unit(u->manager, u->service, &error, &job);
507 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
511 free(u->service_job);
512 u->service_job = job;
517 static int user_remove_runtime_path(User *u) {
522 if (!u->runtime_path)
525 r = rm_rf(u->runtime_path, false, false, false);
527 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
529 /* Ignore cases where the directory isn't mounted, as that's
530 * quite possible, if we lacked the permissions to mount
532 r = umount2(u->runtime_path, MNT_DETACH);
533 if (r < 0 && errno != EINVAL && errno != ENOENT)
534 log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
536 r = rm_rf(u->runtime_path, false, true, false);
538 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
540 free(u->runtime_path);
541 u->runtime_path = NULL;
546 int user_stop(User *u, bool force) {
551 /* Stop jobs have already been queued */
557 LIST_FOREACH(sessions_by_user, s, u->sessions) {
558 k = session_stop(s, force);
564 k = user_stop_service(u);
569 k = user_stop_slice(u);
580 int user_finalize(User *u) {
587 log_debug("User %s logged out.", u->name);
589 LIST_FOREACH(sessions_by_user, s, u->sessions) {
590 k = session_finalize(s);
595 /* Kill XDG_RUNTIME_DIR */
596 k = user_remove_runtime_path(u);
600 /* Clean SysV + POSIX IPC objects */
601 if (u->manager->remove_ipc) {
602 k = clean_ipc(u->uid);
607 unlink(u->state_file);
608 user_add_to_gc_queue(u);
611 user_send_signal(u, false);
618 int user_get_idle_hint(User *u, dual_timestamp *t) {
620 bool idle_hint = true;
621 dual_timestamp ts = { 0, 0 };
625 LIST_FOREACH(sessions_by_user, s, u->sessions) {
629 ih = session_get_idle_hint(s, &k);
635 if (k.monotonic < ts.monotonic)
641 } else if (idle_hint) {
643 if (k.monotonic > ts.monotonic)
654 int user_check_linger_file(User *u) {
655 _cleanup_free_ char *cc = NULL;
658 cc = cescape(u->name);
662 p = strjoina("/var/lib/systemd/linger/", cc);
664 return access(p, F_OK) >= 0;
667 bool user_check_gc(User *u, bool drop_not_started) {
670 if (drop_not_started && !u->started)
676 if (user_check_linger_file(u) > 0)
679 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
682 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
688 void user_add_to_gc_queue(User *u) {
694 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
695 u->in_gc_queue = true;
698 UserState user_get_state(User *u) {
706 if (u->slice_job || u->service_job)
710 bool all_closing = true;
712 LIST_FOREACH(sessions_by_user, i, u->sessions) {
715 state = session_get_state(i);
716 if (state == SESSION_ACTIVE)
718 if (state != SESSION_CLOSING)
722 return all_closing ? USER_CLOSING : USER_ONLINE;
725 if (user_check_linger_file(u) > 0)
726 return USER_LINGERING;
731 int user_kill(User *u, int signo) {
737 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
740 void user_elect_display(User *u) {
741 Session *graphical = NULL, *text = NULL, *other = NULL, *s;
745 /* This elects a primary session for each user, which we call
746 * the "display". We try to keep the assignment stable, but we
747 * "upgrade" to better choices. */
749 LIST_FOREACH(sessions_by_user, s, u->sessions) {
751 if (s->class != SESSION_USER)
757 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
759 else if (s->type == SESSION_TTY)
767 u->display->class != SESSION_USER ||
768 u->display->stopping ||
769 !SESSION_TYPE_IS_GRAPHICAL(u->display->type))) {
770 u->display = graphical;
776 u->display->class != SESSION_USER ||
777 u->display->stopping ||
778 u->display->type != SESSION_TTY)) {
785 u->display->class != SESSION_USER ||
786 u->display->stopping))
790 static const char* const user_state_table[_USER_STATE_MAX] = {
791 [USER_OFFLINE] = "offline",
792 [USER_OPENING] = "opening",
793 [USER_LINGERING] = "lingering",
794 [USER_ONLINE] = "online",
795 [USER_ACTIVE] = "active",
796 [USER_CLOSING] = "closing"
799 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
801 int config_parse_tmpfs_size(
803 const char *filename,
806 unsigned section_line,
822 e = endswith(rvalue, "%");
828 ul = strtoul(rvalue, &f, 10);
829 if (errno != 0 || f != e) {
830 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
834 if (ul <= 0 || ul >= 100) {
835 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
839 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
843 r = parse_size(rvalue, 1024, &o);
844 if (r < 0 || (off_t) (size_t) o != o) {
845 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
849 *sz = PAGE_ALIGN((size_t) o);