1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
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.
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.
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/>.
27 #include "alloc-util.h"
31 #include "formats-util.h"
32 #include "logind-inhibit.h"
34 #include "parse-util.h"
35 #include "string-table.h"
36 #include "string-util.h"
37 #include "user-util.h"
40 Inhibitor* inhibitor_new(Manager *m, const char* id) {
45 i = new0(Inhibitor, 1);
49 i->state_file = strappend("/run/systemd/inhibit/", id);
55 i->id = basename(i->state_file);
57 if (hashmap_put(m->inhibitors, i->id, i) < 0) {
69 void inhibitor_free(Inhibitor *i) {
72 hashmap_remove(i->manager->inhibitors, i->id);
74 inhibitor_remove_fifo(i);
80 unlink(i->state_file);
87 int inhibitor_save(Inhibitor *i) {
88 _cleanup_free_ char *temp_path = NULL;
89 _cleanup_fclose_ FILE *f = NULL;
94 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
98 r = fopen_temporary(i->state_file, &f, &temp_path);
102 fchmod(fileno(f), 0644);
105 "# This is private data. Do not parse.\n"
110 inhibit_what_to_string(i->what),
111 inhibit_mode_to_string(i->mode),
116 _cleanup_free_ char *cc = NULL;
118 cc = cescape(i->who);
124 fprintf(f, "WHO=%s\n", cc);
128 _cleanup_free_ char *cc = NULL;
130 cc = cescape(i->why);
136 fprintf(f, "WHY=%s\n", cc);
140 fprintf(f, "FIFO=%s\n", i->fifo_path);
142 r = fflush_and_check(f);
146 if (rename(temp_path, i->state_file) < 0) {
154 (void) unlink(i->state_file);
157 (void) unlink(temp_path);
159 return log_error_errno(r, "Failed to save inhibit data %s: %m", i->state_file);
162 int inhibitor_start(Inhibitor *i) {
168 dual_timestamp_get(&i->since);
170 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s started.",
171 strna(i->who), strna(i->why),
173 inhibit_mode_to_string(i->mode));
179 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
184 int inhibitor_stop(Inhibitor *i) {
188 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s stopped.",
189 strna(i->who), strna(i->why),
191 inhibit_mode_to_string(i->mode));
194 unlink(i->state_file);
198 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
203 int inhibitor_load(Inhibitor *i) {
218 r = parse_env_file(i->state_file, NEWLINE,
225 "FIFO", &i->fifo_path,
230 w = what ? inhibit_what_from_string(what) : 0;
234 mm = mode ? inhibit_mode_from_string(mode) : INHIBIT_BLOCK;
239 r = parse_uid(uid, &i->uid);
245 r = parse_pid(pid, &i->pid);
251 r = cunescape(who, 0, &cc);
260 r = cunescape(why, 0, &cc);
271 fd = inhibitor_create_fifo(i);
278 static int inhibitor_dispatch_fifo(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
279 Inhibitor *i = userdata;
282 assert(fd == i->fifo_fd);
291 int inhibitor_create_fifo(Inhibitor *i) {
298 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
302 i->fifo_path = strjoin("/run/systemd/inhibit/", i->id, ".ref", NULL);
306 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
310 /* Open reading side */
311 if (i->fifo_fd < 0) {
312 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
317 if (!i->event_source) {
318 r = sd_event_add_io(i->manager->event, &i->event_source, i->fifo_fd, 0, inhibitor_dispatch_fifo, i);
322 r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE);
327 /* Open writing side */
328 r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
335 void inhibitor_remove_fifo(Inhibitor *i) {
338 i->event_source = sd_event_source_unref(i->event_source);
339 i->fifo_fd = safe_close(i->fifo_fd);
342 unlink(i->fifo_path);
343 i->fifo_path = mfree(i->fifo_path);
347 InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
350 InhibitWhat what = 0;
354 HASHMAP_FOREACH(i, m->inhibitors, j)
361 static int pid_is_active(Manager *m, pid_t pid) {
365 r = manager_get_session_by_pid(m, pid, &s);
369 /* If there's no session assigned to it, then it's globally
370 * active on all ttys */
374 return session_is_active(s);
377 bool manager_is_inhibited(
381 dual_timestamp *since,
382 bool ignore_inactive,
385 Inhibitor **offending) {
389 struct dual_timestamp ts = DUAL_TIMESTAMP_NULL;
390 bool inhibited = false;
393 assert(w > 0 && w < _INHIBIT_WHAT_MAX);
395 HASHMAP_FOREACH(i, m->inhibitors, j) {
402 if (ignore_inactive && pid_is_active(m, i->pid) <= 0)
405 if (ignore_uid && i->uid == uid)
409 i->since.monotonic < ts.monotonic)
424 const char *inhibit_what_to_string(InhibitWhat w) {
425 static thread_local char buffer[97];
428 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
432 if (w & INHIBIT_SHUTDOWN)
433 p = stpcpy(p, "shutdown:");
434 if (w & INHIBIT_SLEEP)
435 p = stpcpy(p, "sleep:");
436 if (w & INHIBIT_IDLE)
437 p = stpcpy(p, "idle:");
438 if (w & INHIBIT_HANDLE_POWER_KEY)
439 p = stpcpy(p, "handle-power-key:");
440 if (w & INHIBIT_HANDLE_SUSPEND_KEY)
441 p = stpcpy(p, "handle-suspend-key:");
442 if (w & INHIBIT_HANDLE_HIBERNATE_KEY)
443 p = stpcpy(p, "handle-hibernate-key:");
444 if (w & INHIBIT_HANDLE_LID_SWITCH)
445 p = stpcpy(p, "handle-lid-switch:");
455 InhibitWhat inhibit_what_from_string(const char *s) {
456 InhibitWhat what = 0;
457 const char *word, *state;
460 FOREACH_WORD_SEPARATOR(word, l, s, ":", state) {
461 if (l == 8 && strneq(word, "shutdown", l))
462 what |= INHIBIT_SHUTDOWN;
463 else if (l == 5 && strneq(word, "sleep", l))
464 what |= INHIBIT_SLEEP;
465 else if (l == 4 && strneq(word, "idle", l))
466 what |= INHIBIT_IDLE;
467 else if (l == 16 && strneq(word, "handle-power-key", l))
468 what |= INHIBIT_HANDLE_POWER_KEY;
469 else if (l == 18 && strneq(word, "handle-suspend-key", l))
470 what |= INHIBIT_HANDLE_SUSPEND_KEY;
471 else if (l == 20 && strneq(word, "handle-hibernate-key", l))
472 what |= INHIBIT_HANDLE_HIBERNATE_KEY;
473 else if (l == 17 && strneq(word, "handle-lid-switch", l))
474 what |= INHIBIT_HANDLE_LID_SWITCH;
476 return _INHIBIT_WHAT_INVALID;
482 static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
483 [INHIBIT_BLOCK] = "block",
484 [INHIBIT_DELAY] = "delay"
487 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);