#include <systemd/sd-event.h>
#include <systemd/sd-login.h>
#include "bus-util.h"
-#include "event-util.h"
#include "macro.h"
-#include "set.h"
#include "sysview.h"
#include "sysview-internal.h"
#include "udev-util.h"
return session->name;
}
+sysview_seat *sysview_session_get_seat(sysview_session *session) {
+ assert_return(session, NULL);
+
+ return session->seat;
+}
+
static int session_take_control_fn(sd_bus *bus,
sd_bus_message *reply,
void *userdata,
r = context_raise_session_control(session->seat->context, session, error);
if (r < 0)
- log_debug("sysview: callback failed while signalling session control '%d' on session '%s': %s",
- error, session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while signalling session control '%d' on session '%s': %m",
+ error, session->name);
return 0;
}
r = sd_bus_send(session->seat->context->sysbus, m, NULL);
if (r < 0 && r != -ENOTCONN)
- log_debug("sysview: %s: cannot send ReleaseControl: %s",
- session->name, strerror(-r));
+ log_debug_errno(r, "sysview: %s: cannot send ReleaseControl: %m",
+ session->name);
}
/*
if (!seat->name)
return -ENOMEM;
+ r = sd_bus_path_encode("/org/freedesktop/login1/seat", seat->name, &seat->path);
+ if (r < 0)
+ return r;
+
seat->session_map = hashmap_new(&string_hash_ops);
if (!seat->session_map)
return -ENOMEM;
hashmap_free(seat->device_map);
hashmap_free(seat->session_map);
+ free(seat->path);
free(seat->name);
free(seat);
return seat->name;
}
+int sysview_seat_switch_to(sysview_seat *seat, uint32_t nr) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ int r;
+
+ assert_return(seat, -EINVAL);
+ assert_return(seat->context->sysbus, -EINVAL);
+
+ r = sd_bus_message_new_method_call(seat->context->sysbus,
+ &m,
+ "org.freedesktop.login1",
+ seat->path,
+ "org.freedesktop.login1.Seat",
+ "SwitchTo");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "u", nr);
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(seat->context->sysbus, m, NULL);
+}
+
/*
* Contexts
*/
return c->running ? c->event_fn(c, c->userdata, event) : def;
}
+static int context_raise_settle(sysview_context *c) {
+ sysview_event event = {
+ .type = SYSVIEW_EVENT_SETTLE,
+ };
+
+ return context_raise(c, &event, 0);
+}
+
static int context_raise_seat_add(sysview_context *c, sysview_seat *seat) {
sysview_event event = {
.type = SYSVIEW_EVENT_SEAT_ADD,
return context_raise(c, &event, 0);
}
+static void context_settle(sysview_context *c) {
+ int r;
+
+ if (c->n_probe <= 0 || --c->n_probe > 0)
+ return;
+
+ log_debug("sysview: settle");
+
+ c->settled = true;
+
+ r = context_raise_settle(c);
+ if (r < 0)
+ log_debug_errno(r, "sysview: callback failed on settle: %m");
+}
+
static void context_add_device(sysview_context *c, sysview_device *device) {
sysview_session *session;
Iterator i;
r = context_raise_session_attach(c, session, device);
if (r < 0)
- log_debug("sysview: callback failed while attaching device '%s' to session '%s': %s",
- device->name, session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while attaching device '%s' to session '%s': %m",
+ device->name, session->name);
}
}
r = context_raise_session_detach(c, session, device);
if (r < 0)
- log_debug("sysview: callback failed while detaching device '%s' from session '%s': %s",
- device->name, session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while detaching device '%s' from session '%s': %m",
+ device->name, session->name);
}
sysview_device_free(device);
r = context_raise_session_refresh(c, session, device, ud);
if (r < 0)
- log_debug("sysview: callback failed while changing device '%s' on session '%s': %s",
- device->name, session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while changing device '%s' on session '%s': %m",
+ device->name, session->name);
}
}
session->public = true;
r = context_raise_session_add(c, session);
if (r < 0) {
- log_debug("sysview: callback failed while adding session '%s': %s",
- session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while adding session '%s': %m",
+ session->name);
session->public = false;
goto error;
}
HASHMAP_FOREACH(device, seat->device_map, i) {
r = context_raise_session_attach(c, session, device);
if (r < 0)
- log_debug("sysview: callback failed while attaching device '%s' to new session '%s': %s",
- device->name, session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while attaching device '%s' to new session '%s': %m",
+ device->name, session->name);
}
}
error:
if (r < 0)
- log_debug("sysview: error while adding session '%s': %s",
- id, strerror(-r));
+ log_debug_errno(r, "sysview: error while adding session '%s': %m",
+ id);
}
static void context_remove_session(sysview_context *c, sysview_session *session) {
HASHMAP_FOREACH(device, session->seat->device_map, i) {
r = context_raise_session_detach(c, session, device);
if (r < 0)
- log_debug("sysview: callback failed while detaching device '%s' from old session '%s': %s",
- device->name, session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while detaching device '%s' from old session '%s': %m",
+ device->name, session->name);
}
session->public = false;
r = context_raise_session_remove(c, session);
if (r < 0)
- log_debug("sysview: callback failed while removing session '%s': %s",
- session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while removing session '%s': %m",
+ session->name);
}
if (!session->custom)
seat->public = true;
r = context_raise_seat_add(c, seat);
if (r < 0) {
- log_debug("sysview: callback failed while adding seat '%s': %s",
- seat->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while adding seat '%s': %m",
+ seat->name);
seat->public = false;
}
error:
if (r < 0)
- log_debug("sysview: error while adding seat '%s': %s",
- id, strerror(-r));
+ log_debug_errno(r, "sysview: error while adding seat '%s': %m",
+ id);
}
static void context_remove_seat(sysview_context *c, sysview_seat *seat) {
seat->public = false;
r = context_raise_seat_remove(c, seat);
if (r < 0)
- log_debug("sysview: callback failed while removing seat '%s': %s",
- seat->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while removing seat '%s': %m",
+ seat->name);
}
sysview_seat_free(seat);
return 0;
r = device_new_ud(&device, seat, type, d);
- if (r < 0) {
- log_debug("sysview: cannot create device for udev-device '%s': %s",
- syspath, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "sysview: cannot create device for udev-device '%s': %m",
+ syspath);
context_add_device(c, device);
}
d = udev_device_new_from_syspath(c->ud, name);
if (!d) {
r = errno > 0 ? -errno : -EFAULT;
- log_debug("sysview: cannot create udev-device for %s: %s",
- name, strerror(-r));
+ log_debug_errno(r, "sysview: cannot create udev-device for %s: %m",
+ name);
continue;
}
int r;
r = sd_bus_message_read(signal, "so", &id, &path);
- if (r < 0) {
- log_debug("sysview: cannot parse SeatNew from logind: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "sysview: cannot parse SeatNew from logind: %m");
context_add_seat(c, id);
return 0;
int r;
r = sd_bus_message_read(signal, "so", &id, &path);
- if (r < 0) {
- log_debug("sysview: cannot parse SeatRemoved from logind: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "sysview: cannot parse SeatRemoved from logind: %m");
seat = sysview_find_seat(c, id);
if (!seat)
int r;
r = sd_bus_message_read(signal, "so", &id, &path);
- if (r < 0) {
- log_debug("sysview: cannot parse SessionNew from logind: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "sysview: cannot parse SessionNew from logind: %m");
/*
* As the dbus message didn't contain enough information, we
r = context_raise_session_filter(c, id, seatid, username, uid);
if (r < 0)
- log_debug("sysview: callback failed while filtering session '%s': %s",
- id, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while filtering session '%s': %m",
+ id);
else if (r > 0)
context_add_session(c, seat, id);
return 0;
error:
- log_debug("sysview: failed retrieving information for new session '%s': %s",
- id, strerror(-r));
- return r;
+ return log_debug_errno(r, "sysview: failed retrieving information for new session '%s': %m",
+ id);
}
static int context_ld_session_removed(sysview_context *c, sd_bus_message *signal) {
int r;
r = sd_bus_message_read(signal, "so", &id, &path);
- if (r < 0) {
- log_debug("sysview: cannot parse SessionRemoved from logind: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "sysview: cannot parse SessionRemoved from logind: %m");
session = sysview_find_session(c, id);
if (!session)
log_debug("sysview: ListSeats on logind failed: %s: %s",
error->name, error->message);
- return -sd_bus_error_get_errno(error);
+ r = -sd_bus_error_get_errno(error);
+ goto settle;
}
r = sd_bus_message_enter_container(reply, 'a', "(so)");
r = sd_bus_message_exit_container(reply);
if (r < 0)
- return r;
+ goto error;
- return 0;
+ r = 0;
+ goto settle;
error:
- log_debug("sysview: erroneous ListSeats response from logind: %s",
- strerror(-r));
+ log_debug_errno(r, "sysview: erroneous ListSeats response from logind: %m");
+settle:
+ context_settle(c);
return r;
}
log_debug("sysview: ListSessions on logind failed: %s: %s",
error->name, error->message);
- return -sd_bus_error_get_errno(error);
+ r = -sd_bus_error_get_errno(error);
+ goto settle;
}
r = sd_bus_message_enter_container(reply, 'a', "(susso)");
if (seat) {
r = context_raise_session_filter(c, id, seatid, username, uid);
if (r < 0)
- log_debug("sysview: callback failed while filtering session '%s': %s",
- id, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while filtering session '%s': %m",
+ id);
else if (r > 0)
context_add_session(c, seat, id);
}
r = sd_bus_message_exit_container(reply);
if (r < 0)
- return r;
+ goto error;
- return 0;
+ r = 0;
+ goto settle;
error:
- log_debug("sysview: erroneous ListSessions response from logind: %s",
- strerror(-r));
+ log_debug_errno(r, "sysview: erroneous ListSessions response from logind: %m");
+settle:
+ context_settle(c);
return r;
}
if (r < 0)
return r;
+ if (!c->settled)
+ ++c->n_probe;
+
/* request session list */
m = sd_bus_message_unref(m);
if (r < 0)
return r;
+ if (!c->settled)
+ ++c->n_probe;
+
return 0;
}
log_debug("sysview: stop");
- c->running = false;
- c->scanned = false;
- c->event_fn = NULL;
- c->userdata = NULL;
- c->scan_src = sd_event_source_unref(c->scan_src);
- context_ud_stop(c);
- context_ld_stop(c);
-
- /*
- * Event-callbacks are already cleared, hence we can safely ignore
- * return codes of the context_remove_*() helpers. They cannot be
- * originated from user-callbacks, so we already handled them.
- */
-
while ((device = hashmap_first(c->device_map)))
context_remove_device(c, device);
while ((seat = hashmap_first(c->seat_map)))
context_remove_seat(c, seat);
+
+ c->running = false;
+ c->scanned = false;
+ c->settled = false;
+ c->n_probe = 0;
+ c->event_fn = NULL;
+ c->userdata = NULL;
+ c->scan_src = sd_event_source_unref(c->scan_src);
+ context_ud_stop(c);
+ context_ld_stop(c);
}
static int context_scan_fn(sd_event_source *s, void *userdata) {
Iterator i;
int r;
+ c->rescan = false;
+
if (!c->scanned) {
r = context_ld_scan(c);
- if (r < 0) {
- log_debug("sysview: logind scan failed: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "sysview: logind scan failed: %m");
}
/* skip device scans if no sessions are available */
if (hashmap_size(c->session_map) > 0) {
r = context_ud_scan(c);
- if (r < 0) {
- log_debug("sysview: udev scan failed: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "sysview: udev scan failed: %m");
HASHMAP_FOREACH(seat, c->seat_map, i)
seat->scanned = true;
}
c->scanned = true;
+ context_settle(c);
return 0;
}
if (!c->running)
return 0;
+ if (!c->rescan) {
+ c->rescan = true;
+ if (!c->settled)
+ ++c->n_probe;
+ }
+
if (c->scan_src)
return sd_event_source_set_enabled(c->scan_src, SD_EVENT_ONESHOT);
else