[systemd-commits] 24 commits - fixme man/systemctl.xml man/systemd.exec.xml man/systemd.timer.xml src/dbus-automount.c src/dbus.c src/dbus-execute.c src/dbus-execute.h src/dbus.h src/dbus-job.c src/dbus-manager.c src/dbus-mount.c src/dbus-path.c src/dbus-service.c src/dbus-socket.c src/dbus-target.c src/dbus-timer.c src/dbus-unit.c src/dbus-unit.h src/execute.c src/execute.h src/job.c src/job.h src/load-fragment.c src/log.c src/manager.c src/manager.h src/missing.h src/mount.c src/service.c src/socket.c src/systemctl.c src/timer.c src/unit.c src/util.c src/util.h

Lennart Poettering lennart at kemper.freedesktop.org
Mon Jul 5 05:40:50 PDT 2010


 fixme                 |    2 
 man/systemctl.xml     |  134 +++++---
 man/systemd.exec.xml  |   24 -
 man/systemd.timer.xml |   32 -
 src/dbus-automount.c  |    4 
 src/dbus-execute.c    |  271 ++++++++++++++++
 src/dbus-execute.h    |  105 +++++-
 src/dbus-job.c        |   34 +-
 src/dbus-manager.c    |   53 ++-
 src/dbus-mount.c      |   23 -
 src/dbus-path.c       |   43 ++
 src/dbus-service.c    |   49 ++-
 src/dbus-socket.c     |   51 +--
 src/dbus-target.c     |   25 +
 src/dbus-timer.c      |   57 +++
 src/dbus-unit.c       |    4 
 src/dbus-unit.h       |    4 
 src/dbus.c            |  112 +++++-
 src/dbus.h            |    7 
 src/execute.c         |   43 +-
 src/execute.h         |   15 
 src/job.c             |    8 
 src/job.h             |    4 
 src/load-fragment.c   |   30 -
 src/log.c             |    4 
 src/manager.c         |    2 
 src/manager.h         |    4 
 src/missing.h         |    1 
 src/mount.c           |    4 
 src/service.c         |    6 
 src/socket.c          |    2 
 src/systemctl.c       |  810 +++++++++++++++++++++++++++++++++++++++++++++++---
 src/timer.c           |   10 
 src/unit.c            |    3 
 src/util.c            |   87 +++++
 src/util.h            |    7 
 36 files changed, 1785 insertions(+), 289 deletions(-)

New commits:
commit c59760eedae9d9de3be1572b9b612dfd8cc37547
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jul 5 03:06:02 2010 +0200

    systemctl: show cgroup contents in status

diff --git a/src/systemctl.c b/src/systemctl.c
index d32a688..76f6b84 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -959,6 +959,43 @@ finish:
         return r;
 }
 
+static void show_cgroup(const char *name) {
+        char *fn, *pids;
+        int r;
+        char *p;
+
+        if (!startswith(name, "name=systemd:"))
+                return;
+
+        if (asprintf(&fn, "/cgroup/systemd/%s/tasks", name + 13) < 0)
+                return;
+
+        r = read_one_line_file(fn, &pids);
+        free(fn);
+
+        if (r < 0)
+                return;
+
+        p = pids;
+        while (p[0]) {
+                unsigned long ul;
+                char *t = NULL;
+
+                p += strspn(p, WHITESPACE);
+
+                errno = 0;
+                ul = strtoul(p, &p, 0);
+                if (errno != 0 || ul <= 0)
+                        break;
+
+                get_process_cmdline((pid_t) ul, 60, &t);
+                printf("\t\t%lu %s\n", ul, strna(t));
+                free(t);
+        }
+
+        free(pids);
+}
+
 typedef struct UnitStatusInfo {
         const char *id;
         const char *load_state;
@@ -1079,8 +1116,10 @@ static void print_status_info(UnitStatusInfo *i) {
                 printf("\n");
         }
 
-        if (i->default_control_group)
+        if (i->default_control_group) {
                 printf("\t  CGroup: %s\n", i->default_control_group);
+                show_cgroup(i->default_control_group);
+        }
 }
 
 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
diff --git a/src/util.c b/src/util.c
index ea8bfc1..8c22dbe 100644
--- a/src/util.c
+++ b/src/util.c
@@ -566,6 +566,65 @@ int get_process_name(pid_t pid, char **name) {
         return 0;
 }
 
+int get_process_cmdline(pid_t pid, size_t max_length, char **line) {
+        char *p, *r, *k;
+        int c;
+        bool space = false;
+        size_t left;
+        FILE *f;
+
+        assert(pid >= 1);
+        assert(max_length > 0);
+        assert(line);
+
+        if (asprintf(&p, "/proc/%lu/cmdline", (unsigned long) pid) < 0)
+                return -ENOMEM;
+
+        f = fopen(p, "r");
+        free(p);
+
+        if (!f)
+                return -errno;
+
+        if (!(r = new(char, max_length))) {
+                fclose(f);
+                return -ENOMEM;
+        }
+
+        k = r;
+        left = max_length;
+        while ((c = getc(f)) != EOF) {
+
+                if (isprint(c)) {
+                        if (space) {
+                                if (left <= 4)
+                                        break;
+
+                                *(k++) = ' ';
+                                space = false;
+                        }
+
+                        if (left <= 4)
+                                break;
+
+                        *(k++) = (char) c;
+                }  else
+                        space = true;
+        }
+
+        if (left <= 4) {
+                size_t n = MIN(left-1, 3U);
+                memcpy(k, "...", n);
+                k[n] = 0;
+        } else
+                *k = 0;
+
+        fclose(f);
+
+        *line = r;
+        return 0;
+}
+
 char *strappend(const char *s, const char *suffix) {
         size_t a, b;
         char *r;
diff --git a/src/util.h b/src/util.h
index 8c91714..cb47c7a 100644
--- a/src/util.h
+++ b/src/util.h
@@ -183,6 +183,7 @@ int mkdir_p(const char *path, mode_t mode);
 int rmdir_parents(const char *path, const char *stop);
 
 int get_process_name(pid_t pid, char **name);
+int get_process_cmdline(pid_t pid, size_t max_length, char **line);
 
 char hexchar(int x);
 int unhexchar(char c);
commit 61cbdc4b307718d74e8aa04875475aac2f8617ab
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jul 5 02:40:39 2010 +0200

    systemctl: implement 'status' command

diff --git a/man/systemctl.xml b/man/systemctl.xml
index 1bd08da..c0b8d79 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -247,16 +247,25 @@
                                 state to STDOUT.</para></listitem>
                         </varlistentry>
                         <varlistentry>
+                                <term><command>status [NAME...]</command></term>
+
+                                <listitem><para>Show short status
+                                information about one or more
+                                units. This shows terse runtime
+                                information about
+                                units.</para></listitem>
+                        </varlistentry>
+                        <varlistentry>
                                 <term><command>show [NAME...|JOB...]</command></term>
 
-                                <listitem><para>Show information about
+                                <listitem><para>Show properties of
                                 one or more units, jobs or the manager
                                 itself. If no argument is specified
-                                information about the manager will be
+                                properties of the manager will be
                                 shown. If a unit name is specified
-                                information about the unit is shown,
+                                properties of the unit is shown,
                                 and if a job id is specified
-                                information about the job is
+                                properties of the job is
                                 shown.</para></listitem>
                         </varlistentry>
                         <varlistentry>
diff --git a/src/log.c b/src/log.c
index a47285c..e67a5b3 100644
--- a/src/log.c
+++ b/src/log.c
@@ -227,10 +227,10 @@ static int write_to_console(
         if (show_location)
                 IOVEC_SET_STRING(iovec[n++], location);
         if (highlight)
-                IOVEC_SET_STRING(iovec[n++], "\x1B[1;31m");
+                IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_ON);
         IOVEC_SET_STRING(iovec[n++], buffer);
         if (highlight)
-                IOVEC_SET_STRING(iovec[n++], "\x1B[0m");
+                IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
         IOVEC_SET_STRING(iovec[n++], "\n");
 
         if (writev(console_fd, iovec, n) < 0)
diff --git a/src/systemctl.c b/src/systemctl.c
index 1ad0c48..d32a688 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -959,10 +959,227 @@ finish:
         return r;
 }
 
+typedef struct UnitStatusInfo {
+        const char *id;
+        const char *load_state;
+        const char *active_state;
+        const char *sub_state;
+
+        const char *description;
+
+        const char *fragment_path;
+        const char *default_control_group;
+
+        /* Service */
+        pid_t main_pid;
+        pid_t control_pid;
+        const char *status_text;
+        bool running;
+
+        usec_t start_timestamp;
+        usec_t exit_timestamp;
+
+        int exit_code, exit_status;
+
+        /* Socket */
+        unsigned n_accepted;
+        unsigned n_connections;
+
+        /* Device */
+        const char *sysfs_path;
+
+        /* Mount, Automount */
+        const char *where;
+
+        /* Swap */
+        const char *what;
+} UnitStatusInfo;
+
+static void print_status_info(UnitStatusInfo *i) {
+        assert(i);
+
+        /* This shows pretty information about a unit. See
+         * print_property() for a low-level property printer */
+
+        printf("%s", strna(i->id));
+
+        if (i->description && !streq_ptr(i->id, i->description))
+                printf(" - %s", i->description);
+
+        printf("\n");
+
+        if (i->fragment_path)
+                printf("\t  Loaded: %s (%s)\n", strna(i->load_state), i->fragment_path);
+        else if (streq_ptr(i->load_state, "failed"))
+                printf("\t  Loaded: " ANSI_HIGHLIGHT_ON "%s" ANSI_HIGHLIGHT_OFF "\n", strna(i->load_state));
+        else
+                printf("\t  Loaded: %s\n", strna(i->load_state));
+
+        if (streq_ptr(i->active_state, "maintenance"))
+                printf("\t  Active: " ANSI_HIGHLIGHT_ON "%s (%s)" ANSI_HIGHLIGHT_OFF "\n",
+                       strna(i->active_state),
+                       strna(i->sub_state));
+        else
+                printf("\t  Active: %s (%s)\n",
+                       strna(i->active_state),
+                       strna(i->sub_state));
+
+        if (i->sysfs_path)
+                printf("\t  Device: %s\n", i->sysfs_path);
+        else if (i->where)
+                printf("\t   Where: %s\n", i->where);
+        else if (i->what)
+                printf("\t    What: %s\n", i->what);
+
+        if (i->status_text)
+                printf("\t  Status: \"%s\"\n", i->status_text);
+
+        if (i->id && endswith(i->id, ".socket"))
+                printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
+
+        if (i->main_pid > 0 || i->control_pid > 0) {
+                printf("\t");
+
+                if (i->main_pid > 0) {
+                        printf(" Process: %u", (unsigned) i->main_pid);
+
+                        if (i->running) {
+                                char *t = NULL;
+                                get_process_name(i->main_pid, &t);
+                                if (t) {
+                                        printf(" (%s)", t);
+                                        free(t);
+                                }
+                        } else {
+                                printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
+
+                                if (i->exit_code == CLD_EXITED)
+                                        printf("status=%i", i->exit_status);
+                                else
+                                        printf("signal=%s", strsignal(i->exit_status));
+                                printf(")");
+                        }
+                }
+
+                if (i->main_pid > 0 && i->control_pid > 0)
+                        printf(";");
+
+                if (i->control_pid > 0) {
+                        char *t = NULL;
+
+                        printf(" Control: %u", (unsigned) i->control_pid);
+
+                        get_process_name(i->control_pid, &t);
+                        if (t) {
+                                printf(" (%s)", t);
+                                free(t);
+                        }
+                }
+
+                printf("\n");
+        }
+
+        if (i->default_control_group)
+                printf("\t  CGroup: %s\n", i->default_control_group);
+}
+
+static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
+
+        switch (dbus_message_iter_get_arg_type(iter)) {
+
+        case DBUS_TYPE_STRING: {
+                const char *s;
+
+                dbus_message_iter_get_basic(iter, &s);
+
+                if (s[0]) {
+                        if (streq(name, "Id"))
+                                i->id = s;
+                        else if (streq(name, "LoadState"))
+                                i->load_state = s;
+                        else if (streq(name, "ActiveState"))
+                                i->active_state = s;
+                        else if (streq(name, "SubState"))
+                                i->sub_state = s;
+                        else if (streq(name, "Description"))
+                                i->description = s;
+                        else if (streq(name, "FragmentPath"))
+                                i->fragment_path = s;
+                        else if (streq(name, "DefaultControlGroup"))
+                                i->default_control_group = s;
+                        else if (streq(name, "StatusText"))
+                                i->status_text = s;
+                        else if (streq(name, "SysFSPath"))
+                                i->sysfs_path = s;
+                        else if (streq(name, "Where"))
+                                i->where = s;
+                        else if (streq(name, "What"))
+                                i->what = s;
+                }
+
+                break;
+        }
+
+        case DBUS_TYPE_UINT32: {
+                uint32_t u;
+
+                dbus_message_iter_get_basic(iter, &u);
+
+                if (streq(name, "MainPID")) {
+                        if (u > 0) {
+                                i->main_pid = (pid_t) u;
+                                i->running = true;
+                        }
+                } else if (streq(name, "ControlPID"))
+                        i->control_pid = (pid_t) u;
+                else if (streq(name, "ExecMainPID")) {
+                        if (u > 0)
+                                i->main_pid = (pid_t) u;
+                } else if (streq(name, "NAccepted"))
+                        i->n_accepted = u;
+                else if (streq(name, "NConnections"))
+                        i->n_connections = u;
+
+                break;
+        }
+
+        case DBUS_TYPE_INT32: {
+                int32_t j;
+
+                dbus_message_iter_get_basic(iter, &j);
+
+                if (streq(name, "ExecMainCode"))
+                        i->exit_code = (int) j;
+                else if (streq(name, "ExecMainStatus"))
+                        i->exit_status = (int) j;
+
+                break;
+        }
+
+        case DBUS_TYPE_UINT64: {
+                uint64_t u;
+
+                dbus_message_iter_get_basic(iter, &u);
+
+                if (streq(name, "ExecMainStartTimestamp"))
+                        i->start_timestamp = (usec_t) u;
+                else if (streq(name, "ExecMainExitTimestamp"))
+                        i->exit_timestamp = (usec_t) u;
+
+                break;
+        }
+        }
+
+        return 0;
+}
+
 static int print_property(const char *name, DBusMessageIter *iter) {
         assert(name);
         assert(iter);
 
+        /* This is a low-level property printer, see
+         * print_status_info() for the nicer output */
+
         if (arg_property && !streq(name, arg_property))
                 return 0;
 
@@ -1200,7 +1417,7 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                                                (unsigned) pid,
                                                sigchld_code_to_string(code),
                                                status,
-                                               strna(code == CLD_EXITED ? NULL : strsignal(status)));
+                                               strempty(code == CLD_EXITED ? NULL : strsignal(status)));
                                 }
 
                                 printf(" }\n");
@@ -1220,16 +1437,19 @@ static int print_property(const char *name, DBusMessageIter *iter) {
         return 0;
 }
 
