]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journal-send.c
tree-wide: introduce new SOCKADDR_UN_LEN() macro, and use it everywhere
[thirdparty/systemd.git] / src / journal / journal-send.c
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
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
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
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <printf.h>
23 #include <stddef.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <unistd.h>
27
28 #define SD_JOURNAL_SUPPRESS_LOCATION
29
30 #include "sd-journal.h"
31
32 #include "alloc-util.h"
33 #include "fd-util.h"
34 #include "fileio.h"
35 #include "io-util.h"
36 #include "memfd-util.h"
37 #include "socket-util.h"
38 #include "stdio-util.h"
39 #include "string-util.h"
40 #include "util.h"
41
42 #define SNDBUF_SIZE (8*1024*1024)
43
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); \
53 } while (false)
54
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
60 static int journal_fd(void) {
61 int fd;
62 static int fd_plus_one = 0;
63
64 retry:
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
72 fd_inc_sndbuf(fd, SNDBUF_SIZE);
73
74 if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
75 safe_close(fd);
76 goto retry;
77 }
78
79 return fd;
80 }
81
82 _public_ int sd_journal_print(int priority, const char *format, ...) {
83 int r;
84 va_list ap;
85
86 va_start(ap, format);
87 r = sd_journal_printv(priority, format, ap);
88 va_end(ap);
89
90 return r;
91 }
92
93 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
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
98 char buffer[8 + LINE_MAX], p[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
99 struct iovec iov[2];
100
101 assert_return(priority >= 0, -EINVAL);
102 assert_return(priority <= 7, -EINVAL);
103 assert_return(format, -EINVAL);
104
105 xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
106
107 memcpy(buffer, "MESSAGE=", 8);
108 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
109
110 zero(iov);
111 IOVEC_SET_STRING(iov[0], buffer);
112 IOVEC_SET_STRING(iov[1], p);
113
114 return sd_journal_sendv(iov, 2);
115 }
116
117 _printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
118 PROTECT_ERRNO;
119 int r, n = 0, i = 0, j;
120 struct iovec *iov = NULL;
121
122 assert(_iov);
123
124 if (extra > 0) {
125 n = MAX(extra * 2, extra + 4);
126 iov = malloc0(n * sizeof(struct iovec));
127 if (!iov) {
128 r = -ENOMEM;
129 goto fail;
130 }
131
132 i = extra;
133 }
134
135 while (format) {
136 struct iovec *c;
137 char *buffer;
138 va_list aq;
139
140 if (i >= n) {
141 n = MAX(i*2, 4);
142 c = realloc(iov, n * sizeof(struct iovec));
143 if (!c) {
144 r = -ENOMEM;
145 goto fail;
146 }
147
148 iov = c;
149 }
150
151 va_copy(aq, ap);
152 if (vasprintf(&buffer, format, aq) < 0) {
153 va_end(aq);
154 r = -ENOMEM;
155 goto fail;
156 }
157 va_end(aq);
158
159 VA_FORMAT_ADVANCE(format, ap);
160
161 IOVEC_SET_STRING(iov[i++], buffer);
162
163 format = va_arg(ap, char *);
164 }
165
166 *_iov = iov;
167
168 return i;
169
170 fail:
171 for (j = 0; j < i; j++)
172 free(iov[j].iov_base);
173
174 free(iov);
175
176 return r;
177 }
178
179 _public_ int sd_journal_send(const char *format, ...) {
180 int r, i, j;
181 va_list ap;
182 struct iovec *iov = NULL;
183
184 va_start(ap, format);
185 i = fill_iovec_sprintf(format, ap, 0, &iov);
186 va_end(ap);
187
188 if (_unlikely_(i < 0)) {
189 r = i;
190 goto finish;
191 }
192
193 r = sd_journal_sendv(iov, i);
194
195 finish:
196 for (j = 0; j < i; j++)
197 free(iov[j].iov_base);
198
199 free(iov);
200
201 return r;
202 }
203
204 _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
205 PROTECT_ERRNO;
206 int fd, r;
207 _cleanup_close_ int buffer_fd = -1;
208 struct iovec *w;
209 uint64_t *l;
210 int i, j = 0;
211 static const union sockaddr_union sa = {
212 .un.sun_family = AF_UNIX,
213 .un.sun_path = "/run/systemd/journal/socket",
214 };
215 struct msghdr mh = {
216 .msg_name = (struct sockaddr*) &sa.sa,
217 .msg_namelen = SOCKADDR_UN_LEN(sa.un),
218 };
219 ssize_t k;
220 bool have_syslog_identifier = false;
221 bool seal = true;
222
223 assert_return(iov, -EINVAL);
224 assert_return(n > 0, -EINVAL);
225
226 w = newa(struct iovec, n * 5 + 3);
227 l = newa(uint64_t, n);
228
229 for (i = 0; i < n; i++) {
230 char *c, *nl;
231
232 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1))
233 return -EINVAL;
234
235 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
236 if (_unlikely_(!c || c == iov[i].iov_base))
237 return -EINVAL;
238
239 have_syslog_identifier = have_syslog_identifier ||
240 (c == (char *) iov[i].iov_base + 17 &&
241 startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER"));
242
243 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
244 if (nl) {
245 if (_unlikely_(nl < c))
246 return -EINVAL;
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
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
290 fd = journal_fd();
291 if (_unlikely_(fd < 0))
292 return fd;
293
294 mh.msg_iov = w;
295 mh.msg_iovlen = j;
296
297 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
298 if (k >= 0)
299 return 0;
300
301 /* Fail silently if the journal is not available */
302 if (errno == ENOENT)
303 return 0;
304
305 if (errno != EMSGSIZE && errno != ENOBUFS)
306 return -errno;
307
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.
311 *
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_new(NULL);
317 if (buffer_fd < 0) {
318 if (buffer_fd == -ENOSYS) {
319 buffer_fd = open_tmpfile_unlinkable("/dev/shm", O_RDWR | O_CLOEXEC);
320 if (buffer_fd < 0)
321 return buffer_fd;
322
323 seal = false;
324 } else
325 return buffer_fd;
326 }
327
328 n = writev(buffer_fd, w, j);
329 if (n < 0)
330 return -errno;
331
332 if (seal) {
333 r = memfd_set_sealed(buffer_fd);
334 if (r < 0)
335 return r;
336 }
337
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;
343 }
344
345 static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
346 PROTECT_ERRNO;
347 size_t n, k;
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;
357 j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k);
358 if (errno == 0) {
359 char error[sizeof("ERRNO=")-1 + DECIMAL_STR_MAX(int) + 1];
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
371 xsprintf(error, "ERRNO=%i", _saved_errno_);
372
373 assert_cc(3 == LOG_ERR);
374 IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
375 IOVEC_SET_STRING(iov[skip+1], buffer);
376 IOVEC_SET_STRING(iov[skip+2], error);
377
378 return sd_journal_sendv(iov, skip + 3);
379 }
380
381 if (errno != ERANGE)
382 return -errno;
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
394 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
395 static const union sockaddr_union sa = {
396 .un.sun_family = AF_UNIX,
397 .un.sun_path = "/run/systemd/journal/stdout",
398 };
399 _cleanup_close_ int fd = -1;
400 char *header;
401 size_t l;
402 int r;
403
404 assert_return(priority >= 0, -EINVAL);
405 assert_return(priority <= 7, -EINVAL);
406
407 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
408 if (fd < 0)
409 return -errno;
410
411 r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
412 if (r < 0)
413 return -errno;
414
415 if (shutdown(fd, SHUT_RD) < 0)
416 return -errno;
417
418 fd_inc_sndbuf(fd, SNDBUF_SIZE);
419
420 if (!identifier)
421 identifier = "";
422
423 l = strlen(identifier);
424 header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
425
426 memcpy(header, identifier, l);
427 header[l++] = '\n';
428 header[l++] = '\n'; /* unit id */
429 header[l++] = '0' + priority;
430 header[l++] = '\n';
431 header[l++] = '0' + !!level_prefix;
432 header[l++] = '\n';
433 header[l++] = '0';
434 header[l++] = '\n';
435 header[l++] = '0';
436 header[l++] = '\n';
437 header[l++] = '0';
438 header[l++] = '\n';
439
440 r = loop_write(fd, header, l, false);
441 if (r < 0)
442 return r;
443
444 r = fd;
445 fd = -1;
446 return r;
447 }
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) {
461 char buffer[8 + LINE_MAX], p[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
462 struct iovec iov[5];
463 char *f;
464
465 assert_return(priority >= 0, -EINVAL);
466 assert_return(priority <= 7, -EINVAL);
467 assert_return(format, -EINVAL);
468
469 xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
470
471 memcpy(buffer, "MESSAGE=", 8);
472 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
473
474 /* func is initialized from __func__ which is not a macro, but
475 * a static const char[], hence cannot easily be prefixed with
476 * CODE_FUNC=, hence let's do it manually here. */
477 ALLOCA_CODE_FUNC(f, func);
478
479 zero(iov);
480 IOVEC_SET_STRING(iov[0], buffer);
481 IOVEC_SET_STRING(iov[1], p);
482 IOVEC_SET_STRING(iov[2], file);
483 IOVEC_SET_STRING(iov[3], line);
484 IOVEC_SET_STRING(iov[4], f);
485
486 return sd_journal_sendv(iov, ELEMENTSOF(iov));
487 }
488
489 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
490 int r, i, j;
491 va_list ap;
492 struct iovec *iov = NULL;
493 char *f;
494
495 va_start(ap, format);
496 i = fill_iovec_sprintf(format, ap, 3, &iov);
497 va_end(ap);
498
499 if (_unlikely_(i < 0)) {
500 r = i;
501 goto finish;
502 }
503
504 ALLOCA_CODE_FUNC(f, func);
505
506 IOVEC_SET_STRING(iov[0], file);
507 IOVEC_SET_STRING(iov[1], line);
508 IOVEC_SET_STRING(iov[2], f);
509
510 r = sd_journal_sendv(iov, i);
511
512 finish:
513 for (j = 3; j < i; j++)
514 free(iov[j].iov_base);
515
516 free(iov);
517
518 return r;
519 }
520
521 _public_ int sd_journal_sendv_with_location(
522 const char *file, const char *line,
523 const char *func,
524 const struct iovec *iov, int n) {
525
526 struct iovec *niov;
527 char *f;
528
529 assert_return(iov, -EINVAL);
530 assert_return(n > 0, -EINVAL);
531
532 niov = alloca(sizeof(struct iovec) * (n + 3));
533 memcpy(niov, iov, sizeof(struct iovec) * n);
534
535 ALLOCA_CODE_FUNC(f, func);
536
537 IOVEC_SET_STRING(niov[n++], file);
538 IOVEC_SET_STRING(niov[n++], line);
539 IOVEC_SET_STRING(niov[n++], f);
540
541 return sd_journal_sendv(niov, n);
542 }
543
544 _public_ int sd_journal_perror_with_location(
545 const char *file, const char *line,
546 const char *func,
547 const char *message) {
548
549 struct iovec iov[6];
550 char *f;
551
552 ALLOCA_CODE_FUNC(f, func);
553
554 IOVEC_SET_STRING(iov[0], file);
555 IOVEC_SET_STRING(iov[1], line);
556 IOVEC_SET_STRING(iov[2], f);
557
558 return fill_iovec_perror_and_send(message, 3, iov);
559 }