]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-button.c
localed: mark bus properties as change emitting
[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>
29#include <sys/epoll.h>
30
31#include "conf-parser.h"
32#include "util.h"
33#include "logind-button.h"
34#include "special.h"
35#include "dbus-common.h"
c485437f 36#include "sd-messages.h"
e9d21f24
LP
37
38Button* button_new(Manager *m, const char *name) {
39 Button *b;
40
41 assert(m);
42 assert(name);
43
44 b = new0(Button, 1);
45 if (!b)
46 return NULL;
47
48 b->name = strdup(name);
49 if (!b->name) {
50 free(b);
51 return NULL;
52 }
53
54 if (hashmap_put(m->buttons, b->name, b) < 0) {
55 free(b->name);
56 free(b);
57 return NULL;
58 }
59
60 b->manager = m;
61 b->fd = -1;
62
63 return b;
64}
65
66void button_free(Button *b) {
67 assert(b);
68
69 hashmap_remove(b->manager->buttons, b->name);
70
71 if (b->fd >= 0) {
72 hashmap_remove(b->manager->button_fds, INT_TO_PTR(b->fd + 1));
73 assert_se(epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_DEL, b->fd, NULL) == 0);
c30a0c62
LP
74
75 /* If the device has been unplugged close() returns
76 * ENODEV, let's ignore this, hence we don't use
77 * close_nointr_nofail() */
78 close(b->fd);
e9d21f24
LP
79 }
80
81 free(b->name);
82 free(b->seat);
83 free(b);
84}
85
86int button_set_seat(Button *b, const char *sn) {
87 char *s;
88
89 assert(b);
90 assert(sn);
91
92 s = strdup(sn);
93 if (!s)
94 return -ENOMEM;
95
96 free(b->seat);
97 b->seat = s;
98
99 return 0;
100}
101
102int button_open(Button *b) {
103 char name[256], *p;
104 struct epoll_event ev;
105 int r;
106
107 assert(b);
108
109 if (b->fd >= 0) {
c30a0c62 110 close(b->fd);
e9d21f24
LP
111 b->fd = -1;
112 }
113
114 p = strappend("/dev/input/", b->name);
0d0f0c50
SL
115 if (!p)
116 return log_oom();
e9d21f24
LP
117
118 b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
119 free(p);
120 if (b->fd < 0) {
121 log_warning("Failed to open %s: %m", b->name);
122 return -errno;
123 }
124
125 if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
126 log_error("Failed to get input name: %m");
127 r = -errno;
128 goto fail;
129 }
130
131 zero(ev);
132 ev.events = EPOLLIN;
133 ev.data.u32 = FD_OTHER_BASE + b->fd;
134
135 if (epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_ADD, b->fd, &ev) < 0) {
136 log_error("Failed to add to epoll: %m");
137 r = -errno;
138 goto fail;
139 }
140
141 r = hashmap_put(b->manager->button_fds, INT_TO_PTR(b->fd + 1), b);
142 if (r < 0) {
143 log_error("Failed to add to hash map: %s", strerror(-r));
144 assert_se(epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_DEL, b->fd, NULL) == 0);
145 goto fail;
146 }
147
148 log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name);
149
150 return 0;
151
152fail:
c30a0c62 153 close(b->fd);
e9d21f24
LP
154 b->fd = -1;
155 return r;
156}
157
65b51162
LP
158static int button_handle(
159 Button *b,
160 InhibitWhat inhibit_key,
23406ce5 161 HandleAction handle,
65b51162
LP
162 bool ignore_inhibited,
163 bool is_edge) {
beaafb2e 164
e9d21f24
LP
165 int r;
166
167 assert(b);
168
23406ce5
LP
169 r = manager_handle_action(b->manager, inhibit_key, handle, ignore_inhibited, is_edge);
170 if (r > 0)
171 /* We are executing the operation, so make sure we don't
172 * execute another one until the lid is opened/closed again */
173 b->lid_close_queued = false;
6de0e0e5 174
23406ce5 175 return r;
e9d21f24
LP
176}
177
178int button_process(Button *b) {
179 struct input_event ev;
180 ssize_t l;
181
182 assert(b);
183
184 l = read(b->fd, &ev, sizeof(ev));
185 if (l < 0)
186 return errno != EAGAIN ? -errno : 0;
187 if ((size_t) l < sizeof(ev))
188 return -EIO;
189
e9d21f24
LP
190 if (ev.type == EV_KEY && ev.value > 0) {
191
192 switch (ev.code) {
193
194 case KEY_POWER:
195 case KEY_POWER2:
c485437f
ZJS
196 log_struct(LOG_INFO,
197 "MESSAGE=Power key pressed.",
198 MESSAGE_ID(SD_MESSAGE_POWER_KEY),
199 NULL);
65b51162 200 return button_handle(b, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
e9d21f24 201
8e7fd6ad
LP
202 /* The kernel is a bit confused here:
203
204 KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend"
205 KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
206 */
207
e9d21f24 208 case KEY_SLEEP:
c485437f
ZJS
209 log_struct(LOG_INFO,
210 "MESSAGE=Suspend key pressed.",
211 MESSAGE_ID(SD_MESSAGE_SUSPEND_KEY),
212 NULL);
8e7fd6ad 213 return button_handle(b, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
e9d21f24 214
8e7fd6ad 215 case KEY_SUSPEND:
c485437f
ZJS
216 log_struct(LOG_INFO,
217 "MESSAGE=Hibernate key pressed.",
218 MESSAGE_ID(SD_MESSAGE_HIBERNATE_KEY),
219 NULL);
8e7fd6ad 220 return button_handle(b, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
e9d21f24 221 }
8e7fd6ad 222
e9d21f24
LP
223 } else if (ev.type == EV_SW && ev.value > 0) {
224
225 switch (ev.code) {
226
227 case SW_LID:
c485437f
ZJS
228 log_struct(LOG_INFO,
229 "MESSAGE=Lid closed.",
230 MESSAGE_ID(SD_MESSAGE_LID_CLOSED),
231 NULL);
65b51162
LP
232 b->lid_close_queued = true;
233
234 return button_handle(b, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, true);
235 }
236
237 } else if (ev.type == EV_SW && ev.value == 0) {
238
239 switch (ev.code) {
240
241 case SW_LID:
c485437f
ZJS
242 log_struct(LOG_INFO,
243 "MESSAGE=Lid opened.",
244 MESSAGE_ID(SD_MESSAGE_LID_OPENED),
245 NULL);
65b51162
LP
246 b->lid_close_queued = false;
247 break;
e9d21f24
LP
248 }
249 }
250
251 return 0;
252}
253
65b51162
LP
254int button_recheck(Button *b) {
255 assert(b);
256
257 if (!b->lid_close_queued)
258 return 0;
259
260 return button_handle(b, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, false);
261}