OSDN Git Service

gpt: add commands to manipulate pMBR boot flag
authorMatthew Garrett <mjg@redhat.com>
Wed, 1 Feb 2012 14:12:20 +0000 (15:12 +0100)
committerJim Meyering <meyering@redhat.com>
Thu, 2 Feb 2012 15:01:18 +0000 (16:01 +0100)
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.in.h (_PedDiskFlag): Add PED_DISK_GPT_PMBR_BOOT
* libparted/disk.c (ped_disk_flag_get_name): Add PED_DISK_GPT_PMBR_BOOT
* libparted/labels/gpt.c (_GPTDiskData): Add pmbr_boot flag.
(gpt_alloc): Init pmbr_boot to 0.
(gpt_read_headers): Set pmbr_boot state from PMBR boot flag.
(_write_pmbr): Add pmbr_boot flag and set PMBR boot flag from it.
(gpt_write): Pass pmbr_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.in.h
libparted/disk.c
libparted/labels/gpt.c
parted/parted.c
parted/ui.c
parted/ui.h

index 46bde3f..9734edd 100644 (file)
@@ -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_GPT_PMBR_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_GPT_PMBR_BOOT
 
 /**
  * Partition types
index f64f0fc..f9b5fd2 100644 (file)
@@ -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_GPT_PMBR_BOOT:
+                return N_("pmbr_boot");
         default:
                 ped_exception_throw (
                         PED_EXCEPTION_BUG,
index bad9ed4..4a5d357 100644 (file)
@@ -264,6 +264,7 @@ struct __attribute__ ((packed)) _GPTDiskData
   PedGeometry data_area;
   int entry_count;
   efi_guid_t uuid;
+  int pmbr_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->pmbr_boot = 0;
   return disk;
 
 error_free_disk:
@@ -842,6 +844,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->pmbr_boot = 1;
+  free (mbr);
 
   void *s1;
   if (!ptt_read_sector (dev, 1, &s1))
@@ -1079,7 +1090,7 @@ error:
 #ifndef DISCOVER_ONLY
 /* Write the protective MBR (to keep DOS happy) */
 static int
-_write_pmbr (PedDevice *dev)
+_write_pmbr (PedDevice *dev, bool pmbr_boot)
 {
   /* The UEFI spec is not clear about what to do with the following
      elements of the Protective MBR (pmbr): BootCode (0-440B),
@@ -1104,6 +1115,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 (pmbr_boot)
+    pmbr->PartitionRecord[0].BootIndicator = 0x80;
 
   int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
                                    GPT_PMBR_SECTORS);
@@ -1221,7 +1234,7 @@ gpt_write (const PedDisk *disk)
   ptes_crc = efi_crc32 (ptes, ptes_bytes);
 
   /* Write protective MBR */
-  if (!_write_pmbr (disk->dev))
+  if (!_write_pmbr (disk->dev, gpt_disk_data->pmbr_boot))
     goto error_free_ptes;
 
   /* Write PTH and PTEs */
@@ -1509,6 +1522,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_GPT_PMBR_BOOT:
+      gpt_disk_data->pmbr_boot = state;
+      return 1;
+    default:
+      return 0;
+    }
+}
+
+static int
+gpt_disk_is_flag_available(const PedDisk *disk, PedDiskFlag flag)
+{
+  switch (flag)
+    {
+    case PED_DISK_GPT_PMBR_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_GPT_PMBR_BOOT:
+      return gpt_disk_data->pmbr_boot;
+      break;
+    default:
+      return 0;
+    }
+}
+
+static int
 gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
 {
   GPTPartitionData *gpt_part_data;
@@ -1796,6 +1849,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)
 };
index 02c5fdb..eb91835 100644 (file)
@@ -1560,6 +1560,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;
@@ -1600,6 +1637,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;
@@ -1836,6 +1885,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 (
index a0f8820..d00c65a 100644 (file)
@@ -1116,6 +1116,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)
 {
index c39afb9..9c8605a 100644 (file)
@@ -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);