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