summaryrefslogtreecommitdiffstats
path: root/daemon
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-03-20 17:17:02 +0000
committerRichard W.M. Jones <rjones@redhat.com>2012-03-20 18:50:24 +0000
commit3f6cc550ff5dcaca813b19938daaf41baacb1efa (patch)
tree112bec75e5bb37ce22448401cf9c92c720f73b86 /daemon
parent65ebec4a7a70cd179e4c39d72f539e500931c267 (diff)
downloadlibguestfs-3f6cc550ff5dcaca813b19938daaf41baacb1efa.tar.gz
libguestfs-3f6cc550ff5dcaca813b19938daaf41baacb1efa.tar.xz
libguestfs-3f6cc550ff5dcaca813b19938daaf41baacb1efa.zip
New API: md-stat.
This returns information about the underlying devices of an MD (software RAID) device.
Diffstat (limited to 'daemon')
-rw-r--r--daemon/md.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/daemon/md.c b/daemon/md.c
index 265f4f4c..0e2f7048 100644
--- a/daemon/md.c
+++ b/daemon/md.c
@@ -329,3 +329,175 @@ do_md_stop(const char *md)
free (err);
return 0;
}
+
+static size_t
+count_spaces (const char *line)
+{
+ size_t r = 0;
+ while (*line) {
+ if (*line == ' ')
+ r++;
+ line++;
+ }
+ return r;
+}
+
+/* Parse a line like: "active raid1 sdb1[0] sdc1[1](F)" */
+static guestfs_int_mdstat_list *
+parse_md_stat_line (char *line)
+{
+ guestfs_int_mdstat_list *ret;
+ guestfs_int_mdstat *t;
+ size_t spaces, n, i, len;
+ char *next;
+ char *p, *q;
+
+ ret = malloc (sizeof *ret);
+ if (!ret) {
+ reply_with_perror ("malloc");
+ return NULL;
+ }
+
+ /* We don't know exactly how many entries we will need yet, but we
+ * can estimate it, and this will always be an over-estimate.
+ */
+ spaces = count_spaces (line);
+ ret->guestfs_int_mdstat_list_val =
+ calloc (spaces+1, sizeof (struct guestfs_int_mdstat));
+ if (ret->guestfs_int_mdstat_list_val == NULL) {
+ reply_with_perror ("malloc");
+ free (ret);
+ return NULL;
+ }
+
+ for (n = 0; *line; line = next) {
+ len = strcspn (line, " ");
+ if (line[len] == '\0')
+ next = &line[len];
+ else {
+ line[len] = '\0';
+ next = &line[len+1];
+ }
+
+ if (verbose)
+ printf ("mdstat: %s\n", line);
+
+ /* Looking for entries that contain "[..]", skip ones which don't. */
+ p = strchr (line, '[');
+ if (p == NULL)
+ continue;
+ q = strchr (line, ']');
+ if (q == NULL)
+ continue;
+ if (p > q)
+ continue;
+
+ ret->guestfs_int_mdstat_list_len = n+1;
+ t = &ret->guestfs_int_mdstat_list_val[n];
+
+ /* Device name is everything before the '[' character, but we
+ * need to prefix with /dev/.
+ */
+ if (p == line) {
+ reply_with_error ("device entry is too short: %s", line);
+ goto error;
+ }
+
+ *p = '\0';
+ if (asprintf (&t->mdstat_device, "/dev/%s", line) == -1) {
+ reply_with_perror ("asprintf");
+ goto error;
+ }
+
+ /* Device index is the number after '['. */
+ line = p+1;
+ *q = '\0';
+ if (sscanf (line, "%" SCNi32, &t->mdstat_index) != 1) {
+ reply_with_error ("not a device number: %s", line);
+ goto error;
+ }
+
+ /* Looking for flags "(F)(S)...". */
+ line = q+1;
+ len = strlen (line);
+ t->mdstat_flags = malloc (len+1);
+ if (!t->mdstat_flags) {
+ reply_with_error ("malloc");
+ goto error;
+ }
+
+ for (i = 0; *line; line++) {
+ if (c_isalpha (*line))
+ t->mdstat_flags[i++] = *line;
+ }
+ t->mdstat_flags[i] = '\0';
+
+ n++;
+ }
+
+ return ret;
+
+ error:
+ for (i = 0; i <= spaces; ++i) {
+ free (ret->guestfs_int_mdstat_list_val[i].mdstat_device);
+ free (ret->guestfs_int_mdstat_list_val[i].mdstat_flags);
+ }
+ free (ret->guestfs_int_mdstat_list_val);
+ free (ret);
+ return NULL;
+}
+
+extern guestfs_int_mdstat_list *
+do_md_stat (const char *md)
+{
+ size_t mdlen;
+ FILE *fp;
+ char *line = NULL;
+ size_t len = 0;
+ ssize_t n;
+ guestfs_int_mdstat_list *ret = NULL;
+
+ if (STRPREFIX (md, "/dev/"))
+ md += 5;
+ mdlen = strlen (md);
+
+ fp = fopen ("/proc/mdstat", "r");
+ if (fp == NULL) {
+ reply_with_perror ("fopen: %s", "/proc/mdstat");
+ return NULL;
+ }
+
+ /* Search for a line which begins with "<md> : ". */
+ while ((n = getline (&line, &len, fp)) != -1) {
+ if (STRPREFIX (line, md) &&
+ line[mdlen] == ' ' && line[mdlen+1] == ':' && line[mdlen+2] == ' ') {
+ /* Found it. */
+ ret = parse_md_stat_line (&line[mdlen+3]);
+ if (!ret) {
+ free (line);
+ fclose (fp);
+ return NULL;
+ }
+
+ /* Stop parsing the mdstat file after we've found the line
+ * we are interested in.
+ */
+ break;
+ }
+ }
+
+ free (line);
+
+ if (fclose (fp) == EOF) {
+ reply_with_perror ("fclose: %s", "/proc/mdstat");
+ return NULL;
+ }
+
+ /* Did we find the line? */
+ if (!ret) {
+ reply_with_error ("%s: MD device not found", md);
+ return NULL;
+ }
+
+ return ret;
+}