2009-05-09 11:04:08 +00:00
|
|
|
|
/* gptsync.c - fill the mbr based on gpt entries */
|
|
|
|
|
/* XXX: I don't know what to do if sector size isn't 512 bytes */
|
|
|
|
|
/*
|
|
|
|
|
* GRUB -- GRand Unified Bootloader
|
|
|
|
|
* Copyright (C) 2009 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 <grub/command.h>
|
|
|
|
|
#include <grub/dl.h>
|
|
|
|
|
#include <grub/device.h>
|
|
|
|
|
#include <grub/disk.h>
|
2009-08-23 Robert Millan <rmh.grub@aybabtu.com>
* partmap/pc.c: Rename to ...
* partmap/msdos.c: ... this. Update all users.
(grub_pc_partition_map): Rename to ...
(grub_msdos_partition_map): ... this. Update all users.
* parttool/pcpart.c: Rename to ...
* parttool/msdospart.c: ... this. Update all users.
* include/grub/pc_partition.h: Rename to ...
* include/grub/msdos_partition.h: ... this. Update all users.
(grub_pc_partition_bsd_entry): Rename to ...
(grub_msdos_partition_bsd_entry): ... this. Update all users.
(grub_pc_partition_disk_label): Rename to ...
(grub_msdos_partition_disk_label): ... this. Update all users.
(grub_pc_partition_entry): Rename to ...
(grub_msdos_partition_entry): ... this. Update all users.
(grub_pc_partition_mbr): Rename to ...
(grub_msdos_partition_mbr): ... this. Update all users.
(grub_pc_partition): Rename to ...
(grub_msdos_partition): ... this. Update all users.
(grub_pc_partition_is_empty): Rename to ...
(grub_msdos_partition_is_empty): ... this. Update all users.
(grub_pc_partition_is_extended): Rename to ...
(grub_msdos_partition_is_extended): ... this. Update all users.
(grub_pc_partition_is_bsd): Rename to ...
(grub_msdos_partition_is_bsd): ... this. Update all users.
* conf/common.rmk (amiga_mod_SOURCES, amiga_mod_CFLAGS)
(amiga_mod_LDFLAGS, apple_mod_SOURCES, apple_mod_CFLAGS)
(apple_mod_LDFLAGS, msdos_mod_SOURCES, msdos_mod_CFLAGS)
(msdos_mod_LDFLAGS, sun_mod_SOURCES, sun_mod_CFLAGS)
(sun_mod_LDFLAGS, acorn_mod_SOURCES, acorn_mod_CFLAGS)
(acorn_mod_LDFLAGS, gpt_mod_SOURCES, gpt_mod_CFLAGS)
(gpt_mod_LDFLAGS): Rename to ...
(part_amiga_mod_SOURCES, part_amiga_mod_CFLAGS, part_amiga_mod_LDFLAGS)
(part_apple_mod_SOURCES, part_apple_mod_CFLAGS, part_apple_mod_LDFLAGS)
(part_msdos_mod_SOURCES, part_msdos_mod_CFLAGS, part_msdos_mod_LDFLAGS)
(part_sun_mod_SOURCES, part_sun_mod_CFLAGS, part_sun_mod_LDFLAGS)
(part_acorn_mod_SOURCES, part_acorn_mod_CFLAGS, part_acorn_mod_LDFLAGS)
(part_gpt_mod_SOURCES, part_gpt_mod_CFLAGS)
(part_gpt_mod_LDFLAGS): ... this.
(pkglib_MODULES): Prefix partition modules with `part_'. Rename
`pcpart.mod' to `msdospart.mod'.
(pcpart_mod_SOURCES, pcpart_mod_CFLAGS, pcpart_mod_LDFLAGS): Rename
to ...
(msdospart_mod_SOURCES, msdospart_mod_CFLAGS)
(msdospart_mod_LDFLAGS): ... this.
2009-08-23 12:00:57 +00:00
|
|
|
|
#include <grub/msdos_partition.h>
|
2009-05-09 11:04:08 +00:00
|
|
|
|
#include <grub/partition.h>
|
|
|
|
|
#include <grub/misc.h>
|
|
|
|
|
#include <grub/mm.h>
|
|
|
|
|
#include <grub/fs.h>
|
2010-01-03 18:24:22 +00:00
|
|
|
|
#include <grub/i18n.h>
|
2009-05-09 11:04:08 +00:00
|
|
|
|
|
2011-04-11 21:01:51 +00:00
|
|
|
|
GRUB_MOD_LICENSE ("GPLv3+");
|
|
|
|
|
|
2009-05-09 11:04:08 +00:00
|
|
|
|
/* Convert a LBA address to a CHS address in the INT 13 format. */
|
|
|
|
|
/* Taken from grub1. */
|
2009-06-10 21:04:23 +00:00
|
|
|
|
/* XXX: use hardcoded geometry of C = 1024, H = 255, S = 63.
|
2009-05-09 11:04:08 +00:00
|
|
|
|
Is it a problem?
|
|
|
|
|
*/
|
2009-06-10 21:04:23 +00:00
|
|
|
|
static void
|
2013-10-25 16:02:40 +00:00
|
|
|
|
lba_to_chs (grub_uint32_t lba, grub_uint8_t *cl, grub_uint8_t *ch,
|
2009-05-09 11:04:08 +00:00
|
|
|
|
grub_uint8_t *dh)
|
|
|
|
|
{
|
2013-10-25 16:02:40 +00:00
|
|
|
|
grub_uint32_t cylinder, head, sector;
|
|
|
|
|
grub_uint32_t sectors = 63, heads = 255, cylinders = 1024;
|
2009-06-10 21:04:23 +00:00
|
|
|
|
|
2009-05-09 11:04:08 +00:00
|
|
|
|
sector = lba % sectors + 1;
|
|
|
|
|
head = (lba / sectors) % heads;
|
|
|
|
|
cylinder = lba / (sectors * heads);
|
2009-06-10 21:04:23 +00:00
|
|
|
|
|
2009-05-09 11:04:08 +00:00
|
|
|
|
if (cylinder >= cylinders)
|
|
|
|
|
{
|
|
|
|
|
*cl = *ch = *dh = 0xff;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-06-10 21:04:23 +00:00
|
|
|
|
|
2009-05-09 11:04:08 +00:00
|
|
|
|
*cl = sector | ((cylinder & 0x300) >> 2);
|
|
|
|
|
*ch = cylinder & 0xFF;
|
|
|
|
|
*dh = head;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static grub_err_t
|
2009-06-10 21:04:23 +00:00
|
|
|
|
grub_cmd_gptsync (grub_command_t cmd __attribute__ ((unused)),
|
2009-05-09 11:04:08 +00:00
|
|
|
|
int argc, char **args)
|
|
|
|
|
{
|
|
|
|
|
grub_device_t dev;
|
2009-08-23 Robert Millan <rmh.grub@aybabtu.com>
* partmap/pc.c: Rename to ...
* partmap/msdos.c: ... this. Update all users.
(grub_pc_partition_map): Rename to ...
(grub_msdos_partition_map): ... this. Update all users.
* parttool/pcpart.c: Rename to ...
* parttool/msdospart.c: ... this. Update all users.
* include/grub/pc_partition.h: Rename to ...
* include/grub/msdos_partition.h: ... this. Update all users.
(grub_pc_partition_bsd_entry): Rename to ...
(grub_msdos_partition_bsd_entry): ... this. Update all users.
(grub_pc_partition_disk_label): Rename to ...
(grub_msdos_partition_disk_label): ... this. Update all users.
(grub_pc_partition_entry): Rename to ...
(grub_msdos_partition_entry): ... this. Update all users.
(grub_pc_partition_mbr): Rename to ...
(grub_msdos_partition_mbr): ... this. Update all users.
(grub_pc_partition): Rename to ...
(grub_msdos_partition): ... this. Update all users.
(grub_pc_partition_is_empty): Rename to ...
(grub_msdos_partition_is_empty): ... this. Update all users.
(grub_pc_partition_is_extended): Rename to ...
(grub_msdos_partition_is_extended): ... this. Update all users.
(grub_pc_partition_is_bsd): Rename to ...
(grub_msdos_partition_is_bsd): ... this. Update all users.
* conf/common.rmk (amiga_mod_SOURCES, amiga_mod_CFLAGS)
(amiga_mod_LDFLAGS, apple_mod_SOURCES, apple_mod_CFLAGS)
(apple_mod_LDFLAGS, msdos_mod_SOURCES, msdos_mod_CFLAGS)
(msdos_mod_LDFLAGS, sun_mod_SOURCES, sun_mod_CFLAGS)
(sun_mod_LDFLAGS, acorn_mod_SOURCES, acorn_mod_CFLAGS)
(acorn_mod_LDFLAGS, gpt_mod_SOURCES, gpt_mod_CFLAGS)
(gpt_mod_LDFLAGS): Rename to ...
(part_amiga_mod_SOURCES, part_amiga_mod_CFLAGS, part_amiga_mod_LDFLAGS)
(part_apple_mod_SOURCES, part_apple_mod_CFLAGS, part_apple_mod_LDFLAGS)
(part_msdos_mod_SOURCES, part_msdos_mod_CFLAGS, part_msdos_mod_LDFLAGS)
(part_sun_mod_SOURCES, part_sun_mod_CFLAGS, part_sun_mod_LDFLAGS)
(part_acorn_mod_SOURCES, part_acorn_mod_CFLAGS, part_acorn_mod_LDFLAGS)
(part_gpt_mod_SOURCES, part_gpt_mod_CFLAGS)
(part_gpt_mod_LDFLAGS): ... this.
(pkglib_MODULES): Prefix partition modules with `part_'. Rename
`pcpart.mod' to `msdospart.mod'.
(pcpart_mod_SOURCES, pcpart_mod_CFLAGS, pcpart_mod_LDFLAGS): Rename
to ...
(msdospart_mod_SOURCES, msdospart_mod_CFLAGS)
(msdospart_mod_LDFLAGS): ... this.
2009-08-23 12:00:57 +00:00
|
|
|
|
struct grub_msdos_partition_mbr mbr;
|
2009-05-09 11:04:08 +00:00
|
|
|
|
struct grub_partition *partition;
|
|
|
|
|
grub_disk_addr_t first_sector;
|
|
|
|
|
int numactive = 0;
|
2012-05-30 11:51:50 +00:00
|
|
|
|
int i;
|
2009-05-09 11:04:08 +00:00
|
|
|
|
|
|
|
|
|
if (argc < 1)
|
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
|
|
|
|
|
if (argc > 4)
|
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "only 3 partitions can be "
|
|
|
|
|
"in hybrid MBR");
|
|
|
|
|
|
|
|
|
|
if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')')
|
|
|
|
|
{
|
|
|
|
|
args[0][grub_strlen (args[0]) - 1] = 0;
|
2009-06-10 21:04:23 +00:00
|
|
|
|
dev = grub_device_open (args[0] + 1);
|
2009-05-09 11:04:08 +00:00
|
|
|
|
args[0][grub_strlen (args[0])] = ')';
|
|
|
|
|
}
|
|
|
|
|
else
|
2009-06-10 21:04:23 +00:00
|
|
|
|
dev = grub_device_open (args[0]);
|
2009-05-09 11:04:08 +00:00
|
|
|
|
|
|
|
|
|
if (! dev)
|
|
|
|
|
return grub_errno;
|
|
|
|
|
|
|
|
|
|
if (! dev->disk)
|
|
|
|
|
{
|
|
|
|
|
grub_device_close (dev);
|
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read the protective MBR. */
|
2009-05-13 18:58:38 +00:00
|
|
|
|
if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
|
2009-05-09 11:04:08 +00:00
|
|
|
|
{
|
|
|
|
|
grub_device_close (dev);
|
|
|
|
|
return grub_errno;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check if it is valid. */
|
2014-09-22 16:47:10 +00:00
|
|
|
|
if (mbr.signature != grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE))
|
2009-05-09 11:04:08 +00:00
|
|
|
|
{
|
2009-06-10 21:04:23 +00:00
|
|
|
|
grub_device_close (dev);
|
2009-05-09 11:04:08 +00:00
|
|
|
|
return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make sure the MBR is a protective MBR and not a normal MBR. */
|
2012-05-30 11:51:50 +00:00
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
|
if (mbr.entries[i].type == GRUB_PC_PARTITION_TYPE_GPT_DISK)
|
|
|
|
|
break;
|
|
|
|
|
if (i == 4)
|
2009-05-09 11:04:08 +00:00
|
|
|
|
{
|
|
|
|
|
grub_device_close (dev);
|
|
|
|
|
return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
|
|
|
|
|
}
|
2009-06-10 21:04:23 +00:00
|
|
|
|
|
2009-05-09 11:04:08 +00:00
|
|
|
|
first_sector = dev->disk->total_sectors;
|
|
|
|
|
for (i = 1; i < argc; i++)
|
|
|
|
|
{
|
|
|
|
|
char *separator, csep = 0;
|
|
|
|
|
grub_uint8_t type;
|
|
|
|
|
separator = grub_strchr (args[i], '+');
|
|
|
|
|
if (! separator)
|
|
|
|
|
separator = grub_strchr (args[i], '-');
|
|
|
|
|
if (separator)
|
|
|
|
|
{
|
|
|
|
|
csep = *separator;
|
|
|
|
|
*separator = 0;
|
|
|
|
|
}
|
|
|
|
|
partition = grub_partition_probe (dev->disk, args[i]);
|
|
|
|
|
if (separator)
|
|
|
|
|
*separator = csep;
|
|
|
|
|
if (! partition)
|
2009-06-10 21:04:23 +00:00
|
|
|
|
{
|
2009-05-09 11:04:08 +00:00
|
|
|
|
grub_device_close (dev);
|
2012-02-12 14:25:25 +00:00
|
|
|
|
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
|
|
|
|
|
N_("no such partition"));
|
2009-05-09 11:04:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (partition->start + partition->len > 0xffffffff)
|
2009-06-10 21:04:23 +00:00
|
|
|
|
{
|
2009-05-09 11:04:08 +00:00
|
|
|
|
grub_device_close (dev);
|
2009-06-10 21:04:23 +00:00
|
|
|
|
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
2010-06-02 01:37:55 +00:00
|
|
|
|
"only partitions residing in the first 2TB "
|
|
|
|
|
"can be present in hybrid MBR");
|
2009-05-09 11:04:08 +00:00
|
|
|
|
}
|
2009-06-10 21:04:23 +00:00
|
|
|
|
|
2009-05-09 11:04:08 +00:00
|
|
|
|
|
|
|
|
|
if (first_sector > partition->start)
|
|
|
|
|
first_sector = partition->start;
|
|
|
|
|
|
|
|
|
|
if (separator && *(separator + 1))
|
|
|
|
|
type = grub_strtoul (separator + 1, 0, 0);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
grub_fs_t fs = 0;
|
|
|
|
|
dev->disk->partition = partition;
|
|
|
|
|
fs = grub_fs_probe (dev);
|
|
|
|
|
|
|
|
|
|
/* Unknown filesystem isn't fatal. */
|
|
|
|
|
if (grub_errno == GRUB_ERR_UNKNOWN_FS)
|
|
|
|
|
{
|
|
|
|
|
fs = 0;
|
|
|
|
|
grub_errno = GRUB_ERR_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fs && grub_strcmp (fs->name, "ntfs") == 0)
|
|
|
|
|
type = GRUB_PC_PARTITION_TYPE_NTFS;
|
|
|
|
|
else if (fs && grub_strcmp (fs->name, "fat") == 0)
|
|
|
|
|
/* FIXME: detect FAT16. */
|
|
|
|
|
type = GRUB_PC_PARTITION_TYPE_FAT32_LBA;
|
|
|
|
|
else if (fs && (grub_strcmp (fs->name, "hfsplus") == 0
|
|
|
|
|
|| grub_strcmp (fs->name, "hfs") == 0))
|
|
|
|
|
type = GRUB_PC_PARTITION_TYPE_HFS;
|
|
|
|
|
else
|
|
|
|
|
/* FIXME: detect more types. */
|
|
|
|
|
type = GRUB_PC_PARTITION_TYPE_EXT2FS;
|
|
|
|
|
|
|
|
|
|
dev->disk->partition = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mbr.entries[i].flag = (csep == '+') ? 0x80 : 0;
|
|
|
|
|
if (csep == '+')
|
|
|
|
|
{
|
|
|
|
|
numactive++;
|
|
|
|
|
if (numactive == 2)
|
|
|
|
|
{
|
|
|
|
|
grub_device_close (dev);
|
2009-06-10 21:04:23 +00:00
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
2009-05-09 11:04:08 +00:00
|
|
|
|
"only one partition can be active");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mbr.entries[i].type = type;
|
|
|
|
|
mbr.entries[i].start = grub_cpu_to_le32 (partition->start);
|
2009-06-10 21:04:23 +00:00
|
|
|
|
lba_to_chs (partition->start,
|
2009-05-09 11:04:08 +00:00
|
|
|
|
&(mbr.entries[i].start_sector),
|
|
|
|
|
&(mbr.entries[i].start_cylinder),
|
|
|
|
|
&(mbr.entries[i].start_head));
|
2009-06-10 21:04:23 +00:00
|
|
|
|
lba_to_chs (partition->start + partition->len - 1,
|
2009-05-09 11:04:08 +00:00
|
|
|
|
&(mbr.entries[i].end_sector),
|
|
|
|
|
&(mbr.entries[i].end_cylinder),
|
|
|
|
|
&(mbr.entries[i].end_head));
|
|
|
|
|
mbr.entries[i].length = grub_cpu_to_le32 (partition->len);
|
|
|
|
|
grub_free (partition);
|
|
|
|
|
}
|
|
|
|
|
for (; i < 4; i++)
|
|
|
|
|
grub_memset (&(mbr.entries[i]), 0, sizeof (mbr.entries[i]));
|
|
|
|
|
|
|
|
|
|
/* The protective partition. */
|
|
|
|
|
if (first_sector > 0xffffffff)
|
|
|
|
|
first_sector = 0xffffffff;
|
|
|
|
|
else
|
|
|
|
|
first_sector--;
|
|
|
|
|
mbr.entries[0].flag = 0;
|
|
|
|
|
mbr.entries[0].type = GRUB_PC_PARTITION_TYPE_GPT_DISK;
|
2014-09-22 16:47:10 +00:00
|
|
|
|
mbr.entries[0].start = grub_cpu_to_le32_compile_time (1);
|
2009-06-10 21:04:23 +00:00
|
|
|
|
lba_to_chs (1,
|
2009-05-09 11:04:08 +00:00
|
|
|
|
&(mbr.entries[0].start_sector),
|
|
|
|
|
&(mbr.entries[0].start_cylinder),
|
|
|
|
|
&(mbr.entries[0].start_head));
|
2009-06-10 21:04:23 +00:00
|
|
|
|
lba_to_chs (first_sector,
|
2009-05-09 11:04:08 +00:00
|
|
|
|
&(mbr.entries[0].end_sector),
|
|
|
|
|
&(mbr.entries[0].end_cylinder),
|
|
|
|
|
&(mbr.entries[0].end_head));
|
|
|
|
|
mbr.entries[0].length = grub_cpu_to_le32 (first_sector);
|
|
|
|
|
|
2014-09-22 16:47:10 +00:00
|
|
|
|
mbr.signature = grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE);
|
2009-05-09 11:04:08 +00:00
|
|
|
|
|
2009-05-13 18:58:38 +00:00
|
|
|
|
if (grub_disk_write (dev->disk, 0, 0, sizeof (mbr), &mbr))
|
2009-05-09 11:04:08 +00:00
|
|
|
|
{
|
|
|
|
|
grub_device_close (dev);
|
|
|
|
|
return grub_errno;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-03 12:05:08 +00:00
|
|
|
|
grub_printf_ (N_("New MBR is written to `%s'\n"), args[0]);
|
2009-05-09 11:04:08 +00:00
|
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static grub_command_t cmd;
|
|
|
|
|
|
|
|
|
|
GRUB_MOD_INIT(gptsync)
|
|
|
|
|
{
|
|
|
|
|
(void) mod; /* To stop warning. */
|
2009-06-10 21:04:23 +00:00
|
|
|
|
cmd = grub_register_command ("gptsync", grub_cmd_gptsync,
|
2010-01-03 18:24:22 +00:00
|
|
|
|
N_("DEVICE [PARTITION[+/-[TYPE]]] ..."),
|
2012-03-06 13:11:10 +00:00
|
|
|
|
/* TRANSLATORS: MBR type is one-byte partition
|
|
|
|
|
type id. */
|
2010-01-03 18:24:22 +00:00
|
|
|
|
N_("Fill hybrid MBR of GPT drive DEVICE. "
|
2010-06-02 01:37:55 +00:00
|
|
|
|
"Specified partitions will be a part "
|
|
|
|
|
"of hybrid MBR. Up to 3 partitions are "
|
2009-05-09 11:04:08 +00:00
|
|
|
|
"allowed. TYPE is an MBR type. "
|
|
|
|
|
"+ means that partition is active. "
|
2010-01-03 18:24:22 +00:00
|
|
|
|
"Only one partition can be active."));
|
2009-05-09 11:04:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GRUB_MOD_FINI(gptsync)
|
|
|
|
|
{
|
|
|
|
|
grub_unregister_command (cmd);
|
|
|
|
|
}
|