chiark / gitweb /
logind: rework button setting semantics
authorLennart Poettering <lennart@poettering.net>
Wed, 30 May 2012 19:40:32 +0000 (21:40 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 30 May 2012 19:40:32 +0000 (21:40 +0200)
If a graphical session without full DE that handles power/suspend events
is used this can now be controlled by logind instead, optionally.

man/logind.conf.xml
src/login/logind-button.c
src/login/logind-button.h
src/login/logind.c
src/login/logind.conf

index 09db6001433521379733ac65049eb982623e3a57..35a7d4855e07b2dc25e5cf456284c4da4123d376 100644 (file)
                                 and sleep keys and the lid switch to
                                 trigger system power-off or
                                 suspend. Can be one of
-                                <literal>no</literal>,
-                                <literal>yes</literal> and
+                                <literal>off</literal>,
+                                <literal>no-session</literal>,
+                                <literal>tty-session</literal>,
+                                <literal>any-session</literal> and
                                 <literal>always</literal>. If
-                                <literal>no</literal> logind will
+                                <literal>off</literal> logind will
                                 never handle these keys. If
-                                <literal>yes</literal> logind will
-                                handle these keys when no user is
+                                <literal>no-session</literal> logind
+                                will handle these keys when no user is
                                 logged in and no inhibitor lock is
                                 taken, and trigger a warnig beep
                                 otherwise. If set to
+                                <literal>tty-session</literal> logind
+                                will handle these keys if no inhibitor
+                                lock is taken, and either no user is
+                                logged in or the foreground session is
+                                a text login and the only one
+                                existing. If
+                                <literal>any-session</literal> is set
+                                logind will handle these keys if no
+                                inhibitor lock is taken, and either no
+                                user is logged in or the foreground
+                                session is the only one existing
+                                (regardless whether graphical or
+                                text). If set to
                                 <literal>always</literal> logind will
-                                handle these keys even if a user is
-                                logged in or an inhibitor lock is
-                                taken. In all cases logind will not
-                                handle these keys if a graphical
-                                session is in the foreground under the
-                                assumption that the graphical session
-                                will handle these keys
-                                internally. Only input devices with
-                                the <literal>power-switch</literal>
-                                udev tag will be watched for key
+                                handle these keys in any case, even if
+                                one or more users are logged in or an
+                                inhibitor lock is taken. Only input
+                                devices with the
+                                <literal>power-switch</literal> udev
+                                tag will be watched for key
                                 events. <varname>HandlePowerKey=</varname>
-                                and <varname>HandleSleepKey=</varname>
-                                default to <literal>yes</literal>,
+                                defaults to
+                                <literal>no-session</literal>.
+                                <varname>HandleSleepKey=</varname>
+                                defaults to
+                                <literal>tty-session</literal>,
                                 <varname>HandleLidSwitch=</varname>
                                 defaults to
-                                <literal>no</literal>.</para></listitem>
+                                <literal>off</literal>.</para></listitem>
                         </varlistentry>
 
                 </variablelist>
index 48432e195d717da8b2048ccaa8fe024ee92ada3d..8b59c2b0c36be02f961af1aa5b5b35605f463a04 100644 (file)
@@ -152,20 +152,18 @@ fail:
         return r;
 }
 
