Branch data Line data Source code
1 : : /* GIO - GLib Input, Output and Streaming Library
2 : : *
3 : : * Copyright 2004 Ximian Inc.
4 : : * Copyright 2011-2022 systemd contributors
5 : : * Copyright (C) 2018 Endless Mobile, Inc.
6 : : * Copyright 2022 Collabora Ltd.
7 : : *
8 : : * SPDX-License-Identifier: LGPL-2.1-or-later
9 : : *
10 : : * This library is free software; you can redistribute it and/or
11 : : * modify it under the terms of the GNU Lesser General Public
12 : : * License as published by the Free Software Foundation; either
13 : : * version 2.1 of the License, or (at your option) any later version.
14 : : *
15 : : * This library is distributed in the hope that it will be useful,
16 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 : : * Lesser General Public License for more details.
19 : : *
20 : : * You should have received a copy of the GNU Lesser General
21 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 : : *
23 : : * Author: Daniel Drake <drake@endlessm.com>
24 : : */
25 : :
26 : : /*
27 : : * gio-launch-desktop: GDesktopAppInfo helper
28 : : * Executable wrapper to set GIO_LAUNCHED_DESKTOP_FILE_PID
29 : : * There are complications when doing this in a fork()/exec() codepath,
30 : : * and it cannot otherwise be done with posix_spawn().
31 : : * This wrapper is designed to be minimal and lightweight.
32 : : * It does not even link against glib.
33 : : */
34 : :
35 : : #include <stdio.h>
36 : : #include <stdlib.h>
37 : : #include <sys/types.h>
38 : : #include <unistd.h>
39 : :
40 : : #if defined(__linux__) && !defined(__ANDROID__)
41 : : #include <alloca.h>
42 : : #include <errno.h>
43 : : #include <limits.h>
44 : : #include <stddef.h>
45 : : #include <string.h>
46 : : #include <syslog.h>
47 : : #include <sys/socket.h>
48 : : #include <sys/un.h>
49 : :
50 : : #include "gjournal-private.h"
51 : : #define GLIB_COMPILATION
52 : : #include "gmacros.h" /* For G_STATIC_ASSERT define */
53 : : #undef GLIB_COMPILATION
54 : :
55 : : /*
56 : : * write_all:
57 : : * @fd: a file descriptor
58 : : * @vbuf: a buffer
59 : : * @to_write: length of @vbuf
60 : : *
61 : : * Write all bytes from @vbuf to @fd, blocking if necessary.
62 : : *
63 : : * Returns: 0 on success, -1 with errno set on failure
64 : : */
65 : : static int
66 : 0 : write_all (int fd, const void *vbuf, size_t to_write)
67 : : {
68 : 0 : const char *buf = vbuf;
69 : :
70 : 0 : while (to_write > 0)
71 : : {
72 : 0 : ssize_t count = write (fd, buf, to_write);
73 : 0 : if (count < 0)
74 : : {
75 : 0 : if (errno != EINTR)
76 : 0 : return -1;
77 : : }
78 : : else
79 : : {
80 : 0 : to_write -= count;
81 : 0 : buf += count;
82 : : }
83 : : }
84 : :
85 : 0 : return 0;
86 : : }
87 : :
88 : : /*
89 : : * journal_stream_fd:
90 : : * @identifier: identifier (syslog tag) for logged messages
91 : : * @priority: a priority between `LOG_EMERG` and `LOG_DEBUG` inclusive
92 : : * @level_prefix: if nonzero, journald will interpret prefixes like <0>
93 : : * as specifying the priority for a line
94 : : *
95 : : * Reimplementation of sd_journal_stream_fd(), to avoid having to link
96 : : * gio-launch-desktop to libsystemd.
97 : : *
98 : : * Note that unlike the libsystemd version, this reports errors by returning
99 : : * -1 with errno set.
100 : : *
101 : : * Returns: a non-negative fd number, or -1 with errno set on error
102 : : */
103 : : static int
104 : 0 : journal_stream_fd (const char *identifier,
105 : : int priority,
106 : : int level_prefix)
107 : : {
108 : : union
109 : : {
110 : : struct sockaddr sa;
111 : : struct sockaddr_un un;
112 : 0 : } sa =
113 : : {
114 : : .un.sun_family = AF_UNIX,
115 : : .un.sun_path = "/run/systemd/journal/stdout",
116 : : };
117 : : socklen_t salen;
118 : : char *header;
119 : : int fd;
120 : : size_t l;
121 : : int saved_errno;
122 : : /* Arbitrary large size for the sending buffer, from systemd */
123 : 0 : int large_buffer_size = 8 * 1024 * 1024;
124 : :
125 : : G_STATIC_ASSERT (LOG_EMERG == 0 && sizeof "Linux ABI defines LOG_EMERG");
126 : : G_STATIC_ASSERT (LOG_DEBUG == 7 && sizeof "Linux ABI defines LOG_DEBUG");
127 : :
128 : 0 : fd = socket (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
129 : :
130 : 0 : if (fd < 0)
131 : 0 : goto fail;
132 : :
133 : 0 : salen = offsetof (struct sockaddr_un, sun_path) + (socklen_t) strlen (sa.un.sun_path) + 1;
134 : :
135 : 0 : if (connect (fd, &sa.sa, salen) < 0)
136 : 0 : goto fail;
137 : :
138 : 0 : if (shutdown (fd, SHUT_RD) < 0)
139 : 0 : goto fail;
140 : :
141 : 0 : (void) setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &large_buffer_size,
142 : : (socklen_t) sizeof (large_buffer_size));
143 : :
144 : 0 : if (identifier == NULL)
145 : 0 : identifier = "";
146 : :
147 : 0 : if (priority < 0)
148 : 0 : priority = 0;
149 : :
150 : 0 : if (priority > 7)
151 : 0 : priority = 7;
152 : :
153 : 0 : l = strlen (identifier);
154 : 0 : if (l > PATH_MAX)
155 : : {
156 : 0 : errno = EINVAL;
157 : 0 : goto fail;
158 : : }
159 : :
160 : 0 : header = alloca (l + 1 /* identifier, newline */
161 : : + 1 /* empty unit ID, newline */
162 : : + 2 /* priority, newline */
163 : : + 2 /* level prefix, newline */
164 : : + 2 /* don't forward to syslog */
165 : : + 2 /* don't forward to kmsg */
166 : : + 2 /* don't forward to console */);
167 : 0 : memcpy (header, identifier, l);
168 : 0 : header[l++] = '\n';
169 : 0 : header[l++] = '\n'; /* empty unit ID */
170 : 0 : header[l++] = '0' + priority;
171 : 0 : header[l++] = '\n';
172 : 0 : header[l++] = '0' + !!level_prefix;
173 : 0 : header[l++] = '\n';
174 : 0 : header[l++] = '0'; /* don't forward to syslog */
175 : 0 : header[l++] = '\n';
176 : 0 : header[l++] = '0'; /* don't forward to kmsg */
177 : 0 : header[l++] = '\n';
178 : 0 : header[l++] = '0'; /* don't forward to console */
179 : 0 : header[l++] = '\n';
180 : :
181 : 0 : if (write_all (fd, header, l) < 0)
182 : 0 : goto fail;
183 : :
184 : 0 : return fd;
185 : :
186 : 0 : fail:
187 : 0 : saved_errno = errno;
188 : :
189 : 0 : if (fd >= 0)
190 : 0 : close (fd);
191 : :
192 : 0 : errno = saved_errno;
193 : 0 : return -1;
194 : : }
195 : :
196 : : static void
197 : 100 : set_up_journal (const char *argv1)
198 : : {
199 : : int stdout_is_journal;
200 : : int stderr_is_journal;
201 : : const char *identifier;
202 : : const char *slash;
203 : : int fd;
204 : :
205 : 100 : stdout_is_journal = _g_fd_is_journal (STDOUT_FILENO);
206 : 100 : stderr_is_journal = _g_fd_is_journal (STDERR_FILENO);
207 : :
208 : 100 : if (!stdout_is_journal && !stderr_is_journal)
209 : 100 : return;
210 : :
211 : 0 : identifier = getenv ("GIO_LAUNCHED_DESKTOP_FILE");
212 : :
213 : 0 : if (identifier == NULL)
214 : 0 : identifier = argv1;
215 : :
216 : 0 : slash = strrchr (identifier, '/');
217 : :
218 : 0 : if (slash != NULL && slash[1] != '\0')
219 : 0 : identifier = slash + 1;
220 : :
221 : 0 : fd = journal_stream_fd (identifier, LOG_INFO, 0);
222 : :
223 : : /* Silently ignore failure to open the Journal */
224 : 0 : if (fd < 0)
225 : 0 : return;
226 : :
227 : 0 : if (stdout_is_journal && dup2 (fd, STDOUT_FILENO) != STDOUT_FILENO)
228 : 0 : fprintf (stderr,
229 : : "gio-launch-desktop[%d]: Unable to redirect \"%s\" to Journal: %s",
230 : : getpid (),
231 : : identifier,
232 : 0 : strerror (errno));
233 : :
234 : 0 : if (stderr_is_journal && dup2 (fd, STDERR_FILENO) != STDERR_FILENO)
235 : 0 : fprintf (stderr,
236 : : "gio-launch-desktop[%d]: Unable to redirect \"%s\" to Journal: %s",
237 : : getpid (),
238 : : identifier,
239 : 0 : strerror (errno));
240 : :
241 : 0 : close (fd);
242 : : }
243 : :
244 : : #endif
245 : :
246 : : int
247 : 100 : main (int argc, char *argv[])
248 : : {
249 : 100 : pid_t pid = getpid ();
250 : : char buf[50];
251 : : int r;
252 : :
253 : 100 : if (argc < 2)
254 : 0 : return -1;
255 : :
256 : 100 : r = snprintf (buf, sizeof (buf), "GIO_LAUNCHED_DESKTOP_FILE_PID=%ld", (long) pid);
257 : 100 : if (r < 0 || (size_t) r >= sizeof (buf))
258 : 0 : return -1;
259 : :
260 : 100 : putenv (buf);
261 : :
262 : : #if defined(__linux__) && !defined(__ANDROID__)
263 : 100 : set_up_journal (argv[1]);
264 : : #endif
265 : :
266 : 0 : return execvp (argv[1], argv + 1);
267 : : }
|