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