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