1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
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.
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.
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/>.
22 #include <sys/socket.h>
30 #define SD_JOURNAL_SUPPRESS_LOCATION
32 #include "sd-journal.h"
34 #include "socket-util.h"
36 #define SNDBUF_SIZE (8*1024*1024)
38 #define ALLOCA_CODE_FUNC(f, func) \
41 const char *_func = (func); \
43 _fl = strlen(_func) + 1; \
44 *_f = alloca(_fl + 10); \
45 memcpy(*_f, "CODE_FUNC=", 10); \
46 memcpy(*_f + 10, _func, _fl); \
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 */
54 static int journal_fd(void) {
56 static int fd_plus_one = 0;
60 return fd_plus_one - 1;
62 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
66 fd_inc_sndbuf(fd, SNDBUF_SIZE);
68 if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
76 _public_ int sd_journal_print(int priority, const char *format, ...) {
81 r = sd_journal_printv(priority, format, ap);
87 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
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. */
92 char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2];
94 assert_return(priority >= 0, -EINVAL);
95 assert_return(priority <= 7, -EINVAL);
96 assert_return(format, -EINVAL);
98 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
101 memcpy(buffer, "MESSAGE=", 8);
102 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
103 char_array_0(buffer);
106 IOVEC_SET_STRING(iov[0], buffer);
107 IOVEC_SET_STRING(iov[1], p);
109 return sd_journal_sendv(iov, 2);
112 _printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
114 int r, n = 0, i = 0, j;
115 struct iovec *iov = NULL;
120 n = MAX(extra * 2, extra + 4);
121 iov = malloc0(n * sizeof(struct iovec));
137 c = realloc(iov, n * sizeof(struct iovec));
147 if (vasprintf(&buffer, format, aq) < 0) {
154 VA_FORMAT_ADVANCE(format, ap);
156 IOVEC_SET_STRING(iov[i++], buffer);
158 format = va_arg(ap, char *);
166 for (j = 0; j < i; j++)
167 free(iov[j].iov_base);
174 _public_ int sd_journal_send(const char *format, ...) {
177 struct iovec *iov = NULL;
179 va_start(ap, format);
180 i = fill_iovec_sprintf(format, ap, 0, &iov);
183 if (_unlikely_(i < 0)) {
188 r = sd_journal_sendv(iov, i);
191 for (j = 0; j < i; j++)
192 free(iov[j].iov_base);
199 _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
202 _cleanup_close_ int buffer_fd = -1;
206 struct sockaddr_un sa = {
207 .sun_family = AF_UNIX,
208 .sun_path = "/run/systemd/journal/socket",
212 .msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path),
216 struct cmsghdr cmsghdr;
217 uint8_t buf[CMSG_SPACE(sizeof(int))];
219 struct cmsghdr *cmsg;
220 bool have_syslog_identifier = false;
223 assert_return(iov, -EINVAL);
224 assert_return(n > 0, -EINVAL);
226 w = alloca(sizeof(struct iovec) * n * 5 + 3);
227 l = alloca(sizeof(uint64_t) * n);
229 for (i = 0; i < n; i++) {
232 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1))
235 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
236 if (_unlikely_(!c || c == iov[i].iov_base))
239 have_syslog_identifier = have_syslog_identifier ||
240 (c == (char *) iov[i].iov_base + 17 &&
241 startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER"));
243 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
245 if (_unlikely_(nl < c))
248 /* Already includes a newline? Bummer, then
249 * let's write the variable name, then a
250 * newline, then the size (64bit LE), followed
251 * by the data and a final newline */
253 w[j].iov_base = iov[i].iov_base;
254 w[j].iov_len = c - (char*) iov[i].iov_base;
257 IOVEC_SET_STRING(w[j++], "\n");
259 l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
260 w[j].iov_base = &l[i];
261 w[j].iov_len = sizeof(uint64_t);
264 w[j].iov_base = c + 1;
265 w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
269 /* Nothing special? Then just add the line and
270 * append a newline */
273 IOVEC_SET_STRING(w[j++], "\n");
276 if (!have_syslog_identifier &&
277 string_is_safe(program_invocation_short_name)) {
279 /* Implicitly add program_invocation_short_name, if it
280 * is not set explicitly. We only do this for
281 * program_invocation_short_name, and nothing else
282 * since everything else is much nicer to retrieve
283 * from the outside. */
285 IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER=");
286 IOVEC_SET_STRING(w[j++], program_invocation_short_name);
287 IOVEC_SET_STRING(w[j++], "\n");
291 if (_unlikely_(fd < 0))
297 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
301 /* Fail silently if the journal is not available */
305 if (errno != EMSGSIZE && errno != ENOBUFS)
308 /* Message doesn't fit... Let's dump the data in a memfd or
309 * temporary file and just pass a file descriptor of it to the
312 * For the temporary files we use /dev/shm instead of /tmp
313 * here, since we want this to be a tmpfs, and one that is
314 * available from early boot on and where unprivileged users
315 * can create files. */
316 buffer_fd = memfd_create("journal-message", MFD_ALLOW_SEALING | MFD_CLOEXEC);
318 if (errno == ENOSYS) {
319 buffer_fd = open_tmpfile("/dev/shm", O_RDWR | O_CLOEXEC);
328 n = writev(buffer_fd, w, j);
333 r = fcntl(buffer_fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL);
342 mh.msg_control = &control;
343 mh.msg_controllen = sizeof(control);
345 cmsg = CMSG_FIRSTHDR(&mh);
346 cmsg->cmsg_level = SOL_SOCKET;
347 cmsg->cmsg_type = SCM_RIGHTS;
348 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
349 memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
351 mh.msg_controllen = cmsg->cmsg_len;
353 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
360 static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
364 k = isempty(message) ? 0 : strlen(message) + 2;
372 j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k);
374 char error[6 + 10 + 1]; /* for a 32bit value */
376 if (j != buffer + 8 + k)
377 memmove(buffer + 8 + k, j, strlen(j)+1);
379 memcpy(buffer, "MESSAGE=", 8);
382 memcpy(buffer + 8, message, k - 2);
383 memcpy(buffer + 8 + k - 2, ": ", 2);
386 snprintf(error, sizeof(error), "ERRNO=%u", _saved_errno_);
389 IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
390 IOVEC_SET_STRING(iov[skip+1], buffer);
391 IOVEC_SET_STRING(iov[skip+2], error);
393 return sd_journal_sendv(iov, skip + 3);
403 _public_ int sd_journal_perror(const char *message) {
404 struct iovec iovec[3];
406 return fill_iovec_perror_and_send(message, 0, iovec);
409 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
410 union sockaddr_union sa = {
411 .un.sun_family = AF_UNIX,
412 .un.sun_path = "/run/systemd/journal/stdout",
414 _cleanup_close_ int fd = -1;
419 assert_return(priority >= 0, -EINVAL);
420 assert_return(priority <= 7, -EINVAL);
422 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
426 r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
430 if (shutdown(fd, SHUT_RD) < 0)
433 fd_inc_sndbuf(fd, SNDBUF_SIZE);
438 l = strlen(identifier);
439 header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
441 memcpy(header, identifier, l);
443 header[l++] = '\n'; /* unit id */
444 header[l++] = '0' + priority;
446 header[l++] = '0' + !!level_prefix;
455 r = (int) loop_write(fd, header, l, false);
467 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
471 va_start(ap, format);
472 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
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];
483 assert_return(priority >= 0, -EINVAL);
484 assert_return(priority <= 7, -EINVAL);
485 assert_return(format, -EINVAL);
487 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
490 memcpy(buffer, "MESSAGE=", 8);
491 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
492 char_array_0(buffer);
494 /* func is initialized from __func__ which is not a macro, but
495 * a static const char[], hence cannot easily be prefixed with
496 * CODE_FUNC=, hence let's do it manually here. */
497 ALLOCA_CODE_FUNC(f, func);
500 IOVEC_SET_STRING(iov[0], buffer);
501 IOVEC_SET_STRING(iov[1], p);
502 IOVEC_SET_STRING(iov[2], file);
503 IOVEC_SET_STRING(iov[3], line);
504 IOVEC_SET_STRING(iov[4], f);
506 return sd_journal_sendv(iov, ELEMENTSOF(iov));
509 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
512 struct iovec *iov = NULL;
515 va_start(ap, format);
516 i = fill_iovec_sprintf(format, ap, 3, &iov);
519 if (_unlikely_(i < 0)) {
524 ALLOCA_CODE_FUNC(f, func);
526 IOVEC_SET_STRING(iov[0], file);
527 IOVEC_SET_STRING(iov[1], line);
528 IOVEC_SET_STRING(iov[2], f);
530 r = sd_journal_sendv(iov, i);
533 for (j = 3; j < i; j++)
534 free(iov[j].iov_base);
541 _public_ int sd_journal_sendv_with_location(
542 const char *file, const char *line,
544 const struct iovec *iov, int n) {
549 assert_return(iov, -EINVAL);
550 assert_return(n > 0, -EINVAL);
552 niov = alloca(sizeof(struct iovec) * (n + 3));
553 memcpy(niov, iov, sizeof(struct iovec) * n);
555 ALLOCA_CODE_FUNC(f, func);
557 IOVEC_SET_STRING(niov[n++], file);
558 IOVEC_SET_STRING(niov[n++], line);
559 IOVEC_SET_STRING(niov[n++], f);
561 return sd_journal_sendv(niov, n);
564 _public_ int sd_journal_perror_with_location(
565 const char *file, const char *line,
567 const char *message) {
572 ALLOCA_CODE_FUNC(f, func);
574 IOVEC_SET_STRING(iov[0], file);
575 IOVEC_SET_STRING(iov[1], line);
576 IOVEC_SET_STRING(iov[2], f);
578 return fill_iovec_perror_and_send(message, 3, iov);