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