]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-button.c
update TODO
[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
22#include <assert.h>
23#include <string.h>
24#include <errno.h>
25#include <fcntl.h>
26#include <sys/ioctl.h>
27#include <unistd.h>
28#include <linux/input.h>
e9d21f24 29
cc377381 30#include "sd-messages.h"
e9d21f24
LP
31#include "conf-parser.h"
32#include "util.h"
e9d21f24 33#include "special.h"
cc377381 34#include "logind-button.h"
e9d21f24
LP
35
36Button* button_new(Manager *m, const char *name) {
37 Button *b;
38
39 assert(m);
40 assert(name);
41
42 b = new0(Button, 1);
43 if (!b)
44 return NULL;
45
46 b->name = strdup(name);
47 if (!b->name) {
48 free(b);
49 return NULL;
50 }
51
52 if (hashmap_put(m->buttons, b->name, b) < 0) {
53 free(b->name);
54 free(b);
55 return NULL;
56 }
57
58 b->manager = m;
59 b->fd = -1;
60
61 return b;
62}
63
64void button_free(Button *b) {
65 assert(b);
66
67 hashmap_remove(b->manager->buttons, b->name);
68
ed4ba7e4
LP
69 sd_event_source_unref(b->io_event_source);
70 sd_event_source_unref(b->check_event_source);
c30a0c62 71
cc377381 72 if (b->fd >= 0) {
c30a0c62
LP
73 /* If the device has been unplugged close() returns
74 * ENODEV, let's ignore this, hence we don't use
75 * close_nointr_nofail() */
76 close(b->fd);
e9d21f24
LP
77 }
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
ed4ba7e4
LP
100static int button_recheck(sd_event_source *e, void *userdata) {
101 Button *b = userdata;
beaafb2e 102
ed4ba7e4
LP
103 assert(b);
104 assert(b->lid_closed);
105
106 manager_handle_action(b->manager, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, false);
107 return 1;
108}
e9d21f24 109
ed4ba7e4
LP
110static int button_install_check_event_source(Button *b) {
111 int r;
e9d21f24
LP
112 assert(b);
113
ed4ba7e4 114 /* Install a post handler, so that we keep rechecking as long as the lid is closed. */
6de0e0e5 115
ed4ba7e4
LP
116 if (b->check_event_source)
117 return 0;
118
119 r = sd_event_add_post(b->manager->event, &b->check_event_source, button_recheck, b);
120 if (r < 0)
121 return r;
122
123 return sd_event_source_set_priority(b->check_event_source, SD_EVENT_PRIORITY_IDLE+1);
e9d21f24
LP
124}
125
cc377381
LP
126static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
127 Button *b = userdata;
e9d21f24
LP
128 struct input_event ev;
129 ssize_t l;
130
cc377381
LP
131 assert(s);
132 assert(fd == b->fd);
e9d21f24
LP
133 assert(b);
134
135 l = read(b->fd, &ev, sizeof(ev));
136 if (l < 0)
137 return errno != EAGAIN ? -errno : 0;
138 if ((size_t) l < sizeof(ev))
139 return -EIO;
140
e9d21f24
LP
141 if (ev.type == EV_KEY && ev.value > 0) {
142
143 switch (ev.code) {
144
145 case KEY_POWER:
146 case KEY_POWER2:
c485437f
ZJS
147 log_struct(LOG_INFO,
148 "MESSAGE=Power key pressed.",
149 MESSAGE_ID(SD_MESSAGE_POWER_KEY),
150 NULL);
7b77ed8c 151
ed4ba7e4 152 manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
7b77ed8c 153 break;
e9d21f24 154
8e7fd6ad
LP
155 /* The kernel is a bit confused here:
156
157 KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend"
158 KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
159 */
160
e9d21f24 161 case KEY_SLEEP:
c485437f
ZJS
162 log_struct(LOG_INFO,
163 "MESSAGE=Suspend key pressed.",
164 MESSAGE_ID(SD_MESSAGE_SUSPEND_KEY),
165 NULL);
7b77ed8c 166
ed4ba7e4 167 manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
7b77ed8c 168 break;
e9d21f24 169
8e7fd6ad 170 case KEY_SUSPEND:
c485437f
ZJS
171 log_struct(LOG_INFO,
172 "MESSAGE=Hibernate key pressed.",
173 MESSAGE_ID(SD_MESSAGE_HIBERNATE_KEY),
174 NULL);
7b77ed8c 175
ed4ba7e4 176 manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
7b77ed8c 177 break;
e9d21f24 178 }
8e7fd6ad 179
e9d21f24
LP
180 } else if (ev.type == EV_SW && ev.value > 0) {
181
7b77ed8c 182 if (ev.code == SW_LID) {
c485437f
ZJS
183 log_struct(LOG_INFO,
184 "MESSAGE=Lid closed.",
185 MESSAGE_ID(SD_MESSAGE_LID_CLOSED),
186 NULL);
65b51162 187
ed4ba7e4
LP
188 b->lid_closed = true;
189 manager_handle_action(b->manager, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, true);
190 button_install_check_event_source(b);
65b51162
LP
191 }
192
193 } else if (ev.type == EV_SW && ev.value == 0) {
194
7b77ed8c 195 if (ev.code == SW_LID) {
c485437f
ZJS
196 log_struct(LOG_INFO,
197 "MESSAGE=Lid opened.",
198 MESSAGE_ID(SD_MESSAGE_LID_OPENED),
199 NULL);
7b77ed8c 200
ed4ba7e4
LP
201 b->lid_closed = false;
202 b->check_event_source = sd_event_source_unref(b->check_event_source);
e9d21f24
LP
203 }
204 }
205
206 return 0;
207}
208
cc377381
LP
209int button_open(Button *b) {
210 char *p, name[256];
211 int r;
212
213 assert(b);
214
215 if (b->fd >= 0) {
216 close(b->fd);
217 b->fd = -1;
218 }
219
220 p = strappenda("/dev/input/", b->name);
221
222 b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
223 if (b->fd < 0) {
224 log_warning("Failed to open %s: %m", b->name);
225 return -errno;
226 }
227
228 if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
229 log_error("Failed to get input name: %m");
230 r = -errno;
231 goto fail;
232 }
233
ed4ba7e4 234 r = sd_event_add_io(b->manager->event, &b->io_event_source, b->fd, EPOLLIN, button_dispatch, b);
cc377381
LP
235 if (r < 0) {
236 log_error("Failed to add button event: %s", strerror(-r));
237 goto fail;
238 }
239
240 log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name);
241
242 return 0;
243
244fail:
245 close(b->fd);
246 b->fd = -1;
247 return r;
248}
249
ed4ba7e4
LP
250int button_check_lid(Button *b) {
251 uint8_t switches[SW_MAX/8+1] = {};
65b51162
LP
252 assert(b);
253
ed4ba7e4
LP
254 if (b->fd < 0)
255 return -EINVAL;
256
257 if (ioctl(b->fd, EVIOCGSW(sizeof(switches)), switches) < 0)
258 return -errno;
65b51162 259
ed4ba7e4
LP
260 b->lid_closed = (switches[SW_LID/8] >> (SW_LID % 8)) & 1;
261
262 if (b->lid_closed) {
263 manager_handle_action(b->manager, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, true);
264 button_install_check_event_source(b);
265 }
266
267 return 0;
65b51162 268}