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/>.
29 #include "logind-inhibit.h"
32 Inhibitor* inhibitor_new(Manager *m, const char* id) {
37 i = new0(Inhibitor, 1);
41 i->state_file = strappend("/run/systemd/inhibit/", id);
47 i->id = basename(i->state_file);
49 if (hashmap_put(m->inhibitors, i->id, i) < 0) {
61 void inhibitor_free(Inhibitor *i) {
64 hashmap_remove(i->manager->inhibitors, i->id);
66 inhibitor_remove_fifo(i);
72 unlink(i->state_file);
79 int inhibitor_save(Inhibitor *i) {
80 _cleanup_free_ char *temp_path = NULL;
81 _cleanup_fclose_ FILE *f = NULL;
86 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
90 r = fopen_temporary(i->state_file, &f, &temp_path);
94 fchmod(fileno(f), 0644);
97 "# This is private data. Do not parse.\n"
102 inhibit_what_to_string(i->what),
103 inhibit_mode_to_string(i->mode),
108 _cleanup_free_ char *cc = NULL;
110 cc = cescape(i->who);
114 fprintf(f, "WHO=%s\n", cc);
118 _cleanup_free_ char *cc = NULL;
120 cc = cescape(i->why);
124 fprintf(f, "WHY=%s\n", cc);
128 fprintf(f, "FIFO=%s\n", i->fifo_path);
132 if (ferror(f) || rename(temp_path, i->state_file) < 0) {
134 unlink(i->state_file);
140 log_error_errno(r, "Failed to save inhibit data %s: %m", i->state_file);
145 int inhibitor_start(Inhibitor *i) {
151 dual_timestamp_get(&i->since);
153 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s started.",
154 strna(i->who), strna(i->why),
156 inhibit_mode_to_string(i->mode));
162 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
167 int inhibitor_stop(Inhibitor *i) {
171 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s stopped.",
172 strna(i->who), strna(i->why),
174 inhibit_mode_to_string(i->mode));
177 unlink(i->state_file);
181 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
186 int inhibitor_load(Inhibitor *i) {
201 r = parse_env_file(i->state_file, NEWLINE,
208 "FIFO", &i->fifo_path,
213 w = what ? inhibit_what_from_string(what) : 0;
217 mm = mode ? inhibit_mode_from_string(mode) : INHIBIT_BLOCK;
222 r = parse_uid(uid, &i->uid);
228 r = parse_pid(pid, &i->pid);
234 r = cunescape(who, 0, &cc);
243 r = cunescape(why, 0, &cc);
254 fd = inhibitor_create_fifo(i);
261 static int inhibitor_dispatch_fifo(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
262 Inhibitor *i = userdata;
265 assert(fd == i->fifo_fd);
274 int inhibitor_create_fifo(Inhibitor *i) {
281 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
285 i->fifo_path = strjoin("/run/systemd/inhibit/", i->id, ".ref", NULL);
289 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
293 /* Open reading side */
294 if (i->fifo_fd < 0) {
295 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
300 if (!i->event_source) {
301 r = sd_event_add_io(i->manager->event, &i->event_source, i->fifo_fd, 0, inhibitor_dispatch_fifo, i);
305 r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE);
310 /* Open writing side */
311 r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
318 void inhibitor_remove_fifo(Inhibitor *i) {
321 i->event_source = sd_event_source_unref(i->event_source);
322 i->fifo_fd = safe_close(i->fifo_fd);
325 unlink(i->fifo_path);
331 InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
334 InhibitWhat what = 0;
338 HASHMAP_FOREACH(i, m->inhibitors, j)
345 static int pid_is_active(Manager *m, pid_t pid) {
349 r = manager_get_session_by_pid(m, pid, &s);
353 /* If there's no session assigned to it, then it's globally
354 * active on all ttys */
358 return session_is_active(s);
361 bool manager_is_inhibited(
365 dual_timestamp *since,
366 bool ignore_inactive,
369 Inhibitor **offending) {
373 struct dual_timestamp ts = { 0, 0 };
374 bool inhibited = false;
377 assert(w > 0 && w < _INHIBIT_WHAT_MAX);
379 HASHMAP_FOREACH(i, m->inhibitors, j) {
386 if (ignore_inactive && pid_is_active(m, i->pid) <= 0)
389 if (ignore_uid && i->uid == uid)
393 i->since.monotonic < ts.monotonic)
408 const char *inhibit_what_to_string(InhibitWhat w) {
409 static thread_local char buffer[97];
412 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
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:");
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:");
428 if (w & INHIBIT_HANDLE_LID_SWITCH)
429 p = stpcpy(p, "handle-lid-switch:");
439 InhibitWhat inhibit_what_from_string(const char *s) {
440 InhibitWhat what = 0;
441 const char *word, *state;
444 FOREACH_WORD_SEPARATOR(word, l, s, ":", state) {
445 if (l == 8 && strneq(word, "shutdown", l))
446 what |= INHIBIT_SHUTDOWN;
447 else if (l == 5 && strneq(word, "sleep", l))
448 what |= INHIBIT_SLEEP;
449 else if (l == 4 && strneq(word, "idle", l))
450 what |= INHIBIT_IDLE;
451 else if (l == 16 && strneq(word, "handle-power-key", l))
452 what |= INHIBIT_HANDLE_POWER_KEY;
453 else if (l == 18 && strneq(word, "handle-suspend-key", l))
454 what |= INHIBIT_HANDLE_SUSPEND_KEY;
455 else if (l == 20 && strneq(word, "handle-hibernate-key", l))
456 what |= INHIBIT_HANDLE_HIBERNATE_KEY;
457 else if (l == 17 && strneq(word, "handle-lid-switch", l))
458 what |= INHIBIT_HANDLE_LID_SWITCH;
460 return _INHIBIT_WHAT_INVALID;
466 static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
467 [INHIBIT_BLOCK] = "block",
468 [INHIBIT_DELAY] = "delay"
471 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);