]> git.proxmox.com Git - grub2.git/blobdiff - grub-core/disk/raid.c
* grub-core/disk/raid.c (insert_array): Ensure uniqueness of readable
[grub2.git] / grub-core / disk / raid.c
index f1b67a8591b69d538f20e15c08ab55a7559dc008..7c7dbc3dc7859d9c23a0f9c4b3ffff5b5c68e846 100644 (file)
 #include <grub/err.h>
 #include <grub/misc.h>
 #include <grub/raid.h>
+#ifdef GRUB_UTIL
+#include <grub/util/misc.h>
+#endif
+
+GRUB_MOD_LICENSE ("GPLv3+");
 
 /* Linked list of RAID arrays. */
 static struct grub_raid_array *array_list;
@@ -117,18 +122,49 @@ grub_raid_getname (struct grub_disk *disk)
 }
 #endif
 
+static inline int
+ascii2hex (char c)
+{
+  if (c >= '0' && c <= '9')
+    return c - '0';
+  if (c >= 'a' && c <= 'f')
+    return c - 'a' + 10;
+  if (c >= 'A' && c <= 'F')
+    return c - 'A' + 10;
+  return 0;
+}
+
 static grub_err_t
 grub_raid_open (const char *name, grub_disk_t disk)
 {
   struct grub_raid_array *array;
   unsigned n;
 
-  for (array = array_list; array != NULL; array = array->next)
+  if (grub_memcmp (name, "mduuid/", sizeof ("mduuid/") - 1) == 0)
     {
-      if (!grub_strcmp (array->name, name))
-       if (grub_is_array_readable (array))
-         break;
+      const char *uuidstr = name + sizeof ("mduuid/") - 1;
+      grub_size_t uuid_len = grub_strlen (uuidstr) / 2;
+      grub_uint8_t uuidbin[uuid_len];
+      unsigned i;
+      for (i = 0; i < uuid_len; i++)
+       uuidbin[i] = ascii2hex (uuidstr[2 * i + 1])
+         | (ascii2hex (uuidstr[2 * i]) << 4);
+      
+      for (array = array_list; array != NULL; array = array->next)
+       {
+         if (uuid_len == (unsigned) array->uuid_len
+             && grub_memcmp (uuidbin, array->uuid, uuid_len) == 0)
+           if (grub_is_array_readable (array))
+             break;
+       }
     }
+  else
+    for (array = array_list; array != NULL; array = array->next)
+      {
+       if (!grub_strcmp (array->name, name))
+         if (grub_is_array_readable (array))
+           break;
+      }
 
   if (!array)
     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
@@ -209,7 +245,7 @@ grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector,
     case 10:
       {
         grub_disk_addr_t read_sector, far_ofs;
-       grub_uint32_t disknr, b, near, far, ofs;
+       grub_uint64_t disknr, b, near, far, ofs;
 
         read_sector = grub_divmod64 (sector, array->chunk_size, &b);
         far = ofs = near = 1;
@@ -315,7 +351,7 @@ grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector,
     case 6:
       {
        grub_disk_addr_t read_sector;
-       grub_uint32_t b, p, n, disknr, e;
+       grub_uint64_t b, p, n, disknr, e;
 
         /* n = 1 for level 4 and 5, 2 for level 6.  */
         n = array->level / 3;
@@ -522,14 +558,16 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
           /* We found more members of the array than the array
              actually has according to its superblock.  This shouldn't
              happen normally.  */
-          grub_dprintf ("raid", "array->nr_devs > array->total_devs (%d)?!?",
-                       array->total_devs);
+          return grub_error (GRUB_ERR_BAD_DEVICE,
+                            "superfluous RAID member (%d found)",
+                            array->total_devs);
 
         if (array->members[new_array->index].device != NULL)
           /* We found multiple devices with the same number. Again,
              this shouldn't happen.  */
-          grub_dprintf ("raid", "Found two disks with the number %d?!?",
-                       new_array->number);
+         return grub_error (GRUB_ERR_BAD_DEVICE,
+                            "found two disks with the index %d for RAID %s",
+                            new_array->index, array->name);
 
         if (new_array->disk_size < array->disk_size)
           array->disk_size = new_array->disk_size;
@@ -568,7 +606,7 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
        {
          for (p = array_list; p != NULL; p = p->next)
            {
-             if (! p->name && p->number == array->number) 
+             if (p->number == array->number) 
                break;
            }
        }
@@ -636,6 +674,53 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
 
       grub_dprintf ("raid", "Found array %s (%s)\n", array->name,
                     scanner_name);
+#ifdef GRUB_UTIL
+      grub_util_info ("Found array %s (%s)", array->name,
+                     scanner_name);
+#endif
+
+      {
+       int max_used_number = 0, len, need_new_name = 0;
+       int add_us = 0;
+       len = grub_strlen (array->name);
+       if (len && grub_isdigit (array->name[len-1]))
+         add_us = 1;
+       for (p = array_list; p != NULL; p = p->next)
+         {
+           int cur_num;
+           char *num, *end;
+           if (grub_strncmp (p->name, array->name, len) != 0)
+             continue;
+           if (p->name[len] == 0)
+             {
+               need_new_name = 1;
+               continue;
+             }
+           if (add_us && p->name[len] != '_')
+             continue;
+           if (add_us)
+             num = p->name + len + 1;
+           else
+             num = p->name + len;
+           if (!grub_isdigit (num[0]))
+             continue;
+           cur_num = grub_strtoull (num, &end, 10);
+           if (end[0])
+             continue;
+           if (cur_num > max_used_number)
+             max_used_number = cur_num;
+         }
+       if (need_new_name)
+         {
+           char *tmp;
+           tmp = grub_xasprintf ("%s%s%d", array->name, add_us ? "_" : "",
+                                 max_used_number + 1);
+           if (!tmp)
+             return grub_errno;
+           grub_free (array->name);
+           array->name = tmp;
+         }
+      }
 
       /* Add our new array to the list.  */
       array->next = array_list;
@@ -694,7 +779,12 @@ grub_raid_register (grub_raid_t raid)
       struct grub_raid_array array;
       grub_disk_addr_t start_sector;
 
-      grub_dprintf ("raid", "Scanning for RAID devices on disk %s\n", name);
+      grub_dprintf ("raid", "Scanning for %s RAID devices on disk %s\n",
+                   grub_raid_list->name, name);
+#ifdef GRUB_UTIL
+      grub_util_info ("Scanning for %s RAID devices on disk %s",
+                     grub_raid_list->name, name);
+#endif
 
       disk = grub_disk_open (name);
       if (!disk)