chiark / gitweb /
machined: various simplifications
[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 #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 }