diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-03-20 17:17:02 +0000 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-03-20 18:50:24 +0000 |
commit | 3f6cc550ff5dcaca813b19938daaf41baacb1efa (patch) | |
tree | 112bec75e5bb37ce22448401cf9c92c720f73b86 /daemon | |
parent | 65ebec4a7a70cd179e4c39d72f539e500931c267 (diff) | |
download | libguestfs-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.c | 172 |
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; +} |