chiark / gitweb /
journal: if the data to be sent is larger than the maximum datagram size resort to...
[elogind.git] / src / journal / journal-send.c
index d51aec9690bf48e22988efeceb4bcba8022140bb..03bd17072830c3000911d8adb8fa10b1eadc0b04 100644 (file)
@@ -23,6 +23,8 @@
 #include <sys/un.h>
 #include <errno.h>
 #include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
 
 #include "sd-journal.h"
 #include "util.h"
@@ -132,12 +134,19 @@ fail:
 }
 
 _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
-        int fd;
+        int fd, buffer_fd;
         struct iovec *w;
         uint64_t *l;
         int i, j = 0;
         struct msghdr mh;
         struct sockaddr_un sa;
+        char path[] = "/tmp/journal.XXXXXX";
+        ssize_t k;
+        union {
+                struct cmsghdr cmsghdr;
+                uint8_t buf[CMSG_SPACE(sizeof(int))];
+        } control;
+        struct cmsghdr *cmsg;
 
         if (!iov || n <= 0)
                 return -EINVAL;
@@ -203,7 +212,51 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
         mh.msg_iov = w;
         mh.msg_iovlen = j;
 
-        if (sendmsg(fd, &mh, MSG_NOSIGNAL) < 0)
+        k = sendmsg(fd, &mh, MSG_NOSIGNAL);
+        if (k >= 0)
+                return 0;
+
+        if (errno != EMSGSIZE)
+                return -errno;
+
+        /* 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 (unlink(path) < 0) {
+                close_nointr_nofail(buffer_fd);
+                return -errno;
+        }
+
+        n = writev(buffer_fd, w, j);
+        if (n < 0)  {
+                close_nointr_nofail(buffer_fd);
+                return -errno;
+        }
+
+        mh.msg_iov = NULL;
+        mh.msg_iovlen = 0;
+
+        zero(control);
+        mh.msg_control = &control;
+        mh.msg_controllen = sizeof(control);
+
+        cmsg = CMSG_FIRSTHDR(&mh);
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_type = SCM_RIGHTS;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+        memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
+
+        mh.msg_controllen = cmsg->cmsg_len;
+
+        k = sendmsg(fd, &mh, MSG_NOSIGNAL);
+        close_nointr_nofail(buffer_fd);
+
+        if (k < 0)
                 return -errno;
 
         return 0;