]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-button.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / login / logind-button.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2012 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <sys/ioctl.h>
25 #include <unistd.h>
26 #include <linux/input.h>
27
28 #include "sd-messages.h"
29
30 #include "alloc-util.h"
31 #include "fd-util.h"
32 #include "logind-button.h"
33 #include "string-util.h"
34 #include "util.h"
35
36 #define CONST_MAX4(a, b, c, d) CONST_MAX(CONST_MAX(a, b), CONST_MAX(c, d))
37
38 #define ULONG_BITS (sizeof(unsigned long)*8)
39
40 static bool bitset_get(const unsigned long *bits, unsigned i) {
41 return (bits[i / ULONG_BITS] >> (i % ULONG_BITS)) & 1UL;
42 }
43
44 static void bitset_put(unsigned long *bits, unsigned i) {
45 bits[i / ULONG_BITS] |= (unsigned long) 1 << (i % ULONG_BITS);
46 }
47
48 Button* button_new(Manager *m, const char *name) {
49 Button *b;
50
51 assert(m);
52 assert(name);
53
54 b = new0(Button, 1);
55 if (!b)
56 return NULL;
57
58 b->name = strdup(name);
59 if (!b->name)
60 return mfree(b);
61
62 if (hashmap_put(m->buttons, b->name, b) < 0) {
63 free(b->name);
64 return mfree(b);
65 }
66
67 b->manager = m;
68 b->fd = -1;
69
70 return b;
71 }
72
73 void button_free(Button *b) {
74 assert(b);
75
76 hashmap_remove(b->manager->buttons, b->name);
77
78 sd_event_source_unref(b->io_event_source);
79 sd_event_source_unref(b->check_event_source);
80
81 if (b->fd >= 0)
82 /* If the device has been unplugged close() returns
83 * ENODEV, let's ignore this, hence we don't use
84 * safe_close() */
85 (void) close(b->fd);
86
87 free(b->name);
88 free(b->seat);
89 free(b);
90 }
91
92 int button_set_seat(Button *b, const char *sn) {
93 char *s;
94
95 assert(b);
96 assert(sn);
97
98 s = strdup(sn);
99 if (!s)
100 return -ENOMEM;
101
102 free(b->seat);
103 b->seat = s;
104
105 return 0;
106 }
107
108 static void button_lid_switch_handle_action(Manager *manager, bool is_edge) {
109 HandleAction handle_action;
110
111 assert(manager);
112
113 /* If we are docked, handle the lid switch differently */
114 if (manager_is_docked_or_external_displays(manager))
115 handle_action = manager->handle_lid_switch_docked;
116 else
117 handle_action = manager->handle_lid_switch;
118
119 manager_handle_action(manager, INHIBIT_HANDLE_LID_SWITCH, handle_action, manager->lid_switch_ignore_inhibited, is_edge);
120 }
121
122 static int button_recheck(sd_event_source *e, void *userdata) {
123 Button *b = userdata;
124
125 assert(b);
126 assert(b->lid_closed);
127
128 button_lid_switch_handle_action(b->manager, false);
129 return 1;
130 }
131
132 static int button_install_check_event_source(Button *b) {
133 int r;
134 assert(b);
135
136 /* Install a post handler, so that we keep rechecking as long as the lid is closed. */
137
138 if (b->check_event_source)
139 return 0;
140
141 r = sd_event_add_post(b->manager->event, &b->check_event_source, button_recheck, b);
142 if (r < 0)
143 return r;
144
145 return sd_event_source_set_priority(b->check_event_source, SD_EVENT_PRIORITY_IDLE+1);
146 }
147
148 static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
149 Button *b = userdata;
150 struct input_event ev;
151 ssize_t l;
152
153 assert(s);
154 assert(fd == b->fd);
155 assert(b);
156
157 l = read(b->fd, &ev, sizeof(ev));
158 if (l < 0)
159 return errno != EAGAIN ? -errno : 0;
160 if ((size_t) l < sizeof(ev))
161 return -EIO;
162
163 if (ev.type == EV_KEY && ev.value > 0) {
164
165 switch (ev.code) {
166
167 case KEY_POWER:
168 case KEY_POWER2:
169 log_struct(LOG_INFO,
170 LOG_MESSAGE("Power key pressed."),
171 "MESSAGE_ID=" SD_MESSAGE_POWER_KEY_STR,
172 NULL);
173
174 manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
175 break;
176
177 /* The kernel is a bit confused here:
178
179 KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend"
180 KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
181 */
182
183 case KEY_SLEEP:
184 log_struct(LOG_INFO,
185 LOG_MESSAGE("Suspend key pressed."),
186 "MESSAGE_ID=" SD_MESSAGE_SUSPEND_KEY_STR,
187 NULL);
188
189 manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
190 break;
191
192 case KEY_SUSPEND:
193 log_struct(LOG_INFO,
194 LOG_MESSAGE("Hibernate key pressed."),
195 "MESSAGE_ID=" SD_MESSAGE_HIBERNATE_KEY_STR,
196 NULL);
197
198 manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
199 break;
200 }
201
202 } else if (ev.type == EV_SW && ev.value > 0) {
203
204 if (ev.code == SW_LID) {
205 log_struct(LOG_INFO,
206 LOG_MESSAGE("Lid closed."),
207 "MESSAGE_ID=" SD_MESSAGE_LID_CLOSED_STR,
208 NULL);
209
210 b->lid_closed = true;
211 button_lid_switch_handle_action(b->manager, true);
212 button_install_check_event_source(b);
213
214 } else if (ev.code == SW_DOCK) {
215 log_struct(LOG_INFO,
216 LOG_MESSAGE("System docked."),
217 "MESSAGE_ID=" SD_MESSAGE_SYSTEM_DOCKED_STR,
218 NULL);
219
220 b->docked = true;
221 }
222
223 } else if (ev.type == EV_SW && ev.value == 0) {
224
225 if (ev.code == SW_LID) {
226 log_struct(LOG_INFO,
227 LOG_MESSAGE("Lid opened."),
228 "MESSAGE_ID=" SD_MESSAGE_LID_OPENED_STR,
229 NULL);
230
231 b->lid_closed = false;
232 b->check_event_source = sd_event_source_unref(b->check_event_source);
233
234 } else if (ev.code == SW_DOCK) {
235 log_struct(LOG_INFO,
236 LOG_MESSAGE("System undocked."),
237 "MESSAGE_ID=" SD_MESSAGE_SYSTEM_UNDOCKED_STR,
238 NULL);
239
240 b->docked = false;
241 }
242 }
243
244 return 0;
245 }
246
247 static int button_suitable(Button *b) {
248 unsigned long types[CONST_MAX(EV_KEY, EV_SW)/ULONG_BITS+1];
249
250 assert(b);
251 assert(b->fd);
252
253 if (ioctl(b->fd, EVIOCGBIT(EV_SYN, sizeof(types)), types) < 0)
254 return -errno;
255
256 if (bitset_get(types, EV_KEY)) {
257 unsigned long keys[CONST_MAX4(KEY_POWER, KEY_POWER2, KEY_SLEEP, KEY_SUSPEND)/ULONG_BITS+1];
258
259 if (ioctl(b->fd, EVIOCGBIT(EV_KEY, sizeof(keys)), keys) < 0)
260 return -errno;
261
262 if (bitset_get(keys, KEY_POWER) ||
263 bitset_get(keys, KEY_POWER2) ||
264 bitset_get(keys, KEY_SLEEP) ||
265 bitset_get(keys, KEY_SUSPEND))
266 return true;
267 }
268
269 if (bitset_get(types, EV_SW)) {
270 unsigned long switches[CONST_MAX(SW_LID, SW_DOCK)/ULONG_BITS+1];
271
272 if (ioctl(b->fd, EVIOCGBIT(EV_SW, sizeof(switches)), switches) < 0)
273 return -errno;
274
275 if (bitset_get(switches, SW_LID) ||
276 bitset_get(switches, SW_DOCK))
277 return true;
278 }
279
280 return false;
281 }
282
283 static int button_set_mask(Button *b) {
284 unsigned long
285 types[CONST_MAX(EV_KEY, EV_SW)/ULONG_BITS+1] = {},
286 keys[CONST_MAX4(KEY_POWER, KEY_POWER2, KEY_SLEEP, KEY_SUSPEND)/ULONG_BITS+1] = {},
287 switches[CONST_MAX(SW_LID, SW_DOCK)/ULONG_BITS+1] = {};
288 struct input_mask mask;
289
290 assert(b);
291 assert(b->fd >= 0);
292
293 bitset_put(types, EV_KEY);
294 bitset_put(types, EV_SW);
295
296 mask = (struct input_mask) {
297 .type = EV_SYN,
298 .codes_size = sizeof(types),
299 .codes_ptr = PTR_TO_UINT64(types),
300 };
301
302 if (ioctl(b->fd, EVIOCSMASK, &mask) < 0)
303 /* Log only at debug level if the kernel doesn't do EVIOCSMASK yet */
304 return log_full_errno(IN_SET(errno, ENOTTY, EOPNOTSUPP, EINVAL) ? LOG_DEBUG : LOG_WARNING,
305 errno, "Failed to set EV_SYN event mask on /dev/input/%s: %m", b->name);
306
307 bitset_put(keys, KEY_POWER);
308 bitset_put(keys, KEY_POWER2);
309 bitset_put(keys, KEY_SLEEP);
310 bitset_put(keys, KEY_SUSPEND);
311
312 mask = (struct input_mask) {
313 .type = EV_KEY,
314 .codes_size = sizeof(keys),
315 .codes_ptr = PTR_TO_UINT64(keys),
316 };
317
318 if (ioctl(b->fd, EVIOCSMASK, &mask) < 0)
319 return log_warning_errno(errno, "Failed to set EV_KEY event mask on /dev/input/%s: %m", b->name);
320
321 bitset_put(switches, SW_LID);
322 bitset_put(switches, SW_DOCK);
323
324 mask = (struct input_mask) {
325 .type = EV_SW,
326 .codes_size = sizeof(switches),
327 .codes_ptr = PTR_TO_UINT64(switches),
328 };
329
330 if (ioctl(b->fd, EVIOCSMASK, &mask) < 0)
331 return log_warning_errno(errno, "Failed to set EV_SW event mask on /dev/input/%s: %m", b->name);
332
333 return 0;
334 }
335
336 int button_open(Button *b) {
337 char *p, name[256];
338 int r;
339
340 assert(b);
341
342 b->fd = safe_close(b->fd);
343
344 p = strjoina("/dev/input/", b->name);
345
346 b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
347 if (b->fd < 0)
348 return log_warning_errno(errno, "Failed to open %s: %m", p);
349
350 r = button_suitable(b);
351 if (r < 0)
352 return log_warning_errno(r, "Failed to determine whether input device is relevant to us: %m");
353 if (r == 0) {
354 log_debug("Device %s does not expose keys or switches relevant to us, ignoring.", p);
355 return -EADDRNOTAVAIL;
356 }
357
358 if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
359 r = log_error_errno(errno, "Failed to get input name: %m");
360 goto fail;
361 }
362
363 (void) button_set_mask(b);
364
365 r = sd_event_add_io(b->manager->event, &b->io_event_source, b->fd, EPOLLIN, button_dispatch, b);
366 if (r < 0) {
367 log_error_errno(r, "Failed to add button event: %m");
368 goto fail;
369 }
370
371 log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name);
372
373 return 0;
374
375 fail:
376 b->fd = safe_close(b->fd);
377 return r;
378 }
379
380 int button_check_switches(Button *b) {
381 unsigned long switches[CONST_MAX(SW_LID, SW_DOCK)/ULONG_BITS+1] = {};
382 assert(b);
383
384 if (b->fd < 0)
385 return -EINVAL;
386
387 if (ioctl(b->fd, EVIOCGSW(sizeof(switches)), switches) < 0)
388 return -errno;
389
390 b->lid_closed = bitset_get(switches, SW_LID);
391 b->docked = bitset_get(switches, SW_DOCK);
392
393 if (b->lid_closed)
394 button_install_check_event_source(b);
395
396 return 0;
397 }