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