X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd-terminal%2Fsysview.c;h=9ee32db1bc2ab08f07f7fbb0f8a90664454d0030;hb=be795898c0d2fa21e3389b89793dcd45c47f8b9f;hp=fde87d11174b73bdc09a46114a812cb105e99064;hpb=9169b9a8cc43046f92a4c5c85b0b3fe9ca0fb429;p=elogind.git diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c index fde87d111..9ee32db1b 100644 --- a/src/libsystemd-terminal/sysview.c +++ b/src/libsystemd-terminal/sysview.c @@ -104,6 +104,12 @@ sysview_device *sysview_device_free(sysview_device *device) { return NULL; } +const char *sysview_device_get_name(sysview_device *device) { + assert_return(device, NULL); + + return device->name; +} + unsigned int sysview_device_get_type(sysview_device *device) { assert_return(device, (unsigned)-1); @@ -243,18 +249,36 @@ sysview_session *sysview_session_free(sysview_session *session) { return NULL; } +void sysview_session_set_userdata(sysview_session *session, void *userdata) { + assert(session); + + session->userdata = userdata; +} + +void *sysview_session_get_userdata(sysview_session *session) { + assert_return(session, NULL); + + return session->userdata; +} + const char *sysview_session_get_name(sysview_session *session) { assert_return(session, NULL); 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, sd_bus_error *ret_error) { sysview_session *session = userdata; - int error; + int r, error; session->slot_take_control = sd_bus_slot_unref(session->slot_take_control); @@ -269,7 +293,12 @@ static int session_take_control_fn(sd_bus *bus, error = 0; } - return context_raise_session_control(session->seat->context, session, error); + r = context_raise_session_control(session->seat->context, session, error); + if (r < 0) + log_debug_errno(r, "sysview: callback failed while signalling session control '%d' on session '%s': %m", + error, session->name); + + return 0; } int sysview_session_take_control(sysview_session *session) { @@ -336,8 +365,8 @@ void sysview_session_release_control(sysview_session *session) { 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); } /* @@ -368,6 +397,10 @@ int sysview_seat_new(sysview_seat **out, sysview_context *c, const char *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; @@ -399,6 +432,7 @@ sysview_seat *sysview_seat_free(sysview_seat *seat) { hashmap_free(seat->device_map); hashmap_free(seat->session_map); + free(seat->path); free(seat->name); free(seat); @@ -411,6 +445,29 @@ const char *sysview_seat_get_name(sysview_seat *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 */ @@ -517,10 +574,23 @@ static int context_raise_session_detach(sysview_context *c, sysview_session *ses return context_raise(c, &event, 0); } -static int context_add_device(sysview_context *c, sysview_device *device) { +static int context_raise_session_refresh(sysview_context *c, sysview_session *session, sysview_device *device, struct udev_device *ud) { + sysview_event event = { + .type = SYSVIEW_EVENT_SESSION_REFRESH, + .session_refresh = { + .session = session, + .device = device, + .ud = ud, + } + }; + + return context_raise(c, &event, 0); +} + +static void context_add_device(sysview_context *c, sysview_device *device) { sysview_session *session; - int r, error = 0; Iterator i; + int r; assert(c); assert(device); @@ -533,20 +603,16 @@ static int context_add_device(sysview_context *c, sysview_device *device) { continue; r = context_raise_session_attach(c, session, device); - if (r != 0) - error = r; + if (r < 0) + log_debug_errno(r, "sysview: callback failed while attaching device '%s' to session '%s': %m", + device->name, session->name); } - - if (error < 0) - log_debug("sysview: error while adding device '%s': %s", - device->name, strerror(-r)); - return error; } -static int context_remove_device(sysview_context *c, sysview_device *device) { +static void context_remove_device(sysview_context *c, sysview_device *device) { sysview_session *session; - int r, error = 0; Iterator i; + int r; assert(c); assert(device); @@ -558,22 +624,40 @@ static int context_remove_device(sysview_context *c, sysview_device *device) { continue; r = context_raise_session_detach(c, session, device); - if (r != 0) - error = r; + if (r < 0) + log_debug_errno(r, "sysview: callback failed while detaching device '%s' from session '%s': %m", + device->name, session->name); } - if (error < 0) - log_debug("sysview: error while removing device '%s': %s", - device->name, strerror(-r)); sysview_device_free(device); - return error; } -static int context_add_session(sysview_context *c, sysview_seat *seat, const char *id) { +static void context_change_device(sysview_context *c, sysview_device *device, struct udev_device *ud) { + sysview_session *session; + Iterator i; + int r; + + assert(c); + assert(device); + + log_debug("sysview: change device '%s'", device->name); + + HASHMAP_FOREACH(session, device->seat->session_map, i) { + if (!session->public) + continue; + + r = context_raise_session_refresh(c, session, device, ud); + if (r < 0) + log_debug_errno(r, "sysview: callback failed while changing device '%s' on session '%s': %m", + device->name, session->name); + } +} + +static void context_add_session(sysview_context *c, sysview_seat *seat, const char *id) { sysview_session *session; sysview_device *device; - int r, error = 0; Iterator i; + int r; assert(c); assert(seat); @@ -581,7 +665,7 @@ static int context_add_session(sysview_context *c, sysview_seat *seat, const cha session = sysview_find_session(c, id); if (session) - return 0; + return; log_debug("sysview: add session '%s' on seat '%s'", id, seat->name); @@ -598,35 +682,33 @@ static int context_add_session(sysview_context *c, sysview_seat *seat, const cha if (seat->public) { session->public = true; r = context_raise_session_add(c, session); - if (r != 0) { + if (r < 0) { + 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) - error = r; + if (r < 0) + log_debug_errno(r, "sysview: callback failed while attaching device '%s' to new session '%s': %m", + device->name, session->name); } - - r = error; - if (r != 0) - goto error; } - return 0; + return; error: if (r < 0) - log_debug("sysview: error while adding session '%s': %s", - id, strerror(-r)); - return r; + log_debug_errno(r, "sysview: error while adding session '%s': %m", + id); } -static int context_remove_session(sysview_context *c, sysview_session *session) { +static void context_remove_session(sysview_context *c, sysview_session *session) { sysview_device *device; - int r, error = 0; Iterator i; + int r; assert(c); assert(session); @@ -636,27 +718,25 @@ static int context_remove_session(sysview_context *c, sysview_session *session) if (session->public) { HASHMAP_FOREACH(device, session->seat->device_map, i) { r = context_raise_session_detach(c, session, device); - if (r != 0) - error = r; + if (r < 0) + 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) - error = r; + if (r < 0) + log_debug_errno(r, "sysview: callback failed while removing session '%s': %m", + session->name); } if (!session->custom) sysview_session_release_control(session); - if (error < 0) - log_debug("sysview: error while removing session '%s': %s", - session->name, strerror(-error)); sysview_session_free(session); - return error; } -static int context_add_seat(sysview_context *c, const char *id) { +static void context_add_seat(sysview_context *c, const char *id) { sysview_seat *seat; int r; @@ -665,7 +745,7 @@ static int context_add_seat(sysview_context *c, const char *id) { seat = sysview_find_seat(c, id); if (seat) - return 0; + return; log_debug("sysview: add seat '%s'", id); @@ -675,54 +755,45 @@ static int context_add_seat(sysview_context *c, const char *id) { seat->public = true; r = context_raise_seat_add(c, seat); - if (r != 0) { + if (r < 0) { + log_debug_errno(r, "sysview: callback failed while adding seat '%s': %m", + seat->name); seat->public = false; - goto error; } - return 0; + return; error: if (r < 0) - log_debug("sysview: error while adding seat '%s': %s", - id, strerror(-r)); - return r; + log_debug_errno(r, "sysview: error while adding seat '%s': %m", + id); } -static int context_remove_seat(sysview_context *c, sysview_seat *seat) { +static void context_remove_seat(sysview_context *c, sysview_seat *seat) { sysview_session *session; sysview_device *device; - int r, error = 0; + int r; assert(c); assert(seat); log_debug("sysview: remove seat '%s'", seat->name); - while ((device = hashmap_first(seat->device_map))) { - r = context_remove_device(c, device); - if (r != 0) - error = r; - } + while ((device = hashmap_first(seat->device_map))) + context_remove_device(c, device); - while ((session = hashmap_first(seat->session_map))) { - r = context_remove_session(c, session); - if (r != 0) - error = r; - } + while ((session = hashmap_first(seat->session_map))) + context_remove_session(c, session); if (seat->public) { seat->public = false; r = context_raise_seat_remove(c, seat); - if (r != 0) - error = r; + if (r < 0) + log_debug_errno(r, "sysview: callback failed while removing seat '%s': %m", + seat->name); } - if (error < 0) - log_debug("sysview: error while removing seat '%s': %s", - seat->name, strerror(-error)); sysview_seat_free(seat); - return error; } int sysview_context_new(sysview_context **out, @@ -867,12 +938,12 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) { if (!device) return 0; - return context_remove_device(c, device); + context_remove_device(c, device); } else if (streq_ptr(action, "change")) { if (!device) return 0; - /* TODO: send REFRESH event */ + context_change_device(c, device, d); } else if (!action || streq_ptr(action, "add")) { struct udev_device *p; unsigned int type, t; @@ -883,7 +954,7 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) { if (streq(subsystem, "input") && startswith(sysname, "event") && safe_atou(sysname + 5, &t) >= 0) type = SYSVIEW_DEVICE_EVDEV; - else if (streq(subsystem, "drm") && startswith(sysname, "card") && safe_atou(sysname + 4, &t) >= 0) + else if (streq(subsystem, "drm") && startswith(sysname, "card")) type = SYSVIEW_DEVICE_DRM; else type = (unsigned)-1; @@ -893,24 +964,22 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) { p = d; seatname = NULL; - while ((p = udev_device_get_parent(p))) { + do { seatname = udev_device_get_property_value(p, "ID_SEAT"); if (seatname) break; - } + } while ((p = udev_device_get_parent(p))); seat = sysview_find_seat(c, seatname ? : "seat0"); if (!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); - return context_add_device(c, device); + context_add_device(c, device); } return 0; @@ -1012,8 +1081,8 @@ static int context_ud_scan(sysview_context *c) { 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; } @@ -1031,13 +1100,11 @@ static int context_ld_seat_new(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 SeatNew from logind: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_debug_errno(r, "sysview: cannot parse SeatNew from logind: %m"); - return context_add_seat(c, id); + context_add_seat(c, id); + return 0; } static int context_ld_seat_removed(sysview_context *c, sd_bus_message *signal) { @@ -1046,17 +1113,15 @@ static int context_ld_seat_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 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) return 0; - return context_remove_seat(c, seat); + context_remove_seat(c, seat); + return 0; } static int context_ld_session_new(sysview_context *c, sd_bus_message *signal) { @@ -1067,11 +1132,8 @@ static int context_ld_session_new(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 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 @@ -1103,19 +1165,17 @@ static int context_ld_session_new(sysview_context *c, sd_bus_message *signal) { } r = context_raise_session_filter(c, id, seatid, username, uid); - if (r <= 0) { - if (r < 0) - log_debug("sysview: cannot filter new session '%s' on seat '%s': %s", - id, seatid, strerror(-r)); - return r; - } + if (r < 0) + log_debug_errno(r, "sysview: callback failed while filtering session '%s': %m", + id); + else if (r > 0) + context_add_session(c, seat, id); - return 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) { @@ -1124,17 +1184,15 @@ 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) return 0; - return context_remove_session(c, session); + context_remove_session(c, session); + return 0; } static int context_ld_manager_signal_fn(sd_bus *bus, @@ -1209,9 +1267,7 @@ static int context_ld_list_seats_fn(sd_bus *bus, if (r < 0) goto error; - r = context_add_seat(c, id); - if (r != 0) - return r; + context_add_seat(c, id); r = sd_bus_message_exit_container(reply); if (r < 0) @@ -1228,9 +1284,7 @@ static int context_ld_list_seats_fn(sd_bus *bus, return 0; error: - log_debug("sysview: erroneous ListSeats response from logind: %s", - strerror(-r)); - return r; + return log_debug_errno(r, "sysview: erroneous ListSeats response from logind: %m"); } static int context_ld_list_sessions_fn(sd_bus *bus, @@ -1272,15 +1326,11 @@ static int context_ld_list_sessions_fn(sd_bus *bus, seat = sysview_find_seat(c, seatid); if (seat) { r = context_raise_session_filter(c, id, seatid, username, uid); - if (r < 0) { - log_debug("sysview: cannot filter listed session '%s' on seat '%s': %s", - id, seatid, strerror(-r)); - return r; - } else if (r > 0) { - r = context_add_session(c, seat, id); - if (r != 0) - return r; - } + if (r < 0) + 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); @@ -1298,9 +1348,7 @@ static int context_ld_list_sessions_fn(sd_bus *bus, return 0; error: - log_debug("sysview: erroneous ListSessions response from logind: %s", - strerror(-r)); - return r; + return log_debug_errno(r, "sysview: erroneous ListSessions response from logind: %m"); } static int context_ld_scan(sysview_context *c) { @@ -1404,20 +1452,6 @@ void sysview_context_stop(sysview_context *c) { 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); @@ -1426,6 +1460,14 @@ void sysview_context_stop(sysview_context *c) { while ((seat = hashmap_first(c->seat_map))) context_remove_seat(c, seat); + + 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); } static int context_scan_fn(sd_event_source *s, void *userdata) { @@ -1436,19 +1478,15 @@ static int context_scan_fn(sd_event_source *s, void *userdata) { 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;