[libvirt] [PATCH] qemu: unescape HMP commands before converting them to json

QMP commands don't need to be escaped since converting them to json also escapes special characters. When a QMP command fails, however, libvirt falls back to HMP commands. These fallback functions (qemuMonitorText*) do their own escaping, and pass the result directly to qemuMonitorHMPCommandWithFd. If the monitor is in json mode, these pre-escaped commands will be escaped again when converted to json, which can result in the wrong arguments being sent. For example, a filename test\file would be sent in json as test\\file. This prevented attaching an image file with a " or \ in its name in qemu 1.0.50, and also broke rbd attachment (which uses backslashes to escape some internal arguments.) Reported-by: Masuko Tomoya <tomoya.masuko@gmail.com> Signed-off-by: Josh Durgin <josh.durgin@dreamhost.com> --- .gitignore | 1 + src/qemu/qemu_monitor.c | 59 +++++++++++++++++++++++- src/qemu/qemu_monitor.h | 1 + tests/Makefile.am | 12 ++++- tests/qemumonitortest.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 181 insertions(+), 6 deletions(-) create mode 100644 tests/qemumonitortest.c diff --git a/.gitignore b/.gitignore index b7561dc..264a419 100644 --- a/.gitignore +++ b/.gitignore @@ -128,6 +128,7 @@ /tests/openvzutilstest /tests/qemuargv2xmltest /tests/qemuhelptest +/tests/qemumonitortest /tests/qemuxmlnstest /tests/qparamtest /tests/reconnect diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 93f3505..85212a7 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -153,6 +153,49 @@ char *qemuMonitorEscapeArg(const char *in) return out; } +char *qemuMonitorUnescapeArg(const char *in) +{ + int i, j; + char *out; + int len = strlen(in) + 1; + char next; + + if (VIR_ALLOC_N(out, len) < 0) + return NULL; + + for (i = j = 0; i < len; ++i) { + next = in[i]; + if (in[i] == '\\') { + if (len < i + 1) { + // trailing backslash shouldn't be possible + VIR_FREE(out); + return NULL; + } + ++i; + switch(in[i]) { + case 'r': + next = '\r'; + break; + case 'n': + next = '\n'; + break; + case '"': + case '\\': + next = in[i]; + break; + default: + // invalid input + VIR_FREE(out); + return NULL; + } + } + out[j++] = next; + } + out[j] = '\0'; + + return out; +} + #if DEBUG_RAW_IO # include <c-ctype.h> static char * qemuMonitorEscapeNonPrintable(const char *text) @@ -852,10 +895,20 @@ int qemuMonitorHMPCommandWithFd(qemuMonitorPtr mon, int scm_fd, char **reply) { - if (mon->json) - return qemuMonitorJSONHumanCommandWithFd(mon, cmd, scm_fd, reply); - else + char *json_cmd = NULL; + if (mon->json) { + // hack to avoid complicating each call to text monitor functions + json_cmd = qemuMonitorUnescapeArg(cmd); + if (!json_cmd) { + VIR_DEBUG("Could not unescape command: %s", cmd); + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to unescape command")); + return -1; + } + return qemuMonitorJSONHumanCommandWithFd(mon, json_cmd, scm_fd, reply); + } else { return qemuMonitorTextCommandWithFd(mon, cmd, scm_fd, reply); + } } /* Ensure proper locking around callbacks. */ diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 7c6c52b..9768457 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -128,6 +128,7 @@ struct _qemuMonitorCallbacks { char *qemuMonitorEscapeArg(const char *in); +char *qemuMonitorUnescapeArg(const char *in); qemuMonitorPtr qemuMonitorOpen(virDomainObjPtr vm, virDomainChrSourceDefPtr config, diff --git a/tests/Makefile.am b/tests/Makefile.am index 9974c2f..3e505a5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -72,6 +72,7 @@ EXTRA_DIST = \ nwfilterxml2xmlout \ oomtrace.pl \ qemuhelpdata \ + qemumonitortest \ qemuxml2argvdata \ qemuxml2xmloutdata \ qemuxmlnsdata \ @@ -110,7 +111,8 @@ check_PROGRAMS += xml2sexprtest sexpr2xmltest \ endif if WITH_QEMU check_PROGRAMS += qemuxml2argvtest qemuxml2xmltest qemuxmlnstest \ - qemuargv2xmltest qemuhelptest domainsnapshotxml2xmltest + qemuargv2xmltest qemuhelptest domainsnapshotxml2xmltest \ + qemumonitortest endif if WITH_OPENVZ @@ -237,7 +239,8 @@ endif if WITH_QEMU TESTS += qemuxml2argvtest qemuxml2xmltest qemuxmlnstest qemuargv2xmltest \ - qemuhelptest domainsnapshotxml2xmltest nwfilterxml2xmltest + qemuhelptest domainsnapshotxml2xmltest nwfilterxml2xmltest \ + qemumonitortest endif if WITH_OPENVZ @@ -365,6 +368,9 @@ qemuargv2xmltest_LDADD = $(qemu_LDADDS) $(LDADDS) qemuhelptest_SOURCES = qemuhelptest.c testutils.c testutils.h qemuhelptest_LDADD = $(qemu_LDADDS) $(LDADDS) +qemumonitortest_SOURCES = qemumonitortest.c testutils.c testutils.h +qemumonitortest_LDADD = $(qemu_LDADDS) $(LDADDS) + domainsnapshotxml2xmltest_SOURCES = \ domainsnapshotxml2xmltest.c testutilsqemu.c testutilsqemu.h \ testutils.c testutils.h @@ -372,7 +378,7 @@ domainsnapshotxml2xmltest_LDADD = $(qemu_LDADDS) $(LDADDS) else EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c qemuargv2xmltest.c \ qemuxmlnstest.c qemuhelptest.c domainsnapshotxml2xmltest.c \ - testutilsqemu.c testutilsqemu.h + qemumonitortest.c testutilsqemu.c testutilsqemu.h endif if WITH_OPENVZ diff --git a/tests/qemumonitortest.c b/tests/qemumonitortest.c new file mode 100644 index 0000000..bf90502 --- /dev/null +++ b/tests/qemumonitortest.c @@ -0,0 +1,114 @@ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef WITH_QEMU + +# include "internal.h" +# include "memory.h" +# include "testutils.h" +# include "util.h" +# include "qemu/qemu_monitor.h" + +struct testEscapeString +{ + const char* unescaped; + const char* escaped; +}; + +static struct testEscapeString escapeStrings[] = { + { "", "" }, + { " ", " " }, + { "\\", "\\\\" }, + { "\n", "\\n" }, + { "\r", "\\r" }, + { "\"", "\\\"" }, + { "\"\"\"\\\\\n\r\\\\\n\r\"\"\"", "\\\"\\\"\\\"\\\\\\\\\\n\\r\\\\\\\\\\n\\r\\\"\\\"\\\"" }, + { "drive_add dummy file=foo\\", "drive_add dummy file=foo\\\\" }, + { "block info", "block info" }, + { "set_password \":\\\"\"", "set_password \\\":\\\\\\\"\\\"" }, +}; + +static int testEscapeArg(const void *data ATTRIBUTE_UNUSED) +{ + int i; + char *escaped = NULL; + for (i = 0; i < ARRAY_CARDINALITY(escapeStrings); ++i) { + escaped = qemuMonitorEscapeArg(escapeStrings[i].unescaped); + if (!escaped) { + if (virTestGetDebug() > 0) { + fprintf(stderr, "\nUnescaped string [%s]\n", escapeStrings[i].unescaped); + fprintf(stderr, "Expect result [%s]\n", escapeStrings[i].escaped); + fprintf(stderr, "Actual result [%s]\n", escaped); + } + return -1; + } + if (STRNEQ(escapeStrings[i].escaped, escaped)) { + virtTestDifference(stderr, escapeStrings[i].escaped, escaped); + VIR_FREE(escaped); + return -1; + } + VIR_FREE(escaped); + } + + return 0; +} + +static int testUnescapeArg(const void *data ATTRIBUTE_UNUSED) +{ + int i; + char *unescaped = NULL; + for (i = 0; i < ARRAY_CARDINALITY(escapeStrings); ++i) { + unescaped = qemuMonitorUnescapeArg(escapeStrings[i].escaped); + if (!unescaped) { + if (virTestGetDebug() > 0) { + fprintf(stderr, "\nEscaped string [%s]\n", escapeStrings[i].escaped); + fprintf(stderr, "Expect result [%s]\n", escapeStrings[i].unescaped); + fprintf(stderr, "Actual result [%s]\n", unescaped); + } + return -1; + } + if (STRNEQ(escapeStrings[i].unescaped, unescaped)) { + virtTestDifference(stderr, escapeStrings[i].unescaped, unescaped); + VIR_FREE(unescaped); + return -1; + } + VIR_FREE(unescaped); + } + + return 0; +} + +static int +mymain(void) +{ + int result = 0; + +#define DO_TEST(_name) \ + do { \ + if (virtTestRun("qemu monitor "#_name, 1, test##_name, \ + NULL) < 0) { \ + result = -1; \ + } \ + } while (0) + + DO_TEST(EscapeArg); + DO_TEST(UnescapeArg); + + return result == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIRT_TEST_MAIN(mymain) + +#else +# include "testutils.h" + +int main(void) +{ + return EXIT_AM_SKIP; +} + +#endif /* WITH_QEMU */ -- 1.7.1

QMP commands don't need to be escaped since converting them to json also escapes special characters. When a QMP command fails, however, libvirt falls back to HMP commands. These fallback functions (qemuMonitorText*) do their own escaping, and pass the result directly to qemuMonitorHMPCommandWithFd. If the monitor is in json mode, these pre-escaped commands will be escaped again when converted to json, which can result in the wrong arguments being sent. For example, a filename test\file would be sent in json as test\\file. This prevented attaching an image file with a " or \ in its name in qemu 1.0.50, and also broke rbd attachment (which uses backslashes to escape some internal arguments.) Reported-by: Masuko Tomoya <tomoya.masuko@gmail.com> Signed-off-by: Josh Durgin <josh.durgin@dreamhost.com> --- Changes since v1: * fix leak of json_cmd * change comments to /* */ instead of // .gitignore | 1 + src/qemu/qemu_monitor.c | 67 ++++++++++++++++++++++++++-- src/qemu/qemu_monitor.h | 1 + tests/Makefile.am | 12 ++++- tests/qemumonitortest.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 188 insertions(+), 7 deletions(-) create mode 100644 tests/qemumonitortest.c diff --git a/.gitignore b/.gitignore index b7561dc..264a419 100644 --- a/.gitignore +++ b/.gitignore @@ -128,6 +128,7 @@ /tests/openvzutilstest /tests/qemuargv2xmltest /tests/qemuhelptest +/tests/qemumonitortest /tests/qemuxmlnstest /tests/qparamtest /tests/reconnect diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 93f3505..1068280 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -153,6 +153,49 @@ char *qemuMonitorEscapeArg(const char *in) return out; } +char *qemuMonitorUnescapeArg(const char *in) +{ + int i, j; + char *out; + int len = strlen(in) + 1; + char next; + + if (VIR_ALLOC_N(out, len) < 0) + return NULL; + + for (i = j = 0; i < len; ++i) { + next = in[i]; + if (in[i] == '\\') { + if (len < i + 1) { + /* trailing backslash shouldn't be possible */ + VIR_FREE(out); + return NULL; + } + ++i; + switch(in[i]) { + case 'r': + next = '\r'; + break; + case 'n': + next = '\n'; + break; + case '"': + case '\\': + next = in[i]; + break; + default: + /* invalid input */ + VIR_FREE(out); + return NULL; + } + } + out[j++] = next; + } + out[j] = '\0'; + + return out; +} + #if DEBUG_RAW_IO # include <c-ctype.h> static char * qemuMonitorEscapeNonPrintable(const char *text) @@ -852,10 +895,26 @@ int qemuMonitorHMPCommandWithFd(qemuMonitorPtr mon, int scm_fd, char **reply) { - if (mon->json) - return qemuMonitorJSONHumanCommandWithFd(mon, cmd, scm_fd, reply); - else - return qemuMonitorTextCommandWithFd(mon, cmd, scm_fd, reply); + char *json_cmd = NULL; + int ret = -1; + + if (mon->json) { + /* hack to avoid complicating each call to text monitor functions */ + json_cmd = qemuMonitorUnescapeArg(cmd); + if (!json_cmd) { + VIR_DEBUG("Could not unescape command: %s", cmd); + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to unescape command")); + goto cleanup; + } + ret = qemuMonitorJSONHumanCommandWithFd(mon, json_cmd, scm_fd, reply); + } else { + ret = qemuMonitorTextCommandWithFd(mon, cmd, scm_fd, reply); + } + +cleanup: + VIR_FREE(json_cmd); + return ret; } /* Ensure proper locking around callbacks. */ diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 7c6c52b..9768457 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -128,6 +128,7 @@ struct _qemuMonitorCallbacks { char *qemuMonitorEscapeArg(const char *in); +char *qemuMonitorUnescapeArg(const char *in); qemuMonitorPtr qemuMonitorOpen(virDomainObjPtr vm, virDomainChrSourceDefPtr config, diff --git a/tests/Makefile.am b/tests/Makefile.am index 9974c2f..3e505a5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -72,6 +72,7 @@ EXTRA_DIST = \ nwfilterxml2xmlout \ oomtrace.pl \ qemuhelpdata \ + qemumonitortest \ qemuxml2argvdata \ qemuxml2xmloutdata \ qemuxmlnsdata \ @@ -110,7 +111,8 @@ check_PROGRAMS += xml2sexprtest sexpr2xmltest \ endif if WITH_QEMU check_PROGRAMS += qemuxml2argvtest qemuxml2xmltest qemuxmlnstest \ - qemuargv2xmltest qemuhelptest domainsnapshotxml2xmltest + qemuargv2xmltest qemuhelptest domainsnapshotxml2xmltest \ + qemumonitortest endif if WITH_OPENVZ @@ -237,7 +239,8 @@ endif if WITH_QEMU TESTS += qemuxml2argvtest qemuxml2xmltest qemuxmlnstest qemuargv2xmltest \ - qemuhelptest domainsnapshotxml2xmltest nwfilterxml2xmltest + qemuhelptest domainsnapshotxml2xmltest nwfilterxml2xmltest \ + qemumonitortest endif if WITH_OPENVZ @@ -365,6 +368,9 @@ qemuargv2xmltest_LDADD = $(qemu_LDADDS) $(LDADDS) qemuhelptest_SOURCES = qemuhelptest.c testutils.c testutils.h qemuhelptest_LDADD = $(qemu_LDADDS) $(LDADDS) +qemumonitortest_SOURCES = qemumonitortest.c testutils.c testutils.h +qemumonitortest_LDADD = $(qemu_LDADDS) $(LDADDS) + domainsnapshotxml2xmltest_SOURCES = \ domainsnapshotxml2xmltest.c testutilsqemu.c testutilsqemu.h \ testutils.c testutils.h @@ -372,7 +378,7 @@ domainsnapshotxml2xmltest_LDADD = $(qemu_LDADDS) $(LDADDS) else EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c qemuargv2xmltest.c \ qemuxmlnstest.c qemuhelptest.c domainsnapshotxml2xmltest.c \ - testutilsqemu.c testutilsqemu.h + qemumonitortest.c testutilsqemu.c testutilsqemu.h endif if WITH_OPENVZ diff --git a/tests/qemumonitortest.c b/tests/qemumonitortest.c new file mode 100644 index 0000000..bf90502 --- /dev/null +++ b/tests/qemumonitortest.c @@ -0,0 +1,114 @@ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef WITH_QEMU + +# include "internal.h" +# include "memory.h" +# include "testutils.h" +# include "util.h" +# include "qemu/qemu_monitor.h" + +struct testEscapeString +{ + const char* unescaped; + const char* escaped; +}; + +static struct testEscapeString escapeStrings[] = { + { "", "" }, + { " ", " " }, + { "\\", "\\\\" }, + { "\n", "\\n" }, + { "\r", "\\r" }, + { "\"", "\\\"" }, + { "\"\"\"\\\\\n\r\\\\\n\r\"\"\"", "\\\"\\\"\\\"\\\\\\\\\\n\\r\\\\\\\\\\n\\r\\\"\\\"\\\"" }, + { "drive_add dummy file=foo\\", "drive_add dummy file=foo\\\\" }, + { "block info", "block info" }, + { "set_password \":\\\"\"", "set_password \\\":\\\\\\\"\\\"" }, +}; + +static int testEscapeArg(const void *data ATTRIBUTE_UNUSED) +{ + int i; + char *escaped = NULL; + for (i = 0; i < ARRAY_CARDINALITY(escapeStrings); ++i) { + escaped = qemuMonitorEscapeArg(escapeStrings[i].unescaped); + if (!escaped) { + if (virTestGetDebug() > 0) { + fprintf(stderr, "\nUnescaped string [%s]\n", escapeStrings[i].unescaped); + fprintf(stderr, "Expect result [%s]\n", escapeStrings[i].escaped); + fprintf(stderr, "Actual result [%s]\n", escaped); + } + return -1; + } + if (STRNEQ(escapeStrings[i].escaped, escaped)) { + virtTestDifference(stderr, escapeStrings[i].escaped, escaped); + VIR_FREE(escaped); + return -1; + } + VIR_FREE(escaped); + } + + return 0; +} + +static int testUnescapeArg(const void *data ATTRIBUTE_UNUSED) +{ + int i; + char *unescaped = NULL; + for (i = 0; i < ARRAY_CARDINALITY(escapeStrings); ++i) { + unescaped = qemuMonitorUnescapeArg(escapeStrings[i].escaped); + if (!unescaped) { + if (virTestGetDebug() > 0) { + fprintf(stderr, "\nEscaped string [%s]\n", escapeStrings[i].escaped); + fprintf(stderr, "Expect result [%s]\n", escapeStrings[i].unescaped); + fprintf(stderr, "Actual result [%s]\n", unescaped); + } + return -1; + } + if (STRNEQ(escapeStrings[i].unescaped, unescaped)) { + virtTestDifference(stderr, escapeStrings[i].unescaped, unescaped); + VIR_FREE(unescaped); + return -1; + } + VIR_FREE(unescaped); + } + + return 0; +} + +static int +mymain(void) +{ + int result = 0; + +#define DO_TEST(_name) \ + do { \ + if (virtTestRun("qemu monitor "#_name, 1, test##_name, \ + NULL) < 0) { \ + result = -1; \ + } \ + } while (0) + + DO_TEST(EscapeArg); + DO_TEST(UnescapeArg); + + return result == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIRT_TEST_MAIN(mymain) + +#else +# include "testutils.h" + +int main(void) +{ + return EXIT_AM_SKIP; +} + +#endif /* WITH_QEMU */ -- 1.7.1