-static bool has_graphical_session(Manager *m, const char *seat) {
-        Seat *s;
-
-        assert(m);
-        assert(seat);
+static Session *button_get_session(Button *b) {
+        Seat *seat;
+        assert(b);
 
-        s = hashmap_get(m->seats, seat);
-        if (!s)
-                return false;
+        if (!b->seat)
+                return NULL;
 
-        if (!s->active)
-                return false;
+        seat = hashmap_get(b->manager->seats, b->seat);
+        if (!seat)
+                return NULL;
 
-        return s->active->type == SESSION_X11;
+        return seat->active;
 }
 
 static int button_power_off(Button *b, HandleButton handle) {
@@ -174,17 +172,38 @@ static int button_power_off(Button *b, HandleButton handle) {
 
         assert(b);
 
-        if (handle == HANDLE_NO)
+        if (handle == HANDLE_OFF)
                 return 0;
 
-        if (handle != HANDLE_ALWAYS) {
-
+        if (handle == HANDLE_NO_SESSION) {
                 if (hashmap_size(b->manager->sessions) > 0) {
                         log_error("Refusing power-off, user is logged in.");
                         warn_melody();
                         return -EPERM;
                 }
 
+        } else if (handle == HANDLE_TTY_SESSION ||
+                   handle == HANDLE_ANY_SESSION) {
+                unsigned n;
+                Session *s;
+
+                n = hashmap_size(b->manager->sessions);
+                s = button_get_session(b);
+
+                /* Silently ignore events of graphical sessions */
+                if (handle == HANDLE_TTY_SESSION &&
+                    s && s->type == SESSION_X11)
+                        return 0;
+
+                if (n > 1 || (n == 1 && !s)) {
+                        log_error("Refusing power-off, other user is logged in.");
+                        warn_melody();
+                        return -EPERM;
+                }
+
+        }
+
+        if (handle != HANDLE_ALWAYS) {
                 if (manager_is_inhibited(b->manager, INHIBIT_SHUTDOWN, INHIBIT_BLOCK, NULL)) {
                         log_error("Refusing power-off, shutdown is inhibited.");
                         warn_melody();
@@ -210,17 +229,37 @@ static int button_suspend(Button *b, HandleButton handle) {
 
         assert(b);
 
-        if (handle == HANDLE_NO)
+        if (handle == HANDLE_OFF)
                 return 0;
 
-        if (handle != HANDLE_ALWAYS) {
-
+        if (handle == HANDLE_NO_SESSION) {
                 if (hashmap_size(b->manager->sessions) > 0) {
                         log_error("Refusing suspend, user is logged in.");
                         warn_melody();
                         return -EPERM;
                 }
 
+        } else if (handle == HANDLE_TTY_SESSION ||
+                   handle == HANDLE_ANY_SESSION) {
+                unsigned n;
+                Session *s;
+
+                n = hashmap_size(b->manager->sessions);
+                s = button_get_session(b);
+
+                /* Silently ignore events of graphical sessions */
+                if (handle == HANDLE_TTY_SESSION &&
+                    s && s->type == SESSION_X11)
+                        return 0;
+
+                if (n > 1 || (n == 1 && !s)) {
+                        log_error("Refusing suspend, other user is logged in.");
+                        warn_melody();
+                        return -EPERM;
+                }
+        }
+
+        if (handle != HANDLE_ALWAYS) {
                 if (manager_is_inhibited(b->manager, INHIBIT_SLEEP, INHIBIT_BLOCK, NULL)) {
                         log_error("Refusing suspend, sleeping is inhibited.");
                         warn_melody();
@@ -252,12 +291,6 @@ int button_process(Button *b) {
         if ((size_t) l < sizeof(ev))
                 return -EIO;
 
-        /* If there's a graphical session on the seat this device
-         * belongs to we ignore events, it is job of the graphical
-         * session to handle the event. */
-        if (has_graphical_session(b->manager, b->seat))
-                return 0;
-
         if (ev.type == EV_KEY && ev.value > 0) {
 
                 switch (ev.code) {
@@ -287,8 +320,10 @@ int button_process(Button *b) {
 }
 
 static const char* const handle_button_table[_HANDLE_BUTTON_MAX] = {
-        [HANDLE_YES] = "yes",
-        [HANDLE_NO] = "no",
+        [HANDLE_OFF] = "off",
+        [HANDLE_NO_SESSION] = "no-session",
+        [HANDLE_TTY_SESSION] = "tty-session",
+        [HANDLE_ANY_SESSION] = "any-session",
         [HANDLE_ALWAYS] = "always"
 };
 DEFINE_STRING_TABLE_LOOKUP(handle_button, HandleButton);
index 0378211325c1a7e9dcef56e815d02799be77ec90..7518d05ccb8290efe39c6571a530ada9d6b09a47 100644 (file)
 typedef struct Button Button;
 
 typedef enum HandleButton {
-        HANDLE_NO,
-        HANDLE_YES, /* only if no inhibitor is taken/no session is around */
-        HANDLE_ALWAYS, /* regardless if inhibitor is taken/session is around */
+        HANDLE_OFF,
+        HANDLE_NO_SESSION,   /* Only handle key when nobody is logged in; honour inhibitors */
+        HANDLE_TTY_SESSION,  /* Only handle key when nobody is logged in, or the fg session is the only one and non-graphical; honour inhibitors */
+        HANDLE_ANY_SESSION,  /* Only handle key when nobody is logged in, or the fg session is the only one; honour inhibtors */
+        HANDLE_ALWAYS,       /* Always handle, ignore sessions; ignore inhibitors */
         _HANDLE_BUTTON_MAX,
         _HANDLE_BUTTON_INVALID = -1
 } HandleButton;
index 0382972e8bfb0ef771b30585a1d9c2d53d86a966..632987c8b379c5269d5b12f6e48ba3a5fa723999 100644 (file)
@@ -53,9 +53,9 @@ Manager *manager_new(void) {
 
         m->n_autovts = 6;
         m->inhibit_delay_max = 5 * USEC_PER_SEC;
-        m->handle_power_key = HANDLE_YES;
-        m->handle_sleep_key = HANDLE_YES;
-        m->handle_lid_switch = HANDLE_NO;
+        m->handle_power_key = HANDLE_NO_SESSION;
+        m->handle_sleep_key = HANDLE_TTY_SESSION;
+        m->handle_lid_switch = HANDLE_OFF;
 
         m->devices = hashmap_new(string_hash_func, string_compare_func);
         m->seats = hashmap_new(string_hash_func, string_compare_func);
@@ -484,6 +484,11 @@ int manager_enumerate_buttons(Manager *m) {
 
         /* Loads buttons from udev */
 
+        if (m->handle_power_key == HANDLE_OFF &&
+            m->handle_sleep_key == HANDLE_OFF &&
+            m->handle_lid_switch == HANDLE_OFF)
+                return 0;
+
         e = udev_enumerate_new(m->udev);
         if (!e) {
                 r = -ENOMEM;
@@ -1234,59 +1239,62 @@ static int manager_connect_udev(Manager *m) {
         zero(ev);
         ev.events = EPOLLIN;
         ev.data.u32 = FD_SEAT_UDEV;
-
         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_seat_fd, &ev) < 0)
                 return -errno;
 
-        m->udev_button_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
-        if (!m->udev_button_monitor)
-                return -ENOMEM;
+        /* Don't watch keys if nobody cares */
+        if (m->handle_power_key != HANDLE_OFF ||
+            m->handle_sleep_key != HANDLE_OFF ||
+            m->handle_lid_switch != HANDLE_OFF) {
 
-        r = udev_monitor_filter_add_match_tag(m->udev_button_monitor, "power-switch");
-        if (r < 0)
-                return r;
+                m->udev_button_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
+                if (!m->udev_button_monitor)
+                        return -ENOMEM;
 
-        r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_button_monitor, "input", NULL);
-        if (r < 0)
-                return r;
+                r = udev_monitor_filter_add_match_tag(m->udev_button_monitor, "power-switch");
+                if (r < 0)
+                        return r;
 
-        r = udev_monitor_enable_receiving(m->udev_button_monitor);
-        if (r < 0)
-                return r;
+                r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_button_monitor, "input", NULL);
+                if (r < 0)
+                        return r;
 
-        m->udev_button_fd = udev_monitor_get_fd(m->udev_button_monitor);
+                r = udev_monitor_enable_receiving(m->udev_button_monitor);
+                if (r < 0)
+                        return r;
 
-        zero(ev);
-        ev.events = EPOLLIN;
-        ev.data.u32 = FD_BUTTON_UDEV;
+                m->udev_button_fd = udev_monitor_get_fd(m->udev_button_monitor);
 
-        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_button_fd, &ev) < 0)
-                return -errno;
+                zero(ev);
+                ev.events = EPOLLIN;
+                ev.data.u32 = FD_BUTTON_UDEV;
+                if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_button_fd, &ev) < 0)
+                        return -errno;
+        }
 
         /* Don't bother watching VCSA devices, if nobody cares */
-        if (m->n_autovts <= 0 || m->console_active_fd < 0)
-                return 0;
+        if (m->n_autovts > 0 && m->console_active_fd >= 0) {
 
-        m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
-        if (!m->udev_vcsa_monitor)
-                return -ENOMEM;
+                m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
+                if (!m->udev_vcsa_monitor)
+                        return -ENOMEM;
 
-        r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL);
-        if (r < 0)
-                return r;
-
-        r = udev_monitor_enable_receiving(m->udev_vcsa_monitor);
-        if (r < 0)
-                return r;
+                r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL);
+                if (r < 0)
+                        return r;
 
-        m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor);
+                r = udev_monitor_enable_receiving(m->udev_vcsa_monitor);
+                if (r < 0)
+                        return r;
 
-        zero(ev);
-        ev.events = EPOLLIN;
-        ev.data.u32 = FD_VCSA_UDEV;
+                m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor);
 
-        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_vcsa_fd, &ev) < 0)
-                return -errno;
+                zero(ev);
+                ev.events = EPOLLIN;
+                ev.data.u32 = FD_VCSA_UDEV;
+                if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_vcsa_fd, &ev) < 0)
+                        return -errno;
+        }
 
         return 0;
 }
index 4f012e5d89b2fbce2958de5dc2d7f62d6cbdf753..78496a0ef164f9181c1901d55644d5cf8b445c32 100644 (file)
@@ -15,6 +15,6 @@
 #Controllers=
 #ResetControllers=cpu
 #InhibitDelayMaxSec=5
-#HandlePowerKey=yes
-#HandleSleepKey=yes
-#HandleLidSwitch=no
+#HandlePowerKey=no-session
+#HandleSleepKey=tty-session
+#HandleLidSwitch=off