chiark / gitweb /
util: add a bit of syntactic sugar for saving/restoring errno
[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         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 msghdr mh;
208         struct sockaddr_un sa;
209         ssize_t k;
210         union {
211                 struct cmsghdr cmsghdr;
212                 uint8_t buf[CMSG_SPACE(sizeof(int))];
213         } control;
214         struct cmsghdr *cmsg;
215         /* We use /dev/shm instead of /tmp here, since we want this to
216          * be a tmpfs, and one that is available from early boot on
217          * and where unprivileged users can create files. */
218         char path[] = "/dev/shm/journal.XXXXXX";
219         bool have_syslog_identifier = false;
220
221         if (_unlikely_(!iov))
222                 return -EINVAL;
223
224         if (_unlikely_(n <= 0))
225                 return -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                          memcmp(iov[i].iov_base, "SYSLOG_IDENTIFIER", 17) == 0);
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         zero(sa);
296         sa.sun_family = AF_UNIX;
297         strncpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path));
298
299         zero(mh);
300         mh.msg_name = &sa;
301         mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
302         mh.msg_iov = w;
303         mh.msg_iovlen = j;
304
305         k = sendmsg(fd, &mh, MSG_NOSIGNAL);
306         if (k >= 0)
307                 return 0;
308
309         if (errno != EMSGSIZE && errno != ENOBUFS)
310                 return -errno;
311
312         /* Message doesn't fit... Let's dump the data in a temporary
313          * file and just pass a file descriptor of it to the other
314          * side */
315
316         buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
317         if (buffer_fd < 0)
318                 return -errno;
319
320         if (unlink(path) < 0) {
321                 close_nointr_nofail(buffer_fd);
322                 return -errno;
323         }
324
325         n = writev(buffer_fd, w, j);
326         if (n < 0) {
327                 close_nointr_nofail(buffer_fd);
328                 return -errno;
329         }
330
331         mh.msg_iov = NULL;
332         mh.msg_iovlen = 0;
333
334         zero(control);
335         mh.msg_control = &control;
336         mh.msg_controllen = sizeof(control);
337
338         cmsg = CMSG_FIRSTHDR(&mh);
339         cmsg->cmsg_level = SOL_SOCKET;
340         cmsg->cmsg_type = SCM_RIGHTS;
341         cmsg->cmsg_len = CMSG_LEN(sizeof(int));
342         memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
343
344         mh.msg_controllen = cmsg->cmsg_len;
345
346         k = sendmsg(fd, &mh, MSG_NOSIGNAL);
347         close_nointr_nofail(buffer_fd);
348
349         if (k < 0)
350                 return -errno;
351
352         return 0;
353 }
354
355 static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
356         PROTECT_ERRNO;
357         size_t n, k;
358
359         k = isempty(message) ? 0 : strlen(message) + 2;
360         n = 8 + k + 256 + 1;
361
362         for (;;) {
363                 char buffer[n];
364                 char* j;
365
366                 errno = 0;
367                 j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k);
368                 if (errno == 0) {
369                         char error[6 + 10 + 1]; /* for a 32bit value */
370
371                         if (j != buffer + 8 + k)
372                                 memmove(buffer + 8 + k, j, strlen(j)+1);
373
374                         memcpy(buffer, "MESSAGE=", 8);
375
376                         if (k > 0) {
377                                 memcpy(buffer + 8, message, k - 2);
378                                 memcpy(buffer + 8 + k - 2, ": ", 2);
379                         }
380
381                         snprintf(error, sizeof(error), "ERRNO=%u", _saved_errno_);
382                         char_array_0(error);
383
384                         IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
385                         IOVEC_SET_STRING(iov[skip+1], buffer);
386                         IOVEC_SET_STRING(iov[skip+2], error);
387
388                         return sd_journal_sendv(iov, skip + 3);
389                 }
390
391                 if (errno != ERANGE)
392                         return -errno;
393
394                 n *= 2;
395         }
396 }
397
398 _public_ int sd_journal_perror(const char *message) {
399         struct iovec iovec[3];
400
401         return fill_iovec_perror_and_send(message, 0, iovec);
402 }
403
404 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
405         union sockaddr_union sa;
406         int fd;
407         char *header;
408         size_t l;
409         ssize_t r;
410
411         if (priority < 0 || priority > 7)
412                 return -EINVAL;
413
414         fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
415         if (fd < 0)
416                 return -errno;
417
418         zero(sa);
419         sa.un.sun_family = AF_UNIX;
420         strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
421
422         r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
423         if (r < 0) {
424                 close_nointr_nofail(fd);
425                 return -errno;
426         }
427
428         if (shutdown(fd, SHUT_RD) < 0) {
429                 close_nointr_nofail(fd);
430                 return -errno;
431         }
432
433         fd_inc_sndbuf(fd, SNDBUF_SIZE);
434
435         if (!identifier)
436                 identifier = "";
437
438         l = strlen(identifier);
439         header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
440
441         memcpy(header, identifier, l);
442         header[l++] = '\n';
443         header[l++] = '\n'; /* unit id */
444         header[l++] = '0' + priority;
445         header[l++] = '\n';
446         header[l++] = '0' + !!level_prefix;
447         header[l++] = '\n';
448         header[l++] = '0';
449         header[l++] = '\n';
450         header[l++] = '0';
451         header[l++] = '\n';
452         header[l++] = '0';
453         header[l++] = '\n';
454
455         r = loop_write(fd, header, l, false);
456         if (r < 0) {
457                 close_nointr_nofail(fd);
458                 return (int) r;
459         }
460
461         if ((size_t) r != l) {
462                 close_nointr_nofail(fd);
463                 return -errno;
464         }
465
466         return fd;
467 }
468
469 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
470         int r;
471         va_list ap;
472
473         va_start(ap, format);
474         r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
475         va_end(ap);
476
477         return r;
478 }
479
480 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
481         char buffer[8 + LINE_MAX], p[11];
482         struct iovec iov[5];
483         char *f;
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         ALLOCA_CODE_FUNC(f, func);
502
503         zero(iov);
504         IOVEC_SET_STRING(iov[0], buffer);
505         IOVEC_SET_STRING(iov[1], p);
506         IOVEC_SET_STRING(iov[2], file);
507         IOVEC_SET_STRING(iov[3], line);
508         IOVEC_SET_STRING(iov[4], f);
509
510         return sd_journal_sendv(iov, ELEMENTSOF(iov));
511 }
512
513 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
514         int r, i, j;
515         va_list ap;
516         struct iovec *iov = NULL;
517         char *f;
518
519         va_start(ap, format);
520         i = fill_iovec_sprintf(format, ap, 3, &iov);
521         va_end(ap);
522
523         if (_unlikely_(i < 0)) {
524                 r = i;
525                 goto finish;
526         }
527
528         ALLOCA_CODE_FUNC(f, func);
529
530         IOVEC_SET_STRING(iov[0], file);
531         IOVEC_SET_STRING(iov[1], line);
532         IOVEC_SET_STRING(iov[2], f);
533
534         r = sd_journal_sendv(iov, i);
535
536 finish:
537         for (j = 3; j < i; j++)
538                 free(iov[j].iov_base);
539
540         free(iov);
541
542         return r;
543 }
544
545 _public_ int sd_journal_sendv_with_location(
546                 const char *file, const char *line,
547                 const char *func,
548                 const struct iovec *iov, int n) {
549
550         struct iovec *niov;
551         char *f;
552
553         if (_unlikely_(!iov))
554                 return -EINVAL;
555
556         if (_unlikely_(n <= 0))
557                 return -EINVAL;
558
559         niov = alloca(sizeof(struct iovec) * (n + 3));
560         memcpy(niov, iov, sizeof(struct iovec) * n);
561
562         ALLOCA_CODE_FUNC(f, func);
563
564         IOVEC_SET_STRING(niov[n++], file);
565         IOVEC_SET_STRING(niov[n++], line);
566         IOVEC_SET_STRING(niov[n++], f);
567
568         return sd_journal_sendv(niov, n);
569 }
570
571 _public_ int sd_journal_perror_with_location(
572                 const char *file, const char *line,
573                 const char *func,
574                 const char *message) {
575
576         struct iovec iov[6];
577         char *f;
578
579         ALLOCA_CODE_FUNC(f, func);
580
581         IOVEC_SET_STRING(iov[0], file);
582         IOVEC_SET_STRING(iov[1], line);
583         IOVEC_SET_STRING(iov[2], f);
584
585         return fill_iovec_perror_and_send(message, 3, iov);
586 }