static struct grub_archelp_data * grub_cbfs_mount (grub_disk_t disk) { struct cbfs_file hd; struct grub_archelp_data *data = NULL; grub_uint32_t ptr; grub_off_t header_off; struct cbfs_header head; if (grub_disk_get_size (disk) == GRUB_DISK_SIZE_UNKNOWN) goto fail; if (grub_disk_read (disk, grub_disk_get_size (disk) - 1, GRUB_DISK_SECTOR_SIZE - sizeof (ptr), sizeof (ptr), &ptr)) goto fail; ptr = grub_cpu_to_le32 (ptr); header_off = (grub_disk_get_size (disk) << GRUB_DISK_SECTOR_BITS) + (grub_int32_t) ptr; if (grub_disk_read (disk, 0, header_off, sizeof (head), &head)) goto fail; if (!validate_head (&head)) goto fail; data = (struct grub_archelp_data *) grub_zalloc (sizeof (*data)); if (!data) goto fail; data->cbfs_start = (grub_disk_get_size (disk) << GRUB_DISK_SECTOR_BITS) - (grub_be_to_cpu32 (head.romsize) - grub_be_to_cpu32 (head.offset)); data->cbfs_end = (grub_disk_get_size (disk) << GRUB_DISK_SECTOR_BITS) - grub_be_to_cpu32 (head.bootblocksize); data->cbfs_align = grub_be_to_cpu32 (head.align); if (data->cbfs_start >= (grub_disk_get_size (disk) << GRUB_DISK_SECTOR_BITS)) goto fail; if (data->cbfs_end > (grub_disk_get_size (disk) << GRUB_DISK_SECTOR_BITS)) data->cbfs_end = (grub_disk_get_size (disk) << GRUB_DISK_SECTOR_BITS); data->next_hofs = data->cbfs_start; if (grub_disk_read (disk, 0, data->cbfs_start, sizeof (hd), &hd)) goto fail; if (grub_memcmp (hd.magic, CBFS_FILE_MAGIC, sizeof (CBFS_FILE_MAGIC) - 1)) goto fail; data->disk = disk; return data; fail: grub_free (data); grub_error (GRUB_ERR_BAD_FS, "not a cbfs filesystem"); return 0; }
static grub_err_t grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array) { grub_disk_addr_t sector; struct grub_nv_super sb; if (disk->partition) return grub_error (GRUB_ERR_OUT_OF_RANGE, "skip partition"); sector = grub_disk_get_size (disk) - 2; if (grub_disk_read (disk, sector, 0, sizeof (sb), &sb)) return grub_errno; if (grub_memcmp (sb.vendor, NV_ID_STRING, 6)) return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); if (sb.version != NV_VERSION) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "unknown version: %d.%d", sb.version); switch (sb.array.raid_level) { case NV_LEVEL_0: array->level = 0; array->disk_size = sb.capacity / sb.array.total_volumes; break; case NV_LEVEL_1: array->level = 1; array->disk_size = sb.capacity; break; case NV_LEVEL_5: array->level = 5; array->layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC; array->disk_size = sb.capacity / (sb.array.total_volumes - 1); break; default: return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "unsupported RAID level: %d", sb.array.raid_level); } array->number = 0; array->total_devs = sb.array.total_volumes; array->chunk_size = sb.array.stripe_block_size; array->disk_offset = 0; array->index = sb.unit_number; array->uuid_len = sizeof (sb.array.signature); array->uuid = grub_malloc (sizeof (sb.array.signature)); if (! array->uuid) return grub_errno; grub_memcpy (array->uuid, (char *) &sb.array.signature, sizeof (sb.array.signature)); return 0; }
/* Helper for scan_disk. */ static int scan_disk_partition_iter (grub_disk_t disk, grub_partition_t p, void *data) { const char *name = data; struct grub_diskfilter_vg *arr; grub_disk_addr_t start_sector; struct grub_diskfilter_pv_id id; grub_diskfilter_t diskfilter; grub_dprintf ("diskfilter", "Scanning for DISKFILTER devices on disk %s\n", name); #ifdef GRUB_UTIL grub_util_info ("Scanning for DISKFILTER devices on disk %s", name); #endif disk->partition = p; for (arr = array_list; arr != NULL; arr = arr->next) { struct grub_diskfilter_pv *m; for (m = arr->pvs; m; m = m->next) if (m->disk && m->disk->id == disk->id && m->disk->dev->id == disk->dev->id && m->part_start == grub_partition_get_start (disk->partition) && m->part_size == grub_disk_get_size (disk)) return 0; } for (diskfilter = grub_diskfilter_list; diskfilter; diskfilter = diskfilter->next) { #ifdef GRUB_UTIL grub_util_info ("Scanning for %s devices on disk %s", diskfilter->name, name); #endif id.uuid = 0; id.uuidlen = 0; arr = diskfilter->detect (disk, &id, &start_sector); if (arr && (! insert_array (disk, &id, arr, start_sector, diskfilter))) { if (id.uuidlen) grub_free (id.uuid); return 0; } if (arr && id.uuidlen) grub_free (id.uuid); /* This error usually means it's not diskfilter, no need to display it. */ if (grub_errno != GRUB_ERR_OUT_OF_RANGE) grub_print_error (); grub_errno = GRUB_ERR_NONE; } return 0; }
int grub_util_is_ldm (grub_disk_t disk) { int i; int has_ldm = msdos_has_ldm_partition (disk); for (i = 0; i < 3; i++) { grub_disk_addr_t sector = LDM_LABEL_SECTOR; grub_err_t err; struct grub_ldm_label label; switch (i) { case 0: if (!has_ldm) continue; sector = LDM_LABEL_SECTOR; break; case 1: /* LDM is never inside a partition. */ if (!has_ldm || disk->partition) continue; sector = grub_disk_get_size (disk); if (sector == GRUB_DISK_SIZE_UNKNOWN) continue; sector--; break; /* FIXME: try the third copy. */ case 2: sector = gpt_ldm_sector (disk); if (!sector) continue; break; } err = grub_disk_read (disk, sector, 0, sizeof(label), &label); if (err) { grub_errno = GRUB_ERR_NONE; return 0; } /* This check is more relaxed on purpose. */ if (grub_memcmp (label.magic, LDM_MAGIC, sizeof (label.magic)) == 0) return 1; } return 0; }
static void probe (const char *path, char **device_names, char delim) { char **drives_names = NULL; char **curdev, **curdrive; char *grub_path = NULL; int ndev = 0; if (path != NULL) { grub_path = canonicalize_file_name (path); if (! grub_path) grub_util_error (_("failed to get canonical path of `%s'"), path); device_names = grub_guess_root_devices (grub_path); free (grub_path); } if (! device_names) grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), path); if (print == PRINT_DEVICE) { for (curdev = device_names; *curdev; curdev++) { printf ("%s", *curdev); putchar (delim); } return; } if (print == PRINT_DISK) { for (curdev = device_names; *curdev; curdev++) { char *disk; disk = grub_util_get_os_disk (*curdev); if (!disk) { grub_print_error (); continue; } printf ("%s", disk); putchar (delim); } return; } for (curdev = device_names; *curdev; curdev++) { grub_util_pull_device (*curdev); ndev++; } drives_names = xmalloc (sizeof (drives_names[0]) * (ndev + 1)); for (curdev = device_names, curdrive = drives_names; *curdev; curdev++, curdrive++) { *curdrive = grub_util_get_grub_dev (*curdev); if (! *curdrive) grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), *curdev); } *curdrive = 0; if (print == PRINT_DRIVE) { for (curdrive = drives_names; *curdrive; curdrive++) { printf ("(%s)", *curdrive); putchar (delim); } goto end; } if (print == PRINT_ZERO_CHECK) { for (curdev = drives_names; *curdev; curdev++) { grub_device_t dev = NULL; grub_uint32_t buffer[32768]; grub_disk_addr_t addr; grub_disk_addr_t dsize; grub_util_info ("opening %s", *curdev); dev = grub_device_open (*curdev); if (! dev || !dev->disk) grub_util_error ("%s", grub_errmsg); dsize = grub_disk_get_size (dev->disk); for (addr = 0; addr < dsize; addr += sizeof (buffer) / GRUB_DISK_SECTOR_SIZE) { grub_size_t sz = sizeof (buffer); grub_uint32_t *ptr; if (sizeof (buffer) / GRUB_DISK_SECTOR_SIZE > dsize - addr) sz = (dsize - addr) * GRUB_DISK_SECTOR_SIZE; grub_disk_read (dev->disk, addr, 0, sz, buffer); for (ptr = buffer; ptr < buffer + sz / sizeof (*buffer); ptr++) if (*ptr) { grub_printf ("false\n"); grub_device_close (dev); goto end; } } grub_device_close (dev); } grub_printf ("true\n"); } if (print == PRINT_FS || print == PRINT_FS_UUID || print == PRINT_FS_LABEL) { grub_device_t dev = NULL; grub_fs_t fs; grub_util_info ("opening %s", drives_names[0]); dev = grub_device_open (drives_names[0]); if (! dev) grub_util_error ("%s", grub_errmsg); fs = grub_fs_probe (dev); if (! fs) grub_util_error ("%s", grub_errmsg); if (print == PRINT_FS) { printf ("%s", fs->name); putchar (delim); } else if (print == PRINT_FS_UUID) { char *uuid; if (! fs->uuid) grub_util_error (_("%s does not support UUIDs"), fs->name); if (fs->uuid (dev, &uuid) != GRUB_ERR_NONE) grub_util_error ("%s", grub_errmsg); printf ("%s", uuid); putchar (delim); } else if (print == PRINT_FS_LABEL) { char *label; if (! fs->label) grub_util_error (_("filesystem `%s' does not support labels"), fs->name); if (fs->label (dev, &label) != GRUB_ERR_NONE) grub_util_error ("%s", grub_errmsg); printf ("%s", label); putchar (delim); } grub_device_close (dev); goto end; } for (curdrive = drives_names, curdev = device_names; *curdrive; curdrive++, curdev++) { grub_device_t dev = NULL; grub_util_info ("opening %s", *curdrive); dev = grub_device_open (*curdrive); if (! dev) grub_util_error ("%s", grub_errmsg); if (print == PRINT_HINT_STR) { const char *osdev = grub_util_biosdisk_get_osdev (dev->disk); const char *ofpath = osdev ? grub_util_devname_to_ofpath (osdev) : 0; char *biosname, *bare, *efi; const char *map; if (ofpath) { char *tmp = xmalloc (strlen (ofpath) + sizeof ("ieee1275/")); char *p; p = grub_stpcpy (tmp, "ieee1275/"); strcpy (p, ofpath); printf ("--hint-ieee1275='"); print_full_name (tmp, dev); printf ("' "); free (tmp); } biosname = guess_bios_drive (*curdev); if (biosname) { printf ("--hint-bios="); print_full_name (biosname, dev); printf (" "); } free (biosname); efi = guess_efi_drive (*curdev); if (efi) { printf ("--hint-efi="); print_full_name (efi, dev); printf (" "); } free (efi); bare = guess_baremetal_drive (*curdev); if (bare) { printf ("--hint-baremetal="); print_full_name (bare, dev); printf (" "); } free (bare); /* FIXME: Add ARC hint. */ map = grub_util_biosdisk_get_compatibility_hint (dev->disk); if (map) { printf ("--hint='"); print_full_name (map, dev); printf ("' "); } if (curdrive[1]) printf (" "); else printf ("\n"); grub_device_close (dev); continue; } if ((print == PRINT_COMPATIBILITY_HINT || print == PRINT_BIOS_HINT || print == PRINT_IEEE1275_HINT || print == PRINT_BAREMETAL_HINT || print == PRINT_EFI_HINT || print == PRINT_ARC_HINT) && dev->disk->dev->id != GRUB_DISK_DEVICE_HOSTDISK_ID) { print_full_name (dev->disk->name, dev); putchar (delim); continue; } if (print == PRINT_COMPATIBILITY_HINT) { const char *map; char *biosname; map = grub_util_biosdisk_get_compatibility_hint (dev->disk); if (map) { print_full_name (map, dev); putchar (delim); grub_device_close (dev); /* Compatibility hint is one device only. */ break; } biosname = guess_bios_drive (*curdev); if (biosname) { print_full_name (biosname, dev); putchar (delim); } free (biosname); grub_device_close (dev); /* Compatibility hint is one device only. */ if (biosname) break; continue; } if (print == PRINT_BIOS_HINT) { char *biosname; biosname = guess_bios_drive (*curdev); if (biosname) { print_full_name (biosname, dev); putchar (delim); } free (biosname); grub_device_close (dev); continue; } if (print == PRINT_IEEE1275_HINT) { const char *osdev = grub_util_biosdisk_get_osdev (dev->disk); const char *ofpath = grub_util_devname_to_ofpath (osdev); const char *map; map = grub_util_biosdisk_get_compatibility_hint (dev->disk); if (map) { print_full_name (map, dev); putchar (delim); } if (ofpath) { char *tmp = xmalloc (strlen (ofpath) + sizeof ("ieee1275/")); char *p; p = grub_stpcpy (tmp, "ieee1275/"); strcpy (p, ofpath); print_full_name (tmp, dev); free (tmp); putchar (delim); } grub_device_close (dev); continue; } if (print == PRINT_EFI_HINT) { char *biosname; const char *map; biosname = guess_efi_drive (*curdev); map = grub_util_biosdisk_get_compatibility_hint (dev->disk); if (map) { print_full_name (map, dev); putchar (delim); } if (biosname) { print_full_name (biosname, dev); putchar (delim); } free (biosname); grub_device_close (dev); continue; } if (print == PRINT_BAREMETAL_HINT) { char *biosname; const char *map; biosname = guess_baremetal_drive (*curdev); map = grub_util_biosdisk_get_compatibility_hint (dev->disk); if (map) { print_full_name (map, dev); putchar (delim); } if (biosname) { print_full_name (biosname, dev); putchar (delim); } free (biosname); grub_device_close (dev); continue; } if (print == PRINT_ARC_HINT) { const char *map; map = grub_util_biosdisk_get_compatibility_hint (dev->disk); if (map) { print_full_name (map, dev); putchar (delim); } /* FIXME */ grub_device_close (dev); continue; } if (print == PRINT_ABSTRACTION) { probe_abstraction (dev->disk); putchar (delim); grub_device_close (dev); continue; } if (print == PRINT_CRYPTODISK_UUID) { probe_cryptodisk_uuid (dev->disk); putchar (delim); grub_device_close (dev); continue; } if (print == PRINT_PARTMAP) { /* Check if dev->disk itself is contained in a partmap. */ probe_partmap (dev->disk); putchar (delim); grub_device_close (dev); continue; } if (print == PRINT_MSDOS_PARTTYPE) { if (dev->disk->partition && strcmp(dev->disk->partition->partmap->name, "msdos") == 0) printf ("%02x", dev->disk->partition->msdostype); putchar (delim); grub_device_close (dev); continue; } if (print == PRINT_GPT_PARTTYPE) { if (dev->disk->partition && strcmp (dev->disk->partition->partmap->name, "gpt") == 0) { struct grub_gpt_partentry gptdata; grub_partition_t p = dev->disk->partition; dev->disk->partition = dev->disk->partition->parent; if (grub_disk_read (dev->disk, p->offset, p->index, sizeof (gptdata), &gptdata) == 0) { grub_gpt_part_type_t gpttype; gpttype.data1 = grub_le_to_cpu32 (gptdata.type.data1); gpttype.data2 = grub_le_to_cpu16 (gptdata.type.data2); gpttype.data3 = grub_le_to_cpu16 (gptdata.type.data3); grub_memcpy (gpttype.data4, gptdata.type.data4, 8); grub_printf ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", gpttype.data1, gpttype.data2, gpttype.data3, gpttype.data4[0], gpttype.data4[1], gpttype.data4[2], gpttype.data4[3], gpttype.data4[4], gpttype.data4[5], gpttype.data4[6], gpttype.data4[7]); } dev->disk->partition = p; } putchar (delim); grub_device_close (dev); continue; } } end: for (curdrive = drives_names; *curdrive; curdrive++) free (*curdrive); free (drives_names); }
static struct grub_diskfilter_vg * grub_mdraid_detect (grub_disk_t disk, struct grub_diskfilter_pv_id *id, grub_disk_addr_t *start_sector) { grub_uint64_t size; grub_uint8_t minor_version; size = grub_disk_get_size (disk); /* Check for an 1.x superblock. * It's always aligned to a 4K boundary * and depending on the minor version it can be: * 0: At least 8K, but less than 12K, from end of device * 1: At start of device * 2: 4K from start of device. */ for (minor_version = 0; minor_version < 3; ++minor_version) { grub_disk_addr_t sector = 0; struct grub_raid_super_1x sb; grub_uint16_t role; grub_uint32_t level; struct grub_diskfilter_vg *array; char *uuid; if (size == GRUB_DISK_SIZE_UNKNOWN && minor_version == 0) continue; switch (minor_version) { case 0: sector = (size - 8 * 2) & ~(4 * 2 - 1); break; case 1: sector = 0; break; case 2: sector = 4 * 2; break; } if (grub_disk_read (disk, sector, 0, sizeof (struct grub_raid_super_1x), &sb)) return NULL; if (sb.magic != grub_cpu_to_le32_compile_time (SB_MAGIC) || grub_le_to_cpu64 (sb.super_offset) != sector) continue; if (sb.major_version != grub_cpu_to_le32_compile_time (1)) /* Unsupported version. */ return NULL; level = grub_le_to_cpu32 (sb.level); /* Multipath. */ if ((int) level == -4) level = 1; if (level != 0 && level != 1 && level != 4 && level != 5 && level != 6 && level != 10) { grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported RAID level: %d", sb.level); return NULL; } if (grub_le_to_cpu32 (sb.dev_number) >= grub_le_to_cpu32 (sb.max_dev)) /* Spares aren't implemented. */ return NULL; if (grub_disk_read (disk, sector, (char *) &sb.dev_roles[grub_le_to_cpu32 (sb.dev_number)] - (char *) &sb, sizeof (role), &role)) return NULL; if (grub_le_to_cpu16 (role) >= grub_le_to_cpu32 (sb.raid_disks)) /* Spares aren't implemented. */ return NULL; id->uuidlen = 0; id->id = grub_le_to_cpu16 (role); uuid = grub_malloc (16); if (!uuid) return NULL; grub_memcpy (uuid, sb.set_uuid, 16); *start_sector = grub_le_to_cpu64 (sb.data_offset); array = grub_diskfilter_make_raid (16, uuid, grub_le_to_cpu32 (sb.raid_disks), sb.set_name, (sb.size) ? grub_le_to_cpu64 (sb.size) : grub_le_to_cpu64 (sb.data_size), grub_le_to_cpu32 (sb.chunksize), grub_le_to_cpu32 (sb.layout), grub_le_to_cpu32 (sb.level)); return array; } /* not 1.x raid. */ return NULL; }
static struct grub_diskfilter_vg * grub_ldm_detect (grub_disk_t disk, struct grub_diskfilter_pv_id *id, grub_disk_addr_t *start_sector) { grub_err_t err; struct grub_ldm_label label; struct grub_diskfilter_vg *vg; #ifdef GRUB_UTIL grub_util_info ("scanning %s for LDM", disk->name); #endif { int i; int has_ldm = msdos_has_ldm_partition (disk); for (i = 0; i < 3; i++) { grub_disk_addr_t sector = LDM_LABEL_SECTOR; switch (i) { case 0: if (!has_ldm) continue; sector = LDM_LABEL_SECTOR; break; case 1: /* LDM is never inside a partition. */ if (!has_ldm || disk->partition) continue; sector = grub_disk_get_size (disk); if (sector == GRUB_DISK_SIZE_UNKNOWN) continue; sector--; break; /* FIXME: try the third copy. */ case 2: sector = gpt_ldm_sector (disk); if (!sector) continue; break; } err = grub_disk_read (disk, sector, 0, sizeof(label), &label); if (err) return NULL; if (grub_memcmp (label.magic, LDM_MAGIC, sizeof (label.magic)) == 0 && grub_be_to_cpu16 (label.ver_major) == 0x02 && grub_be_to_cpu16 (label.ver_minor) >= 0x0b && grub_be_to_cpu16 (label.ver_minor) <= 0x0c) break; } /* Return if we didn't find a label. */ if (i == 3) { #ifdef GRUB_UTIL grub_util_info ("no LDM signature found"); #endif return NULL; } } id->uuid = grub_malloc (LDM_GUID_STRLEN + 1); if (!id->uuid) return NULL; grub_memcpy (id->uuid, label.disk_guid, LDM_GUID_STRLEN); id->uuid[LDM_GUID_STRLEN] = 0; id->uuidlen = grub_strlen ((char *) id->uuid); *start_sector = grub_be_to_cpu64 (label.pv_start); { grub_size_t s; for (s = 0; s < LDM_GUID_STRLEN && label.group_guid[s]; s++); vg = grub_diskfilter_get_vg_by_uuid (s, label.group_guid); if (! vg) vg = make_vg (disk, &label); } if (!vg) { grub_free (id->uuid); return NULL; } return vg; }
static grub_err_t grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array, grub_disk_addr_t *start_sector) { grub_disk_addr_t sector = 0; grub_uint64_t size; struct grub_raid_super_1x sb; grub_uint8_t minor_version; /* The sector where the mdraid 0.90 superblock is stored, if available. */ size = grub_disk_get_size (disk); /* Check for an 1.x superblock. * It's always aligned to a 4K boundary * and depending on the minor version it can be: * 0: At least 8K, but less than 12K, from end of device * 1: At start of device * 2: 4K from start of device. */ for (minor_version = 0; minor_version < 3; ++minor_version) { if (size == GRUB_DISK_SIZE_UNKNOWN && minor_version == 0) continue; switch (minor_version) { case 0: sector = (size - 8 * 2) & ~(4 * 2 - 1); break; case 1: sector = 0; break; case 2: sector = 4 * 2; break; } if (grub_disk_read (disk, sector, 0, sizeof (struct grub_raid_super_1x), &sb)) return grub_errno; if (grub_le_to_cpu32 (sb.magic) != SB_MAGIC || grub_le_to_cpu64 (sb.super_offset) != sector) continue; { grub_uint64_t sb_size; struct grub_raid_super_1x *real_sb; grub_uint32_t level; if (grub_le_to_cpu32 (sb.major_version) != 1) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported RAID version: %d", grub_le_to_cpu32 (sb.major_version)); level = grub_le_to_cpu32 (sb.level); /* Multipath. */ if ((int) level == -4) level = 1; if (level != 0 && level != 1 && level != 4 && level != 5 && level != 6 && level != 10) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported RAID level: %d", sb.level); /* 1.x superblocks don't have a fixed size on disk. So we have to read it again now that we now the max device count. */ sb_size = sizeof (struct grub_raid_super_1x) + 2 * grub_le_to_cpu32 (sb.max_dev); real_sb = grub_malloc (sb_size); if (! real_sb) return grub_errno; if (grub_disk_read (disk, sector, 0, sb_size, real_sb)) { grub_free (real_sb); return grub_errno; } array->name = grub_strdup (real_sb->set_name); if (! array->name) { grub_free (real_sb); return grub_errno; } array->number = 0; array->level = grub_le_to_cpu32 (real_sb->level); array->layout = grub_le_to_cpu32 (real_sb->layout); array->total_devs = grub_le_to_cpu32 (real_sb->raid_disks); array->disk_size = grub_le_to_cpu64 (real_sb->size); array->chunk_size = grub_le_to_cpu32 (real_sb->chunksize); if (grub_le_to_cpu32 (real_sb->dev_number) >= grub_le_to_cpu32 (real_sb->max_dev)) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "spares aren't implemented"); array->index = grub_le_to_cpu16 (real_sb->dev_roles[grub_le_to_cpu32 (real_sb->dev_number)]); array->uuid_len = 16; array->uuid = grub_malloc (16); if (!array->uuid) { grub_free (real_sb); return grub_errno; } grub_memcpy (array->uuid, real_sb->set_uuid, 16); *start_sector = grub_le_to_cpu64 (real_sb->data_offset); grub_free (real_sb); return 0; } } return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 1.x raid"); }
static struct grub_diskfilter_vg * grub_dmraid_nv_detect (grub_disk_t disk, struct grub_diskfilter_pv_id *id, grub_disk_addr_t *start_sector) { grub_disk_addr_t sector; struct grub_nv_super sb; int level; grub_uint64_t disk_size; char *uuid; if (disk->partition) /* Skip partition. */ return NULL; sector = grub_disk_get_size (disk); if (sector == GRUB_DISK_SIZE_UNKNOWN) /* Not raid. */ return NULL; sector -= 2; if (grub_disk_read (disk, sector, 0, sizeof (sb), &sb)) return NULL; if (grub_memcmp (sb.vendor, NV_ID_STRING, 6)) /* Not raid. */ return NULL; if (sb.version != NV_VERSION) { grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "unknown version: %d.%d", sb.version); return NULL; } switch (sb.array.raid_level) { case NV_LEVEL_0: level = 0; disk_size = sb.capacity / sb.array.total_volumes; break; case NV_LEVEL_1: level = 1; disk_size = sb.capacity; break; case NV_LEVEL_5: level = 5; disk_size = sb.capacity / (sb.array.total_volumes - 1); break; default: grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "unsupported RAID level: %d", sb.array.raid_level); return NULL; } uuid = grub_malloc (sizeof (sb.array.signature)); if (! uuid) return NULL; grub_memcpy (uuid, (char *) &sb.array.signature, sizeof (sb.array.signature)); id->uuidlen = 0; id->id = sb.unit_number; *start_sector = 0; return grub_diskfilter_make_raid (sizeof (sb.array.signature), uuid, sb.array.total_volumes, NULL, disk_size, sb.array.stripe_block_size, GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC, level); }