]> git.proxmox.com Git - systemd.git/blob - src/journal/journal-send.c
Imported Upstream version 219
[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 union {
216 struct cmsghdr cmsghdr;
217 uint8_t buf[CMSG_SPACE(sizeof(int))];
218 } control;
219 struct cmsghdr *cmsg;
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 = alloca(sizeof(struct iovec) * n * 5 + 3);
227 l = alloca(sizeof(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("/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 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);
354 if (k < 0)
355 return -errno;
356
357 return 0;
358 }
359
360 static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
361 PROTECT_ERRNO;
362 size_t n, k;
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;
372 j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k);
373 if (errno == 0) {
374 char error[sizeof("ERRNO=")-1 + DECIMAL_STR_MAX(int) + 1];
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
386 xsprintf(error, "ERRNO=%i", _saved_errno_);
387
388 IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
389 IOVEC_SET_STRING(iov[skip+1], buffer);
390 IOVEC_SET_STRING(iov[skip+2], error);
391
392 return sd_journal_sendv(iov, skip + 3);
393 }
394
395 if (errno != ERANGE)
396 return -errno;
397
398 n *= 2;
399 }
400 }
401
402 _public_ int sd_journal_perror(const char *message) {
403 struct iovec iovec[3];
404
405 return fill_iovec_perror_and_send(message, 0, iovec);
406 }
407
408 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
409 union sockaddr_union sa = {
410 .un.sun_family = AF_UNIX,
411 .un.sun_path = "/run/systemd/journal/stdout",
412 };
413 _cleanup_close_ int fd = -1;
414 char *header;
415 size_t l;
416 int r;
417
418 assert_return(priority >= 0, -EINVAL);
419 assert_return(priority <= 7, -EINVAL);
420
421 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
422 if (fd < 0)
423 return -errno;
424
425 r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
426 if (r < 0)
427 return -errno;
428
429 if (shutdown(fd, SHUT_RD) < 0)
430 return -errno;
431
432 fd_inc_sndbuf(fd, SNDBUF_SIZE);
433
434 if (!identifier)
435 identifier = "";
436
437 l = strlen(identifier);
438 header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
439
440 memcpy(header, identifier, l);
441 header[l++] = '\n';
442 header[l++] = '\n'; /* unit id */
443 header[l++] = '0' + priority;
444 header[l++] = '\n';
445 header[l++] = '0' + !!level_prefix;
446 header[l++] = '\n';
447 header[l++] = '0';
448 header[l++] = '\n';
449 header[l++] = '0';
450 header[l++] = '\n';
451 header[l++] = '0';
452 header[l++] = '\n';
453
454 r = loop_write(fd, header, l, false);
455 if (r < 0)
456 return r;
457
458 r = fd;
459 fd = -1;
460 return r;
461 }
462
463 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
464 int r;
465 va_list ap;
466
467 va_start(ap, format);
468 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
469 va_end(ap);
470
471 return r;
472 }
473
474 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
475 char buffer[8 + LINE_MAX], p[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
476 struct iovec iov[5];
477 char *f;
478
479 assert_return(priority >= 0, -EINVAL);
480 assert_return(priority <= 7, -EINVAL);
481 assert_return(format, -EINVAL);
482
483 xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
484
485 memcpy(buffer, "MESSAGE=", 8);
486 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
487
488 /* func is initialized from __func__ which is not a macro, but
489 * a static const char[], hence cannot easily be prefixed with
490 * CODE_FUNC=, hence let's do it manually here. */
491 ALLOCA_CODE_FUNC(f, func);
492
493 zero(iov);
494 IOVEC_SET_STRING(iov[0], buffer);
495 IOVEC_SET_STRING(iov[1], p);
496 IOVEC_SET_STRING(iov[2], file);
497 IOVEC_SET_STRING(iov[3], line);
498 IOVEC_SET_STRING(iov[4], f);
499
500 return sd_journal_sendv(iov, ELEMENTSOF(iov));
501 }
502
503 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
504 int r, i, j;
505 va_list ap;
506 struct iovec *iov = NULL;
507 char *f;
508
509 va_start(ap, format);
510 i = fill_iovec_sprintf(format, ap, 3, &iov);
511 va_end(ap);
512
513 if (_unlikely_(i < 0)) {
514 r = i;
515 goto finish;
516 }
517
518 ALLOCA_CODE_FUNC(f, func);
519
520 IOVEC_SET_STRING(iov[0], file);
521 IOVEC_SET_STRING(iov[1], line);
522 IOVEC_SET_STRING(iov[2], f);
523
524 r = sd_journal_sendv(iov, i);
525
526 finish:
527 for (j = 3; j < i; j++)
528 free(iov[j].iov_base);
529
530 free(iov);
531
532 return r;
533 }
534
535 _public_ int sd_journal_sendv_with_location(
536 const char *file, const char *line,
537 const char *func,
538 const struct iovec *iov, int n) {
539
540 struct iovec *niov;
541 char *f;
542
543 assert_return(iov, -EINVAL);
544 assert_return(n > 0, -EINVAL);
545
546 niov = alloca(sizeof(struct iovec) * (n + 3));
547 memcpy(niov, iov, sizeof(struct iovec) * n);
548
549 ALLOCA_CODE_FUNC(f, func);
550
551 IOVEC_SET_STRING(niov[n++], file);
552 IOVEC_SET_STRING(niov[n++], line);
553 IOVEC_SET_STRING(niov[n++], f);
554
555 return sd_journal_sendv(niov, n);
556 }
557
558 _public_ int sd_journal_perror_with_location(
559 const char *file, const char *line,
560 const char *func,
561 const char *message) {
562
563 struct iovec iov[6];
564 char *f;
565
566 ALLOCA_CODE_FUNC(f, func);
567
568 IOVEC_SET_STRING(iov[0], file);
569 IOVEC_SET_STRING(iov[1], line);
570 IOVEC_SET_STRING(iov[2], f);
571
572 return fill_iovec_perror_and_send(message, 3, iov);
573 }