[glib: 7/10] gio-launch-desktop: Redirect stdout, stderr to systemd Journal




commit 763643ceaacc4b9863562d35b606cb15104211fa
Author: Simon McVittie <smcv collabora com>
Date:   Thu Jul 14 13:11:30 2022 +0100

    gio-launch-desktop: Redirect stdout, stderr to systemd Journal
    
    This prevents a launched process's output from being mixed up with the
    output of the parent process, which can lead to the wrong program being
    blamed for warning messages.
    
    Signed-off-by: Simon McVittie <smcv collabora com>

 gio/gio-launch-desktop.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 195 insertions(+)
---
diff --git a/gio/gio-launch-desktop.c b/gio/gio-launch-desktop.c
index 405e8c9119..1af25e739e 100644
--- a/gio/gio-launch-desktop.c
+++ b/gio/gio-launch-desktop.c
@@ -1,6 +1,10 @@
 /* GIO - GLib Input, Output and Streaming Library
  *
+ * Copyright 2004 Ximian Inc.
+ * Copyright 2011-2022 systemd contributors
  * Copyright (C) 2018 Endless Mobile, Inc.
+ * Copyright 2022 Collabora Ltd.
+ *
  * SPDX-License-Identifier: LGPL-2.1-or-later
  *
  * This library is free software; you can redistribute it and/or
@@ -33,6 +37,193 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#if defined(__linux__) && !defined(__BIONIC__)
+#include <alloca.h>
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+/*
+ * write_all:
+ * @fd: a file descriptor
+ * @vbuf: a buffer
+ * @to_write: length of @vbuf
+ *
+ * Write all bytes from @vbuf to @fd, blocking if necessary.
+ *
+ * Returns: 0 on success, -1 with errno set on failure
+ */
+static int
+write_all (int fd, const void *vbuf, size_t to_write)
+{
+  const char *buf = vbuf;
+
+  while (to_write > 0)
+    {
+      ssize_t count = write (fd, buf, to_write);
+      if (count < 0)
+        {
+          if (errno != EINTR)
+            return -1;
+        }
+      else
+        {
+          to_write -= count;
+          buf += count;
+        }
+    }
+
+  return 0;
+}
+
+/*
+ * journal_stream_fd:
+ * @identifier: identifier (syslog tag) for logged messages
+ * @priority: a priority between `LOG_EMERG` and `LOG_DEBUG` inclusive
+ * @level_prefix: if nonzero, journald will interpret prefixes like <0>
+ *  as specifying the priority for a line
+ *
+ * Reimplementation of sd_journal_stream_fd(), to avoid having to link
+ * gio-launch-desktop to libsystemd.
+ *
+ * Note that unlike the libsystemd version, this reports errors by returning
+ * -1 with errno set.
+ *
+ * Returns: a non-negative fd number, or -1 with errno set on error
+ */
+static int
+journal_stream_fd (const char *identifier,
+                   int priority,
+                   int level_prefix)
+{
+  union
+  {
+    struct sockaddr sa;
+    struct sockaddr_un un;
+  } sa =
+  {
+    .un.sun_family = AF_UNIX,
+    .un.sun_path = "/run/systemd/journal/stdout",
+  };
+  socklen_t salen;
+  char *header;
+  int fd;
+  size_t l;
+  int saved_errno;
+  /* Arbitrary large size for the sending buffer, from systemd */
+  int large_buffer_size = 8 * 1024 * 1024;
+
+  static_assert (LOG_EMERG == 0, "Linux ABI defines LOG_EMERG");
+  static_assert (LOG_DEBUG == 7, "Linux ABI defines LOG_DEBUG");
+
+  fd = socket (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+
+  if (fd < 0)
+    goto fail;
+
+  salen = offsetof (struct sockaddr_un, sun_path) + strlen (sa.un.sun_path) + 1;
+
+  if (connect (fd, &sa.sa, salen) < 0)
+    goto fail;
+
+  if (shutdown (fd, SHUT_RD) < 0)
+    goto fail;
+
+  (void) setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &large_buffer_size,
+                     (socklen_t) sizeof (large_buffer_size));
+
+  if (identifier == NULL)
+    identifier = "";
+
+  if (priority < 0)
+    priority = 0;
+
+  if (priority > 7)
+    priority = 7;
+
+  l = strlen (identifier);
+  header = alloca (l + 1  /* identifier, newline */
+                   + 1    /* empty unit ID, newline */
+                   + 2    /* priority, newline */
+                   + 2    /* level prefix, newline */
+                   + 2    /* don't forward to syslog */
+                   + 2    /* don't forward to kmsg */
+                   + 2    /* don't forward to console */);
+  memcpy (header, identifier, l);
+  header[l++] = '\n';
+  header[l++] = '\n';   /* empty unit ID */
+  header[l++] = '0' + priority;
+  header[l++] = '\n';
+  header[l++] = '0' + !!level_prefix;
+  header[l++] = '\n';
+  header[l++] = '0';    /* don't forward to syslog */
+  header[l++] = '\n';
+  header[l++] = '0';    /* don't forward to kmsg */
+  header[l++] = '\n';
+  header[l++] = '0';    /* don't forward to console */
+  header[l++] = '\n';
+
+  if (write_all (fd, header, l) < 0)
+    goto fail;
+
+  return fd;
+
+fail:
+  saved_errno = errno;
+
+  if (fd >= 0)
+    close (fd);
+
+  errno = saved_errno;
+  return -1;
+}
+
+static void
+set_up_journal (const char *argv1)
+{
+  const char *identifier;
+  const char *slash;
+  int fd;
+
+  identifier = getenv ("GIO_LAUNCHED_DESKTOP_FILE");
+
+  if (identifier == NULL)
+    identifier = argv1;
+
+  slash = strrchr (identifier, '/');
+
+  if (slash != NULL && slash[1] != '\0')
+    identifier = slash + 1;
+
+  fd = journal_stream_fd (identifier, LOG_INFO, 0);
+
+  /* Silently ignore failure to open the Journal */
+  if (fd < 0)
+    return;
+
+  if (dup2 (fd, STDOUT_FILENO) != STDOUT_FILENO)
+    fprintf (stderr,
+             "gio-launch-desktop[%d]: Unable to redirect \"%s\" to Journal: %s",
+             getpid (),
+             identifier,
+             strerror (errno));
+
+  if (dup2 (fd, STDERR_FILENO) != STDERR_FILENO)
+    fprintf (stderr,
+             "gio-launch-desktop[%d]: Unable to redirect \"%s\" to Journal: %s",
+             getpid (),
+             identifier,
+             strerror (errno));
+
+  close (fd);
+}
+
+#endif
+
 int
 main (int argc, char *argv[])
 {
@@ -49,5 +240,9 @@ main (int argc, char *argv[])
 
   putenv (buf);
 
+#if defined(__linux__) && !defined(__BIONIC__)
+  set_up_journal (argv[1]);
+#endif
+
   return execvp (argv[1], argv + 1);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]