-static int show_one(DBusConnection *bus, const char *path) {
+static int show_one(DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
         DBusMessage *m = NULL, *reply = NULL;
         const char *interface = "";
         int r;
         DBusError error;
         DBusMessageIter iter, sub, sub2, sub3;
+        UnitStatusInfo info;
 
         assert(bus);
         assert(path);
+        assert(new_line);
 
+        zero(info);
         dbus_error_init(&error);
 
         if (!(m = dbus_message_new_method_call(
@@ -1266,6 +1486,11 @@ static int show_one(DBusConnection *bus, const char *path) {
 
         dbus_message_iter_recurse(&iter, &sub);
 
+        if (*new_line)
+                printf("\n");
+
+        *new_line = true;
+
         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
                 const char *name;
 
@@ -1291,7 +1516,12 @@ static int show_one(DBusConnection *bus, const char *path) {
 
                 dbus_message_iter_recurse(&sub2, &sub3);
 
-                if (print_property(name, &sub3) < 0) {
+                if (show_properties)
+                        r = print_property(name, &sub3);
+                else
+                        r = status_property(name, &sub3, &info);
+
+                if (r < 0) {
                         log_error("Failed to parse reply.");
                         r = -EIO;
                         goto finish;
@@ -1300,6 +1530,9 @@ static int show_one(DBusConnection *bus, const char *path) {
                 dbus_message_iter_next(&sub);
         }
 
+        if (!show_properties)
+                print_status_info(&info);
+
         r = 0;
 
 finish:
@@ -1319,17 +1552,20 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
         int r;
         DBusError error;
         unsigned i;
+        bool show_properties, new_line = false;
 
         assert(bus);
         assert(args);
 
         dbus_error_init(&error);
 
-        if (n <= 1) {
+        show_properties = !streq(args[0], "status");
+
+        if (show_properties && n <= 1) {
                 /* If not argument is specified inspect the manager
                  * itself */
 
-                r = show_one(bus, "/org/freedesktop/systemd1");
+                r = show_one(bus, "/org/freedesktop/systemd1", show_properties, &new_line);
                 goto finish;
         }
 
@@ -1337,7 +1573,7 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                 const char *path = NULL;
                 uint32_t id;
 
-                if (safe_atou32(args[i], &id) < 0) {
+                if (!show_properties || safe_atou32(args[i], &id) < 0) {
 
                         if (!(m = dbus_message_new_method_call(
                                               "org.freedesktop.systemd1",
@@ -1392,7 +1628,7 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                         goto finish;
                 }
 
-                if ((r = show_one(bus, path)) < 0)
+                if ((r = show_one(bus, path, show_properties, &new_line)) < 0)
                         goto finish;
 
                 dbus_message_unref(m);
@@ -2098,7 +2334,8 @@ static int systemctl_help(void) {
                "  reload [NAME...]                Reload one or more units\n"
                "  isolate [NAME]                  Start one unit and stop all others\n"
                "  check [NAME...]                 Check whether any of the passed units are active\n"
-               "  show [NAME...|JOB...]           Show information about one or more units/jobs/manager\n"
+               "  status [NAME...]                Show status of one or more units\n"
+               "  show [NAME...|JOB...]           Show properties of one or more units/jobs/manager\n"
                "  load [NAME...]                  Load one or more units\n"
                "  list-jobs                       List jobs\n"
                "  cancel [JOB...]                 Cancel one or more jobs\n"
@@ -2780,6 +3017,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
                 { "isolate",           EQUAL, 2, start_unit      },
                 { "check",             MORE,  2, check_unit      },
                 { "show",              MORE,  1, show            },
+                { "status",            MORE,  2, show            },
                 { "monitor",           EQUAL, 1, monitor         },
                 { "dump",              EQUAL, 1, dump            },
                 { "snapshot",          LESS,  2, snapshot        },
diff --git a/src/util.h b/src/util.h
index 50bac6e..8c91714 100644
--- a/src/util.h
+++ b/src/util.h
@@ -59,6 +59,9 @@ typedef struct dual_timestamp {
 #define FORMAT_TIMESTAMP_MAX 64
 #define FORMAT_TIMESPAN_MAX 64
 
+#define ANSI_HIGHLIGHT_ON "\x1B[1;31m"
+#define ANSI_HIGHLIGHT_OFF "\x1B[0m"
+
 usec_t now(clockid_t clock);
 
 dual_timestamp* dual_timestamp_get(dual_timestamp *ts);
commit 74922904348e53a992af63c581d4ccd3317ccce0
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jul 5 01:08:13 2010 +0200

    turn negative options into positive options

diff --git a/fixme b/fixme
index 2f133d4..1e27844 100644
--- a/fixme
+++ b/fixme
@@ -39,8 +39,6 @@
 
 * systemctl daemon-reload is kaputt
 
-* Turn around negative options
-
 * Add missing man pages: update systemd.1, finish daemon.7
 
 External:
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 83eef32..6502d87 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -468,7 +468,7 @@
                                 the default log level specified
                                 here. The interpretation of these
                                 prefixes may be disabled with
-                                <varname>SyslogNoPrefix=</varname>,
+                                <varname>SyslogLevelPrefix=</varname>,
                                 see below. For details see
                                 <citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
 
@@ -477,9 +477,9 @@
                         </varlistentry>
 
                         <varlistentry>
-                                <term><varname>SyslogNoPrefix=</varname></term>
+                                <term><varname>SyslogLevelPrefix=</varname></term>
                                 <listitem><para>Takes a boolean
-                                argument. If false and
+                                argument. If true and
                                 <varname>StandardOutput=</varname> or
                                 <varname>StandardError=</varname> are
                                 set to <option>syslog</option> or
@@ -488,12 +488,12 @@
                                 are prefixed with a log level will be
                                 passed on to syslog with this log
                                 level set but the prefix removed. If
-                                set to true, the interpretation of
+                                set to false, the interpretation of
                                 these prefixes is disabled and the
                                 logged lines are passed on as-is. For
                                 details about this prefixing see
                                 <citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
-                                Defaults to false.</para></listitem>
+                                Defaults to true.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
diff --git a/src/dbus-execute.h b/src/dbus-execute.h
index 5208159..32d58d6 100644
--- a/src/dbus-execute.h
+++ b/src/dbus-execute.h
@@ -69,7 +69,7 @@
         "  <property name=\"TTYPath\" type=\"s\" access=\"read\"/>\n"   \
         "  <property name=\"SyslogPriority\" type=\"i\" access=\"read\"/>\n" \
         "  <property name=\"SyslogIdentifier\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"SyslogNoPrefix\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"SyslogLevelPrefix\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"Capabilities\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"SecureBits\" type=\"i\" access=\"read\"/>\n" \
         "  <property name=\"CapabilityBoundingSetDrop\" type=\"t\" access=\"read\"/>\n" \
@@ -83,7 +83,7 @@
         "  <property name=\"InaccessibleDirectories\" type=\"as\" access=\"read\"/>\n" \
         "  <property name=\"MountFlags\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"PrivateTmp\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"NoSetSID\" type=\"b\" access=\"read\"/>\n"
+        "  <property name=\"SameProcessGroup\" type=\"b\" access=\"read\"/>\n"
 
 #define BUS_EXEC_COMMAND_INTERFACE(name)                             \
         "  <property name=\"" name "\" type=\"a(sasttuii)\" access=\"read\"/>\n"
@@ -115,7 +115,7 @@
         { interface, "CPUSchedulingPolicy",           bus_execute_append_cpu_sched_policy, "i", &(context)                         }, \
         { interface, "CPUSchedulingPriority",         bus_execute_append_cpu_sched_priority, "i", &(context)                       }, \
         { interface, "CPUAffinity",                   bus_execute_append_affinity,"ay",    &(context)                              }, \
-        { interface, "TimerSlackNSec",                bus_execute_append_timer_slack_nsec, "t", &(context)                           }, \
+        { interface, "TimerSlackNSec",                bus_execute_append_timer_slack_nsec, "t", &(context)                         }, \
         { interface, "CPUSchedulingResetOnFork",      bus_property_append_bool,   "b",     &(context).cpu_sched_reset_on_fork      }, \
         { interface, "NonBlocking",                   bus_property_append_bool,   "b",     &(context).non_blocking                 }, \
         { interface, "StandardInput",                 bus_execute_append_input,   "s",     &(context).std_input                    }, \
@@ -124,7 +124,7 @@
         { interface, "TTYPath",                       bus_property_append_string, "s",     (context).tty_path                      }, \
         { interface, "SyslogPriority",                bus_property_append_int,    "i",     &(context).syslog_priority              }, \
         { interface, "SyslogIdentifier",              bus_property_append_string, "s",     (context).syslog_identifier             }, \
-        { interface, "SyslogNoPrefix",                bus_property_append_bool,   "b",     &(context).syslog_no_prefix             }, \
+        { interface, "SyslogLevelPrefix",             bus_property_append_bool,   "b",     &(context).syslog_level_prefix          }, \
         { interface, "Capabilities",                  bus_property_append_string, "s",     (context).capabilities                  }, \
         { interface, "SecureBits",                    bus_property_append_int,    "i",     &(context).secure_bits                  }, \
         { interface, "CapabilityBoundingSetDrop",     bus_property_append_uint64, "t",     &(context).capability_bounding_set_drop }, \
@@ -138,7 +138,7 @@
         { interface, "InaccessibleDirectories",       bus_property_append_strv,   "as",    (context).inaccessible_dirs             }, \
         { interface, "MountFlags",                    bus_property_append_ul,     "t",     &(context).mount_flags                  }, \
         { interface, "PrivateTmp",                    bus_property_append_bool,   "b",     &(context).private_tmp                  }, \
-        { interface, "NoSetSID",                      bus_property_append_bool,   "b",     &(context).no_setsid                    }
+        { interface, "SameProcessGroup",              bus_property_append_bool,   "b",     &(context).same_pgrp                    }
 
 #define BUS_EXEC_STATUS_PROPERTIES(interface, estatus, prefix)           \
         { interface, prefix "StartTimestamp",         bus_property_append_usec,   "t",     &(estatus).start_timestamp.realtime     }, \
@@ -147,7 +147,7 @@
         { interface, prefix "Code",                   bus_property_append_int,    "i",     &(estatus).code                         }, \
         { interface, prefix "Status",                 bus_property_append_int,    "i",     &(estatus).status                       }
 
-#define BUS_EXEC_COMMAND_PROPERTY(interface, command, name)            \
+#define BUS_EXEC_COMMAND_PROPERTY(interface, command, name)             \
         { interface, name, bus_execute_append_command, "a(sasttuii)", (command) }
 
 int bus_execute_append_output(Manager *m, DBusMessageIter *i, const char *property, void *data);
diff --git a/src/execute.c b/src/execute.c
index 982b7d1..2acb111 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -197,7 +197,7 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons
                 output == EXEC_OUTPUT_KMSG ? "kmsg" : "syslog",
                 context->syslog_priority,
                 context->syslog_identifier ? context->syslog_identifier : ident,
-                !context->syslog_no_prefix);
+                context->syslog_level_prefix);
 
         if (fd != nfd) {
                 r = dup2(fd, nfd) < 0 ? -errno : nfd;
@@ -964,7 +964,7 @@ int exec_spawn(ExecCommand *command,
                         goto fail;
                 }
 
-                if (!context->no_setsid)
+                if (!context->same_pgrp)
                         if (setsid() < 0) {
                                 r = EXIT_SETSID;
                                 goto fail;
@@ -1294,6 +1294,7 @@ void exec_context_init(ExecContext *c) {
         c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
         c->cpu_sched_policy = SCHED_OTHER;
         c->syslog_priority = LOG_DAEMON|LOG_INFO;
+        c->syslog_level_prefix = true;
         c->mount_flags = MS_SHARED;
 }
 
diff --git a/src/execute.h b/src/execute.h
index 1ab6a24..2e0e6cc 100644
--- a/src/execute.h
+++ b/src/execute.h
@@ -103,7 +103,7 @@ struct ExecContext {
 
         int syslog_priority;
         char *syslog_identifier;
-        bool syslog_no_prefix;
+        bool syslog_level_prefix;
 
         char *tcpwrap_name;
 
@@ -142,7 +142,7 @@ struct ExecContext {
          * /bin/mount it is run in the same process group as us so
          * that the autofs logic detects that it belongs to us and we
          * don't enter a trigger loop. */
-        bool no_setsid;
+        bool same_pgrp;
 };
 
 typedef enum ExitStatus {
diff --git a/src/load-fragment.c b/src/load-fragment.c
index 8e777fd..3c0cccf 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -1464,7 +1464,7 @@ static int load_from_path(Unit *u, const char *path) {
                 { "SyslogIdentifier",       config_parse_string_printf,   &(context).syslog_identifier,                    section   }, \
                 { "SyslogFacility",         config_parse_facility,        &(context).syslog_priority,                      section   }, \
                 { "SyslogLevel",            config_parse_level,           &(context).syslog_priority,                      section   }, \
-                { "SyslogNoPrefix",         config_parse_bool,            &(context).syslog_no_prefix,                     section   }, \
+                { "SyslogLevelPrefix",      config_parse_bool,            &(context).syslog_level_prefix,                  section   }, \
                 { "Capabilities",           config_parse_capabilities,    &(context),                                      section   }, \
                 { "SecureBits",             config_parse_secure_bits,     &(context),                                      section   }, \
                 { "CapabilityBoundingSetDrop", config_parse_bounding_set, &(context),                                      section   }, \
diff --git a/src/mount.c b/src/mount.c
index b99e5ff..6da880e 100644
--- a/src/mount.c
+++ b/src/mount.c
@@ -68,7 +68,7 @@ static void mount_init(Unit *u) {
          * the same process group as us, so that the autofs kernel
          * side doesn't send us another mount request while we are
          * already trying to comply its last one. */
-        m->exec_context.no_setsid = true;
+        m->exec_context.same_pgrp = true;
 
         m->timer_watch.type = WATCH_INVALID;
 
commit a567261a29b4e19c0c195240411b7562063d99f8
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jul 5 00:58:07 2010 +0200

    dbus: send signals about jobs to the clients having created them unconditionally, and thus get rid of broadcast signals in most cases

diff --git a/fixme b/fixme
index 49b69a6..2f133d4 100644
--- a/fixme
+++ b/fixme
@@ -39,8 +39,6 @@
 
 * systemctl daemon-reload is kaputt
 
-* get rid of Subscribe() in systemctl
-
 * Turn around negative options
 
 * Add missing man pages: update systemd.1, finish daemon.7
diff --git a/src/dbus-job.c b/src/dbus-job.c
index 48b1588..0956dcf 100644
--- a/src/dbus-job.c
+++ b/src/dbus-job.c
@@ -146,6 +146,32 @@ const DBusObjectPathVTable bus_job_vtable = {
         .message_function = bus_job_message_handler
 };
 
+static int job_send_message(Job *j, DBusMessage *m) {
+        int r;
+
+        assert(j);
+        assert(m);
+
+        if (bus_has_subscriber(j->manager)) {
+                if ((r = bus_broadcast(j->manager, m)) < 0)
+                        return r;
+
+        } else  if (j->bus_client) {
+                /* If nobody is subscribed, we just send the message
+                 * to the client which created the job */
+
+                assert(j->bus);
+
+                if (!dbus_message_set_destination(m, j->bus_client))
+                        return -ENOMEM;
+
+                if (!dbus_connection_send(j->bus, m, NULL))
+                        return -ENOMEM;
+        }
+
+        return 0;
+}
+
 void bus_job_send_change_signal(Job *j) {
         char *p = NULL;
         DBusMessage *m = NULL;
@@ -156,7 +182,7 @@ void bus_job_send_change_signal(Job *j) {
         LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
         j->in_dbus_queue = false;
 
-        if (set_isempty(j->manager->subscribed)) {
+        if (!bus_has_subscriber(j->manager) && !j->bus_client) {
                 j->sent_dbus_new_signal = true;
                 return;
         }
@@ -182,7 +208,7 @@ void bus_job_send_change_signal(Job *j) {
                         goto oom;
         }
 
-        if (bus_broadcast(j->manager, m) < 0)
+        if (job_send_message(j, m) < 0)
                 goto oom;
 
         free(p);
@@ -208,7 +234,7 @@ void bus_job_send_removed_signal(Job *j, bool success) {
 
         assert(j);
 
-        if (set_isempty(j->manager->subscribed))
+        if (!bus_has_subscriber(j->manager) && !j->bus_client)
                 return;
 
         if (!j->sent_dbus_new_signal)
@@ -227,7 +253,7 @@ void bus_job_send_removed_signal(Job *j, bool success) {
                                       DBUS_TYPE_INVALID))
                 goto oom;
 
-        if (bus_broadcast(j->manager, m) < 0)
+        if (job_send_message(j, m) < 0)
                 goto oom;
 
         free(p);
diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index 705a4dc..704e5fa 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -452,14 +452,25 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
 
         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
                 char *client;
+                Set *s;
+
+                if (!(s = BUS_CONNECTION_SUBSCRIBED(m, connection))) {
+                        if (!(s = set_new(string_hash_func, string_compare_func)))
+                                goto oom;
+
+                        if (!(dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL))) {
+                                set_free(s);
+                                goto oom;
+                        }
+                }
 
                 if (!(client = strdup(dbus_message_get_sender(message))))
                         goto oom;
 
-                r = set_put(m->subscribed, client);
-
-                if (r < 0)
+                if ((r = set_put(s, client)) < 0) {
+                        free(client);
                         return bus_send_error_reply(m, connection, message, NULL, r);
+                }
 
                 if (!(reply = dbus_message_new_method_return(message)))
                         goto oom;
@@ -467,7 +478,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
                 char *client;
 
-                if (!(client = set_remove(m->subscribed, (char*) dbus_message_get_sender(message))))
+                if (!(client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) dbus_message_get_sender(message))))
                         return bus_send_error_reply(m, connection, message, NULL, -ENOENT);
 
                 free(client);
@@ -702,6 +713,11 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
                 if ((r = manager_add_job(m, job_type, u, mode, true, &j)) < 0)
                         return bus_send_error_reply(m, connection, message, NULL, r);
 
+                if (!(j->bus_client = strdup(dbus_message_get_sender(message))))
+                        goto oom;
+
+                j->bus = connection;
+
                 if (!(reply = dbus_message_new_method_return(message)))
                         goto oom;
 
@@ -713,6 +729,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
                                     DBUS_TYPE_OBJECT_PATH, &path,
                                     DBUS_TYPE_INVALID))
                         goto oom;
+
         }
 
         free(path);
diff --git a/src/dbus-unit.c b/src/dbus-unit.c
index 17ca7bd..1f74a2a 100644
--- a/src/dbus-unit.c
+++ b/src/dbus-unit.c
@@ -376,7 +376,7 @@ void bus_unit_send_change_signal(Unit *u) {
         LIST_REMOVE(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta);
         u->meta.in_dbus_queue = false;
 
-        if (set_isempty(u->meta.manager->subscribed)) {
+        if (!bus_has_subscriber(u->meta.manager)) {
                 u->meta.sent_dbus_new_signal = true;
                 return;
         }
@@ -427,7 +427,7 @@ void bus_unit_send_removed_signal(Unit *u) {
 
         assert(u);
 
-        if (set_isempty(u->meta.manager->subscribed))
+        if (!bus_has_subscriber(u->meta.manager))
                 return;
 
         if (!u->meta.sent_dbus_new_signal)
diff --git a/src/dbus.c b/src/dbus.c
index 385bf6a..6660cf0 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -355,8 +355,8 @@ static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBus
                                            DBUS_TYPE_INVALID))
                         log_error("Failed to parse NameOwnerChanged message: %s", error.message);
                 else  {
-                        if (set_remove(m->subscribed, (char*) name))
-                                log_debug("Subscription client vanished: %s (left: %u)", name, set_size(m->subscribed));
+                        if (set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) name))
+                                log_debug("Subscription client vanished: %s (left: %u)", name, set_size(BUS_CONNECTION_SUBSCRIBED(m, connection)));
 
                         if (old_owner[0] == 0)
                                 old_owner = NULL;
@@ -882,13 +882,6 @@ static int bus_init_api(Manager *m) {
                   strnull(dbus_bus_get_unique_name(m->api_bus)));
         dbus_free(id);
 
-        if (!m->subscribed)
-                if (!(m->subscribed = set_new(string_hash_func, string_compare_func))) {
-                        log_error("Not enough memory");
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
         return 0;
 
 fail:
@@ -959,6 +952,12 @@ int bus_init(Manager *m) {
                         return -ENOMEM;
                 }
 
+        if (m->subscribed_data_slot < 0)
+                if (!dbus_pending_call_allocate_data_slot(&m->subscribed_data_slot)) {
+                        log_error("Not enough memory");
+                        return -ENOMEM;
+                }
+
         if ((r = bus_init_system(m)) < 0 ||
             (r = bus_init_api(m)) < 0 ||
             (r = bus_init_private(m)) < 0)
@@ -968,9 +967,30 @@ int bus_init(Manager *m) {
 }
 
 static void shutdown_connection(Manager *m, DBusConnection *c) {
+        Set *s;
+        Job *j;
+        Iterator i;
+
+        HASHMAP_FOREACH(j, m->jobs, i)
+                if (j->bus == c) {
+                        free(j->bus_client);
+                        j->bus_client = NULL;
+
+                        j->bus = NULL;
+                }
+
         set_remove(m->bus_connections, c);
         set_remove(m->bus_connections_for_dispatch, c);
 
+        if ((s = BUS_CONNECTION_SUBSCRIBED(m, c))) {
+                char *t;
+
+                while ((t = set_steal_first(s)))
+                        free(t);
+
+                set_free(s);
+        }
+
         dbus_connection_set_dispatch_status_function(c, NULL, NULL, NULL);
         dbus_connection_flush(c);
         dbus_connection_close(c);
@@ -988,15 +1008,6 @@ static void bus_done_api(Manager *m) {
                 m->api_bus = NULL;
         }
 
-        if (m->subscribed) {
-                char *c;
-
-                while ((c = set_steal_first(m->subscribed)))
-                        free(c);
-
-                set_free(m->subscribed);
-                m->subscribed = NULL;
-        }
 
        if (m->queued_message) {
                dbus_message_unref(m->queued_message);
@@ -1043,6 +1054,9 @@ void bus_done(Manager *m) {
 
         if (m->name_data_slot >= 0)
                dbus_pending_call_free_data_slot(&m->name_data_slot);
+
+        if (m->subscribed_data_slot >= 0)
+                dbus_pending_call_free_data_slot(&m->subscribed_data_slot);
 }
 
 static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) {
@@ -1053,7 +1067,7 @@ static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) {
 
         dbus_error_init(&error);
 
-        assert_se(name = dbus_pending_call_get_data(pending, m->name_data_slot));
+        assert_se(name = BUS_PENDING_CALL_NAME(m, pending));
         assert_se(reply = dbus_pending_call_steal_reply(pending));
 
         switch (dbus_message_get_type(reply)) {
@@ -1538,3 +1552,27 @@ int bus_parse_strv(DBusMessage *m, char ***_l) {
 
         return 0;
 }
+
+bool bus_has_subscriber(Manager *m) {
+        Iterator i;
+        DBusConnection *c;
+
+        assert(m);
+
+        SET_FOREACH(c, m->bus_connections_for_dispatch, i)
+                if (bus_connection_has_subscriber(m, c))
+                        return true;
+
+        SET_FOREACH(c, m->bus_connections, i)
+                if (bus_connection_has_subscriber(m, c))
+                        return true;
+
+        return false;
+}
+
+bool bus_connection_has_subscriber(Manager *m, DBusConnection *c) {
+        assert(m);
+        assert(c);
+
+        return !set_isempty(BUS_CONNECTION_SUBSCRIBED(m, c));
+}
diff --git a/src/dbus.h b/src/dbus.h
index ccee74f..01ab2fc 100644
--- a/src/dbus.h
+++ b/src/dbus.h
@@ -105,6 +105,12 @@ int bus_property_append_ul(Manager *m, DBusMessageIter *i, const char *property,
 
 int bus_parse_strv(DBusMessage *m, char ***_l);
 
+bool bus_has_subscriber(Manager *m);
+bool bus_connection_has_subscriber(Manager *m, DBusConnection *c);
+
+#define BUS_CONNECTION_SUBSCRIBED(m, c) dbus_connection_get_data((c), (m)->subscribed_data_slot)
+#define BUS_PENDING_CALL_NAME(m, p) dbus_pending_call_get_data((p), (m)->name_data_slot)
+
 extern const char * const bus_interface_table[];
 
 #endif
diff --git a/src/job.c b/src/job.c
index 31e9cfe..a090ec9 100644
--- a/src/job.c
+++ b/src/job.c
@@ -76,6 +76,7 @@ void job_free(Job *j) {
         if (j->in_dbus_queue)
                 LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
 
+        free(j->bus_client);
         free(j);
 }
 
@@ -544,10 +545,9 @@ void job_add_to_dbus_queue(Job *j) {
         if (j->in_dbus_queue)
                 return;
 
-        if (set_isempty(j->manager->subscribed)) {
-                j->sent_dbus_new_signal = true;
-                return;
-        }
+        /* We don't check if anybody is subscribed here, since this
+         * job might just have been created and not yet assigned to a
+         * connection/client. */
 
         LIST_PREPEND(Job, dbus_queue, j->manager->dbus_job_queue, j);
         j->in_dbus_queue = true;
diff --git a/src/job.h b/src/job.h
index 054aa53..9c685f1 100644
--- a/src/job.h
+++ b/src/job.h
@@ -102,6 +102,10 @@ struct Job {
         JobType type;
         JobState state;
 
+        /* Note that this bus object is not ref counted here. */
+        DBusConnection *bus;
+        char *bus_client;
+
         bool installed:1;
         bool in_run_queue:1;
         bool matters_to_anchor:1;
diff --git a/src/manager.c b/src/manager.c
index 74a414a..6e571ea 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -198,7 +198,7 @@ int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **_m) {
 
         m->running_as = running_as;
         m->confirm_spawn = confirm_spawn;
-        m->name_data_slot = -1;
+        m->name_data_slot = m->subscribed_data_slot = -1;
         m->exit_code = _MANAGER_EXIT_CODE_INVALID;
         m->pin_cgroupfs_fd = -1;
 
diff --git a/src/manager.h b/src/manager.h
index e856f53..aff4cb8 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -156,7 +156,6 @@ struct Manager {
         DBusServer *private_bus;
         Set *bus_connections, *bus_connections_for_dispatch;
 
-        Set *subscribed;
         DBusMessage *queued_message; /* This is used during reloading:
                                       * before the reload we queue the
                                       * reply message here, and
@@ -164,6 +163,7 @@ struct Manager {
 
         Hashmap *watch_bus;  /* D-Bus names => Unit object n:1 */
         int32_t name_data_slot;
+        int32_t subscribed_data_slot;
 
         /* Data specific to the Automount subsystem */
         int dev_autofs_fd;
diff --git a/src/systemctl.c b/src/systemctl.c
index 226ecee..1ad0c48 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -583,13 +583,10 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me
 
 static int enable_wait_for_jobs(DBusConnection *bus) {
         DBusError error;
-        DBusMessage *m = NULL, *reply = NULL;
-        int r;
 
         assert(bus);
 
         dbus_error_init(&error);
-
         dbus_bus_add_match(bus,
                            "type='signal',"
                            "sender='org.freedesktop.systemd1',"
@@ -600,40 +597,12 @@ static int enable_wait_for_jobs(DBusConnection *bus) {
 
         if (dbus_error_is_set(&error)) {
                 log_error("Failed to add match: %s", error.message);
-                r = -EIO;
-                goto finish;
-        }
-
-        if (!(m = dbus_message_new_method_call(
-                              "org.freedesktop.systemd1",
-                              "/org/freedesktop/systemd1",
-                              "org.freedesktop.systemd1.Manager",
-                              "Subscribe"))) {
-                log_error("Could not allocate message.");
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to issue method call: %s", error.message);
-                r = -EIO;
-                goto finish;
+                dbus_error_free(&error);
+                return -EIO;
         }
 
-        r = 0;
-
-finish:
         /* This is slightly dirty, since we don't undo the match registrations. */
-
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        return r;
+        return 0;
 }
 
 static int wait_for_jobs(DBusConnection *bus, Set *s) {
diff --git a/src/unit.c b/src/unit.c
index 8f5ae8a..8b57148 100644
--- a/src/unit.c
+++ b/src/unit.c
@@ -282,7 +282,8 @@ void unit_add_to_dbus_queue(Unit *u) {
         if (u->meta.load_state == UNIT_STUB || u->meta.in_dbus_queue)
                 return;
 
-        if (set_isempty(u->meta.manager->subscribed)) {
+        /* Shortcut things if nobody cares */
+        if (!bus_has_subscriber(u->meta.manager)) {
                 u->meta.sent_dbus_new_signal = true;
                 return;
         }
commit 552e4331bf165290eb02596355d9570c1ef9af47
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 21:18:06 2010 +0200

    systemctl: use format_timespan() where applicable

diff --git a/fixme b/fixme
index 8143f01..49b69a6 100644
--- a/fixme
+++ b/fixme
@@ -41,8 +41,6 @@
 
 * get rid of Subscribe() in systemctl
 
-* use format_timespan where applicable
-
 * Turn around negative options
 
 * Add missing man pages: update systemd.1, finish daemon.7
diff --git a/src/systemctl.c b/src/systemctl.c
index 72bb7d8..226ecee 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -1029,6 +1029,10 @@ static int print_property(const char *name, DBusMessageIter *iter) {
 
                         if ((t = format_timestamp(timestamp, sizeof(timestamp), u)) || arg_all)
                                 printf("%s=%s\n", name, strempty(t));
+                } else if (strstr(name, "USec")) {
+                        char timespan[FORMAT_TIMESPAN_MAX];
+
+                        printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
                 } else
                         printf("%s=%llu\n", name, (unsigned long long) u);
 
@@ -1165,11 +1169,14 @@ static int print_property(const char *name, DBusMessageIter *iter) {
 
                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
-                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0)
-                                        printf("%s={ value=%llu ; next_elapse=%llu }\n",
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
+                                        char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
+
+                                        printf("%s={ value=%s ; next_elapse=%s }\n",
                                                base,
-                                               (unsigned long long) value,
-                                               (unsigned long long) next_elapse);
+                                               format_timespan(timespan1, sizeof(timespan1), value),
+                                               format_timespan(timespan2, sizeof(timespan2), next_elapse));
+                                }
 
                                 dbus_message_iter_next(&sub);
                         }
commit fae20b110fe8734440ebfbcb676838dffda60b1b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 21:17:40 2010 +0200

    dbus: fix unclean shut-down

diff --git a/src/dbus.c b/src/dbus.c
index 405ea46..385bf6a 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -967,7 +967,10 @@ int bus_init(Manager *m) {
         return 0;
 }
 
-static void shutdown_connection(DBusConnection *c) {
+static void shutdown_connection(Manager *m, DBusConnection *c) {
+        set_remove(m->bus_connections, c);
+        set_remove(m->bus_connections_for_dispatch, c);
+
         dbus_connection_set_dispatch_status_function(c, NULL, NULL, NULL);
         dbus_connection_flush(c);
         dbus_connection_close(c);
@@ -981,8 +984,7 @@ static void bus_done_api(Manager *m) {
                 if (m->system_bus == m->api_bus)
                         m->system_bus = NULL;
 
-                set_remove(m->bus_connections, m->api_bus);
-                shutdown_connection(m->api_bus);
+                shutdown_connection(m, m->api_bus);
                 m->api_bus = NULL;
         }
 
@@ -1009,8 +1011,7 @@ static void bus_done_system(Manager *m) {
                 bus_done_api(m);
 
         if (m->system_bus) {
-                set_remove(m->bus_connections, m->system_bus);
-                shutdown_connection(m->system_bus);
+                shutdown_connection(m, m->system_bus);
                 m->system_bus = NULL;
         }
 }
@@ -1032,10 +1033,10 @@ void bus_done(Manager *m) {
         bus_done_private(m);
 
         while ((c = set_steal_first(m->bus_connections)))
-                shutdown_connection(c);
+                shutdown_connection(m, c);
 
         while ((c = set_steal_first(m->bus_connections_for_dispatch)))
-                shutdown_connection(c);
+                shutdown_connection(m, c);
 
         set_free(m->bus_connections);
         set_free(m->bus_connections_for_dispatch);
commit 03fae01822b5275a2940458f65644796283a8a23
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 21:12:10 2010 +0200

    uniformly suffix time span properties with their unit

diff --git a/fixme b/fixme
index 55e47d7..8143f01 100644
--- a/fixme
+++ b/fixme
@@ -41,10 +41,12 @@
 
 * get rid of Subscribe() in systemctl
 
-* Unify NS, USec, NSec, Sec suffixes in properties, use format_timespan
+* use format_timespan where applicable
 
 * Turn around negative options
 
+* Add missing man pages: update systemd.1, finish daemon.7
+
 External:
 
 * patch /etc/init.d/functions with:
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 6e9051d..83eef32 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -497,13 +497,19 @@
                         </varlistentry>
 
                         <varlistentry>
-                                <term><varname>TimerSlackNS=</varname></term>
+                                <term><varname>TimerSlackNSec=</varname></term>
                                 <listitem><para>Sets the timer slack
                                 in nanoseconds for the executed
-                                processes The timer slack controls the accuracy
-                                of wake-ups triggered by timers. See
+                                processes The timer slack controls the
+                                accuracy of wake-ups triggered by
+                                timers. See
                                 <citerefentry><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>
-                                for more information.</para></listitem>
+                                for more information. Note that in
+                                contrast to most other time span
+                                definitions this value is takes a
+                                nano-seconds integer and does not
+                                understand any other
+                                units.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml
index ef89693..557a45e 100644
--- a/man/systemd.timer.xml
+++ b/man/systemd.timer.xml
@@ -99,27 +99,27 @@
 
                 <variablelist>
                         <varlistentry>
-                                <term><varname>OnActive=</varname></term>
-                                <term><varname>OnBootup=</varname></term>
-                                <term><varname>OnStartup=</varname></term>
-                                <term><varname>OnUnitActive=</varname></term>
-                                <term><varname>OnUnitInactive=</varname></term>
+                                <term><varname>OnActiveSec=</varname></term>
+                                <term><varname>OnBootSec=</varname></term>
+                                <term><varname>OnStartupSec=</varname></term>
+                                <term><varname>OnUnitActiveSec=</varname></term>
+                                <term><varname>OnUnitInactiveSec=</varname></term>
 
                                 <listitem><para>Defines timers
                                 relative to different starting points:
-                                <varname>OnActive=</varname> defines a
+                                <varname>OnActiveSec=</varname> defines a
                                 timer relative to the moment the timer
                                 itself is
-                                activated. <varname>OnBootup=</varname>
+                                activated. <varname>OnBootSec=</varname>
                                 defines a timer relative to when the
                                 machine was booted
-                                up. <varname>OnStartup=</varname>
+                                up. <varname>OnStartupSec=</varname>
                                 defines a timer relative to when
                                 systemd was
-                                started. <varname>OnUnitActive=</varname>
+                                started. <varname>OnUnitActiveSec=</varname>
                                 defines a timer relative to when the
                                 unit the timer is activating was last
-                                activated. <varname>OnUnitInactive=</varname>
+                                activated. <varname>OnUnitInactiveSec=</varname>
                                 defines a timer relative to when the
                                 unit the timer is activating was last
                                 deactivated.</para>
@@ -127,8 +127,8 @@
                                 <para>Multiple directives may be
                                 combined of the same and of different
                                 types. For example, by combining
-                                <varname>OnBoot=</varname> and
-                                <varname>OnUnitActive=</varname> it is
+                                <varname>OnBootSec=</varname> and
+                                <varname>OnUnitActiveSec=</varname> it is
                                 possible to define a timer that
                                 elapses in regular intervals and
                                 activates a specific service each
@@ -136,17 +136,17 @@
 
                                 <para>The arguments to the directives
                                 are time spans configured in
-                                seconds. Example: "OnBoot=50" means
+                                seconds. Example: "OnBootSec=50" means
                                 50s after boot-up. The argument may
                                 also include time units. Example:
-                                "OnBoot=5h 30min" means 5 hours and 30
+                                "OnBootSec=5h 30min" means 5 hours and 30
                                 minutes after boot-up. For details
                                 about the syntax of time spans see
                                 <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
 
                                 <para>If a timer configured with
-                                <varname>OnBootup=</varname> or
-                                <varname>OnStartup=</varname> is
+                                <varname>OnBootSec=</varname> or
+                                <varname>OnStartupSec=</varname> is
                                 already in the past when the timer
                                 unit is activated, it will immediately
                                 elapse and the configured unit is
diff --git a/src/dbus-execute.c b/src/dbus-execute.c
index 529f72d..d37bd55 100644
--- a/src/dbus-execute.c
+++ b/src/dbus-execute.c
@@ -171,7 +171,7 @@ int bus_execute_append_affinity(Manager *m, DBusMessageIter *i, const char *prop
         return 0;
 }
 
-int bus_execute_append_timer_slack_ns(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+int bus_execute_append_timer_slack_nsec(Manager *m, DBusMessageIter *i, const char *property, void *data) {
         ExecContext *c = data;
         uint64_t u;
 
@@ -180,8 +180,8 @@ int bus_execute_append_timer_slack_ns(Manager *m, DBusMessageIter *i, const char
         assert(property);
         assert(c);
 
-        if (c->timer_slack_ns_set)
-                u = (uint64_t) c->timer_slack_ns_set;
+        if (c->timer_slack_nsec_set)
+                u = (uint64_t) c->timer_slack_nsec;
         else
                 u = (uint64_t) prctl(PR_GET_TIMERSLACK);
 
diff --git a/src/dbus-execute.h b/src/dbus-execute.h
index 95d400d..5208159 100644
--- a/src/dbus-execute.h
+++ b/src/dbus-execute.h
@@ -115,7 +115,7 @@
         { interface, "CPUSchedulingPolicy",           bus_execute_append_cpu_sched_policy, "i", &(context)                         }, \
         { interface, "CPUSchedulingPriority",         bus_execute_append_cpu_sched_priority, "i", &(context)                       }, \
         { interface, "CPUAffinity",                   bus_execute_append_affinity,"ay",    &(context)                              }, \
-        { interface, "TimerSlackNS",                  bus_execute_append_timer_slack_ns, "t", &(context)                           }, \
+        { interface, "TimerSlackNSec",                bus_execute_append_timer_slack_nsec, "t", &(context)                           }, \
         { interface, "CPUSchedulingResetOnFork",      bus_property_append_bool,   "b",     &(context).cpu_sched_reset_on_fork      }, \
         { interface, "NonBlocking",                   bus_property_append_bool,   "b",     &(context).non_blocking                 }, \
         { interface, "StandardInput",                 bus_execute_append_input,   "s",     &(context).std_input                    }, \
@@ -158,7 +158,7 @@ int bus_execute_append_ioprio(Manager *m, DBusMessageIter *i, const char *proper
 int bus_execute_append_cpu_sched_policy(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_execute_append_cpu_sched_priority(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_execute_append_affinity(Manager *m, DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_timer_slack_ns(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_timer_slack_nsec(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_execute_append_capabilities(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_execute_append_rlimits(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_execute_append_command(Manager *m, DBusMessageIter *u, const char *property, void *data);
diff --git a/src/dbus-timer.c b/src/dbus-timer.c
index d548227..0cd37d9 100644
--- a/src/dbus-timer.c
+++ b/src/dbus-timer.c
@@ -29,7 +29,7 @@
         " <interface name=\"org.freedesktop.systemd1.Timer\">\n"        \
         "  <property name=\"Unit\" type=\"s\" access=\"read\"/>\n"      \
         "  <property name=\"Timers\" type=\"a(stt)\" access=\"read\"/>\n" \
-        "  <property name=\"NextElapse\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"NextElapseUSec\" type=\"t\" access=\"read\"/>\n" \
         " </interface>\n"
 
 #define INTROSPECTION                                                   \
@@ -57,13 +57,30 @@ static int bus_timer_append_timers(Manager *m, DBusMessageIter *i, const char *p
                 return -ENOMEM;
 
         LIST_FOREACH(value, k, p->values) {
-                const char *t = timer_base_to_string(k->base);
+                char *buf;
+                const char *t;
+                size_t l;
+                bool b;
 
-                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &t) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->value) ||
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->next_elapse) ||
-                    !dbus_message_iter_close_container(&sub, &sub2))
+                t = timer_base_to_string(k->base);
+                assert(endswith(t, "Sec"));
+
+                /* s/Sec/USec/ */
+                l = strlen(t);
+                if (!(buf = new(char, l+2)))
+                        return -ENOMEM;
+
+                memcpy(buf, t, l-3);
+                memcpy(buf+l-3, "USec", 5);
+
+                b = dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) &&
+                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &buf) &&
+                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->value) &&
+                        dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->next_elapse) &&
+                        dbus_message_iter_close_container(&sub, &sub2);
+
+                free(buf);
+                if (!b)
                         return -ENOMEM;
         }
 
@@ -76,9 +93,9 @@ static int bus_timer_append_timers(Manager *m, DBusMessageIter *i, const char *p
 DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
         const BusProperty properties[] = {
                 BUS_UNIT_PROPERTIES,
-                { "org.freedesktop.systemd1.Timer", "Unit",       bus_property_append_string, "s",      u->timer.unit->meta.id },
-                { "org.freedesktop.systemd1.Timer", "Timers",     bus_timer_append_timers,    "a(stt)", u                      },
-                { "org.freedesktop.systemd1.Timer", "NextElapse", bus_property_append_usec,   "t",      &u->timer.next_elapse  },
+                { "org.freedesktop.systemd1.Timer", "Unit",           bus_property_append_string, "s",      u->timer.unit->meta.id },
+                { "org.freedesktop.systemd1.Timer", "Timers",         bus_timer_append_timers,    "a(stt)", u                      },
+                { "org.freedesktop.systemd1.Timer", "NextElapseUSec", bus_property_append_usec,   "t",      &u->timer.next_elapse  },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 
diff --git a/src/execute.c b/src/execute.c
index f3f95ff..982b7d1 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -1083,8 +1083,8 @@ int exec_spawn(ExecCommand *command,
                                 goto fail;
                         }
 
-                if (context->timer_slack_ns_set)
-                        if (prctl(PR_SET_TIMERSLACK, context->timer_slack_ns_set) < 0) {
+                if (context->timer_slack_nsec_set)
+                        if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
                                 r = EXIT_TIMERSLACK;
                                 goto fail;
                         }
@@ -1468,8 +1468,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                 fputs("\n", f);
         }
 
-        if (c->timer_slack_ns_set)
-                fprintf(f, "%sTimerSlackNS: %lu\n", prefix, c->timer_slack_ns);
+        if (c->timer_slack_nsec_set)
+                fprintf(f, "%sTimerSlackNSec: %lu\n", prefix, c->timer_slack_nsec);
 
         fprintf(f,
                 "%sStandardInput: %s\n"
diff --git a/src/execute.h b/src/execute.h
index aa5f566..1ab6a24 100644
--- a/src/execute.h
+++ b/src/execute.h
@@ -95,7 +95,7 @@ struct ExecContext {
 
         cpu_set_t *cpuset;
         unsigned cpuset_ncpus;
-        unsigned long timer_slack_ns;
+        unsigned long timer_slack_nsec;
 
         ExecInput std_input;
         ExecOutput std_output;
@@ -135,7 +135,7 @@ struct ExecContext {
         bool nice_set:1;
         bool ioprio_set:1;
         bool cpu_sched_set:1;
-        bool timer_slack_ns_set:1;
+        bool timer_slack_nsec_set:1;
 
         /* This is not exposed to the user but available
          * internally. We need it to make sure that whenever we spawn
diff --git a/src/load-fragment.c b/src/load-fragment.c
index a5ea0e4..8e777fd 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -857,7 +857,7 @@ static int config_parse_bounding_set(
         return 0;
 }
 
-static int config_parse_timer_slack_ns(
+static int config_parse_timer_slack_nsec(
                 const char *filename,
                 unsigned line,
                 const char *section,
@@ -880,7 +880,7 @@ static int config_parse_timer_slack_ns(
                 return r;
         }
 
-        c->timer_slack_ns = u;
+        c->timer_slack_nsec = u;
 
         return 0;
 }
@@ -1373,7 +1373,7 @@ static void dump_items(FILE *f, const ConfigItem *items) {
                 { config_parse_capabilities,     "CAPABILITIES" },
                 { config_parse_secure_bits,      "SECUREBITS" },
                 { config_parse_bounding_set,     "BOUNDINGSET" },
-                { config_parse_timer_slack_ns,   "TIMERSLACK" },
+                { config_parse_timer_slack_nsec, "TIMERSLACK" },
                 { config_parse_limit,            "LIMIT" },
                 { config_parse_cgroup,           "CGROUP [...]" },
                 { config_parse_deps,             "UNIT [...]" },
@@ -1468,7 +1468,7 @@ static int load_from_path(Unit *u, const char *path) {
                 { "Capabilities",           config_parse_capabilities,    &(context),                                      section   }, \
                 { "SecureBits",             config_parse_secure_bits,     &(context),                                      section   }, \
                 { "CapabilityBoundingSetDrop", config_parse_bounding_set, &(context),                                      section   }, \
-                { "TimerSlackNS",           config_parse_timer_slack_ns,  &(context),                                      section   }, \
+                { "TimerSlackNSec",         config_parse_timer_slack_nsec,&(context),                                      section   }, \
                 { "LimitCPU",               config_parse_limit,           &(context).rlimit[RLIMIT_CPU],                   section   }, \
                 { "LimitFSIZE",             config_parse_limit,           &(context).rlimit[RLIMIT_FSIZE],                 section   }, \
                 { "LimitDATA",              config_parse_limit,           &(context).rlimit[RLIMIT_DATA],                  section   }, \
@@ -1574,11 +1574,11 @@ static int load_from_path(Unit *u, const char *path) {
                 { "What",                   config_parse_path,            &u->swap.parameters_fragment.what,               "Swap"    },
                 { "Priority",               config_parse_int,             &u->swap.parameters_fragment.priority,           "Swap"    },
 
-                { "OnActive",               config_parse_timer,           &u->timer,                                       "Timer"   },
-                { "OnBoot",                 config_parse_timer,           &u->timer,                                       "Timer"   },
-                { "OnStartup",              config_parse_timer,           &u->timer,                                       "Timer"   },
-                { "OnUnitActive",           config_parse_timer,           &u->timer,                                       "Timer"   },
-                { "OnUnitInactive",         config_parse_timer,           &u->timer,                                       "Timer"   },
+                { "OnActiveSec",            config_parse_timer,           &u->timer,                                       "Timer"   },
+                { "OnBootSec",              config_parse_timer,           &u->timer,                                       "Timer"   },
+                { "OnStartupSec",           config_parse_timer,           &u->timer,                                       "Timer"   },
+                { "OnUnitActiveSec",        config_parse_timer,           &u->timer,                                       "Timer"   },
+                { "OnUnitInactiveSec",      config_parse_timer,           &u->timer,                                       "Timer"   },
                 { "Unit",                   config_parse_timer_unit,      &u->timer,                                       "Timer"   },
 
                 { "PathExists",             config_parse_path_spec,       &u->path,                                        "Path"    },
diff --git a/src/timer.c b/src/timer.c
index e3c916b..b4521e6 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -440,11 +440,11 @@ static const char* const timer_state_table[_TIMER_STATE_MAX] = {
 DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
 
 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
-        [TIMER_ACTIVE] = "OnActive",
-        [TIMER_BOOT] = "OnBoot",
-        [TIMER_STARTUP] = "OnStartup",
-        [TIMER_UNIT_ACTIVE] = "OnUnitActive",
-        [TIMER_UNIT_INACTIVE] = "OnUnitInactive"
+        [TIMER_ACTIVE] = "OnActiveSec",
+        [TIMER_BOOT] = "OnBootSec",
+        [TIMER_STARTUP] = "OnStartupSec",
+        [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
+        [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec"
 };
 
 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
commit 393a2f9be167f4147e117fd2fc912292899b6b33
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 20:46:12 2010 +0200

    man: update systemctl man page

diff --git a/man/systemctl.xml b/man/systemctl.xml
index e3a07d5..1bd08da 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -91,13 +91,28 @@
                         </varlistentry>
 
                         <varlistentry>
+                                <term><option>--property=</option></term>
+                                <term><option>-p</option></term>
+
+                                <listitem><para>When showing
+                                unit/job/manager information, limit
+                                display to certain property names. If
+                                not specified all set properties are
+                                shown. The argument should be a
+                                property name, such as
+                                <literal>MainPID</literal>.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
                                 <term><option>--all</option></term>
                                 <term><option>-a</option></term>
 
                                 <listitem><para>When listing units,
                                 show all units, regardless of their
-                                state, including inactive
-                                units.</para></listitem>
+                                state, including inactive units. When
+                                showing unit/job/manager information,
+                                show all properties regardless whether
+                                they are set or not.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
@@ -165,53 +180,6 @@
                                 <listitem><para>List known units.</para></listitem>
                         </varlistentry>
                         <varlistentry>
-                                <term><command>list-jobs</command></term>
-
-                                <listitem><para>List jobs that are in progress.</para></listitem>
-                        </varlistentry>
-                        <varlistentry>
-                                <term><command>clear-jobs</command></term>
-
-                                <listitem><para>Cancel all jobs that are in progress.</para></listitem>
-                        </varlistentry>
-                        <varlistentry>
-                                <term><command>load [NAME...]</command></term>
-
-                                <listitem><para>Load one or more units
-                                specified on the command line. This
-                                will simply load their configuration
-                                from disk, but not start them. To
-                                start them you need to use the
-                                <command>start</command> command which
-                                will implicitly load a unit that has
-                                not been loaded yet. Note that systemd
-                                garbage collects loaded units that are
-                                not active or referenced by an active
-                                unit. This means that units loaded
-                                this way will usually not stay loaded
-                                for long. Also note that this command
-                                cannot be used to reload unit
-                                configuration. Use the
-                                <command>daemon-reload</command>
-                                command for that. All in all, this
-                                command is of little use except for
-                                debugging.</para>
-                                <para>This command should not be
-                                confused with the
-                                <command>daemon-reload</command> or
-                                <command>reload</command>
-                                commands.</para></listitem>
-                        </varlistentry>
-
-                        <varlistentry>
-                                <term><command>cancel [JOB...]</command></term>
-
-                                <listitem><para>Cancel one or more
-                                jobs specified on the command line by
-                                their numeric job
-                                IDs.</para></listitem>
-                        </varlistentry>
-                        <varlistentry>
                                 <term><command>start [NAME...]</command></term>
 
                                 <listitem><para>Start one or more
@@ -279,6 +247,65 @@
                                 state to STDOUT.</para></listitem>
                         </varlistentry>
                         <varlistentry>
+                                <term><command>show [NAME...|JOB...]</command></term>
+
+                                <listitem><para>Show information about
+                                one or more units, jobs or the manager
+                                itself. If no argument is specified
+                                information about the manager will be
+                                shown. If a unit name is specified
+                                information about the unit is shown,
+                                and if a job id is specified
+                                information about the job is
+                                shown.</para></listitem>
+                        </varlistentry>
+                        <varlistentry>
+                                <term><command>load [NAME...]</command></term>
+
+                                <listitem><para>Load one or more units
+                                specified on the command line. This
+                                will simply load their configuration
+                                from disk, but not start them. To
+                                start them you need to use the
+                                <command>start</command> command which
+                                will implicitly load a unit that has
+                                not been loaded yet. Note that systemd
+                                garbage collects loaded units that are
+                                not active or referenced by an active
+                                unit. This means that units loaded
+                                this way will usually not stay loaded
+                                for long. Also note that this command
+                                cannot be used to reload unit
+                                configuration. Use the
+                                <command>daemon-reload</command>
+                                command for that. All in all, this
+                                command is of little use except for
+                                debugging.</para>
+                                <para>This command should not be
+                                confused with the
+                                <command>daemon-reload</command> or
+                                <command>reload</command>
+                                commands.</para></listitem>
+                        </varlistentry>
+                        <varlistentry>
+                                <term><command>list-jobs</command></term>
+
+                                <listitem><para>List jobs that are in progress.</para></listitem>
+                        </varlistentry>
+                        <varlistentry>
+                                <term><command>cancel [JOB...]</command></term>
+
+                                <listitem><para>Cancel one or more
+                                jobs specified on the command line by
+                                their numeric job
+                                IDs.</para></listitem>
+                        </varlistentry>
+                        <varlistentry>
+                                <term><command>clear-jobs</command></term>
+
+                                <listitem><para>Cancel all jobs that are in progress.</para></listitem>
+                        </varlistentry>
+                        <varlistentry>
                                 <term><command>monitor</command></term>
 
                                 <listitem><para>Monitor unit/job
diff --git a/src/systemctl.c b/src/systemctl.c
index 12ddae8..72bb7d8 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -2106,7 +2106,7 @@ static int systemctl_help(void) {
                "Send control commands to the systemd manager.\n\n"
                "  -h --help          Show this help\n"
                "  -t --type=TYPE     List only units of a particular type\n"
-               "  -p --property=NAME Show only property by this name\n"
+               "  -p --property=NAME Show only properties by this name\n"
                "  -a --all           Show all units/properties, including dead/empty ones\n"
                "     --replace       When installing a new job, replace existing conflicting ones\n"
                "     --system        Connect to system bus\n"
@@ -2122,7 +2122,7 @@ static int systemctl_help(void) {
                "  reload [NAME...]                Reload one or more units\n"
                "  isolate [NAME]                  Start one unit and stop all others\n"
                "  check [NAME...]                 Check whether any of the passed units are active\n"
-               "  show [NAME...|JOB...]           Show information about one or more units\n"
+               "  show [NAME...|JOB...]           Show information about one or more units/jobs/manager\n"
                "  load [NAME...]                  Load one or more units\n"
                "  list-jobs                       List jobs\n"
                "  cancel [JOB...]                 Cancel one or more jobs\n"
commit fe68089df69f3580ebc9bbaf2483bdcda40a6933
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 20:38:14 2010 +0200

    dbus: complete exec command coverage

diff --git a/src/dbus-execute.c b/src/dbus-execute.c
index a41b639..529f72d 100644
--- a/src/dbus-execute.c
+++ b/src/dbus-execute.c
@@ -26,6 +26,7 @@
 #include "dbus-execute.h"
 #include "missing.h"
 #include "ioprio.h"
+#include "strv.h"
 
 DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput);
 DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput);
@@ -153,7 +154,7 @@ int bus_execute_append_affinity(Manager *m, DBusMessageIter *i, const char *prop
         assert(property);
         assert(c);
 
-        if (!(dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub)))
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub))
                 return -ENOMEM;
 
         if (c->cpuset)
@@ -246,3 +247,53 @@ int bus_execute_append_rlimits(Manager *m, DBusMessageIter *i, const char *prope
 
         return 0;
 }
+
+int bus_execute_append_command(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        ExecCommand *c = data;
+        DBusMessageIter sub, sub2, sub3;
+
+        assert(m);
+        assert(i);
+        assert(property);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sasttuii)", &sub))
+                return -ENOMEM;
+
+        LIST_FOREACH(command, c, c) {
+                char **l;
+                uint32_t pid;
+                int32_t code, status;
+
+                if (!c->path)
+                        continue;
+
+                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &c->path) ||
+                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_ARRAY, "s", &sub3))
+                        return -ENOMEM;
+
+                STRV_FOREACH(l, c->argv)
+                        if (!dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, l))
+                                return -ENOMEM;
+
+                pid = (uint32_t) c->exec_status.pid;
+                code = (int32_t) c->exec_status.code;
+                status = (int32_t) c->exec_status.status;
+
+                if (!dbus_message_iter_close_container(&sub2, &sub3) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.realtime) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.realtime) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &c->exec_status.pid) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &c->exec_status.code) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &c->exec_status.status))
+                        return -ENOMEM;
+
+                if (!dbus_message_iter_close_container(&sub, &sub2))
+                        return -ENOMEM;
+        }
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
diff --git a/src/dbus-execute.h b/src/dbus-execute.h
index 1ab196f..95d400d 100644
--- a/src/dbus-execute.h
+++ b/src/dbus-execute.h
@@ -83,7 +83,10 @@
         "  <property name=\"InaccessibleDirectories\" type=\"as\" access=\"read\"/>\n" \
         "  <property name=\"MountFlags\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"PrivateTmp\" type=\"b\" access=\"read\"/>\n" \
-        "  <property name=\"NoSetSID\" type=\"b\" access=\"read\"/>\n"  \
+        "  <property name=\"NoSetSID\" type=\"b\" access=\"read\"/>\n"
+
+#define BUS_EXEC_COMMAND_INTERFACE(name)                             \
+        "  <property name=\"" name "\" type=\"a(sasttuii)\" access=\"read\"/>\n"
 
 #define BUS_EXEC_CONTEXT_PROPERTIES(interface, context)                 \
         { interface, "Environment",                   bus_property_append_strv,   "as",    (context).environment                   }, \
@@ -144,6 +147,9 @@
         { interface, prefix "Code",                   bus_property_append_int,    "i",     &(estatus).code                         }, \
         { interface, prefix "Status",                 bus_property_append_int,    "i",     &(estatus).status                       }
 
+#define BUS_EXEC_COMMAND_PROPERTY(interface, command, name)            \
+        { interface, name, bus_execute_append_command, "a(sasttuii)", (command) }
+
 int bus_execute_append_output(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_execute_append_input(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_execute_append_oom_adjust(Manager *m, DBusMessageIter *i, const char *property, void *data);
@@ -155,5 +161,6 @@ int bus_execute_append_affinity(Manager *m, DBusMessageIter *i, const char *prop
 int bus_execute_append_timer_slack_ns(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_execute_append_capabilities(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_execute_append_rlimits(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_command(Manager *m, DBusMessageIter *u, const char *property, void *data);
 
 #endif
diff --git a/src/dbus-mount.c b/src/dbus-mount.c
index 5e17ec2..76a010b 100644
--- a/src/dbus-mount.c
+++ b/src/dbus-mount.c
@@ -32,6 +32,9 @@
         "  <property name=\"Options\" type=\"s\" access=\"read\"/>\n"   \
         "  <property name=\"Type\" type=\"s\" access=\"read\"/>\n"      \
         "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
+        BUS_EXEC_COMMAND_INTERFACE("ExecMount")                         \
+        BUS_EXEC_COMMAND_INTERFACE("ExecUnmount")                       \
+        BUS_EXEC_COMMAND_INTERFACE("ExecRemount")                       \
         BUS_EXEC_CONTEXT_INTERFACE                                      \
         "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n"  \
         "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
@@ -129,7 +132,9 @@ DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMess
                 { "org.freedesktop.systemd1.Mount", "Options",       bus_mount_append_options,   "s", u                      },
                 { "org.freedesktop.systemd1.Mount", "Type",          bus_mount_append_type,      "s", u                      },
                 { "org.freedesktop.systemd1.Mount", "TimeoutUSec",   bus_property_append_usec,   "t", &u->mount.timeout_usec },
-                /* ExecCommand */
+                BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Mount", u->mount.exec_command+MOUNT_EXEC_MOUNT,   "ExecMount"),
+                BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Mount", u->mount.exec_command+MOUNT_EXEC_UNMOUNT, "ExecUnmount"),
+                BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Mount", u->mount.exec_command+MOUNT_EXEC_REMOUNT, "ExecRemount"),
                 BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Mount", u->mount.exec_context),
                 { "org.freedesktop.systemd1.Mount", "KillMode",      bus_unit_append_kill_mode,  "s", &u->mount.kill_mode    },
                 { "org.freedesktop.systemd1.Mount", "ControlPID",    bus_property_append_pid,    "u", &u->mount.control_pid  },
diff --git a/src/dbus-service.c b/src/dbus-service.c
index 26524f4..46a6ff1 100644
--- a/src/dbus-service.c
+++ b/src/dbus-service.c
@@ -33,6 +33,12 @@
         "  <property name=\"NotifyAccess\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"RestartUSec\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStartPre")                      \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStart")                         \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStartPost")                     \
+        BUS_EXEC_COMMAND_INTERFACE("ExecReload")                        \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStop")                          \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStopPost")                      \
         BUS_EXEC_CONTEXT_INTERFACE                                      \
         "  <property name=\"PermissionsStartOnly\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"RootDirectoryStartOnly\" type=\"b\" access=\"read\"/>\n" \
@@ -72,7 +78,12 @@ DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connectio
                 { "org.freedesktop.systemd1.Service", "NotifyAccess",           bus_service_append_notify_access, "s", &u->service.notify_access       },
                 { "org.freedesktop.systemd1.Service", "RestartUSec",            bus_property_append_usec,   "t", &u->service.restart_usec              },
                 { "org.freedesktop.systemd1.Service", "TimeoutUSec",            bus_property_append_usec,   "t", &u->service.timeout_usec              },
-                /* ExecCommand */
+                BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Service", u->service.exec_command[SERVICE_EXEC_START_PRE],  "ExecStartPre"),
+                BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Service", u->service.exec_command[SERVICE_EXEC_START],      "ExecStart"),
+                BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Service", u->service.exec_command[SERVICE_EXEC_START_POST], "ExecStartPost"),
+                BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Service", u->service.exec_command[SERVICE_EXEC_RELOAD],     "ExecReload"),
+                BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Service", u->service.exec_command[SERVICE_EXEC_STOP],       "ExecStop"),
+                BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Service", u->service.exec_command[SERVICE_EXEC_STOP_POST],  "ExecStopPost"),
                 BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Service", u->service.exec_context),
                 { "org.freedesktop.systemd1.Service", "PermissionsStartOnly",   bus_property_append_bool,   "b", &u->service.permissions_start_only    },
                 { "org.freedesktop.systemd1.Service", "RootDirectoryStartOnly", bus_property_append_bool,   "b", &u->service.root_directory_start_only },
diff --git a/src/dbus-socket.c b/src/dbus-socket.c
index 5f195a1..22a4ce8 100644
--- a/src/dbus-socket.c
+++ b/src/dbus-socket.c
@@ -30,6 +30,10 @@
         "  <property name=\"BindIPv6Only\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"Backlog\" type=\"u\" access=\"read\"/>\n"   \
         "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStartPre")                      \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStartPost")                     \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStopPre")                       \
+        BUS_EXEC_COMMAND_INTERFACE("ExecStopPost")                      \
         BUS_EXEC_CONTEXT_INTERFACE                                      \
         "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n"  \
         "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
@@ -70,7 +74,10 @@ DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMes
                 { "org.freedesktop.systemd1.Socket", "BindIPv6Only",   bus_socket_append_bind_ipv6_only, "s", &u->socket.bind_ipv6_only  },
                 { "org.freedesktop.systemd1.Socket", "Backlog",        bus_property_append_unsigned,     "u", &u->socket.backlog         },
                 { "org.freedesktop.systemd1.Socket", "TimeoutUSec",    bus_property_append_usec,         "t", &u->socket.timeout_usec    },
-                /* ExecCommand */
+                BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Socket", u->service.exec_command[SOCKET_EXEC_START_PRE],  "ExecStartPre"),
+                BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Socket", u->service.exec_command[SOCKET_EXEC_START_POST], "ExecStartPost"),
+                BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Socket", u->service.exec_command[SOCKET_EXEC_STOP_PRE],   "ExecStopPre"),
+                BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Socket", u->service.exec_command[SOCKET_EXEC_STOP_POST],  "ExecStopPost"),
                 BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Socket", u->socket.exec_context),
                 { "org.freedesktop.systemd1.Socket", "KillMode",       bus_unit_append_kill_mode,        "s", &u->socket.kill_mode       },
                 { "org.freedesktop.systemd1.Socket", "ControlPID",     bus_property_append_pid,          "u", &u->socket.control_pid     },
diff --git a/src/systemctl.c b/src/systemctl.c
index f97fa10..12ddae8 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -1166,7 +1166,68 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0)
-                                        printf("%s=%llu\n", base, (unsigned long long) value);
+                                        printf("%s={ value=%llu ; next_elapse=%llu }\n",
+                                               base,
+                                               (unsigned long long) value,
+                                               (unsigned long long) next_elapse);
+
+                                dbus_message_iter_next(&sub);
+                        }
+
+                        return 0;
+                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
+
+                        DBusMessageIter sub, sub2, sub3;
+
+                        dbus_message_iter_recurse(iter, &sub);
+
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                                const char *path;
+                                uint64_t start_time, exit_time;
+                                uint32_t pid;
+                                int32_t code, status;
+
+                                dbus_message_iter_recurse(&sub, &sub2);
+
+                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
+                                        continue;
+
+                                if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
+                                    dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
+                                        continue;
+
+                                printf("%s={ path=%s ; argv[]=", name, path);
+
+                                dbus_message_iter_recurse(&sub2, &sub3);
+
+                                while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
+                                        const char *s;
+
+                                        assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
+                                        dbus_message_iter_get_basic(&sub3, &s);
+                                        printf("%s ", s);
+                                        dbus_message_iter_next(&sub3);
+                                }
+
+                                if (dbus_message_iter_next(&sub2) &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_time, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_time, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) >= 0) {
+
+                                        char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
+
+                                        printf("; start=%s ; stop=%s ; pid=%u ; code=%s ; status=%i/%s",
+                                               strna(format_timestamp(timestamp1, sizeof(timestamp1), start_time)),
+                                               strna(format_timestamp(timestamp2, sizeof(timestamp2), exit_time)),
+                                               (unsigned) pid,
+                                               sigchld_code_to_string(code),
+                                               status,
+                                               strna(code == CLD_EXITED ? NULL : strsignal(status)));
+                                }
+
+                                printf(" }\n");
 
                                 dbus_message_iter_next(&sub);
                         }
commit b58b41160fde88a82cba1ddec4be7dfb08825e35
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 18:49:58 2010 +0200

    dbus: complete exec status coverage

diff --git a/src/dbus-execute.h b/src/dbus-execute.h
index f6cca9c..1ab196f 100644
--- a/src/dbus-execute.h
+++ b/src/dbus-execute.h
@@ -26,6 +26,13 @@
 
 #include "manager.h"
 
+#define BUS_EXEC_STATUS_INTERFACE(prefix)                               \
+        "  <property name=\"" prefix "StartTimestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"" prefix "ExitTimestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"" prefix "PID\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"" prefix "Code\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"" prefix "Status\" type=\"i\" access=\"read\"/>\n"
+
 #define BUS_EXEC_CONTEXT_INTERFACE                                      \
         "  <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
         "  <property name=\"UMask\" type=\"u\" access=\"read\"/>\n"     \
@@ -130,6 +137,13 @@
         { interface, "PrivateTmp",                    bus_property_append_bool,   "b",     &(context).private_tmp                  }, \
         { interface, "NoSetSID",                      bus_property_append_bool,   "b",     &(context).no_setsid                    }
 
+#define BUS_EXEC_STATUS_PROPERTIES(interface, estatus, prefix)           \
+        { interface, prefix "StartTimestamp",         bus_property_append_usec,   "t",     &(estatus).start_timestamp.realtime     }, \
+        { interface, prefix "ExitTimestamp",          bus_property_append_usec,   "t",     &(estatus).start_timestamp.realtime     }, \
+        { interface, prefix "PID",                    bus_property_append_pid,    "u",     &(estatus).pid                          }, \
+        { interface, prefix "Code",                   bus_property_append_int,    "i",     &(estatus).code                         }, \
+        { interface, prefix "Status",                 bus_property_append_int,    "i",     &(estatus).status                       }
+
 int bus_execute_append_output(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_execute_append_input(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_execute_append_oom_adjust(Manager *m, DBusMessageIter *i, const char *property, void *data);
diff --git a/src/dbus-service.c b/src/dbus-service.c
index 84c4730..26524f4 100644
--- a/src/dbus-service.c
+++ b/src/dbus-service.c
@@ -38,6 +38,7 @@
         "  <property name=\"RootDirectoryStartOnly\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"ValidNoProcess\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n"  \
+        BUS_EXEC_STATUS_INTERFACE("ExecMain")                           \
         "  <property name=\"MainPID\" type=\"u\" access=\"read\"/>\n"   \
         "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
         "  <property name=\"SysVStartPriority\" type=\"i\" access=\"read\"/>\n" \
@@ -77,7 +78,7 @@ DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connectio
                 { "org.freedesktop.systemd1.Service", "RootDirectoryStartOnly", bus_property_append_bool,   "b", &u->service.root_directory_start_only },
                 { "org.freedesktop.systemd1.Service", "ValidNoProcess",         bus_property_append_bool,   "b", &u->service.valid_no_process          },
                 { "org.freedesktop.systemd1.Service", "KillMode",               bus_unit_append_kill_mode,  "s", &u->service.kill_mode                 },
-                /* MainExecStatus */
+                BUS_EXEC_STATUS_PROPERTIES("org.freedesktop.systemd1.Service", u->service.main_exec_status, "ExecMain"),
                 { "org.freedesktop.systemd1.Service", "MainPID",                bus_property_append_pid,    "u", &u->service.main_pid                  },
                 { "org.freedesktop.systemd1.Service", "ControlPID",             bus_property_append_pid,    "u", &u->service.control_pid               },
                 { "org.freedesktop.systemd1.Service", "SysVPath",               bus_property_append_string, "s", u->service.sysv_path                  },
diff --git a/src/execute.c b/src/execute.c
index 0bdd600..f3f95ff 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -1281,8 +1281,7 @@ int exec_spawn(ExecCommand *command,
 
         log_debug("Forked %s as %lu", command->path, (unsigned long) pid);
 
-        command->exec_status.pid = pid;
-        dual_timestamp_get(&command->exec_status.start_timestamp);
+        exec_status_start(&command->exec_status, pid);
 
         *ret = pid;
         return 0;
@@ -1561,9 +1560,21 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
         }
 }
 
-void exec_status_fill(ExecStatus *s, pid_t pid, int code, int status) {
+void exec_status_start(ExecStatus *s, pid_t pid) {
         assert(s);
 
+        zero(*s);
+        s->pid = pid;
+        dual_timestamp_get(&s->start_timestamp);
+}
+
+void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status) {
+        assert(s);
+
+        if ((s->pid && s->pid != pid) ||
+            !s->start_timestamp.realtime <= 0)
+                zero(*s);
+
         s->pid = pid;
         dual_timestamp_get(&s->exit_timestamp);
 
diff --git a/src/execute.h b/src/execute.h
index 9fb48e6..aa5f566 100644
--- a/src/execute.h
+++ b/src/execute.h
@@ -217,7 +217,8 @@ void exec_context_init(ExecContext *c);
 void exec_context_done(ExecContext *c);
 void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);
 
-void exec_status_fill(ExecStatus *s, pid_t pid, int code, int status);
+void exec_status_start(ExecStatus *s, pid_t pid);
+void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status);
 void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix);
 
 const char* exec_output_to_string(ExecOutput i);
diff --git a/src/mount.c b/src/mount.c
index 6b38741..b99e5ff 100644
--- a/src/mount.c
+++ b/src/mount.c
@@ -936,7 +936,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         m->failure = m->failure || !success;
 
         if (m->control_command) {
-                exec_status_fill(&m->control_command->exec_status, pid, code, status);
+                exec_status_exit(&m->control_command->exec_status, pid, code, status);
                 m->control_command = NULL;
                 m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
         }
diff --git a/src/service.c b/src/service.c
index 04ed684..ae8a763 100644
--- a/src/service.c
+++ b/src/service.c
@@ -144,6 +144,8 @@ static int service_set_main_pid(Service *s, pid_t pid) {
         s->main_pid = pid;
         s->main_pid_known = true;
 
+        exec_status_start(&s->main_exec_status, pid);
+
         return 0;
 }
 
@@ -2082,7 +2084,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
 
         if (s->main_pid == pid) {
 
-                exec_status_fill(&s->main_exec_status, pid, code, status);
+                exec_status_exit(&s->main_exec_status, pid, code, status);
                 s->main_pid = 0;
 
                 if (s->type != SERVICE_FORKING) {
@@ -2138,7 +2140,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         } else if (s->control_pid == pid) {
 
                 if (s->control_command)
-                        exec_status_fill(&s->control_command->exec_status, pid, code, status);
+                        exec_status_exit(&s->control_command->exec_status, pid, code, status);
 
                 s->control_pid = 0;
 
diff --git a/src/socket.c b/src/socket.c
index 03e556c..00e0685 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -1397,7 +1397,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         s->failure = s->failure || !success;
 
         if (s->control_command)
-                exec_status_fill(&s->control_command->exec_status, pid, code, status);
+                exec_status_exit(&s->control_command->exec_status, pid, code, status);
 
         log_debug("%s control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);
 
commit 14ad1d1437f51b8ebc8dc6e8d3707b41d48d0a3a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 16:48:24 2010 +0200

    dbus: include NextElapse field in timer properties

diff --git a/src/dbus-timer.c b/src/dbus-timer.c
index af0ae72..d548227 100644
--- a/src/dbus-timer.c
+++ b/src/dbus-timer.c
@@ -29,6 +29,7 @@
         " <interface name=\"org.freedesktop.systemd1.Timer\">\n"        \
         "  <property name=\"Unit\" type=\"s\" access=\"read\"/>\n"      \
         "  <property name=\"Timers\" type=\"a(stt)\" access=\"read\"/>\n" \
+        "  <property name=\"NextElapse\" type=\"t\" access=\"read\"/>\n" \
         " </interface>\n"
 
 #define INTROSPECTION                                                   \
@@ -77,6 +78,7 @@ DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMess
                 BUS_UNIT_PROPERTIES,
                 { "org.freedesktop.systemd1.Timer", "Unit",       bus_property_append_string, "s",      u->timer.unit->meta.id },
                 { "org.freedesktop.systemd1.Timer", "Timers",     bus_timer_append_timers,    "a(stt)", u                      },
+                { "org.freedesktop.systemd1.Timer", "NextElapse", bus_property_append_usec,   "t",      &u->timer.next_elapse  },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 
diff --git a/src/systemctl.c b/src/systemctl.c
index 392ecf2..f97fa10 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -1024,7 +1024,7 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                 /* Yes, heuristics! But we can change this check
                  * should it turn out to not be sufficient */
 
-                if (strstr(name, "Timestamp") || strstr(name, "Elapse")) {
+                if (strstr(name, "Timestamp")) {
                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
 
                         if ((t = format_timestamp(timestamp, sizeof(timestamp), u)) || arg_all)
commit 82c121a4754a9d405b07c75796e329942af2ccc5
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 16:44:58 2010 +0200

    dbus: complete exec coverage

diff --git a/fixme b/fixme
index 2f0f929..55e47d7 100644
--- a/fixme
+++ b/fixme
@@ -39,6 +39,12 @@
 
 * systemctl daemon-reload is kaputt
 
+* get rid of Subscribe() in systemctl
+
+* Unify NS, USec, NSec, Sec suffixes in properties, use format_timespan
+
+* Turn around negative options
+
 External:
 
 * patch /etc/init.d/functions with:
diff --git a/src/dbus-execute.c b/src/dbus-execute.c
index 8840396..a41b639 100644
--- a/src/dbus-execute.c
+++ b/src/dbus-execute.c
@@ -21,8 +21,228 @@
 
 #include <errno.h>
 #include <dbus/dbus.h>
+#include <sys/prctl.h>
 
 #include "dbus-execute.h"
+#include "missing.h"
+#include "ioprio.h"
 
 DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput);
 DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput);
+
+int bus_execute_append_oom_adjust(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        int32_t n;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (c->oom_adjust_set)
+                n = c->oom_adjust;
+        else {
+                char *t;
+
+                n = 0;
+                if (read_one_line_file("/proc/self/oom_adj", &t) >= 0) {
+                        safe_atoi(t, &n);
+                        free(t);
+                }
+        }
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_nice(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        int32_t n;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (c->nice_set)
+                n = c->nice;
+        else
+                n = getpriority(PRIO_PROCESS, 0);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_ioprio(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        int32_t n;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (c->ioprio_set)
+                n = c->ioprio;
+        else
+                n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_cpu_sched_policy(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        int32_t n;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (c->cpu_sched_set)
+                n = c->cpu_sched_policy;
+        else
+                n = sched_getscheduler(0);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_cpu_sched_priority(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        int32_t n;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (c->cpu_sched_set)
+                n = c->cpu_sched_priority;
+        else {
+                struct sched_param p;
+                n = 0;
+
+                zero(p);
+                if (sched_getparam(0, &p) >= 0)
+                        n = p.sched_priority;
+        }
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_affinity(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        dbus_bool_t b;
+        DBusMessageIter sub;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (!(dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub)))
+                return -ENOMEM;
+
+        if (c->cpuset)
+                b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
+        else
+                b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, 0);
+
+        if (!b)
+                return -ENOMEM;
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_timer_slack_ns(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        uint64_t u;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (c->timer_slack_ns_set)
+                u = (uint64_t) c->timer_slack_ns_set;
+        else
+                u = (uint64_t) prctl(PR_GET_TIMERSLACK);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_capabilities(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        char *t = NULL;
+        const char *s;
+        dbus_bool_t b;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(c);
+
+        if (c->capabilities)
+                s = t = cap_to_text(c->capabilities, NULL);
+        else
+                s = "";
+
+        if (!t)
+                return -ENOMEM;
+
+        b = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &s);
+        cap_free(t);
+
+        if (!b)
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_execute_append_rlimits(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        ExecContext *c = data;
+        int r;
+        uint64_t u;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(c);
+
+        assert_se((r = rlimit_from_string(property)) >= 0);
+
+        if (c->rlimit[r])
+                u = (uint64_t) c->rlimit[r]->rlim_max;
+        else {
+                struct rlimit rl;
+
+                zero(rl);
+                getrlimit(r, &rl);
+
+                u = (uint64_t) rl.rlim_max;
+        }
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
+                return -ENOMEM;
+
+        return 0;
+}
diff --git a/src/dbus-execute.h b/src/dbus-execute.h
index 1e83cac..f6cca9c 100644
--- a/src/dbus-execute.h
+++ b/src/dbus-execute.h
@@ -29,8 +29,31 @@
 #define BUS_EXEC_CONTEXT_INTERFACE                                      \
         "  <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
         "  <property name=\"UMask\" type=\"u\" access=\"read\"/>\n"     \
+        "  <property name=\"LimitCPU\" type=\"t\" access=\"read\"/>\n"  \
+        "  <property name=\"LimitFSIZE\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitDATA\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitSTACK\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitCORE\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitRSS\" type=\"t\" access=\"read\"/>\n"  \
+        "  <property name=\"LimitNOFILE\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitAS\" type=\"t\" access=\"read\"/>\n"   \
+        "  <property name=\"LimitNPROC\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitMEMLOCK\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitLOCKS\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitSIGPENDING\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitMSGQUEUE\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitNICE\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitRTPRIO\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"LimitRTTIME\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"WorkingDirectory\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"RootDirectory\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"OOMAdjust\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"Nice\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"IOScheduling\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"CPUSchedulingPolicy\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"CPUSchedulingPriority\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"CPUAffinity\" type=\"ay\" access=\"read\"/>\n" \
+        "  <property name=\"TimerSlackNS\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"CPUSchedulingResetOnFork\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"NonBlocking\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"StandardInput\" type=\"s\" access=\"read\"/>\n" \
@@ -39,27 +62,50 @@
         "  <property name=\"TTYPath\" type=\"s\" access=\"read\"/>\n"   \
         "  <property name=\"SyslogPriority\" type=\"i\" access=\"read\"/>\n" \
         "  <property name=\"SyslogIdentifier\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"SyslogNoPrefix\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"Capabilities\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"SecureBits\" type=\"i\" access=\"read\"/>\n" \
         "  <property name=\"CapabilityBoundingSetDrop\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"User\" type=\"s\" access=\"read\"/>\n"      \
         "  <property name=\"Group\" type=\"s\" access=\"read\"/>\n"     \
         "  <property name=\"SupplementaryGroups\" type=\"as\" access=\"read\"/>\n" \
         "  <property name=\"TCPWrapName\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"PAMName\" type=\"s\" access=\"read\"/>\n"
+        "  <property name=\"PAMName\" type=\"s\" access=\"read\"/>\n"   \
+        "  <property name=\"ReadWriteDirectories\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"ReadOnlyDirectories\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"InaccessibleDirectories\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"MountFlags\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"PrivateTmp\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"NoSetSID\" type=\"b\" access=\"read\"/>\n"  \
 
 #define BUS_EXEC_CONTEXT_PROPERTIES(interface, context)                 \
         { interface, "Environment",                   bus_property_append_strv,   "as",    (context).environment                   }, \
         { interface, "UMask",                         bus_property_append_mode,   "u",     &(context).umask                        }, \
-            /* RLimits */                                               \
+        { interface, "LimitCPU",                      bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitFSIZE",                    bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitDATA",                     bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitSTACK",                    bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitCORE",                     bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitRSS",                      bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitNOFILE",                   bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitAS",                       bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitNPROC",                    bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitMEMLOCK",                  bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitLOCKS",                    bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitSIGPENDING",               bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitMSGQUEUE",                 bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitNICE",                     bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitRTPRIO",                   bus_execute_append_rlimits, "t",     &(context)                              }, \
+        { interface, "LimitRTTIME",                   bus_execute_append_rlimits, "t",     &(context)                              }, \
         { interface, "WorkingDirectory",              bus_property_append_string, "s",     (context).working_directory             }, \
         { interface, "RootDirectory",                 bus_property_append_string, "s",     (context).root_directory                }, \
-            /* OOM Adjust */                                            \
-            /* Nice */                                                  \
-            /* IOPrio */                                                \
-            /* CPUSchedPolicy */                                        \
-            /* CPUSchedPriority */                                      \
-            /* CPUAffinity */                                           \
-            /* TimerSlackNS */                                          \
+        { interface, "OOMAdjust",                     bus_execute_append_oom_adjust, "i",  &(context)                              }, \
+        { interface, "Nice",                          bus_execute_append_nice,    "i",     &(context)                              }, \
+        { interface, "IOScheduling",                  bus_execute_append_ioprio,  "i",     &(context)                              }, \
+        { interface, "CPUSchedulingPolicy",           bus_execute_append_cpu_sched_policy, "i", &(context)                         }, \
+        { interface, "CPUSchedulingPriority",         bus_execute_append_cpu_sched_priority, "i", &(context)                       }, \
+        { interface, "CPUAffinity",                   bus_execute_append_affinity,"ay",    &(context)                              }, \
+        { interface, "TimerSlackNS",                  bus_execute_append_timer_slack_ns, "t", &(context)                           }, \
         { interface, "CPUSchedulingResetOnFork",      bus_property_append_bool,   "b",     &(context).cpu_sched_reset_on_fork      }, \
         { interface, "NonBlocking",                   bus_property_append_bool,   "b",     &(context).non_blocking                 }, \
         { interface, "StandardInput",                 bus_execute_append_input,   "s",     &(context).std_input                    }, \
@@ -68,16 +114,32 @@
         { interface, "TTYPath",                       bus_property_append_string, "s",     (context).tty_path                      }, \
         { interface, "SyslogPriority",                bus_property_append_int,    "i",     &(context).syslog_priority              }, \
         { interface, "SyslogIdentifier",              bus_property_append_string, "s",     (context).syslog_identifier             }, \
-            /* CAPABILITIES */                                          \
+        { interface, "SyslogNoPrefix",                bus_property_append_bool,   "b",     &(context).syslog_no_prefix             }, \
+        { interface, "Capabilities",                  bus_property_append_string, "s",     (context).capabilities                  }, \
         { interface, "SecureBits",                    bus_property_append_int,    "i",     &(context).secure_bits                  }, \
         { interface, "CapabilityBoundingSetDrop",     bus_property_append_uint64, "t",     &(context).capability_bounding_set_drop }, \
         { interface, "User",                          bus_property_append_string, "s",     (context).user                          }, \
         { interface, "Group",                         bus_property_append_string, "s",     (context).group                         }, \
         { interface, "SupplementaryGroups",           bus_property_append_strv,   "as",    (context).supplementary_groups          }, \
         { interface, "TCPWrapName",                   bus_property_append_string, "s",     (context).tcpwrap_name                  }, \
-        { interface, "PAMName",                       bus_property_append_string, "s",     (context).pam_name                      }
+        { interface, "PAMName",                       bus_property_append_string, "s",     (context).pam_name                      }, \
+        { interface, "ReadWriteDirectories",          bus_property_append_strv,   "as",    (context).read_write_dirs               }, \
+        { interface, "ReadOnlyDirectories",           bus_property_append_strv,   "as",    (context).read_only_dirs                }, \
+        { interface, "InaccessibleDirectories",       bus_property_append_strv,   "as",    (context).inaccessible_dirs             }, \
+        { interface, "MountFlags",                    bus_property_append_ul,     "t",     &(context).mount_flags                  }, \
+        { interface, "PrivateTmp",                    bus_property_append_bool,   "b",     &(context).private_tmp                  }, \
+        { interface, "NoSetSID",                      bus_property_append_bool,   "b",     &(context).no_setsid                    }
 
 int bus_execute_append_output(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_execute_append_input(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_oom_adjust(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_nice(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_ioprio(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_cpu_sched_policy(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_cpu_sched_priority(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_affinity(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_timer_slack_ns(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_capabilities(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_rlimits(Manager *m, DBusMessageIter *i, const char *property, void *data);
 
 #endif
diff --git a/src/dbus.c b/src/dbus.c
index 3a6d79f..405ea46 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -1473,6 +1473,22 @@ int bus_property_append_size(Manager *m, DBusMessageIter *i, const char *propert
         return 0;
 }
 
+int bus_property_append_ul(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        uint64_t u;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(data);
+
+        u = (uint64_t) *(unsigned long*) data;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
+                return -ENOMEM;
+
+        return 0;
+}
+
 int bus_parse_strv(DBusMessage *m, char ***_l) {
         DBusMessageIter iter, sub;
         unsigned n = 0, i = 0;
diff --git a/src/dbus.h b/src/dbus.h
index 91132fd..ccee74f 100644
--- a/src/dbus.h
+++ b/src/dbus.h
@@ -78,6 +78,7 @@ int bus_property_append_int32(Manager *m, DBusMessageIter *i, const char *proper
 int bus_property_append_uint32(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_property_append_uint64(Manager *m, DBusMessageIter *i, const char *property, void *data);
 int bus_property_append_size(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_ul(Manager *m, DBusMessageIter *i, const char *property, void *data);
 
 #define bus_property_append_int bus_property_append_int32
 #define bus_property_append_pid bus_property_append_uint32
diff --git a/src/execute.c b/src/execute.c
index 9ded1c7..0bdd600 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -1071,8 +1071,8 @@ int exec_spawn(ExecCommand *command,
                         }
                 }
 
-                if (context->cpu_affinity_set)
-                        if (sched_setaffinity(0, sizeof(context->cpu_affinity), &context->cpu_affinity) < 0) {
+                if (context->cpuset)
+                        if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
                                 r = EXIT_CPUAFFINITY;
                                 goto fail;
                         }
@@ -1350,6 +1350,9 @@ void exec_context_done(ExecContext *c) {
 
         strv_free(c->inaccessible_dirs);
         c->inaccessible_dirs = NULL;
+
+        if (c->cpuset)
+                CPU_FREE(c->cpuset);
 }
 
 void exec_command_done(ExecCommand *c) {
@@ -1458,10 +1461,10 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                         prefix, c->cpu_sched_priority,
                         prefix, yes_no(c->cpu_sched_reset_on_fork));
 
-        if (c->cpu_affinity_set) {
+        if (c->cpuset) {
                 fprintf(f, "%sCPUAffinity:", prefix);
-                for (i = 0; i < CPU_SETSIZE; i++)
-                        if (CPU_ISSET(i, &c->cpu_affinity))
+                for (i = 0; i < c->cpuset_ncpus; i++)
+                        if (CPU_ISSET_S(i, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset))
                                 fprintf(f, " %i", i);
                 fputs("\n", f);
         }
diff --git a/src/execute.h b/src/execute.h
index 841670a..9fb48e6 100644
--- a/src/execute.h
+++ b/src/execute.h
@@ -93,7 +93,8 @@ struct ExecContext {
         int cpu_sched_policy;
         int cpu_sched_priority;
 
-        cpu_set_t cpu_affinity;
+        cpu_set_t *cpuset;
+        unsigned cpuset_ncpus;
         unsigned long timer_slack_ns;
 
         ExecInput std_input;
@@ -134,7 +135,6 @@ struct ExecContext {
         bool nice_set:1;
         bool ioprio_set:1;
         bool cpu_sched_set:1;
-        bool cpu_affinity_set:1;
         bool timer_slack_ns_set:1;
 
         /* This is not exposed to the user but available
@@ -142,7 +142,7 @@ struct ExecContext {
          * /bin/mount it is run in the same process group as us so
          * that the autofs logic detects that it belongs to us and we
          * don't enter a trigger loop. */
-        bool no_setsid:1;
+        bool no_setsid;
 };
 
 typedef enum ExitStatus {
diff --git a/src/load-fragment.c b/src/load-fragment.c
index e5c7ba2..a5ea0e4 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -725,19 +725,21 @@ static int config_parse_cpu_affinity(
                 if (!(t = strndup(w, l)))
                         return -ENOMEM;
 
+                if (!(c->cpuset))
+                        if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
+                                return -ENOMEM;
+
                 r = safe_atou(t, &cpu);
                 free(t);
 
-                if (r < 0 || cpu >= CPU_SETSIZE) {
+                if (r < 0 || cpu >= c->cpuset_ncpus) {
                         log_error("[%s:%u] Failed to parse CPU affinity: %s", filename, line, rvalue);
                         return -EBADMSG;
                 }
 
-                CPU_SET(cpu, &c->cpu_affinity);
+                CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
         }
 
-        c->cpu_affinity_set = true;
-
         return 0;
 }
 
diff --git a/src/missing.h b/src/missing.h
index 3b4cb9c..602d44a 100644
--- a/src/missing.h
+++ b/src/missing.h
@@ -27,6 +27,7 @@
 #include <sys/resource.h>
 #include <sys/syscall.h>
 #include <fcntl.h>
+#include <unistd.h>
 
 #ifndef RLIMIT_RTTIME
 #define RLIMIT_RTTIME 15
diff --git a/src/systemctl.c b/src/systemctl.c
index 66d6ef0..392ecf2 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -1111,7 +1111,29 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                         }
 
                         return 0;
+                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
+                        DBusMessageIter sub;
+
+                        dbus_message_iter_recurse(iter, &sub);
+
+                        if (arg_all ||
+                            dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                                printf("%s=", name);
+
+                                while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                                        uint8_t u;
 
+                                        assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
+                                        dbus_message_iter_get_basic(&sub, &u);
+                                        printf("%02x", u);
+
+                                        dbus_message_iter_next(&sub);
+                                }
+
+                                puts("");
+                        }
+
+                        return 0;
                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
                         DBusMessageIter sub, sub2;
 
diff --git a/src/util.c b/src/util.c
index b66eb46..ea8bfc1 100644
--- a/src/util.c
+++ b/src/util.c
@@ -2538,6 +2538,34 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
         return 0;
 }
 
+cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
+        cpu_set_t *r;
+        unsigned n = 1024;
+
+        /* Allocates the cpuset in the right size */
+
+        for (;;) {
+                if (!(r = CPU_ALLOC(n)))
+                        return NULL;
+
+                if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) {
+                        CPU_ZERO_S(CPU_ALLOC_SIZE(n), r);
+
+                        if (ncpus)
+                                *ncpus = n;
+
+                        return r;
+                }
+
+                CPU_FREE(r);
+
+                if (errno != EINVAL)
+                        return NULL;
+
+                n *= 2;
+        }
+}
+
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",
diff --git a/src/util.h b/src/util.h
index eda8e5c..50bac6e 100644
--- a/src/util.h
+++ b/src/util.h
@@ -29,6 +29,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <signal.h>
+#include <sched.h>
 
 #include "macro.h"
 
@@ -284,6 +285,8 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
 
 int rm_rf(const char *path, bool only_dirs, bool delete_root);
 
+cpu_set_t* cpu_set_malloc(unsigned *ncpus);
+
 const char *ioprio_class_to_string(int i);
 int ioprio_class_from_string(const char *s);
 
commit d264aa332a016501ae164a4316f0acc7da0636f4
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 05:14:30 2010 +0200

    dbus: complete coverage of service units

diff --git a/src/dbus-service.c b/src/dbus-service.c
index 283932c..84c4730 100644
--- a/src/dbus-service.c
+++ b/src/dbus-service.c
@@ -30,6 +30,7 @@
         "  <property name=\"Type\" type=\"s\" access=\"read\"/>\n"      \
         "  <property name=\"Restart\" type=\"s\" access=\"read\"/>\n"   \
         "  <property name=\"PIDFile\" type=\"s\" access=\"read\"/>\n"   \
+        "  <property name=\"NotifyAccess\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"RestartUSec\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
         BUS_EXEC_CONTEXT_INTERFACE                                      \
@@ -39,6 +40,8 @@
         "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n"  \
         "  <property name=\"MainPID\" type=\"u\" access=\"read\"/>\n"   \
         "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"SysVStartPriority\" type=\"i\" access=\"read\"/>\n" \
+        "  <property name=\"SysVRunLevels\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"SysVPath\" type=\"s\" access=\"read\"/>\n"  \
         "  <property name=\"BusName\" type=\"s\" access=\"read\"/>\n"   \
         "  <property name=\"StatusText\" type=\"s\" access=\"read\"/>\n" \
@@ -57,27 +60,31 @@ const char bus_service_interface[] = BUS_SERVICE_INTERFACE;
 
 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_type, service_type, ServiceType);
 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_restart, service_restart, ServiceRestart);
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_notify_access, notify_access, NotifyAccess);
 
 DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connection, DBusMessage *message) {
         const BusProperty properties[] = {
                 BUS_UNIT_PROPERTIES,
-                { "org.freedesktop.systemd1.Service", "Type",                   bus_service_append_type,    "s", &u->service.type },
-                { "org.freedesktop.systemd1.Service", "Restart",                bus_service_append_restart, "s", &u->service.restart },
-                { "org.freedesktop.systemd1.Service", "PIDFile",                bus_property_append_string, "s", u->service.pid_file },
-                { "org.freedesktop.systemd1.Service", "RestartUSec",            bus_property_append_usec,   "t", &u->service.restart_usec },
-                { "org.freedesktop.systemd1.Service", "TimeoutUSec",            bus_property_append_usec,   "t", &u->service.timeout_usec },
+                { "org.freedesktop.systemd1.Service", "Type",                   bus_service_append_type,    "s", &u->service.type                      },
+                { "org.freedesktop.systemd1.Service", "Restart",                bus_service_append_restart, "s", &u->service.restart                   },
+                { "org.freedesktop.systemd1.Service", "PIDFile",                bus_property_append_string, "s", u->service.pid_file                   },
+                { "org.freedesktop.systemd1.Service", "NotifyAccess",           bus_service_append_notify_access, "s", &u->service.notify_access       },
+                { "org.freedesktop.systemd1.Service", "RestartUSec",            bus_property_append_usec,   "t", &u->service.restart_usec              },
+                { "org.freedesktop.systemd1.Service", "TimeoutUSec",            bus_property_append_usec,   "t", &u->service.timeout_usec              },
                 /* ExecCommand */
                 BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Service", u->service.exec_context),
-                { "org.freedesktop.systemd1.Service", "PermissionsStartOnly",   bus_property_append_bool,   "b", &u->service.permissions_start_only },
+                { "org.freedesktop.systemd1.Service", "PermissionsStartOnly",   bus_property_append_bool,   "b", &u->service.permissions_start_only    },
                 { "org.freedesktop.systemd1.Service", "RootDirectoryStartOnly", bus_property_append_bool,   "b", &u->service.root_directory_start_only },
-                { "org.freedesktop.systemd1.Service", "ValidNoProcess",         bus_property_append_bool,   "b", &u->service.valid_no_process },
-                { "org.freedesktop.systemd1.Service", "KillMode",               bus_unit_append_kill_mode,  "s", &u->service.kill_mode },
+                { "org.freedesktop.systemd1.Service", "ValidNoProcess",         bus_property_append_bool,   "b", &u->service.valid_no_process          },
+                { "org.freedesktop.systemd1.Service", "KillMode",               bus_unit_append_kill_mode,  "s", &u->service.kill_mode                 },
                 /* MainExecStatus */
-                { "org.freedesktop.systemd1.Service", "MainPID",                bus_property_append_pid,    "u", &u->service.main_pid },
-                { "org.freedesktop.systemd1.Service", "ControlPID",             bus_property_append_pid,    "u", &u->service.control_pid },
-                { "org.freedesktop.systemd1.Service", "SysVPath",               bus_property_append_string, "s", u->service.sysv_path },
-                { "org.freedesktop.systemd1.Service", "BusName",                bus_property_append_string, "s", u->service.bus_name },
-                { "org.freedesktop.systemd1.Service", "StatusText",             bus_property_append_string, "s", u->service.status_text },
+                { "org.freedesktop.systemd1.Service", "MainPID",                bus_property_append_pid,    "u", &u->service.main_pid                  },
+                { "org.freedesktop.systemd1.Service", "ControlPID",             bus_property_append_pid,    "u", &u->service.control_pid               },
+                { "org.freedesktop.systemd1.Service", "SysVPath",               bus_property_append_string, "s", u->service.sysv_path                  },
+                { "org.freedesktop.systemd1.Service", "BusName",                bus_property_append_string, "s", u->service.bus_name                   },
+                { "org.freedesktop.systemd1.Service", "StatusText",             bus_property_append_string, "s", u->service.status_text                },
+                { "org.freedesktop.systemd1.Service", "SysVRunLevels",          bus_property_append_string, "s", u->service.sysv_runlevels             },
+                { "org.freedesktop.systemd1.Service", "SysVStartPriority",      bus_property_append_int,    "i", &u->service.sysv_start_priority       },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 
commit 4e1e43c8f066c356aa5337156a1501b8ae4aef04
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 05:07:31 2010 +0200

    dbus: complete socket unit coverage

diff --git a/src/dbus-socket.c b/src/dbus-socket.c
index cadb904..5f195a1 100644
--- a/src/dbus-socket.c
+++ b/src/dbus-socket.c
@@ -46,6 +46,9 @@
         "  <property name=\"PipeSize\" type=\"t\" access=\"read\"/>\n"  \
         "  <property name=\"FreeBind\" type=\"b\" access=\"read\"/>\n"  \
         "  <property name=\"Mark\" type=\"i\" access=\"read\"/>\n"      \
+        "  <property name=\"MaxConnections\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"NAccepted\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"NConnections\" type=\"u\" access=\"read\"/>\n" \
         " </interface>\n"                                               \
 
 #define INTROSPECTION                                                   \
@@ -64,26 +67,29 @@ static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_socket_append_bind_ipv6_only, socket_
 DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
         const BusProperty properties[] = {
                 BUS_UNIT_PROPERTIES,
-                { "org.freedesktop.systemd1.Socket", "BindIPv6Only",  bus_socket_append_bind_ipv6_only, "s", &u->socket.bind_ipv6_only },
-                { "org.freedesktop.systemd1.Socket", "Backlog",       bus_property_append_unsigned, "u", &u->socket.backlog },
-                { "org.freedesktop.systemd1.Socket", "TimeoutUSec",   bus_property_append_usec,     "t", &u->socket.timeout_usec },
+                { "org.freedesktop.systemd1.Socket", "BindIPv6Only",   bus_socket_append_bind_ipv6_only, "s", &u->socket.bind_ipv6_only  },
+                { "org.freedesktop.systemd1.Socket", "Backlog",        bus_property_append_unsigned,     "u", &u->socket.backlog         },
+                { "org.freedesktop.systemd1.Socket", "TimeoutUSec",    bus_property_append_usec,         "t", &u->socket.timeout_usec    },
                 /* ExecCommand */
                 BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Socket", u->socket.exec_context),
-                { "org.freedesktop.systemd1.Socket", "KillMode",      bus_unit_append_kill_mode,    "s", &u->socket.kill_mode },
-                { "org.freedesktop.systemd1.Socket", "ControlPID",    bus_property_append_pid,      "u", &u->socket.control_pid },
-                { "org.freedesktop.systemd1.Socket", "BindToDevice",  bus_property_append_string,   "s", u->socket.bind_to_device },
-                { "org.freedesktop.systemd1.Socket", "DirectoryMode", bus_property_append_mode,     "u", &u->socket.directory_mode },
-                { "org.freedesktop.systemd1.Socket", "SocketMode",    bus_property_append_mode,     "u", &u->socket.socket_mode },
-                { "org.freedesktop.systemd1.Socket", "Accept",        bus_property_append_bool,     "b", &u->socket.accept },
-                { "org.freedesktop.systemd1.Socket", "KeepAlive",     bus_property_append_bool,     "b", &u->socket.keep_alive },
-                { "org.freedesktop.systemd1.Socket", "Priority",      bus_property_append_int,      "i", &u->socket.priority },
-                { "org.freedesktop.systemd1.Socket", "ReceiveBuffer", bus_property_append_size,     "t", &u->socket.receive_buffer },
-                { "org.freedesktop.systemd1.Socket", "SendBuffer",    bus_property_append_size,     "t", &u->socket.send_buffer },
-                { "org.freedesktop.systemd1.Socket", "IPTOS",         bus_property_append_int,      "i", &u->socket.ip_tos },
-                { "org.freedesktop.systemd1.Socket", "IPTTL",         bus_property_append_int,      "i", &u->socket.ip_ttl },
-                { "org.freedesktop.systemd1.Socket", "PipeSize",      bus_property_append_size,     "t", &u->socket.pipe_size },
-                { "org.freedesktop.systemd1.Socket", "FreeBind",      bus_property_append_bool,     "b", &u->socket.free_bind },
-                { "org.freedesktop.systemd1.Socket", "Mark",          bus_property_append_int,      "i", &u->socket.mark },
+                { "org.freedesktop.systemd1.Socket", "KillMode",       bus_unit_append_kill_mode,        "s", &u->socket.kill_mode       },
+                { "org.freedesktop.systemd1.Socket", "ControlPID",     bus_property_append_pid,          "u", &u->socket.control_pid     },
+                { "org.freedesktop.systemd1.Socket", "BindToDevice",   bus_property_append_string,       "s", u->socket.bind_to_device   },
+                { "org.freedesktop.systemd1.Socket", "DirectoryMode",  bus_property_append_mode,         "u", &u->socket.directory_mode  },
+                { "org.freedesktop.systemd1.Socket", "SocketMode",     bus_property_append_mode,         "u", &u->socket.socket_mode     },
+                { "org.freedesktop.systemd1.Socket", "Accept",         bus_property_append_bool,         "b", &u->socket.accept          },
+                { "org.freedesktop.systemd1.Socket", "KeepAlive",      bus_property_append_bool,         "b", &u->socket.keep_alive      },
+                { "org.freedesktop.systemd1.Socket", "Priority",       bus_property_append_int,          "i", &u->socket.priority        },
+                { "org.freedesktop.systemd1.Socket", "ReceiveBuffer",  bus_property_append_size,         "t", &u->socket.receive_buffer  },
+                { "org.freedesktop.systemd1.Socket", "SendBuffer",     bus_property_append_size,         "t", &u->socket.send_buffer     },
+                { "org.freedesktop.systemd1.Socket", "IPTOS",          bus_property_append_int,          "i", &u->socket.ip_tos          },
+                { "org.freedesktop.systemd1.Socket", "IPTTL",          bus_property_append_int,          "i", &u->socket.ip_ttl          },
+                { "org.freedesktop.systemd1.Socket", "PipeSize",       bus_property_append_size,         "t", &u->socket.pipe_size       },
+                { "org.freedesktop.systemd1.Socket", "FreeBind",       bus_property_append_bool,         "b", &u->socket.free_bind       },
+                { "org.freedesktop.systemd1.Socket", "Mark",           bus_property_append_int,          "i", &u->socket.mark            },
+                { "org.freedesktop.systemd1.Socket", "MaxConnections", bus_property_append_unsigned,     "u", &u->socket.max_connections },
+                { "org.freedesktop.systemd1.Socket", "NConnections",   bus_property_append_unsigned,     "u", &u->socket.n_connections   },
+                { "org.freedesktop.systemd1.Socket", "NAccepted",      bus_property_append_unsigned,     "u", &u->socket.n_accepted      },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 
commit 6681ad4d4164d59175064c42f90dd0641bfa66fd
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 05:01:36 2010 +0200

    dbus: complete target unit coverage

diff --git a/src/dbus-target.c b/src/dbus-target.c
index fb84430..c109d9a 100644
--- a/src/dbus-target.c
+++ b/src/dbus-target.c
@@ -19,11 +19,14 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <errno.h>
+
 #include "dbus-unit.h"
 #include "dbus-target.h"
 
 #define BUS_TARGET_INTERFACE                                            \
         " <interface name=\"org.freedesktop.systemd1.Target\">\n"       \
+        "  <property name=\"SysVRunLevel\" type=\"s\" access=\"read\"/>\n" \
         " </interface>\n"
 
 #define INTROSPECTION                                                   \
@@ -37,9 +40,31 @@
 
 const char bus_target_interface[] = BUS_TARGET_INTERFACE;
 
+static int bus_target_append_runlevel(Manager *n, DBusMessageIter *i, const char *property, void *data) {
+        Target *t = data;
+        const char *d;
+        char buf[2];
+
+        assert(n);
+        assert(i);
+        assert(property);
+        assert(t);
+
+        buf[0] = (char) target_get_runlevel(t);
+        buf[1] = 0;
+
+        d = buf;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
+                return -ENOMEM;
+
+        return 0;
+}
+
 DBusHandlerResult bus_target_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
         const BusProperty properties[] = {
                 BUS_UNIT_PROPERTIES,
+                { "org.freedesktop.systemd1.Target", "SysVRunLevel", bus_target_append_runlevel, "s", u },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 
commit 5bd0707340570f48675a53f5dec8dd34b162e415
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 04:55:33 2010 +0200

    dbus: complete automount and mount unit coverage

diff --git a/src/dbus-automount.c b/src/dbus-automount.c
index 61732f9..ada2d22 100644
--- a/src/dbus-automount.c
+++ b/src/dbus-automount.c
@@ -25,6 +25,7 @@
 #define BUS_AUTOMOUNT_INTERFACE                                      \
         " <interface name=\"org.freedesktop.systemd1.Automount\">\n" \
         "  <property name=\"Where\" type=\"s\" access=\"read\"/>\n"  \
+        "  <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
         " </interface>\n"
 
 #define INTROSPECTION                                                \
@@ -41,7 +42,8 @@ const char bus_automount_interface[] = BUS_AUTOMOUNT_INTERFACE;
 DBusHandlerResult bus_automount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
         const BusProperty properties[] = {
                 BUS_UNIT_PROPERTIES,
-                { "org.freedesktop.systemd1.Automount", "Where", bus_property_append_string, "s", u->automount.where },
+                { "org.freedesktop.systemd1.Automount", "Where", bus_property_append_string,       "s", u->automount.where           },
+                { "org.freedesktop.systemd1.Automount", "DirectoryMode", bus_property_append_mode, "u", &u->automount.directory_mode },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 
diff --git a/src/dbus-mount.c b/src/dbus-mount.c
index 0f417e7..5e17ec2 100644
--- a/src/dbus-mount.c
+++ b/src/dbus-mount.c
@@ -35,6 +35,7 @@
         BUS_EXEC_CONTEXT_INTERFACE                                      \
         "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n"  \
         "  <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
+        "  <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
         " </interface>\n"
 
 #define INTROSPECTION                                                   \
@@ -123,15 +124,16 @@ static int bus_mount_append_type(Manager *n, DBusMessageIter *i, const char *pro
 DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
         const BusProperty properties[] = {
                 BUS_UNIT_PROPERTIES,
-                { "org.freedesktop.systemd1.Mount", "Where",       bus_property_append_string, "s", u->mount.where         },
-                { "org.freedesktop.systemd1.Mount", "What",        bus_mount_append_what,      "s", u                      },
-                { "org.freedesktop.systemd1.Mount", "Options",     bus_mount_append_options,   "s", u                      },
-                { "org.freedesktop.systemd1.Mount", "Type",        bus_mount_append_type,      "s", u                      },
-                { "org.freedesktop.systemd1.Mount", "TimeoutUSec", bus_property_append_usec,   "t", &u->mount.timeout_usec },
+                { "org.freedesktop.systemd1.Mount", "Where",         bus_property_append_string, "s", u->mount.where         },
+                { "org.freedesktop.systemd1.Mount", "What",          bus_mount_append_what,      "s", u                      },
+                { "org.freedesktop.systemd1.Mount", "Options",       bus_mount_append_options,   "s", u                      },
+                { "org.freedesktop.systemd1.Mount", "Type",          bus_mount_append_type,      "s", u                      },
+                { "org.freedesktop.systemd1.Mount", "TimeoutUSec",   bus_property_append_usec,   "t", &u->mount.timeout_usec },
                 /* ExecCommand */
                 BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Mount", u->mount.exec_context),
-                { "org.freedesktop.systemd1.Mount", "KillMode",    bus_unit_append_kill_mode,  "s", &u->mount.kill_mode    },
-                { "org.freedesktop.systemd1.Mount", "ControlPID",  bus_property_append_pid,    "u", &u->mount.control_pid  },
+                { "org.freedesktop.systemd1.Mount", "KillMode",      bus_unit_append_kill_mode,  "s", &u->mount.kill_mode    },
+                { "org.freedesktop.systemd1.Mount", "ControlPID",    bus_property_append_pid,    "u", &u->mount.control_pid  },
+                { "org.freedesktop.systemd1.Mount", "DirectoryMode", bus_property_append_mode,   "u", &u->mount.directory_mode },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 
diff --git a/src/systemctl.c b/src/systemctl.c
index dddd689..66d6ef0 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -1039,7 +1039,7 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                 uint32_t u;
                 dbus_message_iter_get_basic(iter, &u);
 
-                if (strstr(name, "UMask"))
+                if (strstr(name, "UMask") || strstr(name, "Mode"))
                         printf("%s=%04o\n", name, u);
                 else
                         printf("%s=%u\n", name, (unsigned) u);
commit f295f5c0c0a31afd1914adf5d8a4d7f51e8e0be0
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 04:47:19 2010 +0200

    dbus: complete coverage of manager interface

diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index f68092a..705a4dc 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -109,6 +109,11 @@
         "  <property name=\"NNames\" type=\"u\" access=\"read\"/>\n"    \
         "  <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n"     \
         "  <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"SysVInitPath\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"SysVRcndPath\" type=\"as\" access=\"read\"/>\n" \
+        "  <property name=\"NotifySocket\" type=\"s\" access=\"read\"/>\n" \
         " </interface>\n"
 
 #define INTROSPECTION_BEGIN                                             \
@@ -189,14 +194,19 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
         Manager *m = data;
 
         const BusProperty properties[] = {
-                { "org.freedesktop.systemd1.Manager", "Version",       bus_property_append_string,    "s", PACKAGE_STRING     },
-                { "org.freedesktop.systemd1.Manager", "RunningAs",     bus_manager_append_running_as, "s", &m->running_as     },
-                { "org.freedesktop.systemd1.Manager", "StartupTimestamp", bus_property_append_uint64, "t", &m->startup_timestamp.realtime },
-                { "org.freedesktop.systemd1.Manager", "LogLevel",      bus_manager_append_log_level,  "s", NULL               },
-                { "org.freedesktop.systemd1.Manager", "LogTarget",     bus_manager_append_log_target, "s", NULL               },
-                { "org.freedesktop.systemd1.Manager", "NNames",        bus_manager_append_n_names,    "u", NULL               },
-                { "org.freedesktop.systemd1.Manager", "NJobs",         bus_manager_append_n_jobs,     "u", NULL               },
-                { "org.freedesktop.systemd1.Manager", "Environment",   bus_property_append_strv,      "as", m->environment    },
+                { "org.freedesktop.systemd1.Manager", "Version",       bus_property_append_string,    "s",  PACKAGE_STRING     },
+                { "org.freedesktop.systemd1.Manager", "RunningAs",     bus_manager_append_running_as, "s",  &m->running_as     },
+                { "org.freedesktop.systemd1.Manager", "StartupTimestamp", bus_property_append_uint64, "t",  &m->startup_timestamp.realtime },
+                { "org.freedesktop.systemd1.Manager", "LogLevel",      bus_manager_append_log_level,  "s",  NULL               },
+                { "org.freedesktop.systemd1.Manager", "LogTarget",     bus_manager_append_log_target, "s",  NULL               },
+                { "org.freedesktop.systemd1.Manager", "NNames",        bus_manager_append_n_names,    "u",  NULL               },
+                { "org.freedesktop.systemd1.Manager", "NJobs",         bus_manager_append_n_jobs,     "u",  NULL               },
+                { "org.freedesktop.systemd1.Manager", "Environment",   bus_property_append_strv,      "as", m->environment     },
+                { "org.freedesktop.systemd1.Manager", "ConfirmSpawn",  bus_property_append_bool,      "b",  &m->confirm_spawn  },
+                { "org.freedesktop.systemd1.Manager", "UnitPath",      bus_property_append_strv,      "as", m->lookup_paths.unit_path },
+                { "org.freedesktop.systemd1.Manager", "SysVInitPath",  bus_property_append_strv,      "as", m->lookup_paths.sysvinit_path },
+                { "org.freedesktop.systemd1.Manager", "SysVRcndPath",  bus_property_append_strv,      "as", m->lookup_paths.sysvrcnd_path },
+                { "org.freedesktop.systemd1.Manager", "NotifySocket",  bus_property_append_string,    "s",  m->notify_socket   },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 
diff --git a/src/manager.h b/src/manager.h
index eed137b..e856f53 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -192,7 +192,7 @@ struct Manager {
 
         bool utmp_reboot_written:1;
 
-        bool confirm_spawn:1;
+        bool confirm_spawn;
 };
 
 int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **m);
commit 707e5e52804a8f041f0d2f822f0bcf7062ad24ac
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 04:37:03 2010 +0200

    dbus: complete coverage of timer units

diff --git a/src/dbus-timer.c b/src/dbus-timer.c
index 68bd8a4..af0ae72 100644
--- a/src/dbus-timer.c
+++ b/src/dbus-timer.c
@@ -27,8 +27,9 @@
 
 #define BUS_TIMER_INTERFACE                                             \
         " <interface name=\"org.freedesktop.systemd1.Timer\">\n"        \
-        "  <property name=\"Unit\" type=\"s\"  access=\"read\"/>\n"     \
-        " </interface>\n"                                               \
+        "  <property name=\"Unit\" type=\"s\" access=\"read\"/>\n"      \
+        "  <property name=\"Timers\" type=\"a(stt)\" access=\"read\"/>\n" \
+        " </interface>\n"
 
 #define INTROSPECTION                                                   \
         DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
@@ -41,10 +42,41 @@
 
 const char bus_timer_interface[] = BUS_TIMER_INTERFACE;
 
+static int bus_timer_append_timers(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        Timer *p = data;
+        DBusMessageIter sub, sub2;
+        TimerValue *k;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(p);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(stt)", &sub))
+                return -ENOMEM;
+
+        LIST_FOREACH(value, k, p->values) {
+                const char *t = timer_base_to_string(k->base);
+
+                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &t) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->value) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->next_elapse) ||
+                    !dbus_message_iter_close_container(&sub, &sub2))
+                        return -ENOMEM;
+        }
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
 DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
         const BusProperty properties[] = {
                 BUS_UNIT_PROPERTIES,
-                { "org.freedesktop.systemd1.Timer", "Unit", bus_property_append_string, "s", &u->timer.unit->meta.id },
+                { "org.freedesktop.systemd1.Timer", "Unit",       bus_property_append_string, "s",      u->timer.unit->meta.id },
+                { "org.freedesktop.systemd1.Timer", "Timers",     bus_timer_append_timers,    "a(stt)", u                      },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 
diff --git a/src/systemctl.c b/src/systemctl.c
index 4620315..dddd689 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -1024,7 +1024,7 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                 /* Yes, heuristics! But we can change this check
                  * should it turn out to not be sufficient */
 
-                if (strstr(name, "Timestamp")) {
+                if (strstr(name, "Timestamp") || strstr(name, "Elapse")) {
                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
 
                         if ((t = format_timestamp(timestamp, sizeof(timestamp), u)) || arg_all)
@@ -1130,6 +1130,26 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                         }
 
                         return 0;
+                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
+                        DBusMessageIter sub, sub2;
+
+                        dbus_message_iter_recurse(iter, &sub);
+
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                                const char *base;
+                                uint64_t value, next_elapse;
+
+                                dbus_message_iter_recurse(&sub, &sub2);
+
+                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0)
+                                        printf("%s=%llu\n", base, (unsigned long long) value);
+
+                                dbus_message_iter_next(&sub);
+                        }
+
+                        return 0;
                 }
 
                 break;
commit e87d1818cdf26b8d946776a2182e4ef2847bc0aa
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 04:24:23 2010 +0200

    systemctl: load unit when introspecting

diff --git a/src/systemctl.c b/src/systemctl.c
index 63d5d9c..4620315 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -1264,7 +1264,7 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                                               "org.freedesktop.systemd1",
                                               "/org/freedesktop/systemd1",
                                               "org.freedesktop.systemd1.Manager",
-                                              "GetUnit"))) {
+                                              "LoadUnit"))) {
                                 log_error("Could not allocate message.");
                                 r = -ENOMEM;
                                 goto finish;
commit a68c7a7ace65354d09e8bb751ae416db4460a20f
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 04:24:07 2010 +0200

    dbus: complete coverage for unit interface

diff --git a/src/dbus-unit.h b/src/dbus-unit.h
index 5662d30..7babb23 100644
--- a/src/dbus-unit.h
+++ b/src/dbus-unit.h
@@ -72,6 +72,8 @@
         "  <property name=\"Job\" type=\"(uo)\" access=\"read\"/>\n"    \
         "  <property name=\"RecursiveStop\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"StopWhenUneeded\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"OnlyByDependency\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"DefaultDependencies\" type=\"b\" access=\"read\"/>\n" \
         "  <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"ControlGroups\" type=\"as\" access=\"read\"/>\n" \
         " </interface>\n"
@@ -104,6 +106,8 @@
         { "org.freedesktop.systemd1.Unit", "Job",                  bus_unit_append_job,            "(uo)", u                                 }, \
         { "org.freedesktop.systemd1.Unit", "RecursiveStop",        bus_property_append_bool,       "b",    &u->meta.recursive_stop           }, \
         { "org.freedesktop.systemd1.Unit", "StopWhenUneeded",      bus_property_append_bool,       "b",    &u->meta.stop_when_unneeded       }, \
+        { "org.freedesktop.systemd1.Unit", "OnlyByDependency",     bus_property_append_bool,       "b",    &u->meta.only_by_dependency       }, \
+        { "org.freedesktop.systemd1.Unit", "DefaultDependencies",  bus_property_append_bool,       "b",    &u->meta.default_dependencies     }, \
         { "org.freedesktop.systemd1.Unit", "DefaultControlGroup",  bus_unit_append_default_cgroup, "s",    u                                 }, \
         { "org.freedesktop.systemd1.Unit", "ControlGroups",        bus_unit_append_cgroups,        "as",   u                                 }
 
commit ebf57b80c37c3931ec7503b63da1a34f702d9cca
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 04:23:48 2010 +0200

    dbus: complete coverage for path units

diff --git a/src/dbus-path.c b/src/dbus-path.c
index 7589f5b..8d58de3 100644
--- a/src/dbus-path.c
+++ b/src/dbus-path.c
@@ -25,26 +25,57 @@
 #include "dbus-path.h"
 #include "dbus-execute.h"
 
-#define BUS_PATH_INTERFACE                                             \
-        " <interface name=\"org.freedesktop.systemd1.Path\">\n"        \
-        "  <property name=\"Unit\" type=\"s\"  access=\"read\"/>\n"     \
-        " </interface>\n"                                               \
+#define BUS_PATH_INTERFACE                                              \
+        " <interface name=\"org.freedesktop.systemd1.Path\">\n"         \
+        "  <property name=\"Unit\" type=\"s\" access=\"read\"/>\n"      \
+        "  <property name=\"Paths\" type=\"a(ss)\" access=\"read\"/>\n" \
+        " </interface>\n"
 
 #define INTROSPECTION                                                   \
         DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
         "<node>\n"                                                      \
         BUS_UNIT_INTERFACE                                              \
-        BUS_PATH_INTERFACE                                             \
+        BUS_PATH_INTERFACE                                              \
         BUS_PROPERTIES_INTERFACE                                        \
         BUS_INTROSPECTABLE_INTERFACE                                    \
         "</node>\n"
 
 const char bus_path_interface[] = BUS_PATH_INTERFACE;
 
+static int bus_path_append_paths(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+        Path *p = data;
+        DBusMessageIter sub, sub2;
+        PathSpec *k;
+
+        assert(m);
+        assert(i);
+        assert(property);
+        assert(p);
+
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &sub))
+                return -ENOMEM;
+
+        LIST_FOREACH(spec, k, p->specs) {
+                const char *t = path_type_to_string(k->type);
+
+                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &t) ||
+                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &k->path) ||
+                    !dbus_message_iter_close_container(&sub, &sub2))
+                        return -ENOMEM;
+        }
+
+        if (!dbus_message_iter_close_container(i, &sub))
+                return -ENOMEM;
+
+        return 0;
+}
+
 DBusHandlerResult bus_path_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
         const BusProperty properties[] = {
                 BUS_UNIT_PROPERTIES,
-                { "org.freedesktop.systemd1.Path", "Unit", bus_property_append_string, "s", &u->path.unit->meta.id },
+                { "org.freedesktop.systemd1.Path", "Unit",  bus_property_append_string, "s",     u->path.unit->meta.id  },
+                { "org.freedesktop.systemd1.Path", "Paths", bus_path_append_paths,      "a(ss)", u                      },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 
diff --git a/src/systemctl.c b/src/systemctl.c
index b66901b..63d5d9c 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -1059,7 +1059,7 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                 DBusMessageIter sub;
                 dbus_message_iter_recurse(iter, &sub);
 
-                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && strstr(name, "Job")) {
+                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
                         uint32_t u;
 
                         dbus_message_iter_get_basic(&sub, &u);
@@ -1070,7 +1070,7 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                                 printf("%s=\n", name);
 
                         return 0;
-                } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && strstr(name, "Unit")) {
+                } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
                         const char *s;
 
                         dbus_message_iter_get_basic(&sub, &s);
@@ -1111,6 +1111,25 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                         }
 
                         return 0;
+
+                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
+                        DBusMessageIter sub, sub2;
+
+                        dbus_message_iter_recurse(iter, &sub);
+
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                                const char *type, *path;
+
+                                dbus_message_iter_recurse(&sub, &sub2);
+
+                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
+                                        printf("%s=%s\n", type, path);
+
+                                dbus_message_iter_next(&sub);
+                        }
+
+                        return 0;
                 }
 
                 break;
commit 48220598fed70bd2c310c52a4f9af9224b87abf4
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 03:43:57 2010 +0200

    systemctl: implement 'show' command

diff --git a/src/systemctl.c b/src/systemctl.c
index 8445430..b66901b 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -43,6 +43,7 @@
 #include "strv.h"
 
 static const char *arg_type = NULL;
+static const char *arg_property = NULL;
 static bool arg_all = false;
 static bool arg_replace = false;
 static bool arg_session = false;
@@ -987,7 +988,332 @@ finish:
         dbus_error_free(&error);
 
         return r;
+}
+
+static int print_property(const char *name, DBusMessageIter *iter) {
+        assert(name);
+        assert(iter);
+
+        if (arg_property && !streq(name, arg_property))
+                return 0;
+
+        switch (dbus_message_iter_get_arg_type(iter)) {
+
+        case DBUS_TYPE_STRING: {
+                const char *s;
+                dbus_message_iter_get_basic(iter, &s);
+
+                if (arg_all || s[0])
+                        printf("%s=%s\n", name, s);
+
+                return 0;
+        }
+
+        case DBUS_TYPE_BOOLEAN: {
+                dbus_bool_t b;
+                dbus_message_iter_get_basic(iter, &b);
+                printf("%s=%s\n", name, yes_no(b));
+
+                return 0;
+        }
+
+        case DBUS_TYPE_UINT64: {
+                uint64_t u;
+                dbus_message_iter_get_basic(iter, &u);
+
+                /* Yes, heuristics! But we can change this check
+                 * should it turn out to not be sufficient */
+
+                if (strstr(name, "Timestamp")) {
+                        char timestamp[FORMAT_TIMESTAMP_MAX], *t;
+
+                        if ((t = format_timestamp(timestamp, sizeof(timestamp), u)) || arg_all)
+                                printf("%s=%s\n", name, strempty(t));
+                } else
+                        printf("%s=%llu\n", name, (unsigned long long) u);
+
+                return 0;
+        }
+
+        case DBUS_TYPE_UINT32: {
+                uint32_t u;
+                dbus_message_iter_get_basic(iter, &u);
+
+                if (strstr(name, "UMask"))
+                        printf("%s=%04o\n", name, u);
+                else
+                        printf("%s=%u\n", name, (unsigned) u);
+
+                return 0;
+        }
+
+        case DBUS_TYPE_INT32: {
+                int32_t i;
+                dbus_message_iter_get_basic(iter, &i);
+
+                printf("%s=%i\n", name, (int) i);
+                return 0;
+        }
+
+        case DBUS_TYPE_STRUCT: {
+                DBusMessageIter sub;
+                dbus_message_iter_recurse(iter, &sub);
+
+                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && strstr(name, "Job")) {
+                        uint32_t u;
+
+                        dbus_message_iter_get_basic(&sub, &u);
+
+                        if (u)
+                                printf("%s=%u\n", name, (unsigned) u);
+                        else if (arg_all)
+                                printf("%s=\n", name);
+
+                        return 0;
+                } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && strstr(name, "Unit")) {
+                        const char *s;
+
+                        dbus_message_iter_get_basic(&sub, &s);
+
+                        if (arg_all || s[0])
+                                printf("%s=%s\n", name, s);
+
+                        return 0;
+                }
+
+                break;
+        }
+
+        case DBUS_TYPE_ARRAY:
+
+                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
+                        DBusMessageIter sub;
+                        bool space = false;
+
+                        dbus_message_iter_recurse(iter, &sub);
+
+                        if (arg_all ||
+                            dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                                printf("%s=", name);
+
+                                while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                                        const char *s;
+
+                                        assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
+                                        dbus_message_iter_get_basic(&sub, &s);
+                                        printf("%s%s", space ? " " : "", s);
+
+                                        space = true;
+                                        dbus_message_iter_next(&sub);
+                                }
+
+                                puts("");
+                        }
+
+                        return 0;
+                }
+
+                break;
+        }
+
+        if (arg_all)
+                printf("%s=[unprintable]\n", name);
+
+        return 0;
+}
+
+static int show_one(DBusConnection *bus, const char *path) {
+        DBusMessage *m = NULL, *reply = NULL;
+        const char *interface = "";
+        int r;
+        DBusError error;
+        DBusMessageIter iter, sub, sub2, sub3;
+
+        assert(bus);
+        assert(path);
+
+        dbus_error_init(&error);
+
+        if (!(m = dbus_message_new_method_call(
+                              "org.freedesktop.systemd1",
+                              path,
+                              "org.freedesktop.DBus.Properties",
+                              "GetAll"))) {
+                log_error("Could not allocate message.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_STRING, &interface,
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Could not append arguments to message.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
+                log_error("Failed to issue method call: %s", error.message);
+                r = -EIO;
+                goto finish;
+        }
+
+        if (!dbus_message_iter_init(reply, &iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
+                log_error("Failed to parse reply.");
+                r = -EIO;
+                goto finish;
+        }
+
+        dbus_message_iter_recurse(&iter, &sub);
+
+        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                const char *name;
+
+                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_recurse(&sub, &sub2);
+
+                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_recurse(&sub2, &sub3);
+
+                if (print_property(name, &sub3) < 0) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_next(&sub);
+        }
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
 
+        dbus_error_free(&error);
+
+        return r;
+}
+
+static int show(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL, *reply = NULL;
+        int r;
+        DBusError error;
+        unsigned i;
+
+        assert(bus);
+        assert(args);
+
+        dbus_error_init(&error);
+
+        if (n <= 1) {
+                /* If not argument is specified inspect the manager
+                 * itself */
+
+                r = show_one(bus, "/org/freedesktop/systemd1");
+                goto finish;
+        }
+
+        for (i = 1; i < n; i++) {
+                const char *path = NULL;
+                uint32_t id;
+
+                if (safe_atou32(args[i], &id) < 0) {
+
+                        if (!(m = dbus_message_new_method_call(
+                                              "org.freedesktop.systemd1",
+                                              "/org/freedesktop/systemd1",
+                                              "org.freedesktop.systemd1.Manager",
+                                              "GetUnit"))) {
+                                log_error("Could not allocate message.");
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        if (!dbus_message_append_args(m,
+                                                      DBUS_TYPE_STRING, &args[i],
+                                                      DBUS_TYPE_INVALID)) {
+                                log_error("Could not append arguments to message.");
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                } else {
+
+                        if (!(m = dbus_message_new_method_call(
+                                              "org.freedesktop.systemd1",
+                                              "/org/freedesktop/systemd1",
+                                              "org.freedesktop.systemd1.Manager",
+                                              "GetJob"))) {
+                                log_error("Could not allocate message.");
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        if (!dbus_message_append_args(m,
+                                                      DBUS_TYPE_UINT32, &id,
+                                                      DBUS_TYPE_INVALID)) {
+                                log_error("Could not append arguments to message.");
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+                }
+
+                if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
+                        log_error("Failed to issue method call: %s", error.message);
+                        r = -EIO;
+                        goto finish;
+                }
+
+                if (!dbus_message_get_args(reply, &error,
+                                           DBUS_TYPE_OBJECT_PATH, &path,
+                                           DBUS_TYPE_INVALID)) {
+                        log_error("Failed to parse reply: %s", error.message);
+                        r = -EIO;
+                        goto finish;
+                }
+
+                if ((r = show_one(bus, path)) < 0)
+                        goto finish;
+
+                dbus_message_unref(m);
+                dbus_message_unref(reply);
+                m = reply = NULL;
+        }
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return r;
 }
 
 static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage *message, void *data) {
@@ -1656,27 +1982,29 @@ static int systemctl_help(void) {
 
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
                "Send control commands to the systemd manager.\n\n"
-               "  -h --help      Show this help\n"
-               "  -t --type=TYPE List only units of a particular type\n"
-               "  -a --all       Show all units, including dead ones\n"
-               "     --replace   When installing a new job, replace existing conflicting ones\n"
-               "     --system    Connect to system bus\n"
-               "     --session   Connect to session bus\n"
-               "  -q --quiet     Suppress output\n"
-               "     --no-block  Do not wait until operation finished\n"
-               "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
+               "  -h --help          Show this help\n"
+               "  -t --type=TYPE     List only units of a particular type\n"
+               "  -p --property=NAME Show only property by this name\n"
+               "  -a --all           Show all units/properties, including dead/empty ones\n"
+               "     --replace       When installing a new job, replace existing conflicting ones\n"
+               "     --system        Connect to system bus\n"
+               "     --session       Connect to session bus\n"
+               "  -q --quiet         Suppress output\n"
+               "     --no-block      Do not wait until operation finished\n"
+               "     --no-wall       Don't send wall message before halt/power-off/reboot\n\n"
                "Commands:\n"
                "  list-units                      List units\n"
-               "  list-jobs                       List jobs\n"
-               "  clear-jobs                      Cancel all jobs\n"
-               "  load [NAME...]                  Load one or more units\n"
-               "  cancel [JOB...]                 Cancel one or more jobs\n"
                "  start [NAME...]                 Start one or more units\n"
                "  stop [NAME...]                  Stop one or more units\n"
                "  restart [NAME...]               Restart one or more units\n"
                "  reload [NAME...]                Reload one or more units\n"
                "  isolate [NAME]                  Start one unit and stop all others\n"
                "  check [NAME...]                 Check whether any of the passed units are active\n"
+               "  show [NAME...|JOB...]           Show information about one or more units\n"
+               "  load [NAME...]                  Load one or more units\n"
+               "  list-jobs                       List jobs\n"
+               "  cancel [JOB...]                 Cancel one or more jobs\n"
+               "  clear-jobs                      Cancel all jobs\n"
                "  monitor                         Monitor unit/job changes\n"
                "  dump                            Dump server status\n"
                "  snapshot [NAME]                 Create a snapshot\n"
@@ -1776,6 +2104,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
         static const struct option options[] = {
                 { "help",      no_argument,       NULL, 'h'          },
                 { "type",      required_argument, NULL, 't'          },
+                { "property",  required_argument, NULL, 'p'          },
                 { "all",       no_argument,       NULL, 'a'          },
                 { "replace",   no_argument,       NULL, ARG_REPLACE  },
                 { "session",   no_argument,       NULL, ARG_SESSION  },
@@ -1791,7 +2120,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "htaq", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "ht:p:aq", options, NULL)) >= 0) {
 
                 switch (c) {
 
@@ -1803,6 +2132,15 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_type = optarg;
                         break;
 
+                case 'p':
+                        arg_property = optarg;
+
+                        /* If the user asked for a particular
+                         * property, show it to him, even if it is
+                         * empty. */
+                        arg_all = true;
+                        break;
+
                 case 'a':
                         arg_all = true;
                         break;
@@ -2343,6 +2681,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
                 { "restart",           MORE,  2, start_unit      },
                 { "isolate",           EQUAL, 2, start_unit      },
                 { "check",             MORE,  2, check_unit      },
+                { "show",              MORE,  1, show            },
                 { "monitor",           EQUAL, 1, monitor         },
                 { "dump",              EQUAL, 1, dump            },
                 { "snapshot",          LESS,  2, snapshot        },
commit 09c661966c31301ced89de93a97e9758a50fe071
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 03:43:20 2010 +0200

    dbus: implement GetAll() with empty interface string properly

diff --git a/src/dbus.c b/src/dbus.c
index 2c2a9cd..3a6d79f 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -1201,7 +1201,6 @@ DBusHandlerResult bus_default_message_handler(Manager *m, DBusConnection *c, DBu
                 const char *interface;
                 const BusProperty *p;
                 DBusMessageIter iter, sub, sub2, sub3;
-                bool any = false;
 
                 if (!dbus_message_get_args(
                             message,
@@ -1219,7 +1218,7 @@ DBusHandlerResult bus_default_message_handler(Manager *m, DBusConnection *c, DBu
                         goto oom;
 
                 for (p = properties; p->property; p++) {
-                        if (!streq(p->interface, interface))
+                        if (interface[0] && !streq(p->interface, interface))
                                 continue;
 
                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
@@ -1239,8 +1238,6 @@ DBusHandlerResult bus_default_message_handler(Manager *m, DBusConnection *c, DBu
                         if (!dbus_message_iter_close_container(&sub2, &sub3) ||
                             !dbus_message_iter_close_container(&sub, &sub2))
                                 goto oom;
-
-                        any = true;
                 }
 
                 if (!dbus_message_iter_close_container(&iter, &sub))
commit 0442c13bfa7bff1e47312606a75f22f75aa4b60d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Jul 4 03:42:55 2010 +0200

    dbus: properly name StartupTimestamp property

diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index b3e42fc..f68092a 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -103,7 +103,7 @@
         "  </signal>"                                                   \
         "  <property name=\"Version\" type=\"s\" access=\"read\"/>\n"   \
         "  <property name=\"RunningAs\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"BootTimestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"StartupTimestamp\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"LogLevel\" type=\"s\" access=\"read\"/>\n"  \
         "  <property name=\"LogTarget\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"NNames\" type=\"u\" access=\"read\"/>\n"    \
@@ -191,12 +191,12 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
         const BusProperty properties[] = {
                 { "org.freedesktop.systemd1.Manager", "Version",       bus_property_append_string,    "s", PACKAGE_STRING     },
                 { "org.freedesktop.systemd1.Manager", "RunningAs",     bus_manager_append_running_as, "s", &m->running_as     },
-                { "org.freedesktop.systemd1.Manager", "BootTimestamp", bus_property_append_uint64,    "t", &m->startup_timestamp.realtime },
+                { "org.freedesktop.systemd1.Manager", "StartupTimestamp", bus_property_append_uint64, "t", &m->startup_timestamp.realtime },
                 { "org.freedesktop.systemd1.Manager", "LogLevel",      bus_manager_append_log_level,  "s", NULL               },
                 { "org.freedesktop.systemd1.Manager", "LogTarget",     bus_manager_append_log_target, "s", NULL               },
                 { "org.freedesktop.systemd1.Manager", "NNames",        bus_manager_append_n_names,    "u", NULL               },
                 { "org.freedesktop.systemd1.Manager", "NJobs",         bus_manager_append_n_jobs,     "u", NULL               },
-                { "org.freedesktop.systemd1.Manager", "Environment",   bus_property_append_strv,      "as", m->environment   },
+                { "org.freedesktop.systemd1.Manager", "Environment",   bus_property_append_strv,      "as", m->environment    },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 


More information about the systemd-commits mailing list