]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - util.c
MISC: Add --examine-badblocks option
[thirdparty/mdadm.git] / util.c
diff --git a/util.c b/util.c
index c63a232c919931063beb51b131e6c036eec695e7..6c10365e80c99a39e55111af98b5ccc4e40c5296 100644 (file)
--- a/util.c
+++ b/util.c
@@ -43,10 +43,10 @@ int __offroot;
 
 /* The argument structure */
 struct blkpg_ioctl_arg {
-        int op;
-        int flags;
-        int datalen;
-        void *data;
+       int op;
+       int flags;
+       int datalen;
+       void *data;
 };
 
 /* The subfunctions (for the op field) */
@@ -127,21 +127,21 @@ int parse_uuid(char *str, int uuid[4])
 
 int md_get_version(int fd)
 {
-    struct stat stb;
-    mdu_version_t vers;
+       struct stat stb;
+       mdu_version_t vers;
 
-    if (fstat(fd, &stb)<0)
-       return -1;
-    if ((S_IFMT&stb.st_mode) != S_IFBLK)
-       return -1;
+       if (fstat(fd, &stb)<0)
+               return -1;
+       if ((S_IFMT&stb.st_mode) != S_IFBLK)
+               return -1;
 
-    if (ioctl(fd, RAID_VERSION, &vers) == 0)
-       return  (vers.major*10000) + (vers.minor*100) + vers.patchlevel;
-    if (errno == EACCES)
-           return -1;
-    if (major(stb.st_rdev) == MD_MAJOR)
-       return (3600);
-    return -1;
+       if (ioctl(fd, RAID_VERSION, &vers) == 0)
+               return  (vers.major*10000) + (vers.minor*100) + vers.patchlevel;
+       if (errno == EACCES)
+               return -1;
+       if (major(stb.st_rdev) == MD_MAJOR)
+               return (3600);
+       return -1;
 }
 
 int get_linux_version()
@@ -194,7 +194,7 @@ unsigned long long parse_size(char *size)
         * followed by 'K', 'M', or 'G'.
         * Without a suffix, K is assumed.
         * Number returned is in sectors (half-K)
-        * 0 returned on error.
+        * INVALID_SECTORS returned on error.
         */
        char *c;
        long long s = strtoll(size, &c, 10);
@@ -213,11 +213,14 @@ unsigned long long parse_size(char *size)
                        c++;
                        s *= 1024 * 1024 * 2;
                        break;
+               case 's': /* sectors */
+                       c++;
+                       break;
                }
        } else
-               s = 0;
+               s = INVALID_SECTORS;
        if (*c)
-               s = 0;
+               s = INVALID_SECTORS;
        return s;
 }
 
@@ -344,14 +347,15 @@ int enough(int level, int raid_disks, int layout, int clean, char *avail)
                        /* there must be one of the 'copies' form 'first' */
                        int n = copies;
                        int cnt = 0;
+                       int this = first;
                        while (n--) {
-                               if (avail[first])
+                               if (avail[this])
                                        cnt++;
-                               first = (first+1) % raid_disks;
+                               this = (this+1) % raid_disks;
                        }
                        if (cnt == 0)
                                return 0;
-
+                       first = (first+(layout&255)) % raid_disks;
                } while (first != 0);
                return 1;
 
@@ -555,8 +559,8 @@ int check_raid(int fd, char *name)
        char *level;
        struct supertype *st = guess_super(fd);
 
-       if (!st) return 0;
-       st->ignore_hw_compat = 1;
+       if (!st)
+               return 0;
        st->ss->load_super(st, fd, name);
        /* Looks like a raid array .. */
        pr_err("%s appears to be part of a raid array:\n",
@@ -682,24 +686,49 @@ char *human_size(long long bytes)
        return buf;
 }
 
