diff --git a/src/basic/io-util.c b/src/basic/io-util.c index f642beca3a..6f6fb8068c 100644 --- a/src/basic/io-util.c +++ b/src/basic/io-util.c @@ -362,3 +362,13 @@ size_t iovw_size(struct iovec_wrapper *iovw) { return n; } + +void iovec_array_free(struct iovec *iov, size_t n) { + if (!iov) + return; + + for (size_t i = 0; i < n; i++) + free(iov[i].iov_base); + + free(iov); +} diff --git a/src/basic/io-util.h b/src/basic/io-util.h index 3afb134266..a5c1f89a8d 100644 --- a/src/basic/io-util.h +++ b/src/basic/io-util.h @@ -74,10 +74,15 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) { } +#define IOVEC_NULL (struct iovec) {} #define IOVEC_INIT(base, len) { .iov_base = (base), .iov_len = (len) } #define IOVEC_MAKE(base, len) (struct iovec) IOVEC_INIT(base, len) -#define IOVEC_INIT_STRING(string) IOVEC_INIT((char*) string, strlen(string)) -#define IOVEC_MAKE_STRING(string) (struct iovec) IOVEC_INIT_STRING(string) +#define IOVEC_INIT_STRING(string) \ + ({ \ + char *_s = (char*) (string); \ + IOVEC_MAKE(_s, strlen(_s)); \ + }) +#define IOVEC_MAKE_STRING(string) IOVEC_INIT_STRING(string) char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value); char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value); @@ -105,3 +110,5 @@ int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const c int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value); void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new); size_t iovw_size(struct iovec_wrapper *iovw); + +void iovec_array_free(struct iovec *iov, size_t n); diff --git a/src/libsystemd/sd-journal/journal-send.c b/src/libsystemd/sd-journal/journal-send.c index 00c53f6d5b..c360d0e182 100644 --- a/src/libsystemd/sd-journal/journal-send.c +++ b/src/libsystemd/sd-journal/journal-send.c @@ -148,93 +148,64 @@ _public_ int sd_journal_printv(int priority, const char *format, va_list ap) { return sd_journal_sendv(iov, 2); } -_printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) { +_printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, size_t extra, struct iovec **ret_iov, size_t *ret_n_iov) { PROTECT_ERRNO; - int r, n = 0, i = 0, j; struct iovec *iov = NULL; + size_t n = 0; - assert(_iov); + assert(ret_iov); + assert(ret_n_iov); if (extra > 0) { - n = MAX(extra * 2, extra + 4); - iov = malloc0(n * sizeof(struct iovec)); - if (!iov) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC0(iov, extra)) + return -ENOMEM; - i = extra; + n = extra; } + CLEANUP_ARRAY(iov, n, iovec_array_free); + while (format) { - struct iovec *c; - char *buffer; + _cleanup_free_ char *buffer = NULL; va_list aq; - if (i >= n) { - n = MAX(i*2, 4); - c = reallocarray(iov, n, sizeof(struct iovec)); - if (!c) { - r = -ENOMEM; - goto fail; - } - - iov = c; - } - va_copy(aq, ap); if (vasprintf(&buffer, format, aq) < 0) { va_end(aq); - r = -ENOMEM; - goto fail; + return -ENOMEM; } va_end(aq); VA_FORMAT_ADVANCE(format, ap); - - (void) strstrip(buffer); /* strip trailing whitespace, keep prefixing whitespace */ - - iov[i++] = IOVEC_MAKE_STRING(buffer); - format = va_arg(ap, char *); + + if (!GREEDY_REALLOC(iov, n + 1)) + return -ENOMEM; + + /* strip trailing whitespace, keep prefixing whitespace */ + iov[n++] = IOVEC_MAKE_STRING(delete_trailing_chars(TAKE_PTR(buffer), NULL)); } - *_iov = iov; - - return i; - -fail: - for (j = 0; j < i; j++) - free(iov[j].iov_base); - - free(iov); - - return r; + *ret_iov = TAKE_PTR(iov); + *ret_n_iov = n; + return 0; } _public_ int sd_journal_send(const char *format, ...) { - int r, i, j; - va_list ap; struct iovec *iov = NULL; + size_t n_iov = 0; + va_list ap; + int r; + + CLEANUP_ARRAY(iov, n_iov, iovec_array_free); va_start(ap, format); - i = fill_iovec_sprintf(format, ap, 0, &iov); + r = fill_iovec_sprintf(format, ap, 0, &iov, &n_iov); va_end(ap); + if (r < 0) + return r; - if (_unlikely_(i < 0)) { - r = i; - goto finish; - } - - r = sd_journal_sendv(iov, i); - -finish: - for (j = 0; j < i; j++) - free(iov[j].iov_base); - - free(iov); - - return r; + return sd_journal_sendv(iov, n_iov); } _public_ int sd_journal_sendv(const struct iovec *iov, int n) { @@ -529,19 +500,19 @@ _public_ int sd_journal_printv_with_location(int priority, const char *file, con } _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) { - _cleanup_free_ struct iovec *iov = NULL; - int r, i, j; + struct iovec *iov = NULL; + size_t n_iov = 0; va_list ap; char *f; + int r; + + CLEANUP_ARRAY(iov, n_iov, iovec_array_free); va_start(ap, format); - i = fill_iovec_sprintf(format, ap, 3, &iov); + r = fill_iovec_sprintf(format, ap, 3, &iov, &n_iov); va_end(ap); - - if (_unlikely_(i < 0)) { - r = i; - goto finish; - } + if (r < 0) + return r; ALLOCA_CODE_FUNC(f, func); @@ -549,11 +520,9 @@ _public_ int sd_journal_send_with_location(const char *file, const char *line, c iov[1] = IOVEC_MAKE_STRING(line); iov[2] = IOVEC_MAKE_STRING(f); - r = sd_journal_sendv(iov, i); + r = sd_journal_sendv(iov, n_iov); -finish: - for (j = 3; j < i; j++) - free(iov[j].iov_base); + iov[0] = iov[1] = iov[2] = IOVEC_NULL; return r; }