From 57e674ae7bff996a263ca4f70ebea7606e250eb0 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 3 Oct 2013 18:17:39 +0100 Subject: [PATCH] daemon: Fix xfs_info parser because of new format. The old parser had several problems: firstly it called the error path sometimes without calling reply_with_error causing a protocol hang. More seriously it had hard-coded line numbers, and since Fedora 21 the output of xfs_info has changed, moving lines around. Change the parser to be more robust against added fields by using the first name on the line as the section name, thus 'bsize=' is interpreted differently depending on whether it appears in the "data" section or the "naming" section. Ensure also that we don't call the error path without calling reply_with_error, which is a side-effect of the above change. (cherry picked from commit 8abd0a83b3a94e4adbd0926df818686be982cdb8) --- daemon/xfs.c | 114 ++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 44 deletions(-) diff --git a/daemon/xfs.c b/daemon/xfs.c index e31da8f..725f7b3 100644 --- a/daemon/xfs.c +++ b/daemon/xfs.c @@ -28,6 +28,8 @@ #include "actions.h" #include "optgroups.h" +#include "c-ctype.h" + #define MAX_ARGS 64 GUESTFSD_EXT_CMD(str_mkfs_xfs, mkfs.xfs); @@ -42,7 +44,7 @@ optgroup_xfs_available (void) return prog_exists (str_mkfs_xfs); } -/* Return everything up to the first comma or space in the input +/* Return everything up to the first comma, equals or space in the input * string, strdup'ing the return value. */ static char * @@ -51,7 +53,7 @@ split_strdup (char *string) size_t len; char *ret; - len = strcspn (string, " ,"); + len = strcspn (string, " ,="); ret = strndup (string, len); if (!ret) { reply_with_perror ("malloc"); @@ -92,6 +94,7 @@ parse_uint64 (uint64_t *ret, const char *str) * * meta-data=/dev/sda1 isize=256 agcount=4, agsize=6392 blks * = sectsz=512 attr=2 + *[ = crc=0 ] * data = bsize=4096 blocks=25568, imaxpct=25 * = sunit=0 swidth=0 blks * naming =version 2 bsize=4096 ascii-ci=0 @@ -99,6 +102,8 @@ parse_uint64 (uint64_t *ret, const char *str) * = sectsz=512 sunit=0 blks, lazy-count=1 * realtime =none extsz=4096 blocks=0, rtextents=0 * + * [...] line only appears in Fedora >= 21 + * * We may need to revisit this parsing code if the output changes * in future. */ @@ -106,6 +111,7 @@ static guestfs_int_xfsinfo * parse_xfs_info (char **lines) { guestfs_int_xfsinfo *ret; + CLEANUP_FREE char *section = NULL; /* first column, eg "meta-data", "data" */ char *p; size_t i; @@ -145,6 +151,18 @@ parse_xfs_info (char **lines) ret->xfs_rtextents = -1; for (i = 0; lines[i] != NULL; ++i) { + if (verbose) + fprintf (stderr, "xfs_info: lines[%zu] = \'%s\'\n", i, lines[i]); + + if (c_isalpha (lines[i][0])) { + free (section); + section = split_strdup (lines[i]); + if (!section) goto error; + + if (verbose) + fprintf (stderr, "xfs_info: new section %s\n", section); + } + if ((p = strstr (lines[i], "meta-data="))) { ret->xfs_mntpoint = split_strdup (p + 10); if (ret->xfs_mntpoint == NULL) goto error; @@ -168,15 +186,17 @@ parse_xfs_info (char **lines) goto error; } if ((p = strstr (lines[i], "sectsz="))) { - CLEANUP_FREE char *buf = split_strdup (p + 7); - if (buf == NULL) goto error; - if (i == 1) { - if (parse_uint32 (&ret->xfs_sectsize, buf) == -1) - goto error; - } else if (i == 6) { - if (parse_uint32 (&ret->xfs_logsectsize, buf) == -1) - goto error; - } else goto error; + if (section) { + CLEANUP_FREE char *buf = split_strdup (p + 7); + if (buf == NULL) goto error; + if (STREQ (section, "meta-data")) { + if (parse_uint32 (&ret->xfs_sectsize, buf) == -1) + goto error; + } else if (STREQ (section, "log")) { + if (parse_uint32 (&ret->xfs_logsectsize, buf) == -1) + goto error; + } + } } if ((p = strstr (lines[i], "attr="))) { CLEANUP_FREE char *buf = split_strdup (p + 5); @@ -185,32 +205,36 @@ parse_xfs_info (char **lines) goto error; } if ((p = strstr (lines[i], "bsize="))) { - CLEANUP_FREE char *buf = split_strdup (p + 6); - if (buf == NULL) goto error; - if (i == 2) { - if (parse_uint32 (&ret->xfs_blocksize, buf) == -1) - goto error; - } else if (i == 4) { - if (parse_uint32 (&ret->xfs_dirblocksize, buf) == -1) - goto error; - } else if (i == 5) { - if (parse_uint32 (&ret->xfs_logblocksize, buf) == -1) - goto error; - } else goto error; + if (section) { + CLEANUP_FREE char *buf = split_strdup (p + 6); + if (buf == NULL) goto error; + if (STREQ (section, "data")) { + if (parse_uint32 (&ret->xfs_blocksize, buf) == -1) + goto error; + } else if (STREQ (section, "naming")) { + if (parse_uint32 (&ret->xfs_dirblocksize, buf) == -1) + goto error; + } else if (STREQ (section, "log")) { + if (parse_uint32 (&ret->xfs_logblocksize, buf) == -1) + goto error; + } + } } if ((p = strstr (lines[i], "blocks="))) { - CLEANUP_FREE char *buf = split_strdup (p + 7); - if (buf == NULL) goto error; - if (i == 2) { - if (parse_uint64 (&ret->xfs_datablocks, buf) == -1) - goto error; - } else if (i == 5) { - if (parse_uint32 (&ret->xfs_logblocks, buf) == -1) - goto error; - } else if (i == 7) { - if (parse_uint64 (&ret->xfs_rtblocks, buf) == -1) - goto error; - } else goto error; + if (section) { + CLEANUP_FREE char *buf = split_strdup (p + 7); + if (buf == NULL) goto error; + if (STREQ (section, "data")) { + if (parse_uint64 (&ret->xfs_datablocks, buf) == -1) + goto error; + } else if (STREQ (section, "log")) { + if (parse_uint32 (&ret->xfs_logblocks, buf) == -1) + goto error; + } else if (STREQ (section, "realtime")) { + if (parse_uint64 (&ret->xfs_rtblocks, buf) == -1) + goto error; + } + } } if ((p = strstr (lines[i], "imaxpct="))) { CLEANUP_FREE char *buf = split_strdup (p + 8); @@ -219,15 +243,17 @@ parse_xfs_info (char **lines) goto error; } if ((p = strstr (lines[i], "sunit="))) { - CLEANUP_FREE char *buf = split_strdup (p + 6); - if (buf == NULL) goto error; - if (i == 3) { - if (parse_uint32 (&ret->xfs_sunit, buf) == -1) - goto error; - } else if (i == 6) { - if (parse_uint32 (&ret->xfs_logsunit, buf) == -1) - goto error; - } else goto error; + if (section) { + CLEANUP_FREE char *buf = split_strdup (p + 6); + if (buf == NULL) goto error; + if (STREQ (section, "data")) { + if (parse_uint32 (&ret->xfs_sunit, buf) == -1) + goto error; + } else if (STREQ (section, "log")) { + if (parse_uint32 (&ret->xfs_logsunit, buf) == -1) + goto error; + } + } } if ((p = strstr (lines[i], "swidth="))) { CLEANUP_FREE char *buf = split_strdup (p + 7); -- 1.8.3.1