[systemd-commits] 4 commits - fixme Makefile.am src/automount.c src/dbus-automount.c src/dbus.c src/dbus-device.c src/dbus-device.h src/dbus.h src/dbus-job.c src/dbus-manager.c src/dbus-mount.c src/dbus-mount.h src/dbus-path.c src/dbus-service.c src/dbus-service.h src/dbus-snapshot.c src/dbus-socket.c src/dbus-socket.h src/dbus-swap.c src/dbus-swap.h src/dbus-target.c src/dbus-timer.c src/dbus-timer.h src/dbus-unit.c src/dbus-unit.h src/device.c src/execute.c src/execute.h src/label.c src/label.h src/manager.c src/mount.c src/path.c src/service.c src/snapshot.c src/socket.c src/swap.c src/systemadm.vala src/systemctl.c src/systemd-interfaces.vala src/target.c src/timer.c src/unit.h src/util.c src/util.h

Lennart Poettering lennart at kemper.freedesktop.org
Thu Aug 19 17:32:04 PDT 2010


 Makefile.am                 |    4 +
 fixme                       |   12 +---
 src/automount.c             |    1 
 src/dbus-automount.c        |    1 
 src/dbus-device.c           |    5 +
 src/dbus-device.h           |    1 
 src/dbus-job.c              |   11 +++-
 src/dbus-manager.c          |    1 
 src/dbus-mount.c            |   11 ++++
 src/dbus-mount.h            |    1 
 src/dbus-path.c             |    1 
 src/dbus-service.c          |   14 +++++
 src/dbus-service.h          |    1 
 src/dbus-snapshot.c         |    1 
 src/dbus-socket.c           |   11 ++++
 src/dbus-socket.h           |    1 
 src/dbus-swap.c             |    6 ++
 src/dbus-swap.h             |    1 
 src/dbus-target.c           |    1 
 src/dbus-timer.c            |    6 ++
 src/dbus-timer.h            |    1 
 src/dbus-unit.c             |   33 ++++++++++++
 src/dbus-unit.h             |    1 
 src/dbus.c                  |   39 +++++++++++++++
 src/dbus.h                  |   15 +++++
 src/device.c                |    2 
 src/execute.c               |  112 --------------------------------------------
 src/execute.h               |   46 ------------------
 src/label.c                 |   37 ++------------
 src/label.h                 |    2 
 src/manager.c               |    5 +
 src/mount.c                 |    5 +
 src/path.c                  |    1 
 src/service.c               |   17 +++++-
 src/snapshot.c              |    1 
 src/socket.c                |   32 ++++++++----
 src/swap.c                  |    2 
 src/systemadm.vala          |   58 ++++++++++++++++++----
 src/systemctl.c             |   61 ++++++++++++++---------
 src/systemd-interfaces.vala |   46 +++++++++++++-----
 src/target.c                |    1 
 src/timer.c                 |    4 +
 src/unit.h                  |    8 +++
 src/util.c                  |   11 ++++
 src/util.h                  |    4 +
 45 files changed, 368 insertions(+), 267 deletions(-)

New commits:
commit 049f86421bfe8afcbb00c7ee5a76fd14841f8bbf
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Aug 20 02:27:05 2010 +0200

    selinux: properly query policy for FIFO files

diff --git a/src/label.c b/src/label.c
index 21e7ee6..8b80784 100644
--- a/src/label.c
+++ b/src/label.c
@@ -41,31 +41,6 @@ static inline bool use_selinux(void) {
         return use_selinux_ind;
 }
 
-static int label_get_file_label_from_path(
-                const char *label,
-                const char *path,
-                const char *class,
-                security_context_t *fcon) {
-
-        security_context_t dir_con = NULL;
-        security_class_t sclass;
-        int r = 0;
-
-        r = getfilecon(path, &dir_con);
-        if (r >= 0) {
-                r = -1;
-                errno = EINVAL;
-
-                if ((sclass = string_to_security_class(class)) != 0)
-                        r = security_compute_create((security_context_t) label, dir_con, sclass, fcon);
-        }
-        if (r < 0)
-                r = -errno;
-
-        freecon(dir_con);
-        return r;
-}
-
 #endif
 
 int label_init(void) {
@@ -80,7 +55,7 @@ int label_init(void) {
         if (!label_hnd) {
                 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
                          "Failed to initialize SELinux context: %m");
-                r = (security_getenforce() == 1) ? -errno : 0;
+                r = security_getenforce() == 1 ? -errno : 0;
         }
 #endif
 
@@ -109,7 +84,7 @@ int label_fix(const char *path) {
         if (r < 0) {
                 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
                          "Unable to fix label of %s: %m", path);
-                r = (security_getenforce() == 1) ? -errno : 0;
+                r = security_getenforce() == 1 ? -errno : 0;
         }
 #endif
 
@@ -161,18 +136,18 @@ fail:
         return r;
 }
 
