chiark / gitweb /
Remove src/libsystemd-network
[elogind.git] / src / libsystemd-terminal / sysview.c
index cd776f62d8c162ce8b5b2a5c11b1535d83bdd67f..550f0305af0e2590d5b40b3745707c72b1da04d1 100644 (file)
@@ -27,9 +27,7 @@
 #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"
@@ -267,6 +265,12 @@ const char *sysview_session_get_name(sysview_session *session) {
         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,
@@ -289,8 +293,8 @@ static int session_take_control_fn(sd_bus *bus,
 
         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;
 }
@@ -359,8 +363,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);
 }
 
 /*
@@ -391,6 +395,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;
@@ -422,6 +430,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);
 
@@ -434,6 +443,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
  */
@@ -442,6 +474,14 @@ static int context_raise(sysview_context *c, sysview_event *event, int def) {
         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,
@@ -553,6 +593,21 @@ static int context_raise_session_refresh(sysview_context *c, sysview_session *se
         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;
@@ -570,8 +625,8 @@ static void context_add_device(sysview_context *c, sysview_device *device) {
 
                 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);
         }
 }
 
@@ -591,8 +646,8 @@ static void context_remove_device(sysview_context *c, sysview_device *device) {
 
                 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);
@@ -614,8 +669,8 @@ static void context_change_device(sysview_context *c, sysview_device *device, st
 
                 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);
         }
 }
 
@@ -649,8 +704,8 @@ static void context_add_session(sysview_context *c, sysview_seat *seat, const ch
                 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;
                 }
@@ -658,8 +713,8 @@ static void context_add_session(sysview_context *c, sysview_seat *seat, const ch
                 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);
                 }
         }
 
@@ -667,8 +722,8 @@ static void context_add_session(sysview_context *c, sysview_seat *seat, const ch
 
 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) {
@@ -685,15 +740,15 @@ 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)
@@ -722,8 +777,8 @@ static void context_add_seat(sysview_context *c, const char *id) {
         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;
         }
 
@@ -731,8 +786,8 @@ static void context_add_seat(sysview_context *c, const char *id) {
 
 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) {
@@ -755,8 +810,8 @@ 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);
@@ -941,11 +996,9 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) {
                         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);
         }
@@ -1049,8 +1102,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;
                 }
 
@@ -1068,11 +1121,8 @@ 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");
 
         context_add_seat(c, id);
         return 0;
@@ -1084,11 +1134,8 @@ 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)
@@ -1106,11 +1153,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
@@ -1143,17 +1187,16 @@ 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)
-                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) {
@@ -1162,11 +1205,8 @@ 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)
@@ -1234,7 +1274,8 @@ static int context_ld_list_seats_fn(sd_bus *bus,
 
                 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)");
@@ -1260,13 +1301,15 @@ static int context_ld_list_seats_fn(sd_bus *bus,
 
         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;
 }
 
@@ -1284,7 +1327,8 @@ static int context_ld_list_sessions_fn(sd_bus *bus,
 
                 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)");
@@ -1310,8 +1354,8 @@ static int context_ld_list_sessions_fn(sd_bus *bus,
                 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);
                 }
@@ -1326,13 +1370,15 @@ static int context_ld_list_sessions_fn(sd_bus *bus,
 
         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;
 }
 
@@ -1363,6 +1409,9 @@ static int context_ld_scan(sysview_context *c) {
         if (r < 0)
                 return r;
 
+        if (!c->settled)
+                ++c->n_probe;
+
         /* request session list */
 
         m = sd_bus_message_unref(m);
@@ -1384,6 +1433,9 @@ static int context_ld_scan(sysview_context *c) {
         if (r < 0)
                 return r;
 
+        if (!c->settled)
+                ++c->n_probe;
+
         return 0;
 }
 
@@ -1448,6 +1500,8 @@ void sysview_context_stop(sysview_context *c) {
 
         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);
@@ -1461,27 +1515,26 @@ 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;
 }
@@ -1492,6 +1545,12 @@ int sysview_context_rescan(sysview_context *c) {
         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