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/>.
30 #include "path-util.h"
31 #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) {
66 hashmap_remove(i->manager->inhibitors, i->id);
68 inhibitor_remove_fifo(i);
74 unlink(i->state_file);
81 int inhibitor_save(Inhibitor *i) {
82 _cleanup_free_ char *temp_path = NULL;
83 _cleanup_fclose_ FILE *f = NULL;
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 _cleanup_free_ char *cc = NULL;
112 cc = cescape(i->who);
116 fprintf(f, "WHO=%s\n", cc);
120 _cleanup_free_ char *cc = NULL;
122 cc = cescape(i->why);
126 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);
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 mode=%s started.",
156 strna(i->who), strna(i->why),
157 (unsigned long) i->pid, (unsigned long) i->uid,
158 inhibit_mode_to_string(i->mode));
164 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
169 int inhibitor_stop(Inhibitor *i) {
173 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s stopped.",
174 strna(i->who), strna(i->why),
175 (unsigned long) i->pid, (unsigned long) i->uid,
176 inhibit_mode_to_string(i->mode));
179 unlink(i->state_file);
183 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
188 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);
256 fd = inhibitor_create_fifo(i);
258 close_nointr_nofail(fd);
264 static int inhibitor_dispatch_fifo(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
265 Inhibitor *i = userdata;
268 assert(fd == i->fifo_fd);
277 int inhibitor_create_fifo(Inhibitor *i) {
284 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
288 i->fifo_path = strjoin("/run/systemd/inhibit/", i->id, ".ref", NULL);
292 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
296 /* Open reading side */
297 if (i->fifo_fd < 0) {
298 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
303 if (!i->event_source) {
304 r = sd_event_add_io(i->manager->event, i->fifo_fd, 0, inhibitor_dispatch_fifo, i, &i->event_source);
308 r = sd_event_source_set_priority(i->event_source, SD_PRIORITY_IDLE);
313 /* Open writing side */
314 r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
321 void inhibitor_remove_fifo(Inhibitor *i) {
325 i->event_source = sd_event_source_unref(i->event_source);
327 if (i->fifo_fd >= 0) {
328 close_nointr_nofail(i->fifo_fd);
333 unlink(i->fifo_path);
339 InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
342 InhibitWhat what = 0;
346 HASHMAP_FOREACH(i, m->inhibitors, j)
353 static int pid_is_active(Manager *m, pid_t pid) {
357 r = manager_get_session_by_pid(m, pid, &s);
361 /* If there's no session assigned to it, then it's globally
362 * active on all ttys */
366 return session_is_active(s);
369 bool manager_is_inhibited(
373 dual_timestamp *since,
374 bool ignore_inactive,
380 struct dual_timestamp ts = { 0, 0 };
381 bool inhibited = false;
384 assert(w > 0 && w < _INHIBIT_WHAT_MAX);
386 HASHMAP_FOREACH(i, m->inhibitors, j) {
393 if (ignore_inactive && pid_is_active(m, i->pid) <= 0)
396 if (ignore_uid && i->uid == uid)
400 i->since.monotonic < ts.monotonic)
412 const char *inhibit_what_to_string(InhibitWhat w) {
413 static __thread char buffer[97];
416 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
420 if (w & INHIBIT_SHUTDOWN)
421 p = stpcpy(p, "shutdown:");
422 if (w & INHIBIT_SLEEP)
423 p = stpcpy(p, "sleep:");
424 if (w & INHIBIT_IDLE)
425 p = stpcpy(p, "idle:");
426 if (w & INHIBIT_HANDLE_POWER_KEY)
427 p = stpcpy(p, "handle-power-key:");
428 if (w & INHIBIT_HANDLE_SUSPEND_KEY)
429 p = stpcpy(p, "handle-suspend-key:");
430 if (w & INHIBIT_HANDLE_HIBERNATE_KEY)
431 p = stpcpy(p, "handle-hibernate-key:");
432 if (w & INHIBIT_HANDLE_LID_SWITCH)
433 p = stpcpy(p, "handle-lid-switch:");
443 InhibitWhat inhibit_what_from_string(const char *s) {
444 InhibitWhat what = 0;
448 FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
449 if (l == 8 && strneq(w, "shutdown", l))
450 what |= INHIBIT_SHUTDOWN;
451 else if (l == 5 && strneq(w, "sleep", l))
452 what |= INHIBIT_SLEEP;
453 else if (l == 4 && strneq(w, "idle", l))
454 what |= INHIBIT_IDLE;
455 else if (l == 16 && strneq(w, "handle-power-key", l))
456 what |= INHIBIT_HANDLE_POWER_KEY;
457 else if (l == 18 && strneq(w, "handle-suspend-key", l))
458 what |= INHIBIT_HANDLE_SUSPEND_KEY;
459 else if (l == 20 && strneq(w, "handle-hibernate-key", l))
460 what |= INHIBIT_HANDLE_HIBERNATE_KEY;
461 else if (l == 17 && strneq(w, "handle-lid-switch", l))
462 what |= INHIBIT_HANDLE_LID_SWITCH;
464 return _INHIBIT_WHAT_INVALID;
470 static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
471 [INHIBIT_BLOCK] = "block",
472 [INHIBIT_DELAY] = "delay"
475 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);