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/>.
24 #include <sys/epoll.h>
31 #include "path-util.h"
32 #include "logind-inhibit.h"
35 Inhibitor* inhibitor_new(Manager *m, const char* id) {
40 i = new0(Inhibitor, 1);
44 i->state_file = strappend("/run/systemd/inhibit/", id);
50 i->id = path_get_file_name(i->state_file);
52 if (hashmap_put(m->inhibitors, i->id, i) < 0) {
64 void inhibitor_free(Inhibitor *i) {
70 hashmap_remove(i->manager->inhibitors, i->id);
71 inhibitor_remove_fifo(i);
74 unlink(i->state_file);
81 int inhibitor_save(Inhibitor *i) {
88 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
92 r = fopen_temporary(i->state_file, &f, &temp_path);
96 fchmod(fileno(f), 0644);
99 "# This is private data. Do not parse.\n"
104 inhibit_what_to_string(i->what),
105 inhibit_mode_to_string(i->mode),
106 (unsigned long) i->uid,
107 (unsigned long) i->pid);
110 cc = cescape(i->who);
114 fprintf(f, "WHO=%s\n", cc);
120 cc = cescape(i->why);
124 fprintf(f, "WHY=%s\n", cc);
130 fprintf(f, "FIFO=%s\n", i->fifo_path);
134 if (ferror(f) || rename(temp_path, i->state_file) < 0) {
136 unlink(i->state_file);
145 log_error("Failed to save inhibit data for %s: %s", i->id, strerror(-r));
150 int inhibitor_start(Inhibitor *i) {
156 dual_timestamp_get(&i->since);
158 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s started.",
159 strna(i->who), strna(i->why),
160 (unsigned long) i->pid, (unsigned long) i->uid,
161 inhibit_mode_to_string(i->mode));
167 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited\0" : "DelayInhibited\0");
172 int inhibitor_stop(Inhibitor *i) {
176 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s stopped.",
177 strna(i->who), strna(i->why),
178 (unsigned long) i->pid, (unsigned long) i->uid,
179 inhibit_mode_to_string(i->mode));
182 unlink(i->state_file);
186 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited\0" : "DelayInhibited\0");
191 int inhibitor_load(Inhibitor *i) {
203 r = parse_env_file(i->state_file, NEWLINE,
210 "FIFO", &i->fifo_path,
215 w = what ? inhibit_what_from_string(what) : 0;
219 mm = mode ? inhibit_mode_from_string(mode) : INHIBIT_BLOCK;
224 r = parse_uid(uid, &i->uid);
230 r = parse_pid(pid, &i->pid);
260 fd = inhibitor_create_fifo(i);
262 close_nointr_nofail(fd);
275 int inhibitor_create_fifo(Inhibitor *i) {
282 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
286 if (asprintf(&i->fifo_path, "/run/systemd/inhibit/%s.ref", i->id) < 0)
289 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
293 /* Open reading side */
294 if (i->fifo_fd < 0) {
295 struct epoll_event ev = {};
297 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
301 r = hashmap_put(i->manager->inhibitor_fds, INT_TO_PTR(i->fifo_fd + 1), i);
306 ev.data.u32 = FD_OTHER_BASE + i->fifo_fd;
308 if (epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_ADD, i->fifo_fd, &ev) < 0)
312 /* Open writing side */
313 r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
320 void inhibitor_remove_fifo(Inhibitor *i) {
323 if (i->fifo_fd >= 0) {
324 assert_se(hashmap_remove(i->manager->inhibitor_fds, INT_TO_PTR(i->fifo_fd + 1)) == i);
325 assert_se(epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_DEL, i->fifo_fd, NULL) == 0);
326 close_nointr_nofail(i->fifo_fd);
331 unlink(i->fifo_path);
337 InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
340 InhibitWhat what = 0;
344 HASHMAP_FOREACH(i, m->inhibitor_fds, j)
351 static int pid_is_active(Manager *m, pid_t pid) {
355 r = manager_get_session_by_pid(m, pid, &s);
359 /* If there's no session assigned to it, then it's globally
360 * active on all ttys */
364 return session_is_active(s);
367 bool manager_is_inhibited(
371 dual_timestamp *since,
372 bool ignore_inactive,
378 struct dual_timestamp ts = { 0, 0 };
379 bool inhibited = false;
382 assert(w > 0 && w < _INHIBIT_WHAT_MAX);
384 HASHMAP_FOREACH(i, m->inhibitor_fds, 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)
410 const char *inhibit_what_to_string(InhibitWhat w) {
411 static __thread char buffer[97];
414 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
418 if (w & INHIBIT_SHUTDOWN)
419 p = stpcpy(p, "shutdown:");
420 if (w & INHIBIT_SLEEP)
421 p = stpcpy(p, "sleep:");
422 if (w & INHIBIT_IDLE)
423 p = stpcpy(p, "idle:");
424 if (w & INHIBIT_HANDLE_POWER_KEY)
425 p = stpcpy(p, "handle-power-key:");
426 if (w & INHIBIT_HANDLE_SUSPEND_KEY)
427 p = stpcpy(p, "handle-suspend-key:");
428 if (w & INHIBIT_HANDLE_HIBERNATE_KEY)
429 p = stpcpy(p, "handle-hibernate-key:");
430 if (w & INHIBIT_HANDLE_LID_SWITCH)
431 p = stpcpy(p, "handle-lid-switch:");
441 InhibitWhat inhibit_what_from_string(const char *s) {
442 InhibitWhat what = 0;
446 FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
447 if (l == 8 && strneq(w, "shutdown", l))
448 what |= INHIBIT_SHUTDOWN;
449 else if (l == 5 && strneq(w, "sleep", l))
450 what |= INHIBIT_SLEEP;
451 else if (l == 4 && strneq(w, "idle", l))
452 what |= INHIBIT_IDLE;
453 else if (l == 16 && strneq(w, "handle-power-key", l))
454 what |= INHIBIT_HANDLE_POWER_KEY;
455 else if (l == 18 && strneq(w, "handle-suspend-key", l))
456 what |= INHIBIT_HANDLE_SUSPEND_KEY;
457 else if (l == 20 && strneq(w, "handle-hibernate-key", l))
458 what |= INHIBIT_HANDLE_HIBERNATE_KEY;
459 else if (l == 17 && strneq(w, "handle-lid-switch", l))
460 what |= INHIBIT_HANDLE_LID_SWITCH;
462 return _INHIBIT_WHAT_INVALID;
468 static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
469 [INHIBIT_BLOCK] = "block",
470 [INHIBIT_DELAY] = "delay"
473 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);