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"
34 Inhibitor* inhibitor_new(Manager *m, const char* id) {
39 i = new0(Inhibitor, 1);
43 i->state_file = strappend("/run/systemd/inhibit/", id);
49 i->id = path_get_file_name(i->state_file);
51 if (hashmap_put(m->inhibitors, i->id, i) < 0) {
63 void inhibitor_free(Inhibitor *i) {
69 hashmap_remove(i->manager->inhibitors, i->id);
70 inhibitor_remove_fifo(i);
73 unlink(i->state_file);
80 int inhibitor_save(Inhibitor *i) {
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),
105 (unsigned long) i->uid,
106 (unsigned long) i->pid);
109 cc = cescape(i->who);
113 fprintf(f, "WHO=%s\n", cc);
119 cc = cescape(i->why);
123 fprintf(f, "WHY=%s\n", cc);
129 fprintf(f, "FIFO=%s\n", i->fifo_path);
133 if (ferror(f) || rename(temp_path, i->state_file) < 0) {
135 unlink(i->state_file);
144 log_error("Failed to save inhibit data for %s: %s", i->id, strerror(-r));
149 int inhibitor_start(Inhibitor *i) {
155 dual_timestamp_get(&i->since);
157 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s started.",
158 strna(i->who), strna(i->why),
159 (unsigned long) i->pid, (unsigned long) i->uid,
160 inhibit_mode_to_string(i->mode));
166 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited\0" : "DelayInhibited\0");
171 int inhibitor_stop(Inhibitor *i) {
175 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s stopped.",
176 strna(i->who), strna(i->why),
177 (unsigned long) i->pid, (unsigned long) i->uid,
178 inhibit_mode_to_string(i->mode));
181 unlink(i->state_file);
185 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited\0" : "DelayInhibited\0");
190 int inhibitor_load(Inhibitor *i) {
202 r = parse_env_file(i->state_file, NEWLINE,
209 "FIFO", &i->fifo_path,
214 w = what ? inhibit_what_from_string(what) : 0;
218 mm = mode ? inhibit_mode_from_string(mode) : INHIBIT_BLOCK;
223 r = parse_uid(uid, &i->uid);
229 r = parse_pid(pid, &i->pid);
259 fd = inhibitor_create_fifo(i);
261 close_nointr_nofail(fd);
274 int inhibitor_create_fifo(Inhibitor *i) {
281 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
285 if (asprintf(&i->fifo_path, "/run/systemd/inhibit/%s.ref", i->id) < 0)
288 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
292 /* Open reading side */
293 if (i->fifo_fd < 0) {
294 struct epoll_event ev;
296 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
300 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 return session_is_active(s);
362 bool manager_is_inhibited(
366 dual_timestamp *since,
367 bool ignore_inactive,
373 struct dual_timestamp ts = { 0, 0 };
374 bool inhibited = false;
377 assert(w > 0 && w < _INHIBIT_WHAT_MAX);
379 HASHMAP_FOREACH(i, m->inhibitor_fds, 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)
405 const char *inhibit_what_to_string(InhibitWhat w) {
406 static __thread char buffer[97];
409 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
413 if (w & INHIBIT_SHUTDOWN)
414 p = stpcpy(p, "shutdown:");
415 if (w & INHIBIT_SLEEP)
416 p = stpcpy(p, "sleep:");
417 if (w & INHIBIT_IDLE)
418 p = stpcpy(p, "idle:");
419 if (w & INHIBIT_HANDLE_POWER_KEY)
420 p = stpcpy(p, "handle-power-key:");
421 if (w & INHIBIT_HANDLE_SUSPEND_KEY)
422 p = stpcpy(p, "handle-suspend-key:");
423 if (w & INHIBIT_HANDLE_HIBERNATE_KEY)
424 p = stpcpy(p, "handle-hibernate-key:");
425 if (w & INHIBIT_HANDLE_LID_SWITCH)
426 p = stpcpy(p, "handle-lid-switch:");
436 InhibitWhat inhibit_what_from_string(const char *s) {
437 InhibitWhat what = 0;
441 FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
442 if (l == 8 && strneq(w, "shutdown", l))
443 what |= INHIBIT_SHUTDOWN;
444 else if (l == 5 && strneq(w, "sleep", l))
445 what |= INHIBIT_SLEEP;
446 else if (l == 4 && strneq(w, "idle", l))
447 what |= INHIBIT_IDLE;
448 else if (l == 16 && strneq(w, "handle-power-key", l))
449 what |= INHIBIT_HANDLE_POWER_KEY;
450 else if (l == 18 && strneq(w, "handle-suspend-key", l))
451 what |= INHIBIT_HANDLE_SUSPEND_KEY;
452 else if (l == 20 && strneq(w, "handle-hibernate-key", l))
453 what |= INHIBIT_HANDLE_HIBERNATE_KEY;
454 else if (l == 17 && strneq(w, "handle-lid-switch", l))
455 what |= INHIBIT_HANDLE_LID_SWITCH;
457 return _INHIBIT_WHAT_INVALID;
463 static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
464 [INHIBIT_BLOCK] = "block",
465 [INHIBIT_DELAY] = "delay"
468 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);