]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/login/logind-user.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / login / logind-user.c
index e92f2a5243f04debdf93737ba61988b73a744c27..fe47c78bdb1fd4268f1f2adc5c6bf36c64f77ee1 100644 (file)
@@ -11,6 +11,7 @@
 #include "bus-util.h"
 #include "cgroup-util.h"
 #include "clean-ipc.h"
+#include "env-file.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "rm-rf.h"
+#include "serialize.h"
 #include "special.h"
 #include "stdio-util.h"
 #include "string-table.h"
+#include "strv.h"
+#include "tmpfile-util.h"
 #include "unit-name.h"
 #include "user-util.h"
 #include "util.h"
@@ -310,13 +314,12 @@ int user_load(User *u) {
 
         assert(u);
 
-        r = parse_env_file(NULL, u->state_file, NEWLINE,
+        r = parse_env_file(NULL, u->state_file,
                            "SERVICE_JOB",            &u->service_job,
                            "STOPPING",               &stopping,
                            "REALTIME",               &realtime,
                            "MONOTONIC",              &monotonic,
-                           "LAST_SESSION_TIMESTAMP", &last_session_timestamp,
-                           NULL);
+                           "LAST_SESSION_TIMESTAMP", &last_session_timestamp);
         if (r == -ENOENT)
                 return 0;
         if (r < 0)
@@ -331,11 +334,11 @@ int user_load(User *u) {
         }
 
         if (realtime)
-                (void) timestamp_deserialize(realtime, &u->timestamp.realtime);
+                (void) deserialize_usec(realtime, &u->timestamp.realtime);
         if (monotonic)
-                (void) timestamp_deserialize(monotonic, &u->timestamp.monotonic);
+                (void) deserialize_usec(monotonic, &u->timestamp.monotonic);
         if (last_session_timestamp)
-                (void) timestamp_deserialize(last_session_timestamp, &u->last_session_timestamp);
+                (void) deserialize_usec(last_session_timestamp, &u->last_session_timestamp);
 
         return 0;
 }
@@ -354,7 +357,8 @@ static void user_start_service(User *u) {
 
         r = manager_start_unit(u->manager, u->service, &error, &u->service_job);
         if (r < 0)
-                log_warning_errno(r, "Failed to start user service '%s', ignoring: %s", u->service, bus_error_message(&error, r));
+                log_full_errno(sd_bus_error_has_name(&error, BUS_ERROR_UNIT_MASKED) ? LOG_DEBUG : LOG_WARNING, r,
+                               "Failed to start user service '%s', ignoring: %s", u->service, bus_error_message(&error, r));
 }
 
 int user_start(User *u) {
@@ -530,8 +534,35 @@ int user_check_linger_file(User *u) {
                 return -ENOMEM;
 
         p = strjoina("/var/lib/systemd/linger/", cc);
+        if (access(p, F_OK) < 0) {
+                if (errno != ENOENT)
+                        return -errno;
 
-        return access(p, F_OK) >= 0;
+                return false;
+        }
+
+        return true;
+}
+
+static bool user_unit_active(User *u) {
+        const char *i;
+        int r;
+
+        assert(u->service);
+        assert(u->runtime_dir_service);
+        assert(u->slice);
+
+        FOREACH_STRING(i, u->service, u->runtime_dir_service, u->slice) {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+
+                r = manager_unit_is_active(u->manager, i, &error);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to determine whether unit '%s' is active, ignoring: %s", u->service, bus_error_message(&error, r));
+                if (r != 0)
+                        return true;
+        }
+
+        return false;
 }
 
 bool user_may_gc(User *u, bool drop_not_started) {
@@ -555,8 +586,10 @@ bool user_may_gc(User *u, bool drop_not_started) {
                         return false; /* Leave it around for a bit longer. */
         }
 
-        /* Is this a user that shall stay around forever? */
-        if (user_check_linger_file(u) > 0)
+        /* Is this a user that shall stay around forever ("linger")? Before we say "no" to GC'ing for lingering users, let's check
+         * if any of the three units that we maintain for this user is still around. If none of them is,
+         * there's no need to keep this user around even if lingering is enabled. */
+        if (user_check_linger_file(u) > 0 && user_unit_active(u))
                 return false;
 
         /* Check if our job is still pending */
@@ -613,7 +646,7 @@ UserState user_get_state(User *u) {
                 return all_closing ? USER_CLOSING : USER_ONLINE;
         }
 
-        if (user_check_linger_file(u) > 0)
+        if (user_check_linger_file(u) > 0 && user_unit_active(u))
                 return USER_LINGERING;
 
         return USER_CLOSING;