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, bool force) {
502 /* Stop jobs have already been queued */
508 LIST_FOREACH(sessions_by_user, s, u->sessions) {
509 k = session_stop(s, force);
515 k = user_stop_service(u);
520 k = user_stop_slice(u);
531 int user_finalize(User *u) {
538 log_debug("User %s logged out.", u->name);
540 LIST_FOREACH(sessions_by_user, s, u->sessions) {
541 k = session_finalize(s);
546 /* Kill XDG_RUNTIME_DIR */
547 k = user_remove_runtime_path(u);
551 unlink(u->state_file);
552 user_add_to_gc_queue(u);
555 user_send_signal(u, false);
562 int user_get_idle_hint(User *u, dual_timestamp *t) {
564 bool idle_hint = true;
565 dual_timestamp ts = { 0, 0 };
569 LIST_FOREACH(sessions_by_user, s, u->sessions) {
573 ih = session_get_idle_hint(s, &k);
579 if (k.monotonic < ts.monotonic)
585 } else if (idle_hint) {
587 if (k.monotonic > ts.monotonic)
598 int user_check_linger_file(User *u) {
599 _cleanup_free_ char *cc = NULL;
602 cc = cescape(u->name);
606 p = strappenda("/var/lib/systemd/linger/", cc);
608 return access(p, F_OK) >= 0;
611 bool user_check_gc(User *u, bool drop_not_started) {
614 if (drop_not_started && !u->started)
620 if (user_check_linger_file(u) > 0)
623 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
626 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
632 void user_add_to_gc_queue(User *u) {
638 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
639 u->in_gc_queue = true;
642 UserState user_get_state(User *u) {
650 if (u->slice_job || u->service_job)
654 bool all_closing = true;
656 LIST_FOREACH(sessions_by_user, i, u->sessions) {
659 state = session_get_state(i);
660 if (state == SESSION_ACTIVE)
662 if (state != SESSION_CLOSING)
666 return all_closing ? USER_CLOSING : USER_ONLINE;
669 if (user_check_linger_file(u) > 0)
670 return USER_LINGERING;
675 int user_kill(User *u, int signo) {
681 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
684 static const char* const user_state_table[_USER_STATE_MAX] = {
685 [USER_OFFLINE] = "offline",
686 [USER_OPENING] = "opening",
687 [USER_LINGERING] = "lingering",
688 [USER_ONLINE] = "online",
689 [USER_ACTIVE] = "active",
690 [USER_CLOSING] = "closing"
693 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);