[systemd-commits] 7 commits - .gitignore Makefile.am TODO man/systemd-cgls.xml src/cgls src/core src/login src/shared src/systemctl

Lennart Poettering lennart at kemper.freedesktop.org
Mon Apr 16 10:00:17 PDT 2012


 .gitignore                                 |    1 
 Makefile.am                                |   16 +
 TODO                                       |   15 -
 man/systemd-cgls.xml                       |   18 +
 src/cgls/cgls.c                            |   27 +
 src/core/cgroup.c                          |   47 +++
 src/core/cgroup.h                          |    1 
 src/core/manager.c                         |    5 
 src/login/loginctl.c                       |   24 -
 src/login/logind-dbus.c                    |  316 ++++++++++++++++++++---
 src/login/logind-inhibit.c                 |  393 +++++++++++++++++++++++++++++
 src/login/logind-inhibit.h                 |   79 +++++
 src/login/logind-session-dbus.c            |   24 +
 src/login/logind-session.c                 |   21 -
 src/login/logind-user-dbus.c               |   24 +
 src/login/logind.c                         |  118 +++++++-
 src/login/logind.h                         |    8 
 src/login/org.freedesktop.login1.conf      |    8 
 src/login/org.freedesktop.login1.policy.in |   30 ++
 src/login/test-inhibit.c                   |  137 ++++++++++
 src/shared/cgroup-label.c                  |    3 
 src/shared/cgroup-show.c                   |  233 +++++++++++------
 src/shared/cgroup-show.h                   |    8 
 src/shared/cgroup-util.c                   |  129 ++++++---
 src/shared/cgroup-util.h                   |    1 
 src/shared/dbus-common.c                   |   50 +++
 src/shared/dbus-common.h                   |    2 
 src/shared/polkit.c                        |   52 ---
 src/shared/util.c                          |    3 
 src/shared/util.h                          |    2 
 src/systemctl/systemctl.c                  |   14 -
 31 files changed, 1526 insertions(+), 283 deletions(-)

New commits:
commit b69d29ce049f12d463a589e18561dd10ee8c09f1
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 16 18:56:18 2012 +0200

    systemctl: show main and control PID explicitly in cgroup-show
    
    In some cases the main/control PID of a service can be outside of the
    services cgroups (for example, if logind readjusts the processes'
    cgroup). In order to clarify this for the user show the main/control PID
    in the cgroup tree nonetheless, but mark them specially.

diff --git a/TODO b/TODO
index 2ebf786..dd38fc8 100644
--- a/TODO
+++ b/TODO
@@ -19,8 +19,6 @@ Features:
 
 * filter default cgroups in logind too
 
-* remove empty cgroups from cgls output
-
 * udev: remove /sys and /dev configurability
 
 * udev: find a way to tell udev to not cancel firmware requests when running in initramfs
@@ -59,8 +57,6 @@ Features:
 * journald: make configurable "store-on-var", "store-on-run", "dont-store", "auto"
   (store-persistent, store-volatile?)
 
-* Add ConditionReadWriteFileSystem= so that systemd-sysctl doesn't get executed when /proc/sys is read-only
-
 * introduce mix of BindTo and Requisite
 
 * journalctl: show multiline log messages sanely, expand tabs, and show all valid utf8 messages
@@ -69,8 +65,6 @@ Features:
 
 * add DeleteSocketsOnStop=yes|no option to socket units
 
-* add shutdown inhibit API for usage by libvirt and friends
-
 * journal: store euid in journal if it differs from uid
 
 * support chrony in addition to ntpd in timedated
@@ -79,14 +73,8 @@ Features:
 
 * There's currently no way to cancel fsck (used to be possible via C-c or c on the console)
 
-* when dumping cgroup contents, include main/control PID of a service, explicitly
-
 * keep an eye on https://bugzilla.gnome.org/show_bug.cgi?id=670100
 
-* D-Bus: always pass cred data along each message
-
-* journal: allow turning off logging entirely
-
 * journal: sanely deal with entries which are larger than the individual file size, but where the componets would fit
 
 * add command to systemctl to plot dependency graph as tree (see rhbz 795365)
@@ -310,6 +298,7 @@ External:
    - allow specification of socket mode/umask when allocating DBusServer
    - allow disabling of fd passing when connecting a AF_UNIX connection
    - allow disabling of UID passing for AUTH EXTERNAL
+   - always pass cred data along each message
 
 * systemd --user
     PR_SET_CHILD_REAPER patch: https://lkml.org/lkml/2011/7/28/426
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index f1cb16e..3ec8057 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -352,7 +352,7 @@ typedef struct SessionStatusInfo {
         uid_t uid;
         const char *name;
         usec_t timestamp;
-        const char *control_group;
+        const char *default_control_group;
         int vtnr;
         const char *seat;
         const char *tty;
@@ -371,7 +371,7 @@ typedef struct UserStatusInfo {
         uid_t uid;
         const char *name;
         usec_t timestamp;
-        const char *control_group;
+        const char *default_control_group;
         const char *state;
         char **sessions;
         const char *display;
@@ -461,10 +461,10 @@ static void print_session_status_info(SessionStatusInfo *i) {
 
         printf("\t  Active: %s\n", yes_no(i->active));
 
-        if (i->control_group) {
+        if (i->default_control_group) {
                 unsigned c;
 
-                printf("\t  CGroup: %s\n", i->control_group);
+                printf("\t  CGroup: %s\n", i->default_control_group);
 
                 if (arg_transport != TRANSPORT_SSH) {
                         c = columns();
@@ -473,7 +473,7 @@ static void print_session_status_info(SessionStatusInfo *i) {
                         else
                                 c = 0;
 
-                        show_cgroup_by_path(i->control_group, "\t\t  ", c, false, arg_all);
+                        show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, arg_all, &i->leader, i->leader > 0 ? 1 : 0);
                 }
         }
 }
@@ -513,10 +513,10 @@ static void print_user_status_info(UserStatusInfo *i) {
                 printf("\n");
         }
 
-        if (i->control_group) {
+        if (i->default_control_group) {
                 unsigned c;
 
-                printf("\t  CGroup: %s\n", i->control_group);
+                printf("\t  CGroup: %s\n", i->default_control_group);
 
                 if (arg_transport != TRANSPORT_SSH) {
                         c = columns();
@@ -525,7 +525,7 @@ static void print_user_status_info(UserStatusInfo *i) {
                         else
                                 c = 0;
 
-                        show_cgroup_by_path(i->control_group, "\t\t  ", c, false, arg_all);
+                        show_cgroup_by_path(i->default_control_group, "\t\t  ", c, false, arg_all);
                 }
         }
 }
@@ -581,8 +581,8 @@ static int status_property_session(const char *name, DBusMessageIter *iter, Sess
                                 i->id = s;
                         else if (streq(name, "Name"))
                                 i->name = s;
-                        else if (streq(name, "ControlGroupPath"))
-                                i->control_group = s;
+                        else if (streq(name, "DefaultControlGroup"))
+                                i->default_control_group = s;
                         else if (streq(name, "TTY"))
                                 i->tty = s;
                         else if (streq(name, "Display"))
@@ -680,8 +680,8 @@ static int status_property_user(const char *name, DBusMessageIter *iter, UserSta
                 if (!isempty(s)) {
                         if (streq(name, "Name"))
                                 i->name = s;
-                        else if (streq(name, "ControlGroupPath"))
-                                i->control_group = s;
+                        else if (streq(name, "DefaultControlGroup"))
+                                i->default_control_group = s;
                         else if (streq(name, "State"))
                                 i->state = s;
                 }
diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
index 0780f3f..7f1b580 100644
--- a/src/login/logind-session-dbus.c
+++ b/src/login/logind-session-dbus.c
@@ -45,7 +45,7 @@
         "  <property name=\"Name\" type=\"s\" access=\"read\"/>\n"      \
         "  <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
-        "  <property name=\"ControlGroupPath\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"VTNr\" type=\"u\" access=\"read\"/>\n"      \
         "  <property name=\"Seat\" type=\"(so)\" access=\"read\"/>\n"   \
         "  <property name=\"TTY\" type=\"s\" access=\"read\"/>\n"       \
@@ -196,6 +196,26 @@ static int bus_session_append_idle_hint_since(DBusMessageIter *i, const char *pr
         return 0;
 }
 
+static int bus_session_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
+        Session *s = data;
+        char *t;
+        int r;
+        bool success;
+
+        assert(i);
+        assert(property);
+        assert(s);
+
+        r = cg_join_spec(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &t);
+        if (r < 0)
+                return r;
+
+        success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
+        free(t);
+
+        return success ? 0 : -ENOMEM;
+}
+
 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_class, session_class, SessionClass);
 
@@ -228,7 +248,7 @@ static const BusProperty bus_login_session_properties[] = {
         { "Id",                     bus_property_append_string,         "s", offsetof(Session, id),                 true },
         { "Timestamp",              bus_property_append_usec,           "t", offsetof(Session, timestamp.realtime)  },
         { "TimestampMonotonic",     bus_property_append_usec,           "t", offsetof(Session, timestamp.monotonic) },
-        { "ControlGroupPath",       bus_property_append_string,         "s", offsetof(Session, cgroup_path),        true },
+        { "DefaultControlGroup",    bus_session_append_default_cgroup,  "s", 0,                                     },
         { "VTNr",                   bus_property_append_uint32,         "u", offsetof(Session, vtnr)                },
         { "Seat",                   bus_session_append_seat,         "(so)", 0 },
         { "TTY",                    bus_property_append_string,         "s", offsetof(Session, tty),                true },
diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c
index 2d3375a..21b608d 100644
--- a/src/login/logind-user-dbus.c
+++ b/src/login/logind-user-dbus.c
@@ -38,7 +38,7 @@
         "  <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"RuntimePath\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"ControlGroupPath\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"Service\" type=\"s\" access=\"read\"/>\n"   \
         "  <property name=\"Display\" type=\"(so)\" access=\"read\"/>\n" \
         "  <property name=\"State\" type=\"s\" access=\"read\"/>\n"     \
@@ -189,6 +189,26 @@ static int bus_user_append_idle_hint_since(DBusMessageIter *i, const char *prope
         return 0;
 }
 
+static bus_user_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
+        User *u = data;
+        char *t;
+        int r;
+        bool success;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        r = cg_join_spec(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &t);
+        if (r < 0)
+                return r;
+
+        success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
+        free(t);
+
+        return success ? 0 : -ENOMEM;
+}
+
 static int get_user_for_path(Manager *m, const char *path, User **_u) {
         User *u;
         unsigned long lu;
@@ -220,7 +240,7 @@ static const BusProperty bus_login_user_properties[] = {
         { "Timestamp",              bus_property_append_usec,        "t", offsetof(User, timestamp.realtime)  },
         { "TimestampMonotonic",     bus_property_append_usec,        "t", offsetof(User, timestamp.monotonic) },
         { "RuntimePath",            bus_property_append_string,      "s", offsetof(User, runtime_path),       true },
-        { "ControlGroupPath",       bus_property_append_string,      "s", offsetof(User, cgroup_path),        true },
+        { "DefaultControlGroup",    bus_user_append_default_cgroup,  "s", 0 },
         { "Service",                bus_property_append_string,      "s", offsetof(User, service),            true },
         { "Display",                bus_user_append_display,      "(so)", 0 },
         { "State",                  bus_user_append_state,           "s", 0 },
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
index 5b639e0..19f87e4 100644
--- a/src/shared/cgroup-show.c
+++ b/src/shared/cgroup-show.c
@@ -50,33 +50,72 @@ static unsigned ilog10(unsigned long ul) {
         return n;
 }
 
+static void show_pid_array(int pids[], unsigned n_pids, const char *prefix, unsigned n_columns, bool extra, bool more, bool kernel_threads) {
+        unsigned i, m;
+        pid_t biggest = 0;
+
+        /* Filter duplicates */
+        m = 0;
+        for (i = 0; i < n_pids; i++) {
+                unsigned j;
+
+                if (pids[i] > biggest)
+                        biggest = pids[i];
+
+                for (j = i+1; j < n_pids; j++)
+                        if (pids[i] == pids[j])
+                                break;
+
+                if (j >= n_pids)
+                        pids[m++] = pids[i];
+        }
+        n_pids = m;
+
+        /* And sort */
+        qsort(pids, n_pids, sizeof(pid_t), compare);
+
+        if (n_columns > 8)
+                n_columns -= 8;
+        else
+                n_columns = 20;
+
+        for (i = 0; i < n_pids; i++) {
+                char *t = NULL;
+
+                get_process_cmdline(pids[i], n_columns, true, &t);
+
+                printf("%s%s %*lu %s\n",
+                       prefix,
+                       extra ? "\342\200\243" : ((more || i < n_pids-1) ? "\342\224\234" : "\342\224\224"),
+                       (int) ilog10(biggest),
+                       (unsigned long) pids[i],
+                       strna(t));
+
+                free(t);
+        }
+}
+
+
 static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads) {
         char *fn;
         FILE *f;
         size_t n = 0, n_allocated = 0;
         pid_t *pids = NULL;
         char *p;
-        pid_t pid, biggest = 0;
+        pid_t pid;
         int r;
 
-        if (n_columns <= 0)
-                n_columns = columns();
-
-        if (!prefix)
-                prefix = "";
-
-        if ((r = cg_fix_path(path, &p)) < 0)
+        r = cg_fix_path(path, &p);
+        if (r < 0)
                 return r;
 
         r = asprintf(&fn, "%s/cgroup.procs", p);
         free(p);
-
         if (r < 0)
                 return -ENOMEM;
 
         f = fopen(fn, "re");
         free(fn);
-
         if (!f)
                 return -errno;
 
@@ -90,7 +129,8 @@ static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigne
 
                         n_allocated = MAX(16U, n*2U);
 
-                        if (!(npids = realloc(pids, sizeof(pid_t) * n_allocated))) {
+                        npids = realloc(pids, sizeof(pid_t) * n_allocated);
+                        if (!npids) {
                                 r = -ENOMEM;
                                 goto finish;
                         }
@@ -100,54 +140,13 @@ static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigne
 
                 assert(n < n_allocated);
                 pids[n++] = pid;
-
-                if (pid > biggest)
-                        biggest = pid;
         }
 
         if (r < 0)
                 goto finish;
 
-        if (n > 0) {
-                unsigned i, m;
-
-                /* Filter duplicates */
-                m = 0;
-                for (i = 0; i < n; i++) {
-                        unsigned j;
-
-                        for (j = i+1; j < n; j++)
-                                if (pids[i] == pids[j])
-                                        break;
-
-                        if (j >= n)
-                                pids[m++] = pids[i];
-                }
-                n = m;
-
-                /* And sort */
-                qsort(pids, n, sizeof(pid_t), compare);
-
-                if (n_columns > 8)
-                        n_columns -= 8;
-                else
-                        n_columns = 20;
-
-                for (i = 0; i < n; i++) {
-                        char *t = NULL;
-
-                        get_process_cmdline(pids[i], n_columns, true, &t);
-
-                        printf("%s%s %*lu %s\n",
-                               prefix,
-                               (more || i < n-1) ? "\342\224\234" : "\342\224\224",
-                               (int) ilog10(biggest),
-                               (unsigned long) pids[i],
-                               strna(t));
-
-                        free(t);
-                }
-        }
+        if (n > 0)
+                show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads);
 
         r = 0;
 
@@ -167,6 +166,8 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
         bool shown_pids = false;
         int r;
 
+        assert(path);
+
         if (n_columns <= 0)
                 n_columns = columns();
 
@@ -188,7 +189,6 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
 
                 r = asprintf(&k, "%s/%s", fn, gn);
                 free(gn);
-
                 if (r < 0) {
                         r = -ENOMEM;
                         goto finish;
@@ -272,3 +272,75 @@ int show_cgroup(const char *controller, const char *path, const char *prefix, un
 
         return r;
 }
+
+static int show_extra_pids(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t pids[], unsigned n_pids) {
+        pid_t *copy;
+        unsigned i, j;
+        int r;
+
+        assert(controller);
+        assert(path);
+
+        if (n_pids <= 0)
+                return 0;
+
+        if (n_columns <= 0)
+                n_columns = columns();
+
+        if (!prefix)
+                prefix = "";
+
+        copy = new(pid_t, n_pids);
+        if (!copy)
+                return -ENOMEM;
+
+        for (i = 0, j = 0; i < n_pids; i++) {
+                char *k;
+
+                r = cg_get_by_pid(controller, pids[i], &k);
+                if (r < 0) {
+                        free(copy);
+                        return r;
+                }
+
+                if (path_startswith(k, path))
+                        continue;
+
+                copy[j++] = pids[i];
+        }
+
+        show_pid_array(copy, j, prefix, n_columns, true, false, false);
+
+        free(copy);
+        return 0;
+}
+
+int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, bool all, const pid_t extra_pids[], unsigned n_extra_pids) {
+        int r;
+
+        assert(controller);
+        assert(path);
+
+        r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, all);
+        if (r < 0)
+                return r;
+
+        return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids);
+}
+
+int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, bool all, const pid_t extra_pids[], unsigned n_extra_pids) {
+        int r;
+        char *controller, *path;
+
+        assert(spec);
+
+        r = cg_split_spec(spec, &controller, &path);
+        if (r < 0)
+                return r;
+
+        r = show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, all, extra_pids, n_extra_pids);
+        free(controller);
+        free(path);
+
+        return r;
+}
diff --git a/src/shared/cgroup-show.h b/src/shared/cgroup-show.h
index e1d67a3..dba900a 100644
--- a/src/shared/cgroup-show.h
+++ b/src/shared/cgroup-show.h
@@ -23,8 +23,12 @@
 ***/
 
 #include <stdbool.h>
+#include <sys/types.h>
 
 int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads, bool all);
 int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads, bool all);
 
