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