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/>.
28 #include "cgroup-util.h"
33 #include "unit-name.h"
34 #include "dbus-common.h"
35 #include "logind-user.h"
37 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
47 u->name = strdup(name);
51 if (asprintf(&u->state_file, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
54 if (hashmap_put(m->users, ULONG_TO_PTR((unsigned long) uid), u) < 0)
71 void user_free(User *u) {
75 LIST_REMOVE(User, gc_queue, u->manager->user_gc_queue, u);
78 session_free(u->sessions);
81 hashmap_remove(u->manager->user_units, u->slice);
86 hashmap_remove(u->manager->user_units, u->service);
93 free(u->runtime_path);
95 hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid));
102 int user_save(User *u) {
103 _cleanup_free_ char *temp_path = NULL;
104 _cleanup_fclose_ FILE *f = NULL;
108 assert(u->state_file);
113 r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
117 r = fopen_temporary(u->state_file, &f, &temp_path);
121 fchmod(fileno(f), 0644);
124 "# This is private data. Do not parse.\n"
128 user_state_to_string(user_get_state(u)));
131 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
134 fprintf(f, "SERVICE=%s\n", u->service);
136 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
139 fprintf(f, "SLICE=%s\n", u->slice);
141 fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
144 fprintf(f, "DISPLAY=%s\n", u->display->id);
146 if (dual_timestamp_is_set(&u->timestamp))
150 (unsigned long long) u->timestamp.realtime,
151 (unsigned long long) u->timestamp.monotonic);
157 fputs("SESSIONS=", f);
159 LIST_FOREACH(sessions_by_user, i, u->sessions) {
168 fputs("\nSEATS=", f);
170 LIST_FOREACH(sessions_by_user, i, u->sessions) {
179 fputs(i->seat->id, f);
182 fputs("\nACTIVE_SESSIONS=", f);
184 LIST_FOREACH(sessions_by_user, i, u->sessions) {
185 if (!session_is_active(i))
196 fputs("\nONLINE_SESSIONS=", f);
198 LIST_FOREACH(sessions_by_user, i, u->sessions) {
199 if (session_get_state(i) == SESSION_CLOSING)
210 fputs("\nACTIVE_SEATS=", f);
212 LIST_FOREACH(sessions_by_user, i, u->sessions) {
213 if (!session_is_active(i) || !i->seat)
221 fputs(i->seat->id, f);
224 fputs("\nONLINE_SEATS=", f);
226 LIST_FOREACH(sessions_by_user, i, u->sessions) {
227 if (session_get_state(i) == SESSION_CLOSING || !i->seat)
235 fputs(i->seat->id, f);
242 if (ferror(f) || rename(temp_path, u->state_file) < 0) {
244 unlink(u->state_file);
250 log_error("Failed to save user data for %s: %s", u->name, strerror(-r));
255 int user_load(User *u) {
256 _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
262 r = parse_env_file(u->state_file, NEWLINE,
263 "RUNTIME", &u->runtime_path,
264 "SERVICE", &u->service,
265 "SERVICE_JOB", &u->service_job,
267 "SLICE_JOB", &u->slice_job,
269 "REALTIME", &realtime,
270 "MONOTONIC", &monotonic,
276 log_error("Failed to read %s: %s", u->state_file, strerror(-r));
281 s = hashmap_get(u->manager->sessions, display);
283 if (s && s->display && display_is_local(s->display))
287 unsigned long long l;
288 if (sscanf(realtime, "%llu", &l) > 0)
289 u->timestamp.realtime = l;
293 unsigned long long l;
294 if (sscanf(monotonic, "%llu", &l) > 0)
295 u->timestamp.monotonic = l;
301 static int user_mkdir_runtime_path(User *u) {
307 r = mkdir_safe_label("/run/user", 0755, 0, 0);
309 log_error("Failed to create /run/user: %s", strerror(-r));
313 if (!u->runtime_path) {
314 if (asprintf(&p, "/run/user/%lu", (unsigned long) u->uid) < 0)
319 r = mkdir_safe_label(p, 0700, u->uid, u->gid);
321 log_error("Failed to create runtime directory %s: %s", p, strerror(-r));
323 u->runtime_path = NULL;
331 static int user_start_slice(User *u) {
338 dbus_error_init(&error);
341 char lu[DECIMAL_STR_MAX(unsigned long) + 1], *slice;
342 sprintf(lu, "%lu", (unsigned long) u->uid);
344 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
348 r = manager_start_unit(u->manager, slice, &error, &job);
350 log_error("Failed to start user slice: %s", bus_error(&error, r));
351 dbus_error_free(&error);
363 hashmap_put(u->manager->user_units, u->slice, u);
368 static int user_start_service(User *u) {
375 dbus_error_init(&error);
378 char lu[DECIMAL_STR_MAX(unsigned long) + 1], *service;
379 sprintf(lu, "%lu", (unsigned long) u->uid);
381 service = unit_name_build("user", lu, ".service");
385 r = manager_start_unit(u->manager, service, &error, &job);
387 log_error("Failed to start user service: %s", bus_error(&error, r));
388 dbus_error_free(&error);
392 u->service = service;
394 free(u->service_job);
395 u->service_job = job;
400 hashmap_put(u->manager->user_units, u->service, u);
405 int user_start(User *u) {
413 log_debug("New user %s logged in.", u->name);
415 /* Make XDG_RUNTIME_DIR */
416 r = user_mkdir_runtime_path(u);
421 r = user_start_slice(u);
425 /* Spawn user systemd */
426 r = user_start_service(u);
430 if (!dual_timestamp_is_set(&u->timestamp))
431 dual_timestamp_get(&u->timestamp);
435 /* Save new user data */
438 user_send_signal(u, true);
443 static int user_stop_slice(User *u) {
450 dbus_error_init(&error);
455 r = manager_stop_unit(u->manager, u->slice, &error, &job);
457 log_error("Failed to stop user slice: %s", bus_error(&error, r));
458 dbus_error_free(&error);
468 static int user_stop_service(User *u) {
475 dbus_error_init(&error);
480 r = manager_stop_unit(u->manager, u->service, &error, &job);
482 log_error("Failed to stop user service: %s", bus_error(&error, r));
483 dbus_error_free(&error);
487 free(u->service_job);
488 u->service_job = job;
493 static int user_remove_runtime_path(User *u) {
498 if (!u->runtime_path)
501 r = rm_rf(u->runtime_path, false, true, false);
503 log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
505 free(u->runtime_path);
506 u->runtime_path = NULL;
511 int user_stop(User *u) {
516 LIST_FOREACH(sessions_by_user, s, u->sessions) {
523 k = user_stop_service(u);
528 k = user_stop_slice(u);
537 int user_finalize(User *u) {
544 log_debug("User %s logged out.", u->name);
546 LIST_FOREACH(sessions_by_user, s, u->sessions) {
547 k = session_finalize(s);
552 /* Kill XDG_RUNTIME_DIR */
553 k = user_remove_runtime_path(u);
557 unlink(u->state_file);
558 user_add_to_gc_queue(u);
561 user_send_signal(u, false);
568 int user_get_idle_hint(User *u, dual_timestamp *t) {
570 bool idle_hint = true;
571 dual_timestamp ts = { 0, 0 };
575 LIST_FOREACH(sessions_by_user, s, u->sessions) {
579 ih = session_get_idle_hint(s, &k);
585 if (k.monotonic < ts.monotonic)
591 } else if (idle_hint) {
593 if (k.monotonic > ts.monotonic)
604 static int user_check_linger_file(User *u) {
608 if (asprintf(&p, "/var/lib/systemd/linger/%s", u->name) < 0)
611 r = access(p, F_OK) >= 0;
617 int user_check_gc(User *u, bool drop_not_started) {
620 if (drop_not_started && !u->started)
626 if (user_check_linger_file(u) > 0)
629 if (u->slice_job || u->service_job)
632 if (u->slice && manager_unit_is_active(u->manager, u->slice) != 0)
635 if (u->service && manager_unit_is_active(u->manager, u->service) != 0)
641 void user_add_to_gc_queue(User *u) {
647 LIST_PREPEND(User, gc_queue, u->manager->user_gc_queue, u);
648 u->in_gc_queue = true;
651 UserState user_get_state(User *u) {
653 bool all_closing = true;
660 if (u->slice_job || u->service_job)
663 LIST_FOREACH(sessions_by_user, i, u->sessions) {
664 if (session_is_active(i))
666 if (session_get_state(i) != SESSION_CLOSING)
671 return all_closing ? USER_CLOSING : USER_ONLINE;
673 if (user_check_linger_file(u) > 0)
674 return USER_LINGERING;
679 int user_kill(User *u, int signo) {
685 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
688 static const char* const user_state_table[_USER_STATE_MAX] = {
689 [USER_OFFLINE] = "offline",
690 [USER_OPENING] = "opening",
691 [USER_LINGERING] = "lingering",
692 [USER_ONLINE] = "online",
693 [USER_ACTIVE] = "active",
694 [USER_CLOSING] = "closing"
697 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);