chiark / gitweb /
login: fix re-use of users
[elogind.git] / src / login / logind-user.c
index 2733117c641977de41cf08f74e52a7d886eb2d2e..27f73700008ccbc8f6fc3fdd4fca56cdb8a1739a 100644 (file)
@@ -30,7 +30,7 @@
 #include "hashmap.h"
 #include "fileio.h"
 #include "path-util.h"
-#include "special.h"
+// #include "special.h"
 #include "unit-name.h"
 #include "bus-util.h"
 #include "bus-error.h"
@@ -409,26 +409,26 @@ static int user_start_slice(User *u) {
                 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
                 sprintf(lu, UID_FMT, u->uid);
 
-                r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &slice);
+                r = slice_build_subslice("user.slice", lu, &slice);
                 if (r < 0)
                         return r;
 
 /// elogind : Do not try to use dbus to ask systemd
 #if 0
                 r = manager_start_unit(u->manager, slice, &error, &job);
-#endif // 0
                 if (r < 0) {
                         log_error("Failed to start user slice: %s", bus_error_message(&error, r));
                         free(slice);
                 } else {
+#endif // 0
                         u->slice = slice;
 
 /// elogind does not support slice jobs
 #if 0
                         free(u->slice_job);
                         u->slice_job = job;
-#endif // 0
                 }
+#endif // 0
         }
 
         if (u->slice)
@@ -481,15 +481,32 @@ int user_start(User *u) {
 
         assert(u);
 
-        if (u->started)
+        if (u->started && !u->stopping)
                 return 0;
 
-        log_debug("New user %s logged in.", u->name);
-
-        /* Make XDG_RUNTIME_DIR */
-        r = user_mkdir_runtime_path(u);
-        if (r < 0)
-                return r;
+        /*
+         * If u->stopping is set, the user is marked for removal and the slice
+         * and service stop-jobs are queued. We have to clear that flag before
+         * queing the start-jobs again. If they succeed, the user object can be
+         * re-used just fine (pid1 takes care of job-ordering and proper
+         * restart), but if they fail, we want to force another user_stop() so
+         * possibly pending units are stopped.
+         * Note that we don't clear u->started, as we have no clue what state
+         * the user is in on failure here. Hence, we pretend the user is
+         * running so it will be properly taken down by GC. However, we clearly
+         * return an error from user_start() in that case, so no further
+         * reference to the user is taken.
+         */
+        u->stopping = false;
+
+        if (!u->started) {
+                log_debug("New user %s logged in.", u->name);
+
+                /* Make XDG_RUNTIME_DIR */
+                r = user_mkdir_runtime_path(u);
+                if (r < 0)
+                        return r;
+        }
 
         /* Create cgroup */
         r = user_start_slice(u);
@@ -507,16 +524,16 @@ int user_start(User *u) {
         if (r < 0)
                 return r;
 
-        if (!dual_timestamp_is_set(&u->timestamp))
-                dual_timestamp_get(&u->timestamp);
-
-        u->started = true;
+        if (!u->started) {
+                if (!dual_timestamp_is_set(&u->timestamp))
+                        dual_timestamp_get(&u->timestamp);
+                user_send_signal(u, true);
+                u->started = true;
+        }
 
         /* Save new user data */
         user_save(u);
 
-        user_send_signal(u, true);
-
         return 0;
 }
 
@@ -590,8 +607,7 @@ static int user_remove_runtime_path(User *u) {
         if (r < 0)
                 log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
 
-        free(u->runtime_path);
-        u->runtime_path = NULL;
+        u->runtime_path = mfree(u->runtime_path);
 
         return r;
 }
@@ -793,16 +809,27 @@ UserState user_get_state(User *u) {
 }
 
 int user_kill(User *u, int signo) {
+/// Without systemd unit support, elogind has to rely on its session system
+#if 0
         assert(u);
 
-/// FIXME: Without direct cgroup support, elogind can not kill users
-#if 0
         if (!u->slice)
                 return -ESRCH;
 
         return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
 #else
-        return -ESRCH;
+        Session *s;
+        int res = 0;
+
+        assert(u);
+
+        LIST_FOREACH(sessions_by_user, s, u->sessions) {
+                int r = session_kill(s, KILL_ALL, signo);
+                if (res == 0 && r < 0)
+                        res = r;
+        }
+
+        return res;
 #endif // 0
 }
 
@@ -915,26 +942,26 @@ int config_parse_tmpfs_size(
                 errno = 0;
                 ul = strtoul(rvalue, &f, 10);
                 if (errno != 0 || f != e) {
-                        log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse percentage value, ignoring: %s", rvalue);
                         return 0;
                 }
 
                 if (ul <= 0 || ul >= 100) {
-                        log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Percentage value out of range, ignoring: %s", rvalue);
                         return 0;
                 }
 
                 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
         } else {
-                off_t o;
+                uint64_t k;
 
-                r = parse_size(rvalue, 1024, &o);
-                if (r < 0 || (off_t) (size_t) o != o) {
-                        log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
+                r = parse_size(rvalue, 1024, &k);
+                if (r < 0 || (uint64_t) (size_t) k != k) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
                         return 0;
                 }
 
-                *sz = PAGE_ALIGN((size_t) o);
+                *sz = PAGE_ALIGN((size_t) k);
         }
 
         return 0;