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 <stddef.h>
44 : : #include <string.h>
45 : : #include <syslog.h>
46 : : #include <sys/socket.h>
47 : : #include <sys/un.h>
48 : :
49 : : #include "gjournal-private.h"
50 : : #define GLIB_COMPILATION
51 : : #include "gmacros.h" /* For G_STATIC_ASSERT define */
52 : : #undef GLIB_COMPILATION
53 : :
54 : : /*
55 : : * write_all:
56 : : * @fd: a file descriptor
57 : : * @vbuf: a buffer
58 : : * @to_write: length of @vbuf
59 : : *
60 : : * Write all bytes from @vbuf to @fd, blocking if necessary.
61 : : *
62 : : * Returns: 0 on success, -1 with errno set on failure
63 : : */
64 : : static int
65 : 0 : write_all (int fd, const void *vbuf, size_t to_write)
66 : : {
67 : 0 : const char *buf = vbuf;
68 : :
69 : 0 : while (to_write > 0)
70 : : {
71 : 0 : ssize_t count = write (fd, buf, to_write);
72 : 0 : if (count < 0)
73 : : {
74 : 0 : if (errno != EINTR)
75 : 0 : return -1;
76 : : }
77 : : else
78 : : {
79 : 0 : to_write -= count;
80 : 0 : buf += count;
81 : : }
82 : : }
83 : :
84 : 0 : return 0;
85 : : }
86 : :
87 : : /*
88 : : * journal_stream_fd:
89 : : * @identifier: identifier (syslog tag) for logged messages
90 : : * @priority: a priority between `LOG_EMERG` and `LOG_DEBUG` inclusive
91 : : * @level_prefix: if nonzero, journald will interpret prefixes like <0>
92 : : * as specifying the priority for a line
93 : : *
94 : : * Reimplementation of sd_journal_stream_fd(), to avoid having to link
95 : : * gio-launch-desktop to libsystemd.
96 : : *
97 : : * Note that unlike the libsystemd version, this reports errors by returning
98 : : * -1 with errno set.
99 : : *
100 : : * Returns: a non-negative fd number, or -1 with errno set on error
101 : : */
102 : : static int
103 : 0 : journal_stream_fd (const char *identifier,
104 : : int priority,
105 : : int level_prefix)
106 : : {
107 : : union
108 : : {
109 : : struct sockaddr sa;
110 : : struct sockaddr_un un;
111 : 0 : } sa =
112 : : {
113 : : .un.sun_family = AF_UNIX,
114 : : .un.sun_path = "/run/systemd/journal/stdout",
115 : : };
116 : : socklen_t salen;
117 : : char *header;
118 : : int fd;
119 : : size_t l;
120 : : int saved_errno;
121 : : /* Arbitrary large size for the sending buffer, from systemd */
122 : 0 : int large_buffer_size = 8 * 1024 * 1024;
123 : :
124 : : G_STATIC_ASSERT (LOG_EMERG == 0 && sizeof "Linux ABI defines LOG_EMERG");
125 : : G_STATIC_ASSERT (LOG_DEBUG == 7 && sizeof "Linux ABI defines LOG_DEBUG");
126 : :
127 : 0 : fd = socket (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
128 : :
129 : 0 : if (fd < 0)
130 : 0 : goto fail;
131 : :
132 : 0 : salen = offsetof (struct sockaddr_un, sun_path) + strlen (sa.un.sun_path) + 1;
133 : :
134 : 0 : if (connect (fd, &sa.sa, salen) < 0)
135 : 0 : goto fail;
136 : :
137 : 0 : if (shutdown (fd, SHUT_RD) < 0)
138 : 0 : goto fail;
139 : :
140 : 0 : (void) setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &large_buffer_size,
141 : : (socklen_t) sizeof (large_buffer_size));
142 : :
143 : 0 : if (identifier == NULL)
144 : 0 : identifier = "";
145 : :
146 : 0 : if (priority < 0)
147 : 0 : priority = 0;
148 : :
149 : 0 : if (priority > 7)
150 : 0 : priority = 7;
151 : :
152 : 0 : l = strlen (identifier);
153 : 0 : header = alloca (l + 1 /* identifier, newline */
154 : : + 1 /* empty unit ID, newline */
155 : : + 2 /* priority, newline */
156 : : + 2 /* level prefix, newline */
157 : : + 2 /* don't forward to syslog */
158 : : + 2 /* don't forward to kmsg */
159 : : + 2 /* don't forward to console */);
160 : 0 : memcpy (header, identifier, l);
161 : 0 : header[l++] = '\n';
162 : 0 : header[l++] = '\n'; /* empty unit ID */
163 : 0 : header[l++] = '0' + priority;
164 : 0 : header[l++] = '\n';
165 : 0 : header[l++] = '0' + !!level_prefix;
166 : 0 : header[l++] = '\n';
167 : 0 : header[l++] = '0'; /* don't forward to syslog */
168 : 0 : header[l++] = '\n';
169 : 0 : header[l++] = '0'; /* don't forward to kmsg */
170 : 0 : header[l++] = '\n';
171 : 0 : header[l++] = '0'; /* don't forward to console */
172 : 0 : header[l++] = '\n';
173 : :
174 : 0 : if (write_all (fd, header, l) < 0)
175 : 0 : goto fail;
176 : :
177 : 0 : return fd;
178 : :
179 : 0 : fail:
180 : 0 : saved_errno = errno;
181 : :
182 : 0 : if (fd >= 0)
183 : 0 : close (fd);
184 : :
185 : 0 : errno = saved_errno;
186 : 0 : return -1;
187 : : }
188 : :
189 : : static void
190 : 93 : set_up_journal (const char *argv1)
191 : : {
192 : : int stdout_is_journal;
193 : : int stderr_is_journal;
194 : : const char *identifier;
195 : : const char *slash;
196 : : int fd;
197 : :
198 : 93 : stdout_is_journal = _g_fd_is_journal (STDOUT_FILENO);
199 : 93 : stderr_is_journal = _g_fd_is_journal (STDERR_FILENO);
200 : :
201 : 93 : if (!stdout_is_journal && !stderr_is_journal)
202 : 93 : return;
203 : :
204 : 0 : identifier = getenv ("GIO_LAUNCHED_DESKTOP_FILE");
205 : :
206 : 0 : if (identifier == NULL)
207 : 0 : identifier = argv1;
208 : :
209 : 0 : slash = strrchr (identifier, '/');
210 : :
211 : 0 : if (slash != NULL && slash[1] != '\0')
212 : 0 : identifier = slash + 1;
213 : :
214 : 0 : fd = journal_stream_fd (identifier, LOG_INFO, 0);
215 : :
216 : : /* Silently ignore failure to open the Journal */
217 : 0 : if (fd < 0)
218 : 0 : return;
219 : :
220 : 0 : if (stdout_is_journal && dup2 (fd, STDOUT_FILENO) != STDOUT_FILENO)
221 : 0 : fprintf (stderr,
222 : : "gio-launch-desktop[%d]: Unable to redirect \"%s\" to Journal: %s",
223 : : getpid (),
224 : : identifier,
225 : 0 : strerror (errno));
226 : :
227 : 0 : if (stderr_is_journal && dup2 (fd, STDERR_FILENO) != STDERR_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 : close (fd);
235 : : }
236 : :
237 : : #endif
238 : :
239 : : int
240 : 93 : main (int argc, char *argv[])
241 : : {
242 : 93 : pid_t pid = getpid ();
243 : : char buf[50];
244 : : int r;
245 : :
246 : 93 : if (argc < 2)
247 : 0 : return -1;
248 : :
249 : 93 : r = snprintf (buf, sizeof (buf), "GIO_LAUNCHED_DESKTOP_FILE_PID=%ld", (long) pid);
250 : 93 : if (r < 0 || (size_t) r >= sizeof (buf))
251 : 0 : return -1;
252 : :
253 : 93 : putenv (buf);
254 : :
255 : : #if defined(__linux__) && !defined(__ANDROID__)
256 : 93 : set_up_journal (argv[1]);
257 : : #endif
258 : :
259 : 0 : return execvp (argv[1], argv + 1);
260 : : }
|