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, ULONG_TO_PTR((unsigned long) 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, ULONG_TO_PTR((unsigned long) 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("Failed to save user data %s: %s", u->state_file, strerror(-r));
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("Failed to read %s: %s", u->state_file, strerror(-r));
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 log_error("Failed to create /run/user: %s", strerror(-r));
318 if (!u->runtime_path) {
319 if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
324 if (path_is_mount_point(p, false) <= 0) {
325 _cleanup_free_ char *t = NULL;
330 r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
332 r = asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
339 r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
341 log_error("Failed to mount per-user tmpfs directory %s: %s", p, strerror(-r));
351 u->runtime_path = NULL;
355 static int user_start_slice(User *u) {
362 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
363 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
364 sprintf(lu, UID_FMT, u->uid);
366 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
370 r = manager_start_unit(u->manager, slice, &error, &job);
372 log_error("Failed to start user slice: %s", bus_error_message(&error, r));
383 hashmap_put(u->manager->user_units, u->slice, u);
388 static int user_start_service(User *u) {
389 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
396 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
397 sprintf(lu, UID_FMT, u->uid);
399 service = unit_name_build("user", lu, ".service");
403 r = manager_start_unit(u->manager, service, &error, &job);
405 log_error("Failed to start user service: %s", bus_error_message(&error, r));
408 u->service = service;
410 free(u->service_job);
411 u->service_job = job;
416 hashmap_put(u->manager->user_units, u->service, u);
421 int user_start(User *u) {
429 log_debug("New user %s logged in.", u->name);
431 /* Make XDG_RUNTIME_DIR */
432 r = user_mkdir_runtime_path(u);
437 r = user_start_slice(u);
441 /* Spawn user systemd */
442 r = user_start_service(u);
446 if (!dual_timestamp_is_set(&u->timestamp))
447 dual_timestamp_get(&u->timestamp);
451 /* Save new user data */
454 user_send_signal(u, true);
459 static int user_stop_slice(User *u) {
460 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
469 r = manager_stop_unit(u->manager, u->slice, &error, &job);
471 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
481 static int user_stop_service(User *u) {
482 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
491 r = manager_stop_unit(u->manager, u->service, &error, &job);
493 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
497 free(u->service_job);
498 u->service_job = job;
503 static int user_remove_runtime_path(User *u) {
508 if (!u->runtime_path)
511 r = rm_rf(u->runtime_path, false, false, false);
513 log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
515 if (umount2(u->runtime_path, MNT_DETACH) < 0)
516 log_error("Failed to unmount user runtime directory %s: %m", u->runtime_path);
518 r = rm_rf(u->runtime_path, false, true, false);
520 log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
522 free(u->runtime_path);
523 u->runtime_path = NULL;
528 int user_stop(User *u, bool force) {
533 /* Stop jobs have already been queued */
539 LIST_FOREACH(sessions_by_user, s, u->sessions) {
540 k = session_stop(s, force);
546 k = user_stop_service(u);
551 k = user_stop_slice(u);
562 int user_finalize(User *u) {
569 log_debug("User %s logged out.", u->name);
571 LIST_FOREACH(sessions_by_user, s, u->sessions) {
572 k = session_finalize(s);
577 /* Kill XDG_RUNTIME_DIR */
578 k = user_remove_runtime_path(u);
582 /* Clean SysV + POSIX IPC objects */
583 if (u->manager->remove_ipc) {
584 k = clean_ipc(u->uid);
589 unlink(u->state_file);
590 user_add_to_gc_queue(u);
593 user_send_signal(u, false);
600 int user_get_idle_hint(User *u, dual_timestamp *t) {
602 bool idle_hint = true;
603 dual_timestamp ts = { 0, 0 };
607 LIST_FOREACH(sessions_by_user, s, u->sessions) {
611 ih = session_get_idle_hint(s, &k);
617 if (k.monotonic < ts.monotonic)
623 } else if (idle_hint) {
625 if (k.monotonic > ts.monotonic)
636 int user_check_linger_file(User *u) {
637 _cleanup_free_ char *cc = NULL;
640 cc = cescape(u->name);
644 p = strappenda("/var/lib/systemd/linger/", cc);
646 return access(p, F_OK) >= 0;
649 bool user_check_gc(User *u, bool drop_not_started) {
652 if (drop_not_started && !u->started)
658 if (user_check_linger_file(u) > 0)
661 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
664 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
670 void user_add_to_gc_queue(User *u) {
676 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
677 u->in_gc_queue = true;
680 UserState user_get_state(User *u) {
688 if (u->slice_job || u->service_job)
692 bool all_closing = true;
694 LIST_FOREACH(sessions_by_user, i, u->sessions) {
697 state = session_get_state(i);
698 if (state == SESSION_ACTIVE)
700 if (state != SESSION_CLOSING)
704 return all_closing ? USER_CLOSING : USER_ONLINE;
707 if (user_check_linger_file(u) > 0)
708 return USER_LINGERING;
713 int user_kill(User *u, int signo) {
719 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
722 void user_elect_display(User *u) {
723 Session *graphical = NULL, *text = NULL, *other = NULL, *s;
727 /* This elects a primary session for each user, which we call
728 * the "display". We try to keep the assignment stable, but we
729 * "upgrade" to better choices. */
731 LIST_FOREACH(sessions_by_user, s, u->sessions) {
733 if (s->class != SESSION_USER)
739 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
741 else if (s->type == SESSION_TTY)
749 u->display->class != SESSION_USER ||
750 u->display->stopping ||
751 !SESSION_TYPE_IS_GRAPHICAL(u->display->type))) {
752 u->display = graphical;
758 u->display->class != SESSION_USER ||
759 u->display->stopping ||
760 u->display->type != SESSION_TTY)) {
767 u->display->class != SESSION_USER ||
768 u->display->stopping))
772 static const char* const user_state_table[_USER_STATE_MAX] = {
773 [USER_OFFLINE] = "offline",
774 [USER_OPENING] = "opening",
775 [USER_LINGERING] = "lingering",
776 [USER_ONLINE] = "online",
777 [USER_ACTIVE] = "active",
778 [USER_CLOSING] = "closing"
781 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
783 int config_parse_tmpfs_size(
785 const char *filename,
788 unsigned section_line,
804 e = endswith(rvalue, "%");
810 ul = strtoul(rvalue, &f, 10);
811 if (errno != 0 || f != e) {
812 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
816 if (ul <= 0 || ul >= 100) {
817 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
821 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
825 r = parse_size(rvalue, 1024, &o);
826 if (r < 0 || (off_t) (size_t) o != o) {
827 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
831 *sz = PAGE_ALIGN((size_t) o);