diff --git a/ChangeLog b/ChangeLog index ff13ff5a7..2438ae32b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +2010-09-20 Vladimir Serbinenko + + Support some annoying BSD and Minix subpartitions. + + * Makefile.util.def (libgrub.a): Add grub-core/partmap/bsdlabel.c. + * grub-core/disk/efi/efidisk.c (grub_efidisk_get_device_name): + Properly handle concatenation. + * grub-core/kern/device.c (grub_device_iterate): Likewise. + * grub-core/normal/completion.c (iterate_partition): Likewise. + * grub-core/kern/disk.c (grub_disk_open): Make disk->name not + contain partition. All users updated. + * grub-core/partmap/bsdlabel.c (grub_netbsdlabel_partition_map): New + struct. + (grub_openbsdlabel_partition_map): Likewise. + (bsdlabel_partition_map_iterate): Rename to .. + (iterate_real): ... this. New arguments sector, freebsd and pmap. + (bsdlabel_partition_map_iterate): New function. + (netopenbsdlabel_partition_map_iterate): Likewise. + (netbsdlabel_partition_map_iterate): Likewise. + (openbsdlabel_partition_map_iterate): Likewise. + (GRUB_MOD_INIT): Register new partmaps. + (GRUB_MOD_FINI): Unregister new partmaps. + * grub-core/partmap/msdos.c (pc_partition_map_iterate): Rename to ... + (grub_partition_msdos_iterate): ... this. All users updated. + Don't support embedding other than in a minix partition. + * include/grub/msdos_partition.h (grub_partition_msdos_iterate): New + proto. + * include/grub/partition.h (grub_partition): New field msdostype. + * util/grub-install.in: Handle openbsd and netbsd types being in + part_bsd module. + 2010-09-20 Vladimir Serbinenko Split mdraid.mod into mdraid09.mod and mdraid1x.mod. diff --git a/Makefile.util.def b/Makefile.util.def index ad99b0f31..f4ae01bd3 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -82,6 +82,7 @@ library = { common = grub-core/partmap/msdos.c; common = grub-core/partmap/sun.c; common = grub-core/partmap/sunpc.c; + common = grub-core/partmap/bsdlabel.c; common = grub-core/script/function.c; common = grub-core/script/lexer.c; common = grub-core/script/main.c; diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c index 7aec1efe8..293467a68 100644 --- a/grub-core/disk/efi/efidisk.c +++ b/grub-core/disk/efi/efidisk.c @@ -727,7 +727,7 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) { /* This is a hard disk partition. */ grub_disk_t parent = 0; - char *partition_name = 0; + const grub_partition_t tpart = NULL; char *device_name; grub_efi_device_path_t *dup_dp, *dup_ldp; grub_efi_hard_drive_device_path_t hd; @@ -766,7 +766,7 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) if (grub_partition_get_start (part) == hd.partition_start && grub_partition_get_len (part) == hd.partition_size) { - partition_name = grub_partition_get_name (part); + tpart = part; return 1; } @@ -795,14 +795,17 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) grub_memcpy (&hd, ldp, sizeof (hd)); grub_partition_iterate (parent, find_partition); - if (! partition_name) + if (! tpart) { grub_disk_close (parent); return 0; } - device_name = grub_xasprintf ("%s,%s", parent->name, partition_name); - grub_free (partition_name); + { + char *partition_name = grub_partition_get_name (tpart); + device_name = grub_xasprintf ("%s,%s", parent->name, partition_name); + grub_free (partition_name); + } grub_disk_close (parent); return device_name; diff --git a/grub-core/kern/device.c b/grub-core/kern/device.c index 9554ca76a..3db14f50e 100644 --- a/grub-core/kern/device.c +++ b/grub-core/kern/device.c @@ -135,28 +135,28 @@ grub_device_iterate (int (*hook) (const char *name)) int iterate_partition (grub_disk_t disk, const grub_partition_t partition) { - char *partition_name; struct part_ent *p; - - partition_name = grub_partition_get_name (partition); - if (! partition_name) - return 1; + char *part_name; p = grub_malloc (sizeof (*p)); if (!p) { - grub_free (partition_name); return 1; } - p->name = grub_xasprintf ("%s,%s", disk->name, partition_name); - if (!p->name) + part_name = grub_partition_get_name (partition); + if (!part_name) + { + grub_free (p); + return 1; + } + p->name = grub_xasprintf ("%s,%s", disk->name, part_name); + grub_free (part_name); + if (!p->name) { - grub_free (partition_name); grub_free (p); return 1; } - grub_free (partition_name); p->next = ents; ents = p; diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c index 7cf29ae7c..807ee4277 100644 --- a/grub-core/kern/disk.c +++ b/grub-core/kern/disk.c @@ -248,10 +248,6 @@ grub_disk_open (const char *name) if (! disk) return 0; - disk->name = grub_strdup (name); - if (! disk->name) - goto fail; - p = find_part_sep (name); if (p) { @@ -263,7 +259,13 @@ grub_disk_open (const char *name) grub_memcpy (raw, name, len); raw[len] = '\0'; + disk->name = grub_strdup (raw); } + else + disk->name = grub_strdup (name); + if (! disk->name) + goto fail; + for (dev = grub_disk_dev_list; dev; dev = dev->next) { diff --git a/grub-core/normal/completion.c b/grub-core/normal/completion.c index 197cb1145..67676dfe4 100644 --- a/grub-core/normal/completion.c +++ b/grub-core/normal/completion.c @@ -100,15 +100,16 @@ static int iterate_partition (grub_disk_t disk, const grub_partition_t p) { const char *disk_name = disk->name; - char *partition_name = grub_partition_get_name (p); char *name; int ret; + char *part_name; - if (! partition_name) + part_name = grub_partition_get_name (p); + if (! part_name) return 1; - name = grub_xasprintf ("%s,%s", disk_name, partition_name); - grub_free (partition_name); + name = grub_xasprintf ("%s,%s", disk_name, part_name); + grub_free (part_name); if (! name) return 1; diff --git a/grub-core/partmap/bsdlabel.c b/grub-core/partmap/bsdlabel.c index a27b8eaec..eff3bbe44 100644 --- a/grub-core/partmap/bsdlabel.c +++ b/grub-core/partmap/bsdlabel.c @@ -23,18 +23,23 @@ #include #include #include +#include #ifdef GRUB_UTIL #include #endif static struct grub_partition_map grub_bsdlabel_partition_map; +static struct grub_partition_map grub_netbsdlabel_partition_map; +static struct grub_partition_map grub_openbsdlabel_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)) +iterate_real (grub_disk_t disk, grub_disk_addr_t sector, int freebsd, + struct grub_partition_map *pmap, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) { struct grub_partition_bsd_disk_label label; struct grub_partition p; @@ -42,8 +47,7 @@ bsdlabel_partition_map_iterate (grub_disk_t disk, unsigned pos; /* Read the BSD label. */ - if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, - 0, sizeof (label), &label)) + if (grub_disk_read (disk, sector, 0, sizeof (label), &label)) return grub_errno; /* Check if it is valid. */ @@ -52,12 +56,12 @@ bsdlabel_partition_map_iterate (grub_disk_t disk, /* A kludge to determine a base of be.offset. */ if (GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION - < grub_cpu_to_le16 (label.num_partitions)) + < grub_cpu_to_le16 (label.num_partitions) && freebsd) { struct grub_partition_bsd_entry whole_disk_be; - pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR - * GRUB_DISK_SECTOR_SIZE + sizeof (struct grub_partition_bsd_entry) + pos = sizeof (label) + sector * GRUB_DISK_SECTOR_SIZE + + sizeof (struct grub_partition_bsd_entry) * GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION; if (grub_disk_read (disk, pos / GRUB_DISK_SECTOR_SIZE, @@ -68,8 +72,7 @@ bsdlabel_partition_map_iterate (grub_disk_t disk, delta = grub_le_to_cpu32 (whole_disk_be.offset); } - pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR - * GRUB_DISK_SECTOR_SIZE; + pos = sizeof (label) + sector * GRUB_DISK_SECTOR_SIZE; for (p.number = 0; p.number < grub_cpu_to_le16 (label.num_partitions); @@ -88,13 +91,7 @@ bsdlabel_partition_map_iterate (grub_disk_t disk, p.start = grub_le_to_cpu32 (be.offset); p.len = grub_le_to_cpu32 (be.size); - p.partmap = &grub_bsdlabel_partition_map; - - grub_dprintf ("partition", - "partition %d: type 0x%x, start 0x%llx, len 0x%llx\n", - p.number, be.fs_type, - (unsigned long long) p.start, - (unsigned long long) p.len); + p.partmap = pmap; if (p.len == 0) continue; @@ -103,13 +100,6 @@ bsdlabel_partition_map_iterate (grub_disk_t disk, { #ifdef GRUB_UTIL char *partname; -#endif - grub_dprintf ("partition", - "partition %d: invalid start (found 0x%llx, wanted >= 0x%llx)\n", - p.number, - (unsigned long long) p.start, - (unsigned long long) delta); -#ifdef GRUB_UTIL /* disk->partition != NULL as 0 < delta */ partname = grub_partition_get_name (disk->partition); grub_util_warn ("Discarding improperly nested partition (%s,%s,%s%d)", @@ -124,24 +114,138 @@ bsdlabel_partition_map_iterate (grub_disk_t disk, if (hook (disk, &p)) return grub_errno; } - return GRUB_ERR_NONE; } - -/* Partition map type. */ +static grub_err_t +bsdlabel_partition_map_iterate (grub_disk_t disk, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) +{ + + if (disk->partition && grub_strcmp (disk->partition->partmap->name, "msdos") + == 0 && disk->partition->msdostype == GRUB_PC_PARTITION_TYPE_FREEBSD) + return iterate_real (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 1, + &grub_bsdlabel_partition_map, hook); + + if (disk->partition + && (grub_strcmp (disk->partition->partmap->name, "msdos") == 0 + || disk->partition->partmap == &grub_bsdlabel_partition_map + || disk->partition->partmap == &grub_netbsdlabel_partition_map + || disk->partition->partmap == &grub_openbsdlabel_partition_map)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported"); + + return iterate_real (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, + &grub_bsdlabel_partition_map, hook); +} + +/* This is a total breakage. Even when net-/openbsd label is inside partition + it actually describes the whole disk. + */ +static grub_err_t +netopenbsdlabel_partition_map_iterate (grub_disk_t disk, grub_uint8_t type, + struct grub_partition_map *pmap, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) +{ + int count = 0; + + auto int check_msdos (grub_disk_t dsk, + const grub_partition_t partition); + + int check_msdos (grub_disk_t dsk, + const grub_partition_t partition) + { + grub_err_t err; + + if (partition->msdostype != type) + return 0; + + err = iterate_real (dsk, partition->start + + GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, pmap, hook); + if (err == GRUB_ERR_NONE) + { + count++; + return 1; + } + if (err == GRUB_ERR_BAD_PART_TABLE) + { + grub_errno = GRUB_ERR_NONE; + return 0; + } + grub_print_error (); + return 0; + } + + if (disk->partition && grub_strcmp (disk->partition->partmap->name, "msdos") + == 0) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported"); + + { + grub_err_t err; + err = grub_partition_msdos_iterate (disk, check_msdos); + + if (err) + return err; + if (!count) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no bsdlabel found"); + } + return GRUB_ERR_NONE; +} + +static grub_err_t +netbsdlabel_partition_map_iterate (grub_disk_t disk, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) +{ + return netopenbsdlabel_partition_map_iterate (disk, + GRUB_PC_PARTITION_TYPE_NETBSD, + &grub_netbsdlabel_partition_map, + hook); +} + +static grub_err_t +openbsdlabel_partition_map_iterate (grub_disk_t disk, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) +{ + return netopenbsdlabel_partition_map_iterate (disk, + GRUB_PC_PARTITION_TYPE_OPENBSD, + &grub_openbsdlabel_partition_map, + hook); +} + + static struct grub_partition_map grub_bsdlabel_partition_map = { .name = "bsd", .iterate = bsdlabel_partition_map_iterate, }; +static struct grub_partition_map grub_openbsdlabel_partition_map = + { + .name = "openbsd", + .iterate = openbsdlabel_partition_map_iterate, + }; + +static struct grub_partition_map grub_netbsdlabel_partition_map = + { + .name = "netbsd", + .iterate = netbsdlabel_partition_map_iterate, + }; + + + GRUB_MOD_INIT(part_bsd) { grub_partition_map_register (&grub_bsdlabel_partition_map); + grub_partition_map_register (&grub_netbsdlabel_partition_map); + grub_partition_map_register (&grub_openbsdlabel_partition_map); } GRUB_MOD_FINI(part_bsd) { grub_partition_map_unregister (&grub_bsdlabel_partition_map); + grub_partition_map_unregister (&grub_netbsdlabel_partition_map); + grub_partition_map_unregister (&grub_openbsdlabel_partition_map); } diff --git a/grub-core/partmap/msdos.c b/grub-core/partmap/msdos.c index 7dab4aa0f..921e2554e 100644 --- a/grub-core/partmap/msdos.c +++ b/grub-core/partmap/msdos.c @@ -27,16 +27,25 @@ static struct grub_partition_map grub_msdos_partition_map; -static grub_err_t -pc_partition_map_iterate (grub_disk_t disk, - int (*hook) (grub_disk_t disk, - const grub_partition_t partition)) +grub_err_t +grub_partition_msdos_iterate (grub_disk_t disk, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) { struct grub_partition p; struct grub_msdos_partition_mbr mbr; int labeln = 0; grub_disk_addr_t lastaddr; grub_disk_addr_t ext_offset; + grub_disk_addr_t delta = 0; + + if (disk->partition && disk->partition->partmap == &grub_msdos_partition_map) + { + if (disk->partition->msdostype == GRUB_PC_PARTITION_TYPE_LINUX_MINIX) + delta = disk->partition->start; + else + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported"); + } p.offset = 0; ext_offset = 0; @@ -81,8 +90,9 @@ pc_partition_map_iterate (grub_disk_t disk, { e = mbr.entries + p.index; - p.start = p.offset + grub_le_to_cpu32 (e->start); + p.start = p.offset + grub_le_to_cpu32 (e->start) - delta; p.len = grub_le_to_cpu32 (e->length); + p.msdostype = e->type; grub_dprintf ("partition", "partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n", @@ -251,7 +261,7 @@ pc_partition_map_embed (struct grub_disk *disk, unsigned int nsectors, static struct grub_partition_map grub_msdos_partition_map = { .name = "msdos", - .iterate = pc_partition_map_iterate, + .iterate = grub_partition_msdos_iterate, #ifdef GRUB_UTIL .embed = pc_partition_map_embed #endif diff --git a/include/grub/msdos_partition.h b/include/grub/msdos_partition.h index 650d78493..a6e3fda49 100644 --- a/include/grub/msdos_partition.h +++ b/include/grub/msdos_partition.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include /* The signature. */ #define GRUB_PC_PARTITION_SIGNATURE 0xaa55 @@ -114,4 +116,9 @@ grub_msdos_partition_is_extended (int type) || type == GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED); } +grub_err_t +grub_partition_msdos_iterate (grub_disk_t disk, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)); + #endif /* ! GRUB_PC_PARTITION_HEADER */ diff --git a/include/grub/partition.h b/include/grub/partition.h index a29a3440d..7ccb7cffd 100644 --- a/include/grub/partition.h +++ b/include/grub/partition.h @@ -77,6 +77,10 @@ struct grub_partition /* The type partition map. */ grub_partition_map_t partmap; + + /* The type of partition whne it's on MSDOS. + Used for embedding detection. */ + grub_uint8_t msdostype; }; grub_partition_t EXPORT_FUNC(grub_partition_probe) (struct grub_disk *disk, diff --git a/util/grub-install.in b/util/grub-install.in index 955bf0257..ebbd63c42 100644 --- a/util/grub-install.in +++ b/util/grub-install.in @@ -470,7 +470,12 @@ fi # filesystem will be accessible). partmap_module= for x in `$grub_probe --target=partmap --device ${grub_device} 2> /dev/null`; do - partmap_module="$partmap_module part_$x"; + case "$x" in + netbsd | openbsd) + partmap_module="$partmap_module part_bsd";; + *) + partmap_module="$partmap_module part_$x";; + esac done # Device abstraction module, if any (lvm, raid).