]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - util.c
Make scanning of /dev work even if it is a symlink
[thirdparty/mdadm.git] / util.c
diff --git a/util.c b/util.c
index 7621340bc2b24d6f34abfc1758e930b4a1361f4f..ab606ab12fa08f4861eb6fef549e89050f6f4131 100644 (file)
--- a/util.c
+++ b/util.c
@@ -118,10 +118,31 @@ int get_linux_version()
        return (a*1000000)+(b*1000)+c;
 }
 
-int enough(int level, int raid_disks, int avail_disks)
+int enough(int level, int raid_disks, int layout,
+          char *avail, int avail_disks)
 {
+       int copies, first;
        switch (level) {
-       case 10: return 1; /* a lie, but it is hard to tell */
+       case 10:
+               /* This is the tricky one - we need to check
+                * which actual disks are present.
+                */
+               copies = (layout&255)* (layout>>8);
+               first=0;
+               do {
+                       /* there must be one of the 'copies' form 'first' */
+                       int n = copies;
+                       int cnt=0;
+                       while (n--) {
+                               if (avail[first])
+                                       cnt++;
+                               first = (first+1) % raid_disks;
+                       }
+                       if (cnt == 0)
+                               return 0;
+
+               } while (first != 0);
+               return 1;
 
        case -4:
                return avail_disks>= 1;
@@ -208,7 +229,7 @@ int check_reiser(int fd, char *name)
         *
         */
        unsigned char sb[1024];
-       int size;
+       unsigned long size;
        if (lseek(fd, 64*1024, 0) != 64*1024)
                return 0;
        if (read(fd, sb, 1024) != 1024)
@@ -218,7 +239,7 @@ int check_reiser(int fd, char *name)
                return 0;
        fprintf(stderr, Name ": %s appears to contain a reiserfs file system\n",name);
        size = sb[0]|(sb[1]|(sb[2]|sb[3]<<8)<<8)<<8;
-       fprintf(stderr, "    size = %dK\n", size*4);
+       fprintf(stderr, "    size = %luK\n", size*4);
                
        return 1;
 }
@@ -228,6 +249,7 @@ int check_raid(int fd, char *name)
        void *super;
        struct mdinfo info;
        time_t crtime;
+       char *level;
        struct supertype *st = guess_super(fd);
 
        if (!st) return 0;
@@ -238,8 +260,10 @@ int check_raid(int fd, char *name)
        st->ss->getinfo_super(&info, super);
        free(super);
        crtime = info.array.ctime;
-       fprintf(stderr, "    level=%d devices=%d ctime=%s",
-               info.array.level, info.array.raid_disks, ctime(&crtime));
+       level = map_num(pers, info.array.level);
+       if (!level) level = "-unknown-";
+       fprintf(stderr, "    level=%s devices=%d ctime=%s",
+               level, info.array.raid_disks, ctime(&crtime));
        return 1;
 }
 
@@ -360,6 +384,8 @@ int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s)
     if ((stb->st_mode&S_IFMT)== S_IFBLK) {
        char *n = strdup(name);
        struct devmap *dm = malloc(sizeof(*dm));
+       if (strncmp(n, "/dev/.", 6)==0)
+               strcpy(n+4, name+6);
        if (dm) {
            dm->major = major(stb->st_rdev);
            dm->minor = minor(stb->st_rdev);
@@ -383,7 +409,12 @@ char *map_dev(int major, int minor)
        struct devmap *p;
        char *std = NULL, *nonstd=NULL;
        if (!devlist_ready) {
-               nftw("/dev", add_dev, 10, FTW_PHYS);
+               char *dev = "/dev";
+               struct stat stb;
+               if (lstat(dev, &stb)==0 &&
+                   S_ISLNK(stb.st_mode))
+                       dev = "/dev/.";
+               nftw(dev, add_dev, 10, FTW_PHYS);
                devlist_ready=1;
        }
 
@@ -564,7 +595,28 @@ void put_md_name(char *name)
                unlink(name);
 }
 
-
+int dev_open(char *dev, int flags)
+{
+       /* like 'open', but if 'dev' matches %d:%d, create a temp
+        * block device and open that
+        */
+       char *e;
+       int fd = -1;
+       char devname[32];
+       int major = strtoul(dev, &e, 0);
+       int minor;
+       if (e > dev && *e == ':' && e[1] &&
+           (minor = strtoul(e+1, &e, 0)) >= 0 &&
+           *e == 0) {
+               snprintf(devname, sizeof(devname), "/dev/.tmp.md.%d:%d", major, minor);
+               if (mknod(devname, S_IFBLK|0600, makedev(major, minor))==0) {
+                       fd = open(devname, flags);
+                       unlink(devname);
+               }
+       } else
+               fd = open(dev, flags);
+       return fd;
+}
 
 struct superswitch *superlist[] = { &super0, &super1, NULL };
 
@@ -629,6 +681,7 @@ struct supertype *guess_super(int fd)
        return NULL;
 }
 
+
 #ifdef __TINYC__
 /* tinyc doesn't optimize this check in ioctl.h out ... */
 unsigned int __invalid_size_argument_for_IOC = 0;