chiark / gitweb /
shared: add terminal-util.[ch]
[elogind.git] / src / login / logind-inhibit.c
index b5b801e5e09a84bcbaa8d9cb43391c66e0304366..68304a1610dd3b4b5a5c702ee4df78f933257395 100644 (file)
 
 #include <errno.h>
 #include <fcntl.h>
-#include <sys/epoll.h>
 #include <string.h>
-#include <errno.h>
 #include <unistd.h>
 
 #include "util.h"
 #include "mkdir.h"
-#include "path-util.h"
 #include "logind-inhibit.h"
+#include "fileio.h"
+#include "formats-util.h"
 
 Inhibitor* inhibitor_new(Manager *m, const char* id) {
         Inhibitor *i;
@@ -46,7 +45,7 @@ Inhibitor* inhibitor_new(Manager *m, const char* id) {
                 return NULL;
         }
 
-        i->id = path_get_file_name(i->state_file);
+        i->id = basename(i->state_file);
 
         if (hashmap_put(m->inhibitors, i->id, i) < 0) {
                 free(i->state_file);
@@ -63,12 +62,13 @@ Inhibitor* inhibitor_new(Manager *m, const char* id) {
 void inhibitor_free(Inhibitor *i) {
         assert(i);
 
-        free(i->who);
-        free(i->why);
-
         hashmap_remove(i->manager->inhibitors, i->id);
+
         inhibitor_remove_fifo(i);
 
+        free(i->who);
+        free(i->why);
+
         if (i->state_file) {
                 unlink(i->state_file);
                 free(i->state_file);
@@ -78,13 +78,13 @@ void inhibitor_free(Inhibitor *i) {
 }
 
 int inhibitor_save(Inhibitor *i) {
-        char *temp_path, *cc;
+        _cleanup_free_ char *temp_path = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
         int r;
-        FILE *f;
 
         assert(i);
 
-        r = safe_mkdir("/run/systemd/inhibit", 0755, 0, 0);
+        r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
         if (r < 0)
                 goto finish;
 
@@ -98,31 +98,31 @@ int inhibitor_save(Inhibitor *i) {
                 "# This is private data. Do not parse.\n"
                 "WHAT=%s\n"
                 "MODE=%s\n"
-                "UID=%lu\n"
-                "PID=%lu\n",
+                "UID="UID_FMT"\n"
+                "PID="PID_FMT"\n",
                 inhibit_what_to_string(i->what),
                 inhibit_mode_to_string(i->mode),
-                (unsigned long) i->uid,
-                (unsigned long) i->pid);
+                i->uid,
+                i->pid);
 
         if (i->who) {
+                _cleanup_free_ char *cc = NULL;
+
                 cc = cescape(i->who);
                 if (!cc)
                         r = -ENOMEM;
-                else {
+                else
                         fprintf(f, "WHO=%s\n", cc);
-                        free(cc);
-                }
         }
 
         if (i->why) {
+                _cleanup_free_ char *cc = NULL;
+
                 cc = cescape(i->why);
                 if (!cc)
                         r = -ENOMEM;
-                else {
+                else
                         fprintf(f, "WHY=%s\n", cc);
-                        free(cc);
-                }
         }
 
         if (i->fifo_path)
@@ -136,12 +136,9 @@ int inhibitor_save(Inhibitor *i) {
                 unlink(temp_path);
         }
 
-        fclose(f);
-        free(temp_path);
-
 finish:
         if (r < 0)
-                log_error("Failed to save inhibit data for %s: %s", i->id, strerror(-r));
+                log_error_errno(r, "Failed to save inhibit data %s: %m", i->state_file);
 
         return r;
 }
@@ -154,16 +151,16 @@ int inhibitor_start(Inhibitor *i) {
 
         dual_timestamp_get(&i->since);
 
-        log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s started.",
+        log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s started.",
                   strna(i->who), strna(i->why),
-                  (unsigned long) i->pid, (unsigned long) i->uid,
+                  i->pid, i->uid,
                   inhibit_mode_to_string(i->mode));
 
         inhibitor_save(i);
 
         i->started = true;
 
-        manager_send_changed(i->manager, "Inhibited\0");
+        manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
 
         return 0;
 }
@@ -172,9 +169,9 @@ int inhibitor_stop(Inhibitor *i) {
         assert(i);
 
         if (i->started)
-                log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s stopped.",
+                log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s stopped.",
                           strna(i->who), strna(i->why),
-                          (unsigned long) i->pid, (unsigned long) i->uid,
+                          i->pid, i->uid,
                           inhibit_mode_to_string(i->mode));
 
         if (i->state_file)
@@ -182,16 +179,14 @@ int inhibitor_stop(Inhibitor *i) {
 
         i->started = false;
 
-        manager_send_changed(i->manager, "Inhibited\0");
+        manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
 
         return 0;
 }
 
 int inhibitor_load(Inhibitor *i) {
-        InhibitWhat w;
-        InhibitMode mm;
-        int r;
-        char *cc,
+
+        _cleanup_free_ char
                 *what = NULL,
                 *uid = NULL,
                 *pid = NULL,
@@ -199,6 +194,11 @@ int inhibitor_load(Inhibitor *i) {
                 *why = NULL,
                 *mode = NULL;
 
+        InhibitWhat w;
+        InhibitMode mm;
+        char *cc;
+        int r;
+
         r = parse_env_file(i->state_file, NEWLINE,
                            "WHAT", &what,
                            "UID", &uid,
@@ -209,7 +209,7 @@ int inhibitor_load(Inhibitor *i) {
                            "FIFO", &i->fifo_path,
                            NULL);
         if (r < 0)
-                goto finish;
+                return r;
 
         w = what ? inhibit_what_from_string(what) : 0;
         if (w >= 0)
@@ -219,29 +219,31 @@ int inhibitor_load(Inhibitor *i) {
         if  (mm >= 0)
                 i->mode = mm;
 
-        if (uid)
-                parse_uid(uid, &i->uid);
+        if (uid) {
+                r = parse_uid(uid, &i->uid);
+                if (r < 0)
+                        return r;
+        }
 
-        if (pid)
-                parse_pid(pid, &i->pid);
+        if (pid) {
+                r = parse_pid(pid, &i->pid);
+                if (r < 0)
+                        return r;
+        }
 
         if (who) {
-                cc = cunescape(who);
-                if (!cc) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
+                r = cunescape(who, 0, &cc);
+                if (r < 0)
+                        return r;
 
                 free(i->who);
                 i->who = cc;
         }
 
         if (why) {
-                cc = cunescape(why);
-                if (!cc) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
+                r = cunescape(why, 0, &cc);
+                if (r < 0)
+                        return r;
 
                 free(i->why);
                 i->why = cc;
@@ -251,18 +253,23 @@ int inhibitor_load(Inhibitor *i) {
                 int fd;
 
                 fd = inhibitor_create_fifo(i);
-                if (fd >= 0)
-                        close_nointr_nofail(fd);
+                safe_close(fd);
         }
 
-finish:
-        free(what);
-        free(uid);
-        free(pid);
-        free(who);
-        free(why);
+        return 0;
+}
 
-        return r;
+static int inhibitor_dispatch_fifo(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        Inhibitor *i = userdata;
+
+        assert(s);
+        assert(fd == i->fifo_fd);
+        assert(i);
+
+        inhibitor_stop(i);
+        inhibitor_free(i);
+
+        return 0;
 }
 
 int inhibitor_create_fifo(Inhibitor *i) {
@@ -272,11 +279,12 @@ int inhibitor_create_fifo(Inhibitor *i) {
 
         /* Create FIFO */
         if (!i->fifo_path) {
-                r = safe_mkdir("/run/systemd/inhibit", 0755, 0, 0);
+                r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
                 if (r < 0)
                         return r;
 
-                if (asprintf(&i->fifo_path, "/run/systemd/inhibit/%s.ref", i->id) < 0)
+                i->fifo_path = strjoin("/run/systemd/inhibit/", i->id, ".ref", NULL);
+                if (!i->fifo_path)
                         return -ENOMEM;
 
                 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
@@ -285,22 +293,19 @@ int inhibitor_create_fifo(Inhibitor *i) {
 
         /* Open reading side */
         if (i->fifo_fd < 0) {
-                struct epoll_event ev;
-
                 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
                 if (i->fifo_fd < 0)
                         return -errno;
+        }
 
-                r = hashmap_put(i->manager->inhibitor_fds, INT_TO_PTR(i->fifo_fd + 1), i);
+        if (!i->event_source) {
+                r = sd_event_add_io(i->manager->event, &i->event_source, i->fifo_fd, 0, inhibitor_dispatch_fifo, i);
                 if (r < 0)
                         return r;
 
-                zero(ev);
-                ev.events = 0;
-                ev.data.u32 = FD_FIFO_BASE + i->fifo_fd;
-
-                if (epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_ADD, i->fifo_fd, &ev) < 0)
-                        return -errno;
+                r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE);
+                if (r < 0)
+                        return r;
         }
 
         /* Open writing side */
@@ -314,12 +319,8 @@ int inhibitor_create_fifo(Inhibitor *i) {
 void inhibitor_remove_fifo(Inhibitor *i) {
         assert(i);
 
-        if (i->fifo_fd >= 0) {
-                assert_se(hashmap_remove(i->manager->inhibitor_fds, INT_TO_PTR(i->fifo_fd + 1)) == i);
-                assert_se(epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_DEL, i->fifo_fd, NULL) == 0);
-                close_nointr_nofail(i->fifo_fd);
-                i->fifo_fd = -1;
-        }
+        i->event_source = sd_event_source_unref(i->event_source);
+        i->fifo_fd = safe_close(i->fifo_fd);
 
         if (i->fifo_path) {
                 unlink(i->fifo_path);
@@ -335,14 +336,39 @@ InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
 
         assert(m);
 
-        HASHMAP_FOREACH(i, m->inhibitor_fds, j)
+        HASHMAP_FOREACH(i, m->inhibitors, j)
                 if (i->mode == mm)
                         what |= i->what;
 
         return what;
 }
 
-bool manager_is_inhibited(Manager *m, InhibitWhat w, InhibitMode mm, dual_timestamp *since) {
+static int pid_is_active(Manager *m, pid_t pid) {
+        Session *s;
+        int r;
+
+        r = manager_get_session_by_pid(m, pid, &s);
+        if (r < 0)
+                return r;
+
+        /* If there's no session assigned to it, then it's globally
+         * active on all ttys */
+        if (r == 0)
+                return 1;
+
+        return session_is_active(s);
+}
+
+bool manager_is_inhibited(
+                Manager *m,
+                InhibitWhat w,
+                InhibitMode mm,
+                dual_timestamp *since,
+                bool ignore_inactive,
+                bool ignore_uid,
+                uid_t uid,
+                Inhibitor **offending) {
+
         Inhibitor *i;
         Iterator j;
         struct dual_timestamp ts = { 0, 0 };
@@ -351,18 +377,27 @@ bool manager_is_inhibited(Manager *m, InhibitWhat w, InhibitMode mm, dual_timest
         assert(m);
         assert(w > 0 && w < _INHIBIT_WHAT_MAX);
 
-        HASHMAP_FOREACH(i, m->inhibitor_fds, j) {
+        HASHMAP_FOREACH(i, m->inhibitors, j) {
                 if (!(i->what & w))
                         continue;
 
                 if (i->mode != mm)
                         continue;
 
+                if (ignore_inactive && pid_is_active(m, i->pid) <= 0)
+                        continue;
+
+                if (ignore_uid && i->uid == uid)
+                        continue;
+
                 if (!inhibited ||
                     i->since.monotonic < ts.monotonic)
                         ts = i->since;
 
                 inhibited = true;
+
+                if (offending)
+                        *offending = i;
         }
 
         if (since)
@@ -372,42 +407,61 @@ bool manager_is_inhibited(Manager *m, InhibitWhat w, InhibitMode mm, dual_timest
 }
 
 const char *inhibit_what_to_string(InhibitWhat w) {
-
-        static const char* const table[_INHIBIT_WHAT_MAX] = {
-                [0] = "",
-                [INHIBIT_SHUTDOWN] = "shutdown",
-                [INHIBIT_SUSPEND] = "suspend",
-                [INHIBIT_IDLE] = "idle",
-                [INHIBIT_SHUTDOWN|INHIBIT_SUSPEND] = "shutdown:suspend",
-                [INHIBIT_SHUTDOWN|INHIBIT_IDLE] = "shutdown:idle",
-                [INHIBIT_SHUTDOWN|INHIBIT_SUSPEND|INHIBIT_IDLE] = "shutdown:suspend:idle",
-                [INHIBIT_SUSPEND|INHIBIT_IDLE] = "suspend:idle"
-        };
+        static thread_local char buffer[97];
+        char *p;
 
         if (w < 0 || w >= _INHIBIT_WHAT_MAX)
                 return NULL;
 
-        return table[w];
+        p = buffer;
+        if (w & INHIBIT_SHUTDOWN)
+                p = stpcpy(p, "shutdown:");
+        if (w & INHIBIT_SLEEP)
+                p = stpcpy(p, "sleep:");
+        if (w & INHIBIT_IDLE)
+                p = stpcpy(p, "idle:");
+        if (w & INHIBIT_HANDLE_POWER_KEY)
+                p = stpcpy(p, "handle-power-key:");
+        if (w & INHIBIT_HANDLE_SUSPEND_KEY)
+                p = stpcpy(p, "handle-suspend-key:");
+        if (w & INHIBIT_HANDLE_HIBERNATE_KEY)
+                p = stpcpy(p, "handle-hibernate-key:");
+        if (w & INHIBIT_HANDLE_LID_SWITCH)
+                p = stpcpy(p, "handle-lid-switch:");
+
+        if (p > buffer)
+                *(p-1) = 0;
+        else
+                *p = 0;
+
+        return buffer;
 }
 
 InhibitWhat inhibit_what_from_string(const char *s) {
         InhibitWhat what = 0;
-        char *w, *state;
+        const char *word, *state;
         size_t l;
 
-        FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
-                if (l == 8 && strncmp(w, "shutdown", l) == 0)
+        FOREACH_WORD_SEPARATOR(word, l, s, ":", state) {
+                if (l == 8 && strneq(word, "shutdown", l))
                         what |= INHIBIT_SHUTDOWN;
-                else if (l == 7 && strncmp(w, "suspend", l) == 0)
-                        what |= INHIBIT_SUSPEND;
-                else if (l == 4 && strncmp(w, "idle", l) == 0)
+                else if (l == 5 && strneq(word, "sleep", l))
+                        what |= INHIBIT_SLEEP;
+                else if (l == 4 && strneq(word, "idle", l))
                         what |= INHIBIT_IDLE;
+                else if (l == 16 && strneq(word, "handle-power-key", l))
+                        what |= INHIBIT_HANDLE_POWER_KEY;
+                else if (l == 18 && strneq(word, "handle-suspend-key", l))
+                        what |= INHIBIT_HANDLE_SUSPEND_KEY;
+                else if (l == 20 && strneq(word, "handle-hibernate-key", l))
+                        what |= INHIBIT_HANDLE_HIBERNATE_KEY;
+                else if (l == 17 && strneq(word, "handle-lid-switch", l))
+                        what |= INHIBIT_HANDLE_LID_SWITCH;
                 else
                         return _INHIBIT_WHAT_INVALID;
         }
 
         return what;
-
 }
 
 static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {