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)) {
69 close_nointr_nofail(fd);
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) {
205 struct sockaddr_un sa = {
206 .sun_family = AF_UNIX,
207 .sun_path = "/run/systemd/journal/socket",
211 .msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path),
215 struct cmsghdr cmsghdr;
216 uint8_t buf[CMSG_SPACE(sizeof(int))];
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;
225 assert_return(iov, -EINVAL);
226 assert_return(n > 0, -EINVAL);
228 w = alloca(sizeof(struct iovec) * n * 5 + 3);
229 l = alloca(sizeof(uint64_t) * n);
231 for (i = 0; i < n; i++) {
234 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1))
237 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
238 if (_unlikely_(!c || c == iov[i].iov_base))
241 have_syslog_identifier = have_syslog_identifier ||
242 (c == (char *) iov[i].iov_base + 17 &&
243 startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER"));
245 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
247 if (_unlikely_(nl < c))
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 */
255 w[j].iov_base = iov[i].iov_base;
256 w[j].iov_len = c - (char*) iov[i].iov_base;
259 IOVEC_SET_STRING(w[j++], "\n");
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);
266 w[j].iov_base = c + 1;
267 w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
271 /* Nothing special? Then just add the line and
272 * append a newline */
275 IOVEC_SET_STRING(w[j++], "\n");
278 if (!have_syslog_identifier &&
279 string_is_safe(program_invocation_short_name)) {
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. */
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");
293 if (_unlikely_(fd < 0))
299 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
303 /* Fail silently if the journal is not available */
307 if (errno != EMSGSIZE && errno != ENOBUFS)
310 /* Message doesn't fit... Let's dump the data in a temporary
311 * file and just pass a file descriptor of it to the other
314 buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
318 if (unlink(path) < 0) {
319 close_nointr_nofail(buffer_fd);
323 n = writev(buffer_fd, w, j);
325 close_nointr_nofail(buffer_fd);
333 mh.msg_control = &control;
334 mh.msg_controllen = sizeof(control);
336 cmsg = CMSG_FIRSTHDR(&mh);
337 cmsg->cmsg_level = SOL_SOCKET;
338 cmsg->cmsg_type = SCM_RIGHTS;
339 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
340 memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
342 mh.msg_controllen = cmsg->cmsg_len;
344 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
345 close_nointr_nofail(buffer_fd);
353 static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
357 k = isempty(message) ? 0 : strlen(message) + 2;
365 j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k);
367 char error[6 + 10 + 1]; /* for a 32bit value */
369 if (j != buffer + 8 + k)
370 memmove(buffer + 8 + k, j, strlen(j)+1);
372 memcpy(buffer, "MESSAGE=", 8);
375 memcpy(buffer + 8, message, k - 2);
376 memcpy(buffer + 8 + k - 2, ": ", 2);
379 snprintf(error, sizeof(error), "ERRNO=%u", _saved_errno_);
382 IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
383 IOVEC_SET_STRING(iov[skip+1], buffer);
384 IOVEC_SET_STRING(iov[skip+2], error);
386 return sd_journal_sendv(iov, skip + 3);
396 _public_ int sd_journal_perror(const char *message) {
397 struct iovec iovec[3];
399 return fill_iovec_perror_and_send(message, 0, iovec);
402 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
403 union sockaddr_union sa = {
404 .un.sun_family = AF_UNIX,
405 .un.sun_path = "/run/systemd/journal/stdout",
412 assert_return(priority >= 0, -EINVAL);
413 assert_return(priority <= 7, -EINVAL);
415 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
419 r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
421 close_nointr_nofail(fd);
425 if (shutdown(fd, SHUT_RD) < 0) {
426 close_nointr_nofail(fd);
430 fd_inc_sndbuf(fd, SNDBUF_SIZE);
435 l = strlen(identifier);
436 header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
438 memcpy(header, identifier, l);
440 header[l++] = '\n'; /* unit id */
441 header[l++] = '0' + priority;
443 header[l++] = '0' + !!level_prefix;
452 r = loop_write(fd, header, l, false);
454 close_nointr_nofail(fd);
458 if ((size_t) r != l) {
459 close_nointr_nofail(fd);
466 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
470 va_start(ap, format);
471 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
477 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
478 char buffer[8 + LINE_MAX], p[11];
482 assert_return(priority >= 0, -EINVAL);
483 assert_return(priority <= 7, -EINVAL);
484 assert_return(format, -EINVAL);
486 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
489 memcpy(buffer, "MESSAGE=", 8);
490 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
491 char_array_0(buffer);
493 /* func is initialized from __func__ which is not a macro, but
494 * a static const char[], hence cannot easily be prefixed with
495 * CODE_FUNC=, hence let's do it manually here. */
496 ALLOCA_CODE_FUNC(f, func);
499 IOVEC_SET_STRING(iov[0], buffer);
500 IOVEC_SET_STRING(iov[1], p);
501 IOVEC_SET_STRING(iov[2], file);
502 IOVEC_SET_STRING(iov[3], line);
503 IOVEC_SET_STRING(iov[4], f);
505 return sd_journal_sendv(iov, ELEMENTSOF(iov));
508 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
511 struct iovec *iov = NULL;
514 va_start(ap, format);
515 i = fill_iovec_sprintf(format, ap, 3, &iov);
518 if (_unlikely_(i < 0)) {
523 ALLOCA_CODE_FUNC(f, func);
525 IOVEC_SET_STRING(iov[0], file);
526 IOVEC_SET_STRING(iov[1], line);
527 IOVEC_SET_STRING(iov[2], f);
529 r = sd_journal_sendv(iov, i);
532 for (j = 3; j < i; j++)
533 free(iov[j].iov_base);
540 _public_ int sd_journal_sendv_with_location(
541 const char *file, const char *line,
543 const struct iovec *iov, int n) {
548 assert_return(iov, -EINVAL);
549 assert_return(n > 0, -EINVAL);
551 niov = alloca(sizeof(struct iovec) * (n + 3));
552 memcpy(niov, iov, sizeof(struct iovec) * n);
554 ALLOCA_CODE_FUNC(f, func);
556 IOVEC_SET_STRING(niov[n++], file);
557 IOVEC_SET_STRING(niov[n++], line);
558 IOVEC_SET_STRING(niov[n++], f);
560 return sd_journal_sendv(niov, n);
563 _public_ int sd_journal_perror_with_location(
564 const char *file, const char *line,
566 const char *message) {
571 ALLOCA_CODE_FUNC(f, func);
573 IOVEC_SET_STRING(iov[0], file);
574 IOVEC_SET_STRING(iov[1], line);
575 IOVEC_SET_STRING(iov[2], f);
577 return fill_iovec_perror_and_send(message, 3, iov);