chiark / gitweb /
logind: log which process is delaying suspend and not closing locks
[elogind.git] / src / login / logind-inhibit.c
index 60b6237ce5e71b3604bbee4b528a74cfa2956992..35e1abd72918fcea2d8893829ecc57f17efc3d0f 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"
 
 Inhibitor* inhibitor_new(Manager *m, const char* id) {
         Inhibitor *i;
@@ -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,9 +78,9 @@ 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);
 
@@ -106,23 +106,23 @@ int inhibitor_save(Inhibitor *i) {
                 (unsigned long) 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,9 +136,6 @@ 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));
@@ -163,7 +160,7 @@ int inhibitor_start(Inhibitor *i) {
 
         i->started = true;
 
-        manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited\0" : "DelayInhibited\0");
+        manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
 
         return 0;
 }
@@ -182,16 +179,14 @@ int inhibitor_stop(Inhibitor *i) {
 
         i->started = false;
 
-        manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited\0" : "DelayInhibited\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)
@@ -222,21 +222,19 @@ int inhibitor_load(Inhibitor *i) {
         if (uid) {
                 r = parse_uid(uid, &i->uid);
                 if (r < 0)
-                        goto finish;
+                        return r;
         }
 
         if (pid) {
                 r = parse_pid(pid, &i->pid);
                 if (r < 0)
-                        goto finish;
+                        return r;
         }
 
         if (who) {
                 cc = cunescape(who);
-                if (!cc) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
+                if (!cc)
+                        return -ENOMEM;
 
                 free(i->who);
                 i->who = cc;
@@ -244,10 +242,8 @@ int inhibitor_load(Inhibitor *i) {
 
         if (why) {
                 cc = cunescape(why);
-                if (!cc) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
+                if (!cc)
+                        return -ENOMEM;
 
                 free(i->why);
                 i->why = cc;
@@ -261,14 +257,20 @@ int inhibitor_load(Inhibitor *i) {
                         close_nointr_nofail(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) {
@@ -282,7 +284,8 @@ int inhibitor_create_fifo(Inhibitor *i) {
                 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)
@@ -291,22 +294,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->fifo_fd, 0, inhibitor_dispatch_fifo, i, &i->event_source);
                 if (r < 0)
                         return r;
 
-                zero(ev);
-                ev.events = 0;
-                ev.data.u32 = FD_OTHER_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 */
@@ -320,9 +320,10 @@ int inhibitor_create_fifo(Inhibitor *i) {
 void inhibitor_remove_fifo(Inhibitor *i) {
         assert(i);
 
+        if (i->event_source)
+                i->event_source = sd_event_source_unref(i->event_source);
+
         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;
         }
@@ -341,14 +342,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 };
@@ -357,18 +383,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)
@@ -378,22 +413,34 @@ 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_SLEEP] = "sleep",
-                [INHIBIT_IDLE] = "idle",
-                [INHIBIT_SHUTDOWN|INHIBIT_SLEEP] = "shutdown:sleep",
-                [INHIBIT_SHUTDOWN|INHIBIT_IDLE] = "shutdown:idle",
-                [INHIBIT_SHUTDOWN|INHIBIT_SLEEP|INHIBIT_IDLE] = "shutdown:sleep:idle",
-                [INHIBIT_SLEEP|INHIBIT_IDLE] = "sleep:idle"
-        };
+        static __thread 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) {
@@ -402,18 +449,25 @@ InhibitWhat inhibit_what_from_string(const char *s) {
         size_t l;
 
         FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
-                if (l == 8 && strncmp(w, "shutdown", l) == 0)
+                if (l == 8 && strneq(w, "shutdown", l))
                         what |= INHIBIT_SHUTDOWN;
-                else if (l == 5 && strncmp(w, "sleep", l) == 0)
+                else if (l == 5 && strneq(w, "sleep", l))
                         what |= INHIBIT_SLEEP;
-                else if (l == 4 && strncmp(w, "idle", l) == 0)
+                else if (l == 4 && strneq(w, "idle", l))
                         what |= INHIBIT_IDLE;
+                else if (l == 16 && strneq(w, "handle-power-key", l))
+                        what |= INHIBIT_HANDLE_POWER_KEY;
+                else if (l == 18 && strneq(w, "handle-suspend-key", l))
+                        what |= INHIBIT_HANDLE_SUSPEND_KEY;
+                else if (l == 20 && strneq(w, "handle-hibernate-key", l))
+                        what |= INHIBIT_HANDLE_HIBERNATE_KEY;
+                else if (l == 17 && strneq(w, "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] = {