modified: disk/i386/pc/biosdisk.c modified: disk/mdraid_linux.c modified: disk/raid.c modified: include/grub/disk.h modified: include/grub/raid.h modified: kern/device.c modified: kern/disk.c modified: kern/fs.c modified: kern/parser.c modified: normal/main.c modified: partmap/apple.c modified: partmap/gpt.c modified: util/deviceiter.c modified: util/getroot.c modified: util/grub-install.in modified: util/grub-mkconfig.in modified: util/grub-probe.c modified: util/hostdisk.c modified: util/i386/pc/grub-setup.c
Signed-off-by: Gaëtan Schmidt <jimmy.j...@gmx.net> --- disk/i386/pc/biosdisk.c | 2 +- disk/mdraid_linux.c | 177 +++++++++++++--- disk/raid.c | 52 ++++- include/grub/disk.h | 3 + include/grub/raid.h | 2 + kern/device.c | 4 + kern/disk.c | 17 ++- kern/fs.c | 6 + kern/parser.c | 8 +- normal/main.c | 6 + partmap/apple.c | 4 +- partmap/gpt.c | 9 +- util/deviceiter.c | 19 ++ util/getroot.c | 23 +-- util/grub-install.in | 2 +- util/grub-mkconfig.in | 18 ++- util/grub-probe.c | 13 +- util/hostdisk.c | 15 ++- util/i386/pc/grub-setup.c | 502 ++++++++++++++++++++++---------------------- 19 files changed, 563 insertions(+), 319 deletions(-) diff --git a/disk/i386/pc/biosdisk.c b/disk/i386/pc/biosdisk.c index 94d0e37..4dfc49f 100644 --- a/disk/i386/pc/biosdisk.c +++ b/disk/i386/pc/biosdisk.c @@ -108,7 +108,7 @@ grub_biosdisk_open (const char *name, grub_disk_t disk) return grub_errno; disk->has_partitions = ((drive & 0x80) && (drive != cd_drive)); - disk->id = drive; + disk->id = drive % 0x80; /* XXX */ data = (struct grub_biosdisk_data *) grub_zalloc (sizeof (*data)); if (! data) diff --git a/disk/mdraid_linux.c b/disk/mdraid_linux.c index 306c66a..e53085e 100644 --- a/disk/mdraid_linux.c +++ b/disk/mdraid_linux.c @@ -159,59 +159,178 @@ struct grub_raid_super_09 struct grub_raid_disk_09 this_disk; } __attribute__ ((packed)); +struct grub_raid_super_1 +{ + /* constant array information - 128 bytes */ + grub_uint32_t magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */ + grub_uint32_t major_version; /* 1 */ + grub_uint32_t feature_map; /* 0 for now */ + grub_uint32_t pad0; /* always set to 0 when writing */ + + grub_uint8_t set_uuid[16]; /* user-space generated. */ + char set_name[32]; /* set and interpreted by user-space */ + + grub_uint64_t ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/ + grub_uint32_t level; /* -4 (multipath), -1 (linear), 0,1,4,5 */ + grub_uint32_t layout; /* only for raid5 currently */ + grub_uint64_t size; /* used size of component devices, in 512byte sectors */ + + grub_uint32_t chunksize; /* in 512byte sectors */ + grub_uint32_t raid_disks; + grub_uint32_t bitmap_offset; /* sectors after start of superblock that bitmap starts + * NOTE: signed, so bitmap can be before superblock + * only meaningful of feature_map[0] is set. + */ + + /* These are only valid with feature bit '4' */ + grub_uint32_t new_level; /* new level we are reshaping to */ + grub_uint64_t reshape_position; /* next address in array-space for reshape */ + grub_uint32_t delta_disks; /* change in number of raid_disks */ + grub_uint32_t new_layout; /* new layout */ + grub_uint32_t new_chunk; /* new chunk size (bytes) */ + grub_uint8_t pad1[128-124]; /* set to 0 when written */ + + /* constant this-device information - 64 bytes */ + grub_uint64_t data_offset; /* sector start of data, often 0 */ + grub_uint64_t data_size; /* sectors in this device that can be used for data */ + grub_uint64_t super_offset; /* sector start of this superblock */ + grub_uint64_t recovery_offset;/* sectors before this offset (from data_offset) have been recovered */ + grub_uint32_t dev_number; /* permanent identifier of this device - not role in raid */ + grub_uint32_t cnt_corrected_read; /* number of read errors that were corrected by re-writing */ + grub_uint8_t device_uuid[16]; /* user-space setable, ignored by kernel */ + grub_uint8_t devflags; /* per-device flags. Only one defined...*/ +#define WriteMostly1 1 /* mask for writemostly flag in above */ + grub_uint8_t pad2[64-57]; /* set to 0 when writing */ + + /* array state information - 64 bytes */ + grub_uint64_t utime; /* 40 bits second, 24 btes microseconds */ + grub_uint64_t events; /* incremented when superblock updated */ + grub_uint64_t resync_offset; /* data before this offset (from data_offset) known to be in sync */ + grub_uint32_t sb_csum; /* checksum upto devs[max_dev] */ + grub_uint32_t max_dev; /* size of devs[] array to consider */ + grub_uint8_t pad3[64-32]; /* set to 0 when writing */ + + /* device state information. Indexed by dev_number. + * 2 bytes per device + * Note there are no per-device state flags. State information is rolled + * into the 'roles' value. If a device is spare or faulty, then it doesn't + * have a meaningful role. + */ + grub_uint16_t dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */ + +} __attribute__ ((packed)); + +typedef union __attribute__ ((__transparent_union__)) { + struct grub_raid_super_09 v0; + struct grub_raid_super_1 v1; +} grub_raid_super_t; + 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_raid_super_t sb; grub_uint32_t *uuid; + int i; /* The sector where the RAID superblock is stored, if available. */ size = grub_disk_get_size (disk); sector = NEW_SIZE_SECTORS (size); - if (grub_disk_read (disk, sector, 0, SB_BYTES, &sb)) + if (grub_disk_read (disk, sector, 0, sizeof(struct grub_raid_super_09), &(sb.v0))) return grub_errno; - /* Look whether there is a RAID superblock. */ - if (sb.md_magic != 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); - + if ((sb.v0).md_magic == SB_MAGIC) { /* FIXME: Check the checksum. */ /* Multipath. */ - if ((int) sb.level == -4) - sb.level = 1; + if ((int) (sb.v0).level == -4) + (sb.v0).level = 1; - if (sb.level != 0 && sb.level != 1 && sb.level != 4 && - sb.level != 5 && sb.level != 6 && sb.level != 10) + if ((sb.v0).level != 0 && (sb.v0).level != 1 && (sb.v0).level != 4 && + (sb.v0).level != 5 && (sb.v0).level != 6 && (sb.v0).level != 10) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unsupported RAID level: %d", sb.level); - - array->number = sb.md_minor; - array->level = sb.level; - array->layout = sb.layout; - array->total_devs = sb.raid_disks; - array->disk_size = (sb.size) ? sb.size * 2 : sector; - array->chunk_size = sb.chunk_size >> 9; - array->index = sb.this_disk.number; + "Unsupported RAID level: %d", (sb.v0).level); + + array->version = (sb.v0).major_version; + array->data_offset = 0; + array->number = (sb.v0).md_minor; + array->level = (sb.v0).level; + array->layout = (sb.v0).layout; + array->total_devs = (sb.v0).raid_disks; + array->disk_size = ((sb.v0).size) ? (sb.v0).size * 2 : sector; + array->chunk_size = (sb.v0).chunk_size >> 9; + array->index = (sb.v0).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.v0).set_uuid0; + uuid[1] = (sb.v0).set_uuid1; + uuid[2] = (sb.v0).set_uuid2; + uuid[3] = (sb.v0).set_uuid3; + + } + else { + + /* Look whether there is a RAID superblock. */ + grub_dprintf ("mdraid", "No signature found for %s at sector 0x%llx\n", disk->name, (unsigned long long) sector); + + sector = SB_SECTORS; + + if (grub_disk_read (disk, sector, 0, sizeof (struct grub_raid_super_1), &(sb.v1))) + return grub_errno; + + if (grub_le_to_cpu32((sb.v1).magic) != SB_MAGIC) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); + + grub_dprintf ("mdraid", "Signature found for %s at sector 0x%llx\n", disk->name, (unsigned long long) sector); + + if ((int) grub_le_to_cpu32((sb.v1).level) == -4) + (sb.v1).level = 1; + + switch(grub_le_to_cpu32((sb.v1).level)) { + case 0: + case 1: + case 4: + case 5: + case 6: + case 10: + break; + default: + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported RAID level: %d", grub_le_to_cpu32((sb.v1).level)); + } + + array->version = grub_le_to_cpu32((sb.v1).major_version); + array->data_offset = grub_le_to_cpu64((sb.v1).data_offset); + /* array->number = grub_le_to_cpu32((sb.v1).dev_number); */ + array->number = 0; + array->level = grub_le_to_cpu32((sb.v1).level); + array->layout = grub_le_to_cpu32((sb.v1).layout); + array->total_devs = grub_le_to_cpu32((sb.v1).raid_disks); + array->disk_size = grub_le_to_cpu64((sb.v1).size); + array->chunk_size = grub_le_to_cpu32((sb.v1).chunksize)*512; + /* array->index = grub_le_to_cpu32((sb.v1).dev_number); dev_number could be anything >=0 */ + array->index = disk->id; /* gives many prbs when id isn't modulo 0x80, devices are counted from 0 */ 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; + + for (i = 0; i < 4; i++) + uuid[i] = (sb.v1).set_uuid[i]; + + grub_dprintf ("mdraid", "(sb.v1).data_offset=%lld\n", (long long int) grub_le_to_cpu64((sb.v1).data_offset)); + grub_dprintf ("mdraid", "array->number=%d ((sb.v1).dev_number=%ld)\n", + array->number, grub_le_to_cpu64((sb.v1).dev_number)); + } + + grub_dprintf("mdraid", "Found RAID %d, vers. %d\n", (int) array->level, array->version); return 0; } diff --git a/disk/raid.c b/disk/raid.c index 2d544af..dce4a44 100644 --- a/disk/raid.c +++ b/disk/raid.c @@ -23,6 +23,9 @@ #include <grub/err.h> #include <grub/misc.h> #include <grub/raid.h> +#if 0 && ! defined (GRUB_UTIL) +#include <grub/env.h> +#endif /* Linked list of RAID arrays. */ static struct grub_raid_array *array_list; @@ -80,6 +83,8 @@ grub_raid_iterate (int (*hook) (const char *name)) for (array = array_list; array != NULL; array = array->next) { + grub_dprintf ("raid", "iterate(%s)\n", array->name); + if (grub_is_array_readable (array)) if (hook (array->name)) return 1; @@ -130,8 +135,8 @@ grub_raid_open (const char *name, grub_disk_t disk) 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); + grub_dprintf ("raid", "%s: total_devs=%d, disk_size=%lld, number=%lu\n", name, + array->total_devs, (unsigned long long) array->disk_size, disk->id); switch (array->level) { @@ -195,6 +200,13 @@ grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector, struct grub_raid_array *array = disk->data; grub_err_t err = 0; + grub_dprintf ("raid", "idx %d, devs %d, vers %d, layout %d, d...@0x%llx, chunk %lu\n", + array->index, array->total_devs, array->version, array->layout, + (unsigned long long) array->data_offset, (unsigned long) array->chunk_size); + grub_dprintf("raid", "\tread('%s', 0x%lx, 0x%lx)\n",disk->name, (unsigned long) sector, (unsigned long) size); + + sector += array->data_offset; + switch (array->level) { case 0: @@ -226,9 +238,11 @@ grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector, far_ofs *= array->chunk_size; } + grub_dprintf("raid", "\tdivmod64(%lld,%d,?)\n", + (unsigned long long) read_sector * near,array->total_devs); read_sector = grub_divmod64 (read_sector * near, array->total_devs, &disknr); - + grub_dprintf("raid", "read sector %ld, devs %d, disknr %d\n",(unsigned long) read_sector,array->total_devs,disknr); ofs *= array->chunk_size; read_sector *= ofs; @@ -250,6 +264,7 @@ grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector, { if (array->device[k]) { + grub_dprintf("raid", "read physical device '%s' %d\n",array->device[k]->name, k); if (grub_errno == GRUB_ERR_READ_ERROR) grub_errno = GRUB_ERR_NONE; @@ -479,6 +494,14 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, { struct grub_raid_array *array = 0, *p; +#if 0 && ! defined (GRUB_UTIL) + grub_env_set("debug","raid"); +#endif + grub_dprintf ("raid", "See whether the device is part of an array\n"); + if (disk->dev->id == GRUB_DISK_DEVICE_RAID_ID ) { + grub_dprintf ("raid", "Already a raid array!\n"); + return 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) @@ -497,13 +520,13 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, /* We found more members of the array than the array actually has according to its superblock. This shouldn't happen normally. */ - grub_dprintf ("raid", "array->nr_devs > array->total_devs (%d)?!?", + grub_dprintf ("raid", "array->nr_devs > array->total_devs (%d)?!?\n", array->total_devs); if (array->device[new_array->index] != NULL) /* We found multiple devices with the same number. Again, this shouldn't happen.*/ - grub_dprintf ("raid", "Found two disks with the number %d?!?", + grub_dprintf ("raid", "Found two disks with the number %d?!?\n", new_array->number); if (new_array->disk_size < array->disk_size) @@ -565,7 +588,12 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, return grub_errno; } - grub_dprintf ("raid", "Found array %s (%s)\n", array->name, + if (array->version == 1) + array->name = grub_xasprintf ("md_d%d", array->number); + else + array->name = grub_xasprintf ("md%d", array->number); + + grub_dprintf ("raid", "Found array %s (scanner is %s)\n", array->name, scanner_name); /* Add our new array to the list. */ @@ -574,10 +602,17 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, /* RAID 1 doesn't use a chunksize but code assumes one so set one. */ - if (array->level == 1) + if (array->level == 1) { array->chunk_size = 64; + grub_dprintf ("raid", "warning: chunk size is forced to %lu\n", (unsigned long) array->chunk_size); + } } + grub_dprintf ("raid", "Add device '%s', id %lu to the array %s at index %d\n", + disk->name, disk->id, array->name, new_array->index); +#if 0 && ! defined (GRUB_UTIL) + grub_dprintf ("device '%s' at position %d is id %lu\n", disk->name, new_array->index, disk->id); +#endif /* Add the device to the array. */ array->device[new_array->index] = disk; array->nr_devs++; @@ -633,6 +668,9 @@ grub_raid_register (grub_raid_t raid) (! insert_array (disk, &array, grub_raid_list->name))) return 0; + if (grub_errno == GRUB_ERR_OUT_OF_RANGE) + grub_dprintf ("raid", "'%s' is not a raid device\n", name); + /* This error usually means it's not raid, no need to display it. */ if (grub_errno != GRUB_ERR_OUT_OF_RANGE) diff --git a/include/grub/disk.h b/include/grub/disk.h index e60b1f3..92c73a1 100644 --- a/include/grub/disk.h +++ b/include/grub/disk.h @@ -105,6 +105,9 @@ struct grub_disk /* The id used by the disk cache manager. */ unsigned long id; + /* The start of data. */ + grub_uint64_t data_offset; + /* The partition information. This is machine-specific. */ struct grub_partition *partition; diff --git a/include/grub/raid.h b/include/grub/raid.h index 8fa4c38..848040c 100644 --- a/include/grub/raid.h +++ b/include/grub/raid.h @@ -34,6 +34,8 @@ struct grub_raid_array { + unsigned int version; + grub_disk_addr_t data_offset; int number; /* The device number, taken from md_minor so we are consistent with the device name in Linux. */ diff --git a/kern/device.c b/kern/device.c index cd019fd..5b96528 100644 --- a/kern/device.c +++ b/kern/device.c @@ -100,6 +100,8 @@ grub_device_iterate (int (*hook) (const char *name)) if (! dev) return 0; + grub_dprintf("device","iterate_disk(%s)\n", disk_name); + if (dev->disk && dev->disk->has_partitions) { struct part_ent *p; @@ -146,6 +148,8 @@ grub_device_iterate (int (*hook) (const char *name)) return 1; } + grub_dprintf ("device","iterate_partition(%s,%s)\n", disk->name, partition_name); + p->name = grub_xasprintf ("%s,%s", disk->name, partition_name); if (!p->name) { diff --git a/kern/disk.c b/kern/disk.c index 5c30e17..d77f9e0 100644 --- a/kern/disk.c +++ b/kern/disk.c @@ -24,6 +24,7 @@ #include <grub/misc.h> #include <grub/time.h> #include <grub/file.h> +#include <grub/raid.h> #define GRUB_CACHE_TIMEOUT 2 @@ -386,6 +387,9 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, char *tmp_buf; unsigned real_offset; + grub_dprintf ("disk", "\tReading '%s' @ sector 0x%llx:0x%x, len %llu, buf %p)\n", disk->name, + (unsigned long long) sector, (unsigned int) offset, (unsigned long long) size, buf); + /* First of all, check if the region is within the disk. */ if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE) { @@ -398,6 +402,8 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, real_offset = offset; + grub_dprintf ("disk", "\tAdjust range to 0x%llx:0x%x\n", (unsigned long long) sector, (unsigned) real_offset); + /* Allocate a temporary buffer. */ tmp_buf = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS); if (! tmp_buf) @@ -430,6 +436,10 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, else { /* Otherwise read data from the disk actually. */ + grub_dprintf ("disk", "\tread data from '%s' (%s) id=%lu at 0x%llx of size %d into cache %p\n", + disk->name, disk->dev->name, disk->id, + (unsigned long long )start_sector, GRUB_DISK_CACHE_SIZE, tmp_buf); + if (start_sector + GRUB_DISK_CACHE_SIZE > disk->total_sectors || (disk->dev->read) (disk, start_sector, GRUB_DISK_CACHE_SIZE, tmp_buf) @@ -450,6 +460,8 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, tmp_buf = p; + grub_dprintf ("disk", "\tread retry: sector 0x%llx len %d, cache %p\n", + (unsigned long long ) sector, num, tmp_buf); if ((disk->dev->read) (disk, sector, num, tmp_buf)) { grub_error_push (); @@ -465,13 +477,14 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, while (size) { grub_size_t to_read = (size > GRUB_DISK_SECTOR_SIZE) ? GRUB_DISK_SECTOR_SIZE : size; + grub_dprintf ("disk", "\tcall read hook\n"); (disk->read_hook) (sector, real_offset, to_read); if (grub_errno != GRUB_ERR_NONE) goto finish; sector++; - size -= to_read - real_offset; + size -= to_read - real_offset; /* size -= GRUB_DISK_SECTOR_SIZE - real_offset; */ real_offset = 0; } @@ -511,10 +524,12 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, buf = (char *) buf + len; size -= len; real_offset = 0; + grub_dprintf ("disk", "\tremains %lu bytes to read...\n", (unsigned long) size); } finish: + grub_dprintf ("disk", "End reading `%s'...\n", disk->name); grub_free (tmp_buf); return grub_errno; diff --git a/kern/fs.c b/kern/fs.c index 0c45637..7f2972a 100644 --- a/kern/fs.c +++ b/kern/fs.c @@ -26,6 +26,7 @@ #include <grub/types.h> #include <grub/mm.h> #include <grub/term.h> +#include <grub/partition.h> static grub_fs_t grub_fs_list; @@ -76,6 +77,11 @@ grub_fs_probe (grub_device_t device) if (device->disk) { + grub_dprintf ("fs", "Probe device %s (data offset %lu)...\n", device->disk->name, device->disk->data_offset); + grub_dprintf ("fs", "\tdevice has%s partition(s)\n", device->disk->has_partitions ? "": "n't"); + if (device->disk->partition) + grub_dprintf ("fs", "\tpartition offset %lu\n", ((grub_partition_t) device->disk->partition)->offset); + /* Make it sure not to have an infinite recursive calls. */ static int count = 0; diff --git a/kern/parser.c b/kern/parser.c index dd4608b..26e9c57 100644 --- a/kern/parser.c +++ b/kern/parser.c @@ -249,8 +249,12 @@ grub_parser_execute (char *source) } p = grub_strchr (source, '\n'); - if (p) - *p = 0; + if (p) { + char *c = p - 1; + /* sweep away trailing spaces */ + for (; c >= source && grub_isspace(*c); c--); + *++c = 0; + } *line = grub_strdup (source); if (p) diff --git a/normal/main.c b/normal/main.c index 5a54674..7e3d086 100644 --- a/normal/main.c +++ b/normal/main.c @@ -110,8 +110,14 @@ grub_file_getline (grub_file_t file) } } + /* GROSS: Get Rid Of Space Series */ + while (pos > 0 && grub_isspace(cmdline[pos - 1])) { + pos--; + } + cmdline[pos] = '\0'; + /* If the buffer is empty, don't return anything at all. */ if (pos == 0) { diff --git a/partmap/apple.c b/partmap/apple.c index a1a645a..7fc55f9 100644 --- a/partmap/apple.c +++ b/partmap/apple.c @@ -121,7 +121,7 @@ apple_partition_map_iterate (grub_disk_t disk, if (grub_be_to_cpu16 (aheader.magic) != GRUB_APPLE_HEADER_MAGIC) { grub_dprintf ("partition", - "bad magic (found 0x%x; wanted 0x%x\n", + "bad magic (found 0x%x; wanted 0x%x)\n", grub_be_to_cpu16 (aheader.magic), GRUB_APPLE_HEADER_MAGIC); goto fail; @@ -139,7 +139,7 @@ apple_partition_map_iterate (grub_disk_t disk, if (grub_be_to_cpu16 (apart.magic) != GRUB_APPLE_PART_MAGIC) { grub_dprintf ("partition", - "partition %d: bad magic (found 0x%x; wanted 0x%x\n", + "partition %d: bad magic (found 0x%x; wanted 0x%x)\n", partno, grub_be_to_cpu16 (apart.magic), GRUB_APPLE_PART_MAGIC); break; diff --git a/partmap/gpt.c b/partmap/gpt.c index cb1229b..9caabcc 100644 --- a/partmap/gpt.c +++ b/partmap/gpt.c @@ -24,6 +24,7 @@ #include <grub/dl.h> #include <grub/msdos_partition.h> #include <grub/gpt_partition.h> +#include <grub/raid.h> static grub_uint8_t grub_gpt_magic[8] = { @@ -58,6 +59,8 @@ gpt_partition_map_iterate (grub_disk_t disk, if (grub_disk_read (&raw, 0, 0, sizeof (mbr), &mbr)) return grub_errno; + grub_dprintf ("gpt", "Read the protective MBR of %s\n", disk->name); + /* Check if it is valid. */ if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE)) return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature"); @@ -73,7 +76,7 @@ gpt_partition_map_iterate (grub_disk_t disk, if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic))) return grub_error (GRUB_ERR_BAD_PART_TABLE, "no valid GPT header"); - grub_dprintf ("gpt", "Read a valid GPT header\n"); + grub_dprintf ("gpt", "Found a valid GPT header at sector 0x%x\n", 1); entries = grub_le_to_cpu64 (gpt.partitions); for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++) @@ -101,6 +104,7 @@ gpt_partition_map_iterate (grub_disk_t disk, if (hook (disk, &part)) return 1; } + else grub_dprintf ("gpt", "GPT entry %d: empty\n", i); last_offset += grub_le_to_cpu32 (gpt.partentry_size); if (last_offset == GRUB_DISK_SECTOR_SIZE) @@ -110,6 +114,8 @@ gpt_partition_map_iterate (grub_disk_t disk, } } + grub_dprintf ("gpt", "GPT last partition %d reached\n", gpt.maxpart - 1); + return 0; } @@ -126,6 +132,7 @@ gpt_partition_map_probe (grub_disk_t disk, const char *str) int find_func (grub_disk_t d __attribute__ ((unused)), const grub_partition_t partition) { + grub_dprintf ("gpt", "find_func() partition %d == %d\n", partnum, partition->index); if (partnum == partition->index) { p = (grub_partition_t) grub_malloc (sizeof (*p)); diff --git a/util/deviceiter.c b/util/deviceiter.c index b0a9e13..37d2d16 100644 --- a/util/deviceiter.c +++ b/util/deviceiter.c @@ -283,6 +283,12 @@ get_virtio_disk_name (char *name, int unit) } static void +get_mdraid_disk_name (char *name, int unit) +{ + sprintf (name, "/dev/md_d%d", unit); +} + +static void get_dac960_disk_name (char *name, int controller, int drive) { sprintf (name, "/dev/rd/c%dd%d", controller, drive); @@ -485,7 +491,20 @@ grub_util_iterate_devices (int NESTED_FUNC_ATTR (*hook) (const char *, int), return; } } +#if 0 + /* MDRAID disks. */ + for (i = 0; i < 8; i++) + { + char name[20]; + get_mdraid_disk_name (name, i); + if (check_device (name)) + { + if (hook (name, 0)) + return; + } + } +#endif /* ATARAID disks. */ for (i = 0; i < 8; i++) { diff --git a/util/getroot.c b/util/getroot.c index 8239363..090a8ae 100644 --- a/util/getroot.c +++ b/util/getroot.c @@ -535,34 +535,19 @@ grub_util_get_grub_dev (const char *os_dev) case GRUB_DEV_ABSTRACTION_RAID: - if (os_dev[7] == '_' && os_dev[8] == 'd') + if ((os_dev[7] == '_' || os_dev[7] == '/') && os_dev[8] == 'd') { - /* This a partitionable RAID device of the form /dev/md_dNNpMM. */ + /* This a partitionable RAID device of the form /dev/md[/_]dNNpMM. */ char *p, *q; - p = strdup (os_dev + sizeof ("/dev/md_d") - 1); + p = strdup (&os_dev[9]); q = strchr (p, 'p'); if (q) *q = ','; - grub_dev = xasprintf ("md%s", p); - free (p); - } - else if (os_dev[7] == '/' && os_dev[8] == 'd') - { - /* This a partitionable RAID device of the form /dev/md/dNNpMM. */ - - char *p, *q; - - p = strdup (os_dev + sizeof ("/dev/md/d") - 1); - - q = strchr (p, 'p'); - if (q) - *q = ','; - - grub_dev = xasprintf ("md%s", p); + grub_dev = xasprintf ("md_d%s", p); free (p); } else if (os_dev[7] >= '0' && os_dev[7] <= '9') diff --git a/util/grub-install.in b/util/grub-install.in index bb323d7..6d08929 100644 --- a/util/grub-install.in +++ b/util/grub-install.in @@ -306,7 +306,7 @@ config_opt= if [ "x${devabstraction_module}" = "x" ] ; then if [ x"${install_device}" != x ]; then - if echo "${install_device}" | grep -qx "(.*)" ; then + if echo "${install_device}" | grep -q "(.*)" ; then install_drive="${install_device}" else install_drive="`$grub_probe --target=drive --device ${install_device}`" diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in index daa110b..ffd925b 100644 --- a/util/grub-mkconfig.in +++ b/util/grub-mkconfig.in @@ -44,6 +44,7 @@ Generate a grub config file -o, --output=FILE output generated config to FILE [default=stdout] -h, --help print this message and exit -v, --version print the version information and exit + -t, --target=PATH mountpoint of target device Report bugs to <bug-g...@gnu.org>. EOF @@ -62,6 +63,9 @@ for option in "$@"; do shift grub_cfg=$1 ;; + --target=*) + ROOT=`echo "$option" | sed 's/--target=//'` + ;; --output=*) grub_cfg=`echo "$option" | sed 's/--output=//'` ;; @@ -118,17 +122,25 @@ if test -e ${grub_prefix}/device.map ; then : ; else ${grub_mkdevicemap} fi +if test -f ${sysconfdir}/default/grub ; then + . ${sysconfdir}/default/grub +fi + +if [ -z "${GRUB_DEVICE}" ]; then # Device containing our userland. Typically used for root= parameter. -GRUB_DEVICE="`${grub_probe} --target=device /`" + GRUB_DEVICE="`${grub_probe} --target=device ${ROOT}/`" +fi GRUB_DEVICE_UUID="`${grub_probe} --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`" || true +if [ -z "${GRUB_DEVICE_BOOT}" ]; then # Device containing our /boot partition. Usually the same as GRUB_DEVICE. -GRUB_DEVICE_BOOT="`${grub_probe} --target=device /boot`" + GRUB_DEVICE_BOOT="`${grub_probe} --target=device ${ROOT}/boot`" +fi GRUB_DEVICE_BOOT_UUID="`${grub_probe} --device ${GRUB_DEVICE_BOOT} --target=fs_uuid 2> /dev/null`" || true # Filesystem for the device containing our userland. Used for stuff like # choosing Hurd filesystem module. -GRUB_FS="`${grub_probe} --target=fs / 2> /dev/null || echo unknown`" +GRUB_FS="`${grub_probe} --target=fs ${ROOT}/ 2> /dev/null || echo unknown`" if test -f ${sysconfdir}/default/grub ; then . ${sysconfdir}/default/grub diff --git a/util/grub-probe.c b/util/grub-probe.c index ba2fe4c..4b5a876 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -99,9 +99,11 @@ probe_raid_level (grub_disk_t disk) if (!disk) return -1; + grub_util_info("disk->name=%s disk->dev->id=%d\n", disk->name, disk->dev->id); if (disk->dev->id != GRUB_DISK_DEVICE_RAID_ID) return -1; + grub_util_info("disk->name=%s disk->data->level=%d\n", disk->name, ((struct grub_raid_array *) disk->data)->level); return ((struct grub_raid_array *) disk->data)->level; } @@ -161,6 +163,7 @@ probe (const char *path, char *device_name) int raid_level; raid_level = probe_raid_level (dev->disk); + grub_util_info ("raid_level=%d", raid_level); if (raid_level >= 0) { is_raid = 1; @@ -168,10 +171,12 @@ probe (const char *path, char *device_name) is_raid6 |= (raid_level == 6); } - if ((is_lvm) && (dev->disk->dev->memberlist)) + if (!is_raid && dev->disk->dev->memberlist) list = dev->disk->dev->memberlist (dev->disk); + while (list) { + grub_util_info ("list->disk->name=%s", list->disk->name); raid_level = probe_raid_level (list->disk); if (raid_level >= 0) { @@ -210,6 +215,9 @@ probe (const char *path, char *device_name) /* Check if dev->disk itself is contained in a partmap. */ probe_partmap (dev->disk); + if (dev->disk->dev->id == GRUB_DISK_DEVICE_RAID_ID && dev->disk->data_offset > 0) + goto end; + /* In case of LVM/RAID, check the member devices as well. */ if (dev->disk->dev->memberlist) list = dev->disk->dev->memberlist (dev->disk); @@ -402,6 +410,9 @@ main (int argc, char *argv[]) } } + /* in case we are in debug mode */ + grub_env_set ("debug", ""); + if (verbosity > 1) grub_env_set ("debug", "all"); diff --git a/util/hostdisk.c b/util/hostdisk.c index 98d3d53..46c7d29 100644 --- a/util/hostdisk.c +++ b/util/hostdisk.c @@ -121,7 +121,7 @@ have_devfs (void) } #endif /* __linux__ */ -static int +int find_grub_drive (const char *name) { unsigned int i; @@ -335,6 +335,8 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) int is_partition = 0; char dev[PATH_MAX]; + grub_dprintf ("hostdisk", "opening device '%s', map[%ld]\n", map[disk->id].device, disk->id); + strcpy (dev, map[disk->id].device); if (disk->partition && sector >= disk->partition->start && strncmp (map[disk->id].device, "/dev/", 5) == 0) @@ -797,6 +799,17 @@ convert_system_partition_to_system_disk (const char *os_dev) return path; } + /* If this is a md Raid Array. */ + if (!strncmp ("md/d", p, 4) || !strncmp ("md_d", p, 4)) + { + /* /dev/md[_/]d[0-9]+(p[0-9]+)? */ + p = strchr (p, 'p'); + if (p) + *p = '\0'; +grub_dprintf("hostdisk", "path=%s\n", path); + return path; + } + /* If this is a Compaq Intelligent Drive Array. */ if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0) { diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index 4e2517e..5c59cca 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -34,10 +34,11 @@ #include <grub/term.h> #include <grub/i18n.h> #include <grub/util/raid.h> +#include <grub/raid.h> #include <grub/util/lvm.h> #include <grub/util/getroot.h> -static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT; +#include <grub/mm.h> #include <grub_setup_init.h> @@ -50,8 +51,12 @@ static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_P #include <dirent.h> #include <assert.h> #include "progname.h" +#include <grub/util/getroot.h> +#include <sys/ioctl.h> +#include <linux/fs.h> +#include <fcntl.h> + -#define _GNU_SOURCE 1 #include <getopt.h> #define DEFAULT_BOOT_FILE "boot.img" @@ -78,17 +83,49 @@ grub_refresh (void) fflush (stdout); } +/* awrite() comes from the MDADM project (http://neil.brown.name/blog/mdadm). */ +static char abuf[4096+4096]; +static int awrite(int fd, void *buf, int len) { + /* aligned write. + * On devices with a 4K sector size, we need to write + * the full sector. We pre-read if the sector is larger + * than the write. + * The address must be sector-aligned. + */ + int bsize; + char *b; + int n; + if(ioctl(fd, BLKSSZGET, &bsize) != 0 || + bsize <= len) + return write(fd, buf, len); + if(bsize > 4096) + return -1; + b =(char*)(((long)(abuf+4096))&~4095UL); + + n = read(fd, b, bsize); + if(n <= 0) + return n; + lseek(fd, -n, 1); + memcpy(b, buf, len); + n = write(fd, b, bsize); + if(n <= 0) + return n; + lseek(fd, len - n, 1); + return len; +} + 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, int fs_probe) + const char *root, const char *dest, int must_embed __attribute__ ((unused)), int force __attribute__ ((unused)), int fs_probe) { - char *boot_path, *core_path, *core_path_dev, *core_path_dev_full; + char *boot_path, *core_path; char *boot_img, *core_img; size_t boot_size, core_size; grub_uint16_t core_sectors; grub_device_t root_dev, dest_dev; - const char *dest_partmap; + grub_disk_t disk; + const char *partmap; grub_uint8_t *boot_drive; grub_disk_addr_t *kernel_sector; grub_uint16_t *boot_drive_check; @@ -96,52 +133,18 @@ setup (const char *dir, grub_int32_t *install_dos_part, *install_bsd_part; grub_int32_t dos_part, bsd_part; char *tmp_img; - int i; - grub_disk_addr_t first_sector; - grub_uint16_t current_segment - = GRUB_BOOT_MACHINE_KERNEL_SEG + (GRUB_DISK_SECTOR_SIZE >> 4); - grub_uint16_t last_length = GRUB_DISK_SECTOR_SIZE; - grub_file_t file; - FILE *fp; - struct { grub_uint64_t start; grub_uint64_t end; } embed_region; - embed_region.start = embed_region.end = ~0UL; - - auto void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, unsigned offset, - unsigned length); - auto void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, unsigned offset, - unsigned length); - - auto int NESTED_FUNC_ATTR find_usable_region_msdos (grub_disk_t disk, - const grub_partition_t p); - int NESTED_FUNC_ATTR find_usable_region_msdos (grub_disk_t disk __attribute__ ((unused)), - const grub_partition_t p) - { - struct grub_msdos_partition *pcdata = p->data; - - /* There's always an embed region, and it starts right after the MBR. */ - embed_region.start = 1; + grub_disk_addr_t first_sector = 0; + struct { grub_uint64_t start; grub_uint64_t end; int index;} embed_region = { ~0UL, ~0UL, 0 }; - /* For its end offset, include as many dummy partitions as we can. */ - if (! grub_msdos_partition_is_empty (pcdata->dos_type) - && ! grub_msdos_partition_is_bsd (pcdata->dos_type) - && embed_region.end > p->start) - embed_region.end = p->start; - - return 0; - } - - auto int NESTED_FUNC_ATTR find_usable_region_gpt (grub_disk_t disk, - const grub_partition_t p); - int NESTED_FUNC_ATTR find_usable_region_gpt (grub_disk_t disk __attribute__ ((unused)), - const grub_partition_t p) - { + auto int NESTED_FUNC_ATTR + part_gpt(grub_disk_t d __attribute__((unused)), const grub_partition_t p) { struct grub_gpt_partentry *gptdata = p->data; + grub_gpt_part_type_t grub_bios = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT; - /* If there's an embed region, it is in a dedicated partition. */ - if (! memcmp (&gptdata->type, &grub_gpt_partition_type_bios_boot, 16)) - { + if(!memcmp(&gptdata->type, &grub_bios, 16)) { embed_region.start = p->start; embed_region.end = p->start + p->len; + embed_region.index = p->index + 1; return 1; } @@ -149,48 +152,25 @@ setup (const char *dir, return 0; } - void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, unsigned offset, - unsigned length) - { - grub_util_info ("the first sector is <%llu,%u,%u>", - sector, offset, length); - - if (offset != 0 || length != GRUB_DISK_SECTOR_SIZE) - grub_util_error (_("the first sector of the core file is not sector-aligned")); - - first_sector = sector; - } - - void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, unsigned offset, - unsigned length) - { - struct grub_boot_blocklist *prev = block + 1; + auto int NESTED_FUNC_ATTR + part_msdos(grub_disk_t d __attribute__((unused)),const grub_partition_t p){ + struct grub_msdos_partition *pcdata = p->data; - grub_util_info ("saving <%llu,%u,%u> with the segment 0x%x", - sector, offset, length, (unsigned) current_segment); + /* There's always an embed region, and it starts right after the MBR */ + embed_region.start = 1; - if (offset != 0 || last_length != GRUB_DISK_SECTOR_SIZE) - grub_util_error (_("non-sector-aligned data is found in the core file")); + /* For its end offset, include as many dummy partitions as we can */ + if(grub_msdos_partition_is_empty(pcdata->dos_type)) + return 0; - if (block != first_block - && (grub_le_to_cpu64 (prev->start) - + grub_le_to_cpu16 (prev->len)) == sector) - prev->len = grub_cpu_to_le16 (grub_le_to_cpu16 (prev->len) + 1); - else - { - block->start = grub_cpu_to_le64 (sector); - block->len = grub_cpu_to_le16 (1); - block->segment = grub_cpu_to_le16 (current_segment); + if(embed_region.end > p->start) { + embed_region.end = p->start; - block--; - if (block->len) - grub_util_error (_("the sectors of the core file are too fragmented")); + return 1; } - last_length = length; - current_segment += GRUB_DISK_SECTOR_SIZE >> 4; + return 0; } - /* Read the boot image by the OS service. */ boot_path = grub_util_get_path (dir, boot_file); boot_size = grub_util_get_image_size (boot_path); @@ -241,9 +221,11 @@ setup (const char *dir, if (grub_env_set ("root", root) != GRUB_ERR_NONE) grub_util_error ("%s", grub_errmsg); + disk = dest_dev->disk; + /* Read the original sector from the disk. */ tmp_img = xmalloc (GRUB_DISK_SECTOR_SIZE); - if (grub_disk_read (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, tmp_img)) + if (grub_disk_read (disk, 0, 0, GRUB_DISK_SECTOR_SIZE, tmp_img)) grub_util_error ("%s", grub_errmsg); if (dest_dev->disk->partition && fs_probe) @@ -268,7 +250,7 @@ setup (const char *dir, GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START); /* Copy the possible partition table. */ - if (dest_dev->disk->has_partitions) + if (disk->has_partitions) memcpy (boot_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC, tmp_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC, GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC); @@ -278,7 +260,7 @@ setup (const char *dir, /* If DEST_DRIVE is a hard disk, enable the workaround, which is for buggy BIOSes which don't pass boot drive correctly. Instead, they pass 0x00 or 0x01 even when booted from 0x80. */ - if (dest_dev->disk->id & 0x80) + if (disk->id & 0x80) /* Replace the jmp (2 bytes) with double nop's. */ *boot_drive_check = 0x9090; @@ -311,23 +293,23 @@ setup (const char *dir, } else { + grub_util_info ("drive is part of prefix"); dos_part = grub_le_to_cpu32 (*install_dos_part); bsd_part = grub_le_to_cpu32 (*install_bsd_part); } - grub_util_info ("dos partition is %d, bsd partition is %d", - dos_part, bsd_part); + grub_util_info ("DOS partition is %d, BSD partition is %d", dos_part, bsd_part); - if (! dest_dev->disk->has_partitions) + if (! disk->has_partitions) { grub_util_warn (_("Attempting to install GRUB to a partitionless disk. This is a BAD idea.")); - goto unable_to_embed; + goto finish; } - if (dest_dev->disk->partition) + if (disk->partition) { grub_util_warn (_("Attempting to install GRUB to a partition instead of the MBR. This is a BAD idea.")); - goto unable_to_embed; + goto finish; } /* Unlike root_dev, with dest_dev we're interested in the partition map even @@ -337,51 +319,68 @@ setup (const char *dir, int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk __attribute__ ((unused)), const grub_partition_t p) { - dest_partmap = p->partmap->name; + partmap = p->partmap->name; return 1; } - dest_partmap = 0; - grub_partition_iterate (dest_dev->disk, identify_partmap); - if (! dest_partmap) - { - grub_util_warn (_("Attempting to install GRUB to a partitionless disk. This is a BAD idea.")); - goto unable_to_embed; + + partmap = 0; + grub_partition_iterate (disk, identify_partmap); + + if (! partmap) { + grub_util_warn ("Attempting to install GRUB to a partitionless disk %s", disk->name); + goto finish; } - if (strcmp (dest_partmap, "part_msdos") == 0) - grub_partition_iterate (dest_dev->disk, find_usable_region_msdos); - else if (strcmp (dest_partmap, "part_gpt") == 0) - grub_partition_iterate (dest_dev->disk, find_usable_region_gpt); - else - grub_util_error (_("No DOS-style partitions found")); + grub_util_info ("%s: identified partmap %s\n", disk->name, partmap); + + grub_util_info ("Scanning device %s for usable region (data offset=%lu)...\n", disk->name, disk->data_offset); + + int(*find)(grub_disk_t d, const grub_partition_t p); + + find =(strcmp(partmap, "part_msdos")? part_gpt : part_msdos); + grub_partition_iterate(disk, find); if (embed_region.end == embed_region.start) { - if (! strcmp (dest_partmap, "part_msdos")) + if (! strcmp (partmap, "part_msdos")) grub_util_warn (_("This msdos-style partition label has no post-MBR gap; embedding won't be possible!")); else grub_util_warn (_("This GPT partition label has no BIOS Boot Partition; embedding won't be possible!")); - goto unable_to_embed; + goto finish; } if ((unsigned long) core_sectors > embed_region.end - embed_region.start) { if (core_sectors > 62) grub_util_warn (_("Your core.img is unusually large. It won't fit in the embedding area.")); - else /* embed_region.end - embed_region.start < 62 */ + else if (embed_region.end - embed_region.start < 62) grub_util_warn (_("Your embedding area is unusually small. core.img won't fit in it.")); - goto unable_to_embed; + else + grub_util_warn ("Embedding area is too small for core.img."); + goto finish; } + if (!embed_region.index) + grub_util_info ("Embedding area of %s is right after MBR", disk->name); + else + grub_util_info ("Embedding area of %s is GPT BIOS partition %d", disk->name, embed_region.index); + + if (disk->dev->id == GRUB_DISK_DEVICE_RAID_ID) { + struct grub_raid_array *array = disk->data; + + first_sector = array->data_offset; + grub_util_info ("disk %s is a raid device\n", disk->name); + } + + grub_util_info ("first data sector for %s is %ld\n", disk->name, first_sector); - grub_util_info ("the core image will be embedded at sector 0x%llx", embed_region.start); *install_dos_part = grub_cpu_to_le32 (dos_part); *install_bsd_part = grub_cpu_to_le32 (bsd_part); /* The first blocklist contains the whole sectors. */ - first_block->start = grub_cpu_to_le64 (embed_region.start + 1); + first_block->start = grub_cpu_to_le64 (embed_region.start + first_sector + 1); /* These are filled elsewhere. Verify them just in case. */ assert (first_block->len == grub_host_to_target16 (core_sectors - 1)); @@ -394,165 +393,179 @@ setup (const char *dir, block->len = 0; block->segment = 0; - /* Write the core image onto the disk. */ - if (grub_disk_write (dest_dev->disk, embed_region.start, 0, core_size, core_img)) - grub_util_error ("%s", grub_errmsg); - /* FIXME: can this be skipped? */ - *boot_drive = 0xFF; - - *kernel_sector = grub_cpu_to_le64 (embed_region.start); - - /* Write the boot image onto the disk. */ - if (grub_disk_write (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, - boot_img)) - grub_util_error ("%s", grub_errmsg); + int fd; + char *os_dev = NULL; + int drive; - goto finish; + extern int find_grub_drive (const char *); + extern struct { + char *drive; + char *device; + } map[256]; -unable_to_embed: + char *partname = NULL; + char *p; - 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")); + drive = find_grub_drive(disk->name); - grub_util_warn (_("Embedding is not possible. GRUB can only be installed in this " - "setup by using blocklists. However, blocklists are UNRELIABLE and " - "its use is discouraged.")); - if (! force) - grub_util_error (_("if you really want blocklists, use --force")); + if (drive < 0) { - /* Make sure that GRUB reads the identical image as the OS. */ - tmp_img = xmalloc (core_size); - core_path_dev_full = grub_util_get_path (dir, core_file); - core_path_dev = make_system_path_relative_to_its_root (core_path_dev_full); - free (core_path_dev_full); + if (embed_region.index) + partname = xasprintf ("%s,%d", disk->name, embed_region.index); + else + partname = xasprintf ("%s", disk->name); - /* It is a Good Thing to sync two times. */ - sync (); - sync (); + os_dev = xasprintf ("/dev/%s", partname); + p = strchr (os_dev, ','); + if (p) *p = 'p'; -#define MAX_TRIES 5 + grub_util_info ("%s (%s) is a md%c RAID array, also no mapping is needed for it.", + os_dev, partname, (p)? *p:' '); + } + else { + os_dev = grub_malloc (PATH_MAX); - for (i = 0; i < MAX_TRIES; i++) - { - grub_util_info ((i == 0) ? _("attempting to read the core image `%s' from GRUB") - : _("attempting to read the core image `%s' from GRUB again"), - core_path_dev); + strcpy(os_dev, map[drive].device); - grub_disk_cache_invalidate_all (); + if (embed_region.index) { + size_t len = strlen (map[drive].device); + const char *format; - file = grub_file_open (core_path_dev); - if (file) - { - if (grub_file_size (file) != core_size) - grub_util_info ("succeeded in opening the core image but the size is different (%d != %d)", - (int) grub_file_size (file), (int) core_size); - else if (grub_file_read (file, tmp_img, core_size) - != (grub_ssize_t) core_size) - grub_util_info ("succeeded in opening the core image but cannot read %d bytes", - (int) core_size); - else if (memcmp (core_img, tmp_img, core_size) != 0) - { -#if 0 - FILE *dump; - FILE *dump2; - - dump = fopen ("dump.img", "wb"); - if (dump) - { - fwrite (tmp_img, 1, core_size, dump); - fclose (dump); + if (strcmp (os_dev + len - 5, "/disc") == 0) { + p = os_dev + len - 4; + format = "part%d"; + } + else if (os_dev[len - 1] >= '0' && os_dev[len - 1] <= '9') { + p = os_dev + len; + format = "p%d"; + } + else { + p = os_dev + len; + format = "%d"; } - dump2 = fopen ("dump2.img", "wb"); - if (dump2) - { - fwrite (core_img, 1, core_size, dump2); - fclose (dump2); + sprintf (p, format, embed_region.index); + } } -#endif - grub_util_info ("succeeded in opening the core image but the data is different"); + if (partname) + free(partname); + + fprintf(stderr, "Opening %s\n", os_dev); + + fd = open(os_dev, O_RDWR); + if(fd < 0) { + fprintf(stderr, "open(): invalid device %s\n",os_dev); + exit(4); } - else - { - grub_file_close (file); - break; + + free (os_dev); + + if (!embed_region.index) { + off_t offset = embed_region.start * GRUB_DISK_SECTOR_SIZE; + if (lseek(fd, offset , SEEK_SET) != offset) { + fprintf(stderr, "lseek(): unable to seek\n"); + exit(4); } - grub_file_close (file); + grub_util_info ("Write the core image (%d bytes) after the MBR", core_size); } else - grub_util_info ("couldn't open the core image"); + grub_util_info ("Write the core image (%d bytes) into partition %d", core_size, embed_region.index); - if (grub_errno) - grub_util_info ("error message = %s", grub_errmsg); + /* Write the core image onto the disk. */ + if (awrite (fd, core_img, core_size) != (int) core_size) + grub_util_error ("%s", grub_errmsg); - grub_errno = GRUB_ERR_NONE; - sync (); - sleep (1); - } + close(fd); - if (i == MAX_TRIES) - grub_util_error (_("cannot read `%s' correctly"), core_path_dev); + /* Write the boot image onto the disk. */ + /* FIXME: can this be skipped? */ + *boot_drive = 0xFF; - /* Clean out the blocklists. */ - block = first_block; - while (block->len) - { - block->start = 0; - block->len = 0; - block->segment = 0; + *kernel_sector = grub_cpu_to_le64 (embed_region.start + first_sector); + + grub_util_info ("Copy the boot image (%d bytes) into the legacy MBR", boot_size); + + grub_disk_memberlist_t list = NULL; + + if (disk->dev->id == GRUB_DISK_DEVICE_RAID_ID) { + grub_disk_memberlist_t tmp; - block--; + grub_util_info ("disk %s is a raid\n", disk->name); - if ((char *) block <= core_img) - grub_util_error (_("no terminator in the core image")); + if (disk->dev->memberlist) + list = disk->dev->memberlist (disk); + + while (list) + { + grub_util_info ("list->disk->name=%s", list->disk->name); + drive = find_grub_drive (list->disk->name); + if (drive < 0) { + grub_util_warn ("no mapping exists for %s", list->disk->name); + continue; + } + else { + grub_util_info ("found array %s", list->disk->name); + + os_dev = strdup(map[drive].device); + + fprintf(stderr, "Opening %s\n", os_dev); + + fd = open(os_dev, O_RDWR); + if(fd < 0) { + grub_util_warn("invalid device %s\n",os_dev); + exit(4); } - /* Now read the core image to determine where the sectors are. */ - file = grub_file_open (core_path_dev); - if (! file) + grub_util_info ("Copy the boot image into the legacy MBR of %s\n", os_dev); + + free (os_dev); + + /* Write the boot image onto the disk. */ + if (awrite (fd, boot_img, boot_size) != (int) boot_size) grub_util_error ("%s", grub_errmsg); - file->read_hook = save_first_sector; - if (grub_file_read (file, tmp_img, GRUB_DISK_SECTOR_SIZE) - != GRUB_DISK_SECTOR_SIZE) - grub_util_error (_("failed to read the first sector of the core image")); + } - block = first_block; - file->read_hook = save_blocklists; - if (grub_file_read (file, tmp_img, core_size - GRUB_DISK_SECTOR_SIZE) - != (grub_ssize_t) core_size - GRUB_DISK_SECTOR_SIZE) - grub_util_error (_("failed to read the rest sectors of the core image")); + tmp = list->next; + free (list); + list = tmp; + } - grub_file_close (file); + goto finish; + } - free (core_path_dev); - free (tmp_img); + drive = find_grub_drive(disk->name); - *kernel_sector = grub_cpu_to_le64 (first_sector); + if (drive < 0) { + grub_util_warn ("no mapping exists for %s", disk->name); + goto finish; + } - /* FIXME: can this be skipped? */ - *boot_drive = 0xFF; + grub_util_info ("found device %s", disk->name); - *install_dos_part = grub_cpu_to_le32 (dos_part); - *install_bsd_part = grub_cpu_to_le32 (bsd_part); + os_dev = strdup(map[drive].device); + + fprintf(stderr, "Opening %s\n", os_dev); + + fd = open(os_dev, O_RDWR); + if(fd < 0) { + grub_util_warn("invalid device %s\n",os_dev); + exit(4); + } - /* Write the first two sectors of the core image onto the disk. */ - grub_util_info ("opening the core image `%s'", core_path); - fp = fopen (core_path, "r+b"); - if (! fp) - grub_util_error (_("cannot open `%s'"), core_path); + grub_util_info ("Copy the boot image into the legacy MBR of %s\n", os_dev); - grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE * 2, fp); - fclose (fp); + free (os_dev); /* Write the boot image onto the disk. */ - if (grub_disk_write (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, boot_img)) + if (awrite (fd, boot_img, boot_size) != (int) boot_size) grub_util_error ("%s", grub_errmsg); + close(fd); + finish: /* Sync is a Good Thing. */ @@ -710,6 +723,9 @@ main (int argc, char *argv[]) } } + /* if we have forced the debug mode in the code */ + grub_env_set ("debug", ""); + if (verbosity > 1) grub_env_set ("debug", "all"); @@ -727,7 +743,7 @@ main (int argc, char *argv[]) } /* Initialize the emulated biosdisk driver. */ - grub_util_biosdisk_init (dev_map ? : DEFAULT_DEVICE_MAP); + grub_util_biosdisk_init (dev_map ? dev_map : DEFAULT_DEVICE_MAP); /* Initialize all modules. */ grub_init_all (); @@ -760,7 +776,7 @@ main (int argc, char *argv[]) } else { - root_dev = grub_util_get_grub_dev (grub_guess_root_device (dir ? : DEFAULT_DIRECTORY)); + root_dev = grub_util_get_grub_dev (grub_guess_root_device (dir ? dir : DEFAULT_DIRECTORY)); if (! root_dev) { grub_util_info ("guessing the root device failed, because of `%s'", @@ -773,35 +789,18 @@ main (int argc, char *argv[]) if (grub_util_lvm_isvolume (root_dev)) must_embed = 1; - if (root_dev[0] == 'm' && root_dev[1] == 'd' - && root_dev[2] >= '0' && root_dev[2] <= '9') - { + if (root_dev[0] == 'm' && root_dev[1] == 'd') { + int i = (root_dev[2] == '_')? 2 : 3; + if ( root_dev[i] >= '0' && root_dev[i] <= '9') /* 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') - { - char **devicelist; - int i; - - devicelist = grub_util_raid_getmembers (dest_dev); - - for (i = 0; devicelist[i]; i++) - { - setup (dir ? : DEFAULT_DIRECTORY, - boot_file ? : DEFAULT_BOOT_FILE, - core_file ? : DEFAULT_CORE_FILE, - root_dev, grub_util_get_grub_dev (devicelist[i]), 1, force, fs_probe); - } - } - else #endif /* Do the real work. */ - setup (dir ? : DEFAULT_DIRECTORY, - boot_file ? : DEFAULT_BOOT_FILE, - core_file ? : DEFAULT_CORE_FILE, + setup (dir ? dir : DEFAULT_DIRECTORY, + boot_file ? boot_file : DEFAULT_BOOT_FILE, + core_file ? core_file : DEFAULT_CORE_FILE, root_dev, dest_dev, must_embed, force, fs_probe); /* Free resources. */ @@ -817,3 +816,4 @@ main (int argc, char *argv[]) return 0; } + -- 1.7.1.1 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel