chiark / gitweb /
logind: optionally handle power, sleep and lid switch events
authorLennart Poettering <lennart@poettering.net>
Wed, 30 May 2012 13:01:51 +0000 (15:01 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 30 May 2012 13:01:51 +0000 (15:01 +0200)
This takes handling of chassis power and sleep keys as well as the lid
switch over from acpid.

This logic is enabled by default for power and sleep keys, but not for
the lid switch.

If a graphical session is in the foreground no action is taken under the
assumption that the graphical session does this.

12 files changed:
Makefile.am
TODO
man/logind.conf.xml
src/login/logind-dbus.c
src/login/logind-gperf.gperf
src/login/logind-inhibit.c
src/login/logind-session.c
src/login/logind.c
src/login/logind.conf
src/login/logind.h
src/shared/util.c
src/shared/util.h

index dad97ca45beed207d2ad6f7094fa1abd06a7678f..2d3378e309c58484c19517340aaa061adb0ec99c 100644 (file)
@@ -2658,6 +2658,8 @@ systemd_logind_SOURCES = \
        src/login/logind-dbus.c \
        src/login/logind-device.c \
        src/login/logind-device.h \
        src/login/logind-dbus.c \
        src/login/logind-device.c \
        src/login/logind-device.h \
+       src/login/logind-button.c \
+       src/login/logind-button.h \
        src/login/logind-seat.c \
        src/login/logind-seat.h \
        src/login/logind-session.c \
        src/login/logind-seat.c \
        src/login/logind-seat.h \
        src/login/logind-session.c \
@@ -2873,7 +2875,8 @@ rootlibexec_PROGRAMS += \
 
 dist_udevrules_DATA += \
        src/login/70-uaccess.rules \
 
 dist_udevrules_DATA += \
        src/login/70-uaccess.rules \
-       src/login/71-seat.rules
+       src/login/71-seat.rules \
+       src/login/70-power-switch.rules
 
 nodist_udevrules_DATA += \
        src/login/73-seat-late.rules
 
 nodist_udevrules_DATA += \
        src/login/73-seat-late.rules
diff --git a/TODO b/TODO
index 3b3c451c7621174e2640f64260c96bd0fbb726bc..f4d3c63464b4d26fa265ca426761892bc1c5e849 100644 (file)
--- a/TODO
+++ b/TODO
@@ -31,6 +31,9 @@ Bugfixes:
 * properly handle .mount unit state tracking when two mount points are stacked one on top of another on the exact same mount point.
 
 Features:
 * properly handle .mount unit state tracking when two mount points are stacked one on top of another on the exact same mount point.
 
 Features:
+
+* nspawn: make use of device cgroup contrller by default
+
 * parse kernel cmdline option for capability bset
 
 * logind: listen to power-button events
 * parse kernel cmdline option for capability bset
 
 * logind: listen to power-button events
index 166038b383972c06267a31be645b7bfdec51b083..09db6001433521379733ac65049eb982623e3a57 100644 (file)
                                 the operation executed
                                 anyway. Defaults to
                                 5s.</para></listitem>
                                 the operation executed
                                 anyway. Defaults to
                                 5s.</para></listitem>
+                        </varlistentry>
 
 
+                        <varlistentry>
+                                <term><varname>HandlePowerKey=</varname></term>
+                                <term><varname>HandleSleepKey=</varname></term>
+                                <term><varname>HandleLidSwitch=</varname></term>
+
+                                <listitem><para>Controls whether
+                                logind shall handle the system power
+                                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>always</literal>. If
+                                <literal>no</literal> logind will
+                                never handle these keys. If
+                                <literal>yes</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>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
+                                events. <varname>HandlePowerKey=</varname>
+                                and <varname>HandleSleepKey=</varname>
+                                default to <literal>yes</literal>,
+                                <varname>HandleLidSwitch=</varname>
+                                defaults to
+                                <literal>no</literal>.</para></listitem>
                         </varlistentry>
 
                 </variablelist>
                         </varlistentry>
 
                 </variablelist>
index e089eebed96d33b24a3ba4b4e3668724c51e1623..5cdd0890e395d2239b846d4d0d06ee1bf1a634d7 100644 (file)
         "  <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"HandleSleepKey\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
         " </interface>\n"
 
 #define INTROSPECTION_BEGIN                                             \
         " </interface>\n"
 
 #define INTROSPECTION_BEGIN                                             \
@@ -1136,6 +1139,36 @@ finish:
         return 0;
 }
 
         return 0;
 }
 
+int bus_manager_shutdown_or_sleep_now_or_later(
+                Manager *m,
+                const char *unit_name,
+                InhibitWhat w,
+                DBusError *error) {
+
+        bool delayed;
+        int r;
+
+        assert(m);
+        assert(unit_name);
+        assert(w >= 0);
+        assert(w <= _INHIBIT_WHAT_MAX);
+
+        delayed =
+                m->inhibit_delay_max > 0 &&
+                manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
+
+        if (delayed)
+                /* Shutdown is delayed, keep in mind what we
+                 * want to do, and start a timeout */
+                r = delay_shutdown_or_sleep(m, w, unit_name);
+        else
+                /* Shutdown is not delayed, execute it
+                 * immediately */
+                r = send_start_unit(m->bus, unit_name, error);
+
+        return r;
+}
+
 static int bus_manager_do_shutdown_or_sleep(
                 Manager *m,
                 DBusConnection *connection,
 static int bus_manager_do_shutdown_or_sleep(
                 Manager *m,
                 DBusConnection *connection,
@@ -1150,7 +1183,7 @@ static int bus_manager_do_shutdown_or_sleep(
                 DBusMessage **_reply) {
 
         dbus_bool_t interactive;
                 DBusMessage **_reply) {
 
         dbus_bool_t interactive;
-        bool multiple_sessions, blocked, delayed;
+        bool multiple_sessions, blocked;
         DBusMessage *reply = NULL;
         int r;
 
         DBusMessage *reply = NULL;
         int r;
 
@@ -1207,19 +1240,7 @@ static int bus_manager_do_shutdown_or_sleep(
                         return r;
         }
 
                         return r;
         }
 
-        delayed =
-                m->inhibit_delay_max > 0 &&
-                manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
-
-        if (delayed) {
-                /* Shutdown is delayed, keep in mind what we
-                 * want to do, and start a timeout */
-                r = delay_shutdown_or_sleep(m, w, unit_name);
-        } else
-                /* Shutdown is not delayed, execute it
-                 * immediately */
-                r = send_start_unit(connection, unit_name, error);
-
+        r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
@@ -1231,6 +1252,8 @@ static int bus_manager_do_shutdown_or_sleep(
         return 0;
 }
 
         return 0;
 }
 
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
+
 static const BusProperty bus_login_manager_properties[] = {
         { "ControlGroupHierarchy",  bus_property_append_string,         "s",  offsetof(Manager, cgroup_path),        true },
         { "Controllers",            bus_property_append_strv,           "as", offsetof(Manager, controllers),        true },
 static const BusProperty bus_login_manager_properties[] = {
         { "ControlGroupHierarchy",  bus_property_append_string,         "s",  offsetof(Manager, cgroup_path),        true },
         { "Controllers",            bus_property_append_strv,           "as", offsetof(Manager, controllers),        true },
@@ -1245,6 +1268,9 @@ static const BusProperty bus_login_manager_properties[] = {
         { "BlockInhibited",         bus_manager_append_inhibited,       "s",  0 },
         { "DelayInhibited",         bus_manager_append_inhibited,       "s",  0 },
         { "InhibitDelayMaxUSec",    bus_property_append_usec,           "t",  offsetof(Manager, inhibit_delay_max)   },
         { "BlockInhibited",         bus_manager_append_inhibited,       "s",  0 },
         { "DelayInhibited",         bus_manager_append_inhibited,       "s",  0 },
         { "InhibitDelayMaxUSec",    bus_property_append_usec,           "t",  offsetof(Manager, inhibit_delay_max)   },
+        { "HandlePowerKey",         bus_manager_append_handle_button,   "s",  offsetof(Manager, handle_power_key)    },
+        { "HandleSleepKey",         bus_manager_append_handle_button,   "s",  offsetof(Manager, handle_sleep_key)    },
+        { "HandleLidSwitch",        bus_manager_append_handle_button,   "s",  offsetof(Manager, handle_lid_switch)   },
         { NULL, }
 };
 
         { NULL, }
 };
 
index d8ef92a01600eb4d5c64917724e98faada54e167..72fdad739b9dfc1617245043c797f84547dc5a1e 100644 (file)
@@ -21,3 +21,6 @@ Login.KillExcludeUsers,  config_parse_strv,     0, offsetof(Manager, kill_exclud
 Login.Controllers,       config_parse_strv,     0, offsetof(Manager, controllers)
 Login.ResetControllers,  config_parse_strv,     0, offsetof(Manager, reset_controllers)
 Login.InhibitDelayMaxSec,config_parse_usec,     0, offsetof(Manager, inhibit_delay_max)
 Login.Controllers,       config_parse_strv,     0, offsetof(Manager, controllers)
 Login.ResetControllers,  config_parse_strv,     0, offsetof(Manager, reset_controllers)
 Login.InhibitDelayMaxSec,config_parse_usec,     0, offsetof(Manager, inhibit_delay_max)
+Login.HandlePowerKey,    config_parse_handle_button, 0, offsetof(Manager, handle_power_key)
+Login.HandleSleepKey,    config_parse_handle_button, 0, offsetof(Manager, handle_sleep_key)
+Login.HandleLidSwitch,   config_parse_handle_button, 0, offsetof(Manager, handle_lid_switch)
index 512fc0716bb4f1ad9ad3b6833ec7907f8a016331..2d25b79c251af327bd71bd46705348eae3880ac3 100644 (file)
@@ -297,7 +297,7 @@ int inhibitor_create_fifo(Inhibitor *i) {
 
                 zero(ev);
                 ev.events = 0;
 
                 zero(ev);
                 ev.events = 0;
-                ev.data.u32 = FD_FIFO_BASE + i->fifo_fd;
+                ev.data.u32 = FD_OTHER_BASE + i->fifo_fd;
 
                 if (epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_ADD, i->fifo_fd, &ev) < 0)
                         return -errno;
 
                 if (epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_ADD, i->fifo_fd, &ev) < 0)
                         return -errno;
index 1f3a7f375514802e09e71e61c490631823540830..dd0de7805b4f59c447b5d8cf2cd7296a622cb97d 100644 (file)
@@ -841,7 +841,7 @@ int session_create_fifo(Session *s) {
 
                 zero(ev);
                 ev.events = 0;
 
                 zero(ev);
                 ev.events = 0;
-                ev.data.u32 = FD_FIFO_BASE + s->fifo_fd;
+                ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
 
                 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
                         return -errno;
 
                 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
                         return -errno;
index 8d4f7333c950d7045ce8c4813458113bb6bed8c4..0382972e8bfb0ef771b30585a1d9c2d53d86a966 100644 (file)
@@ -48,22 +48,29 @@ Manager *manager_new(void) {
         m->bus_fd = -1;
         m->udev_seat_fd = -1;
         m->udev_vcsa_fd = -1;
         m->bus_fd = -1;
         m->udev_seat_fd = -1;
         m->udev_vcsa_fd = -1;
+        m->udev_button_fd = -1;
         m->epoll_fd = -1;
         m->epoll_fd = -1;
+
         m->n_autovts = 6;
         m->inhibit_delay_max = 5 * USEC_PER_SEC;
         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->devices = hashmap_new(string_hash_func, string_compare_func);
         m->seats = hashmap_new(string_hash_func, string_compare_func);
         m->sessions = hashmap_new(string_hash_func, string_compare_func);
         m->users = hashmap_new(trivial_hash_func, trivial_compare_func);
         m->inhibitors = hashmap_new(string_hash_func, string_compare_func);
 
         m->devices = hashmap_new(string_hash_func, string_compare_func);
         m->seats = hashmap_new(string_hash_func, string_compare_func);
         m->sessions = hashmap_new(string_hash_func, string_compare_func);
         m->users = hashmap_new(trivial_hash_func, trivial_compare_func);
         m->inhibitors = hashmap_new(string_hash_func, string_compare_func);
+        m->buttons = hashmap_new(string_hash_func, string_compare_func);
 
         m->cgroups = hashmap_new(string_hash_func, string_compare_func);
         m->session_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
         m->inhibitor_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
 
         m->cgroups = hashmap_new(string_hash_func, string_compare_func);
         m->session_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
         m->inhibitor_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
+        m->button_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
 
 
-        if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors ||
-            !m->cgroups || !m->session_fds || !m->inhibitor_fds) {
+        if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons ||
+            !m->cgroups || !m->session_fds || !m->inhibitor_fds || !m->button_fds) {
                 manager_free(m);
                 return NULL;
         }
                 manager_free(m);
                 return NULL;
         }
@@ -95,6 +102,7 @@ void manager_free(Manager *m) {
         Device *d;
         Seat *s;
         Inhibitor *i;
         Device *d;
         Seat *s;
         Inhibitor *i;
+        Button *b;
 
         assert(m);
 
 
         assert(m);
 
@@ -113,24 +121,30 @@ void manager_free(Manager *m) {
         while ((i = hashmap_first(m->inhibitors)))
                 inhibitor_free(i);
 
         while ((i = hashmap_first(m->inhibitors)))
                 inhibitor_free(i);
 
+        while ((b = hashmap_first(m->buttons)))
+                button_free(b);
+
         hashmap_free(m->devices);
         hashmap_free(m->seats);
         hashmap_free(m->sessions);
         hashmap_free(m->users);
         hashmap_free(m->inhibitors);
         hashmap_free(m->devices);
         hashmap_free(m->seats);
         hashmap_free(m->sessions);
         hashmap_free(m->users);
         hashmap_free(m->inhibitors);
+        hashmap_free(m->buttons);
 
         hashmap_free(m->cgroups);
         hashmap_free(m->session_fds);
         hashmap_free(m->inhibitor_fds);
 
         hashmap_free(m->cgroups);
         hashmap_free(m->session_fds);
         hashmap_free(m->inhibitor_fds);
+        hashmap_free(m->button_fds);
 
         if (m->console_active_fd >= 0)
                 close_nointr_nofail(m->console_active_fd);
 
         if (m->udev_seat_monitor)
                 udev_monitor_unref(m->udev_seat_monitor);
 
         if (m->console_active_fd >= 0)
                 close_nointr_nofail(m->console_active_fd);
 
         if (m->udev_seat_monitor)
                 udev_monitor_unref(m->udev_seat_monitor);
-
         if (m->udev_vcsa_monitor)
                 udev_monitor_unref(m->udev_vcsa_monitor);
         if (m->udev_vcsa_monitor)
                 udev_monitor_unref(m->udev_vcsa_monitor);
+        if (m->udev_button_monitor)
+                udev_monitor_unref(m->udev_button_monitor);
 
         if (m->udev)
                 udev_unref(m->udev);
 
         if (m->udev)
                 udev_unref(m->udev);
@@ -304,6 +318,30 @@ int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor) {
         return 0;
 }
 
         return 0;
 }
 
+int manager_add_button(Manager *m, const char *name, Button **_button) {
+        Button *b;
+
+        assert(m);
+        assert(name);
+
+        b = hashmap_get(m->buttons, name);
+        if (b) {
+                if (_button)
+                        *_button = b;
+
+                return 0;
+        }
+
+        b = button_new(m, name);
+        if (!b)
+                return -ENOMEM;
+
+        if (_button)
+                *_button = b;
+
+        return 0;
+}
+
 int manager_process_seat_device(Manager *m, struct udev_device *d) {
         Device *device;
         int r;
 int manager_process_seat_device(Manager *m, struct udev_device *d) {
         Device *device;
         int r;
@@ -351,6 +389,39 @@ int manager_process_seat_device(Manager *m, struct udev_device *d) {
         return 0;
 }
 
         return 0;
 }
 
+int manager_process_button_device(Manager *m, struct udev_device *d) {
+        Button *b;
+
+        int r;
+
+        assert(m);
+
+        if (streq_ptr(udev_device_get_action(d), "remove")) {
+
+                b = hashmap_get(m->buttons, udev_device_get_sysname(d));
+                if (!b)
+                        return 0;
+
+                button_free(b);
+
+        } else {
+                const char *sn;
+
+                r = manager_add_button(m, udev_device_get_sysname(d), &b);
+                if (r < 0)
+                        return r;
+
+                sn = udev_device_get_property_value(d, "ID_SEAT");
+                if (isempty(sn))
+                        sn = "seat0";
+
+                button_set_seat(b, sn);
+                button_open(b);
+        }
+
+        return 0;
+}
+
 int manager_enumerate_devices(Manager *m) {
         struct udev_list_entry *item = NULL, *first = NULL;
         struct udev_enumerate *e;
 int manager_enumerate_devices(Manager *m) {
         struct udev_list_entry *item = NULL, *first = NULL;
         struct udev_enumerate *e;
@@ -404,6 +475,58 @@ finish:
         return r;
 }
 
         return r;
 }
 
+int manager_enumerate_buttons(Manager *m) {
+        struct udev_list_entry *item = NULL, *first = NULL;
+        struct udev_enumerate *e;
+        int r;
+
+        assert(m);
+
+        /* Loads buttons from udev */
+
+        e = udev_enumerate_new(m->udev);
+        if (!e) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        r = udev_enumerate_add_match_subsystem(e, "input");
+        if (r < 0)
+                goto finish;
+
+        r = udev_enumerate_add_match_tag(e, "power-switch");
+        if (r < 0)
+                goto finish;
+
+        r = udev_enumerate_scan_devices(e);
+        if (r < 0)
+                goto finish;
+
+        first = udev_enumerate_get_list_entry(e);
+        udev_list_entry_foreach(item, first) {
+                struct udev_device *d;
+                int k;
+
+                d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
+                if (!d) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                k = manager_process_button_device(m, d);
+                udev_device_unref(d);
+
+                if (k < 0)
+                        r = k;
+        }
+
+finish:
+        if (e)
+                udev_enumerate_unref(e);
+
+        return r;
+}
+
 int manager_enumerate_seats(Manager *m) {
         DIR *d;
         struct dirent *de;
 int manager_enumerate_seats(Manager *m) {
         DIR *d;
         struct dirent *de;
@@ -756,6 +879,22 @@ int manager_dispatch_vcsa_udev(Manager *m) {
         return r;
 }
 
         return r;
 }
 
+int manager_dispatch_button_udev(Manager *m) {
+        struct udev_device *d;
+        int r;
+
+        assert(m);
+
+        d = udev_monitor_receive_device(m->udev_button_monitor);
+        if (!d)
+                return -ENOMEM;
+
+        r = manager_process_button_device(m, d);
+        udev_device_unref(d);
+
+        return r;
+}
+
 int manager_dispatch_console(Manager *m) {
         assert(m);
 
 int manager_dispatch_console(Manager *m) {
         assert(m);
 
@@ -926,9 +1065,10 @@ void manager_cgroup_notify_empty(Manager *m, const char *cgroup) {
         session_add_to_gc_queue(s);
 }
 
         session_add_to_gc_queue(s);
 }
 
-static void manager_pipe_notify_eof(Manager *m, int fd) {
+static void manager_dispatch_other(Manager *m, int fd) {
         Session *s;
         Inhibitor *i;
         Session *s;
         Inhibitor *i;
+        Button *b;
 
         assert_se(m);
         assert_se(fd >= 0);
 
         assert_se(m);
         assert_se(fd >= 0);
@@ -949,7 +1089,14 @@ static void manager_pipe_notify_eof(Manager *m, int fd) {
                 return;
         }
 
                 return;
         }
 
-        assert_not_reached("Got EOF on unknown pipe");
+        b = hashmap_get(m->button_fds, INT_TO_PTR(fd + 1));
+        if (b) {
+                assert(b->fd == fd);
+                button_process(b);
+                return;
+        }
+
+        assert_not_reached("Got event for unknown fd");
 }
 
 static int manager_connect_bus(Manager *m) {
 }
 
 static int manager_connect_bus(Manager *m) {
@@ -1064,6 +1211,7 @@ static int manager_connect_udev(Manager *m) {
         assert(m);
         assert(!m->udev_seat_monitor);
         assert(!m->udev_vcsa_monitor);
         assert(m);
         assert(!m->udev_seat_monitor);
         assert(!m->udev_vcsa_monitor);
+        assert(!m->udev_button_monitor);
 
         m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
         if (!m->udev_seat_monitor)
 
         m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
         if (!m->udev_seat_monitor)
@@ -1087,13 +1235,38 @@ static int manager_connect_udev(Manager *m) {
         ev.events = EPOLLIN;
         ev.data.u32 = FD_SEAT_UDEV;
 
         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;
+
+        r = udev_monitor_filter_add_match_tag(m->udev_button_monitor, "power-switch");
+        if (r < 0)
+                return r;
+
+        r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_button_monitor, "input", NULL);
+        if (r < 0)
+                return r;
+
+        r = udev_monitor_enable_receiving(m->udev_button_monitor);
+        if (r < 0)
+                return r;
+
+        m->udev_button_fd = udev_monitor_get_fd(m->udev_button_monitor);
+
+        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;
 
         /* Don't bother watching VCSA devices, if nobody cares */
         if (m->n_autovts <= 0 || m->console_active_fd < 0)
                 return 0;
 
-        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_seat_fd, &ev) < 0)
-                return -errno;
-
         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;
@@ -1239,6 +1412,7 @@ int manager_startup(Manager *m) {
         manager_enumerate_users(m);
         manager_enumerate_sessions(m);
         manager_enumerate_inhibitors(m);
         manager_enumerate_users(m);
         manager_enumerate_sessions(m);
         manager_enumerate_inhibitors(m);
+        manager_enumerate_buttons(m);
 
         /* Remove stale objects before we start them */
         manager_gc(m, false);
 
         /* Remove stale objects before we start them */
         manager_gc(m, false);
@@ -1308,6 +1482,10 @@ int manager_run(Manager *m) {
                         manager_dispatch_vcsa_udev(m);
                         break;
 
                         manager_dispatch_vcsa_udev(m);
                         break;
 
+                case FD_BUTTON_UDEV:
+                        manager_dispatch_button_udev(m);
+                        break;
+
                 case FD_CONSOLE:
                         manager_dispatch_console(m);
                         break;
                 case FD_CONSOLE:
                         manager_dispatch_console(m);
                         break;
@@ -1317,8 +1495,8 @@ int manager_run(Manager *m) {
                         break;
 
                 default:
                         break;
 
                 default:
-                        if (event.data.u32 >= FD_FIFO_BASE)
-                                manager_pipe_notify_eof(m, event.data.u32 - FD_FIFO_BASE);
+                        if (event.data.u32 >= FD_OTHER_BASE)
+                                manager_dispatch_other(m, event.data.u32 - FD_OTHER_BASE);
                 }
         }
 
                 }
         }
 
index c0779a7685c47fb7a633d72d51191602f2b524a1..4f012e5d89b2fbce2958de5dc2d7f62d6cbdf753 100644 (file)
@@ -15,3 +15,6 @@
 #Controllers=
 #ResetControllers=cpu
 #InhibitDelayMaxSec=5
 #Controllers=
 #ResetControllers=cpu
 #InhibitDelayMaxSec=5
+#HandlePowerKey=yes
+#HandleSleepKey=yes
+#HandleLidSwitch=no
index 24332210c2dedc625db3fba4d1e28c9a478b69cb..6fcef6f310d2956343fafd0163d6ef3dfe713b62 100644 (file)
@@ -40,6 +40,7 @@ typedef struct Manager Manager;
 #include "logind-session.h"
 #include "logind-user.h"
 #include "logind-inhibit.h"
 #include "logind-session.h"
 #include "logind-user.h"
 #include "logind-inhibit.h"
+#include "logind-button.h"
 
 struct Manager {
         DBusConnection *bus;
 
 struct Manager {
         DBusConnection *bus;
@@ -49,16 +50,18 @@ struct Manager {
         Hashmap *sessions;
         Hashmap *users;
         Hashmap *inhibitors;
         Hashmap *sessions;
         Hashmap *users;
         Hashmap *inhibitors;
+        Hashmap *buttons;
 
         LIST_HEAD(Seat, seat_gc_queue);
         LIST_HEAD(Session, session_gc_queue);
         LIST_HEAD(User, user_gc_queue);
 
         struct udev *udev;
 
         LIST_HEAD(Seat, seat_gc_queue);
         LIST_HEAD(Session, session_gc_queue);
         LIST_HEAD(User, user_gc_queue);
 
         struct udev *udev;
-        struct udev_monitor *udev_seat_monitor, *udev_vcsa_monitor;
+        struct udev_monitor *udev_seat_monitor, *udev_vcsa_monitor, *udev_button_monitor;
 
         int udev_seat_fd;
         int udev_vcsa_fd;
 
         int udev_seat_fd;
         int udev_vcsa_fd;
+        int udev_button_fd;
 
         int console_active_fd;
         int bus_fd;
 
         int console_active_fd;
         int bus_fd;
@@ -81,6 +84,7 @@ struct Manager {
         Hashmap *cgroups;
         Hashmap *session_fds;
         Hashmap *inhibitor_fds;
         Hashmap *cgroups;
         Hashmap *session_fds;
         Hashmap *inhibitor_fds;
+        Hashmap *button_fds;
 
         /* If a shutdown was delayed due to a inhibitor this contains
            the unit name we are supposed to start after the delay is
 
         /* If a shutdown was delayed due to a inhibitor this contains
            the unit name we are supposed to start after the delay is
@@ -90,20 +94,26 @@ struct Manager {
         usec_t delayed_timestamp;
 
         usec_t inhibit_delay_max;
         usec_t delayed_timestamp;
 
         usec_t inhibit_delay_max;
+
+        HandleButton handle_power_key;
+        HandleButton handle_sleep_key;
+        HandleButton handle_lid_switch;
 };
 
 enum {
         FD_SEAT_UDEV,
         FD_VCSA_UDEV,
 };
 
 enum {
         FD_SEAT_UDEV,
         FD_VCSA_UDEV,
+        FD_BUTTON_UDEV,
         FD_CONSOLE,
         FD_BUS,
         FD_CONSOLE,
         FD_BUS,
-        FD_FIFO_BASE
+        FD_OTHER_BASE
 };
 
 Manager *manager_new(void);
 void manager_free(Manager *m);
 
 int manager_add_device(Manager *m, const char *sysfs, Device **_device);
 };
 
 Manager *manager_new(void);
 void manager_free(Manager *m);
 
 int manager_add_device(Manager *m, const char *sysfs, Device **_device);
+int manager_add_button(Manager *m, const char *name, Button **_button);
 int manager_add_seat(Manager *m, const char *id, Seat **_seat);
 int manager_add_session(Manager *m, User *u, const char *id, Session **_session);
 int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user);
 int manager_add_seat(Manager *m, const char *id, Seat **_seat);
 int manager_add_session(Manager *m, User *u, const char *id, Session **_session);
 int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user);
@@ -112,11 +122,15 @@ int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user);
 int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor);
 
 int manager_process_seat_device(Manager *m, struct udev_device *d);
 int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor);
 
 int manager_process_seat_device(Manager *m, struct udev_device *d);
+int manager_process_button_device(Manager *m, struct udev_device *d);
+
 int manager_dispatch_seat_udev(Manager *m);
 int manager_dispatch_vcsa_udev(Manager *m);
 int manager_dispatch_seat_udev(Manager *m);
 int manager_dispatch_vcsa_udev(Manager *m);
+int manager_dispatch_button_udev(Manager *m);
 int manager_dispatch_console(Manager *m);
 
 int manager_enumerate_devices(Manager *m);
 int manager_dispatch_console(Manager *m);
 
 int manager_enumerate_devices(Manager *m);
+int manager_enumerate_buttons(Manager *m);
 int manager_enumerate_seats(Manager *m);
 int manager_enumerate_sessions(Manager *m);
 int manager_enumerate_users(Manager *m);
 int manager_enumerate_seats(Manager *m);
 int manager_enumerate_sessions(Manager *m);
 int manager_enumerate_users(Manager *m);
@@ -139,6 +153,8 @@ extern const DBusObjectPathVTable bus_manager_vtable;
 
 DBusHandlerResult bus_message_filter(DBusConnection *c, DBusMessage *message, void *userdata);
 
 
 DBusHandlerResult bus_message_filter(DBusConnection *c, DBusMessage *message, void *userdata);
 
+int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name, InhibitWhat w, DBusError *error);
+
 int manager_send_changed(Manager *manager, const char *properties);
 
 int manager_dispatch_delayed(Manager *manager);
 int manager_send_changed(Manager *manager, const char *properties);
 
 int manager_dispatch_delayed(Manager *manager);
index 7d98dc6e4fb34ff85d8ed1e12a7a38c1448d930e..70b159f8c314ead6fb62964ece54117d7e4bd240 100644 (file)
@@ -5639,3 +5639,25 @@ bool in_initrd(void) {
 
         return saved;
 }
 
         return saved;
 }
+
+void warn_melody(void) {
+        int fd;
+
+        fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY);
+        if (fd < 0)
+                return;
+
+        /* Yeah, this is synchronous. Kinda sucks. Bute well... */
+
+        ioctl(fd, KIOCSOUND, (int)(1193180/440));
+        usleep(125*USEC_PER_MSEC);
+
+        ioctl(fd, KIOCSOUND, (int)(1193180/220));
+        usleep(125*USEC_PER_MSEC);
+
+        ioctl(fd, KIOCSOUND, (int)(1193180/220));
+        usleep(125*USEC_PER_MSEC);
+
+        ioctl(fd, KIOCSOUND, 0);
+        close_nointr_nofail(fd);
+}
index 2d890fa6a376a18ac5268a324835fa57b1ca2250..35ff2e3547f42e22f42ab10a677c79c090dadeb2 100644 (file)
@@ -513,4 +513,7 @@ int can_sleep(const char *type);
 bool is_valid_documentation_url(const char *url);
 
 bool in_initrd(void);
 bool is_valid_documentation_url(const char *url);
 
 bool in_initrd(void);
+
+void warn_melody(void);
+
 #endif
 #endif