+int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, bool all, const pid_t extra_pids[], unsigned n_extra_pids);
+int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, bool all, const pid_t extra_pids[], unsigned n_extra_pids);
+
 #endif
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index 48da4cb..8ceb382 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -1050,11 +1050,11 @@ int cg_fix_path(const char *path, char **result) {
         assert(result);
 
         /* First check if it already is a filesystem path */
-        if (path_is_absolute(path) &&
-            path_startswith(path, "/sys/fs/cgroup") &&
+        if (path_startswith(path, "/sys/fs/cgroup") &&
             access(path, F_OK) >= 0) {
 
-                if (!(t = strdup(path)))
+                t = strdup(path);
+                if (!t)
                         return -ENOMEM;
 
                 *result = t;
@@ -1062,7 +1062,8 @@ int cg_fix_path(const char *path, char **result) {
         }
 
         /* Otherwise treat it as cg spec */
-        if ((r = cg_split_spec(path, &c, &p)) < 0)
+        r = cg_split_spec(path, &c, &p);
+        if (r < 0)
                 return r;
 
         r = cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index e8b8b51..d57e093 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -2378,12 +2378,22 @@ static void print_status_info(UnitStatusInfo *i) {
                 printf("\t  CGroup: %s\n", i->default_control_group);
 
                 if (arg_transport != TRANSPORT_SSH) {
-                        if ((c = columns()) > 18)
+                        unsigned k = 0;
+                        pid_t extra[2];
+
+                        c = columns();
+                        if (c > 18)
                                 c -= 18;
                         else
                                 c = 0;
 
-                        show_cgroup_by_path(i->default_control_group, "\t\t  ", c, false, arg_all);
+                        if (i->main_pid > 0)
+                                extra[k++] = i->main_pid;
+
+                        if (i->control_pid > 0)
+                                extra[k++] = i->control_pid;
+
+                        show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, arg_all, extra, k);
                 }
         }
 

commit 888c7102355af1450aa26253d60cc2cb46eeb71d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 16 18:54:45 2012 +0200

    util: introduce memdup()

diff --git a/src/shared/util.h b/src/shared/util.h
index c487b70..efb2c7d 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -100,6 +100,8 @@ bool streq_ptr(const char *a, const char *b);
 
 #define new0(t, n) ((t*) calloc((n), sizeof(t)))
 
+#define newdup(t, p, n) ((t*) memdup(p, sizeof(t)*(n))
+
 #define malloc0(n) (calloc((n), 1))
 
 static inline const char* yes_no(bool b) {

commit c3175a7f40a2d2fabc3a2de63033a6810d45221a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 16 17:35:58 2012 +0200

    cgls: don't show empty cgroups by default

diff --git a/TODO b/TODO
index 06a2afc..2ebf786 100644
--- a/TODO
+++ b/TODO
@@ -15,6 +15,8 @@ Bugfixes:
 
 Features:
 
+* suspend/hibernate/hybrid support, auto-suspend logic with idle hint
+
 * filter default cgroups in logind too
 
 * remove empty cgroups from cgls output
diff --git a/man/systemd-cgls.xml b/man/systemd-cgls.xml
index fb9f06b..df51685 100644
--- a/man/systemd-cgls.xml
+++ b/man/systemd-cgls.xml
@@ -69,6 +69,9 @@
                 of the control group the working directory refers
                 to. Otherwise the full systemd control group hierarchy
                 is shown.</para>
+
+                <para>By default empty control cgroups are not
+                shown.</para>
         </refsect1>
 
         <refsect1>
@@ -86,6 +89,13 @@
                         </varlistentry>
 
                         <varlistentry>
+                                <term><option>--version</option></term>
+
+                                <listitem><para>Prints a short version
+                                string and exits.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
                                 <term><option>--no-pager</option></term>
 
 				<listitem><para>Do not pipe output into a
@@ -93,6 +103,14 @@
 			</varlistentry>
 
                         <varlistentry>
+                                <term><option>--all</option></term>
+
+				<listitem><para>Don't hide empty
+				control groups in the
+				outpout.</para></listitem>
+			</varlistentry>
+
+                        <varlistentry>
                                 <term><option>-k</option></term>
 
                                 <listitem><para>Include kernel
diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c
index fd02d52..4bec6a8 100644
--- a/src/cgls/cgls.c
+++ b/src/cgls/cgls.c
@@ -31,16 +31,20 @@
 #include "log.h"
 #include "util.h"
 #include "pager.h"
+#include "build.h"
 
 static bool arg_no_pager = false;
 static bool arg_kernel_threads = false;
+static bool arg_all = false;
 
 static void help(void) {
 
         printf("%s [OPTIONS...] [CGROUP...]\n\n"
                "Recursively show control group contents.\n\n"
                "  -h --help           Show this help\n"
+               "     --version        Show package version\n"
                "     --no-pager       Do not pipe output into a pager\n"
+               "  -a --all            Show all groups, including empty\n"
                "  -k                  Include kernel threads in output\n",
                program_invocation_short_name);
 }
@@ -48,12 +52,15 @@ static void help(void) {
 static int parse_argv(int argc, char *argv[]) {
 
         enum {
-                ARG_NO_PAGER = 0x100
+                ARG_NO_PAGER = 0x100,
+                ARG_VERSION
         };
 
         static const struct option options[] = {
                 { "help",      no_argument,       NULL, 'h'          },
+                { "version",   no_argument,       NULL, ARG_VERSION  },
                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER },
+                { "all",       no_argument,       NULL, 'a'          },
                 { NULL,        0,                 NULL, 0            }
         };
 
@@ -62,7 +69,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 1);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hk", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hka", options, NULL)) >= 0) {
 
                 switch (c) {
 
@@ -70,10 +77,20 @@ static int parse_argv(int argc, char *argv[]) {
                         help();
                         return 0;
 
+                case ARG_VERSION:
+                        puts(PACKAGE_STRING);
+                        puts(DISTRIBUTION);
+                        puts(SYSTEMD_FEATURES);
+                        return 0;
+
                 case ARG_NO_PAGER:
                         arg_no_pager = true;
                         break;
 
+                case 'a':
+                        arg_all = true;
+                        break;
+
                 case 'k':
                         arg_kernel_threads = true;
                         break;
@@ -114,7 +131,7 @@ int main(int argc, char *argv[]) {
                         int q;
                         printf("%s:\n", argv[i]);
 
-                        q = show_cgroup_by_path(argv[i], NULL, 0, arg_kernel_threads);
+                        q = show_cgroup_by_path(argv[i], NULL, 0, arg_kernel_threads, arg_all);
                         if (q < 0)
                                 r = q;
                 }
@@ -130,7 +147,7 @@ int main(int argc, char *argv[]) {
 
                 if (path_startswith(p, "/sys/fs/cgroup")) {
                         printf("Working Directory %s:\n", p);
-                        r = show_cgroup_by_path(p, NULL, 0, arg_kernel_threads);
+                        r = show_cgroup_by_path(p, NULL, 0, arg_kernel_threads, arg_all);
                 } else {
                         char *root = NULL;
                         const char *t = NULL;
@@ -145,7 +162,7 @@ int main(int argc, char *argv[]) {
                                 t = root[0] ? root : "/";
                         }
 
-                        r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, t, NULL, 0, arg_kernel_threads);
+                        r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, t, NULL, 0, arg_kernel_threads, arg_all);
                         free(root);
                 }
 
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index c460490..f1cb16e 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -473,7 +473,7 @@ static void print_session_status_info(SessionStatusInfo *i) {
                         else
                                 c = 0;
 
-                        show_cgroup_by_path(i->control_group, "\t\t  ", c, false);
+                        show_cgroup_by_path(i->control_group, "\t\t  ", c, false, arg_all);
                 }
         }
 }
