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