chiark / gitweb /
login: fix re-use of users
[elogind.git] / src / login / logind-user.c
index ccabe3d4771aeb15d03f8d2ba89ecfea6ba028b0..27f73700008ccbc8f6fc3fdd4fca56cdb8a1739a 100644 (file)
@@ -409,7 +409,7 @@ 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("user", lu, &slice);
+                r = slice_build_subslice("user.slice", lu, &slice);
                 if (r < 0)
                         return r;
 
@@ -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;
 }
@@ -926,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;