]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-button.c
git: update .gitignore
[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);
65b51162 144 return button_handle(b, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
e9d21f24 145
8e7fd6ad
LP
146 /* The kernel is a bit confused here:
147
148 KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend"
149 KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
150 */
151
e9d21f24 152 case KEY_SLEEP:
c485437f
ZJS
153 log_struct(LOG_INFO,
154 "MESSAGE=Suspend key pressed.",
155 MESSAGE_ID(SD_MESSAGE_SUSPEND_KEY),
156 NULL);
8e7fd6ad 157 return button_handle(b, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
e9d21f24 158
8e7fd6ad 159 case KEY_SUSPEND:
c485437f
ZJS
160 log_struct(LOG_INFO,
161 "MESSAGE=Hibernate key pressed.",
162 MESSAGE_ID(SD_MESSAGE_HIBERNATE_KEY),
163 NULL);
8e7fd6ad 164 return button_handle(b, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
e9d21f24 165 }
8e7fd6ad 166
e9d21f24
LP
167 } else if (ev.type == EV_SW && ev.value > 0) {
168
169 switch (ev.code) {
170
171 case SW_LID:
c485437f
ZJS
172 log_struct(LOG_INFO,
173 "MESSAGE=Lid closed.",
174 MESSAGE_ID(SD_MESSAGE_LID_CLOSED),
175 NULL);
65b51162
LP
176 b->lid_close_queued = true;
177
178 return button_handle(b, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, true);
179 }
180
181 } else if (ev.type == EV_SW && ev.value == 0) {
182
183 switch (ev.code) {
184
185 case SW_LID:
c485437f
ZJS
186 log_struct(LOG_INFO,
187 "MESSAGE=Lid opened.",
188 MESSAGE_ID(SD_MESSAGE_LID_OPENED),
189 NULL);
65b51162
LP
190 b->lid_close_queued = false;
191 break;
e9d21f24
LP
192 }
193 }
194
195 return 0;
196}
197
cc377381
LP
198int button_open(Button *b) {
199 char *p, name[256];
200 int r;
201
202 assert(b);
203
204 if (b->fd >= 0) {
205 close(b->fd);
206 b->fd = -1;
207 }
208
209 p = strappenda("/dev/input/", b->name);
210
211 b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
212 if (b->fd < 0) {
213 log_warning("Failed to open %s: %m", b->name);
214 return -errno;
215 }
216
217 if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
218 log_error("Failed to get input name: %m");
219 r = -errno;
220 goto fail;
221 }
222
223 r = sd_event_add_io(b->manager->event, b->fd, EPOLLIN, button_dispatch, b, &b->event_source);
224 if (r < 0) {
225 log_error("Failed to add button event: %s", strerror(-r));
226 goto fail;
227 }
228
229 log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name);
230
231 return 0;
232
233fail:
234 close(b->fd);
235 b->fd = -1;
236 return r;
237}
238
65b51162
LP
239int button_recheck(Button *b) {
240 assert(b);
241
242 if (!b->lid_close_queued)
243 return 0;
244
245 return button_handle(b, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, false);
246}