]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-button.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / login / logind-button.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <sys/ioctl.h>
6 #include <unistd.h>
7
8 #include "sd-messages.h"
9
10 #include "alloc-util.h"
11 #include "async.h"
12 #include "fd-util.h"
13 #include "logind-button.h"
14 #include "missing_input.h"
15 #include "string-util.h"
16 #include "util.h"
17
18 #define CONST_MAX5(a, b, c, d, e) CONST_MAX(CONST_MAX(a, b), CONST_MAX(CONST_MAX(c, d), e))
19
20 #define ULONG_BITS (sizeof(unsigned long)*8)
21
22 #define LONG_PRESS_DURATION (5 * USEC_PER_SEC)
23
24 static bool bitset_get(const unsigned long *bits, unsigned i) {
25 return (bits[i / ULONG_BITS] >> (i % ULONG_BITS)) & 1UL;
26 }
27
28 static void bitset_put(unsigned long *bits, unsigned i) {
29 bits[i / ULONG_BITS] |= (unsigned long) 1 << (i % ULONG_BITS);
30 }
31
32 Button* button_new(Manager *m, const char *name) {
33 Button *b;
34
35 assert(m);
36 assert(name);
37
38 b = new0(Button, 1);
39 if (!b)
40 return NULL;
41
42 b->name = strdup(name);
43 if (!b->name)
44 return mfree(b);
45
46 if (hashmap_put(m->buttons, b->name, b) < 0) {
47 free(b->name);
48 return mfree(b);
49 }
50
51 b->manager = m;
52 b->fd = -1;
53
54 return b;
55 }
56
57 void button_free(Button *b) {
58 assert(b);
59
60 hashmap_remove(b->manager->buttons, b->name);
61
62 sd_event_source_unref(b->io_event_source);
63 sd_event_source_unref(b->check_event_source);
64
65 asynchronous_close(b->fd);
66
67 free(b->name);
68 free(b->seat);
69 free(b);
70 }
71
72 int button_set_seat(Button *b, const char *sn) {
73 assert(b);
74
75 return free_and_strdup(&b->seat, sn);
76 }
77
78 static void button_lid_switch_handle_action(Manager *manager, bool is_edge) {
79 HandleAction handle_action;
80
81 assert(manager);
82
83 /* If we are docked or on external power, handle the lid switch
84 * differently */
85 if (manager_is_docked_or_external_displays(manager))
86 handle_action = manager->handle_lid_switch_docked;
87 else if (handle_action_valid(manager->handle_lid_switch_ep) && manager_is_on_external_power())
88 handle_action = manager->handle_lid_switch_ep;
89 else
90 handle_action = manager->handle_lid_switch;
91
92 manager_handle_action(manager, INHIBIT_HANDLE_LID_SWITCH, handle_action, manager->lid_switch_ignore_inhibited, is_edge);
93 }
94
95 static int button_recheck(sd_event_source *e, void *userdata) {
96 Button *b = ASSERT_PTR(userdata);
97
98 assert(b->lid_closed);
99
100 button_lid_switch_handle_action(b->manager, false);
101 return 1;
102 }
103
104 static int button_install_check_event_source(Button *b) {
105 int r;
106 assert(b);
107
108 /* Install a post handler, so that we keep rechecking as long as the lid is closed. */
109
110 if (b->check_event_source)
111 return 0;
112
113 r = sd_event_add_post(b->manager->event, &b->check_event_source, button_recheck, b);
114 if (r < 0)
115 return r;
116
117 return sd_event_source_set_priority(b->check_event_source, SD_EVENT_PRIORITY_IDLE+1);
118 }
119
120 static int long_press_of_power_key_handler(sd_event_source *e, uint64_t usec, void *userdata) {
121 Manager *m = ASSERT_PTR(userdata);
122
123 assert(e);
124
125 m->power_key_long_press_event_source = sd_event_source_unref(m->power_key_long_press_event_source);
126
127 log_struct(LOG_INFO,
128 LOG_MESSAGE("Power key pressed long."),
129 "MESSAGE_ID=" SD_MESSAGE_POWER_KEY_LONG_PRESS_STR);
130
131 manager_handle_action(m, INHIBIT_HANDLE_POWER_KEY, m->handle_power_key_long_press, m->power_key_ignore_inhibited, true);
132 return 0;
133 }
134
135 static int long_press_of_reboot_key_handler(sd_event_source *e, uint64_t usec, void *userdata) {
136 Manager *m = ASSERT_PTR(userdata);
137
138 assert(e);
139
140 m->reboot_key_long_press_event_source = sd_event_source_unref(m->reboot_key_long_press_event_source);
141
142 log_struct(LOG_INFO,
143 LOG_MESSAGE("Reboot key pressed long."),
144 "MESSAGE_ID=" SD_MESSAGE_REBOOT_KEY_LONG_PRESS_STR);
145
146 manager_handle_action(m, INHIBIT_HANDLE_REBOOT_KEY, m->handle_reboot_key_long_press, m->reboot_key_ignore_inhibited, true);
147 return 0;
148 }
149
150 static int long_press_of_suspend_key_handler(sd_event_source *e, uint64_t usec, void *userdata) {
151 Manager *m = ASSERT_PTR(userdata);
152
153 assert(e);
154
155 m->suspend_key_long_press_event_source = sd_event_source_unref(m->suspend_key_long_press_event_source);
156
157 log_struct(LOG_INFO,
158 LOG_MESSAGE("Suspend key pressed long."),
159 "MESSAGE_ID=" SD_MESSAGE_SUSPEND_KEY_LONG_PRESS_STR);
160
161 manager_handle_action(m, INHIBIT_HANDLE_SUSPEND_KEY, m->handle_suspend_key_long_press, m->suspend_key_ignore_inhibited, true);
162 return 0;
163 }
164
165 static int long_press_of_hibernate_key_handler(sd_event_source *e, uint64_t usec, void *userdata) {
166 Manager *m = ASSERT_PTR(userdata);
167
168 assert(e);
169
170 m->hibernate_key_long_press_event_source = sd_event_source_unref(m->hibernate_key_long_press_event_source);
171
172 log_struct(LOG_INFO,
173 LOG_MESSAGE("Hibernate key pressed long."),
174 "MESSAGE_ID=" SD_MESSAGE_HIBERNATE_KEY_LONG_PRESS_STR);
175
176 manager_handle_action(m, INHIBIT_HANDLE_HIBERNATE_KEY, m->handle_hibernate_key_long_press, m->hibernate_key_ignore_inhibited, true);
177 return 0;
178 }
179
180 static void start_long_press(Manager *m, sd_event_source **e, sd_event_time_handler_t callback) {
181 int r;
182
183 assert(m);
184 assert(e);
185
186 if (*e)
187 return;
188
189 r = sd_event_add_time_relative(
190 m->event,
191 e,
192 CLOCK_MONOTONIC,
193 LONG_PRESS_DURATION, 0,
194 callback, m);
195 if (r < 0)
196 log_warning_errno(r, "Failed to add long press timer event, ignoring: %m");
197 }
198
199 static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
200 Button *b = ASSERT_PTR(userdata);
201 struct input_event ev;
202 ssize_t l;
203
204 assert(s);
205 assert(fd == b->fd);
206
207 l = read(b->fd, &ev, sizeof(ev));
208 if (l < 0)
209 return errno != EAGAIN ? -errno : 0;
210 if ((size_t) l < sizeof(ev))
211 return -EIO;
212
213 if (ev.type == EV_KEY && ev.value > 0) {
214
215 switch (ev.code) {
216
217 case KEY_POWER:
218 case KEY_POWER2:
219 if (b->manager->handle_power_key_long_press != HANDLE_IGNORE && b->manager->handle_power_key_long_press != b->manager->handle_power_key) {
220 log_debug("Power key pressed. Further action depends on the key press duration.");
221 start_long_press(b->manager, &b->manager->power_key_long_press_event_source, long_press_of_power_key_handler);
222 } else {
223 log_struct(LOG_INFO,
224 LOG_MESSAGE("Power key pressed short."),
225 "MESSAGE_ID=" SD_MESSAGE_POWER_KEY_STR);
226 manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
227 }
228 break;
229
230 /* The kernel naming is a bit confusing here:
231 KEY_RESTART was probably introduced for media playback purposes, but
232 is now being predominantly used to indicate device reboot.
233 */
234
235 case KEY_RESTART:
236 if (b->manager->handle_reboot_key_long_press != HANDLE_IGNORE && b->manager->handle_reboot_key_long_press != b->manager->handle_reboot_key) {
237 log_debug("Reboot key pressed. Further action depends on the key press duration.");
238 start_long_press(b->manager, &b->manager->reboot_key_long_press_event_source, long_press_of_reboot_key_handler);
239 } else {
240 log_struct(LOG_INFO,
241 LOG_MESSAGE("Reboot key pressed short."),
242 "MESSAGE_ID=" SD_MESSAGE_REBOOT_KEY_STR);
243 manager_handle_action(b->manager, INHIBIT_HANDLE_REBOOT_KEY, b->manager->handle_reboot_key, b->manager->reboot_key_ignore_inhibited, true);
244 }
245 break;
246
247 /* The kernel naming is a bit confusing here:
248
249 KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend"
250 KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
251 */
252
253 case KEY_SLEEP:
254 if (b->manager->handle_suspend_key_long_press != HANDLE_IGNORE && b->manager->handle_suspend_key_long_press != b->manager->handle_suspend_key) {
255 log_debug("Suspend key pressed. Further action depends on the key press duration.");
256 start_long_press(b->manager, &b->manager->suspend_key_long_press_event_source, long_press_of_suspend_key_handler);
257 } else {
258 log_struct(LOG_INFO,
259 LOG_MESSAGE("Suspend key pressed short."),
260 "MESSAGE_ID=" SD_MESSAGE_SUSPEND_KEY_STR);
261 manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
262 }
263 break;
264
265 case KEY_SUSPEND:
266 if (b->manager->handle_hibernate_key_long_press != HANDLE_IGNORE && b->manager->handle_hibernate_key_long_press != b->manager->handle_hibernate_key) {
267 log_debug("Hibernate key pressed. Further action depends on the key press duration.");
268 start_long_press(b->manager, &b->manager->hibernate_key_long_press_event_source, long_press_of_hibernate_key_handler);
269 } else {
270 log_struct(LOG_INFO,
271 LOG_MESSAGE("Hibernate key pressed short."),
272 "MESSAGE_ID=" SD_MESSAGE_HIBERNATE_KEY_STR);
273 manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
274 }
275 break;
276 }
277
278 } else if (ev.type == EV_KEY && ev.value == 0) {
279
280 switch (ev.code) {
281
282 case KEY_POWER:
283 case KEY_POWER2:
284 if (b->manager->power_key_long_press_event_source) {
285 /* Long press event timer is still pending and key release
286 event happened. This means that key press duration was
287 insufficient to trigger a long press event
288 */
289 log_struct(LOG_INFO,
290 LOG_MESSAGE("Power key pressed short."),
291 "MESSAGE_ID=" SD_MESSAGE_POWER_KEY_STR);
292
293 b->manager->power_key_long_press_event_source = sd_event_source_unref(b->manager->power_key_long_press_event_source);
294
295 manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
296 }
297 break;
298
299 case KEY_RESTART:
300 if (b->manager->reboot_key_long_press_event_source) {
301 log_struct(LOG_INFO,
302 LOG_MESSAGE("Reboot key pressed short."),
303 "MESSAGE_ID=" SD_MESSAGE_REBOOT_KEY_STR);
304
305 b->manager->reboot_key_long_press_event_source = sd_event_source_unref(b->manager->reboot_key_long_press_event_source);
306
307 manager_handle_action(b->manager, INHIBIT_HANDLE_REBOOT_KEY, b->manager->handle_reboot_key, b->manager->reboot_key_ignore_inhibited, true);
308 }
309 break;
310
311 case KEY_SLEEP:
312 if (b->manager->suspend_key_long_press_event_source) {
313 log_struct(LOG_INFO,
314 LOG_MESSAGE("Suspend key pressed short."),
315 "MESSAGE_ID=" SD_MESSAGE_SUSPEND_KEY_STR);
316
317 b->manager->suspend_key_long_press_event_source = sd_event_source_unref(b->manager->suspend_key_long_press_event_source);
318
319 manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
320 }
321 break;
322 case KEY_SUSPEND:
323 if (b->manager->hibernate_key_long_press_event_source) {
324 log_struct(LOG_INFO,
325 LOG_MESSAGE("Hibernate key pressed short."),
326 "MESSAGE_ID=" SD_MESSAGE_HIBERNATE_KEY_STR);
327
328 b->manager->hibernate_key_long_press_event_source = sd_event_source_unref(b->manager->hibernate_key_long_press_event_source);
329
330 manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
331 }
332 break;
333 }
334
335 } else if (ev.type == EV_SW && ev.value > 0) {
336
337 if (ev.code == SW_LID) {
338 log_struct(LOG_INFO,
339 LOG_MESSAGE("Lid closed."),
340 "MESSAGE_ID=" SD_MESSAGE_LID_CLOSED_STR);
341
342 b->lid_closed = true;
343 button_lid_switch_handle_action(b->manager, true);
344 button_install_check_event_source(b);
345
346 } else if (ev.code == SW_DOCK) {
347 log_struct(LOG_INFO,
348 LOG_MESSAGE("System docked."),
349 "MESSAGE_ID=" SD_MESSAGE_SYSTEM_DOCKED_STR);
350
351 b->docked = true;
352 }
353
354 } else if (ev.type == EV_SW && ev.value == 0) {
355
356 if (ev.code == SW_LID) {
357 log_struct(LOG_INFO,
358 LOG_MESSAGE("Lid opened."),
359 "MESSAGE_ID=" SD_MESSAGE_LID_OPENED_STR);
360
361 b->lid_closed = false;
362 b->check_event_source = sd_event_source_unref(b->check_event_source);
363
364 } else if (ev.code == SW_DOCK) {
365 log_struct(LOG_INFO,
366 LOG_MESSAGE("System undocked."),
367 "MESSAGE_ID=" SD_MESSAGE_SYSTEM_UNDOCKED_STR);
368
369 b->docked = false;
370 }
371 }
372
373 return 0;
374 }
375
376 static int button_suitable(int fd) {
377 unsigned long types[CONST_MAX(EV_KEY, EV_SW)/ULONG_BITS+1];
378
379 assert(fd >= 0);
380
381 if (ioctl(fd, EVIOCGBIT(EV_SYN, sizeof types), types) < 0)
382 return -errno;
383
384 if (bitset_get(types, EV_KEY)) {
385 unsigned long keys[CONST_MAX5(KEY_POWER, KEY_POWER2, KEY_SLEEP, KEY_SUSPEND, KEY_RESTART)/ULONG_BITS+1];
386
387 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof keys), keys) < 0)
388 return -errno;
389
390 if (bitset_get(keys, KEY_POWER) ||
391 bitset_get(keys, KEY_POWER2) ||
392 bitset_get(keys, KEY_SLEEP) ||
393 bitset_get(keys, KEY_SUSPEND) ||
394 bitset_get(keys, KEY_RESTART))
395 return true;
396 }
397
398 if (bitset_get(types, EV_SW)) {
399 unsigned long switches[CONST_MAX(SW_LID, SW_DOCK)/ULONG_BITS+1];
400
401 if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof switches), switches) < 0)
402 return -errno;
403
404 if (bitset_get(switches, SW_LID) ||
405 bitset_get(switches, SW_DOCK))
406 return true;
407 }
408
409 return false;
410 }
411
412 static int button_set_mask(const char *name, int fd) {
413 unsigned long
414 types[CONST_MAX(EV_KEY, EV_SW)/ULONG_BITS+1] = {},
415 keys[CONST_MAX5(KEY_POWER, KEY_POWER2, KEY_SLEEP, KEY_SUSPEND, KEY_RESTART)/ULONG_BITS+1] = {},
416 switches[CONST_MAX(SW_LID, SW_DOCK)/ULONG_BITS+1] = {};
417 struct input_mask mask;
418
419 assert(name);
420 assert(fd >= 0);
421
422 bitset_put(types, EV_KEY);
423 bitset_put(types, EV_SW);
424
425 mask = (struct input_mask) {
426 .type = EV_SYN,
427 .codes_size = sizeof(types),
428 .codes_ptr = PTR_TO_UINT64(types),
429 };
430
431 if (ioctl(fd, EVIOCSMASK, &mask) < 0)
432 /* Log only at debug level if the kernel doesn't do EVIOCSMASK yet */
433 return log_full_errno(IN_SET(errno, ENOTTY, EOPNOTSUPP, EINVAL) ? LOG_DEBUG : LOG_WARNING,
434 errno, "Failed to set EV_SYN event mask on /dev/input/%s: %m", name);
435
436 bitset_put(keys, KEY_POWER);
437 bitset_put(keys, KEY_POWER2);
438 bitset_put(keys, KEY_SLEEP);
439 bitset_put(keys, KEY_SUSPEND);
440 bitset_put(keys, KEY_RESTART);
441
442 mask = (struct input_mask) {
443 .type = EV_KEY,
444 .codes_size = sizeof(keys),
445 .codes_ptr = PTR_TO_UINT64(keys),
446 };
447
448 if (ioctl(fd, EVIOCSMASK, &mask) < 0)
449 return log_warning_errno(errno, "Failed to set EV_KEY event mask on /dev/input/%s: %m", name);
450
451 bitset_put(switches, SW_LID);
452 bitset_put(switches, SW_DOCK);
453
454 mask = (struct input_mask) {
455 .type = EV_SW,
456 .codes_size = sizeof(switches),
457 .codes_ptr = PTR_TO_UINT64(switches),
458 };
459
460 if (ioctl(fd, EVIOCSMASK, &mask) < 0)
461 return log_warning_errno(errno, "Failed to set EV_SW event mask on /dev/input/%s: %m", name);
462
463 return 0;
464 }
465
466 int button_open(Button *b) {
467 _cleanup_(asynchronous_closep) int fd = -1;
468 const char *p;
469 char name[256];
470 int r;
471
472 assert(b);
473
474 b->fd = asynchronous_close(b->fd);
475
476 p = strjoina("/dev/input/", b->name);
477
478 fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
479 if (fd < 0)
480 return log_warning_errno(errno, "Failed to open %s: %m", p);
481
482 r = button_suitable(fd);
483 if (r < 0)
484 return log_warning_errno(r, "Failed to determine whether input device %s is relevant to us: %m", p);
485 if (r == 0)
486 return log_debug_errno(SYNTHETIC_ERRNO(EADDRNOTAVAIL),
487 "Device %s does not expose keys or switches relevant to us, ignoring.", p);
488
489 if (ioctl(fd, EVIOCGNAME(sizeof name), name) < 0)
490 return log_error_errno(errno, "Failed to get input name for %s: %m", p);
491
492 (void) button_set_mask(b->name, fd);
493
494 b->io_event_source = sd_event_source_unref(b->io_event_source);
495 r = sd_event_add_io(b->manager->event, &b->io_event_source, fd, EPOLLIN, button_dispatch, b);
496 if (r < 0)
497 return log_error_errno(r, "Failed to add button event for %s: %m", p);
498
499 b->fd = TAKE_FD(fd);
500 log_info("Watching system buttons on %s (%s)", p, name);
501 return 0;
502 }
503
504 int button_check_switches(Button *b) {
505 unsigned long switches[CONST_MAX(SW_LID, SW_DOCK)/ULONG_BITS+1] = {};
506 assert(b);
507
508 if (b->fd < 0)
509 return -EINVAL;
510
511 if (ioctl(b->fd, EVIOCGSW(sizeof(switches)), switches) < 0)
512 return -errno;
513
514 b->lid_closed = bitset_get(switches, SW_LID);
515 b->docked = bitset_get(switches, SW_DOCK);
516
517 if (b->lid_closed)
518 button_install_check_event_source(b);
519
520 return 0;
521 }