chiark / gitweb /
logind: add new user state 'closing'
[elogind.git] / src / login / logind-user.c
index 717f0e20a2c26adcfe8ac91e19d629a449600ba6..4622812e3c66eda4a2153e13f18f8af9864df5db 100644 (file)
@@ -6,16 +6,16 @@
   Copyright 2011 Lennart Poettering
 
   systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
   (at your option) any later version.
 
   systemd is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  General Public License for more details.
+  Lesser General Public License for more details.
 
-  You should have received a copy of the GNU General Public License
+  You should have received a copy of the GNU Lesser General Public License
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
@@ -25,6 +25,7 @@
 
 #include "logind-user.h"
 #include "util.h"
+#include "mkdir.h"
 #include "cgroup-util.h"
 #include "hashmap.h"
 #include "strv.h"
@@ -74,6 +75,8 @@ void user_free(User *u) {
         while (u->sessions)
                 session_free(u->sessions);
 
+        if (u->cgroup_path)
+                hashmap_remove(u->manager->user_cgroups, u->cgroup_path);
         free(u->cgroup_path);
 
         free(u->service);
@@ -97,7 +100,7 @@ int user_save(User *u) {
         if (!u->started)
                 return 0;
 
-        r = safe_mkdir("/run/systemd/users", 0755, 0, 0);
+        r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
         if (r < 0)
                 goto finish;
 
@@ -136,40 +139,59 @@ int user_save(User *u) {
 
         if (u->sessions) {
                 Session *i;
+                bool first;
 
                 fputs("SESSIONS=", f);
+                first = true;
                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
-                        fprintf(f,
-                                "%s%c",
-                                i->id,
-                                i->sessions_by_user_next ? ' ' : '\n');
+                        if (first)
+                                first = false;
+                        else
+                                fputc(' ', f);
+
+                        fputs(i->id, f);
                 }
 
-                fputs("SEATS=", f);
+                fputs("\nSEATS=", f);
+                first = true;
                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
-                        if (i->seat)
-                                fprintf(f,
-                                        "%s%c",
-                                        i->seat->id,
-                                        i->sessions_by_user_next ? ' ' : '\n');
+                        if (!i->seat)
+                                continue;
+
+                        if (first)
+                                first = false;
+                        else
+                                fputc(' ', f);
+
+                        fputs(i->seat->id, f);
                 }
 
-                fputs("ACTIVE_SESSIONS=", f);
-                LIST_FOREACH(sessions_by_user, i, u->sessions)
-                        if (session_is_active(i))
-                                fprintf(f,
-                                        "%lu%c",
-                                        (unsigned long) i->user->uid,
-                                        i->sessions_by_user_next ? ' ' : '\n');
+                fputs("\nACTIVE_SESSIONS=", f);
+                first = true;
+                LIST_FOREACH(sessions_by_user, i, u->sessions) {
+                        if (!session_is_active(i))
+                                continue;
 
-                fputs("ACTIVE_SEATS=", f);
+                        if (first)
+                                first = false;
+                        else
+                                fputc(' ', f);
+
+                        fputs(i->id, f);
+                }
+
+                fputs("\nACTIVE_SEATS=", f);
+                first = true;
                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
-                        if (session_is_active(i) && i->seat)
-                                fprintf(f,
-                                        "%s%c",
-                                        i->seat->id,
-                                        i->sessions_by_user_next ? ' ' : '\n');
+                        if (!session_is_active(i) || !i->seat)
+                                continue;
+
+                        if (first)
+                                first = false;
+                        else
+                                fputs(i->seat->id, f);
                 }
+                fputc('\n', f);
         }
 
         fflush(f);
@@ -230,7 +252,7 @@ static int user_mkdir_runtime_path(User *u) {
 
         assert(u);
 
-        r = safe_mkdir("/run/user", 0755, 0, 0);
+        r = mkdir_safe_label("/run/user", 0755, 0, 0);
         if (r < 0) {
                 log_error("Failed to create /run/user: %s", strerror(-r));
                 return r;
@@ -246,7 +268,7 @@ static int user_mkdir_runtime_path(User *u) {
         } else
                 p = u->runtime_path;
 
-        r = safe_mkdir(p, 0700, u->uid, u->gid);
+        r = mkdir_safe_label(p, 0700, u->uid, u->gid);
         if (r < 0) {
                 log_error("Failed to create runtime directory %s: %s", p, strerror(-r));
                 free(p);
@@ -293,6 +315,8 @@ static int user_create_cgroup(User *u) {
                         log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r));
         }
 
+        hashmap_put(u->manager->user_cgroups, u->cgroup_path, u);
+
         return 0;
 }
 
@@ -397,6 +421,8 @@ static int user_terminate_cgroup(User *u) {
         STRV_FOREACH(k, u->manager->controllers)
                 cg_trim(*k, u->cgroup_path, true);
 
+        hashmap_remove(u->manager->user_cgroups, u->cgroup_path);
+
         free(u->cgroup_path);
         u->cgroup_path = NULL;
 
@@ -497,9 +523,21 @@ int user_get_idle_hint(User *u, dual_timestamp *t) {
         return idle_hint;
 }
 
+static int user_check_linger_file(User *u) {
+        char *p;
+        int r;
+
+        if (asprintf(&p, "/var/lib/systemd/linger/%s", u->name) < 0)
+                return -ENOMEM;
+
+        r = access(p, F_OK) >= 0;
+        free(p);
+
+        return r;
+}
+
 int user_check_gc(User *u, bool drop_not_started) {
         int r;
-        char *p;
 
         assert(u);
 
@@ -509,13 +547,7 @@ int user_check_gc(User *u, bool drop_not_started) {
         if (u->sessions)
                 return 1;
 
-        if (asprintf(&p, "/var/lib/systemd/linger/%s", u->name) < 0)
-                return -ENOMEM;
-
-        r = access(p, F_OK) >= 0;
-        free(p);
-
-        if (r > 0)
+        if (user_check_linger_file(u) > 0)
                 return 1;
 
         if (u->cgroup_path) {
@@ -545,14 +577,17 @@ UserState user_get_state(User *u) {
 
         assert(u);
 
-        if (!u->sessions)
-                return USER_LINGERING;
-
         LIST_FOREACH(sessions_by_user, i, u->sessions)
                 if (session_is_active(i))
                         return USER_ACTIVE;
 
-        return USER_ONLINE;
+        if (u->sessions)
+                return USER_ONLINE;
+
+        if (user_check_linger_file(u) > 0)
+                return USER_LINGERING;
+
+        return USER_CLOSING;
 }
 
 int user_kill(User *u, int signo) {
@@ -583,7 +618,8 @@ static const char* const user_state_table[_USER_STATE_MAX] = {
         [USER_OFFLINE] = "offline",
         [USER_LINGERING] = "lingering",
         [USER_ONLINE] = "online",
-        [USER_ACTIVE] = "active"
+        [USER_ACTIVE] = "active",
+        [USER_CLOSING] = "closing"
 };
 
 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);