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