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);
137 if (ferror(f) || rename(temp_path, i->state_file) < 0) {
139 unlink(i->state_file);
145 log_error_errno(r, "Failed to save inhibit data %s: %m", i->state_file);
150 int inhibitor_start(Inhibitor *i) {
156 dual_timestamp_get(&i->since);
158 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s started.",
159 strna(i->who), strna(i->why),
161 inhibit_mode_to_string(i->mode));
167 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
172 int inhibitor_stop(Inhibitor *i) {
176 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s stopped.",
177 strna(i->who), strna(i->why),
179 inhibit_mode_to_string(i->mode));
182 unlink(i->state_file);
186 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
191 int inhibitor_load(Inhibitor *i) {
206 r = parse_env_file(i->state_file, NEWLINE,
213 "FIFO", &i->fifo_path,
218 w = what ? inhibit_what_from_string(what) : 0;
222 mm = mode ? inhibit_mode_from_string(mode) : INHIBIT_BLOCK;
227 r = parse_uid(uid, &i->uid);
233 r = parse_pid(pid, &i->pid);
239 r = cunescape(who, 0, &cc);
248 r = cunescape(why, 0, &cc);
259 fd = inhibitor_create_fifo(i);
266 static int inhibitor_dispatch_fifo(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
267 Inhibitor *i = userdata;
270 assert(fd == i->fifo_fd);
279 int inhibitor_create_fifo(Inhibitor *i) {
286 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
290 i->fifo_path = strjoin("/run/systemd/inhibit/", i->id, ".ref", NULL);
294 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
298 /* Open reading side */
299 if (i->fifo_fd < 0) {
300 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
305 if (!i->event_source) {
306 r = sd_event_add_io(i->manager->event, &i->event_source, i->fifo_fd, 0, inhibitor_dispatch_fifo, i);
310 r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE);
315 /* Open writing side */
316 r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
323 void inhibitor_remove_fifo(Inhibitor *i) {
326 i->event_source = sd_event_source_unref(i->event_source);
327 i->fifo_fd = safe_close(i->fifo_fd);
330 unlink(i->fifo_path);
336 InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
339 InhibitWhat what = 0;
343 HASHMAP_FOREACH(i, m->inhibitors, j)
350 static int pid_is_active(Manager *m, pid_t pid) {
354 r = manager_get_session_by_pid(m, pid, &s);
358 /* If there's no session assigned to it, then it's globally
359 * active on all ttys */
363 return session_is_active(s);
366 bool manager_is_inhibited(
370 dual_timestamp *since,
371 bool ignore_inactive,
374 Inhibitor **offending) {
378 struct dual_timestamp ts = DUAL_TIMESTAMP_NULL;
379 bool inhibited = false;
382 assert(w > 0 && w < _INHIBIT_WHAT_MAX);
384 HASHMAP_FOREACH(i, m->inhibitors, j) {
391 if (ignore_inactive && pid_is_active(m, i->pid) <= 0)
394 if (ignore_uid && i->uid == uid)
398 i->since.monotonic < ts.monotonic)
413 const char *inhibit_what_to_string(InhibitWhat w) {
414 static thread_local char buffer[97];
417 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
421 if (w & INHIBIT_SHUTDOWN)
422 p = stpcpy(p, "shutdown:");
423 if (w & INHIBIT_SLEEP)
424 p = stpcpy(p, "sleep:");
425 if (w & INHIBIT_IDLE)
426 p = stpcpy(p, "idle:");
427 if (w & INHIBIT_HANDLE_POWER_KEY)
428 p = stpcpy(p, "handle-power-key:");
429 if (w & INHIBIT_HANDLE_SUSPEND_KEY)
430 p = stpcpy(p, "handle-suspend-key:");
431 if (w & INHIBIT_HANDLE_HIBERNATE_KEY)
432 p = stpcpy(p, "handle-hibernate-key:");
433 if (w & INHIBIT_HANDLE_LID_SWITCH)
434 p = stpcpy(p, "handle-lid-switch:");
444 InhibitWhat inhibit_what_from_string(const char *s) {
445 InhibitWhat what = 0;
446 const char *word, *state;
449 FOREACH_WORD_SEPARATOR(word, l, s, ":", state) {
450 if (l == 8 && strneq(word, "shutdown", l))
451 what |= INHIBIT_SHUTDOWN;
452 else if (l == 5 && strneq(word, "sleep", l))
453 what |= INHIBIT_SLEEP;
454 else if (l == 4 && strneq(word, "idle", l))
455 what |= INHIBIT_IDLE;
456 else if (l == 16 && strneq(word, "handle-power-key", l))
457 what |= INHIBIT_HANDLE_POWER_KEY;
458 else if (l == 18 && strneq(word, "handle-suspend-key", l))
459 what |= INHIBIT_HANDLE_SUSPEND_KEY;
460 else if (l == 20 && strneq(word, "handle-hibernate-key", l))
461 what |= INHIBIT_HANDLE_HIBERNATE_KEY;
462 else if (l == 17 && strneq(word, "handle-lid-switch", l))
463 what |= INHIBIT_HANDLE_LID_SWITCH;
465 return _INHIBIT_WHAT_INVALID;
471 static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
472 [INHIBIT_BLOCK] = "block",
473 [INHIBIT_DELAY] = "delay"
476 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);