logind-button.c revision 23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering/***
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering This file is part of systemd.
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering Copyright 2012 Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering (at your option) any later version.
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering systemd is distributed in the hope that it will be useful, but
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering Lesser General Public License for more details.
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering***/
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering#include <assert.h>
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering#include <string.h>
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering#include <errno.h>
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering#include <fcntl.h>
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering#include <sys/ioctl.h>
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering#include <unistd.h>
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering#include <linux/input.h>
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering#include <sys/epoll.h>
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering#include "conf-parser.h"
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering#include "util.h"
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering#include "logind-button.h"
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering#include "special.h"
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering#include "dbus-common.h"
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart PoetteringButton* button_new(Manager *m, const char *name) {
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering Button *b;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering assert(m);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering assert(name);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering b = new0(Button, 1);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering if (!b)
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering return NULL;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering b->name = strdup(name);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering if (!b->name) {
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering free(b);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering return NULL;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering }
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering if (hashmap_put(m->buttons, b->name, b) < 0) {
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering free(b->name);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering free(b);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering return NULL;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering }
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering b->manager = m;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering b->fd = -1;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering return b;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering}
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poetteringvoid button_free(Button *b) {
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering assert(b);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering hashmap_remove(b->manager->buttons, b->name);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering if (b->fd >= 0) {
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering hashmap_remove(b->manager->button_fds, INT_TO_PTR(b->fd + 1));
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering assert_se(epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_DEL, b->fd, NULL) == 0);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering close_nointr_nofail(b->fd);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering }
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering free(b->name);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering free(b->seat);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering free(b);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering}
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poetteringint button_set_seat(Button *b, const char *sn) {
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering char *s;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering assert(b);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering assert(sn);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering s = strdup(sn);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering if (!s)
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering return -ENOMEM;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering free(b->seat);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering b->seat = s;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering return 0;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering}
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poetteringint button_open(Button *b) {
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering char name[256], *p;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering struct epoll_event ev;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering int r;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering assert(b);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering if (b->fd >= 0) {
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering close_nointr_nofail(b->fd);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering b->fd = -1;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering }
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering p = strappend("/dev/input/", b->name);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering if (!p)
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering return log_oom();
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering free(p);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering if (b->fd < 0) {
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering log_warning("Failed to open %s: %m", b->name);
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering return -errno;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering }
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering log_error("Failed to get input name: %m");
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering r = -errno;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering goto fail;
23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0Lennart Poettering }
zero(ev);
ev.events = EPOLLIN;
ev.data.u32 = FD_OTHER_BASE + b->fd;
if (epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_ADD, b->fd, &ev) < 0) {
log_error("Failed to add to epoll: %m");
r = -errno;
goto fail;
}
r = hashmap_put(b->manager->button_fds, INT_TO_PTR(b->fd + 1), b);
if (r < 0) {
log_error("Failed to add to hash map: %s", strerror(-r));
assert_se(epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_DEL, b->fd, NULL) == 0);
goto fail;
}
log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name);
return 0;
fail:
close_nointr_nofail(b->fd);
b->fd = -1;
return r;
}
static int button_handle(
Button *b,
InhibitWhat inhibit_key,
HandleAction handle,
bool ignore_inhibited,
bool is_edge) {
int r;
assert(b);
r = manager_handle_action(b->manager, inhibit_key, handle, ignore_inhibited, is_edge);
if (r > 0)
/* We are executing the operation, so make sure we don't
* execute another one until the lid is opened/closed again */
b->lid_close_queued = false;
return r;
}
int button_process(Button *b) {
struct input_event ev;
ssize_t l;
assert(b);
l = read(b->fd, &ev, sizeof(ev));
if (l < 0)
return errno != EAGAIN ? -errno : 0;
if ((size_t) l < sizeof(ev))
return -EIO;
if (ev.type == EV_KEY && ev.value > 0) {
switch (ev.code) {
case KEY_POWER:
case KEY_POWER2:
log_info("Power key pressed.");
return button_handle(b, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
/* The kernel is a bit confused here:
KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend"
KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
*/
case KEY_SLEEP:
log_info("Suspend key pressed.");
return button_handle(b, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
case KEY_SUSPEND:
log_info("Hibernate key pressed.");
return button_handle(b, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
}
} else if (ev.type == EV_SW && ev.value > 0) {
switch (ev.code) {
case SW_LID:
log_info("Lid closed.");
b->lid_close_queued = true;
return button_handle(b, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, true);
}
} else if (ev.type == EV_SW && ev.value == 0) {
switch (ev.code) {
case SW_LID:
log_info("Lid opened.");
b->lid_close_queued = false;
break;
}
}
return 0;
}
int button_recheck(Button *b) {
assert(b);
if (!b->lid_close_queued)
return 0;
return button_handle(b, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, false);
}