chiark / gitweb /
journal: also use new VA_FORMAT_ADVANCE() macro in sd_journal_send()
[elogind.git] / src / journal / journal-send.c
index bc44828e1c0e0ea724d496d397d6fa6f5928e178..d503f3f428e56c5cab0a4f41aaaaad897ca1f050 100644 (file)
@@ -25,6 +25,7 @@
 #include <stddef.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <printf.h>
 
 #define SD_JOURNAL_SUPPRESS_LOCATION
 
@@ -73,8 +74,11 @@ _public_ int sd_journal_print(int priority, const char *format, ...) {
 }
 
 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
-        char buffer[8 + LINE_MAX], p[11];
-        struct iovec iov[2];
+
+        /* FIXME: Instead of limiting things to LINE_MAX we could do a
+           C99 variable-length array on the stack here in a loop. */
+
+        char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2];
 
         if (priority < 0 || priority > 7)
                 return -EINVAL;
@@ -118,6 +122,7 @@ static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct
         while (format) {
                 struct iovec *c;
                 char *buffer;
+                va_list aq;
 
                 if (i >= n) {
                         n = MAX(i*2, 4);
@@ -130,10 +135,15 @@ static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct
                         iov = c;
                 }
 
-                if (vasprintf(&buffer, format, ap) < 0) {
+                va_copy(aq, ap);
+                if (vasprintf(&buffer, format, aq) < 0) {
+                        va_end(aq);
                         r = -ENOMEM;
                         goto fail;
                 }
+                va_end(aq);
+
+                VA_FORMAT_ADVANCE(format, ap);
 
                 IOVEC_SET_STRING(iov[i++], buffer);
 
@@ -340,6 +350,63 @@ finish:
         return r;
 }
 
+static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
+        size_t n, k, r;
+        int saved_errno;
+
+        saved_errno = errno;
+
+        k = isempty(message) ? 0 : strlen(message) + 2;
+        n = 8 + k + 256 + 1;
+
+        for (;;) {
+                char buffer[n];
+                char* j;
+
+                errno = 0;
+                j = strerror_r(saved_errno, buffer + 8 + k, n - 8 - k);
+                if (errno == 0) {
+                        char error[6 + 10 + 1]; /* for a 32bit value */
+
+                        if (j != buffer + 8 + k)
+                                memmove(buffer + 8 + k, j, strlen(j)+1);
+
+                        memcpy(buffer, "MESSAGE=", 8);
+
+                        if (k > 0) {
+                                memcpy(buffer + 8, message, k - 2);
+                                memcpy(buffer + 8 + k - 2, ": ", 2);
+                        }
+
+                        snprintf(error, sizeof(error), "ERRNO=%u", saved_errno);
+                        char_array_0(error);
+
+                        IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
+                        IOVEC_SET_STRING(iov[skip+1], buffer);
+                        IOVEC_SET_STRING(iov[skip+2], error);
+
+                        r = sd_journal_sendv(iov, skip + 3);
+
+                        errno = saved_errno;
+                        return r;
+                }
+
+                if (errno != ERANGE) {
+                        r = -errno;
+                        errno = saved_errno;
+                        return r;
+                }
+
+                n *= 2;
+        }
+}
+
+_public_ int sd_journal_perror(const char *message) {
+        struct iovec iovec[3];
+
+        return fill_iovec_perror_and_send(message, 0, iovec);
+}
+
 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
         union sockaddr_union sa;
         int fd;
@@ -379,7 +446,7 @@ _public_ int sd_journal_stream_fd(const char *identifier, int priority, int leve
 
         memcpy(header, identifier, l);
         header[l++] = '\n';
-        header[l++] = '\n';
+        header[l++] = '\n'; /* unit id */
         header[l++] = '0' + priority;
         header[l++] = '\n';
         header[l++] = '0' + !!level_prefix;
@@ -489,7 +556,11 @@ finish:
         return r;
 }
 
-_public_ int sd_journal_sendv_with_location(const char *file, const char *line, const char *func, const struct iovec *iov, int n) {
+_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;
@@ -514,3 +585,24 @@ _public_ int sd_journal_sendv_with_location(const char *file, const char *line,
 
         return sd_journal_sendv(niov, n);
 }
+
+_public_ int sd_journal_perror_with_location(
+                const char *file, const char *line,
+                const char *func,
+                const char *message) {
+
+        struct iovec iov[6];
+        size_t fl;
+        char *f;
+
+        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);
+
+        return fill_iovec_perror_and_send(message, 3, iov);
+}