btrfs_subvolume_show shows the detailed information of a subvolume or
snapshot.
Signed-off-by: Hu Tao <hutao(a)cn.fujitsu.com>
---
daemon/btrfs.c | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++
generator/actions.ml | 9 +++
src/MAX_PROC_NR | 2 +-
3 files changed, 194 insertions(+), 1 deletion(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 471cfbd..b6b2804 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -24,11 +24,13 @@
#include <pcre.h>
#include <string.h>
#include <unistd.h>
+#include <assert.h>
#include "daemon.h"
#include "actions.h"
#include "optgroups.h"
#include "xstrtol.h"
+#include "c-ctype.h"
GUESTFSD_EXT_CMD(str_btrfs, btrfs);
GUESTFSD_EXT_CMD(str_btrfstune, btrfstune);
@@ -810,3 +812,185 @@ do_btrfs_fsck (const char *device, int64_t superblock, int repair)
return 0;
}
+
+/* analyze_line: analyze one line contains key:value pair.
+ * returns the next position following \n.
+ */
+static char *analyze_line (char *line, char **key, char **value)
+{
+ char *p = line;
+ char *next = NULL;
+ char delimiter = ':';
+ char *del_pos = NULL;
+
+ if (!line || *line == '\0') {
+ *key = NULL;
+ *value = NULL;
+ return NULL;
+ }
+
+ next = strchr (p, '\n');
+ if (next) {
+ *next = '\0';
+ ++next;
+ }
+
+ /* leading spaces and tabs */
+ while (*p && c_isspace (*p))
+ ++p;
+
+ assert (key);
+ if (*p == delimiter)
+ *key = NULL;
+ else
+ *key = p;
+
+ del_pos = strchr (p, delimiter);
+ if (del_pos) {
+ *del_pos = '\0';
+ ++del_pos;
+ /* leading spaces and tabs */
+ while (*del_pos && c_isspace (*del_pos))
+ ++del_pos;
+ assert (value);
+ *value = del_pos;
+ } else
+ *value = NULL;
+
+ return next;
+}
+
+char **do_btrfs_subvolume_show (const char *subvolume)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ CLEANUP_FREE char *subvolume_buf = NULL;
+ CLEANUP_FREE char *err = NULL;
+ CLEANUP_FREE char *out = NULL;
+ char *p, *key = NULL, *value = NULL;
+ DECLARE_STRINGSBUF (ret);
+ int r;
+
+ subvolume_buf = sysroot_path (subvolume);
+ if (subvolume_buf == NULL) {
+ reply_with_perror ("malloc");
+ return NULL;
+ }
+
+ ADD_ARG (argv, i, str_btrfs);
+ ADD_ARG (argv, i, "subvolume");
+ ADD_ARG (argv, i, "show");
+ ADD_ARG (argv, i, subvolume_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (&out, &err, argv);
+ if (r == -1) {
+ reply_with_error ("%s: %s", subvolume, err);
+ return NULL;
+ }
+
+ /* Output is:
+ *
+ * /
+ * Name: root
+ * uuid: c875169e-cf4e-a04d-9959-b667dec36234
+ * Parent uuid: -
+ * Creation time: 2014-11-13 10:13:08
+ * Object ID: 256
+ * Generation (Gen): 6579
+ * Gen at creation: 5
+ * Parent: 5
+ * Top Level: 5
+ * Flags: -
+ * Snapshot(s):
+ * snapshots/test1
+ * snapshots/test2
+ * snapshots/test3
+ *
+ */
+ p = analyze_line(out, &key, &value);
+ if (!p) {
+ reply_with_error ("truncated output: %s", out);
+ return NULL;
+ }
+
+ /* If the path is the btrfs root, `btrfs subvolume show' reports:
+ * <path> is btrfs root
+ */
+ if (strstr (key, "is btrfs root") != NULL) {
+ reply_with_error ("%s is btrfs root", subvolume);
+ return NULL;
+ }
+
+ /* The first line is the path of the subvolume. */
+ if (key && !value) {
+ if (add_string (&ret, "path") == -1)
+ return NULL;
+ if (add_string (&ret, key) == -1)
+ return NULL;
+ } else {
+ if (add_string (&ret, key) == -1)
+ return NULL;
+ if (add_string (&ret, value) == -1)
+ return NULL;
+ }
+
+ /* Read the lines and split into "key: value". */
+ p = analyze_line(p, &key, &value);
+ while (key) {
+ /* snapshot is special, see the output above */
+ if (!STREQLEN (key, "Snapshot(s)", sizeof ("Snapshot(s)") - 1))
{
+ if (add_string (&ret, key ? key : "") == -1)
+ return NULL;
+ if (value) {
+ if (add_string (&ret, value) == -1)
+ return NULL;
+ } else {
+ if (add_string (&ret, "") == -1)
+ return NULL;
+ }
+
+ p = analyze_line(p, &key, &value);
+ } else {
+ char *ss = NULL;
+ int ss_len = 0;
+
+ if (add_string (&ret, key) == -1)
+ return NULL;
+
+ p = analyze_line(p, &key, &value);
+
+ while (key && !value) {
+ ss = realloc (ss, ss_len + strlen (key) + 1);
+ if (!ss)
+ return NULL;
+
+ if (ss_len != 0)
+ ss[ss_len++] = ',';
+
+ memcpy (ss + ss_len, key, strlen (key));
+ ss_len += strlen (key);
+ ss[ss_len] = '\0';
+
+ p = analyze_line(p, &key, &value);
+ }
+
+ if (ss) {
+ if (add_string_nodup (&ret, ss) == -1) {
+ free (ss);
+ return NULL;
+ }
+ } else {
+ if (add_string (&ret, "") == -1)
+ return NULL;
+ }
+ }
+ }
+
+ if (end_stringsbuf (&ret) == -1)
+ return NULL;
+
+ return ret.argv;
+
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index 2dcf938..754b275 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12035,6 +12035,15 @@ This uses the L<blockdev(8)> command." };
longdesc = "\
Get the default subvolume or snapshot of a filesystem mounted at
C<mountpoint>." };
+ { defaults with
+ name = "btrfs_subvolume_show";
+ style = RHashtable "btrfssubvolumeinfo", [Pathname "subvolume"],
[];
+ proc_nr = Some 426;
+ optional = Some "btrfs"; camel_name = "BTRFSSubvolumeShow";
+ shortdesc = "return detailed information of the subvolume";
+ longdesc = "\
+Return detailed information of the subvolume." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index 5e4a522..9f51d08 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-425
+426
--
1.9.3