]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-button.c
api: in constructor function calls, always put the returned object pointer first...
[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
cc377381 69 sd_event_source_unref(b->event_source);
c30a0c62 70
cc377381 71 if (b->fd >= 0) {
c30a0c62
LP
72 /* If the device has been unplugged close() returns
73 * ENODEV, let's ignore this, hence we don't use
74 * close_nointr_nofail() */
75 close(b->fd);
e9d21f24
LP
76 }
77
78 free(b->name);
79 free(b->seat);
80 free(b);
81}
82
83int button_set_seat(Button *b, const char *sn) {
84 char *s;
85
86 assert(b);
87 assert(sn);
88
89 s = strdup(sn);
90 if (!s)
91 return -ENOMEM;
92
93 free(b->seat);
94 b->seat = s;
95
96 return 0;
97}
98
65b51162
LP
99static int button_handle(
100 Button *b,
101 InhibitWhat inhibit_key,
23406ce5 102 HandleAction handle,
65b51162
LP
103 bool ignore_inhibited,
104 bool is_edge) {
beaafb2e 105
e9d21f24
LP
106 int r;
107
108 assert(b);
109
23406ce5
LP
110 r = manager_handle_action(b->manager, inhibit_key, handle, ignore_inhibited, is_edge);
111 if (r > 0)
112 /* We are executing the operation, so make sure we don't
113 * execute another one until the lid is opened/closed again */
114 b->lid_close_queued = false;
6de0e0e5 115
95056b27 116 return 0;
e9d21f24
LP
117}
118
cc377381
LP
119static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
120 Button *b = userdata;
e9d21f24
LP
121 struct input_event ev;
122 ssize_t l;
123
cc377381
LP
124 assert(s);
125 assert(fd == b->fd);
e9d21f24
LP
126 assert(b);
127
128 l = read(b->fd, &ev, sizeof(ev));
129 if (l < 0)
130 return errno != EAGAIN ? -errno : 0;
131 if ((size_t) l < sizeof(ev))
132 return -EIO;
133
e9d21f24
LP
134 if (ev.type == EV_KEY && ev.value > 0) {
135
136 switch (ev.code) {
137
138 case KEY_POWER:
139 case KEY_POWER2:
c485437f
ZJS
140 log_struct(LOG_INFO,
141 "MESSAGE=Power key pressed.",
142 MESSAGE_ID(SD_MESSAGE_POWER_KEY),
143 NULL);
7b77ed8c
LP
144
145 button_handle(b, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
146 break;
e9d21f24 147
8e7fd6ad
LP
148 /* The kernel is a bit confused here:
149
150 KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend"
151 KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
152 */
153
e9d21f24 154 case KEY_SLEEP:
c485437f
ZJS
155 log_struct(LOG_INFO,
156 "MESSAGE=Suspend key pressed.",
157 MESSAGE_ID(SD_MESSAGE_SUSPEND_KEY),
158 NULL);
7b77ed8c
LP
159
160 button_handle(b, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
161 break;
e9d21f24 162
8e7fd6ad 163 case KEY_SUSPEND:
c485437f
ZJS
164 log_struct(LOG_INFO,
165 "MESSAGE=Hibernate key pressed.",
166 MESSAGE_ID(SD_MESSAGE_HIBERNATE_KEY),
167 NULL);
7b77ed8c
LP
168
169 button_handle(b, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
170 break;
e9d21f24 171 }
8e7fd6ad 172
e9d21f24
LP
173 } else if (ev.type == EV_SW && ev.value > 0) {
174
7b77ed8c 175 if (ev.code == SW_LID) {
c485437f
ZJS
176 log_struct(LOG_INFO,
177 "MESSAGE=Lid closed.",
178 MESSAGE_ID(SD_MESSAGE_LID_CLOSED),
179 NULL);
65b51162 180
7b77ed8c
LP
181 b->lid_close_queued = true;
182 button_handle(b, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, true);
65b51162
LP
183 }
184
185 } else if (ev.type == EV_SW && ev.value == 0) {
186
7b77ed8c 187 if (ev.code == SW_LID) {
c485437f
ZJS
188 log_struct(LOG_INFO,
189 "MESSAGE=Lid opened.",
190 MESSAGE_ID(SD_MESSAGE_LID_OPENED),
191 NULL);
7b77ed8c 192
65b51162 193 b->lid_close_queued = false;
e9d21f24
LP
194 }
195 }
196
197 return 0;
198}
199
cc377381
LP
200int button_open(Button *b) {
201 char *p, name[256];
202 int r;
203
204 assert(b);
205
206 if (b->fd >= 0) {
207 close(b->fd);
208 b->fd = -1;
209 }
210
211 p = strappenda("/dev/input/", b->name);
212
213 b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
214 if (b->fd < 0) {
215 log_warning("Failed to open %s: %m", b->name);
216 return -errno;
217 }
218
219 if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
220 log_error("Failed to get input name: %m");
221 r = -errno;
222 goto fail;
223 }
224
151b9b96 225 r = sd_event_add_io(b->manager->event, &b->event_source, b->fd, EPOLLIN, button_dispatch, b);
cc377381
LP
226 if (r < 0) {
227 log_error("Failed to add button event: %s", strerror(-r));
228 goto fail;
229 }
230
231 log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name);
232
233 return 0;
234
235fail:
236 close(b->fd);
237 b->fd = -1;
238 return r;
239}
240
65b51162
LP
241int button_recheck(Button *b) {
242 assert(b);
243
244 if (!b->lid_close_queued)
245 return 0;
246
247 return button_handle(b, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, false);
248}