chiark / gitweb /
journal-gatewayd: SSL support
[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                 close_nointr_nofail(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         if (priority < 0 || priority > 7)
95                 return -EINVAL;
96
97         if (!format)
98                 return -EINVAL;
99
100         snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
101         char_array_0(p);
102
103         memcpy(buffer, "MESSAGE=", 8);
104         vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
105         char_array_0(buffer);
106
107         zero(iov);
108         IOVEC_SET_STRING(iov[0], buffer);
109         IOVEC_SET_STRING(iov[1], p);
110
111         return sd_journal_sendv(iov, 2);
112 }
113
114 static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
115         int r, n = 0, i = 0, j;
116         struct iovec *iov = NULL;
117         int saved_errno;
118
119         assert(_iov);
120         saved_errno = errno;
121
122         if (extra > 0) {
123                 n = MAX(extra * 2, extra + 4);
124                 iov = malloc0(n * sizeof(struct iovec));
125                 if (!iov) {
126                         r = -ENOMEM;
127                         goto fail;
128                 }
129
130                 i = extra;
131         }
132
133         while (format) {
134                 struct iovec *c;
135                 char *buffer;
136                 va_list aq;
137
138                 if (i >= n) {
139                         n = MAX(i*2, 4);
140                         c = realloc(iov, n * sizeof(struct iovec));
141                         if (!c) {
142                                 r = -ENOMEM;
143                                 goto fail;
144                         }
145
146                         iov = c;
147                 }
148
149                 va_copy(aq, ap);
150                 if (vasprintf(&buffer, format, aq) < 0) {
151                         va_end(aq);
152                         r = -ENOMEM;
153                         goto fail;
154                 }
155                 va_end(aq);
156
157                 VA_FORMAT_ADVANCE(format, ap);
158
159                 IOVEC_SET_STRING(iov[i++], buffer);
160
161                 format = va_arg(ap, char *);
162         }
163
164         *_iov = iov;
165
166         errno = saved_errno;
167         return i;
168
169 fail:
170         for (j = 0; j < i; j++)
171                 free(iov[j].iov_base);
172
173         free(iov);
174
175         errno = saved_errno;
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         int fd, buffer_fd;
206         struct iovec *w;
207         uint64_t *l;
208         int r, i, j = 0;
209         struct msghdr mh;
210         struct sockaddr_un sa;
211         ssize_t k;
212         int saved_errno;
213         union {
214                 struct cmsghdr cmsghdr;
215                 uint8_t buf[CMSG_SPACE(sizeof(int))];
216         } control;
217         struct cmsghdr *cmsg;
218         /* We use /dev/shm instead of /tmp here, since we want this to
219          * be a tmpfs, and one that is available from early boot on
220          * and where unprivileged users can create files. */
221         char path[] = "/dev/shm/journal.XXXXXX";
222         bool have_syslog_identifier = false;
223
224         if (_unlikely_(!iov))
225                 return -EINVAL;
226
227         if (_unlikely_(n <= 0))
228                 return -EINVAL;
229
230         saved_errno = errno;
231
232         w = alloca(sizeof(struct iovec) * n * 5 + 3);
233         l = alloca(sizeof(uint64_t) * n);
234
235         for (i = 0; i < n; i++) {
236                 char *c, *nl;
237
238                 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1)) {
239                         r = -EINVAL;
240                         goto finish;
241                 }
242
243                 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
244                 if (_unlikely_(!c || c == iov[i].iov_base)) {
245                         r = -EINVAL;
246                         goto finish;
247                 }
248
249                 have_syslog_identifier = have_syslog_identifier ||
250                         (c == (char *) iov[i].iov_base + 17 &&
251                          memcmp(iov[i].iov_base, "SYSLOG_IDENTIFIER", 17) == 0);
252
253                 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
254                 if (nl) {
255                         if (_unlikely_(nl < c)) {
256                                 r = -EINVAL;
257                                 goto finish;
258                         }
259
260                         /* Already includes a newline? Bummer, then
261                          * let's write the variable name, then a
262                          * newline, then the size (64bit LE), followed
263                          * by the data and a final newline */
264
265                         w[j].iov_base = iov[i].iov_base;
266                         w[j].iov_len = c - (char*) iov[i].iov_base;
267                         j++;
268
269                         IOVEC_SET_STRING(w[j++], "\n");
270
271                         l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
272                         w[j].iov_base = &l[i];
273                         w[j].iov_len = sizeof(uint64_t);
274                         j++;
275
276                         w[j].iov_base = c + 1;
277                         w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
278                         j++;
279
280                 } else
281                         /* Nothing special? Then just add the line and
282                          * append a newline */
283                         w[j++] = iov[i];
284
285                 IOVEC_SET_STRING(w[j++], "\n");
286         }
287
288         if (!have_syslog_identifier &&
289             string_is_safe(program_invocation_short_name)) {
290
291                 /* Implicitly add program_invocation_short_name, if it
292                  * is not set explicitly. We only do this for
293                  * program_invocation_short_name, and nothing else
294                  * since everything else is much nicer to retrieve
295                  * from the outside. */
296
297                 IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER=");
298                 IOVEC_SET_STRING(w[j++], program_invocation_short_name);
299                 IOVEC_SET_STRING(w[j++], "\n");
300         }
301
302         fd = journal_fd();
303         if (_unlikely_(fd < 0)) {
304                 r = fd;
305                 goto finish;
306         }
307
308         zero(sa);
309         sa.sun_family = AF_UNIX;
310         strncpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path));
311
312         zero(mh);
313         mh.msg_name = &sa;
314         mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
315         mh.msg_iov = w;
316         mh.msg_iovlen = j;
317
318         k = sendmsg(fd, &mh, MSG_NOSIGNAL);
319         if (k >= 0) {
320                 r = 0;
321                 goto finish;
322         }
323
324         if (errno != EMSGSIZE && errno != ENOBUFS) {
325                 r = -errno;
326                 goto finish;
327         }
328
329         /* Message doesn't fit... Let's dump the data in a temporary
330          * file and just pass a file descriptor of it to the other
331          * side */
332
333         buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
334         if (buffer_fd < 0) {
335                 r = -errno;
336                 goto finish;
337         }
338
339         if (unlink(path) < 0) {
340                 close_nointr_nofail(buffer_fd);
341                 r = -errno;
342                 goto finish;
343         }
344
345         n = writev(buffer_fd, w, j);
346         if (n < 0) {
347                 close_nointr_nofail(buffer_fd);
348                 r = -errno;
349                 goto finish;
350         }
351
352         mh.msg_iov = NULL;
353         mh.msg_iovlen = 0;
354
355         zero(control);
356         mh.msg_control = &control;
357         mh.msg_controllen = sizeof(control);
358
359         cmsg = CMSG_FIRSTHDR(&mh);
360         cmsg->cmsg_level = SOL_SOCKET;
361         cmsg->cmsg_type = SCM_RIGHTS;
362         cmsg->cmsg_len = CMSG_LEN(sizeof(int));
363         memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
364
365         mh.msg_controllen = cmsg->cmsg_len;
366
367         k = sendmsg(fd, &mh, MSG_NOSIGNAL);
368         close_nointr_nofail(buffer_fd);
369
370         if (k < 0) {
371                 r = -errno;
372                 goto finish;
373         }
374
375         r = 0;
376
377 finish:
378         errno = saved_errno;
379
380         return r;
381 }
382
383 static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
384         size_t n, k, r;
385         int saved_errno;
386
387         saved_errno = errno;
388
389         k = isempty(message) ? 0 : strlen(message) + 2;
390         n = 8 + k + 256 + 1;
391
392         for (;;) {
393                 char buffer[n];
394                 char* j;
395
396                 errno = 0;
397                 j = strerror_r(saved_errno, buffer + 8 + k, n - 8 - k);
398                 if (errno == 0) {
399                         char error[6 + 10 + 1]; /* for a 32bit value */
400
401                         if (j != buffer + 8 + k)
402                                 memmove(buffer + 8 + k, j, strlen(j)+1);
403
404                         memcpy(buffer, "MESSAGE=", 8);
405
406                         if (k > 0) {
407                                 memcpy(buffer + 8, message, k - 2);
408                                 memcpy(buffer + 8 + k - 2, ": ", 2);
409                         }
410
411                         snprintf(error, sizeof(error), "ERRNO=%u", saved_errno);
412                         char_array_0(error);
413
414                         IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
415                         IOVEC_SET_STRING(iov[skip+1], buffer);
416                         IOVEC_SET_STRING(iov[skip+2], error);
417
418                         r = sd_journal_sendv(iov, skip + 3);
419
420                         errno = saved_errno;
421                         return r;
422                 }
423
424                 if (errno != ERANGE) {
425                         r = -errno;
426                         errno = saved_errno;
427                         return r;
428                 }
429
430                 n *= 2;
431         }
432 }
433
434 _public_ int sd_journal_perror(const char *message) {
435         struct iovec iovec[3];
436
437         return fill_iovec_perror_and_send(message, 0, iovec);
438 }
439
440 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
441         union sockaddr_union sa;
442         int fd;
443         char *header;
444         size_t l;
445         ssize_t r;
446
447         if (priority < 0 || priority > 7)
448                 return -EINVAL;
449
450         fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
451         if (fd < 0)
452                 return -errno;
453
454         zero(sa);
455         sa.un.sun_family = AF_UNIX;
456         strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
457
458         r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
459         if (r < 0) {
460                 close_nointr_nofail(fd);
461                 return -errno;
462         }
463
464         if (shutdown(fd, SHUT_RD) < 0) {
465                 close_nointr_nofail(fd);
466                 return -errno;
467         }
468
469         fd_inc_sndbuf(fd, SNDBUF_SIZE);
470
471         if (!identifier)
472                 identifier = "";
473
474         l = strlen(identifier);
475         header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
476
477         memcpy(header, identifier, l);
478         header[l++] = '\n';
479         header[l++] = '\n'; /* unit id */
480         header[l++] = '0' + priority;
481         header[l++] = '\n';
482         header[l++] = '0' + !!level_prefix;
483         header[l++] = '\n';
484         header[l++] = '0';
485         header[l++] = '\n';
486         header[l++] = '0';
487         header[l++] = '\n';
488         header[l++] = '0';
489         header[l++] = '\n';
490
491         r = loop_write(fd, header, l, false);
492         if (r < 0) {
493                 close_nointr_nofail(fd);
494                 return (int) r;
495         }
496
497         if ((size_t) r != l) {
498                 close_nointr_nofail(fd);
499                 return -errno;
500         }
501
502         return fd;
503 }
504
505 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
506         int r;
507         va_list ap;
508
509         va_start(ap, format);
510         r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
511         va_end(ap);
512
513         return r;
514 }
515
516 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
517         char buffer[8 + LINE_MAX], p[11];
518         struct iovec iov[5];
519         char *f;
520
521         if (priority < 0 || priority > 7)
522                 return -EINVAL;
523
524         if (_unlikely_(!format))
525                 return -EINVAL;
526
527         snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
528         char_array_0(p);
529
530         memcpy(buffer, "MESSAGE=", 8);
531         vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
532         char_array_0(buffer);
533
534         /* func is initialized from __func__ which is not a macro, but
535          * a static const char[], hence cannot easily be prefixed with
536          * CODE_FUNC=, hence let's do it manually here. */
537         ALLOCA_CODE_FUNC(f, func);
538
539         zero(iov);
540         IOVEC_SET_STRING(iov[0], buffer);
541         IOVEC_SET_STRING(iov[1], p);
542         IOVEC_SET_STRING(iov[2], file);
543         IOVEC_SET_STRING(iov[3], line);
544         IOVEC_SET_STRING(iov[4], f);
545
546         return sd_journal_sendv(iov, ELEMENTSOF(iov));
547 }
548
549 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
550         int r, i, j;
551         va_list ap;
552         struct iovec *iov = NULL;
553         char *f;
554
555         va_start(ap, format);
556         i = fill_iovec_sprintf(format, ap, 3, &iov);
557         va_end(ap);
558
559         if (_unlikely_(i < 0)) {
560                 r = i;
561                 goto finish;
562         }
563
564         ALLOCA_CODE_FUNC(f, func);
565
566         IOVEC_SET_STRING(iov[0], file);
567         IOVEC_SET_STRING(iov[1], line);
568         IOVEC_SET_STRING(iov[2], f);
569
570         r = sd_journal_sendv(iov, i);
571
572 finish:
573         for (j = 3; j < i; j++)
574                 free(iov[j].iov_base);
575
576         free(iov);
577
578         return r;
579 }
580
581 _public_ int sd_journal_sendv_with_location(
582                 const char *file, const char *line,
583                 const char *func,
584                 const struct iovec *iov, int n) {
585
586         struct iovec *niov;
587         char *f;
588
589         if (_unlikely_(!iov))
590                 return -EINVAL;
591
592         if (_unlikely_(n <= 0))
593                 return -EINVAL;
594
595         niov = alloca(sizeof(struct iovec) * (n + 3));
596         memcpy(niov, iov, sizeof(struct iovec) * n);
597
598         ALLOCA_CODE_FUNC(f, func);
599
600         IOVEC_SET_STRING(niov[n++], file);
601         IOVEC_SET_STRING(niov[n++], line);
602         IOVEC_SET_STRING(niov[n++], f);
603
604         return sd_journal_sendv(niov, n);
605 }
606
607 _public_ int sd_journal_perror_with_location(
608                 const char *file, const char *line,
609                 const char *func,
610                 const char *message) {
611
612         struct iovec iov[6];
613         char *f;
614
615         ALLOCA_CODE_FUNC(f, func);
616
617         IOVEC_SET_STRING(iov[0], file);
618         IOVEC_SET_STRING(iov[1], line);
619         IOVEC_SET_STRING(iov[2], f);
620
621         return fill_iovec_perror_and_send(message, 3, iov);
622 }