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