@@ -525,7 +525,7 @@ static void print_user_status_info(UserStatusInfo *i) {
                         else
                                 c = 0;
 
-                        show_cgroup_by_path(i->control_group, "\t\t  ", c, false);
+                        show_cgroup_by_path(i->control_group, "\t\t  ", c, false, arg_all);
                 }
         }
 }
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
index 550a2f5..5b639e0 100644
--- a/src/shared/cgroup-show.c
+++ b/src/shared/cgroup-show.c
@@ -160,7 +160,7 @@ finish:
         return r;
 }
 
-int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads) {
+int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, bool all) {
         DIR *d;
         char *last = NULL;
         char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL;
@@ -173,15 +173,31 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
         if (!prefix)
                 prefix = "";
 
-        if ((r = cg_fix_path(path, &fn)) < 0)
+        r = cg_fix_path(path, &fn);
+        if (r < 0)
                 return r;
 
-        if (!(d = opendir(fn))) {
+        d = opendir(fn);
+        if (!d) {
                 free(fn);
                 return -errno;
         }
 
         while ((r = cg_read_subgroup(d, &gn)) > 0) {
+                char *k;
+
+                r = asprintf(&k, "%s/%s", fn, gn);
+                free(gn);
+
+                if (r < 0) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!all && cg_is_empty_recursive(NULL, k, false) > 0) {
+                        free(k);
+                        continue;
+                }
 
                 if (!shown_pids) {
                         show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads);
@@ -191,25 +207,20 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
                 if (last) {
                         printf("%s\342\224\234 %s\n", prefix, file_name_from_path(last));
 
-                        if (!p1)
-                                if (!(p1 = strappend(prefix, "\342\224\202 "))) {
+                        if (!p1) {
+                                p1 = strappend(prefix, "\342\224\202 ");
+                                if (!p1) {
+                                        free(k);
                                         r = -ENOMEM;
                                         goto finish;
                                 }
+                        }
 
-                        show_cgroup_by_path(last, p1, n_columns-2, kernel_threads);
-
+                        show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, all);
                         free(last);
-                        last = NULL;
                 }
 
-                r = asprintf(&last, "%s/%s", fn, gn);
-                free(gn);
-
-                if (r < 0) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
+                last = k;
         }
 
         if (r < 0)
@@ -221,13 +232,15 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
         if (last) {
                 printf("%s\342\224\224 %s\n", prefix, file_name_from_path(last));
 
-                if (!p2)
-                        if (!(p2 = strappend(prefix, "  "))) {
+                if (!p2) {
+                        p2 = strappend(prefix, "  ");
+                        if (!p2) {
                                 r = -ENOMEM;
                                 goto finish;
                         }
+                }
 
-                show_cgroup_by_path(last, p2, n_columns-2, kernel_threads);
+                show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, all);
         }
 
         r = 0;
@@ -243,7 +256,7 @@ finish:
         return r;
 }
 
-int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads) {
+int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, bool all) {
         char *p;
         int r;
 
@@ -254,7 +267,7 @@ int show_cgroup(const char *controller, const char *path, const char *prefix, un
         if (r < 0)
                 return r;
 
-        r = show_cgroup_by_path(p, prefix, n_columns, kernel_threads);
+        r = show_cgroup_by_path(p, prefix, n_columns, kernel_threads, all);
         free(p);
 
         return r;
diff --git a/src/shared/cgroup-show.h b/src/shared/cgroup-show.h
index 5433f46..e1d67a3 100644
--- a/src/shared/cgroup-show.h
+++ b/src/shared/cgroup-show.h
@@ -24,7 +24,7 @@
 
 #include <stdbool.h>
 
-int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads);
-int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads);
+int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads, bool all);
+int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads, bool all);
 
 #endif
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index b2fb324..48da4cb 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -40,11 +40,11 @@ int cg_enumerate_processes(const char *controller, const char *path, FILE **_f)
         int r;
         FILE *f;
 
-        assert(controller);
         assert(path);
         assert(_f);
 
-        if ((r = cg_get_path(controller, path, "cgroup.procs", &fs)) < 0)
+        r = cg_get_path(controller, path, "cgroup.procs", &fs);
+        if (r < 0)
                 return r;
 
         f = fopen(fs, "re");
