debian: Use mdadm -D --export instead of mdadm -DY.
[libguestfs.git] / daemon / md.c
index 257bd0f..5a4d815 100644 (file)
@@ -27,6 +27,7 @@
 #include "daemon.h"
 #include "actions.h"
 #include "optgroups.h"
+#include "c-ctype.h"
 
 int
 optgroup_mdadm_available (void)
@@ -49,9 +50,9 @@ count_bits (uint64_t bitmap)
 
 /* Takes optional arguments, consult optargs_bitmask. */
 int
-do_mdadm_create (const char *name, char *const *devices,
-                 int64_t missingbitmap, int nrdevices, int spare,
-                 int64_t chunk, const char *level)
+do_md_create (const char *name, char *const *devices,
+              int64_t missingbitmap, int nrdevices, int spare,
+              int64_t chunk, const char *level)
 {
   char nrdevices_s[32];
   char spare_s[32];
@@ -62,10 +63,10 @@ do_mdadm_create (const char *name, char *const *devices,
   uint64_t umissingbitmap = (uint64_t) missingbitmap;
 
   /* Check the optional parameters and set defaults where appropriate. */
-  if (!(optargs_bitmask & GUESTFS_MDADM_CREATE_MISSINGBITMAP_BITMASK))
+  if (!(optargs_bitmask & GUESTFS_MD_CREATE_MISSINGBITMAP_BITMASK))
     umissingbitmap = 0;
 
-  if (optargs_bitmask & GUESTFS_MDADM_CREATE_SPARE_BITMASK) {
+  if (optargs_bitmask & GUESTFS_MD_CREATE_SPARE_BITMASK) {
     if (spare < 0) {
       reply_with_error ("spare must not be negative");
       return -1;
@@ -74,7 +75,7 @@ do_mdadm_create (const char *name, char *const *devices,
   else
     spare = 0;
 
-  if (optargs_bitmask & GUESTFS_MDADM_CREATE_NRDEVICES_BITMASK) {
+  if (optargs_bitmask & GUESTFS_MD_CREATE_NRDEVICES_BITMASK) {
     if (nrdevices < 2) {
       reply_with_error ("nrdevices is less than 2");
       return -1;
@@ -83,7 +84,7 @@ do_mdadm_create (const char *name, char *const *devices,
   else
     nrdevices = count_strings (devices) + count_bits (umissingbitmap);
 
-  if (optargs_bitmask & GUESTFS_MDADM_CREATE_LEVEL_BITMASK) {
+  if (optargs_bitmask & GUESTFS_MD_CREATE_LEVEL_BITMASK) {
     if (STRNEQ (level, "linear") && STRNEQ (level, "raid0") &&
         STRNEQ (level, "0") && STRNEQ (level, "stripe") &&
         STRNEQ (level, "raid1") && STRNEQ (level, "1") &&
@@ -99,7 +100,7 @@ do_mdadm_create (const char *name, char *const *devices,
   else
     level = "raid1";
 
-  if (optargs_bitmask & GUESTFS_MDADM_CREATE_CHUNK_BITMASK) {
+  if (optargs_bitmask & GUESTFS_MD_CREATE_CHUNK_BITMASK) {
     /* chunk is bytes in the libguestfs API, but K when we pass it to mdadm */
     if ((chunk & 1023) != 0) {
       reply_with_error ("chunk size must be a multiple of 1024 bytes");
@@ -130,12 +131,12 @@ do_mdadm_create (const char *name, char *const *devices,
   ADD_ARG (argv, i, "--raid-devices");
   snprintf (nrdevices_s, sizeof nrdevices_s, "%d", nrdevices);
   ADD_ARG (argv, i, nrdevices_s);
-  if (optargs_bitmask & GUESTFS_MDADM_CREATE_SPARE_BITMASK) {
+  if (optargs_bitmask & GUESTFS_MD_CREATE_SPARE_BITMASK) {
     ADD_ARG (argv, i, "--spare-devices");
     snprintf (spare_s, sizeof spare_s, "%d", spare);
     ADD_ARG (argv, i, spare_s);
   }
-  if (optargs_bitmask & GUESTFS_MDADM_CREATE_CHUNK_BITMASK) {
+  if (optargs_bitmask & GUESTFS_MD_CREATE_CHUNK_BITMASK) {
     ADD_ARG (argv, i, "--chunk");
     snprintf (chunk_s, sizeof chunk_s, "%" PRIi64, chunk / 1024);
     ADD_ARG (argv, i, chunk_s);
@@ -230,3 +231,98 @@ error:
   if (r != NULL) free_strings (r);
   return NULL;
 }
+
+char **
+do_md_detail(const char *md)
+{
+  int r;
+
+  char *out = NULL, *err = NULL;
+  char **lines = NULL;
+
+  char **ret = NULL;
+  int size = 0, alloc = 0;
+
+  const char *mdadm[] = { "mdadm", "-D", "--export", md, NULL };
+  r = commandv(&out, &err, mdadm);
+  if (r == -1) {
+    reply_with_error("%s", err);
+    goto error;
+  }
+
+  /* Split the command output into lines */
+  lines = split_lines(out);
+  if (lines == NULL) {
+    reply_with_perror("malloc");
+    goto error;
+  }
+
+  /* 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 (char **i = lines; *i != NULL; i++) {
+    char *line = *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, &size, &alloc, line) == -1 ||
+          add_string(&ret, &size, &alloc, eq) == -1) goto error;
+    } 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);
+    }
+  }
+
+  free(out);
+  free(err);
+  free(lines); /* We freed the contained strings when we freed out */
+
+  if (add_string(&ret, &size, &alloc, NULL) == -1) return NULL;
+
+  return ret;
+
+error:
+  free(out);
+  free(err);
+  if (lines) free(lines);
+  if (ret) free_strings(ret);
+
+  return NULL;
+}
+
+int
+do_md_stop(const char *md)
+{
+  int r;
+  char *err = NULL;
+
+  const char *mdadm[] = { "mdadm", "--stop", md, NULL};
+  r = commandv(NULL, &err, mdadm);
+  if (r == -1) {
+    reply_with_error("%s", err);
+    free(err);
+    return -1;
+  }
+  return 0;
+}