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;
222 assert_return(iov, -EINVAL);
223 assert_return(n > 0, -EINVAL);
225 w = alloca(sizeof(struct iovec) * n * 5 + 3);
226 l = alloca(sizeof(uint64_t) * n);
228 for (i = 0; i < n; i++) {
231 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1))
234 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
235 if (_unlikely_(!c || c == iov[i].iov_base))
238 have_syslog_identifier = have_syslog_identifier ||
239 (c == (char *) iov[i].iov_base + 17 &&
240 startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER"));
242 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
244 if (_unlikely_(nl < c))
247 /* Already includes a newline? Bummer, then
248 * let's write the variable name, then a
249 * newline, then the size (64bit LE), followed
250 * by the data and a final newline */
252 w[j].iov_base = iov[i].iov_base;
253 w[j].iov_len = c - (char*) iov[i].iov_base;
256 IOVEC_SET_STRING(w[j++], "\n");
258 l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
259 w[j].iov_base = &l[i];
260 w[j].iov_len = sizeof(uint64_t);
263 w[j].iov_base = c + 1;
264 w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
268 /* Nothing special? Then just add the line and
269 * append a newline */
272 IOVEC_SET_STRING(w[j++], "\n");
275 if (!have_syslog_identifier &&
276 string_is_safe(program_invocation_short_name)) {
278 /* Implicitly add program_invocation_short_name, if it
279 * is not set explicitly. We only do this for
280 * program_invocation_short_name, and nothing else
281 * since everything else is much nicer to retrieve
282 * from the outside. */
284 IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER=");
285 IOVEC_SET_STRING(w[j++], program_invocation_short_name);
286 IOVEC_SET_STRING(w[j++], "\n");
290 if (_unlikely_(fd < 0))
296 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
300 /* Fail silently if the journal is not available */
304 if (errno != EMSGSIZE && errno != ENOBUFS)
307 /* Message doesn't fit... Let's dump the data in a temporary
308 * file and just pass a file descriptor of it to the other
311 * We use /dev/shm instead of /tmp here, since we want this to
312 * be a tmpfs, and one that is available from early boot on
313 * and where unprivileged users can create files. */
314 buffer_fd = open_tmpfile("/dev/shm", O_RDWR | O_CLOEXEC);
318 n = writev(buffer_fd, w, j);
326 mh.msg_control = &control;
327 mh.msg_controllen = sizeof(control);
329 cmsg = CMSG_FIRSTHDR(&mh);
330 cmsg->cmsg_level = SOL_SOCKET;
331 cmsg->cmsg_type = SCM_RIGHTS;
332 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
333 memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
335 mh.msg_controllen = cmsg->cmsg_len;
337 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
344 static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
348 k = isempty(message) ? 0 : strlen(message) + 2;
356 j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k);
358 char error[6 + 10 + 1]; /* for a 32bit value */
360 if (j != buffer + 8 + k)
361 memmove(buffer + 8 + k, j, strlen(j)+1);
363 memcpy(buffer, "MESSAGE=", 8);
366 memcpy(buffer + 8, message, k - 2);
367 memcpy(buffer + 8 + k - 2, ": ", 2);
370 snprintf(error, sizeof(error), "ERRNO=%u", _saved_errno_);
373 IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
374 IOVEC_SET_STRING(iov[skip+1], buffer);
375 IOVEC_SET_STRING(iov[skip+2], error);
377 return sd_journal_sendv(iov, skip + 3);
387 _public_ int sd_journal_perror(const char *message) {
388 struct iovec iovec[3];
390 return fill_iovec_perror_and_send(message, 0, iovec);
393 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
394 union sockaddr_union sa = {
395 .un.sun_family = AF_UNIX,
396 .un.sun_path = "/run/systemd/journal/stdout",
398 _cleanup_close_ int fd = -1;
403 assert_return(priority >= 0, -EINVAL);
404 assert_return(priority <= 7, -EINVAL);
406 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
410 r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
414 if (shutdown(fd, SHUT_RD) < 0)
417 fd_inc_sndbuf(fd, SNDBUF_SIZE);
422 l = strlen(identifier);
423 header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
425 memcpy(header, identifier, l);
427 header[l++] = '\n'; /* unit id */
428 header[l++] = '0' + priority;
430 header[l++] = '0' + !!level_prefix;
439 r = (int) loop_write(fd, header, l, false);
451 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
455 va_start(ap, format);
456 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
462 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
463 char buffer[8 + LINE_MAX], p[11];
467 assert_return(priority >= 0, -EINVAL);
468 assert_return(priority <= 7, -EINVAL);
469 assert_return(format, -EINVAL);
471 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
474 memcpy(buffer, "MESSAGE=", 8);
475 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
476 char_array_0(buffer);
478 /* func is initialized from __func__ which is not a macro, but
479 * a static const char[], hence cannot easily be prefixed with
480 * CODE_FUNC=, hence let's do it manually here. */
481 ALLOCA_CODE_FUNC(f, func);
484 IOVEC_SET_STRING(iov[0], buffer);
485 IOVEC_SET_STRING(iov[1], p);
486 IOVEC_SET_STRING(iov[2], file);
487 IOVEC_SET_STRING(iov[3], line);
488 IOVEC_SET_STRING(iov[4], f);
490 return sd_journal_sendv(iov, ELEMENTSOF(iov));
493 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
496 struct iovec *iov = NULL;
499 va_start(ap, format);
500 i = fill_iovec_sprintf(format, ap, 3, &iov);
503 if (_unlikely_(i < 0)) {
508 ALLOCA_CODE_FUNC(f, func);
510 IOVEC_SET_STRING(iov[0], file);
511 IOVEC_SET_STRING(iov[1], line);
512 IOVEC_SET_STRING(iov[2], f);
514 r = sd_journal_sendv(iov, i);
517 for (j = 3; j < i; j++)
518 free(iov[j].iov_base);
525 _public_ int sd_journal_sendv_with_location(
526 const char *file, const char *line,
528 const struct iovec *iov, int n) {
533 assert_return(iov, -EINVAL);
534 assert_return(n > 0, -EINVAL);
536 niov = alloca(sizeof(struct iovec) * (n + 3));
537 memcpy(niov, iov, sizeof(struct iovec) * n);
539 ALLOCA_CODE_FUNC(f, func);
541 IOVEC_SET_STRING(niov[n++], file);
542 IOVEC_SET_STRING(niov[n++], line);
543 IOVEC_SET_STRING(niov[n++], f);
545 return sd_journal_sendv(niov, n);
548 _public_ int sd_journal_perror_with_location(
549 const char *file, const char *line,
551 const char *message) {
556 ALLOCA_CODE_FUNC(f, func);
558 IOVEC_SET_STRING(iov[0], file);
559 IOVEC_SET_STRING(iov[1], line);
560 IOVEC_SET_STRING(iov[2], f);
562 return fill_iovec_perror_and_send(message, 3, iov);