]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-button.c
sd-journal: never log anything by default from a library
[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
03e334a1 75 * safe_close() */
c30a0c62 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);
2d62c530
LP
191
192 } else if (ev.code == SW_DOCK) {
193 log_struct(LOG_INFO,
194 "MESSAGE=System docked.",
195 MESSAGE_ID(SD_MESSAGE_SYSTEM_DOCKED),
196 NULL);
197
198 b->docked = true;
65b51162
LP
199 }
200
201 } else if (ev.type == EV_SW && ev.value == 0) {
202
7b77ed8c 203 if (ev.code == SW_LID) {
c485437f
ZJS
204 log_struct(LOG_INFO,
205 "MESSAGE=Lid opened.",
206 MESSAGE_ID(SD_MESSAGE_LID_OPENED),
207 NULL);
7b77ed8c 208
ed4ba7e4
LP
209 b->lid_closed = false;
210 b->check_event_source = sd_event_source_unref(b->check_event_source);
2d62c530
LP
211
212 } else if (ev.code == SW_DOCK) {
213 log_struct(LOG_INFO,
214 "MESSAGE=System undocked.",
215 MESSAGE_ID(SD_MESSAGE_SYSTEM_UNDOCKED),
216 NULL);
217
218 b->docked = false;
e9d21f24
LP
219 }
220 }
221
222 return 0;
223}
224
cc377381
LP
225int button_open(Button *b) {
226 char *p, name[256];
227 int r;
228
229 assert(b);
230
231 if (b->fd >= 0) {
232 close(b->fd);
233 b->fd = -1;
234 }
235
236 p = strappenda("/dev/input/", b->name);
237
238 b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
239 if (b->fd < 0) {
240 log_warning("Failed to open %s: %m", b->name);
241 return -errno;
242 }
243
244 if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
245 log_error("Failed to get input name: %m");
246 r = -errno;
247 goto fail;
248 }
249
ed4ba7e4 250 r = sd_event_add_io(b->manager->event, &b->io_event_source, b->fd, EPOLLIN, button_dispatch, b);
cc377381
LP
251 if (r < 0) {
252 log_error("Failed to add button event: %s", strerror(-r));
253 goto fail;
254 }
255
256 log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name);
257
258 return 0;
259
260fail:
261 close(b->fd);
262 b->fd = -1;
263 return r;
264}
265
2d62c530 266int button_check_switches(Button *b) {
ed4ba7e4 267 uint8_t switches[SW_MAX/8+1] = {};
65b51162
LP
268 assert(b);
269
ed4ba7e4
LP
270 if (b->fd < 0)
271 return -EINVAL;
272
273 if (ioctl(b->fd, EVIOCGSW(sizeof(switches)), switches) < 0)
274 return -errno;
65b51162 275
ed4ba7e4 276 b->lid_closed = (switches[SW_LID/8] >> (SW_LID % 8)) & 1;
2d62c530 277 b->docked = (switches[SW_DOCK/8] >> (SW_DOCK % 8)) & 1;
ed4ba7e4 278
2d62c530 279 if (b->lid_closed)
ed4ba7e4 280 button_install_check_event_source(b);
ed4ba7e4
LP
281
282 return 0;
65b51162 283}