On 02/25/2012 05:48 PM, Josh Durgin wrote:
QMP commands don't need to be escaped since converting them to json also escapes special characters. When a QMP command fails, however, libvirt falls back to HMP commands. These fallback functions (qemuMonitorText*) do their own escaping, and pass the result directly to qemuMonitorHMPCommandWithFd. If the monitor is in json mode, these pre-escaped commands will be escaped again when converted to json, which can result in the wrong arguments being sent.
For example, a filename test\file would be sent in json as test\\file.
This prevented attaching an image file with a " or \ in its name in qemu 1.0.50, and also broke rbd attachment (which uses backslashes to escape some internal arguments.)
Reported-by: Masuko Tomoya <tomoya.masuko@gmail.com> Signed-off-by: Josh Durgin <josh.durgin@dreamhost.com> ---
Changes since v1: * fix leak of json_cmd * change comments to /* */ instead of //
.gitignore | 1 + src/qemu/qemu_monitor.c | 67 ++++++++++++++++++++++++++-- src/qemu/qemu_monitor.h | 1 + tests/Makefile.am | 12 ++++- tests/qemumonitortest.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 188 insertions(+), 7 deletions(-) create mode 100644 tests/qemumonitortest.c
diff --git a/.gitignore b/.gitignore index b7561dc..264a419 100644 --- a/.gitignore +++ b/.gitignore @@ -128,6 +128,7 @@ /tests/openvzutilstest /tests/qemuargv2xmltest /tests/qemuhelptest +/tests/qemumonitortest
Nice - adding a new test alongside a bug fix is always appreciated.
+++ b/tests/qemumonitortest.c @@ -0,0 +1,114 @@ +#include <config.h>
Adding new files without copyright is bad practice. But you are copying existing practice in that directory; which means I'm assuming that you are okay if we later make a global pass on that directory and add a header on all files that need one, whether that header is LGPLv2+ (like most of the rest of the project), GPLv3+ (since tests aren't installed programs), or anything else. I'll go ahead and commit this as is, but please speak up if my assumptions about globally adding an appropriate copyright header to all tests in the future would give you grief.
+struct testEscapeString +{ + const char* unescaped; + const char* escaped;
Associate the * with the variable, not the type.
+static int testEscapeArg(const void *data ATTRIBUTE_UNUSED) +{ + int i; + char *escaped = NULL; + for (i = 0; i < ARRAY_CARDINALITY(escapeStrings); ++i) { + escaped = qemuMonitorEscapeArg(escapeStrings[i].unescaped); + if (!escaped) { + if (virTestGetDebug() > 0) { + fprintf(stderr, "\nUnescaped string [%s]\n", escapeStrings[i].unescaped); + fprintf(stderr, "Expect result [%s]\n", escapeStrings[i].escaped);
Long lines.
+ fprintf(stderr, "Actual result [%s]\n", escaped);
Missing the NULLSTR() wrapper around escaped. Or, since we _know_ escaped is NULL, we can inline the effects of the NULLSTR() wrapper in the first place.
+static int testUnescapeArg(const void *data ATTRIBUTE_UNUSED) +{ + int i; + char *unescaped = NULL; + for (i = 0; i < ARRAY_CARDINALITY(escapeStrings); ++i) { + unescaped = qemuMonitorUnescapeArg(escapeStrings[i].escaped); + if (!unescaped) { + if (virTestGetDebug() > 0) { + fprintf(stderr, "\nEscaped string [%s]\n", escapeStrings[i].escaped); + fprintf(stderr, "Expect result [%s]\n", escapeStrings[i].unescaped); + fprintf(stderr, "Actual result [%s]\n", unescaped);
Same problems in reverse :)
+static int +mymain(void) +{ + int result = 0; + +#define DO_TEST(_name) \
If you install 'cppi', then 'make syntax-check' complains about this line. ACK with the nits fixed, so I squashed this and pushed. diff --git i/tests/qemumonitortest.c w/tests/qemumonitortest.c index bf90502..cf460ad 100644 --- i/tests/qemumonitortest.c +++ w/tests/qemumonitortest.c @@ -15,8 +15,8 @@ struct testEscapeString { - const char* unescaped; - const char* escaped; + const char *unescaped; + const char *escaped; }; static struct testEscapeString escapeStrings[] = { @@ -40,9 +40,11 @@ static int testEscapeArg(const void *data ATTRIBUTE_UNUSED) escaped = qemuMonitorEscapeArg(escapeStrings[i].unescaped); if (!escaped) { if (virTestGetDebug() > 0) { - fprintf(stderr, "\nUnescaped string [%s]\n", escapeStrings[i].unescaped); - fprintf(stderr, "Expect result [%s]\n", escapeStrings[i].escaped); - fprintf(stderr, "Actual result [%s]\n", escaped); + fprintf(stderr, "\nUnescaped string [%s]\n", + escapeStrings[i].unescaped); + fprintf(stderr, "Expect result [%s]\n", + escapeStrings[i].escaped); + fprintf(stderr, "Actual result [(null)]\n"); } return -1; } @@ -65,9 +67,11 @@ static int testUnescapeArg(const void *data ATTRIBUTE_UNUSED) unescaped = qemuMonitorUnescapeArg(escapeStrings[i].escaped); if (!unescaped) { if (virTestGetDebug() > 0) { - fprintf(stderr, "\nEscaped string [%s]\n", escapeStrings[i].escaped); - fprintf(stderr, "Expect result [%s]\n", escapeStrings[i].unescaped); - fprintf(stderr, "Actual result [%s]\n", unescaped); + fprintf(stderr, "\nEscaped string [%s]\n", + escapeStrings[i].escaped); + fprintf(stderr, "Expect result [%s]\n", + escapeStrings[i].unescaped); + fprintf(stderr, "Actual result [(null)]\n"); } return -1; } @@ -87,7 +91,7 @@ mymain(void) { int result = 0; -#define DO_TEST(_name) \ +# define DO_TEST(_name) \ do { \ if (virtTestRun("qemu monitor "#_name, 1, test##_name, \ NULL) < 0) { \ -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (2)
-
Eric Blake
-
Josh Durgin