]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
logind-user: take gc_mode into account when reporting user state
authorMike Yuan <me@yhndnzj.com>
Sat, 6 Jul 2024 17:05:57 +0000 (19:05 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 12 Jul 2024 16:32:53 +0000 (18:32 +0200)
Prompted by #33650

Previously, if a user manually starts user@.service (which is
something we support), we'd track it as 'manager' session.
However, since user_get_state() ignores all non-pinning sessions,
if lingering is not enabled, the user state would always be
reported as 'closing', which is spurious.

Let's instead take gc_mode into consideration, and ignore
non-pinning sessions only if USER_GC_BY_PIN.

src/login/logind-user.c

index 8066b3e32012fff6727c8d1aa73bf8d8e6f890c9..276d5b86f583ee9e2247140cc265ff10e83f70ff 100644 (file)
@@ -821,30 +821,30 @@ UserState user_get_state(User *u) {
         if (!u->started || u->runtime_dir_job)
                 return USER_OPENING;
 
-        bool any = false, all_closing = true;
+        /* USER_GC_BY_PIN: Only pinning sessions count. None -> closing
+         * USER_GC_BY_ANY: 'manager' sessions also count. However, if lingering is enabled, 'lingering' state
+         *                 shall be preferred. 'online' if the manager is manually started by user. */
+
+        bool has_pinning = false, all_closing = true;
         LIST_FOREACH(sessions_by_user, i, u->sessions) {
-                SessionState state;
+                bool pinned = SESSION_CLASS_PIN_USER(i->class);
 
-                /* Ignore sessions that don't pin the user, i.e. are not supposed to have an effect on user state */
-                if (!SESSION_CLASS_PIN_USER(i->class))
+                if (u->gc_mode == USER_GC_BY_PIN && !pinned)
                         continue;
 
-                state = session_get_state(i);
-                if (state == SESSION_ACTIVE)
+                has_pinning = has_pinning || pinned;
+
+                SessionState state = session_get_state(i);
+                if (state == SESSION_ACTIVE && pinned)
                         return USER_ACTIVE;
                 if (state != SESSION_CLOSING)
                         all_closing = false;
-
-                any = true;
         }
 
-        if (any)
-                return all_closing ? USER_CLOSING : USER_ONLINE;
-
-        if (user_check_linger_file(u) > 0 && user_unit_active(u))
+        if (!has_pinning && user_check_linger_file(u) > 0 && user_unit_active(u))
                 return USER_LINGERING;
 
-        return USER_CLOSING;
+        return all_closing ? USER_CLOSING : USER_ONLINE;
 }
 
 int user_kill(User *u, int signo) {