2013-10-15 14:16:04 +00:00
/* grub-setup.c - make GRUB usable */
/*
* GRUB - - GRand Unified Bootloader
* Copyright ( C ) 1999 , 2000 , 2001 , 2002 , 2003 , 2004 , 2005 , 2006 , 2007 , 2008 , 2009 , 2010 , 2011 Free Software Foundation , Inc .
*
* GRUB is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* GRUB is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with GRUB . If not , see < http : //www.gnu.org/licenses/>.
*/
# include <config.h>
# include <grub/types.h>
# include <grub/emu/misc.h>
# include <grub/util/misc.h>
# include <grub/device.h>
# include <grub/disk.h>
# include <grub/file.h>
# include <grub/fs.h>
# include <grub/partition.h>
# include <grub/env.h>
# include <grub/emu/hostdisk.h>
# include <grub/term.h>
# include <grub/i18n.h>
# ifdef GRUB_SETUP_SPARC64
# include <grub/util/ofpath.h>
# include <grub/sparc64/ieee1275/boot.h>
# include <grub/sparc64/ieee1275/kernel.h>
# else
# include <grub/i386/pc/boot.h>
# include <grub/i386/pc/kernel.h>
# endif
# include <stdio.h>
# include <unistd.h>
# include <string.h>
# include <stdlib.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <dirent.h>
# include <assert.h>
# include <grub/emu/getroot.h>
# include "progname.h"
# include <grub/reed_solomon.h>
# include <grub/msdos_partition.h>
# include <grub/crypto.h>
# include <grub/util/install.h>
2013-10-15 15:02:26 +00:00
# include <grub/emu/hostfile.h>
2013-10-15 14:16:04 +00:00
2013-10-15 15:02:26 +00:00
# include <errno.h>
2013-10-15 14:16:04 +00:00
/* On SPARC this program fills in various fields inside of the 'boot' and 'core'
* image files .
*
* The ' boot ' image needs to know the OBP path name of the root
* device . It also needs to know the initial block number of
* ' core ' ( which is ' diskboot ' concatenated with ' kernel ' and
* all the modules , this is created by grub - mkimage ) . This resulting
* ' boot ' image is 512 bytes in size and is placed in the second block
* of a partition .
*
* The initial ' diskboot ' block acts as a loader for the actual GRUB
* kernel . It contains the loading code and then a block list .
*
* The block list of ' core ' starts at the end of the ' diskboot ' image
* and works it ' s way backwards towards the end of the code of ' diskboot ' .
*
* We patch up the images with the necessary values and write out the
* result .
*/
# ifdef GRUB_SETUP_SPARC64
# define grub_target_to_host16(x) grub_be_to_cpu16(x)
# define grub_target_to_host32(x) grub_be_to_cpu32(x)
# define grub_target_to_host64(x) grub_be_to_cpu64(x)
# define grub_host_to_target16(x) grub_cpu_to_be16(x)
# define grub_host_to_target32(x) grub_cpu_to_be32(x)
# define grub_host_to_target64(x) grub_cpu_to_be64(x)
# elif defined (GRUB_SETUP_BIOS)
# define grub_target_to_host16(x) grub_le_to_cpu16(x)
# define grub_target_to_host32(x) grub_le_to_cpu32(x)
# define grub_target_to_host64(x) grub_le_to_cpu64(x)
# define grub_host_to_target16(x) grub_cpu_to_le16(x)
# define grub_host_to_target32(x) grub_cpu_to_le32(x)
# define grub_host_to_target64(x) grub_cpu_to_le64(x)
# else
# error Complete this
# endif
static void
write_rootdev ( grub_device_t root_dev ,
char * boot_img , grub_uint64_t first_sector )
{
# ifdef GRUB_SETUP_BIOS
{
grub_uint8_t * boot_drive ;
void * kernel_sector ;
boot_drive = ( grub_uint8_t * ) ( boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE ) ;
kernel_sector = ( boot_img + GRUB_BOOT_MACHINE_KERNEL_SECTOR ) ;
/* FIXME: can this be skipped? */
* boot_drive = 0xFF ;
grub_set_unaligned64 ( kernel_sector , grub_cpu_to_le64 ( first_sector ) ) ;
}
# endif
# ifdef GRUB_SETUP_SPARC64
{
void * kernel_byte ;
kernel_byte = ( boot_img + GRUB_BOOT_AOUT_HEADER_SIZE
+ GRUB_BOOT_MACHINE_KERNEL_BYTE ) ;
grub_set_unaligned64 ( kernel_byte ,
grub_cpu_to_be64 ( first_sector < < GRUB_DISK_SECTOR_BITS ) ) ;
}
# endif
}
# ifdef GRUB_SETUP_SPARC64
# define BOOT_SECTOR 1
# else
# define BOOT_SECTOR 0
# endif
/* Helper for setup. */
struct blocklists
{
struct grub_boot_blocklist * first_block , * block ;
# ifdef GRUB_SETUP_BIOS
grub_uint16_t current_segment ;
# endif
grub_uint16_t last_length ;
2013-10-15 15:02:26 +00:00
grub_disk_addr_t first_sector ;
2013-10-15 14:16:04 +00:00
} ;
/* Helper for setup. */
static void
save_blocklists ( grub_disk_addr_t sector , unsigned offset , unsigned length ,
void * data )
{
struct blocklists * bl = data ;
struct grub_boot_blocklist * prev = bl - > block + 1 ;
2013-11-01 22:28:03 +00:00
grub_uint64_t seclen ;
2013-10-15 14:16:04 +00:00
2013-12-17 15:04:47 +00:00
grub_util_info ( " saving <% " GRUB_HOST_PRIuLONG_LONG " ,%u,%u> " ,
( unsigned long long ) sector , offset , length ) ;
2013-10-15 14:16:04 +00:00
2013-10-15 15:02:26 +00:00
if ( bl - > first_sector = = ( grub_disk_addr_t ) - 1 )
{
2013-11-01 22:28:03 +00:00
if ( offset ! = 0 | | length < GRUB_DISK_SECTOR_SIZE )
2013-10-15 15:02:26 +00:00
grub_util_error ( " %s " , _ ( " the first sector of the core file is not sector-aligned " ) ) ;
bl - > first_sector = sector ;
2013-11-01 22:28:03 +00:00
sector + + ;
length - = GRUB_DISK_SECTOR_SIZE ;
if ( ! length )
return ;
2013-10-15 15:02:26 +00:00
}
2013-11-01 22:28:03 +00:00
if ( offset ! = 0 | | bl - > last_length ! = 0 )
2013-10-15 14:16:04 +00:00
grub_util_error ( " %s " , _ ( " non-sector-aligned data is found in the core file " ) ) ;
2013-11-01 22:28:03 +00:00
seclen = ( length + GRUB_DISK_SECTOR_SIZE - 1 ) > > GRUB_DISK_SECTOR_BITS ;
2013-10-15 14:16:04 +00:00
if ( bl - > block ! = bl - > first_block
& & ( grub_target_to_host64 ( prev - > start )
+ grub_target_to_host16 ( prev - > len ) ) = = sector )
{
2013-11-01 22:28:03 +00:00
grub_uint16_t t = grub_target_to_host16 ( prev - > len ) ;
t + = seclen ;
2013-10-15 14:16:04 +00:00
prev - > len = grub_host_to_target16 ( t ) ;
}
else
{
bl - > block - > start = grub_host_to_target64 ( sector ) ;
2013-11-01 22:28:03 +00:00
bl - > block - > len = grub_host_to_target16 ( seclen ) ;
2013-10-15 14:16:04 +00:00
# ifdef GRUB_SETUP_BIOS
bl - > block - > segment = grub_host_to_target16 ( bl - > current_segment ) ;
# endif
bl - > block - - ;
if ( bl - > block - > len )
grub_util_error ( " %s " , _ ( " the sectors of the core file are too fragmented " ) ) ;
}
2013-11-01 22:28:03 +00:00
bl - > last_length = length & ( GRUB_DISK_SECTOR_SIZE - 1 ) ;
2013-10-15 14:16:04 +00:00
# ifdef GRUB_SETUP_BIOS
2013-11-01 22:28:03 +00:00
bl - > current_segment + = seclen < < ( GRUB_DISK_SECTOR_BITS - 4 ) ;
2013-10-15 14:16:04 +00:00
# endif
}
# ifdef GRUB_SETUP_BIOS
/* Context for setup/identify_partmap. */
struct identify_partmap_ctx
{
grub_partition_map_t dest_partmap ;
grub_partition_t container ;
int multiple_partmaps ;
} ;
/* Helper for setup.
Unlike root_dev , with dest_dev we ' re interested in the partition map even
if dest_dev itself is a whole disk . */
static int
identify_partmap ( grub_disk_t disk __attribute__ ( ( unused ) ) ,
const grub_partition_t p , void * data )
{
struct identify_partmap_ctx * ctx = data ;
if ( p - > parent ! = ctx - > container )
return 0 ;
/* NetBSD and OpenBSD subpartitions have metadata inside a partition,
so they are safe to ignore .
*/
if ( grub_strcmp ( p - > partmap - > name , " netbsd " ) = = 0
| | grub_strcmp ( p - > partmap - > name , " openbsd " ) = = 0 )
return 0 ;
if ( ctx - > dest_partmap = = NULL )
{
ctx - > dest_partmap = p - > partmap ;
return 0 ;
}
if ( ctx - > dest_partmap = = p - > partmap )
return 0 ;
ctx - > multiple_partmaps = 1 ;
return 1 ;
}
# endif
# ifdef GRUB_SETUP_BIOS
# define SETUP grub_util_bios_setup
# elif GRUB_SETUP_SPARC64
# define SETUP grub_util_sparc_setup
# else
# error "Shouldn't happen"
# endif
void
SETUP ( const char * dir ,
const char * boot_file , const char * core_file ,
2013-12-07 11:00:37 +00:00
const char * dest , int force ,
2013-12-10 00:52:12 +00:00
int fs_probe , int allow_floppy ,
int add_rs_codes __attribute__ ( ( unused ) ) ) /* unused on sparc64 */
2013-10-15 14:16:04 +00:00
{
2013-10-15 15:02:26 +00:00
char * core_path ;
char * boot_img , * core_img , * boot_path ;
2013-10-15 14:16:04 +00:00
char * root = 0 ;
size_t boot_size , core_size ;
# ifdef GRUB_SETUP_BIOS
grub_uint16_t core_sectors ;
# endif
grub_device_t root_dev = 0 , dest_dev , core_dev ;
2013-10-15 15:02:26 +00:00
grub_util_fd_t fp ;
2013-10-15 14:16:04 +00:00
struct blocklists bl ;
2013-10-15 15:02:26 +00:00
bl . first_sector = ( grub_disk_addr_t ) - 1 ;
2013-10-15 14:16:04 +00:00
# ifdef GRUB_SETUP_BIOS
bl . current_segment =
GRUB_BOOT_I386_PC_KERNEL_SEG + ( GRUB_DISK_SECTOR_SIZE > > 4 ) ;
# endif
2013-11-01 22:28:03 +00:00
bl . last_length = 0 ;
2013-10-15 14:16:04 +00:00
/* 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 ) ;
if ( boot_size ! = GRUB_DISK_SECTOR_SIZE )
grub_util_error ( _ ( " the size of `%s' is not %u " ) ,
boot_path , GRUB_DISK_SECTOR_SIZE ) ;
boot_img = grub_util_read_image ( boot_path ) ;
free ( boot_path ) ;
core_path = grub_util_get_path ( dir , core_file ) ;
core_size = grub_util_get_image_size ( core_path ) ;
# ifdef GRUB_SETUP_BIOS
core_sectors = ( ( core_size + GRUB_DISK_SECTOR_SIZE - 1 )
> > GRUB_DISK_SECTOR_BITS ) ;
# endif
if ( core_size < GRUB_DISK_SECTOR_SIZE )
grub_util_error ( _ ( " the size of `%s' is too small " ) , core_path ) ;
# ifdef GRUB_SETUP_BIOS
if ( core_size > 0xFFFF * GRUB_DISK_SECTOR_SIZE )
grub_util_error ( _ ( " the size of `%s' is too large " ) , core_path ) ;
# endif
core_img = grub_util_read_image ( core_path ) ;
/* Have FIRST_BLOCK to point to the first blocklist. */
bl . first_block = ( struct grub_boot_blocklist * ) ( core_img
+ GRUB_DISK_SECTOR_SIZE
- sizeof ( * bl . block ) ) ;
grub_util_info ( " root is `%s', dest is `%s' " , root , dest ) ;
grub_util_info ( " Opening dest " ) ;
dest_dev = grub_device_open ( dest ) ;
if ( ! dest_dev )
grub_util_error ( " %s " , grub_errmsg ) ;
core_dev = dest_dev ;
{
char * * root_devices = grub_guess_root_devices ( dir ) ;
char * * cur ;
int found = 0 ;
for ( cur = root_devices ; * cur ; cur + + )
{
char * drive ;
grub_device_t try_dev ;
drive = grub_util_get_grub_dev ( * cur ) ;
if ( ! drive )
continue ;
try_dev = grub_device_open ( drive ) ;
if ( ! try_dev )
continue ;
if ( ! found & & try_dev - > disk - > id = = dest_dev - > disk - > id
& & try_dev - > disk - > dev - > id = = dest_dev - > disk - > dev - > id )
{
if ( root_dev )
grub_device_close ( root_dev ) ;
free ( root ) ;
root_dev = try_dev ;
root = drive ;
found = 1 ;
continue ;
}
if ( ! root_dev )
{
root_dev = try_dev ;
root = drive ;
continue ;
}
grub_device_close ( try_dev ) ;
free ( drive ) ;
}
if ( ! root_dev )
{
grub_util_error ( " guessing the root device failed, because of `%s' " ,
grub_errmsg ) ;
}
grub_util_info ( " guessed root_dev `%s' from "
" dir `%s' " , root_dev - > disk - > name , dir ) ;
}
grub_util_info ( " setting the root device to `%s' " , root ) ;
if ( grub_env_set ( " root " , root ) ! = GRUB_ERR_NONE )
grub_util_error ( " %s " , grub_errmsg ) ;
# ifdef GRUB_SETUP_BIOS
{
2013-10-15 15:02:26 +00:00
char * tmp_img ;
2013-10-15 14:16:04 +00:00
grub_uint8_t * boot_drive_check ;
2013-10-15 15:02:26 +00:00
/* 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 ) )
grub_util_error ( " %s " , grub_errmsg ) ;
2013-10-15 14:16:04 +00:00
boot_drive_check = ( grub_uint8_t * ) ( boot_img
+ GRUB_BOOT_MACHINE_DRIVE_CHECK ) ;
/* Copy the possible DOS BPB. */
memcpy ( boot_img + GRUB_BOOT_MACHINE_BPB_START ,
tmp_img + GRUB_BOOT_MACHINE_BPB_START ,
GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START ) ;
/* 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 ( ! allow_floppy & & ! grub_util_biosdisk_is_floppy ( dest_dev - > disk ) )
{
/* Replace the jmp (2 bytes) with double nop's. */
boot_drive_check [ 0 ] = 0x90 ;
boot_drive_check [ 1 ] = 0x90 ;
}
struct identify_partmap_ctx ctx = {
. dest_partmap = NULL ,
. container = dest_dev - > disk - > partition ,
. multiple_partmaps = 0
} ;
int is_ldm ;
grub_err_t err ;
grub_disk_addr_t * sectors ;
int i ;
grub_fs_t fs ;
unsigned int nsec , maxsec ;
grub_partition_iterate ( dest_dev - > disk , identify_partmap , & ctx ) ;
/* Copy the partition table. */
if ( ctx . dest_partmap | |
( ! allow_floppy & & ! grub_util_biosdisk_is_floppy ( dest_dev - > disk ) ) )
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 ) ;
free ( tmp_img ) ;
if ( ctx . container
& & grub_strcmp ( ctx . container - > partmap - > name , " msdos " ) = = 0
& & ctx . dest_partmap
& & ( ctx . container - > msdostype = = GRUB_PC_PARTITION_TYPE_NETBSD
| | ctx . container - > msdostype = = GRUB_PC_PARTITION_TYPE_OPENBSD ) )
{
grub_util_warn ( " %s " , _ ( " Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem. This is not supported yet. " ) ) ;
goto unable_to_embed ;
}
fs = grub_fs_probe ( dest_dev ) ;
if ( ! fs )
grub_errno = GRUB_ERR_NONE ;
is_ldm = grub_util_is_ldm ( dest_dev - > disk ) ;
if ( fs_probe )
{
if ( ! fs & & ! ctx . dest_partmap )
grub_util_error ( _ ( " unable to identify a filesystem in %s; safety check can't be performed " ) ,
dest_dev - > disk - > name ) ;
if ( fs & & ! fs - > reserved_first_sector )
/* TRANSLATORS: Filesystem may reserve the space just GRUB isn't sure about it. */
grub_util_error ( _ ( " %s appears to contain a %s filesystem which isn't known to "
" reserve space for DOS-style boot. Installing GRUB there could "
" result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
" by grub-setup (--skip-fs-probe disables this "
" check, use at your own risk) " ) , dest_dev - > disk - > name , fs - > name ) ;
if ( ctx . dest_partmap & & strcmp ( ctx . dest_partmap - > name , " msdos " ) ! = 0
& & strcmp ( ctx . dest_partmap - > name , " gpt " ) ! = 0
& & strcmp ( ctx . dest_partmap - > name , " bsd " ) ! = 0
& & strcmp ( ctx . dest_partmap - > name , " netbsd " ) ! = 0
& & strcmp ( ctx . dest_partmap - > name , " openbsd " ) ! = 0
& & strcmp ( ctx . dest_partmap - > name , " sunpc " ) ! = 0 )
/* TRANSLATORS: Partition map may reserve the space just GRUB isn't sure about it. */
grub_util_error ( _ ( " %s appears to contain a %s partition map which isn't known to "
" reserve space for DOS-style boot. Installing GRUB there could "
" result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
" by grub-setup (--skip-fs-probe disables this "
" check, use at your own risk) " ) , dest_dev - > disk - > name , ctx . dest_partmap - > name ) ;
if ( is_ldm & & ctx . dest_partmap & & strcmp ( ctx . dest_partmap - > name , " msdos " ) ! = 0
& & strcmp ( ctx . dest_partmap - > name , " gpt " ) ! = 0 )
grub_util_error ( _ ( " %s appears to contain a %s partition map and "
" LDM which isn't known to be a safe combination. "
" Installing GRUB there could "
" result in FILESYSTEM DESTRUCTION if valuable data "
" is overwritten "
" by grub-setup (--skip-fs-probe disables this "
" check, use at your own risk) " ) ,
dest_dev - > disk - > name , ctx . dest_partmap - > name ) ;
}
if ( ! ctx . dest_partmap & & ! fs & & ! is_ldm )
{
grub_util_warn ( " %s " , _ ( " Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea. " ) ) ;
goto unable_to_embed ;
}
if ( ctx . multiple_partmaps | | ( ctx . dest_partmap & & fs ) | | ( is_ldm & & fs ) )
{
grub_util_warn ( " %s " , _ ( " Attempting to install GRUB to a disk with multiple partition labels. This is not supported yet. " ) ) ;
goto unable_to_embed ;
}
if ( ctx . dest_partmap & & ! ctx . dest_partmap - > embed )
{
grub_util_warn ( _ ( " Partition style `%s' doesn't support embedding " ) ,
ctx . dest_partmap - > name ) ;
goto unable_to_embed ;
}
if ( fs & & ! fs - > embed )
{
grub_util_warn ( _ ( " File system `%s' doesn't support embedding " ) ,
fs - > name ) ;
goto unable_to_embed ;
}
nsec = core_sectors ;
2013-12-10 00:52:12 +00:00
if ( add_rs_codes )
maxsec = 2 * core_sectors ;
else
maxsec = core_sectors ;
2013-10-15 14:16:04 +00:00
if ( maxsec > ( ( 0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR )
> > GRUB_DISK_SECTOR_BITS ) )
maxsec = ( ( 0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR )
> > GRUB_DISK_SECTOR_BITS ) ;
if ( is_ldm )
err = grub_util_ldm_embed ( dest_dev - > disk , & nsec , maxsec ,
GRUB_EMBED_PCBIOS , & sectors ) ;
else if ( ctx . dest_partmap )
err = ctx . dest_partmap - > embed ( dest_dev - > disk , & nsec , maxsec ,
GRUB_EMBED_PCBIOS , & sectors ) ;
else
err = fs - > embed ( dest_dev , & nsec , maxsec ,
GRUB_EMBED_PCBIOS , & sectors ) ;
if ( ! err & & nsec < core_sectors )
{
err = grub_error ( GRUB_ERR_OUT_OF_RANGE ,
N_ ( " Your embedding area is unusually small. "
" core.img won't fit in it. " ) ) ;
}
if ( err )
{
grub_util_warn ( " %s " , grub_errmsg ) ;
grub_errno = GRUB_ERR_NONE ;
goto unable_to_embed ;
}
assert ( nsec < = maxsec ) ;
/* Clean out the blocklists. */
bl . block = bl . first_block ;
while ( bl . block - > len )
{
grub_memset ( bl . block , 0 , sizeof ( bl . block ) ) ;
bl . block - - ;
if ( ( char * ) bl . block < = core_img )
grub_util_error ( " %s " , _ ( " no terminator in the core image " ) ) ;
}
bl . block = bl . first_block ;
2013-10-15 15:02:26 +00:00
for ( i = 0 ; i < nsec ; i + + )
2013-10-15 14:16:04 +00:00
save_blocklists ( sectors [ i ] + grub_partition_get_start ( ctx . container ) ,
0 , GRUB_DISK_SECTOR_SIZE , & bl ) ;
/* Make sure that the last blocklist is a terminator. */
if ( bl . block = = bl . first_block )
bl . block - - ;
bl . block - > start = 0 ;
bl . block - > len = 0 ;
bl . block - > segment = 0 ;
2013-10-15 15:02:26 +00:00
write_rootdev ( root_dev , boot_img , bl . first_sector ) ;
2013-10-15 14:16:04 +00:00
2013-12-10 00:52:12 +00:00
/* Round up to the nearest sector boundary, and zero the extra memory */
core_img = xrealloc ( core_img , nsec * GRUB_DISK_SECTOR_SIZE ) ;
assert ( core_img & & ( nsec * GRUB_DISK_SECTOR_SIZE > = core_size ) ) ;
memset ( core_img + core_size , 0 , nsec * GRUB_DISK_SECTOR_SIZE - core_size ) ;
2013-10-15 14:16:04 +00:00
bl . first_block = ( struct grub_boot_blocklist * ) ( core_img
+ GRUB_DISK_SECTOR_SIZE
- sizeof ( * bl . block ) ) ;
grub_size_t no_rs_length ;
no_rs_length = grub_target_to_host16
( grub_get_unaligned16 ( core_img
+ GRUB_DISK_SECTOR_SIZE
+ GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH ) ) ;
if ( no_rs_length = = 0xffff )
grub_util_error ( " %s " , _ ( " core.img version mismatch " ) ) ;
2013-12-10 00:52:12 +00:00
if ( add_rs_codes )
{
grub_set_unaligned32 ( ( core_img + GRUB_DISK_SECTOR_SIZE
+ GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY ) ,
grub_host_to_target32 ( nsec * GRUB_DISK_SECTOR_SIZE - core_size ) ) ;
void * tmp = xmalloc ( core_size ) ;
grub_memcpy ( tmp , core_img , core_size ) ;
grub_reed_solomon_add_redundancy ( core_img + no_rs_length + GRUB_DISK_SECTOR_SIZE ,
core_size - no_rs_length - GRUB_DISK_SECTOR_SIZE ,
nsec * GRUB_DISK_SECTOR_SIZE
- core_size ) ;
assert ( grub_memcmp ( tmp , core_img , core_size ) = = 0 ) ;
free ( tmp ) ;
}
2013-10-15 14:16:04 +00:00
/* Write the core image onto the disk. */
for ( i = 0 ; i < nsec ; i + + )
grub_disk_write ( dest_dev - > disk , sectors [ i ] , 0 ,
GRUB_DISK_SECTOR_SIZE ,
core_img + i * GRUB_DISK_SECTOR_SIZE ) ;
grub_free ( sectors ) ;
goto finish ;
}
unable_to_embed :
# endif
if ( dest_dev - > disk - > dev - > id ! = root_dev - > disk - > dev - > id )
grub_util_error ( " %s " , _ ( " embedding is not possible, but this is required for "
" RAID and LVM install " ) ) ;
{
grub_fs_t fs ;
fs = grub_fs_probe ( root_dev ) ;
if ( ! fs )
grub_util_error ( _ ( " can't determine filesystem on %s " ) , root ) ;
if ( ! fs - > blocklist_install )
grub_util_error ( _ ( " filesystem `%s' doesn't support blocklists " ) ,
fs - > name ) ;
}
# ifdef GRUB_SETUP_BIOS
if ( dest_dev - > disk - > id ! = root_dev - > disk - > id
| | dest_dev - > disk - > dev - > id ! = root_dev - > disk - > dev - > id )
/* TRANSLATORS: cross-disk refers to /boot being on one disk
but MBR on another . */
grub_util_error ( " %s " , _ ( " embedding is not possible, but this is required for "
" cross-disk install " ) ) ;
# else
core_dev = root_dev ;
# endif
grub_util_warn ( " %s " , _ ( " Embedding is not possible. GRUB can only be installed in this "
" setup by using blocklists. However, blocklists are UNRELIABLE and "
" their use is discouraged. " ) ) ;
if ( ! force )
/* TRANSLATORS: Here GRUB refuses to continue with blocklist install. */
grub_util_error ( " %s " , _ ( " will not proceed with blocklists " ) ) ;
/* The core image must be put on a filesystem unfortunately. */
grub_util_info ( " will leave the core image on the filesystem " ) ;
grub_util_biosdisk_flush ( root_dev - > disk ) ;
/* Clean out the blocklists. */
bl . block = bl . first_block ;
while ( bl . block - > len )
{
bl . block - > start = 0 ;
bl . block - > len = 0 ;
# ifdef GRUB_SETUP_BIOS
bl . block - > segment = 0 ;
# endif
bl . block - - ;
if ( ( char * ) bl . block < = core_img )
grub_util_error ( " %s " , _ ( " no terminator in the core image " ) ) ;
}
bl . block = bl . first_block ;
2013-10-15 15:02:26 +00:00
grub_install_get_blocklist ( root_dev , core_path , core_img , core_size ,
save_blocklists , & bl ) ;
2013-10-15 14:16:04 +00:00
2013-10-15 15:02:26 +00:00
if ( bl . first_sector = = ( grub_disk_addr_t ) - 1 )
grub_util_error ( " %s " , _ ( " can't retrieve blocklists " ) ) ;
2013-10-15 14:16:04 +00:00
# ifdef GRUB_SETUP_SPARC64
{
char * boot_devpath ;
boot_devpath = ( char * ) ( boot_img
+ GRUB_BOOT_AOUT_HEADER_SIZE
+ GRUB_BOOT_MACHINE_BOOT_DEVPATH ) ;
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 ( 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 ) ;
boot_devpath [ GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
- GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1 ] = 0 ;
}
else
{
grub_util_info ( " non cross-disk install " ) ;
memset ( boot_devpath , 0 , GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
- GRUB_BOOT_MACHINE_BOOT_DEVPATH ) ;
}
grub_util_info ( " boot device path %s " , boot_devpath ) ;
}
# endif
2013-10-15 15:02:26 +00:00
write_rootdev ( root_dev , boot_img , bl . first_sector ) ;
2013-10-15 14:16:04 +00:00
/* Write the first two sectors of the core image onto the disk. */
grub_util_info ( " opening the core image `%s' " , core_path ) ;
2013-10-15 15:02:26 +00:00
fp = grub_util_fd_open ( core_path , GRUB_UTIL_FD_O_WRONLY ) ;
if ( ! GRUB_UTIL_FD_IS_VALID ( fp ) )
2013-10-15 14:16:04 +00:00
grub_util_error ( _ ( " cannot open `%s': %s " ) , core_path ,
2013-10-15 15:02:26 +00:00
grub_util_fd_strerror ( ) ) ;
if ( grub_util_fd_write ( fp , core_img , GRUB_DISK_SECTOR_SIZE * 2 )
! = GRUB_DISK_SECTOR_SIZE * 2 )
grub_util_error ( _ ( " cannot write to `%s': %s " ) ,
core_path , strerror ( errno ) ) ;
grub_util_fd_sync ( fp ) ;
grub_util_fd_close ( fp ) ;
2013-10-15 14:16:04 +00:00
grub_util_biosdisk_flush ( root_dev - > disk ) ;
grub_disk_cache_invalidate_all ( ) ;
{
char * buf , * ptr = core_img ;
size_t len = core_size ;
grub_uint64_t blk ;
grub_partition_t container = core_dev - > disk - > partition ;
grub_err_t err ;
core_dev - > disk - > partition = 0 ;
buf = xmalloc ( core_size ) ;
2013-10-15 15:02:26 +00:00
blk = bl . first_sector ;
2013-10-15 14:16:04 +00:00
err = grub_disk_read ( core_dev - > disk , blk , 0 , GRUB_DISK_SECTOR_SIZE , buf ) ;
if ( err )
grub_util_error ( _ ( " cannot read `%s': %s " ) , core_dev - > disk - > name ,
grub_errmsg ) ;
if ( grub_memcmp ( buf , ptr , GRUB_DISK_SECTOR_SIZE ) ! = 0 )
grub_util_error ( " %s " , _ ( " blocklists are invalid " ) ) ;
ptr + = GRUB_DISK_SECTOR_SIZE ;
len - = GRUB_DISK_SECTOR_SIZE ;
bl . block = bl . first_block ;
while ( bl . block - > len )
{
size_t cur = grub_target_to_host16 ( bl . block - > len ) < < GRUB_DISK_SECTOR_BITS ;
blk = grub_target_to_host64 ( bl . block - > start ) ;
if ( cur > len )
cur = len ;
err = grub_disk_read ( core_dev - > disk , blk , 0 , cur , buf ) ;
if ( err )
grub_util_error ( _ ( " cannot read `%s': %s " ) , core_dev - > disk - > name ,
grub_errmsg ) ;
if ( grub_memcmp ( buf , ptr , cur ) ! = 0 )
grub_util_error ( " %s " , _ ( " blocklists are invalid " ) ) ;
ptr + = cur ;
len - = cur ;
bl . block - - ;
if ( ( char * ) bl . block < = core_img )
grub_util_error ( " %s " , _ ( " no terminator in the core image " ) ) ;
}
2013-11-01 22:28:03 +00:00
if ( len )
grub_util_error ( " %s " , _ ( " blocklists are incomplete " ) ) ;
2013-10-15 14:16:04 +00:00
core_dev - > disk - > partition = container ;
free ( buf ) ;
}
# ifdef GRUB_SETUP_BIOS
finish :
# endif
/* Write the boot image onto the disk. */
if ( grub_disk_write ( dest_dev - > disk , BOOT_SECTOR ,
0 , GRUB_DISK_SECTOR_SIZE , boot_img ) )
grub_util_error ( " %s " , grub_errmsg ) ;
grub_util_biosdisk_flush ( root_dev - > disk ) ;
grub_util_biosdisk_flush ( dest_dev - > disk ) ;
free ( core_path ) ;
free ( core_img ) ;
free ( boot_img ) ;
grub_device_close ( dest_dev ) ;
grub_device_close ( root_dev ) ;
}