X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flogin%2Flogind-inhibit.c;h=1b6f1362b3fbfb34dc2dee5731cfb570297fd907;hp=2f7a758e7cf2bba48efe87b6b500eee00f84b483;hb=718db96199eb307751264e4163555662c9a389fa;hpb=f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6 diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index 2f7a758e7..1b6f1362b 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -21,15 +21,14 @@ #include #include -#include #include -#include #include #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; @@ -46,7 +45,7 @@ Inhibitor* inhibitor_new(Manager *m, const char* id) { return NULL; } - i->id = file_name_from_path(i->state_file); + i->id = path_get_file_name(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; @@ -97,30 +97,32 @@ int inhibitor_save(Inhibitor *i) { fprintf(f, "# This is private data. Do not parse.\n" "WHAT=%s\n" + "MODE=%s\n" "UID=%lu\n" "PID=%lu\n", inhibit_what_to_string(i->what), + inhibit_mode_to_string(i->mode), (unsigned long) i->uid, (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) @@ -134,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)); @@ -150,15 +149,18 @@ int inhibitor_start(Inhibitor *i) { if (i->started) return 0; - log_debug("Inhibitor %s (%s) pid=%lu uid=%lu started.", + dual_timestamp_get(&i->since); + + log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s started.", strna(i->who), strna(i->why), - (unsigned long) i->pid, (unsigned long) i->uid); + (unsigned long) i->pid, (unsigned long) 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; } @@ -167,29 +169,35 @@ int inhibitor_stop(Inhibitor *i) { assert(i); if (i->started) - log_debug("Inhibitor %s (%s) pid=%lu uid=%lu stopped.", + log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s stopped.", strna(i->who), strna(i->why), - (unsigned long) i->pid, (unsigned long) i->uid); + (unsigned long) i->pid, (unsigned long) i->uid, + inhibit_mode_to_string(i->mode)); if (i->state_file) unlink(i->state_file); 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; - int r; - char *cc, + + _cleanup_free_ char *what = NULL, *uid = NULL, *pid = NULL, *who = NULL, - *why = NULL; + *why = NULL, + *mode = NULL; + + InhibitWhat w; + InhibitMode mm; + char *cc; + int r; r = parse_env_file(i->state_file, NEWLINE, "WHAT", &what, @@ -197,24 +205,36 @@ int inhibitor_load(Inhibitor *i) { "PID", &pid, "WHO", &who, "WHY", &why, + "MODE", &mode, "FIFO", &i->fifo_path, NULL); if (r < 0) - goto finish; + return r; - w = inhibit_what_from_string(what); + w = what ? inhibit_what_from_string(what) : 0; if (w >= 0) i->what = w; - parse_uid(uid, &i->uid); - parse_pid(pid, &i->pid); + mm = mode ? inhibit_mode_from_string(mode) : INHIBIT_BLOCK; + if (mm >= 0) + i->mode = mm; + + if (uid) { + r = parse_uid(uid, &i->uid); + if (r < 0) + return r; + } + + if (pid) { + r = parse_pid(pid, &i->pid); + if (r < 0) + return r; + } if (who) { cc = cunescape(who); - if (!cc) { - r = -ENOMEM; - goto finish; - } + if (!cc) + return -ENOMEM; free(i->who); i->who = cc; @@ -222,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; @@ -239,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) { @@ -256,11 +280,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) @@ -269,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_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 */ @@ -298,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; } @@ -312,36 +335,108 @@ void inhibitor_remove_fifo(Inhibitor *i) { } } -InhibitWhat manager_inhibit_what(Manager *m) { +InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) { Inhibitor *i; Iterator j; InhibitWhat what = 0; assert(m); - HASHMAP_FOREACH(i, m->inhibitor_fds, j) - what |= i->what; + HASHMAP_FOREACH(i, m->inhibitors, j) + if (i->mode == mm) + what |= i->what; return what; } -const char *inhibit_what_to_string(InhibitWhat w) { +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; - 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" - }; + 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 *i; + Iterator j; + struct dual_timestamp ts = { 0, 0 }; + bool inhibited = false; + + assert(m); + assert(w > 0 && w < _INHIBIT_WHAT_MAX); + + 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 (since) + *since = ts; + + return inhibited; +} + +const char *inhibit_what_to_string(InhibitWhat w) { + 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) { @@ -350,16 +445,30 @@ 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 == 7 && strncmp(w, "suspend", l) == 0) - what |= INHIBIT_SUSPEND; - else if (l == 4 && strncmp(w, "idle", l) == 0) + else if (l == 5 && strneq(w, "sleep", l)) + what |= INHIBIT_SLEEP; + 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] = { + [INHIBIT_BLOCK] = "block", + [INHIBIT_DELAY] = "delay" +}; + +DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);