]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - mdstat.c
Add gpt pseudo-metadata
[thirdparty/mdadm.git] / mdstat.c
index ebdfc67bf6d46705e1ebcb74212299b2aa47b66c..47be2bba21fabaac7a617f8b4f0264f7fcd966a3 100644 (file)
--- a/mdstat.c
+++ b/mdstat.c
@@ -2,7 +2,7 @@
  * mdstat - parse /proc/mdstat file. Part of:
  * mdadm - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2002-2006 Neil Brown <neilb@suse.de>
+ * Copyright (C) 2002-2009 Neil Brown <neilb@suse.de>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  *    Author: Neil Brown
- *    Email: <neilb@cse.unsw.edu.au>
- *    Paper: Neil Brown
- *           School of Computer Science and Engineering
- *           The University of New South Wales
- *           Sydney, 2052
- *           Australia
+ *    Email: <neilb@suse.de>
  */
 
 /*
 #include       <sys/select.h>
 #include       <ctype.h>
 
+static void free_member_devnames(struct dev_member *m)
+{
+       while(m) {
+               struct dev_member *t = m;
+
+               m = m->next;
+               free(t->name);
+               free(t);
+       }
+}
+
+static int add_member_devname(struct dev_member **m, char *name)
+{
+       struct dev_member *new;
+       char *t;
+
+       if ((t = strchr(name, '[')) == NULL)
+               /* not a device */
+               return 0;
+
+       new = malloc(sizeof(*new));
+       new->name = strndup(name, t - name);
+       new->next = *m;
+       *m = new;
+       return 1;
+}
+
 void free_mdstat(struct mdstat_ent *ms)
 {
        while (ms) {
                struct mdstat_ent *t;
-               if (ms->dev) free(ms->dev);
-               if (ms->level) free(ms->level);
-               if (ms->pattern) free(ms->pattern);
-               if (ms->metadata_version) free(ms->metadata_version);
+               free(ms->dev);
+               free(ms->level);
+               free(ms->pattern);
+               free(ms->metadata_version);
+               free_member_devnames(ms->members);
                t = ms;
                ms = ms->next;
                free(t);
@@ -164,6 +187,7 @@ struct mdstat_ent *mdstat_read(int hold, int start)
                ent->raid_disks = 0;
                ent->chunk_size = 0;
                ent->devcnt = 0;
+               ent->members = NULL;
 
                ent->dev = strdup(line);
                ent->devnum = devnum;
@@ -173,9 +197,10 @@ struct mdstat_ent *mdstat_read(int hold, int start)
                        char *eq;
                        if (strcmp(w, "active")==0)
                                ent->active = 1;
-                       else if (strcmp(w, "inactive")==0)
+                       else if (strcmp(w, "inactive")==0) {
                                ent->active = 0;
-                       else if (ent->active >=0 &&
+                               in_devs = 1;
+                       } else if (ent->active > 0 &&
                                 ent->level == NULL &&
                                 w[0] != '(' /*readonly*/) {
                                ent->level = strdup(w);
@@ -183,7 +208,8 @@ struct mdstat_ent *mdstat_read(int hold, int start)
                        } else if (in_devs && strcmp(w, "blocks")==0)
                                in_devs = 0;
                        else if (in_devs) {
-                               ent->devcnt++;
+                               ent->devcnt +=
+                                       add_member_devname(&ent->members, w);
                                if (strncmp(w, "md", 2)==0) {
                                        /* This has an md device as a component.
                                         * If that device is already in the
@@ -274,14 +300,29 @@ void mdstat_wait(int seconds)
 void mdstat_wait_fd(int fd, const sigset_t *sigmask)
 {
        fd_set fds, rfds;
-       int maxfd = fd;
+       int maxfd = 0;
 
        FD_ZERO(&fds);
        FD_ZERO(&rfds);
        if (mdstat_fd >= 0)
                FD_SET(mdstat_fd, &fds);
-       if (fd >= 0)
-               FD_SET(fd, &rfds);
+
+       if (fd >= 0) {
+               struct stat stb;
+               fstat(fd, &stb);
+               if ((stb.st_mode & S_IFMT) == S_IFREG)
+                       /* Must be a /proc or /sys fd, so expect
+                        * POLLPRI
+                        * i.e. an 'exceptional' event.
+                        */
+                       FD_SET(fd, &fds);
+               else
+                       FD_SET(fd, &rfds);
+
+               if (fd > maxfd)
+                       maxfd = fd;
+
+       }
        if (mdstat_fd > maxfd)
                maxfd = mdstat_fd;
 
@@ -300,3 +341,30 @@ int mddev_busy(int devnum)
        free_mdstat(mdstat);
        return me != NULL;
 }
+
+struct mdstat_ent *mdstat_by_component(char *name)
+{
+       struct mdstat_ent *mdstat = mdstat_read(0, 0);
+
+       while (mdstat) {
+               struct dev_member *m;
+               struct mdstat_ent *ent;
+               if (mdstat->metadata_version &&
+                   strncmp(mdstat->metadata_version, "external:", 9) == 0 &&
+                   is_subarray(mdstat->metadata_version+9))
+                       /* don't return subarrays, only containers */
+                       ;
+               else for (m = mdstat->members; m; m = m->next) {
+                               if (strcmp(m->name, name) == 0) {
+                                       free_mdstat(mdstat->next);
+                                       mdstat->next = NULL;
+                                       return mdstat;
+                               }
+                       }
+               ent = mdstat;
+               mdstat = mdstat->next;
+               ent->next = NULL;
+               free_mdstat(ent);
+       }
+       return NULL;
+}