[parted-devel] [PATCH 1/4] libparted: Add legacy_boot flag to GPT PMBR (#754850)

bcl at redhat.com bcl at redhat.com
Sat Jan 28 00:59:02 UTC 2012


From: Matthew Garrett <mjg at redhat.com>

Some BIOS systems will only boot from GPT partitions if the boot flag is
set on the protective MBR partition. This adds the ability to set this
flag using the disk_set and disk_toggle commands.

* include/parted/disk.h (_PedDiskFlag): Add PED_DISK_LEGACY_BOOT
* libparted/disk.c (ped_disk_flag_get_name): Add PED_DISK_LEGACY_BOOT
* libparted/labels/gpt.c (_GPTDiskData): Add legacy_boot flag.
(gpt_alloc): Init legacy_boot to 0.
(gpt_read_headers): Set legacy_boot state from PMBR boot flag.
(_write_pmbr): Add legacy_boot flag and set PMBR boot flag from it.
(gpt_write): Pass legacy_boot flag through to _write_pmbr
(gpt_disk_set_flag): New function
(gpt_disk_is_flag_available): New function
(gpt_disk_get_flag): New function
(gpt_disk_ops): Add disk_set_flag, disk_get_flag, disk_is_flag_available
* parted/parted.c (do_disk_set): New function
(do_disk_toggle): New function
(_init_commands): Add do_disk_set and do_disk_toggle
* parted/ui.c (command_line_get_disk_flag): New function
* parted/ui.h: Add command_line_get_disk_flag prototype.
---
 include/parted/disk.h  |    4 ++-
 libparted/disk.c       |    3 +-
 libparted/labels/gpt.c |   60 ++++++++++++++++++++++++++++++++++++++++++-
 parted/parted.c        |   66 ++++++++++++++++++++++++++++++++++++++++++++++++
 parted/ui.c            |   29 +++++++++++++++++++++
 parted/ui.h            |    3 ++
 6 files changed, 161 insertions(+), 4 deletions(-)

diff --git a/include/parted/disk.h b/include/parted/disk.h
index dd461fb..18c2874 100644
--- a/include/parted/disk.h
+++ b/include/parted/disk.h
@@ -36,9 +36,11 @@ enum _PedDiskFlag {
            This flag is available for msdos and sun disklabels (for sun labels
            it only controls the aligning of the end of the partition) */
         PED_DISK_CYLINDER_ALIGNMENT=1,
+        /* This flag controls whether the boot flag of a GPT PMBR is set */
+        PED_DISK_LEGACY_BOOT=2,
 };
 #define PED_DISK_FIRST_FLAG             PED_DISK_CYLINDER_ALIGNMENT
-#define PED_DISK_LAST_FLAG              PED_DISK_CYLINDER_ALIGNMENT
+#define PED_DISK_LAST_FLAG              PED_DISK_LEGACY_BOOT
 
 /**
  * Partition types
diff --git a/libparted/disk.c b/libparted/disk.c
index 1057aa8..b76c9f7 100644
--- a/libparted/disk.c
+++ b/libparted/disk.c
@@ -836,7 +836,8 @@ ped_disk_flag_get_name(PedDiskFlag flag)
         switch (flag) {
         case PED_DISK_CYLINDER_ALIGNMENT:
                 return N_("cylinder_alignment");
-
+        case PED_DISK_LEGACY_BOOT:
+                return N_("legacy_boot");
         default:
                 ped_exception_throw (
                         PED_EXCEPTION_BUG,
diff --git a/libparted/labels/gpt.c b/libparted/labels/gpt.c
index 7b4e014..4125f5c 100644
--- a/libparted/labels/gpt.c
+++ b/libparted/labels/gpt.c
@@ -264,6 +264,7 @@ struct __attribute__ ((packed)) _GPTDiskData
   PedGeometry data_area;
   int entry_count;
   efi_guid_t uuid;
+  int legacy_boot;
 };
 
 /* uses libparted's disk_specific field in PedPartition, to store our info */
@@ -535,6 +536,7 @@ gpt_alloc (const PedDevice *dev)
   gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
   uuid_generate ((unsigned char *) &gpt_disk_data->uuid);
   swap_uuid_and_efi_guid ((unsigned char *) (&gpt_disk_data->uuid));
+  gpt_disk_data->legacy_boot = 0;
   return disk;
 
 error_free_disk:
@@ -848,6 +850,15 @@ gpt_read_headers (PedDisk const *disk,
   *primary_gpt = NULL;
   *backup_gpt = NULL;
   PedDevice const *dev = disk->dev;
+  GPTDiskData *gpt_disk_data = disk->disk_specific;
+  LegacyMBR_t *mbr;
+
+  if (!ptt_read_sector (dev, 0, (void *)&mbr))
+    return 1;
+
+  if (mbr->PartitionRecord[0].BootIndicator == 0x80)
+    gpt_disk_data->legacy_boot = 1;
+  free (mbr);
 
   void *s1;
   if (!ptt_read_sector (dev, 1, &s1))
@@ -1085,7 +1096,7 @@ error:
 #ifndef DISCOVER_ONLY
 /* Write the protective MBR (to keep DOS happy) */
 static int
-_write_pmbr (PedDevice *dev)
+_write_pmbr (PedDevice *dev, int legacy_boot)
 {
   /* The UEFI spec is not clear about what to do with the following
      elements of the Protective MBR (pmbr): BootCode (0-440B),
@@ -1110,6 +1121,8 @@ _write_pmbr (PedDevice *dev)
     pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF);
   else
     pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL);
+  if (legacy_boot)
+    pmbr->PartitionRecord[0].BootIndicator = 0x80;
 
   int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
                                    GPT_PMBR_SECTORS);
@@ -1226,7 +1239,7 @@ gpt_write (const PedDisk *disk)
   ptes_crc = efi_crc32 (ptes, ptes_size);
 
   /* Write protective MBR */
-  if (!_write_pmbr (disk->dev))
+  if (!_write_pmbr (disk->dev, gpt_disk_data->legacy_boot))
     goto error_free_ptes;
 
   /* Write PTH and PTEs */
@@ -1529,6 +1542,46 @@ gpt_partition_enumerate (PedPartition *part)
 }
 
 static int
+gpt_disk_set_flag (PedDisk *disk, PedDiskFlag flag, int state)
+{
+  GPTDiskData *gpt_disk_data = disk->disk_specific;
+  switch (flag)
+    {
+    case PED_DISK_LEGACY_BOOT:
+      gpt_disk_data->legacy_boot = state;
+      return 1;
+    default:
+      return 0;
+    }
+}
+
+static int
+gpt_disk_is_flag_available(const PedDisk *disk, PedDiskFlag flag)
+{
+  switch (flag)
+    {
+    case PED_DISK_LEGACY_BOOT:
+      return 1;
+    default:
+      return 0;
+    }
+}
+
+static int
+gpt_disk_get_flag (const PedDisk *disk, PedDiskFlag flag)
+{
+  GPTDiskData *gpt_disk_data = disk->disk_specific;
+  switch (flag)
+    {
+    case PED_DISK_LEGACY_BOOT:
+      return gpt_disk_data->legacy_boot;
+      break;
+    default:
+      return 0;
+    }
+}
+
+static int
 gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
 {
   GPTPartitionData *gpt_part_data;
@@ -1816,6 +1869,9 @@ static PedDiskOps gpt_disk_ops =
 
   partition_set_name:		gpt_partition_set_name,
   partition_get_name:		gpt_partition_get_name,
+  disk_set_flag:		gpt_disk_set_flag,
+  disk_get_flag:		gpt_disk_get_flag,
+  disk_is_flag_available:	gpt_disk_is_flag_available,
 
   PT_op_function_initializers (gpt)
 };
diff --git a/parted/parted.c b/parted/parted.c
index 32c2fcc..4220265 100644
--- a/parted/parted.c
+++ b/parted/parted.c
@@ -1475,6 +1475,43 @@ error:
 }
 
 static int
+do_disk_set (PedDevice** dev)
+{
+    PedDisk*    disk;
+    PedDiskFlag flag;
+    int         state;
+
+    disk = ped_disk_new (*dev);
+    if (!disk)
+        goto error;
+
+    if (!command_line_get_disk_flag (_("Flag to Invert?"), disk, &flag))
+        goto error_destroy_disk;
+    state = (ped_disk_get_flag (disk, flag) == 0 ? 1 : 0);
+
+    if (!is_toggle_mode) {
+        if (!command_line_get_state (_("New state?"), &state))
+            goto error_destroy_disk;
+    }
+
+    if (!ped_disk_set_flag (disk, flag, state))
+        goto error_destroy_disk;
+    if (!ped_disk_commit (disk))
+        goto error_destroy_disk;
+    ped_disk_destroy (disk);
+
+    if ((*dev)->type != PED_DEVICE_FILE)
+        disk_is_modified = 1;
+
+    return 1;
+
+error_destroy_disk:
+    ped_disk_destroy (disk);
+error:
+    return 0;
+}
+
+static int
 do_set (PedDevice** dev)
 {
         PedDisk*                disk;
@@ -1515,6 +1552,18 @@ error:
 }
 
 static int
+do_disk_toggle (PedDevice **dev)
+{
+    int result;
+
+    is_toggle_mode = 1;
+    result = do_disk_set (dev);
+    is_toggle_mode = 0;
+
+    return result;
+}
+
+static int
 do_toggle (PedDevice **dev)
 {
         int result;
@@ -1751,6 +1800,23 @@ NULL),
         str_list_create (_(device_msg), NULL), 1));
 
 command_register (commands, command_create (
+        str_list_create_unique ("disk_set", _("disk_set"), NULL),
+        do_disk_set,
+        str_list_create (
+_("disk_set FLAG STATE                      change the FLAG on selected device"),
+NULL),
+        str_list_create (flag_msg, _(state_msg), NULL), 1));
+
+command_register (commands, command_create (
+        str_list_create_unique ("disk_toggle", _("disk_toggle"), NULL),
+        do_disk_toggle,
+        str_list_create (
+_("disk_toggle [FLAG]                       toggle the state of FLAG on "
+"selected device"),
+NULL),
+        str_list_create (flag_msg, NULL), 1));
+
+command_register (commands, command_create (
 		str_list_create_unique ("set", _("set"), NULL),
 		do_set,
 		str_list_create (
diff --git a/parted/ui.c b/parted/ui.c
index 6d2fde1..d66029f 100644
--- a/parted/ui.c
+++ b/parted/ui.c
@@ -1113,6 +1113,35 @@ command_line_get_disk_type (const char* prompt, const PedDiskType*(* value))
 }
 
 int
+command_line_get_disk_flag (const char* prompt, const PedDisk* disk,
+                            PedDiskFlag* flag)
+{
+        StrList*            opts = NULL;
+        PedPartitionFlag    walk = 0;
+        char*               flag_name;
+
+        while ( (walk = ped_disk_flag_next (walk)) ) {
+                if (ped_disk_is_flag_available (disk, walk)) {
+                        const char*        walk_name;
+
+                        walk_name = ped_disk_flag_get_name (walk);
+                        opts = str_list_append (opts, walk_name);
+                        opts = str_list_append_unique (opts, _(walk_name));
+                }
+        }
+
+        flag_name = command_line_get_word (prompt, NULL, opts, 1);
+        str_list_destroy (opts);
+
+        if (flag_name) {
+                *flag = ped_disk_flag_get_by_name (flag_name);
+                free (flag_name);
+                return 1;
+        } else
+                return 0;
+}
+
+int
 command_line_get_part_flag (const char* prompt, const PedPartition* part,
                             PedPartitionFlag* flag)
 {
diff --git a/parted/ui.h b/parted/ui.h
index 44b521a..2a27c86 100644
--- a/parted/ui.h
+++ b/parted/ui.h
@@ -63,6 +63,9 @@ extern int command_line_get_fs_type (const char* prompt,
 				     const PedFileSystemType*(* value));
 extern int command_line_get_disk_type (const char* prompt,
 				       const PedDiskType*(* value));
+extern int command_line_get_disk_flag (const char* prompt,
+				       const PedDisk* disk,
+				       PedDiskFlag* flag);
 extern int command_line_get_part_flag (const char* prompt,
 				       const PedPartition* part,
 				       PedPartitionFlag* flag);
-- 
1.7.6.5




More information about the parted-devel mailing list