Blob Blame History Raw
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