]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-button.c
tree-wide: drop {} from one-line if blocks
[thirdparty/systemd.git] / src / login / logind-button.c
CommitLineData
e9d21f24
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
e9d21f24
LP
22#include <string.h>
23#include <errno.h>
24#include <fcntl.h>
25#include <sys/ioctl.h>
26#include <unistd.h>
27#include <linux/input.h>
e9d21f24 28
cc377381 29#include "sd-messages.h"
e9d21f24 30#include "util.h"
cc377381 31#include "logind-button.h"
e9d21f24
LP
32
33Button* button_new(Manager *m, const char *name) {
34 Button *b;
35
36 assert(m);
37 assert(name);
38
39 b = new0(Button, 1);
40 if (!b)
41 return NULL;
42
43 b->name = strdup(name);
44 if (!b->name) {
45 free(b);
46 return NULL;
47 }
48
49 if (hashmap_put(m->buttons, b->name, b) < 0) {
50 free(b->name);
51 free(b);
52 return NULL;
53 }
54
55 b->manager = m;
56 b->fd = -1;
57
58 return b;
59}
60
61void button_free(Button *b) {
62 assert(b);
63
64 hashmap_remove(b->manager->buttons, b->name);
65
ed4ba7e4
LP
66 sd_event_source_unref(b->io_event_source);
67 sd_event_source_unref(b->check_event_source);
c30a0c62 68
ece174c5 69 if (b->fd >= 0)
c30a0c62
LP
70 /* If the device has been unplugged close() returns
71 * ENODEV, let's ignore this, hence we don't use
03e334a1 72 * safe_close() */
4fba5796 73 (void) close(b->fd);
e9d21f24
LP
74
75 free(b->name);
76 free(b->seat);
77 free(b);
78}
79
80int button_set_seat(Button *b, const char *sn) {
81 char *s;
82
83 assert(b);
84 assert(sn);
85
86 s = strdup(sn);
87 if (!s)
88 return -ENOMEM;
89
90 free(b->seat);
91 b->seat = s;
92
93 return 0;
94}
95
3c56cab4
BW
96static void button_lid_switch_handle_action(Manager *manager, bool is_edge) {
97 HandleAction handle_action;
98
99 assert(manager);
100
101 /* If we are docked, handle the lid switch differently */
602a41c2 102 if (manager_is_docked_or_external_displays(manager))
3c56cab4
BW
103 handle_action = manager->handle_lid_switch_docked;
104 else
105 handle_action = manager->handle_lid_switch;
106
107 manager_handle_action(manager, INHIBIT_HANDLE_LID_SWITCH, handle_action, manager->lid_switch_ignore_inhibited, is_edge);
108}
109
ed4ba7e4
LP
110static int button_recheck(sd_event_source *e, void *userdata) {
111 Button *b = userdata;
beaafb2e 112
ed4ba7e4
LP
113 assert(b);
114 assert(b->lid_closed);
115
3c56cab4 116 button_lid_switch_handle_action(b->manager, false);
ed4ba7e4
LP
117 return 1;
118}
e9d21f24 119
ed4ba7e4
LP
120static int button_install_check_event_source(Button *b) {
121 int r;
e9d21f24
LP
122 assert(b);
123
ed4ba7e4 124 /* Install a post handler, so that we keep rechecking as long as the lid is closed. */
6de0e0e5 125
ed4ba7e4
LP
126 if (b->check_event_source)
127 return 0;
128
129 r = sd_event_add_post(b->manager->event, &b->check_event_source, button_recheck, b);
130 if (r < 0)
131 return r;
132
133 return sd_event_source_set_priority(b->check_event_source, SD_EVENT_PRIORITY_IDLE+1);
e9d21f24
LP
134}
135
cc377381
LP
136static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
137 Button *b = userdata;
e9d21f24
LP
138 struct input_event ev;
139 ssize_t l;
140
cc377381
LP
141 assert(s);
142 assert(fd == b->fd);
e9d21f24
LP
143 assert(b);
144
145 l = read(b->fd, &ev, sizeof(ev));
146 if (l < 0)
147 return errno != EAGAIN ? -errno : 0;
148 if ((size_t) l < sizeof(ev))
149 return -EIO;
150
e9d21f24
LP
151 if (ev.type == EV_KEY && ev.value > 0) {
152
153 switch (ev.code) {
154
155 case KEY_POWER:
156 case KEY_POWER2:
c485437f 157 log_struct(LOG_INFO,
e2cc6eca
LP
158 LOG_MESSAGE("Power key pressed."),
159 LOG_MESSAGE_ID(SD_MESSAGE_POWER_KEY),
c485437f 160 NULL);
7b77ed8c 161
ed4ba7e4 162 manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
7b77ed8c 163 break;
e9d21f24 164
8e7fd6ad
LP
165 /* The kernel is a bit confused here:
166
167 KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend"
168 KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
169 */
170
e9d21f24 171 case KEY_SLEEP:
c485437f 172 log_struct(LOG_INFO,
e2cc6eca
LP
173 LOG_MESSAGE("Suspend key pressed."),
174 LOG_MESSAGE_ID(SD_MESSAGE_SUSPEND_KEY),
c485437f 175 NULL);
7b77ed8c 176
ed4ba7e4 177 manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
7b77ed8c 178 break;
e9d21f24 179
8e7fd6ad 180 case KEY_SUSPEND:
c485437f 181 log_struct(LOG_INFO,
e2cc6eca
LP
182 LOG_MESSAGE("Hibernate key pressed."),
183 LOG_MESSAGE_ID(SD_MESSAGE_HIBERNATE_KEY),
c485437f 184 NULL);
7b77ed8c 185
ed4ba7e4 186 manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
7b77ed8c 187 break;
e9d21f24 188 }
8e7fd6ad 189
e9d21f24
LP
190 } else if (ev.type == EV_SW && ev.value > 0) {
191
7b77ed8c 192 if (ev.code == SW_LID) {
c485437f 193 log_struct(LOG_INFO,
e2cc6eca
LP
194 LOG_MESSAGE("Lid closed."),
195 LOG_MESSAGE_ID(SD_MESSAGE_LID_CLOSED),
c485437f 196 NULL);
65b51162 197
ed4ba7e4 198 b->lid_closed = true;
3c56cab4 199 button_lid_switch_handle_action(b->manager, true);
ed4ba7e4 200 button_install_check_event_source(b);
2d62c530
LP
201
202 } else if (ev.code == SW_DOCK) {
203 log_struct(LOG_INFO,
e2cc6eca
LP
204 LOG_MESSAGE("System docked."),
205 LOG_MESSAGE_ID(SD_MESSAGE_SYSTEM_DOCKED),
2d62c530
LP
206 NULL);
207
208 b->docked = true;
65b51162
LP
209 }
210
211 } else if (ev.type == EV_SW && ev.value == 0) {
212
7b77ed8c 213 if (ev.code == SW_LID) {
c485437f 214 log_struct(LOG_INFO,
e2cc6eca
LP
215 LOG_MESSAGE("Lid opened."),
216 LOG_MESSAGE_ID(SD_MESSAGE_LID_OPENED),
c485437f 217 NULL);
7b77ed8c 218
ed4ba7e4
LP
219 b->lid_closed = false;
220 b->check_event_source = sd_event_source_unref(b->check_event_source);
2d62c530
LP
221
222 } else if (ev.code == SW_DOCK) {
223 log_struct(LOG_INFO,
e2cc6eca
LP
224 LOG_MESSAGE("System undocked."),
225 LOG_MESSAGE_ID(SD_MESSAGE_SYSTEM_UNDOCKED),
2d62c530
LP
226 NULL);
227
228 b->docked = false;
e9d21f24
LP
229 }
230 }
231
232 return 0;
233}
234
cc377381
LP
235int button_open(Button *b) {
236 char *p, name[256];
237 int r;
238
239 assert(b);
240
7f6e12b0 241 b->fd = safe_close(b->fd);
cc377381 242
63c372cb 243 p = strjoina("/dev/input/", b->name);
cc377381
LP
244
245 b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
4a62c710
MS
246 if (b->fd < 0)
247 return log_warning_errno(errno, "Failed to open %s: %m", b->name);
cc377381
LP
248
249 if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
76ef789d 250 r = log_error_errno(errno, "Failed to get input name: %m");
cc377381
LP
251 goto fail;
252 }
253
ed4ba7e4 254 r = sd_event_add_io(b->manager->event, &b->io_event_source, b->fd, EPOLLIN, button_dispatch, b);
cc377381 255 if (r < 0) {
da927ba9 256 log_error_errno(r, "Failed to add button event: %m");
cc377381
LP
257 goto fail;
258 }
259
260 log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name);
261
262 return 0;
263
264fail:
66e40583 265 b->fd = safe_close(b->fd);
cc377381
LP
266 return r;
267}
268
2d62c530 269int button_check_switches(Button *b) {
ed4ba7e4 270 uint8_t switches[SW_MAX/8+1] = {};
65b51162
LP
271 assert(b);
272
ed4ba7e4
LP
273 if (b->fd < 0)
274 return -EINVAL;
275
276 if (ioctl(b->fd, EVIOCGSW(sizeof(switches)), switches) < 0)
277 return -errno;
65b51162 278
ed4ba7e4 279 b->lid_closed = (switches[SW_LID/8] >> (SW_LID % 8)) & 1;
2d62c530 280 b->docked = (switches[SW_DOCK/8] >> (SW_DOCK % 8)) & 1;
ed4ba7e4 281
2d62c530 282 if (b->lid_closed)
ed4ba7e4 283 button_install_check_event_source(b);
ed4ba7e4
LP
284
285 return 0;
65b51162 286}