#include "util.h"
#include "mkdir.h"
-#include "cgroup-util.h"
#include "hashmap.h"
#include "strv.h"
#include "fileio.h"
#include "special.h"
#include "unit-name.h"
-#include "dbus-common.h"
+#include "bus-util.h"
+#include "bus-error.h"
#include "logind-user.h"
User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
assert(u);
if (u->in_gc_queue)
- LIST_REMOVE(User, gc_queue, u->manager->user_gc_queue, u);
+ LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
while (u->sessions)
session_free(u->sessions);
if (dual_timestamp_is_set(&u->timestamp))
fprintf(f,
- "REALTIME=%llu\n"
- "MONOTONIC=%llu\n",
- (unsigned long long) u->timestamp.realtime,
- (unsigned long long) u->timestamp.monotonic);
+ "REALTIME="USEC_FMT"\n"
+ "MONOTONIC="USEC_FMT"\n",
+ u->timestamp.realtime,
+ u->timestamp.monotonic);
if (u->sessions) {
Session *i;
finish:
if (r < 0)
- log_error("Failed to save user data for %s: %s", u->name, strerror(-r));
+ log_error("Failed to save user data %s: %s", u->state_file, strerror(-r));
return r;
}
}
static int user_start_slice(User *u) {
- DBusError error;
char *job;
int r;
assert(u);
- dbus_error_init(&error);
-
if (!u->slice) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
char lu[DECIMAL_STR_MAX(unsigned long) + 1], *slice;
sprintf(lu, "%lu", (unsigned long) u->uid);
r = manager_start_unit(u->manager, slice, &error, &job);
if (r < 0) {
- log_error("Failed to start user slice: %s", bus_error(&error, r));
- dbus_error_free(&error);
-
+ log_error("Failed to start user slice: %s", bus_error_message(&error, r));
free(slice);
} else {
u->slice = slice;
}
static int user_start_service(User *u) {
- DBusError error;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
char *job;
int r;
assert(u);
- dbus_error_init(&error);
-
if (!u->service) {
char lu[DECIMAL_STR_MAX(unsigned long) + 1], *service;
sprintf(lu, "%lu", (unsigned long) u->uid);
r = manager_start_unit(u->manager, service, &error, &job);
if (r < 0) {
- log_error("Failed to start user service: %s", bus_error(&error, r));
- dbus_error_free(&error);
-
+ log_error("Failed to start user service: %s", bus_error_message(&error, r));
free(service);
} else {
u->service = service;
}
static int user_stop_slice(User *u) {
- DBusError error;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
char *job;
int r;
assert(u);
- dbus_error_init(&error);
-
if (!u->slice)
return 0;
r = manager_stop_unit(u->manager, u->slice, &error, &job);
if (r < 0) {
- log_error("Failed to stop user slice: %s", bus_error(&error, r));
- dbus_error_free(&error);
+ log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
return r;
}
}
static int user_stop_service(User *u) {
- DBusError error;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
char *job;
int r;
assert(u);
- dbus_error_init(&error);
-
if (!u->service)
return 0;
r = manager_stop_unit(u->manager, u->service, &error, &job);
if (r < 0) {
- log_error("Failed to stop user service: %s", bus_error(&error, r));
- dbus_error_free(&error);
+ log_error("Failed to stop user service: %s", bus_error_message(&error, r));
return r;
}
return r;
}
-/* static int user_shall_kill(User *u) { */
-/* assert(u); */
-
-/* if (!u->manager->kill_user_processes) */
-/* return false; */
-
-/* if (strv_contains(u->manager->kill_exclude_users, u->name)) */
-/* return false; */
-
-/* if (strv_isempty(u->manager->kill_only_users)) */
-/* return true; */
-
-/* return strv_contains(u->manager->kill_only_users, u->name); */
-/* } */
-
static int user_remove_runtime_path(User *u) {
int r;
int r = 0, k;
assert(u);
- if (u->started)
- log_debug("User %s logged out.", u->name);
-
LIST_FOREACH(sessions_by_user, s, u->sessions) {
k = session_stop(s);
if (k < 0)
if (k < 0)
r = k;
+ u->stopping = true;
+
+ user_save(u);
+
+ return r;
+}
+
+int user_finalize(User *u) {
+ Session *s;
+ int r = 0, k;
+
+ assert(u);
+
+ if (u->started)
+ log_debug("User %s logged out.", u->name);
+
+ LIST_FOREACH(sessions_by_user, s, u->sessions) {
+ k = session_finalize(s);
+ if (k < 0)
+ r = k;
+ }
+
/* Kill XDG_RUNTIME_DIR */
k = user_remove_runtime_path(u);
if (k < 0)
unlink(u->state_file);
user_add_to_gc_queue(u);
- if (u->started)
+ if (u->started) {
user_send_signal(u, false);
-
- u->started = false;
+ u->started = false;
+ }
return r;
}
return idle_hint;
}
-static int user_check_linger_file(User *u) {
- char *p;
- int r;
+int user_check_linger_file(User *u) {
+ _cleanup_free_ char *cc = NULL;
+ char *p = NULL;
- if (asprintf(&p, "/var/lib/systemd/linger/%s", u->name) < 0)
+ cc = cescape(u->name);
+ if (!cc)
return -ENOMEM;
- r = access(p, F_OK) >= 0;
- free(p);
+ p = strappenda("/var/lib/systemd/linger/", cc);
- return r;
+ return access(p, F_OK) >= 0;
}
-int user_check_gc(User *u, bool drop_not_started) {
+bool user_check_gc(User *u, bool drop_not_started) {
assert(u);
if (drop_not_started && !u->started)
- return 0;
+ return false;
if (u->sessions)
- return 1;
+ return true;
if (user_check_linger_file(u) > 0)
- return 1;
+ return true;
- return 0;
+ if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
+ return true;
+
+ if (u->service_job && manager_job_is_active(u->manager, u->service_job))
+ return true;
+
+ return false;
}
void user_add_to_gc_queue(User *u) {
if (u->in_gc_queue)
return;
- LIST_PREPEND(User, gc_queue, u->manager->user_gc_queue, u);
+ LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
u->in_gc_queue = true;
}
UserState user_get_state(User *u) {
Session *i;
- bool all_closing = true;
assert(u);
+ if (u->stopping)
+ return USER_CLOSING;
+
if (u->slice_job || u->service_job)
- return u->started ? USER_OPENING : USER_CLOSING;
+ return USER_OPENING;
- LIST_FOREACH(sessions_by_user, i, u->sessions) {
- if (session_is_active(i))
- return USER_ACTIVE;
- if (session_get_state(i) != SESSION_CLOSING)
- all_closing = false;
- }
+ if (u->sessions) {
+ bool all_closing = true;
+
+ LIST_FOREACH(sessions_by_user, i, u->sessions) {
+ if (session_is_active(i))
+ return USER_ACTIVE;
+ if (session_get_state(i) != SESSION_CLOSING)
+ all_closing = false;
+ }
- if (u->sessions)
return all_closing ? USER_CLOSING : USER_ONLINE;
+ }
if (user_check_linger_file(u) > 0)
return USER_LINGERING;