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 if (priority < 0 || priority > 7)
100 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
103 memcpy(buffer, "MESSAGE=", 8);
104 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
105 char_array_0(buffer);
108 IOVEC_SET_STRING(iov[0], buffer);
109 IOVEC_SET_STRING(iov[1], p);
111 return sd_journal_sendv(iov, 2);
114 static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
115 int r, n = 0, i = 0, j;
116 struct iovec *iov = NULL;
123 n = MAX(extra * 2, extra + 4);
124 iov = malloc0(n * sizeof(struct iovec));
140 c = realloc(iov, n * sizeof(struct iovec));
150 if (vasprintf(&buffer, format, aq) < 0) {
157 VA_FORMAT_ADVANCE(format, ap);
159 IOVEC_SET_STRING(iov[i++], buffer);
161 format = va_arg(ap, char *);
170 for (j = 0; j < i; j++)
171 free(iov[j].iov_base);
179 _public_ int sd_journal_send(const char *format, ...) {
182 struct iovec *iov = NULL;
184 va_start(ap, format);
185 i = fill_iovec_sprintf(format, ap, 0, &iov);
188 if (_unlikely_(i < 0)) {
193 r = sd_journal_sendv(iov, i);
196 for (j = 0; j < i; j++)
197 free(iov[j].iov_base);
204 _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
210 struct sockaddr_un sa;
214 struct cmsghdr cmsghdr;
215 uint8_t buf[CMSG_SPACE(sizeof(int))];
217 struct cmsghdr *cmsg;
218 /* We use /dev/shm instead of /tmp here, since we want this to
219 * be a tmpfs, and one that is available from early boot on
220 * and where unprivileged users can create files. */
221 char path[] = "/dev/shm/journal.XXXXXX";
222 bool have_syslog_identifier = false;
224 if (_unlikely_(!iov))
227 if (_unlikely_(n <= 0))
232 w = alloca(sizeof(struct iovec) * n * 5 + 3);
233 l = alloca(sizeof(uint64_t) * n);
235 for (i = 0; i < n; i++) {
238 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1)) {
243 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
244 if (_unlikely_(!c || c == iov[i].iov_base)) {
249 have_syslog_identifier = have_syslog_identifier ||
250 (c == (char *) iov[i].iov_base + 17 &&
251 memcmp(iov[i].iov_base, "SYSLOG_IDENTIFIER", 17) == 0);
253 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
255 if (_unlikely_(nl < c)) {
260 /* Already includes a newline? Bummer, then
261 * let's write the variable name, then a
262 * newline, then the size (64bit LE), followed
263 * by the data and a final newline */
265 w[j].iov_base = iov[i].iov_base;
266 w[j].iov_len = c - (char*) iov[i].iov_base;
269 IOVEC_SET_STRING(w[j++], "\n");
271 l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
272 w[j].iov_base = &l[i];
273 w[j].iov_len = sizeof(uint64_t);
276 w[j].iov_base = c + 1;
277 w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
281 /* Nothing special? Then just add the line and
282 * append a newline */
285 IOVEC_SET_STRING(w[j++], "\n");
288 if (!have_syslog_identifier &&
289 string_is_safe(program_invocation_short_name)) {
291 /* Implicitly add program_invocation_short_name, if it
292 * is not set explicitly. We only do this for
293 * program_invocation_short_name, and nothing else
294 * since everything else is much nicer to retrieve
295 * from the outside. */
297 IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER=");
298 IOVEC_SET_STRING(w[j++], program_invocation_short_name);
299 IOVEC_SET_STRING(w[j++], "\n");
303 if (_unlikely_(fd < 0)) {
309 sa.sun_family = AF_UNIX;
310 strncpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path));
314 mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
318 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
324 if (errno != EMSGSIZE && errno != ENOBUFS) {
329 /* Message doesn't fit... Let's dump the data in a temporary
330 * file and just pass a file descriptor of it to the other
333 buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
339 if (unlink(path) < 0) {
340 close_nointr_nofail(buffer_fd);
345 n = writev(buffer_fd, w, j);
347 close_nointr_nofail(buffer_fd);
356 mh.msg_control = &control;
357 mh.msg_controllen = sizeof(control);
359 cmsg = CMSG_FIRSTHDR(&mh);
360 cmsg->cmsg_level = SOL_SOCKET;
361 cmsg->cmsg_type = SCM_RIGHTS;
362 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
363 memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
365 mh.msg_controllen = cmsg->cmsg_len;
367 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
368 close_nointr_nofail(buffer_fd);
383 static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
389 k = isempty(message) ? 0 : strlen(message) + 2;
397 j = strerror_r(saved_errno, buffer + 8 + k, n - 8 - k);
399 char error[6 + 10 + 1]; /* for a 32bit value */
401 if (j != buffer + 8 + k)
402 memmove(buffer + 8 + k, j, strlen(j)+1);
404 memcpy(buffer, "MESSAGE=", 8);
407 memcpy(buffer + 8, message, k - 2);
408 memcpy(buffer + 8 + k - 2, ": ", 2);
411 snprintf(error, sizeof(error), "ERRNO=%u", saved_errno);
414 IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
415 IOVEC_SET_STRING(iov[skip+1], buffer);
416 IOVEC_SET_STRING(iov[skip+2], error);
418 r = sd_journal_sendv(iov, skip + 3);
424 if (errno != ERANGE) {
434 _public_ int sd_journal_perror(const char *message) {
435 struct iovec iovec[3];
437 return fill_iovec_perror_and_send(message, 0, iovec);
440 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
441 union sockaddr_union sa;
447 if (priority < 0 || priority > 7)
450 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
455 sa.un.sun_family = AF_UNIX;
456 strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
458 r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
460 close_nointr_nofail(fd);
464 if (shutdown(fd, SHUT_RD) < 0) {
465 close_nointr_nofail(fd);
469 fd_inc_sndbuf(fd, SNDBUF_SIZE);
474 l = strlen(identifier);
475 header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
477 memcpy(header, identifier, l);
479 header[l++] = '\n'; /* unit id */
480 header[l++] = '0' + priority;
482 header[l++] = '0' + !!level_prefix;
491 r = loop_write(fd, header, l, false);
493 close_nointr_nofail(fd);
497 if ((size_t) r != l) {
498 close_nointr_nofail(fd);
505 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
509 va_start(ap, format);
510 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
516 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
517 char buffer[8 + LINE_MAX], p[11];
521 if (priority < 0 || priority > 7)
524 if (_unlikely_(!format))
527 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
530 memcpy(buffer, "MESSAGE=", 8);
531 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
532 char_array_0(buffer);
534 /* func is initialized from __func__ which is not a macro, but
535 * a static const char[], hence cannot easily be prefixed with
536 * CODE_FUNC=, hence let's do it manually here. */
537 ALLOCA_CODE_FUNC(f, func);
540 IOVEC_SET_STRING(iov[0], buffer);
541 IOVEC_SET_STRING(iov[1], p);
542 IOVEC_SET_STRING(iov[2], file);
543 IOVEC_SET_STRING(iov[3], line);
544 IOVEC_SET_STRING(iov[4], f);
546 return sd_journal_sendv(iov, ELEMENTSOF(iov));
549 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
552 struct iovec *iov = NULL;
555 va_start(ap, format);
556 i = fill_iovec_sprintf(format, ap, 3, &iov);
559 if (_unlikely_(i < 0)) {
564 ALLOCA_CODE_FUNC(f, func);
566 IOVEC_SET_STRING(iov[0], file);
567 IOVEC_SET_STRING(iov[1], line);
568 IOVEC_SET_STRING(iov[2], f);
570 r = sd_journal_sendv(iov, i);
573 for (j = 3; j < i; j++)
574 free(iov[j].iov_base);
581 _public_ int sd_journal_sendv_with_location(
582 const char *file, const char *line,
584 const struct iovec *iov, int n) {
589 if (_unlikely_(!iov))
592 if (_unlikely_(n <= 0))
595 niov = alloca(sizeof(struct iovec) * (n + 3));
596 memcpy(niov, iov, sizeof(struct iovec) * n);
598 ALLOCA_CODE_FUNC(f, func);
600 IOVEC_SET_STRING(niov[n++], file);
601 IOVEC_SET_STRING(niov[n++], line);
602 IOVEC_SET_STRING(niov[n++], f);
604 return sd_journal_sendv(niov, n);
607 _public_ int sd_journal_perror_with_location(
608 const char *file, const char *line,
610 const char *message) {
615 ALLOCA_CODE_FUNC(f, func);
617 IOVEC_SET_STRING(iov[0], file);
618 IOVEC_SET_STRING(iov[1], line);
619 IOVEC_SET_STRING(iov[2], f);
621 return fill_iovec_perror_and_send(message, 3, iov);