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"
31 #include "formats-util.h"
33 Inhibitor* inhibitor_new(Manager *m, const char* id) {
38 i = new0(Inhibitor, 1);
42 i->state_file = strappend("/run/systemd/inhibit/", id);
48 i->id = basename(i->state_file);
50 if (hashmap_put(m->inhibitors, i->id, i) < 0) {
62 void inhibitor_free(Inhibitor *i) {
65 hashmap_remove(i->manager->inhibitors, i->id);
67 inhibitor_remove_fifo(i);
73 unlink(i->state_file);
80 int inhibitor_save(Inhibitor *i) {
81 _cleanup_free_ char *temp_path = NULL;
82 _cleanup_fclose_ FILE *f = NULL;
87 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
91 r = fopen_temporary(i->state_file, &f, &temp_path);
95 fchmod(fileno(f), 0644);
98 "# This is private data. Do not parse.\n"
103 inhibit_what_to_string(i->what),
104 inhibit_mode_to_string(i->mode),
109 _cleanup_free_ char *cc = NULL;
111 cc = cescape(i->who);
117 fprintf(f, "WHO=%s\n", cc);
121 _cleanup_free_ char *cc = NULL;
123 cc = cescape(i->why);
129 fprintf(f, "WHY=%s\n", cc);
133 fprintf(f, "FIFO=%s\n", i->fifo_path);
135 r = fflush_and_check(f);
139 if (rename(temp_path, i->state_file) < 0) {
147 (void) unlink(i->state_file);
150 (void) unlink(temp_path);
152 return log_error_errno(r, "Failed to save inhibit data %s: %m", i->state_file);
155 int inhibitor_start(Inhibitor *i) {
161 dual_timestamp_get(&i->since);
163 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s started.",
164 strna(i->who), strna(i->why),
166 inhibit_mode_to_string(i->mode));
172 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
177 int inhibitor_stop(Inhibitor *i) {
181 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s stopped.",
182 strna(i->who), strna(i->why),
184 inhibit_mode_to_string(i->mode));
187 unlink(i->state_file);
191 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
196 int inhibitor_load(Inhibitor *i) {
211 r = parse_env_file(i->state_file, NEWLINE,
218 "FIFO", &i->fifo_path,
223 w = what ? inhibit_what_from_string(what) : 0;
227 mm = mode ? inhibit_mode_from_string(mode) : INHIBIT_BLOCK;
232 r = parse_uid(uid, &i->uid);
238 r = parse_pid(pid, &i->pid);
244 r = cunescape(who, 0, &cc);
253 r = cunescape(why, 0, &cc);
264 fd = inhibitor_create_fifo(i);
271 static int inhibitor_dispatch_fifo(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
272 Inhibitor *i = userdata;
275 assert(fd == i->fifo_fd);
284 int inhibitor_create_fifo(Inhibitor *i) {
291 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
295 i->fifo_path = strjoin("/run/systemd/inhibit/", i->id, ".ref", NULL);
299 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
303 /* Open reading side */
304 if (i->fifo_fd < 0) {
305 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
310 if (!i->event_source) {
311 r = sd_event_add_io(i->manager->event, &i->event_source, i->fifo_fd, 0, inhibitor_dispatch_fifo, i);
315 r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE);
320 /* Open writing side */
321 r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
328 void inhibitor_remove_fifo(Inhibitor *i) {
331 i->event_source = sd_event_source_unref(i->event_source);
332 i->fifo_fd = safe_close(i->fifo_fd);
335 unlink(i->fifo_path);
336 i->fifo_path = mfree(i->fifo_path);
340 InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
343 InhibitWhat what = 0;
347 HASHMAP_FOREACH(i, m->inhibitors, j)
354 static int pid_is_active(Manager *m, pid_t pid) {
358 r = manager_get_session_by_pid(m, pid, &s);
362 /* If there's no session assigned to it, then it's globally
363 * active on all ttys */
367 return session_is_active(s);
370 bool manager_is_inhibited(
374 dual_timestamp *since,
375 bool ignore_inactive,
378 Inhibitor **offending) {
382 struct dual_timestamp ts = DUAL_TIMESTAMP_NULL;
383 bool inhibited = false;
386 assert(w > 0 && w < _INHIBIT_WHAT_MAX);
388 HASHMAP_FOREACH(i, m->inhibitors, j) {
395 if (ignore_inactive && pid_is_active(m, i->pid) <= 0)
398 if (ignore_uid && i->uid == uid)
402 i->since.monotonic < ts.monotonic)
417 const char *inhibit_what_to_string(InhibitWhat w) {
418 static thread_local char buffer[97];
421 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
425 if (w & INHIBIT_SHUTDOWN)
426 p = stpcpy(p, "shutdown:");
427 if (w & INHIBIT_SLEEP)
428 p = stpcpy(p, "sleep:");
429 if (w & INHIBIT_IDLE)
430 p = stpcpy(p, "idle:");
431 if (w & INHIBIT_HANDLE_POWER_KEY)
432 p = stpcpy(p, "handle-power-key:");
433 if (w & INHIBIT_HANDLE_SUSPEND_KEY)
434 p = stpcpy(p, "handle-suspend-key:");
435 if (w & INHIBIT_HANDLE_HIBERNATE_KEY)
436 p = stpcpy(p, "handle-hibernate-key:");
437 if (w & INHIBIT_HANDLE_LID_SWITCH)
438 p = stpcpy(p, "handle-lid-switch:");
448 InhibitWhat inhibit_what_from_string(const char *s) {
449 InhibitWhat what = 0;
450 const char *word, *state;
453 FOREACH_WORD_SEPARATOR(word, l, s, ":", state) {
454 if (l == 8 && strneq(word, "shutdown", l))
455 what |= INHIBIT_SHUTDOWN;
456 else if (l == 5 && strneq(word, "sleep", l))
457 what |= INHIBIT_SLEEP;
458 else if (l == 4 && strneq(word, "idle", l))
459 what |= INHIBIT_IDLE;
460 else if (l == 16 && strneq(word, "handle-power-key", l))
461 what |= INHIBIT_HANDLE_POWER_KEY;
462 else if (l == 18 && strneq(word, "handle-suspend-key", l))
463 what |= INHIBIT_HANDLE_SUSPEND_KEY;
464 else if (l == 20 && strneq(word, "handle-hibernate-key", l))
465 what |= INHIBIT_HANDLE_HIBERNATE_KEY;
466 else if (l == 17 && strneq(word, "handle-lid-switch", l))
467 what |= INHIBIT_HANDLE_LID_SWITCH;
469 return _INHIBIT_WHAT_INVALID;
475 static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
476 [INHIBIT_BLOCK] = "block",
477 [INHIBIT_DELAY] = "delay"
480 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);