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