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);
85 free(u->runtime_path);
87 hashmap_remove(u->manager->users, UID_TO_PTR(u->uid));
94 int user_save(User *u) {
95 _cleanup_free_ char *temp_path = NULL;
96 _cleanup_fclose_ FILE *f = NULL;
100 assert(u->state_file);
105 r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
109 r = fopen_temporary(u->state_file, &f, &temp_path);
113 fchmod(fileno(f), 0644);
116 "# This is private data. Do not parse.\n"
120 user_state_to_string(user_get_state(u)));
123 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
126 fprintf(f, "DISPLAY=%s\n", u->display->id);
128 if (dual_timestamp_is_set(&u->timestamp))
130 "REALTIME="USEC_FMT"\n"
131 "MONOTONIC="USEC_FMT"\n",
132 u->timestamp.realtime,
133 u->timestamp.monotonic);
139 fputs("SESSIONS=", f);
141 LIST_FOREACH(sessions_by_user, i, u->sessions) {
150 fputs("\nSEATS=", f);
152 LIST_FOREACH(sessions_by_user, i, u->sessions) {
161 fputs(i->seat->id, f);
164 fputs("\nACTIVE_SESSIONS=", f);
166 LIST_FOREACH(sessions_by_user, i, u->sessions) {
167 if (!session_is_active(i))
178 fputs("\nONLINE_SESSIONS=", f);
180 LIST_FOREACH(sessions_by_user, i, u->sessions) {
181 if (session_get_state(i) == SESSION_CLOSING)
192 fputs("\nACTIVE_SEATS=", f);
194 LIST_FOREACH(sessions_by_user, i, u->sessions) {
195 if (!session_is_active(i) || !i->seat)
203 fputs(i->seat->id, f);
206 fputs("\nONLINE_SEATS=", f);
208 LIST_FOREACH(sessions_by_user, i, u->sessions) {
209 if (session_get_state(i) == SESSION_CLOSING || !i->seat)
217 fputs(i->seat->id, f);
224 if (ferror(f) || rename(temp_path, u->state_file) < 0) {
226 unlink(u->state_file);
232 log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
237 int user_load(User *u) {
238 _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
244 r = parse_env_file(u->state_file, NEWLINE,
245 "RUNTIME", &u->runtime_path,
247 "REALTIME", &realtime,
248 "MONOTONIC", &monotonic,
254 log_error_errno(r, "Failed to read %s: %m", u->state_file);
259 s = hashmap_get(u->manager->sessions, display);
261 if (s && s->display && display_is_local(s->display))
265 unsigned long long l;
266 if (sscanf(realtime, "%llu", &l) > 0)
267 u->timestamp.realtime = l;
271 unsigned long long l;
272 if (sscanf(monotonic, "%llu", &l) > 0)
273 u->timestamp.monotonic = l;
279 static int user_mkdir_runtime_path(User *u) {
285 r = mkdir_safe_label("/run/user", 0755, 0, 0);
287 return log_error_errno(r, "Failed to create /run/user: %m");
289 if (!u->runtime_path) {
290 if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
295 if (path_is_mount_point(p, false) <= 0) {
296 _cleanup_free_ char *t = NULL;
298 (void) mkdir(p, 0700);
301 r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
303 r = asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
309 r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
311 if (errno != EPERM) {
312 r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", p);
316 /* Lacking permissions, maybe
317 * CAP_SYS_ADMIN-less container? In this case,
318 * just use a normal directory. */
320 r = chmod_and_chown(p, 0700, u->uid, u->gid);
322 log_error_errno(r, "Failed to change runtime directory ownership and mode: %m");
333 /* Try to clean up, but ignore errors */
338 u->runtime_path = NULL;
342 int user_start(User *u) {
350 log_debug("New user %s logged in.", u->name);
352 /* Make XDG_RUNTIME_DIR */
353 r = user_mkdir_runtime_path(u);
357 if (!dual_timestamp_is_set(&u->timestamp))
358 dual_timestamp_get(&u->timestamp);
362 /* Save new user data */
365 user_send_signal(u, true);
370 static int user_remove_runtime_path(User *u) {
375 if (!u->runtime_path)
378 r = rm_rf(u->runtime_path, 0);
380 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
382 /* Ignore cases where the directory isn't mounted, as that's
383 * quite possible, if we lacked the permissions to mount
385 r = umount2(u->runtime_path, MNT_DETACH);
386 if (r < 0 && errno != EINVAL && errno != ENOENT)
387 log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
389 r = rm_rf(u->runtime_path, REMOVE_ROOT);
391 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
393 free(u->runtime_path);
394 u->runtime_path = NULL;
399 int user_stop(User *u, bool force) {
404 /* Stop jobs have already been queued */
410 LIST_FOREACH(sessions_by_user, s, u->sessions) {
411 k = session_stop(s, force);
423 int user_finalize(User *u) {
430 log_debug("User %s logged out.", u->name);
432 LIST_FOREACH(sessions_by_user, s, u->sessions) {
433 k = session_finalize(s);
438 /* Kill XDG_RUNTIME_DIR */
439 k = user_remove_runtime_path(u);
443 /* Clean SysV + POSIX IPC objects */
444 if (u->manager->remove_ipc) {
445 k = clean_ipc(u->uid);
450 unlink(u->state_file);
451 user_add_to_gc_queue(u);
454 user_send_signal(u, false);
461 int user_get_idle_hint(User *u, dual_timestamp *t) {
463 bool idle_hint = true;
464 dual_timestamp ts = { 0, 0 };
468 LIST_FOREACH(sessions_by_user, s, u->sessions) {
472 ih = session_get_idle_hint(s, &k);
478 if (k.monotonic < ts.monotonic)
484 } else if (idle_hint) {
486 if (k.monotonic > ts.monotonic)
497 int user_check_linger_file(User *u) {
498 _cleanup_free_ char *cc = NULL;
501 cc = cescape(u->name);
505 p = strjoina("/var/lib/systemd/linger/", cc);
507 return access(p, F_OK) >= 0;
510 bool user_check_gc(User *u, bool drop_not_started) {
513 if (drop_not_started && !u->started)
519 if (user_check_linger_file(u) > 0)
525 void user_add_to_gc_queue(User *u) {
531 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
532 u->in_gc_queue = true;
535 UserState user_get_state(User *u) {
544 bool all_closing = true;
546 LIST_FOREACH(sessions_by_user, i, u->sessions) {
549 state = session_get_state(i);
550 if (state == SESSION_ACTIVE)
552 if (state != SESSION_CLOSING)
556 return all_closing ? USER_CLOSING : USER_ONLINE;
559 if (user_check_linger_file(u) > 0)
560 return USER_LINGERING;
565 int user_kill(User *u, int signo) {
571 LIST_FOREACH(sessions_by_user, s, u->sessions) {
572 int r = session_kill(s, KILL_ALL, signo);
573 if (res == 0 && r < 0)
580 void user_elect_display(User *u) {
581 Session *graphical = NULL, *text = NULL, *other = NULL, *s;
585 /* This elects a primary session for each user, which we call
586 * the "display". We try to keep the assignment stable, but we
587 * "upgrade" to better choices. */
589 LIST_FOREACH(sessions_by_user, s, u->sessions) {
591 if (s->class != SESSION_USER)
597 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
599 else if (s->type == SESSION_TTY)
607 u->display->class != SESSION_USER ||
608 u->display->stopping ||
609 !SESSION_TYPE_IS_GRAPHICAL(u->display->type))) {
610 u->display = graphical;
616 u->display->class != SESSION_USER ||
617 u->display->stopping ||
618 u->display->type != SESSION_TTY)) {
625 u->display->class != SESSION_USER ||
626 u->display->stopping))
630 static const char* const user_state_table[_USER_STATE_MAX] = {
631 [USER_OFFLINE] = "offline",
632 [USER_OPENING] = "opening",
633 [USER_LINGERING] = "lingering",
634 [USER_ONLINE] = "online",
635 [USER_ACTIVE] = "active",
636 [USER_CLOSING] = "closing"
639 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
641 int config_parse_tmpfs_size(
643 const char *filename,
646 unsigned section_line,
662 e = endswith(rvalue, "%");
668 ul = strtoul(rvalue, &f, 10);
669 if (errno != 0 || f != e) {
670 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
674 if (ul <= 0 || ul >= 100) {
675 log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
679 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
683 r = parse_size(rvalue, 1024, &o);
684 if (r < 0 || (off_t) (size_t) o != o) {
685 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
689 *sz = PAGE_ALIGN((size_t) o);