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