=== modified file 'grub-core/fs/affs.c' --- grub-core/fs/affs.c 2012-01-14 14:44:34 +0000 +++ grub-core/fs/affs.c 2012-01-27 11:55:52 +0000 @@ -571,6 +571,7 @@ .label = grub_affs_label, #ifdef GRUB_UTIL .reserved_first_sector = 0, + .blocklist_install = 1, #endif .next = 0 }; === modified file 'grub-core/fs/bfs.c' --- grub-core/fs/bfs.c 2011-10-30 15:10:18 +0000 +++ grub-core/fs/bfs.c 2012-01-27 11:56:05 +0000 @@ -1026,6 +1026,7 @@ #endif #ifdef GRUB_UTIL .reserved_first_sector = 1, + .blocklist_install = 1, #endif }; === modified file 'grub-core/fs/btrfs.c' --- grub-core/fs/btrfs.c 2012-01-25 14:10:56 +0000 +++ grub-core/fs/btrfs.c 2012-01-27 11:56:17 +0000 @@ -1653,6 +1653,7 @@ #ifdef GRUB_UTIL .embed = grub_btrfs_embed, .reserved_first_sector = 1, + .blocklist_install = 0, #endif }; === modified file 'grub-core/fs/cpio.c' --- grub-core/fs/cpio.c 2011-12-24 14:09:26 +0000 +++ grub-core/fs/cpio.c 2012-01-27 11:56:31 +0000 @@ -714,6 +714,7 @@ .close = grub_cpio_close, #ifdef GRUB_UTIL .reserved_first_sector = 0, + .blocklist_install = 0, #endif }; === modified file 'grub-core/fs/ext2.c' --- grub-core/fs/ext2.c 2012-01-14 10:55:20 +0000 +++ grub-core/fs/ext2.c 2012-01-27 11:56:43 +0000 @@ -971,6 +971,7 @@ .mtime = grub_ext2_mtime, #ifdef GRUB_UTIL .reserved_first_sector = 1, + .blocklist_install = 1, #endif .next = 0 }; === modified file 'grub-core/fs/fat.c' --- grub-core/fs/fat.c 2011-12-13 00:41:16 +0000 +++ grub-core/fs/fat.c 2012-01-27 11:56:56 +0000 @@ -1158,6 +1158,7 @@ #else .reserved_first_sector = 1, #endif + .blocklist_install = 1, #endif .next = 0 }; === modified file 'grub-core/fs/hfs.c' --- grub-core/fs/hfs.c 2012-01-14 22:34:33 +0000 +++ grub-core/fs/hfs.c 2012-01-27 11:57:13 +0000 @@ -1356,6 +1356,10 @@ .label = grub_hfs_label, .uuid = grub_hfs_uuid, .mtime = grub_hfs_mtime, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, + .blocklist_install = 1, +#endif .next = 0 }; === modified file 'grub-core/fs/hfsplus.c' --- grub-core/fs/hfsplus.c 2012-01-14 22:34:33 +0000 +++ grub-core/fs/hfsplus.c 2012-01-27 11:57:20 +0000 @@ -1084,6 +1084,7 @@ .uuid = grub_hfsplus_uuid, #ifdef GRUB_UTIL .reserved_first_sector = 1, + .blocklist_install = 1, #endif .next = 0 }; === modified file 'grub-core/fs/iso9660.c' --- grub-core/fs/iso9660.c 2011-12-13 15:35:12 +0000 +++ grub-core/fs/iso9660.c 2012-01-27 11:57:51 +0000 @@ -1092,6 +1092,10 @@ .label = grub_iso9660_label, .uuid = grub_iso9660_uuid, .mtime = grub_iso9660_mtime, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, + .blocklist_install = 1, +#endif .next = 0 }; === modified file 'grub-core/fs/jfs.c' --- grub-core/fs/jfs.c 2011-12-13 22:11:48 +0000 +++ grub-core/fs/jfs.c 2012-01-27 11:58:04 +0000 @@ -906,6 +906,10 @@ .close = grub_jfs_close, .label = grub_jfs_label, .uuid = grub_jfs_uuid, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, + .blocklist_install = 1, +#endif .next = 0 }; === modified file 'grub-core/fs/minix.c' --- grub-core/fs/minix.c 2011-12-25 21:44:42 +0000 +++ grub-core/fs/minix.c 2012-01-27 11:58:13 +0000 @@ -653,6 +653,10 @@ .open = grub_minix_open, .read = grub_minix_read, .close = grub_minix_close, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, + .blocklist_install = 1, +#endif .next = 0 }; === modified file 'grub-core/fs/nilfs2.c' --- grub-core/fs/nilfs2.c 2012-01-25 14:09:00 +0000 +++ grub-core/fs/nilfs2.c 2012-01-27 11:58:24 +0000 @@ -1178,6 +1178,7 @@ .mtime = grub_nilfs2_mtime, #ifdef GRUB_UTIL .reserved_first_sector = 1, + .blocklist_install = 0, #endif .next = 0 }; === modified file 'grub-core/fs/ntfs.c' --- grub-core/fs/ntfs.c 2012-01-20 14:01:35 +0000 +++ grub-core/fs/ntfs.c 2012-01-27 11:58:35 +0000 @@ -1248,6 +1248,7 @@ .uuid = grub_ntfs_uuid, #ifdef GRUB_UTIL .reserved_first_sector = 1, + .blocklist_install = 1, #endif .next = 0 }; === modified file 'grub-core/fs/reiserfs.c' --- grub-core/fs/reiserfs.c 2012-01-14 22:36:21 +0000 +++ grub-core/fs/reiserfs.c 2012-01-27 11:58:46 +0000 @@ -1387,6 +1387,10 @@ .close = grub_reiserfs_close, .label = grub_reiserfs_label, .uuid = grub_reiserfs_uuid, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, + .blocklist_install = 1, +#endif .next = 0 }; === modified file 'grub-core/fs/romfs.c' --- grub-core/fs/romfs.c 2011-12-13 22:15:56 +0000 +++ grub-core/fs/romfs.c 2012-01-27 11:58:54 +0000 @@ -452,6 +452,7 @@ .label = grub_romfs_label, #ifdef GRUB_UTIL .reserved_first_sector = 0, + .blocklist_install = 0, #endif .next = 0 }; === modified file 'grub-core/fs/sfs.c' --- grub-core/fs/sfs.c 2011-12-25 21:39:56 +0000 +++ grub-core/fs/sfs.c 2012-01-27 11:59:04 +0000 @@ -616,6 +616,7 @@ .label = grub_sfs_label, #ifdef GRUB_UTIL .reserved_first_sector = 0, + .blocklist_install = 1, #endif .next = 0 }; === modified file 'grub-core/fs/squash4.c' --- grub-core/fs/squash4.c 2012-01-27 12:09:57 +0000 +++ grub-core/fs/squash4.c 2012-01-27 12:11:00 +0000 @@ -935,6 +935,7 @@ .mtime = grub_squash_mtime, #ifdef GRUB_UTIL .reserved_first_sector = 0, + .blocklist_install = 0, #endif .next = 0 }; === modified file 'grub-core/fs/udf.c' --- grub-core/fs/udf.c 2011-12-13 12:58:33 +0000 +++ grub-core/fs/udf.c 2012-01-27 11:59:22 +0000 @@ -1097,6 +1097,10 @@ .read = grub_udf_read, .close = grub_udf_close, .label = grub_udf_label, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, + .blocklist_install = 1, +#endif .next = 0 }; === modified file 'grub-core/fs/ufs.c' --- grub-core/fs/ufs.c 2011-11-03 14:00:45 +0000 +++ grub-core/fs/ufs.c 2012-01-27 12:00:04 +0000 @@ -792,6 +792,10 @@ .label = grub_ufs_label, .uuid = grub_ufs_uuid, .mtime = grub_ufs_mtime, + /* FIXME: set reserved_first_sector. */ +#ifdef GRUB_UTIL + .blocklist_install = 1, +#endif .next = 0 }; === modified file 'grub-core/fs/xfs.c' --- grub-core/fs/xfs.c 2011-12-13 01:02:38 +0000 +++ grub-core/fs/xfs.c 2012-01-27 12:00:20 +0000 @@ -884,6 +884,7 @@ .uuid = grub_xfs_uuid, #ifdef GRUB_UTIL .reserved_first_sector = 0, + .blocklist_install = 1, #endif .next = 0 }; === modified file 'grub-core/fs/zfs/zfs.c' --- grub-core/fs/zfs/zfs.c 2012-01-27 12:50:21 +0000 +++ grub-core/fs/zfs/zfs.c 2012-01-27 12:51:06 +0000 @@ -3931,6 +3931,7 @@ #ifdef GRUB_UTIL .embed = grub_zfs_embed, .reserved_first_sector = 1, + .blocklist_install = 0, #endif .next = 0 }; === modified file 'include/grub/fs.h' --- include/grub/fs.h 2012-01-24 12:31:12 +0000 +++ include/grub/fs.h 2012-01-27 11:55:24 +0000 @@ -86,6 +86,9 @@ /* Whether this filesystem reserves first sector for DOS-style boot. */ int reserved_first_sector; + + /* Whether blocklist installs have a chance to work. */ + int blocklist_install; #endif }; typedef struct grub_fs *grub_fs_t; === modified file 'util/grub-setup.c' --- util/grub-setup.c 2012-01-24 13:39:29 +0000 +++ util/grub-setup.c 2012-01-27 12:24:59 +0000 @@ -51,6 +51,12 @@ #include #include +#ifdef __linux__ +#include +#include +#include +#endif + #define _GNU_SOURCE 1 #include @@ -141,7 +147,7 @@ size_t boot_size, core_size; grub_uint16_t core_sectors; grub_device_t root_dev, dest_dev; - struct grub_boot_blocklist *first_block, *block; + struct grub_boot_blocklist *first_block, *block, *last_block; char *tmp_img; int i; grub_disk_addr_t first_sector; @@ -150,7 +156,6 @@ = GRUB_BOOT_MACHINE_KERNEL_SEG + (GRUB_DISK_SECTOR_SIZE >> 4); #endif grub_uint16_t last_length = GRUB_DISK_SECTOR_SIZE; - grub_file_t file; FILE *fp; auto void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, @@ -490,11 +495,23 @@ "the root device is on a RAID array or LVM volume")); #ifdef GRUB_MACHINE_PCBIOS - if (dest_dev->disk->id != root_dev->disk->id) + if (dest_dev->disk->id != root_dev->disk->id + || dest_dev->disk->dev->id != root_dev->disk->dev->id) grub_util_error (_("embedding is not possible, but this is required for " "cross-disk install")); #endif + { + grub_fs_t fs; + fs = grub_fs_probe (root_dev); + if (!fs) + grub_util_error (_("can't determine filesystem")); + + if (!fs->blocklist_install) + grub_util_error (_("filesystem '%s' doesn't support blocklists"), + fs->name); + } + grub_util_warn (_("Embedding is not possible. GRUB can only be installed in this " "setup by using blocklists. However, blocklists are UNRELIABLE and " "their use is discouraged.")); @@ -512,10 +529,14 @@ grub_util_biosdisk_flush (root_dev->disk); +#ifndef __linux__ + #define MAX_TRIES 5 for (i = 0; i < MAX_TRIES; i++) { + grub_file_t file; + 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); @@ -578,6 +599,8 @@ if (i == MAX_TRIES) grub_util_error (_("cannot read `%s' correctly"), core_path_dev); +#endif + /* Clean out the blocklists. */ block = first_block; while (block->len) @@ -593,23 +616,130 @@ if ((char *) block <= core_img) grub_util_error (_("no terminator in the core image")); } - - /* Now read the core image to determine where the sectors are. */ - grub_file_filter_disable_compression (); - file = grub_file_open (core_path_dev); - if (! file) - 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")); - + last_block = block + 1; 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")); + +#ifdef __linux__ + { + grub_partition_t container = root_dev->disk->partition; + struct fiemap fie1; + int fd; + + /* 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, "rb"); + if (! fp) + grub_util_error (_("cannot open `%s'"), core_path); + fd = fileno (fp); + + grub_memset (&fie1, 0, sizeof (fie1)); + fie1.fm_length = core_size; + fie1.fm_flags = FIEMAP_FLAG_SYNC; + + if (ioctl (fd, FS_IOC_FIEMAP, &fie1) < 0) + { + int nblocks, i, j; + int bsize; + int mul; + + grub_util_warn ("FIEMAP failed. Reverting to FIBMAP"); + + if (ioctl (fd, FIGETBSZ, &bsize) < 0) + grub_util_error (_("can't get blocklist")); + if (bsize & (GRUB_DISK_SECTOR_SIZE - 1)) + grub_util_error (_("blocksize not divisible by 512")); + mul = bsize >> GRUB_DISK_SECTOR_BITS; + nblocks = (core_size + bsize - 1) / bsize; + for (i = 0; i < nblocks; i++) + { + unsigned blk = i; + grub_err_t err; + if (ioctl (fd, FIBMAP, &blk) < 0) + grub_util_error (_("can't get blocklist")); + + for (j = 0; j < mul; j++) + { + int rest = core_size - ((i * mul + j) << GRUB_DISK_SECTOR_BITS); + if (rest <= 0) + break; + if (rest > GRUB_DISK_SECTOR_SIZE) + rest = GRUB_DISK_SECTOR_SIZE; + if (i == 0 && j == 0) + save_first_sector (((grub_uint64_t) blk) * mul + + grub_partition_get_start (container), + 0, rest); + else + save_blocklists (((grub_uint64_t) blk) * mul + j + + grub_partition_get_start (container), + 0, rest); + } + } + } + else + { + struct fiemap *fie2; + int i, j; + fie2 = xmalloc (sizeof (*fie2) + + fie1.fm_mapped_extents + * sizeof (fie1.fm_extents[1])); + memset (fie2, 0, sizeof (*fie2) + + fie1.fm_mapped_extents * sizeof (fie2->fm_extents[1])); + fie2->fm_length = core_size; + fie2->fm_flags = FIEMAP_FLAG_SYNC; + fie2->fm_extent_count = fie1.fm_mapped_extents; + if (ioctl (fd, FS_IOC_FIEMAP, fie2) < 0) + grub_util_error ("FIEMAP fails"); + for (i = 0; i < fie2->fm_mapped_extents; i++) + { + for (j = 0; + j < ((fie2->fm_extents[i].fe_length + + GRUB_DISK_SECTOR_SIZE - 1) + >> GRUB_DISK_SECTOR_BITS); + j++) + { + size_t len = (fie2->fm_extents[i].fe_length + - j * GRUB_DISK_SECTOR_SIZE); + if (len > GRUB_DISK_SECTOR_SIZE) + len = GRUB_DISK_SECTOR_SIZE; + if (i == 0 && j == 0) + save_first_sector ((fie2->fm_extents[i].fe_physical + >> GRUB_DISK_SECTOR_BITS) + + j, + fie2->fm_extents[i].fe_physical + & (GRUB_DISK_SECTOR_SIZE - 1), len); + else + save_blocklists ((fie2->fm_extents[i].fe_physical + >> GRUB_DISK_SECTOR_BITS) + + j, + fie2->fm_extents[i].fe_physical + & (GRUB_DISK_SECTOR_SIZE - 1), len); + + + } + } + } + fclose (fp); + } +#else + { + /* Now read the core image to determine where the sectors are. */ + grub_file_filter_disable_compression (); + file = grub_file_open (core_path_dev); + if (! file) + 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")); + + 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")); + grub_file_close (file); + } +#endif #ifdef GRUB_MACHINE_IEEE1275 { @@ -617,11 +747,12 @@ boot_devpath = (char *) (boot_img + GRUB_BOOT_AOUT_HEADER_SIZE + GRUB_BOOT_MACHINE_BOOT_DEVPATH); - if (file->device->disk->id != dest_dev->disk->id) + if (dest_dev->disk->id != root_dev->disk->id + || dest_dev->disk->dev->id != root_dev->disk->dev->id) { const char *dest_ofpath; dest_ofpath - = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (file->device->disk)); + = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (root_dev->disk)); grub_util_info ("dest_ofpath is `%s'", dest_ofpath); strncpy (boot_devpath, dest_ofpath, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1); @@ -638,8 +769,6 @@ } #endif - grub_file_close (file); - free (core_path_dev); free (tmp_img); @@ -652,8 +781,80 @@ grub_util_error (_("cannot open `%s'"), core_path); grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE * 2, fp); + fsync (fileno (fp)); fclose (fp); + grub_disk_cache_invalidate_all (); + + { + char *buf, *ptr = core_img; + size_t len = core_size; + grub_uint64_t blk; + grub_partition_t container = root_dev->disk->partition; + grub_err_t err; + + root_dev->disk->partition = 0; + + buf = xmalloc (core_size); + blk = first_sector; + err = grub_disk_read (dest_dev->disk, blk, 0, GRUB_DISK_SECTOR_SIZE, buf); + if (err) + grub_util_error (_("read failed: %s"), grub_errmsg); + if (grub_memcmp (buf, ptr, (char *) last_block - core_img) != 0) + { + int i; + grub_printf ("%ld\n", ptr - core_img); + for (i = 0; i < 512; i++) + grub_printf ("%02x%c", (unsigned char) ptr[i], + ((i & 0xf) == 0xf) ? '\n': ' '); + grub_printf ("--\n"); + for (i = 0; i < 512; i++) + grub_printf ("%02x%c", (unsigned char) buf[i], + ((i & 0xf) == 0xf) ? '\n': ' '); + grub_util_error (_("blocklists are invalid")); + } + + ptr += GRUB_DISK_SECTOR_SIZE; + len -= GRUB_DISK_SECTOR_SIZE; + + block = first_block; + while (block->len) + { + size_t cur = grub_target_to_host16 (block->len) << GRUB_DISK_SECTOR_BITS; + blk = grub_target_to_host64 (block->start); + + if (cur > len) + cur = len; + + err = grub_disk_read (dest_dev->disk, blk, 0, cur, buf); + if (err) + grub_util_error (_("read failed: %s"), grub_errmsg); + + if (grub_memcmp (buf, ptr, cur) != 0) + { + int i; + grub_printf ("%ld\n", ptr - core_img); + for (i = 0; i < cur; i++) + grub_printf ("%02x%c", (unsigned char) ptr[i], + ((i & 0xf) == 0xf) ? '\n': ' '); + grub_printf ("--\n"); + for (i = 0; i < cur; i++) + grub_printf ("%02x%c", (unsigned char) buf[i], + ((i & 0xf) == 0xf) ? '\n': ' '); + grub_util_error (_("blocklists are invalid")); + } + + ptr += cur; + len -= cur; + block--; + + if ((char *) block <= core_img) + grub_util_error (_("no terminator in the core image")); + } + root_dev->disk->partition = container; + free (buf); + } + finish: /* Write the boot image onto the disk. */