1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
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 <sys/ioctl.h>
28 #include <linux/input.h>
29 #include <sys/epoll.h>
31 #include "conf-parser.h"
33 #include "logind-button.h"
35 #include "dbus-common.h"
37 Button* button_new(Manager *m, const char *name) {
47 b->name = strdup(name);
53 if (hashmap_put(m->buttons, b->name, b) < 0) {
65 void button_free(Button *b) {
68 hashmap_remove(b->manager->buttons, b->name);
71 hashmap_remove(b->manager->button_fds, INT_TO_PTR(b->fd + 1));
72 assert_se(epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_DEL, b->fd, NULL) == 0);
73 close_nointr_nofail(b->fd);
81 int button_set_seat(Button *b, const char *sn) {
97 int button_open(Button *b) {
99 struct epoll_event ev;
105 close_nointr_nofail(b->fd);
109 p = strappend("/dev/input/", b->name);
111 log_error("Out of memory");
115 b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
118 log_warning("Failed to open %s: %m", b->name);
122 if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
123 log_error("Failed to get input name: %m");
130 ev.data.u32 = FD_OTHER_BASE + b->fd;
132 if (epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_ADD, b->fd, &ev) < 0) {
133 log_error("Failed to add to epoll: %m");
138 r = hashmap_put(b->manager->button_fds, INT_TO_PTR(b->fd + 1), b);
140 log_error("Failed to add to hash map: %s", strerror(-r));
141 assert_se(epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_DEL, b->fd, NULL) == 0);
145 log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name);
150 close_nointr_nofail(b->fd);
155 static bool has_graphical_session(Manager *m, const char *seat) {
161 s = hashmap_get(m->seats, seat);
168 return s->active->type == SESSION_X11;
171 static int button_power_off(Button *b, HandleButton handle) {
177 if (handle == HANDLE_NO)
180 if (handle != HANDLE_ALWAYS) {
182 if (hashmap_size(b->manager->sessions) > 0) {
183 log_error("Refusing power-off, user is logged in.");
188 if (manager_is_inhibited(b->manager, INHIBIT_SHUTDOWN, INHIBIT_BLOCK, NULL)) {
189 log_error("Refusing power-off, shutdown is inhibited.");
195 log_info("Powering off...");
197 dbus_error_init(&error);
198 r = bus_manager_shutdown_or_sleep_now_or_later(b->manager, SPECIAL_POWEROFF_TARGET, INHIBIT_SHUTDOWN, &error);
200 log_error("Failed to power off: %s", bus_error_message(&error));
201 dbus_error_free(&error);
207 static int button_suspend(Button *b, HandleButton handle) {
213 if (handle == HANDLE_NO)
216 if (handle != HANDLE_ALWAYS) {
218 if (hashmap_size(b->manager->sessions) > 0) {
219 log_error("Refusing suspend, user is logged in.");
224 if (manager_is_inhibited(b->manager, INHIBIT_SLEEP, INHIBIT_BLOCK, NULL)) {
225 log_error("Refusing suspend, sleeping is inhibited.");
231 log_info("Suspending...");
233 dbus_error_init(&error);
234 r = bus_manager_shutdown_or_sleep_now_or_later(b->manager, SPECIAL_SUSPEND_TARGET, INHIBIT_SLEEP, &error);
236 log_error("Failed to suspend: %s", bus_error_message(&error));
237 dbus_error_free(&error);
243 int button_process(Button *b) {
244 struct input_event ev;
249 l = read(b->fd, &ev, sizeof(ev));
251 return errno != EAGAIN ? -errno : 0;
252 if ((size_t) l < sizeof(ev))
255 /* If there's a graphical session on the seat this device
256 * belongs to we ignore events, it is job of the graphical
257 * session to handle the event. */
258 if (has_graphical_session(b->manager, b->seat))
261 if (ev.type == EV_KEY && ev.value > 0) {
267 log_info("Power key pressed.");
268 return button_power_off(b, b->manager->handle_power_key);
272 log_info("Sleep key pressed.");
273 return button_suspend(b, b->manager->handle_sleep_key);
276 } else if (ev.type == EV_SW && ev.value > 0) {
281 log_info("Lid closed.");
282 return button_suspend(b, b->manager->handle_lid_switch);
289 static const char* const handle_button_table[_HANDLE_BUTTON_MAX] = {
290 [HANDLE_YES] = "yes",
292 [HANDLE_ALWAYS] = "always"
294 DEFINE_STRING_TABLE_LOOKUP(handle_button, HandleButton);
295 DEFINE_CONFIG_PARSE_ENUM(config_parse_handle_button, handle_button, HandleButton, "Failed to parse handle button setting");