#include "daemon.h"
#include "actions.h"
#include "optgroups.h"
+#include "c-ctype.h"
int
optgroup_mdadm_available (void)
/* 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];
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;
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;
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") &&
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");
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);
return 0;
}
+
+static int
+glob_errfunc (const char *epath, int eerrno)
+{
+ fprintf (stderr, "glob: failure reading %s: %s\n", epath, strerror (eerrno));
+ return 1;
+}
+
+char **
+do_list_md_devices (void)
+{
+ char **r = NULL;
+ int size = 0, alloc = 0;
+ glob_t mds;
+
+ memset(&mds, 0, sizeof(mds));
+
+#define PREFIX "/sys/block/md"
+#define SUFFIX "/md"
+
+ /* Look for directories under /sys/block matching md[0-9]*
+ * As an additional check, we also make sure they have a md subdirectory.
+ */
+ int err = glob (PREFIX "[0-9]*" SUFFIX, GLOB_ERR, glob_errfunc, &mds);
+ if (err == GLOB_NOSPACE) {
+ reply_with_error ("glob: returned GLOB_NOSPACE: "
+ "rerun with LIBGUESTFS_DEBUG=1");
+ goto error;
+ } else if (err == GLOB_ABORTED) {
+ reply_with_error ("glob: returned GLOB_ABORTED: "
+ "rerun with LIBGUESTFS_DEBUG=1");
+ goto error;
+ }
+
+ for (size_t i = 0; i < mds.gl_pathc; i++) {
+ size_t len = strlen (mds.gl_pathv[i]) - strlen (PREFIX) - strlen (SUFFIX);
+
+#define DEV "/dev/md"
+ char *dev = malloc (strlen(DEV) + len + 1);
+ if (NULL == dev) {
+ reply_with_perror("malloc");
+ goto error;
+ }
+
+ char *n = dev;
+ n = mempcpy(n, DEV, strlen(DEV));
+ n = mempcpy(n, &mds.gl_pathv[i][strlen(PREFIX)], len);
+ *n = '\0';
+
+ if (add_string_nodup (&r, &size, &alloc, dev) == -1) goto error;
+ }
+
+ if (add_string_nodup (&r, &size, &alloc, NULL) == -1) goto error;
+ globfree (&mds);
+
+ return r;
+
+error:
+ globfree (&mds);
+ 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;
+}