diff --git a/Changelog.phcoder b/Changelog.phcoder new file mode 100644 index 0000000..a272618 --- /dev/null +++ b/Changelog.phcoder @@ -0,0 +1,73 @@ +2009-06-08 Vladimir Serbinenko + + Nested partitions + + * commands/blocklist.c (grub_cmd_blocklist): Don't check whether + 'partition' is NULL, grub_partition_get_start already does that. + * commands/loadenv.c (check_blocklists): Likewise. + (write_blocklists): Likewise. + * conf/common.rmk (grub_probe_SOURCES): Add partmap/bsdlabel.c. + (grub_fstest_SOURCES): Likewise. + (pkglib_MODULES): Add bsdlabel.mod. + (bsdlabel_mod_SOURCES): New variable. + (bsdlabel_mod_CFLAGS): Likewise. + (bsdlabel_mod_LDFLAGS): Likewise. + * conf/i386-coreboot.rmk (grub_emu_SOURCES): Add partmap/bsdlabel.c. + * conf/i386-pc.rmk (grub_setup_SOURCES): Likewise. + (grub_emu_SOURCES): Likewise. + * conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): Likewise. + * conf/sparc64-ieee1275.rmk (grub_emu_SOURCES): Likewise. + * include/grub/bsdlabel.h: New file. + * include/grub/partition.h (grub_partition_map): Remove 'probe' and + 'get_name'. + (grub_partition): Add 'parent' and 'number'. + (grub_partition_get_start): Handle nested partitions. + * include/grub/pc_partition.h: Remove bsd-related entries. + (grub_pc_partition): Remove. + * kern/disk.c (grub_disk_close): Free partition data. + (grub_disk_adjust_range): Handle nested partitions. + * kern/partition.c (grub_partition_map_probe): New function. + (grub_partition_probe): Parse name to number, handle subpartitions. + (get_partmap): New function. + (grub_partition_iterate): Handle subpartitions. + (grub_partition_get_name): Likewise. + * loader/i386/pc/bsd.c (grub_bsd_get_device): Likewise. + * loader/i386/multiboot.c (grub_multiboot_get_bootdev): Likewise. + * loader/i386/pc/chainloader.c (grub_chainloader_cmd): Likewise. + * partmap/acorn.c (acorn_partition_map_iterate): Don't force raw access. + Set 'number'. + (acorn_partition_map_probe): Remove. + (acorn_partition_map_get_name): Likewise. + * partmap/amiga.c (amiga_partition_map_iterate): Don't force raw access. + Set 'number'. + Set 'index' to 0 since there can be only one partition entry per sector. + (amiga_partition_map_probe): Remove. + (amiga_partition_map_get_name): Likewise. + * partmap/apple.c (apple_partition_map_iterate): Don't force raw access. + Set 'number'. + Set 'offset' and 'index' to real positions of partitions. + (apple_partition_map_probe): Remove. + (apple_partition_map_get_name): Likewise. + * partmap/bsdlabel.c: New file. + * partmap/gpt.c (gpt_partition_map_iterate): Don't force raw access. + Set 'number'. + Allocate 'data' so it can be correctly freed. + Set 'index' to offset inside sector. + (gpt_partition_map_probe): Remove. + (gpt_partition_map_get_name): Likewise. + * partmap/pc.c (grub_partition_parse): Remove. + (pc_partition_map_iterate): Don't force raw access. + Set 'number'. + Make 'ext_offset' a local variable. + (pc_partition_map_probe): Remove. + (pc_partition_map_get_name): Remove. + * partmap/sun.c (sun_partition_map_iterate): Don't force raw access. + Set 'number'. + (sun_partition_map_probe): Remove. + (sun_partition_map_get_name): Likewise. + * parttool/pcpart.c (grub_pcpart_boot): Handle nested partitions. + (grub_pcpart_type): Likewise. + * util/hostdisk.c (open_device): Handle new numbering scheme. + (grub_util_biosdisk_get_grub_dev): Handle nested partitions. + * util/i386/pc/grub-setup.c (setup): Handle new numbering scheme. + * util/grub-probe.c (probe_partmap): Handle nested paritions. diff --git a/commands/blocklist.c b/commands/blocklist.c index b457b7c..6cc7d69 100644 --- a/commands/blocklist.c +++ b/commands/blocklist.c @@ -89,8 +89,7 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)), return grub_error (GRUB_ERR_BAD_DEVICE, "this command is available only for disk devices."); - if (file->device->disk->partition) - part_start = grub_partition_get_start (file->device->disk->partition); + part_start = grub_partition_get_start (file->device->disk->partition); file->read_hook = read_blocklist; diff --git a/commands/loadenv.c b/commands/loadenv.c index 22665f9..51cffd3 100644 --- a/commands/loadenv.c +++ b/commands/loadenv.c @@ -236,10 +236,8 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists, /* One more sanity check. Re-read all sectors by blocklists, and compare those with the data read via a file. */ disk = file->device->disk; - if (disk->partition) - part_start = grub_partition_get_start (disk->partition); - else - part_start = 0; + + part_start = grub_partition_get_start (disk->partition); buf = grub_envblk_buffer (envblk); for (p = blocklists, index = 0; p; p = p->next, index += p->length) @@ -272,10 +270,7 @@ write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists, buf = grub_envblk_buffer (envblk); disk = file->device->disk; - if (disk->partition) - part_start = grub_partition_get_start (disk->partition); - else - part_start = 0; + part_start = grub_partition_get_start (disk->partition); index = 0; for (p = blocklists; p; p = p->next, index += p->length) diff --git a/conf/common.rmk b/conf/common.rmk index 6d76746..2aee811 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -19,7 +19,8 @@ grub_probe_SOURCES = util/grub-probe.c \ fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \ fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c \ \ - partmap/msdos.c partmap/apple.c partmap/sun.c partmap/gpt.c\ + partmap/msdos.c partmap/bsdlabel.c partmap/apple.c \ + partmap/sun.c partmap/gpt.c\ kern/fs.c kern/env.c fs/fshelp.c \ disk/raid.c disk/mdraid_linux.c disk/lvm.c grub_probe_init.c @@ -40,8 +41,8 @@ grub_fstest_SOURCES = util/grub-fstest.c util/hostfs.c util/misc.c \ fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \ fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c \ \ - kern/partition.c partmap/msdos.c partmap/apple.c partmap/sun.c \ - partmap/gpt.c \ + kern/partition.c partmap/msdos.c partmap/bsdlabel.c \ + partmap/apple.c partmap/sun.c partmap/gpt.c \ kern/fs.c kern/env.c fs/fshelp.c disk/raid.c \ disk/raid5_recover.c disk/raid6_recover.c \ disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ @@ -316,6 +317,11 @@ part_gpt_mod_SOURCES = partmap/gpt.c part_gpt_mod_CFLAGS = $(COMMON_CFLAGS) part_gpt_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES += part_bsd.mod +part_bsd_mod_SOURCES = partmap/bsdlabel.c +part_bsd_mod_CFLAGS = $(COMMON_CFLAGS) +part_bsd_mod_LDFLAGS = $(COMMON_LDFLAGS) + # Special disk structures and generic drivers pkglib_MODULES += raid.mod raid5rec.mod raid6rec.mod mdraid.mod dm_nv.mod \ diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index 7e9f853..a626a9a 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -135,8 +135,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ normal/color.c \ script/sh/main.c script/sh/execute.c script/sh/function.c \ script/sh/lexer.c script/sh/script.c grub_script.tab.c \ - partmap/amiga.c partmap/apple.c partmap/msdos.c partmap/sun.c \ - partmap/acorn.c partmap/gpt.c \ + partmap/amiga.c partmap/apple.c partmap/msdos.c \ + partmap/bsdlabel.c partmap/sun.c partmap/acorn.c partmap/gpt.c \ util/console.c util/hostfs.c util/grub-emu.c util/misc.c \ util/hostdisk.c util/getroot.c \ \ diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index 67234eb..f21a612 100644 --- a/conf/i386-ieee1275.rmk +++ b/conf/i386-ieee1275.rmk @@ -89,8 +89,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ normal/color.c \ script/sh/main.c script/sh/execute.c script/sh/function.c \ script/sh/lexer.c script/sh/script.c grub_script.tab.c \ - partmap/amiga.c partmap/apple.c partmap/msdos.c partmap/sun.c \ - partmap/acorn.c partmap/gpt.c \ + partmap/amiga.c partmap/apple.c partmap/msdos.c \ + partmap/bsdlabel.c partmap/sun.c partmap/acorn.c partmap/gpt.c \ util/console.c util/hostfs.c util/grub-emu.c util/misc.c \ util/hostdisk.c util/getroot.c \ \ diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 6b17796..55bd22f 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -104,7 +104,7 @@ grub_setup_SOURCES = util/i386/pc/grub-setup.c util/hostdisk.c \ fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \ fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c \ \ - partmap/msdos.c partmap/gpt.c \ + partmap/msdos.c partmap/bsdlabel.c partmap/gpt.c \ \ disk/raid.c disk/mdraid_linux.c disk/lvm.c \ util/raid.c util/lvm.c \ @@ -141,8 +141,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ normal/menu_text.c \ script/sh/main.c script/sh/execute.c script/sh/function.c \ script/sh/lexer.c script/sh/script.c grub_script.tab.c \ - partmap/amiga.c partmap/apple.c partmap/msdos.c partmap/sun.c \ - partmap/acorn.c partmap/gpt.c \ + partmap/amiga.c partmap/apple.c partmap/bsdlabel.c \ + partmap/msdos.c partmap/sun.c partmap/acorn.c partmap/gpt.c \ \ fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \ fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \ diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk index c9b7e75..db423e1 100644 --- a/conf/powerpc-ieee1275.rmk +++ b/conf/powerpc-ieee1275.rmk @@ -70,8 +70,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ normal/color.c \ script/sh/main.c script/sh/execute.c script/sh/function.c \ script/sh/lexer.c script/sh/script.c \ - partmap/amiga.c partmap/apple.c partmap/msdos.c partmap/sun.c \ - partmap/acorn.c \ + partmap/amiga.c partmap/apple.c partmap/msdos.c \ + partmap/bsdlabel.c partmap/sun.c partmap/acorn.c \ util/console.c util/hostfs.c util/grub-emu.c util/misc.c \ util/hostdisk.c util/getroot.c \ \ diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk index 6216213..c2cb7b0 100644 --- a/conf/sparc64-ieee1275.rmk +++ b/conf/sparc64-ieee1275.rmk @@ -80,8 +80,8 @@ grub_setup_SOURCES = util/sparc64/ieee1275/grub-setup.c util/hostdisk.c \ fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \ fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c \ \ - partmap/amiga.c partmap/apple.c partmap/msdos.c \ - partmap/sun.c partmap/acorn.c \ + partmap/amiga.c partmap/apple.c partmap/msdos.c \ + partmap/bsdlabel.c partmap/sun.c partmap/acorn.c \ \ disk/raid.c disk/mdraid_linux.c disk/lvm.c \ util/raid.c util/lvm.c \ diff --git a/include/grub/bsdlabel.h b/include/grub/bsdlabel.h new file mode 100644 index 0000000..d88b253 --- /dev/null +++ b/include/grub/bsdlabel.h @@ -0,0 +1,89 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2004,2007 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 . + */ + +#ifndef GRUB_BSDLABEL_PARTITION_HEADER +#define GRUB_BSDLABEL_PARTITION_HEADER 1 + +/* Constants for BSD disk label. */ +#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR 1 +#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC 0x82564557 + +/* BSD partition types. */ +#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED 0 +#define GRUB_PC_PARTITION_BSD_TYPE_SWAP 1 +#define GRUB_PC_PARTITION_BSD_TYPE_V6 2 +#define GRUB_PC_PARTITION_BSD_TYPE_V7 3 +#define GRUB_PC_PARTITION_BSD_TYPE_SYSV 4 +#define GRUB_PC_PARTITION_BSD_TYPE_V71K 5 +#define GRUB_PC_PARTITION_BSD_TYPE_V8 6 +#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS 7 +#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS 8 +#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS 9 +#define GRUB_PC_PARTITION_BSD_TYPE_OTHER 10 +#define GRUB_PC_PARTITION_BSD_TYPE_HPFS 11 +#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660 12 +#define GRUB_PC_PARTITION_BSD_TYPE_BOOT 13 + +/* FreeBSD-specific types. */ +#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM 14 +#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID 15 +#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2 21 + +/* NetBSD-specific types. */ +#define GRUB_PC_PARTITION_NETBSD_TYPE_ADOS 14 +#define GRUB_PC_PARTITION_NETBSD_TYPE_HFS 15 +#define GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE 16 +#define GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS 17 +#define GRUB_PC_PARTITION_NETBSD_TYPE_NTFS 18 +#define GRUB_PC_PARTITION_NETBSD_TYPE_RAID 19 +#define GRUB_PC_PARTITION_NETBSD_TYPE_CCD 20 +#define GRUB_PC_PARTITION_NETBSD_TYPE_JFS2 21 +#define GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS 22 + +/* OpenBSD-specific types. */ +#define GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS 14 +#define GRUB_PC_PARTITION_OPENBSD_TYPE_HFS 15 +#define GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE 16 +#define GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS 17 +#define GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS 18 +#define GRUB_PC_PARTITION_OPENBSD_TYPE_RAID 19 + +/* The BSD partition entry. */ +struct grub_partition_bsd_entry +{ + grub_uint32_t size; + grub_uint32_t offset; + grub_uint32_t fragment_size; + grub_uint8_t fs_type; + grub_uint8_t fs_fragments; + grub_uint16_t fs_cylinders; +} __attribute__ ((packed)); + +/* The BSD disk label. Only define members useful for GRUB. */ +struct grub_partition_bsd_disk_label +{ + grub_uint32_t magic; + grub_uint8_t padding[128]; + grub_uint32_t magic2; + grub_uint16_t checksum; + grub_uint16_t num_partitions; + grub_uint32_t boot_size; + grub_uint32_t superblock_size; +} __attribute__ ((packed)); + +#endif /* ! GRUB_PC_PARTITION_HEADER */ diff --git a/include/grub/msdos_partition.h b/include/grub/msdos_partition.h index 273d8c9..650d784 100644 --- a/include/grub/msdos_partition.h +++ b/include/grub/msdos_partition.h @@ -53,75 +53,6 @@ #define GRUB_PC_PARTITION_TYPE_GPT_DISK 0xee #define GRUB_PC_PARTITION_TYPE_LINUX_RAID 0xfd -/* Constants for BSD disk label. */ -#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR 1 -#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC 0x82564557 -#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES 8 - -/* BSD partition types. */ -#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED 0 -#define GRUB_PC_PARTITION_BSD_TYPE_SWAP 1 -#define GRUB_PC_PARTITION_BSD_TYPE_V6 2 -#define GRUB_PC_PARTITION_BSD_TYPE_V7 3 -#define GRUB_PC_PARTITION_BSD_TYPE_SYSV 4 -#define GRUB_PC_PARTITION_BSD_TYPE_V71K 5 -#define GRUB_PC_PARTITION_BSD_TYPE_V8 6 -#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS 7 -#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS 8 -#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS 9 -#define GRUB_PC_PARTITION_BSD_TYPE_OTHER 10 -#define GRUB_PC_PARTITION_BSD_TYPE_HPFS 11 -#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660 12 -#define GRUB_PC_PARTITION_BSD_TYPE_BOOT 13 - -/* FreeBSD-specific types. */ -#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM 14 -#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID 15 -#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2 21 - -/* NetBSD-specific types. */ -#define GRUB_PC_PARTITION_NETBSD_TYPE_ADOS 14 -#define GRUB_PC_PARTITION_NETBSD_TYPE_HFS 15 -#define GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE 16 -#define GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS 17 -#define GRUB_PC_PARTITION_NETBSD_TYPE_NTFS 18 -#define GRUB_PC_PARTITION_NETBSD_TYPE_RAID 19 -#define GRUB_PC_PARTITION_NETBSD_TYPE_CCD 20 -#define GRUB_PC_PARTITION_NETBSD_TYPE_JFS2 21 -#define GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS 22 - -/* OpenBSD-specific types. */ -#define GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS 14 -#define GRUB_PC_PARTITION_OPENBSD_TYPE_HFS 15 -#define GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE 16 -#define GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS 17 -#define GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS 18 -#define GRUB_PC_PARTITION_OPENBSD_TYPE_RAID 19 - -/* The BSD partition entry. */ -struct grub_msdos_partition_bsd_entry -{ - grub_uint32_t size; - grub_uint32_t offset; - grub_uint32_t fragment_size; - grub_uint8_t fs_type; - grub_uint8_t fs_fragments; - grub_uint16_t fs_cylinders; -} __attribute__ ((packed)); - -/* The BSD disk label. Only define members useful for GRUB. */ -struct grub_msdos_partition_disk_label -{ - grub_uint32_t magic; - grub_uint8_t padding[128]; - grub_uint32_t magic2; - grub_uint16_t checksum; - grub_uint16_t num_partitions; - grub_uint32_t boot_size; - grub_uint32_t superblock_size; - struct grub_msdos_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES]; -} __attribute__ ((packed)); - /* The partition entry. */ struct grub_msdos_partition_entry { @@ -168,23 +99,6 @@ struct grub_msdos_partition_mbr } __attribute__ ((packed)); -struct grub_msdos_partition -{ - /* The DOS partition number. */ - int dos_part; - - /* The BSD partition number (a == 0). */ - int bsd_part; - - /* The DOS partition type. */ - int dos_type; - - /* The BSD partition type. */ - int bsd_type; - - /* The offset of the extended partition. */ - unsigned long ext_offset; -}; static inline int grub_msdos_partition_is_empty (int type) @@ -200,12 +114,4 @@ grub_msdos_partition_is_extended (int type) || type == GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED); } -static inline int -grub_msdos_partition_is_bsd (int type) -{ - return (type == GRUB_PC_PARTITION_TYPE_FREEBSD - || type == GRUB_PC_PARTITION_TYPE_OPENBSD - || type == GRUB_PC_PARTITION_TYPE_NETBSD); -} - #endif /* ! GRUB_PC_PARTITION_HEADER */ diff --git a/include/grub/partition.h b/include/grub/partition.h index d35658c..5e8c476 100644 --- a/include/grub/partition.h +++ b/include/grub/partition.h @@ -36,13 +36,6 @@ struct grub_partition_map int (*hook) (struct grub_disk *disk, const grub_partition_t partition)); - /* Return the partition named STR on the disk DISK. */ - grub_partition_t (*probe) (struct grub_disk *disk, - const char *str); - - /* Return the name of the partition PARTITION. */ - char *(*get_name) (const grub_partition_t partition); - /* The next partition map type. */ struct grub_partition_map *next; }; @@ -51,6 +44,9 @@ typedef struct grub_partition_map *grub_partition_map_t; /* Partition description. */ struct grub_partition { + /* The partition number. */ + int number; + /* The start sector. */ grub_disk_addr_t start; @@ -66,6 +62,9 @@ struct grub_partition /* Partition map type specific data. */ void *data; + /* Parent partition map. */ + struct grub_partition *parent; + /* The type partition map. */ grub_partition_map_t partmap; }; @@ -101,7 +100,13 @@ void grub_apple_partition_map_fini (void); static inline grub_disk_addr_t grub_partition_get_start (const grub_partition_t p) { - return p->start; + grub_partition_t part; + grub_uint64_t part_start = 0; + + for (part = p; part; part = part->parent) + part_start += part->start; + + return part_start; } static inline grub_uint64_t diff --git a/kern/disk.c b/kern/disk.c index e463626..657ac8d 100644 --- a/kern/disk.c +++ b/kern/disk.c @@ -330,6 +330,7 @@ grub_disk_open (const char *name) void grub_disk_close (grub_disk_t disk) { + grub_partition_t part; grub_dprintf ("disk", "Closing `%s'.\n", disk->name); if (disk->dev && disk->dev->close) @@ -338,7 +339,13 @@ grub_disk_close (grub_disk_t disk) /* Reset the timer. */ grub_last_time = grub_get_time_ms (); - grub_free (disk->partition); + while (disk->partition) + { + part = disk->partition->parent; + grub_free (disk->partition->data); + grub_free (disk->partition); + disk->partition = part; + } grub_free ((void *) disk->name); grub_free (disk); } @@ -349,18 +356,19 @@ grub_disk_close (grub_disk_t disk) - Verify that the range is inside the partition. */ static grub_err_t grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector, - grub_off_t *offset, grub_size_t size) + grub_off_t *offset, grub_size_t size) { + grub_partition_t part; *sector += *offset >> GRUB_DISK_SECTOR_BITS; *offset &= GRUB_DISK_SECTOR_SIZE - 1; - if (disk->partition) + for (part = disk->partition; part; part = part->parent) { grub_disk_addr_t start; grub_uint64_t len; - start = grub_partition_get_start (disk->partition); - len = grub_partition_get_len (disk->partition); + start = part->start; + len = part->len; if (*sector >= len || len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1) diff --git a/kern/partition.c b/kern/partition.c index 4d5c63a..4bcd8c7 100644 --- a/kern/partition.c +++ b/kern/partition.c @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -54,17 +55,58 @@ grub_partition_map_iterate (int (*hook) (const grub_partition_map_t partmap)) return 0; } +static grub_partition_t +grub_partition_map_probe (const grub_partition_map_t partmap, + grub_disk_t disk, int partnum) +{ + grub_partition_t p = 0; + + auto int find_func (grub_disk_t d, const grub_partition_t partition); + + int find_func (grub_disk_t d __attribute__ ((unused)), + const grub_partition_t partition) + { + if (partnum == partition->number) + { + p = (grub_partition_t) grub_malloc (sizeof (*p)); + if (! p) + return 1; + + grub_memcpy (p, partition, sizeof (*p)); + return 1; + } + + return 0; + } + + partmap->iterate (disk, find_func); + if (grub_errno) + goto fail; + + return p; + + fail: + grub_free (p); + return 0; +} + grub_partition_t grub_partition_probe (struct grub_disk *disk, const char *str) { grub_partition_t part = 0; + grub_partition_t curpart = 0; + grub_partition_t tail; + const char *ptr; + int num; auto int part_map_probe (const grub_partition_map_t partmap); int part_map_probe (const grub_partition_map_t partmap) { - part = partmap->probe (disk, str); - if (part) + disk->partition = part; + curpart = grub_partition_map_probe (partmap, disk, num); + disk->partition = tail; + if (curpart) return 1; if (grub_errno == GRUB_ERR_BAD_PART_TABLE) @@ -77,27 +119,54 @@ grub_partition_probe (struct grub_disk *disk, const char *str) return 1; } - /* Use the first partition map type found. */ - grub_partition_map_iterate (part_map_probe); + part = tail = disk->partition; + + for (ptr = str; *ptr;) + { + /* BSD-like partition specification. */ + if (*ptr >= 'a' && *ptr <= 'z') + num = *(ptr++) - 'a'; + else + num = grub_strtoul (ptr, (char **) &ptr, 0) - 1; + + curpart = 0; + /* Use the first partition map type found. */ + grub_partition_map_iterate (part_map_probe); + + if (! curpart) + { + while (part) + { + curpart = part->parent; + grub_free (part); + part = curpart; + } + return 0; + } + curpart->parent = part; + part = curpart; + if (! ptr || *ptr != ',') + break; + ptr++; + } return part; } -int -grub_partition_iterate (struct grub_disk *disk, - int (*hook) (grub_disk_t disk, - const grub_partition_t partition)) +static grub_partition_map_t +get_partmap (struct grub_disk *disk) { grub_partition_map_t partmap = 0; - int ret = 0; - + struct grub_partition part; + int found = 0; auto int part_map_iterate (const grub_partition_map_t p); auto int part_map_iterate_hook (grub_disk_t d, const grub_partition_t partition); - int part_map_iterate_hook (grub_disk_t d __attribute__ ((unused)), - const grub_partition_t partition __attribute__ ((unused))) + const grub_partition_t partition) { + found = 1; + part = *partition; return 1; } @@ -106,22 +175,58 @@ grub_partition_iterate (struct grub_disk *disk, grub_dprintf ("partition", "Detecting %s...\n", p->name); p->iterate (disk, part_map_iterate_hook); - if (grub_errno != GRUB_ERR_NONE) + if (grub_errno != GRUB_ERR_NONE || ! found) { /* Continue to next partition map type. */ grub_dprintf ("partition", "%s detection failed.\n", p->name); grub_errno = GRUB_ERR_NONE; return 0; } + grub_free (part.data); grub_dprintf ("partition", "%s detection succeeded.\n", p->name); partmap = p; return 1; } - grub_partition_map_iterate (part_map_iterate); - if (partmap) - ret = partmap->iterate (disk, hook); + return partmap; +} + +int +grub_partition_iterate (struct grub_disk *disk, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) +{ + int ret = 0; + + auto int part_iterate (grub_disk_t dsk, const grub_partition_t p); + + int part_iterate (grub_disk_t dsk, + const grub_partition_t partition) + { + struct grub_partition p = *partition; + grub_partition_map_t partmap = 0; + p.parent = dsk->partition; + dsk->partition = 0; + if (hook (dsk, &p)) + return 1; + if (p.start != 0) + { + dsk->partition = &p; + partmap = get_partmap (dsk); + if (partmap) + ret = partmap->iterate (dsk, part_iterate); + } + dsk->partition = p.parent; + return ret; + } + + { + grub_partition_map_t partmap = 0; + partmap = get_partmap (disk); + if (partmap) + ret = partmap->iterate (disk, part_iterate); + } return ret; } @@ -129,5 +234,30 @@ grub_partition_iterate (struct grub_disk *disk, char * grub_partition_get_name (const grub_partition_t partition) { - return partition->partmap->get_name (partition); + char *out = 0; + /* Even on 64-bit machines this buffer is enough to hold longest number. */ + char buf[25]; + int curlen = 0; + grub_partition_t part; + for (part = partition; part; part = part->parent) + { + int strl; + grub_sprintf (buf, "%d", part->number + 1); + strl = grub_strlen (buf); + if (curlen) + { + out = grub_realloc (out, curlen + strl + 2); + grub_memcpy (out + strl + 1, out, curlen); + out[curlen + 1 + strl] = 0; + grub_memcpy (out, buf, strl); + out[strl] = ','; + curlen = curlen + 1 + strl; + } + else + { + curlen = strl; + out = grub_strdup (buf); + } + } + return out; } diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c index 0b9a2b4..792d38f 100644 --- a/loader/i386/bsd.c +++ b/loader/i386/bsd.c @@ -135,7 +135,6 @@ grub_bsd_get_device (grub_uint32_t * biosdev, grub_uint32_t * unit, grub_uint32_t * slice, grub_uint32_t * part) { - char *p; grub_device_t dev; *biosdev = grub_get_root_biosnumber () & 0xff; @@ -145,21 +144,13 @@ grub_bsd_get_device (grub_uint32_t * biosdev, dev = grub_device_open (0); if (dev && dev->disk && dev->disk->partition) { - - p = dev->disk->partition->partmap->get_name (dev->disk->partition); - if (p) + if (dev->disk->partition->parent) { - if ((p[0] >= '0') && (p[0] <= '9')) - { - *slice = grub_strtoul (p, &p, 0); - - if ((p) && (p[0] == ',')) - p++; - } - - if ((p[0] >= 'a') && (p[0] <= 'z')) - *part = p[0] - 'a'; + *part = dev->disk->partition->number; + *slice = dev->disk->partition->parent->number + 1; } + else + *slice = dev->disk->partition->number + 1; } if (dev) grub_device_close (dev); diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c index 8c3139b..719a51d 100644 --- a/loader/i386/multiboot.c +++ b/loader/i386/multiboot.c @@ -155,7 +155,6 @@ static int grub_multiboot_get_bootdev (grub_uint32_t *bootdev) { #ifdef GRUB_MACHINE_PCBIOS - char *p; grub_uint32_t biosdev, slice = ~0, part = ~0; grub_device_t dev; @@ -164,21 +163,13 @@ grub_multiboot_get_bootdev (grub_uint32_t *bootdev) dev = grub_device_open (0); if (dev && dev->disk && dev->disk->partition) { - - p = dev->disk->partition->partmap->get_name (dev->disk->partition); - if (p) + if (dev->disk->partition->parent) { - if ((p[0] >= '0') && (p[0] <= '9')) - { - slice = grub_strtoul (p, &p, 0) - 1; - - if ((p) && (p[0] == ',')) - p++; - } - - if ((p[0] >= 'a') && (p[0] <= 'z')) - part = p[0] - 'a'; + part = dev->disk->partition->number; + slice = dev->disk->partition->parent->number; } + else + slice = dev->disk->partition->number; } if (dev) grub_device_close (dev); diff --git a/loader/i386/pc/chainloader.c b/loader/i386/pc/chainloader.c index caf1450..b0503ae 100644 --- a/loader/i386/pc/chainloader.c +++ b/loader/i386/pc/chainloader.c @@ -31,6 +31,7 @@ #include #include #include +#include #include static grub_dl_t my_mod; @@ -94,10 +95,22 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags) dev = grub_device_open (0); if (dev && dev->disk && dev->disk->partition) { - grub_disk_read (dev->disk, dev->disk->partition->offset, 446, 64, - (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR); - part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR - + (dev->disk->partition->index << 4)); + grub_disk_t disk = dev->disk; + + if (disk) + { + grub_partition_t p = disk->partition; + + if (p && grub_strcmp (p->partmap->name, "part_msdos") == 0) + { + disk->partition = p->parent; + grub_disk_read (disk, p->offset, 446, 64, + (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR); + part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR + + (p->index << 4)); + disk->partition = p; + } + } } if (dev) diff --git a/partmap/acorn.c b/partmap/acorn.c index e005975..af9498e 100644 --- a/partmap/acorn.c +++ b/partmap/acorn.c @@ -96,21 +96,17 @@ acorn_partition_map_iterate (grub_disk_t disk, const grub_partition_t partition)) { struct grub_partition part; - struct grub_disk raw; struct linux_part map[LINUX_MAP_ENTRIES]; int i; - grub_disk_addr_t sector; + grub_disk_addr_t sector = 0; grub_err_t err; - /* Enforce raw disk access. */ - raw = *disk; - raw.partition = 0; - - err = acorn_partition_map_find (&raw, map, §or); + err = acorn_partition_map_find (disk, map, §or); if (err) return err; part.partmap = &grub_acorn_partition_map; + part.data = 0; for (i = 0; i != LINUX_MAP_ENTRIES; ++i) { @@ -121,7 +117,7 @@ acorn_partition_map_iterate (grub_disk_t disk, part.start = sector + map[i].start; part.len = map[i].size; part.offset = 6; - part.index = i; + part.number = part.index = i; if (hook (disk, &part)) return grub_errno; @@ -130,60 +126,6 @@ acorn_partition_map_iterate (grub_disk_t disk, return GRUB_ERR_NONE; } - -static grub_partition_t -acorn_partition_map_probe (grub_disk_t disk, const char *str) -{ - struct linux_part map[LINUX_MAP_ENTRIES]; - struct grub_disk raw = *disk; - unsigned long partnum = grub_strtoul (str, 0, 10) - 1; - grub_disk_addr_t sector; - grub_err_t err; - grub_partition_t p; - - /* Enforce raw disk access. */ - raw.partition = 0; - - /* Get the partition number. */ - if (partnum > LINUX_MAP_ENTRIES) - goto fail; - - err = acorn_partition_map_find (&raw, map, §or); - if (err) - return 0; - - if (map[partnum].magic != LINUX_NATIVE_MAGIC - && map[partnum].magic != LINUX_SWAP_MAGIC) - goto fail; - - p = grub_malloc (sizeof (struct grub_partition)); - if (! p) - return 0; - - p->start = sector + map[partnum].start; - p->len = map[partnum].size; - p->offset = 6; - p->index = partnum; - return p; - -fail: - grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition"); - return 0; -} - - -static char * -acorn_partition_map_get_name (const grub_partition_t p) -{ - char *name; - - name = grub_malloc (13); - if (! name) - return 0; - - grub_sprintf (name, "%d", p->index + 1); - return name; -} /* Partition map type. */ @@ -191,8 +133,6 @@ static struct grub_partition_map grub_acorn_partition_map = { .name = "part_acorn", .iterate = acorn_partition_map_iterate, - .probe = acorn_partition_map_probe, - .get_name = acorn_partition_map_get_name }; GRUB_MOD_INIT(acorn_partition_map) diff --git a/partmap/amiga.c b/partmap/amiga.c index dce9f4f..27ccf95 100644 --- a/partmap/amiga.c +++ b/partmap/amiga.c @@ -76,20 +76,15 @@ amiga_partition_map_iterate (grub_disk_t disk, { struct grub_partition part; struct grub_amiga_rdsk rdsk; - struct grub_disk raw; int partno = 0; int next = -1; unsigned pos; - /* Enforce raw disk access. */ - raw = *disk; - raw.partition = 0; - /* The RDSK block is one of the first 15 blocks. */ for (pos = 0; pos < 15; pos++) { /* Read the RDSK block which is a descriptor for the entire disk. */ - if (grub_disk_read (&raw, pos, 0, sizeof (rdsk), &rdsk)) + if (grub_disk_read (disk, pos, 0, sizeof (rdsk), &rdsk)) return grub_errno; if (grub_strcmp ((char *) rdsk.magic, "RDSK") == 0) @@ -104,13 +99,15 @@ amiga_partition_map_iterate (grub_disk_t disk, return grub_error (GRUB_ERR_BAD_PART_TABLE, "Amiga partition map not found."); + part.data = 0; + /* The end of the partition list is marked using "-1". */ while (next != -1) { struct grub_amiga_partition apart; /* Read the RDSK block which is a descriptor for the entire disk. */ - if (grub_disk_read (&raw, next, 0, sizeof (apart), &apart)) + if (grub_disk_read (disk, next, 0, sizeof (apart), &apart)) return grub_errno; /* Calculate the first block and the size of the partition. */ @@ -123,7 +120,8 @@ amiga_partition_map_iterate (grub_disk_t disk, * grub_be_to_cpu32 (apart.block_per_track)); part.offset = (grub_off_t) next * 512; - part.index = partno; + part.number = partno; + part.index = 0; part.partmap = &grub_amiga_partition_map; if (hook (disk, &part)) @@ -136,72 +134,12 @@ amiga_partition_map_iterate (grub_disk_t disk, return 0; } - -static grub_partition_t -amiga_partition_map_probe (grub_disk_t disk, const char *str) -{ - grub_partition_t p = 0; - int partnum = 0; - char *s = (char *) str; - - auto int find_func (grub_disk_t d, const grub_partition_t partition); - - int find_func (grub_disk_t d __attribute__ ((unused)), - const grub_partition_t partition) - { - if (partnum == partition->index) - { - p = (grub_partition_t) grub_malloc (sizeof (*p)); - if (! p) - return 1; - - grub_memcpy (p, partition, sizeof (*p)); - return 1; - } - - return 0; - } - - /* Get the partition number. */ - partnum = grub_strtoul (s, 0, 10) - 1; - if (grub_errno) - { - grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition"); - return 0; - } - - if (amiga_partition_map_iterate (disk, find_func)) - goto fail; - - return p; - - fail: - grub_free (p); - return 0; -} - - -static char * -amiga_partition_map_get_name (const grub_partition_t p) -{ - char *name; - - name = grub_malloc (13); - if (! name) - return 0; - - grub_sprintf (name, "%d", p->index + 1); - return name; -} - /* Partition map type. */ static struct grub_partition_map grub_amiga_partition_map = { .name = "part_amiga", .iterate = amiga_partition_map_iterate, - .probe = amiga_partition_map_probe, - .get_name = amiga_partition_map_get_name }; GRUB_MOD_INIT(amiga_partition_map) diff --git a/partmap/apple.c b/partmap/apple.c index 4dea55a..3534ac3 100644 --- a/partmap/apple.c +++ b/partmap/apple.c @@ -105,17 +105,12 @@ apple_partition_map_iterate (grub_disk_t disk, struct grub_partition part; struct grub_apple_header aheader; struct grub_apple_part apart; - struct grub_disk raw; int partno = 0, partnum = 0; unsigned pos; - /* Enforce raw disk access. */ - raw = *disk; - raw.partition = 0; - part.partmap = &grub_apple_partition_map; - if (grub_disk_read (&raw, 0, 0, sizeof (aheader), &aheader)) + if (grub_disk_read (disk, 0, 0, sizeof (aheader), &aheader)) return grub_errno; if (grub_be_to_cpu16 (aheader.magic) != GRUB_APPLE_HEADER_MAGIC) @@ -127,14 +122,17 @@ apple_partition_map_iterate (grub_disk_t disk, goto fail; } + part.data = 0; pos = grub_be_to_cpu16 (aheader.blocksize); do { - if (grub_disk_read (&raw, pos / GRUB_DISK_SECTOR_SIZE, - pos % GRUB_DISK_SECTOR_SIZE, - sizeof (struct grub_apple_part), &apart)) - return grub_errno; + part.offset = pos / GRUB_DISK_SECTOR_SIZE; + part.index = pos % GRUB_DISK_SECTOR_SIZE; + + if (grub_disk_read (disk, part.offset, part.index, + sizeof (struct grub_apple_part), &apart)) + return grub_errno; if (grub_be_to_cpu16 (apart.magic) != GRUB_APPLE_PART_MAGIC) { @@ -156,6 +154,7 @@ apple_partition_map_iterate (grub_disk_t disk, / GRUB_DISK_SECTOR_SIZE; part.offset = pos; part.index = partno; + part.number = partno; grub_dprintf ("partition", "partition %d: name %s, type %s, start 0x%x, len 0x%x\n", @@ -179,72 +178,12 @@ apple_partition_map_iterate (grub_disk_t disk, "Apple partition map not found."); } - -static grub_partition_t -apple_partition_map_probe (grub_disk_t disk, const char *str) -{ - grub_partition_t p = 0; - int partnum = 0; - char *s = (char *) str; - - auto int find_func (grub_disk_t d, const grub_partition_t partition); - - int find_func (grub_disk_t d __attribute__ ((unused)), - const grub_partition_t partition) - { - if (partnum == partition->index) - { - p = (grub_partition_t) grub_malloc (sizeof (*p)); - if (! p) - return 1; - - grub_memcpy (p, partition, sizeof (*p)); - return 1; - } - - return 0; - } - - /* Get the partition number. */ - partnum = grub_strtoul (s, 0, 10) - 1; - if (grub_errno) - { - grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition"); - return 0; - } - - if (apple_partition_map_iterate (disk, find_func)) - goto fail; - - return p; - - fail: - grub_free (p); - return 0; -} - - -static char * -apple_partition_map_get_name (const grub_partition_t p) -{ - char *name; - - name = grub_malloc (13); - if (! name) - return 0; - - grub_sprintf (name, "%d", p->index + 1); - return name; -} - /* Partition map type. */ static struct grub_partition_map grub_apple_partition_map = { .name = "part_apple", .iterate = apple_partition_map_iterate, - .probe = apple_partition_map_probe, - .get_name = apple_partition_map_get_name }; GRUB_MOD_INIT(apple_partition_map) diff --git a/partmap/bsdlabel.c b/partmap/bsdlabel.c new file mode 100644 index 0000000..8613881 --- /dev/null +++ b/partmap/bsdlabel.c @@ -0,0 +1,97 @@ +/* bsdlabel.c - Read BSD style partition tables. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2005,2006,2007,2008,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 . + */ + +#include +#include +#include +#include +#include +#include + +static struct grub_partition_map grub_bsdlabel_partition_map; + + +static grub_err_t +bsdlabel_partition_map_iterate (grub_disk_t disk, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) +{ + struct grub_partition_bsd_disk_label label; + struct grub_partition p; + grub_disk_addr_t delta = 0; + unsigned pos; + + /* BSDLabel offsets are absolute even when it's embed inside partition. */ + delta = grub_partition_get_start (disk->partition); + + /* Read the BSD label. */ + if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, + 0, sizeof (label), &label)) + return grub_errno; + + /* Check if it is valid. */ + if (label.magic != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature"); + + pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR + * GRUB_DISK_SECTOR_SIZE; + + for (p.number = 0; + p.number < grub_cpu_to_le16 (label.num_partitions); + p.number++) + { + struct grub_partition_bsd_entry be; + + p.offset = pos / GRUB_DISK_SECTOR_SIZE; + p.index = pos % GRUB_DISK_SECTOR_SIZE; + + if (grub_disk_read (disk, p.offset, p.index, sizeof (be), &be)) + return grub_errno; + + p.start = grub_le_to_cpu32 (be.offset) - delta; + p.len = grub_le_to_cpu32 (be.size); + p.partmap = &grub_bsdlabel_partition_map; + + if (be.fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED) + if (hook (disk, &p)) + return grub_errno; + + pos += sizeof (struct grub_partition_bsd_entry); + } + + return GRUB_ERR_NONE; +} + + +/* Partition map type. */ +static struct grub_partition_map grub_bsdlabel_partition_map = + { + .name = "part_bsd", + .iterate = bsdlabel_partition_map_iterate, + }; + +GRUB_MOD_INIT(bsd_partition_map) +{ + grub_partition_map_register (&grub_bsdlabel_partition_map); +} + +GRUB_MOD_FINI(bsd_partition_map) +{ + grub_partition_map_unregister (&grub_bsdlabel_partition_map); +} diff --git a/partmap/gpt.c b/partmap/gpt.c index 4a49574..c53c395 100644 --- a/partmap/gpt.c +++ b/partmap/gpt.c @@ -44,18 +44,13 @@ gpt_partition_map_iterate (grub_disk_t disk, struct grub_partition part; struct grub_gpt_header gpt; struct grub_gpt_partentry entry; - struct grub_disk raw; struct grub_msdos_partition_mbr mbr; grub_uint64_t entries; unsigned int i; int last_offset = 0; - /* Enforce raw disk access. */ - raw = *disk; - raw.partition = 0; - /* Read the protective MBR. */ - if (grub_disk_read (&raw, 0, 0, sizeof (mbr), &mbr)) + if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr)) return grub_errno; /* Check if it is valid. */ @@ -67,7 +62,7 @@ gpt_partition_map_iterate (grub_disk_t disk, return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found"); /* Read the GPT header. */ - if (grub_disk_read (&raw, 1, 0, sizeof (gpt), &gpt)) + if (grub_disk_read (disk, 1, 0, sizeof (gpt), &gpt)) return grub_errno; if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic))) @@ -76,11 +71,15 @@ gpt_partition_map_iterate (grub_disk_t disk, grub_dprintf ("gpt", "Read a valid GPT header\n"); entries = grub_le_to_cpu64 (gpt.partitions); + part.data = grub_malloc (sizeof (entry)); for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++) { - if (grub_disk_read (&raw, entries, last_offset, + if (grub_disk_read (disk, entries, last_offset, sizeof (entry), &entry)) - return grub_errno; + { + grub_free (part.data); + return grub_errno; + } if (grub_memcmp (&grub_gpt_partition_type_empty, &entry.type, sizeof (grub_gpt_partition_type_empty))) @@ -90,16 +89,17 @@ gpt_partition_map_iterate (grub_disk_t disk, part.len = (grub_le_to_cpu64 (entry.end) - grub_le_to_cpu64 (entry.start) + 1); part.offset = entries; - part.index = i; + part.number = i; + part.index = last_offset; part.partmap = &grub_gpt_partition_map; - part.data = &entry; + grub_memcpy (part.data, &entry, sizeof (entry)); grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i, (unsigned long long) part.start, (unsigned long long) part.len); if (hook (disk, &part)) - return 1; + return grub_errno; } last_offset += grub_le_to_cpu32 (gpt.partentry_size); @@ -109,67 +109,9 @@ gpt_partition_map_iterate (grub_disk_t disk, entries++; } } + grub_free (part.data); - return 0; -} - - -static grub_partition_t -gpt_partition_map_probe (grub_disk_t disk, const char *str) -{ - grub_partition_t p = 0; - int partnum = 0; - char *s = (char *) str; - - auto int find_func (grub_disk_t d, const grub_partition_t partition); - - int find_func (grub_disk_t d __attribute__ ((unused)), - const grub_partition_t partition) - { - if (partnum == partition->index) - { - p = (grub_partition_t) grub_malloc (sizeof (*p)); - if (! p) - return 1; - - grub_memcpy (p, partition, sizeof (*p)); - return 1; - } - - return 0; - } - - /* Get the partition number. */ - partnum = grub_strtoul (s, 0, 10) - 1; - if (grub_errno) - { - grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition"); - return 0; - } - - gpt_partition_map_iterate (disk, find_func); - if (grub_errno) - goto fail; - - return p; - - fail: - grub_free (p); - return 0; -} - - -static char * -gpt_partition_map_get_name (const grub_partition_t p) -{ - char *name; - - name = grub_malloc (13); - if (! name) - return 0; - - grub_sprintf (name, "%d", p->index + 1); - return name; + return GRUB_ERR_NONE; } @@ -178,8 +120,6 @@ static struct grub_partition_map grub_gpt_partition_map = { .name = "part_gpt", .iterate = gpt_partition_map_iterate, - .probe = gpt_partition_map_probe, - .get_name = gpt_partition_map_get_name }; GRUB_MOD_INIT(gpt_partition_map) diff --git a/partmap/msdos.c b/partmap/msdos.c index d0fc18e..598d189 100644 --- a/partmap/msdos.c +++ b/partmap/msdos.c @@ -27,85 +27,19 @@ static struct grub_partition_map grub_msdos_partition_map; -/* Parse the partition representation in STR and return a partition. */ -static grub_partition_t -grub_partition_parse (const char *str) -{ - grub_partition_t p; - struct grub_msdos_partition *pcdata; - - char *s = (char *) str; - - p = (grub_partition_t) grub_malloc (sizeof (*p)); - if (! p) - return 0; - - pcdata = (struct grub_msdos_partition *) grub_malloc (sizeof (*pcdata)); - if (! pcdata) - goto fail; - - p->data = pcdata; - p->partmap = &grub_msdos_partition_map; - - /* Initialize some of the fields with invalid values. */ - pcdata->bsd_part = pcdata->dos_type = pcdata->bsd_type = p->index = -1; - - /* Get the DOS partition number. The number is counted from one for - the user interface, and from zero internally. */ - pcdata->dos_part = grub_strtoul (s, &s, 0) - 1; - - if (grub_errno) - { - /* Not found. Maybe only a BSD label is specified. */ - pcdata->dos_part = -1; - grub_errno = GRUB_ERR_NONE; - } - else if (*s == ',') - s++; - - if (*s) - { - if (*s >= 'a' && *s <= 'h') - { - pcdata->bsd_part = *s - 'a'; - s++; - } - - if (*s) - goto fail; - } - - if (pcdata->dos_part == -1 && pcdata->bsd_part == -1) - goto fail; - - return p; - - fail: - grub_free (p); - grub_free (pcdata); - grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition"); - return 0; -} - static grub_err_t pc_partition_map_iterate (grub_disk_t disk, int (*hook) (grub_disk_t disk, const grub_partition_t partition)) { struct grub_partition p; - struct grub_msdos_partition pcdata; struct grub_msdos_partition_mbr mbr; - struct grub_msdos_partition_disk_label label; - struct grub_disk raw; - - /* Enforce raw disk access. */ - raw = *disk; - raw.partition = 0; + grub_disk_addr_t ext_offset; p.offset = 0; - pcdata.ext_offset = 0; - pcdata.dos_part = -1; - p.data = &pcdata; + ext_offset = 0; + p.data = 0; + p.number = -1; p.partmap = &grub_msdos_partition_map; while (1) @@ -114,7 +48,7 @@ pc_partition_map_iterate (grub_disk_t disk, struct grub_msdos_partition_entry *e; /* Read the MBR. */ - if (grub_disk_read (&raw, p.offset, 0, sizeof (mbr), &mbr)) + if (grub_disk_read (disk, p.offset, 0, sizeof (mbr), &mbr)) goto finish; /* Check if it is valid. */ @@ -132,13 +66,10 @@ pc_partition_map_iterate (grub_disk_t disk, p.start = p.offset + grub_le_to_cpu32 (e->start); p.len = grub_le_to_cpu32 (e->length); - pcdata.bsd_part = -1; - pcdata.dos_type = e->type; - pcdata.bsd_type = -1; grub_dprintf ("partition", "partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n", - p.index, e->flag, pcdata.dos_type, + p.index, e->flag, e->type, (unsigned long long) p.start, (unsigned long long) p.len); @@ -150,59 +81,15 @@ pc_partition_map_iterate (grub_disk_t disk, if (! grub_msdos_partition_is_empty (e->type) && ! grub_msdos_partition_is_extended (e->type)) { - pcdata.dos_part++; + p.number++; if (hook (disk, &p)) - return 1; - - /* Check if this is a BSD partition. */ - if (grub_msdos_partition_is_bsd (e->type)) - { - /* Check if the BSD label is within the DOS partition. */ - if (p.len <= GRUB_PC_PARTITION_BSD_LABEL_SECTOR) - { - grub_dprintf ("partition", "no space for disk label\n"); - continue; - } - /* Read the BSD label. */ - if (grub_disk_read (&raw, - (p.start - + GRUB_PC_PARTITION_BSD_LABEL_SECTOR), - 0, - sizeof (label), - &label)) - goto finish; - - /* Check if it is valid. */ - if (label.magic - != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC)) - { - grub_dprintf ("partition", - "invalid disk label magic 0x%x on partition %d\n", - label.magic, p.index); - continue; - } - for (pcdata.bsd_part = 0; - pcdata.bsd_part < grub_cpu_to_le16 (label.num_partitions); - pcdata.bsd_part++) - { - struct grub_msdos_partition_bsd_entry *be - = label.entries + pcdata.bsd_part; - - p.start = grub_le_to_cpu32 (be->offset); - p.len = grub_le_to_cpu32 (be->size); - pcdata.bsd_type = be->fs_type; - - if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED) - if (hook (disk, &p)) - return 1; - } - } + return grub_errno; } - else if (pcdata.dos_part < 4) + else if (p.number < 4) /* If this partition is a logical one, shouldn't increase the partition number. */ - pcdata.dos_part++; + p.number++; } /* Find an extended partition. */ @@ -212,9 +99,9 @@ pc_partition_map_iterate (grub_disk_t disk, if (grub_msdos_partition_is_extended (e->type)) { - p.offset = pcdata.ext_offset + grub_le_to_cpu32 (e->start); - if (! pcdata.ext_offset) - pcdata.ext_offset = p.offset; + p.offset = ext_offset + grub_le_to_cpu32 (e->start); + if (! ext_offset) + ext_offset = p.offset; break; } @@ -229,84 +116,12 @@ pc_partition_map_iterate (grub_disk_t disk, return grub_errno; } - -static grub_partition_t -pc_partition_map_probe (grub_disk_t disk, const char *str) -{ - grub_partition_t p; - struct grub_msdos_partition *pcdata; - - auto int find_func (grub_disk_t d, const grub_partition_t partition); - - int find_func (grub_disk_t d __attribute__ ((unused)), - const grub_partition_t partition) - { - struct grub_msdos_partition *partdata = partition->data; - - if ((pcdata->dos_part == partdata->dos_part || pcdata->dos_part == -1) - && pcdata->bsd_part == partdata->bsd_part) - { - grub_memcpy (p, partition, sizeof (*p)); - p->data = pcdata; - grub_memcpy (pcdata, partdata, sizeof (*pcdata)); - return 1; - } - - return 0; - } - - p = grub_partition_parse (str); - if (! p) - return 0; - - pcdata = p->data; - pc_partition_map_iterate (disk, find_func); - if (grub_errno) - goto fail; - - if (p->index < 0) - { - grub_error (GRUB_ERR_BAD_DEVICE, "no such partition"); - goto fail; - } - - return p; - - fail: - grub_free (p); - grub_free (pcdata); - return 0; -} - - -static char * -pc_partition_map_get_name (const grub_partition_t p) -{ - char *name; - struct grub_msdos_partition *pcdata = p->data; - - name = grub_malloc (13); - if (! name) - return 0; - - if (pcdata->bsd_part < 0) - grub_sprintf (name, "%d", pcdata->dos_part + 1); - else if (pcdata->dos_part < 0) - grub_sprintf (name, "%c", pcdata->bsd_part + 'a'); - else - grub_sprintf (name, "%d,%c", pcdata->dos_part + 1, pcdata->bsd_part + 'a'); - - return name; -} - /* Partition map type. */ static struct grub_partition_map grub_msdos_partition_map = { .name = "part_msdos", .iterate = pc_partition_map_iterate, - .probe = pc_partition_map_probe, - .get_name = pc_partition_map_get_name }; GRUB_MOD_INIT(pc_partition_map) diff --git a/partmap/sun.c b/partmap/sun.c index e816ec1..ff01d10 100644 --- a/partmap/sun.c +++ b/partmap/sun.c @@ -88,19 +88,15 @@ sun_partition_map_iterate (grub_disk_t disk, const grub_partition_t partition)) { grub_partition_t p; - struct grub_disk raw; struct grub_sun_block block; int partnum; - raw = *disk; - raw.partition = 0; - p = (grub_partition_t) grub_zalloc (sizeof (struct grub_partition)); if (! p) return grub_errno; p->partmap = &grub_sun_partition_map; - if (grub_disk_read (&raw, 0, 0, sizeof (struct grub_sun_block), + if (grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block), &block) == GRUB_ERR_NONE) { if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic)) @@ -124,7 +120,7 @@ sun_partition_map_iterate (grub_disk_t disk, * grub_be_to_cpu16 (block.ntrks) * grub_be_to_cpu16 (block.nsect)); p->len = grub_be_to_cpu32 (desc->num_sectors); - p->index = partnum; + p->number = p->index = partnum; if (p->len) { if (hook (disk, p)) @@ -138,68 +134,11 @@ sun_partition_map_iterate (grub_disk_t disk, return grub_errno; } -static grub_partition_t -sun_partition_map_probe (grub_disk_t disk, const char *str) -{ - grub_partition_t p = 0; - int partnum = 0; - char *s = (char *) str; - - auto int find_func (grub_disk_t d, const grub_partition_t partition); - - int find_func (grub_disk_t d __attribute__ ((unused)), - const grub_partition_t partition) - { - if (partnum == partition->index) - { - p = (grub_partition_t) grub_malloc (sizeof (*p)); - if (p) - grub_memcpy (p, partition, sizeof (*p)); - - return 1; - } - - return 0; - } - - grub_errno = GRUB_ERR_NONE; - partnum = grub_strtoul (s, 0, 10) - 1; - if (grub_errno == GRUB_ERR_NONE) - { - if (sun_partition_map_iterate (disk, find_func)) - { - grub_free (p); - p = 0; - } - } - else - { - grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition"); - p = 0; - } - - return p; -} - -static char * -sun_partition_map_get_name (const grub_partition_t p) -{ - char *name; - - name = grub_malloc (13); - if (name) - grub_sprintf (name, "%d", p->index + 1); - - return name; -} - /* Partition map type. */ static struct grub_partition_map grub_sun_partition_map = { .name = "part_sun", .iterate = sun_partition_map_iterate, - .probe = sun_partition_map_probe, - .get_name = sun_partition_map_get_name }; GRUB_MOD_INIT(sun_partition_map) diff --git a/parttool/msdospart.c b/parttool/msdospart.c index dbb25bc..b1fe689 100644 --- a/parttool/msdospart.c +++ b/parttool/msdospart.c @@ -49,7 +49,7 @@ static grub_err_t grub_pcpart_boot (const grub_device_t dev, index = dev->disk->partition->index; part = dev->disk->partition; - dev->disk->partition = 0; + dev->disk->partition = part->parent; /* Read the MBR. */ if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr)) @@ -96,7 +96,7 @@ static grub_err_t grub_pcpart_type (const grub_device_t dev, index = dev->disk->partition->index; part = dev->disk->partition; - dev->disk->partition = 0; + dev->disk->partition = part->parent; /* Read the parttable. */ if (grub_disk_read (dev->disk, part->offset, 0, diff --git a/util/grub-probe.c b/util/grub-probe.c index 1710ec5..d6406ce 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -79,13 +79,16 @@ grub_refresh (void) static void probe_partmap (grub_disk_t disk) { + grub_partition_t part; + if (disk->partition == NULL) { grub_util_info ("No partition map found for %s", disk->name); return; } - printf ("%s\n", disk->partition->partmap->name); + for (part = disk->partition; part; part = part->parent) + printf ("%s\n", part->partmap->name); } static int diff --git a/util/hostdisk.c b/util/hostdisk.c index a06ecca..6e876df 100644 --- a/util/hostdisk.c +++ b/util/hostdisk.c @@ -333,10 +333,13 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) { int is_partition = 0; char dev[PATH_MAX]; + grub_disk_addr_t part_start = 0; + + part_start = grub_partition_get_start (disk->partition); strcpy (dev, map[disk->id].device); if (disk->partition && strncmp (map[disk->id].device, "/dev/", 5) == 0) - is_partition = linux_find_partition (dev, disk->partition->start); + is_partition = linux_find_partition (dev, part_start); /* Open the partition. */ grub_dprintf ("hostdisk", "opening the device `%s' in open_device()", dev); @@ -351,7 +354,7 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) ioctl (fd, BLKFLSBUF, 0); if (is_partition) - sector -= disk->partition->start; + sector -= part_start; } #else /* ! __linux__ */ #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) @@ -947,39 +950,25 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev) int find_partition (grub_disk_t disk __attribute__ ((unused)), const grub_partition_t partition) { - struct grub_msdos_partition *pcdata = NULL; - - if (strcmp (partition->partmap->name, "part_msdos") == 0) - pcdata = partition->data; + grub_disk_addr_t part_start = 0; + grub_util_info ("Partition %d starts from %lu", + partition->number, partition->start); - if (pcdata) - { - if (pcdata->bsd_part < 0) - grub_util_info ("DOS partition %d starts from %lu", - pcdata->dos_part, partition->start); - else - grub_util_info ("BSD partition %d,%c starts from %lu", - pcdata->dos_part, pcdata->bsd_part + 'a', - partition->start); - } - else - { - grub_util_info ("Partition %d starts from %lu", - partition->index, partition->start); - } + part_start = grub_partition_get_start (partition); - if (hdg.start == partition->start) + if (hdg.start == part_start) { - if (pcdata) + if (partition->parent) { - dos_part = pcdata->dos_part; - bsd_part = pcdata->bsd_part; + dos_part = partition->parent->number; + bsd_part = partition->number; } else { - dos_part = partition->index; + dos_part = partition->number; bsd_part = -1; } + return 1; } diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index ccfbd1d..06add7c 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -121,15 +121,10 @@ setup (const char *dir, int NESTED_FUNC_ATTR find_usable_region_msdos (grub_disk_t disk __attribute__ ((unused)), const grub_partition_t p) { - struct grub_msdos_partition *pcdata = p->data; - /* There's always an embed region, and it starts right after the MBR. */ embed_region.start = 1; - /* For its end offset, include as many dummy partitions as we can. */ - if (! grub_msdos_partition_is_empty (pcdata->dos_type) - && ! grub_msdos_partition_is_bsd (pcdata->dos_type) - && embed_region.end > p->start) + if (embed_region.end > p->start) embed_region.end = p->start; return 0; @@ -278,22 +273,19 @@ setup (const char *dir, /* Embed information about the installed location. */ if (root_dev->disk->partition) { - if (strcmp (root_dev->disk->partition->partmap->name, - "part_msdos") == 0) + if (root_dev->disk->partition->parent) { - struct grub_msdos_partition *pcdata = - root_dev->disk->partition->data; - dos_part = pcdata->dos_part; - bsd_part = pcdata->bsd_part; + if (root_dev->disk->partition->parent->parent) + grub_util_error ("Installing on doubly nested partitions is " + "not supported"); + dos_part = root_dev->disk->partition->parent->number; + bsd_part = root_dev->disk->partition->number; } - else if (strcmp (root_dev->disk->partition->partmap->name, - "part_gpt") == 0) + else { - dos_part = root_dev->disk->partition->index; + dos_part = root_dev->disk->partition->number; bsd_part = -1; } - else - grub_util_error ("No PC style partitions found"); } else dos_part = bsd_part = -1; @@ -326,6 +318,8 @@ setup (const char *dir, int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk __attribute__ ((unused)), const grub_partition_t p) { + if (p->parent) + return 0; dest_partmap = p->partmap->name; return 1; }