From 06019bc82e107f7715ebc59e491610e06dad1e39 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 18 Aug 2011 17:46:50 +0100 Subject: [PATCH] Escape special/non-printing characters in debug output (RHBZ#731744). The default event handler in libguestfs was simply writing all debug output directly to stderr. However if the output contains non-printable characters such as terminal control codes then these would also be sent directly. With newer SeaBIOS there is a lame attempt to implement a splash screen using terminal control codes, thus when libguestfs tries to display debugging output it would cause the screen to clear and debug output to be lost. This commit causes all non-printing characters to be escaped. (\n and \r characters from the appliance are treated somewhat specially). Furthermore, instead of using write(2), use buffered stderr calls. --- src/events.c | 54 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/src/events.c b/src/events.c index 3894349..aa30fd2 100644 --- a/src/events.c +++ b/src/events.c @@ -28,6 +28,7 @@ #include #include +#include "c-ctype.h" #include "ignore-value.h" #include "guestfs.h" @@ -116,9 +117,9 @@ guestfs___call_callbacks_message (guestfs_h *g, uint64_t event, * override print-on-stderr simply by registering a callback. */ if (count == 0 && (g->verbose || event == GUESTFS_EVENT_TRACE)) { - const char *prefix = "libguestfs: "; - const char *trace = "trace: "; - const char *nl = "\n"; + int from_appliance = event == GUESTFS_EVENT_APPLIANCE; + size_t i; + char c; /* APPLIANCE => * LIBRARY => libguestfs: \n @@ -126,18 +127,47 @@ guestfs___call_callbacks_message (guestfs_h *g, uint64_t event, */ if (event != GUESTFS_EVENT_APPLIANCE) - ignore_value (write (STDERR_FILENO, prefix, strlen (prefix))); + fputs ("libguestfs: ", stderr); if (event == GUESTFS_EVENT_TRACE) - ignore_value (write (STDERR_FILENO, trace, strlen (trace))); - - ignore_value (write (STDERR_FILENO, buf, buf_len)); - - /* Messages from the appliance already contain \n characters, others - * need this to be appended. + fputs ("trace: ", stderr); + + /* Special or non-printing characters in the buffer must be + * escaped (RHBZ#731744). The buffer can contain any 8 bit + * character, even \0. + * + * Handling of \n and \r characters is complex: + * + * Case 1: Messages from the appliance: These messages already + * contain \n and \r characters at logical positions, so we just + * echo those out directly. + * + * Case 2: Messages from other sources: These messages should NOT + * contain \n or \r. If they do, it is escaped. However we also + * need to print a real end of line after these messages. */ - if (event != GUESTFS_EVENT_APPLIANCE) - ignore_value (write (STDERR_FILENO, nl, strlen (nl))); + for (i = 0; i < buf_len; ++i) { + c = buf[i]; + if (c_isprint (c) || (from_appliance && (c == '\n' || c == '\r'))) + putc (c, stderr); + else { + switch (c) { + case '\0': fputs ("\\0", stderr); break; + case '\a': fputs ("\\a", stderr); break; + case '\b': fputs ("\\b", stderr); break; + case '\f': fputs ("\\f", stderr); break; + case '\n': fputs ("\\n", stderr); break; + case '\r': fputs ("\\r", stderr); break; + case '\t': fputs ("\\t", stderr); break; + case '\v': fputs ("\\v", stderr); break; + default: + fprintf (stderr, "\\x%x", (unsigned) c); + } + } + } + + if (!from_appliance) + putc ('\n', stderr); } } -- 1.8.3.1