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))
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 _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);
523 int user_finalize(User *u) {
530 log_debug("User %s logged out.", u->name);
532 LIST_FOREACH(sessions_by_user, s, u->sessions) {
533 k = session_finalize(s);
538 /* Kill XDG_RUNTIME_DIR */
539 k = user_remove_runtime_path(u);
543 unlink(u->state_file);
544 user_add_to_gc_queue(u);
547 user_send_signal(u, false);
554 int user_get_idle_hint(User *u, dual_timestamp *t) {
556 bool idle_hint = true;
557 dual_timestamp ts = { 0, 0 };
561 LIST_FOREACH(sessions_by_user, s, u->sessions) {
565 ih = session_get_idle_hint(s, &k);
571 if (k.monotonic < ts.monotonic)
577 } else if (idle_hint) {
579 if (k.monotonic > ts.monotonic)
590 int user_check_linger_file(User *u) {
591 _cleanup_free_ char *cc = NULL;
594 cc = cescape(u->name);
598 p = strappenda("/var/lib/systemd/linger/", cc);
600 return access(p, F_OK) >= 0;
603 bool user_check_gc(User *u, bool drop_not_started) {
606 if (drop_not_started && !u->started)
612 if (user_check_linger_file(u) > 0)
615 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
618 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
621 if (u->slice && manager_unit_is_active(u->manager, u->slice) != 0)
624 if (u->service && manager_unit_is_active(u->manager, u->service) != 0)
630 void user_add_to_gc_queue(User *u) {
636 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
637 u->in_gc_queue = true;
640 UserState user_get_state(User *u) {
642 bool all_closing = true;
649 if (u->slice_job || u->service_job)
652 LIST_FOREACH(sessions_by_user, i, u->sessions) {
653 if (session_is_active(i))
655 if (session_get_state(i) != SESSION_CLOSING)
660 return all_closing ? USER_CLOSING : USER_ONLINE;
662 if (user_check_linger_file(u) > 0)
663 return USER_LINGERING;
668 int user_kill(User *u, int signo) {
674 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
677 static const char* const user_state_table[_USER_STATE_MAX] = {
678 [USER_OFFLINE] = "offline",
679 [USER_OPENING] = "opening",
680 [USER_LINGERING] = "lingering",
681 [USER_ONLINE] = "online",
682 [USER_ACTIVE] = "active",
683 [USER_CLOSING] = "closing"
686 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);