chiark / gitweb /
Prep v236 : Add missing SPDX-License-Identifier (5/9) src/login
[elogind.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 }