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 bool manager_is_inhibited(Manager *m, InhibitWhat w, InhibitMode mm, dual_timestamp *since) {
354 struct dual_timestamp ts = { 0, 0 };
355 bool inhibited = false;
358 assert(w > 0 && w < _INHIBIT_WHAT_MAX);
360 HASHMAP_FOREACH(i, m->inhibitor_fds, j) {
368 i->since.monotonic < ts.monotonic)
380 const char *inhibit_what_to_string(InhibitWhat w) {
382 static const char* const table[_INHIBIT_WHAT_MAX] = {
384 [INHIBIT_SHUTDOWN] = "shutdown",
385 [INHIBIT_SLEEP] = "sleep",
386 [INHIBIT_IDLE] = "idle",
387 [INHIBIT_SHUTDOWN|INHIBIT_SLEEP] = "shutdown:sleep",
388 [INHIBIT_SHUTDOWN|INHIBIT_IDLE] = "shutdown:idle",
389 [INHIBIT_SHUTDOWN|INHIBIT_SLEEP|INHIBIT_IDLE] = "shutdown:sleep:idle",
390 [INHIBIT_SLEEP|INHIBIT_IDLE] = "sleep:idle"
393 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
399 InhibitWhat inhibit_what_from_string(const char *s) {
400 InhibitWhat what = 0;
404 FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
405 if (l == 8 && strncmp(w, "shutdown", l) == 0)
406 what |= INHIBIT_SHUTDOWN;
407 else if (l == 5 && strncmp(w, "sleep", l) == 0)
408 what |= INHIBIT_SLEEP;
409 else if (l == 4 && strncmp(w, "idle", l) == 0)
410 what |= INHIBIT_IDLE;
412 return _INHIBIT_WHAT_INVALID;
419 static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
420 [INHIBIT_BLOCK] = "block",
421 [INHIBIT_DELAY] = "delay"
424 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);