chiark / gitweb /
journal: when sending huge log messages prefer memfds over temporary files in /dev/shm
[elogind.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
36 #define SNDBUF_SIZE (8*1024*1024)
37
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
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
54 static int journal_fd(void) {
55         int fd;
56         static int fd_plus_one = 0;
57
58 retry:
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
66         fd_inc_sndbuf(fd, SNDBUF_SIZE);
67
68         if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
69                 safe_close(fd);
70                 goto retry;
71         }
72
73         return fd;
74 }
75
76 _public_ int sd_journal_print(int priority, const char *format, ...) {
77         int r;
78         va_list ap;
79
80         va_start(ap, format);
81         r = sd_journal_printv(priority, format, ap);
82         va_end(ap);
83
84         return r;
85 }
86
87 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
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];
93
94         assert_return(priority >= 0, -EINVAL);
95         assert_return(priority <= 7, -EINVAL);
96         assert_return(format, -EINVAL);
97
98         snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
99         char_array_0(p);
100
101         memcpy(buffer, "MESSAGE=", 8);
102         vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
103         char_array_0(buffer);
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_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         }
327
328         n = writev(buffer_fd, w, j);
329         if (n < 0)
330                 return -errno;
331
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
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[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
386                         snprintf(error, sizeof(error), "ERRNO=%u", _saved_errno_);
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
393                         return sd_journal_sendv(iov, skip + 3);
394                 }
395
396                 if (errno != ERANGE)
397                         return -errno;
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
409 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
410         union sockaddr_union sa = {
411                 .un.sun_family = AF_UNIX,
412                 .un.sun_path = "/run/systemd/journal/stdout",
413         };
414         _cleanup_close_ int fd = -1;
415         char *header;
416         size_t l;
417         int r;
418
419         assert_return(priority >= 0, -EINVAL);
420         assert_return(priority <= 7, -EINVAL);
421
422         fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
423         if (fd < 0)
424                 return -errno;
425
426         r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
427         if (r < 0)
428                 return -errno;
429
430         if (shutdown(fd, SHUT_RD) < 0)
431                 return -errno;
432
433         fd_inc_sndbuf(fd, SNDBUF_SIZE);
434
435         if (!identifier)
436                 identifier = "";
437
438         l = strlen(identifier);
439         header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
440
441         memcpy(header, identifier, l);
442         header[l++] = '\n';
443         header[l++] = '\n'; /* unit id */
444         header[l++] = '0' + priority;
445         header[l++] = '\n';
446         header[l++] = '0' + !!level_prefix;
447         header[l++] = '\n';
448         header[l++] = '0';
449         header[l++] = '\n';
450         header[l++] = '0';
451         header[l++] = '\n';
452         header[l++] = '0';
453         header[l++] = '\n';
454
455         r = (int) loop_write(fd, header, l, false);
456         if (r < 0)
457                 return r;
458
459         if ((size_t) r != l)
460                 return -errno;
461
462         r = fd;
463         fd = -1;
464         return r;
465 }
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;
482
483         assert_return(priority >= 0, -EINVAL);
484         assert_return(priority <= 7, -EINVAL);
485         assert_return(format, -EINVAL);
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. */
497         ALLOCA_CODE_FUNC(f, func);
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;
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
524         ALLOCA_CODE_FUNC(f, func);
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
532 finish:
533         for (j = 3; j < i; j++)
534                 free(iov[j].iov_base);
535
536         free(iov);
537
538         return r;
539 }
540
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
546         struct iovec *niov;
547         char *f;
548
549         assert_return(iov, -EINVAL);
550         assert_return(n > 0, -EINVAL);
551
552         niov = alloca(sizeof(struct iovec) * (n + 3));
553         memcpy(niov, iov, sizeof(struct iovec) * n);
554
555         ALLOCA_CODE_FUNC(f, func);
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 }
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];
570         char *f;
571
572         ALLOCA_CODE_FUNC(f, func);
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 }