-char *human_size_brief(long long bytes)
+char *human_size_brief(long long bytes, int prefix)
 {
        static char buf[30];
 
+       /* We convert bytes to either centi-M{ega,ibi}bytes or
+        * centi-G{igi,ibi}bytes, with appropriate rounding,
+        * and then print 1/100th of those as a decimal.
+        * We allow upto 2048Megabytes before converting to
+        * gigabytes, as that shows more precision and isn't
+        * too large a number.
+        * Terabytes are not yet handled.
+        *
+        * If prefix == IEC, we mean prefixes like kibi,mebi,gibi etc.
+        * If prefix == JEDEC, we mean prefixes like kilo,mega,giga etc.
+        */
+
        if (bytes < 5000*1024)
-               snprintf(buf, sizeof(buf), "%ld.%02ldKiB",
-                       (long)(bytes>>10), (long)(((bytes&1023)*100+512)/1024)
-                       );
-       else if (bytes < 2*1024LL*1024LL*1024LL)
-               snprintf(buf, sizeof(buf), "%ld.%02ldMiB",
-                       (long)(bytes>>20),
-                       (long)((bytes&0xfffff)+0x100000/200)/(0x100000/100)
-                       );
+               buf[0] = 0;
+       else if (prefix == IEC) {
+               if (bytes < 2*1024LL*1024LL*1024LL) {
+                       long cMiB = (bytes / ( (1LL<<20) / 200LL ) +1) /2;
+                       snprintf(buf, sizeof(buf), "%ld.%02ldMiB",
+                               cMiB/100 , cMiB % 100);
+               } else {
+                       long cGiB = (bytes / ( (1LL<<30) / 200LL ) +1) /2;
+                       snprintf(buf, sizeof(buf), "%ld.%02ldGiB",
+                                       cGiB/100 , cGiB % 100);
+               }
+       }
+       else if (prefix == JEDEC) {
+               if (bytes < 2*1024LL*1024LL*1024LL) {
+                       long cMB  = (bytes / ( 1000000LL / 200LL ) +1) /2;
+                       snprintf(buf, sizeof(buf), "%ld.%02ldMB",
+                                       cMB/100, cMB % 100);
+               } else {
+                       long cGB  = (bytes / (1000000000LL/200LL ) +1) /2;
+                       snprintf(buf, sizeof(buf), "%ld.%02ldGB",
+                                       cGB/100 , cGB % 100);
+               }
+       }
        else
-               snprintf(buf, sizeof(buf), "%ld.%02ldGiB",
-                       (long)(bytes>>30),
-                       (long)(((bytes>>10)&0xfffff)+0x100000/200)/(0x100000/100)
-                       );
+               buf[0] = 0;
+
        return buf;
 }
 
@@ -1048,6 +1077,7 @@ struct supertype *dup_super(struct supertype *orig)
        st->ss = orig->ss;
        st->max_devs = orig->max_devs;
        st->minor_version = orig->minor_version;
+       st->ignore_hw_compat = orig->ignore_hw_compat;
        st->sb = NULL;
        st->info = NULL;
        return st;
@@ -1095,7 +1125,6 @@ struct supertype *guess_super_type(int fd, enum guess_types guess_type)
                rv = superlist[bestsuper]->load_super(st, fd, NULL);
                if (rv == 0) {
                        superlist[bestsuper]->free_super(st);
-                       st->ignore_hw_compat = 0;
                        return st;
                }
        }
@@ -1283,18 +1312,6 @@ int check_partitions(int fd, char *dname, unsigned long long freesize,
        return 0;
 }
 
-void get_one_disk(int mdfd, mdu_array_info_t *ainf, mdu_disk_info_t *disk)
-{
-       int d;
-
-       ioctl(mdfd, GET_ARRAY_INFO, ainf);
-       for (d = 0 ; d < MAX_DISKS ; d++) {
-               if (ioctl(mdfd, GET_DISK_INFO, disk) == 0 &&
-                   (disk->major || disk->minor))
-                       return;
-       }
-}
-
 int open_container(int fd)
 {
        /* 'fd' is a block device.  Find out if it is in use
@@ -1323,6 +1340,20 @@ int open_container(int fd)
                        continue;
                if (de->d_name[0] == '.')
                        continue;
+               /* Need to make sure it is a container and not a volume */
+               sprintf(e, "/%s/md/metadata_version", de->d_name);
+               dfd = open(path, O_RDONLY);
+               if (dfd < 0)
+                       continue;
+               n = read(dfd, buf, sizeof(buf));
+               close(dfd);
+               if (n <= 0 || (unsigned)n >= sizeof(buf))
+                       continue;
+               buf[n] = 0;
+               if (strncmp(buf, "external", 8) != 0 ||
+                   n < 10 ||
+                   buf[9] == '/')
+                       continue;
                sprintf(e, "/%s/dev", de->d_name);
                dfd = open(path, O_RDONLY);
                if (dfd < 0)
@@ -1808,3 +1839,24 @@ struct mdinfo *container_choose_spares(struct supertype *st,
        }
        return disks;
 }
+
+/* Checks if paths point to the same device
+ * Returns 0 if they do.
+ * Returns 1 if they don't.
+ * Returns -1 if something went wrong,
+ * e.g. paths are empty or the files
+ * they point to don't exist */
+int compare_paths (char* path1, char* path2)
+{
+       struct stat st1,st2;
+
+       if (path1 == NULL || path2 == NULL)
+               return -1;
+       if (stat(path1,&st1) != 0)
+               return -1;
+       if (stat(path2,&st2) != 0)
+               return -1;
+       if ((st1.st_ino == st2.st_ino) && (st1.st_dev == st2.st_dev))
+               return 0;
+       return 1;
+}