X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fjournal%2Fjournal-send.c;h=32e94af91f15b9c989efc399ef47ef7935e30526;hp=03bd17072830c3000911d8adb8fa10b1eadc0b04;hb=b070e7f3c9ed680c821bd89d42506695f2438506;hpb=0dad12c190b7493955cd60d2a1625199b1709f69 diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c index 03bd17072..32e94af91 100644 --- a/src/journal/journal-send.c +++ b/src/journal/journal-send.c @@ -26,10 +26,14 @@ #include #include +#define SD_JOURNAL_SUPPRESS_LOCATION + #include "sd-journal.h" #include "util.h" #include "socket-util.h" +#define SNDBUF_SIZE (8*1024*1024) + /* We open a single fd, and we'll share it with the current process, * all its threads, and all its subprocesses. This means we need to * initialize it atomically, and need to operate on it atomically @@ -47,6 +51,8 @@ retry: if (fd < 0) return -errno; + fd_inc_sndbuf(fd, SNDBUF_SIZE); + if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) { close_nointr_nofail(fd); goto retry; @@ -90,12 +96,26 @@ _public_ int sd_journal_printv(int priority, const char *format, va_list ap) { return sd_journal_sendv(iov, 2); } -_public_ int sd_journal_send(const char *format, ...) { - int r, n = 0, i = 0, j; - va_list ap; +static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) { + int r, n = 0, i, j; struct iovec *iov = NULL; + int saved_errno; + + assert(_iov); + saved_errno = errno; + + if (extra > 0) { + n = MAX(extra * 2, extra + 4); + iov = malloc0(n * sizeof(struct iovec)); + if (!iov) { + r = -ENOMEM; + goto fail; + } + + i = extra; + } else + i = 0; - va_start(ap, format); while (format) { struct iovec *c; char *buffer; @@ -120,11 +140,39 @@ _public_ int sd_journal_send(const char *format, ...) { format = va_arg(ap, char *); } + + *_iov = iov; + + errno = saved_errno; + return i; + +fail: + for (j = 0; j < i; j++) + free(iov[j].iov_base); + + free(iov); + + errno = saved_errno; + return r; +} + +_public_ int sd_journal_send(const char *format, ...) { + int r, i, j; + va_list ap; + struct iovec *iov = NULL; + + va_start(ap, format); + i = fill_iovec_sprintf(format, ap, 0, &iov); va_end(ap); + if (_unlikely_(i < 0)) { + r = i; + goto finish; + } + r = sd_journal_sendv(iov, i); -fail: +finish: for (j = 0; j < i; j++) free(iov[j].iov_base); @@ -137,38 +185,52 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) { int fd, buffer_fd; struct iovec *w; uint64_t *l; - int i, j = 0; + int r, i, j = 0; struct msghdr mh; struct sockaddr_un sa; - char path[] = "/tmp/journal.XXXXXX"; ssize_t k; + int saved_errno; union { struct cmsghdr cmsghdr; uint8_t buf[CMSG_SPACE(sizeof(int))]; } control; struct cmsghdr *cmsg; + /* We use /dev/shm instead of /tmp here, since we want this to + * be a tmpfs, and one that is available from early boot on + * and where unprivileged users can create files. */ + char path[] = "/dev/shm/journal.XXXXXX"; - if (!iov || n <= 0) + if (_unlikely_(!iov)) return -EINVAL; + if (_unlikely_(n <= 0)) + return -EINVAL; + + saved_errno = errno; + w = alloca(sizeof(struct iovec) * n * 5); l = alloca(sizeof(uint64_t) * n); for (i = 0; i < n; i++) { char *c, *nl; - if (!iov[i].iov_base || - iov[i].iov_len <= 1) - return -EINVAL; + if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1)) { + r = -EINVAL; + goto finish; + } c = memchr(iov[i].iov_base, '=', iov[i].iov_len); - if (!c || c == iov[i].iov_base) - return -EINVAL; + if (_unlikely_(!c || c == iov[i].iov_base)) { + r = -EINVAL; + goto finish; + } nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len); if (nl) { - if (nl < c) - return -EINVAL; + if (_unlikely_(nl < c)) { + r = -EINVAL; + goto finish; + } /* Already includes a newline? Bummer, then * let's write the variable name, then a @@ -199,8 +261,10 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) { } fd = journal_fd(); - if (fd < 0) - return fd; + if (_unlikely_(fd < 0)) { + r = fd; + goto finish; + } zero(sa); sa.sun_family = AF_UNIX; @@ -213,29 +277,37 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) { mh.msg_iovlen = j; k = sendmsg(fd, &mh, MSG_NOSIGNAL); - if (k >= 0) - return 0; + if (k >= 0) { + r = 0; + goto finish; + } - if (errno != EMSGSIZE) - return -errno; + if (errno != EMSGSIZE && errno != ENOBUFS) { + r = -errno; + goto finish; + } /* Message doesn't fit... Let's dump the data in a temporary * file and just pass a file descriptor of it to the other * side */ buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR); - if (buffer_fd < 0) - return -errno; + if (buffer_fd < 0) { + r = -errno; + goto finish; + } if (unlink(path) < 0) { close_nointr_nofail(buffer_fd); - return -errno; + r = -errno; + goto finish; } n = writev(buffer_fd, w, j); - if (n < 0) { + if (n < 0) { close_nointr_nofail(buffer_fd); - return -errno; + r = -errno; + goto finish; } mh.msg_iov = NULL; @@ -256,10 +328,17 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) { k = sendmsg(fd, &mh, MSG_NOSIGNAL); close_nointr_nofail(buffer_fd); - if (k < 0) - return -errno; + if (k < 0) { + r = -errno; + goto finish; + } - return 0; + r = 0; + +finish: + errno = saved_errno; + + return r; } _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) { @@ -291,6 +370,8 @@ _public_ int sd_journal_stream_fd(const char *identifier, int priority, int leve return -errno; } + fd_inc_sndbuf(fd, SNDBUF_SIZE); + if (!identifier) identifier = ""; @@ -323,3 +404,113 @@ _public_ int sd_journal_stream_fd(const char *identifier, int priority, int leve return fd; } + +_public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) { + int r; + va_list ap; + + va_start(ap, format); + r = sd_journal_printv_with_location(priority, file, line, func, format, ap); + va_end(ap); + + return r; +} + +_public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) { + char buffer[8 + LINE_MAX], p[11]; + struct iovec iov[5]; + char *f; + size_t fl; + + if (priority < 0 || priority > 7) + return -EINVAL; + + if (_unlikely_(!format)) + return -EINVAL; + + snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK); + char_array_0(p); + + memcpy(buffer, "MESSAGE=", 8); + vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap); + char_array_0(buffer); + + /* func is initialized from __func__ which is not a macro, but + * a static const char[], hence cannot easily be prefixed with + * CODE_FUNC=, hence let's do it manually here. */ + fl = strlen(func); + f = alloca(fl + 10); + memcpy(f, "CODE_FUNC=", 10); + memcpy(f + 10, func, fl + 1); + + zero(iov); + IOVEC_SET_STRING(iov[0], buffer); + IOVEC_SET_STRING(iov[1], p); + IOVEC_SET_STRING(iov[2], file); + IOVEC_SET_STRING(iov[3], line); + IOVEC_SET_STRING(iov[4], f); + + return sd_journal_sendv(iov, ELEMENTSOF(iov)); +} + +_public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) { + int r, i, j; + va_list ap; + struct iovec *iov = NULL; + char *f; + size_t fl; + + va_start(ap, format); + i = fill_iovec_sprintf(format, ap, 3, &iov); + va_end(ap); + + if (_unlikely_(i < 0)) { + r = i; + goto finish; + } + + fl = strlen(func); + f = alloca(fl + 10); + memcpy(f, "CODE_FUNC=", 10); + memcpy(f + 10, func, fl + 1); + + IOVEC_SET_STRING(iov[0], file); + IOVEC_SET_STRING(iov[1], line); + IOVEC_SET_STRING(iov[2], f); + + r = sd_journal_sendv(iov, i); + +finish: + for (j = 3; j < i; j++) + free(iov[j].iov_base); + + free(iov); + + return r; +} + +_public_ int sd_journal_sendv_with_location(const char *file, const char *line, const char *func, const struct iovec *iov, int n) { + struct iovec *niov; + char *f; + size_t fl; + + if (_unlikely_(!iov)) + return -EINVAL; + + if (_unlikely_(n <= 0)) + return -EINVAL; + + niov = alloca(sizeof(struct iovec) * (n + 3)); + memcpy(niov, iov, sizeof(struct iovec) * n); + + fl = strlen(func); + f = alloca(fl + 10); + memcpy(f, "CODE_FUNC=", 10); + memcpy(f + 10, func, fl + 1); + + IOVEC_SET_STRING(niov[n++], file); + IOVEC_SET_STRING(niov[n++], line); + IOVEC_SET_STRING(niov[n++], f); + + return sd_journal_sendv(niov, n); +}