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);
107 unsigned int sysview_device_get_type(sysview_device *device) {
108 assert_return(device, (unsigned)-1);
113 struct udev_device *sysview_device_get_ud(sysview_device *device) {
114 assert_return(device, NULL);
116 switch (device->type) {
117 case SYSVIEW_DEVICE_EVDEV:
118 return device->evdev.ud;
119 case SYSVIEW_DEVICE_DRM:
120 return device->drm.ud;
122 assert_return(0, NULL);
126 static int device_new_ud(sysview_device **out, sysview_seat *seat, unsigned int type, struct udev_device *ud) {
127 _cleanup_(sysview_device_freep) sysview_device *device = NULL;
130 assert_return(seat, -EINVAL);
131 assert_return(ud, -EINVAL);
133 r = sysview_device_new(&device, seat, udev_device_get_syspath(ud));
140 case SYSVIEW_DEVICE_EVDEV:
141 device->evdev.ud = udev_device_ref(ud);
143 case SYSVIEW_DEVICE_DRM:
144 device->drm.ud = udev_device_ref(ud);
147 assert_not_reached("sysview: invalid udev-device type");
160 sysview_session *sysview_find_session(sysview_context *c, const char *name) {
161 assert_return(c, NULL);
162 assert_return(name, NULL);
164 return hashmap_get(c->session_map, name);
167 int sysview_session_new(sysview_session **out, sysview_seat *seat, const char *name) {
168 _cleanup_(sysview_session_freep) sysview_session *session = NULL;
171 assert_return(seat, -EINVAL);
173 session = new0(sysview_session, 1);
177 session->seat = seat;
181 * If a name is given, we require it to be a logind session
182 * name. The session will be put in managed mode and we use
183 * logind to request controller access.
186 session->name = strdup(name);
190 r = sd_bus_path_encode("/org/freedesktop/login1/session",
191 session->name, &session->path);
195 session->custom = false;;
198 * No session name was given. We assume this is an unmanaged
199 * session controlled by the application. We don't use logind
200 * at all and leave session management to the application. The
201 * name of the session-object is set to a unique random string
202 * that does not clash with the logind namespace.
205 r = asprintf(&session->name, "@custom%" PRIu64,
206 ++seat->context->custom_sid);
210 session->custom = true;
213 r = hashmap_put(seat->context->session_map, session->name, session);
217 r = hashmap_put(seat->session_map, session->name, session);
227 sysview_session *sysview_session_free(sysview_session *session) {
231 assert(!session->public);
232 assert(!session->wants_control);
235 hashmap_remove_value(session->seat->session_map, session->name, session);
236 hashmap_remove_value(session->seat->context->session_map, session->name, session);
246 const char *sysview_session_get_name(sysview_session *session) {
247 assert_return(session, NULL);
249 return session->name;
252 static int session_take_control_fn(sd_bus *bus,
253 sd_bus_message *reply,
255 sd_bus_error *ret_error) {
256 sysview_session *session = userdata;
259 session->slot_take_control = sd_bus_slot_unref(session->slot_take_control);
261 if (sd_bus_message_is_method_error(reply, NULL)) {
262 const sd_bus_error *e = sd_bus_message_get_error(reply);
264 log_debug("sysview: %s: TakeControl failed: %s: %s",
265 session->name, e->name, e->message);
266 error = sd_bus_error_get_errno(e);
268 session->has_control = true;
272 return context_raise_session_control(session->seat->context, session, error);
275 int sysview_session_take_control(sysview_session *session) {
276 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
279 assert_return(session, -EINVAL);
280 assert_return(!session->custom, -EINVAL);
282 if (session->wants_control)
285 r = sd_bus_message_new_method_call(session->seat->context->sysbus,
287 "org.freedesktop.login1",
289 "org.freedesktop.login1.Session",
294 r = sd_bus_message_append(m, "b", 0);
298 r = sd_bus_call_async(session->seat->context->sysbus,
299 &session->slot_take_control,
301 session_take_control_fn,
307 session->wants_control = true;
311 void sysview_session_release_control(sysview_session *session) {
312 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
316 assert(!session->custom);
318 if (!session->wants_control)
321 session->wants_control = false;
323 if (!session->has_control && !session->slot_take_control)
326 session->has_control = false;
327 session->slot_take_control = sd_bus_slot_unref(session->slot_take_control);
329 r = sd_bus_message_new_method_call(session->seat->context->sysbus,
331 "org.freedesktop.login1",
333 "org.freedesktop.login1.Session",
336 r = sd_bus_send(session->seat->context->sysbus, m, NULL);
338 if (r < 0 && r != -ENOTCONN)
339 log_debug("sysview: %s: cannot send ReleaseControl: %s",
340 session->name, strerror(-r));
347 sysview_seat *sysview_find_seat(sysview_context *c, const char *name) {
348 assert_return(c, NULL);
349 assert_return(name, NULL);
351 return hashmap_get(c->seat_map, name);
354 int sysview_seat_new(sysview_seat **out, sysview_context *c, const char *name) {
355 _cleanup_(sysview_seat_freep) sysview_seat *seat = NULL;
358 assert_return(c, -EINVAL);
359 assert_return(name, -EINVAL);
361 seat = new0(sysview_seat, 1);
367 seat->name = strdup(name);
371 seat->session_map = hashmap_new(string_hash_func, string_compare_func);
372 if (!seat->session_map)
375 seat->device_map = hashmap_new(string_hash_func, string_compare_func);
376 if (!seat->device_map)
379 r = hashmap_put(c->seat_map, seat->name, seat);
389 sysview_seat *sysview_seat_free(sysview_seat *seat) {
393 assert(!seat->public);
394 assert(hashmap_size(seat->device_map) == 0);
395 assert(hashmap_size(seat->session_map) == 0);
398 hashmap_remove_value(seat->context->seat_map, seat->name, seat);
400 hashmap_free(seat->device_map);
401 hashmap_free(seat->session_map);
408 const char *sysview_seat_get_name(sysview_seat *seat) {
409 assert_return(seat, NULL);
418 static int context_raise(sysview_context *c, sysview_event *event, int def) {
419 return c->running ? c->event_fn(c, c->userdata, event) : def;
422 static int context_raise_seat_add(sysview_context *c, sysview_seat *seat) {
423 sysview_event event = {
424 .type = SYSVIEW_EVENT_SEAT_ADD,
430 return context_raise(c, &event, 0);
433 static int context_raise_seat_remove(sysview_context *c, sysview_seat *seat) {
434 sysview_event event = {
435 .type = SYSVIEW_EVENT_SEAT_REMOVE,
441 return context_raise(c, &event, 0);
444 static int context_raise_session_filter(sysview_context *c,
447 const char *username,
449 sysview_event event = {
450 .type = SYSVIEW_EVENT_SESSION_FILTER,
454 .username = username,
459 return context_raise(c, &event, 1);
462 static int context_raise_session_add(sysview_context *c, sysview_session *session) {
463 sysview_event event = {
464 .type = SYSVIEW_EVENT_SESSION_ADD,
470 return context_raise(c, &event, 0);
473 static int context_raise_session_remove(sysview_context *c, sysview_session *session) {
474 sysview_event event = {
475 .type = SYSVIEW_EVENT_SESSION_REMOVE,
481 return context_raise(c, &event, 0);
484 static int context_raise_session_control(sysview_context *c, sysview_session *session, int error) {
485 sysview_event event = {
486 .type = SYSVIEW_EVENT_SESSION_CONTROL,
493 return context_raise(c, &event, 0);
496 static int context_raise_session_attach(sysview_context *c, sysview_session *session, sysview_device *device) {
497 sysview_event event = {
498 .type = SYSVIEW_EVENT_SESSION_ATTACH,
505 return context_raise(c, &event, 0);
508 static int context_raise_session_detach(sysview_context *c, sysview_session *session, sysview_device *device) {
509 sysview_event event = {
510 .type = SYSVIEW_EVENT_SESSION_DETACH,
517 return context_raise(c, &event, 0);
520 static int context_add_device(sysview_context *c, sysview_device *device) {
521 sysview_session *session;
528 log_debug("sysview: add device '%s' on seat '%s'",
529 device->name, device->seat->name);
531 HASHMAP_FOREACH(session, device->seat->session_map, i) {
532 if (!session->public)
535 r = context_raise_session_attach(c, session, device);
541 log_debug("sysview: error while adding device '%s': %s",
542 device->name, strerror(-r));
546 static int context_remove_device(sysview_context *c, sysview_device *device) {
547 sysview_session *session;
554 log_debug("sysview: remove device '%s'", device->name);
556 HASHMAP_FOREACH(session, device->seat->session_map, i) {
557 if (!session->public)
560 r = context_raise_session_detach(c, session, device);
566 log_debug("sysview: error while removing device '%s': %s",
567 device->name, strerror(-r));
568 sysview_device_free(device);
572 static int context_add_session(sysview_context *c, sysview_seat *seat, const char *id) {
573 sysview_session *session;
574 sysview_device *device;
582 session = sysview_find_session(c, id);
586 log_debug("sysview: add session '%s' on seat '%s'", id, seat->name);
588 r = sysview_session_new(&session, seat, id);
592 if (!seat->scanned) {
593 r = sysview_context_rescan(c);
599 session->public = true;
600 r = context_raise_session_add(c, session);
602 session->public = false;
606 HASHMAP_FOREACH(device, seat->device_map, i) {
607 r = context_raise_session_attach(c, session, device);
621 log_debug("sysview: error while adding session '%s': %s",
626 static int context_remove_session(sysview_context *c, sysview_session *session) {
627 sysview_device *device;
634 log_debug("sysview: remove session '%s'", session->name);
636 if (session->public) {
637 HASHMAP_FOREACH(device, session->seat->device_map, i) {
638 r = context_raise_session_detach(c, session, device);
643 session->public = false;
644 r = context_raise_session_remove(c, session);
649 if (!session->custom)
650 sysview_session_release_control(session);
653 log_debug("sysview: error while removing session '%s': %s",
654 session->name, strerror(-error));
655 sysview_session_free(session);
659 static int context_add_seat(sysview_context *c, const char *id) {
666 seat = sysview_find_seat(c, id);
670 log_debug("sysview: add seat '%s'", id);
672 r = sysview_seat_new(&seat, c, id);
677 r = context_raise_seat_add(c, seat);
679 seat->public = false;
687 log_debug("sysview: error while adding seat '%s': %s",
692 static int context_remove_seat(sysview_context *c, sysview_seat *seat) {
693 sysview_session *session;
694 sysview_device *device;
700 log_debug("sysview: remove seat '%s'", seat->name);
702 while ((device = hashmap_first(seat->device_map))) {
703 r = context_remove_device(c, device);
708 while ((session = hashmap_first(seat->session_map))) {
709 r = context_remove_session(c, session);
715 seat->public = false;
716 r = context_raise_seat_remove(c, seat);
722 log_debug("sysview: error while removing seat '%s': %s",
723 seat->name, strerror(-error));
724 sysview_seat_free(seat);
728 int sysview_context_new(sysview_context **out,
733 _cleanup_(sysview_context_freep) sysview_context *c = NULL;
736 assert_return(out, -EINVAL);
737 assert_return(event, -EINVAL);
739 log_debug("sysview: new");
741 c = new0(sysview_context, 1);
745 c->event = sd_event_ref(event);
746 if (flags & SYSVIEW_CONTEXT_SCAN_LOGIND)
747 c->scan_logind = true;
748 if (flags & SYSVIEW_CONTEXT_SCAN_EVDEV)
749 c->scan_evdev = true;
750 if (flags & SYSVIEW_CONTEXT_SCAN_DRM)
754 c->sysbus = sd_bus_ref(sysbus);
755 } else if (c->scan_logind) {
756 r = sd_bus_open_system(&c->sysbus);
762 c->ud = udev_ref(ud);
763 } else if (c->scan_evdev || c->scan_drm) {
767 return errno > 0 ? -errno : -EFAULT;
770 c->seat_map = hashmap_new(string_hash_func, string_compare_func);
774 c->session_map = hashmap_new(string_hash_func, string_compare_func);
778 c->device_map = hashmap_new(string_hash_func, string_compare_func);
787 sysview_context *sysview_context_free(sysview_context *c) {
791 log_debug("sysview: free");
793 sysview_context_stop(c);
795 assert(hashmap_size(c->device_map) == 0);
796 assert(hashmap_size(c->session_map) == 0);
797 assert(hashmap_size(c->seat_map) == 0);
799 hashmap_free(c->device_map);
800 hashmap_free(c->session_map);
801 hashmap_free(c->seat_map);
802 c->ud = udev_unref(c->ud);
803 c->sysbus = sd_bus_unref(c->sysbus);
804 c->event = sd_event_unref(c->event);
810 static int context_ud_prepare_monitor(sysview_context *c, struct udev_monitor *m) {
814 r = udev_monitor_filter_add_match_subsystem_devtype(m, "input", NULL);
820 r = udev_monitor_filter_add_match_subsystem_devtype(m, "drm", NULL);
828 static int context_ud_prepare_scan(sysview_context *c, struct udev_enumerate *e) {
832 r = udev_enumerate_add_match_subsystem(e, "input");
838 r = udev_enumerate_add_match_subsystem(e, "drm");
843 r = udev_enumerate_add_match_is_initialized(e);
850 static int context_ud_hotplug(sysview_context *c, struct udev_device *d) {
851 const char *syspath, *sysname, *subsystem, *action, *seatname;
852 sysview_device *device;
855 syspath = udev_device_get_syspath(d);
856 sysname = udev_device_get_sysname(d);
857 subsystem = udev_device_get_subsystem(d);
858 action = udev_device_get_action(d);
860 /* not interested in custom devices without syspath/etc */
861 if (!syspath || !sysname || !subsystem)
864 device = sysview_find_device(c, syspath);
866 if (streq_ptr(action, "remove")) {
870 return context_remove_device(c, device);
871 } else if (streq_ptr(action, "change")) {
875 /* TODO: send REFRESH event */
876 } else if (!action || streq_ptr(action, "add")) {
877 struct udev_device *p;
878 unsigned int type, t;
884 if (streq(subsystem, "input") && startswith(sysname, "event") && safe_atou(sysname + 5, &t) >= 0)
885 type = SYSVIEW_DEVICE_EVDEV;
886 else if (streq(subsystem, "drm") && startswith(sysname, "card") && safe_atou(sysname + 4, &t) >= 0)
887 type = SYSVIEW_DEVICE_DRM;
891 if (type >= SYSVIEW_DEVICE_CNT)
896 while ((p = udev_device_get_parent(p))) {
897 seatname = udev_device_get_property_value(p, "ID_SEAT");
902 seat = sysview_find_seat(c, seatname ? : "seat0");
906 r = device_new_ud(&device, seat, type, d);
908 log_debug("sysview: cannot create device for udev-device '%s': %s",
909 syspath, strerror(-r));
913 return context_add_device(c, device);
919 static int context_ud_monitor_fn(sd_event_source *s,
923 sysview_context *c = userdata;
924 struct udev_device *d;
927 if (revents & EPOLLIN) {
928 while ((d = udev_monitor_receive_device(c->ud_monitor))) {
929 r = context_ud_hotplug(c, d);
930 udev_device_unref(d);
935 /* as long as EPOLLIN is signalled, read pending data */
939 if (revents & (EPOLLHUP | EPOLLERR)) {
940 log_debug("sysview: HUP on udev-monitor");
941 c->ud_monitor_src = sd_event_source_unref(c->ud_monitor_src);
947 static int context_ud_start(sysview_context *c) {
954 c->ud_monitor = udev_monitor_new_from_netlink(c->ud, "udev");
956 return errno > 0 ? -errno : -EFAULT;
958 r = context_ud_prepare_monitor(c, c->ud_monitor);
962 r = udev_monitor_enable_receiving(c->ud_monitor);
966 fd = udev_monitor_get_fd(c->ud_monitor);
967 r = sd_event_add_io(c->event,
970 EPOLLHUP | EPOLLERR | EPOLLIN,
971 context_ud_monitor_fn,
979 static void context_ud_stop(sysview_context *c) {
980 c->ud_monitor_src = sd_event_source_unref(c->ud_monitor_src);
981 c->ud_monitor = udev_monitor_unref(c->ud_monitor);
984 static int context_ud_scan(sysview_context *c) {
985 _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL;
986 struct udev_list_entry *entry;
987 struct udev_device *d;
994 e = udev_enumerate_new(c->ud);
996 return errno > 0 ? -errno : -EFAULT;
998 r = context_ud_prepare_scan(c, e);
1002 r = udev_enumerate_scan_devices(e);
1006 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1009 name = udev_list_entry_get_name(entry);
1012 d = udev_device_new_from_syspath(c->ud, name);
1014 r = errno > 0 ? -errno : -EFAULT;
1015 log_debug("sysview: cannot create udev-device for %s: %s",
1016 name, strerror(-r));
1020 r = context_ud_hotplug(c, d);
1021 udev_device_unref(d);
1029 static int context_ld_seat_new(sysview_context *c, sd_bus_message *signal) {
1030 const char *id, *path;
1033 r = sd_bus_message_read(signal, "so", &id, &path);
1035 log_debug("sysview: cannot parse SeatNew from logind: %s",
1040 return context_add_seat(c, id);
1043 static int context_ld_seat_removed(sysview_context *c, sd_bus_message *signal) {
1044 const char *id, *path;
1048 r = sd_bus_message_read(signal, "so", &id, &path);
1050 log_debug("sysview: cannot parse SeatRemoved from logind: %s",
1055 seat = sysview_find_seat(c, id);
1059 return context_remove_seat(c, seat);
1062 static int context_ld_session_new(sysview_context *c, sd_bus_message *signal) {
1063 _cleanup_free_ char *seatid = NULL, *username = NULL;
1064 const char *id, *path;
1069 r = sd_bus_message_read(signal, "so", &id, &path);
1071 log_debug("sysview: cannot parse SessionNew from logind: %s",
1077 * As the dbus message didn't contain enough information, we
1078 * read missing bits via sd-login. Note that this might race session
1079 * destruction, so we handle ENOENT properly.
1082 /* ENOENT is also returned for sessions without seats */
1083 r = sd_session_get_seat(id, &seatid);
1089 seat = sysview_find_seat(c, seatid);
1093 r = sd_session_get_uid(id, &uid);
1099 username = lookup_uid(uid);
1105 r = context_raise_session_filter(c, id, seatid, username, uid);
1108 log_debug("sysview: cannot filter new session '%s' on seat '%s': %s",
1109 id, seatid, strerror(-r));
1113 return context_add_session(c, seat, id);
1116 log_debug("sysview: failed retrieving information for new session '%s': %s",
1121 static int context_ld_session_removed(sysview_context *c, sd_bus_message *signal) {
1122 sysview_session *session;
1123 const char *id, *path;
1126 r = sd_bus_message_read(signal, "so", &id, &path);
1128 log_debug("sysview: cannot parse SessionRemoved from logind: %s",
1133 session = sysview_find_session(c, id);
1137 return context_remove_session(c, session);
1140 static int context_ld_manager_signal_fn(sd_bus *bus,
1141 sd_bus_message *signal,
1143 sd_bus_error *ret_error) {
1144 sysview_context *c = userdata;
1146 if (sd_bus_message_is_signal(signal, "org.freedesktop.login1.Manager", "SeatNew"))
1147 return context_ld_seat_new(c, signal);
1148 else if (sd_bus_message_is_signal(signal, "org.freedesktop.login1.Manager", "SeatRemoved"))
1149 return context_ld_seat_removed(c, signal);
1150 else if (sd_bus_message_is_signal(signal, "org.freedesktop.login1.Manager", "SessionNew"))
1151 return context_ld_session_new(c, signal);
1152 else if (sd_bus_message_is_signal(signal, "org.freedesktop.login1.Manager", "SessionRemoved"))
1153 return context_ld_session_removed(c, signal);
1158 static int context_ld_start(sysview_context *c) {
1161 if (!c->scan_logind)
1164 r = sd_bus_add_match(c->sysbus,
1165 &c->ld_slot_manager_signal,
1167 "sender='org.freedesktop.login1',"
1168 "interface='org.freedesktop.login1.Manager',"
1169 "path='/org/freedesktop/login1'",
1170 context_ld_manager_signal_fn,
1178 static void context_ld_stop(sysview_context *c) {
1179 c->ld_slot_list_sessions = sd_bus_slot_unref(c->ld_slot_list_sessions);
1180 c->ld_slot_list_seats = sd_bus_slot_unref(c->ld_slot_list_seats);
1181 c->ld_slot_manager_signal = sd_bus_slot_unref(c->ld_slot_manager_signal);
1184 static int context_ld_list_seats_fn(sd_bus *bus,
1185 sd_bus_message *reply,
1187 sd_bus_error *ret_error) {
1188 sysview_context *c = userdata;
1191 c->ld_slot_list_seats = sd_bus_slot_unref(c->ld_slot_list_seats);
1193 if (sd_bus_message_is_method_error(reply, NULL)) {
1194 const sd_bus_error *error = sd_bus_message_get_error(reply);
1196 log_debug("sysview: ListSeats on logind failed: %s: %s",
1197 error->name, error->message);
1198 return sd_bus_error_get_errno(error);
1201 r = sd_bus_message_enter_container(reply, 'a', "(so)");
1205 while ((r = sd_bus_message_enter_container(reply, 'r', "so")) > 0) {
1206 const char *id, *path;
1208 r = sd_bus_message_read(reply, "so", &id, &path);
1212 r = context_add_seat(c, id);
1216 r = sd_bus_message_exit_container(reply);
1224 r = sd_bus_message_exit_container(reply);
1231 log_debug("sysview: erroneous ListSeats response from logind: %s",
1236 static int context_ld_list_sessions_fn(sd_bus *bus,
1237 sd_bus_message *reply,
1239 sd_bus_error *ret_error) {
1240 sysview_context *c = userdata;
1243 c->ld_slot_list_sessions = sd_bus_slot_unref(c->ld_slot_list_sessions);
1245 if (sd_bus_message_is_method_error(reply, NULL)) {
1246 const sd_bus_error *error = sd_bus_message_get_error(reply);
1248 log_debug("sysview: ListSessions on logind failed: %s: %s",
1249 error->name, error->message);
1250 return sd_bus_error_get_errno(error);
1253 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
1257 while ((r = sd_bus_message_enter_container(reply, 'r', "susso")) > 0) {
1258 const char *id, *username, *seatid, *path;
1262 r = sd_bus_message_read(reply,
1272 seat = sysview_find_seat(c, seatid);
1274 r = context_raise_session_filter(c, id, seatid, username, uid);
1276 log_debug("sysview: cannot filter listed session '%s' on seat '%s': %s",
1277 id, seatid, strerror(-r));
1280 r = context_add_session(c, seat, id);
1286 r = sd_bus_message_exit_container(reply);
1294 r = sd_bus_message_exit_container(reply);
1301 log_debug("sysview: erroneous ListSessions response from logind: %s",
1306 static int context_ld_scan(sysview_context *c) {
1307 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1310 if (!c->ld_slot_manager_signal)
1313 /* request seat list */
1315 r = sd_bus_message_new_method_call(c->sysbus,
1317 "org.freedesktop.login1",
1318 "/org/freedesktop/login1",
1319 "org.freedesktop.login1.Manager",
1324 r = sd_bus_call_async(c->sysbus,
1325 &c->ld_slot_list_seats,
1327 context_ld_list_seats_fn,
1333 /* request session list */
1335 m = sd_bus_message_unref(m);
1336 r = sd_bus_message_new_method_call(c->sysbus,
1338 "org.freedesktop.login1",
1339 "/org/freedesktop/login1",
1340 "org.freedesktop.login1.Manager",
1345 r = sd_bus_call_async(c->sysbus,
1346 &c->ld_slot_list_sessions,
1348 context_ld_list_sessions_fn,
1357 bool sysview_context_is_running(sysview_context *c) {
1358 return c && c->running;
1361 int sysview_context_start(sysview_context *c, sysview_event_fn event_fn, void *userdata) {
1364 assert_return(c, -EINVAL);
1365 assert_return(event_fn, -EINVAL);
1370 log_debug("sysview: start");
1373 c->event_fn = event_fn;
1374 c->userdata = userdata;
1376 r = context_ld_start(c);
1380 r = context_ud_start(c);
1384 r = sysview_context_rescan(c);
1391 sysview_context_stop(c);
1395 void sysview_context_stop(sysview_context *c) {
1396 sysview_session *session;
1397 sysview_device *device;
1405 log_debug("sysview: stop");
1411 c->scan_src = sd_event_source_unref(c->scan_src);
1416 * Event-callbacks are already cleared, hence we can safely ignore
1417 * return codes of the context_remove_*() helpers. They cannot be
1418 * originated from user-callbacks, so we already handled them.
1421 while ((device = hashmap_first(c->device_map)))
1422 context_remove_device(c, device);
1424 while ((session = hashmap_first(c->session_map)))
1425 context_remove_session(c, session);
1427 while ((seat = hashmap_first(c->seat_map)))
1428 context_remove_seat(c, seat);
1431 static int context_scan_fn(sd_event_source *s, void *userdata) {
1432 sysview_context *c = userdata;
1438 r = context_ld_scan(c);
1440 log_debug("sysview: logind scan failed: %s", strerror(-r));
1445 /* skip device scans if no sessions are available */
1446 if (hashmap_size(c->session_map) > 0) {
1447 r = context_ud_scan(c);
1449 log_debug("sysview: udev scan failed: %s", strerror(-r));
1453 HASHMAP_FOREACH(seat, c->seat_map, i)
1454 seat->scanned = true;
1462 int sysview_context_rescan(sysview_context *c) {
1469 return sd_event_source_set_enabled(c->scan_src, SD_EVENT_ONESHOT);
1471 return sd_event_add_defer(c->event, &c->scan_src, context_scan_fn, c);