-int label_fifofile_set(const char *label, const char *path) {
+int label_fifofile_set(const char *path) {
         int r = 0;
 
 #ifdef HAVE_SELINUX
         security_context_t filecon = NULL;
 
-        if (!use_selinux() || !label)
+        if (!use_selinux() || !label_hnd)
                 return 0;
 
-        if (((r = label_get_file_label_from_path(label, path, "fifo_file", &filecon)) == 0)) {
+        if ((r = selabel_lookup_raw(label_hnd, &filecon, path, S_IFIFO)) == 0) {
                 if ((r = setfscreatecon(filecon)) < 0) {
-                        log_error("Failed to set SELinux file context (%s) on %s: %m", label, path);
+                        log_error("Failed to set SELinux file context on %s: %m", path);
                         r = -errno;
                 }
 
diff --git a/src/label.h b/src/label.h
index 95a2829..0c59da1 100644
--- a/src/label.h
+++ b/src/label.h
@@ -32,7 +32,7 @@ int label_fix(const char *path);
 int label_socket_set(const char *label);
 void label_socket_clear(void);
 
-int label_fifofile_set(const char *label, const char *path);
+int label_fifofile_set(const char *path);
 void label_file_clear(void);
 
 void label_free(const char *label);
diff --git a/src/socket.c b/src/socket.c
index 7510a6d..d0568c9 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -724,15 +724,10 @@ static int socket_open_fds(Socket *s) {
         SocketPort *p;
         int r;
         char *label = NULL;
+        bool know_label = false;
 
         assert(s);
 
-        if ((r = socket_instantiate_service(s)) < 0)
-                return r;
-
-        if ((r = label_get_socket_label_from_exe(s->service->exec_command[SERVICE_EXEC_START]->path, &label)) < 0)
-                return r;
-
         LIST_FOREACH(port, p, s->ports) {
 
                 if (p->fd >= 0)
@@ -740,6 +735,17 @@ static int socket_open_fds(Socket *s) {
 
                 if (p->type == SOCKET_SOCKET) {
 
+                        if (!know_label) {
+
+                                if ((r = socket_instantiate_service(s)) < 0)
+                                        return r;
+
+                                if ((r = label_get_socket_label_from_exe(s->service->exec_command[SERVICE_EXEC_START]->path, &label)) < 0)
+                                        return r;
+
+                                know_label = true;
+                        }
+
                         if ((r = socket_address_listen(
                                              &p->address,
                                              s->backlog,
@@ -760,7 +766,6 @@ static int socket_open_fds(Socket *s) {
                                              p->path,
                                              s->directory_mode,
                                              s->socket_mode,
-                                             label,
                                              &p->fd)) < 0)
                                 goto rollback;
 
commit c4e2ceae941d02de5574becbfd3b4db15de2eda3
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Aug 20 02:26:05 2010 +0200

    dbus: follow standardized fdo PropertiesChanged signal spec

diff --git a/fixme b/fixme
index 855f9d6..b1474f5 100644
--- a/fixme
+++ b/fixme
@@ -40,8 +40,6 @@
 
 * write utmp record a la upstart for processes
 
-* follow property change dbus spec
-
 * selinux policy loading
 
 * place /etc/inittab with explaining blurb.
@@ -62,6 +60,10 @@
 
 * bash completion a la gdbus
 
+* fstab mit tüdelchen
+
+* api mounts gegen fstab mergen und remounten
+
 External:
 
 * procps, psmisc, sysvinit-tools, hostname → util-linux-ng
diff --git a/src/automount.c b/src/automount.c
index d5da497..b32e002 100644
--- a/src/automount.c
+++ b/src/automount.c
@@ -843,6 +843,7 @@ const UnitVTable automount_vtable = {
 
         .reset_maintenance = automount_reset_maintenance,
 
+        .bus_interface = "org.freedesktop.systemd1.Automount",
         .bus_message_handler = bus_automount_message_handler,
 
         .shutdown = automount_shutdown
diff --git a/src/dbus-automount.c b/src/dbus-automount.c
index b7b31a1..3bccb4e 100644
--- a/src/dbus-automount.c
+++ b/src/dbus-automount.c
@@ -34,6 +34,7 @@
         BUS_UNIT_INTERFACE                                           \
         BUS_AUTOMOUNT_INTERFACE                                      \
         BUS_PROPERTIES_INTERFACE                                     \
+        BUS_PEER_INTERFACE                                           \
         BUS_INTROSPECTABLE_INTERFACE                                 \
         "</node>\n"
 
diff --git a/src/dbus-device.c b/src/dbus-device.c
index bb8b40e..fcb05a4 100644
--- a/src/dbus-device.c
+++ b/src/dbus-device.c
@@ -33,11 +33,16 @@
         BUS_UNIT_INTERFACE                                              \
         BUS_DEVICE_INTERFACE                                            \
         BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
         BUS_INTROSPECTABLE_INTERFACE                                    \
         "</node>\n"
 
 const char bus_device_interface[] = BUS_DEVICE_INTERFACE;
 
+const char bus_device_invalidating_properties[] =
+        "SysFSPath\0"
+        "\0";
+
 DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
         const BusProperty properties[] = {
                 BUS_UNIT_PROPERTIES,
diff --git a/src/dbus-device.h b/src/dbus-device.h
index 639255d..fba270b 100644
--- a/src/dbus-device.h
+++ b/src/dbus-device.h
@@ -29,5 +29,6 @@
 DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
 
 extern const char bus_device_interface[];
+extern const char bus_device_invalidating_properties[];
 
 #endif
diff --git a/src/dbus-job.c b/src/dbus-job.c
index 727e2ac..0f76c7d 100644
--- a/src/dbus-job.c
+++ b/src/dbus-job.c
@@ -28,7 +28,6 @@
 #define BUS_JOB_INTERFACE                                             \
         " <interface name=\"org.freedesktop.systemd1.Job\">\n"        \
         "  <method name=\"Cancel\"/>\n"                               \
-        "  <signal name=\"Changed\"/>\n"                              \
         "  <property name=\"Id\" type=\"u\" access=\"read\"/>\n"      \
         "  <property name=\"Unit\" type=\"(so)\" access=\"read\"/>\n" \
         "  <property name=\"JobType\" type=\"s\" access=\"read\"/>\n" \
@@ -40,11 +39,16 @@
         "<node>\n"                                                    \
         BUS_JOB_INTERFACE                                             \
         BUS_PROPERTIES_INTERFACE                                      \
+        BUS_PEER_INTERFACE                                            \
         BUS_INTROSPECTABLE_INTERFACE                                  \
         "</node>\n"
 
 const char bus_job_interface[] = BUS_JOB_INTERFACE;
 
+#define INVALIDATING_PROPERTIES                 \
+        "State\0"                               \
+        "\0"                                    \
+
 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_state, job_state, JobState);
 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_type, job_type, JobType);
 
@@ -187,10 +191,11 @@ void bus_job_send_change_signal(Job *j) {
                 goto oom;
 
         if (j->sent_dbus_new_signal) {
-                /* Send a change signal */
+                /* Send a properties changed signal */
 
-                if (!(m = dbus_message_new_signal(p, "org.freedesktop.systemd1.Job", "Changed")))
+                if (!(m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Job", INVALIDATING_PROPERTIES)))
                         goto oom;
+
         } else {
                 /* Send a new signal */
 
diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index 1fca8b5..eb37684 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -148,6 +148,7 @@
         "<node>\n"                                                      \
         BUS_MANAGER_INTERFACE                                           \
         BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
         BUS_INTROSPECTABLE_INTERFACE
 
 #define INTROSPECTION_END                                               \
diff --git a/src/dbus-mount.c b/src/dbus-mount.c
index 933e3bb..92d74cb 100644
--- a/src/dbus-mount.c
+++ b/src/dbus-mount.c
@@ -46,11 +46,22 @@
         BUS_UNIT_INTERFACE                                              \
         BUS_MOUNT_INTERFACE                                             \
         BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
         BUS_INTROSPECTABLE_INTERFACE                                    \
         "</node>\n"
 
 const char bus_mount_interface[] = BUS_MOUNT_INTERFACE;
 
+const char bus_mount_invalidating_properties[] =
+        "What\0"
+        "Options\0"
+        "Type\0"
+        "ExecMount\0"
+        "ExecUnmount\0"
+        "ExecRemount\0"
+        "ControlPID\0"
+        "\0";
+
 static int bus_mount_append_what(Manager *n, DBusMessageIter *i, const char *property, void *data) {
         Mount *m = data;
         const char *d;
diff --git a/src/dbus-mount.h b/src/dbus-mount.h
index c9ab73f..b5613fa 100644
--- a/src/dbus-mount.h
+++ b/src/dbus-mount.h
@@ -29,5 +29,6 @@
 DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
 
 extern const char bus_mount_interface[];
+extern const char bus_mount_invalidating_properties[];
 
 #endif
diff --git a/src/dbus-path.c b/src/dbus-path.c
index 45472e5..c8c302a 100644
--- a/src/dbus-path.c
+++ b/src/dbus-path.c
@@ -37,6 +37,7 @@
         BUS_UNIT_INTERFACE                                              \
         BUS_PATH_INTERFACE                                              \
         BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
         BUS_INTROSPECTABLE_INTERFACE                                    \
         "</node>\n"
 
diff --git a/src/dbus-service.c b/src/dbus-service.c
index 5922206..86c18dd 100644
--- a/src/dbus-service.c
+++ b/src/dbus-service.c
@@ -59,11 +59,25 @@
         BUS_UNIT_INTERFACE                                              \
         BUS_SERVICE_INTERFACE                                           \
         BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
         BUS_INTROSPECTABLE_INTERFACE                                    \
         "</node>\n"
 
 const char bus_service_interface[] = BUS_SERVICE_INTERFACE;
 
+const char bus_service_invalidating_properties[] =
+        "ExecStartPre\0"
+        "ExecStart\0"
+        "ExecStartPost\0"
+        "ExecReload\0"
+        "ExecStop\0"
+        "ExecStopPost\0"
+        "ExecMain\0"
+        "MainPID\0"
+        "ControlPID\0"
+        "StatusText\0"
+        "\0";
+
 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);
diff --git a/src/dbus-service.h b/src/dbus-service.h
index 4f628ed..d6eab65 100644
--- a/src/dbus-service.h
+++ b/src/dbus-service.h
@@ -29,5 +29,6 @@
 DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
 
 extern const char bus_service_interface[];
+extern const char bus_service_invalidating_properties[];
 
 #endif
diff --git a/src/dbus-snapshot.c b/src/dbus-snapshot.c
index ecb7ec8..efaec7d 100644
--- a/src/dbus-snapshot.c
+++ b/src/dbus-snapshot.c
@@ -34,6 +34,7 @@
         BUS_UNIT_INTERFACE                                              \
         BUS_SNAPSHOT_INTERFACE                                          \
         BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
         BUS_INTROSPECTABLE_INTERFACE                                    \
         "</node>\n"
 
diff --git a/src/dbus-socket.c b/src/dbus-socket.c
index 9406bb2..5931f00 100644
--- a/src/dbus-socket.c
+++ b/src/dbus-socket.c
@@ -60,11 +60,22 @@
         BUS_UNIT_INTERFACE                                              \
         BUS_SOCKET_INTERFACE                                            \
         BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
         BUS_INTROSPECTABLE_INTERFACE                                    \
         "</node>\n"
 
 const char bus_socket_interface[] = BUS_SOCKET_INTERFACE;
 
+const char bus_socket_invalidating_properties[] =
+        "ExecStartPre\0"
+        "ExecStartPost\0"
+        "ExecStopPre\0"
+        "ExecStopPost\0"
+        "ControlPID\0"
+        "NAccepted\0"
+        "NConnections\0"
+        "\0";
+
 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_socket_append_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
 
 DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
diff --git a/src/dbus-socket.h b/src/dbus-socket.h
index 71d5b4f..069a2f5 100644
--- a/src/dbus-socket.h
+++ b/src/dbus-socket.h
@@ -29,5 +29,6 @@
 DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
 
 extern const char bus_socket_interface[];
+extern const char bus_socket_invalidating_properties[];
 
 #endif
diff --git a/src/dbus-swap.c b/src/dbus-swap.c
index 1de4427..c345d4b 100644
--- a/src/dbus-swap.c
+++ b/src/dbus-swap.c
@@ -37,11 +37,17 @@
         BUS_UNIT_INTERFACE                                              \
         BUS_SWAP_INTERFACE                                              \
         BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
         BUS_INTROSPECTABLE_INTERFACE                                    \
         "</node>\n"
 
 const char bus_swap_interface[] = BUS_SWAP_INTERFACE;
 
+const char bus_swap_invalidating_properties[] =
+        "What\0"
+        "Priority\0"
+        "\0";
+
 static int bus_swap_append_priority(Manager *m, DBusMessageIter *i, const char *property, void *data) {
         Swap *s = data;
         dbus_int32_t j;
diff --git a/src/dbus-swap.h b/src/dbus-swap.h
index 5eeb02a..15b9147 100644
--- a/src/dbus-swap.h
+++ b/src/dbus-swap.h
@@ -30,5 +30,6 @@
 DBusHandlerResult bus_swap_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
 
 extern const char bus_swap_interface[];
+extern const char bus_swap_invalidating_properties[];
 
 #endif
diff --git a/src/dbus-target.c b/src/dbus-target.c
index 03e8fc8..69e8212 100644
--- a/src/dbus-target.c
+++ b/src/dbus-target.c
@@ -34,6 +34,7 @@
         BUS_UNIT_INTERFACE                                              \
         BUS_TARGET_INTERFACE                                            \
         BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
         BUS_INTROSPECTABLE_INTERFACE                                    \
         "</node>\n"
 
diff --git a/src/dbus-timer.c b/src/dbus-timer.c
index 6dfadf2..e57e973 100644
--- a/src/dbus-timer.c
+++ b/src/dbus-timer.c
@@ -38,11 +38,17 @@
         BUS_UNIT_INTERFACE                                              \
         BUS_TIMER_INTERFACE                                             \
         BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
         BUS_INTROSPECTABLE_INTERFACE                                    \
         "</node>\n"
 
 const char bus_timer_interface[] = BUS_TIMER_INTERFACE;
 
+const char bus_timer_invalidating_properties[] =
+        "Timers\0"
+        "NextElapseUSec\0"
+        "\0";
+
 static int bus_timer_append_timers(Manager *m, DBusMessageIter *i, const char *property, void *data) {
         Timer *p = data;
         DBusMessageIter sub, sub2;
diff --git a/src/dbus-timer.h b/src/dbus-timer.h
index 6f35aa7..e692e12 100644
--- a/src/dbus-timer.h
+++ b/src/dbus-timer.h
@@ -29,5 +29,6 @@
 DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
 
 extern const char bus_timer_interface[];
+extern const char bus_timer_invalidating_properties[];
 
 #endif
diff --git a/src/dbus-unit.c b/src/dbus-unit.c
index ca4e5f2..519aa5c 100644
--- a/src/dbus-unit.c
+++ b/src/dbus-unit.c
@@ -28,6 +28,18 @@
 
 const char bus_unit_interface[] = BUS_UNIT_INTERFACE;
 
+#define INVALIDATING_PROPERTIES                 \
+        "LoadState\0"                           \
+        "ActiveState\0"                         \
+        "SubState\0"                            \
+        "InactiveExitTimestamp\0"               \
+        "ActiveEnterTimestamp\0"                \
+        "ActiveExitTimestamp\0"                 \
+        "InactiveEnterTimestamp\0"              \
+        "Job\0"                                 \
+        "NeedDaemonReload\0"                    \
+        "\0"
+
 int bus_unit_append_names(Manager *m, DBusMessageIter *i, const char *property, void *data) {
         char *t;
         Iterator j;
@@ -470,10 +482,27 @@ void bus_unit_send_change_signal(Unit *u) {
                 goto oom;
 
         if (u->meta.sent_dbus_new_signal) {
-                /* Send a change signal */
+                /* Send a properties changed signal. First for the
+                 * specific type, then for the generic unit. The
+                 * clients may rely on this order to get atomic
+                 * behaviour if needed. */
+
+                if (UNIT_VTABLE(u)->bus_invalidating_properties) {
+
+                        if (!(m = bus_properties_changed_new(p,
+                                                             UNIT_VTABLE(u)->bus_interface,
+                                                             UNIT_VTABLE(u)->bus_invalidating_properties)))
+                                goto oom;
+
+                        if (bus_broadcast(u->meta.manager, m) < 0)
+                                goto oom;
 
-                if (!(m = dbus_message_new_signal(p, "org.freedesktop.systemd1.Unit", "Changed")))
+                        dbus_message_unref(m);
+                }
+
+                if (!(m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Unit", INVALIDATING_PROPERTIES)))
                         goto oom;
+
         } else {
                 /* Send a new signal */
 
diff --git a/src/dbus-unit.h b/src/dbus-unit.h
index 8f17bf2..cc55ad7 100644
--- a/src/dbus-unit.h
+++ b/src/dbus-unit.h
@@ -57,7 +57,6 @@
         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
         "  </method>\n"                                                 \
         "  <method name=\"ResetMaintenance\"/>\n"                       \
-        "  <signal name=\"Changed\"/>\n"                                \
         "  <property name=\"Id\" type=\"s\" access=\"read\"/>\n"        \
         "  <property name=\"Names\" type=\"as\" access=\"read\"/>\n"    \
         "  <property name=\"Following\" type=\"s\" access=\"read\"/>\n" \
diff --git a/src/dbus.c b/src/dbus.c
index e8828d0..952806b 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -1247,6 +1247,7 @@ DBusHandlerResult bus_default_message_handler(Manager *m, DBusConnection *c, DBu
                         if (!dbus_message_iter_close_container(&iter, &sub))
                                 goto oom;
                 }
+
         } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && properties) {
                 const char *interface;
                 const BusProperty *p;
@@ -1611,3 +1612,41 @@ bool bus_connection_has_subscriber(Manager *m, DBusConnection *c) {
 
         return !set_isempty(BUS_CONNECTION_SUBSCRIBED(m, c));
 }
+
+DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
+        DBusMessage *m;
+        DBusMessageIter iter, sub;
+        const char *i;
+
+        assert(interface);
+        assert(properties);
+
+        if (!(m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged")))
+                goto oom;
+
+        dbus_message_iter_init_append(m, &iter);
+
+        /* We won't send any property values, since they might be
+         * large and sometimes not cheap to generated */
+
+        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
+            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
+            !dbus_message_iter_close_container(&iter, &sub) ||
+            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
+                goto oom;
+
+        NULSTR_FOREACH(i, properties)
+                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
+                        goto oom;
+
+        if (!dbus_message_iter_close_container(&iter, &sub))
+                goto oom;
+
+        return m;
+
+oom:
+        if (m)
+                dbus_message_unref(m);
+
+        return NULL;
+}
diff --git a/src/dbus.h b/src/dbus.h
index f15a3f9..7c0da33 100644
--- a/src/dbus.h
+++ b/src/dbus.h
@@ -47,6 +47,11 @@ typedef struct BusProperty {
         "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
         "   <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \
         "  </method>\n"                                                 \
+        "  <signal name=\"PropertiesChanged\">\n"                       \
+        "   <arg type=\"s\" name=\"interface\"/>\n"                     \
+        "   <arg type=\"a{sv}\" name=\"changed_properties\"/>\n"        \
+        "   <arg type=\"as\" name=\"invalidated_properties\"/>\n"       \
+        "  </signal>\n"                                                 \
         " </interface>\n"
 
 #define BUS_INTROSPECTABLE_INTERFACE                                    \
@@ -56,6 +61,14 @@ typedef struct BusProperty {
         "  </method>\n"                                                 \
         " </interface>\n"
 
+#define BUS_PEER_INTERFACE                                              \
+        "<interface name=\"org.freedesktop.DBus.Peer\">\n"              \
+        " <method name=\"Ping\"/>\n"                                    \
+        " <method name=\"GetMachineId\">\n"                             \
+        "  <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \
+        " </method>\n"                                                  \
+        "</interface>\n"
+
 int bus_init(Manager *m);
 void bus_done(Manager *m);
 
@@ -108,6 +121,8 @@ int bus_parse_strv(DBusMessage *m, char ***_l);
 bool bus_has_subscriber(Manager *m);
 bool bus_connection_has_subscriber(Manager *m, DBusConnection *c);
 
+DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties);
+
 #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)
 
diff --git a/src/device.c b/src/device.c
index 7323192..8074a3e 100644
--- a/src/device.c
+++ b/src/device.c
@@ -537,7 +537,9 @@ const UnitVTable device_vtable = {
         .active_state = device_active_state,
         .sub_state_to_string = device_sub_state_to_string,
 
+        .bus_interface = "org.freedesktop.systemd1.Device",
         .bus_message_handler = bus_device_message_handler,
+        .bus_invalidating_properties =  bus_device_invalidating_properties,
 
         .following = device_following,
 
diff --git a/src/mount.c b/src/mount.c
index 89b1843..e0ca5bb 100644
--- a/src/mount.c
+++ b/src/mount.c
@@ -1005,6 +1005,9 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         default:
                 assert_not_reached("Uh, control process died at wrong time.");
         }
+
+        /* Notify clients about changed exit status */
+        unit_add_to_dbus_queue(u);
 }
 
 static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
@@ -1557,7 +1560,9 @@ const UnitVTable mount_vtable = {
 
         .reset_maintenance = mount_reset_maintenance,
 
+        .bus_interface = "org.freedesktop.systemd1.Mount",
         .bus_message_handler = bus_mount_message_handler,
+        .bus_invalidating_properties =  bus_mount_invalidating_properties,
 
         .enumerate = mount_enumerate,
         .shutdown = mount_shutdown
diff --git a/src/path.c b/src/path.c
index 9af1cd4..42c64f3 100644
--- a/src/path.c
+++ b/src/path.c
@@ -607,5 +607,6 @@ const UnitVTable path_vtable = {
 
         .reset_maintenance = path_reset_maintenance,
 
+        .bus_interface = "org.freedesktop.systemd1.Path",
         .bus_message_handler = bus_path_message_handler
 };
diff --git a/src/service.c b/src/service.c
index 66e233a..d2ef1ad 100644
--- a/src/service.c
+++ b/src/service.c
@@ -2454,6 +2454,9 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                         }
                 }
         }
+
+        /* Notify clients about changed exit status */
+        unit_add_to_dbus_queue(u);
 }
 
 static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
@@ -2610,6 +2613,9 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) {
                 }
 
         }
+
+        /* Notify clients about changed status or main pid */
+        unit_add_to_dbus_queue(u);
 }
 
 static int service_enumerate(Manager *m) {
@@ -2944,7 +2950,9 @@ const UnitVTable service_vtable = {
         .bus_name_owner_change = service_bus_name_owner_change,
         .bus_query_pid_done = service_bus_query_pid_done,
 
+        .bus_interface = "org.freedesktop.systemd1.Service",
         .bus_message_handler = bus_service_message_handler,
+        .bus_invalidating_properties =  bus_service_invalidating_properties,
 
         .enumerate = service_enumerate
 };
diff --git a/src/snapshot.c b/src/snapshot.c
index 2c46837..f58d46e 100644
--- a/src/snapshot.c
+++ b/src/snapshot.c
@@ -292,5 +292,6 @@ const UnitVTable snapshot_vtable = {
         .active_state = snapshot_active_state,
         .sub_state_to_string = snapshot_sub_state_to_string,
 
+        .bus_interface = "org.freedesktop.systemd1.Snapshot",
         .bus_message_handler = bus_snapshot_message_handler
 };
diff --git a/src/socket.c b/src/socket.c
index 3a37191..7510a6d 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -659,7 +659,6 @@ static int fifo_address_create(
                 const char *path,
                 mode_t directory_mode,
                 mode_t socket_mode,
-                const char *label,
                 int *_fd) {
 
         int fd = -1, r = 0;
@@ -671,7 +670,7 @@ static int fifo_address_create(
 
         mkdir_parents(path, directory_mode);
 
-        if ((r = label_fifofile_set(label, path)) < 0)
+        if ((r = label_fifofile_set(path)) < 0)
                 goto fail;
 
         /* Enforce the right access mode for the fifo */
@@ -1217,6 +1216,9 @@ static void socket_enter_running(Socket *s, int cfd) {
 
                 if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(service), JOB_REPLACE, true, &error, NULL)) < 0)
                         goto fail;
+
+                /* Notify clients about changed counters */
+                unit_add_to_dbus_queue(UNIT(s));
         }
 
         return;
@@ -1594,6 +1596,9 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                         assert_not_reached("Uh, control process died at wrong time.");
                 }
         }
+
+        /* Notify clients about changed exit status */
+        unit_add_to_dbus_queue(u);
 }
 
 static void socket_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
@@ -1774,5 +1779,7 @@ const UnitVTable socket_vtable = {
 
         .reset_maintenance = socket_reset_maintenance,
 
-        .bus_message_handler = bus_socket_message_handler
+        .bus_interface = "org.freedesktop.systemd1.Socket",
+        .bus_message_handler = bus_socket_message_handler,
+        .bus_invalidating_properties =  bus_socket_invalidating_properties
 };
diff --git a/src/swap.c b/src/swap.c
index ffe7688..c81fd67 100644
--- a/src/swap.c
+++ b/src/swap.c
@@ -599,7 +599,9 @@ const UnitVTable swap_vtable = {
 
         .check_gc = swap_check_gc,
 
+        .bus_interface = "org.freedesktop.systemd1.Swap",
         .bus_message_handler = bus_swap_message_handler,
+        .bus_invalidating_properties =  bus_swap_invalidating_properties,
 
         .reset_maintenance = swap_reset_maintenance,
 
diff --git a/src/systemadm.vala b/src/systemadm.vala
index 3610e2b..4aee1d3 100644
--- a/src/systemadm.vala
+++ b/src/systemadm.vala
@@ -325,13 +325,19 @@ public class MainWindow : Window {
                 foreach (var i in list) {
                         TreeIter iter;
 
+                        Properties p = bus.get_object(
+                                        "org.freedesktop.systemd1",
+                                        i.unit_path,
+                                        "org.freedesktop.DBus.Properties") as Properties;
+
+
+                        p.properties_changed.connect(on_unit_changed);
+
                         Unit u = bus.get_object(
                                         "org.freedesktop.systemd1",
                                         i.unit_path,
                                         "org.freedesktop.systemd1.Unit") as Unit;
 
-                        u.changed.connect(on_unit_changed);
-
                         unit_model.append(out iter);
                         unit_model.set(iter,
                                        0, i.id,
@@ -352,13 +358,18 @@ public class MainWindow : Window {
                 foreach (var i in list) {
                         TreeIter iter;
 
+                        Properties p = bus.get_object(
+                                        "org.freedesktop.systemd1",
+                                        i.job_path,
+                                        "org.freedesktop.DBus.Properties") as Properties;
+
+                        p.properties_changed.connect(on_job_changed);
+
                         Job j = bus.get_object(
                                         "org.freedesktop.systemd1",
                                         i.job_path,
                                         "org.freedesktop.systemd1.Job") as Job;
 
-                        j.changed.connect(on_job_changed);
-
                         job_model.append(out iter);
                         job_model.set(iter,
                                       0, "%u".printf(i.id),
@@ -672,15 +683,21 @@ public class MainWindow : Window {
         }
 
         public void on_unit_new(string id, ObjectPath path) {
-                Unit u = bus.get_object(
+                Properties p = bus.get_object(
                                 "org.freedesktop.systemd1",
                                 path,
-                                "org.freedesktop.systemd1.Unit") as Unit;
+                                "org.freedesktop.DBus.Properties") as Properties;
 
-                u.changed.connect(on_unit_changed);
+                p.properties_changed.connect(on_unit_changed);
 
                 TreeIter iter;
                 unit_model.append(out iter);
+
+                Unit u = bus.get_object(
+                                "org.freedesktop.systemd1",
+                                path,
+                                "org.freedesktop.systemd1.Unit") as Unit;
+
                 update_unit_iter(iter, id, u);
         }
 
@@ -695,15 +712,22 @@ public class MainWindow : Window {
         }
 
         public void on_job_new(uint32 id, ObjectPath path) {
-                Job j = bus.get_object(
+
+                Properties p = bus.get_object(
                                 "org.freedesktop.systemd1",
                                 path,
-                                "org.freedesktop.systemd1.Job") as Job;
+                                "org.freedesktop.DBus.Properties") as Properties;
 
-                j.changed.connect(on_job_changed);
+                p.properties_changed.connect(on_job_changed);
 
                 TreeIter iter;
                 job_model.append(out iter);
+
+                Job j = bus.get_object(
+                                "org.freedesktop.systemd1",
+                                path,
+                                "org.freedesktop.systemd1.Job") as Job;
+
                 update_job_iter(iter, id, j);
         }
 
@@ -750,10 +774,15 @@ public class MainWindow : Window {
                 } while (job_model.iter_next(ref iter));
         }
 
-        public void on_unit_changed(Unit u) {
+        public void on_unit_changed(Properties p, string iface, HashTable<string, Value?> changed_properties, string[] invalidated_properties) {
                 TreeIter iter;
                 string id;
 
+                Unit u = bus.get_object(
+                                p.get_bus_name(),
+                                p.get_path(),
+                                "org.freedesktop.systemd1.Unit") as Unit;
+
                 if (!(unit_model.get_iter_first(out iter)))
                         return;
 
@@ -776,10 +805,15 @@ public class MainWindow : Window {
                 } while (unit_model.iter_next(ref iter));
         }
 
-        public void on_job_changed(Job j) {
+        public void on_job_changed(Properties p, string iface, HashTable<string, Value?> changed_properties, string[] invalidated_properties) {
                 TreeIter iter;
                 uint32 id;
 
+                Job j = bus.get_object(
+                                p.get_bus_name(),
+                                p.get_path(),
+                                "org.freedesktop.systemd1.Job") as Job;
+
                 if (!(job_model.get_iter_first(out iter)))
                         return;
 
diff --git a/src/systemctl.c b/src/systemctl.c
index 5bf5e9f..30f6b2a 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -2390,14 +2390,23 @@ static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage
                         printf("Job %u removed.\n", id);
 
 
-        } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Unit", "Changed") ||
-                   dbus_message_is_signal(message, "org.freedesktop.systemd1.Job", "Changed")) {
+        } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
 
                 const char *path, *interface, *property = "Id";
                 DBusMessageIter iter, sub;
 
                 path = dbus_message_get_path(message);
-                interface = dbus_message_get_interface(message);
+
+                if (!dbus_message_get_args(message, &error,
+                                          DBUS_TYPE_STRING, &interface,
+                                          DBUS_TYPE_INVALID)) {
+                        log_error("Failed to parse message: %s", error.message);
+                        goto finish;
+                }
+
+                if (!streq(interface, "org.freedesktop.systemd1.Job") &&
+                    !streq(interface, "org.freedesktop.systemd1.Unit"))
+                        goto finish;
 
                 if (!(m = dbus_message_new_method_call(
                               "org.freedesktop.systemd1",
@@ -2497,21 +2506,8 @@ static int monitor(DBusConnection *bus, char **args, unsigned n) {
                 dbus_bus_add_match(bus,
                                    "type='signal',"
                                    "sender='org.freedesktop.systemd1',"
-                                   "interface='org.freedesktop.systemd1.Unit',"
-                                   "member='Changed'",
-                                   &error);
-
-                if (dbus_error_is_set(&error)) {
-                        log_error("Failed to add match: %s", error.message);
-                        r = -EIO;
-                        goto finish;
-                }
-
-                dbus_bus_add_match(bus,
-                                   "type='signal',"
-                                   "sender='org.freedesktop.systemd1',"
-                                   "interface='org.freedesktop.systemd1.Job',"
-                                   "member='Changed'",
+                                   "interface='org.freedesktop.DBus.Properties',"
+                                   "member='PropertiesChanged'",
                                    &error);
 
                 if (dbus_error_is_set(&error)) {
diff --git a/src/systemd-interfaces.vala b/src/systemd-interfaces.vala
index 612cb13..9a8c1dc 100644
--- a/src/systemd-interfaces.vala
+++ b/src/systemd-interfaces.vala
@@ -50,13 +50,19 @@ public interface Manager : DBus.Object {
         public abstract JobInfo[] list_jobs() throws DBus.Error;
 
         public abstract ObjectPath get_unit(string name) throws DBus.Error;
+        public abstract ObjectPath get_unit_by_pid(uint32 pid) throws DBus.Error;
         public abstract ObjectPath load_unit(string name) throws DBus.Error;
         public abstract ObjectPath get_job(uint32 id) throws DBus.Error;
 
-        public abstract ObjectPath start_unit(string name, string mode) throws DBus.Error;
-        public abstract ObjectPath stop_unit(string name, string mode) throws DBus.Error;
-        public abstract ObjectPath reload_unit(string name, string mode) throws DBus.Error;
-        public abstract ObjectPath restart_unit(string name, string mode) throws DBus.Error;
+        public abstract ObjectPath start_unit(string name, string mode = "replace") throws DBus.Error;
+        public abstract ObjectPath stop_unit(string name, string mode = "replace") throws DBus.Error;
+        public abstract ObjectPath reload_unit(string name, string mode = "replace") throws DBus.Error;
+        public abstract ObjectPath restart_unit(string name, string mode = "replace") throws DBus.Error;
+        public abstract ObjectPath try_restart_unit(string name, string mode = "replace") throws DBus.Error;
+        public abstract ObjectPath reload_or_restart_unit(string name, string mode = "replace") throws DBus.Error;
+        public abstract ObjectPath reload_or_try_restart_unit(string name, string mode = "replace") throws DBus.Error;
+
+        public abstract void reset_maintenance_unit(string name = "") throws DBus.Error;
 
         public abstract void clear_jobs() throws DBus.Error;
 
@@ -89,6 +95,7 @@ public interface Unit : DBus.Object {
 
         public abstract string id { owned get; }
         public abstract string[] names { owned get; }
+        public abstract string following { owned get; }
         public abstract string[] requires { owned get; }
         public abstract string[] requires_overridable { owned get; }
         public abstract string[] requisite { owned get; }
@@ -98,8 +105,10 @@ public interface Unit : DBus.Object {
         public abstract string[] required_by_overridable { owned get; }
         public abstract string[] wanted_by { owned get; }
         public abstract string[] conflicts { owned get; }
+        public abstract string[] conflicted_by { owned get; }
         public abstract string[] before { owned get; }
         public abstract string[] after { owned get; }
+        public abstract string[] on_failure { owned get; }
         public abstract string description { owned get; }
         public abstract string load_state { owned get; }
         public abstract string active_state { owned get; }
@@ -110,19 +119,28 @@ public interface Unit : DBus.Object {
         public abstract uint64 active_exit_timestamp { owned get; }
         public abstract uint64 inactive_enter_timestamp { owned get; }
         public abstract bool can_start { owned get; }
+        public abstract bool can_stop { owned get; }
         public abstract bool can_reload { owned get; }
         public abstract JobLink job { owned get; }
         public abstract bool recursive_stop { owned get; }
         public abstract bool stop_when_unneeded { owned get; }
+        public abstract bool refuse_manual_start { owned get; }
+        public abstract bool refuse_manual_stop { owned get; }
+        public abstract bool default_dependencies { owned get; }
         public abstract string default_control_group { owned get; }
         public abstract string[] control_groups { owned get; }
-
-        public abstract ObjectPath start(string mode) throws DBus.Error;
-        public abstract ObjectPath stop(string mode) throws DBus.Error;
-        public abstract ObjectPath restart(string mode) throws DBus.Error;
-        public abstract ObjectPath reload(string mode) throws DBus.Error;
-
-        public abstract signal void changed();
+        public abstract bool need_daemon_reload { owned get; }
+        public abstract uint64 job_timeout_usec { owned get; }
+
+        public abstract ObjectPath start(string mode = "replace") throws DBus.Error;
+        public abstract ObjectPath stop(string mode = "replace") throws DBus.Error;
+        public abstract ObjectPath reload(string mode = "replace") throws DBus.Error;
+        public abstract ObjectPath restart(string mode = "replace") throws DBus.Error;
+        public abstract ObjectPath try_restart(string mode = "replace") throws DBus.Error;
+        public abstract ObjectPath reload_or_restart(string mode = "replace") throws DBus.Error;
+        public abstract ObjectPath reload_or_try_restart(string mode = "replace") throws DBus.Error;
+
+        public abstract void reset_maintenance() throws DBus.Error;
 }
 
 [DBus (name = "org.freedesktop.systemd1.Job")]
@@ -138,6 +156,10 @@ public interface Job : DBus.Object {
         public abstract UnitLink unit { owned get; }
 
         public abstract void cancel() throws DBus.Error;
+}
 
-        public abstract signal void changed();
+[DBus (name = "org.freedesktop.DBus.Properties")]
+public interface Properties : DBus.Object {
+        public abstract Value? get(string iface, string property) throws DBus.Error;
+        public abstract signal void properties_changed(string iface, HashTable<string, Value?> changed_properties, string[] invalidated_properties);
 }
diff --git a/src/target.c b/src/target.c
index 48137fe..c7285fa 100644
--- a/src/target.c
+++ b/src/target.c
@@ -207,5 +207,6 @@ const UnitVTable target_vtable = {
         .active_state = target_active_state,
         .sub_state_to_string = target_sub_state_to_string,
 
+        .bus_interface = "org.freedesktop.systemd1.Target",
         .bus_message_handler = bus_target_message_handler
 };
diff --git a/src/timer.c b/src/timer.c
index 61bd85c..89deb01 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -498,5 +498,7 @@ const UnitVTable timer_vtable = {
 
         .reset_maintenance = timer_reset_maintenance,
 
-        .bus_message_handler = bus_timer_message_handler
+        .bus_interface = "org.freedesktop.systemd1.Timer",
+        .bus_message_handler = bus_timer_message_handler,
+        .bus_invalidating_properties =  bus_timer_invalidating_properties
 };
diff --git a/src/unit.h b/src/unit.h
index 993a6cb..0362602 100644
--- a/src/unit.h
+++ b/src/unit.h
@@ -334,6 +334,14 @@ struct UnitVTable {
         /* Type specific cleanups. */
         void (*shutdown)(Manager *m);
 
+        /* When sending out PropertiesChanged signal, which properties
+         * shall be invalidated? This is a NUL seperated list of
+         * strings, to minimize relocations a little. */
+        const char *bus_invalidating_properties;
+
+        /* The interface name */
+        const char *bus_interface;
+
         /* Can units of this type have multiple names? */
         bool no_alias:1;
 
diff --git a/src/util.h b/src/util.h
index e8d9b3e..7490236 100644
--- a/src/util.h
+++ b/src/util.h
@@ -339,6 +339,9 @@ char *ellipsize(const char *s, unsigned length, unsigned percent);
 
 int touch(const char *path);
 
+#define NULSTR_FOREACH(i, l) \
+        for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
+
 const char *ioprio_class_to_string(int i);
 int ioprio_class_from_string(const char *s);
 
commit d06dacd0020af7e31ff6089deff339b00ed979e3
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Aug 19 03:18:49 2010 +0200

    service/systemctl: don't consider LSB exit codes 5 and 6 as failure, and decode exit codes in systemctl

diff --git a/Makefile.am b/Makefile.am
index bf329e5..1a71421 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -299,6 +299,7 @@ libsystemd_core_la_SOURCES = \
 	src/path.c \
         src/load-dropin.c \
         src/execute.c \
+	src/exit-status.c \
         src/dbus.c \
         src/dbus-manager.c \
         src/dbus-unit.c \
@@ -604,7 +605,8 @@ systemctl_SOURCES = \
 	src/path-lookup.c \
 	src/sd-daemon.c \
 	src/cgroup-show.c \
-	src/cgroup-util.c
+	src/cgroup-util.c \
+	src/exit-status.c
 
 systemctl_CFLAGS = \
 	$(AM_CFLAGS) \
diff --git a/fixme b/fixme
index a8a0dad..855f9d6 100644
--- a/fixme
+++ b/fixme
@@ -58,11 +58,7 @@
 
 * if a service fails too often, make the service enter maintenance mode, and the socket, too.
 
-* exit code 5, 6 von sysv diensten ignorieren
-
-* decode exit codes in systemctl status
-
-* systemctl: ln -s output muss abschaltbar sein, und warning wenn [Install] leer ist.
+* systemctl: warning wenn [Install] leer ist bei enable
 
 * bash completion a la gdbus
 
diff --git a/src/execute.c b/src/execute.c
index b4ddf89..f35e916 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -51,6 +51,7 @@
 #include "cgroup.h"
 #include "namespace.h"
 #include "tcpwrap.h"
+#include "exit-status.h"
 
 /* This assumes there is a 'tty' group */
 #define TTY_MODE 0620
@@ -1757,117 +1758,6 @@ int exec_command_set(ExecCommand *c, const char *path, ...) {
         return 0;
 }
 
-const char* exit_status_to_string(ExitStatus status) {
-
-        /* We cast to int here, so that -Wenum doesn't complain that
-         * EXIT_SUCCESS/EXIT_FAILURE aren't in the enum */
-
-        switch ((int) status) {
-
-        case EXIT_SUCCESS:
-                return "SUCCESS";
-
-        case EXIT_FAILURE:
-                return "FAILURE";
-
-        case EXIT_INVALIDARGUMENT:
-                return "INVALIDARGUMENT";
-
-        case EXIT_NOTIMPLEMENTED:
-                return "NOTIMPLEMENTED";
-
-        case EXIT_NOPERMISSION:
-                return "NOPERMISSION";
-
-        case EXIT_NOTINSTALLED:
-                return "NOTINSSTALLED";
-
-        case EXIT_NOTCONFIGURED:
-                return "NOTCONFIGURED";
-
-        case EXIT_NOTRUNNING:
-                return "NOTRUNNING";
-
-        case EXIT_CHDIR:
-                return "CHDIR";
-
-        case EXIT_NICE:
-                return "NICE";
-
-        case EXIT_FDS:
-                return "FDS";
-
-        case EXIT_EXEC:
-                return "EXEC";
-
-        case EXIT_MEMORY:
-                return "MEMORY";
-
-        case EXIT_LIMITS:
-                return "LIMITS";
-
-        case EXIT_OOM_ADJUST:
-                return "OOM_ADJUST";
-
-        case EXIT_SIGNAL_MASK:
-                return "SIGNAL_MASK";
-
-        case EXIT_STDIN:
-                return "STDIN";
-
-        case EXIT_STDOUT:
-                return "STDOUT";
-
-        case EXIT_CHROOT:
-                return "CHROOT";
-
-        case EXIT_IOPRIO:
-                return "IOPRIO";
-
-        case EXIT_TIMERSLACK:
-                return "TIMERSLACK";
-
-        case EXIT_SECUREBITS:
-                return "SECUREBITS";
-
-        case EXIT_SETSCHEDULER:
-                return "SETSCHEDULER";
-
-        case EXIT_CPUAFFINITY:
-                return "CPUAFFINITY";
-
-        case EXIT_GROUP:
-                return "GROUP";
-
-        case EXIT_USER:
-                return "USER";
-
-        case EXIT_CAPABILITIES:
-                return "CAPABILITIES";
-
-        case EXIT_CGROUP:
-                return "CGROUP";
-
-        case EXIT_SETSID:
-                return "SETSID";
-
-        case EXIT_CONFIRM:
-                return "CONFIRM";
-
-        case EXIT_STDERR:
-                return "STDERR";
-
-        case EXIT_TCPWRAP:
-                return "TCPWRAP";
-
-        case EXIT_PAM:
-                return "PAM";
-
-        default:
-                return NULL;
-        }
-}
-
 static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
         [EXEC_INPUT_NULL] = "null",
         [EXEC_INPUT_TTY] = "tty",
diff --git a/src/execute.h b/src/execute.h
index 3818935..0dc5a1d 100644
--- a/src/execute.h
+++ b/src/execute.h
@@ -160,50 +160,6 @@ struct ExecContext {
         bool timer_slack_nsec_set:1;
 };
 
-typedef enum ExitStatus {
-        /* EXIT_SUCCESS defined by libc */
-        /* EXIT_FAILURE defined by libc */
-        EXIT_INVALIDARGUMENT = 2,
-        EXIT_NOTIMPLEMENTED = 3,
-        EXIT_NOPERMISSION = 4,
-        EXIT_NOTINSTALLED = 5,
-        EXIT_NOTCONFIGURED = 6,
-        EXIT_NOTRUNNING = 7,
-
-        /* The LSB suggests that error codes >= 200 are "reserved". We
-         * use them here under the assumption that they hence are
-         * unused by init scripts.
-         *
-         * http://refspecs.freestandards.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html */
-
-        EXIT_CHDIR = 200,
-        EXIT_NICE,
-        EXIT_FDS,
-        EXIT_EXEC,
-        EXIT_MEMORY,
-        EXIT_LIMITS,
-        EXIT_OOM_ADJUST,
-        EXIT_SIGNAL_MASK,
-        EXIT_STDIN,
-        EXIT_STDOUT,
-        EXIT_CHROOT,   /* 210 */
-        EXIT_IOPRIO,
-        EXIT_TIMERSLACK,
-        EXIT_SECUREBITS,
-        EXIT_SETSCHEDULER,
-        EXIT_CPUAFFINITY,
-        EXIT_GROUP,
-        EXIT_USER,
-        EXIT_CAPABILITIES,
-        EXIT_CGROUP,
-        EXIT_SETSID,   /* 220 */
-        EXIT_CONFIRM,
-        EXIT_STDERR,
-        EXIT_TCPWRAP,
-        EXIT_PAM
-
-} ExitStatus;
-
 int exec_spawn(ExecCommand *command,
                char **argv,
                const ExecContext *context,
@@ -243,6 +199,4 @@ int exec_output_from_string(const char *s);
 const char* exec_input_to_string(ExecInput i);
 int exec_input_from_string(const char *s);
 
-const char* exit_status_to_string(ExitStatus status);
-
 #endif
diff --git a/src/manager.c b/src/manager.c
index c8fdbb5..900a00a 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -57,6 +57,7 @@
 #include "path-lookup.h"
 #include "special.h"
 #include "bus-errors.h"
+#include "exit-status.h"
 
 /* As soon as 16 units are in our GC queue, make sure to run a gc sweep */
 #define GC_QUEUE_ENTRIES_MAX 16
@@ -1885,7 +1886,9 @@ static int manager_dispatch_sigchld(Manager *m) {
                           (long unsigned) si.si_pid,
                           sigchld_code_to_string(si.si_code),
                           si.si_status,
-                          strna(si.si_code == CLD_EXITED ? exit_status_to_string(si.si_status) : signal_to_string(si.si_status)));
+                          strna(si.si_code == CLD_EXITED
+                                ? exit_status_to_string(si.si_status, EXIT_STATUS_FULL)
+                                : signal_to_string(si.si_status)));
 
                 if (!u)
                         continue;
diff --git a/src/service.c b/src/service.c
index 80cd6ad..66e233a 100644
--- a/src/service.c
+++ b/src/service.c
@@ -2263,7 +2263,10 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         assert(s);
         assert(pid >= 0);
 
-        success = is_clean_exit(code, status);
+        if (s->sysv_path)
+                success = is_clean_exit_lsb(code, status);
+        else
+                success = is_clean_exit(code, status);
 
         if (s->main_pid == pid) {
 
diff --git a/src/systemctl.c b/src/systemctl.c
index 4f39cac..5bf5e9f 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -50,6 +50,7 @@
 #include "conf-parser.h"
 #include "sd-daemon.h"
 #include "shutdownd.h"
+#include "exit-status.h"
 
 static const char *arg_type = NULL;
 static char **arg_property = NULL;
@@ -1489,7 +1490,8 @@ typedef struct UnitStatusInfo {
         pid_t main_pid;
         pid_t control_pid;
         const char *status_text;
-        bool running;
+        bool running:1;
+        bool is_sysv:1;
 
         usec_t start_timestamp;
         usec_t exit_timestamp;
@@ -1584,9 +1586,15 @@ static void print_status_info(UnitStatusInfo *i) {
                 printf("\t  Exited: %u (%s, code=%s, ", p->pid, strna(t), sigchld_code_to_string(p->code));
                 free(t);
 
-                if (p->code == CLD_EXITED)
+                if (p->code == CLD_EXITED) {
+                        const char *c;
+
                         printf("status=%i", p->status);
-                else
+
+                        if ((c = exit_status_to_string(p->status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
+                                printf("/%s", c);
+
+                } else
                         printf("signal=%s", signal_to_string(p->status));
                 printf(")\n");
 
@@ -1616,9 +1624,15 @@ static void print_status_info(UnitStatusInfo *i) {
                         } else if (i->exit_code > 0) {
                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
 
-                                if (i->exit_code == CLD_EXITED)
+                                if (i->exit_code == CLD_EXITED) {
+                                        const char *c;
+
                                         printf("status=%i", i->exit_status);
-                                else
+
+                                        if ((c = exit_status_to_string(i->exit_status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
+                                                printf("/%s", c);
+
+                                } else
                                         printf("signal=%s", signal_to_string(i->exit_status));
                                 printf(")");
                         }
@@ -1687,9 +1701,10 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
                                 i->description = s;
                         else if (streq(name, "FragmentPath"))
                                 i->path = s;
-                        else if (streq(name, "SysVPath"))
+                        else if (streq(name, "SysVPath")) {
+                                i->is_sysv = true;
                                 i->path = s;
-                        else if (streq(name, "DefaultControlGroup"))
+                        } else if (streq(name, "DefaultControlGroup"))
                                 i->default_control_group = s;
                         else if (streq(name, "StatusText"))
                                 i->status_text = s;
diff --git a/src/util.c b/src/util.c
index 0b0063e..7903ca0 100644
--- a/src/util.c
+++ b/src/util.c
@@ -57,6 +57,7 @@
 #include "log.h"
 #include "strv.h"
 #include "label.h"
+#include "exit-status.h"
 
 bool streq_ptr(const char *a, const char *b) {
 
@@ -2398,6 +2399,16 @@ bool is_clean_exit(int code, int status) {
         return false;
 }
 
+bool is_clean_exit_lsb(int code, int status) {
+
+        if (is_clean_exit(code, status))
+                return true;
+
+        return
+                code == CLD_EXITED &&
+                (status == EXIT_NOTINSTALLED || status == EXIT_NOTCONFIGURED);
+}
+
 bool is_device_path(const char *path) {
 
         /* Returns true on paths that refer to a device, either in
diff --git a/src/util.h b/src/util.h
index 97e1b1b..e8d9b3e 100644
--- a/src/util.h
+++ b/src/util.h
@@ -253,6 +253,7 @@ char *format_timespan(char *buf, size_t l, usec_t t);
 int make_stdio(int fd);
 
 bool is_clean_exit(int code, int status);
+bool is_clean_exit_lsb(int code, int status);
 
 unsigned long long random_ull(void);
 
commit 8a2b3c097b5ebd53348700f591e50530a82b5cea
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Aug 19 02:42:07 2010 +0200

    service: make sure sysv services marked as interactive in the LSB header get output on the TTY in all cases

diff --git a/fixme b/fixme
index df80d8a..a8a0dad 100644
--- a/fixme
+++ b/fixme
@@ -64,8 +64,6 @@
 
 * systemctl: ln -s output muss abschaltbar sein, und warning wenn [Install] leer ist.
 
-* X-Interactive is kaputt
-
 * bash completion a la gdbus
 
 External:
diff --git a/src/service.c b/src/service.c
index ff74a6d..80cd6ad 100644
--- a/src/service.c
+++ b/src/service.c
@@ -708,7 +708,9 @@ static int service_load_sysv_path(Service *s, const char *path) {
         s->type = SERVICE_FORKING;
         s->remain_after_exit = true;
         s->restart = SERVICE_ONCE;
-        s->exec_context.std_output = s->meta.manager->sysv_console ? EXEC_OUTPUT_TTY : EXEC_OUTPUT_NULL;
+        s->exec_context.std_output =
+                (s->meta.manager->sysv_console || s->exec_context.std_input == EXEC_INPUT_TTY)
+                ? EXEC_OUTPUT_TTY : EXEC_OUTPUT_NULL;
         s->exec_context.kill_mode = KILL_PROCESS_GROUP;
 
         u->meta.load_state = UNIT_LOADED;


More information about the systemd-commits mailing list