Handle activated child stdout/stderr correctly in systemd environment
authorChengwei Yang <chengwei.yang@intel.com>
Tue, 15 Oct 2013 05:27:51 +0000 (13:27 +0800)
committerSimon McVittie <simon.mcvittie@collabora.co.uk>
Fri, 1 Nov 2013 12:41:02 +0000 (12:41 +0000)
In systemd environment, dbus-daemon will run as no-fork mode since this
is the recommended practice of systemd.

In that scenario, child activated by dbus-daemon will inherit
dbus-daemon standard streams, includes stdin/stdout/stderr. stdin will
be redirected to /dev/null by systemd and stdout/stderr will be catched
by systemd log subsystem. Since the child inherit stdout/stderr from
dbus-daemon, so from systemd journal log, the child log output will be
identified with dbus-daemon identifier. So it's a little confusing.

This patch redirects the child stdout/stderr to systemd journal stream,
and with its owned service name as identifier. However, thing not fixed
perfectly due to the socket ucred of the child is owned by dbus-daemon,
so the pid isn't the real pid of the chile.

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=68559
Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
configure.ac
dbus/dbus-spawn.c

index b29c8f092f5d1328122c1ca12bee202c00e6c31f..37e555b990cc711f72395401b679fcd381bb5ef9 100644 (file)
@@ -1143,7 +1143,7 @@ if test x$enable_systemd = xno ; then
     have_systemd=no;
 else
     PKG_CHECK_MODULES(SYSTEMD,
-        [libsystemd-login >= 32, libsystemd-daemon >= 32],
+        [libsystemd-login >= 32, libsystemd-daemon >= 32, libsystemd-journal >= 32],
         have_systemd=yes,
         have_systemd=no)
 fi
index a0ff2f4e551579f3fd40c77756e96ba01f160fa0..0802d89de3b74f8db8c6f0a0586df805114bb7a2 100644 (file)
@@ -38,6 +38,9 @@
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
+#ifdef HAVE_SYSTEMD
+#include <systemd/sd-journal.h>
+#endif
 
 extern char **environ;
 
@@ -1197,6 +1200,10 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
   int child_err_report_pipe[2] = { -1, -1 };
   int babysitter_pipe[2] = { -1, -1 };
   pid_t pid;
+#ifdef HAVE_SYSTEMD
+  int fd_out = -1;
+  int fd_err = -1;
+#endif
   
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   _dbus_assert (argv[0] != NULL);
@@ -1283,7 +1290,13 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
     }
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
+#ifdef HAVE_SYSTEMD
+  /* this may fail, but not critical */
+  fd_out = sd_journal_stream_fd (sitter->log_name, LOG_INFO, FALSE);
+  fd_err = sd_journal_stream_fd (sitter->log_name, LOG_WARNING, FALSE);
+#endif
+
   pid = fork ();
   
   if (pid < 0)
@@ -1323,6 +1336,15 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
            */
           signal (SIGPIPE, SIG_IGN);
 
+#ifdef HAVE_SYSTEMD
+         /* log to systemd journal */
+         if (fd_out >= 0)
+            dup2 (fd_out, STDOUT_FILENO);
+         if (fd_err >= 0)
+            dup2 (fd_err, STDERR_FILENO);
+          close_and_invalidate (&fd_out);
+          close_and_invalidate (&fd_err);
+#endif
          do_exec (child_err_report_pipe[WRITE_END],
                   argv,
                   env,
@@ -1331,6 +1353,10 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
        }
       else
        {
+#ifdef HAVE_SYSTEMD
+          close_and_invalidate (&fd_out);
+          close_and_invalidate (&fd_err);
+#endif
           babysit (grandchild_pid, babysitter_pipe[1]);
           _dbus_assert_not_reached ("Got to code after babysit()");
        }
@@ -1340,6 +1366,10 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
       /* Close the uncared-about ends of the pipes */
       close_and_invalidate (&child_err_report_pipe[WRITE_END]);
       close_and_invalidate (&babysitter_pipe[1]);
+#ifdef HAVE_SYSTEMD
+      close_and_invalidate (&fd_out);
+      close_and_invalidate (&fd_err);
+#endif
 
       sitter->socket_to_babysitter = babysitter_pipe[0];
       babysitter_pipe[0] = -1;
@@ -1369,6 +1399,10 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
   close_and_invalidate (&child_err_report_pipe[WRITE_END]);
   close_and_invalidate (&babysitter_pipe[0]);
   close_and_invalidate (&babysitter_pipe[1]);
+#ifdef HAVE_SYSTEMD
+  close_and_invalidate (&fd_out);
+  close_and_invalidate (&fd_err);
+#endif
 
   if (sitter != NULL)
     _dbus_babysitter_unref (sitter);