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