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/>.
29 #include "path-util.h"
30 #include "logind-inhibit.h"
33 Inhibitor* inhibitor_new(Manager *m, const char* id) {
38 i = new0(Inhibitor, 1);
42 i->state_file = strappend("/run/systemd/inhibit/", id);
48 i->id = basename(i->state_file);
50 if (hashmap_put(m->inhibitors, i->id, i) < 0) {
62 void inhibitor_free(Inhibitor *i) {
65 hashmap_remove(i->manager->inhibitors, i->id);
67 inhibitor_remove_fifo(i);
73 unlink(i->state_file);
80 int inhibitor_save(Inhibitor *i) {
81 _cleanup_free_ char *temp_path = NULL;
82 _cleanup_fclose_ FILE *f = NULL;
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 _cleanup_free_ char *cc = NULL;
111 cc = cescape(i->who);
115 fprintf(f, "WHO=%s\n", cc);
119 _cleanup_free_ char *cc = NULL;
121 cc = cescape(i->why);
125 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);
141 log_error("Failed to save inhibit data for %s: %s", i->id, strerror(-r));
146 int inhibitor_start(Inhibitor *i) {
152 dual_timestamp_get(&i->since);
154 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s started.",
155 strna(i->who), strna(i->why),
156 (unsigned long) i->pid, (unsigned long) i->uid,
157 inhibit_mode_to_string(i->mode));
163 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
168 int inhibitor_stop(Inhibitor *i) {
172 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s stopped.",
173 strna(i->who), strna(i->why),
174 (unsigned long) i->pid, (unsigned long) i->uid,
175 inhibit_mode_to_string(i->mode));
178 unlink(i->state_file);
182 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
187 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);
255 fd = inhibitor_create_fifo(i);
257 close_nointr_nofail(fd);
263 static int inhibitor_dispatch_fifo(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
264 Inhibitor *i = userdata;
267 assert(fd == i->fifo_fd);
276 int inhibitor_create_fifo(Inhibitor *i) {
283 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
287 i->fifo_path = strjoin("/run/systemd/inhibit/", i->id, ".ref", NULL);
291 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
295 /* Open reading side */
296 if (i->fifo_fd < 0) {
297 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
302 if (!i->event_source) {
303 r = sd_event_add_io(i->manager->event, i->fifo_fd, 0, inhibitor_dispatch_fifo, i, &i->event_source);
307 r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE);
312 /* Open writing side */
313 r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
320 void inhibitor_remove_fifo(Inhibitor *i) {
324 i->event_source = sd_event_source_unref(i->event_source);
326 if (i->fifo_fd >= 0) {
327 close_nointr_nofail(i->fifo_fd);
332 unlink(i->fifo_path);
338 InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
341 InhibitWhat what = 0;
345 HASHMAP_FOREACH(i, m->inhibitors, j)
352 static int pid_is_active(Manager *m, pid_t pid) {
356 r = manager_get_session_by_pid(m, pid, &s);
360 /* If there's no session assigned to it, then it's globally
361 * active on all ttys */
365 return session_is_active(s);
368 bool manager_is_inhibited(
372 dual_timestamp *since,
373 bool ignore_inactive,
376 Inhibitor **offending) {
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)
415 const char *inhibit_what_to_string(InhibitWhat w) {
416 static __thread char buffer[97];
419 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
423 if (w & INHIBIT_SHUTDOWN)
424 p = stpcpy(p, "shutdown:");
425 if (w & INHIBIT_SLEEP)
426 p = stpcpy(p, "sleep:");
427 if (w & INHIBIT_IDLE)
428 p = stpcpy(p, "idle:");
429 if (w & INHIBIT_HANDLE_POWER_KEY)
430 p = stpcpy(p, "handle-power-key:");
431 if (w & INHIBIT_HANDLE_SUSPEND_KEY)
432 p = stpcpy(p, "handle-suspend-key:");
433 if (w & INHIBIT_HANDLE_HIBERNATE_KEY)
434 p = stpcpy(p, "handle-hibernate-key:");
435 if (w & INHIBIT_HANDLE_LID_SWITCH)
436 p = stpcpy(p, "handle-lid-switch:");
446 InhibitWhat inhibit_what_from_string(const char *s) {
447 InhibitWhat what = 0;
451 FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
452 if (l == 8 && strneq(w, "shutdown", l))
453 what |= INHIBIT_SHUTDOWN;
454 else if (l == 5 && strneq(w, "sleep", l))
455 what |= INHIBIT_SLEEP;
456 else if (l == 4 && strneq(w, "idle", l))
457 what |= INHIBIT_IDLE;
458 else if (l == 16 && strneq(w, "handle-power-key", l))
459 what |= INHIBIT_HANDLE_POWER_KEY;
460 else if (l == 18 && strneq(w, "handle-suspend-key", l))
461 what |= INHIBIT_HANDLE_SUSPEND_KEY;
462 else if (l == 20 && strneq(w, "handle-hibernate-key", l))
463 what |= INHIBIT_HANDLE_HIBERNATE_KEY;
464 else if (l == 17 && strneq(w, "handle-lid-switch", l))
465 what |= INHIBIT_HANDLE_LID_SWITCH;
467 return _INHIBIT_WHAT_INVALID;
473 static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
474 [INHIBIT_BLOCK] = "block",
475 [INHIBIT_DELAY] = "delay"
478 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);