]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journal-send.c
d42f8262a57881db04a2f72c7c040949bdd60ebd
[thirdparty/systemd.git] / src / journal / journal-send.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <printf.h>
25 #include <stddef.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <unistd.h>
29
30 #define SD_JOURNAL_SUPPRESS_LOCATION
31
32 #include "sd-journal.h"
33
34 #include "fd-util.h"
35 #include "memfd-util.h"
36 #include "socket-util.h"
37 #include "string-util.h"
38 #include "util.h"
39
40 #define SNDBUF_SIZE (8*1024*1024)
41
42 #define ALLOCA_CODE_FUNC(f, func) \
43 do { \
44 size_t _fl; \
45 const char *_func = (func); \
46 char **_f = &(f); \
47 _fl = strlen(_func) + 1; \
48 *_f = alloca(_fl + 10); \
49 memcpy(*_f, "CODE_FUNC=", 10); \
50 memcpy(*_f + 10, _func, _fl); \
51 } while(false)
52
53 /* We open a single fd, and we'll share it with the current process,
54 * all its threads, and all its subprocesses. This means we need to
55 * initialize it atomically, and need to operate on it atomically
56 * never assuming we are the only user */
57
58 static int journal_fd(void) {
59 int fd;
60 static int fd_plus_one = 0;
61
62 retry:
63 if (fd_plus_one > 0)
64 return fd_plus_one - 1;
65
66 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
67 if (fd < 0)
68 return -errno;
69
70 fd_inc_sndbuf(fd, SNDBUF_SIZE);
71
72 if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
73 safe_close(fd);
74 goto retry;
75 }
76
77 return fd;
78 }
79
80 _public_ int sd_journal_print(int priority, const char *format, ...) {
81 int r;
82 va_list ap;
83
84 va_start(ap, format);
85 r = sd_journal_printv(priority, format, ap);
86 va_end(ap);
87
88 return r;
89 }
90
91 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
92
93 /* FIXME: Instead of limiting things to LINE_MAX we could do a
94 C99 variable-length array on the stack here in a loop. */
95
96 char buffer[8 + LINE_MAX], p[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
97 struct iovec iov[2];
98
99 assert_return(priority >= 0, -EINVAL);
100 assert_return(priority <= 7, -EINVAL);
101 assert_return(format, -EINVAL);
102
103 xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
104
105 memcpy(buffer, "MESSAGE=", 8);
106 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
107
108 zero(iov);
109 IOVEC_SET_STRING(iov[0], buffer);
110 IOVEC_SET_STRING(iov[1], p);
111
112 return sd_journal_sendv(iov, 2);
113 }
114
115 _printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
116 PROTECT_ERRNO;
117 int r, n = 0, i = 0, j;
118 struct iovec *iov = NULL;
119
120 assert(_iov);
121
122 if (extra > 0) {
123 n = MAX(extra * 2, extra + 4);
124 iov = malloc0(n * sizeof(struct iovec));
125 if (!iov) {
126 r = -ENOMEM;
127 goto fail;
128 }
129
130 i = extra;
131 }
132
133 while (format) {
134 struct iovec *c;
135 char *buffer;
136 va_list aq;
137
138 if (i >= n) {
139 n = MAX(i*2, 4);
140 c = realloc(iov, n * sizeof(struct iovec));
141 if (!c) {
142 r = -ENOMEM;
143 goto fail;
144 }
145
146 iov = c;
147 }
148
149 va_copy(aq, ap);
150 if (vasprintf(&buffer, format, aq) < 0) {
151 va_end(aq);
152 r = -ENOMEM;
153 goto fail;
154 }
155 va_end(aq);
156
157 VA_FORMAT_ADVANCE(format, ap);
158
159 IOVEC_SET_STRING(iov[i++], buffer);
160
161 format = va_arg(ap, char *);
162 }
163
164 *_iov = iov;
165
166 return i;
167
168 fail:
169 for (j = 0; j < i; j++)
170 free(iov[j].iov_base);
171
172 free(iov);
173
174 return r;
175 }
176
177 _public_ int sd_journal_send(const char *format, ...) {
178 int r, i, j;
179 va_list ap;
180 struct iovec *iov = NULL;
181
182 va_start(ap, format);
183 i = fill_iovec_sprintf(format, ap, 0, &iov);
184 va_end(ap);
185
186 if (_unlikely_(i < 0)) {
187 r = i;
188 goto finish;
189 }
190
191 r = sd_journal_sendv(iov, i);
192
193 finish:
194 for (j = 0; j < i; j++)
195 free(iov[j].iov_base);
196
197 free(iov);
198
199 return r;
200 }
201
202 _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
203 PROTECT_ERRNO;
204 int fd, r;
205 _cleanup_close_ int buffer_fd = -1;
206 struct iovec *w;
207 uint64_t *l;
208 int i, j = 0;
209 struct sockaddr_un sa = {
210 .sun_family = AF_UNIX,
211 .sun_path = "/run/systemd/journal/socket",
212 };
213 struct msghdr mh = {
214 .msg_name = &sa,
215 .msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path),
216 };
217 ssize_t k;
218 bool have_syslog_identifier = false;
219 bool seal = true;
220
221 assert_return(iov, -EINVAL);
222 assert_return(n > 0, -EINVAL);
223
224 w = alloca(sizeof(struct iovec) * n * 5 + 3);
225 l = alloca(sizeof(uint64_t) * n);
226
227 for (i = 0; i < n; i++) {
228 char *c, *nl;
229
230 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1))
231 return -EINVAL;
232
233 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
234 if (_unlikely_(!c || c == iov[i].iov_base))
235 return -EINVAL;
236
237 have_syslog_identifier = have_syslog_identifier ||
238 (c == (char *) iov[i].iov_base + 17 &&
239 startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER"));
240
241 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
242 if (nl) {
243 if (_unlikely_(nl < c))
244 return -EINVAL;
245
246 /* Already includes a newline? Bummer, then
247 * let's write the variable name, then a
248 * newline, then the size (64bit LE), followed
249 * by the data and a final newline */
250
251 w[j].iov_base = iov[i].iov_base;
252 w[j].iov_len = c - (char*) iov[i].iov_base;
253 j++;
254
255 IOVEC_SET_STRING(w[j++], "\n");
256
257 l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
258 w[j].iov_base = &l[i];
259 w[j].iov_len = sizeof(uint64_t);
260 j++;
261
262 w[j].iov_base = c + 1;
263 w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
264 j++;
265
266 } else
267 /* Nothing special? Then just add the line and
268 * append a newline */
269 w[j++] = iov[i];
270
271 IOVEC_SET_STRING(w[j++], "\n");
272 }
273
274 if (!have_syslog_identifier &&
275 string_is_safe(program_invocation_short_name)) {
276
277 /* Implicitly add program_invocation_short_name, if it
278 * is not set explicitly. We only do this for
279 * program_invocation_short_name, and nothing else
280 * since everything else is much nicer to retrieve
281 * from the outside. */
282
283 IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER=");
284 IOVEC_SET_STRING(w[j++], program_invocation_short_name);
285 IOVEC_SET_STRING(w[j++], "\n");
286 }
287
288 fd = journal_fd();
289 if (_unlikely_(fd < 0))
290 return fd;
291
292 mh.msg_iov = w;
293 mh.msg_iovlen = j;
294
295 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
296 if (k >= 0)
297 return 0;
298
299 /* Fail silently if the journal is not available */
300 if (errno == ENOENT)
301 return 0;
302
303 if (errno != EMSGSIZE && errno != ENOBUFS)
304 return -errno;
305
306 /* Message doesn't fit... Let's dump the data in a memfd or
307 * temporary file and just pass a file descriptor of it to the
308 * other side.
309 *
310 * For the temporary files we use /dev/shm instead of /tmp
311 * here, since we want this to be a tmpfs, and one that is
312 * available from early boot on and where unprivileged users
313 * can create files. */
314 buffer_fd = memfd_new(NULL);
315 if (buffer_fd < 0) {
316 if (buffer_fd == -ENOSYS) {
317 buffer_fd = open_tmpfile("/dev/shm", O_RDWR | O_CLOEXEC);
318 if (buffer_fd < 0)
319 return buffer_fd;
320
321 seal = false;
322 } else
323 return buffer_fd;
324 }
325
326 n = writev(buffer_fd, w, j);
327 if (n < 0)
328 return -errno;
329
330 if (seal) {
331 r = memfd_set_sealed(buffer_fd);
332 if (r < 0)
333 return r;
334 }
335
336 return send_one_fd(fd, buffer_fd, 0);
337 }
338
339 static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
340 PROTECT_ERRNO;
341 size_t n, k;
342
343 k = isempty(message) ? 0 : strlen(message) + 2;
344 n = 8 + k + 256 + 1;
345
346 for (;;) {
347 char buffer[n];
348 char* j;
349
350 errno = 0;
351 j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k);
352 if (errno == 0) {
353 char error[sizeof("ERRNO=")-1 + DECIMAL_STR_MAX(int) + 1];
354
355 if (j != buffer + 8 + k)
356 memmove(buffer + 8 + k, j, strlen(j)+1);
357
358 memcpy(buffer, "MESSAGE=", 8);
359
360 if (k > 0) {
361 memcpy(buffer + 8, message, k - 2);
362 memcpy(buffer + 8 + k - 2, ": ", 2);
363 }
364
365 xsprintf(error, "ERRNO=%i", _saved_errno_);
366
367 IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
368 IOVEC_SET_STRING(iov[skip+1], buffer);
369 IOVEC_SET_STRING(iov[skip+2], error);
370
371 return sd_journal_sendv(iov, skip + 3);
372 }
373
374 if (errno != ERANGE)
375 return -errno;
376
377 n *= 2;
378 }
379 }
380
381 _public_ int sd_journal_perror(const char *message) {
382 struct iovec iovec[3];
383
384 return fill_iovec_perror_and_send(message, 0, iovec);
385 }
386
387 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
388 union sockaddr_union sa = {
389 .un.sun_family = AF_UNIX,
390 .un.sun_path = "/run/systemd/journal/stdout",
391 };
392 _cleanup_close_ int fd = -1;
393 char *header;
394 size_t l;
395 int r;
396
397 assert_return(priority >= 0, -EINVAL);
398 assert_return(priority <= 7, -EINVAL);
399
400 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
401 if (fd < 0)
402 return -errno;
403
404 r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
405 if (r < 0)
406 return -errno;
407
408 if (shutdown(fd, SHUT_RD) < 0)
409 return -errno;
410
411 fd_inc_sndbuf(fd, SNDBUF_SIZE);
412
413 if (!identifier)
414 identifier = "";
415
416 l = strlen(identifier);
417 header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
418
419 memcpy(header, identifier, l);
420 header[l++] = '\n';
421 header[l++] = '\n'; /* unit id */
422 header[l++] = '0' + priority;
423 header[l++] = '\n';
424 header[l++] = '0' + !!level_prefix;
425 header[l++] = '\n';
426 header[l++] = '0';
427 header[l++] = '\n';
428 header[l++] = '0';
429 header[l++] = '\n';
430 header[l++] = '0';
431 header[l++] = '\n';
432
433 r = loop_write(fd, header, l, false);
434 if (r < 0)
435 return r;
436
437 r = fd;
438 fd = -1;
439 return r;
440 }
441
442 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
443 int r;
444 va_list ap;
445
446 va_start(ap, format);
447 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
448 va_end(ap);
449
450 return r;
451 }
452
453 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
454 char buffer[8 + LINE_MAX], p[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
455 struct iovec iov[5];
456 char *f;
457
458 assert_return(priority >= 0, -EINVAL);
459 assert_return(priority <= 7, -EINVAL);
460 assert_return(format, -EINVAL);
461
462 xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
463
464 memcpy(buffer, "MESSAGE=", 8);
465 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
466
467 /* func is initialized from __func__ which is not a macro, but
468 * a static const char[], hence cannot easily be prefixed with
469 * CODE_FUNC=, hence let's do it manually here. */
470 ALLOCA_CODE_FUNC(f, func);
471
472 zero(iov);
473 IOVEC_SET_STRING(iov[0], buffer);
474 IOVEC_SET_STRING(iov[1], p);
475 IOVEC_SET_STRING(iov[2], file);
476 IOVEC_SET_STRING(iov[3], line);
477 IOVEC_SET_STRING(iov[4], f);
478
479 return sd_journal_sendv(iov, ELEMENTSOF(iov));
480 }
481
482 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
483 int r, i, j;
484 va_list ap;
485 struct iovec *iov = NULL;
486 char *f;
487
488 va_start(ap, format);
489 i = fill_iovec_sprintf(format, ap, 3, &iov);
490 va_end(ap);
491
492 if (_unlikely_(i < 0)) {
493 r = i;
494 goto finish;
495 }
496
497 ALLOCA_CODE_FUNC(f, func);
498
499 IOVEC_SET_STRING(iov[0], file);
500 IOVEC_SET_STRING(iov[1], line);
501 IOVEC_SET_STRING(iov[2], f);
502
503 r = sd_journal_sendv(iov, i);
504
505 finish:
506 for (j = 3; j < i; j++)
507 free(iov[j].iov_base);
508
509 free(iov);
510
511 return r;
512 }
513
514 _public_ int sd_journal_sendv_with_location(
515 const char *file, const char *line,
516 const char *func,
517 const struct iovec *iov, int n) {
518
519 struct iovec *niov;
520 char *f;
521
522 assert_return(iov, -EINVAL);
523 assert_return(n > 0, -EINVAL);
524
525 niov = alloca(sizeof(struct iovec) * (n + 3));
526 memcpy(niov, iov, sizeof(struct iovec) * n);
527
528 ALLOCA_CODE_FUNC(f, func);
529
530 IOVEC_SET_STRING(niov[n++], file);
531 IOVEC_SET_STRING(niov[n++], line);
532 IOVEC_SET_STRING(niov[n++], f);
533
534 return sd_journal_sendv(niov, n);
535 }
536
537 _public_ int sd_journal_perror_with_location(
538 const char *file, const char *line,
539 const char *func,
540 const char *message) {
541
542 struct iovec iov[6];
543 char *f;
544
545 ALLOCA_CODE_FUNC(f, func);
546
547 IOVEC_SET_STRING(iov[0], file);
548 IOVEC_SET_STRING(iov[1], line);
549 IOVEC_SET_STRING(iov[2], f);
550
551 return fill_iovec_perror_and_send(message, 3, iov);
552 }