diff --git a/ChangeLog b/ChangeLog
index 63daa3a..574227f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,76 @@
+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.
+
2009-07-31 Vladimir Serbinenko
* commands/hexdump.c (grub_cmd_hexdump): Use grub_disk_read instead
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 032517f..dbbf38f 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/xfs.c fs/afs.c fs/befs.c fs/tar.c \
\
- partmap/pc.c partmap/apple.c partmap/sun.c partmap/gpt.c\
+ partmap/pc.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/xfs.c fs/afs.c fs/befs.c fs/tar.c \
\
- kern/partition.c partmap/pc.c partmap/apple.c partmap/sun.c \
- partmap/gpt.c \
+ kern/partition.c partmap/pc.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 \
@@ -280,7 +281,8 @@ befs_mod_CFLAGS = $(COMMON_CFLAGS)
befs_mod_LDFLAGS = $(COMMON_LDFLAGS)
# Partition maps.
-pkglib_MODULES += amiga.mod apple.mod pc.mod sun.mod acorn.mod gpt.mod
+pkglib_MODULES += amiga.mod apple.mod pc.mod sun.mod acorn.mod gpt.mod \
+ bsdlabel.mod
# For amiga.mod
amiga_mod_SOURCES = partmap/amiga.c
@@ -297,6 +299,11 @@ pc_mod_SOURCES = partmap/pc.c
pc_mod_CFLAGS = $(COMMON_CFLAGS)
pc_mod_LDFLAGS = $(COMMON_LDFLAGS)
+# For pc.mod
+bsdlabel_mod_SOURCES = partmap/bsdlabel.c
+bsdlabel_mod_CFLAGS = $(COMMON_CFLAGS)
+bsdlabel_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
# For sun.mod
sun_mod_SOURCES = partmap/sun.c
sun_mod_CFLAGS = $(COMMON_CFLAGS)
diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
index 7ba5737..252f6e1 100644
--- a/conf/i386-coreboot.rmk
+++ b/conf/i386-coreboot.rmk
@@ -134,8 +134,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/pc.c partmap/sun.c \
- partmap/acorn.c partmap/gpt.c \
+ partmap/amiga.c partmap/apple.c partmap/pc.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 0321979..cd31408 100644
--- a/conf/i386-ieee1275.rmk
+++ b/conf/i386-ieee1275.rmk
@@ -88,8 +88,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/pc.c partmap/sun.c \
- partmap/acorn.c partmap/gpt.c \
+ partmap/amiga.c partmap/apple.c partmap/pc.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 798aee2..c213bfd 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -106,7 +106,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/xfs.c fs/afs.c fs/befs.c fs/tar.c \
\
- partmap/pc.c partmap/gpt.c \
+ partmap/pc.c partmap/bsdlabel.c partmap/gpt.c \
\
disk/raid.c disk/mdraid_linux.c disk/lvm.c \
util/raid.c util/lvm.c \
@@ -142,8 +142,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/pc.c partmap/sun.c \
- partmap/acorn.c partmap/gpt.c \
+ partmap/amiga.c partmap/apple.c partmap/bsdlabel.c partmap/pc.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 af29d23..5a1e837 100644
--- a/conf/powerpc-ieee1275.rmk
+++ b/conf/powerpc-ieee1275.rmk
@@ -69,8 +69,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/pc.c partmap/sun.c \
- partmap/acorn.c \
+ partmap/amiga.c partmap/apple.c partmap/pc.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 aabccee..7d7e6d2 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/xfs.c fs/afs.c fs/befs.c fs/tar.c \
\
- partmap/amiga.c partmap/apple.c partmap/pc.c \
- partmap/sun.c partmap/acorn.c \
+ partmap/amiga.c partmap/apple.c partmap/pc.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..ba75897
--- /dev/null
+++ b/include/grub/bsdlabel.h
@@ -0,0 +1,91 @@
+/*
+ * 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
+#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_pc_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_pc_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_pc_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
+} __attribute__ ((packed));
+
+#endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/include/grub/partition.h b/include/grub/partition.h
index 37c5f24..1c4ba31 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/include/grub/pc_partition.h b/include/grub/pc_partition.h
index 67c312e..0b081ed 100644
--- a/include/grub/pc_partition.h
+++ b/include/grub/pc_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_pc_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_pc_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_pc_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
-} __attribute__ ((packed));
-
/* The partition entry. */
struct grub_pc_partition_entry
{
@@ -168,23 +99,6 @@ struct grub_pc_partition_mbr
} __attribute__ ((packed));
-struct grub_pc_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_pc_partition_is_empty (int type)
@@ -200,12 +114,4 @@ grub_pc_partition_is_extended (int type)
|| type == GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED);
}
-static inline int
-grub_pc_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/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 468e6d0..d9135b2 100644
--- a/loader/i386/bsd.c
+++ b/loader/i386/bsd.c
@@ -86,7 +86,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;
@@ -96,21 +95,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 87ffcae..cbb07bb 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..925163e 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,25 @@ 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;
+
+ /* In i386-pc, the id is equal to the BIOS drive number. */
+ drive = (int) disk->id;
+
+ if (p && grub_strcmp (p->partmap->name, "pc_partition_map") == 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 42fd61f..8443554 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 = "Linux/ADFS partition map",
.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 ffb807f..90cf525 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 = "amiga_partition_map",
.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 fce2f2c..9929190 100644
--- a/partmap/apple.c
+++ b/partmap/apple.c
@@ -104,17 +104,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;
unsigned pos = GRUB_DISK_SECTOR_SIZE;
- /* 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)
@@ -126,12 +121,16 @@ apple_partition_map_iterate (grub_disk_t disk,
goto fail;
}
+ part.data = 0;
+
for (;;)
{
- 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)
{
@@ -144,8 +143,7 @@ apple_partition_map_iterate (grub_disk_t disk,
part.start = grub_be_to_cpu32 (apart.first_phys_block);
part.len = grub_be_to_cpu32 (apart.blockcnt);
- 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",
@@ -172,72 +170,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 = "apple_partition_map",
.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..f376dce
--- /dev/null
+++ b/partmap/bsdlabel.c
@@ -0,0 +1,87 @@
+/* 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_pc_partition_disk_label label;
+ struct grub_partition p;
+ grub_disk_addr_t delta = 0;
+
+ /* 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))
+ goto finish;
+
+ /* 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");
+ for (p.number = 0;
+ p.number < grub_cpu_to_le16 (label.num_partitions);
+ p.number++)
+ {
+ struct grub_pc_partition_bsd_entry *be
+ = label.entries + p.number;
+
+ p.start = grub_le_to_cpu32 (be->offset) - delta;
+ p.len = grub_le_to_cpu32 (be->size);
+ p.offset = GRUB_PC_PARTITION_BSD_LABEL_SECTOR;
+ p.partmap = &grub_bsdlabel_partition_map;
+ p.index = p.number;
+
+ if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
+ if (hook (disk, &p))
+ return 1;
+ }
+ finish:
+ return grub_errno;
+}
+
+
+/* Partition map type. */
+static struct grub_partition_map grub_bsdlabel_partition_map =
+ {
+ .name = "bsdlabel_partition_map",
+ .iterate = bsdlabel_partition_map_iterate,
+ };
+
+GRUB_MOD_INIT(bsdlabel_partition_map)
+{
+ grub_partition_map_register (&grub_bsdlabel_partition_map);
+}
+
+GRUB_MOD_FINI(bsdlabel_partition_map)
+{
+ grub_partition_map_unregister (&grub_bsdlabel_partition_map);
+}
diff --git a/partmap/gpt.c b/partmap/gpt.c
index d646d41..041d6be 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_pc_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,9 +89,10 @@ 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,
@@ -109,77 +109,17 @@ 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;
-}
-
/* Partition map type. */
static struct grub_partition_map grub_gpt_partition_map =
{
.name = "gpt_partition_map",
.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/pc.c b/partmap/pc.c
index 6a2efd2..cb56c9b 100644
--- a/partmap/pc.c
+++ b/partmap/pc.c
@@ -27,85 +27,19 @@
static struct grub_partition_map grub_pc_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_pc_partition *pcdata;
-
- char *s = (char *) str;
-
- p = (grub_partition_t) grub_malloc (sizeof (*p));
- if (! p)
- return 0;
-
- pcdata = (struct grub_pc_partition *) grub_malloc (sizeof (*pcdata));
- if (! pcdata)
- goto fail;
-
- p->data = pcdata;
- p->partmap = &grub_pc_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_pc_partition pcdata;
struct grub_pc_partition_mbr mbr;
- struct grub_pc_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_pc_partition_map;
while (1)
@@ -114,7 +48,7 @@ pc_partition_map_iterate (grub_disk_t disk,
struct grub_pc_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_pc_partition_is_empty (e->type)
&& ! grub_pc_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_pc_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_pc_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;
- }
- }
}
- 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_pc_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_pc_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_pc_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_pc_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_pc_partition_map =
{
.name = "pc_partition_map",
.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 ce6d588..63ba6ae 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 = "sun_partition_map",
.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/pcpart.c b/parttool/pcpart.c
index 6876d0d..da4d921 100644
--- a/parttool/pcpart.c
+++ b/parttool/pcpart.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/hostdisk.c b/util/hostdisk.c
index fdf3514..ca57893 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_pc_partition *pcdata = NULL;
-
- if (strcmp (partition->partmap->name, "pc_partition_map") == 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 92c69ef..e737233 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_pc_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_pc_partition_is_empty (pcdata->dos_type)
- && ! grub_pc_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,
- "pc_partition_map") == 0)
+ if (root_dev->disk->partition->parent)
{
- struct grub_pc_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 partitiond 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,
- "gpt_partition_map") == 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;