#include "sd-messages.h"
#include "alloc-util.h"
-#include "devnode-acl.h"
+#include "device-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-util.h"
#include "fs-util.h"
+#include "id128-util.h"
#include "logind.h"
#include "logind-device.h"
#include "logind-seat.h"
hashmap_remove(s->manager->seats, s->id);
+ set_free(s->uevents);
free(s->positions);
free(s->state_file);
free(s->id);
return r;
}
-int seat_apply_acls(Seat *s, Session *old_active) {
+static void seat_triggered_uevents_done(Seat *s) {
+ assert(s);
+
+ if (!set_isempty(s->uevents))
+ return;
+
+ Session *session = s->active;
+
+ if (session) {
+ session_save(session);
+ user_save(session->user);
+ }
+
+ if (session && session->started) {
+ session_send_changed(session, "Active");
+ session_device_resume_all(session);
+ }
+
+ if (!session || session->started)
+ seat_send_changed(s, "ActiveSession");
+}
+
+int manager_process_device_triggered_by_seat(Manager *m, sd_device *dev) {
+ int r;
+
+ assert(m);
+ assert(dev);
+
+ sd_id128_t uuid;
+ r = sd_device_get_trigger_uuid(dev, &uuid);
+ if (IN_SET(r, -ENOENT, -ENODATA))
+ return 0;
+ if (r < 0)
+ return r;
+
+ Seat *s;
+ HASHMAP_FOREACH(s, m->seats)
+ if (set_contains(s->uevents, &uuid))
+ break;
+ if (!s)
+ return 0;
+
+ free(ASSERT_PTR(set_remove(s->uevents, &uuid)));
+ seat_triggered_uevents_done(s);
+
+ const char *id;
+ r = device_get_seat(dev, &id);
+ if (r < 0)
+ return r;
+
+ if (!streq(id, s->id)) {
+ log_device_debug(dev, "ID_SEAT is changed in the triggered uevent: \"%s\" -> \"%s\"", s->id, id);
+ return 0;
+ }
+
+ return 1; /* The uevent is triggered by the relevant seat. */
+}
+
+static int seat_trigger_devices(Seat *s) {
int r;
assert(s);
- r = devnode_acl_all(s->id,
- false,
- !!old_active, old_active ? old_active->user->user_record->uid : 0,
- !!s->active, s->active ? s->active->user->user_record->uid : 0);
+ set_clear(s->uevents);
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ r = sd_device_enumerator_new(&e);
if (r < 0)
- return log_error_errno(r, "Failed to apply ACLs: %m");
+ return r;
+
+ r = sd_device_enumerator_add_match_tag(e, "uaccess");
+ if (r < 0)
+ return r;
+ FOREACH_DEVICE(e, d) {
+ /* Verify that the tag is still in place. */
+ r = sd_device_has_current_tag(d, "uaccess");
+ if (r < 0)
+ return r;
+ if (r == 0)
+ continue;
+
+ /* In case people mistag devices without nodes, we need to ignore this. */
+ r = sd_device_get_devname(d, NULL);
+ if (r == -ENOENT)
+ continue;
+ if (r < 0)
+ return r;
+
+ const char *id;
+ r = device_get_seat(d, &id);
+ if (r < 0)
+ return r;
+
+ if (!streq(id, s->id))
+ continue;
+
+ sd_id128_t uuid;
+ r = sd_device_trigger_with_uuid(d, SD_DEVICE_CHANGE, &uuid);
+ if (r < 0) {
+ log_device_debug_errno(d, r, "Failed to trigger 'change' event, ignoring: %m");
+ continue;
+ }
+
+ _cleanup_free_ sd_id128_t *copy = newdup(sd_id128_t, &uuid, 1);
+ if (!copy)
+ return -ENOMEM;
+
+ r = set_ensure_consume(&s->uevents, &id128_hash_ops_free, TAKE_PTR(copy));
+ if (r < 0)
+ return r;
+ }
+
+ seat_triggered_uevents_done(s);
return 0;
}
* Therefore, if the active session has executed session_leave_vt ,
* A resume is required here. */
if (session == s->active) {
- if (session) {
+ if (session && set_isempty(s->uevents)) {
log_debug("Active session remains unchanged, resuming session devices.");
session_device_resume_all(session);
}
seat_save(s);
if (old_active) {
+ user_save(old_active->user);
+ session_save(old_active);
session_device_pause_all(old_active);
session_send_changed(old_active, "Active");
}
- (void) seat_apply_acls(s, old_active);
-
- if (session && session->started) {
- session_send_changed(session, "Active");
- session_device_resume_all(session);
- }
-
- if (!session || session->started)
- seat_send_changed(s, "ActiveSession");
-
- if (session) {
- session_save(session);
- user_save(session->user);
- }
-
- if (old_active) {
- session_save(old_active);
- if (!session || session->user != old_active->user)
- user_save(old_active->user);
- }
-
- return 0;
+ return seat_trigger_devices(s);
}
static Session* seat_get_position(Seat *s, unsigned pos) {
assert(device);
+ /* If the event is triggered by us, do not try to start the relevant seat again. Otherwise, starting
+ * the seat may trigger uevents again again again... */
+ r = manager_process_device_triggered_by_seat(m, device);
+ if (r < 0)
+ log_device_warning_errno(device, r, "Failed to process seat device event triggered by us, ignoring: %m");
+ if (r != 0)
+ return 0;
+
r = manager_process_seat_device(m, device);
if (r < 0)
log_device_warning_errno(device, r, "Failed to process seat device, ignoring: %m");
if (r != 0)
return 0;
+ /* If the event is triggered by us, do not try to start the relevant seat again. Otherwise, starting
+ * the seat may trigger uevents again again again... */
+ r = manager_process_device_triggered_by_seat(m, device);
+ if (r < 0)
+ log_device_warning_errno(device, r, "Failed to process seat device event triggered by us, ignoring: %m");
+ if (r != 0)
+ return 0;
+
r = manager_process_seat_device(m, device);
if (r < 0)
log_device_warning_errno(device, r, "Failed to process seat device, ignoring: %m");