1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <printf.h>
6 #include <stddef.h>
7 #include <sys/un.h>
8 #include <unistd.h>
9 #if HAVE_VALGRIND_VALGRIND_H
10 #include <valgrind/valgrind.h>
11 #endif
12
13 #define SD_JOURNAL_SUPPRESS_LOCATION
14
15 #include "sd-journal.h"
16
17 #include "alloc-util.h"
18 #include "errno-util.h"
19 #include "fd-util.h"
20 #include "fileio.h"
21 #include "io-util.h"
22 #include "journal-send.h"
23 #include "memfd-util.h"
24 #include "socket-util.h"
25 #include "stdio-util.h"
26 #include "string-util.h"
27 #include "tmpfile-util.h"
28
29 #define SNDBUF_SIZE (8*1024*1024)
30
31 #define ALLOCA_CODE_FUNC(f, func) \
32 do { \
33 size_t _fl; \
34 const char *_func = (func); \
35 char **_f = &(f); \
36 _fl = strlen(_func) + 1; \
37 *_f = newa(char, _fl + 10); \
38 memcpy(*_f, "CODE_FUNC=", 10); \
39 memcpy(*_f + 10, _func, _fl); \
40 } while (false)
41
42 /* We open a single fd, and we'll share it with the current process,
43 * all its threads, and all its subprocesses. This means we need to
44 * initialize it atomically, and need to operate on it atomically
45 * never assuming we are the only user */
46 static int fd_plus_one = 0;
47
journal_fd(void)48 static int journal_fd(void) {
49 int fd;
50
51 retry:
52 if (fd_plus_one > 0)
53 return fd_plus_one - 1;
54
55 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
56 if (fd < 0)
57 return -errno;
58
59 fd_inc_sndbuf(fd, SNDBUF_SIZE);
60
61 if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
62 safe_close(fd);
63 goto retry;
64 }
65
66 return fd;
67 }
68
69 #if VALGRIND
close_journal_fd(void)70 void close_journal_fd(void) {
71 /* Be nice to valgrind. This is not atomic. This must be used only in tests. */
72
73 if (!RUNNING_ON_VALGRIND)
74 return;
75
76 if (getpid() != gettid())
77 return;
78
79 if (fd_plus_one <= 0)
80 return;
81
82 safe_close(fd_plus_one - 1);
83 fd_plus_one = 0;
84 }
85 #endif
86
sd_journal_print(int priority,const char * format,...)87 _public_ int sd_journal_print(int priority, const char *format, ...) {
88 int r;
89 va_list ap;
90
91 va_start(ap, format);
92 r = sd_journal_printv(priority, format, ap);
93 va_end(ap);
94
95 return r;
96 }
97
sd_journal_printv(int priority,const char * format,va_list ap)98 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
99 char p[STRLEN("PRIORITY=") + DECIMAL_STR_MAX(int) + 1];
100 char sbuf[LINE_MAX + 8] = "MESSAGE=";
101 struct iovec iov[2];
102 int len;
103 va_list aq;
104 char *buffer = sbuf;
105
106 assert_return(priority >= 0, -EINVAL);
107 assert_return(priority <= 7, -EINVAL);
108 assert_return(format, -EINVAL);
109
110 xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
111
112 va_copy(aq, ap);
113 len = vsnprintf(buffer + 8, LINE_MAX, format, aq);
114 va_end(aq);
115
116 if (len >= (int)LONG_LINE_MAX - 8)
117 return -ENOBUFS;
118
119 /* Allocate large buffer to accommodate big message */
120 if (len >= LINE_MAX) {
121 buffer = alloca_safe(len + 9);
122 memcpy(buffer, "MESSAGE=", 8);
123 assert_se(vsnprintf(buffer + 8, len + 1, format, ap) == len);
124 }
125
126 /* Strip trailing whitespace, keep prefix whitespace. */
127 (void) strstrip(buffer);
128
129 /* Suppress empty lines */
130 if (isempty(buffer + 8))
131 return 0;
132
133 iov[0] = IOVEC_MAKE_STRING(buffer);
134 iov[1] = IOVEC_MAKE_STRING(p);
135
136 return sd_journal_sendv(iov, 2);
137 }
138
fill_iovec_sprintf(const char * format,va_list ap,int extra,struct iovec ** _iov)139 _printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
140 PROTECT_ERRNO;
141 int r, n = 0, i = 0, j;
142 struct iovec *iov = NULL;
143
144 assert(_iov);
145
146 if (extra > 0) {
147 n = MAX(extra * 2, extra + 4);
148 iov = malloc0(n * sizeof(struct iovec));
149 if (!iov) {
150 r = -ENOMEM;
151 goto fail;
152 }
153
154 i = extra;
155 }
156
157 while (format) {
158 struct iovec *c;
159 char *buffer;
160 va_list aq;
161
162 if (i >= n) {
163 n = MAX(i*2, 4);
164 c = reallocarray(iov, n, sizeof(struct iovec));
165 if (!c) {
166 r = -ENOMEM;
167 goto fail;
168 }
169
170 iov = c;
171 }
172
173 va_copy(aq, ap);
174 if (vasprintf(&buffer, format, aq) < 0) {
175 va_end(aq);
176 r = -ENOMEM;
177 goto fail;
178 }
179 va_end(aq);
180
181 VA_FORMAT_ADVANCE(format, ap);
182
183 (void) strstrip(buffer); /* strip trailing whitespace, keep prefixing whitespace */
184
185 iov[i++] = IOVEC_MAKE_STRING(buffer);
186
187 format = va_arg(ap, char *);
188 }
189
190 *_iov = iov;
191
192 return i;
193
194 fail:
195 for (j = 0; j < i; j++)
196 free(iov[j].iov_base);
197
198 free(iov);
199
200 return r;
201 }
202
sd_journal_send(const char * format,...)203 _public_ int sd_journal_send(const char *format, ...) {
204 int r, i, j;
205 va_list ap;
206 struct iovec *iov = NULL;
207
208 va_start(ap, format);
209 i = fill_iovec_sprintf(format, ap, 0, &iov);
210 va_end(ap);
211
212 if (_unlikely_(i < 0)) {
213 r = i;
214 goto finish;
215 }
216
217 r = sd_journal_sendv(iov, i);
218
219 finish:
220 for (j = 0; j < i; j++)
221 free(iov[j].iov_base);
222
223 free(iov);
224
225 return r;
226 }
227
sd_journal_sendv(const struct iovec * iov,int n)228 _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
229 PROTECT_ERRNO;
230 int fd, r;
231 _cleanup_close_ int buffer_fd = -1;
232 struct iovec *w;
233 uint64_t *l;
234 int i, j = 0;
235 static const union sockaddr_union sa = {
236 .un.sun_family = AF_UNIX,
237 .un.sun_path = "/run/systemd/journal/socket",
238 };
239 struct msghdr mh = {
240 .msg_name = (struct sockaddr*) &sa.sa,
241 .msg_namelen = SOCKADDR_UN_LEN(sa.un),
242 };
243 ssize_t k;
244 bool have_syslog_identifier = false;
245 bool seal = true;
246
247 assert_return(iov, -EINVAL);
248 assert_return(n > 0, -EINVAL);
249
250 w = newa(struct iovec, n * 5 + 3);
251 l = newa(uint64_t, n);
252
253 for (i = 0; i < n; i++) {
254 char *c, *nl;
255
256 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1))
257 return -EINVAL;
258
259 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
260 if (_unlikely_(!c || c == iov[i].iov_base))
261 return -EINVAL;
262
263 have_syslog_identifier = have_syslog_identifier ||
264 (c == (char *) iov[i].iov_base + 17 &&
265 startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER"));
266
267 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
268 if (nl) {
269 if (_unlikely_(nl < c))
270 return -EINVAL;
271
272 /* Already includes a newline? Bummer, then
273 * let's write the variable name, then a
274 * newline, then the size (64bit LE), followed
275 * by the data and a final newline */
276
277 w[j++] = IOVEC_MAKE(iov[i].iov_base, c - (char*) iov[i].iov_base);
278 w[j++] = IOVEC_MAKE_STRING("\n");
279
280 l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
281 w[j++] = IOVEC_MAKE(&l[i], sizeof(uint64_t));
282
283 w[j++] = IOVEC_MAKE(c + 1, iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
284 } else
285 /* Nothing special? Then just add the line and
286 * append a newline */
287 w[j++] = iov[i];
288
289 w[j++] = IOVEC_MAKE_STRING("\n");
290 }
291
292 if (!have_syslog_identifier &&
293 string_is_safe(program_invocation_short_name)) {
294
295 /* Implicitly add program_invocation_short_name, if it
296 * is not set explicitly. We only do this for
297 * program_invocation_short_name, and nothing else
298 * since everything else is much nicer to retrieve
299 * from the outside. */
300
301 w[j++] = IOVEC_MAKE_STRING("SYSLOG_IDENTIFIER=");
302 w[j++] = IOVEC_MAKE_STRING(program_invocation_short_name);
303 w[j++] = IOVEC_MAKE_STRING("\n");
304 }
305
306 fd = journal_fd();
307 if (_unlikely_(fd < 0))
308 return fd;
309
310 mh.msg_iov = w;
311 mh.msg_iovlen = j;
312
313 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
314 if (k >= 0)
315 return 0;
316
317 /* Fail silently if the journal is not available */
318 if (errno == ENOENT)
319 return 0;
320
321 if (!IN_SET(errno, EMSGSIZE, ENOBUFS))
322 return -errno;
323
324 /* Message doesn't fit... Let's dump the data in a memfd or
325 * temporary file and just pass a file descriptor of it to the
326 * other side.
327 *
328 * For the temporary files we use /dev/shm instead of /tmp
329 * here, since we want this to be a tmpfs, and one that is
330 * available from early boot on and where unprivileged users
331 * can create files. */
332 buffer_fd = memfd_new(NULL);
333 if (buffer_fd < 0) {
334 if (buffer_fd == -ENOSYS) {
335 buffer_fd = open_tmpfile_unlinkable("/dev/shm", O_RDWR | O_CLOEXEC);
336 if (buffer_fd < 0)
337 return buffer_fd;
338
339 seal = false;
340 } else
341 return buffer_fd;
342 }
343
344 n = writev(buffer_fd, w, j);
345 if (n < 0)
346 return -errno;
347
348 if (seal) {
349 r = memfd_set_sealed(buffer_fd);
350 if (r < 0)
351 return r;
352 }
353
354 r = send_one_fd_sa(fd, buffer_fd, mh.msg_name, mh.msg_namelen, 0);
355 if (r == -ENOENT)
356 /* Fail silently if the journal is not available */
357 return 0;
358 return r;
359 }
360
fill_iovec_perror_and_send(const char * message,int skip,struct iovec iov[])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[STRLEN("ERRNO=") + DECIMAL_STR_MAX(int) + 1];
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 xsprintf(error, "ERRNO=%i", _saved_errno_);
388
389 assert_cc(3 == LOG_ERR);
390 iov[skip+0] = IOVEC_MAKE_STRING("PRIORITY=3");
391 iov[skip+1] = IOVEC_MAKE_STRING(buffer);
392 iov[skip+2] = IOVEC_MAKE_STRING(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
sd_journal_perror(const char * message)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
sd_journal_stream_fd(const char * identifier,int priority,int level_prefix)410 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
411 static const 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, SOCKADDR_UN_LEN(sa.un));
428 if (r < 0)
429 return -errno;
430
431 if (shutdown(fd, SHUT_RD) < 0)
432 return -errno;
433
434 (void) fd_inc_sndbuf(fd, SNDBUF_SIZE);
435
436 identifier = strempty(identifier);
437
438 l = strlen(identifier);
439 header = newa(char, 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 return r;
458
459 return TAKE_FD(fd);
460 }
461
sd_journal_print_with_location(int priority,const char * file,const char * line,const char * func,const char * format,...)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
sd_journal_printv_with_location(int priority,const char * file,const char * line,const char * func,const char * format,va_list ap)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 p[STRLEN("PRIORITY=") + DECIMAL_STR_MAX(int) + 1];
475 char sbuf[LINE_MAX + 8] = "MESSAGE=";
476 struct iovec iov[5];
477 char *f;
478 int len;
479 char *buffer = sbuf;
480 va_list aq;
481
482 assert_return(priority >= 0, -EINVAL);
483 assert_return(priority <= 7, -EINVAL);
484 assert_return(format, -EINVAL);
485
486 xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
487
488 va_copy(aq, ap);
489 len = vsnprintf(buffer + 8, LINE_MAX, format, aq);
490 va_end(aq);
491
492 if (len >= (int)LONG_LINE_MAX - 8)
493 return -ENOBUFS;
494
495 /* Allocate large buffer to accommodate big message */
496 if (len >= LINE_MAX) {
497 buffer = alloca_safe(len + 9);
498 memcpy(buffer, "MESSAGE=", 8);
499 assert_se(vsnprintf(buffer + 8, len + 1, format, ap) == len);
500 }
501
502 /* Strip trailing whitespace, keep prefixing whitespace */
503 (void) strstrip(buffer);
504
505 /* Suppress empty lines */
506 if (isempty(buffer + 8))
507 return 0;
508
509 /* func is initialized from __func__ which is not a macro, but
510 * a static const char[], hence cannot easily be prefixed with
511 * CODE_FUNC=, hence let's do it manually here. */
512 ALLOCA_CODE_FUNC(f, func);
513
514 iov[0] = IOVEC_MAKE_STRING(buffer);
515 iov[1] = IOVEC_MAKE_STRING(p);
516 iov[2] = IOVEC_MAKE_STRING(file);
517 iov[3] = IOVEC_MAKE_STRING(line);
518 iov[4] = IOVEC_MAKE_STRING(f);
519
520 return sd_journal_sendv(iov, ELEMENTSOF(iov));
521 }
522
sd_journal_send_with_location(const char * file,const char * line,const char * func,const char * format,...)523 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
524 _cleanup_free_ struct iovec *iov = NULL;
525 int r, i, j;
526 va_list ap;
527 char *f;
528
529 va_start(ap, format);
530 i = fill_iovec_sprintf(format, ap, 3, &iov);
531 va_end(ap);
532
533 if (_unlikely_(i < 0)) {
534 r = i;
535 goto finish;
536 }
537
538 ALLOCA_CODE_FUNC(f, func);
539
540 iov[0] = IOVEC_MAKE_STRING(file);
541 iov[1] = IOVEC_MAKE_STRING(line);
542 iov[2] = IOVEC_MAKE_STRING(f);
543
544 r = sd_journal_sendv(iov, i);
545
546 finish:
547 for (j = 3; j < i; j++)
548 free(iov[j].iov_base);
549
550 return r;
551 }
552
sd_journal_sendv_with_location(const char * file,const char * line,const char * func,const struct iovec * iov,int n)553 _public_ int sd_journal_sendv_with_location(
554 const char *file, const char *line,
555 const char *func,
556 const struct iovec *iov, int n) {
557
558 struct iovec *niov;
559 char *f;
560
561 assert_return(iov, -EINVAL);
562 assert_return(n > 0, -EINVAL);
563
564 niov = newa(struct iovec, n + 3);
565 memcpy(niov, iov, sizeof(struct iovec) * n);
566
567 ALLOCA_CODE_FUNC(f, func);
568
569 niov[n++] = IOVEC_MAKE_STRING(file);
570 niov[n++] = IOVEC_MAKE_STRING(line);
571 niov[n++] = IOVEC_MAKE_STRING(f);
572
573 return sd_journal_sendv(niov, n);
574 }
575
sd_journal_perror_with_location(const char * file,const char * line,const char * func,const char * message)576 _public_ int sd_journal_perror_with_location(
577 const char *file, const char *line,
578 const char *func,
579 const char *message) {
580
581 struct iovec iov[6];
582 char *f;
583
584 ALLOCA_CODE_FUNC(f, func);
585
586 iov[0] = IOVEC_MAKE_STRING(file);
587 iov[1] = IOVEC_MAKE_STRING(line);
588 iov[2] = IOVEC_MAKE_STRING(f);
589
590 return fill_iovec_perror_and_send(message, 3, iov);
591 }
592