summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/log.c74
-rw-r--r--src/macro.h30
2 files changed, 87 insertions, 17 deletions
diff --git a/src/log.c b/src/log.c
index 21fc9f4fa0..2dd3e978ff 100644
--- a/src/log.c
+++ b/src/log.c
@@ -40,6 +40,8 @@ static int console_fd = STDERR_FILENO;
static int syslog_fd = -1;
static int kmsg_fd = -1;
+static bool syslog_is_stream = false;
+
static bool show_color = false;
static bool show_location = false;
@@ -112,39 +114,63 @@ void log_close_syslog(void) {
syslog_fd = -1;
}
+static int create_log_socket(int type) {
+ struct timeval tv;
+ int fd;
+
+ if ((fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0)) < 0)
+ return -errno;
+
+ /* Make sure we don't block for more than 5s when talking to
+ * syslog */
+ timeval_store(&tv, SYSLOG_TIMEOUT_USEC);
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
+ close_nointr_nofail(fd);
+ return -errno;
+ }
+
+ return fd;
+}
+
static int log_open_syslog(void) {
union {
struct sockaddr sa;
struct sockaddr_un un;
} sa;
- struct timeval tv;
int r;
if (syslog_fd >= 0)
return 0;
- if ((syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
- r = -errno;
- goto fail;
- }
-
- /* Make sure we don't block for more than 5s when talking to
- * syslog */
- timeval_store(&tv, SYSLOG_TIMEOUT_USEC);
- if (setsockopt(syslog_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
- r = -errno;
- goto fail;
- }
-
zero(sa);
sa.un.sun_family = AF_UNIX;
strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
- if (connect(syslog_fd, &sa.sa, sizeof(sa)) < 0) {
+ if ((syslog_fd = create_log_socket(SOCK_DGRAM)) < 0) {
r = -errno;
goto fail;
}
+ if (connect(syslog_fd, &sa.sa, sizeof(sa)) < 0) {
+ close_nointr_nofail(syslog_fd);
+
+ /* Some legacy syslog systems still use stream
+ * sockets. They really shouldn't. But what can we
+ * do... */
+ if ((syslog_fd = create_log_socket(SOCK_STREAM)) < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ if (connect(syslog_fd, &sa.sa, sizeof(sa)) < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ syslog_is_stream = true;
+ } else
+ syslog_is_stream = false;
+
log_debug("Succesfully opened syslog for logging.");
return 0;
@@ -274,12 +300,26 @@ static int write_to_syslog(
IOVEC_SET_STRING(iovec[3], header_pid);
IOVEC_SET_STRING(iovec[4], buffer);
+ /* When using syslog via SOCK_STREAM seperate the messages by NUL chars */
+ if (syslog_is_stream)
+ iovec[4].iov_len++;
+
zero(msghdr);
msghdr.msg_iov = iovec;
msghdr.msg_iovlen = ELEMENTSOF(iovec);
- if (sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL) < 0)
- return -errno;
+ for (;;) {
+ ssize_t n;
+
+ if ((n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL)) < 0)
+ return -errno;
+
+ if (!syslog_is_stream ||
+ (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
+ break;
+
+ IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
+ }
return 1;
}
diff --git a/src/macro.h b/src/macro.h
index acfc277517..44b481775d 100644
--- a/src/macro.h
+++ b/src/macro.h
@@ -24,6 +24,8 @@
#include <assert.h>
#include <sys/types.h>
+#include <sys/uio.h>
+#include <inttypes.h>
#define _printf_attr_(a,b) __attribute__ ((format (printf, a, b)))
#define _sentinel_ __attribute__ ((sentinel))
@@ -134,6 +136,34 @@ static inline size_t ALIGN(size_t l) {
_i->iov_len = strlen(_s); \
} while(false);
+static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
+ unsigned j;
+ size_t r = 0;
+
+ for (j = 0; j < n; j++)
+ r += i[j].iov_len;
+
+ return r;
+}
+
+static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) {
+ unsigned j;
+
+ for (j = 0; j < n; j++) {
+ size_t sub;
+
+ if (_unlikely_(k <= 0))
+ break;
+
+ sub = MIN(i[j].iov_len, k);
+ i[j].iov_len -= sub;
+ i[j].iov_base = (uint8_t*) i[j].iov_base + sub;
+ k -= sub;
+ }
+
+ return k;
+}
+
#include "log.h"
#endif