[Libguestfs] [PATCH v6 36/41] daemon: Reimplement ‘md_detail’ API in OCaml.

Richard W.M. Jones
Thu, 15 Jun 2017 17:06:26 -0000

---
 daemon/md.c               | 66 -----------------------------------------------
 daemon/md.ml              | 37 ++++++++++++++++++++++++++
 daemon/md.mli             |  1 +
 generator/actions_core.ml |  1 +
 generator/daemon.ml       | 27 +++++++++++++++++++
 5 files changed, 66 insertions(+), 66 deletions(-)

diff --git a/daemon/md.c b/daemon/md.c
index 5c9ecd136..549dd89fa 100644
--- a/daemon/md.c
+++ b/daemon/md.c
@@ -218,72 +218,6 @@ do_md_create (const char *name, char *const *devices,
 #pragma GCC diagnostic pop
 #endif

-char **
-do_md_detail (const char *md)
-{
-  size_t i;
-  int r;
-
-  CLEANUP_FREE char *out = NULL, *err = NULL;
-  CLEANUP_FREE_STRING_LIST char **lines = NULL;
-
-  CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (ret);
-
-  const char *mdadm[] = { str_mdadm, "-D", "--export", md,
NULL };
-  r = commandv (&out, &err, mdadm);
-  if (r == -1) {
-    reply_with_error ("%s", err);
-    return NULL;
-  }
-
-  /* Split the command output into lines */
-  lines = split_lines (out);
-  if (lines == NULL)
-    return NULL;
-
-  /* Parse the output of mdadm -D --export:
-   * MD_LEVEL=raid1
-   * MD_DEVICES=2
-   * MD_METADATA=1.0
-   * MD_UUID=cfa81b59:b6cfbd53:3f02085b:58f4a2e1
-   * MD_NAME=localhost.localdomain:0
-   */
-  for (i = 0; lines[i] != NULL; ++i) {
-    char *line = lines[i];
-
-    /* Skip blank lines (shouldn't happen) */
-    if (line[0] == '\0') continue;
-
-    /* Split the line in 2 at the equals sign */
-    char *eq = strchr (line, '=');
-    if (eq) {
-      *eq = '\0'; eq++;
-
-      /* Remove the MD_ prefix from the key and translate the remainder to
lower
-       * case */
-      if (STRPREFIX (line, "MD_")) {
-        line += 3;
-        for (char *j = line; *j != '\0'; j++) {
-          *j = c_tolower (*j);
-        }
-      }
-
-      /* Add the key/value pair to the output */
-      if (add_string (&ret, line) == -1 ||
-          add_string (&ret, eq) == -1) return NULL;
-    } else {
-      /* Ignore lines with no equals sign (shouldn't happen). Log to stderr
so
-       * it will show up in LIBGUESTFS_DEBUG. */
-      fprintf (stderr, "md-detail: unexpected mdadm output ignored:
%s", line);
-    }
-  }
-
-  if (end_stringsbuf (&ret) == -1)
-    return NULL;
-
-  return take_stringsbuf (&ret);
-}
-
 int
 do_md_stop (const char *md)
 {
diff --git a/daemon/md.ml b/daemon/md.ml
index caf87cf8f..ba045b5f7 100644
--- a/daemon/md.ml
+++ b/daemon/md.ml
@@ -46,3 +46,40 @@ let list_md_devices ()
   (* Return the list sorted. *)
   sort_device_names devs
+
+let md_detail md +  let out = command "mdadm" ["-D";
"--export"; md] in
+
+  (* Split the command output into lines. *)
+  let out = String.trim out in
+  let lines = String.nsplit "\n" out in
+
+  (* Parse the output of mdadm -D --export:
+   * MD_LEVEL=raid1
+   * MD_DEVICES=2
+   * MD_METADATA=1.0
+   * MD_UUID=cfa81b59:b6cfbd53:3f02085b:58f4a2e1
+   * MD_NAME=localhost.localdomain:0
+   *)
+  filter_map (
+    fun line ->
+      (* Skip blank lines (shouldn't happen). *)
+      if line = "" then None
+      else (
+        (* Split the line at the equals sign. *)
+        let key, value = String.split "=" line in
+
+        (* Remove the MD_ prefix from the key and translate the
+         * remainder to lower case.
+         *)
+        let key +          if String.is_prefix key "MD_" then
+            String.sub key 3 (String.length key - 3)
+          else
+            key in
+        let key = String.lowercase_ascii key in
+
+        (* Add the key/value pair to the output. *)
+        Some (key, value)
+      )
+  ) lines
diff --git a/daemon/md.mli b/daemon/md.mli
index 56b6ea65e..8f0c79a7f 100644
--- a/daemon/md.mli
+++ b/daemon/md.mli
@@ -17,3 +17,4 @@
  *)

 val list_md_devices : unit -> string list
+val md_detail : string -> (string * string) list
diff --git a/generator/actions_core.ml b/generator/actions_core.ml
index db1411ff8..070a1c641 100644
--- a/generator/actions_core.ml
+++ b/generator/actions_core.ml
@@ -6606,6 +6606,7 @@ List all Linux md devices." };
   { defaults with
     name = "md_detail"; added = (1, 15, 6);
     style = RHashtable (RPlainString, RPlainString, "info"), [String
(Device, "md")], [];
+    impl = OCaml "Md.md_detail";
     optional = Some "mdadm";
     shortdesc = "obtain metadata for an MD device";
     longdesc = "\
diff --git a/generator/daemon.ml b/generator/daemon.ml
index 66b625388..f20c87bea 100644
--- a/generator/daemon.ml
+++ b/generator/daemon.ml
@@ -597,6 +597,30 @@ return_string_mountable (value retv)
   }
 }

+/* Implement RHashtable (RPlainString, RPlainString, _). */
+static char **
+return_hashtable_string_string (value retv)
+{
+  CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (ret);
+  value v, sv;
+
+  while (retv != Val_int (0)) {
+    v = Field (retv, 0);        /* (string, string) */
+    sv = Field (v, 0);          /* string */
+    if (add_string (&ret, String_val (sv)) == -1)
+      return NULL;
+    sv = Field (v, 1);          /* string */
+    if (add_string (&ret, String_val (sv)) == -1)
+      return NULL;
+    retv = Field (retv, 1);
+  }
+
+  if (end_stringsbuf (&ret) == -1)
+    return NULL;
+
+  return take_stringsbuf (&ret); /* caller frees */
+}
+
 /* Implement RHashtable (RMountable, RPlainString, _). */
 static char **
 return_hashtable_mountable_string (value retv)
@@ -878,6 +902,9 @@ return_hashtable_mountable_string (value retv)
           pr "    return_%s_list (retv);\n" typ;
           pr "  /* caller frees */\n";
           pr "  CAMLreturnT (guestfs_int_%s_list *, ret);\n" typ
+       | RHashtable (RPlainString, RPlainString, _) ->
+          pr "  char **ret = return_hashtable_string_string
(retv);\n";
+          pr "  CAMLreturnT (char **, ret); /* caller frees */\n"
        | RHashtable (RMountable, RPlainString, _) ->
           pr "  char **ret = return_hashtable_mountable_string
(retv);\n";
           pr "  CAMLreturnT (char **, ret); /* caller frees */\n"
--
2.13.0