]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: set $JOURNAL_STREAM to the dev_t/ino_t of the journal stream of executed services 3537/head
authorLennart Poettering <lennart@poettering.net>
Tue, 14 Jun 2016 14:50:45 +0000 (16:50 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 15 Jun 2016 21:00:27 +0000 (23:00 +0200)
This permits services to detect whether their stdout/stderr is connected to the
journal, and if so talk to the journal directly, thus permitting carrying of
metadata.

As requested by the gtk folks: #2473

configure.ac
man/systemd.exec.xml
src/basic/formats-util.h
src/core/execute.c

index ffc6eedcdd26b7383aa54d904d97845a210fc70d..7fd78bfb60641e75e6b0dca326277424df787723 100644 (file)
@@ -249,6 +249,7 @@ AC_CHECK_SIZEOF(uid_t)
 AC_CHECK_SIZEOF(gid_t)
 AC_CHECK_SIZEOF(time_t)
 AC_CHECK_SIZEOF(dev_t)
+AC_CHECK_SIZEOF(ino_t)
 AC_CHECK_SIZEOF(rlim_t,,[
        #include <sys/time.h>
        #include <sys/resource.h>
index a39e800854fe9cd919df7cfec5ce4dc4ff6b0deb..dbfc7692f78315604756aecf87527c1b5aaa79f9 100644 (file)
         <citerefentry project='man-pages'><refentrytitle>termcap</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
         </para></listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><varname>$JOURNAL_STREAM</varname></term>
+
+        <listitem><para>If the standard output or standard error output of the executed processes are connected to the
+        journal (for example, by setting <varname>StandardError=journal</varname>) <varname>$JOURNAL_STREAM</varname>
+        contains the device and inode numbers of the connection file descriptor, formatted in decimal, separated by a
+        colon (<literal>:</literal>). This permits invoked processes to safely detect whether their standard output or
+        standard error output are connected to the journal. The device and inode numbers of the file descriptors should
+        be compared with the values set in the environment variable to determine whether the process output is still
+        connected to the journal. Note that it is generally not sufficient to only check whether
+        <varname>$JOURNAL_STREAM</varname> is set at all as services might invoke external processes replacing their
+        standard output or standard error output, without unsetting the environment variable.</para>
+
+        <para>This environment variable is primarily useful to allow services to optionally upgrade their used log
+        protocol to the native journal protocol (using
+        <citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>3</manvolnum></citerefentry> and other
+        functions) if their standard output or standard error output is connected to the journal anyway, thus enabling
+        delivery of structured metadata along with logged messages.</para></listitem>
+      </varlistentry>
     </variablelist>
 
     <para>Additional variables may be configured by the following
index 9b4e8e98faacf301a125a092a2070861c75e0391..39a185f59b4affffedc8044b556a4ab019edcd95 100644 (file)
 #else
 #  error Unknown rlim_t size
 #endif
+
+#if SIZEOF_DEV_T == 8
+#  define DEV_FMT "%" PRIu64
+#elif SIZEOF_DEV_T == 4
+#  define DEV_FMT "%" PRIu32
+#else
+#  error Unknown dev_t size
+#endif
+
+#if SIZEOF_INO_T == 8
+#  define INO_FMT "%" PRIu64
+#elif SIZEOF_INO_T == 4
+#  define INO_FMT "%" PRIu32
+#else
+#  error Unknown ino_t size
+#endif
index b5a5997f15e1ccf21c4669e9fa812f81d0f109ad..3c3369373f54930f2ba97c7758e4532c6e577194 100644 (file)
@@ -454,7 +454,10 @@ static int setup_output(
                 int fileno,
                 int socket_fd,
                 const char *ident,
-                uid_t uid, gid_t gid) {
+                uid_t uid,
+                gid_t gid,
+                dev_t *journal_stream_dev,
+                ino_t *journal_stream_ino) {
 
         ExecOutput o;
         ExecInput i;
@@ -464,6 +467,8 @@ static int setup_output(
         assert(context);
         assert(params);
         assert(ident);
+        assert(journal_stream_dev);
+        assert(journal_stream_ino);
 
         if (fileno == STDOUT_FILENO && params->stdout_fd >= 0) {
 
@@ -543,6 +548,17 @@ static int setup_output(
                 if (r < 0) {
                         log_unit_error_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr");
                         r = open_null_as(O_WRONLY, fileno);
+                } else {
+                        struct stat st;
+
+                        /* If we connected this fd to the journal via a stream, patch the device/inode into the passed
+                         * parameters, but only then. This is useful so that we can set $JOURNAL_STREAM that permits
+                         * services to detect whether they are connected to the journal or not. */
+
+                        if (fstat(fileno, &st) >= 0) {
+                                *journal_stream_dev = st.st_dev;
+                                *journal_stream_ino = st.st_ino;
+                        }
                 }
                 return r;
 
@@ -1286,6 +1302,8 @@ static int build_environment(
                 const char *home,
                 const char *username,
                 const char *shell,
+                dev_t journal_stream_dev,
+                ino_t journal_stream_ino,
                 char ***ret) {
 
         _cleanup_strv_free_ char **our_env = NULL;
@@ -1295,7 +1313,7 @@ static int build_environment(
         assert(c);
         assert(ret);
 
-        our_env = new0(char*, 11);
+        our_env = new0(char*, 12);
         if (!our_env)
                 return -ENOMEM;
 
@@ -1367,8 +1385,15 @@ static int build_environment(
                 our_env[n_env++] = x;
         }
 
+        if (journal_stream_dev != 0 && journal_stream_ino != 0) {
+                if (asprintf(&x, "JOURNAL_STREAM=" DEV_FMT ":" INO_FMT, journal_stream_dev, journal_stream_ino) < 0)
+                        return -ENOMEM;
+
+                our_env[n_env++] = x;
+        }
+
         our_env[n_env++] = NULL;
-        assert(n_env <= 11);
+        assert(n_env <= 12);
 
         *ret = our_env;
         our_env = NULL;
@@ -1481,10 +1506,12 @@ static int exec_child(
         _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **final_argv = NULL;
         _cleanup_free_ char *mac_selinux_context_net = NULL;
         const char *username = NULL, *home = NULL, *shell = NULL, *wd;
+        dev_t journal_stream_dev = 0;
+        ino_t journal_stream_ino = 0;
+        bool needs_mount_namespace;
         uid_t uid = UID_INVALID;
         gid_t gid = GID_INVALID;
         int i, r;
-        bool needs_mount_namespace;
 
         assert(unit);
         assert(command);
@@ -1584,13 +1611,13 @@ static int exec_child(
                 return r;
         }
 
-        r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid);
+        r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
         if (r < 0) {
                 *exit_status = EXIT_STDOUT;
                 return r;
         }
 
-        r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid);
+        r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
         if (r < 0) {
                 *exit_status = EXIT_STDERR;
                 return r;
@@ -1729,7 +1756,16 @@ static int exec_child(
                 }
         }
 
-        r = build_environment(context, params, n_fds, home, username, shell, &our_env);
+        r = build_environment(
+                        context,
+                        params,
+                        n_fds,
+                        home,
+                        username,
+                        shell,
+                        journal_stream_dev,
+                        journal_stream_ino,
+                        &our_env);
         if (r < 0) {
                 *exit_status = EXIT_MEMORY;
                 return r;