#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"
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)
}
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;
}
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) {
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) {
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 */
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;