]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-inhibit.c
update TODO
[thirdparty/systemd.git] / src / login / logind-inhibit.c
CommitLineData
f8e2fb7b
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 <errno.h>
23#include <fcntl.h>
24#include <sys/epoll.h>
25#include <string.h>
26#include <errno.h>
27#include <unistd.h>
28
29#include "util.h"
30#include "mkdir.h"
9eb977db 31#include "path-util.h"
f8e2fb7b
LP
32#include "logind-inhibit.h"
33
34Inhibitor* inhibitor_new(Manager *m, const char* id) {
35 Inhibitor *i;
36
37 assert(m);
38
39 i = new0(Inhibitor, 1);
40 if (!i)
41 return NULL;
42
43 i->state_file = strappend("/run/systemd/inhibit/", id);
44 if (!i->state_file) {
45 free(i);
46 return NULL;
47 }
48
9eb977db 49 i->id = path_get_file_name(i->state_file);
f8e2fb7b
LP
50
51 if (hashmap_put(m->inhibitors, i->id, i) < 0) {
52 free(i->state_file);
53 free(i);
54 return NULL;
55 }
56
57 i->manager = m;
58 i->fifo_fd = -1;
59
60 return i;
61}
62
63void inhibitor_free(Inhibitor *i) {
64 assert(i);
65
66 free(i->who);
67 free(i->why);
68
69 hashmap_remove(i->manager->inhibitors, i->id);
70 inhibitor_remove_fifo(i);
71
72 if (i->state_file) {
73 unlink(i->state_file);
74 free(i->state_file);
75 }
76
77 free(i);
78}
79
80int inhibitor_save(Inhibitor *i) {
81 char *temp_path, *cc;
82 int r;
83 FILE *f;
84
85 assert(i);
86
d2e54fae 87 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
f8e2fb7b
LP
88 if (r < 0)
89 goto finish;
90
91 r = fopen_temporary(i->state_file, &f, &temp_path);
92 if (r < 0)
93 goto finish;
94
95 fchmod(fileno(f), 0644);
96
97 fprintf(f,
98 "# This is private data. Do not parse.\n"
99 "WHAT=%s\n"
eecd1362 100 "MODE=%s\n"
f8e2fb7b
LP
101 "UID=%lu\n"
102 "PID=%lu\n",
103 inhibit_what_to_string(i->what),
eecd1362 104 inhibit_mode_to_string(i->mode),
f8e2fb7b
LP
105 (unsigned long) i->uid,
106 (unsigned long) i->pid);
107
108 if (i->who) {
109 cc = cescape(i->who);
110 if (!cc)
111 r = -ENOMEM;
112 else {
113 fprintf(f, "WHO=%s\n", cc);
114 free(cc);
115 }
116 }
117
118 if (i->why) {
119 cc = cescape(i->why);
120 if (!cc)
121 r = -ENOMEM;
122 else {
123 fprintf(f, "WHY=%s\n", cc);
124 free(cc);
125 }
126 }
127
128 if (i->fifo_path)
129 fprintf(f, "FIFO=%s\n", i->fifo_path);
130
131 fflush(f);
132
133 if (ferror(f) || rename(temp_path, i->state_file) < 0) {
134 r = -errno;
135 unlink(i->state_file);
136 unlink(temp_path);
137 }
138
139 fclose(f);
140 free(temp_path);
141
142finish:
143 if (r < 0)
144 log_error("Failed to save inhibit data for %s: %s", i->id, strerror(-r));
145
146 return r;
147}
148
149int inhibitor_start(Inhibitor *i) {
150 assert(i);
151
152 if (i->started)
153 return 0;
154
c7b5eb98
LP
155 dual_timestamp_get(&i->since);
156
eecd1362 157 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s started.",
f8e2fb7b 158 strna(i->who), strna(i->why),
eecd1362
LP
159 (unsigned long) i->pid, (unsigned long) i->uid,
160 inhibit_mode_to_string(i->mode));
f8e2fb7b
LP
161
162 inhibitor_save(i);
163
164 i->started = true;
165
d889a206 166 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited\0" : "DelayInhibited\0");
f8e2fb7b
LP
167
168 return 0;
169}
170
171int inhibitor_stop(Inhibitor *i) {
172 assert(i);
173
174 if (i->started)
eecd1362 175 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s stopped.",
f8e2fb7b 176 strna(i->who), strna(i->why),
eecd1362
LP
177 (unsigned long) i->pid, (unsigned long) i->uid,
178 inhibit_mode_to_string(i->mode));
f8e2fb7b
LP
179
180 if (i->state_file)
181 unlink(i->state_file);
182
183 i->started = false;
184
d889a206 185 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited\0" : "DelayInhibited\0");
f8e2fb7b
LP
186
187 return 0;
188}
189
190int inhibitor_load(Inhibitor *i) {
191 InhibitWhat w;
eecd1362 192 InhibitMode mm;
f8e2fb7b
LP
193 int r;
194 char *cc,
195 *what = NULL,
196 *uid = NULL,
197 *pid = NULL,
198 *who = NULL,
eecd1362
LP
199 *why = NULL,
200 *mode = NULL;
f8e2fb7b
LP
201
202 r = parse_env_file(i->state_file, NEWLINE,
203 "WHAT", &what,
204 "UID", &uid,
205 "PID", &pid,
206 "WHO", &who,
207 "WHY", &why,
eecd1362 208 "MODE", &mode,
f8e2fb7b
LP
209 "FIFO", &i->fifo_path,
210 NULL);
211 if (r < 0)
212 goto finish;
213
eecd1362 214 w = what ? inhibit_what_from_string(what) : 0;
f8e2fb7b
LP
215 if (w >= 0)
216 i->what = w;
217
eecd1362
LP
218 mm = mode ? inhibit_mode_from_string(mode) : INHIBIT_BLOCK;
219 if (mm >= 0)
220 i->mode = mm;
221
a34faf57
LN
222 if (uid) {
223 r = parse_uid(uid, &i->uid);
224 if (r < 0)
225 goto finish;
226 }
eecd1362 227
a34faf57
LN
228 if (pid) {
229 r = parse_pid(pid, &i->pid);
230 if (r < 0)
231 goto finish;
232 }
f8e2fb7b
LP
233
234 if (who) {
235 cc = cunescape(who);
236 if (!cc) {
237 r = -ENOMEM;
238 goto finish;
239 }
240
241 free(i->who);
242 i->who = cc;
243 }
244
245 if (why) {
246 cc = cunescape(why);
247 if (!cc) {
248 r = -ENOMEM;
249 goto finish;
250 }
251
252 free(i->why);
253 i->why = cc;
254 }
255
256 if (i->fifo_path) {
257 int fd;
258
259 fd = inhibitor_create_fifo(i);
260 if (fd >= 0)
261 close_nointr_nofail(fd);
262 }
263
264finish:
265 free(what);
266 free(uid);
267 free(pid);
268 free(who);
269 free(why);
270
271 return r;
272}
273
274int inhibitor_create_fifo(Inhibitor *i) {
275 int r;
276
277 assert(i);
278
279 /* Create FIFO */
280 if (!i->fifo_path) {
d2e54fae 281 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
f8e2fb7b
LP
282 if (r < 0)
283 return r;
284
285 if (asprintf(&i->fifo_path, "/run/systemd/inhibit/%s.ref", i->id) < 0)
286 return -ENOMEM;
287
288 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
289 return -errno;
290 }
291
292 /* Open reading side */
293 if (i->fifo_fd < 0) {
294 struct epoll_event ev;
295
296 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
297 if (i->fifo_fd < 0)
298 return -errno;
299
300 r = hashmap_put(i->manager->inhibitor_fds, INT_TO_PTR(i->fifo_fd + 1), i);
301 if (r < 0)
302 return r;
303
304 zero(ev);
305 ev.events = 0;
069cfc85 306 ev.data.u32 = FD_OTHER_BASE + i->fifo_fd;
f8e2fb7b
LP
307
308 if (epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_ADD, i->fifo_fd, &ev) < 0)
309 return -errno;
310 }
311
312 /* Open writing side */
313 r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
314 if (r < 0)
315 return -errno;
316
317 return r;
318}
319
320void inhibitor_remove_fifo(Inhibitor *i) {
321 assert(i);
322
323 if (i->fifo_fd >= 0) {
324 assert_se(hashmap_remove(i->manager->inhibitor_fds, INT_TO_PTR(i->fifo_fd + 1)) == i);
325 assert_se(epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_DEL, i->fifo_fd, NULL) == 0);
326 close_nointr_nofail(i->fifo_fd);
327 i->fifo_fd = -1;
328 }
329
330 if (i->fifo_path) {
331 unlink(i->fifo_path);
332 free(i->fifo_path);
333 i->fifo_path = NULL;
334 }
335}
336
eecd1362 337InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
f8e2fb7b
LP
338 Inhibitor *i;
339 Iterator j;
340 InhibitWhat what = 0;
341
342 assert(m);
343
344 HASHMAP_FOREACH(i, m->inhibitor_fds, j)
eecd1362
LP
345 if (i->mode == mm)
346 what |= i->what;
f8e2fb7b
LP
347
348 return what;
349}
350
beaafb2e
LP
351static int pid_is_active(Manager *m, pid_t pid) {
352 Session *s;
353 int r;
354
355 r = manager_get_session_by_pid(m, pid, &s);
356 if (r <= 0)
357 return r;
358
359 return session_is_active(s);
360}
361
362bool manager_is_inhibited(
363 Manager *m,
364 InhibitWhat w,
365 InhibitMode mm,
366 dual_timestamp *since,
367 bool only_active) {
368
c7b5eb98
LP
369 Inhibitor *i;
370 Iterator j;
371 struct dual_timestamp ts = { 0, 0 };
372 bool inhibited = false;
373
374 assert(m);
375 assert(w > 0 && w < _INHIBIT_WHAT_MAX);
376
377 HASHMAP_FOREACH(i, m->inhibitor_fds, j) {
378 if (!(i->what & w))
379 continue;
380
eecd1362
LP
381 if (i->mode != mm)
382 continue;
383
beaafb2e
LP
384 if (only_active && pid_is_active(m, i->pid) <= 0)
385 continue;
386
c7b5eb98
LP
387 if (!inhibited ||
388 i->since.monotonic < ts.monotonic)
389 ts = i->since;
390
391 inhibited = true;
392 }
393
394 if (since)
395 *since = ts;
396
397 return inhibited;
398}
399
f8e2fb7b 400const char *inhibit_what_to_string(InhibitWhat w) {
beaafb2e
LP
401 static __thread char buffer[73];
402 char *p;
f8e2fb7b
LP
403
404 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
405 return NULL;
406
beaafb2e
LP
407 p = buffer;
408 if (w & INHIBIT_SHUTDOWN)
409 p = stpcpy(p, "shutdown:");
410 if (w & INHIBIT_SLEEP)
411 p = stpcpy(p, "sleep:");
412 if (w & INHIBIT_IDLE)
413 p = stpcpy(p, "idle:");
414 if (w & INHIBIT_HANDLE_POWER_KEY)
415 p = stpcpy(p, "handle-power-key:");
416 if (w & INHIBIT_HANDLE_SLEEP_KEY)
417 p = stpcpy(p, "handle-sleep-key:");
418 if (w & INHIBIT_HANDLE_LID_SWITCH)
419 p = stpcpy(p, "handle-lid-switch:");
420
421 if (p > buffer)
422 *(p-1) = 0;
423 else
424 *p = 0;
425
426 return buffer;
f8e2fb7b
LP
427}
428
429InhibitWhat inhibit_what_from_string(const char *s) {
430 InhibitWhat what = 0;
431 char *w, *state;
432 size_t l;
433
434 FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
435 if (l == 8 && strncmp(w, "shutdown", l) == 0)
436 what |= INHIBIT_SHUTDOWN;
4943c1c9
LP
437 else if (l == 5 && strncmp(w, "sleep", l) == 0)
438 what |= INHIBIT_SLEEP;
f8e2fb7b
LP
439 else if (l == 4 && strncmp(w, "idle", l) == 0)
440 what |= INHIBIT_IDLE;
beaafb2e
LP
441 else if (l == 16 && strncmp(w, "handle-power-key", l) == 0)
442 what |= INHIBIT_HANDLE_POWER_KEY;
443 else if (l == 16 && strncmp(w, "handle-sleep-key", l) == 0)
444 what |= INHIBIT_HANDLE_SLEEP_KEY;
f981b9c5 445 else if (l == 17 && strncmp(w, "handle-lid-switch", l) == 0)
beaafb2e 446 what |= INHIBIT_HANDLE_LID_SWITCH;
f8e2fb7b
LP
447 else
448 return _INHIBIT_WHAT_INVALID;
449 }
450
451 return what;
f8e2fb7b 452}
eecd1362
LP
453
454static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
455 [INHIBIT_BLOCK] = "block",
456 [INHIBIT_DELAY] = "delay"
457};
458
459DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);