diff --git a/conf/common.rmk b/conf/common.rmk index 95859f7..3876ce4 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -15,7 +15,7 @@ grub_probe_SOURCES = util/grub-probe.c \ \ partmap/pc.c partmap/apple.c partmap/gpt.c \ kern/fs.c kern/env.c fs/fshelp.c \ - disk/lvm.c disk/raid.c grub_probe_init.c + disk/lvm.c disk/raid.c disk/mdraid_linux.c grub_probe_init.c ifeq ($(enable_grub_fstest), yes) bin_UTILITIES += grub-fstest @@ -35,6 +35,7 @@ grub_fstest_SOURCES = util/grub-fstest.c util/hostfs.c util/misc.c \ \ kern/partition.c partmap/pc.c partmap/apple.c partmap/gpt.c \ kern/fs.c kern/env.c fs/fshelp.c disk/lvm.c disk/raid.c \ + disk/mdraid_linux.c disk/dmraid_nvidia.c \ grub_fstest_init.c # For the parser. @@ -264,7 +265,7 @@ gpt_mod_LDFLAGS = $(COMMON_LDFLAGS) # Special disk structures -pkglib_MODULES += raid.mod lvm.mod +pkglib_MODULES += raid.mod lvm.mod mdraid.mod dm_nv.mod # For raid.mod raid_mod_SOURCES = disk/raid.c @@ -276,6 +277,16 @@ lvm_mod_SOURCES = disk/lvm.c lvm_mod_CFLAGS = $(COMMON_CFLAGS) lvm_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For mdraid.mod +mdraid_mod_SOURCES = disk/mdraid_linux.c +mdraid_mod_CFLAGS = $(COMMON_CFLAGS) +mdraid_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For dm_nv.mod +dm_nv_mod_SOURCES = disk/dmraid_nvidia.c +dm_nv_mod_CFLAGS = $(COMMON_CFLAGS) +dm_nv_mod_LDFLAGS = $(COMMON_LDFLAGS) + # Commands. pkglib_MODULES += hello.mod boot.mod terminal.mod ls.mod \ cmp.mod cat.mod help.mod font.mod search.mod \ diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index 606b99c..74808ca 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -92,7 +92,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ util/biosdisk.c util/getroot.c \ util/i386/pc/misc.c \ \ - disk/raid.c disk/lvm.c \ + disk/raid.c disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ grub_emu_init.c grub_emu_LDFLAGS = $(LIBCURSES) diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk index 2ce21b1..705e4ef 100644 --- a/conf/i386-efi.rmk +++ b/conf/i386-efi.rmk @@ -62,7 +62,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ util/biosdisk.c util/getroot.c \ util/i386/pc/misc.c \ \ - disk/raid.c disk/lvm.c \ + disk/raid.c disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ grub_emu_init.c grub_emu_LDFLAGS = $(LIBCURSES) diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index a93845e..e996865 100644 --- a/conf/i386-ieee1275.rmk +++ b/conf/i386-ieee1275.rmk @@ -90,7 +90,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ util/biosdisk.c util/getroot.c \ util/i386/pc/misc.c \ \ - disk/raid.c disk/lvm.c \ + disk/raid.c disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ grub_emu_init.c grub_emu_LDFLAGS = $(LIBCURSES) diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index c1e4ac4..f3142e4 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -102,7 +102,7 @@ grub_setup_SOURCES = util/i386/pc/grub-setup.c util/biosdisk.c \ \ partmap/pc.c partmap/gpt.c \ \ - disk/raid.c disk/lvm.c \ + disk/raid.c disk/mdraid_linux.c disk/lvm.c \ util/raid.c util/lvm.c \ grub_setup_init.c @@ -142,7 +142,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ util/biosdisk.c util/getroot.c \ util/i386/pc/misc.c \ \ - disk/raid.c disk/lvm.c \ + disk/raid.c disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ grub_emu_init.c grub_emu_LDFLAGS = $(LIBCURSES) diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk index 0ed75f3..15e2fae 100644 --- a/conf/powerpc-ieee1275.rmk +++ b/conf/powerpc-ieee1275.rmk @@ -73,7 +73,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ util/biosdisk.c util/getroot.c \ util/powerpc/ieee1275/misc.c \ \ - disk/raid.c disk/lvm.c \ + disk/raid.c disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ grub_script.tab.c grub_emu_init.c grub_emu_LDFLAGS = $(LIBCURSES) diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk index 4f8abba..8553226 100644 --- a/conf/x86_64-efi.rmk +++ b/conf/x86_64-efi.rmk @@ -64,7 +64,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ util/biosdisk.c util/getroot.c \ util/i386/pc/misc.c \ \ - disk/raid.c disk/lvm.c \ + disk/raid.c disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ grub_emu_init.c grub_emu_LDFLAGS = $(LIBCURSES) diff --git a/disk/dmraid_nvidia.c b/disk/dmraid_nvidia.c new file mode 100644 index 0000000..82eb26a --- /dev/null +++ b/disk/dmraid_nvidia.c @@ -0,0 +1,165 @@ +/* dmraid_nvidia.c - module to handle Nvidia fakeraid. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008 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 . + */ + +#include +#include +#include +#include +#include +#include + +#define NV_SIGNATURES 4 + +#define NV_IDLE 0 +#define NV_SCDB_INIT_RAID 2 +#define NV_SCDB_REBUILD_RAID 3 +#define NV_SCDB_UPGRADE_RAID 4 +#define NV_SCDB_SYNC_RAID 5 + +#define NV_LEVEL_UNKNOWN 0x00 +#define NV_LEVEL_JBOD 0xFF +#define NV_LEVEL_0 0x80 +#define NV_LEVEL_1 0x81 +#define NV_LEVEL_3 0x83 +#define NV_LEVEL_5 0x85 +#define NV_LEVEL_10 0x8a +#define NV_LEVEL_1_0 0x8180 + +#define NV_ARRAY_FLAG_BOOT 1 /* BIOS use only. */ +#define NV_ARRAY_FLAG_ERROR 2 /* Degraded or offling. */ +#define NV_ARRAY_FLAG_PARITY_VALID 4 /* RAID-3/5 parity valid. */ + +struct grub_raid_nv_array +{ + grub_uint32_t version; + grub_uint32_t signature[NV_SIGNATURES]; + grub_uint8_t raid_job_code; + grub_uint8_t stripe_width; + grub_uint8_t total_volumes; + grub_uint8_t original_width; + grub_uint32_t raid_level; + grub_uint32_t stripe_block_size; + grub_uint32_t stripe_block_size_bytes; + grub_uint32_t stripe_block_size_log2; + grub_uint32_t stripe_mask; + grub_uint32_t stripe_size; + grub_uint32_t stripe_size_bytes; + grub_uint32_t raid_job_mask; + grub_uint32_t original_capacity; + grub_uint32_t flags; +}; + +#define NV_ID_LENGTH 8 +#define NV_ID_STRING "NVIDIA" +#define NV_VERSION 100 + +#define NV_PRODUCTIDS 16 +#define NV_PRODUCTREVISIONS 4 + +struct grub_raid_nv_super +{ + grub_uint8_t vendor[NV_ID_LENGTH]; /* 0x00 - 0x07 ID string. */ + grub_uint32_t size; /* 0x08 - 0x0B Size of metadata in dwords. */ + grub_uint32_t chksum; /* 0x0C - 0x0F Checksum of this struct. */ + grub_uint16_t version; /* 0x10 - 0x11 NV version. */ + grub_uint8_t unit_number; /* 0x12 Disk index in array. */ + grub_uint8_t reserved; /* 0x13. */ + grub_uint32_t capacity; /* 0x14 - 0x17 Array capacity in sectors. */ + grub_uint32_t sector_size; /* 0x18 - 0x1B Sector size. */ + grub_uint8_t product_id[NV_PRODUCTIDS]; /* 0x1C - 0x2B Array product ID. */ + grub_uint8_t product_rev[NV_PRODUCTREVISIONS]; /* 0x2C - 0x2F Array product revision */ + grub_uint32_t unit_flags; /* 0x30 - 0x33 Flags for this disk */ + struct grub_raid_nv_array array; /* Array information */ +} __attribute__ ((packed)); + +static grub_err_t +grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array) +{ + grub_disk_addr_t sector; + struct grub_raid_nv_super sb; + grub_uint32_t *uuid; + + if (disk->partition) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "skip partition"); + + sector = grub_disk_get_size (disk) - 2; + + if (grub_disk_read (disk, sector, 0, sizeof (sb), (char *) &sb)) + return grub_errno; + + if (grub_memcmp (sb.vendor, NV_ID_STRING, 6)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); + + if (sb.version != NV_VERSION) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Unknown version: %d.%d", sb.version); + + switch (sb.array.raid_level) + { + case NV_LEVEL_0: + array->level = 0; + array->disk_size = sb.capacity / sb.array.total_volumes; + break; + + case NV_LEVEL_1: + array->level = 1; + array->disk_size = sb.capacity; + break; + + case NV_LEVEL_5: + array->level = 5; + array->disk_size = sb.capacity / (sb.array.total_volumes - 1); + break; + + default: + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Unsupported RAID level: %d", sb.array.raid_level); + } + + array->number = 0; + array->total_devs = sb.array.total_volumes; + array->chunk_size = sb.array.stripe_block_size; + array->index = sb.unit_number; + array->uuid_len = sizeof (sb.array.signature); + array->uuid = grub_malloc (sizeof (sb.array.signature)); + if (! array->uuid) + return grub_errno; + + grub_memcpy (array->uuid, (char *) &sb.array.signature, + sizeof (sb.array.signature)); + + return 0; +} + +static struct grub_raid grub_dmraid_nv_dev = +{ + .name = "dmraid_nv", + .detect = grub_dmraid_nv_detect, + .next = 0 +}; + +GRUB_MOD_INIT(dm_nv) +{ + grub_raid_register (&grub_dmraid_nv_dev); +} + +GRUB_MOD_FINI(dm_nv) +{ + grub_raid_register (&grub_dmraid_nv_dev); +} diff --git a/disk/i386/pc/biosdisk.c b/disk/i386/pc/biosdisk.c index c8fd142..8b7f5ed 100644 --- a/disk/i386/pc/biosdisk.c +++ b/disk/i386/pc/biosdisk.c @@ -120,7 +120,7 @@ grub_biosdisk_open (const char *name, grub_disk_t disk) { data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM; data->sectors = 32; - total_sectors = 9000000; /* TODO: get the correct size. */ + total_sectors = ULONG_MAX; /* TODO: get the correct size. */ } else if (drive & 0x80) { diff --git a/disk/mdraid_linux.c b/disk/mdraid_linux.c new file mode 100644 index 0000000..c77f2e2 --- /dev/null +++ b/disk/mdraid_linux.c @@ -0,0 +1,243 @@ +/* mdraid_linux.c - module to handle linux softraid. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 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 . + */ + +#include +#include +#include +#include +#include +#include + +/* Linux RAID on disk structures and constants, + copied from include/linux/raid/md_p.h. */ + +#define GRUB_RAID_RESERVED_BYTES (64 * 1024) +#define GRUB_RAID_RESERVED_SECTORS (GRUB_RAID_RESERVED_BYTES / 512) + +#define GRUB_RAID_NEW_SIZE_SECTORS(x) ((x & ~(GRUB_RAID_RESERVED_SECTORS - 1)) \ + - GRUB_RAID_RESERVED_SECTORS) + +#define GRUB_RAID_SB_BYTES 4096 +#define GRUB_RAID_SB_WORDS (GRUB_RAID_SB_BYTES / 4) +#define GRUB_RAID_SB_SECTORS (GRUB_RAID_SB_BYTES / 512) + +/* + * The following are counted in 32-bit words + */ +#define GRUB_RAID_SB_GENERIC_OFFSET 0 + +#define GRUB_RAID_SB_PERSONALITY_OFFSET 64 +#define GRUB_RAID_SB_DISKS_OFFSET 128 +#define GRUB_RAID_SB_DESCRIPTOR_OFFSET 992 + +#define GRUB_RAID_SB_GENERIC_CONSTANT_WORDS 32 +#define GRUB_RAID_SB_GENERIC_STATE_WORDS 32 +#define GRUB_RAID_SB_GENERIC_WORDS (GRUB_RAID_SB_GENERIC_CONSTANT_WORDS \ + + GRUB_RAID_SB_GENERIC_STATE_WORDS) +#define GRUB_RAID_SB_PERSONALITY_WORDS 64 +#define GRUB_RAID_SB_DESCRIPTOR_WORDS 32 +#define GRUB_RAID_SB_DISKS 27 +#define GRUB_RAID_SB_DISKS_WORDS (GRUB_RAID_SB_DISKS*GRUB_RAID_SB_DESCRIPTOR_WORDS) +#define GRUB_RAID_SB_RESERVED_WORDS (1024 - GRUB_RAID_SB_GENERIC_WORDS \ + - GRUB_RAID_SB_PERSONALITY_WORDS \ + - GRUB_RAID_SB_DISKS_WORDS \ + - GRUB_RAID_SB_DESCRIPTOR_WORDS) +#define GRUB_RAID_SB_EQUAL_WORDS (GRUB_RAID_SB_GENERIC_WORDS \ + + GRUB_RAID_SB_PERSONALITY_WORDS \ + + GRUB_RAID_SB_DISKS_WORDS) + +/* + * Device "operational" state bits + */ +#define GRUB_RAID_DISK_FAULTY 0 /* disk is faulty / operational */ +#define GRUB_RAID_DISK_ACTIVE 1 /* disk is running or spare disk */ +#define GRUB_RAID_DISK_SYNC 2 /* disk is in sync with the raid set */ +#define GRUB_RAID_DISK_REMOVED 3 /* disk is in sync with the raid set */ + +#define GRUB_RAID_DISK_WRITEMOSTLY 9 /* disk is "write-mostly" is RAID1 config. + * read requests will only be sent here in + * dire need + */ + + +#define GRUB_RAID_SB_MAGIC 0xa92b4efc + +/* + * Superblock state bits + */ +#define GRUB_RAID_SB_CLEAN 0 +#define GRUB_RAID_SB_ERRORS 1 + +#define GRUB_RAID_SB_BITMAP_PRESENT 8 /* bitmap may be present nearby */ + +struct grub_raid_disk_09 { + grub_uint32_t number; /* 0 Device number in the entire set */ + grub_uint32_t major; /* 1 Device major number */ + grub_uint32_t minor; /* 2 Device minor number */ + grub_uint32_t raid_disk; /* 3 The role of the device in the raid set */ + grub_uint32_t state; /* 4 Operational state */ + grub_uint32_t reserved[GRUB_RAID_SB_DESCRIPTOR_WORDS - 5]; +}; + +struct grub_raid_super_09 { + /* + * Constant generic information + */ + grub_uint32_t md_magic; /* 0 MD identifier */ + grub_uint32_t major_version; /* 1 major version to which the set conforms */ + grub_uint32_t minor_version; /* 2 minor version ... */ + grub_uint32_t patch_version; /* 3 patchlevel version ... */ + grub_uint32_t gvalid_words; /* 4 Number of used words in this section */ + grub_uint32_t set_uuid0; /* 5 Raid set identifier */ + grub_uint32_t ctime; /* 6 Creation time */ + grub_uint32_t level; /* 7 Raid personality */ + grub_uint32_t size; /* 8 Apparent size of each individual disk */ + grub_uint32_t nr_disks; /* 9 total disks in the raid set */ + grub_uint32_t raid_disks; /* 10 disks in a fully functional raid set */ + grub_uint32_t md_minor; /* 11 preferred MD minor device number */ + grub_uint32_t not_persistent; /* 12 does it have a persistent superblock */ + grub_uint32_t set_uuid1; /* 13 Raid set identifier #2 */ + grub_uint32_t set_uuid2; /* 14 Raid set identifier #3 */ + grub_uint32_t set_uuid3; /* 15 Raid set identifier #4 */ + grub_uint32_t gstate_creserved[GRUB_RAID_SB_GENERIC_CONSTANT_WORDS - 16]; + + /* + * Generic state information + */ + grub_uint32_t utime; /* 0 Superblock update time */ + grub_uint32_t state; /* 1 State bits (clean, ...) */ + grub_uint32_t active_disks; /* 2 Number of currently active disks */ + grub_uint32_t working_disks; /* 3 Number of working disks */ + grub_uint32_t failed_disks; /* 4 Number of failed disks */ + grub_uint32_t spare_disks; /* 5 Number of spare disks */ + grub_uint32_t sb_csum; /* 6 checksum of the whole superblock */ +#ifdef GRUB_HOST_WORDS_BIGENDIAN + grub_uint32_t events_hi; /* 7 high-order of superblock update count */ + grub_uint32_t events_lo; /* 8 low-order of superblock update count */ + grub_uint32_t cp_events_hi; /* 9 high-order of checkpoint update count */ + grub_uint32_t cp_events_lo; /* 10 low-order of checkpoint update count */ +#else + grub_uint32_t events_lo; /* 7 low-order of superblock update count */ + grub_uint32_t events_hi; /* 8 high-order of superblock update count */ + grub_uint32_t cp_events_lo; /* 9 low-order of checkpoint update count */ + grub_uint32_t cp_events_hi; /* 10 high-order of checkpoint update count */ +#endif + grub_uint32_t recovery_cp; /* 11 recovery checkpoint sector count */ + grub_uint32_t gstate_sreserved[GRUB_RAID_SB_GENERIC_STATE_WORDS - 12]; + + /* + * Personality information + */ + grub_uint32_t layout; /* 0 the array's physical layout */ + grub_uint32_t chunk_size; /* 1 chunk size in bytes */ + grub_uint32_t root_pv; /* 2 LV root PV */ + grub_uint32_t root_block; /* 3 LV root block */ + grub_uint32_t pstate_reserved[GRUB_RAID_SB_PERSONALITY_WORDS - 4]; + + /* + * Disks information + */ + struct grub_raid_disk_09 disks[GRUB_RAID_SB_DISKS]; + + /* + * Reserved + */ + grub_uint32_t reserved[GRUB_RAID_SB_RESERVED_WORDS]; + + /* + * Active descriptor + */ + struct grub_raid_disk_09 this_disk; +}; + +static grub_err_t +grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array) +{ + grub_disk_addr_t sector; + grub_uint64_t size; + struct grub_raid_super_09 sb; + grub_uint32_t *uuid; + + /* The sector where the RAID superblock is stored, if available. */ + size = grub_disk_get_size (disk); + sector = GRUB_RAID_NEW_SIZE_SECTORS(size); + + if (grub_disk_read (disk, sector, 0, GRUB_RAID_SB_BYTES, (char *) &sb)) + return grub_errno; + + /* Look whether there is a RAID superblock. */ + if (sb.md_magic != GRUB_RAID_SB_MAGIC) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); + + /* FIXME: Also support version 1.0. */ + if (sb.major_version != 0 || sb.minor_version != 90) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Unsupported RAID version: %d.%d", + sb.major_version, sb.minor_version); + + /* FIXME: Check the checksum. */ + + /* FIXME: Support all RAID levels. */ + if (sb.level != 0 && sb.level != 1 && sb.level != 5) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Unsupported RAID level: %d", + sb.level); + + /* FIXME: Support all layouts. */ + if (sb.level == 5 && sb.layout != 2) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Unsupported RAID5 layout: %d", + sb.layout); + + array->number = sb.md_minor; + array->level = sb.level; + array->total_devs = sb.nr_disks; + array->disk_size = (sb.size) ? sb.size * 2 : sector; + array->chunk_size = sb.chunk_size >> 9; + array->index = sb.this_disk.number; + array->uuid_len = 16; + array->uuid = grub_malloc (16); + if (! array->uuid) + return grub_errno; + + uuid = (grub_uint32_t *) array->uuid; + uuid[0] = sb.set_uuid0; + uuid[1] = sb.set_uuid1; + uuid[2] = sb.set_uuid2; + uuid[3] = sb.set_uuid3; + + return 0; +} + +static struct grub_raid grub_mdraid_dev = +{ + .name = "mdraid", + .detect = grub_mdraid_detect, + .next = 0 +}; + +GRUB_MOD_INIT(mdraid) +{ + grub_raid_register (&grub_mdraid_dev); +} + +GRUB_MOD_FINI(mdraid) +{ + grub_raid_register (&grub_mdraid_dev); +} diff --git a/disk/raid.c b/disk/raid.c index 731bf1f..3333f4b 100644 --- a/disk/raid.c +++ b/disk/raid.c @@ -112,9 +112,15 @@ grub_raid_open (const char *name, grub_disk_t disk) switch (array->level) { case 0: - /* FIXME: RAID0 disks can have different sizes! */ - disk->total_sectors = array->total_devs * array->disk_size; - break; + { + unsigned i; + + disk->total_sectors = 0; + for (i = 0; i < array->total_devs; i++) + disk->total_sectors += array->device[i]->total_sectors; + + break; + } case 1: disk->total_sectors = array->disk_size; @@ -152,56 +158,39 @@ grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector, grub_uint32_t b; unsigned int disknr; grub_disk_addr_t read_sector; - grub_size_t read_size; /* Find the first sector to read. */ - a = grub_divmod64 (sector, array->chunk_size, NULL); - grub_divmod64 (a, array->total_devs, &disknr); - - a = grub_divmod64 (sector, array->chunk_size * array->total_devs, NULL); - grub_divmod64 (sector, array->chunk_size, &b); - read_sector = a * array->chunk_size + b; - - grub_divmod64 (read_sector, array->chunk_size, &b); - read_size = array->chunk_size - b; - - if (read_size > size) - read_size = size; + a = grub_divmod64 (sector, array->chunk_size, &b); + a = grub_divmod64 (a, array->total_devs, &disknr); + read_sector = a * array->chunk_size; while (1) { - grub_uint32_t i; + grub_size_t read_size; - err = grub_disk_read (array->device[disknr], read_sector, 0, + read_size = array->chunk_size - b; + if (read_size > size) + read_size = size; + + err = grub_disk_read (array->device[disknr], read_sector + b, 0, read_size << GRUB_DISK_SECTOR_BITS, buf); if (err) break; - buf += read_size; + buf += read_size << GRUB_DISK_SECTOR_BITS; size -= read_size; if (! size) break; - if (size > array->chunk_size) - read_size = array->chunk_size; - else - read_size = size; - - /* Check whether the sector was aligned on a chunk size - boundary. If this isn't the case, it's the first read - and the next read should be set back to start of the - boundary. */ - grub_divmod64 (read_sector, array->chunk_size, &i); - read_sector -= i; - + b = 0; disknr++; /* See whether the disk was the last disk, and start reading from the first disk in that case. */ if (disknr == array->total_devs) - { - disknr = 0; - read_sector += array->chunk_size; - } + { + read_sector += array->chunk_size; + disknr = 0; + } } } break; @@ -348,169 +337,103 @@ grub_raid_write (grub_disk_t disk __attribute ((unused)), return GRUB_ERR_NOT_IMPLEMENTED_YET; } -static int -grub_raid_scan_device (const char *name) +static grub_err_t +insert_array (grub_disk_t disk, struct grub_raid_array *new_array, + const char *scanner_name) { - grub_err_t err; - grub_disk_t disk; - grub_disk_addr_t sector; - grub_uint64_t size; - struct grub_raid_super_09 sb; - struct grub_raid_array *p, *array = NULL; - - grub_dprintf ("raid", "Scanning for RAID devices\n"); - - disk = grub_disk_open (name); - if (!disk) - return 0; - - /* The sector where the RAID superblock is stored, if available. */ - size = grub_disk_get_size (disk); - sector = GRUB_RAID_NEW_SIZE_SECTORS(size); - - err = grub_disk_read (disk, sector, 0, GRUB_RAID_SB_BYTES, (char *) &sb); - grub_disk_close (disk); - if (err) - { - grub_errno = GRUB_ERR_NONE; - return 0; - } - - /* Look whether there is a RAID superblock. */ - if (sb.md_magic != GRUB_RAID_SB_MAGIC) - return 0; - - /* FIXME: Also support version 1.0. */ - if (sb.major_version != 0 || sb.minor_version != 90) - { - grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "Unsupported RAID version: %d.%d", - sb.major_version, sb.minor_version); - return 0; - } - - /* FIXME: Check the checksum. */ - - /* FIXME: Support all RAID levels. */ - if (sb.level != 0 && sb.level != 1 && sb.level != 5) - { - grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "Unsupported RAID level: %d", - sb.level); - return 0; - } - - /* FIXME: Support all layouts. */ - if (sb.level == 5 && sb.layout != 2) - { - grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "Unsupported RAID5 layout: %d", - sb.layout); - return 0; - } + struct grub_raid_array *array = 0, *p; /* 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[0] == sb.set_uuid0 && p->uuid[1] == sb.set_uuid1 - && p->uuid[2] == sb.set_uuid2 && p->uuid[3] == sb.set_uuid3) - { - array = p; - break; - } - } - - /* Do some checks before adding the device to the array. */ - if (array) - { - /* 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, but what is the sanest things to do in such - a case? */ - - grub_error (GRUB_ERR_BAD_NUMBER, - "array->nr_devs > array->total_devs (%d)?!?", - array->total_devs); - - return 0; - } - - if (array->device[sb.this_disk.number] != NULL) - /* We found multiple devices with the same number. Again, - this shouldn't happen.*/ - grub_dprintf ("raid", "Found two disks with the number %d?!?", - sb.this_disk.number); - } + 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; + + /* Do some checks before adding the device to the array. */ + + /* 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, but what is the sanest things to do in such + a case? */ + return grub_error (GRUB_ERR_BAD_NUMBER, + "array->nr_devs > array->total_devs (%d)?!?", + array->total_devs); + + if (array->device[new_array->index] != NULL) + /* We found multiple devices with the same number. Again, + this shouldn't happen.*/ + return grub_error (GRUB_ERR_BAD_NUMBER, + "Found two disks with the number %d?!?", + new_array->number); + + break; + } /* Add an array to the list if we didn't find any. */ if (!array) { array = grub_malloc (sizeof (*array)); if (!array) - return 0; - grub_memset (array, 0, sizeof (*array)); - array->number = sb.md_minor; - array->version = sb.major_version; - array->level = sb.level; - array->layout = sb.layout; - array->total_devs = sb.nr_disks; + { + grub_free (new_array->uuid); + return grub_errno; + } + + *array = *new_array; array->nr_devs = 0; - array->uuid[0] = sb.set_uuid0; - array->uuid[1] = sb.set_uuid1; - array->uuid[2] = sb.set_uuid2; - array->uuid[3] = sb.set_uuid3; - /* The superblock specifies the size in 1024-byte sectors. */ - array->disk_size = sb.size * 2; - array->chunk_size = sb.chunk_size / 512; + grub_memset (&array->device, 0, sizeof (array->device)); /* Check whether we don't have multiple arrays with the same number. */ for (p = array_list; p != NULL; p = p->next) - { - if (p->number == array->number) - break; - } + { + if (p->number == array->number) + break; + } if (p) - { - /* The number is already in use, so we need to find an new number. */ - int i = 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++; - } - } + { + /* The number is already in use, so we need to find an new number. */ + int i = 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++; + } + } array->name = grub_malloc (13); if (! array->name) - { - grub_free (array); + { + grub_free (array->uuid); + grub_free (array); - return 0; - } + return grub_errno; + } grub_sprintf (array->name, "md%d", array->number); - grub_dprintf ("raid", "Found array: %s\n", array->name); + grub_dprintf ("raid", "Found array %s (%s)\n", array->name, + scanner_name); /* Add our new array to the list. */ array->next = array_list; @@ -518,47 +441,117 @@ grub_raid_scan_device (const char *name) } /* Add the device to the array. */ - array->device[sb.this_disk.number] = grub_disk_open (name); + array->device[new_array->index] = disk; + array->nr_devs++; - if (array->disk_size != array->device[sb.this_disk.number]->total_sectors) + return 0; +} + + +static grub_raid_t grub_raid_list; + +static void +grub_raid_scan_device (int head_only) +{ + auto int hook (const char *name); + int hook (const char *name) { - if (array->total_devs == 1) - { - grub_dprintf ("raid", "Array contains only one disk, but its size (0x%llx) " - "doesn't match with size indicated by superblock (0x%llx). " - "Assuming superblock is wrong.\n", - (unsigned long long) array->device[sb.this_disk.number]->total_sectors, - (unsigned long long) array->disk_size); - array->disk_size = array->device[sb.this_disk.number]->total_sectors; - } - else if (array->level == 1) - { - grub_dprintf ("raid", "Array is RAID level 1, but the size of disk %d (0x%llx) " - "doesn't match with size indicated by superblock (0x%llx). " - "Assuming superblock is wrong.\n", - sb.this_disk.number, - (unsigned long long) array->device[sb.this_disk.number]->total_sectors, - (unsigned long long) array->disk_size); - array->disk_size = array->device[sb.this_disk.number]->total_sectors; - } + grub_disk_t disk; + struct grub_raid_array array; + struct grub_raid *p; + + grub_dprintf ("raid", "Scanning for RAID devices\n"); + + disk = grub_disk_open (name); + if (!disk) + return 0; + + if (disk->total_sectors == ULONG_MAX) + { + grub_disk_close (disk); + return 0; + } + + for (p = grub_raid_list; p; p = p->next) + { + if (! p->detect (disk, &array)) + { + if (! insert_array (disk, &array, p->name)) + return 0; + + break; + } + + /* 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; + if (head_only) + break; + } + + grub_disk_close (disk); + + return 0; } - if (! array->device[sb.this_disk.number]) + grub_device_iterate (&hook); +} + +static void +free_array (void) +{ + struct grub_raid_array *array; + + array = array_list; + while (array) { - /* Remove array from the list if we have just added it. */ - if (array->nr_devs == 0) - { - array_list = array->next; - grub_free (array->name); - grub_free (array); - } + struct grub_raid_array *p; + int i; - return 0; + p = array; + array = array->next; + + for (i = 0; i < GRUB_RAID_MAX_DEVICES; i++) + if (p->device[i]) + grub_disk_close (p->device[i]); + + grub_free (p->uuid); + grub_free (p->name); + grub_free (p); } - array->nr_devs++; + array_list = 0; +} - return 0; +void +grub_raid_register (grub_raid_t raid) +{ + raid->next = grub_raid_list; + grub_raid_list = raid; + grub_raid_scan_device (1); +} + +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; + } +} + +void +grub_raid_rescan (void) +{ + free_array (); + grub_raid_scan_device (0); } static struct grub_disk_dev grub_raid_dev = @@ -579,12 +572,11 @@ static struct grub_disk_dev grub_raid_dev = GRUB_MOD_INIT(raid) { - grub_device_iterate (&grub_raid_scan_device); grub_disk_dev_register (&grub_raid_dev); } GRUB_MOD_FINI(raid) { grub_disk_dev_unregister (&grub_raid_dev); - /* FIXME: free the array list. */ + free_array (); } diff --git a/include/grub/raid.h b/include/grub/raid.h index 4af97f1..0920f0f 100644 --- a/include/grub/raid.h +++ b/include/grub/raid.h @@ -22,165 +22,42 @@ #include +#define GRUB_RAID_MAX_DEVICES 32 + struct grub_raid_array { int number; /* The device number, taken from md_minor so we are consistent with the device name in Linux. */ - int version; /* 0 = 0.90, 1 = 1.0 */ int level; /* RAID levels, only 0, 1 or 5 at the moment. */ - int layout; /* Only for RAID 5. */ unsigned int total_devs; /* Total number of devices in the array. */ - unsigned int nr_devs; /* The number of devices we've found so far. */ - grub_size_t chunk_size; /* The size of a chunk, in 512 byte sectors. */ - grub_uint32_t uuid[4]; /* The UUID of the device. */ - char *name; /* That will be "md". */ + 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. */ - grub_disk_t device[32]; /* Array of total_devs devices. */ + 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". */ + unsigned int nr_devs; /* The number of devices we've found so far. */ + grub_disk_t device[GRUB_RAID_MAX_DEVICES]; /* Array of total_devs devices. */ struct grub_raid_array *next; }; -/* Linux RAID on disk structures and constants, - copied from include/linux/raid/md_p.h. */ - -#define GRUB_RAID_RESERVED_BYTES (64 * 1024) -#define GRUB_RAID_RESERVED_SECTORS (GRUB_RAID_RESERVED_BYTES / 512) - -#define GRUB_RAID_NEW_SIZE_SECTORS(x) ((x & ~(GRUB_RAID_RESERVED_SECTORS - 1)) \ - - GRUB_RAID_RESERVED_SECTORS) - -#define GRUB_RAID_SB_BYTES 4096 -#define GRUB_RAID_SB_WORDS (GRUB_RAID_SB_BYTES / 4) -#define GRUB_RAID_SB_SECTORS (GRUB_RAID_SB_BYTES / 512) - -/* - * The following are counted in 32-bit words - */ -#define GRUB_RAID_SB_GENERIC_OFFSET 0 - -#define GRUB_RAID_SB_PERSONALITY_OFFSET 64 -#define GRUB_RAID_SB_DISKS_OFFSET 128 -#define GRUB_RAID_SB_DESCRIPTOR_OFFSET 992 - -#define GRUB_RAID_SB_GENERIC_CONSTANT_WORDS 32 -#define GRUB_RAID_SB_GENERIC_STATE_WORDS 32 -#define GRUB_RAID_SB_GENERIC_WORDS (GRUB_RAID_SB_GENERIC_CONSTANT_WORDS \ - + GRUB_RAID_SB_GENERIC_STATE_WORDS) -#define GRUB_RAID_SB_PERSONALITY_WORDS 64 -#define GRUB_RAID_SB_DESCRIPTOR_WORDS 32 -#define GRUB_RAID_SB_DISKS 27 -#define GRUB_RAID_SB_DISKS_WORDS (GRUB_RAID_SB_DISKS*GRUB_RAID_SB_DESCRIPTOR_WORDS) -#define GRUB_RAID_SB_RESERVED_WORDS (1024 - GRUB_RAID_SB_GENERIC_WORDS \ - - GRUB_RAID_SB_PERSONALITY_WORDS \ - - GRUB_RAID_SB_DISKS_WORDS \ - - GRUB_RAID_SB_DESCRIPTOR_WORDS) -#define GRUB_RAID_SB_EQUAL_WORDS (GRUB_RAID_SB_GENERIC_WORDS \ - + GRUB_RAID_SB_PERSONALITY_WORDS \ - + GRUB_RAID_SB_DISKS_WORDS) - -/* - * Device "operational" state bits - */ -#define GRUB_RAID_DISK_FAULTY 0 /* disk is faulty / operational */ -#define GRUB_RAID_DISK_ACTIVE 1 /* disk is running or spare disk */ -#define GRUB_RAID_DISK_SYNC 2 /* disk is in sync with the raid set */ -#define GRUB_RAID_DISK_REMOVED 3 /* disk is in sync with the raid set */ - -#define GRUB_RAID_DISK_WRITEMOSTLY 9 /* disk is "write-mostly" is RAID1 config. - * read requests will only be sent here in - * dire need - */ - - -#define GRUB_RAID_SB_MAGIC 0xa92b4efc - -/* - * Superblock state bits - */ -#define GRUB_RAID_SB_CLEAN 0 -#define GRUB_RAID_SB_ERRORS 1 +struct grub_raid +{ + const char *name; -#define GRUB_RAID_SB_BITMAP_PRESENT 8 /* bitmap may be present nearby */ + grub_err_t (*detect) (grub_disk_t disk, struct grub_raid_array *array); -struct grub_raid_disk_09 { - grub_uint32_t number; /* 0 Device number in the entire set */ - grub_uint32_t major; /* 1 Device major number */ - grub_uint32_t minor; /* 2 Device minor number */ - grub_uint32_t raid_disk; /* 3 The role of the device in the raid set */ - grub_uint32_t state; /* 4 Operational state */ - grub_uint32_t reserved[GRUB_RAID_SB_DESCRIPTOR_WORDS - 5]; + struct grub_raid *next; }; +typedef struct grub_raid *grub_raid_t; -struct grub_raid_super_09 { - /* - * Constant generic information - */ - grub_uint32_t md_magic; /* 0 MD identifier */ - grub_uint32_t major_version; /* 1 major version to which the set conforms */ - grub_uint32_t minor_version; /* 2 minor version ... */ - grub_uint32_t patch_version; /* 3 patchlevel version ... */ - grub_uint32_t gvalid_words; /* 4 Number of used words in this section */ - grub_uint32_t set_uuid0; /* 5 Raid set identifier */ - grub_uint32_t ctime; /* 6 Creation time */ - grub_uint32_t level; /* 7 Raid personality */ - grub_uint32_t size; /* 8 Apparent size of each individual disk */ - grub_uint32_t nr_disks; /* 9 total disks in the raid set */ - grub_uint32_t raid_disks; /* 10 disks in a fully functional raid set */ - grub_uint32_t md_minor; /* 11 preferred MD minor device number */ - grub_uint32_t not_persistent; /* 12 does it have a persistent superblock */ - grub_uint32_t set_uuid1; /* 13 Raid set identifier #2 */ - grub_uint32_t set_uuid2; /* 14 Raid set identifier #3 */ - grub_uint32_t set_uuid3; /* 15 Raid set identifier #4 */ - grub_uint32_t gstate_creserved[GRUB_RAID_SB_GENERIC_CONSTANT_WORDS - 16]; - - /* - * Generic state information - */ - grub_uint32_t utime; /* 0 Superblock update time */ - grub_uint32_t state; /* 1 State bits (clean, ...) */ - grub_uint32_t active_disks; /* 2 Number of currently active disks */ - grub_uint32_t working_disks; /* 3 Number of working disks */ - grub_uint32_t failed_disks; /* 4 Number of failed disks */ - grub_uint32_t spare_disks; /* 5 Number of spare disks */ - grub_uint32_t sb_csum; /* 6 checksum of the whole superblock */ -#ifdef GRUB_HOST_WORDS_BIGENDIAN - grub_uint32_t events_hi; /* 7 high-order of superblock update count */ - grub_uint32_t events_lo; /* 8 low-order of superblock update count */ - grub_uint32_t cp_events_hi; /* 9 high-order of checkpoint update count */ - grub_uint32_t cp_events_lo; /* 10 low-order of checkpoint update count */ -#else - grub_uint32_t events_lo; /* 7 low-order of superblock update count */ - grub_uint32_t events_hi; /* 8 high-order of superblock update count */ - grub_uint32_t cp_events_lo; /* 9 low-order of checkpoint update count */ - grub_uint32_t cp_events_hi; /* 10 high-order of checkpoint update count */ -#endif - grub_uint32_t recovery_cp; /* 11 recovery checkpoint sector count */ - grub_uint32_t gstate_sreserved[GRUB_RAID_SB_GENERIC_STATE_WORDS - 12]; - - /* - * Personality information - */ - grub_uint32_t layout; /* 0 the array's physical layout */ - grub_uint32_t chunk_size; /* 1 chunk size in bytes */ - grub_uint32_t root_pv; /* 2 LV root PV */ - grub_uint32_t root_block; /* 3 LV root block */ - grub_uint32_t pstate_reserved[GRUB_RAID_SB_PERSONALITY_WORDS - 4]; +void grub_raid_register (grub_raid_t raid); +void grub_raid_unregister (grub_raid_t raid); - /* - * Disks information - */ - struct grub_raid_disk_09 disks[GRUB_RAID_SB_DISKS]; - - /* - * Reserved - */ - grub_uint32_t reserved[GRUB_RAID_SB_RESERVED_WORDS]; - - /* - * Active descriptor - */ - struct grub_raid_disk_09 this_disk; -}; +void grub_raid_rescan (void); #endif /* ! GRUB_RAID_H */ diff --git a/util/grub-fstest.c b/util/grub-fstest.c index 35af6a5..29234ac 100644 --- a/util/grub-fstest.c +++ b/util/grub-fstest.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -141,7 +142,6 @@ grub_unregister_command (const char *name __attribute__ ((unused))) #define BUF_SIZE 32256 static grub_off_t skip, leng; -static char *part; static void read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len)) @@ -273,32 +273,61 @@ cmd_hex (char *pathname) return 0; } - read_file (pathname, hex_hook); + if (pathname) + read_file (pathname, hex_hook); + else + { + char buf[BUF_SIZE]; + grub_device_t dev; + + dev = grub_device_open (0); + if ((! dev) || (! dev->disk)) + grub_util_error ("Can\'t open device"); + + if (! leng) + leng = GRUB_DISK_SECTOR_SIZE; + + while (leng) + { + grub_size_t len; + + len = (leng > BUF_SIZE) ? BUF_SIZE : leng; + + if (grub_disk_read (dev->disk, 0, skip, len, buf)) + grub_util_error ("Disk read fails at offset %lld, length %d\n", + skip, len); + + hexdump (skip, buf, len); + + skip += len; + leng -= len; + } + + grub_device_close (dev); + } } static void -fstest (char *image_path, int cmd, int n, char **args) +fstest (char **images, int num_disks, int cmd, int n, char **args) { - char host_file[7 + grub_strlen (image_path) + 1]; - char device_name[(part) ? (6 + grub_strlen (part)) : 5]; - char *argv[3] = { "-p", "loop", host_file }; - - - grub_sprintf (host_file, "(host)/%s", image_path); + char host_file[128]; + char loop_name[8]; + char *argv[3] = { "-p", loop_name, host_file}; + int i; - if (execute_command (&cmd_loopback, 3, argv)) + for (i = 0; i < num_disks; i++) { - grub_util_error ("loopback command fails.\n"); - goto fail; - } + if (grub_strlen (images[i]) + 7 > sizeof (host_file)) + grub_util_error ("Pathname %s too long", images[i]); - if (part) - grub_sprintf (device_name, "loop,%s", part); - else - grub_strcpy (device_name, "loop"); + grub_sprintf (loop_name, "loop%d", i); + grub_sprintf (host_file, "(host)%s", images[i]); - grub_env_set ("root", device_name); + if (execute_command (&cmd_loopback, 3, argv)) + grub_util_error ("loopback command fails.\n"); + } + grub_raid_rescan (); switch (cmd) { case CMD_LS: @@ -311,31 +340,31 @@ fstest (char *image_path, int cmd, int n, char **args) cmd_cmp (args[0], args[1]); break; case CMD_HEX: - cmd_hex (args[0]); + cmd_hex ((n == 0) ? 0 : args[0]); break; case CMD_BLOCKLIST: execute_command (&cmd_blocklist, n, args); grub_printf ("\n"); } -fail: - argv[0] = "-d"; - execute_command (&cmd_loopback, 2, argv); + for (i = 0; i < num_disks; i++) + { + grub_sprintf (loop_name, "loop%d", i); + execute_command (&cmd_loopback, 2, argv); + } } static struct option options[] = { - {"part", required_argument, 0, 'p'}, + {"root", required_argument, 0, 'r'}, {"skip", required_argument, 0, 's'}, {"length", required_argument, 0, 'n'}, + {"diskcount", required_argument, 0, 'c'}, {"debug", required_argument, 0, 'd'}, - {"raw", no_argument, 0, 'r'}, - {"long", no_argument, 0, 'l'}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"verbose", no_argument, 0, 'v'}, - {0, 0, 0, 0} }; @@ -353,15 +382,14 @@ Debug tool for filesystem driver.\n\ ls PATH list files in PATH\n\ cp SRC DEST copy file to local system\n\ cmp SRC DEST compare files\n\ - hex FILE hex dump FILE\n\ + hex [FILE] Hex dump FILE\n\ blocklist FILE display blocklist of FILE\n\ \nOptions:\n\ - -p, --part=NUM select partition NUM\n\ + -r, --root=DEVICE_NAME set root device\n\ -s, --skip=N skip N bytes from output file\n\ -n, --length=N handle N bytes in output file\n\ + -c, --diskcount=N N input files\n\ -d, --debug=S Set debug environment variable\n\ - -r, --raw disable auto decompression\n\ - -l, --long show long directory list\n\ -h, --help display this message and exit\n\ -V, --version print version information and exit\n\ -v, --verbose print verbose messages\n\ @@ -374,45 +402,66 @@ Report bugs to <%s>.\n", PACKAGE_BUGREPORT); int main (int argc, char *argv[]) { - char *image_path, *debug_str = 0; - int cmd, is_raw = 0, is_long = 0; + char *debug_str = 0, *root = 0, *default_root, *alloc_root; + int i, cmd, num_opts, image_index, num_disks = 1; progname = "grub-fstest"; + /* Find the first non option entry. */ + for (num_opts = 1; num_opts < argc; num_opts++) + if (argv[num_opts][0] == '-') + { + if ((argv[num_opts][2] == 0) && (num_opts < argc - 1) && + ((argv[num_opts][1] == 'r') || + (argv[num_opts][1] == 's') || + (argv[num_opts][1] == 'n') || + (argv[num_opts][1] == 'c') || + (argv[num_opts][1] == 'd'))) + num_opts++; + } + else + break; + /* Check for options. */ while (1) { - int c = getopt_long (argc, argv, "p:s:n:d:rlhVv", options, 0); + int c = getopt_long (num_opts, argv, "r:s:n:c:d:hVv", options, 0); + char *p; if (c == -1) break; else switch (c) { - case 'p': - part = optarg; + case 'r': + root = optarg; break; case 's': - skip = grub_strtoul (optarg, NULL, 0); + skip = grub_strtoul (optarg, &p, 0); + if (*p == 's') + skip <<= GRUB_DISK_SECTOR_BITS; break; case 'n': - leng = grub_strtoul (optarg, NULL, 0); + leng = grub_strtoul (optarg, &p, 0); + if (*p == 's') + leng <<= GRUB_DISK_SECTOR_BITS; break; + case 'c': + num_disks = grub_strtoul (optarg, NULL, 0); + if (num_disks < 1) + { + fprintf (stderr, "Invalid disk count.\n"); + usage (1); + } + break; + case 'd': debug_str = optarg; break; - case 'r': - is_raw = 1; - break; - - case 'l': - is_long = 1; - break; - case 'h': usage (0); break; @@ -432,35 +481,29 @@ main (int argc, char *argv[]) } /* Obtain PATH. */ - if (optind >= argc) - { - fprintf (stderr, "No path is specified.\n"); - usage (1); - } - - image_path = argv[optind]; - - if (*image_path != '/') + if (optind + num_disks - 1 >= argc) { - fprintf (stderr, "Must use absolute path.\n"); + fprintf (stderr, "Not enough pathname.\n"); usage (1); } - optind++; + image_index = optind; + for (i = 0; i < num_disks; i++, optind++) + if (argv[optind][0] != '/') + { + fprintf (stderr, "Must use absolute path.\n"); + usage (1); + } cmd = 0; if (optind < argc) { - int nparm = 1; + int nparm = 0; if (!grub_strcmp (argv[optind], "ls")) - { - cmd = CMD_LS; - if (is_long) - argv[optind--] = "-l"; - else - nparm = 0; - } + { + cmd = CMD_LS; + } else if (!grub_strcmp (argv[optind], "cp")) { cmd = CMD_CP; @@ -478,6 +521,7 @@ main (int argc, char *argv[]) else if (!grub_strcmp (argv[optind], "blocklist")) { cmd = CMD_BLOCKLIST; + nparm = 1; } else { @@ -503,14 +547,31 @@ main (int argc, char *argv[]) /* Initialize all modules. */ grub_init_all (); - if (is_raw) - grub_env_set ("filehook", "0"); - if (debug_str) grub_env_set ("debug", debug_str); + default_root = (num_disks == 1) ? "loop0" : "md0"; + alloc_root = 0; + if (root) + { + if ((*root >= '0') && (*root <= '9')) + { + alloc_root = xmalloc (strlen (default_root) + strlen (root) + 2); + + sprintf (alloc_root, "%s,%s", default_root, root); + root = alloc_root; + } + } + else + root = default_root; + + grub_env_set ("root", root); + + if (alloc_root) + free (alloc_root); + /* Do it. */ - fstest (image_path + 1, cmd, argc - optind, argv + optind); + fstest (argv + image_index, num_disks, cmd, argc - optind, argv + optind); /* Free resources. */ grub_fini_all (); diff --git a/util/grub-probe.c b/util/grub-probe.c index a4f51e2..ce9cbff 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -142,7 +142,7 @@ probe (const char *path, char *device_name) abstraction_name = "lvm"; break; case GRUB_DEV_ABSTRACTION_RAID: - abstraction_name = "raid"; + abstraction_name = "raid mdraid"; break; default: grub_util_info ("did not find LVM/RAID in %s, assuming raw device", device_name);