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/>.
32 #include "unit-name.h"
34 #include "bus-error.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(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))
148 "REALTIME="USEC_FMT"\n"
149 "MONOTONIC="USEC_FMT"\n",
150 u->timestamp.realtime,
151 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 %s: %s", u->state_file, 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 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
339 char lu[DECIMAL_STR_MAX(unsigned long) + 1], *slice;
340 sprintf(lu, "%lu", (unsigned long) u->uid);
342 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
346 r = manager_start_unit(u->manager, slice, &error, &job);
348 log_error("Failed to start user slice: %s", bus_error_message(&error, r));
359 hashmap_put(u->manager->user_units, u->slice, u);
364 static int user_start_service(User *u) {
365 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
372 char lu[DECIMAL_STR_MAX(unsigned long) + 1], *service;
373 sprintf(lu, "%lu", (unsigned long) u->uid);
375 service = unit_name_build("user", lu, ".service");
379 r = manager_start_unit(u->manager, service, &error, &job);
381 log_error("Failed to start user service: %s", bus_error_message(&error, r));
384 u->service = service;
386 free(u->service_job);
387 u->service_job = job;
392 hashmap_put(u->manager->user_units, u->service, u);
397 int user_start(User *u) {
405 log_debug("New user %s logged in.", u->name);
407 /* Make XDG_RUNTIME_DIR */
408 r = user_mkdir_runtime_path(u);
413 r = user_start_slice(u);
417 /* Spawn user systemd */
418 r = user_start_service(u);
422 if (!dual_timestamp_is_set(&u->timestamp))
423 dual_timestamp_get(&u->timestamp);
427 /* Save new user data */
430 user_send_signal(u, true);
435 static int user_stop_slice(User *u) {
436 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
445 r = manager_stop_unit(u->manager, u->slice, &error, &job);
447 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
457 static int user_stop_service(User *u) {
458 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
467 r = manager_stop_unit(u->manager, u->service, &error, &job);
469 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
473 free(u->service_job);
474 u->service_job = job;
479 static int user_remove_runtime_path(User *u) {
484 if (!u->runtime_path)
487 r = rm_rf(u->runtime_path, false, true, false);
489 log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
491 free(u->runtime_path);
492 u->runtime_path = NULL;
497 int user_stop(User *u) {
502 LIST_FOREACH(sessions_by_user, s, u->sessions) {
509 k = user_stop_service(u);
514 k = user_stop_slice(u);
525 int user_finalize(User *u) {
532 log_debug("User %s logged out.", u->name);
534 LIST_FOREACH(sessions_by_user, s, u->sessions) {
535 k = session_finalize(s);
540 /* Kill XDG_RUNTIME_DIR */
541 k = user_remove_runtime_path(u);
545 unlink(u->state_file);
546 user_add_to_gc_queue(u);
549 user_send_signal(u, false);
556 int user_get_idle_hint(User *u, dual_timestamp *t) {
558 bool idle_hint = true;
559 dual_timestamp ts = { 0, 0 };
563 LIST_FOREACH(sessions_by_user, s, u->sessions) {
567 ih = session_get_idle_hint(s, &k);
573 if (k.monotonic < ts.monotonic)
579 } else if (idle_hint) {
581 if (k.monotonic > ts.monotonic)
592 int user_check_linger_file(User *u) {
593 _cleanup_free_ char *cc = NULL;
596 cc = cescape(u->name);
600 p = strappenda("/var/lib/systemd/linger/", cc);
602 return access(p, F_OK) >= 0;
605 bool user_check_gc(User *u, bool drop_not_started) {
608 if (drop_not_started && !u->started)
614 if (user_check_linger_file(u) > 0)
617 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
620 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
626 void user_add_to_gc_queue(User *u) {
632 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
633 u->in_gc_queue = true;
636 UserState user_get_state(User *u) {
644 if (u->slice_job || u->service_job)
648 bool all_closing = true;
650 LIST_FOREACH(sessions_by_user, i, u->sessions) {
651 if (session_is_active(i))
653 if (session_get_state(i) != SESSION_CLOSING)
657 return all_closing ? USER_CLOSING : USER_ONLINE;
660 if (user_check_linger_file(u) > 0)
661 return USER_LINGERING;
666 int user_kill(User *u, int signo) {
672 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
675 static const char* const user_state_table[_USER_STATE_MAX] = {
676 [USER_OFFLINE] = "offline",
677 [USER_OPENING] = "opening",
678 [USER_LINGERING] = "lingering",
679 [USER_ONLINE] = "online",
680 [USER_ACTIVE] = "active",
681 [USER_CLOSING] = "closing"
684 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);