chiark / gitweb /
journald: avoid logging to kmsg in the normal paths
[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
29 #define SD_JOURNAL_SUPPRESS_LOCATION
30
31 #include "sd-journal.h"
32 #include "util.h"
33 #include "socket-util.h"
34
35 #define SNDBUF_SIZE (8*1024*1024)
36
37 /* We open a single fd, and we'll share it with the current process,
38  * all its threads, and all its subprocesses. This means we need to
39  * initialize it atomically, and need to operate on it atomically
40  * never assuming we are the only user */
41
42 static int journal_fd(void) {
43         int fd;
44         static int fd_plus_one = 0;
45
46 retry:
47         if (fd_plus_one > 0)
48                 return fd_plus_one - 1;
49
50         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
51         if (fd < 0)
52                 return -errno;
53
54         fd_inc_sndbuf(fd, SNDBUF_SIZE);
55
56         if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
57                 close_nointr_nofail(fd);
58                 goto retry;
59         }
60
61         return fd;
62 }
63
64 _public_ int sd_journal_print(int priority, const char *format, ...) {
65         int r;
66         va_list ap;
67
68         va_start(ap, format);
69         r = sd_journal_printv(priority, format, ap);
70         va_end(ap);
71
72         return r;
73 }
74
75 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
76
77         /* FIXME: Instead of limiting things to LINE_MAX we could do a
78            C99 variable-length array on the stack here in a loop. */
79
80         char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2];
81
82         if (priority < 0 || priority > 7)
83                 return -EINVAL;
84
85         if (!format)
86                 return -EINVAL;
87
88         snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
89         char_array_0(p);
90
91         memcpy(buffer, "MESSAGE=", 8);
92         vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
93         char_array_0(buffer);
94
95         zero(iov);
96         IOVEC_SET_STRING(iov[0], buffer);
97         IOVEC_SET_STRING(iov[1], p);
98
99         return sd_journal_sendv(iov, 2);
100 }
101
102 static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
103         int r, n = 0, i = 0, j;
104         struct iovec *iov = NULL;
105         int saved_errno;
106
107         assert(_iov);
108         saved_errno = errno;
109
110         if (extra > 0) {
111                 n = MAX(extra * 2, extra + 4);
112                 iov = malloc0(n * sizeof(struct iovec));
113                 if (!iov) {
114                         r = -ENOMEM;
115                         goto fail;
116                 }
117
118                 i = extra;
119         }
120
121         while (format) {
122                 struct iovec *c;
123                 char *buffer;
124
125                 if (i >= n) {
126                         n = MAX(i*2, 4);
127                         c = realloc(iov, n * sizeof(struct iovec));
128                         if (!c) {
129                                 r = -ENOMEM;
130                                 goto fail;
131                         }
132
133                         iov = c;
134                 }
135
136                 if (vasprintf(&buffer, format, ap) < 0) {
137                         r = -ENOMEM;
138                         goto fail;
139                 }
140
141                 IOVEC_SET_STRING(iov[i++], buffer);
142
143                 format = va_arg(ap, char *);
144         }
145
146         *_iov = iov;
147
148         errno = saved_errno;
149         return i;
150
151 fail:
152         for (j = 0; j < i; j++)
153                 free(iov[j].iov_base);
154
155         free(iov);
156
157         errno = saved_errno;
158         return r;
159 }
160
161 _public_ int sd_journal_send(const char *format, ...) {
162         int r, i, j;
163         va_list ap;
164         struct iovec *iov = NULL;
165
166         va_start(ap, format);
167         i = fill_iovec_sprintf(format, ap, 0, &iov);
168         va_end(ap);
169
170         if (_unlikely_(i < 0)) {
171                 r = i;
172                 goto finish;
173         }
174
175         r = sd_journal_sendv(iov, i);
176
177 finish:
178         for (j = 0; j < i; j++)
179                 free(iov[j].iov_base);
180
181         free(iov);
182
183         return r;
184 }
185
186 _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
187         int fd, buffer_fd;
188         struct iovec *w;
189         uint64_t *l;
190         int r, i, j = 0;
191         struct msghdr mh;
192         struct sockaddr_un sa;
193         ssize_t k;
194         int saved_errno;
195         union {
196                 struct cmsghdr cmsghdr;
197                 uint8_t buf[CMSG_SPACE(sizeof(int))];
198         } control;
199         struct cmsghdr *cmsg;
200         /* We use /dev/shm instead of /tmp here, since we want this to
201          * be a tmpfs, and one that is available from early boot on
202          * and where unprivileged users can create files. */
203         char path[] = "/dev/shm/journal.XXXXXX";
204
205         if (_unlikely_(!iov))
206                 return -EINVAL;
207
208         if (_unlikely_(n <= 0))
209                 return -EINVAL;
210
211         saved_errno = errno;
212
213         w = alloca(sizeof(struct iovec) * n * 5);
214         l = alloca(sizeof(uint64_t) * n);
215
216         for (i = 0; i < n; i++) {
217                 char *c, *nl;
218
219                 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1)) {
220                         r = -EINVAL;
221                         goto finish;
222                 }
223
224                 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
225                 if (_unlikely_(!c || c == iov[i].iov_base)) {
226                         r = -EINVAL;
227                         goto finish;
228                 }
229
230                 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
231                 if (nl) {
232                         if (_unlikely_(nl < c)) {
233                                 r = -EINVAL;
234                                 goto finish;
235                         }
236
237                         /* Already includes a newline? Bummer, then
238                          * let's write the variable name, then a
239                          * newline, then the size (64bit LE), followed
240                          * by the data and a final newline */
241
242                         w[j].iov_base = iov[i].iov_base;
243                         w[j].iov_len = c - (char*) iov[i].iov_base;
244                         j++;
245
246                         IOVEC_SET_STRING(w[j++], "\n");
247
248                         l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
249                         w[j].iov_base = &l[i];
250                         w[j].iov_len = sizeof(uint64_t);
251                         j++;
252
253                         w[j].iov_base = c + 1;
254                         w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
255                         j++;
256
257                 } else
258                         /* Nothing special? Then just add the line and
259                          * append a newline */
260                         w[j++] = iov[i];
261
262                 IOVEC_SET_STRING(w[j++], "\n");
263         }
264
265         fd = journal_fd();
266         if (_unlikely_(fd < 0)) {
267                 r = fd;
268                 goto finish;
269         }
270
271         zero(sa);
272         sa.sun_family = AF_UNIX;
273         strncpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path));
274
275         zero(mh);
276         mh.msg_name = &sa;
277         mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
278         mh.msg_iov = w;
279         mh.msg_iovlen = j;
280
281         k = sendmsg(fd, &mh, MSG_NOSIGNAL);
282         if (k >= 0) {
283                 r = 0;
284                 goto finish;
285         }
286
287         if (errno != EMSGSIZE && errno != ENOBUFS) {
288                 r = -errno;
289                 goto finish;
290         }
291
292         /* Message doesn't fit... Let's dump the data in a temporary
293          * file and just pass a file descriptor of it to the other
294          * side */
295
296         buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
297         if (buffer_fd < 0) {
298                 r = -errno;
299                 goto finish;
300         }
301
302         if (unlink(path) < 0) {
303                 close_nointr_nofail(buffer_fd);
304                 r = -errno;
305                 goto finish;
306         }
307
308         n = writev(buffer_fd, w, j);
309         if (n < 0) {
310                 close_nointr_nofail(buffer_fd);
311                 r = -errno;
312                 goto finish;
313         }
314
315         mh.msg_iov = NULL;
316         mh.msg_iovlen = 0;
317
318         zero(control);
319         mh.msg_control = &control;
320         mh.msg_controllen = sizeof(control);
321
322         cmsg = CMSG_FIRSTHDR(&mh);
323         cmsg->cmsg_level = SOL_SOCKET;
324         cmsg->cmsg_type = SCM_RIGHTS;
325         cmsg->cmsg_len = CMSG_LEN(sizeof(int));
326         memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
327
328         mh.msg_controllen = cmsg->cmsg_len;
329
330         k = sendmsg(fd, &mh, MSG_NOSIGNAL);
331         close_nointr_nofail(buffer_fd);
332
333         if (k < 0) {
334                 r = -errno;
335                 goto finish;
336         }
337
338         r = 0;
339
340 finish:
341         errno = saved_errno;
342
343         return r;
344 }
345
346 static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
347         size_t n, k, r;
348         int saved_errno;
349
350         saved_errno = errno;
351
352         k = isempty(message) ? 0 : strlen(message) + 2;
353         n = 8 + k + 256 + 1;
354
355         for (;;) {
356                 char buffer[n];
357                 char* j;
358
359                 errno = 0;
360                 j = strerror_r(saved_errno, buffer + 8 + k, n - 8 - k);
361                 if (errno == 0) {
362                         char error[6 + 10 + 1]; /* for a 32bit value */
363
364                         if (j != buffer + 8 + k)
365                                 memmove(buffer + 8 + k, j, strlen(j)+1);
366
367                         memcpy(buffer, "MESSAGE=", 8);
368
369                         if (k > 0) {
370                                 memcpy(buffer + 8, message, k - 2);
371                                 memcpy(buffer + 8 + k - 2, ": ", 2);
372                         }
373
374                         snprintf(error, sizeof(error), "ERRNO=%u", saved_errno);
375                         char_array_0(error);
376
377                         IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
378                         IOVEC_SET_STRING(iov[skip+1], buffer);
379                         IOVEC_SET_STRING(iov[skip+2], error);
380
381                         r = sd_journal_sendv(iov, skip + 3);
382
383                         errno = saved_errno;
384                         return r;
385                 }
386
387                 if (errno != ERANGE) {
388                         r = -errno;
389                         errno = saved_errno;
390                         return r;
391                 }
392
393                 n *= 2;
394         }
395 }
396
397 _public_ int sd_journal_perror(const char *message) {
398         struct iovec iovec[3];
399
400         return fill_iovec_perror_and_send(message, 0, iovec);
401 }
402
403 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
404         union sockaddr_union sa;
405         int fd;
406         char *header;
407         size_t l;
408         ssize_t r;
409
410         if (priority < 0 || priority > 7)
411                 return -EINVAL;
412
413         fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
414         if (fd < 0)
415                 return -errno;
416
417         zero(sa);
418         sa.un.sun_family = AF_UNIX;
419         strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
420
421         r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
422         if (r < 0) {
423                 close_nointr_nofail(fd);
424                 return -errno;
425         }
426
427         if (shutdown(fd, SHUT_RD) < 0) {
428                 close_nointr_nofail(fd);
429                 return -errno;
430         }
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                 close_nointr_nofail(fd);
457                 return (int) r;
458         }
459
460         if ((size_t) r != l) {
461                 close_nointr_nofail(fd);
462                 return -errno;
463         }
464
465         return fd;
466 }
467
468 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
469         int r;
470         va_list ap;
471
472         va_start(ap, format);
473         r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
474         va_end(ap);
475
476         return r;
477 }
478
479 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
480         char buffer[8 + LINE_MAX], p[11];
481         struct iovec iov[5];
482         char *f;
483         size_t fl;
484
485         if (priority < 0 || priority > 7)
486                 return -EINVAL;
487
488         if (_unlikely_(!format))
489                 return -EINVAL;
490
491         snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
492         char_array_0(p);
493
494         memcpy(buffer, "MESSAGE=", 8);
495         vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
496         char_array_0(buffer);
497
498         /* func is initialized from __func__ which is not a macro, but
499          * a static const char[], hence cannot easily be prefixed with
500          * CODE_FUNC=, hence let's do it manually here. */
501         fl = strlen(func);
502         f = alloca(fl + 10);
503         memcpy(f, "CODE_FUNC=", 10);
504         memcpy(f + 10, func, fl + 1);
505
506         zero(iov);
507         IOVEC_SET_STRING(iov[0], buffer);
508         IOVEC_SET_STRING(iov[1], p);
509         IOVEC_SET_STRING(iov[2], file);
510         IOVEC_SET_STRING(iov[3], line);
511         IOVEC_SET_STRING(iov[4], f);
512
513         return sd_journal_sendv(iov, ELEMENTSOF(iov));
514 }
515
516 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
517         int r, i, j;
518         va_list ap;
519         struct iovec *iov = NULL;
520         char *f;
521         size_t fl;
522
523         va_start(ap, format);
524         i = fill_iovec_sprintf(format, ap, 3, &iov);
525         va_end(ap);
526
527         if (_unlikely_(i < 0)) {
528                 r = i;
529                 goto finish;
530         }
531
532         fl = strlen(func);
533         f = alloca(fl + 10);
534         memcpy(f, "CODE_FUNC=", 10);
535         memcpy(f + 10, func, fl + 1);
536
537         IOVEC_SET_STRING(iov[0], file);
538         IOVEC_SET_STRING(iov[1], line);
539         IOVEC_SET_STRING(iov[2], f);
540
541         r = sd_journal_sendv(iov, i);
542
543 finish:
544         for (j = 3; j < i; j++)
545                 free(iov[j].iov_base);
546
547         free(iov);
548
549         return r;
550 }
551
552 _public_ int sd_journal_sendv_with_location(
553                 const char *file, const char *line,
554                 const char *func,
555                 const struct iovec *iov, int n) {
556
557         struct iovec *niov;
558         char *f;
559         size_t fl;
560
561         if (_unlikely_(!iov))
562                 return -EINVAL;
563
564         if (_unlikely_(n <= 0))
565                 return -EINVAL;
566
567         niov = alloca(sizeof(struct iovec) * (n + 3));
568         memcpy(niov, iov, sizeof(struct iovec) * n);
569
570         fl = strlen(func);
571         f = alloca(fl + 10);
572         memcpy(f, "CODE_FUNC=", 10);
573         memcpy(f + 10, func, fl + 1);
574
575         IOVEC_SET_STRING(niov[n++], file);
576         IOVEC_SET_STRING(niov[n++], line);
577         IOVEC_SET_STRING(niov[n++], f);
578
579         return sd_journal_sendv(niov, n);
580 }
581
582 _public_ int sd_journal_perror_with_location(
583                 const char *file, const char *line,
584                 const char *func,
585                 const char *message) {
586
587         struct iovec iov[6];
588         size_t fl;
589         char *f;
590
591         fl = strlen(func);
592         f = alloca(fl + 10);
593         memcpy(f, "CODE_FUNC=", 10);
594         memcpy(f + 10, func, fl + 1);
595
596         IOVEC_SET_STRING(iov[0], file);
597         IOVEC_SET_STRING(iov[1], line);
598         IOVEC_SET_STRING(iov[2], f);
599
600         return fill_iovec_perror_and_send(message, 3, iov);
601 }