From 57e674ae7bff996a263ca4f70ebea7606e250eb0 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
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