1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include <systemd/sd-bus.h>
27 #include <systemd/sd-event.h>
28 #include <systemd/sd-login.h>
30 #include "event-util.h"
34 #include "sysview-internal.h"
35 #include "udev-util.h"
38 static int context_raise_session_control(sysview_context *c, sysview_session *session, int error);
44 sysview_device *sysview_find_device(sysview_context *c, const char *name) {
45 assert_return(c, NULL);
46 assert_return(name, NULL);
48 return hashmap_get(c->device_map, name);
51 int sysview_device_new(sysview_device **out, sysview_seat *seat, const char *name) {
52 _cleanup_(sysview_device_freep) sysview_device *device = NULL;
55 assert_return(seat, -EINVAL);
56 assert_return(name, -EINVAL);
58 device = new0(sysview_device, 1);
63 device->type = (unsigned)-1;
65 device->name = strdup(name);
69 r = hashmap_put(seat->context->device_map, device->name, device);
73 r = hashmap_put(seat->device_map, device->name, device);
83 sysview_device *sysview_device_free(sysview_device *device) {
88 hashmap_remove_value(device->seat->device_map, device->name, device);
89 hashmap_remove_value(device->seat->context->device_map, device->name, device);
92 switch (device->type) {
93 case SYSVIEW_DEVICE_EVDEV:
94 device->evdev.ud = udev_device_unref(device->evdev.ud);
96 case SYSVIEW_DEVICE_DRM:
97 device->drm.ud = udev_device_unref(device->drm.ud);
106 unsigned int sysview_device_get_type(sysview_device *device) {
107 assert_return(device, (unsigned)-1);
112 struct udev_device *sysview_device_get_ud(sysview_device *device) {
113 assert_return(device, NULL);
115 switch (device->type) {
116 case SYSVIEW_DEVICE_EVDEV:
117 return device->evdev.ud;
118 case SYSVIEW_DEVICE_DRM:
119 return device->drm.ud;
121 assert_return(0, NULL);
125 static int device_new_ud(sysview_device **out, sysview_seat *seat, unsigned int type, struct udev_device *ud) {
126 _cleanup_(sysview_device_freep) sysview_device *device = NULL;
129 assert_return(seat, -EINVAL);
130 assert_return(ud, -EINVAL);
132 r = sysview_device_new(&device, seat, udev_device_get_syspath(ud));
139 case SYSVIEW_DEVICE_EVDEV:
140 device->evdev.ud = udev_device_ref(ud);
142 case SYSVIEW_DEVICE_DRM:
143 device->drm.ud = udev_device_ref(ud);
146 assert_not_reached("sysview: invalid udev-device type");
159 sysview_session *sysview_find_session(sysview_context *c, const char *name) {
160 assert_return(c, NULL);
161 assert_return(name, NULL);
163 return hashmap_get(c->session_map, name);
166 int sysview_session_new(sysview_session **out, sysview_seat *seat, const char *name) {
167 _cleanup_(sysview_session_freep) sysview_session *session = NULL;
170 assert_return(seat, -EINVAL);
172 session = new0(sysview_session, 1);
176 session->seat = seat;
180 * If a name is given, we require it to be a logind session
181 * name. The session will be put in managed mode and we use
182 * logind to request controller access.
185 session->name = strdup(name);
189 r = sd_bus_path_encode("/org/freedesktop/login1/session",
190 session->name, &session->path);
194 session->custom = false;;
197 * No session name was given. We assume this is an unmanaged
198 * session controlled by the application. We don't use logind
199 * at all and leave session management to the application. The
200 * name of the session-object is set to a unique random string
201 * that does not clash with the logind namespace.
204 r = asprintf(&session->name, "@custom%" PRIu64,
205 ++seat->context->custom_sid);
209 session->custom = true;
212 r = hashmap_put(seat->context->session_map, session->name, session);
216 r = hashmap_put(seat->session_map, session->name, session);
226 sysview_session *sysview_session_free(sysview_session *session) {
230 assert(!session->public);
231 assert(!session->wants_control);
234 hashmap_remove_value(session->seat->session_map, session->name, session);
235 hashmap_remove_value(session->seat->context->session_map, session->name, session);
245 const char *sysview_session_get_name(sysview_session *session) {
246 assert_return(session, NULL);
248 return session->name;
251 static int session_take_control_fn(sd_bus *bus,
252 sd_bus_message *reply,
254 sd_bus_error *ret_error) {
255 sysview_session *session = userdata;
258 session->slot_take_control = sd_bus_slot_unref(session->slot_take_control);
260 if (sd_bus_message_is_method_error(reply, NULL)) {
261 const sd_bus_error *e = sd_bus_message_get_error(reply);
263 log_debug("sysview: %s: TakeControl failed: %s: %s",
264 session->name, e->name, e->message);
265 error = sd_bus_error_get_errno(e);
267 session->has_control = true;
271 return context_raise_session_control(session->seat->context, session, error);
274 int sysview_session_take_control(sysview_session *session) {
275 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
278 assert_return(session, -EINVAL);
279 assert_return(!session->custom, -EINVAL);
281 if (session->wants_control)
284 r = sd_bus_message_new_method_call(session->seat->context->sysbus,
286 "org.freedesktop.login1",
288 "org.freedesktop.login1.Session",
293 r = sd_bus_message_append(m, "b", 0);
297 r = sd_bus_call_async(session->seat->context->sysbus,
298 &session->slot_take_control,
300 session_take_control_fn,
306 session->wants_control = true;
310 void sysview_session_release_control(sysview_session *session) {
311 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
315 assert(!session->custom);
317 if (!session->wants_control)
320 session->wants_control = false;
322 if (!session->has_control && !session->slot_take_control)
325 session->has_control = false;
326 session->slot_take_control = sd_bus_slot_unref(session->slot_take_control);
328 r = sd_bus_message_new_method_call(session->seat->context->sysbus,
330 "org.freedesktop.login1",
332 "org.freedesktop.login1.Session",
335 r = sd_bus_send(session->seat->context->sysbus, m, NULL);
337 if (r < 0 && r != -ENOTCONN)
338 log_debug("sysview: %s: cannot send ReleaseControl: %s",
339 session->name, strerror(-r));
346 sysview_seat *sysview_find_seat(sysview_context *c, const char *name) {
347 assert_return(c, NULL);
348 assert_return(name, NULL);
350 return hashmap_get(c->seat_map, name);
353 int sysview_seat_new(sysview_seat **out, sysview_context *c, const char *name) {
354 _cleanup_(sysview_seat_freep) sysview_seat *seat = NULL;
357 assert_return(c, -EINVAL);
358 assert_return(name, -EINVAL);
360 seat = new0(sysview_seat, 1);
366 seat->name = strdup(name);
370 seat->session_map = hashmap_new(string_hash_func, string_compare_func);
371 if (!seat->session_map)
374 seat->device_map = hashmap_new(string_hash_func, string_compare_func);
375 if (!seat->device_map)
378 r = hashmap_put(c->seat_map, seat->name, seat);
388 sysview_seat *sysview_seat_free(sysview_seat *seat) {
392 assert(!seat->public);
393 assert(hashmap_size(seat->device_map) == 0);
394 assert(hashmap_size(seat->session_map) == 0);
397 hashmap_remove_value(seat->context->seat_map, seat->name, seat);
399 hashmap_free(seat->device_map);
400 hashmap_free(seat->session_map);
407 const char *sysview_seat_get_name(sysview_seat *seat) {
408 assert_return(seat, NULL);
417 static int context_raise(sysview_context *c, sysview_event *event, int def) {
418 return c->running ? c->event_fn(c, c->userdata, event) : def;
421 static int context_raise_seat_add(sysview_context *c, sysview_seat *seat) {
422 sysview_event event = {
423 .type = SYSVIEW_EVENT_SEAT_ADD,
429 return context_raise(c, &event, 0);
432 static int context_raise_seat_remove(sysview_context *c, sysview_seat *seat) {
433 sysview_event event = {
434 .type = SYSVIEW_EVENT_SEAT_REMOVE,
440 return context_raise(c, &event, 0);
443 static int context_raise_session_filter(sysview_context *c,
446 const char *username,
448 sysview_event event = {
449 .type = SYSVIEW_EVENT_SESSION_FILTER,
453 .username = username,
458 return context_raise(c, &event, 1);
461 static int context_raise_session_add(sysview_context *c, sysview_session *session) {
462 sysview_event event = {
463 .type = SYSVIEW_EVENT_SESSION_ADD,
469 return context_raise(c, &event, 0);
472 static int context_raise_session_remove(sysview_context *c, sysview_session *session) {
473 sysview_event event = {
474 .type = SYSVIEW_EVENT_SESSION_REMOVE,
480 return context_raise(c, &event, 0);
483 static int context_raise_session_control(sysview_context *c, sysview_session *session, int error) {
484 sysview_event event = {
485 .type = SYSVIEW_EVENT_SESSION_CONTROL,
492 return context_raise(c, &event, 0);
495 static int context_raise_session_attach(sysview_context *c, sysview_session *session, sysview_device *device) {
496 sysview_event event = {
497 .type = SYSVIEW_EVENT_SESSION_ATTACH,
504 return context_raise(c, &event, 0);
507 static int context_raise_session_detach(sysview_context *c, sysview_session *session, sysview_device *device) {
508 sysview_event event = {
509 .type = SYSVIEW_EVENT_SESSION_DETACH,
516 return context_raise(c, &event, 0);
519 static int context_add_device(sysview_context *c, sysview_device *device) {
520 sysview_session *session;
527 log_debug("sysview: add device '%s' on seat '%s'",
528 device->name, device->seat->name);
530 HASHMAP_FOREACH(session, device->seat->session_map, i) {
531 if (!session->public)
534 r = context_raise_session_attach(c, session, device);
540 log_debug("sysview: error while adding device '%s': %s",
541 device->name, strerror(-r));
545 static int context_remove_device(sysview_context *c, sysview_device *device) {
546 sysview_session *session;
553 log_debug("sysview: remove device '%s'", device->name);
555 HASHMAP_FOREACH(session, device->seat->session_map, i) {
556 if (!session->public)
559 r = context_raise_session_detach(c, session, device);
565 log_debug("sysview: error while removing device '%s': %s",
566 device->name, strerror(-r));
567 sysview_device_free(device);
571 static int context_add_session(sysview_context *c, sysview_seat *seat, const char *id) {
572 sysview_session *session;
573 sysview_device *device;
581 session = sysview_find_session(c, id);
585 log_debug("sysview: add session '%s' on seat '%s'", id, seat->name);
587 r = sysview_session_new(&session, seat, id);
591 if (!seat->scanned) {
592 r = sysview_context_rescan(c);
598 session->public = true;
599 r = context_raise_session_add(c, session);
601 session->public = false;
605 HASHMAP_FOREACH(device, seat->device_map, i) {
606 r = context_raise_session_attach(c, session, device);
620 log_debug("sysview: error while adding session '%s': %s",
625 static int context_remove_session(sysview_context *c, sysview_session *session) {
626 sysview_device *device;
633 log_debug("sysview: remove session '%s'", session->name);
635 if (session->public) {
636 HASHMAP_FOREACH(device, session->seat->device_map, i) {
637 r = context_raise_session_detach(c, session, device);
642 session->public = false;
643 r = context_raise_session_remove(c, session);
648 if (!session->custom)
649 sysview_session_release_control(session);
652 log_debug("sysview: error while removing session '%s': %s",
653 session->name, strerror(-error));
654 sysview_session_free(session);
658 static int context_add_seat(sysview_context *c, const char *id) {
665 seat = sysview_find_seat(c, id);
669 log_debug("sysview: add seat '%s'", id);
671 r = sysview_seat_new(&seat, c, id);
676 r = context_raise_seat_add(c, seat);
678 seat->public = false;
686 log_debug("sysview: error while adding seat '%s': %s",
691 static int context_remove_seat(sysview_context *c, sysview_seat *seat) {
692 sysview_session *session;
693 sysview_device *device;
699 log_debug("sysview: remove seat '%s'", seat->name);
701 while ((device = hashmap_first(seat->device_map))) {
702 r = context_remove_device(c, device);
707 while ((session = hashmap_first(seat->session_map))) {
708 r = context_remove_session(c, session);
714 seat->public = false;
715 r = context_raise_seat_remove(c, seat);
721 log_debug("sysview: error while removing seat '%s': %s",
722 seat->name, strerror(-error));
723 sysview_seat_free(seat);
727 int sysview_context_new(sysview_context **out,
732 _cleanup_(sysview_context_freep) sysview_context *c = NULL;
735 assert_return(out, -EINVAL);
736 assert_return(event, -EINVAL);
738 log_debug("sysview: new");
740 c = new0(sysview_context, 1);
744 c->event = sd_event_ref(event);
745 if (flags & SYSVIEW_CONTEXT_SCAN_LOGIND)
746 c->scan_logind = true;
747 if (flags & SYSVIEW_CONTEXT_SCAN_EVDEV)
748 c->scan_evdev = true;
749 if (flags & SYSVIEW_CONTEXT_SCAN_DRM)
753 c->sysbus = sd_bus_ref(sysbus);
754 } else if (c->scan_logind) {
755 r = sd_bus_open_system(&c->sysbus);
761 c->ud = udev_ref(ud);
762 } else if (c->scan_evdev || c->scan_drm) {
766 return errno > 0 ? -errno : -EFAULT;
769 c->seat_map = hashmap_new(string_hash_func, string_compare_func);
773 c->session_map = hashmap_new(string_hash_func, string_compare_func);
777 c->device_map = hashmap_new(string_hash_func, string_compare_func);
786 sysview_context *sysview_context_free(sysview_context *c) {
790 log_debug("sysview: free");
792 sysview_context_stop(c);
794 assert(hashmap_size(c->device_map) == 0);
795 assert(hashmap_size(c->session_map) == 0);
796 assert(hashmap_size(c->seat_map) == 0);
798 hashmap_free(c->device_map);
799 hashmap_free(c->session_map);
800 hashmap_free(c->seat_map);
801 c->ud = udev_unref(c->ud);
802 c->sysbus = sd_bus_unref(c->sysbus);
803 c->event = sd_event_unref(c->event);
809 static int context_ud_prepare_monitor(sysview_context *c, struct udev_monitor *m) {
813 r = udev_monitor_filter_add_match_subsystem_devtype(m, "input", NULL);
819 r = udev_monitor_filter_add_match_subsystem_devtype(m, "drm", NULL);
827 static int context_ud_prepare_scan(sysview_context *c, struct udev_enumerate *e) {
831 r = udev_enumerate_add_match_subsystem(e, "input");
837 r = udev_enumerate_add_match_subsystem(e, "drm");
842 r = udev_enumerate_add_match_is_initialized(e);
849 static int context_ud_hotplug(sysview_context *c, struct udev_device *d) {
850 const char *syspath, *sysname, *subsystem, *action, *seatname;
851 sysview_device *device;
854 syspath = udev_device_get_syspath(d);
855 sysname = udev_device_get_sysname(d);
856 subsystem = udev_device_get_subsystem(d);
857 action = udev_device_get_action(d);
859 /* not interested in custom devices without syspath/etc */
860 if (!syspath || !sysname || !subsystem)
863 device = sysview_find_device(c, syspath);
865 if (streq_ptr(action, "remove")) {
869 return context_remove_device(c, device);
870 } else if (streq_ptr(action, "change")) {
874 /* TODO: send REFRESH event */
875 } else if (!action || streq_ptr(action, "add")) {
876 struct udev_device *p;
877 unsigned int type, t;
883 if (streq(subsystem, "input") && startswith(sysname, "event") && safe_atou(sysname + 5, &t) >= 0)
884 type = SYSVIEW_DEVICE_EVDEV;
885 else if (streq(subsystem, "drm") && startswith(sysname, "card") && safe_atou(sysname + 4, &t) >= 0)
886 type = SYSVIEW_DEVICE_DRM;
890 if (type >= SYSVIEW_DEVICE_CNT)
895 while ((p = udev_device_get_parent(p))) {
896 seatname = udev_device_get_property_value(p, "ID_SEAT");
901 seat = sysview_find_seat(c, seatname ? : "seat0");
905 r = device_new_ud(&device, seat, type, d);
907 log_debug("sysview: cannot create device for udev-device '%s': %s",
908 syspath, strerror(-r));
912 return context_add_device(c, device);
918 static int context_ud_monitor_fn(sd_event_source *s,
922 sysview_context *c = userdata;
923 struct udev_device *d;
926 if (revents & EPOLLIN) {
927 while ((d = udev_monitor_receive_device(c->ud_monitor))) {
928 r = context_ud_hotplug(c, d);
929 udev_device_unref(d);
934 /* as long as EPOLLIN is signalled, read pending data */
938 if (revents & (EPOLLHUP | EPOLLERR)) {
939 log_debug("sysview: HUP on udev-monitor");
940 c->ud_monitor_src = sd_event_source_unref(c->ud_monitor_src);
946 static int context_ud_start(sysview_context *c) {
953 c->ud_monitor = udev_monitor_new_from_netlink(c->ud, "udev");
955 return errno > 0 ? -errno : -EFAULT;
957 r = context_ud_prepare_monitor(c, c->ud_monitor);
961 r = udev_monitor_enable_receiving(c->ud_monitor);
965 fd = udev_monitor_get_fd(c->ud_monitor);
966 r = sd_event_add_io(c->event,
969 EPOLLHUP | EPOLLERR | EPOLLIN,
970 context_ud_monitor_fn,
978 static void context_ud_stop(sysview_context *c) {
979 c->ud_monitor_src = sd_event_source_unref(c->ud_monitor_src);
980 c->ud_monitor = udev_monitor_unref(c->ud_monitor);
983 static int context_ud_scan(sysview_context *c) {
984 _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL;
985 struct udev_list_entry *entry;
986 struct udev_device *d;
993 e = udev_enumerate_new(c->ud);
995 return errno > 0 ? -errno : -EFAULT;
997 r = context_ud_prepare_scan(c, e);
1001 r = udev_enumerate_scan_devices(e);
1005 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1008 name = udev_list_entry_get_name(entry);
1011 d = udev_device_new_from_syspath(c->ud, name);
1013 r = errno > 0 ? -errno : -EFAULT;
1014 log_debug("sysview: cannot create udev-device for %s: %s",
1015 name, strerror(-r));
1019 r = context_ud_hotplug(c, d);
1020 udev_device_unref(d);
1028 static int context_ld_seat_new(sysview_context *c, sd_bus_message *signal) {
1029 const char *id, *path;
1032 r = sd_bus_message_read(signal, "so", &id, &path);
1034 log_debug("sysview: cannot parse SeatNew from logind: %s",
1039 return context_add_seat(c, id);
1042 static int context_ld_seat_removed(sysview_context *c, sd_bus_message *signal) {
1043 const char *id, *path;
1047 r = sd_bus_message_read(signal, "so", &id, &path);
1049 log_debug("sysview: cannot parse SeatRemoved from logind: %s",
1054 seat = sysview_find_seat(c, id);
1058 return context_remove_seat(c, seat);
1061 static int context_ld_session_new(sysview_context *c, sd_bus_message *signal) {
1062 _cleanup_free_ char *seatid = NULL, *username = NULL;
1063 const char *id, *path;
1068 r = sd_bus_message_read(signal, "so", &id, &path);
1070 log_debug("sysview: cannot parse SessionNew from logind: %s",
1076 * As the dbus message didn't contain enough information, we
1077 * read missing bits via sd-login. Note that this might race session
1078 * destruction, so we handle ENOENT properly.
1081 /* ENOENT is also returned for sessions without seats */
1082 r = sd_session_get_seat(id, &seatid);
1088 seat = sysview_find_seat(c, seatid);
1092 r = sd_session_get_uid(id, &uid);
1098 username = lookup_uid(uid);
1104 r = context_raise_session_filter(c, id, seatid, username, uid);
1107 log_debug("sysview: cannot filter new session '%s' on seat '%s': %s",
1108 id, seatid, strerror(-r));
1112 return context_add_session(c, seat, id);
1115 log_debug("sysview: failed retrieving information for new session '%s': %s",
1120 static int context_ld_session_removed(sysview_context *c, sd_bus_message *signal) {
1121 sysview_session *session;
1122 const char *id, *path;
1125 r = sd_bus_message_read(signal, "so", &id, &path);
1127 log_debug("sysview: cannot parse SessionRemoved from logind: %s",
1132 session = sysview_find_session(c, id);
1136 return context_remove_session(c, session);
1139 static int context_ld_manager_signal_fn(sd_bus *bus,
1140 sd_bus_message *signal,
1142 sd_bus_error *ret_error) {
1143 sysview_context *c = userdata;
1145 if (sd_bus_message_is_signal(signal, "org.freedesktop.login1.Manager", "SeatNew"))
1146 return context_ld_seat_new(c, signal);
1147 else if (sd_bus_message_is_signal(signal, "org.freedesktop.login1.Manager", "SeatRemoved"))
1148 return context_ld_seat_removed(c, signal);
1149 else if (sd_bus_message_is_signal(signal, "org.freedesktop.login1.Manager", "SessionNew"))
1150 return context_ld_session_new(c, signal);
1151 else if (sd_bus_message_is_signal(signal, "org.freedesktop.login1.Manager", "SessionRemoved"))
1152 return context_ld_session_removed(c, signal);
1157 static int context_ld_start(sysview_context *c) {
1160 if (!c->scan_logind)
1163 r = sd_bus_add_match(c->sysbus,
1164 &c->ld_slot_manager_signal,
1166 "sender='org.freedesktop.login1',"
1167 "interface='org.freedesktop.login1.Manager',"
1168 "path='/org/freedesktop/login1'",
1169 context_ld_manager_signal_fn,
1177 static void context_ld_stop(sysview_context *c) {
1178 c->ld_slot_list_sessions = sd_bus_slot_unref(c->ld_slot_list_sessions);
1179 c->ld_slot_list_seats = sd_bus_slot_unref(c->ld_slot_list_seats);
1180 c->ld_slot_manager_signal = sd_bus_slot_unref(c->ld_slot_manager_signal);
1183 static int context_ld_list_seats_fn(sd_bus *bus,
1184 sd_bus_message *reply,
1186 sd_bus_error *ret_error) {
1187 sysview_context *c = userdata;
1190 c->ld_slot_list_seats = sd_bus_slot_unref(c->ld_slot_list_seats);
1192 if (sd_bus_message_is_method_error(reply, NULL)) {
1193 const sd_bus_error *error = sd_bus_message_get_error(reply);
1195 log_debug("sysview: ListSeats on logind failed: %s: %s",
1196 error->name, error->message);
1197 return sd_bus_error_get_errno(error);
1200 r = sd_bus_message_enter_container(reply, 'a', "(so)");
1204 while ((r = sd_bus_message_enter_container(reply, 'r', "so")) > 0) {
1205 const char *id, *path;
1207 r = sd_bus_message_read(reply, "so", &id, &path);
1211 r = context_add_seat(c, id);
1215 r = sd_bus_message_exit_container(reply);
1223 r = sd_bus_message_exit_container(reply);
1230 log_debug("sysview: erroneous ListSeats response from logind: %s",
1235 static int context_ld_list_sessions_fn(sd_bus *bus,
1236 sd_bus_message *reply,
1238 sd_bus_error *ret_error) {
1239 sysview_context *c = userdata;
1242 c->ld_slot_list_sessions = sd_bus_slot_unref(c->ld_slot_list_sessions);
1244 if (sd_bus_message_is_method_error(reply, NULL)) {
1245 const sd_bus_error *error = sd_bus_message_get_error(reply);
1247 log_debug("sysview: ListSessions on logind failed: %s: %s",
1248 error->name, error->message);
1249 return sd_bus_error_get_errno(error);
1252 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
1256 while ((r = sd_bus_message_enter_container(reply, 'r', "susso")) > 0) {
1257 const char *id, *username, *seatid, *path;
1261 r = sd_bus_message_read(reply,
1271 seat = sysview_find_seat(c, seatid);
1273 r = context_raise_session_filter(c, id, seatid, username, uid);
1275 log_debug("sysview: cannot filter listed session '%s' on seat '%s': %s",
1276 id, seatid, strerror(-r));
1279 r = context_add_session(c, seat, id);
1285 r = sd_bus_message_exit_container(reply);
1293 r = sd_bus_message_exit_container(reply);
1300 log_debug("sysview: erroneous ListSessions response from logind: %s",
1305 static int context_ld_scan(sysview_context *c) {
1306 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1309 if (!c->ld_slot_manager_signal)
1312 /* request seat list */
1314 r = sd_bus_message_new_method_call(c->sysbus,
1316 "org.freedesktop.login1",
1317 "/org/freedesktop/login1",
1318 "org.freedesktop.login1.Manager",
1323 r = sd_bus_call_async(c->sysbus,
1324 &c->ld_slot_list_seats,
1326 context_ld_list_seats_fn,
1332 /* request session list */
1334 m = sd_bus_message_unref(m);
1335 r = sd_bus_message_new_method_call(c->sysbus,
1337 "org.freedesktop.login1",
1338 "/org/freedesktop/login1",
1339 "org.freedesktop.login1.Manager",
1344 r = sd_bus_call_async(c->sysbus,
1345 &c->ld_slot_list_sessions,
1347 context_ld_list_sessions_fn,
1356 bool sysview_context_is_running(sysview_context *c) {
1357 return c && c->running;
1360 int sysview_context_start(sysview_context *c, sysview_event_fn event_fn, void *userdata) {
1363 assert_return(c, -EINVAL);
1364 assert_return(event_fn, -EINVAL);
1369 log_debug("sysview: start");
1372 c->event_fn = event_fn;
1373 c->userdata = userdata;
1375 r = context_ld_start(c);
1379 r = context_ud_start(c);
1383 r = sysview_context_rescan(c);
1390 sysview_context_stop(c);
1394 void sysview_context_stop(sysview_context *c) {
1395 sysview_session *session;
1396 sysview_device *device;
1404 log_debug("sysview: stop");
1410 c->scan_src = sd_event_source_unref(c->scan_src);
1415 * Event-callbacks are already cleared, hence we can safely ignore
1416 * return codes of the context_remove_*() helpers. They cannot be
1417 * originated from user-callbacks, so we already handled them.
1420 while ((device = hashmap_first(c->device_map)))
1421 context_remove_device(c, device);
1423 while ((session = hashmap_first(c->session_map)))
1424 context_remove_session(c, session);
1426 while ((seat = hashmap_first(c->seat_map)))
1427 context_remove_seat(c, seat);
1430 static int context_scan_fn(sd_event_source *s, void *userdata) {
1431 sysview_context *c = userdata;
1437 r = context_ld_scan(c);
1439 log_debug("sysview: logind scan failed: %s", strerror(-r));
1444 /* skip device scans if no sessions are available */
1445 if (hashmap_size(c->session_map) > 0) {
1446 r = context_ud_scan(c);
1448 log_debug("sysview: udev scan failed: %s", strerror(-r));
1452 HASHMAP_FOREACH(seat, c->seat_map, i)
1453 seat->scanned = true;
1461 int sysview_context_rescan(sysview_context *c) {
1468 return sd_event_source_set_enabled(c->scan_src, SD_EVENT_ONESHOT);
1470 return sd_event_add_defer(c->event, &c->scan_src, context_scan_fn, c);