X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flogin%2Flogind-user.c;h=9bbe879571e4c838214478e77e64e24dcdf9f0f3;hb=0325941fff60888ff3486f271b0d513a75f9a324;hp=0a985a53ecf1c7e44394dd2821f1db38977bc092;hpb=d0af76e68a5bab2e4fd9674b1c64a9f38d7afe97;p=elogind.git
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 0a985a53e..9bbe87957 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -19,19 +19,22 @@
along with systemd; If not, see .
***/
+#include
#include
#include
#include
#include "util.h"
#include "mkdir.h"
-#include "cgroup-util.h"
#include "hashmap.h"
#include "strv.h"
#include "fileio.h"
+#include "path-util.h"
#include "special.h"
#include "unit-name.h"
-#include "dbus-common.h"
+#include "bus-util.h"
+#include "bus-error.h"
+#include "conf-parser.h"
#include "logind-user.h"
User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
@@ -72,7 +75,7 @@ void user_free(User *u) {
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);
@@ -145,10 +148,10 @@ int user_save(User *u) {
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;
@@ -247,7 +250,7 @@ int user_save(User *u) {
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;
}
@@ -311,33 +314,45 @@ static int user_mkdir_runtime_path(User *u) {
}
if (!u->runtime_path) {
- if (asprintf(&p, "/run/user/%lu", (unsigned long) u->uid) < 0)
+ if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
return log_oom();
} else
p = u->runtime_path;
- r = mkdir_safe_label(p, 0700, u->uid, u->gid);
- if (r < 0) {
- log_error("Failed to create runtime directory %s: %s", p, strerror(-r));
- free(p);
- u->runtime_path = NULL;
- return r;
+ if (path_is_mount_point(p, false) <= 0) {
+ _cleanup_free_ char *t = NULL;
+
+ mkdir(p, 0700);
+
+ if (asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size) < 0) {
+ r = log_oom();
+ goto fail;
+ }
+
+ r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
+ if (r < 0) {
+ log_error("Failed to mount per-user tmpfs directory %s: %s", p, strerror(-r));
+ goto fail;
+ }
}
u->runtime_path = p;
return 0;
+
+fail:
+ free(p);
+ u->runtime_path = NULL;
+ 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);
@@ -347,9 +362,7 @@ static int user_start_slice(User *u) {
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;
@@ -366,14 +379,12 @@ static int user_start_slice(User *u) {
}
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);
@@ -384,9 +395,7 @@ static int user_start_service(User *u) {
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;
@@ -441,21 +450,18 @@ int user_start(User *u) {
}
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;
}
@@ -466,21 +472,18 @@ static int user_stop_slice(User *u) {
}
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;
}
@@ -490,21 +493,6 @@ static int user_stop_service(User *u) {
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;
@@ -513,6 +501,13 @@ static int user_remove_runtime_path(User *u) {
if (!u->runtime_path)
return 0;
+ r = rm_rf(u->runtime_path, false, false, false);
+ if (r < 0)
+ log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
+
+ if (umount2(u->runtime_path, MNT_DETACH) < 0)
+ log_error("Failed to unmount user runtime directory %s: %m", u->runtime_path);
+
r = rm_rf(u->runtime_path, false, true, false);
if (r < 0)
log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
@@ -523,16 +518,19 @@ static int user_remove_runtime_path(User *u) {
return r;
}
-int user_stop(User *u) {
+int user_stop(User *u, bool force) {
Session *s;
int r = 0, k;
assert(u);
- if (u->started)
- log_debug("User %s logged out.", u->name);
+ /* Stop jobs have already been queued */
+ if (u->stopping) {
+ user_save(u);
+ return r;
+ }
LIST_FOREACH(sessions_by_user, s, u->sessions) {
- k = session_stop(s);
+ k = session_stop(s, force);
if (k < 0)
r = k;
}
@@ -547,6 +545,28 @@ int user_stop(User *u) {
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)
@@ -555,10 +575,10 @@ int user_stop(User *u) {
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;
}
@@ -599,32 +619,38 @@ int user_get_idle_hint(User *u, dual_timestamp *t) {
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) {
@@ -633,28 +659,36 @@ 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) {
+ SessionState state;
+
+ state = session_get_state(i);
+ if (state == SESSION_ACTIVE)
+ return USER_ACTIVE;
+ if (state != 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;
@@ -681,3 +715,57 @@ static const char* const user_state_table[_USER_STATE_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
+
+int config_parse_tmpfs_size(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ size_t *sz = data;
+ const char *e;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ e = endswith(rvalue, "%");
+ if (e) {
+ unsigned long ul;
+ char *f;
+
+ 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);
+ 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);
+ return 0;
+ }
+
+ *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
+ } else {
+ off_t o;
+
+ 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);
+ return 0;
+ }
+
+ *sz = PAGE_ALIGN((size_t) o);
+ }
+
+ return 0;
+}