You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
7.4 KiB
163 lines
7.4 KiB
From 963ddb917de3140308ee62fb642b2307a577a39e Mon Sep 17 00:00:00 2001
|
|
From: Lennart Poettering <lennart@poettering.net>
|
|
Date: Mon, 24 Sep 2012 23:22:19 +0200
|
|
Subject: [PATCH] log: fix repeated invocation of vsnprintf()/vaprintf() in
|
|
log_struct()
|
|
|
|
https://bugs.freedesktop.org/show_bug.cgi?id=55213
|
|
---
|
|
src/nspawn/nspawn.c | 6 ++++++
|
|
src/shared/log.c | 22 ++++++++++++++++++++--
|
|
src/shared/macro.h | 43 +++++++++++++++++++++++++++++++++++++++++++
|
|
src/test/test-log.c | 7 +++++++
|
|
4 files changed, 76 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
|
|
index 959df4e..5cac32c 100644
|
|
--- a/src/nspawn/nspawn.c
|
|
+++ b/src/nspawn/nspawn.c
|
|
@@ -1307,6 +1307,12 @@ int main(int argc, char *argv[]) {
|
|
|
|
if (arg_user) {
|
|
|
|
+ /* Note that this resolves user names
|
|
+ * inside the container, and hence
|
|
+ * accesses the NSS modules from the
|
|
+ * container and not the host. This is
|
|
+ * a bit weird... */
|
|
+
|
|
if (get_user_creds((const char**)&arg_user, &uid, &gid, &home, NULL) < 0) {
|
|
log_error("get_user_creds() failed: %m");
|
|
goto child_fail;
|
|
diff --git a/src/shared/log.c b/src/shared/log.c
|
|
index b618458..6357868 100644
|
|
--- a/src/shared/log.c
|
|
+++ b/src/shared/log.c
|
|
@@ -27,6 +27,7 @@
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <stddef.h>
|
|
+#include <printf.h>
|
|
|
|
#include "log.h"
|
|
#include "util.h"
|
|
@@ -705,11 +706,23 @@ int log_struct_internal(
|
|
va_start(ap, format);
|
|
while (format && n + 1 < ELEMENTSOF(iovec)) {
|
|
char *buf;
|
|
+ va_list aq;
|
|
|
|
- if (vasprintf(&buf, format, ap) < 0) {
|
|
+ /* We need to copy the va_list structure,
|
|
+ * since vasprintf() leaves it afterwards at
|
|
+ * an undefined location */
|
|
+
|
|
+ va_copy(aq, ap);
|
|
+ if (vasprintf(&buf, format, aq) < 0) {
|
|
+ va_end(aq);
|
|
r = -ENOMEM;
|
|
goto finish;
|
|
}
|
|
+ va_end(aq);
|
|
+
|
|
+ /* Now, jump enough ahead, so that we point to
|
|
+ * the next format string */
|
|
+ VA_FORMAT_ADVANCE(format, ap);
|
|
|
|
IOVEC_SET_STRING(iovec[n++], buf);
|
|
|
|
@@ -742,8 +755,11 @@ int log_struct_internal(
|
|
|
|
va_start(ap, format);
|
|
while (format) {
|
|
+ va_list aq;
|
|
|
|
- vsnprintf(buf, sizeof(buf), format, ap);
|
|
+ va_copy(aq, ap);
|
|
+ vsnprintf(buf, sizeof(buf), format, aq);
|
|
+ va_end(aq);
|
|
char_array_0(buf);
|
|
|
|
if (startswith(buf, "MESSAGE=")) {
|
|
@@ -751,6 +767,8 @@ int log_struct_internal(
|
|
break;
|
|
}
|
|
|
|
+ VA_FORMAT_ADVANCE(format, ap);
|
|
+
|
|
format = va_arg(ap, char *);
|
|
}
|
|
va_end(ap);
|
|
diff --git a/src/shared/macro.h b/src/shared/macro.h
|
|
index c7ce7c8..0dd210a 100644
|
|
--- a/src/shared/macro.h
|
|
+++ b/src/shared/macro.h
|
|
@@ -193,4 +193,47 @@ static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) {
|
|
#define _cleanup_closedir_ __attribute__((cleanup(closedirp)))
|
|
#define _cleanup_umask_ __attribute__((cleanup(umaskp)))
|
|
|
|
+#define VA_FORMAT_ADVANCE(format, ap) do { \
|
|
+ int _argtypes[64]; \
|
|
+ size_t _i, _k; \
|
|
+ _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \
|
|
+ for (_i = 0; _i < _k; _i++) { \
|
|
+ if (_argtypes[_i] & PA_FLAG_PTR) { \
|
|
+ (void) va_arg(ap, void*); \
|
|
+ continue; \
|
|
+ } \
|
|
+ \
|
|
+ switch (_argtypes[_i]) { \
|
|
+ case PA_INT: \
|
|
+ case PA_INT|PA_FLAG_SHORT: \
|
|
+ case PA_CHAR: \
|
|
+ (void) va_arg(ap, int); \
|
|
+ break; \
|
|
+ case PA_INT|PA_FLAG_LONG: \
|
|
+ (void) va_arg(ap, long int); \
|
|
+ break; \
|
|
+ case PA_INT|PA_FLAG_LONG_LONG: \
|
|
+ (void) va_arg(ap, long long int); \
|
|
+ break; \
|
|
+ case PA_WCHAR: \
|
|
+ (void) va_arg(ap, wchar_t); \
|
|
+ break; \
|
|
+ case PA_WSTRING: \
|
|
+ case PA_STRING: \
|
|
+ case PA_POINTER: \
|
|
+ (void) va_arg(ap, void*); \
|
|
+ break; \
|
|
+ case PA_FLOAT: \
|
|
+ case PA_DOUBLE: \
|
|
+ (void) va_arg(ap, double); \
|
|
+ break; \
|
|
+ case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \
|
|
+ (void) va_arg(ap, long double); \
|
|
+ break; \
|
|
+ default: \
|
|
+ assert_not_reached("Unknown format string argument."); \
|
|
+ } \
|
|
+ } \
|
|
+} while(false)
|
|
+
|
|
#include "log.h"
|
|
diff --git a/src/test/test-log.c b/src/test/test-log.c
|
|
index cc924fa..8dc3d53 100644
|
|
--- a/src/test/test-log.c
|
|
+++ b/src/test/test-log.c
|
|
@@ -42,5 +42,12 @@ int main(int argc, char* argv[]) {
|
|
"SERVICE=foobar",
|
|
NULL);
|
|
|
|
+ log_struct(LOG_INFO,
|
|
+ "MESSAGE=Foobar PID=%lu", (unsigned long) getpid(),
|
|
+ "FORMAT_STR_TEST=1=%i A=%c 2=%hi 3=%li 4=%lli 1=%p foo=%s 2.5=%g 3.5=%g 4.5=%Lg",
|
|
+ (int) 1, 'A', (short) 2, (long int) 3, (long long int) 4, (void*) 1, "foo", (float) 2.5f, (double) 3.5, (long double) 4.5,
|
|
+ "SUFFIX=GOT IT",
|
|
+ NULL);
|
|
+
|
|
return 0;
|
|
}
|
|
--
|
|
1.7.12
|
|
|