/* gptsync.c - fill the mbr based on gpt entries */ /* XXX: I don't know what to do if sector size isn't 512 bytes */ /* * VasEBoot -- GRand Unified Bootloader * Copyright (C) 2009 Free Software Foundation, Inc. * * VasEBoot 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. * * VasEBoot 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 VasEBoot. If not, see . */ #include #include #include #include #include #include #include #include #include #include VasEBoot_MOD_LICENSE ("GPLv3+"); /* Convert a LBA address to a CHS address in the INT 13 format. */ /* Taken from VasEBoot1. */ /* XXX: use hardcoded geometry of C = 1024, H = 255, S = 63. Is it a problem? */ static void lba_to_chs (VasEBoot_uint32_t lba, VasEBoot_uint8_t *cl, VasEBoot_uint8_t *ch, VasEBoot_uint8_t *dh) { VasEBoot_uint32_t cylinder, head, sector; VasEBoot_uint32_t sectors = 63, heads = 255, cylinders = 1024; sector = lba % sectors + 1; head = (lba / sectors) % heads; cylinder = lba / (sectors * heads); if (cylinder >= cylinders) { *cl = *ch = *dh = 0xff; return; } *cl = sector | ((cylinder & 0x300) >> 2); *ch = cylinder & 0xFF; *dh = head; } static VasEBoot_err_t VasEBoot_cmd_gptsync (VasEBoot_command_t cmd __attribute__ ((unused)), int argc, char **args) { VasEBoot_device_t dev; struct VasEBoot_msdos_partition_mbr mbr; struct VasEBoot_partition *partition; VasEBoot_disk_addr_t first_sector; int numactive = 0; int i; if (argc < 1) return VasEBoot_error (VasEBoot_ERR_BAD_ARGUMENT, "device name required"); if (argc > 4) return VasEBoot_error (VasEBoot_ERR_BAD_ARGUMENT, "only 3 partitions can be " "in hybrid MBR"); if (args[0][0] == '(' && args[0][VasEBoot_strlen (args[0]) - 1] == ')') { args[0][VasEBoot_strlen (args[0]) - 1] = 0; dev = VasEBoot_device_open (args[0] + 1); args[0][VasEBoot_strlen (args[0])] = ')'; } else dev = VasEBoot_device_open (args[0]); if (! dev) return VasEBoot_errno; if (! dev->disk) { VasEBoot_device_close (dev); return VasEBoot_error (VasEBoot_ERR_BAD_ARGUMENT, "not a disk"); } /* Read the protective MBR. */ if (VasEBoot_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr)) { VasEBoot_device_close (dev); return VasEBoot_errno; } /* Check if it is valid. */ if (mbr.signature != VasEBoot_cpu_to_le16_compile_time (VasEBoot_PC_PARTITION_SIGNATURE)) { VasEBoot_device_close (dev); return VasEBoot_error (VasEBoot_ERR_BAD_PART_TABLE, "no signature"); } /* Make sure the MBR is a protective MBR and not a normal MBR. */ for (i = 0; i < 4; i++) if (mbr.entries[i].type == VasEBoot_PC_PARTITION_TYPE_GPT_DISK) break; if (i == 4) { VasEBoot_device_close (dev); return VasEBoot_error (VasEBoot_ERR_BAD_PART_TABLE, "no GPT partition map found"); } first_sector = dev->disk->total_sectors; for (i = 1; i < argc; i++) { char *separator, csep = 0; VasEBoot_uint8_t type; separator = VasEBoot_strchr (args[i], '+'); if (! separator) separator = VasEBoot_strchr (args[i], '-'); if (separator) { csep = *separator; *separator = 0; } partition = VasEBoot_partition_probe (dev->disk, args[i]); if (separator) *separator = csep; if (! partition) { VasEBoot_device_close (dev); return VasEBoot_error (VasEBoot_ERR_UNKNOWN_DEVICE, N_("no such partition")); } if (partition->start + partition->len > 0xffffffff) { VasEBoot_device_close (dev); return VasEBoot_error (VasEBoot_ERR_OUT_OF_RANGE, "only partitions residing in the first 2TB " "can be present in hybrid MBR"); } if (first_sector > partition->start) first_sector = partition->start; if (separator && *(separator + 1)) type = VasEBoot_strtoul (separator + 1, 0, 0); else { VasEBoot_fs_t fs = 0; dev->disk->partition = partition; fs = VasEBoot_fs_probe (dev); /* Unknown filesystem isn't fatal. */ if (VasEBoot_errno == VasEBoot_ERR_UNKNOWN_FS) { fs = 0; VasEBoot_errno = VasEBoot_ERR_NONE; } if (fs && VasEBoot_strcmp (fs->name, "ntfs") == 0) type = VasEBoot_PC_PARTITION_TYPE_NTFS; else if (fs && VasEBoot_strcmp (fs->name, "fat") == 0) /* FIXME: detect FAT16. */ type = VasEBoot_PC_PARTITION_TYPE_FAT32_LBA; else if (fs && (VasEBoot_strcmp (fs->name, "hfsplus") == 0 || VasEBoot_strcmp (fs->name, "hfs") == 0)) type = VasEBoot_PC_PARTITION_TYPE_HFS; else /* FIXME: detect more types. */ type = VasEBoot_PC_PARTITION_TYPE_EXT2FS; dev->disk->partition = 0; } mbr.entries[i].flag = (csep == '+') ? 0x80 : 0; if (csep == '+') { numactive++; if (numactive == 2) { VasEBoot_device_close (dev); return VasEBoot_error (VasEBoot_ERR_BAD_ARGUMENT, "only one partition can be active"); } } mbr.entries[i].type = type; mbr.entries[i].start = VasEBoot_cpu_to_le32 (partition->start); lba_to_chs (partition->start, &(mbr.entries[i].start_sector), &(mbr.entries[i].start_cylinder), &(mbr.entries[i].start_head)); lba_to_chs (partition->start + partition->len - 1, &(mbr.entries[i].end_sector), &(mbr.entries[i].end_cylinder), &(mbr.entries[i].end_head)); mbr.entries[i].length = VasEBoot_cpu_to_le32 (partition->len); VasEBoot_free (partition); } for (; i < 4; i++) VasEBoot_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 = VasEBoot_PC_PARTITION_TYPE_GPT_DISK; mbr.entries[0].start = VasEBoot_cpu_to_le32_compile_time (1); lba_to_chs (1, &(mbr.entries[0].start_sector), &(mbr.entries[0].start_cylinder), &(mbr.entries[0].start_head)); lba_to_chs (first_sector, &(mbr.entries[0].end_sector), &(mbr.entries[0].end_cylinder), &(mbr.entries[0].end_head)); mbr.entries[0].length = VasEBoot_cpu_to_le32 (first_sector); mbr.signature = VasEBoot_cpu_to_le16_compile_time (VasEBoot_PC_PARTITION_SIGNATURE); if (VasEBoot_disk_write (dev->disk, 0, 0, sizeof (mbr), &mbr)) { VasEBoot_device_close (dev); return VasEBoot_errno; } VasEBoot_device_close (dev); VasEBoot_printf_ (N_("New MBR is written to `%s'\n"), args[0]); return VasEBoot_ERR_NONE; } static VasEBoot_command_t cmd; VasEBoot_MOD_INIT(gptsync) { (void) mod; /* To stop warning. */ cmd = VasEBoot_register_command ("gptsync", VasEBoot_cmd_gptsync, N_("DEVICE [PARTITION[+/-[TYPE]]] ..."), /* TRANSLATORS: MBR type is one-byte partition type id. */ N_("Fill hybrid MBR of GPT drive DEVICE. " "Specified partitions will be a part " "of hybrid MBR. Up to 3 partitions are " "allowed. TYPE is an MBR type. " "+ means that partition is active. " "Only one partition can be active.")); } VasEBoot_MOD_FINI(gptsync) { VasEBoot_unregister_command (cmd); }