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>
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 = file_name_from_path(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"
102 inhibit_what_to_string(i->what),
103 (unsigned long) i->uid,
104 (unsigned long) i->pid);
107 cc = cescape(i->who);
111 fprintf(f, "WHO=%s\n", cc);
117 cc = cescape(i->why);
121 fprintf(f, "WHY=%s\n", cc);
127 fprintf(f, "FIFO=%s\n", i->fifo_path);
131 if (ferror(f) || rename(temp_path, i->state_file) < 0) {
133 unlink(i->state_file);
142 log_error("Failed to save inhibit data for %s: %s", i->id, strerror(-r));
147 int inhibitor_start(Inhibitor *i) {
153 dual_timestamp_get(&i->since);
155 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu started.",
156 strna(i->who), strna(i->why),
157 (unsigned long) i->pid, (unsigned long) i->uid);
163 manager_send_changed(i->manager, "Inhibited\0");
168 int inhibitor_stop(Inhibitor *i) {
172 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu stopped.",
173 strna(i->who), strna(i->why),
174 (unsigned long) i->pid, (unsigned long) i->uid);
177 unlink(i->state_file);
181 manager_send_changed(i->manager, "Inhibited\0");
186 int inhibitor_load(Inhibitor *i) {
196 r = parse_env_file(i->state_file, NEWLINE,
202 "FIFO", &i->fifo_path,
207 w = inhibit_what_from_string(what);
211 parse_uid(uid, &i->uid);
212 parse_pid(pid, &i->pid);
239 fd = inhibitor_create_fifo(i);
241 close_nointr_nofail(fd);
254 int inhibitor_create_fifo(Inhibitor *i) {
261 r = safe_mkdir("/run/systemd/inhibit", 0755, 0, 0);
265 if (asprintf(&i->fifo_path, "/run/systemd/inhibit/%s.ref", i->id) < 0)
268 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
272 /* Open reading side */
273 if (i->fifo_fd < 0) {
274 struct epoll_event ev;
276 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
280 r = hashmap_put(i->manager->inhibitor_fds, INT_TO_PTR(i->fifo_fd + 1), i);
286 ev.data.u32 = FD_FIFO_BASE + i->fifo_fd;
288 if (epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_ADD, i->fifo_fd, &ev) < 0)
292 /* Open writing side */
293 r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
300 void inhibitor_remove_fifo(Inhibitor *i) {
303 if (i->fifo_fd >= 0) {
304 assert_se(hashmap_remove(i->manager->inhibitor_fds, INT_TO_PTR(i->fifo_fd + 1)) == i);
305 assert_se(epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_DEL, i->fifo_fd, NULL) == 0);
306 close_nointr_nofail(i->fifo_fd);
311 unlink(i->fifo_path);
317 InhibitWhat manager_inhibit_what(Manager *m) {
320 InhibitWhat what = 0;
324 HASHMAP_FOREACH(i, m->inhibitor_fds, j)
330 bool manager_is_inhibited(Manager *m, InhibitWhat w, dual_timestamp *since) {
333 struct dual_timestamp ts = { 0, 0 };
334 bool inhibited = false;
337 assert(w > 0 && w < _INHIBIT_WHAT_MAX);
339 HASHMAP_FOREACH(i, m->inhibitor_fds, j) {
344 i->since.monotonic < ts.monotonic)
356 const char *inhibit_what_to_string(InhibitWhat w) {
358 static const char* const table[_INHIBIT_WHAT_MAX] = {
360 [INHIBIT_SHUTDOWN] = "shutdown",
361 [INHIBIT_SUSPEND] = "suspend",
362 [INHIBIT_IDLE] = "idle",
363 [INHIBIT_SHUTDOWN|INHIBIT_SUSPEND] = "shutdown:suspend",
364 [INHIBIT_SHUTDOWN|INHIBIT_IDLE] = "shutdown:idle",
365 [INHIBIT_SHUTDOWN|INHIBIT_SUSPEND|INHIBIT_IDLE] = "shutdown:suspend:idle",
366 [INHIBIT_SUSPEND|INHIBIT_IDLE] = "suspend:idle"
369 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
375 InhibitWhat inhibit_what_from_string(const char *s) {
376 InhibitWhat what = 0;
380 FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
381 if (l == 8 && strncmp(w, "shutdown", l) == 0)
382 what |= INHIBIT_SHUTDOWN;
383 else if (l == 7 && strncmp(w, "suspend", l) == 0)
384 what |= INHIBIT_SUSPEND;
385 else if (l == 4 && strncmp(w, "idle", l) == 0)
386 what |= INHIBIT_IDLE;
388 return _INHIBIT_WHAT_INVALID;