@@ -62,11 +62,11 @@ int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) {
         int r;
         FILE *f;
 
-        assert(controller);
         assert(path);
         assert(_f);
 
-        if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
+        r = cg_get_path(controller, path, "tasks", &fs);
+        if (r < 0)
                 return r;
 
         f = fopen(fs, "re");
@@ -106,13 +106,13 @@ int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
         int r;
         DIR *d;
 
-        assert(controller);
         assert(path);
         assert(_d);
 
         /* This is not recursive! */
 
-        if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
+        r = cg_get_path(controller, path, NULL, &fs);
+        if (r < 0)
                 return r;
 
         d = opendir(fs);
@@ -515,14 +515,24 @@ static const char *normalize_controller(const char *controller) {
 static int join_path(const char *controller, const char *path, const char *suffix, char **fs) {
         char *t;
 
-        if (path && suffix)
-                t = join("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL);
-        else if (path)
-                t = join("/sys/fs/cgroup/", controller, "/", path, NULL);
-        else if (suffix)
-                t = join("/sys/fs/cgroup/", controller, "/", suffix, NULL);
-        else
-                t = join("/sys/fs/cgroup/", controller, NULL);
+        if (!(controller || path))
+                return -EINVAL;
+
+        if (controller) {
+                if (path && suffix)
+                        t = join("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL);
+                else if (path)
+                        t = join("/sys/fs/cgroup/", controller, "/", path, NULL);
+                else if (suffix)
+                        t = join("/sys/fs/cgroup/", controller, "/", suffix, NULL);
+                else
+                        t = join("/sys/fs/cgroup/", controller, NULL);
+        } else {
+                if (path && suffix)
+                        t = join(path, "/", suffix, NULL);
+                else if (path)
+                        t = strdup(path);
+        }
 
         if (!t)
                 return -ENOMEM;
@@ -537,12 +547,8 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
         const char *p;
         static __thread bool good = false;
 
-        assert(controller);
         assert(fs);
 
-        if (isempty(controller))
-                return -EINVAL;
-
         if (_unlikely_(!good)) {
                 int r;
 
@@ -554,8 +560,7 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
                 good = true;
         }
 
-        p = normalize_controller(controller);
-
+        p = controller ? normalize_controller(controller) : NULL;
         return join_path(p, path, suffix, fs);
 }
 
@@ -883,20 +888,22 @@ finish:
 }
 
 int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
-        pid_t pid = 0;
+        pid_t pid = 0, self_pid;
         int r;
         FILE *f = NULL;
         bool found = false;
 
-        assert(controller);
         assert(path);
 
-        if ((r = cg_enumerate_tasks(controller, path, &f)) < 0)
+        r = cg_enumerate_tasks(controller, path, &f);
+        if (r < 0)
                 return r == -ENOENT ? 1 : r;
 
+        self_pid = getpid();
+
         while ((r = cg_read_pid(f, &pid)) > 0) {
 
-                if (ignore_self && pid == getpid())
+                if (ignore_self && pid == self_pid)
                         continue;
 
                 found = true;
@@ -916,13 +923,14 @@ int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_
         DIR *d = NULL;
         char *fn;
 
-        assert(controller);
         assert(path);
 
-        if ((r = cg_is_empty(controller, path, ignore_self)) <= 0)
+        r = cg_is_empty(controller, path, ignore_self);
+        if (r <= 0)
                 return r;
 
-        if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0)
+        r = cg_enumerate_subgroups(controller, path, &d);
+        if (r < 0)
                 return r == -ENOENT ? 1 : r;
 
         while ((r = cg_read_subgroup(d, &fn)) > 0) {
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 28bdfa9..e8b8b51 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -2383,7 +2383,7 @@ static void print_status_info(UnitStatusInfo *i) {
                         else
                                 c = 0;
 
-                        show_cgroup_by_path(i->default_control_group, "\t\t  ", c, false);
+                        show_cgroup_by_path(i->default_control_group, "\t\t  ", c, false, arg_all);
                 }
         }
 

commit c7b5eb98e8eeafe63a079ee3c51e9670872437ae
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 16 17:05:15 2012 +0200

    logind: hook up inhibit logic with idle hint logic

diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index d01cf1a..b8143b6 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -1649,7 +1649,7 @@ static DBusHandlerResult manager_message_handler(
                         return bus_send_error_reply(connection, message, &error, r);
 
                 multiple_sessions = r > 0;
-                inhibit = !!(manager_inhibit_what(m) & INHIBIT_SHUTDOWN);
+                inhibit = manager_is_inhibited(m, INHIBIT_SHUTDOWN, NULL);
 
                 if (multiple_sessions) {
                         action = streq(dbus_message_get_member(message), "PowerOff") ?
@@ -1723,7 +1723,7 @@ static DBusHandlerResult manager_message_handler(
                         return bus_send_error_reply(connection, message, &error, r);
 
                 multiple_sessions = r > 0;
-                inhibit = !!(manager_inhibit_what(m) & INHIBIT_SHUTDOWN);
+                inhibit = manager_is_inhibited(m, INHIBIT_SHUTDOWN, NULL);
 
                 if (multiple_sessions) {
                         action = streq(dbus_message_get_member(message), "CanPowerOff") ?
diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c
index 2f7a758..78afee3 100644
--- a/src/login/logind-inhibit.c
+++ b/src/login/logind-inhibit.c
@@ -150,6 +150,8 @@ int inhibitor_start(Inhibitor *i) {
         if (i->started)
                 return 0;
 
+        dual_timestamp_get(&i->since);
+
         log_debug("Inhibitor %s (%s) pid=%lu uid=%lu started.",
                   strna(i->who), strna(i->why),
                   (unsigned long) i->pid, (unsigned long) i->uid);
@@ -325,6 +327,32 @@ InhibitWhat manager_inhibit_what(Manager *m) {
         return what;
 }
 
+bool manager_is_inhibited(Manager *m, InhibitWhat w, dual_timestamp *since) {
+        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->inhibitor_fds, j) {
+                if (!(i->what & w))
+                        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 const char* const table[_INHIBIT_WHAT_MAX] = {
diff --git a/src/login/logind-inhibit.h b/src/login/logind-inhibit.h
index 0670a7f..1d47cfc 100644
--- a/src/login/logind-inhibit.h
+++ b/src/login/logind-inhibit.h
@@ -52,6 +52,8 @@ struct Inhibitor {
         pid_t pid;
         uid_t uid;
 
+        dual_timestamp since;
+
         char *fifo_path;
         int fifo_fd;
 };
@@ -69,6 +71,7 @@ int inhibitor_create_fifo(Inhibitor *i);
 void inhibitor_remove_fifo(Inhibitor *i);
 
 InhibitWhat manager_inhibit_what(Manager *m);
+bool manager_is_inhibited(Manager *m, InhibitWhat w, dual_timestamp *since);
 
 const char *inhibit_what_to_string(InhibitWhat k);
 InhibitWhat inhibit_what_from_string(const char *s);
diff --git a/src/login/logind.c b/src/login/logind.c
index 7222e3a..1169752 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -1157,12 +1157,14 @@ void manager_gc(Manager *m, bool drop_not_started) {
 
 int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
         Session *s;
-        bool idle_hint = true;
+        bool idle_hint;
         dual_timestamp ts = { 0, 0 };
         Iterator i;
 
         assert(m);
 
+        idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, t);
+
         HASHMAP_FOREACH(s, m->sessions, i) {
                 dual_timestamp k;
                 int ih;

commit f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 16 16:47:33 2012 +0200

    logind: add shutdown/suspend/idle inhibition framework

diff --git a/.gitignore b/.gitignore
index cf1dff8..af7a017 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@
 /test-id128
 /test-journal
 /test-install
+/test-inhibit
 /org.freedesktop.hostname1.xml
 /org.freedesktop.locale1.xml
 /test-login
diff --git a/Makefile.am b/Makefile.am
index 1353d97..0d2cb70 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2577,6 +2577,8 @@ systemd_logind_SOURCES = \
 	src/login/logind-session.h \
 	src/login/logind-user.c \
 	src/login/logind-user.h \
+	src/login/logind-inhibit.c \
+	src/login/logind-inhibit.h \
 	src/login/logind-session-dbus.c \
 	src/login/logind-seat-dbus.c \
 	src/login/logind-user-dbus.c \
@@ -2638,8 +2640,20 @@ test_login_LDADD = \
 	libsystemd-login.la \
 	libsystemd-shared.la
 
+test_inhibit_SOURCES = \
+	src/login/test-inhibit.c
+
+test_inhibit_LDADD = \
+	libsystemd-shared.la \
+	libsystemd-dbus.la
+
+test_inhibit_CFLAGS = \
+	$(AM_CFLAGS) \
+	$(DBUS_CFLAGS)
+
 noinst_PROGRAMS += \
-	test-login
+	test-login \
+	test-inhibit
 
 libsystemd_login_la_SOURCES = \
 	src/login/sd-login.c
diff --git a/TODO b/TODO
index 3586b41..06a2afc 100644
--- a/TODO
+++ b/TODO
@@ -15,7 +15,9 @@ Bugfixes:
 
 Features:
 
-* cg_create_and_attach() should fail for non-available controllers
+* filter default cgroups in logind too
+
+* remove empty cgroups from cgls output
 
 * udev: remove /sys and /dev configurability
 
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 6b013b9..d01cf1a 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -140,6 +140,15 @@
         "  <method name=\"CanReboot\">\n"                               \
         "   <arg name=\"result\" type=\"s\" direction=\"out\"/>\n"      \
         "  </method>\n"                                                 \
+        "  <method name=\"Inhibit\">\n"                                 \
+        "   <arg name=\"what\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"who\" type=\"s\" direction=\"in\"/>\n"          \
+        "   <arg name=\"why\" type=\"s\" direction=\"in\"/>\n"          \
+        "   <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n"          \
+        "  </method>\n"                                                 \
+        "  <method name=\"ListInhibitors\">\n"                          \
+        "   <arg name=\"inhibitors\" type=\"a(sssuu)\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
         "  <signal name=\"SessionNew\">\n"                              \
         "   <arg name=\"id\" type=\"s\"/>\n"                            \
         "   <arg name=\"path\" type=\"o\"/>\n"                          \
@@ -174,6 +183,7 @@
         "  <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n"  \
         "  <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"Inhibited\" type=\"s\" access=\"read\"/>\n" \
         " </interface>\n"
 
 #define INTROSPECTION_BEGIN                                             \
@@ -224,6 +234,20 @@ static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *pr
         return 0;
 }
 
+static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
+        Manager *m = data;
+        InhibitWhat w;
+        const char *p;
+
+        w = manager_inhibit_what(m);
+        p = inhibit_what_to_string(w);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
+                return -ENOMEM;
+
+        return 0;
+}
+
 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
         Session *session = NULL;
         User *user = NULL;
@@ -466,9 +490,9 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
         } else {
                 do {
                         free(id);
-                        asprintf(&id, "c%lu", ++m->session_counter);
+                        id = NULL;
 
-                        if (!id) {
+                        if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
                                 r = -ENOMEM;
                                 goto fail;
                         }
@@ -602,6 +626,122 @@ fail:
         return r;
 }
 
+static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
+        Inhibitor *i = NULL;
+        char *id = NULL;
+        const char *who, *why, *what;
+        pid_t pid;
+        InhibitWhat w;
+        unsigned long ul;
+        int r, fifo_fd = -1;
+        DBusMessage *reply = NULL;
+
+        assert(m);
+        assert(connection);
+        assert(message);
+        assert(error);
+        assert(_reply);
+
+        if (!dbus_message_get_args(
+                            message,
+                            error,
+                            DBUS_TYPE_STRING, &what,
+                            DBUS_TYPE_STRING, &who,
+                            DBUS_TYPE_STRING, &why,
+                            DBUS_TYPE_INVALID)) {
+                r = -EIO;
+                goto fail;
+        }
+
+        w = inhibit_what_from_string(what);
+        if (w <= 0) {
+                r = -EINVAL;
+                goto fail;
+        }
+
+        r = verify_polkit(connection, message, "org.freedesktop.login1.inhibit", false, NULL, error);
+        if (r < 0)
+                goto fail;
+
+        ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
+        if (ul == (unsigned long) -1) {
+                r = -EIO;
+                goto fail;
+        }
+
+        pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
+        if (pid <= 0) {
+                r = -EIO;
+                goto fail;
+        }
+
+        do {
+                free(id);
+                id = NULL;
+
+                if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        } while (hashmap_get(m->inhibitors, id));
+
+        r = manager_add_inhibitor(m, id, &i);
+        free(id);
+
+        if (r < 0)
+                goto fail;
+
+        i->what = w;
+        i->pid = pid;
+        i->uid = (uid_t) ul;
+        i->why = strdup(why);
+        i->who = strdup(who);
+
+        if (!i->why || !i->who) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        fifo_fd = inhibitor_create_fifo(i);
+        if (fifo_fd < 0) {
+                r = fifo_fd;
+                goto fail;
+        }
+
+        reply = dbus_message_new_method_return(message);
+        if (!reply) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        if (!dbus_message_append_args(
+                            reply,
+                            DBUS_TYPE_UNIX_FD, &fifo_fd,
+                            DBUS_TYPE_INVALID)) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        close_nointr_nofail(fifo_fd);
+        *_reply = reply;
+
+        inhibitor_start(i);
+
+        return 0;
+
+fail:
+        if (i)
+                inhibitor_free(i);
+
+        if (fifo_fd >= 0)
+                close_nointr_nofail(fifo_fd);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        return r;
+}
+
 static int trigger_device(Manager *m, struct udev_device *d) {
         struct udev_enumerate *e;
         struct udev_list_entry *first, *item;
@@ -780,6 +920,7 @@ static const BusProperty bus_login_manager_properties[] = {
         { "IdleHint",               bus_manager_append_idle_hint,       "b",  0 },
         { "IdleSinceHint",          bus_manager_append_idle_hint_since, "t",  0 },
         { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t",  0 },
+        { "Inhibited",              bus_manager_append_inhibited,       "s",  0 },
         { NULL, }
 };
 
@@ -1067,6 +1208,56 @@ static DBusHandlerResult manager_message_handler(
                 if (!dbus_message_iter_close_container(&iter, &sub))
                         goto oom;
 
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
+                Inhibitor *inhibitor;
+                Iterator i;
+                DBusMessageIter iter, sub;
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+                dbus_message_iter_init_append(reply, &iter);
+
+                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sssuu)", &sub))
+                        goto oom;
+
+                HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
+                        DBusMessageIter sub2;
+                        dbus_uint32_t uid, pid;
+                        const char *what, *who, *why;
+
+                        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+                                goto oom;
+
+                        what = inhibit_what_to_string(inhibitor->what);
+                        who = strempty(inhibitor->who);
+                        why = strempty(inhibitor->why);
+                        uid = (dbus_uint32_t) inhibitor->uid;
+                        pid = (dbus_uint32_t) inhibitor->pid;
+
+                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
+                                goto oom;
+
+                        if (!dbus_message_iter_close_container(&sub, &sub2))
+                                goto oom;
+                }
+
+                if (!dbus_message_iter_close_container(&iter, &sub))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
+
+                r = bus_manager_inhibit(m, connection, message, &error, &reply);
+
+                if (r < 0)
+                        return bus_send_error_reply(connection, message, &error, r);
+
+
         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
 
                 r = bus_manager_create_session(m, message, &reply);
@@ -1077,7 +1268,7 @@ static DBusHandlerResult manager_message_handler(
                  * see this fail quickly then be retried later */
 
                 if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
+                        return bus_send_error_reply(connection, message, NULL, r);
 
         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
                 const char *name;
@@ -1441,11 +1632,10 @@ static DBusHandlerResult manager_message_handler(
         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff") ||
                    dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
                 dbus_bool_t interactive;
-                bool multiple_sessions;
+                bool multiple_sessions, inhibit;
                 DBusMessage *forward, *freply;
-                const char *name;
+                const char *name, *action;
                 const char *mode = "replace";
-                const char *action;
 
                 if (!dbus_message_get_args(
                                     message,
@@ -1459,26 +1649,37 @@ static DBusHandlerResult manager_message_handler(
                         return bus_send_error_reply(connection, message, &error, r);
 
                 multiple_sessions = r > 0;
+                inhibit = !!(manager_inhibit_what(m) & INHIBIT_SHUTDOWN);
 
-                if (streq(dbus_message_get_member(message), "PowerOff")) {
-                        if (multiple_sessions)
-                                action = "org.freedesktop.login1.power-off-multiple-sessions";
-                        else
-                                action = "org.freedesktop.login1.power-off";
+                if (multiple_sessions) {
+                        action = streq(dbus_message_get_member(message), "PowerOff") ?
+                                "org.freedesktop.login1.power-off-multiple-sessions" :
+                                "org.freedesktop.login1.reboot-multiple-sessions";
 
-                        name = SPECIAL_POWEROFF_TARGET;
-                } else {
-                        if (multiple_sessions)
-                                action = "org.freedesktop.login1.reboot-multiple-sessions";
-                        else
-                                action = "org.freedesktop.login1.reboot";
+                        r = verify_polkit(connection, message, action, interactive, NULL, &error);
+                        if (r < 0)
+                                return bus_send_error_reply(connection, message, &error, r);
+                }
+
+                if (inhibit) {
+                        action = streq(dbus_message_get_member(message), "PowerOff") ?
+                                "org.freedesktop.login1.power-off-ignore-inhibit" :
+                                "org.freedesktop.login1.reboot-ignore-inhibit";
 
-                        name = SPECIAL_REBOOT_TARGET;
+                        r = verify_polkit(connection, message, action, interactive, NULL, &error);
+                        if (r < 0)
+                                return bus_send_error_reply(connection, message, &error, r);
                 }
 
-                r = verify_polkit(connection, message, action, interactive, NULL, &error);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
+                if (!multiple_sessions && !inhibit) {
+                        action = streq(dbus_message_get_member(message), "PowerOff") ?
+                                "org.freedesktop.login1.power-off" :
+                                "org.freedesktop.login1.reboot";
+
+                        r = verify_polkit(connection, message, action, interactive, NULL, &error);
+                        if (r < 0)
+                                return bus_send_error_reply(connection, message, &error, r);
+                }
 
                 forward = dbus_message_new_method_call(
                               "org.freedesktop.systemd1",
@@ -1488,6 +1689,9 @@ static DBusHandlerResult manager_message_handler(
                 if (!forward)
                         return bus_send_error_reply(connection, message, NULL, -ENOMEM);
 
+                name = streq(dbus_message_get_member(message), "PowerOff") ?
+                        SPECIAL_POWEROFF_TARGET : SPECIAL_REBOOT_TARGET;
+
                 if (!dbus_message_append_args(forward,
                                               DBUS_TYPE_STRING, &name,
                                               DBUS_TYPE_STRING, &mode,
@@ -1511,43 +1715,77 @@ static DBusHandlerResult manager_message_handler(
         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff") ||
                    dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
 
-                bool multiple_sessions, challenge, b;
-                const char *t, *action;
+                bool multiple_sessions, challenge, inhibit, b;
+                const char *action, *result;
 
                 r = have_multiple_sessions(connection, m, message, &error);
                 if (r < 0)
                         return bus_send_error_reply(connection, message, &error, r);
 
                 multiple_sessions = r > 0;
+                inhibit = !!(manager_inhibit_what(m) & INHIBIT_SHUTDOWN);
+
+                if (multiple_sessions) {
+                        action = streq(dbus_message_get_member(message), "CanPowerOff") ?
+                                "org.freedesktop.login1.power-off-multiple-sessions" :
+                                "org.freedesktop.login1.reboot-multiple-sessions";
 
-                if (streq(dbus_message_get_member(message), "CanPowerOff")) {
-                        if (multiple_sessions)
-                                action = "org.freedesktop.login1.power-off-multiple-sessions";
+                        r = verify_polkit(connection, message, action, false, &challenge, &error);
+                        if (r < 0)
+                                return bus_send_error_reply(connection, message, &error, r);
+
+                        if (r > 0)
+                                result = "yes";
+                        else if (challenge)
+                                result = "challenge";
                         else
-                                action = "org.freedesktop.login1.power-off";
+                                result = "no";
+                }
 
-                } else {
-                        if (multiple_sessions)
-                                action = "org.freedesktop.login1.reboot-multiple-sessions";
+                if (inhibit) {
+                        action = streq(dbus_message_get_member(message), "CanPowerOff") ?
+                                "org.freedesktop.login1.power-off-ignore-inhibit" :
+                                "org.freedesktop.login1.reboot-ignore-inhibit";
+
+                        r = verify_polkit(connection, message, action, false, &challenge, &error);
+                        if (r < 0)
+                                return bus_send_error_reply(connection, message, &error, r);
+
+                        if (r > 0 && !result)
+                                result = "yes";
+                        else if (challenge && (!result || streq(result, "yes")))
+                                result = "challenge";
                         else
-                                action = "org.freedesktop.login1.reboot";
+                                result = "no";
                 }
 
-                r = verify_polkit(connection, message, action, false, &challenge, &error);
-                if (r < 0)
-                        return bus_send_error_reply(connection, message, &error, r);
+                if (!multiple_sessions && !inhibit) {
+                        /* If neither inhibit nor multiple sessions
+                         * apply then just check the normal policy */
+
+                        action = streq(dbus_message_get_member(message), "CanPowerOff") ?
+                                "org.freedesktop.login1.power-off" :
+                                "org.freedesktop.login1.reboot";
+
+                        r = verify_polkit(connection, message, action, false, &challenge, &error);
+                        if (r < 0)
+                                return bus_send_error_reply(connection, message, &error, r);
+
+                        if (r > 0)
+                                result = "yes";
+                        else if (challenge)
+                                result = "challenge";
+                        else
+                                result = "no";
+                }
 
                 reply = dbus_message_new_method_return(message);
                 if (!reply)
                         goto oom;
 
-                t =     r > 0 ?     "yes" :
-                        challenge ? "challenge" :
-                                    "no";
-
                 b = dbus_message_append_args(
                                 reply,
-                                DBUS_TYPE_STRING, &t,
+                                DBUS_TYPE_STRING, &result,
                                 DBUS_TYPE_INVALID);
                 if (!b)
                         goto oom;
diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c
new file mode 100644
index 0000000..2f7a758
--- /dev/null
+++ b/src/login/logind-inhibit.c
@@ -0,0 +1,365 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2012 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#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 "logind-inhibit.h"
+
+Inhibitor* inhibitor_new(Manager *m, const char* id) {
+        Inhibitor *i;
+
+        assert(m);
+
+        i = new0(Inhibitor, 1);
+        if (!i)
+                return NULL;
+
+        i->state_file = strappend("/run/systemd/inhibit/", id);
+        if (!i->state_file) {
+                free(i);
+                return NULL;
+        }
+
+        i->id = file_name_from_path(i->state_file);
+
+        if (hashmap_put(m->inhibitors, i->id, i) < 0) {
+                free(i->state_file);
+                free(i);
+                return NULL;
+        }
+
+        i->manager = m;
+        i->fifo_fd = -1;
+
+        return i;
+}
+
+void inhibitor_free(Inhibitor *i) {
+        assert(i);
+
+        free(i->who);
+        free(i->why);
+
+        hashmap_remove(i->manager->inhibitors, i->id);
+        inhibitor_remove_fifo(i);
+
+        if (i->state_file) {
+                unlink(i->state_file);
+                free(i->state_file);
+        }
+
+        free(i);
+}
+
+int inhibitor_save(Inhibitor *i) {
+        char *temp_path, *cc;
+        int r;
+        FILE *f;
+
+        assert(i);
+
+        r = safe_mkdir("/run/systemd/inhibit", 0755, 0, 0);
+        if (r < 0)
+                goto finish;
+
+        r = fopen_temporary(i->state_file, &f, &temp_path);
+        if (r < 0)
+                goto finish;
+
+        fchmod(fileno(f), 0644);
+
+        fprintf(f,
+                "# This is private data. Do not parse.\n"
+                "WHAT=%s\n"
+                "UID=%lu\n"
+                "PID=%lu\n",
+                inhibit_what_to_string(i->what),
+                (unsigned long) i->uid,
+                (unsigned long) i->pid);
+
+        if (i->who) {
+                cc = cescape(i->who);
+                if (!cc)
+                        r = -ENOMEM;
+                else {
+                        fprintf(f, "WHO=%s\n", cc);
+                        free(cc);
+                }
+        }
+
+        if (i->why) {
+                cc = cescape(i->why);
+                if (!cc)
+                        r = -ENOMEM;
+                else {
+                        fprintf(f, "WHY=%s\n", cc);
+                        free(cc);
+                }
+        }
+
+        if (i->fifo_path)
+                fprintf(f, "FIFO=%s\n", i->fifo_path);
+
+        fflush(f);
+
+        if (ferror(f) || rename(temp_path, i->state_file) < 0) {
+                r = -errno;
+                unlink(i->state_file);
+                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));
+
+        return r;
+}
+
+int inhibitor_start(Inhibitor *i) {
+        assert(i);
+
+        if (i->started)
+                return 0;
+
+        log_debug("Inhibitor %s (%s) pid=%lu uid=%lu started.",
+                  strna(i->who), strna(i->why),
+                  (unsigned long) i->pid, (unsigned long) i->uid);
+
+        inhibitor_save(i);
+
+        i->started = true;
+
+        manager_send_changed(i->manager, "Inhibited\0");
+
+        return 0;
+}
+
+int inhibitor_stop(Inhibitor *i) {
+        assert(i);
+
+        if (i->started)
+                log_debug("Inhibitor %s (%s) pid=%lu uid=%lu stopped.",
+                          strna(i->who), strna(i->why),
+                          (unsigned long) i->pid, (unsigned long) i->uid);
+
+        if (i->state_file)
+                unlink(i->state_file);
+
+        i->started = false;
+
+        manager_send_changed(i->manager, "Inhibited\0");
+
+        return 0;
+}
+
+int inhibitor_load(Inhibitor *i) {
+        InhibitWhat w;
+        int r;
+        char *cc,
+                *what = NULL,
+                *uid = NULL,
+                *pid = NULL,
+                *who = NULL,
+                *why = NULL;
+
+        r = parse_env_file(i->state_file, NEWLINE,
+                           "WHAT", &what,
+                           "UID", &uid,
+                           "PID", &pid,
+                           "WHO", &who,
+                           "WHY", &why,
+                           "FIFO", &i->fifo_path,
+                           NULL);
+        if (r < 0)
+                goto finish;
+
+        w = inhibit_what_from_string(what);
+        if (w >= 0)
+                i->what = w;
+
+        parse_uid(uid, &i->uid);
+        parse_pid(pid, &i->pid);
+
+        if (who) {
+                cc = cunescape(who);
+                if (!cc) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                free(i->who);
+                i->who = cc;
+        }
+
+        if (why) {
+                cc = cunescape(why);
+                if (!cc) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                free(i->why);
+                i->why = cc;
+        }
+
+        if (i->fifo_path) {
+                int fd;
+
+                fd = inhibitor_create_fifo(i);
+                if (fd >= 0)
+                        close_nointr_nofail(fd);
+        }
+
+finish:
+        free(what);
+        free(uid);
+        free(pid);
+        free(who);
+        free(why);
+
+        return r;
+}
+
+int inhibitor_create_fifo(Inhibitor *i) {
+        int r;
+
+        assert(i);
+
+        /* Create FIFO */
+        if (!i->fifo_path) {
+                r = safe_mkdir("/run/systemd/inhibit", 0755, 0, 0);
+                if (r < 0)
+                        return r;
+
+                if (asprintf(&i->fifo_path, "/run/systemd/inhibit/%s.ref", i->id) < 0)
+                        return -ENOMEM;
+
+                if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
+                        return -errno;
+        }
+
+        /* 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 (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;
+        }
+
+        /* Open writing side */
+        r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
+        if (r < 0)
+                return -errno;
+
+        return r;
+}
+
+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;
+        }
+
+        if (i->fifo_path) {
+                unlink(i->fifo_path);
+                free(i->fifo_path);
+                i->fifo_path = NULL;
+        }
+}
+
+InhibitWhat manager_inhibit_what(Manager *m) {
+        Inhibitor *i;
+        Iterator j;
+        InhibitWhat what = 0;
+
+        assert(m);
+
+        HASHMAP_FOREACH(i, m->inhibitor_fds, j)
+                what |= i->what;
+
+        return what;
+}
+
+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"
+        };
+
+        if (w < 0 || w >= _INHIBIT_WHAT_MAX)
+                return NULL;
+
+        return table[w];
+}
+
+InhibitWhat inhibit_what_from_string(const char *s) {
+        InhibitWhat what = 0;
+        char *w, *state;
+        size_t l;
+
+        FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
+                if (l == 8 && strncmp(w, "shutdown", l) == 0)
+                        what |= INHIBIT_SHUTDOWN;
+                else if (l == 7 && strncmp(w, "suspend", l) == 0)
+                        what |= INHIBIT_SUSPEND;
+                else if (l == 4 && strncmp(w, "idle", l) == 0)
+                        what |= INHIBIT_IDLE;
+                else
+                        return _INHIBIT_WHAT_INVALID;
+        }
+
+        return what;
+
+}
diff --git a/src/login/logind-inhibit.h b/src/login/logind-inhibit.h
new file mode 100644
index 0000000..0670a7f
--- /dev/null
+++ b/src/login/logind-inhibit.h
@@ -0,0 +1,76 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologindinhibithfoo
+#define foologindinhibithfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2012 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Inhibitor Inhibitor;
+
+#include "list.h"
+#include "util.h"
+#include "logind.h"
+#include "logind-seat.h"
+
+typedef enum InhibitWhat {
+        INHIBIT_SHUTDOWN = 1,
+        INHIBIT_SUSPEND = 2,
+        INHIBIT_IDLE = 4,
+        _INHIBIT_WHAT_MAX = 8,
+        _INHIBIT_WHAT_INVALID = -1
+} InhibitWhat;
+
+struct Inhibitor {
+        Manager *manager;
+
+        char *id;
+        char *state_file;
+
+        bool started;
+
+        InhibitWhat what;
+        char *who;
+        char *why;
+
+        pid_t pid;
+        uid_t uid;
+
+        char *fifo_path;
+        int fifo_fd;
+};
+
+Inhibitor* inhibitor_new(Manager *m, const char *id);
+void inhibitor_free(Inhibitor *i);
+
+int inhibitor_save(Inhibitor *i);
+int inhibitor_load(Inhibitor *i);
+
+int inhibitor_start(Inhibitor *i);
+int inhibitor_stop(Inhibitor *i);
+
+int inhibitor_create_fifo(Inhibitor *i);
+void inhibitor_remove_fifo(Inhibitor *i);
+
+InhibitWhat manager_inhibit_what(Manager *m);
+
+const char *inhibit_what_to_string(InhibitWhat k);
+InhibitWhat inhibit_what_from_string(const char *s);
+
+#endif
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index cbc4b5c..5490366 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -25,11 +25,11 @@
 #include <sys/epoll.h>
 #include <fcntl.h>
 
-#include "logind-session.h"
 #include "strv.h"
 #include "util.h"
 #include "mkdir.h"
 #include "cgroup-util.h"
+#include "logind-session.h"
 
 #define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
 
@@ -52,7 +52,7 @@ Session* session_new(Manager *m, User *u, const char *id) {
         s->id = file_name_from_path(s->state_file);
 
         if (hashmap_put(m->sessions, s->id, s) < 0) {
-                free(s->id);
+                free(s->state_file);
                 free(s);
                 return NULL;
         }
@@ -99,7 +99,6 @@ void session_free(Session *s) {
         free(s->service);
 
         hashmap_remove(s->manager->sessions, s->id);
-
         session_remove_fifo(s);
 
         free(s->state_file);
@@ -287,14 +286,9 @@ int session_load(Session *s) {
         }
 
         if (leader) {
-                pid_t pid;
-
-                k = parse_pid(leader, &pid);
-                if (k >= 0 && pid >= 1) {
-                        s->leader = pid;
-
-                        audit_session_from_pid(pid, &s->audit_id);
-                }
+                k = parse_pid(leader, &s->leader);
+                if (k >= 0)
+                        audit_session_from_pid(s->leader, &s->audit_id);
         }
 
         if (type) {
@@ -326,7 +320,6 @@ int session_load(Session *s) {
                         close_nointr_nofail(fd);
         }
 
-
 finish:
         free(remote);
         free(kill_processes);
@@ -840,7 +833,7 @@ int session_create_fifo(Session *s) {
                 if (s->fifo_fd < 0)
                         return -errno;
 
-                r = hashmap_put(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1), s);
+                r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
                 if (r < 0)
                         return r;
 
@@ -864,7 +857,7 @@ void session_remove_fifo(Session *s) {
         assert(s);
 
         if (s->fifo_fd >= 0) {
-                assert_se(hashmap_remove(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
+                assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
                 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
                 close_nointr_nofail(s->fifo_fd);
                 s->fifo_fd = -1;
diff --git a/src/login/logind.c b/src/login/logind.c
index fc08c4b..7222e3a 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -55,10 +55,14 @@ Manager *manager_new(void) {
         m->seats = hashmap_new(string_hash_func, string_compare_func);
         m->sessions = hashmap_new(string_hash_func, string_compare_func);
         m->users = hashmap_new(trivial_hash_func, trivial_compare_func);
+        m->inhibitors = hashmap_new(string_hash_func, string_compare_func);
+
         m->cgroups = hashmap_new(string_hash_func, string_compare_func);
-        m->fifo_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
+        m->session_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
+        m->inhibitor_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
 
-        if (!m->devices || !m->seats || !m->sessions || !m->users || !m->cgroups || !m->fifo_fds) {
+        if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors ||
+            !m->cgroups || !m->session_fds || !m->inhibitor_fds) {
                 manager_free(m);
                 return NULL;
         }
@@ -89,6 +93,7 @@ void manager_free(Manager *m) {
         User *u;
         Device *d;
         Seat *s;
+        Inhibitor *i;
 
         assert(m);
 
@@ -104,12 +109,18 @@ void manager_free(Manager *m) {
         while ((s = hashmap_first(m->seats)))
                 seat_free(s);
 
-        hashmap_free(m->sessions);
-        hashmap_free(m->users);
+        while ((i = hashmap_first(m->inhibitors)))
+                inhibitor_free(i);
+
         hashmap_free(m->devices);
         hashmap_free(m->seats);
+        hashmap_free(m->sessions);
+        hashmap_free(m->users);
+        hashmap_free(m->inhibitors);
+
         hashmap_free(m->cgroups);
-        hashmap_free(m->fifo_fds);
+        hashmap_free(m->session_fds);
+        hashmap_free(m->inhibitor_fds);
 
         if (m->console_active_fd >= 0)
                 close_nointr_nofail(m->console_active_fd);
@@ -268,6 +279,30 @@ int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
         return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
 }
 
+int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor) {
+        Inhibitor *i;
+
+        assert(m);
+        assert(id);
+
+        i = hashmap_get(m->inhibitors, id);
+        if (i) {
+                if (_inhibitor)
+                        *_inhibitor = i;
+
+                return 0;
+        }
+
+        i = inhibitor_new(m, id);
+        if (!i)
+                return -ENOMEM;
+
+        if (_inhibitor)
+                *_inhibitor = i;
+
+        return 0;
+}
+
 int manager_process_seat_device(Manager *m, struct udev_device *d) {
         Device *device;
         int r;
@@ -412,10 +447,9 @@ int manager_enumerate_seats(Manager *m) {
 }
 
 static int manager_enumerate_users_from_cgroup(Manager *m) {
-        int r = 0;
+        int r = 0, k;
         char *name;
         DIR *d;
-        int k;
 
         r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &d);
         if (r < 0) {
@@ -641,6 +675,46 @@ int manager_enumerate_sessions(Manager *m) {
         return r;
 }
 
+int manager_enumerate_inhibitors(Manager *m) {
+        DIR *d;
+        struct dirent *de;
+        int r = 0;
+
+        assert(m);
+
+        d = opendir("/run/systemd/inhibit");
+        if (!d) {
+                if (errno == ENOENT)
+                        return 0;
+
+                log_error("Failed to open /run/systemd/inhibit: %m");
+                return -errno;
+        }
+
+        while ((de = readdir(d))) {
+                int k;
+                Inhibitor *i;
+
+                if (!dirent_is_file(de))
+                        continue;
+
+                k = manager_add_inhibitor(m, de->d_name, &i);
+                if (k < 0) {
+                        log_notice("Couldn't add inhibitor %s: %s", de->d_name, strerror(-k));
+                        r = k;
+                        continue;
+                }
+
+                k = inhibitor_load(i);
+                if (k < 0)
+                        r = k;
+        }
+
+        closedir(d);
+
+        return r;
+}
+
 int manager_dispatch_seat_udev(Manager *m) {
         struct udev_device *d;
         int r;
@@ -853,15 +927,28 @@ void manager_cgroup_notify_empty(Manager *m, const char *cgroup) {
 
 static void manager_pipe_notify_eof(Manager *m, int fd) {
         Session *s;
+        Inhibitor *i;
 
         assert_se(m);
         assert_se(fd >= 0);
 
-        assert_se(s = hashmap_get(m->fifo_fds, INT_TO_PTR(fd + 1)));
-        assert(s->fifo_fd == fd);
-        session_remove_fifo(s);
+        s = hashmap_get(m->session_fds, INT_TO_PTR(fd + 1));
+        if (s) {
+                assert(s->fifo_fd == fd);
+                session_remove_fifo(s);
+                session_stop(s);
+                return;
+        }
 
-        session_stop(s);
+        i = hashmap_get(m->inhibitor_fds, INT_TO_PTR(fd + 1));
+        if (i) {
+                assert(i->fifo_fd == fd);
+                inhibitor_stop(i);
+                inhibitor_free(i);
+                return;
+        }
+
+        assert_not_reached("Got EOF on unknown pipe");
 }
 
 static int manager_connect_bus(Manager *m) {
@@ -1110,6 +1197,7 @@ int manager_startup(Manager *m) {
         Seat *seat;
         Session *session;
         User *user;
+        Inhibitor *inhibitor;
         Iterator i;
 
         assert(m);
@@ -1144,6 +1232,7 @@ int manager_startup(Manager *m) {
         manager_enumerate_seats(m);
         manager_enumerate_users(m);
         manager_enumerate_sessions(m);
+        manager_enumerate_inhibitors(m);
 
         /* Remove stale objects before we start them */
         manager_gc(m, false);
@@ -1158,6 +1247,9 @@ int manager_startup(Manager *m) {
         HASHMAP_FOREACH(session, m->sessions, i)
                 session_start(session);
 
+        HASHMAP_FOREACH(inhibitor, m->inhibitors, i)
+                inhibitor_start(inhibitor);
+
         return 0;
 }
 
diff --git a/src/login/logind.h b/src/login/logind.h
index a308037..4e9dcd5 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -39,6 +39,7 @@ typedef struct Manager Manager;
 #include "logind-seat.h"
 #include "logind-session.h"
 #include "logind-user.h"
+#include "logind-inhibit.h"
 
 struct Manager {
         DBusConnection *bus;
@@ -47,6 +48,7 @@ struct Manager {
         Hashmap *seats;
         Hashmap *sessions;
         Hashmap *users;
+        Hashmap *inhibitors;
 
         LIST_HEAD(Seat, seat_gc_queue);
         LIST_HEAD(Session, session_gc_queue);
@@ -74,9 +76,11 @@ struct Manager {
         bool kill_user_processes;
 
         unsigned long session_counter;
+        unsigned long inhibit_counter;
 
         Hashmap *cgroups;
-        Hashmap *fifo_fds;
+        Hashmap *session_fds;
+        Hashmap *inhibitor_fds;
 };
 
 enum {
@@ -96,6 +100,7 @@ int manager_add_session(Manager *m, User *u, const char *id, Session **_session)
 int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user);
 int manager_add_user_by_name(Manager *m, const char *name, User **_user);
 int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user);
+int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor);
 
 int manager_process_seat_device(Manager *m, struct udev_device *d);
 int manager_dispatch_seat_udev(Manager *m);
@@ -106,6 +111,7 @@ int manager_enumerate_devices(Manager *m);
 int manager_enumerate_seats(Manager *m);
 int manager_enumerate_sessions(Manager *m);
 int manager_enumerate_users(Manager *m);
+int manager_enumerate_inhibitors(Manager *m);
 
 int manager_startup(Manager *m);
 int manager_run(Manager *m);
diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf
index 7ebf9ea..0f70b37 100644
--- a/src/login/org.freedesktop.login1.conf
+++ b/src/login/org.freedesktop.login1.conf
@@ -66,6 +66,14 @@
 
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Manager"
+                       send_member="ListInhibitors"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="Inhibit"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
                        send_member="SetUserLinger"/>
 
                 <allow send_destination="org.freedesktop.login1"
diff --git a/src/login/org.freedesktop.login1.policy.in b/src/login/org.freedesktop.login1.policy.in
index fb5c539..a2dc402 100644
--- a/src/login/org.freedesktop.login1.policy.in
+++ b/src/login/org.freedesktop.login1.policy.in
@@ -16,6 +16,16 @@
         <vendor>The systemd Project</vendor>
         <vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url>
 
+        <action id="org.freedesktop.login1.inhibit">
+                <_description>Allow applications to inhibit system shutdown and suspend</_description>
+                <_message>Authentication is required to allow an application to inhibit system shutdown or suspend</_message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>yes</allow_inactive>
+                        <allow_active>yes</allow_active>
+                </defaults>
+        </action>
+
         <action id="org.freedesktop.login1.set-user-linger">
                 <_description>Allow non-logged-in users to run programs</_description>
                 <_message>Authentication is required to allow a non-logged-in user to run programs</_message>
@@ -66,6 +76,16 @@
                 </defaults>
         </action>
 
+        <action id="org.freedesktop.login1.power-off-ignore-inhibit">
+                <_description>Power off the system when an application asked to inhibit it</_description>
+                <_message>Authentication is required to allow powering off the system while an application asked to inhibit it</_message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+        </action>
+
         <action id="org.freedesktop.login1.reboot">
                 <_description>Reboot the system</_description>
                 <_message>Authentication is required to allow rebooting the system</_message>
@@ -86,4 +106,14 @@
                 </defaults>
         </action>
 
+        <action id="org.freedesktop.login1.reboot-ignore-inhibit">
+                <_description>Reboot the system when an application asked to inhibit it</_description>
+                <_message>Authentication is required to allow rebooting the system while an application asked to inhibit it</_message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+        </action>
+
 </policyconfig>
diff --git a/src/login/test-inhibit.c b/src/login/test-inhibit.c
new file mode 100644
index 0000000..c83e960
--- /dev/null
+++ b/src/login/test-inhibit.c
@@ -0,0 +1,137 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2012 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <unistd.h>
+
+#include <dbus/dbus.h>
+
+#include "macro.h"
+#include "util.h"
+#include "dbus-common.h"
+
+static int inhibit(DBusConnection *bus, const char *what) {
+        DBusMessage *m, *reply;
+        DBusError error;
+        const char *who = "Test Tool", *reason = "Just because!";
+        int fd;
+
+        dbus_error_init(&error);
+
+        m = dbus_message_new_method_call(
+                        "org.freedesktop.login1",
+                        "/org/freedesktop/login1",
+                        "org.freedesktop.login1.Manager",
+                        "Inhibit");
+        assert(m);
+
+        assert_se(dbus_message_append_args(m,
+                                           DBUS_TYPE_STRING, &what,
+                                           DBUS_TYPE_STRING, &who,
+                                           DBUS_TYPE_STRING, &reason,
+                                           DBUS_TYPE_INVALID));
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+        assert(reply);
+
+        assert(dbus_message_get_args(reply, &error,
+                                     DBUS_TYPE_UNIX_FD, &fd,
+                                     DBUS_TYPE_INVALID));
+
+        dbus_message_unref(m);
+        dbus_message_unref(reply);
+
+        return fd;
+}
+
+static void print_inhibitors(DBusConnection *bus) {
+        DBusMessage *m, *reply;
+        DBusError error;
+        unsigned n = 0;
+        DBusMessageIter iter, sub, sub2;
+
+        dbus_error_init(&error);
+
+        m = dbus_message_new_method_call(
+                        "org.freedesktop.login1",
+                        "/org/freedesktop/login1",
+                        "org.freedesktop.login1.Manager",
+                        "ListInhibitors");
+        assert(m);
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+        assert(reply);
+
+        assert(dbus_message_iter_init(reply, &iter));
+        dbus_message_iter_recurse(&iter, &sub);
+
+        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                const char *what, *who, *reason;
+                dbus_uint32_t uid, pid;
+
+                dbus_message_iter_recurse(&sub, &sub2);
+
+                assert_se(bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) >= 0);
+                assert_se(bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) >= 0);
+                assert_se(bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &reason, true) >= 0);
+                assert_se(bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) >= 0);
+                assert_se(bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) >= 0);
+
+                printf("what=<%s> who=<%s> reason=<%s> uid=<%lu> pid=<%lu>\n",
+                       what, who, reason, (unsigned long) uid, (unsigned long) pid);
+
+                dbus_message_iter_next(&sub);
+
+                n++;
+        }
+
+        printf("%u inhibitors\n", n);
+
+        dbus_message_unref(m);
+        dbus_message_unref(reply);
+}
+
+int main(int argc, char*argv[]) {
+        DBusConnection *bus;
+        int fd1, fd2;
+
+        bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, NULL);
+        assert(bus);
+
+        print_inhibitors(bus);
+
+        fd1 = inhibit(bus, "suspend");
+        assert(fd1 >= 0);
+        print_inhibitors(bus);
+
+        fd2 = inhibit(bus, "idle:shutdown");
+        assert(fd2 >= 0);
+        print_inhibitors(bus);
+
+        close_nointr_nofail(fd1);
+        sleep(1);
+        print_inhibitors(bus);
+
+        close_nointr_nofail(fd2);
+        sleep(1);
+        print_inhibitors(bus);
+
+        return 0;
+}
diff --git a/src/shared/dbus-common.c b/src/shared/dbus-common.c
index 6d000e1..e161273 100644
--- a/src/shared/dbus-common.c
+++ b/src/shared/dbus-common.c
@@ -1155,3 +1155,53 @@ DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void
 
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
+
+/* This mimics dbus_bus_get_unix_user() */
+pid_t bus_get_unix_process_id(
+                DBusConnection *connection,
+                const char *name,
+                DBusError *error) {
+
+        DBusMessage *m = NULL, *reply = NULL;
+        uint32_t pid = 0;
+
+        m = dbus_message_new_method_call(
+                        DBUS_SERVICE_DBUS,
+                        DBUS_PATH_DBUS,
+                        DBUS_INTERFACE_DBUS,
+                        "GetConnectionUnixProcessID");
+        if (!m) {
+                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
+                goto finish;
+        }
+
+        if (!dbus_message_append_args(
+                            m,
+                            DBUS_TYPE_STRING, &name,
+                            DBUS_TYPE_INVALID)) {
+                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
+                goto finish;
+        }
+
+        reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
+        if (!reply)
+                goto finish;
+
+        if (dbus_set_error_from_message(error, reply))
+                goto finish;
+
+        if (!dbus_message_get_args(
+                            reply, error,
+                            DBUS_TYPE_UINT32, &pid,
+                            DBUS_TYPE_INVALID))
+                goto finish;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        return (pid_t) pid;
+}
diff --git a/src/shared/dbus-common.h b/src/shared/dbus-common.h
index 2bfcdfa..8598129 100644
--- a/src/shared/dbus-common.h
+++ b/src/shared/dbus-common.h
@@ -199,4 +199,6 @@ void bus_async_unregister_and_exit(DBusConnection *bus, const char *name);
 
 DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata);
 
+pid_t bus_get_unix_process_id(DBusConnection *connection, const char *name, DBusError *error);
+
 #endif
diff --git a/src/shared/polkit.c b/src/shared/polkit.c
index 07d18e7..14e27cd 100644
--- a/src/shared/polkit.c
+++ b/src/shared/polkit.c
@@ -27,56 +27,6 @@
 #include "dbus-common.h"
 #include "polkit.h"
 
-/* This mimics dbus_bus_get_unix_user() */
-static pid_t get_unix_process_id(
-                DBusConnection *connection,
-                const char *name,
-                DBusError *error) {
-
-        DBusMessage *m = NULL, *reply = NULL;
-        uint32_t pid = 0;
-
-        m = dbus_message_new_method_call(
-                        DBUS_SERVICE_DBUS,
-                        DBUS_PATH_DBUS,
-                        DBUS_INTERFACE_DBUS,
-                        "GetConnectionUnixProcessID");
-        if (!m) {
-                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
-                goto finish;
-        }
-
-        if (!dbus_message_append_args(
-                            m,
-                            DBUS_TYPE_STRING, &name,
-                            DBUS_TYPE_INVALID)) {
-                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
-                goto finish;
-        }
-
-        reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
-        if (!reply)
-                goto finish;
-
-        if (dbus_set_error_from_message(error, reply))
-                goto finish;
-
-        if (!dbus_message_get_args(
-                            reply, error,
-                            DBUS_TYPE_UINT32, &pid,
-                            DBUS_TYPE_INVALID))
-                goto finish;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        return (pid_t) pid;
-}
-
 int verify_polkit(
                 DBusConnection *c,
                 DBusMessage *request,
@@ -104,7 +54,7 @@ int verify_polkit(
         if (!sender)
                 return -EINVAL;
 
-        pid_raw = get_unix_process_id(c, sender, error);
+        pid_raw = bus_get_unix_process_id(c, sender, error);
         if (pid_raw == 0)
                 return -EINVAL;
 
diff --git a/src/shared/util.c b/src/shared/util.c
index 0b4d4d6..15c7f4d 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -1690,7 +1690,8 @@ char *cescape(const char *s) {
 
         /* Does C style string escaping. */
 
-        if (!(r = new(char, strlen(s)*4 + 1)))
+        r = new(char, strlen(s)*4 + 1);
+        if (!r)
                 return NULL;
 
         for (f = s, t = r; *f; f++)

commit 9156e799a258658cf3f51434708cdb194c13eaa4
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Apr 14 02:34:10 2012 +0200

    manager: remove unavailable/redundant entries from default controllers list

diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 3334f21..b1e22e0 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -30,6 +30,7 @@
 #include "cgroup.h"
 #include "cgroup-util.h"
 #include "log.h"
+#include "strv.h"
 
 int cgroup_bonding_realize(CGroupBonding *b) {
         int r;
@@ -305,7 +306,8 @@ int manager_setup_cgroup(Manager *m) {
         }
 
         /* 1. Determine hierarchy */
-        if ((r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &current)) < 0) {
+        r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &current);
+        if (r < 0) {
                 log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
                 goto finish;
         }
@@ -352,7 +354,8 @@ int manager_setup_cgroup(Manager *m) {
                 log_debug("Release agent already installed.");
 
         /* 4. Realize the group */
-        if ((r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0)) < 0) {
+        r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0);
+        if (r < 0) {
                 log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
                 goto finish;
         }
@@ -361,7 +364,8 @@ int manager_setup_cgroup(Manager *m) {
         if (m->pin_cgroupfs_fd >= 0)
                 close_nointr_nofail(m->pin_cgroupfs_fd);
 
-        if ((m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK)) < 0) {
+        m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
+        if (r < 0) {
                 log_error("Failed to open pin file: %m");
                 r = -errno;
                 goto finish;
@@ -369,6 +373,8 @@ int manager_setup_cgroup(Manager *m) {
 
         log_debug("Created root group.");
 
+        manager_shorten_default_controllers(m);
+
 finish:
         free(current);
         free(path);
@@ -391,6 +397,35 @@ void manager_shutdown_cgroup(Manager *m, bool delete) {
         m->cgroup_hierarchy = NULL;
 }
 
+void manager_shorten_default_controllers(Manager *m) {
+        char **f, **t;
+
+        strv_uniq(m->default_controllers);
+
+        if (!m->default_controllers)
+                return;
+
+        for (f = m->default_controllers, t = m->default_controllers; *f; f++) {
+
+                if (!streq(*f, "systemd") && !streq(*f, "name=systemd")) {
+                        char *cc;
+
+                        cc = alloca(sizeof("/sys/fs/cgroup/") + strlen(*f));
+                        strcpy(stpcpy(cc, "/sys/fs/cgroup/"), *f);
+
+                        if (access(cc, F_OK) >= 0) {
+                                *(t++) = *f;
+                                continue;
+                        }
+                }
+
+                log_debug("Controller %s not available or redundant, removing from default controllers list.", *f);
+                free(*f);
+        }
+
+        *t = NULL;
+}
+
 int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
         CGroupBonding *b;
         char *p;
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 95f09e0..dd2e6a4 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -85,6 +85,7 @@ pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *b);
 
 int manager_setup_cgroup(Manager *m);
 void manager_shutdown_cgroup(Manager *m, bool delete);
+void manager_shorten_default_controllers(Manager *m);
 
 int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding);
 int cgroup_notify_empty(Manager *m, const char *group);
diff --git a/src/core/manager.c b/src/core/manager.c
index c8ac29b..4469052 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -3165,12 +3165,15 @@ int manager_set_default_controllers(Manager *m, char **controllers) {
 
         assert(m);
 
-        if (!(l = strv_copy(controllers)))
+        l = strv_copy(controllers);
+        if (!l)
                 return -ENOMEM;
 
         strv_free(m->default_controllers);
         m->default_controllers = l;
 
+        manager_shorten_default_controllers(m);
+
         return 0;
 }
 

commit 3474ae3c7e1981301d0b35bc89d759ca13f06e8f
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Apr 14 02:15:13 2012 +0200

    cgroup: if a controller is not available don't try to create cgroups in its hierarchy

diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 7a5f673..3334f21 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -334,7 +334,8 @@ int manager_setup_cgroup(Manager *m) {
         }
 
         /* 2. Show data */
-        if ((r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path)) < 0) {
+        r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path);
+        if (r < 0) {
                 log_error("Cannot find cgroup mount point: %s", strerror(-r));
                 goto finish;
         }
@@ -342,7 +343,8 @@ int manager_setup_cgroup(Manager *m) {
         log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
 
         /* 3. Install agent */
-        if ((r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH)) < 0)
+        r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
+        if (r < 0)
                 log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
         else if (r > 0)
                 log_debug("Installed release agent.");
diff --git a/src/shared/cgroup-label.c b/src/shared/cgroup-label.c
index f132d71..06e3c16 100644
--- a/src/shared/cgroup-label.c
+++ b/src/shared/cgroup-label.c
@@ -43,7 +43,8 @@ int cg_create(const char *controller, const char *path) {
         assert(controller);
         assert(path);
 
-        if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
+        r = cg_get_path_and_check(controller, path, NULL, &fs);
+        if (r < 0)
                 return r;
 
         r = mkdir_parents(fs, 0755);
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index 86f354d..b2fb324 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -502,14 +502,47 @@ finish:
         return ret;
 }
 
+static const char *normalize_controller(const char *controller) {
+
+        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
+                return "systemd";
+        else if (startswith(controller, "name="))
+                return controller + 5;
+        else
+                return controller;
+}
+
+static int join_path(const char *controller, const char *path, const char *suffix, char **fs) {
+        char *t;
+
+        if (path && suffix)
+                t = join("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL);
+        else if (path)
+                t = join("/sys/fs/cgroup/", controller, "/", path, NULL);
+        else if (suffix)
+                t = join("/sys/fs/cgroup/", controller, "/", suffix, NULL);
+        else
+                t = join("/sys/fs/cgroup/", controller, NULL);
+
+        if (!t)
+                return -ENOMEM;
+
+        path_kill_slashes(t);
+
+        *fs = t;
+        return 0;
+}
+
 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
         const char *p;
-        char *t;
         static __thread bool good = false;
 
         assert(controller);
         assert(fs);
 
+        if (isempty(controller))
+                return -EINVAL;
+
         if (_unlikely_(!good)) {
                 int r;
 
@@ -521,38 +554,30 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
                 good = true;
         }
 
-        if (isempty(controller))
-                return -EINVAL;
+        p = normalize_controller(controller);
 
-        /* This is a very minimal lookup from controller names to
-         * paths. Since we have mounted most hierarchies ourselves
-         * should be kinda safe, but eventually we might want to
-         * extend this to have a fallback to actually check
-         * /proc/mounts. Might need caching then. */
+        return join_path(p, path, suffix, fs);
+}
 
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
-                p = "systemd";
-        else if (startswith(controller, "name="))
-                p = controller + 5;
-        else
-                p = controller;
+int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) {
+        const char *p;
+        char *cc;
 
-        if (path && suffix)
-                t = join("/sys/fs/cgroup/", p, "/", path, "/", suffix, NULL);
-        else if (path)
-                t = join("/sys/fs/cgroup/", p, "/", path, NULL);
-        else if (suffix)
-                t = join("/sys/fs/cgroup/", p, "/", suffix, NULL);
-        else
-                t = join("/sys/fs/cgroup/", p, NULL);
+        assert(controller);
+        assert(fs);
 
-        if (!t)
-                return -ENOMEM;
+        if (isempty(controller))
+                return -EINVAL;
 
-        path_kill_slashes(t);
+        p = normalize_controller(controller);
 
-        *fs = t;
-        return 0;
+        /* Check if this controller actually really exists */
+        cc = alloca(sizeof("/sys/fs/cgroup/") + strlen(p));
+        strcpy(stpcpy(cc, "/sys/fs/cgroup/"), p);
+        if (access(cc, F_OK) < 0)
+                return -errno;
+
+        return join_path(p, path, suffix, fs);
 }
 
 static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
@@ -646,7 +671,8 @@ int cg_attach(const char *controller, const char *path, pid_t pid) {
         assert(path);
         assert(pid >= 0);
 
-        if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
+        r = cg_get_path_and_check(controller, path, "tasks", &fs);
+        if (r < 0)
                 return r;
 
         if (pid == 0)
diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h
index 5da0004..cc0ce54 100644
--- a/src/shared/cgroup-util.h
+++ b/src/shared/cgroup-util.h
@@ -48,6 +48,7 @@ int cg_join_spec(const char *controller, const char *path, char **spec);
 int cg_fix_path(const char *path, char **result);
 
 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs);
+int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs);
 int cg_get_by_pid(const char *controller, pid_t pid, char **path);
 
 int cg_trim(const char *controller, const char *path, bool delete_root);



More information about the systemd-commits mailing list