summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <smcv@collabora.com>2022-07-14 13:11:30 +0100
committerPhilip Withnall <pwithnall@endlessos.org>2022-07-25 01:00:54 +0200
commit763643ceaacc4b9863562d35b606cb15104211fa (patch)
treea6b66a55accf5e1d2c7ebad85bb0caafaf66d4bf
parentae15c800ceeaa79f42cd1fa9f9ffabaab6658abf (diff)
downloadglib-763643ceaacc4b9863562d35b606cb15104211fa.tar.gz
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>
-rw-r--r--gio/gio-launch-desktop.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/gio/gio-launch-desktop.c b/gio/gio-launch-desktop.c
index 405e8c911..1af25e739 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);
}