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 = safe_mkdir("/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 parse_uid(uid, &i->uid);
226 parse_pid(pid, &i->pid);
253 fd = inhibitor_create_fifo(i);
255 close_nointr_nofail(fd);
268 int inhibitor_create_fifo(Inhibitor *i) {
275 r = safe_mkdir("/run/systemd/inhibit", 0755, 0, 0);
279 if (asprintf(&i->fifo_path, "/run/systemd/inhibit/%s.ref", i->id) < 0)
282 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
286 /* Open reading side */
287 if (i->fifo_fd < 0) {
288 struct epoll_event ev;
290 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
294 r = hashmap_put(i->manager->inhibitor_fds, INT_TO_PTR(i->fifo_fd + 1), i);
300 ev.data.u32 = FD_FIFO_BASE + i->fifo_fd;
302 if (epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_ADD, i->fifo_fd, &ev) < 0)
306 /* Open writing side */
307 r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
314 void inhibitor_remove_fifo(Inhibitor *i) {
317 if (i->fifo_fd >= 0) {
318 assert_se(hashmap_remove(i->manager->inhibitor_fds, INT_TO_PTR(i->fifo_fd + 1)) == i);
319 assert_se(epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_DEL, i->fifo_fd, NULL) == 0);
320 close_nointr_nofail(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->inhibitor_fds, j)
345 bool manager_is_inhibited(Manager *m, InhibitWhat w, InhibitMode mm, dual_timestamp *since) {
348 struct dual_timestamp ts = { 0, 0 };
349 bool inhibited = false;
352 assert(w > 0 && w < _INHIBIT_WHAT_MAX);
354 HASHMAP_FOREACH(i, m->inhibitor_fds, j) {
362 i->since.monotonic < ts.monotonic)
374 const char *inhibit_what_to_string(InhibitWhat w) {
376 static const char* const table[_INHIBIT_WHAT_MAX] = {
378 [INHIBIT_SHUTDOWN] = "shutdown",
379 [INHIBIT_SLEEP] = "sleep",
380 [INHIBIT_IDLE] = "idle",
381 [INHIBIT_SHUTDOWN|INHIBIT_SLEEP] = "shutdown:sleep",
382 [INHIBIT_SHUTDOWN|INHIBIT_IDLE] = "shutdown:idle",
383 [INHIBIT_SHUTDOWN|INHIBIT_SLEEP|INHIBIT_IDLE] = "shutdown:sleep:idle",
384 [INHIBIT_SLEEP|INHIBIT_IDLE] = "sleep:idle"
387 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
393 InhibitWhat inhibit_what_from_string(const char *s) {
394 InhibitWhat what = 0;
398 FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
399 if (l == 8 && strncmp(w, "shutdown", l) == 0)
400 what |= INHIBIT_SHUTDOWN;
401 else if (l == 5 && strncmp(w, "sleep", l) == 0)
402 what |= INHIBIT_SLEEP;
403 else if (l == 4 && strncmp(w, "idle", l) == 0)
404 what |= INHIBIT_IDLE;
406 return _INHIBIT_WHAT_INVALID;
413 static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
414 [INHIBIT_BLOCK] = "block",
415 [INHIBIT_DELAY] = "delay"
418 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);