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 | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++
generator/actions.ml | 9 +++
src/MAX_PROC_NR | 2 +-
3 files changed, 177 insertions(+), 1 deletion(-)
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index e179b57..36ba588 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -29,6 +29,7 @@
#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);
@@ -813,3 +814,169 @@ do_btrfs_fsck (const char *device, int64_t superblock, int repair)
return 0;
}
+
+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, *pend, *colon;
+ 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 = out;
+
+ p = strchr (p, '\n');
+ if (p) {
+ *p = '\0';
+ p++;
+ }
+ else {
+ reply_with_error ("truncated output");
+ return NULL;
+ }
+
+ /* If the path is the btrfs root, `btrfs subvolume show' reports:
+ * <path> is btrfs root
+ */
+ if (strstr(out, "is btrfs root") != NULL) {
+ reply_with_error ("%s is btrfs root", subvolume);
+ return NULL;
+ }
+
+ /* The first line is the path of the subvolume. */
+ if (add_string (&ret, strdup("path")) == -1) {
+ return NULL;
+ }
+ if (add_string (&ret, out) == -1) {
+ return NULL;
+ }
+
+ /* Read the lines and split into "key: value". */
+ while (*p) {
+ /* leading spaces and tabs */
+ while (*p && c_isspace (*p)) p++;
+
+ pend = strchrnul (p, '\n');
+ if (*pend == '\n') {
+ *pend = '\0';
+ pend++;
+ }
+
+ if (!*p) continue;
+
+ colon = strchr (p, ':');
+ if (colon) {
+ *colon = '\0';
+
+ /* snapshot is special, see the output above */
+ if (strncmp(p, "Snapshot", sizeof("Snapshot") - 1) == 0) {
+ char *ss = NULL;
+
+ if (add_string (&ret, p) == -1) {
+ return NULL;
+ }
+
+ /* each line is the path of a snapshot. */
+ p = pend;
+ while (*p && strchr(p, ':') == NULL) {
+ while (*p && c_isspace (*p)) p++;
+ pend = strchrnul (p, '\n');
+ if (*pend == '\n') {
+ *pend = '\0';
+ pend++;
+ }
+ if (ss) {
+ ss = realloc(ss, strlen(ss) + strlen(p));
+ strcat(ss, ",");
+ strcat(ss, p);
+ } else {
+ ss = strdup(p);
+ }
+
+ p = pend;
+ }
+
+ if (ss) {
+ if (add_string (&ret, ss) == -1) {
+ free(ss);
+ return NULL;
+ }
+ }
+ else {
+ if (add_string (&ret, strdup("")) == -1) {
+ return NULL;
+ }
+ }
+
+ continue;
+ }
+
+ do { colon++; } while (*colon && c_isspace (*colon));
+
+ if (add_string (&ret, p) == -1) {
+ return NULL;
+ }
+ if (add_string (&ret, colon) == -1) {
+ return NULL;
+ }
+ }
+ else {
+ if (add_string (&ret, p) == -1) {
+ return NULL;
+ }
+ if (add_string (&ret, "") == -1) {
+ return NULL;
+ }
+ }
+
+ p = pend;
+ }
+
+ if (end_stringsbuf (&ret) == -1)
+ return NULL;
+
+ return ret.argv;
+
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index cf96039..24d3ecc 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12014,6 +12014,15 @@ This is the internal call which implements
C<guestfs_lstatnslist>." };
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 425;
+ optional = Some "btrfs"; camel_name = "BTRFSSubvolumeShow";
+ shortdesc = "show detailed information of the subvolume";
+ longdesc = "\
+show 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 9524ef4..5e4a522 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-424
+425
--
1.9.3