/* 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.
*
* 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/partition.h>
#ifdef GRUB_MACHINE_IEEE1275
#endif
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <assert.h>
#include "progname.h"
#include <grub/reed_solomon.h>
#include <grub/msdos_partition.h>
#ifdef __sun__
#include <multiboot.h>
#endif
#include <argp.h>
/* 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_MACHINE_SPARC64
#elif defined (GRUB_MACHINE_PCBIOS)
#else
#endif
const char *current_device;
static void
{
#ifdef GRUB_MACHINE_PCBIOS
{
/* FIXME: can this be skipped? */
*boot_drive = 0xFF;
}
#endif
#ifdef GRUB_MACHINE_IEEE1275
{
}
#endif
}
#ifdef GRUB_MACHINE_IEEE1275
#else
#define BOOT_SECTOR 0
#endif
#ifdef __sun__
#include "grub-solvers.c"
#endif
static void
#ifdef __sun__
, char *version_spec
#endif
)
{
char *tmp_img;
int i;
#ifdef GRUB_MACHINE_PCBIOS
#endif
#ifdef __sun__
int got_embed_region = 0;
#endif
unsigned offset,
unsigned length);
unsigned offset,
unsigned length);
unsigned offset,
unsigned length)
{
grub_util_info ("the first sector is <%llu,%u,%u>",
grub_util_error (_("the first sector of the core file is not sector-aligned"));
}
unsigned offset,
unsigned length)
{
grub_util_error (_("non-sector-aligned data is found in the core file"));
if (block != first_block
else
{
#ifdef GRUB_MACHINE_PCBIOS
#endif
block--;
grub_util_error (_("the sectors of the core file are too fragmented"));
}
#ifdef GRUB_MACHINE_PCBIOS
#endif
}
/* Read the boot image by the OS service. */
if (boot_size != GRUB_DISK_SECTOR_SIZE)
grub_util_error (_("the size of `%s' is not %u"),
if (core_size < GRUB_DISK_SECTOR_SIZE)
#ifdef GRUB_MACHINE_PCBIOS
#endif
/* Have FIRST_BLOCK to point to the first blocklist. */
- sizeof (*block));
/* Open the root device and the destination device. */
grub_util_info ("Opening root");
if (! root_dev)
grub_util_info ("Opening dest");
if (! dest_dev)
#ifdef GRUB_MACHINE_PCBIOS
{
int multiple_partmaps = 0;
int i;
unsigned int nsec;
/* Unlike root_dev, with dest_dev we're interested in the partition map even
if dest_dev itself is a whole disk. */
const grub_partition_t p);
const grub_partition_t p)
{
return 0;
/* NetBSD and OpenBSD subpartitions have metadata inside a partition,
so they are safe to ignore.
*/
return 0;
if (dest_partmap == NULL)
{
dest_partmap = p->partmap;
return 0;
}
if (dest_partmap == p->partmap)
return 0;
multiple_partmaps = 1;
return 1;
}
#ifdef __sun__
if (version_spec)
#endif
nsec = core_sectors;
err = GRUB_ERR_NONE;
#ifdef __sun__
{
{
/*
* sunpc embed function will replace dest_dev->disk->partition with boot slice partition
* if boot slice is not given on command line
*/
got_embed_region = 1;
}
}
{
if (dest_partmap == NULL)
{
goto unable_to_embed;
}
/* sunpc embed function will replace dest_dev->disk->partition with boot slice partition */
got_embed_region = 1;
}
if (got_embed_region)
{
if (err)
{
goto unable_to_embed;
}
/* we don't have grandparent info */
{
/* inside an extended partition. set force_mbr */
if (force_mbr == 0)
{
grub_util_warn("Installing GRUB2 into an extended partition... "
"forcing MBR update");
force_mbr = 1;
}
}
}
if (dest_partmap == NULL)
#endif
&& dest_partmap
{
grub_util_warn (_("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;
}
if (!fs)
#ifdef GRUB_MACHINE_PCBIOS
if (fs_probe)
{
if (!fs && !dest_partmap)
grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"),
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 "
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 "
}
#endif
if (force_mbr)
{
if (comma)
{
*comma = 0;
if (! mbr_dev)
}
else
}
else
#ifdef GRUB_MACHINE_PCBIOS
/* Read the original sector from the disk. */
#endif
#ifdef GRUB_MACHINE_PCBIOS
{
/* Copy the possible DOS BPB. */
/* 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. */
/* Replace the jmp (2 bytes) with double nop's. */
*boot_drive_check = 0x9090;
}
#endif
/* Copy the partition table. */
if (dest_partmap ||
if (! dest_partmap && ! fs)
{
grub_util_warn (_("Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea."));
goto unable_to_embed;
}
{
grub_util_warn (_("A %s%sfilesystem was detected in %s"), fs->name ? : "", fs->name ? " " : "", current_device);
grub_util_warn (_("If this is unexpected, the device should be carefully erased to remove all traces of the filesystem before GRUB can be installed"));
grub_util_warn (_("Additionally, multiple partition schemes have been detected. This combination is not supported and GRUB cannot be installed"));
goto unable_to_embed;
}
{
grub_util_warn (_("Partition style '%s' doesn't support embeding"),
dest_partmap->name);
goto unable_to_embed;
}
{
grub_util_warn (_("File system '%s' doesn't support embeding"),
goto unable_to_embed;
}
#ifdef __sun__
if (got_embed_region == 1)
{
err = 0;
}
else
#endif
{
if (dest_partmap)
else
{
N_("Your embedding area is unusually small. "
"core.img won't fit in it."));
}
}
if (err)
{
goto unable_to_embed;
}
/* Clean out the blocklists. */
block = first_block;
{
block--;
grub_util_error (_("No terminator in the core image"));
}
block = first_block;
for (i = 1; i < nsec; i++)
- sizeof (*block));
#ifdef __sun__
if (version_spec)
{
/* Now update the multiboot header with the new size */
{
&& (grub_target_to_host32 (ptr[0]) +
{
break;
}
}
}
#endif
#if 0
#endif
#ifdef __sun__
if (version_spec)
{
}
#endif
#if 0
grub_reed_solomon_add_redundancy (core_img + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART + GRUB_DISK_SECTOR_SIZE,
- new_core_size);
#endif
/* Make sure that the second blocklist is a terminator. */
/* Write the core image onto the disk. */
if (!dry_run)
{
for (i = 0; i < nsec; i++)
core_img + i * GRUB_DISK_SECTOR_SIZE);
}
goto finish;
}
#endif
if (must_embed)
grub_util_error (_("embedding is not possible, but this is required when "
"the root device is on a RAID array or LVM volume"));
#ifdef GRUB_MACHINE_PCBIOS
grub_util_error (_("embedding is not possible, but this is required for "
"cross-disk install"));
#endif
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."));
if (! force)
grub_util_error (_("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");
/* Make sure that GRUB reads the identical image as the OS. */
for (i = 0; i < MAX_TRIES; i++)
{
grub_util_info ((i == 0) ? _("attempting to read the core image `%s' from GRUB")
: _("attempting to read the core image `%s' from GRUB again"),
if (file)
{
grub_util_info ("succeeded in opening the core image but the size is different (%d != %d)",
!= (grub_ssize_t) core_size)
grub_util_info ("succeeded in opening the core image but cannot read %d bytes",
(int) core_size);
{
#if 0
if (dump)
{
}
if (dump2)
{
}
#endif
grub_util_info ("succeeded in opening the core image but the data is different");
}
else
{
break;
}
}
else
grub_util_info ("couldn't open the core image");
if (grub_errno)
sleep (1);
}
if (i == MAX_TRIES)
/* Clean out the blocklists. */
block = first_block;
{
#ifdef GRUB_MACHINE_PCBIOS
#endif
block--;
grub_util_error (_("no terminator in the core image"));
}
/* Now read the core image to determine where the sectors are. */
if (! file)
grub_util_error (_("failed to read the first sector of the core image"));
block = first_block;
grub_util_error (_("failed to read the rest sectors of the core image"));
#ifdef GRUB_MACHINE_IEEE1275
{
char *boot_devpath;
boot_devpath = (char *) (boot_img
{
const char *dest_ofpath;
- GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1);
- GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1] = 0;
}
else
{
grub_util_info ("non cross-disk install");
}
}
#endif
/* Write the first two sectors of the core image onto the disk. */
if (!dry_run)
{
if (! fp)
}
if (!dry_run)
{
/* Write the boot image onto the disk. */
}
if (mbr_dev)
}
N_("Use FILE as the boot image [default=%s]"), 0},
N_("Use FILE as the core image [default=%s]"), 0},
N_("Use GRUB files in the directory DIR [default=%s]"), 0},
N_("Use FILE as the device map [default=%s]"), 0},
N_("Use DEV as the root device [default=guessed]"), 0},
{"force", 'f', 0, 0,
N_("Install even if problems are detected"), 0},
{"skip-fs-probe",'s',0, 0,
N_("Do not probe for filesystems in DEVICE"), 0},
{"verbose", 'v', 0, 0,
N_("Print verbose messages."), 0},
{"allow-floppy", 'a', 0, 0,
N_("Make the drive also bootable as floppy (default for fdX devices). May break on some BIOSes."), 0},
{"force-mbr", 'M', 0, 0,
N_("Write the GRUB2 first stage loader to the MBR regardless of the destination"), 0},
{"dry-run", 'n', 0, 0,
N_("Dry run. Do not modify any disks or files"), 0},
#ifdef __sun__
N_("Embed the specified version info after the image on disk"), 0},
#endif
{ 0, 0, 0, 0, 0, 0 }
};
static char *
{
switch (key)
{
case 'b':
case 'c':
case 'd':
case 'm':
default:
return (char *) text;
}
}
struct arguments
{
char *boot_file;
char *core_file;
char *dir;
char *dev_map;
char *root_dev;
int force;
int fs_probe;
int allow_floppy;
char *device;
int force_mbr;
int dry_run;
#ifdef __sun__
char *version_spec;
#endif
};
/* Print the version information. */
static void
{
}
/* Set the bug report address */
static error_t
{
/* Get the input argument from argp_parse, which we
know is a pointer to our arguments structure. */
char *p;
switch (key)
{
case 'a':
break;
case 'b':
break;
case 'c':
break;
case 'd':
break;
case 'm':
break;
case 'M':
break;
case 'n':
break;
case 'r':
break;
case 'f':
break;
case 's':
break;
case 'v':
verbosity++;
break;
#ifdef __sun__
case 'V':
if (arguments->version_spec)
break;
#endif
case ARGP_KEY_ARG:
else
{
/* Too many arguments. */
argp_usage (state);
}
break;
case ARGP_KEY_NO_ARGS:
argp_usage (state);
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
Set up images to boot from DEVICE.\n\
\n\
You should not normally run this program directly. Use grub-install instead.")
};
static char *
{
return 0;
return dev + 1;
}
int
{
int must_embed = 0;
set_program_name (argv[0]);
/* Default option values. */
/* Parse our arguments */
{
exit(1);
}
#ifdef GRUB_MACHINE_IEEE1275
#endif
if (verbosity > 1)
/* Initialize the emulated biosdisk driver. */
/* Initialize all modules. */
grub_init_all ();
grub_lvm_fini ();
grub_raid_fini ();
grub_raid_init ();
grub_lvm_init ();
if (! dest_dev)
{
/* Possibly, the user specified an OS device file. */
if (! dest_dev)
{
exit(1);
}
grub_util_info ("transformed OS device `%s' into GRUB device `%s'",
}
else
{
/* For simplicity. */
}
{
if (! root_dev)
}
else
{
char *root_device =
if (! root_dev)
{
grub_util_info ("guessing the root device failed, because of `%s'",
grub_util_error (_("cannot guess the root device. Specify the option "
"`--root-device'"));
}
grub_util_info ("guessed root device `%s' and root_dev `%s' from "
}
if (grub_util_lvm_isvolume (root_dev))
must_embed = 1;
#endif
#ifdef __linux__
{
/* FIXME: we can avoid this on RAID1. */
must_embed = 1;
}
{
char **devicelist;
int i;
else
{
char *devname;
}
for (i = 0; devicelist[i]; i++)
{
current_device = devicelist[i];
}
}
else
#endif
/* Do the real work. */
#ifdef __sun__
#endif
);
/* Free resources. */
grub_fini_all ();
return 0;
}