logind: use named pipes instead of fifos to keep track of sessions so that we can reconnect later
This commit is contained in:
+17
-23
@@ -191,7 +191,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
|
||||
int r;
|
||||
char *id = NULL, *p;
|
||||
uint32_t vtnr = 0;
|
||||
int pipe_fds[2] = { -1, -1 };
|
||||
int fifo_fd = -1;
|
||||
DBusMessage *reply = NULL;
|
||||
bool b;
|
||||
|
||||
@@ -353,6 +353,12 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
|
||||
|
||||
if (session) {
|
||||
|
||||
fifo_fd = session_create_fifo(session);
|
||||
if (fifo_fd < 0) {
|
||||
r = fifo_fd;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Session already exists, client is probably
|
||||
* something like "su" which changes uid but
|
||||
* is still the same audit session */
|
||||
@@ -363,15 +369,6 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Create a throw-away fd */
|
||||
if (pipe(pipe_fds) < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
close_nointr_nofail(pipe_fds[0]);
|
||||
pipe_fds[0] = -1;
|
||||
|
||||
p = session_bus_path(session);
|
||||
if (!p) {
|
||||
r = -ENOMEM;
|
||||
@@ -383,7 +380,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
|
||||
DBUS_TYPE_STRING, &session->id,
|
||||
DBUS_TYPE_OBJECT_PATH, &p,
|
||||
DBUS_TYPE_STRING, &session->user->runtime_path,
|
||||
DBUS_TYPE_UNIX_FD, &pipe_fds[1],
|
||||
DBUS_TYPE_UNIX_FD, &fifo_fd,
|
||||
DBUS_TYPE_INVALID);
|
||||
free(p);
|
||||
|
||||
@@ -392,7 +389,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
|
||||
goto fail;
|
||||
}
|
||||
|
||||
close_nointr_nofail(pipe_fds[1]);
|
||||
close_nointr_nofail(fifo_fd);
|
||||
*_reply = reply;
|
||||
|
||||
return 0;
|
||||
@@ -467,16 +464,12 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
|
||||
}
|
||||
}
|
||||
|
||||
if (pipe(pipe_fds) < 0) {
|
||||
r = -errno;
|
||||
fifo_fd = session_create_fifo(session);
|
||||
if (fifo_fd < 0) {
|
||||
r = fifo_fd;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = session_set_pipe_fd(session, pipe_fds[0]);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
pipe_fds[0] = -1;
|
||||
|
||||
if (s) {
|
||||
r = seat_attach_session(s, session);
|
||||
if (r < 0)
|
||||
@@ -504,7 +497,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
|
||||
DBUS_TYPE_STRING, &session->id,
|
||||
DBUS_TYPE_OBJECT_PATH, &p,
|
||||
DBUS_TYPE_STRING, &session->user->runtime_path,
|
||||
DBUS_TYPE_UNIX_FD, &pipe_fds[1],
|
||||
DBUS_TYPE_UNIX_FD, &fifo_fd,
|
||||
DBUS_TYPE_INVALID);
|
||||
free(p);
|
||||
|
||||
@@ -513,7 +506,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
|
||||
goto fail;
|
||||
}
|
||||
|
||||
close_nointr_nofail(pipe_fds[1]);
|
||||
close_nointr_nofail(fifo_fd);
|
||||
*_reply = reply;
|
||||
|
||||
return 0;
|
||||
@@ -528,7 +521,8 @@ fail:
|
||||
if (user)
|
||||
user_add_to_gc_queue(user);
|
||||
|
||||
close_pipe(pipe_fds);
|
||||
if (fifo_fd >= 0)
|
||||
close_nointr_nofail(fifo_fd);
|
||||
|
||||
if (reply)
|
||||
dbus_message_unref(reply);
|
||||
@@ -611,7 +605,7 @@ static int attach_device(Manager *m, const char *seat, const char *sysfs) {
|
||||
const char *p;
|
||||
|
||||
p = udev_list_entry_get_name(item);
|
||||
if (!startswith(p, sysfs))
|
||||
if (!path_startswith(p, sysfs))
|
||||
continue;
|
||||
|
||||
t = strappend(p, "/uevent");
|
||||
|
||||
@@ -449,6 +449,9 @@ int seat_get_idle_hint(Seat *s, dual_timestamp *t) {
|
||||
int seat_check_gc(Seat *s) {
|
||||
assert(s);
|
||||
|
||||
if (!s->started)
|
||||
return 0;
|
||||
|
||||
if (seat_is_vtconsole(s))
|
||||
return 1;
|
||||
|
||||
|
||||
+66
-20
@@ -23,6 +23,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "logind-session.h"
|
||||
#include "strv.h"
|
||||
@@ -56,7 +57,7 @@ Session* session_new(Manager *m, User *u, const char *id) {
|
||||
}
|
||||
|
||||
s->manager = m;
|
||||
s->pipe_fd = -1;
|
||||
s->fifo_fd = -1;
|
||||
s->user = u;
|
||||
|
||||
LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
|
||||
@@ -98,7 +99,7 @@ void session_free(Session *s) {
|
||||
|
||||
hashmap_remove(s->manager->sessions, s->id);
|
||||
|
||||
session_unset_pipe_fd(s);
|
||||
session_remove_fifo(s);
|
||||
|
||||
free(s->state_file);
|
||||
free(s);
|
||||
@@ -149,6 +150,11 @@ int session_save(Session *s) {
|
||||
"CGROUP=%s\n",
|
||||
s->cgroup_path);
|
||||
|
||||
if (s->fifo_path)
|
||||
fprintf(f,
|
||||
"FIFO=%s\n",
|
||||
s->fifo_path);
|
||||
|
||||
if (s->seat)
|
||||
fprintf(f,
|
||||
"SEAT=%s\n",
|
||||
@@ -229,6 +235,7 @@ int session_load(Session *s) {
|
||||
"REMOTE", &remote,
|
||||
"KILL_PROCESSES", &kill_processes,
|
||||
"CGROUP", &s->cgroup_path,
|
||||
"FIFO", &s->fifo_path,
|
||||
"SEAT", &seat,
|
||||
"TTY", &s->tty,
|
||||
"DISPLAY", &s->display,
|
||||
@@ -290,6 +297,8 @@ int session_load(Session *s) {
|
||||
s->type = t;
|
||||
}
|
||||
|
||||
session_open_fifo(s);
|
||||
|
||||
finish:
|
||||
free(remote);
|
||||
free(kill_processes);
|
||||
@@ -746,43 +755,77 @@ void session_set_idle_hint(Session *s, bool b) {
|
||||
"IdleSinceHintMonotonic\0");
|
||||
}
|
||||
|
||||
int session_set_pipe_fd(Session *s, int fd) {
|
||||
int session_open_fifo(Session *s) {
|
||||
struct epoll_event ev;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(fd >= 0);
|
||||
assert(s->pipe_fd < 0);
|
||||
|
||||
r = hashmap_put(s->manager->pipe_fds, INT_TO_PTR(fd + 1), s);
|
||||
if (s->fifo_fd >= 0)
|
||||
return 0;
|
||||
|
||||
if (!s->fifo_path)
|
||||
return -EINVAL;
|
||||
|
||||
s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
|
||||
if (s->fifo_fd < 0)
|
||||
return -errno;
|
||||
|
||||
r = hashmap_put(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1), s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
zero(ev);
|
||||
ev.events = 0;
|
||||
ev.data.u32 = FD_PIPE_BASE + fd;
|
||||
ev.data.u32 = FD_FIFO_BASE + s->fifo_fd;
|
||||
|
||||
if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
|
||||
assert_se(hashmap_remove(s->manager->pipe_fds, INT_TO_PTR(fd + 1)) == s);
|
||||
if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
s->pipe_fd = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void session_unset_pipe_fd(Session *s) {
|
||||
int session_create_fifo(Session *s) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
if (s->pipe_fd < 0)
|
||||
return;
|
||||
if (!s->fifo_path) {
|
||||
if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
assert_se(hashmap_remove(s->manager->pipe_fds, INT_TO_PTR(s->pipe_fd + 1)) == s);
|
||||
if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->pipe_fd, NULL) == 0);
|
||||
/* Open reading side */
|
||||
r = session_open_fifo(s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
close_nointr_nofail(s->pipe_fd);
|
||||
s->pipe_fd = -1;
|
||||
/* Open writing side */
|
||||
r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void session_remove_fifo(Session *s) {
|
||||
assert(s);
|
||||
|
||||
if (s->fifo_fd >= 0) {
|
||||
assert_se(hashmap_remove(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
|
||||
assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
|
||||
close_nointr_nofail(s->fifo_fd);
|
||||
s->fifo_fd = -1;
|
||||
}
|
||||
|
||||
if (s->fifo_path) {
|
||||
unlink(s->fifo_path);
|
||||
free(s->fifo_path);
|
||||
s->fifo_path = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int session_check_gc(Session *s) {
|
||||
@@ -790,9 +833,12 @@ int session_check_gc(Session *s) {
|
||||
|
||||
assert(s);
|
||||
|
||||
if (s->pipe_fd >= 0) {
|
||||
if (!s->started)
|
||||
return 0;
|
||||
|
||||
r = pipe_eof(s->pipe_fd);
|
||||
if (s->fifo_fd >= 0) {
|
||||
|
||||
r = pipe_eof(s->fifo_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -65,7 +65,8 @@ struct Session {
|
||||
pid_t leader;
|
||||
uint32_t audit_id;
|
||||
|
||||
int pipe_fd;
|
||||
int fifo_fd;
|
||||
char *fifo_path;
|
||||
|
||||
char *cgroup_path;
|
||||
char **controllers, **reset_controllers;
|
||||
@@ -91,8 +92,9 @@ int session_activate(Session *s);
|
||||
bool session_is_active(Session *s);
|
||||
int session_get_idle_hint(Session *s, dual_timestamp *t);
|
||||
void session_set_idle_hint(Session *s, bool b);
|
||||
int session_set_pipe_fd(Session *s, int fd);
|
||||
void session_unset_pipe_fd(Session *s);
|
||||
int session_open_fifo(Session *s);
|
||||
int session_create_fifo(Session *s);
|
||||
void session_remove_fifo(Session *s);
|
||||
int session_start(Session *s);
|
||||
int session_stop(Session *s);
|
||||
int session_save(Session *s);
|
||||
|
||||
@@ -459,6 +459,9 @@ int user_check_gc(User *u) {
|
||||
|
||||
assert(u);
|
||||
|
||||
if (!u->started)
|
||||
return 0;
|
||||
|
||||
if (u->sessions)
|
||||
return 1;
|
||||
|
||||
|
||||
+7
-10
@@ -52,7 +52,7 @@ Manager *manager_new(void) {
|
||||
m->sessions = hashmap_new(string_hash_func, string_compare_func);
|
||||
m->users = hashmap_new(trivial_hash_func, trivial_compare_func);
|
||||
m->cgroups = hashmap_new(string_hash_func, string_compare_func);
|
||||
m->pipe_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
|
||||
m->fifo_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
|
||||
|
||||
if (!m->devices || !m->seats || !m->sessions || !m->users) {
|
||||
manager_free(m);
|
||||
@@ -98,7 +98,7 @@ void manager_free(Manager *m) {
|
||||
hashmap_free(m->devices);
|
||||
hashmap_free(m->seats);
|
||||
hashmap_free(m->cgroups);
|
||||
hashmap_free(m->pipe_fds);
|
||||
hashmap_free(m->fifo_fds);
|
||||
|
||||
if (m->console_active_fd >= 0)
|
||||
close_nointr_nofail(m->console_active_fd);
|
||||
@@ -802,9 +802,9 @@ static void manager_pipe_notify_eof(Manager *m, int fd) {
|
||||
assert_se(m);
|
||||
assert_se(fd >= 0);
|
||||
|
||||
assert_se(s = hashmap_get(m->pipe_fds, INT_TO_PTR(fd + 1)));
|
||||
assert(s->pipe_fd == fd);
|
||||
session_unset_pipe_fd(s);
|
||||
assert_se(s = hashmap_get(m->fifo_fds, INT_TO_PTR(fd + 1)));
|
||||
assert(s->fifo_fd == fd);
|
||||
session_remove_fifo(s);
|
||||
|
||||
session_stop(s);
|
||||
}
|
||||
@@ -1081,9 +1081,6 @@ int manager_startup(Manager *m) {
|
||||
manager_enumerate_users(m);
|
||||
manager_enumerate_sessions(m);
|
||||
|
||||
/* Get rid of objects that are no longer used */
|
||||
manager_gc(m);
|
||||
|
||||
/* And start everything */
|
||||
HASHMAP_FOREACH(seat, m->seats, i)
|
||||
seat_start(seat);
|
||||
@@ -1139,8 +1136,8 @@ int manager_run(Manager *m) {
|
||||
break;
|
||||
|
||||
default:
|
||||
if (event.data.u32 >= FD_PIPE_BASE)
|
||||
manager_pipe_notify_eof(m, event.data.u32 - FD_PIPE_BASE);
|
||||
if (event.data.u32 >= FD_FIFO_BASE)
|
||||
manager_pipe_notify_eof(m, event.data.u32 - FD_FIFO_BASE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-5
@@ -37,15 +37,14 @@
|
||||
* spawn user systemd
|
||||
* direct client API
|
||||
* add configuration file
|
||||
* D-Bus method: AttachDevices(seat, devices[]);
|
||||
* use named pipes to detect when a session dies
|
||||
* verify access to SetIdleHint
|
||||
*
|
||||
* udev:
|
||||
* drop redundant udev_device_get_is_initialized() use as soon as libudev is fixed
|
||||
* properly escape/remove : and . from seat names in udev rules
|
||||
* use device_has_tag() as soon as it is available
|
||||
* trigger based on libudev if available
|
||||
* enumerate recursively with libudev when triggering
|
||||
* make sure IMPORT{parent}="ID_SEAT" works between usb hub and sound card
|
||||
*
|
||||
* non-local X11 server
|
||||
* reboot/shutdown halt management
|
||||
@@ -94,7 +93,7 @@ struct Manager {
|
||||
unsigned long session_counter;
|
||||
|
||||
Hashmap *cgroups;
|
||||
Hashmap *pipe_fds;
|
||||
Hashmap *fifo_fds;
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -102,7 +101,7 @@ enum {
|
||||
FD_VCSA_UDEV,
|
||||
FD_CONSOLE,
|
||||
FD_BUS,
|
||||
FD_PIPE_BASE
|
||||
FD_FIFO_BASE
|
||||
};
|
||||
|
||||
Manager *manager_new(void);
|
||||
|
||||
Reference in New Issue
Block a user