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>
31 #include "path-util.h"
33 #include "unit-name.h"
35 #include "bus-error.h"
36 #include "conf-parser.h"
37 #include "clean-ipc.h"
38 #include "logind-user.h"
39 #include "smack-util.h"
41 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
51 u->name = strdup(name);
55 if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
58 if (hashmap_put(m->users, UID_TO_PTR(uid), u) < 0)
75 void user_free(User *u) {
79 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
82 session_free(u->sessions);
85 hashmap_remove(u->manager->user_units, u->slice);
90 hashmap_remove(u->manager->user_units, u->service);
97 free(u->runtime_path);
99 hashmap_remove(u->manager->users, UID_TO_PTR(u->uid));
106 int user_save(User *u) {
107 _cleanup_free_ char *temp_path = NULL;
108 _cleanup_fclose_ FILE *f = NULL;
112 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);
246 if (ferror(f) || rename(temp_path, u->state_file) < 0) {
248 unlink(u->state_file);
254 log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
259 int user_load(User *u) {
260 _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
266 r = parse_env_file(u->state_file, NEWLINE,
267 "RUNTIME", &u->runtime_path,
268 "SERVICE", &u->service,
269 "SERVICE_JOB", &u->service_job,
271 "SLICE_JOB", &u->slice_job,
273 "REALTIME", &realtime,
274 "MONOTONIC", &monotonic,
280 log_error_errno(r, "Failed to read %s: %m", u->state_file);
285 s = hashmap_get(u->manager->sessions, display);
287 if (s && s->display && display_is_local(s->display))
291 unsigned long long l;
292 if (sscanf(realtime, "%llu", &l) > 0)
293 u->timestamp.realtime = l;
297 unsigned long long l;
298 if (sscanf(monotonic, "%llu", &l) > 0)
299 u->timestamp.monotonic = l;
305 static int user_mkdir_runtime_path(User *u) {
311 r = mkdir_safe_label("/run/user", 0755, 0, 0);
313 return log_error_errno(r, "Failed to create /run/user: %m");
315 if (!u->runtime_path) {
316 if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
321 if (path_is_mount_point(p, false) <= 0) {
322 _cleanup_free_ char *t = NULL;
324 (void) mkdir(p, 0700);
327 r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
329 r = asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
335 r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
337 if (errno != EPERM) {
338 r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", p);
342 /* Lacking permissions, maybe
343 * CAP_SYS_ADMIN-less container? In this case,
344 * just use a normal directory. */
346 r = chmod_and_chown(p, 0700, u->uid, u->gid);
348 log_error_errno(r, "Failed to change runtime directory ownership and mode: %m");
359 /* Try to clean up, but ignore errors */
364 u->runtime_path = NULL;
368 static int user_start_slice(User *u) {
375 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
376 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
377 sprintf(lu, UID_FMT, u->uid);
379 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
383 r = manager_start_unit(u->manager, slice, &error, &job);
385 log_error("Failed to start user slice: %s", bus_error_message(&error, r));
396 hashmap_put(u->manager->user_units, u->slice, u);
401 static int user_start_service(User *u) {
402 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
409 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
410 sprintf(lu, UID_FMT, u->uid);
412 service = unit_name_build("user", lu, ".service");
416 r = manager_start_unit(u->manager, service, &error, &job);
418 log_error("Failed to start user service: %s", bus_error_message(&error, r));
421 u->service = service;
423 free(u->service_job);
424 u->service_job = job;
429 hashmap_put(u->manager->user_units, u->service, u);
434 int user_start(User *u) {
442 log_debug("New user %s logged in.", u->name);
444 /* Make XDG_RUNTIME_DIR */
445 r = user_mkdir_runtime_path(u);
451 r = user_start_slice(u);
455 /* Spawn user systemd */
456 r = user_start_service(u);
461 if (!dual_timestamp_is_set(&u->timestamp))
462 dual_timestamp_get(&u->timestamp);
466 /* Save new user data */
469 user_send_signal(u, true);
474 static int user_stop_slice(User *u) {
475 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
484 r = manager_stop_unit(u->manager, u->slice, &error, &job);
486 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
496 static int user_stop_service(User *u) {
497 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
506 r = manager_stop_unit(u->manager, u->service, &error, &job);
508 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
512 free(u->service_job);
513 u->service_job = job;
518 static int user_remove_runtime_path(User *u) {
523 if (!u->runtime_path)
526 r = rm_rf(u->runtime_path, false, false, false);
528 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
530 /* Ignore cases where the directory isn't mounted, as that's
531 * quite possible, if we lacked the permissions to mount
533 r = umount2(u->runtime_path, MNT_DETACH);
534 if (r < 0 && errno != EINVAL && errno != ENOENT)
535 log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
537 r = rm_rf(u->runtime_path, false, true, false);
539 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
541 free(u->runtime_path);
542 u->runtime_path = NULL;
547 int user_stop(User *u, bool force) {
552 /* Stop jobs have already been queued */
558 LIST_FOREACH(sessions_by_user, s, u->sessions) {
559 k = session_stop(s, force);
565 k = user_stop_service(u);
570 k = user_stop_slice(u);
581 int user_finalize(User *u) {
588 log_debug("User %s logged out.", u->name);
590 LIST_FOREACH(sessions_by_user, s, u->sessions) {
591 k = session_finalize(s);
596 /* Kill XDG_RUNTIME_DIR */
597 k = user_remove_runtime_path(u);
601 /* Clean SysV + POSIX IPC objects */
602 if (u->manager->remove_ipc) {
603 k = clean_ipc(u->uid);
608 unlink(u->state_file);
609 user_add_to_gc_queue(u);
612 user_send_signal(u, false);
619 int user_get_idle_hint(User *u, dual_timestamp *t) {
621 bool idle_hint = true;
622 dual_timestamp ts = { 0, 0 };
626 LIST_FOREACH(sessions_by_user, s, u->sessions) {
630 ih = session_get_idle_hint(s, &k);
636 if (k.monotonic < ts.monotonic)
642 } else if (idle_hint) {
644 if (k.monotonic > ts.monotonic)
655 int user_check_linger_file(User *u) {
656 _cleanup_free_ char *cc = NULL;
659 cc = cescape(u->name);
663 p = strjoina("/var/lib/systemd/linger/", cc);
665 return access(p, F_OK) >= 0;
668 bool user_check_gc(User *u, bool drop_not_started) {
671 if (drop_not_started && !u->started)
677 if (user_check_linger_file(u) > 0)
680 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
683 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
689 void user_add_to_gc_queue(User *u) {
695 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
696 u->in_gc_queue = true;
699 UserState user_get_state(User *u) {
707 if (u->slice_job || u->service_job)
711 bool all_closing = true;
713 LIST_FOREACH(sessions_by_user, i, u->sessions) {
716 state = session_get_state(i);
717 if (state == SESSION_ACTIVE)
719 if (state != SESSION_CLOSING)
723 return all_closing ? USER_CLOSING : USER_ONLINE;
726 if (user_check_linger_file(u) > 0)
727 return USER_LINGERING;
732 int user_kill(User *u, int signo) {
738 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
741 void user_elect_display(User *u) {
742 Session *graphical = NULL, *text = NULL, *other = NULL, *s;
746 /* This elects a primary session for each user, which we call
747 * the "display". We try to keep the assignment stable, but we
748 * "upgrade" to better choices. */
750 LIST_FOREACH(sessions_by_user, s, u->sessions) {
752 if (s->class != SESSION_USER)
758 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
760 else if (s->type == SESSION_TTY)
768 u->display->class != SESSION_USER ||
769 u->display->stopping ||
770 !SESSION_TYPE_IS_GRAPHICAL(u->display->type))) {
771 u->display = graphical;
777 u->display->class != SESSION_USER ||
778 u->display->stopping ||
779 u->display->type != SESSION_TTY)) {
786 u->display->class != SESSION_USER ||
787 u->display->stopping))
791 static const char* const user_state_table[_USER_STATE_MAX] = {
792 [USER_OFFLINE] = "offline",
793 [USER_OPENING] = "opening",
794 [USER_LINGERING] = "lingering",
795 [USER_ONLINE] = "online",
796 [USER_ACTIVE] = "active",
797 [USER_CLOSING] = "closing"
800 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
802 int config_parse_tmpfs_size(
804 const char *filename,
807 unsigned section_line,
823 e = endswith(rvalue, "%");
829 ul = strtoul(rvalue, &f, 10);
830 if (errno != 0 || f != e) {
831 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
835 if (ul <= 0 || ul >= 100) {
836 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
840 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
844 r = parse_size(rvalue, 1024, &o);
845 if (r < 0 || (off_t) (size_t) o != o) {
846 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
850 *sz = PAGE_ALIGN((size_t) o);