Merge common RAID and LVM logic to an abstract diskfilter.
Add LDM support using the same framework. * Makefile.util.def (libgrubkern): Add grub-core/disk/ldm.c, grub-core/disk/diskfilter.c and grub-core/partmap/gpt.c. (libgrubmods): Remove grub-core/disk/raid.c and grub-core/partmap/gpt.c. * grub-core/Makefile.core.def (ldm): New module. (raid): Renamed to diskfilter. All users updated. * grub-core/disk/raid.c: Moved to ... * grub-core/disk/diskfilter.c: ... here. * grub-core/disk/diskfilter.c: Rename grub_raid_ to grub_diskfilter_. (lv_num): New var. (find_array): Renamed to ... (find_lv): ... this. Support multi-LV. Skip nameless LVs (grub_is_array_readable): Renamed to ... (grub_is_lv_readable): ... this. Support multinode hierarchy. (insert_array): New argument id. (is_node_readable): New function. (scan_device): Rename to ... (scan_disk): .. this. Restrict to one disk. (scan_devices): New function. (grub_diskfilter_iterate): Support multi-LV. Skip invisible and nameless LVs. (grub_diskfilter_memberlist): Support multi-LV. (grub_diskfilter_read_node): New function. (grub_raid_read): Most of logic moved to ... (read_segment): ... here (read_lv): New function. (grub_diskfilter_get_vg_by_uuid): New function. (grub_diskfilter_make_raid): Likewise. * grub-core/disk/ldm.c: New file. * grub-core/disk/lvm.c (vg_list): Removed. (lv_count): Likewise. (scan_depth): Likewise. (is_lv_readable): Likewise. (grub_lvm_getvalue): Advance pointer past the number. (find_lv): Removed. (do_lvm_scan): Refactored into ... (grub_lvm_detect): ... this. Support raid. (grub_lvm_iterate): Removed. (grub_lvm_memberlist): Likewise. (grub_lvm_open): Likewise. (grub_lvm_close): Likewise. (read_lv): Likewise. (read_node): Likewise. (is_node_readable): Likewise. (is_lv_readable): Likewise. (grub_lvm_read): Likewise. (grub_lvm_write): Likewise. (grub_lvm_dev): Use diskfilter (GRUB_MOD_INIT): Likewise. (GRUB_MOD_FINI): Likewise. * grub-core/disk/dmraid_nvidia.c (grub_dmraid_nv_detect): Use new interface. * grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): Likewise. * grub-core/disk/mdraid_linux.c (grub_mdraid_detect): Likewise. * grub-core/disk/raid5_recover.c (grub_raid5_recover): Use grub_diskfilter_read_node. Fix a bug with xor. * grub-core/disk/raid6_recover.c (grub_raid6_recover): Use grub_diskfilter_read_node. Support GRUB_RAID_LAYOUT_MUL_FROM_POS. * grub-core/kern/disk.c (grub_disk_dev_list): Make global. (grub_disk_dev_iterate): Move from here... * include/grub/disk.h (grub_disk_dev_iterate): ... to here. Inlined. * grub-core/kern/emu/hostdisk.c (grub_hostdisk_find_partition_start): Make global. (grub_hostdisk_find_partition_start): Likewise. (grub_hostdisk_os_dev_to_grub_drive): New function. (grub_util_biosdisk_get_osdev): Check that disk is biosdisk. * grub-core/kern/emu/hostdisk.c (make_device_name): Move to ... * util/getroot.c (make_device_name): ... here. * grub-core/kern/emu/hostdisk.c (grub_util_get_dm_node_linear_info): Move to ... * util/getroot.c (grub_util_get_dm_node_linear_info): ...here. * grub-core/kern/emu/hostdisk.c (convert_system_partition_to_system_disk): Move to ... * util/getroot.c (convert_system_partition_to_system_disk): ...here. * grub-core/kern/emu/hostdisk.c (device_is_wholedisk): Move to ... * util/getroot.c (device_is_wholedisk): ... here. * grub-core/kern/emu/hostdisk.c (find_system_device): Move to ... * util/getroot.c (find_system_device): ... here. * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_present): Move to ... * util/getroot.c (grub_util_biosdisk_is_present): ...here. * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_get_grub_dev): Move to ... * util/getroot.c (grub_util_biosdisk_get_grub_dev): ... here. Handle LDM. * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_floppy): Move to ... * util/getroot.c (grub_util_biosdisk_is_floppy): ... here. * grub-core/partmap/gpt.c (grub_gpt_partition_map_iterate): Made global. * include/grub/disk.h (grub_disk_dev_id): Replaced RAID and LVM with DISKFILTER. * include/grub/raid.h: Renamed to ... * include/grub/diskfilter.h: ... this. * include/grub/diskfilter.h: Rename grub_raid_* to grub_diskfilter_* (GRUB_RAID_LAYOUT_*): Make into array. (GRUB_RAID_LAYOUT_MUL_FROM_POS): New value. (grub_diskfilter_vg): New struct. (grub_diskfilter_pv_id): Likewise. (grub_raid_member): Removed. (grub_raid_array): Likewise. (grub_diskfilter_pv): New struct. (grub_diskfilter_lv): Likewise. (grub_diskfilter_segment): Likewise. (grub_diskfilter_node): Likewise. (grub_diskfilter_get_vg_by_uuid): New proto. (grub_raid_register): Inline. (grub_diskfilter_unregister): Likewise. (grub_diskfilter_make_raid): New proto. (grub_diskfilter_vg_register): Likewise. (grub_diskfilter_read_node): Likewise. (grub_diskfilter_get_pv_from_disk) [GRUB_UTIL]: Likewise. * include/grub/emu/hostdisk.h (grub_util_get_ldm): New proto. (grub_util_is_ldm): Likewise. (grub_util_ldm_embed) [GRUB_UTIL]: Likewise. (grub_hostdisk_find_partition_start): Likewise. (grub_hostdisk_os_dev_to_grub_drive): Likewise. * include/grub/gpt_partition.h (GRUB_GPT_PARTITION_TYPE_LDM): New definition. (grub_gpt_partition_map_iterate): New proto. * include/grub/lvm.h (grub_lvm_vg): Removed. (grub_lvm_pv): Likewise. (grub_lvm_lv): Likewise. (grub_lvm_segment): Likewise. (grub_lvm_node): Likewise. * util/getroot.c [...] * util/grub-probe.c (probe_raid_level): Handle diskfilter. (probe_abstraction): Likewise. * util/grub-setup.c (setup): Remove must_embed. Support LDM. (main): Remove dead logic.
This commit is contained in:
parent
8a7f9b9c50
commit
076e7c0fda
27 changed files with 4249 additions and 3052 deletions
137
ChangeLog
137
ChangeLog
|
@ -1,3 +1,140 @@
|
|||
2012-01-29 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Merge common RAID and LVM logic to an abstract diskfilter.
|
||||
Add LDM support using the same framework.
|
||||
|
||||
* Makefile.util.def (libgrubkern): Add grub-core/disk/ldm.c,
|
||||
grub-core/disk/diskfilter.c and grub-core/partmap/gpt.c.
|
||||
(libgrubmods): Remove grub-core/disk/raid.c and
|
||||
grub-core/partmap/gpt.c.
|
||||
* grub-core/Makefile.core.def (ldm): New module.
|
||||
(raid): Renamed to diskfilter. All users updated.
|
||||
* grub-core/disk/raid.c: Moved to ...
|
||||
* grub-core/disk/diskfilter.c: ... here.
|
||||
* grub-core/disk/diskfilter.c: Rename grub_raid_ to grub_diskfilter_.
|
||||
(lv_num): New var.
|
||||
(find_array): Renamed to ...
|
||||
(find_lv): ... this. Support multi-LV. Skip nameless LVs
|
||||
(grub_is_array_readable): Renamed to ...
|
||||
(grub_is_lv_readable): ... this. Support multinode hierarchy.
|
||||
(insert_array): New argument id.
|
||||
(is_node_readable): New function.
|
||||
(scan_device): Rename to ...
|
||||
(scan_disk): .. this. Restrict to one disk.
|
||||
(scan_devices): New function.
|
||||
(grub_diskfilter_iterate): Support multi-LV.
|
||||
Skip invisible and nameless LVs.
|
||||
(grub_diskfilter_memberlist): Support multi-LV.
|
||||
(grub_diskfilter_read_node): New function.
|
||||
(grub_raid_read): Most of logic moved to ...
|
||||
(read_segment): ... here
|
||||
(read_lv): New function.
|
||||
(grub_diskfilter_get_vg_by_uuid): New function.
|
||||
(grub_diskfilter_make_raid): Likewise.
|
||||
* grub-core/disk/ldm.c: New file.
|
||||
* grub-core/disk/lvm.c (vg_list): Removed.
|
||||
(lv_count): Likewise.
|
||||
(scan_depth): Likewise.
|
||||
(is_lv_readable): Likewise.
|
||||
(grub_lvm_getvalue): Advance pointer past the number.
|
||||
(find_lv): Removed.
|
||||
(do_lvm_scan): Refactored into ...
|
||||
(grub_lvm_detect): ... this. Support raid.
|
||||
(grub_lvm_iterate): Removed.
|
||||
(grub_lvm_memberlist): Likewise.
|
||||
(grub_lvm_open): Likewise.
|
||||
(grub_lvm_close): Likewise.
|
||||
(read_lv): Likewise.
|
||||
(read_node): Likewise.
|
||||
(is_node_readable): Likewise.
|
||||
(is_lv_readable): Likewise.
|
||||
(grub_lvm_read): Likewise.
|
||||
(grub_lvm_write): Likewise.
|
||||
(grub_lvm_dev): Use diskfilter
|
||||
(GRUB_MOD_INIT): Likewise.
|
||||
(GRUB_MOD_FINI): Likewise.
|
||||
* grub-core/disk/dmraid_nvidia.c (grub_dmraid_nv_detect): Use
|
||||
new interface.
|
||||
* grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): Likewise.
|
||||
* grub-core/disk/mdraid_linux.c (grub_mdraid_detect): Likewise.
|
||||
* grub-core/disk/raid5_recover.c (grub_raid5_recover): Use
|
||||
grub_diskfilter_read_node.
|
||||
Fix a bug with xor.
|
||||
* grub-core/disk/raid6_recover.c (grub_raid6_recover): Use
|
||||
grub_diskfilter_read_node.
|
||||
Support GRUB_RAID_LAYOUT_MUL_FROM_POS.
|
||||
* grub-core/kern/disk.c (grub_disk_dev_list): Make global.
|
||||
(grub_disk_dev_iterate): Move from here...
|
||||
* include/grub/disk.h (grub_disk_dev_iterate): ... to here. Inlined.
|
||||
* grub-core/kern/emu/hostdisk.c (grub_hostdisk_find_partition_start):
|
||||
Make global.
|
||||
(grub_hostdisk_find_partition_start): Likewise.
|
||||
(grub_hostdisk_os_dev_to_grub_drive): New function.
|
||||
(grub_util_biosdisk_get_osdev): Check that disk is biosdisk.
|
||||
* grub-core/kern/emu/hostdisk.c (make_device_name): Move to ...
|
||||
* util/getroot.c (make_device_name): ... here.
|
||||
* grub-core/kern/emu/hostdisk.c (grub_util_get_dm_node_linear_info):
|
||||
Move to ...
|
||||
* util/getroot.c (grub_util_get_dm_node_linear_info): ...here.
|
||||
* grub-core/kern/emu/hostdisk.c
|
||||
(convert_system_partition_to_system_disk): Move to ...
|
||||
* util/getroot.c (convert_system_partition_to_system_disk): ...here.
|
||||
* grub-core/kern/emu/hostdisk.c (device_is_wholedisk): Move to ...
|
||||
* util/getroot.c (device_is_wholedisk): ... here.
|
||||
* grub-core/kern/emu/hostdisk.c (find_system_device): Move to ...
|
||||
* util/getroot.c (find_system_device): ... here.
|
||||
* grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_present):
|
||||
Move to ...
|
||||
* util/getroot.c (grub_util_biosdisk_is_present): ...here.
|
||||
* grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_get_grub_dev):
|
||||
Move to ...
|
||||
* util/getroot.c (grub_util_biosdisk_get_grub_dev): ... here.
|
||||
Handle LDM.
|
||||
* grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_floppy):
|
||||
Move to ...
|
||||
* util/getroot.c (grub_util_biosdisk_is_floppy): ... here.
|
||||
* grub-core/partmap/gpt.c (grub_gpt_partition_map_iterate): Made global.
|
||||
* include/grub/disk.h (grub_disk_dev_id): Replaced RAID and LVM with
|
||||
DISKFILTER.
|
||||
* include/grub/raid.h: Renamed to ...
|
||||
* include/grub/diskfilter.h: ... this.
|
||||
* include/grub/diskfilter.h: Rename grub_raid_* to grub_diskfilter_*
|
||||
(GRUB_RAID_LAYOUT_*): Make into array.
|
||||
(GRUB_RAID_LAYOUT_MUL_FROM_POS): New value.
|
||||
(grub_diskfilter_vg): New struct.
|
||||
(grub_diskfilter_pv_id): Likewise.
|
||||
(grub_raid_member): Removed.
|
||||
(grub_raid_array): Likewise.
|
||||
(grub_diskfilter_pv): New struct.
|
||||
(grub_diskfilter_lv): Likewise.
|
||||
(grub_diskfilter_segment): Likewise.
|
||||
(grub_diskfilter_node): Likewise.
|
||||
(grub_diskfilter_get_vg_by_uuid): New proto.
|
||||
(grub_raid_register): Inline.
|
||||
(grub_diskfilter_unregister): Likewise.
|
||||
(grub_diskfilter_make_raid): New proto.
|
||||
(grub_diskfilter_vg_register): Likewise.
|
||||
(grub_diskfilter_read_node): Likewise.
|
||||
(grub_diskfilter_get_pv_from_disk) [GRUB_UTIL]: Likewise.
|
||||
* include/grub/emu/hostdisk.h (grub_util_get_ldm): New proto.
|
||||
(grub_util_is_ldm): Likewise.
|
||||
(grub_util_ldm_embed) [GRUB_UTIL]: Likewise.
|
||||
(grub_hostdisk_find_partition_start): Likewise.
|
||||
(grub_hostdisk_os_dev_to_grub_drive): Likewise.
|
||||
* include/grub/gpt_partition.h (GRUB_GPT_PARTITION_TYPE_LDM):
|
||||
New definition.
|
||||
(grub_gpt_partition_map_iterate): New proto.
|
||||
* include/grub/lvm.h (grub_lvm_vg): Removed.
|
||||
(grub_lvm_pv): Likewise.
|
||||
(grub_lvm_lv): Likewise.
|
||||
(grub_lvm_segment): Likewise.
|
||||
(grub_lvm_node): Likewise.
|
||||
* util/getroot.c [...]
|
||||
* util/grub-probe.c (probe_raid_level): Handle diskfilter.
|
||||
(probe_abstraction): Likewise.
|
||||
* util/grub-setup.c (setup): Remove must_embed. Support LDM.
|
||||
(main): Remove dead logic.
|
||||
|
||||
2012-01-28 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Simplify root device discover and don't fail when trying to open
|
||||
|
|
|
@ -29,6 +29,9 @@ library = {
|
|||
common = grub-core/lib/pbkdf2.c;
|
||||
common = grub-core/commands/extcmd.c;
|
||||
common = grub-core/lib/arg.c;
|
||||
common = grub-core/disk/ldm.c;
|
||||
common = grub-core/disk/diskfilter.c;
|
||||
common = grub-core/partmap/gpt.c;
|
||||
};
|
||||
|
||||
library = {
|
||||
|
@ -53,7 +56,6 @@ library = {
|
|||
common = grub-core/disk/mdraid1x_linux.c;
|
||||
common = grub-core/disk/raid5_recover.c;
|
||||
common = grub-core/disk/raid6_recover.c;
|
||||
common = grub-core/disk/raid.c;
|
||||
common = grub-core/fs/affs.c;
|
||||
common = grub-core/fs/afs.c;
|
||||
common = grub-core/fs/bfs.c;
|
||||
|
@ -103,7 +105,6 @@ library = {
|
|||
common = grub-core/partmap/acorn.c;
|
||||
common = grub-core/partmap/amiga.c;
|
||||
common = grub-core/partmap/apple.c;
|
||||
common = grub-core/partmap/gpt.c;
|
||||
common = grub-core/partmap/msdos.c;
|
||||
common = grub-core/partmap/sun.c;
|
||||
common = grub-core/partmap/plan.c;
|
||||
|
|
|
@ -874,6 +874,11 @@ module = {
|
|||
common = disk/lvm.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = ldm;
|
||||
common = disk/ldm.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = mdraid09;
|
||||
common = disk/mdraid_linux.c;
|
||||
|
@ -885,8 +890,8 @@ module = {
|
|||
};
|
||||
|
||||
module = {
|
||||
name = raid;
|
||||
common = disk/raid.c;
|
||||
name = diskfilter;
|
||||
common = disk/diskfilter.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
|
|
1081
grub-core/disk/diskfilter.c
Normal file
1081
grub-core/disk/diskfilter.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -22,7 +22,7 @@
|
|||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/raid.h>
|
||||
#include <grub/diskfilter.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -90,72 +90,91 @@ struct grub_nv_super
|
|||
struct grub_nv_array array; /* Array information */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static grub_err_t
|
||||
grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array,
|
||||
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;
|
||||
int layout;
|
||||
grub_uint64_t disk_size;
|
||||
char *uuid;
|
||||
|
||||
if (disk->partition)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "skip partition");
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE, "skip partition");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sector = grub_disk_get_size (disk);
|
||||
if (sector == GRUB_DISK_SIZE_UNKNOWN)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
|
||||
return NULL;
|
||||
}
|
||||
sector -= 2;
|
||||
if (grub_disk_read (disk, sector, 0, sizeof (sb), &sb))
|
||||
return grub_errno;
|
||||
return NULL;
|
||||
|
||||
if (grub_memcmp (sb.vendor, NV_ID_STRING, 6))
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sb.version != NV_VERSION)
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
{
|
||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"unknown version: %d.%d", sb.version);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (sb.array.raid_level)
|
||||
{
|
||||
case NV_LEVEL_0:
|
||||
array->level = 0;
|
||||
array->disk_size = sb.capacity / sb.array.total_volumes;
|
||||
level = 0;
|
||||
disk_size = sb.capacity / sb.array.total_volumes;
|
||||
break;
|
||||
|
||||
case NV_LEVEL_1:
|
||||
array->level = 1;
|
||||
array->disk_size = sb.capacity;
|
||||
level = 1;
|
||||
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);
|
||||
level = 5;
|
||||
layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC;
|
||||
disk_size = sb.capacity / (sb.array.total_volumes - 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"unsupported RAID level: %d", sb.array.raid_level);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
array->name = NULL;
|
||||
array->number = 0;
|
||||
array->total_devs = sb.array.total_volumes;
|
||||
array->chunk_size = sb.array.stripe_block_size;
|
||||
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;
|
||||
uuid = grub_malloc (sizeof (sb.array.signature));
|
||||
if (! uuid)
|
||||
return NULL;
|
||||
|
||||
grub_memcpy (array->uuid, (char *) &sb.array.signature,
|
||||
grub_memcpy (uuid, (char *) &sb.array.signature,
|
||||
sizeof (sb.array.signature));
|
||||
|
||||
id->uuidlen = 0;
|
||||
id->id = sb.unit_number;
|
||||
|
||||
*start_sector = 0;
|
||||
|
||||
return 0;
|
||||
return grub_diskfilter_make_raid (sizeof (sb.array.signature),
|
||||
uuid, sb.array.total_volumes,
|
||||
NULL, disk_size,
|
||||
sb.array.stripe_block_size, layout,
|
||||
level);
|
||||
}
|
||||
|
||||
static struct grub_raid grub_dmraid_nv_dev =
|
||||
static struct grub_diskfilter grub_dmraid_nv_dev =
|
||||
{
|
||||
.name = "dmraid_nv",
|
||||
.detect = grub_dmraid_nv_detect,
|
||||
|
@ -164,10 +183,10 @@ static struct grub_raid grub_dmraid_nv_dev =
|
|||
|
||||
GRUB_MOD_INIT(dm_nv)
|
||||
{
|
||||
grub_raid_register (&grub_dmraid_nv_dev);
|
||||
grub_diskfilter_register (&grub_dmraid_nv_dev);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(dm_nv)
|
||||
{
|
||||
grub_raid_unregister (&grub_dmraid_nv_dev);
|
||||
grub_diskfilter_unregister (&grub_dmraid_nv_dev);
|
||||
}
|
||||
|
|
997
grub-core/disk/ldm.c
Normal file
997
grub-core/disk/ldm.c
Normal file
|
@ -0,0 +1,997 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2006,2007,2008,2009,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/diskfilter.h>
|
||||
#include <grub/gpt_partition.h>
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
#include <grub/emu/misc.h>
|
||||
#include <grub/emu/hostdisk.h>
|
||||
#endif
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define LDM_GUID_STRLEN 64
|
||||
#define LDM_NAME_STRLEN 32
|
||||
|
||||
typedef grub_uint8_t *grub_ldm_id_t;
|
||||
|
||||
enum { STRIPE = 1, SPANNED = 2, RAID5 = 3 };
|
||||
|
||||
#define LDM_LABEL_SECTOR 6
|
||||
struct grub_ldm_vblk {
|
||||
char magic[4];
|
||||
grub_uint8_t unused1[12];
|
||||
grub_uint16_t update_status;
|
||||
grub_uint8_t flags;
|
||||
grub_uint8_t type;
|
||||
grub_uint32_t unused2;
|
||||
grub_uint8_t dynamic[104];
|
||||
} __attribute__ ((packed));
|
||||
#define LDM_VBLK_MAGIC "VBLK"
|
||||
|
||||
enum
|
||||
{
|
||||
STATUS_CONSISTENT = 0,
|
||||
STATUS_STILL_ACTIVE = 1,
|
||||
STATUS_NOT_ACTIVE_YET = 2
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ENTRY_COMPONENT = 0x32,
|
||||
ENTRY_PARTITION = 0x33,
|
||||
ENTRY_DISK = 0x34,
|
||||
ENTRY_VOLUME = 0x51,
|
||||
};
|
||||
|
||||
struct grub_ldm_label
|
||||
{
|
||||
char magic[8];
|
||||
grub_uint32_t unused1;
|
||||
grub_uint16_t ver_major;
|
||||
grub_uint16_t ver_minor;
|
||||
grub_uint8_t unused2[32];
|
||||
char disk_guid[LDM_GUID_STRLEN];
|
||||
char host_guid[LDM_GUID_STRLEN];
|
||||
char group_guid[LDM_GUID_STRLEN];
|
||||
char group_name[LDM_NAME_STRLEN];
|
||||
grub_uint8_t unused3[11];
|
||||
grub_uint64_t pv_start;
|
||||
grub_uint64_t pv_size;
|
||||
grub_uint64_t config_start;
|
||||
grub_uint64_t config_size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
#define LDM_MAGIC "PRIVHEAD"
|
||||
|
||||
|
||||
|
||||
static inline grub_uint64_t
|
||||
read_int (grub_uint8_t *in, grub_size_t s)
|
||||
{
|
||||
grub_uint8_t *ptr2;
|
||||
grub_uint64_t ret;
|
||||
ret = 0;
|
||||
for (ptr2 = in; ptr2 < in + s; ptr2++)
|
||||
{
|
||||
ret <<= 8;
|
||||
ret |= *ptr2;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const grub_gpt_part_type_t ldm_type = GRUB_GPT_PARTITION_TYPE_LDM;
|
||||
|
||||
static grub_disk_addr_t
|
||||
gpt_ldm_sector (grub_disk_t dsk)
|
||||
{
|
||||
grub_disk_addr_t sector = 0;
|
||||
grub_err_t err;
|
||||
auto int hook (grub_disk_t disk, const grub_partition_t p);
|
||||
int hook (grub_disk_t disk, const grub_partition_t p)
|
||||
{
|
||||
struct grub_gpt_partentry gptdata;
|
||||
grub_partition_t p2;
|
||||
|
||||
p2 = disk->partition;
|
||||
disk->partition = p->parent;
|
||||
if (grub_disk_read (disk, p->offset, p->index,
|
||||
sizeof (gptdata), &gptdata))
|
||||
{
|
||||
disk->partition = p2;
|
||||
return 0;
|
||||
}
|
||||
disk->partition = p2;
|
||||
|
||||
if (! grub_memcmp (&gptdata.type, &ldm_type, 16))
|
||||
{
|
||||
sector = p->start + p->len - 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
err = grub_gpt_partition_map_iterate (dsk, hook);
|
||||
if (err)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
return sector;
|
||||
}
|
||||
|
||||
static struct grub_diskfilter_vg *
|
||||
make_vg (grub_disk_t disk,
|
||||
const struct grub_ldm_label *label)
|
||||
{
|
||||
grub_disk_addr_t startsec, endsec, cursec;
|
||||
struct grub_diskfilter_vg *vg;
|
||||
grub_err_t err;
|
||||
|
||||
/* First time we see this volume group. We've to create the
|
||||
whole volume group structure. */
|
||||
vg = grub_malloc (sizeof (*vg));
|
||||
if (! vg)
|
||||
return NULL;
|
||||
vg->extent_size = 1;
|
||||
vg->name = grub_malloc (LDM_NAME_STRLEN + 1);
|
||||
vg->uuid = grub_malloc (LDM_GUID_STRLEN + 1);
|
||||
if (! vg->uuid || !vg->name)
|
||||
{
|
||||
grub_free (vg->uuid);
|
||||
grub_free (vg->name);
|
||||
return NULL;
|
||||
}
|
||||
grub_memcpy (vg->uuid, label->group_guid, LDM_GUID_STRLEN);
|
||||
grub_memcpy (vg->name, label->group_name, LDM_NAME_STRLEN);
|
||||
vg->name[LDM_NAME_STRLEN] = 0;
|
||||
vg->uuid[LDM_GUID_STRLEN] = 0;
|
||||
vg->uuid_len = grub_strlen (vg->uuid);
|
||||
|
||||
vg->lvs = NULL;
|
||||
vg->pvs = NULL;
|
||||
|
||||
startsec = grub_be_to_cpu64 (label->config_start);
|
||||
endsec = startsec + grub_be_to_cpu64 (label->config_size);
|
||||
|
||||
/* First find disks. */
|
||||
for (cursec = startsec + 0x12; cursec < endsec; cursec++)
|
||||
{
|
||||
struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
|
||||
/ sizeof (struct grub_ldm_vblk)];
|
||||
unsigned i;
|
||||
err = grub_disk_read (disk, cursec, 0,
|
||||
sizeof(vblk), &vblk);
|
||||
if (err)
|
||||
goto fail2;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (vblk); i++)
|
||||
{
|
||||
struct grub_diskfilter_pv *pv;
|
||||
grub_uint8_t *ptr;
|
||||
if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
|
||||
sizeof (vblk[i].magic)) != 0)
|
||||
continue;
|
||||
if (grub_be_to_cpu16 (vblk[i].update_status)
|
||||
!= STATUS_CONSISTENT
|
||||
&& grub_be_to_cpu16 (vblk[i].update_status)
|
||||
!= STATUS_STILL_ACTIVE)
|
||||
continue;
|
||||
if (vblk[i].type != ENTRY_DISK)
|
||||
continue;
|
||||
pv = grub_zalloc (sizeof (*pv));
|
||||
if (!pv)
|
||||
goto fail2;
|
||||
|
||||
pv->disk = 0;
|
||||
ptr = vblk[i].dynamic;
|
||||
if (ptr + *ptr + 1 >= vblk[i].dynamic
|
||||
+ sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (pv);
|
||||
goto fail2;
|
||||
}
|
||||
pv->internal_id = grub_malloc (ptr[0] + 2);
|
||||
if (!pv->internal_id)
|
||||
{
|
||||
grub_free (pv);
|
||||
goto fail2;
|
||||
}
|
||||
grub_memcpy (pv->internal_id, ptr, (grub_size_t) ptr[0] + 1);
|
||||
pv->internal_id[(grub_size_t) ptr[0] + 1] = 0;
|
||||
|
||||
ptr += *ptr + 1;
|
||||
if (ptr + *ptr + 1 >= vblk[i].dynamic
|
||||
+ sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (pv);
|
||||
goto fail2;
|
||||
}
|
||||
/* ptr = name. */
|
||||
ptr += *ptr + 1;
|
||||
if (ptr + *ptr + 1
|
||||
>= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (pv);
|
||||
goto fail2;
|
||||
}
|
||||
pv->id.uuidlen = *ptr;
|
||||
pv->id.uuid = grub_malloc (pv->id.uuidlen + 1);
|
||||
grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen);
|
||||
pv->id.uuid[pv->id.uuidlen] = 0;
|
||||
|
||||
pv->next = vg->pvs;
|
||||
vg->pvs = pv;
|
||||
}
|
||||
}
|
||||
|
||||
/* Then find LVs. */
|
||||
for (cursec = startsec + 0x12; cursec < endsec; cursec++)
|
||||
{
|
||||
struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
|
||||
/ sizeof (struct grub_ldm_vblk)];
|
||||
unsigned i;
|
||||
err = grub_disk_read (disk, cursec, 0,
|
||||
sizeof(vblk), &vblk);
|
||||
if (err)
|
||||
goto fail2;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (vblk); i++)
|
||||
{
|
||||
struct grub_diskfilter_lv *lv;
|
||||
grub_uint8_t *ptr;
|
||||
if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
|
||||
sizeof (vblk[i].magic)) != 0)
|
||||
continue;
|
||||
if (grub_be_to_cpu16 (vblk[i].update_status)
|
||||
!= STATUS_CONSISTENT
|
||||
&& grub_be_to_cpu16 (vblk[i].update_status)
|
||||
!= STATUS_STILL_ACTIVE)
|
||||
continue;
|
||||
if (vblk[i].type != ENTRY_VOLUME)
|
||||
continue;
|
||||
lv = grub_zalloc (sizeof (*lv));
|
||||
if (!lv)
|
||||
goto fail2;
|
||||
|
||||
lv->vg = vg;
|
||||
lv->segment_count = 1;
|
||||
lv->segment_alloc = 1;
|
||||
lv->visible = 1;
|
||||
lv->segments = grub_zalloc (sizeof (*lv->segments));
|
||||
if (!lv->segments)
|
||||
goto fail2;
|
||||
lv->segments->start_extent = 0;
|
||||
lv->segments->type = GRUB_DISKFILTER_MIRROR;
|
||||
lv->segments->node_count = 0;
|
||||
lv->segments->node_alloc = 8;
|
||||
lv->segments->nodes = grub_zalloc (sizeof (*lv->segments->nodes)
|
||||
* lv->segments->node_alloc);
|
||||
if (!lv->segments->nodes)
|
||||
goto fail2;
|
||||
ptr = vblk[i].dynamic;
|
||||
if (ptr + *ptr + 1 >= vblk[i].dynamic
|
||||
+ sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (lv);
|
||||
goto fail2;
|
||||
}
|
||||
lv->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2);
|
||||
if (!lv->internal_id)
|
||||
{
|
||||
grub_free (lv);
|
||||
goto fail2;
|
||||
}
|
||||
grub_memcpy (lv->internal_id, ptr, ptr[0] + 1);
|
||||
lv->internal_id[ptr[0] + 1] = 0;
|
||||
|
||||
ptr += *ptr + 1;
|
||||
if (ptr + *ptr + 1 >= vblk[i].dynamic
|
||||
+ sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (lv);
|
||||
goto fail2;
|
||||
}
|
||||
lv->name = grub_malloc (*ptr + 1);
|
||||
if (!lv->name)
|
||||
{
|
||||
grub_free (lv->internal_id);
|
||||
grub_free (lv);
|
||||
goto fail2;
|
||||
}
|
||||
grub_memcpy (lv->name, ptr + 1, *ptr);
|
||||
lv->name[*ptr] = 0;
|
||||
lv->fullname = grub_xasprintf ("ldm/%s/%s",
|
||||
vg->uuid, lv->name);
|
||||
if (!lv->fullname)
|
||||
{
|
||||
grub_free (lv->internal_id);
|
||||
grub_free (lv->name);
|
||||
grub_free (lv);
|
||||
goto fail2;
|
||||
}
|
||||
ptr += *ptr + 1;
|
||||
if (ptr + *ptr + 1
|
||||
>= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (lv->internal_id);
|
||||
grub_free (lv->name);
|
||||
grub_free (lv);
|
||||
goto fail2;
|
||||
}
|
||||
/* ptr = volume type. */
|
||||
ptr += *ptr + 1;
|
||||
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (lv->internal_id);
|
||||
grub_free (lv->name);
|
||||
grub_free (lv);
|
||||
goto fail2;
|
||||
}
|
||||
/* ptr = flags. */
|
||||
ptr += *ptr + 1;
|
||||
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (lv->internal_id);
|
||||
grub_free (lv->name);
|
||||
grub_free (lv);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
/* Skip state, type, unknown, volume number, zeros, flags. */
|
||||
ptr += 14 + 1 + 1 + 1 + 3 + 1;
|
||||
/* ptr = number of children. */
|
||||
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (lv->internal_id);
|
||||
grub_free (lv->name);
|
||||
grub_free (lv);
|
||||
goto fail2;
|
||||
}
|
||||
ptr += *ptr + 1;
|
||||
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (lv->internal_id);
|
||||
grub_free (lv->name);
|
||||
grub_free (lv);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
/* Skip 2 more fields. */
|
||||
ptr += 8 + 8;
|
||||
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
|
||||
|| ptr + *ptr + 1>= vblk[i].dynamic
|
||||
+ sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (lv->internal_id);
|
||||
grub_free (lv->name);
|
||||
grub_free (lv);
|
||||
goto fail2;
|
||||
}
|
||||
lv->size = read_int (ptr + 1, *ptr);
|
||||
lv->segments->extent_count = lv->size;
|
||||
|
||||
lv->next = vg->lvs;
|
||||
vg->lvs = lv;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the components. */
|
||||
for (cursec = startsec + 0x12; cursec < endsec; cursec++)
|
||||
{
|
||||
struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
|
||||
/ sizeof (struct grub_ldm_vblk)];
|
||||
unsigned i;
|
||||
err = grub_disk_read (disk, cursec, 0,
|
||||
sizeof(vblk), &vblk);
|
||||
if (err)
|
||||
goto fail2;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (vblk); i++)
|
||||
{
|
||||
struct grub_diskfilter_lv *comp;
|
||||
struct grub_diskfilter_lv *lv;
|
||||
grub_uint8_t type;
|
||||
|
||||
grub_uint8_t *ptr;
|
||||
if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
|
||||
sizeof (vblk[i].magic)) != 0)
|
||||
continue;
|
||||
if (grub_be_to_cpu16 (vblk[i].update_status)
|
||||
!= STATUS_CONSISTENT
|
||||
&& grub_be_to_cpu16 (vblk[i].update_status)
|
||||
!= STATUS_STILL_ACTIVE)
|
||||
continue;
|
||||
if (vblk[i].type != ENTRY_COMPONENT)
|
||||
continue;
|
||||
comp = grub_zalloc (sizeof (*comp));
|
||||
if (!comp)
|
||||
goto fail2;
|
||||
comp->visible = 0;
|
||||
comp->name = 0;
|
||||
comp->fullname = 0;
|
||||
|
||||
ptr = vblk[i].dynamic;
|
||||
if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
goto fail2;
|
||||
}
|
||||
comp->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2);
|
||||
if (!comp->internal_id)
|
||||
{
|
||||
grub_free (comp);
|
||||
goto fail2;
|
||||
}
|
||||
grub_memcpy (comp->internal_id, ptr, ptr[0] + 1);
|
||||
comp->internal_id[ptr[0] + 1] = 0;
|
||||
|
||||
ptr += *ptr + 1;
|
||||
if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (comp->internal_id);
|
||||
grub_free (comp);
|
||||
goto fail2;
|
||||
}
|
||||
/* ptr = name. */
|
||||
ptr += *ptr + 1;
|
||||
if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (comp->internal_id);
|
||||
grub_free (comp);
|
||||
goto fail2;
|
||||
}
|
||||
/* ptr = state. */
|
||||
ptr += *ptr + 1;
|
||||
type = *ptr++;
|
||||
/* skip zeros. */
|
||||
ptr += 4;
|
||||
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (comp->internal_id);
|
||||
grub_free (comp);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
/* ptr = number of children. */
|
||||
ptr += *ptr + 1;
|
||||
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (comp->internal_id);
|
||||
grub_free (comp);
|
||||
goto fail2;
|
||||
}
|
||||
ptr += 8 + 8;
|
||||
if (ptr + *ptr + 1 >= vblk[i].dynamic
|
||||
+ sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (comp->internal_id);
|
||||
grub_free (comp);
|
||||
goto fail2;
|
||||
}
|
||||
for (lv = vg->lvs; lv; lv = lv->next)
|
||||
{
|
||||
if (lv->internal_id[0] == ptr[0]
|
||||
&& grub_memcmp (lv->internal_id + 1, ptr + 1, ptr[0]) == 0)
|
||||
break;
|
||||
}
|
||||
if (!lv)
|
||||
{
|
||||
grub_free (comp->internal_id);
|
||||
grub_free (comp);
|
||||
continue;
|
||||
}
|
||||
comp->size = lv->size;
|
||||
if (type == SPANNED)
|
||||
{
|
||||
comp->segment_alloc = 8;
|
||||
comp->segment_count = 0;
|
||||
comp->segments = grub_malloc (sizeof (*comp->segments)
|
||||
* comp->segment_alloc);
|
||||
if (!comp->segments)
|
||||
goto fail2;
|
||||
}
|
||||
else
|
||||
{
|
||||
comp->segment_alloc = 1;
|
||||
comp->segment_count = 1;
|
||||
comp->segments = grub_malloc (sizeof (*comp->segments));
|
||||
if (!comp->segments)
|
||||
goto fail2;
|
||||
comp->segments->start_extent = 0;
|
||||
comp->segments->extent_count = lv->size;
|
||||
comp->segments->layout = 0;
|
||||
if (type == STRIPE)
|
||||
comp->segments->type = GRUB_DISKFILTER_STRIPED;
|
||||
else if (type == RAID5)
|
||||
{
|
||||
comp->segments->type = GRUB_DISKFILTER_RAID5;
|
||||
comp->segments->layout = GRUB_RAID_LAYOUT_SYMMETRIC_MASK;
|
||||
}
|
||||
else
|
||||
goto fail2;
|
||||
ptr += *ptr + 1;
|
||||
ptr++;
|
||||
if (!(vblk[i].flags & 0x10))
|
||||
goto fail2;
|
||||
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
|
||||
|| ptr + *ptr + 1 >= vblk[i].dynamic
|
||||
+ sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (comp->internal_id);
|
||||
grub_free (comp);
|
||||
goto fail2;
|
||||
}
|
||||
comp->segments->stripe_size = read_int (ptr + 1, *ptr);
|
||||
ptr += *ptr + 1;
|
||||
if (ptr + *ptr + 1 >= vblk[i].dynamic
|
||||
+ sizeof (vblk[i].dynamic))
|
||||
{
|
||||
grub_free (comp->internal_id);
|
||||
grub_free (comp);
|
||||
goto fail2;
|
||||
}
|
||||
comp->segments->node_count = read_int (ptr + 1, *ptr);
|
||||
comp->segments->node_alloc = comp->segments->node_count;
|
||||
comp->segments->nodes = grub_zalloc (sizeof (*comp->segments->nodes)
|
||||
* comp->segments->node_alloc);
|
||||
if (!lv->segments->nodes)
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
if (lv->segments->node_alloc == lv->segments->node_count)
|
||||
{
|
||||
void *t;
|
||||
lv->segments->node_alloc *= 2;
|
||||
t = grub_realloc (lv->segments->nodes,
|
||||
sizeof (*lv->segments->nodes)
|
||||
* lv->segments->node_alloc);
|
||||
if (!t)
|
||||
goto fail2;
|
||||
lv->segments->nodes = t;
|
||||
}
|
||||
lv->segments->nodes[lv->segments->node_count].pv = 0;
|
||||
lv->segments->nodes[lv->segments->node_count].start = 0;
|
||||
lv->segments->nodes[lv->segments->node_count++].lv = comp;
|
||||
comp->next = vg->lvs;
|
||||
vg->lvs = comp;
|
||||
}
|
||||
}
|
||||
/* Partitions. */
|
||||
for (cursec = startsec + 0x12; cursec < endsec; cursec++)
|
||||
{
|
||||
struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
|
||||
/ sizeof (struct grub_ldm_vblk)];
|
||||
unsigned i;
|
||||
err = grub_disk_read (disk, cursec, 0,
|
||||
sizeof(vblk), &vblk);
|
||||
if (err)
|
||||
goto fail2;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (vblk); i++)
|
||||
{
|
||||
struct grub_diskfilter_lv *comp;
|
||||
struct grub_diskfilter_node part;
|
||||
grub_disk_addr_t start, size;
|
||||
|
||||
grub_uint8_t *ptr;
|
||||
if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
|
||||
sizeof (vblk[i].magic)) != 0)
|
||||
continue;
|
||||
if (grub_be_to_cpu16 (vblk[i].update_status)
|
||||
!= STATUS_CONSISTENT
|
||||
&& grub_be_to_cpu16 (vblk[i].update_status)
|
||||
!= STATUS_STILL_ACTIVE)
|
||||
continue;
|
||||
if (vblk[i].type != ENTRY_PARTITION)
|
||||
continue;
|
||||
part.lv = 0;
|
||||
part.pv = 0;
|
||||
|
||||
ptr = vblk[i].dynamic;
|
||||
if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
goto fail2;
|
||||
}
|
||||
/* ID */
|
||||
ptr += *ptr + 1;
|
||||
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
goto fail2;
|
||||
}
|
||||
/* ptr = name. */
|
||||
ptr += *ptr + 1;
|
||||
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
/* skip zeros and logcommit id. */
|
||||
ptr += 4 + 8;
|
||||
if (ptr + 16 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
goto fail2;
|
||||
}
|
||||
part.start = read_int (ptr, 8);
|
||||
start = read_int (ptr + 8, 8);
|
||||
ptr += 16;
|
||||
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
|
||||
|| ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
goto fail2;
|
||||
}
|
||||
size = read_int (ptr + 1, *ptr);
|
||||
ptr += *ptr + 1;
|
||||
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
|
||||
|| ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
for (comp = vg->lvs; comp; comp = comp->next)
|
||||
if (comp->internal_id[0] == ptr[0]
|
||||
&& grub_memcmp (ptr + 1, comp->internal_id + 1,
|
||||
comp->internal_id[0]) == 0)
|
||||
goto out;
|
||||
continue;
|
||||
out:
|
||||
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
|
||||
|| ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
|
||||
{
|
||||
goto fail2;
|
||||
}
|
||||
ptr += *ptr + 1;
|
||||
struct grub_diskfilter_pv *pv;
|
||||
for (pv = vg->pvs; pv; pv = pv->next)
|
||||
if (pv->internal_id[0] == ptr[0]
|
||||
&& grub_memcmp (pv->internal_id + 1, ptr + 1, ptr[0]) == 0)
|
||||
part.pv = pv;
|
||||
|
||||
if (comp->segment_alloc == 1)
|
||||
{
|
||||
unsigned index;
|
||||
ptr += *ptr + 1;
|
||||
if (ptr + *ptr + 1 >= vblk[i].dynamic
|
||||
+ sizeof (vblk[i].dynamic))
|
||||
{
|
||||
goto fail2;
|
||||
}
|
||||
index = read_int (ptr + 1, *ptr);
|
||||
if (index < comp->segments->node_count)
|
||||
comp->segments->nodes[index] = part;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (comp->segment_alloc == comp->segment_count)
|
||||
{
|
||||
void *t;
|
||||
comp->segment_alloc *= 2;
|
||||
t = grub_realloc (comp->segments,
|
||||
comp->segment_alloc
|
||||
* sizeof (*comp->segments));
|
||||
if (!t)
|
||||
goto fail2;
|
||||
comp->segments = t;
|
||||
}
|
||||
comp->segments[comp->segment_count].start_extent = start;
|
||||
comp->segments[comp->segment_count].extent_count = size;
|
||||
comp->segments[comp->segment_count].type = GRUB_DISKFILTER_STRIPED;
|
||||
comp->segments[comp->segment_count].node_count = 1;
|
||||
comp->segments[comp->segment_count].node_alloc = 1;
|
||||
comp->segments[comp->segment_count].nodes
|
||||
= grub_malloc (sizeof (*comp->segments[comp->segment_count].nodes));
|
||||
if (!comp->segments[comp->segment_count].nodes)
|
||||
goto fail2;
|
||||
comp->segments[comp->segment_count].nodes[0] = part;
|
||||
comp->segment_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (grub_diskfilter_vg_register (vg))
|
||||
goto fail2;
|
||||
return vg;
|
||||
fail2:
|
||||
{
|
||||
struct grub_diskfilter_lv *lv, *next_lv;
|
||||
struct grub_diskfilter_pv *pv, *next_pv;
|
||||
for (lv = vg->lvs; lv; lv = next_lv)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < lv->segment_count; i++)
|
||||
grub_free (lv->segments[i].nodes);
|
||||
|
||||
next_lv = lv->next;
|
||||
grub_free (lv->segments);
|
||||
grub_free (lv->internal_id);
|
||||
grub_free (lv->name);
|
||||
grub_free (lv->fullname);
|
||||
grub_free (lv);
|
||||
}
|
||||
for (pv = vg->pvs; pv; pv = next_pv)
|
||||
{
|
||||
next_pv = pv->next;
|
||||
grub_free (pv->id.uuid);
|
||||
grub_free (pv);
|
||||
}
|
||||
}
|
||||
grub_free (vg->uuid);
|
||||
grub_free (vg);
|
||||
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;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
grub_disk_addr_t sector;
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
sector = LDM_LABEL_SECTOR;
|
||||
break;
|
||||
case 1:
|
||||
/* LDM is never inside a partition. */
|
||||
if (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;
|
||||
}
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
|
||||
char *
|
||||
grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start)
|
||||
{
|
||||
struct grub_diskfilter_pv *pv = NULL;
|
||||
struct grub_diskfilter_vg *vg = NULL;
|
||||
struct grub_diskfilter_lv *res, *lv;
|
||||
int i;
|
||||
|
||||
pv = grub_diskfilter_get_pv_from_disk (disk, &vg);
|
||||
|
||||
if (!pv)
|
||||
return NULL;
|
||||
|
||||
for (lv = vg->lvs; lv; lv = lv->next)
|
||||
if (lv->segment_count == 1 && lv->segments->node_count == 1
|
||||
&& lv->segments->type == GRUB_DISKFILTER_STRIPED
|
||||
&& lv->segments->nodes->pv == pv
|
||||
&& lv->segments->nodes->start + pv->start_sector == start)
|
||||
{
|
||||
res = lv;
|
||||
break;
|
||||
}
|
||||
for (lv = vg->lvs; lv; lv = lv->next)
|
||||
if (lv->segment_count == 1 && lv->segments->node_count == 1
|
||||
&& lv->segments->type == GRUB_DISKFILTER_MIRROR
|
||||
&& lv->segments->nodes->lv == lv)
|
||||
{
|
||||
res = lv;
|
||||
break;
|
||||
}
|
||||
if (res->fullname)
|
||||
return grub_strdup (lv->fullname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
grub_util_is_ldm (grub_disk_t disk)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
grub_disk_addr_t sector;
|
||||
grub_err_t err;
|
||||
struct grub_ldm_label label;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
sector = LDM_LABEL_SECTOR;
|
||||
break;
|
||||
case 1:
|
||||
/* LDM is never inside a partition. */
|
||||
if (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;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_util_ldm_embed (struct grub_disk *disk, unsigned int *nsectors,
|
||||
grub_embed_type_t embed_type,
|
||||
grub_disk_addr_t **sectors)
|
||||
{
|
||||
struct grub_diskfilter_pv *pv = NULL;
|
||||
struct grub_diskfilter_vg *vg;
|
||||
struct grub_diskfilter_lv *lv;
|
||||
unsigned i;
|
||||
|
||||
if (embed_type != GRUB_EMBED_PCBIOS)
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"GPT curently supports only PC-BIOS embedding");
|
||||
if (disk->partition)
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "disk isn't LDM");
|
||||
pv = grub_diskfilter_get_pv_from_disk (disk, &vg);
|
||||
if (!pv)
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "disk isn't LDM");
|
||||
for (lv = vg->lvs; lv; lv = lv->next)
|
||||
{
|
||||
struct grub_diskfilter_lv *comp;
|
||||
struct grub_ldm_partition *part;
|
||||
|
||||
if (!lv->visible || !lv->fullname)
|
||||
continue;
|
||||
|
||||
if (lv->segment_count != 1)
|
||||
continue;
|
||||
if (lv->segments->type != GRUB_DISKFILTER_MIRROR
|
||||
|| lv->segments->node_count != 1
|
||||
|| lv->segments->start_extent != 0
|
||||
|| lv->segments->extent_count != lv->size)
|
||||
continue;
|
||||
|
||||
comp = lv->segments->nodes->lv;
|
||||
if (!comp)
|
||||
continue;
|
||||
|
||||
if (comp->segment_count != 1 || comp->size != lv->size)
|
||||
continue;
|
||||
if (comp->segments->type != GRUB_DISKFILTER_STRIPED
|
||||
|| comp->segments->node_count != 1
|
||||
|| comp->segments->start_extent != 0
|
||||
|| comp->segments->extent_count != lv->size)
|
||||
continue;
|
||||
|
||||
/* How to implement proper check is to be discussed. */
|
||||
#if 1
|
||||
if (1)
|
||||
continue;
|
||||
#else
|
||||
if (grub_strcmp (lv->name, "Volume5") != 0)
|
||||
continue;
|
||||
#endif
|
||||
if (lv->size < *nsectors)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
"Your LDM embed Partition is too small;"
|
||||
" embedding won't be possible!");
|
||||
*nsectors = lv->size;
|
||||
*sectors = grub_malloc (*nsectors * sizeof (**sectors));
|
||||
if (!*sectors)
|
||||
return grub_errno;
|
||||
for (i = 0; i < *nsectors; i++)
|
||||
(*sectors)[i] = (lv->segments->nodes->start
|
||||
+ comp->segments->nodes->start
|
||||
+ comp->segments->nodes->pv->start_sector + i);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
|
||||
"This LDM no Embedding Partition;"
|
||||
" embedding won't be possible!");
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct grub_diskfilter grub_ldm_dev = {
|
||||
.name = "ldm",
|
||||
.detect = grub_ldm_detect,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT (ldm)
|
||||
{
|
||||
grub_diskfilter_register (&grub_ldm_dev);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI (ldm)
|
||||
{
|
||||
grub_diskfilter_unregister (&grub_ldm_dev);
|
||||
}
|
|
@ -33,12 +33,6 @@
|
|||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static struct grub_lvm_vg *vg_list;
|
||||
static int lv_count;
|
||||
static int scan_depth = 0;
|
||||
|
||||
static int is_lv_readable (struct grub_lvm_lv *lv);
|
||||
|
||||
|
||||
/* Go the string STR and return the number after STR. *P will point
|
||||
at the number. In case STR is not found, *P will be NULL and the
|
||||
|
@ -50,7 +44,7 @@ grub_lvm_getvalue (char **p, const char *str)
|
|||
if (! *p)
|
||||
return 0;
|
||||
*p += grub_strlen (str);
|
||||
return grub_strtoul (*p, NULL, 10);
|
||||
return grub_strtoul (*p, p, 10);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -101,31 +95,12 @@ grub_lvm_check_flag (char *p, const char *str, const char *flag)
|
|||
}
|
||||
}
|
||||
|
||||
static struct grub_lvm_lv *
|
||||
find_lv (const char *name)
|
||||
{
|
||||
struct grub_lvm_vg *vg;
|
||||
struct grub_lvm_lv *lv = NULL;
|
||||
for (vg = vg_list; vg; vg = vg->next)
|
||||
{
|
||||
if (vg->lvs)
|
||||
for (lv = vg->lvs; lv; lv = lv->next)
|
||||
if ((grub_strcmp (lv->fullname, name) == 0
|
||||
|| grub_strcmp (lv->compatname, name) == 0)
|
||||
&& is_lv_readable (lv))
|
||||
return lv;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
do_lvm_scan (const char *scan_for)
|
||||
{
|
||||
auto int grub_lvm_scan_device (const char *name);
|
||||
int grub_lvm_scan_device (const char *name)
|
||||
static struct grub_diskfilter_vg *
|
||||
grub_lvm_detect (grub_disk_t disk,
|
||||
struct grub_diskfilter_pv_id *id,
|
||||
grub_disk_addr_t *start_sector)
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_disk_t disk;
|
||||
grub_uint64_t mda_offset, mda_size;
|
||||
char buf[GRUB_LVM_LABEL_SIZE];
|
||||
char vg_id[GRUB_LVM_ID_STRLEN+1];
|
||||
|
@ -137,33 +112,8 @@ do_lvm_scan (const char *scan_for)
|
|||
struct grub_lvm_mda_header *mdah;
|
||||
struct grub_lvm_raw_locn *rlocn;
|
||||
unsigned int i, j, vgname_len;
|
||||
struct grub_lvm_vg *vg;
|
||||
struct grub_lvm_pv *pv;
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("scanning %s for LVM", name);
|
||||
#endif
|
||||
|
||||
disk = grub_disk_open (name);
|
||||
if (!disk)
|
||||
{
|
||||
if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (vg = vg_list; vg; vg = vg->next)
|
||||
for (pv = vg->pvs; pv; pv = pv->next)
|
||||
if (pv->disk && pv->disk->id == disk->id
|
||||
&& pv->disk->dev->id == disk->dev->id
|
||||
&& grub_partition_get_start (pv->disk->partition)
|
||||
== grub_partition_get_start (disk->partition)
|
||||
&& grub_disk_get_size (pv->disk)
|
||||
== grub_disk_get_size (disk))
|
||||
{
|
||||
grub_disk_close (disk);
|
||||
return 0;
|
||||
}
|
||||
struct grub_diskfilter_vg *vg;
|
||||
struct grub_diskfilter_pv *pv;
|
||||
|
||||
/* Search for label. */
|
||||
for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++)
|
||||
|
@ -287,11 +237,7 @@ do_lvm_scan (const char *scan_for)
|
|||
grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN);
|
||||
vg_id[GRUB_LVM_ID_STRLEN] = '\0';
|
||||
|
||||
for (vg = vg_list; vg; vg = vg->next)
|
||||
{
|
||||
if (! grub_memcmp(vg_id, vg->id, GRUB_LVM_ID_STRLEN))
|
||||
break;
|
||||
}
|
||||
vg = grub_diskfilter_get_vg_by_uuid (GRUB_LVM_ID_STRLEN, vg_id);
|
||||
|
||||
if (! vg)
|
||||
{
|
||||
|
@ -301,7 +247,11 @@ do_lvm_scan (const char *scan_for)
|
|||
if (! vg)
|
||||
goto fail3;
|
||||
vg->name = vgname;
|
||||
grub_memcpy (vg->id, vg_id, GRUB_LVM_ID_STRLEN+1);
|
||||
vg->uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
|
||||
if (! vg->uuid)
|
||||
goto fail3;
|
||||
grub_memcpy (vg->uuid, vg_id, GRUB_LVM_ID_STRLEN);
|
||||
vg->uuid_len = GRUB_LVM_ID_STRLEN;
|
||||
|
||||
vg->extent_size = grub_lvm_getvalue (&p, "extent_size = ");
|
||||
if (p == NULL)
|
||||
|
@ -330,7 +280,7 @@ do_lvm_scan (const char *scan_for)
|
|||
if (*p == '}')
|
||||
break;
|
||||
|
||||
pv = grub_malloc (sizeof (*pv));
|
||||
pv = grub_zalloc (sizeof (*pv));
|
||||
q = p;
|
||||
while (*q != ' ')
|
||||
q++;
|
||||
|
@ -345,10 +295,13 @@ do_lvm_scan (const char *scan_for)
|
|||
goto pvs_fail;
|
||||
p += sizeof("id = \"") - 1;
|
||||
|
||||
grub_memcpy (pv->id, p, GRUB_LVM_ID_STRLEN);
|
||||
pv->id[GRUB_LVM_ID_STRLEN] = '\0';
|
||||
pv->id.uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
|
||||
if (!pv->id.uuid)
|
||||
goto pvs_fail;
|
||||
grub_memcpy (pv->id.uuid, p, GRUB_LVM_ID_STRLEN);
|
||||
pv->id.uuidlen = GRUB_LVM_ID_STRLEN;
|
||||
|
||||
pv->start = grub_lvm_getvalue (&p, "pe_start = ");
|
||||
pv->start_sector = grub_lvm_getvalue (&p, "pe_start = ");
|
||||
if (p == NULL)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
|
@ -382,15 +335,15 @@ do_lvm_scan (const char *scan_for)
|
|||
p = grub_strstr (p, "logical_volumes");
|
||||
if (p)
|
||||
{
|
||||
p += 18;
|
||||
p += sizeof ("logical_volumes = ") - 1;
|
||||
|
||||
/* And add all the lvs to the volume group. */
|
||||
while (1)
|
||||
{
|
||||
int s;
|
||||
int skip_lv = 0;
|
||||
struct grub_lvm_lv *lv;
|
||||
struct grub_lvm_segment *seg;
|
||||
struct grub_diskfilter_lv *lv;
|
||||
struct grub_diskfilter_segment *seg;
|
||||
int is_pvmove;
|
||||
|
||||
while (grub_isspace (*p))
|
||||
|
@ -399,7 +352,7 @@ do_lvm_scan (const char *scan_for)
|
|||
if (*p == '}')
|
||||
break;
|
||||
|
||||
lv = grub_malloc (sizeof (*lv));
|
||||
lv = grub_zalloc (sizeof (*lv));
|
||||
|
||||
q = p;
|
||||
while (*q != ' ')
|
||||
|
@ -409,25 +362,17 @@ do_lvm_scan (const char *scan_for)
|
|||
lv->name = grub_strndup (p, s);
|
||||
if (!lv->name)
|
||||
goto lvs_fail;
|
||||
lv->compatname = grub_malloc (vgname_len + 1 + s + 1);
|
||||
if (!lv->compatname)
|
||||
goto lvs_fail;
|
||||
grub_memcpy (lv->compatname, vgname, vgname_len);
|
||||
lv->compatname[vgname_len] = '-';
|
||||
grub_memcpy (lv->compatname + vgname_len + 1, p, s);
|
||||
lv->compatname[vgname_len + 1 + s] = '\0';
|
||||
|
||||
{
|
||||
const char *iptr;
|
||||
char *optr;
|
||||
lv->fullname = grub_malloc (sizeof("lvm/") + 2 * vgname_len
|
||||
lv->fullname = grub_malloc (sizeof ("lvm/") - 1 + 2 * vgname_len
|
||||
+ 1 + 2 * s + 1);
|
||||
if (!lv->fullname)
|
||||
goto lvs_fail;
|
||||
|
||||
optr = lv->fullname;
|
||||
grub_memcpy (optr, "lvm/", sizeof ("lvm/") - 1);
|
||||
optr += sizeof ("lvm/") - 1;
|
||||
grub_memcpy (lv->fullname, "lvm/", sizeof ("lvm/") - 1);
|
||||
optr = lv->fullname + sizeof ("lvm/") - 1;
|
||||
for (iptr = vgname; iptr < vgname + vgname_len; iptr++)
|
||||
{
|
||||
*optr++ = *iptr;
|
||||
|
@ -499,9 +444,9 @@ do_lvm_scan (const char *scan_for)
|
|||
if (grub_memcmp (p, "striped\"",
|
||||
sizeof ("striped\"") - 1) == 0)
|
||||
{
|
||||
struct grub_lvm_node *stripe;
|
||||
struct grub_diskfilter_node *stripe;
|
||||
|
||||
seg->type = GRUB_LVM_STRIPED;
|
||||
seg->type = GRUB_DISKFILTER_STRIPED;
|
||||
seg->node_count = grub_lvm_getvalue (&p, "stripe_count = ");
|
||||
if (p == NULL)
|
||||
{
|
||||
|
@ -546,7 +491,10 @@ do_lvm_scan (const char *scan_for)
|
|||
grub_memcpy (stripe->name, p, s);
|
||||
stripe->name[s] = '\0';
|
||||
|
||||
stripe->start = grub_lvm_getvalue (&p, ",");
|
||||
p = q + 1;
|
||||
|
||||
stripe->start = grub_lvm_getvalue (&p, ",")
|
||||
* vg->extent_size;
|
||||
if (p == NULL)
|
||||
continue;
|
||||
|
||||
|
@ -556,7 +504,7 @@ do_lvm_scan (const char *scan_for)
|
|||
else if (grub_memcmp (p, "mirror\"", sizeof ("mirror\"") - 1)
|
||||
== 0)
|
||||
{
|
||||
seg->type = GRUB_LVM_MIRROR;
|
||||
seg->type = GRUB_DISKFILTER_MIRROR;
|
||||
seg->node_count = grub_lvm_getvalue (&p, "mirror_count = ");
|
||||
if (p == NULL)
|
||||
{
|
||||
|
@ -605,6 +553,94 @@ do_lvm_scan (const char *scan_for)
|
|||
if (is_pvmove)
|
||||
seg->node_count = 1;
|
||||
}
|
||||
else if (grub_memcmp (p, "raid", sizeof ("raid") - 1)
|
||||
== 0 && (p[sizeof ("raid") - 1] >= '4'
|
||||
&& p[sizeof ("raid") - 1] <= '6')
|
||||
&& p[sizeof ("raidX") - 1] == '"')
|
||||
{
|
||||
switch (p[sizeof ("raid") - 1])
|
||||
{
|
||||
case '4':
|
||||
seg->type = GRUB_DISKFILTER_RAID4;
|
||||
seg->layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC;
|
||||
break;
|
||||
case '5':
|
||||
seg->type = GRUB_DISKFILTER_RAID5;
|
||||
seg->layout = GRUB_RAID_LAYOUT_LEFT_SYMMETRIC;
|
||||
break;
|
||||
case '6':
|
||||
seg->type = GRUB_DISKFILTER_RAID6;
|
||||
seg->layout = (GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC
|
||||
| GRUB_RAID_LAYOUT_MUL_FROM_POS);
|
||||
break;
|
||||
}
|
||||
seg->node_count = grub_lvm_getvalue (&p, "device_count = ");
|
||||
|
||||
if (p == NULL)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("unknown device_count\n");
|
||||
#endif
|
||||
goto lvs_segment_fail;
|
||||
}
|
||||
|
||||
seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
|
||||
if (p == NULL)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("unknown stripe_size\n");
|
||||
#endif
|
||||
goto lvs_segment_fail;
|
||||
}
|
||||
|
||||
|
||||
seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
|
||||
* seg->node_count);
|
||||
|
||||
p = grub_strstr (p, "raids = [");
|
||||
if (p == NULL)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("unknown mirrors\n");
|
||||
#endif
|
||||
goto lvs_segment_fail2;
|
||||
}
|
||||
p += sizeof("raids = [") - 1;
|
||||
|
||||
for (j = 0; j < seg->node_count; j++)
|
||||
{
|
||||
char *lvname;
|
||||
|
||||
p = grub_strchr (p, '"');
|
||||
p = p ? grub_strchr (p + 1, '"') : 0;
|
||||
p = p ? grub_strchr (p + 1, '"') : 0;
|
||||
if (p == NULL)
|
||||
continue;
|
||||
q = ++p;
|
||||
while (*q != '"')
|
||||
q++;
|
||||
|
||||
s = q - p;
|
||||
|
||||
lvname = grub_malloc (s + 1);
|
||||
if (lvname == NULL)
|
||||
goto lvs_segment_fail2;
|
||||
|
||||
grub_memcpy (lvname, p, s);
|
||||
lvname[s] = '\0';
|
||||
seg->nodes[j].name = lvname;
|
||||
p = q + 1;
|
||||
}
|
||||
if (seg->type == GRUB_DISKFILTER_RAID4)
|
||||
{
|
||||
char *tmp;
|
||||
tmp = seg->nodes[0].name;
|
||||
grub_memmove (seg->nodes, seg->nodes + 1,
|
||||
sizeof (seg->nodes[0])
|
||||
* (seg->node_count - 1));
|
||||
seg->nodes[seg->node_count - 1].name = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
|
@ -643,7 +679,6 @@ do_lvm_scan (const char *scan_for)
|
|||
continue;
|
||||
}
|
||||
|
||||
lv->number = lv_count++;
|
||||
lv->vg = vg;
|
||||
lv->next = vg->lvs;
|
||||
vg->lvs = lv;
|
||||
|
@ -658,8 +693,8 @@ do_lvm_scan (const char *scan_for)
|
|||
|
||||
/* Match lvs. */
|
||||
{
|
||||
struct grub_lvm_lv *lv1;
|
||||
struct grub_lvm_lv *lv2;
|
||||
struct grub_diskfilter_lv *lv1;
|
||||
struct grub_diskfilter_lv *lv2;
|
||||
for (lv1 = vg->lvs; lv1; lv1 = lv1->next)
|
||||
for (i = 0; i < lv1->segment_count; i++)
|
||||
for (j = 0; j < lv1->segments[i].node_count; j++)
|
||||
|
@ -676,37 +711,28 @@ do_lvm_scan (const char *scan_for)
|
|||
}
|
||||
if (lv1->segments[i].nodes[j].pv == NULL)
|
||||
for (lv2 = vg->lvs; lv2; lv2 = lv2->next)
|
||||
if (grub_strcmp (lv2->name + grub_strlen (vg->name) + 1,
|
||||
if (grub_strcmp (lv2->name,
|
||||
lv1->segments[i].nodes[j].name) == 0)
|
||||
lv1->segments[i].nodes[j].lv = lv2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
vg->next = vg_list;
|
||||
vg_list = vg;
|
||||
if (grub_diskfilter_vg_register (vg))
|
||||
goto fail4;
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_free (vgname);
|
||||
}
|
||||
|
||||
/* Match the device we are currently reading from with the right
|
||||
PV. */
|
||||
if (vg->pvs)
|
||||
for (pv = vg->pvs; pv; pv = pv->next)
|
||||
{
|
||||
if (! grub_memcmp (pv->id, pv_id, GRUB_LVM_ID_STRLEN))
|
||||
{
|
||||
/* This could happen to LVM on RAID, pv->disk points to the
|
||||
raid device, we shouldn't change it. */
|
||||
if (! pv->disk)
|
||||
pv->disk = grub_disk_open (name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
goto fail2;
|
||||
id->uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
|
||||
if (!id->uuid)
|
||||
goto fail4;
|
||||
grub_memcpy (id->uuid, pv_id, GRUB_LVM_ID_STRLEN);
|
||||
id->uuidlen = GRUB_LVM_ID_STRLEN;
|
||||
grub_free (metadatabuf);
|
||||
*start_sector = -1;
|
||||
return vg;
|
||||
|
||||
/* Failure path. */
|
||||
fail4:
|
||||
|
@ -714,319 +740,26 @@ do_lvm_scan (const char *scan_for)
|
|||
fail3:
|
||||
grub_free (vgname);
|
||||
|
||||
/* Normal exit path. */
|
||||
fail2:
|
||||
grub_free (metadatabuf);
|
||||
fail:
|
||||
grub_disk_close (disk);
|
||||
if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
grub_print_error ();
|
||||
if (scan_for && find_lv (scan_for))
|
||||
return 1;
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scan_depth++;
|
||||
grub_device_iterate (&grub_lvm_scan_device);
|
||||
scan_depth--;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
grub_lvm_iterate (int (*hook) (const char *name),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
struct grub_lvm_vg *vg;
|
||||
unsigned old_count = 0;
|
||||
if (pull == GRUB_DISK_PULL_RESCAN && scan_depth)
|
||||
return 0;
|
||||
|
||||
if (pull == GRUB_DISK_PULL_RESCAN)
|
||||
{
|
||||
old_count = lv_count;
|
||||
if (!scan_depth)
|
||||
do_lvm_scan (NULL);
|
||||
}
|
||||
if (pull != GRUB_DISK_PULL_RESCAN && pull != GRUB_DISK_PULL_NONE)
|
||||
return GRUB_ERR_NONE;
|
||||
for (vg = vg_list; vg; vg = vg->next)
|
||||
{
|
||||
struct grub_lvm_lv *lv;
|
||||
if (vg->lvs)
|
||||
for (lv = vg->lvs; lv; lv = lv->next)
|
||||
if (lv->visible && lv->number >= old_count)
|
||||
{
|
||||
if (hook (lv->fullname))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
static grub_disk_memberlist_t
|
||||
grub_lvm_memberlist (grub_disk_t disk)
|
||||
{
|
||||
struct grub_lvm_lv *lv = disk->data;
|
||||
grub_disk_memberlist_t list = NULL, tmp;
|
||||
struct grub_lvm_pv *pv;
|
||||
|
||||
if (lv->vg->pvs)
|
||||
for (pv = lv->vg->pvs; pv; pv = pv->next)
|
||||
{
|
||||
if (!pv->disk)
|
||||
grub_util_error (_("Couldn't find PV %s. Check your device.map"),
|
||||
pv->name);
|
||||
tmp = grub_malloc (sizeof (*tmp));
|
||||
tmp->disk = pv->disk;
|
||||
tmp->next = list;
|
||||
list = tmp;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
#endif
|
||||
|
||||
static grub_err_t
|
||||
grub_lvm_open (const char *name, grub_disk_t disk)
|
||||
{
|
||||
struct grub_lvm_lv *lv = NULL;
|
||||
int explicit = 0;
|
||||
|
||||
if (grub_memcmp (name, "lvm/", sizeof ("lvm/") - 1) == 0)
|
||||
explicit = 1;
|
||||
|
||||
lv = find_lv (name);
|
||||
|
||||
if (! lv && !scan_depth && explicit)
|
||||
{
|
||||
do_lvm_scan (name);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
lv = find_lv (name);
|
||||
}
|
||||
|
||||
if (! lv)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown LVM device %s", name);
|
||||
|
||||
disk->id = lv->number;
|
||||
disk->data = lv;
|
||||
disk->total_sectors = lv->size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_lvm_close (grub_disk_t disk __attribute ((unused)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
read_lv (struct grub_lvm_lv *lv, grub_disk_addr_t sector,
|
||||
grub_size_t size, char *buf);
|
||||
|
||||
static grub_err_t
|
||||
read_node (const struct grub_lvm_node *node, grub_disk_addr_t sector,
|
||||
grub_size_t size, char *buf)
|
||||
{
|
||||
/* Check whether we actually know the physical volume we want to
|
||||
read from. */
|
||||
if (node->pv)
|
||||
{
|
||||
if (node->pv->disk)
|
||||
return grub_disk_read (node->pv->disk, sector + node->pv->start, 0,
|
||||
size << GRUB_DISK_SECTOR_BITS, buf);
|
||||
else
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
|
||||
"physical volume %s not found", node->pv->name);
|
||||
|
||||
}
|
||||
if (node->lv)
|
||||
return read_lv (node->lv, sector, size, buf);
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown node '%s'", node->name);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
read_lv (struct grub_lvm_lv *lv, grub_disk_addr_t sector,
|
||||
grub_size_t size, char *buf)
|
||||
{
|
||||
grub_err_t err = 0;
|
||||
struct grub_lvm_vg *vg = lv->vg;
|
||||
struct grub_lvm_segment *seg = lv->segments;
|
||||
struct grub_lvm_node *node;
|
||||
grub_uint64_t offset;
|
||||
grub_uint64_t extent;
|
||||
unsigned int i;
|
||||
|
||||
if (!lv)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown volume");
|
||||
|
||||
extent = grub_divmod64 (sector, vg->extent_size, NULL);
|
||||
|
||||
/* Find the right segment. */
|
||||
for (i = 0; i < lv->segment_count; i++)
|
||||
{
|
||||
if ((seg->start_extent <= extent)
|
||||
&& ((seg->start_extent + seg->extent_count) > extent))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
seg++;
|
||||
}
|
||||
|
||||
if (i == lv->segment_count)
|
||||
return grub_error (GRUB_ERR_READ_ERROR, "incorrect segment");
|
||||
|
||||
switch (seg->type)
|
||||
{
|
||||
case GRUB_LVM_STRIPED:
|
||||
if (seg->node_count == 1)
|
||||
{
|
||||
/* This segment is linear, so that's easy. We just need to find
|
||||
out the offset in the physical volume and read SIZE bytes
|
||||
from that. */
|
||||
struct grub_lvm_node *stripe = seg->nodes;
|
||||
grub_uint64_t seg_offset; /* Offset of the segment in PV device. */
|
||||
|
||||
node = stripe;
|
||||
seg_offset = ((grub_uint64_t) stripe->start
|
||||
* (grub_uint64_t) vg->extent_size);
|
||||
|
||||
offset = sector - ((grub_uint64_t) seg->start_extent
|
||||
* (grub_uint64_t) vg->extent_size) + seg_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is a striped segment. We have to find the right PV
|
||||
similar to RAID0. */
|
||||
struct grub_lvm_node *stripe = seg->nodes;
|
||||
grub_uint64_t a, b;
|
||||
grub_uint64_t seg_offset; /* Offset of the segment in PV device. */
|
||||
grub_uint64_t stripenr;
|
||||
|
||||
offset = sector - ((grub_uint64_t) seg->start_extent
|
||||
* (grub_uint64_t) vg->extent_size);
|
||||
|
||||
a = grub_divmod64 (offset, seg->stripe_size, NULL);
|
||||
grub_divmod64 (a, seg->node_count, &stripenr);
|
||||
|
||||
a = grub_divmod64 (offset, seg->stripe_size * seg->node_count, NULL);
|
||||
grub_divmod64 (offset, seg->stripe_size, &b);
|
||||
offset = a * seg->stripe_size + b;
|
||||
|
||||
stripe += stripenr;
|
||||
node = stripe;
|
||||
|
||||
seg_offset = ((grub_uint64_t) stripe->start
|
||||
* (grub_uint64_t) vg->extent_size);
|
||||
|
||||
offset += seg_offset;
|
||||
}
|
||||
return read_node (node, offset, size, buf);
|
||||
case GRUB_LVM_MIRROR:
|
||||
i = 0;
|
||||
while (1)
|
||||
{
|
||||
err = read_node (&seg->nodes[i], sector, size, buf);
|
||||
if (!err)
|
||||
return err;
|
||||
if (++i >= seg->node_count)
|
||||
return err;
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
return grub_error (GRUB_ERR_IO, "unknown LVM segment");
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
is_node_readable (const struct grub_lvm_node *node)
|
||||
{
|
||||
/* Check whether we actually know the physical volume we want to
|
||||
read from. */
|
||||
if (node->pv)
|
||||
return !!(node->pv->disk);
|
||||
if (node->lv)
|
||||
return is_lv_readable (node->lv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
is_lv_readable (struct grub_lvm_lv *lv)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
if (!lv)
|
||||
return 0;
|
||||
|
||||
/* Find the right segment. */
|
||||
for (i = 0; i < lv->segment_count; i++)
|
||||
switch (lv->segments[i].type)
|
||||
{
|
||||
case GRUB_LVM_STRIPED:
|
||||
for (j = 0; j < lv->segments[i].node_count; j++)
|
||||
if (!is_node_readable (lv->segments[i].nodes + j))
|
||||
return 0;
|
||||
break;
|
||||
case GRUB_LVM_MIRROR:
|
||||
for (j = 0; j < lv->segments[i].node_count; j++)
|
||||
if (is_node_readable (lv->segments[i].nodes + j))
|
||||
break;
|
||||
if (j == lv->segments[i].node_count)
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static grub_err_t
|
||||
grub_lvm_read (grub_disk_t disk, grub_disk_addr_t sector,
|
||||
grub_size_t size, char *buf)
|
||||
{
|
||||
return read_lv (disk->data, sector, size, buf);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_lvm_write (grub_disk_t disk __attribute ((unused)),
|
||||
grub_disk_addr_t sector __attribute ((unused)),
|
||||
grub_size_t size __attribute ((unused)),
|
||||
const char *buf __attribute ((unused)))
|
||||
{
|
||||
return GRUB_ERR_NOT_IMPLEMENTED_YET;
|
||||
}
|
||||
|
||||
static struct grub_disk_dev grub_lvm_dev =
|
||||
{
|
||||
static struct grub_diskfilter grub_lvm_dev = {
|
||||
.name = "lvm",
|
||||
.id = GRUB_DISK_DEVICE_LVM_ID,
|
||||
.iterate = grub_lvm_iterate,
|
||||
.open = grub_lvm_open,
|
||||
.close = grub_lvm_close,
|
||||
.read = grub_lvm_read,
|
||||
.write = grub_lvm_write,
|
||||
#ifdef GRUB_UTIL
|
||||
.memberlist = grub_lvm_memberlist,
|
||||
#endif
|
||||
.detect = grub_lvm_detect,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
|
||||
GRUB_MOD_INIT (lvm)
|
||||
{
|
||||
grub_disk_dev_register (&grub_lvm_dev);
|
||||
grub_diskfilter_register (&grub_lvm_dev);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI (lvm)
|
||||
{
|
||||
grub_disk_dev_unregister (&grub_lvm_dev);
|
||||
vg_list = NULL;
|
||||
/* FIXME: free the lvm list. */
|
||||
grub_diskfilter_unregister (&grub_lvm_dev);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/raid.h>
|
||||
#include <grub/diskfilter.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -103,8 +103,9 @@ struct grub_raid_super_1x
|
|||
|
||||
#define WriteMostly1 1 /* Mask for writemostly flag in above devflags. */
|
||||
|
||||
static grub_err_t
|
||||
grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
|
||||
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_disk_addr_t sector = 0;
|
||||
|
@ -142,7 +143,7 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
|
|||
|
||||
if (grub_disk_read (disk, sector, 0, sizeof (struct grub_raid_super_1x),
|
||||
&sb))
|
||||
return grub_errno;
|
||||
return NULL;
|
||||
|
||||
if (grub_le_to_cpu32 (sb.magic) != SB_MAGIC
|
||||
|| grub_le_to_cpu64 (sb.super_offset) != sector)
|
||||
|
@ -154,9 +155,12 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
|
|||
grub_uint32_t level;
|
||||
|
||||
if (grub_le_to_cpu32 (sb.major_version) != 1)
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
{
|
||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"Unsupported RAID version: %d",
|
||||
grub_le_to_cpu32 (sb.major_version));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
level = grub_le_to_cpu32 (sb.level);
|
||||
|
||||
|
@ -166,8 +170,11 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
|
|||
|
||||
if (level != 0 && level != 1 && level != 4 &&
|
||||
level != 5 && level != 6 && level != 10)
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
{
|
||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"Unsupported RAID level: %d", sb.level);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
@ -175,62 +182,68 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
|
|||
+ 2 * grub_le_to_cpu32 (sb.max_dev);
|
||||
real_sb = grub_malloc (sb_size);
|
||||
if (! real_sb)
|
||||
return grub_errno;
|
||||
return NULL;
|
||||
|
||||
if (grub_disk_read (disk, sector, 0, sb_size, real_sb))
|
||||
{
|
||||
grub_free (real_sb);
|
||||
return grub_errno;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
if (real_sb->size)
|
||||
array->disk_size = grub_le_to_cpu64 (real_sb->size);
|
||||
else
|
||||
array->disk_size = grub_le_to_cpu64 (real_sb->data_size);
|
||||
array->chunk_size = grub_le_to_cpu32 (real_sb->chunksize);
|
||||
struct grub_diskfilter_vg *array;
|
||||
char *uuid;
|
||||
|
||||
if (grub_le_to_cpu32 (real_sb->dev_number) >=
|
||||
grub_le_to_cpu32 (real_sb->max_dev))
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
"spares aren't implemented");
|
||||
|
||||
array->index = grub_le_to_cpu16
|
||||
(real_sb->dev_roles[grub_le_to_cpu32 (real_sb->dev_number)]);
|
||||
if (array->index >= array->total_devs)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
"spares aren't implemented");
|
||||
array->uuid_len = 16;
|
||||
array->uuid = grub_malloc (16);
|
||||
if (!array->uuid)
|
||||
{
|
||||
grub_free (real_sb);
|
||||
return grub_errno;
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
"spares aren't implemented");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
grub_memcpy (array->uuid, real_sb->set_uuid, 16);
|
||||
id->uuidlen = 0;
|
||||
id->id = grub_le_to_cpu16
|
||||
(real_sb->dev_roles[grub_le_to_cpu32 (real_sb->dev_number)]);
|
||||
|
||||
uuid = grub_malloc (16);
|
||||
if (!uuid)
|
||||
{
|
||||
grub_free (real_sb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
grub_memcpy (uuid, real_sb->set_uuid, 16);
|
||||
|
||||
*start_sector = grub_le_to_cpu64 (real_sb->data_offset);
|
||||
|
||||
if (grub_le_to_cpu32 (real_sb->dev_number)
|
||||
>= grub_le_to_cpu32 (real_sb->raid_disks))
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
"spares aren't implemented");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
array = grub_diskfilter_make_raid (16, uuid,
|
||||
grub_le_to_cpu32 (real_sb->raid_disks),
|
||||
real_sb->set_name,
|
||||
(real_sb->size)
|
||||
? grub_le_to_cpu64 (real_sb->size)
|
||||
: grub_le_to_cpu64 (real_sb->data_size),
|
||||
grub_le_to_cpu32 (real_sb->chunksize),
|
||||
grub_le_to_cpu32 (real_sb->layout),
|
||||
grub_le_to_cpu32 (real_sb->level));
|
||||
|
||||
grub_free (real_sb);
|
||||
return 0;
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 1.x raid");
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE, "not 1.x raid");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct grub_raid grub_mdraid_dev = {
|
||||
static struct grub_diskfilter grub_mdraid_dev = {
|
||||
.name = "mdraid1x",
|
||||
.detect = grub_mdraid_detect,
|
||||
.next = 0
|
||||
|
@ -238,10 +251,10 @@ static struct grub_raid grub_mdraid_dev = {
|
|||
|
||||
GRUB_MOD_INIT (mdraid1x)
|
||||
{
|
||||
grub_raid_register (&grub_mdraid_dev);
|
||||
grub_diskfilter_register (&grub_mdraid_dev);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI (mdraid1x)
|
||||
{
|
||||
grub_raid_unregister (&grub_mdraid_dev);
|
||||
grub_diskfilter_unregister (&grub_mdraid_dev);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/raid.h>
|
||||
#include <grub/diskfilter.h>
|
||||
|
||||
/* Linux RAID on disk structures and constants,
|
||||
copied from include/linux/raid/md_p.h. */
|
||||
|
@ -161,8 +161,9 @@ struct grub_raid_super_09
|
|||
struct grub_raid_disk_09 this_disk;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static grub_err_t
|
||||
grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
|
||||
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_disk_addr_t sector;
|
||||
|
@ -174,22 +175,31 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
|
|||
/* The sector where the mdraid 0.90 superblock is stored, if available. */
|
||||
size = grub_disk_get_size (disk);
|
||||
if (size == GRUB_DISK_SIZE_UNKNOWN)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
|
||||
return NULL;
|
||||
}
|
||||
sector = NEW_SIZE_SECTORS (size);
|
||||
|
||||
if (grub_disk_read (disk, sector, 0, SB_BYTES, &sb))
|
||||
return grub_errno;
|
||||
return NULL;
|
||||
|
||||
/* Look whether there is a mdraid 0.90 superblock. */
|
||||
if (grub_le_to_cpu32 (sb.md_magic) != SB_MAGIC)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (grub_le_to_cpu32 (sb.major_version) != 0
|
||||
|| grub_le_to_cpu32 (sb.minor_version) != 90)
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
{
|
||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"unsupported RAID version: %d.%d",
|
||||
grub_le_to_cpu32 (sb.major_version),
|
||||
grub_le_to_cpu32 (sb.minor_version));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME: Check the checksum. */
|
||||
|
||||
|
@ -200,26 +210,22 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
|
|||
|
||||
if (level != 0 && level != 1 && level != 4 &&
|
||||
level != 5 && level != 6 && level != 10)
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
{
|
||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"unsupported RAID level: %d", level);
|
||||
return NULL;
|
||||
}
|
||||
if (grub_le_to_cpu32 (sb.this_disk.number) == 0xffff
|
||||
|| grub_le_to_cpu32 (sb.this_disk.number) == 0xfffe)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
"spares aren't implemented");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
array->name = NULL;
|
||||
array->number = grub_le_to_cpu32 (sb.md_minor);
|
||||
array->level = level;
|
||||
array->layout = grub_le_to_cpu32 (sb.layout);
|
||||
array->total_devs = grub_le_to_cpu32 (sb.raid_disks);
|
||||
array->disk_size = (sb.size) ? grub_le_to_cpu32 (sb.size) * 2 : sector;
|
||||
array->chunk_size = grub_le_to_cpu32 (sb.chunk_size) >> 9;
|
||||
array->index = grub_le_to_cpu32 (sb.this_disk.number);
|
||||
array->uuid_len = 16;
|
||||
uuid = grub_malloc (16);
|
||||
array->uuid = (char *) uuid;
|
||||
if (!array->uuid)
|
||||
return grub_errno;
|
||||
if (!uuid)
|
||||
return NULL;
|
||||
|
||||
uuid[0] = grub_swap_bytes32 (sb.set_uuid0);
|
||||
uuid[1] = grub_swap_bytes32 (sb.set_uuid1);
|
||||
|
@ -228,10 +234,21 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
|
|||
|
||||
*start_sector = 0;
|
||||
|
||||
return 0;
|
||||
id->uuidlen = 0;
|
||||
id->id = grub_le_to_cpu32 (sb.this_disk.number);
|
||||
|
||||
char buf[32];
|
||||
grub_snprintf (buf, sizeof (buf), "md%d", grub_le_to_cpu32 (sb.md_minor));
|
||||
return grub_diskfilter_make_raid (16, (char *) uuid,
|
||||
grub_le_to_cpu32 (sb.raid_disks), buf,
|
||||
(sb.size) ? grub_le_to_cpu32 (sb.size) * 2
|
||||
: sector,
|
||||
grub_le_to_cpu32 (sb.chunk_size) >> 9,
|
||||
grub_le_to_cpu32 (sb.layout),
|
||||
level);
|
||||
}
|
||||
|
||||
static struct grub_raid grub_mdraid_dev = {
|
||||
static struct grub_diskfilter grub_mdraid_dev = {
|
||||
.name = "mdraid09",
|
||||
.detect = grub_mdraid_detect,
|
||||
.next = 0
|
||||
|
@ -239,10 +256,10 @@ static struct grub_raid grub_mdraid_dev = {
|
|||
|
||||
GRUB_MOD_INIT (mdraid09)
|
||||
{
|
||||
grub_raid_register (&grub_mdraid_dev);
|
||||
grub_diskfilter_register (&grub_mdraid_dev);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI (mdraid09)
|
||||
{
|
||||
grub_raid_unregister (&grub_mdraid_dev);
|
||||
grub_diskfilter_unregister (&grub_mdraid_dev);
|
||||
}
|
||||
|
|
|
@ -1,921 +0,0 @@
|
|||
/* raid.c - module to read RAID arrays. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/raid.h>
|
||||
#include <grub/partition.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;
|
||||
grub_raid5_recover_func_t grub_raid5_recover_func;
|
||||
grub_raid6_recover_func_t grub_raid6_recover_func;
|
||||
static grub_raid_t grub_raid_list;
|
||||
static int inscnt = 0;
|
||||
|
||||
static struct grub_raid_array *
|
||||
find_array (const char *name);
|
||||
|
||||
|
||||
static char
|
||||
grub_is_array_readable (struct grub_raid_array *array)
|
||||
{
|
||||
switch (array->level)
|
||||
{
|
||||
case 0:
|
||||
if (array->nr_devs == array->total_devs)
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (array->nr_devs >= 1)
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 10:
|
||||
{
|
||||
unsigned int n;
|
||||
|
||||
if (array->level == 10)
|
||||
{
|
||||
n = array->layout & 0xFF;
|
||||
if (n == 1)
|
||||
n = (array->layout >> 8) & 0xFF;
|
||||
|
||||
n--;
|
||||
}
|
||||
else
|
||||
n = array->level / 3;
|
||||
|
||||
if (array->nr_devs >= array->total_devs - n)
|
||||
return 1;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
|
||||
grub_disk_addr_t start_sector, const char *scanner_name,
|
||||
grub_raid_t raid __attribute__ ((unused)));
|
||||
|
||||
static int scan_depth = 0;
|
||||
|
||||
static void
|
||||
scan_devices (const char *arname)
|
||||
{
|
||||
grub_raid_t raid;
|
||||
|
||||
auto int hook (const char *name);
|
||||
int hook (const char *name)
|
||||
{
|
||||
grub_disk_t disk;
|
||||
struct grub_raid_array array;
|
||||
struct grub_raid_array *arr;
|
||||
grub_disk_addr_t start_sector;
|
||||
|
||||
grub_dprintf ("raid", "Scanning for %s RAID devices on disk %s\n",
|
||||
raid->name, name);
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("Scanning for %s RAID devices on disk %s",
|
||||
raid->name, name);
|
||||
#endif
|
||||
|
||||
disk = grub_disk_open (name);
|
||||
if (!disk)
|
||||
return 0;
|
||||
|
||||
for (arr = array_list; arr != NULL; arr = arr->next)
|
||||
{
|
||||
struct grub_raid_member *m;
|
||||
for (m = arr->members; m < arr->members + arr->nr_devs; m++)
|
||||
if (m->device && m->device->id == disk->id
|
||||
&& m->device->dev->id == disk->dev->id
|
||||
&& grub_partition_get_start (m->device->partition)
|
||||
== grub_partition_get_start (disk->partition)
|
||||
&& grub_disk_get_size (m->device)
|
||||
== grub_disk_get_size (disk))
|
||||
{
|
||||
grub_disk_close (disk);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((! raid->detect (disk, &array, &start_sector)) &&
|
||||
(! insert_array (disk, &array, start_sector, raid->name,
|
||||
raid)))
|
||||
return 0;
|
||||
|
||||
/* This error usually means it's not raid, no need to display
|
||||
it. */
|
||||
if (grub_errno != GRUB_ERR_OUT_OF_RANGE)
|
||||
grub_print_error ();
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
grub_disk_close (disk);
|
||||
|
||||
if (arname && find_array (arname))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (scan_depth)
|
||||
return;
|
||||
|
||||
scan_depth++;
|
||||
for (raid = grub_raid_list; raid; raid = raid->next)
|
||||
grub_device_iterate (&hook);
|
||||
scan_depth--;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_raid_iterate (int (*hook) (const char *name),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
struct grub_raid_array *array;
|
||||
int islcnt = 0;
|
||||
|
||||
if (pull == GRUB_DISK_PULL_RESCAN)
|
||||
{
|
||||
islcnt = inscnt;
|
||||
scan_devices (NULL);
|
||||
}
|
||||
|
||||
if (pull != GRUB_DISK_PULL_NONE && pull != GRUB_DISK_PULL_RESCAN)
|
||||
return 0;
|
||||
|
||||
for (array = array_list; array != NULL; array = array->next)
|
||||
{
|
||||
if (grub_is_array_readable (array) && array->became_readable_at >= islcnt)
|
||||
if (hook (array->name))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
static grub_disk_memberlist_t
|
||||
grub_raid_memberlist (grub_disk_t disk)
|
||||
{
|
||||
struct grub_raid_array *array = disk->data;
|
||||
grub_disk_memberlist_t list = NULL, tmp;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < array->total_devs; i++)
|
||||
if (array->members[i].device)
|
||||
{
|
||||
tmp = grub_malloc (sizeof (*tmp));
|
||||
tmp->disk = array->members[i].device;
|
||||
tmp->next = list;
|
||||
list = tmp;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static const char *
|
||||
grub_raid_getname (struct grub_disk *disk)
|
||||
{
|
||||
struct grub_raid_array *array = disk->data;
|
||||
|
||||
return array->driver->name;
|
||||
}
|
||||
#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 struct grub_raid_array *
|
||||
find_array (const char *name)
|
||||
{
|
||||
struct grub_raid_array *array;
|
||||
|
||||
if (grub_memcmp (name, "mduuid/", sizeof ("mduuid/") - 1) == 0)
|
||||
{
|
||||
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))
|
||||
return array;
|
||||
}
|
||||
}
|
||||
else
|
||||
for (array = array_list; array != NULL; array = array->next)
|
||||
{
|
||||
if (!grub_strcmp (array->name, name))
|
||||
if (grub_is_array_readable (array))
|
||||
return array;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_raid_open (const char *name, grub_disk_t disk)
|
||||
{
|
||||
struct grub_raid_array *array;
|
||||
unsigned n;
|
||||
|
||||
if (grub_memcmp (name, "md", sizeof ("md") - 1) != 0)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
|
||||
name);
|
||||
|
||||
array = find_array (name);
|
||||
|
||||
if (! array)
|
||||
{
|
||||
scan_devices (name);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
array = find_array (name);
|
||||
}
|
||||
|
||||
if (!array)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
|
||||
name);
|
||||
|
||||
disk->id = array->number;
|
||||
disk->data = array;
|
||||
|
||||
grub_dprintf ("raid", "%s: total_devs=%d, disk_size=%lld\n", name,
|
||||
array->total_devs, (unsigned long long) array->disk_size);
|
||||
|
||||
switch (array->level)
|
||||
{
|
||||
case 1:
|
||||
disk->total_sectors = array->disk_size;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
n = array->layout & 0xFF;
|
||||
if (n == 1)
|
||||
n = (array->layout >> 8) & 0xFF;
|
||||
|
||||
disk->total_sectors = grub_divmod64 (array->total_devs *
|
||||
array->disk_size,
|
||||
n, 0);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
n = array->level / 3;
|
||||
|
||||
disk->total_sectors = (array->total_devs - n) * array->disk_size;
|
||||
break;
|
||||
}
|
||||
|
||||
grub_dprintf ("raid", "%s: level=%d, total_sectors=%lld\n", name,
|
||||
array->level, (unsigned long long) disk->total_sectors);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_raid_close (grub_disk_t disk __attribute ((unused)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector,
|
||||
grub_size_t size, char *buf)
|
||||
{
|
||||
struct grub_raid_array *array = disk->data;
|
||||
grub_err_t err = 0;
|
||||
|
||||
switch (array->level)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 10:
|
||||
{
|
||||
grub_disk_addr_t read_sector, far_ofs;
|
||||
grub_uint64_t disknr, b, near, far, ofs;
|
||||
|
||||
read_sector = grub_divmod64 (sector, array->chunk_size, &b);
|
||||
far = ofs = near = 1;
|
||||
far_ofs = 0;
|
||||
|
||||
if (array->level == 1)
|
||||
near = array->total_devs;
|
||||
else if (array->level == 10)
|
||||
{
|
||||
near = array->layout & 0xFF;
|
||||
far = (array->layout >> 8) & 0xFF;
|
||||
if (array->layout >> 16)
|
||||
{
|
||||
ofs = far;
|
||||
far_ofs = 1;
|
||||
}
|
||||
else
|
||||
far_ofs = grub_divmod64 (array->disk_size,
|
||||
far * array->chunk_size, 0);
|
||||
|
||||
far_ofs *= array->chunk_size;
|
||||
}
|
||||
|
||||
read_sector = grub_divmod64 (read_sector * near, array->total_devs,
|
||||
&disknr);
|
||||
|
||||
ofs *= array->chunk_size;
|
||||
read_sector *= ofs;
|
||||
|
||||
while (1)
|
||||
{
|
||||
grub_size_t read_size;
|
||||
unsigned int i, j;
|
||||
|
||||
read_size = array->chunk_size - b;
|
||||
if (read_size > size)
|
||||
read_size = size;
|
||||
|
||||
for (i = 0; i < near; i++)
|
||||
{
|
||||
unsigned int k;
|
||||
|
||||
k = disknr;
|
||||
for (j = 0; j < far; j++)
|
||||
{
|
||||
if (array->members[k].device)
|
||||
{
|
||||
if (grub_errno == GRUB_ERR_READ_ERROR)
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
err = grub_disk_read (array->members[k].device,
|
||||
array->members[k].start_sector +
|
||||
read_sector + j * far_ofs + b,
|
||||
0,
|
||||
read_size << GRUB_DISK_SECTOR_BITS,
|
||||
buf);
|
||||
if (! err)
|
||||
break;
|
||||
else if (err != GRUB_ERR_READ_ERROR)
|
||||
return err;
|
||||
}
|
||||
else
|
||||
err = grub_error (GRUB_ERR_READ_ERROR,
|
||||
"disk missing");
|
||||
|
||||
k++;
|
||||
if (k == array->total_devs)
|
||||
k = 0;
|
||||
}
|
||||
|
||||
if (! err)
|
||||
break;
|
||||
|
||||
disknr++;
|
||||
if (disknr == array->total_devs)
|
||||
{
|
||||
disknr = 0;
|
||||
read_sector += ofs;
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
buf += read_size << GRUB_DISK_SECTOR_BITS;
|
||||
size -= read_size;
|
||||
if (! size)
|
||||
break;
|
||||
|
||||
b = 0;
|
||||
disknr += (near - i);
|
||||
while (disknr >= array->total_devs)
|
||||
{
|
||||
disknr -= array->total_devs;
|
||||
read_sector += ofs;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
{
|
||||
grub_disk_addr_t read_sector;
|
||||
grub_uint64_t b, p, n, disknr, e;
|
||||
|
||||
/* n = 1 for level 4 and 5, 2 for level 6. */
|
||||
n = array->level / 3;
|
||||
|
||||
/* Find the first sector to read. */
|
||||
read_sector = grub_divmod64 (sector, array->chunk_size, &b);
|
||||
read_sector = grub_divmod64 (read_sector, array->total_devs - n,
|
||||
&disknr);
|
||||
if (array->level >= 5)
|
||||
{
|
||||
grub_divmod64 (read_sector, array->total_devs, &p);
|
||||
|
||||
if (! (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK))
|
||||
p = array->total_devs - 1 - p;
|
||||
|
||||
if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
|
||||
{
|
||||
disknr += p + n;
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_uint32_t q;
|
||||
|
||||
q = p + (n - 1);
|
||||
if (q >= array->total_devs)
|
||||
q -= array->total_devs;
|
||||
|
||||
if (disknr >= p)
|
||||
disknr += n;
|
||||
else if (disknr >= q)
|
||||
disknr += q + 1;
|
||||
}
|
||||
|
||||
if (disknr >= array->total_devs)
|
||||
disknr -= array->total_devs;
|
||||
}
|
||||
else
|
||||
p = array->total_devs - n;
|
||||
|
||||
read_sector *= array->chunk_size;
|
||||
|
||||
while (1)
|
||||
{
|
||||
grub_size_t read_size;
|
||||
int next_level;
|
||||
|
||||
read_size = array->chunk_size - b;
|
||||
if (read_size > size)
|
||||
read_size = size;
|
||||
|
||||
e = 0;
|
||||
if (array->members[disknr].device)
|
||||
{
|
||||
/* Reset read error. */
|
||||
if (grub_errno == GRUB_ERR_READ_ERROR)
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
err = grub_disk_read (array->members[disknr].device,
|
||||
array->members[disknr].start_sector +
|
||||
read_sector + b, 0,
|
||||
read_size << GRUB_DISK_SECTOR_BITS,
|
||||
buf);
|
||||
|
||||
if ((err) && (err != GRUB_ERR_READ_ERROR))
|
||||
break;
|
||||
e++;
|
||||
}
|
||||
else
|
||||
err = GRUB_ERR_READ_ERROR;
|
||||
|
||||
if (err)
|
||||
{
|
||||
if (array->nr_devs < array->total_devs - n + e)
|
||||
break;
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
if (array->level == 6)
|
||||
{
|
||||
err = ((grub_raid6_recover_func) ?
|
||||
(*grub_raid6_recover_func) (array, disknr, p,
|
||||
buf, read_sector + b,
|
||||
read_size) :
|
||||
grub_error (GRUB_ERR_BAD_DEVICE,
|
||||
"raid6rec is not loaded"));
|
||||
}
|
||||
else
|
||||
{
|
||||
err = ((grub_raid5_recover_func) ?
|
||||
(*grub_raid5_recover_func) (array, disknr,
|
||||
buf, read_sector + b,
|
||||
read_size) :
|
||||
grub_error (GRUB_ERR_BAD_DEVICE,
|
||||
"raid5rec is not loaded"));
|
||||
}
|
||||
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
buf += read_size << GRUB_DISK_SECTOR_BITS;
|
||||
size -= read_size;
|
||||
if (! size)
|
||||
break;
|
||||
|
||||
b = 0;
|
||||
disknr++;
|
||||
|
||||
if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
|
||||
{
|
||||
if (disknr == array->total_devs)
|
||||
disknr = 0;
|
||||
|
||||
next_level = (disknr == p);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (disknr == p)
|
||||
disknr += n;
|
||||
|
||||
next_level = (disknr >= array->total_devs);
|
||||
}
|
||||
|
||||
if (next_level)
|
||||
{
|
||||
read_sector += array->chunk_size;
|
||||
|
||||
if (array->level >= 5)
|
||||
{
|
||||
if (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK)
|
||||
p = (p == array->total_devs - 1) ? 0 : p + 1;
|
||||
else
|
||||
p = (p == 0) ? array->total_devs - 1 : p - 1;
|
||||
|
||||
if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
|
||||
{
|
||||
disknr = p + n;
|
||||
if (disknr >= array->total_devs)
|
||||
disknr -= array->total_devs;
|
||||
}
|
||||
else
|
||||
{
|
||||
disknr -= array->total_devs;
|
||||
if (disknr == p)
|
||||
disknr += n;
|
||||
}
|
||||
}
|
||||
else
|
||||
disknr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_raid_write (grub_disk_t disk __attribute ((unused)),
|
||||
grub_disk_addr_t sector __attribute ((unused)),
|
||||
grub_size_t size __attribute ((unused)),
|
||||
const char *buf __attribute ((unused)))
|
||||
{
|
||||
return GRUB_ERR_NOT_IMPLEMENTED_YET;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
|
||||
grub_disk_addr_t start_sector, const char *scanner_name,
|
||||
grub_raid_t raid __attribute__ ((unused)))
|
||||
{
|
||||
struct grub_raid_array *array = 0, *p;
|
||||
int was_readable = 0;
|
||||
|
||||
/* See whether the device is part of an array we have already seen a
|
||||
device from. */
|
||||
for (p = array_list; p != NULL; p = p->next)
|
||||
if ((p->uuid_len == new_array->uuid_len) &&
|
||||
(! grub_memcmp (p->uuid, new_array->uuid, p->uuid_len)))
|
||||
{
|
||||
grub_free (new_array->uuid);
|
||||
array = p;
|
||||
|
||||
was_readable = grub_is_array_readable (array);
|
||||
|
||||
/* Do some checks before adding the device to the array. */
|
||||
|
||||
if (new_array->index >= array->allocated_devs)
|
||||
{
|
||||
void *tmp;
|
||||
unsigned int newnum = 2 * (new_array->index + 1);
|
||||
tmp = grub_realloc (array->members, newnum
|
||||
* sizeof (array->members[0]));
|
||||
if (!tmp)
|
||||
return grub_errno;
|
||||
array->members = tmp;
|
||||
grub_memset (array->members + array->allocated_devs,
|
||||
0, (newnum - array->allocated_devs)
|
||||
* sizeof (array->members[0]));
|
||||
array->allocated_devs = newnum;
|
||||
}
|
||||
|
||||
/* FIXME: Check whether the update time of the superblocks are
|
||||
the same. */
|
||||
|
||||
if (array->total_devs == array->nr_devs)
|
||||
/* We found more members of the array than the array
|
||||
actually has according to its superblock. This shouldn't
|
||||
happen normally. */
|
||||
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. */
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add an array to the list if we didn't find any. */
|
||||
if (!array)
|
||||
{
|
||||
array = grub_malloc (sizeof (*array));
|
||||
if (!array)
|
||||
{
|
||||
grub_free (new_array->uuid);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
*array = *new_array;
|
||||
array->nr_devs = 0;
|
||||
#ifdef GRUB_UTIL
|
||||
array->driver = raid;
|
||||
#endif
|
||||
array->allocated_devs = 32;
|
||||
if (new_array->index >= array->allocated_devs)
|
||||
array->allocated_devs = 2 * (new_array->index + 1);
|
||||
|
||||
array->members = grub_zalloc (array->allocated_devs
|
||||
* sizeof (array->members[0]));
|
||||
|
||||
if (!array->members)
|
||||
{
|
||||
grub_free (new_array->uuid);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
if (! array->name)
|
||||
{
|
||||
for (p = array_list; p != NULL; p = p->next)
|
||||
{
|
||||
if (p->number == array->number)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (array->name || p)
|
||||
{
|
||||
/* The number is already in use, so we need to find a new one.
|
||||
(Or, in the case of named arrays, the array doesn't have its
|
||||
own number, but we need one that doesn't clash for use as a key
|
||||
in the disk cache. */
|
||||
int i = array->name ? 0x40000000 : 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
for (p = array_list; p != NULL; p = p->next)
|
||||
{
|
||||
if (p->number == i)
|
||||
break;
|
||||
}
|
||||
|
||||
if (! p)
|
||||
{
|
||||
/* We found an unused number. */
|
||||
array->number = i;
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* mdraid 1.x superblocks have only a name stored not a number.
|
||||
Use it directly as GRUB device. */
|
||||
if (! array->name)
|
||||
{
|
||||
array->name = grub_xasprintf ("md%d", array->number);
|
||||
if (! array->name)
|
||||
{
|
||||
grub_free (array->members);
|
||||
grub_free (array->uuid);
|
||||
grub_free (array);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Strip off the homehost if present. */
|
||||
char *colon = grub_strchr (array->name, ':');
|
||||
char *new_name = grub_xasprintf ("md/%s",
|
||||
colon ? colon + 1 : array->name);
|
||||
|
||||
if (! new_name)
|
||||
{
|
||||
grub_free (array->members);
|
||||
grub_free (array->uuid);
|
||||
grub_free (array);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
grub_free (array->name);
|
||||
array->name = new_name;
|
||||
}
|
||||
|
||||
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;
|
||||
array_list = array;
|
||||
|
||||
/* RAID 1 doesn't use a chunksize but code assumes one so set
|
||||
one. */
|
||||
if (array->level == 1)
|
||||
array->chunk_size = 64;
|
||||
}
|
||||
|
||||
/* Add the device to the array. */
|
||||
array->members[new_array->index].device = disk;
|
||||
array->members[new_array->index].start_sector = start_sector;
|
||||
array->nr_devs++;
|
||||
if (!was_readable && grub_is_array_readable (array))
|
||||
array->became_readable_at = inscnt++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
free_array (void)
|
||||
{
|
||||
struct grub_raid_array *array;
|
||||
|
||||
array = array_list;
|
||||
while (array)
|
||||
{
|
||||
struct grub_raid_array *p;
|
||||
unsigned int i;
|
||||
|
||||
p = array;
|
||||
array = array->next;
|
||||
|
||||
for (i = 0; i < p->allocated_devs; i++)
|
||||
if (p->members[i].device)
|
||||
grub_disk_close (p->members[i].device);
|
||||
grub_free (p->members);
|
||||
|
||||
grub_free (p->uuid);
|
||||
grub_free (p->name);
|
||||
grub_free (p);
|
||||
}
|
||||
|
||||
array_list = 0;
|
||||
}
|
||||
|
||||
void
|
||||
grub_raid_register (grub_raid_t raid)
|
||||
{
|
||||
raid->next = grub_raid_list;
|
||||
grub_raid_list = raid;
|
||||
}
|
||||
|
||||
void
|
||||
grub_raid_unregister (grub_raid_t raid)
|
||||
{
|
||||
grub_raid_t *p, q;
|
||||
|
||||
for (p = &grub_raid_list, q = *p; q; p = &(q->next), q = q->next)
|
||||
if (q == raid)
|
||||
{
|
||||
*p = q->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct grub_disk_dev grub_raid_dev =
|
||||
{
|
||||
.name = "raid",
|
||||
.id = GRUB_DISK_DEVICE_RAID_ID,
|
||||
.iterate = grub_raid_iterate,
|
||||
.open = grub_raid_open,
|
||||
.close = grub_raid_close,
|
||||
.read = grub_raid_read,
|
||||
.write = grub_raid_write,
|
||||
#ifdef GRUB_UTIL
|
||||
.memberlist = grub_raid_memberlist,
|
||||
.raidname = grub_raid_getname,
|
||||
#endif
|
||||
.next = 0
|
||||
};
|
||||
|
||||
|
||||
GRUB_MOD_INIT(raid)
|
||||
{
|
||||
grub_disk_dev_register (&grub_raid_dev);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(raid)
|
||||
{
|
||||
grub_disk_dev_unregister (&grub_raid_dev);
|
||||
free_array ();
|
||||
}
|
|
@ -22,13 +22,13 @@
|
|||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/raid.h>
|
||||
#include <grub/diskfilter.h>
|
||||
#include <grub/crypto.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static grub_err_t
|
||||
grub_raid5_recover (struct grub_raid_array *array, int disknr,
|
||||
grub_raid5_recover (struct grub_diskfilter_segment *array, int disknr,
|
||||
char *buf, grub_disk_addr_t sector, int size)
|
||||
{
|
||||
char *buf2;
|
||||
|
@ -41,16 +41,15 @@ grub_raid5_recover (struct grub_raid_array *array, int disknr,
|
|||
|
||||
grub_memset (buf, 0, size);
|
||||
|
||||
for (i = 0; i < (int) array->total_devs; i++)
|
||||
for (i = 0; i < (int) array->node_count; i++)
|
||||
{
|
||||
grub_err_t err;
|
||||
|
||||
if (i == disknr)
|
||||
continue;
|
||||
|
||||
err = grub_disk_read (array->members[i].device,
|
||||
array->members[i].start_sector + sector,
|
||||
0, size, buf2);
|
||||
err = grub_diskfilter_read_node (&array->nodes[i], sector,
|
||||
size >> GRUB_DISK_SECTOR_BITS, buf2);
|
||||
|
||||
if (err)
|
||||
{
|
||||
|
@ -58,7 +57,7 @@ grub_raid5_recover (struct grub_raid_array *array, int disknr,
|
|||
return err;
|
||||
}
|
||||
|
||||
grub_crypto_xor (buf, buf2, buf2, size);
|
||||
grub_crypto_xor (buf, buf, buf2, size);
|
||||
}
|
||||
|
||||
grub_free (buf2);
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/raid.h>
|
||||
#include <grub/diskfilter.h>
|
||||
#include <grub/crypto.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
@ -64,7 +64,7 @@ grub_raid6_init_table (void)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
|
||||
grub_raid6_recover (struct grub_diskfilter_segment *array, int disknr, int p,
|
||||
char *buf, grub_disk_addr_t sector, int size)
|
||||
{
|
||||
int i, q, pos;
|
||||
|
@ -81,26 +81,29 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
|
|||
goto quit;
|
||||
|
||||
q = p + 1;
|
||||
if (q == (int) array->total_devs)
|
||||
if (q == (int) array->node_count)
|
||||
q = 0;
|
||||
|
||||
pos = q + 1;
|
||||
if (pos == (int) array->total_devs)
|
||||
if (pos == (int) array->node_count)
|
||||
pos = 0;
|
||||
|
||||
for (i = 0; i < (int) array->total_devs - 2; i++)
|
||||
for (i = 0; i < (int) array->node_count - 2; i++)
|
||||
{
|
||||
int c;
|
||||
if (array->layout & GRUB_RAID_LAYOUT_MUL_FROM_POS)
|
||||
c = pos;
|
||||
else
|
||||
c = i;
|
||||
if (pos == disknr)
|
||||
bad1 = i;
|
||||
bad1 = c;
|
||||
else
|
||||
{
|
||||
if ((array->members[pos].device) &&
|
||||
(! grub_disk_read (array->members[pos].device,
|
||||
array->members[pos].start_sector + sector,
|
||||
0, size, buf)))
|
||||
if (! grub_diskfilter_read_node (&array->nodes[pos], sector,
|
||||
size >> GRUB_DISK_SECTOR_BITS, buf))
|
||||
{
|
||||
grub_crypto_xor (pbuf, pbuf, buf, size);
|
||||
grub_raid_block_mulx (i, buf, size);
|
||||
grub_raid_block_mulx (c, buf, size);
|
||||
grub_crypto_xor (qbuf, qbuf, buf, size);
|
||||
}
|
||||
else
|
||||
|
@ -109,13 +112,13 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
|
|||
if (bad2 >= 0)
|
||||
goto quit;
|
||||
|
||||
bad2 = i;
|
||||
bad2 = c;
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
pos++;
|
||||
if (pos == (int) array->total_devs)
|
||||
if (pos == (int) array->node_count)
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
|
@ -126,24 +129,16 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
|
|||
if (bad2 < 0)
|
||||
{
|
||||
/* One bad device */
|
||||
if ((array->members[p].device) &&
|
||||
(! grub_disk_read (array->members[p].device,
|
||||
array->members[p].start_sector + sector,
|
||||
0, size, buf)))
|
||||
if ((! grub_diskfilter_read_node (&array->nodes[p], sector,
|
||||
size >> GRUB_DISK_SECTOR_BITS, buf)))
|
||||
{
|
||||
grub_crypto_xor (buf, buf, pbuf, size);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (! array->members[q].device)
|
||||
{
|
||||
grub_error (GRUB_ERR_READ_ERROR, "not enough disk to restore");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
if (grub_disk_read (array->members[q].device,
|
||||
array->members[q].start_sector + sector, 0, size, buf))
|
||||
if (grub_diskfilter_read_node (&array->nodes[q], sector,
|
||||
size >> GRUB_DISK_SECTOR_BITS, buf))
|
||||
goto quit;
|
||||
|
||||
grub_crypto_xor (buf, buf, qbuf, size);
|
||||
|
@ -155,22 +150,14 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
|
|||
/* Two bad devices */
|
||||
int c;
|
||||
|
||||
if ((! array->members[p].device) || (! array->members[q].device))
|
||||
{
|
||||
grub_error (GRUB_ERR_READ_ERROR, "not enough disk to restore");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (grub_disk_read (array->members[p].device,
|
||||
array->members[p].start_sector + sector,
|
||||
0, size, buf))
|
||||
if (grub_diskfilter_read_node (&array->nodes[p], sector,
|
||||
size >> GRUB_DISK_SECTOR_BITS, buf))
|
||||
goto quit;
|
||||
|
||||
grub_crypto_xor (pbuf, pbuf, buf, size);
|
||||
|
||||
if (grub_disk_read (array->members[q].device,
|
||||
array->members[q].start_sector + sector,
|
||||
0, size, buf))
|
||||
if (grub_diskfilter_read_node (&array->nodes[q], sector,
|
||||
size >> GRUB_DISK_SECTOR_BITS, buf))
|
||||
goto quit;
|
||||
|
||||
grub_crypto_xor (qbuf, qbuf, buf, size);
|
||||
|
|
|
@ -177,7 +177,7 @@ grub_disk_cache_store (unsigned long dev_id, unsigned long disk_id,
|
|||
|
||||
|
||||
|
||||
static grub_disk_dev_t grub_disk_dev_list;
|
||||
grub_disk_dev_t grub_disk_dev_list;
|
||||
|
||||
void
|
||||
grub_disk_dev_register (grub_disk_dev_t dev)
|
||||
|
@ -199,20 +199,6 @@ grub_disk_dev_unregister (grub_disk_dev_t dev)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
grub_disk_dev_iterate (int (*hook) (const char *name))
|
||||
{
|
||||
grub_disk_dev_t p;
|
||||
grub_disk_pull_t pull;
|
||||
|
||||
for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
|
||||
for (p = grub_disk_dev_list; p; p = p->next)
|
||||
if (p->iterate && (p->iterate) (hook, pull))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the location of the first ',', if any, which is not
|
||||
escaped by a '\'. */
|
||||
static const char *
|
||||
|
|
|
@ -72,8 +72,8 @@ grub_emu_post_init (void)
|
|||
grub_lvm_fini ();
|
||||
grub_mdraid09_fini ();
|
||||
grub_mdraid1x_fini ();
|
||||
grub_raid_fini ();
|
||||
grub_raid_init ();
|
||||
grub_diskfilter_fini ();
|
||||
grub_diskfilter_init ();
|
||||
grub_mdraid09_init ();
|
||||
grub_mdraid1x_init ();
|
||||
grub_lvm_init ();
|
||||
|
|
|
@ -68,26 +68,12 @@ struct hd_geometry
|
|||
# ifndef BLKGETSIZE64
|
||||
# define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */
|
||||
# endif /* ! BLKGETSIZE64 */
|
||||
# ifndef MAJOR
|
||||
# ifndef MINORBITS
|
||||
# define MINORBITS 8
|
||||
# endif /* ! MINORBITS */
|
||||
# define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS))
|
||||
# endif /* ! MAJOR */
|
||||
# ifndef FLOPPY_MAJOR
|
||||
# define FLOPPY_MAJOR 2
|
||||
# endif /* ! FLOPPY_MAJOR */
|
||||
# ifndef LOOP_MAJOR
|
||||
# define LOOP_MAJOR 7
|
||||
# endif /* ! LOOP_MAJOR */
|
||||
#endif /* __linux__ */
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
# include <sys/ioctl.h>
|
||||
# include <cygwin/fs.h> /* BLKGETSIZE64 */
|
||||
# include <cygwin/hdreg.h> /* HDIO_GETGEO */
|
||||
# define MAJOR(dev) ((unsigned) ((dev) >> 16))
|
||||
# define FLOPPY_MAJOR 2
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
|
@ -96,8 +82,6 @@ struct hd_geometry
|
|||
# include <sys/sysctl.h>
|
||||
# include <sys/mount.h>
|
||||
#include <libgeom.h>
|
||||
# define MAJOR(dev) major(dev)
|
||||
# define FLOPPY_MAJOR 2
|
||||
#endif
|
||||
|
||||
#if defined (__sun__)
|
||||
|
@ -125,9 +109,6 @@ struct hd_geometry
|
|||
# include <util.h> /* getrawpartition */
|
||||
# endif /* HAVE_GETRAWPARTITION */
|
||||
# include <sys/fdio.h>
|
||||
# ifndef FLOPPY_MAJOR
|
||||
# define FLOPPY_MAJOR 2
|
||||
# endif /* ! FLOPPY_MAJOR */
|
||||
# ifndef RAW_FLOPPY_MAJOR
|
||||
# define RAW_FLOPPY_MAJOR 9
|
||||
# endif /* ! RAW_FLOPPY_MAJOR */
|
||||
|
@ -481,8 +462,8 @@ grub_util_follow_gpart_up (const char *name, grub_disk_addr_t *off_out, char **n
|
|||
*off_out = 0;
|
||||
}
|
||||
|
||||
static grub_disk_addr_t
|
||||
find_partition_start (const char *dev)
|
||||
grub_disk_addr_t
|
||||
grub_hostdisk_find_partition_start (const char *dev)
|
||||
{
|
||||
grub_disk_addr_t out;
|
||||
if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
|
||||
|
@ -493,8 +474,8 @@ find_partition_start (const char *dev)
|
|||
}
|
||||
|
||||
#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined (__sun__)
|
||||
static grub_disk_addr_t
|
||||
find_partition_start (const char *dev)
|
||||
grub_disk_addr_t
|
||||
grub_hostdisk_find_partition_start (const char *dev)
|
||||
{
|
||||
int fd;
|
||||
#ifdef __sun__
|
||||
|
@ -706,7 +687,7 @@ linux_find_partition (char *dev, grub_disk_addr_t sector)
|
|||
missing = 0;
|
||||
close (fd);
|
||||
|
||||
start = find_partition_start (real_dev);
|
||||
start = grub_hostdisk_find_partition_start (real_dev);
|
||||
/* We don't care about errors here. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
|
@ -761,6 +742,32 @@ grub_util_fd_seek (int fd, const char *name, grub_uint64_t off)
|
|||
}
|
||||
#endif
|
||||
|
||||
const char *
|
||||
grub_hostdisk_os_dev_to_grub_drive (const char *os_disk, int add)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (map); i++)
|
||||
if (! map[i].device)
|
||||
break;
|
||||
else if (strcmp (map[i].device, os_disk) == 0)
|
||||
return map[i].drive;
|
||||
|
||||
if (!add)
|
||||
return NULL;
|
||||
|
||||
if (i == ARRAY_SIZE (map))
|
||||
grub_util_error (_("device count exceeds limit"));
|
||||
|
||||
map[i].device = xstrdup (os_disk);
|
||||
map[i].drive = xmalloc (sizeof ("hostdisk/") + strlen (os_disk));
|
||||
strcpy (map[i].drive, "hostdisk/");
|
||||
strcpy (map[i].drive + sizeof ("hostdisk/") - 1, os_disk);
|
||||
map[i].device_map = 0;
|
||||
|
||||
return map[i].drive;
|
||||
}
|
||||
|
||||
static int
|
||||
open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
|
||||
{
|
||||
|
@ -1241,743 +1248,6 @@ grub_util_biosdisk_fini (void)
|
|||
grub_disk_dev_unregister (&grub_util_biosdisk_dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: we do not use the new partition naming scheme as dos_part does not
|
||||
* necessarily correspond to an msdos partition.
|
||||
*/
|
||||
static char *
|
||||
make_device_name (int drive, int dos_part, int bsd_part)
|
||||
{
|
||||
char *ret, *ptr, *end;
|
||||
const char *iptr;
|
||||
|
||||
ret = xmalloc (strlen (map[drive].drive) * 2
|
||||
+ sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
|
||||
end = (ret + strlen (map[drive].drive) * 2
|
||||
+ sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
|
||||
ptr = ret;
|
||||
for (iptr = map[drive].drive; *iptr; iptr++)
|
||||
{
|
||||
if (*iptr == ',')
|
||||
*ptr++ = '\\';
|
||||
*ptr++ = *iptr;
|
||||
}
|
||||
*ptr = 0;
|
||||
if (dos_part >= 0)
|
||||
snprintf (ptr, end - ptr, ",%d", dos_part + 1);
|
||||
ptr += strlen (ptr);
|
||||
if (bsd_part >= 0)
|
||||
snprintf (ptr, end - ptr, ",%d", bsd_part + 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DEVICE_MAPPER
|
||||
static int
|
||||
grub_util_get_dm_node_linear_info (const char *dev,
|
||||
int *maj, int *min)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
void *next = NULL;
|
||||
uint64_t length, start;
|
||||
char *target, *params;
|
||||
char *ptr;
|
||||
int major, minor;
|
||||
|
||||
dmt = dm_task_create(DM_DEVICE_TABLE);
|
||||
if (!dmt)
|
||||
return 0;
|
||||
|
||||
if (!dm_task_set_name(dmt, dev))
|
||||
return 0;
|
||||
dm_task_no_open_count(dmt);
|
||||
if (!dm_task_run(dmt))
|
||||
return 0;
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target, ¶ms);
|
||||
if (grub_strcmp (target, "linear") != 0)
|
||||
return 0;
|
||||
major = grub_strtoul (params, &ptr, 10);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
if (*ptr != ':')
|
||||
return 0;
|
||||
ptr++;
|
||||
minor = grub_strtoul (ptr, 0, 10);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
if (maj)
|
||||
*maj = major;
|
||||
if (min)
|
||||
*min = minor;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static char *
|
||||
convert_system_partition_to_system_disk (const char *os_dev, struct stat *st)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
char *path = xmalloc (PATH_MAX);
|
||||
if (! realpath (os_dev, path))
|
||||
return NULL;
|
||||
|
||||
if (strncmp ("/dev/", path, 5) == 0)
|
||||
{
|
||||
char *p = path + 5;
|
||||
|
||||
/* If this is an IDE disk. */
|
||||
if (strncmp ("ide/", p, 4) == 0)
|
||||
{
|
||||
p = strstr (p, "part");
|
||||
if (p)
|
||||
strcpy (p, "disc");
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is a SCSI disk. */
|
||||
if (strncmp ("scsi/", p, 5) == 0)
|
||||
{
|
||||
p = strstr (p, "part");
|
||||
if (p)
|
||||
strcpy (p, "disc");
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is a DAC960 disk. */
|
||||
if (strncmp ("rd/c", p, 4) == 0)
|
||||
{
|
||||
/* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
|
||||
p = strchr (p, 'p');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is a Mylex AcceleRAID Array. */
|
||||
if (strncmp ("rs/c", p, 4) == 0)
|
||||
{
|
||||
/* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
|
||||
p = strchr (p, 'p');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
return path;
|
||||
}
|
||||
/* If this is a CCISS disk. */
|
||||
if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0)
|
||||
{
|
||||
/* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
|
||||
p = strchr (p, 'p');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is a Compaq Intelligent Drive Array. */
|
||||
if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0)
|
||||
{
|
||||
/* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
|
||||
p = strchr (p, 'p');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is an I2O disk. */
|
||||
if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0)
|
||||
{
|
||||
/* /dev/i2o/hd[a-z]([0-9]+)? */
|
||||
p[sizeof ("i2o/hda") - 1] = '\0';
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is a MultiMediaCard (MMC). */
|
||||
if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0)
|
||||
{
|
||||
/* /dev/mmcblk[0-9]+(p[0-9]+)? */
|
||||
p = strchr (p, 'p');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
if (strncmp ("md", p, 2) == 0
|
||||
&& p[2] >= '0' && p[2] <= '9')
|
||||
{
|
||||
char *ptr = p + 2;
|
||||
while (*ptr >= '0' && *ptr <= '9')
|
||||
ptr++;
|
||||
*ptr = 0;
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is an IDE, SCSI or Virtio disk. */
|
||||
if (strncmp ("vdisk", p, 5) == 0
|
||||
&& p[5] >= 'a' && p[5] <= 'z')
|
||||
{
|
||||
/* /dev/vdisk[a-z][0-9]* */
|
||||
p[6] = '\0';
|
||||
return path;
|
||||
}
|
||||
if ((strncmp ("hd", p, 2) == 0
|
||||
|| strncmp ("vd", p, 2) == 0
|
||||
|| strncmp ("sd", p, 2) == 0)
|
||||
&& p[2] >= 'a' && p[2] <= 'z')
|
||||
{
|
||||
char *pp = p + 2;
|
||||
while (*pp >= 'a' && *pp <= 'z')
|
||||
pp++;
|
||||
/* /dev/[hsv]d[a-z]+[0-9]* */
|
||||
*pp = '\0';
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is a Xen virtual block device. */
|
||||
if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
|
||||
{
|
||||
char *pp = p + 3;
|
||||
while (*pp >= 'a' && *pp <= 'z')
|
||||
pp++;
|
||||
/* /dev/xvd[a-z]+[0-9]* */
|
||||
*pp = '\0';
|
||||
return path;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DEVICE_MAPPER
|
||||
/* If this is a DM-RAID device.
|
||||
Compare os_dev rather than path here, since nodes under
|
||||
/dev/mapper/ are often symlinks. */
|
||||
if ((strncmp ("/dev/mapper/", os_dev, 12) == 0))
|
||||
{
|
||||
struct dm_tree *tree;
|
||||
uint32_t maj, min;
|
||||
struct dm_tree_node *node = NULL, *child;
|
||||
void *handle;
|
||||
const char *node_uuid, *mapper_name = NULL, *child_uuid, *child_name;
|
||||
|
||||
tree = dm_tree_create ();
|
||||
if (! tree)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "dm_tree_create failed\n");
|
||||
goto devmapper_out;
|
||||
}
|
||||
|
||||
maj = major (st->st_rdev);
|
||||
min = minor (st->st_rdev);
|
||||
if (! dm_tree_add_dev (tree, maj, min))
|
||||
{
|
||||
grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n");
|
||||
goto devmapper_out;
|
||||
}
|
||||
|
||||
node = dm_tree_find_node (tree, maj, min);
|
||||
if (! node)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
|
||||
goto devmapper_out;
|
||||
}
|
||||
node_uuid = dm_tree_node_get_uuid (node);
|
||||
if (! node_uuid)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s has no DM uuid\n", path);
|
||||
node = NULL;
|
||||
goto devmapper_out;
|
||||
}
|
||||
if (strncmp (node_uuid, "LVM-", 4) == 0)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s is an LVM\n", path);
|
||||
node = NULL;
|
||||
goto devmapper_out;
|
||||
}
|
||||
if (strncmp (node_uuid, "mpath-", 6) == 0)
|
||||
{
|
||||
/* Multipath partitions have partN-mpath-* UUIDs, and are
|
||||
linear mappings so are handled by
|
||||
grub_util_get_dm_node_linear_info. Multipath disks are not
|
||||
linear mappings and must be handled specially. */
|
||||
grub_dprintf ("hostdisk", "%s is a multipath disk\n", path);
|
||||
mapper_name = dm_tree_node_get_name (node);
|
||||
goto devmapper_out;
|
||||
}
|
||||
if (strncmp (node_uuid, "DMRAID-", 7) != 0)
|
||||
{
|
||||
int major, minor;
|
||||
const char *node_name;
|
||||
grub_dprintf ("hostdisk", "%s is not DM-RAID\n", path);
|
||||
|
||||
if ((node_name = dm_tree_node_get_name (node))
|
||||
&& grub_util_get_dm_node_linear_info (node_name,
|
||||
&major, &minor))
|
||||
{
|
||||
if (tree)
|
||||
dm_tree_free (tree);
|
||||
free (path);
|
||||
char *ret = grub_find_device ("/dev",
|
||||
(major << 8) | minor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
node = NULL;
|
||||
goto devmapper_out;
|
||||
}
|
||||
|
||||
handle = NULL;
|
||||
/* Counter-intuitively, device-mapper refers to the disk-like
|
||||
device containing a DM-RAID partition device as a "child" of
|
||||
the partition device. */
|
||||
child = dm_tree_next_child (&handle, node, 0);
|
||||
if (! child)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s has no DM children\n", path);
|
||||
goto devmapper_out;
|
||||
}
|
||||
child_uuid = dm_tree_node_get_uuid (child);
|
||||
if (! child_uuid)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s child has no DM uuid\n", path);
|
||||
goto devmapper_out;
|
||||
}
|
||||
else if (strncmp (child_uuid, "DMRAID-", 7) != 0)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s child is not DM-RAID\n", path);
|
||||
goto devmapper_out;
|
||||
}
|
||||
child_name = dm_tree_node_get_name (child);
|
||||
if (! child_name)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s child has no DM name\n", path);
|
||||
goto devmapper_out;
|
||||
}
|
||||
mapper_name = child_name;
|
||||
|
||||
devmapper_out:
|
||||
if (! mapper_name && node)
|
||||
{
|
||||
/* This is a DM-RAID disk, not a partition. */
|
||||
mapper_name = dm_tree_node_get_name (node);
|
||||
if (! mapper_name)
|
||||
grub_dprintf ("hostdisk", "%s has no DM name\n", path);
|
||||
}
|
||||
if (tree)
|
||||
dm_tree_free (tree);
|
||||
free (path);
|
||||
if (mapper_name)
|
||||
return xasprintf ("/dev/mapper/%s", mapper_name);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
#endif /* HAVE_DEVICE_MAPPER */
|
||||
}
|
||||
|
||||
return path;
|
||||
|
||||
#elif defined(__GNU__)
|
||||
char *path = xstrdup (os_dev);
|
||||
if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0)
|
||||
{
|
||||
char *p = strchr (path + 7, 's');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
}
|
||||
return path;
|
||||
|
||||
#elif defined(__CYGWIN__)
|
||||
char *path = xstrdup (os_dev);
|
||||
if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z')
|
||||
path[8] = 0;
|
||||
return path;
|
||||
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
char *out, *out2;
|
||||
if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
|
||||
return xstrdup (os_dev);
|
||||
grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
|
||||
|
||||
out2 = xasprintf ("/dev/%s", out);
|
||||
free (out);
|
||||
|
||||
return out2;
|
||||
#elif defined(__APPLE__)
|
||||
char *path = xstrdup (os_dev);
|
||||
if (strncmp ("/dev/", path, 5) == 0)
|
||||
{
|
||||
char *p;
|
||||
for (p = path + 5; *p; ++p)
|
||||
if (grub_isdigit(*p))
|
||||
{
|
||||
p = strpbrk (p, "sp");
|
||||
if (p)
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
/* NetBSD uses "/dev/r[a-z]+[0-9][a-z]". */
|
||||
char *path = xstrdup (os_dev);
|
||||
if (strncmp ("/dev/r", path, sizeof("/dev/r") - 1) == 0 &&
|
||||
(path[sizeof("/dev/r") - 1] >= 'a' && path[sizeof("/dev/r") - 1] <= 'z') &&
|
||||
strncmp ("fd", path + sizeof("/dev/r") - 1, sizeof("fd") - 1) != 0) /* not a floppy device name */
|
||||
{
|
||||
char *p;
|
||||
for (p = path + sizeof("/dev/r"); *p >= 'a' && *p <= 'z'; p++);
|
||||
if (grub_isdigit(*p))
|
||||
{
|
||||
p++;
|
||||
if ((*p >= 'a' && *p <= 'z') && (*(p+1) == '\0'))
|
||||
{
|
||||
/* path matches the required regular expression and
|
||||
p points to its last character. */
|
||||
int rawpart = -1;
|
||||
# ifdef HAVE_GETRAWPARTITION
|
||||
rawpart = getrawpartition();
|
||||
# endif /* HAVE_GETRAWPARTITION */
|
||||
if (rawpart >= 0)
|
||||
*p = 'a' + rawpart;
|
||||
}
|
||||
}
|
||||
}
|
||||
return path;
|
||||
|
||||
#elif defined (__sun__)
|
||||
char *colon = grub_strrchr (os_dev, ':');
|
||||
if (grub_memcmp (os_dev, "/devices", sizeof ("/devices") - 1) == 0
|
||||
&& colon)
|
||||
{
|
||||
char *ret = xmalloc (colon - os_dev + sizeof (":q,raw"));
|
||||
grub_memcpy (ret, os_dev, colon - os_dev);
|
||||
grub_memcpy (ret + (colon - os_dev), ":q,raw", sizeof (":q,raw"));
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
return xstrdup (os_dev);
|
||||
#else
|
||||
# warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
|
||||
return xstrdup (os_dev);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__sun__)
|
||||
static int
|
||||
device_is_wholedisk (const char *os_dev)
|
||||
{
|
||||
if (grub_memcmp (os_dev, "/devices/", sizeof ("/devices/") - 1) != 0)
|
||||
return 1;
|
||||
if (grub_memcmp (os_dev + strlen (os_dev) - (sizeof (":q,raw") - 1),
|
||||
":q,raw", (sizeof (":q,raw") - 1)) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__CYGWIN__)
|
||||
static int
|
||||
device_is_wholedisk (const char *os_dev)
|
||||
{
|
||||
int len = strlen (os_dev);
|
||||
|
||||
if (os_dev[len - 1] < '0' || os_dev[len - 1] > '9')
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
/* Try to determine whether a given device name corresponds to a whole disk.
|
||||
This function should give in most cases a definite answer, but it may
|
||||
actually give an approximate one in the following sense: if the return
|
||||
value is 0 then the device name does not correspond to a whole disk. */
|
||||
static int
|
||||
device_is_wholedisk (const char *os_dev)
|
||||
{
|
||||
int len = strlen (os_dev);
|
||||
int rawpart = -1;
|
||||
|
||||
# ifdef HAVE_GETRAWPARTITION
|
||||
rawpart = getrawpartition();
|
||||
# endif /* HAVE_GETRAWPARTITION */
|
||||
if (rawpart < 0)
|
||||
return 1;
|
||||
return (os_dev[len - 1] == ('a' + rawpart));
|
||||
}
|
||||
#endif /* defined(__NetBSD__) */
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
static int
|
||||
device_is_wholedisk (const char *os_dev)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
|
||||
return 0;
|
||||
|
||||
for (p = os_dev + sizeof ("/dev/") - 1; *p; ++p)
|
||||
if (grub_isdigit (*p))
|
||||
{
|
||||
if (strchr (p, 's'))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
|
||||
|
||||
static int
|
||||
find_system_device (const char *os_dev, struct stat *st, int convert, int add)
|
||||
{
|
||||
unsigned int i;
|
||||
char *os_disk;
|
||||
|
||||
if (convert)
|
||||
os_disk = convert_system_partition_to_system_disk (os_dev, st);
|
||||
else
|
||||
os_disk = xstrdup (os_dev);
|
||||
if (! os_disk)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (map); i++)
|
||||
if (! map[i].device)
|
||||
break;
|
||||
else if (strcmp (map[i].device, os_disk) == 0)
|
||||
{
|
||||
free (os_disk);
|
||||
return i;
|
||||
}
|
||||
|
||||
if (!add)
|
||||
{
|
||||
free (os_disk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE (map))
|
||||
grub_util_error (_("device count exceeds limit"));
|
||||
|
||||
map[i].device = os_disk;
|
||||
map[i].drive = xmalloc (sizeof ("hostdisk/") + strlen (os_disk));
|
||||
strcpy (map[i].drive, "hostdisk/");
|
||||
strcpy (map[i].drive + sizeof ("hostdisk/") - 1, os_disk);
|
||||
map[i].device_map = 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int
|
||||
grub_util_biosdisk_is_present (const char *os_dev)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat (os_dev, &st) < 0)
|
||||
return 0;
|
||||
|
||||
return find_system_device (os_dev, &st, 1, 0) != -1;
|
||||
}
|
||||
|
||||
char *
|
||||
grub_util_biosdisk_get_grub_dev (const char *os_dev)
|
||||
{
|
||||
struct stat st;
|
||||
int drive;
|
||||
char *sys_disk;
|
||||
|
||||
grub_util_info ("Looking for %s", os_dev);
|
||||
|
||||
if (stat (os_dev, &st) < 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev);
|
||||
grub_util_info ("cannot stat `%s'", os_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
drive = find_system_device (os_dev, &st, 1, 1);
|
||||
if (drive < 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_UNKNOWN_DEVICE,
|
||||
"no mapping exists for `%s'", os_dev);
|
||||
grub_util_info ("no mapping exists for `%s'", os_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sys_disk = convert_system_partition_to_system_disk (os_dev, &st);
|
||||
if (grub_strcmp (os_dev, sys_disk) == 0)
|
||||
{
|
||||
free (sys_disk);
|
||||
return make_device_name (drive, -1, -1);
|
||||
}
|
||||
free (sys_disk);
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__)
|
||||
if (! S_ISCHR (st.st_mode))
|
||||
#else
|
||||
if (! S_ISBLK (st.st_mode))
|
||||
#endif
|
||||
return make_device_name (drive, -1, -1);
|
||||
|
||||
#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__sun__)
|
||||
|
||||
/* Linux counts partitions uniformly, whether a BSD partition or a DOS
|
||||
partition, so mapping them to GRUB devices is not trivial.
|
||||
Here, get the start sector of a partition by HDIO_GETGEO, and
|
||||
compare it with each partition GRUB recognizes.
|
||||
|
||||
Cygwin /dev/sdXN emulation uses Windows partition mapping. It
|
||||
does not count the extended partition and missing primary
|
||||
partitions. Use same method as on Linux here.
|
||||
|
||||
For NetBSD and FreeBSD, proceed as for Linux, except that the start
|
||||
sector is obtained from the disk label. */
|
||||
{
|
||||
char *name, *partname;
|
||||
grub_disk_t disk;
|
||||
grub_disk_addr_t start;
|
||||
auto int find_partition (grub_disk_t dsk,
|
||||
const grub_partition_t partition);
|
||||
|
||||
int find_partition (grub_disk_t dsk __attribute__ ((unused)),
|
||||
const grub_partition_t partition)
|
||||
{
|
||||
grub_disk_addr_t part_start = 0;
|
||||
grub_util_info ("Partition %d starts from %lu",
|
||||
partition->number, partition->start);
|
||||
|
||||
part_start = grub_partition_get_start (partition);
|
||||
|
||||
if (start == part_start)
|
||||
{
|
||||
partname = grub_partition_get_name (partition);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
name = make_device_name (drive, -1, -1);
|
||||
|
||||
# if !defined(HAVE_DIOCGDINFO) && !defined(__sun__)
|
||||
if (MAJOR (st.st_rdev) == FLOPPY_MAJOR)
|
||||
return name;
|
||||
# else /* defined(HAVE_DIOCGDINFO) */
|
||||
/* Since os_dev and convert_system_partition_to_system_disk (os_dev) are
|
||||
* different, we know that os_dev cannot be a floppy device. */
|
||||
# endif /* !defined(HAVE_DIOCGDINFO) */
|
||||
|
||||
start = find_partition_start (os_dev);
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
free (name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_util_info ("%s starts from %lu", os_dev, start);
|
||||
|
||||
if (start == 0 && device_is_wholedisk (os_dev))
|
||||
return name;
|
||||
|
||||
grub_util_info ("opening the device %s", name);
|
||||
disk = grub_disk_open (name);
|
||||
free (name);
|
||||
|
||||
if (! disk)
|
||||
{
|
||||
/* We already know that the partition exists. Given that we already
|
||||
checked the device map above, we can only get
|
||||
GRUB_ERR_UNKNOWN_DEVICE at this point if the disk does not exist.
|
||||
This can happen on Xen, where disk images in the host can be
|
||||
assigned to devices that have partition-like names in the guest
|
||||
but are really more like disks. */
|
||||
if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
|
||||
{
|
||||
grub_util_warn
|
||||
("disk does not exist, so falling back to partition device %s",
|
||||
os_dev);
|
||||
|
||||
drive = find_system_device (os_dev, &st, 0, 1);
|
||||
if (drive < 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_UNKNOWN_DEVICE,
|
||||
"no mapping exists for `%s'", os_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return make_device_name (drive, -1, -1);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
partname = NULL;
|
||||
grub_partition_iterate (disk, find_partition);
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_disk_close (disk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (partname == NULL)
|
||||
{
|
||||
grub_disk_close (disk);
|
||||
grub_util_info ("cannot find the partition of `%s'", os_dev);
|
||||
grub_error (GRUB_ERR_BAD_DEVICE,
|
||||
"cannot find the partition of `%s'", os_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
name = grub_xasprintf ("%s,%s", disk->name, partname);
|
||||
free (partname);
|
||||
grub_disk_close (disk);
|
||||
return name;
|
||||
}
|
||||
|
||||
#elif defined(__GNU__)
|
||||
/* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
|
||||
{
|
||||
char *p;
|
||||
int dos_part = -1;
|
||||
int bsd_part = -1;
|
||||
|
||||
p = strrchr (os_dev, 's');
|
||||
if (p)
|
||||
{
|
||||
long int n;
|
||||
char *q;
|
||||
|
||||
p++;
|
||||
n = strtol (p, &q, 10);
|
||||
if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX)
|
||||
{
|
||||
dos_part = (int) n - 1;
|
||||
|
||||
if (*q >= 'a' && *q <= 'g')
|
||||
bsd_part = *q - 'a';
|
||||
}
|
||||
}
|
||||
|
||||
return make_device_name (drive, dos_part, bsd_part);
|
||||
}
|
||||
|
||||
#else
|
||||
# warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly."
|
||||
return make_device_name (drive, -1, -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
grub_util_biosdisk_get_compatibility_hint (grub_disk_t disk)
|
||||
{
|
||||
|
@ -1989,48 +1259,8 @@ grub_util_biosdisk_get_compatibility_hint (grub_disk_t disk)
|
|||
const char *
|
||||
grub_util_biosdisk_get_osdev (grub_disk_t disk)
|
||||
{
|
||||
return map[disk->id].device;
|
||||
}
|
||||
|
||||
int
|
||||
grub_util_biosdisk_is_floppy (grub_disk_t disk)
|
||||
{
|
||||
struct stat st;
|
||||
int fd;
|
||||
|
||||
if (disk->dev != &grub_util_biosdisk_dev)
|
||||
return 0;
|
||||
|
||||
fd = open (map[disk->id].device, O_RDONLY);
|
||||
/* Shouldn't happen. */
|
||||
if (fd == -1)
|
||||
return 0;
|
||||
|
||||
/* Shouldn't happen either. */
|
||||
if (fstat (fd, &st) < 0)
|
||||
{
|
||||
close (fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close (fd);
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
#if defined(FLOPPY_MAJOR)
|
||||
if (major(st.st_rdev) == FLOPPY_MAJOR)
|
||||
#else
|
||||
/* Some kernels (e.g. kFreeBSD) don't have a static major number
|
||||
for floppies, but they still use a "fd[0-9]" pathname. */
|
||||
if (map[disk->id].device[5] == 'f'
|
||||
&& map[disk->id].device[6] == 'd'
|
||||
&& map[disk->id].device[7] >= '0'
|
||||
&& map[disk->id].device[7] <= '9')
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
return map[disk->id].device;
|
||||
}
|
||||
|
|
|
@ -45,8 +45,8 @@ static struct grub_partition_map grub_gpt_partition_map;
|
|||
|
||||
|
||||
|
||||
static grub_err_t
|
||||
gpt_partition_map_iterate (grub_disk_t disk,
|
||||
grub_err_t
|
||||
grub_gpt_partition_map_iterate (grub_disk_t disk,
|
||||
int (*hook) (grub_disk_t disk,
|
||||
const grub_partition_t partition))
|
||||
{
|
||||
|
@ -167,7 +167,7 @@ gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors,
|
|||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"GPT currently supports only PC-BIOS embedding");
|
||||
|
||||
err = gpt_partition_map_iterate (disk, find_usable_region);
|
||||
err = grub_gpt_partition_map_iterate (disk, find_usable_region);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -197,7 +197,7 @@ gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors,
|
|||
static struct grub_partition_map grub_gpt_partition_map =
|
||||
{
|
||||
.name = "gpt",
|
||||
.iterate = gpt_partition_map_iterate,
|
||||
.iterate = grub_gpt_partition_map_iterate,
|
||||
#ifdef GRUB_UTIL
|
||||
.embed = gpt_partition_map_embed
|
||||
#endif
|
||||
|
|
|
@ -32,8 +32,7 @@ enum grub_disk_dev_id
|
|||
GRUB_DISK_DEVICE_OFDISK_ID,
|
||||
GRUB_DISK_DEVICE_LOOPBACK_ID,
|
||||
GRUB_DISK_DEVICE_EFIDISK_ID,
|
||||
GRUB_DISK_DEVICE_RAID_ID,
|
||||
GRUB_DISK_DEVICE_LVM_ID,
|
||||
GRUB_DISK_DEVICE_DISKFILTER_ID,
|
||||
GRUB_DISK_DEVICE_HOST_ID,
|
||||
GRUB_DISK_DEVICE_ATA_ID,
|
||||
GRUB_DISK_DEVICE_MEMDISK_ID,
|
||||
|
@ -96,6 +95,8 @@ struct grub_disk_dev
|
|||
};
|
||||
typedef struct grub_disk_dev *grub_disk_dev_t;
|
||||
|
||||
extern grub_disk_dev_t EXPORT_VAR (grub_disk_dev_list);
|
||||
|
||||
struct grub_partition;
|
||||
|
||||
/* Disk. */
|
||||
|
@ -158,7 +159,19 @@ void grub_disk_cache_invalidate_all (void);
|
|||
|
||||
void EXPORT_FUNC(grub_disk_dev_register) (grub_disk_dev_t dev);
|
||||
void EXPORT_FUNC(grub_disk_dev_unregister) (grub_disk_dev_t dev);
|
||||
int EXPORT_FUNC(grub_disk_dev_iterate) (int (*hook) (const char *name));
|
||||
static inline int
|
||||
grub_disk_dev_iterate (int (*hook) (const char *name))
|
||||
{
|
||||
grub_disk_dev_t p;
|
||||
grub_disk_pull_t pull;
|
||||
|
||||
for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
|
||||
for (p = grub_disk_dev_list; p; p = p->next)
|
||||
if (p->iterate && (p->iterate) (hook, pull))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_disk_t EXPORT_FUNC(grub_disk_open) (const char *name);
|
||||
void EXPORT_FUNC(grub_disk_close) (grub_disk_t disk);
|
||||
|
@ -185,13 +198,15 @@ extern int EXPORT_VAR(grub_disk_firmware_is_tainted);
|
|||
|
||||
#if defined (GRUB_UTIL) || defined (GRUB_MACHINE_EMU)
|
||||
void grub_lvm_init (void);
|
||||
void grub_ldm_init (void);
|
||||
void grub_mdraid09_init (void);
|
||||
void grub_mdraid1x_init (void);
|
||||
void grub_raid_init (void);
|
||||
void grub_diskfilter_init (void);
|
||||
void grub_lvm_fini (void);
|
||||
void grub_ldm_fini (void);
|
||||
void grub_mdraid09_fini (void);
|
||||
void grub_mdraid1x_fini (void);
|
||||
void grub_raid_fini (void);
|
||||
void grub_diskfilter_fini (void);
|
||||
#endif
|
||||
|
||||
#endif /* ! GRUB_DISK_HEADER */
|
||||
|
|
191
include/grub/diskfilter.h
Normal file
191
include/grub/diskfilter.h
Normal file
|
@ -0,0 +1,191 @@
|
|||
/* diskfilter.h - On disk structures for RAID. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2006,2007,2008,2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_DISKFILTER_H
|
||||
#define GRUB_DISKFILTER_H 1
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/list.h>
|
||||
|
||||
enum
|
||||
{
|
||||
GRUB_RAID_LAYOUT_RIGHT_MASK = 1,
|
||||
GRUB_RAID_LAYOUT_SYMMETRIC_MASK = 2,
|
||||
GRUB_RAID_LAYOUT_MUL_FROM_POS = 4,
|
||||
|
||||
GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC = 0,
|
||||
GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC = GRUB_RAID_LAYOUT_RIGHT_MASK,
|
||||
GRUB_RAID_LAYOUT_LEFT_SYMMETRIC = GRUB_RAID_LAYOUT_SYMMETRIC_MASK,
|
||||
GRUB_RAID_LAYOUT_RIGHT_SYMMETRIC = (GRUB_RAID_LAYOUT_RIGHT_MASK
|
||||
| GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
|
||||
};
|
||||
|
||||
|
||||
struct grub_diskfilter_vg {
|
||||
char *uuid;
|
||||
grub_size_t uuid_len;
|
||||
/* Optional. */
|
||||
char *name;
|
||||
int extent_size;
|
||||
struct grub_diskfilter_pv *pvs;
|
||||
struct grub_diskfilter_lv *lvs;
|
||||
struct grub_diskfilter_vg *next;
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
struct grub_diskfilter *driver;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct grub_diskfilter_pv_id {
|
||||
union
|
||||
{
|
||||
char *uuid;
|
||||
int id;
|
||||
};
|
||||
grub_size_t uuidlen;
|
||||
};
|
||||
|
||||
struct grub_diskfilter_pv {
|
||||
struct grub_diskfilter_pv_id id;
|
||||
/* Optional. */
|
||||
char *name;
|
||||
grub_disk_t disk;
|
||||
grub_disk_addr_t part_start;
|
||||
grub_disk_addr_t part_size;
|
||||
grub_disk_addr_t start_sector; /* Sector number where the data area starts. */
|
||||
struct grub_diskfilter_pv *next;
|
||||
/* Optional. */
|
||||
grub_uint8_t *internal_id;
|
||||
};
|
||||
|
||||
struct grub_diskfilter_lv {
|
||||
/* Name used for disk. */
|
||||
char *fullname;
|
||||
/* Optional. */
|
||||
char *name;
|
||||
int number;
|
||||
unsigned int segment_count;
|
||||
grub_size_t segment_alloc;
|
||||
grub_uint64_t size;
|
||||
int became_readable_at;
|
||||
|
||||
int visible;
|
||||
|
||||
/* Pointer to segment_count segments. */
|
||||
struct grub_diskfilter_segment *segments;
|
||||
struct grub_diskfilter_vg *vg;
|
||||
struct grub_diskfilter_lv *next;
|
||||
|
||||
/* Optional. */
|
||||
char *internal_id;
|
||||
};
|
||||
|
||||
struct grub_diskfilter_segment {
|
||||
unsigned int start_extent;
|
||||
unsigned int extent_count;
|
||||
enum
|
||||
{
|
||||
GRUB_DISKFILTER_STRIPED = 0,
|
||||
GRUB_DISKFILTER_MIRROR = 1,
|
||||
GRUB_DISKFILTER_RAID4 = 4,
|
||||
GRUB_DISKFILTER_RAID5 = 5,
|
||||
GRUB_DISKFILTER_RAID6 = 6,
|
||||
GRUB_DISKFILTER_RAID10 = 10,
|
||||
} type;
|
||||
int layout;
|
||||
/* valid only for raid10. */
|
||||
grub_uint64_t raid_member_size;
|
||||
|
||||
unsigned int node_count;
|
||||
unsigned int node_alloc;
|
||||
struct grub_diskfilter_node *nodes;
|
||||
|
||||
unsigned int stripe_size;
|
||||
};
|
||||
|
||||
struct grub_diskfilter_node {
|
||||
grub_disk_addr_t start;
|
||||
/* Optional. */
|
||||
char *name;
|
||||
struct grub_diskfilter_pv *pv;
|
||||
struct grub_diskfilter_lv *lv;
|
||||
};
|
||||
|
||||
struct grub_diskfilter_vg *
|
||||
grub_diskfilter_get_vg_by_uuid (grub_size_t uuidlen, char *uuid);
|
||||
|
||||
struct grub_diskfilter
|
||||
{
|
||||
struct grub_diskfilter *next;
|
||||
struct grub_diskfilter **prev;
|
||||
|
||||
const char *name;
|
||||
|
||||
struct grub_diskfilter_vg * (*detect) (grub_disk_t disk,
|
||||
struct grub_diskfilter_pv_id *id,
|
||||
grub_disk_addr_t *start_sector);
|
||||
};
|
||||
typedef struct grub_diskfilter *grub_diskfilter_t;
|
||||
|
||||
extern grub_diskfilter_t grub_diskfilter_list;
|
||||
static inline void
|
||||
grub_diskfilter_register (grub_diskfilter_t diskfilter)
|
||||
{
|
||||
grub_list_push (GRUB_AS_LIST_P (&grub_diskfilter_list),
|
||||
GRUB_AS_LIST (diskfilter));
|
||||
}
|
||||
static inline void
|
||||
grub_diskfilter_unregister (grub_diskfilter_t diskfilter)
|
||||
{
|
||||
grub_list_remove (GRUB_AS_LIST (diskfilter));
|
||||
}
|
||||
|
||||
struct grub_diskfilter_vg *
|
||||
grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb,
|
||||
char *name, grub_uint64_t disk_size,
|
||||
grub_uint64_t stripe_size,
|
||||
int layout, int level);
|
||||
|
||||
typedef grub_err_t (*grub_raid5_recover_func_t) (struct grub_diskfilter_segment *array,
|
||||
int disknr, char *buf,
|
||||
grub_disk_addr_t sector,
|
||||
int size);
|
||||
|
||||
typedef grub_err_t (*grub_raid6_recover_func_t) (struct grub_diskfilter_segment *array,
|
||||
int disknr, int p, char *buf,
|
||||
grub_disk_addr_t sector,
|
||||
int size);
|
||||
|
||||
extern grub_raid5_recover_func_t grub_raid5_recover_func;
|
||||
extern grub_raid6_recover_func_t grub_raid6_recover_func;
|
||||
|
||||
grub_err_t grub_diskfilter_vg_register (struct grub_diskfilter_vg *vg);
|
||||
|
||||
grub_err_t
|
||||
grub_diskfilter_read_node (const struct grub_diskfilter_node *node,
|
||||
grub_disk_addr_t sector,
|
||||
grub_size_t size, char *buf);
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
struct grub_diskfilter_pv *
|
||||
grub_diskfilter_get_pv_from_disk (grub_disk_t disk,
|
||||
struct grub_diskfilter_vg **vg);
|
||||
#endif
|
||||
|
||||
#endif /* ! GRUB_RAID_H */
|
|
@ -21,6 +21,7 @@
|
|||
#define GRUB_BIOSDISK_MACHINE_UTIL_HEADER 1
|
||||
|
||||
#include <grub/disk.h>
|
||||
#include <grub/partition.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
void grub_util_biosdisk_init (const char *dev_map);
|
||||
|
@ -39,6 +40,21 @@ ssize_t grub_util_fd_read (int fd, char *buf, size_t len);
|
|||
grub_err_t
|
||||
grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat);
|
||||
void grub_util_cryptodisk_print_uuid (grub_disk_t disk);
|
||||
char *
|
||||
grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start);
|
||||
int
|
||||
grub_util_is_ldm (grub_disk_t disk);
|
||||
#ifdef GRUB_UTIL
|
||||
grub_err_t
|
||||
grub_util_ldm_embed (struct grub_disk *disk, unsigned int *nsectors,
|
||||
grub_embed_type_t embed_type,
|
||||
grub_disk_addr_t **sectors);
|
||||
#endif
|
||||
grub_disk_addr_t
|
||||
grub_hostdisk_find_partition_start (const char *dev);
|
||||
const char *
|
||||
grub_hostdisk_os_dev_to_grub_drive (const char *os_dev, int add);
|
||||
|
||||
#if !defined(__MINGW32__)
|
||||
grub_uint64_t
|
||||
grub_util_get_fd_sectors (int fd, unsigned *log_secsize);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#define GRUB_GPT_PARTITION_HEADER 1
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/partition.h>
|
||||
|
||||
struct grub_gpt_part_type
|
||||
{
|
||||
|
@ -36,10 +37,19 @@ typedef struct grub_gpt_part_type grub_gpt_part_type_t;
|
|||
}
|
||||
|
||||
#define GRUB_GPT_PARTITION_TYPE_BIOS_BOOT \
|
||||
{ grub_cpu_to_le32_compile_time (0x21686148), grub_cpu_to_le16_compile_time (0x6449), grub_cpu_to_le16_compile_time (0x6e6f), \
|
||||
{ grub_cpu_to_le32_compile_time (0x21686148), \
|
||||
grub_cpu_to_le16_compile_time (0x6449), \
|
||||
grub_cpu_to_le16_compile_time (0x6e6f), \
|
||||
{ 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } \
|
||||
}
|
||||
|
||||
#define GRUB_GPT_PARTITION_TYPE_LDM \
|
||||
{ grub_cpu_to_le32_compile_time (0x5808C8AAU),\
|
||||
grub_cpu_to_le16_compile_time (0x7E8F), \
|
||||
grub_cpu_to_le16_compile_time (0x42E0), \
|
||||
{ 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF, 0xB3 } \
|
||||
}
|
||||
|
||||
struct grub_gpt_header
|
||||
{
|
||||
grub_uint8_t magic[8];
|
||||
|
@ -68,4 +78,10 @@ struct grub_gpt_partentry
|
|||
char name[72];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
grub_err_t
|
||||
grub_gpt_partition_map_iterate (grub_disk_t disk,
|
||||
int (*hook) (grub_disk_t disk,
|
||||
const grub_partition_t partition));
|
||||
|
||||
|
||||
#endif /* ! GRUB_GPT_PARTITION_HEADER */
|
||||
|
|
|
@ -21,60 +21,11 @@
|
|||
#define GRUB_LVM_H 1
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/diskfilter.h>
|
||||
|
||||
/* Length of ID string, excluding terminating zero. */
|
||||
#define GRUB_LVM_ID_STRLEN 38
|
||||
|
||||
struct grub_lvm_vg {
|
||||
char id[GRUB_LVM_ID_STRLEN+1];
|
||||
char *name;
|
||||
int extent_size;
|
||||
struct grub_lvm_pv *pvs;
|
||||
struct grub_lvm_lv *lvs;
|
||||
struct grub_lvm_vg *next;
|
||||
};
|
||||
|
||||
struct grub_lvm_pv {
|
||||
char id[GRUB_LVM_ID_STRLEN+1];
|
||||
char *name;
|
||||
grub_disk_t disk;
|
||||
grub_disk_addr_t start; /* Sector number where the data area starts. */
|
||||
struct grub_lvm_pv *next;
|
||||
};
|
||||
|
||||
struct grub_lvm_lv {
|
||||
char *name;
|
||||
char *fullname;
|
||||
char *compatname;
|
||||
unsigned int number;
|
||||
unsigned int segment_count;
|
||||
grub_uint64_t size;
|
||||
|
||||
int visible;
|
||||
|
||||
struct grub_lvm_segment *segments; /* Pointer to segment_count segments. */
|
||||
struct grub_lvm_vg *vg;
|
||||
struct grub_lvm_lv *next;
|
||||
};
|
||||
|
||||
struct grub_lvm_segment {
|
||||
unsigned int start_extent;
|
||||
unsigned int extent_count;
|
||||
enum { GRUB_LVM_STRIPED, GRUB_LVM_MIRROR } type;
|
||||
|
||||
unsigned int node_count;
|
||||
struct grub_lvm_node *nodes;
|
||||
|
||||
unsigned int stripe_size;
|
||||
};
|
||||
|
||||
struct grub_lvm_node {
|
||||
grub_disk_addr_t start;
|
||||
char *name;
|
||||
struct grub_lvm_pv *pv;
|
||||
struct grub_lvm_lv *lv;
|
||||
};
|
||||
|
||||
#define GRUB_LVM_LABEL_SIZE GRUB_DISK_SECTOR_SIZE
|
||||
#define GRUB_LVM_LABEL_SCAN_SECTORS 4L
|
||||
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
/* raid.h - On disk structures for RAID. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2006,2007,2008,2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_RAID_H
|
||||
#define GRUB_RAID_H 1
|
||||
|
||||
#include <grub/types.h>
|
||||
|
||||
#define GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC 0
|
||||
#define GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC 1
|
||||
#define GRUB_RAID_LAYOUT_LEFT_SYMMETRIC 2
|
||||
#define GRUB_RAID_LAYOUT_RIGHT_SYMMETRIC 3
|
||||
|
||||
#define GRUB_RAID_LAYOUT_RIGHT_MASK 1
|
||||
#define GRUB_RAID_LAYOUT_SYMMETRIC_MASK 2
|
||||
|
||||
struct grub_raid_member
|
||||
{
|
||||
grub_disk_t device; /* Array of total_devs devices. */
|
||||
grub_disk_addr_t start_sector;
|
||||
/* Start of each device, in 512 byte sectors. */
|
||||
};
|
||||
|
||||
struct grub_raid_array
|
||||
{
|
||||
int number; /* The device number, taken from md_minor so we
|
||||
are consistent with the device name in
|
||||
Linux. */
|
||||
int became_readable_at;
|
||||
int level; /* RAID levels, only 0, 1 or 5 at the moment. */
|
||||
int layout; /* Layout for RAID 5/6. */
|
||||
unsigned int total_devs; /* Total number of devices in the array. */
|
||||
grub_size_t chunk_size; /* The size of a chunk, in 512 byte sectors. */
|
||||
grub_uint64_t disk_size; /* Size of an individual disk, in 512 byte
|
||||
sectors. */
|
||||
unsigned int index; /* Index of current device. */
|
||||
int uuid_len; /* The length of uuid. */
|
||||
char *uuid; /* The UUID of the device. */
|
||||
|
||||
/* The following field is setup by the caller. */
|
||||
char *name; /* That will be "md<number>". */
|
||||
unsigned int nr_devs; /* The number of devices we've found so far. */
|
||||
unsigned int allocated_devs;
|
||||
struct grub_raid_member *members;
|
||||
struct grub_raid_array *next;
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
struct grub_raid *driver;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct grub_raid
|
||||
{
|
||||
const char *name;
|
||||
|
||||
grub_err_t (*detect) (grub_disk_t disk, struct grub_raid_array *array,
|
||||
grub_disk_addr_t *start_sector);
|
||||
|
||||
struct grub_raid *next;
|
||||
};
|
||||
typedef struct grub_raid *grub_raid_t;
|
||||
|
||||
void grub_raid_register (grub_raid_t raid);
|
||||
void grub_raid_unregister (grub_raid_t raid);
|
||||
|
||||
void grub_raid_block_xor (char *buf1, const char *buf2, int size);
|
||||
|
||||
typedef grub_err_t (*grub_raid5_recover_func_t) (struct grub_raid_array *array,
|
||||
int disknr, char *buf,
|
||||
grub_disk_addr_t sector,
|
||||
int size);
|
||||
|
||||
typedef grub_err_t (*grub_raid6_recover_func_t) (struct grub_raid_array *array,
|
||||
int disknr, int p, char *buf,
|
||||
grub_disk_addr_t sector,
|
||||
int size);
|
||||
|
||||
extern grub_raid5_recover_func_t grub_raid5_recover_func;
|
||||
extern grub_raid6_recover_func_t grub_raid6_recover_func;
|
||||
|
||||
#endif /* ! GRUB_RAID_H */
|
832
util/getroot.c
832
util/getroot.c
|
@ -76,6 +76,71 @@
|
|||
#include <grub/emu/hostdisk.h>
|
||||
#include <grub/emu/getroot.h>
|
||||
|
||||
#ifdef __linux__
|
||||
# include <sys/ioctl.h> /* ioctl */
|
||||
# include <sys/mount.h>
|
||||
# ifndef MAJOR
|
||||
# ifndef MINORBITS
|
||||
# define MINORBITS 8
|
||||
# endif /* ! MINORBITS */
|
||||
# define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS))
|
||||
# endif /* ! MAJOR */
|
||||
# ifndef FLOPPY_MAJOR
|
||||
# define FLOPPY_MAJOR 2
|
||||
# endif /* ! FLOPPY_MAJOR */
|
||||
#endif
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
# include <sys/ioctl.h>
|
||||
# include <cygwin/fs.h> /* BLKGETSIZE64 */
|
||||
# include <cygwin/hdreg.h> /* HDIO_GETGEO */
|
||||
# define MAJOR(dev) ((unsigned) ((dev) >> 16))
|
||||
# define FLOPPY_MAJOR 2
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
# include <sys/disk.h> /* DIOCGMEDIASIZE */
|
||||
# include <sys/param.h>
|
||||
# include <sys/sysctl.h>
|
||||
# include <sys/mount.h>
|
||||
#include <libgeom.h>
|
||||
# define MAJOR(dev) major(dev)
|
||||
# define FLOPPY_MAJOR 2
|
||||
#endif
|
||||
|
||||
#if defined (__sun__)
|
||||
# include <sys/dkio.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <sys/disk.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DEVICE_MAPPER
|
||||
# include <libdevmapper.h>
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
# define HAVE_DIOCGDINFO
|
||||
# include <sys/ioctl.h>
|
||||
# include <sys/disklabel.h> /* struct disklabel */
|
||||
#else /* !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) */
|
||||
# undef HAVE_DIOCGDINFO
|
||||
#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
# ifdef HAVE_GETRAWPARTITION
|
||||
# include <util.h> /* getrawpartition */
|
||||
# endif /* HAVE_GETRAWPARTITION */
|
||||
# include <sys/fdio.h>
|
||||
# ifndef FLOPPY_MAJOR
|
||||
# define FLOPPY_MAJOR 2
|
||||
# endif /* ! FLOPPY_MAJOR */
|
||||
# ifndef RAW_FLOPPY_MAJOR
|
||||
# define RAW_FLOPPY_MAJOR 9
|
||||
# endif /* ! RAW_FLOPPY_MAJOR */
|
||||
#endif /* defined(__NetBSD__) */
|
||||
|
||||
static void
|
||||
strip_extra_slashes (char *dir)
|
||||
{
|
||||
|
@ -1164,6 +1229,773 @@ grub_util_pull_device (const char *os_dev)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_DEVICE_MAPPER
|
||||
static int
|
||||
grub_util_get_dm_node_linear_info (const char *dev,
|
||||
int *maj, int *min)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
void *next = NULL;
|
||||
uint64_t length, start;
|
||||
char *target, *params;
|
||||
char *ptr;
|
||||
int major, minor;
|
||||
|
||||
dmt = dm_task_create(DM_DEVICE_TABLE);
|
||||
if (!dmt)
|
||||
return 0;
|
||||
|
||||
if (!dm_task_set_name(dmt, dev))
|
||||
return 0;
|
||||
dm_task_no_open_count(dmt);
|
||||
if (!dm_task_run(dmt))
|
||||
return 0;
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target, ¶ms);
|
||||
if (grub_strcmp (target, "linear") != 0)
|
||||
return 0;
|
||||
major = grub_strtoul (params, &ptr, 10);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
if (*ptr != ':')
|
||||
return 0;
|
||||
ptr++;
|
||||
minor = grub_strtoul (ptr, 0, 10);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
if (maj)
|
||||
*maj = major;
|
||||
if (min)
|
||||
*min = minor;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
grub_util_biosdisk_is_floppy (grub_disk_t disk)
|
||||
{
|
||||
struct stat st;
|
||||
int fd;
|
||||
const char *dname;
|
||||
|
||||
dname = grub_util_biosdisk_get_osdev (disk);
|
||||
|
||||
if (!dname)
|
||||
return 0;
|
||||
|
||||
fd = open (dname, O_RDONLY);
|
||||
/* Shouldn't happen. */
|
||||
if (fd == -1)
|
||||
return 0;
|
||||
|
||||
/* Shouldn't happen either. */
|
||||
if (fstat (fd, &st) < 0)
|
||||
{
|
||||
close (fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close (fd);
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
#if defined(FLOPPY_MAJOR)
|
||||
if (major(st.st_rdev) == FLOPPY_MAJOR)
|
||||
#else
|
||||
/* Some kernels (e.g. kFreeBSD) don't have a static major number
|
||||
for floppies, but they still use a "fd[0-9]" pathname. */
|
||||
if (map[disk->id].device[5] == 'f'
|
||||
&& map[disk->id].device[6] == 'd'
|
||||
&& map[disk->id].device[7] >= '0'
|
||||
&& map[disk->id].device[7] <= '9')
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
convert_system_partition_to_system_disk (const char *os_dev, struct stat *st)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
char *path = xmalloc (PATH_MAX);
|
||||
if (! realpath (os_dev, path))
|
||||
return NULL;
|
||||
|
||||
if (strncmp ("/dev/", path, 5) == 0)
|
||||
{
|
||||
char *p = path + 5;
|
||||
|
||||
/* If this is an IDE disk. */
|
||||
if (strncmp ("ide/", p, 4) == 0)
|
||||
{
|
||||
p = strstr (p, "part");
|
||||
if (p)
|
||||
strcpy (p, "disc");
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is a SCSI disk. */
|
||||
if (strncmp ("scsi/", p, 5) == 0)
|
||||
{
|
||||
p = strstr (p, "part");
|
||||
if (p)
|
||||
strcpy (p, "disc");
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is a DAC960 disk. */
|
||||
if (strncmp ("rd/c", p, 4) == 0)
|
||||
{
|
||||
/* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
|
||||
p = strchr (p, 'p');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is a Mylex AcceleRAID Array. */
|
||||
if (strncmp ("rs/c", p, 4) == 0)
|
||||
{
|
||||
/* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
|
||||
p = strchr (p, 'p');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
return path;
|
||||
}
|
||||
/* If this is a CCISS disk. */
|
||||
if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0)
|
||||
{
|
||||
/* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
|
||||
p = strchr (p, 'p');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is a Compaq Intelligent Drive Array. */
|
||||
if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0)
|
||||
{
|
||||
/* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
|
||||
p = strchr (p, 'p');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is an I2O disk. */
|
||||
if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0)
|
||||
{
|
||||
/* /dev/i2o/hd[a-z]([0-9]+)? */
|
||||
p[sizeof ("i2o/hda") - 1] = '\0';
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is a MultiMediaCard (MMC). */
|
||||
if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0)
|
||||
{
|
||||
/* /dev/mmcblk[0-9]+(p[0-9]+)? */
|
||||
p = strchr (p, 'p');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
if (strncmp ("md", p, 2) == 0
|
||||
&& p[2] >= '0' && p[2] <= '9')
|
||||
{
|
||||
char *ptr = p + 2;
|
||||
while (*ptr >= '0' && *ptr <= '9')
|
||||
ptr++;
|
||||
*ptr = 0;
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is an IDE, SCSI or Virtio disk. */
|
||||
if (strncmp ("vdisk", p, 5) == 0
|
||||
&& p[5] >= 'a' && p[5] <= 'z')
|
||||
{
|
||||
/* /dev/vdisk[a-z][0-9]* */
|
||||
p[6] = '\0';
|
||||
return path;
|
||||
}
|
||||
if ((strncmp ("hd", p, 2) == 0
|
||||
|| strncmp ("vd", p, 2) == 0
|
||||
|| strncmp ("sd", p, 2) == 0)
|
||||
&& p[2] >= 'a' && p[2] <= 'z')
|
||||
{
|
||||
char *pp = p + 2;
|
||||
while (*pp >= 'a' && *pp <= 'z')
|
||||
pp++;
|
||||
/* /dev/[hsv]d[a-z]+[0-9]* */
|
||||
*pp = '\0';
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is a Xen virtual block device. */
|
||||
if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
|
||||
{
|
||||
char *pp = p + 3;
|
||||
while (*pp >= 'a' && *pp <= 'z')
|
||||
pp++;
|
||||
/* /dev/xvd[a-z]+[0-9]* */
|
||||
*pp = '\0';
|
||||
return path;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DEVICE_MAPPER
|
||||
/* If this is a DM-RAID device.
|
||||
Compare os_dev rather than path here, since nodes under
|
||||
/dev/mapper/ are often symlinks. */
|
||||
if ((strncmp ("/dev/mapper/", os_dev, 12) == 0))
|
||||
{
|
||||
struct dm_tree *tree;
|
||||
uint32_t maj, min;
|
||||
struct dm_tree_node *node = NULL, *child;
|
||||
void *handle;
|
||||
const char *node_uuid, *mapper_name = NULL, *child_uuid, *child_name;
|
||||
|
||||
tree = dm_tree_create ();
|
||||
if (! tree)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "dm_tree_create failed\n");
|
||||
goto devmapper_out;
|
||||
}
|
||||
|
||||
maj = major (st->st_rdev);
|
||||
min = minor (st->st_rdev);
|
||||
if (! dm_tree_add_dev (tree, maj, min))
|
||||
{
|
||||
grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n");
|
||||
goto devmapper_out;
|
||||
}
|
||||
|
||||
node = dm_tree_find_node (tree, maj, min);
|
||||
if (! node)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
|
||||
goto devmapper_out;
|
||||
}
|
||||
node_uuid = dm_tree_node_get_uuid (node);
|
||||
if (! node_uuid)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s has no DM uuid\n", path);
|
||||
node = NULL;
|
||||
goto devmapper_out;
|
||||
}
|
||||
if (strncmp (node_uuid, "LVM-", 4) == 0)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s is an LVM\n", path);
|
||||
node = NULL;
|
||||
goto devmapper_out;
|
||||
}
|
||||
if (strncmp (node_uuid, "mpath-", 6) == 0)
|
||||
{
|
||||
/* Multipath partitions have partN-mpath-* UUIDs, and are
|
||||
linear mappings so are handled by
|
||||
grub_util_get_dm_node_linear_info. Multipath disks are not
|
||||
linear mappings and must be handled specially. */
|
||||
grub_dprintf ("hostdisk", "%s is a multipath disk\n", path);
|
||||
mapper_name = dm_tree_node_get_name (node);
|
||||
goto devmapper_out;
|
||||
}
|
||||
if (strncmp (node_uuid, "DMRAID-", 7) != 0)
|
||||
{
|
||||
int major, minor;
|
||||
const char *node_name;
|
||||
grub_dprintf ("hostdisk", "%s is not DM-RAID\n", path);
|
||||
|
||||
if ((node_name = dm_tree_node_get_name (node))
|
||||
&& grub_util_get_dm_node_linear_info (node_name,
|
||||
&major, &minor))
|
||||
{
|
||||
if (tree)
|
||||
dm_tree_free (tree);
|
||||
free (path);
|
||||
char *ret = grub_find_device ("/dev",
|
||||
(major << 8) | minor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
node = NULL;
|
||||
goto devmapper_out;
|
||||
}
|
||||
|
||||
handle = NULL;
|
||||
/* Counter-intuitively, device-mapper refers to the disk-like
|
||||
device containing a DM-RAID partition device as a "child" of
|
||||
the partition device. */
|
||||
child = dm_tree_next_child (&handle, node, 0);
|
||||
if (! child)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s has no DM children\n", path);
|
||||
goto devmapper_out;
|
||||
}
|
||||
child_uuid = dm_tree_node_get_uuid (child);
|
||||
if (! child_uuid)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s child has no DM uuid\n", path);
|
||||
goto devmapper_out;
|
||||
}
|
||||
else if (strncmp (child_uuid, "DMRAID-", 7) != 0)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s child is not DM-RAID\n", path);
|
||||
goto devmapper_out;
|
||||
}
|
||||
child_name = dm_tree_node_get_name (child);
|
||||
if (! child_name)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s child has no DM name\n", path);
|
||||
goto devmapper_out;
|
||||
}
|
||||
mapper_name = child_name;
|
||||
|
||||
devmapper_out:
|
||||
if (! mapper_name && node)
|
||||
{
|
||||
/* This is a DM-RAID disk, not a partition. */
|
||||
mapper_name = dm_tree_node_get_name (node);
|
||||
if (! mapper_name)
|
||||
grub_dprintf ("hostdisk", "%s has no DM name\n", path);
|
||||
}
|
||||
if (tree)
|
||||
dm_tree_free (tree);
|
||||
free (path);
|
||||
if (mapper_name)
|
||||
return xasprintf ("/dev/mapper/%s", mapper_name);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
#endif /* HAVE_DEVICE_MAPPER */
|
||||
}
|
||||
|
||||
return path;
|
||||
|
||||
#elif defined(__GNU__)
|
||||
char *path = xstrdup (os_dev);
|
||||
if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0)
|
||||
{
|
||||
char *p = strchr (path + 7, 's');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
}
|
||||
return path;
|
||||
|
||||
#elif defined(__CYGWIN__)
|
||||
char *path = xstrdup (os_dev);
|
||||
if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z')
|
||||
path[8] = 0;
|
||||
return path;
|
||||
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
char *out, *out2;
|
||||
if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
|
||||
return xstrdup (os_dev);
|
||||
grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
|
||||
|
||||
out2 = xasprintf ("/dev/%s", out);
|
||||
free (out);
|
||||
|
||||
return out2;
|
||||
#elif defined(__APPLE__)
|
||||
char *path = xstrdup (os_dev);
|
||||
if (strncmp ("/dev/", path, 5) == 0)
|
||||
{
|
||||
char *p;
|
||||
for (p = path + 5; *p; ++p)
|
||||
if (grub_isdigit(*p))
|
||||
{
|
||||
p = strpbrk (p, "sp");
|
||||
if (p)
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
/* NetBSD uses "/dev/r[a-z]+[0-9][a-z]". */
|
||||
char *path = xstrdup (os_dev);
|
||||
if (strncmp ("/dev/r", path, sizeof("/dev/r") - 1) == 0 &&
|
||||
(path[sizeof("/dev/r") - 1] >= 'a' && path[sizeof("/dev/r") - 1] <= 'z') &&
|
||||
strncmp ("fd", path + sizeof("/dev/r") - 1, sizeof("fd") - 1) != 0) /* not a floppy device name */
|
||||
{
|
||||
char *p;
|
||||
for (p = path + sizeof("/dev/r"); *p >= 'a' && *p <= 'z'; p++);
|
||||
if (grub_isdigit(*p))
|
||||
{
|
||||
p++;
|
||||
if ((*p >= 'a' && *p <= 'z') && (*(p+1) == '\0'))
|
||||
{
|
||||
/* path matches the required regular expression and
|
||||
p points to its last character. */
|
||||
int rawpart = -1;
|
||||
# ifdef HAVE_GETRAWPARTITION
|
||||
rawpart = getrawpartition();
|
||||
# endif /* HAVE_GETRAWPARTITION */
|
||||
if (rawpart >= 0)
|
||||
*p = 'a' + rawpart;
|
||||
}
|
||||
}
|
||||
}
|
||||
return path;
|
||||
|
||||
#elif defined (__sun__)
|
||||
char *colon = grub_strrchr (os_dev, ':');
|
||||
if (grub_memcmp (os_dev, "/devices", sizeof ("/devices") - 1) == 0
|
||||
&& colon)
|
||||
{
|
||||
char *ret = xmalloc (colon - os_dev + sizeof (":q,raw"));
|
||||
grub_memcpy (ret, os_dev, colon - os_dev);
|
||||
grub_memcpy (ret + (colon - os_dev), ":q,raw", sizeof (":q,raw"));
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
return xstrdup (os_dev);
|
||||
#else
|
||||
# warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
|
||||
return xstrdup (os_dev);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char *
|
||||
find_system_device (const char *os_dev, struct stat *st, int convert, int add)
|
||||
{
|
||||
unsigned int i;
|
||||
char *os_disk;
|
||||
const char *drive;
|
||||
|
||||
if (convert)
|
||||
os_disk = convert_system_partition_to_system_disk (os_dev, st);
|
||||
else
|
||||
os_disk = xstrdup (os_dev);
|
||||
if (! os_disk)
|
||||
return NULL;
|
||||
|
||||
drive = grub_hostdisk_os_dev_to_grub_drive (os_disk, add);
|
||||
free (os_disk);
|
||||
return drive;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: we do not use the new partition naming scheme as dos_part does not
|
||||
* necessarily correspond to an msdos partition.
|
||||
*/
|
||||
static char *
|
||||
make_device_name (const char *drive, int dos_part, int bsd_part)
|
||||
{
|
||||
char *ret, *ptr, *end;
|
||||
const char *iptr;
|
||||
|
||||
ret = xmalloc (strlen (drive) * 2
|
||||
+ sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
|
||||
end = (ret + strlen (drive) * 2
|
||||
+ sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
|
||||
ptr = ret;
|
||||
for (iptr = drive; *iptr; iptr++)
|
||||
{
|
||||
if (*iptr == ',')
|
||||
*ptr++ = '\\';
|
||||
*ptr++ = *iptr;
|
||||
}
|
||||
*ptr = 0;
|
||||
if (dos_part >= 0)
|
||||
snprintf (ptr, end - ptr, ",%d", dos_part + 1);
|
||||
ptr += strlen (ptr);
|
||||
if (bsd_part >= 0)
|
||||
snprintf (ptr, end - ptr, ",%d", bsd_part + 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(__sun__)
|
||||
static int
|
||||
device_is_wholedisk (const char *os_dev)
|
||||
{
|
||||
if (grub_memcmp (os_dev, "/devices/", sizeof ("/devices/") - 1) != 0)
|
||||
return 1;
|
||||
if (grub_memcmp (os_dev + strlen (os_dev) - (sizeof (":q,raw") - 1),
|
||||
":q,raw", (sizeof (":q,raw") - 1)) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__CYGWIN__)
|
||||
static int
|
||||
device_is_wholedisk (const char *os_dev)
|
||||
{
|
||||
int len = strlen (os_dev);
|
||||
|
||||
if (os_dev[len - 1] < '0' || os_dev[len - 1] > '9')
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
/* Try to determine whether a given device name corresponds to a whole disk.
|
||||
This function should give in most cases a definite answer, but it may
|
||||
actually give an approximate one in the following sense: if the return
|
||||
value is 0 then the device name does not correspond to a whole disk. */
|
||||
static int
|
||||
device_is_wholedisk (const char *os_dev)
|
||||
{
|
||||
int len = strlen (os_dev);
|
||||
int rawpart = -1;
|
||||
|
||||
# ifdef HAVE_GETRAWPARTITION
|
||||
rawpart = getrawpartition();
|
||||
# endif /* HAVE_GETRAWPARTITION */
|
||||
if (rawpart < 0)
|
||||
return 1;
|
||||
return (os_dev[len - 1] == ('a' + rawpart));
|
||||
}
|
||||
#endif /* defined(__NetBSD__) */
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
static int
|
||||
device_is_wholedisk (const char *os_dev)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
|
||||
return 0;
|
||||
|
||||
for (p = os_dev + sizeof ("/dev/") - 1; *p; ++p)
|
||||
if (grub_isdigit (*p))
|
||||
{
|
||||
if (strchr (p, 's'))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
|
||||
|
||||
char *
|
||||
grub_util_biosdisk_get_grub_dev (const char *os_dev)
|
||||
{
|
||||
struct stat st;
|
||||
const char *drive;
|
||||
char *sys_disk;
|
||||
|
||||
grub_util_info ("Looking for %s", os_dev);
|
||||
|
||||
if (stat (os_dev, &st) < 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev);
|
||||
grub_util_info ("cannot stat `%s'", os_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
drive = find_system_device (os_dev, &st, 1, 1);
|
||||
if (!drive)
|
||||
{
|
||||
grub_error (GRUB_ERR_UNKNOWN_DEVICE,
|
||||
"no mapping exists for `%s'", os_dev);
|
||||
grub_util_info ("no mapping exists for `%s'", os_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sys_disk = convert_system_partition_to_system_disk (os_dev, &st);
|
||||
if (grub_strcmp (os_dev, sys_disk) == 0)
|
||||
{
|
||||
free (sys_disk);
|
||||
return make_device_name (drive, -1, -1);
|
||||
}
|
||||
free (sys_disk);
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__)
|
||||
if (! S_ISCHR (st.st_mode))
|
||||
#else
|
||||
if (! S_ISBLK (st.st_mode))
|
||||
#endif
|
||||
return make_device_name (drive, -1, -1);
|
||||
|
||||
#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__sun__)
|
||||
|
||||
/* Linux counts partitions uniformly, whether a BSD partition or a DOS
|
||||
partition, so mapping them to GRUB devices is not trivial.
|
||||
Here, get the start sector of a partition by HDIO_GETGEO, and
|
||||
compare it with each partition GRUB recognizes.
|
||||
|
||||
Cygwin /dev/sdXN emulation uses Windows partition mapping. It
|
||||
does not count the extended partition and missing primary
|
||||
partitions. Use same method as on Linux here.
|
||||
|
||||
For NetBSD and FreeBSD, proceed as for Linux, except that the start
|
||||
sector is obtained from the disk label. */
|
||||
{
|
||||
char *name, *partname;
|
||||
grub_disk_t disk;
|
||||
grub_disk_addr_t start;
|
||||
auto int find_partition (grub_disk_t dsk,
|
||||
const grub_partition_t partition);
|
||||
|
||||
int find_partition (grub_disk_t dsk __attribute__ ((unused)),
|
||||
const grub_partition_t partition)
|
||||
{
|
||||
grub_disk_addr_t part_start = 0;
|
||||
grub_util_info ("Partition %d starts from %lu",
|
||||
partition->number, partition->start);
|
||||
|
||||
part_start = grub_partition_get_start (partition);
|
||||
|
||||
if (start == part_start)
|
||||
{
|
||||
partname = grub_partition_get_name (partition);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
name = make_device_name (drive, -1, -1);
|
||||
|
||||
# if !defined(HAVE_DIOCGDINFO) && !defined(__sun__)
|
||||
if (MAJOR (st.st_rdev) == FLOPPY_MAJOR)
|
||||
return name;
|
||||
# else /* defined(HAVE_DIOCGDINFO) */
|
||||
/* Since os_dev and convert_system_partition_to_system_disk (os_dev) are
|
||||
* different, we know that os_dev cannot be a floppy device. */
|
||||
# endif /* !defined(HAVE_DIOCGDINFO) */
|
||||
|
||||
start = grub_hostdisk_find_partition_start (os_dev);
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
free (name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_util_info ("%s starts from %lu", os_dev, start);
|
||||
|
||||
if (start == 0 && device_is_wholedisk (os_dev))
|
||||
return name;
|
||||
|
||||
grub_util_info ("opening the device %s", name);
|
||||
disk = grub_disk_open (name);
|
||||
free (name);
|
||||
|
||||
if (! disk)
|
||||
{
|
||||
/* We already know that the partition exists. Given that we already
|
||||
checked the device map above, we can only get
|
||||
GRUB_ERR_UNKNOWN_DEVICE at this point if the disk does not exist.
|
||||
This can happen on Xen, where disk images in the host can be
|
||||
assigned to devices that have partition-like names in the guest
|
||||
but are really more like disks. */
|
||||
if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
|
||||
{
|
||||
grub_util_warn
|
||||
("disk does not exist, so falling back to partition device %s",
|
||||
os_dev);
|
||||
|
||||
drive = find_system_device (os_dev, &st, 0, 1);
|
||||
if (!drive)
|
||||
{
|
||||
grub_error (GRUB_ERR_UNKNOWN_DEVICE,
|
||||
"no mapping exists for `%s'", os_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return make_device_name (drive, -1, -1);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
name = grub_util_get_ldm (disk, start);
|
||||
if (name)
|
||||
return name;
|
||||
|
||||
partname = NULL;
|
||||
|
||||
grub_partition_iterate (disk, find_partition);
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_disk_close (disk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (partname == NULL)
|
||||
{
|
||||
grub_disk_close (disk);
|
||||
grub_util_info ("cannot find the partition of `%s'", os_dev);
|
||||
grub_error (GRUB_ERR_BAD_DEVICE,
|
||||
"cannot find the partition of `%s'", os_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
name = grub_xasprintf ("%s,%s", disk->name, partname);
|
||||
free (partname);
|
||||
grub_disk_close (disk);
|
||||
return name;
|
||||
}
|
||||
|
||||
#elif defined(__GNU__)
|
||||
/* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
|
||||
{
|
||||
char *p;
|
||||
int dos_part = -1;
|
||||
int bsd_part = -1;
|
||||
|
||||
p = strrchr (os_dev, 's');
|
||||
if (p)
|
||||
{
|
||||
long int n;
|
||||
char *q;
|
||||
|
||||
p++;
|
||||
n = strtol (p, &q, 10);
|
||||
if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX)
|
||||
{
|
||||
dos_part = (int) n - 1;
|
||||
|
||||
if (*q >= 'a' && *q <= 'g')
|
||||
bsd_part = *q - 'a';
|
||||
}
|
||||
}
|
||||
|
||||
return make_device_name (drive, dos_part, bsd_part);
|
||||
}
|
||||
|
||||
#else
|
||||
# warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly."
|
||||
return make_device_name (drive, -1, -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
grub_util_biosdisk_is_present (const char *os_dev)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat (os_dev, &st) < 0)
|
||||
return 0;
|
||||
|
||||
return find_system_device (os_dev, &st, 1, 0) != NULL;
|
||||
}
|
||||
|
||||
char *
|
||||
grub_util_get_grub_dev (const char *os_dev)
|
||||
{
|
||||
|
|
|
@ -344,14 +344,16 @@ fstest (int n, char **args)
|
|||
}
|
||||
}
|
||||
|
||||
grub_ldm_fini ();
|
||||
grub_lvm_fini ();
|
||||
grub_mdraid09_fini ();
|
||||
grub_mdraid1x_fini ();
|
||||
grub_raid_fini ();
|
||||
grub_raid_init ();
|
||||
grub_diskfilter_fini ();
|
||||
grub_diskfilter_init ();
|
||||
grub_mdraid09_init ();
|
||||
grub_mdraid1x_init ();
|
||||
grub_lvm_init ();
|
||||
grub_ldm_init ();
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
|
|
|
@ -364,8 +364,8 @@ fuse_init (void)
|
|||
grub_lvm_fini ();
|
||||
grub_mdraid09_fini ();
|
||||
grub_mdraid1x_fini ();
|
||||
grub_raid_fini ();
|
||||
grub_raid_init ();
|
||||
grub_diskfilter_fini ();
|
||||
grub_diskfilter_init ();
|
||||
grub_mdraid09_init ();
|
||||
grub_mdraid1x_init ();
|
||||
grub_lvm_init ();
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <grub/emu/getroot.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/raid.h>
|
||||
#include <grub/diskfilter.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/emu/misc.h>
|
||||
#include <grub/util/ofpath.h>
|
||||
|
@ -128,10 +128,15 @@ probe_raid_level (grub_disk_t disk)
|
|||
if (!disk)
|
||||
return -1;
|
||||
|
||||
if (disk->dev->id != GRUB_DISK_DEVICE_RAID_ID)
|
||||
if (disk->dev->id != GRUB_DISK_DEVICE_DISKFILTER_ID)
|
||||
return -1;
|
||||
|
||||
return ((struct grub_raid_array *) disk->data)->level;
|
||||
if (disk->name[0] != 'm' || disk->name[1] != 'd')
|
||||
return -1;
|
||||
|
||||
if (!((struct grub_diskfilter_lv *) disk->data)->segments)
|
||||
return -1;
|
||||
return ((struct grub_diskfilter_lv *) disk->data)->segments->type;
|
||||
}
|
||||
|
||||
/* Since OF path names can have "," characters in them, and GRUB
|
||||
|
@ -281,9 +286,14 @@ probe_abstraction (grub_disk_t disk)
|
|||
list = tmp;
|
||||
}
|
||||
|
||||
if (disk->dev->id == GRUB_DISK_DEVICE_LVM_ID)
|
||||
if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID
|
||||
&& grub_memcmp (disk->name, "lvm/", sizeof ("lvm/") - 1) == 0)
|
||||
printf ("lvm ");
|
||||
|
||||
if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID
|
||||
&& grub_memcmp (disk->name, "ldm/", sizeof ("ldm/") - 1) == 0)
|
||||
printf ("ldm ");
|
||||
|
||||
if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
|
||||
grub_util_cryptodisk_print_abstraction (disk);
|
||||
|
||||
|
@ -747,8 +757,8 @@ main (int argc, char *argv[])
|
|||
grub_lvm_fini ();
|
||||
grub_mdraid09_fini ();
|
||||
grub_mdraid1x_fini ();
|
||||
grub_raid_fini ();
|
||||
grub_raid_init ();
|
||||
grub_diskfilter_fini ();
|
||||
grub_diskfilter_init ();
|
||||
grub_mdraid09_init ();
|
||||
grub_mdraid1x_init ();
|
||||
grub_lvm_init ();
|
||||
|
|
|
@ -133,7 +133,7 @@ write_rootdev (char *core_img, grub_device_t root_dev,
|
|||
static void
|
||||
setup (const char *dir,
|
||||
const char *boot_file, const char *core_file,
|
||||
const char *root, const char *dest, int must_embed, int force,
|
||||
const char *root, const char *dest, int force,
|
||||
int fs_probe, int allow_floppy)
|
||||
{
|
||||
char *boot_path, *core_path, *core_path_dev, *core_path_dev_full;
|
||||
|
@ -281,6 +281,7 @@ setup (const char *dir,
|
|||
grub_partition_map_t dest_partmap = NULL;
|
||||
grub_partition_t container = dest_dev->disk->partition;
|
||||
int multiple_partmaps = 0;
|
||||
int is_ldm;
|
||||
grub_err_t err;
|
||||
grub_disk_addr_t *sectors;
|
||||
int i;
|
||||
|
@ -328,6 +329,8 @@ setup (const char *dir,
|
|||
if (!fs)
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
is_ldm = grub_util_is_ldm (dest_dev->disk);
|
||||
|
||||
#ifdef GRUB_MACHINE_PCBIOS
|
||||
if (fs_probe)
|
||||
{
|
||||
|
@ -352,6 +355,17 @@ setup (const char *dir,
|
|||
"result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
|
||||
"by grub-setup (--skip-fs-probe disables this "
|
||||
"check, use at your own risk)"), dest_dev->disk->name, dest_partmap->name);
|
||||
if (is_ldm && dest_partmap && strcmp (dest_partmap->name, "msdos") != 0
|
||||
&& strcmp (dest_partmap->name, "gpt") != 0)
|
||||
grub_util_error (_("%s appears to contain a %s partition map and "
|
||||
"LDM which isn't known to be a safe combination."
|
||||
" Installing GRUB there could "
|
||||
"result in FILESYSTEM DESTRUCTION if valuable data"
|
||||
" is overwritten "
|
||||
"by grub-setup (--skip-fs-probe disables this "
|
||||
"check, use at your own risk)"),
|
||||
dest_dev->disk->name, dest_partmap->name);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -364,14 +378,14 @@ setup (const char *dir,
|
|||
|
||||
free (tmp_img);
|
||||
|
||||
if (! dest_partmap && ! fs)
|
||||
if (! dest_partmap && ! fs && !is_ldm)
|
||||
{
|
||||
grub_util_warn (_("Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea."));
|
||||
goto unable_to_embed;
|
||||
}
|
||||
if (multiple_partmaps || (dest_partmap && fs))
|
||||
if (multiple_partmaps || (dest_partmap && fs) || (is_ldm && fs))
|
||||
{
|
||||
grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem. This is not supported yet."));
|
||||
grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels. This is not supported yet."));
|
||||
goto unable_to_embed;
|
||||
}
|
||||
|
||||
|
@ -390,7 +404,10 @@ setup (const char *dir,
|
|||
}
|
||||
|
||||
nsec = core_sectors;
|
||||
if (dest_partmap)
|
||||
if (is_ldm)
|
||||
err = grub_util_ldm_embed (dest_dev->disk, &nsec,
|
||||
GRUB_EMBED_PCBIOS, §ors);
|
||||
else if (dest_partmap)
|
||||
err = dest_partmap->embed (dest_dev->disk, &nsec,
|
||||
GRUB_EMBED_PCBIOS, §ors);
|
||||
else
|
||||
|
@ -485,14 +502,16 @@ setup (const char *dir,
|
|||
|
||||
unable_to_embed:
|
||||
|
||||
if (must_embed)
|
||||
grub_util_error (_("embedding is not possible, but this is required when "
|
||||
"the root device is on a RAID array or LVM volume"));
|
||||
|
||||
#ifdef GRUB_MACHINE_PCBIOS
|
||||
if (dest_dev->disk->id != root_dev->disk->id)
|
||||
if (dest_dev->disk->id != root_dev->disk->id
|
||||
|| dest_dev->disk->dev->id != root_dev->disk->dev->id)
|
||||
grub_util_error (_("embedding is not possible, but this is required for "
|
||||
"cross-disk install"));
|
||||
"cross-disk, RAID and LVM install"));
|
||||
#else
|
||||
if (dest_dev->disk->dev->id != root_dev->disk->dev->id)
|
||||
grub_util_error (_("embedding is not possible, but this is required for "
|
||||
"RAID and LVM install"));
|
||||
|
||||
#endif
|
||||
|
||||
grub_util_warn (_("Embedding is not possible. GRUB can only be installed in this "
|
||||
|
@ -853,7 +872,6 @@ main (int argc, char *argv[])
|
|||
{
|
||||
char *root_dev = NULL;
|
||||
char *dest_dev = NULL;
|
||||
int must_embed = 0;
|
||||
struct arguments arguments;
|
||||
|
||||
set_program_name (argv[0]);
|
||||
|
@ -888,8 +906,8 @@ main (int argc, char *argv[])
|
|||
grub_lvm_fini ();
|
||||
grub_mdraid09_fini ();
|
||||
grub_mdraid1x_fini ();
|
||||
grub_raid_fini ();
|
||||
grub_raid_init ();
|
||||
grub_diskfilter_fini ();
|
||||
grub_diskfilter_init ();
|
||||
grub_mdraid09_init ();
|
||||
grub_mdraid1x_init ();
|
||||
grub_lvm_init ();
|
||||
|
@ -944,52 +962,11 @@ main (int argc, char *argv[])
|
|||
arguments.dir ? : DEFAULT_DIRECTORY);
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
if (grub_util_lvm_isvolume (root_dev))
|
||||
must_embed = 1;
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
if (root_dev[0] == 'm' && root_dev[1] == 'd'
|
||||
&& ((root_dev[2] >= '0' && root_dev[2] <= '9') || root_dev[2] == '/'))
|
||||
{
|
||||
/* FIXME: we can avoid this on RAID1. */
|
||||
must_embed = 1;
|
||||
}
|
||||
|
||||
if (dest_dev[0] == 'm' && dest_dev[1] == 'd'
|
||||
&& ((dest_dev[2] >= '0' && dest_dev[2] <= '9') || dest_dev[2] == '/'))
|
||||
{
|
||||
char **devicelist;
|
||||
int i;
|
||||
|
||||
if (arguments.device[0] == '/')
|
||||
devicelist = grub_util_raid_getmembers (arguments.device, 1);
|
||||
else
|
||||
{
|
||||
char *devname;
|
||||
devname = xasprintf ("/dev/%s", dest_dev);
|
||||
devicelist = grub_util_raid_getmembers (dest_dev, 1);
|
||||
free (devname);
|
||||
}
|
||||
|
||||
for (i = 0; devicelist[i]; i++)
|
||||
{
|
||||
setup (arguments.dir ? : DEFAULT_DIRECTORY,
|
||||
arguments.boot_file ? : DEFAULT_BOOT_FILE,
|
||||
arguments.core_file ? : DEFAULT_CORE_FILE,
|
||||
root_dev, grub_util_get_grub_dev (devicelist[i]), 1,
|
||||
arguments.force, arguments.fs_probe,
|
||||
arguments.allow_floppy);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
/* Do the real work. */
|
||||
setup (arguments.dir ? : DEFAULT_DIRECTORY,
|
||||
arguments.boot_file ? : DEFAULT_BOOT_FILE,
|
||||
arguments.core_file ? : DEFAULT_CORE_FILE,
|
||||
root_dev, dest_dev, must_embed, arguments.force,
|
||||
root_dev, dest_dev, arguments.force,
|
||||
arguments.fs_probe, arguments.allow_floppy);
|
||||
|
||||
/* Free resources. */
|
||||
|
|
Loading…
Reference in a new issue