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 "logind-user.h"
40 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
50 u->name = strdup(name);
54 if (asprintf(&u->state_file, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
57 if (hashmap_put(m->users, ULONG_TO_PTR((unsigned long) uid), u) < 0)
74 void user_free(User *u) {
78 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
81 session_free(u->sessions);
84 hashmap_remove(u->manager->user_units, u->slice);
89 hashmap_remove(u->manager->user_units, u->service);
96 free(u->runtime_path);
98 hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid));
105 int user_save(User *u) {
106 _cleanup_free_ char *temp_path = NULL;
107 _cleanup_fclose_ FILE *f = NULL;
111 assert(u->state_file);
116 r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
120 r = fopen_temporary(u->state_file, &f, &temp_path);
124 fchmod(fileno(f), 0644);
127 "# This is private data. Do not parse.\n"
131 user_state_to_string(user_get_state(u)));
134 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
137 fprintf(f, "SERVICE=%s\n", u->service);
139 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
142 fprintf(f, "SLICE=%s\n", u->slice);
144 fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
147 fprintf(f, "DISPLAY=%s\n", u->display->id);
149 if (dual_timestamp_is_set(&u->timestamp))
151 "REALTIME="USEC_FMT"\n"
152 "MONOTONIC="USEC_FMT"\n",
153 u->timestamp.realtime,
154 u->timestamp.monotonic);
160 fputs("SESSIONS=", f);
162 LIST_FOREACH(sessions_by_user, i, u->sessions) {
171 fputs("\nSEATS=", f);
173 LIST_FOREACH(sessions_by_user, i, u->sessions) {
182 fputs(i->seat->id, f);
185 fputs("\nACTIVE_SESSIONS=", f);
187 LIST_FOREACH(sessions_by_user, i, u->sessions) {
188 if (!session_is_active(i))
199 fputs("\nONLINE_SESSIONS=", f);
201 LIST_FOREACH(sessions_by_user, i, u->sessions) {
202 if (session_get_state(i) == SESSION_CLOSING)
213 fputs("\nACTIVE_SEATS=", f);
215 LIST_FOREACH(sessions_by_user, i, u->sessions) {
216 if (!session_is_active(i) || !i->seat)
224 fputs(i->seat->id, f);
227 fputs("\nONLINE_SEATS=", f);
229 LIST_FOREACH(sessions_by_user, i, u->sessions) {
230 if (session_get_state(i) == SESSION_CLOSING || !i->seat)
238 fputs(i->seat->id, f);
245 if (ferror(f) || rename(temp_path, u->state_file) < 0) {
247 unlink(u->state_file);
253 log_error("Failed to save user data %s: %s", u->state_file, strerror(-r));
258 int user_load(User *u) {
259 _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
265 r = parse_env_file(u->state_file, NEWLINE,
266 "RUNTIME", &u->runtime_path,
267 "SERVICE", &u->service,
268 "SERVICE_JOB", &u->service_job,
270 "SLICE_JOB", &u->slice_job,
272 "REALTIME", &realtime,
273 "MONOTONIC", &monotonic,
279 log_error("Failed to read %s: %s", u->state_file, strerror(-r));
284 s = hashmap_get(u->manager->sessions, display);
286 if (s && s->display && display_is_local(s->display))
290 unsigned long long l;
291 if (sscanf(realtime, "%llu", &l) > 0)
292 u->timestamp.realtime = l;
296 unsigned long long l;
297 if (sscanf(monotonic, "%llu", &l) > 0)
298 u->timestamp.monotonic = l;
304 static int user_mkdir_runtime_path(User *u) {
310 r = mkdir_safe_label("/run/user", 0755, 0, 0);
312 log_error("Failed to create /run/user: %s", strerror(-r));
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;
327 if (asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size) < 0) {
332 r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
334 log_error("Failed to mount per-user tmpfs directory %s: %s", p, strerror(-r));
344 u->runtime_path = NULL;
348 static int user_start_slice(User *u) {
355 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
356 char lu[DECIMAL_STR_MAX(unsigned long) + 1], *slice;
357 sprintf(lu, "%lu", (unsigned long) u->uid);
359 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
363 r = manager_start_unit(u->manager, slice, &error, &job);
365 log_error("Failed to start user slice: %s", bus_error_message(&error, r));
376 hashmap_put(u->manager->user_units, u->slice, u);
381 static int user_start_service(User *u) {
382 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
389 char lu[DECIMAL_STR_MAX(unsigned long) + 1], *service;
390 sprintf(lu, "%lu", (unsigned long) u->uid);
392 service = unit_name_build("user", lu, ".service");
396 r = manager_start_unit(u->manager, service, &error, &job);
398 log_error("Failed to start user service: %s", bus_error_message(&error, r));
401 u->service = service;
403 free(u->service_job);
404 u->service_job = job;
409 hashmap_put(u->manager->user_units, u->service, u);
414 int user_start(User *u) {
422 log_debug("New user %s logged in.", u->name);
424 /* Make XDG_RUNTIME_DIR */
425 r = user_mkdir_runtime_path(u);
430 r = user_start_slice(u);
434 /* Spawn user systemd */
435 r = user_start_service(u);
439 if (!dual_timestamp_is_set(&u->timestamp))
440 dual_timestamp_get(&u->timestamp);
444 /* Save new user data */
447 user_send_signal(u, true);
452 static int user_stop_slice(User *u) {
453 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
462 r = manager_stop_unit(u->manager, u->slice, &error, &job);
464 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
474 static int user_stop_service(User *u) {
475 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
484 r = manager_stop_unit(u->manager, u->service, &error, &job);
486 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
490 free(u->service_job);
491 u->service_job = job;
496 static int user_remove_runtime_path(User *u) {
501 if (!u->runtime_path)
504 r = rm_rf(u->runtime_path, false, false, false);
506 log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
508 if (umount2(u->runtime_path, MNT_DETACH) < 0)
509 log_error("Failed to unmount user runtime directory %s: %m", u->runtime_path);
511 r = rm_rf(u->runtime_path, false, true, false);
513 log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
515 free(u->runtime_path);
516 u->runtime_path = NULL;
521 int user_stop(User *u, bool force) {
526 /* Stop jobs have already been queued */
532 LIST_FOREACH(sessions_by_user, s, u->sessions) {
533 k = session_stop(s, force);
539 k = user_stop_service(u);
544 k = user_stop_slice(u);
555 int user_finalize(User *u) {
562 log_debug("User %s logged out.", u->name);
564 LIST_FOREACH(sessions_by_user, s, u->sessions) {
565 k = session_finalize(s);
570 /* Kill XDG_RUNTIME_DIR */
571 k = user_remove_runtime_path(u);
575 unlink(u->state_file);
576 user_add_to_gc_queue(u);
579 user_send_signal(u, false);
586 int user_get_idle_hint(User *u, dual_timestamp *t) {
588 bool idle_hint = true;
589 dual_timestamp ts = { 0, 0 };
593 LIST_FOREACH(sessions_by_user, s, u->sessions) {
597 ih = session_get_idle_hint(s, &k);
603 if (k.monotonic < ts.monotonic)
609 } else if (idle_hint) {
611 if (k.monotonic > ts.monotonic)
622 int user_check_linger_file(User *u) {
623 _cleanup_free_ char *cc = NULL;
626 cc = cescape(u->name);
630 p = strappenda("/var/lib/systemd/linger/", cc);
632 return access(p, F_OK) >= 0;
635 bool user_check_gc(User *u, bool drop_not_started) {
638 if (drop_not_started && !u->started)
644 if (user_check_linger_file(u) > 0)
647 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
650 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
656 void user_add_to_gc_queue(User *u) {
662 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
663 u->in_gc_queue = true;
666 UserState user_get_state(User *u) {
674 if (u->slice_job || u->service_job)
678 bool all_closing = true;
680 LIST_FOREACH(sessions_by_user, i, u->sessions) {
683 state = session_get_state(i);
684 if (state == SESSION_ACTIVE)
686 if (state != SESSION_CLOSING)
690 return all_closing ? USER_CLOSING : USER_ONLINE;
693 if (user_check_linger_file(u) > 0)
694 return USER_LINGERING;
699 int user_kill(User *u, int signo) {
705 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
708 static const char* const user_state_table[_USER_STATE_MAX] = {
709 [USER_OFFLINE] = "offline",
710 [USER_OPENING] = "opening",
711 [USER_LINGERING] = "lingering",
712 [USER_ONLINE] = "online",
713 [USER_ACTIVE] = "active",
714 [USER_CLOSING] = "closing"
717 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
719 int config_parse_tmpfs_size(
721 const char *filename,
724 unsigned section_line,
740 e = endswith(rvalue, "%");
746 ul = strtoul(rvalue, &f, 10);
747 if (errno != 0 || f != e) {
748 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
752 if (ul <= 0 || ul >= 100) {
753 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
757 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
761 r = parse_size(rvalue, 1024, &o);
762 if (r < 0 || (off_t) (size_t) o != o) {
763 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
767 *sz = PAGE_ALIGN((size_t) o);