2004-04-04 13:46:03 +00:00
/* grub-setup.c - make GRUB usable */
2003-01-02 20:12:33 +00:00
/*
2004-04-04 13:46:03 +00:00
* GRUB - - GRand Unified Bootloader
2011-10-09 19:13:00 +00:00
* Copyright ( C ) 1999 , 2000 , 2001 , 2002 , 2003 , 2004 , 2005 , 2006 , 2007 , 2008 , 2009 , 2010 , 2011 Free Software Foundation , Inc .
2003-01-02 20:12:33 +00:00
*
2007-07-21 23:32:33 +00:00
* GRUB is free software : you can redistribute it and / or modify
2003-01-02 20:12:33 +00:00
* it under the terms of the GNU General Public License as published by
2007-07-21 23:32:33 +00:00
* the Free Software Foundation , either version 3 of the License , or
2003-01-02 20:12:33 +00:00
* ( at your option ) any later version .
*
2007-07-21 23:32:33 +00:00
* GRUB is distributed in the hope that it will be useful ,
2003-01-02 20:12:33 +00:00
* 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
2007-07-21 23:32:33 +00:00
* along with GRUB . If not , see < http : //www.gnu.org/licenses/>.
2003-01-02 20:12:33 +00:00
*/
# include <config.h>
2004-04-04 13:46:03 +00:00
# include <grub/types.h>
2010-05-06 06:04:04 +00:00
# include <grub/emu/misc.h>
2004-04-04 13:46:03 +00:00
# include <grub/util/misc.h>
# include <grub/device.h>
# include <grub/disk.h>
# include <grub/file.h>
# include <grub/fs.h>
2004-12-04 Marco Gerards <metgerards@student.han.nl>
Modulize the partition map support and add support for the amiga
partition map.
* commands/ls.c: Include <grub/partition.h> instead of
<grub/machine/partition.h>.
* kern/disk.c: Likewise.
* kern/rescue.c: Likewise.
* loader/i386/pc/chainloader.c: Likewise.
* normal/cmdline.c: Likewise.
* kern/powerpc/ieee1275/init.c: Likewise.
(grub_machine_init): Call `grub_pc_partition_map_init',
`grub_amiga_partition_map_init' and
`grub_apple_partition_map_init'.
* conf/i386-pc.rmk (kernel_img_SOURCES): Remove
`disk/i386/pc/partition.c'. Add `kern/partition.c'.
(kernel_img_HEADERS): Remove `machine/partition.h'. Add
`partition.h' and `pc_partition.h'.
(grub_setup_SOURCES): Remove
`disk/i386/pc/partition.c'. Add `kern/partition.c',
`partmap/amiga.c', `partmap/apple.c' and `partmap/pc.c'.
(grub_emu_SOURCES): Likewise.
(pkgdata_MODULES): Add `amiga.mod', `apple.mod' and `pc.mod'.
(amiga_mod_SOURCES, amiga_mod_CFLAGS, apple_mod_SOURCES)
(apple_mod_CFLAGS, pc_mod_SOURCES, pc_mod_CFLAGS): New variables.
* conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): Remove
`disk/powerpc/ieee1275/partition.c'. Add `kern/partition.c',
`partmap/amiga.c', `partmap/apple.c' and `partmap/pc.c'.
(grubof_SOURCES): Likewise.
* disk/i386/pc/partition.c: File removed.
* disk/powerpc/ieee1275/partition.c: Likewise.
* include/grub/powerpc/ieee1275/partition.h: Likewise.
* include/grub/i386/pc/partition.h: Likewise.
* kern/partition.c: New file.
* partmap/amiga.c: Likewise.
* partmap/apple.c: Likewise.
* partmap/pc.c: Likewise.
* include/grub/partition.h: Likewise..
* include/grub/pc_partition.h: Likewise.
* util/grub-emu.c: Include <grub/partition.h> instead of
<grub/machine/partition.h>.
(main): Call `grub_pc_partition_map_init',
`grub_amiga_partition_map_init' and
`grub_apple_partition_map_init' and deinitialize afterwards.
* util/i386/pc/biosdisk.c: Include `#include
<grub/partition.h>' and `include <grub/pc_partition.h>' instead of
`<grub/machine/partition.h>'.
* util/i386/pc/grub-setup.c: Likewise.
* util/i386/pc/biosdisk.c: Likewise.
(grub_util_biosdisk_get_grub_dev): Only access the PC specific
partition information in case of a PC partition.
* util/i386/pc/grub-setup.c: Include `#include
<grub/partition.h>' and `include <grub/pc_partition.h>' instead of
`<grub/machine/partition.h>'.
(setup): Only access the PC specific partition information in case
of a PC partition.
2004-12-04 18:45:46 +00:00
# include <grub/partition.h>
2005-07-20 20:30:46 +00:00
# include <grub/env.h>
2010-05-06 06:04:04 +00:00
# include <grub/emu/hostdisk.h>
2006-04-23 13:37:36 +00:00
# include <grub/term.h>
2009-11-18 23:20:22 +00:00
# include <grub/i18n.h>
2006-10-14 Yoshinori K. Okuji <okuji@enbug.org>
* DISTLIST: Added commands/echo.c, disk/lvm.c, disk/raid.c,
include/grub/bitmap.h, include/grub/lvm.h, include/grub/raid.h,
include/grub/i386/pc/vbeutil.h, include/grub/util/lvm.h,
include/grub/util/raid.h, util/lvm.c, util/raid.c, video/bitmap.c,
video/readers/tga.c and video/i386/pc/vbeutil.c.
2006-10-14 Jeroen Dekkers <jeroen@dekkers.cx>
Added support for RAID and LVM.
* disk/lvm.c: New file.
* disk/raid.c: Likewise.
* include/grub/lvm.h: Likewise.
* include/grub/raid.h: Likewise.
* include/grub/util/lvm.h: Likewise.
* include/grub/util/raid.h: Likewise.
* util/lvm.c: Likewise.
* util/raid.c: Likewise.
* include/grub/disk.h (grub_disk_dev_id): Add
GRUB_DISK_DEVICE_RAID_ID and GRUB_DISK_DEVICE_LVM_ID.
(grub_disk_get_size): New prototype.
* kern/disk.c (grub_disk_open): Check whether grub_partition_probe()
returns a partition.
(grub_disk_get_size): New function.
* kern/i386/pc/init.c (make_install_device): Copy the prefix
verbatim if grub_install_dos_part is -2.
* util/i386/pc/getroot.c (grub_guess_root_device): Support RAID
and LVM devices.
* util/i386/pc/grub-setup.c (setup): New argument
MUST_EMBED. Force embedding of GRUB when the argument is
true. Close FILE before returning.
(main): Add support for RAID and LVM.
* conf/common.rmk: Add RAID and LVM modules.
* conf/i386-pc.rmk (grub_setup_SOURCES): Add util/raid.c and
util/lvm.c.
(grub_emu_SOURCES): Add disk/raid.c and disk/lvm.c.
* kern/misc.c (grub_strstr): New function.
* include/grub/misc.h (grub_strstr): New prototype.
2006-10-14 15:24:53 +00:00
# include <grub/util/lvm.h>
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_SPARC64
2010-09-14 19:07:39 +00:00
# include <grub/util/ofpath.h>
2012-02-27 13:24:22 +00:00
# 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>
2010-09-14 19:07:39 +00:00
# endif
2008-02-19 14:00:11 +00:00
2003-01-02 20:12:33 +00:00
# include <stdio.h>
# include <unistd.h>
# include <string.h>
# include <stdlib.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <dirent.h>
2010-01-03 22:34:03 +00:00
# include <assert.h>
2010-09-14 19:07:39 +00:00
# include <grub/emu/getroot.h>
2009-11-18 23:20:22 +00:00
# include "progname.h"
2010-09-24 12:05:47 +00:00
# include <grub/reed_solomon.h>
2011-01-07 12:27:34 +00:00
# include <grub/msdos_partition.h>
2011-10-23 21:22:38 +00:00
# include <include/grub/crypto.h>
2003-01-02 20:12:33 +00:00
2012-02-27 20:36:58 +00:00
# ifdef __linux__
# include <sys/ioctl.h>
# include <linux/fs.h>
# include <linux/fiemap.h>
# endif
2003-01-02 20:12:33 +00:00
# define _GNU_SOURCE 1
2010-09-20 10:37:37 +00:00
# include <argp.h>
2003-01-02 20:12:33 +00:00
2010-09-14 19:07:39 +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 .
*/
2003-01-02 20:12:33 +00:00
# define DEFAULT_BOOT_FILE "boot.img"
# define DEFAULT_CORE_FILE "core.img"
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_SPARC64
2010-09-14 19:07:39 +00:00
# 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)
2012-02-27 13:24:22 +00:00
# elif defined (GRUB_SETUP_BIOS)
2010-04-26 19:11:16 +00:00
# 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)
2010-09-14 19:07:39 +00:00
# else
# error Complete this
# endif
static void
2012-09-19 01:41:51 +00:00
write_rootdev ( grub_device_t root_dev ,
2010-09-14 19:07:39 +00:00
char * boot_img , grub_uint64_t first_sector )
{
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_BIOS
2010-09-14 19:07:39 +00:00
{
grub_uint8_t * boot_drive ;
2012-06-07 12:07:02 +00:00
void * kernel_sector ;
2010-09-14 19:07:39 +00:00
boot_drive = ( grub_uint8_t * ) ( boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE ) ;
2012-06-07 12:07:02 +00:00
kernel_sector = ( boot_img + GRUB_BOOT_MACHINE_KERNEL_SECTOR ) ;
2010-09-14 19:07:39 +00:00
/* FIXME: can this be skipped? */
* boot_drive = 0xFF ;
2012-06-07 12:07:02 +00:00
grub_set_unaligned64 ( kernel_sector , grub_cpu_to_le64 ( first_sector ) ) ;
2010-09-14 19:07:39 +00:00
}
# endif
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_SPARC64
2010-09-14 19:07:39 +00:00
{
2012-06-07 12:07:02 +00:00
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 ) ) ;
2010-09-14 19:07:39 +00:00
}
# endif
}
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_SPARC64
2010-09-14 19:07:39 +00:00
# define BOOT_SECTOR 1
# else
# define BOOT_SECTOR 0
# endif
2010-04-26 19:11:16 +00:00
2013-02-27 16:19:15 +00:00
/* Helper for setup. */
static void
save_first_sector ( grub_disk_addr_t sector , unsigned offset , unsigned length ,
void * data )
{
grub_disk_addr_t * first_sector = data ;
grub_util_info ( " the first sector is <% " PRIuGRUB_UINT64_T " ,%u,%u> " ,
sector , offset , length ) ;
if ( offset ! = 0 | | length ! = GRUB_DISK_SECTOR_SIZE )
grub_util_error ( " %s " , _ ( " the first sector of the core file is not sector-aligned " ) ) ;
* first_sector = sector ;
}
struct blocklists
{
struct grub_boot_blocklist * first_block , * block ;
# ifdef GRUB_SETUP_BIOS
grub_uint16_t current_segment ;
# endif
grub_uint16_t last_length ;
} ;
/* 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 ;
grub_util_info ( " saving <% " PRIuGRUB_UINT64_T " ,%u,%u> " ,
sector , offset , length ) ;
if ( offset ! = 0 | | bl - > last_length ! = GRUB_DISK_SECTOR_SIZE )
grub_util_error ( " %s " , _ ( " non-sector-aligned data is found in the core file " ) ) ;
if ( bl - > block ! = bl - > first_block
& & ( grub_target_to_host64 ( prev - > start )
+ grub_target_to_host16 ( prev - > len ) ) = = sector )
{
grub_uint16_t t = grub_target_to_host16 ( prev - > len ) + 1 ;
prev - > len = grub_host_to_target16 ( t ) ;
}
else
{
bl - > block - > start = grub_host_to_target64 ( sector ) ;
bl - > block - > len = grub_host_to_target16 ( 1 ) ;
# 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 " ) ) ;
}
bl - > last_length = length ;
# ifdef GRUB_SETUP_BIOS
bl - > current_segment + = GRUB_DISK_SECTOR_SIZE > > 4 ;
# endif
}
2013-01-20 15:52:15 +00:00
# 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 ;
} ;
2013-02-27 16:19:15 +00:00
/* Helper for setup.
2013-01-20 15:52:15 +00:00
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
2003-01-02 20:12:33 +00:00
static void
2008-06-18 17:35:26 +00:00
setup ( const char * dir ,
2003-01-02 20:12:33 +00:00
const char * boot_file , const char * core_file ,
2012-02-03 09:35:28 +00:00
const char * dest , int force ,
2010-10-16 22:35:14 +00:00
int fs_probe , int allow_floppy )
2003-01-02 20:12:33 +00:00
{
2009-11-11 20:10:58 +00:00
char * boot_path , * core_path , * core_path_dev , * core_path_dev_full ;
2003-01-02 20:12:33 +00:00
char * boot_img , * core_img ;
2012-02-03 09:35:28 +00:00
char * root = 0 ;
2003-01-02 20:12:33 +00:00
size_t boot_size , core_size ;
2012-09-19 01:41:51 +00:00
# ifdef GRUB_SETUP_BIOS
2004-04-04 13:46:03 +00:00
grub_uint16_t core_sectors ;
2012-09-19 01:41:51 +00:00
# endif
2012-04-13 14:58:02 +00:00
grub_device_t root_dev = 0 , dest_dev , core_dev ;
2013-02-27 16:19:15 +00:00
struct blocklists bl ;
2003-01-02 20:12:33 +00:00
char * tmp_img ;
2013-04-04 06:55:06 +00:00
grub_disk_addr_t first_sector = ( grub_disk_addr_t ) - 1 ;
2003-01-02 20:12:33 +00:00
FILE * fp ;
2009-06-10 21:04:23 +00:00
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_BIOS
2013-02-27 16:19:15 +00:00
bl . current_segment =
GRUB_BOOT_I386_PC_KERNEL_SEG + ( GRUB_DISK_SECTOR_SIZE > > 4 ) ;
2010-09-14 19:07:39 +00:00
# endif
2013-02-27 16:19:15 +00:00
bl . last_length = GRUB_DISK_SECTOR_SIZE ;
2009-06-10 21:04:23 +00:00
2003-01-02 20:12:33 +00:00
/* Read the boot image by the OS service. */
2004-04-04 13:46:03 +00:00
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 )
2010-01-16 00:26:52 +00:00
grub_util_error ( _ ( " the size of `%s' is not %u " ) ,
2004-04-04 13:46:03 +00:00
boot_path , GRUB_DISK_SECTOR_SIZE ) ;
boot_img = grub_util_read_image ( boot_path ) ;
2003-01-02 20:12:33 +00:00
free ( boot_path ) ;
2004-04-04 13:46:03 +00:00
core_path = grub_util_get_path ( dir , core_file ) ;
core_size = grub_util_get_image_size ( core_path ) ;
2012-09-19 01:41:51 +00:00
# ifdef GRUB_SETUP_BIOS
2004-04-04 13:46:03 +00:00
core_sectors = ( ( core_size + GRUB_DISK_SECTOR_SIZE - 1 )
> > GRUB_DISK_SECTOR_BITS ) ;
2012-09-19 01:41:51 +00:00
# endif
2004-04-04 13:46:03 +00:00
if ( core_size < GRUB_DISK_SECTOR_SIZE )
2010-01-16 00:26:52 +00:00
grub_util_error ( _ ( " the size of `%s' is too small " ) , core_path ) ;
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_BIOS
2010-09-14 19:07:39 +00:00
if ( core_size > 0xFFFF * GRUB_DISK_SECTOR_SIZE )
2010-01-16 00:26:52 +00:00
grub_util_error ( _ ( " the size of `%s' is too large " ) , core_path ) ;
2010-09-14 19:07:39 +00:00
# endif
2009-06-10 21:04:23 +00:00
2004-04-04 13:46:03 +00:00
core_img = grub_util_read_image ( core_path ) ;
2003-01-02 20:12:33 +00:00
/* Have FIRST_BLOCK to point to the first blocklist. */
2013-02-27 16:19:15 +00:00
bl . first_block = ( struct grub_boot_blocklist * ) ( core_img
+ GRUB_DISK_SECTOR_SIZE
- sizeof ( * bl . block ) ) ;
2010-09-14 19:07:39 +00:00
grub_util_info ( " root is `%s', dest is `%s' " , root , dest ) ;
2003-01-06 00:01:35 +00:00
2010-09-14 19:07:39 +00:00
grub_util_info ( " Opening dest " ) ;
2004-04-04 13:46:03 +00:00
dest_dev = grub_device_open ( dest ) ;
2003-01-02 20:12:33 +00:00
if ( ! dest_dev )
2012-02-10 12:49:24 +00:00
grub_util_error ( " %s " , grub_errmsg ) ;
2003-01-02 20:12:33 +00:00
2012-04-13 14:58:02 +00:00
core_dev = dest_dev ;
2012-02-03 09:35:28 +00:00
{
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 ) ;
}
2009-11-22 10:20:14 +00:00
grub_util_info ( " setting the root device to `%s' " , root ) ;
2005-07-20 20:30:46 +00:00
if ( grub_env_set ( " root " , root ) ! = GRUB_ERR_NONE )
2012-02-10 12:49:24 +00:00
grub_util_error ( " %s " , grub_errmsg ) ;
2003-01-02 20:12:33 +00:00
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_BIOS
2003-01-02 20:12:33 +00:00
/* Read the original sector from the disk. */
2004-04-04 13:46:03 +00:00
tmp_img = xmalloc ( GRUB_DISK_SECTOR_SIZE ) ;
if ( grub_disk_read ( dest_dev - > disk , 0 , 0 , GRUB_DISK_SECTOR_SIZE , tmp_img ) )
2012-02-10 12:49:24 +00:00
grub_util_error ( " %s " , grub_errmsg ) ;
2010-09-14 19:07:39 +00:00
# endif
2003-01-02 20:12:33 +00:00
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_BIOS
2010-09-14 19:07:39 +00:00
{
2012-06-07 12:07:02 +00:00
grub_uint8_t * boot_drive_check ;
boot_drive_check = ( grub_uint8_t * ) ( boot_img
2010-09-14 19:07:39 +00:00
+ 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 . */
2010-10-16 22:35:14 +00:00
if ( ! allow_floppy & & ! grub_util_biosdisk_is_floppy ( dest_dev - > disk ) )
2012-06-07 12:07:02 +00:00
{
/* Replace the jmp (2 bytes) with double nop's. */
boot_drive_check [ 0 ] = 0x90 ;
boot_drive_check [ 1 ] = 0x90 ;
}
2010-09-14 19:07:39 +00:00
}
# endif
2008-06-18 17:35:26 +00:00
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_BIOS
2010-09-15 19:36:57 +00:00
{
2013-01-20 15:52:15 +00:00
struct identify_partmap_ctx ctx = {
. dest_partmap = NULL ,
. container = dest_dev - > disk - > partition ,
. multiple_partmaps = 0
} ;
2012-01-29 13:28:01 +00:00
int is_ldm ;
2010-09-15 19:36:57 +00:00
grub_err_t err ;
2010-09-24 12:05:47 +00:00
grub_disk_addr_t * sectors ;
2010-09-15 19:36:57 +00:00
int i ;
grub_fs_t fs ;
2012-02-27 21:25:39 +00:00
unsigned int nsec , maxsec ;
2010-09-14 19:07:39 +00:00
2013-01-20 15:52:15 +00:00
grub_partition_iterate ( dest_dev - > disk , identify_partmap , & ctx ) ;
2010-09-14 19:07:39 +00:00
2013-01-20 15:52:15 +00:00
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 ) )
2011-01-07 12:27:34 +00:00
{
2012-02-10 12:49:24 +00:00
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. " ) ) ;
2011-01-07 12:27:34 +00:00
goto unable_to_embed ;
}
2010-09-15 19:36:57 +00:00
fs = grub_fs_probe ( dest_dev ) ;
if ( ! fs )
grub_errno = GRUB_ERR_NONE ;
2012-01-29 13:28:01 +00:00
is_ldm = grub_util_is_ldm ( dest_dev - > disk ) ;
2010-09-15 19:36:57 +00:00
if ( fs_probe )
{
2013-01-20 15:52:15 +00:00
if ( ! fs & & ! ctx . dest_partmap )
2010-09-15 19:36:57 +00:00
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 )
2012-02-26 16:28:05 +00:00
/* TRANSLATORS: Filesystem may reserve the space just GRUB isn't sure about it. */
2010-09-15 19:36:57 +00:00
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 ) ;
2013-01-20 15:52:15 +00:00
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 )
2012-02-26 16:28:05 +00:00
/* TRANSLATORS: Partition map may reserve the space just GRUB isn't sure about it. */
2010-09-15 19:36:57 +00:00
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 "
2013-01-20 15:52:15 +00:00
" 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 )
2012-01-29 13:28:01 +00:00
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) " ) ,
2013-01-20 15:52:15 +00:00
dest_dev - > disk - > name , ctx . dest_partmap - > name ) ;
2012-01-29 13:28:01 +00:00
2010-09-15 19:36:57 +00:00
}
2011-03-29 00:20:52 +00:00
/* Copy the partition table. */
2013-01-20 15:52:15 +00:00
if ( ctx . dest_partmap | |
2011-03-29 00:20:52 +00:00
( ! 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 ) ;
2013-01-20 15:52:15 +00:00
if ( ! ctx . dest_partmap & & ! fs & & ! is_ldm )
2010-09-14 19:07:39 +00:00
{
2012-02-10 12:49:24 +00:00
grub_util_warn ( " %s " , _ ( " Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea. " ) ) ;
2010-09-14 19:07:39 +00:00
goto unable_to_embed ;
}
2013-01-20 15:52:15 +00:00
if ( ctx . multiple_partmaps | | ( ctx . dest_partmap & & fs ) | | ( is_ldm & & fs ) )
2010-09-14 19:07:39 +00:00
{
2012-02-10 12:49:24 +00:00
grub_util_warn ( " %s " , _ ( " Attempting to install GRUB to a disk with multiple partition labels. This is not supported yet. " ) ) ;
2010-09-14 19:07:39 +00:00
goto unable_to_embed ;
}
2013-01-20 15:52:15 +00:00
if ( ctx . dest_partmap & & ! ctx . dest_partmap - > embed )
2010-09-14 19:07:39 +00:00
{
2012-03-03 12:05:08 +00:00
grub_util_warn ( _ ( " Partition style `%s' doesn't support embedding " ) ,
2013-01-20 15:52:15 +00:00
ctx . dest_partmap - > name ) ;
2010-09-14 19:07:39 +00:00
goto unable_to_embed ;
}
2011-11-05 13:47:25 +00:00
if ( fs & & ! fs - > embed )
{
2012-03-03 12:05:08 +00:00
grub_util_warn ( _ ( " File system `%s' doesn't support embedding " ) ,
2011-11-05 13:47:25 +00:00
fs - > name ) ;
goto unable_to_embed ;
}
2010-09-24 12:05:47 +00:00
nsec = core_sectors ;
2012-02-27 21:25:39 +00:00
maxsec = 2 * core_sectors ;
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 ) ;
2012-01-29 13:28:01 +00:00
if ( is_ldm )
2012-02-27 21:25:39 +00:00
err = grub_util_ldm_embed ( dest_dev - > disk , & nsec , maxsec ,
2012-01-29 13:28:01 +00:00
GRUB_EMBED_PCBIOS , & sectors ) ;
2013-01-20 15:52:15 +00:00
else if ( ctx . dest_partmap )
err = ctx . dest_partmap - > embed ( dest_dev - > disk , & nsec , maxsec ,
GRUB_EMBED_PCBIOS , & sectors ) ;
2011-11-05 13:47:25 +00:00
else
2012-02-27 21:25:39 +00:00
err = fs - > embed ( dest_dev , & nsec , maxsec ,
2011-11-05 13:47:25 +00:00
GRUB_EMBED_PCBIOS , & sectors ) ;
if ( ! err & & nsec < core_sectors )
{
err = grub_error ( GRUB_ERR_OUT_OF_RANGE ,
2011-11-11 23:34:14 +00:00
N_ ( " Your embedding area is unusually small. "
" core.img won't fit in it. " ) ) ;
2011-11-05 13:47:25 +00:00
}
2010-09-15 19:36:57 +00:00
if ( err )
2010-09-14 19:07:39 +00:00
{
2012-02-10 12:49:24 +00:00
grub_util_warn ( " %s " , grub_errmsg ) ;
2010-09-15 19:36:57 +00:00
grub_errno = GRUB_ERR_NONE ;
2010-09-14 19:07:39 +00:00
goto unable_to_embed ;
}
2012-02-27 21:25:39 +00:00
assert ( nsec < = maxsec ) ;
2011-11-05 13:47:25 +00:00
2010-10-16 22:25:23 +00:00
/* Clean out the blocklists. */
2013-02-27 16:19:15 +00:00
bl . block = bl . first_block ;
while ( bl . block - > len )
2010-10-16 22:25:23 +00:00
{
2013-02-27 16:19:15 +00:00
grub_memset ( bl . block , 0 , sizeof ( bl . block ) ) ;
2010-10-16 22:25:23 +00:00
2013-02-27 16:19:15 +00:00
bl . block - - ;
2010-10-16 22:25:23 +00:00
2013-02-27 16:19:15 +00:00
if ( ( char * ) bl . block < = core_img )
2012-02-10 12:49:24 +00:00
grub_util_error ( " %s " , _ ( " no terminator in the core image " ) ) ;
2010-10-16 22:25:23 +00:00
}
2013-01-20 15:52:15 +00:00
save_first_sector ( sectors [ 0 ] + grub_partition_get_start ( ctx . container ) ,
2013-02-27 16:19:15 +00:00
0 , GRUB_DISK_SECTOR_SIZE , & first_sector ) ;
2010-09-14 19:07:39 +00:00
2013-02-27 16:19:15 +00:00
bl . block = bl . first_block ;
2010-09-25 18:40:26 +00:00
for ( i = 1 ; i < nsec ; i + + )
2013-01-20 15:52:15 +00:00
save_blocklists ( sectors [ i ] + grub_partition_get_start ( ctx . container ) ,
2013-02-27 16:19:15 +00:00
0 , GRUB_DISK_SECTOR_SIZE , & bl ) ;
2010-09-14 19:07:39 +00:00
2010-11-22 22:33:55 +00:00
/* Make sure that the last blocklist is a terminator. */
2013-02-27 16:19:15 +00:00
if ( bl . block = = bl . first_block )
bl . block - - ;
bl . block - > start = 0 ;
bl . block - > len = 0 ;
bl . block - > segment = 0 ;
2010-11-22 22:33:55 +00:00
2012-09-19 01:41:51 +00:00
write_rootdev ( root_dev , boot_img , first_sector ) ;
2010-09-14 19:07:39 +00:00
2010-09-24 12:05:47 +00:00
core_img = realloc ( core_img , nsec * GRUB_DISK_SECTOR_SIZE ) ;
2013-02-27 16:19:15 +00:00
bl . first_block = ( struct grub_boot_blocklist * ) ( core_img
+ GRUB_DISK_SECTOR_SIZE
- sizeof ( * bl . block ) ) ;
2010-09-24 12:05:47 +00:00
2012-01-24 13:39:29 +00:00
grub_size_t no_rs_length ;
2012-06-07 12:07:02 +00:00
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 ) ) ;
2012-01-24 13:39:29 +00:00
no_rs_length = grub_target_to_host16
2012-06-07 12:07:02 +00:00
( grub_get_unaligned16 ( core_img
+ GRUB_DISK_SECTOR_SIZE
+ GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH ) ) ;
2012-01-24 13:39:29 +00:00
if ( no_rs_length = = 0xffff )
2012-02-10 12:49:24 +00:00
grub_util_error ( " %s " , _ ( " core.img version mismatch " ) ) ;
2010-09-24 12:05:47 +00:00
2011-12-23 09:23:41 +00:00
void * tmp = xmalloc ( core_size ) ;
grub_memcpy ( tmp , core_img , core_size ) ;
2012-01-24 13:39:29 +00:00
grub_reed_solomon_add_redundancy ( core_img + no_rs_length + GRUB_DISK_SECTOR_SIZE ,
core_size - no_rs_length - GRUB_DISK_SECTOR_SIZE ,
2010-09-24 12:05:47 +00:00
nsec * GRUB_DISK_SECTOR_SIZE
- core_size ) ;
2011-12-23 09:23:41 +00:00
assert ( grub_memcmp ( tmp , core_img , core_size ) = = 0 ) ;
free ( tmp ) ;
2010-09-24 12:05:47 +00:00
2010-09-14 19:07:39 +00:00
/* Write the core image onto the disk. */
2010-09-24 12:05:47 +00:00
for ( i = 0 ; i < nsec ; i + + )
2010-09-15 19:36:57 +00:00
grub_disk_write ( dest_dev - > disk , sectors [ i ] , 0 ,
2010-09-24 12:05:47 +00:00
GRUB_DISK_SECTOR_SIZE ,
2010-09-15 19:36:57 +00:00
core_img + i * GRUB_DISK_SECTOR_SIZE ) ;
2010-09-14 19:07:39 +00:00
2010-09-24 12:05:47 +00:00
grub_free ( sectors ) ;
2010-09-14 19:07:39 +00:00
goto finish ;
}
2009-06-10 21:04:23 +00:00
2009-05-13 20:59:45 +00:00
unable_to_embed :
2012-02-10 12:49:24 +00:00
# endif
2009-06-10 21:04:23 +00:00
2012-01-29 13:28:01 +00:00
if ( dest_dev - > disk - > dev - > id ! = root_dev - > disk - > dev - > id )
2012-02-10 12:49:24 +00:00
grub_util_error ( " %s " , _ ( " embedding is not possible, but this is required for "
" RAID and LVM install " ) ) ;
2012-01-29 13:28:01 +00:00
2012-02-27 20:36:58 +00:00
{
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 ) ;
}
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_BIOS
2012-02-08 18:26:01 +00:00
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 . */
2012-02-10 12:49:24 +00:00
grub_util_error ( " %s " , _ ( " embedding is not possible, but this is required for "
" cross-disk install " ) ) ;
2012-04-13 14:58:02 +00:00
# else
core_dev = root_dev ;
2010-10-26 10:40:35 +00:00
# endif
2012-02-10 12:49:24 +00:00
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. " ) ) ;
2009-05-04 16:16:03 +00:00
if ( ! force )
2012-03-05 15:42:26 +00:00
/* TRANSLATORS: Here GRUB refuses to continue with blocklist install. */
2012-02-10 12:49:24 +00:00
grub_util_error ( " %s " , _ ( " will not proceed with blocklists " ) ) ;
2009-06-10 21:04:23 +00:00
2010-09-14 19:07:39 +00:00
/* The core image must be put on a filesystem unfortunately. */
grub_util_info ( " will leave the core image on the filesystem " ) ;
2004-04-04 13:46:03 +00:00
/* Make sure that GRUB reads the identical image as the OS. */
2003-01-02 20:12:33 +00:00
tmp_img = xmalloc ( core_size ) ;
2009-11-11 20:10:58 +00:00
core_path_dev_full = grub_util_get_path ( dir , core_file ) ;
2010-05-06 06:04:04 +00:00
core_path_dev = grub_make_system_path_relative_to_its_root ( core_path_dev_full ) ;
2009-11-11 20:10:58 +00:00
free ( core_path_dev_full ) ;
2009-06-10 21:04:23 +00:00
2011-04-19 20:39:14 +00:00
grub_util_biosdisk_flush ( root_dev - > disk ) ;
2003-01-02 20:12:33 +00:00
2012-02-27 20:36:58 +00:00
# ifndef __linux__
2003-01-02 20:12:33 +00:00
# define MAX_TRIES 5
2012-02-10 12:49:24 +00:00
{
int i ;
for ( i = 0 ; i < MAX_TRIES ; i + + )
{
2012-02-27 20:36:58 +00:00
grub_file_t file ;
2012-02-10 12:49:24 +00:00
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 ) ;
2009-06-10 21:04:23 +00:00
2012-02-10 12:49:24 +00:00
grub_disk_cache_invalidate_all ( ) ;
2009-06-10 21:04:23 +00:00
2012-02-10 12:49:24 +00:00
grub_file_filter_disable_compression ( ) ;
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 )
{
2003-01-02 23:46:21 +00:00
#if 0
2012-02-10 12:49:24 +00:00
FILE * dump ;
FILE * dump2 ;
dump = fopen ( " dump.img " , " wb " ) ;
if ( dump )
{
fwrite ( tmp_img , 1 , core_size , dump ) ;
fclose ( dump ) ;
}
dump2 = fopen ( " dump2.img " , " wb " ) ;
if ( dump2 )
{
fwrite ( core_img , 1 , core_size , dump2 ) ;
fclose ( dump2 ) ;
}
2009-06-10 21:04:23 +00:00
# endif
2012-02-10 12:49:24 +00:00
grub_util_info ( " succeeded in opening the core image but the data is different " ) ;
}
else
{
grub_file_close ( file ) ;
break ;
}
grub_file_close ( file ) ;
}
else
grub_util_info ( " couldn't open the core image " ) ;
2003-01-02 23:46:21 +00:00
2012-02-10 12:49:24 +00:00
if ( grub_errno )
grub_util_info ( " error message = %s " , grub_errmsg ) ;
2009-06-10 21:04:23 +00:00
2012-02-10 12:49:24 +00:00
grub_errno = GRUB_ERR_NONE ;
grub_util_biosdisk_flush ( root_dev - > disk ) ;
sleep ( 1 ) ;
}
2003-01-02 20:12:33 +00:00
2012-02-10 12:49:24 +00:00
if ( i = = MAX_TRIES )
grub_util_error ( _ ( " cannot read `%s' correctly " ) , core_path_dev ) ;
}
2003-01-02 20:12:33 +00:00
2012-02-27 20:36:58 +00:00
# endif
2003-01-02 20:12:33 +00:00
/* Clean out the blocklists. */
2013-02-27 16:19:15 +00:00
bl . block = bl . first_block ;
while ( bl . block - > len )
2003-01-02 20:12:33 +00:00
{
2013-02-27 16:19:15 +00:00
bl . block - > start = 0 ;
bl . block - > len = 0 ;
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_BIOS
2013-02-27 16:19:15 +00:00
bl . block - > segment = 0 ;
2010-09-14 19:07:39 +00:00
# endif
2003-01-02 20:12:33 +00:00
2013-02-27 16:19:15 +00:00
bl . block - - ;
2009-06-10 21:04:23 +00:00
2013-02-27 16:19:15 +00:00
if ( ( char * ) bl . block < = core_img )
2012-02-10 12:49:24 +00:00
grub_util_error ( " %s " , _ ( " no terminator in the core image " ) ) ;
2003-01-02 20:12:33 +00:00
}
2009-06-10 21:04:23 +00:00
2013-02-27 16:19:15 +00:00
bl . block = bl . first_block ;
2009-06-10 21:04:23 +00:00
2012-02-27 20:36:58 +00:00
# ifdef __linux__
{
grub_partition_t container = root_dev - > disk - > partition ;
2012-04-13 14:58:02 +00:00
grub_uint64_t container_start = grub_partition_get_start ( container ) ;
2012-02-27 20:36:58 +00:00
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': %s " ) , core_path ,
strerror ( errno ) ) ;
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_info ( " FIEMAP failed. Reverting to FIBMAP " ) ;
if ( ioctl ( fd , FIGETBSZ , & bsize ) < 0 )
grub_util_error ( _ ( " can't retrieve blocklists: %s " ) ,
strerror ( errno ) ) ;
if ( bsize & ( GRUB_DISK_SECTOR_SIZE - 1 ) )
grub_util_error ( " %s " , _ ( " blocksize is not divisible by 512 " ) ) ;
mul = bsize > > GRUB_DISK_SECTOR_BITS ;
nblocks = ( core_size + bsize - 1 ) / bsize ;
2013-04-04 06:55:06 +00:00
if ( mul = = 0 | | nblocks = = 0 )
grub_util_error ( " %s " , _ ( " can't retrieve blocklists " ) ) ;
2012-02-27 20:36:58 +00:00
for ( i = 0 ; i < nblocks ; i + + )
{
unsigned blk = i ;
if ( ioctl ( fd , FIBMAP , & blk ) < 0 )
grub_util_error ( _ ( " can't retrieve blocklists: %s " ) ,
strerror ( errno ) ) ;
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
2012-04-13 14:58:02 +00:00
+ container_start ,
2013-02-27 16:19:15 +00:00
0 , rest , & first_sector ) ;
2012-02-27 20:36:58 +00:00
else
save_blocklists ( ( ( grub_uint64_t ) blk ) * mul + j
2012-04-13 14:58:02 +00:00
+ container_start ,
2013-02-27 16:19:15 +00:00
0 , rest , & bl ) ;
2012-02-27 20:36:58 +00:00
}
}
}
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 ( _ ( " can't retrieve blocklists: %s " ) ,
strerror ( errno ) ) ;
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 ;
2013-04-04 06:55:06 +00:00
if ( first_sector = = ( grub_disk_addr_t ) - 1 )
2012-02-27 20:36:58 +00:00
save_first_sector ( ( fie2 - > fm_extents [ i ] . fe_physical
> > GRUB_DISK_SECTOR_BITS )
2012-04-13 14:58:02 +00:00
+ j + container_start ,
2012-02-27 20:36:58 +00:00
fie2 - > fm_extents [ i ] . fe_physical
2013-02-27 16:19:15 +00:00
& ( GRUB_DISK_SECTOR_SIZE - 1 ) , len ,
& first_sector ) ;
2012-02-27 20:36:58 +00:00
else
save_blocklists ( ( fie2 - > fm_extents [ i ] . fe_physical
> > GRUB_DISK_SECTOR_BITS )
2012-04-13 14:58:02 +00:00
+ j + container_start ,
2012-02-27 20:36:58 +00:00
fie2 - > fm_extents [ i ] . fe_physical
2013-02-27 16:19:15 +00:00
& ( GRUB_DISK_SECTOR_SIZE - 1 ) , len , & bl ) ;
2003-01-02 20:12:33 +00:00
2012-02-27 20:36:58 +00:00
}
}
2013-04-04 06:55:06 +00:00
if ( first_sector = = ( grub_disk_addr_t ) - 1 )
grub_util_error ( " %s " , _ ( " can't retrieve blocklists " ) ) ;
2012-02-27 20:36:58 +00:00
}
fclose ( fp ) ;
}
# else
{
2012-02-29 13:07:53 +00:00
grub_file_t file ;
2012-02-27 20:36:58 +00:00
/* 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 ;
2013-02-27 16:19:15 +00:00
file - > read_hook_data = & first_sector ;
2012-02-27 20:36:58 +00:00
if ( grub_file_read ( file , tmp_img , GRUB_DISK_SECTOR_SIZE )
! = GRUB_DISK_SECTOR_SIZE )
grub_util_error ( " %s " , _ ( " failed to read the first sector of the core image " ) ) ;
2013-02-27 16:19:15 +00:00
bl . block = bl . first_block ;
2012-02-27 20:36:58 +00:00
file - > read_hook = save_blocklists ;
2013-02-27 16:19:15 +00:00
file - > read_hook_data = & bl ;
2012-02-27 20:36:58 +00:00
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 ( " %s " , _ ( " failed to read the rest sectors of the core image " ) ) ;
2012-02-29 13:07:53 +00:00
grub_file_close ( file ) ;
2012-02-27 20:36:58 +00:00
}
# endif
2003-01-02 20:12:33 +00:00
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_SPARC64
2010-09-14 19:07:39 +00:00
{
char * boot_devpath ;
boot_devpath = ( char * ) ( boot_img
+ GRUB_BOOT_AOUT_HEADER_SIZE
+ GRUB_BOOT_MACHINE_BOOT_DEVPATH ) ;
2012-02-03 09:35:28 +00:00
if ( dest_dev - > disk - > id ! = root_dev - > disk - > id
| | dest_dev - > disk - > dev - > id ! = root_dev - > disk - > dev - > id )
2010-09-14 19:07:39 +00:00
{
const char * dest_ofpath ;
dest_ofpath
2012-02-03 09:35:28 +00:00
= grub_util_devname_to_ofpath ( grub_util_biosdisk_get_osdev ( root_dev - > disk ) ) ;
2010-09-14 19:07:39 +00:00
grub_util_info ( " dest_ofpath is `%s' " , dest_ofpath ) ;
2012-02-27 13:24:22 +00:00
strncpy ( boot_devpath , dest_ofpath ,
GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
2010-09-14 19:07:39 +00:00
- 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
2008-06-26 15:29:32 +00:00
free ( core_path_dev ) ;
2003-01-02 20:12:33 +00:00
free ( tmp_img ) ;
2009-06-10 21:04:23 +00:00
2012-09-19 01:41:51 +00:00
write_rootdev ( root_dev , boot_img , first_sector ) ;
2008-06-30 23:52:24 +00:00
2003-01-06 00:01:35 +00:00
/* Write the first two sectors of the core image onto the disk. */
2009-11-22 10:20:14 +00:00
grub_util_info ( " opening the core image `%s' " , core_path ) ;
2003-01-02 20:12:33 +00:00
fp = fopen ( core_path , " r+b " ) ;
if ( ! fp )
2012-02-05 10:07:33 +00:00
grub_util_error ( _ ( " cannot open `%s': %s " ) , core_path ,
strerror ( errno ) ) ;
2003-01-02 20:12:33 +00:00
2012-02-05 10:07:33 +00:00
grub_util_write_image ( core_img , GRUB_DISK_SECTOR_SIZE * 2 , fp , core_path ) ;
2012-02-27 20:36:58 +00:00
fflush ( fp ) ;
fsync ( fileno ( fp ) ) ;
2003-01-02 20:12:33 +00:00
fclose ( fp ) ;
2012-02-27 20:36:58 +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 ;
2012-04-13 14:58:02 +00:00
grub_partition_t container = core_dev - > disk - > partition ;
2012-02-27 20:36:58 +00:00
grub_err_t err ;
2012-04-13 14:58:02 +00:00
core_dev - > disk - > partition = 0 ;
2012-02-27 20:36:58 +00:00
buf = xmalloc ( core_size ) ;
blk = first_sector ;
2012-04-13 14:58:02 +00:00
err = grub_disk_read ( core_dev - > disk , blk , 0 , GRUB_DISK_SECTOR_SIZE , buf ) ;
2012-02-27 20:36:58 +00:00
if ( err )
2012-04-13 14:58:02 +00:00
grub_util_error ( _ ( " cannot read `%s': %s " ) , core_dev - > disk - > name ,
2012-02-27 20:36:58 +00:00
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 ;
2013-02-27 16:19:15 +00:00
bl . block = bl . first_block ;
while ( bl . block - > len )
2012-02-27 20:36:58 +00:00
{
2013-02-27 16:19:15 +00:00
size_t cur = grub_target_to_host16 ( bl . block - > len ) < < GRUB_DISK_SECTOR_BITS ;
blk = grub_target_to_host64 ( bl . block - > start ) ;
2012-02-27 20:36:58 +00:00
if ( cur > len )
cur = len ;
2012-04-13 14:58:02 +00:00
err = grub_disk_read ( core_dev - > disk , blk , 0 , cur , buf ) ;
2012-02-27 20:36:58 +00:00
if ( err )
2012-04-13 14:58:02 +00:00
grub_util_error ( _ ( " cannot read `%s': %s " ) , core_dev - > disk - > name ,
2012-02-27 20:36:58 +00:00
grub_errmsg ) ;
if ( grub_memcmp ( buf , ptr , cur ) ! = 0 )
grub_util_error ( " %s " , _ ( " blocklists are invalid " ) ) ;
ptr + = cur ;
len - = cur ;
2013-02-27 16:19:15 +00:00
bl . block - - ;
2012-02-27 20:36:58 +00:00
2013-02-27 16:19:15 +00:00
if ( ( char * ) bl . block < = core_img )
2012-02-27 20:36:58 +00:00
grub_util_error ( " %s " , _ ( " no terminator in the core image " ) ) ;
}
2012-04-13 14:58:02 +00:00
core_dev - > disk - > partition = container ;
2012-02-27 20:36:58 +00:00
free ( buf ) ;
}
2003-01-02 20:12:33 +00:00
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_BIOS
2010-09-15 22:27:06 +00:00
finish :
2012-02-10 12:49:24 +00:00
# endif
2010-09-15 22:27:06 +00:00
2003-01-02 20:12:33 +00:00
/* Write the boot image onto the disk. */
2010-09-14 19:07:39 +00:00
if ( grub_disk_write ( dest_dev - > disk , BOOT_SECTOR ,
0 , GRUB_DISK_SECTOR_SIZE , boot_img ) )
2012-02-10 12:49:24 +00:00
grub_util_error ( " %s " , grub_errmsg ) ;
2003-01-02 20:12:33 +00:00
2011-04-19 20:39:14 +00:00
grub_util_biosdisk_flush ( root_dev - > disk ) ;
grub_util_biosdisk_flush ( dest_dev - > disk ) ;
2009-06-10 21:04:23 +00:00
2008-06-26 15:29:32 +00:00
free ( core_path ) ;
2003-01-02 20:12:33 +00:00
free ( core_img ) ;
free ( boot_img ) ;
2004-04-04 13:46:03 +00:00
grub_device_close ( dest_dev ) ;
2008-02-03 21:53:32 +00:00
grub_device_close ( root_dev ) ;
2003-01-02 20:12:33 +00:00
}
2010-09-20 10:37:37 +00:00
static struct argp_option options [ ] = {
{ " boot-image " , ' b ' , N_ ( " FILE " ) , 0 ,
2012-02-25 00:15:29 +00:00
N_ ( " use FILE as the boot image [default=%s] " ) , 0 } ,
2010-09-20 10:37:37 +00:00
{ " core-image " , ' c ' , N_ ( " FILE " ) , 0 ,
2012-02-25 00:15:29 +00:00
N_ ( " use FILE as the core image [default=%s] " ) , 0 } ,
2010-09-20 10:37:37 +00:00
{ " directory " , ' d ' , N_ ( " DIR " ) , 0 ,
2012-02-25 00:15:29 +00:00
N_ ( " use GRUB files in the directory DIR [default=%s] " ) , 0 } ,
2010-09-20 10:37:37 +00:00
{ " device-map " , ' m ' , N_ ( " FILE " ) , 0 ,
2012-02-08 18:26:01 +00:00
N_ ( " use FILE as the device map [default=%s] " ) , 0 } ,
2010-09-20 10:37:37 +00:00
{ " force " , ' f ' , 0 , 0 ,
2012-02-08 18:26:01 +00:00
N_ ( " install even if problems are detected " ) , 0 } ,
2010-09-20 10:37:37 +00:00
{ " skip-fs-probe " , ' s ' , 0 , 0 ,
2012-02-25 00:15:29 +00:00
N_ ( " do not probe for filesystems in DEVICE " ) , 0 } ,
2012-02-05 10:23:47 +00:00
{ " verbose " , ' v ' , 0 , 0 , N_ ( " print verbose messages. " ) , 0 } ,
2010-10-16 22:35:14 +00:00
{ " allow-floppy " , ' a ' , 0 , 0 ,
2012-03-05 15:42:26 +00:00
/* TRANSLATORS: The potential breakage isn't limited to floppies but it's
likely to make the install unbootable from HDD . */
2012-02-25 00:15:29 +00:00
N_ ( " make the drive also bootable as floppy (default for fdX devices). May break on some BIOSes. " ) , 0 } ,
2010-10-16 22:35:14 +00:00
2010-09-20 10:37:37 +00:00
{ 0 , 0 , 0 , 0 , 0 , 0 }
} ;
static char *
help_filter ( int key , const char * text , void * input __attribute__ ( ( unused ) ) )
{
switch ( key )
{
case ' b ' :
return xasprintf ( text , DEFAULT_BOOT_FILE ) ;
case ' c ' :
return xasprintf ( text , DEFAULT_CORE_FILE ) ;
case ' d ' :
return xasprintf ( text , DEFAULT_DIRECTORY ) ;
case ' m ' :
return xasprintf ( text , DEFAULT_DEVICE_MAP ) ;
2003-01-02 20:12:33 +00:00
2010-09-20 10:37:37 +00:00
default :
return ( char * ) text ;
}
}
struct arguments
{
char * boot_file ;
char * core_file ;
char * dir ;
char * dev_map ;
int force ;
int fs_probe ;
2010-10-16 22:35:14 +00:00
int allow_floppy ;
2010-09-20 10:37:37 +00:00
char * device ;
} ;
static error_t
argp_parser ( int key , char * arg , struct argp_state * state )
{
/* Get the input argument from argp_parse, which we
know is a pointer to our arguments structure . */
struct arguments * arguments = state - > input ;
switch ( key )
{
2010-10-16 22:35:14 +00:00
case ' a ' :
arguments - > allow_floppy = 1 ;
break ;
2010-09-20 10:37:37 +00:00
case ' b ' :
if ( arguments - > boot_file )
free ( arguments - > boot_file ) ;
arguments - > boot_file = xstrdup ( arg ) ;
break ;
case ' c ' :
if ( arguments - > core_file )
free ( arguments - > core_file ) ;
arguments - > core_file = xstrdup ( arg ) ;
break ;
case ' d ' :
if ( arguments - > dir )
free ( arguments - > dir ) ;
arguments - > dir = xstrdup ( arg ) ;
break ;
case ' m ' :
if ( arguments - > dev_map )
free ( arguments - > dev_map ) ;
arguments - > dev_map = xstrdup ( arg ) ;
break ;
case ' f ' :
arguments - > force = 1 ;
break ;
case ' s ' :
arguments - > fs_probe = 0 ;
break ;
case ' v ' :
verbosity + + ;
break ;
case ARGP_KEY_ARG :
if ( state - > arg_num = = 0 )
arguments - > device = xstrdup ( arg ) ;
else
{
/* Too many arguments. */
2012-02-26 16:28:05 +00:00
fprintf ( stderr , _ ( " Unknown extra argument `%s'. " ) , arg ) ;
fprintf ( stderr , " \n " ) ;
2010-09-20 10:37:37 +00:00
argp_usage ( state ) ;
}
break ;
case ARGP_KEY_NO_ARGS :
2010-09-20 16:56:14 +00:00
fprintf ( stderr , " %s " , _ ( " No device is specified. \n " ) ) ;
2010-09-20 10:37:37 +00:00
argp_usage ( state ) ;
2012-02-03 20:18:37 +00:00
exit ( 1 ) ;
2010-09-20 10:37:37 +00:00
break ;
default :
return ARGP_ERR_UNKNOWN ;
}
return 0 ;
2003-01-02 20:12:33 +00:00
}
2010-09-20 10:37:37 +00:00
static struct argp argp = {
options , argp_parser , N_ ( " DEVICE " ) ,
2010-09-21 09:17:54 +00:00
" \n " N_ ( " \
2010-09-20 10:37:37 +00:00
Set up images to boot from DEVICE . \ n \
\ n \
2010-09-21 09:17:54 +00:00
You should not normally run this program directly . Use grub - install instead . " )
" \v " N_ ( " \
2010-10-26 10:33:57 +00:00
DEVICE must be an OS device ( e . g . / dev / sda ) . " ),
2010-09-20 10:37:37 +00:00
NULL , help_filter , NULL
} ;
2003-01-02 20:12:33 +00:00
static char *
get_device_name ( char * dev )
{
size_t len = strlen ( dev ) ;
2009-06-10 21:04:23 +00:00
2003-01-02 20:12:33 +00:00
if ( dev [ 0 ] ! = ' ( ' | | dev [ len - 1 ] ! = ' ) ' )
return 0 ;
dev [ len - 1 ] = ' \0 ' ;
return dev + 1 ;
}
int
main ( int argc , char * argv [ ] )
{
2010-09-14 19:07:39 +00:00
char * root_dev = NULL ;
char * dest_dev = NULL ;
2010-09-20 10:37:37 +00:00
struct arguments arguments ;
2009-06-10 21:04:23 +00:00
2009-11-18 23:20:22 +00:00
set_program_name ( argv [ 0 ] ) ;
2010-01-01 20:32:30 +00:00
grub_util_init_nls ( ) ;
2003-01-02 20:12:33 +00:00
2010-09-20 10:37:37 +00:00
/* Default option values. */
memset ( & arguments , 0 , sizeof ( struct arguments ) ) ;
arguments . fs_probe = 1 ;
2003-01-02 20:12:33 +00:00
2010-09-20 10:37:37 +00:00
/* Parse our arguments */
if ( argp_parse ( & argp , argc , argv , 0 , 0 , & arguments ) ! = 0 )
{
2010-09-20 16:56:14 +00:00
fprintf ( stderr , " %s " , _ ( " Error in parsing command line arguments \n " ) ) ;
2010-09-20 10:37:37 +00:00
exit ( 1 ) ;
2003-01-02 20:12:33 +00:00
}
2012-02-27 13:24:22 +00:00
# ifdef GRUB_SETUP_SPARC64
2010-09-30 17:27:28 +00:00
arguments . force = 1 ;
# endif
2008-02-09 10:46:37 +00:00
if ( verbosity > 1 )
grub_env_set ( " debug " , " all " ) ;
2005-07-24 18:16:26 +00:00
/* Initialize the emulated biosdisk driver. */
2010-09-20 10:37:37 +00:00
grub_util_biosdisk_init ( arguments . dev_map ? : DEFAULT_DEVICE_MAP ) ;
2003-01-02 20:12:33 +00:00
2007-07-22 19:17:27 +00:00
/* Initialize all modules. */
grub_init_all ( ) ;
2011-08-16 14:19:06 +00:00
grub_gcry_init_all ( ) ;
2009-06-10 21:04:23 +00:00
2010-09-05 21:24:57 +00:00
grub_lvm_fini ( ) ;
2010-09-20 18:09:31 +00:00
grub_mdraid09_fini ( ) ;
grub_mdraid1x_fini ( ) ;
2012-01-29 13:28:01 +00:00
grub_diskfilter_fini ( ) ;
grub_diskfilter_init ( ) ;
2010-09-20 18:09:31 +00:00
grub_mdraid09_init ( ) ;
grub_mdraid1x_init ( ) ;
2010-09-05 21:24:57 +00:00
grub_lvm_init ( ) ;
2010-09-20 10:37:37 +00:00
dest_dev = get_device_name ( arguments . device ) ;
2003-01-02 20:12:33 +00:00
if ( ! dest_dev )
{
2005-07-24 18:16:26 +00:00
/* Possibly, the user specified an OS device file. */
2010-09-20 10:37:37 +00:00
dest_dev = grub_util_get_grub_dev ( arguments . device ) ;
2005-07-24 18:16:26 +00:00
if ( ! dest_dev )
2010-09-20 10:37:37 +00:00
{
char * program = xstrdup ( program_name ) ;
fprintf ( stderr , _ ( " Invalid device `%s'. \n " ) , arguments . device ) ;
argp_help ( & argp , stderr , ARGP_HELP_STD_USAGE , program ) ;
free ( program ) ;
exit ( 1 ) ;
}
2010-09-14 19:07:39 +00:00
grub_util_info ( " transformed OS device `%s' into GRUB device `%s' " ,
2010-09-20 10:37:37 +00:00
arguments . device , dest_dev ) ;
2003-01-02 20:12:33 +00:00
}
2005-07-24 18:16:26 +00:00
else
2010-09-14 19:07:39 +00:00
{
/* For simplicity. */
dest_dev = xstrdup ( dest_dev ) ;
grub_util_info ( " Using `%s' as GRUB device " , dest_dev ) ;
}
2003-01-02 20:12:33 +00:00
2012-01-29 13:28:01 +00:00
/* Do the real work. */
setup ( arguments . dir ? : DEFAULT_DIRECTORY ,
arguments . boot_file ? : DEFAULT_BOOT_FILE ,
arguments . core_file ? : DEFAULT_CORE_FILE ,
2012-02-03 09:35:28 +00:00
dest_dev , arguments . force ,
2012-01-29 13:28:01 +00:00
arguments . fs_probe , arguments . allow_floppy ) ;
2003-01-02 20:12:33 +00:00
/* Free resources. */
2007-07-22 19:17:27 +00:00
grub_fini_all ( ) ;
2004-04-04 13:46:03 +00:00
grub_util_biosdisk_fini ( ) ;
2009-06-10 21:04:23 +00:00
2010-09-20 10:37:37 +00:00
free ( arguments . boot_file ) ;
free ( arguments . core_file ) ;
free ( arguments . dir ) ;
free ( arguments . dev_map ) ;
free ( arguments . device ) ;
2003-01-02 20:12:33 +00:00
free ( root_dev ) ;
2005-07-24 18:16:26 +00:00
free ( dest_dev ) ;
2009-06-10 21:04:23 +00:00
2003-01-02 20:12:33 +00:00
return 0 ;
}