[parted-devel] [PATCH] support read-only and no-auto flags used by systemd-gpt-auto-generator

Arvin Schnell aschnell at suse.com
Fri Oct 2 13:32:35 BST 2020


On Wed, Sep 30, 2020 at 10:58:49AM -0700, Brian C. Lane wrote:

> If you read Table 24 of the UEFI spec[1] you will see that it says that
> attributes are controlled by the owner of the PartitionTypeGUID.
> 
> This means that you can't just arbitrarily carve out some bits and use
> them for new flags. They need to be tied to specific GUIDs and not
> effect other users of the GuidSpecific value.
> 
> So if you:
> 
>  * restore the GuidSpecific struct entry to its previous state

The new patch has generic names for the bits in the struct.

>  * tie read_only and no_auto to the systemd GUID(s)

And it is only possible to set the flags for swap. A new function
supports_read_only_and_no_auto_flag is used to control that.

Setting another partition type, e.g. RAID, clears the two
flags. Unsetting swap also does do.

Kind Regards,
  Arvin

---
 doc/C/parted.8                   |   3 +-
 doc/parted.texi                  |   8 ++
 include/parted/disk.in.h         |   6 +-
 libparted/disk.c                 |   7 ++
 libparted/labels/gpt.c           | 135 ++++++++++++++++++++++++++-----
 tests/Makefile.am                |   1 +
 tests/t3320-read_only-no_auto.sh |  47 +++++++++++
 7 files changed, 185 insertions(+), 22 deletions(-)
 create mode 100755 tests/t3320-read_only-no_auto.sh

diff --git a/doc/C/parted.8 b/doc/C/parted.8
index 297c39a..c3d634f 100644
--- a/doc/C/parted.8
+++ b/doc/C/parted.8
@@ -112,7 +112,8 @@ or an LVM logical volume if necessary.
 .B set \fIpartition\fP \fIflag\fP \fIstate\fP
 Change the state of the \fIflag\fP on \fIpartition\fP to \fIstate\fP.
 Supported flags are: "boot", "root", "swap", "hidden", "raid", "lvm", "lba",
-"legacy_boot", "irst", "msftres", "esp", "chromeos_kernel", "bls_boot" and "palo".
+"legacy_boot", "irst", "msftres", "esp", "chromeos_kernel", "bls_boot", "palo",
+"read_only" and "no_auto".
 \fIstate\fP should be either "on" or "off".
 .TP
 .B unit \fIunit\fP
diff --git a/doc/parted.texi b/doc/parted.texi
index 213fc84..f4761a3 100644
--- a/doc/parted.texi
+++ b/doc/parted.texi
@@ -918,6 +918,14 @@ as a PReP boot partition on PowerPC PReP or IBM RS6K/CHRP hardware.
 (MS-DOS) - Enable this to indicate that a partition can be used
 as a diagnostics / recovery partition.
 
+ at item read_only
+(GPT) - this flags tells systemd-gpt-auto-generator to mount the
+partition read-only. Only supported for swap.
+
+ at item no_auto
+(GPT) - this flags tells systemd-gpt-auto-generator to not automatically
+mount the partition. Only supported for swap.
+
 @end table
 
 The print command displays all enabled flags for each partition.
diff --git a/include/parted/disk.in.h b/include/parted/disk.in.h
index fadb995..4aa8af6 100644
--- a/include/parted/disk.in.h
+++ b/include/parted/disk.in.h
@@ -77,10 +77,12 @@ enum _PedPartitionFlag {
         PED_PARTITION_IRST=17,
         PED_PARTITION_ESP=18,
         PED_PARTITION_CHROMEOS_KERNEL=19,
-        PED_PARTITION_BLS_BOOT=20
+        PED_PARTITION_BLS_BOOT=20,
+        PED_PARTITION_READ_ONLY=21,
+        PED_PARTITION_NO_AUTO=22
 };
 #define PED_PARTITION_FIRST_FLAG        PED_PARTITION_BOOT
-#define PED_PARTITION_LAST_FLAG         PED_PARTITION_BLS_BOOT
+#define PED_PARTITION_LAST_FLAG         PED_PARTITION_NO_AUTO
 
 enum _PedDiskTypeFeature {
         PED_DISK_TYPE_EXTENDED=1,       /**< supports extended partitions */
diff --git a/libparted/disk.c b/libparted/disk.c
index 099837b..3521d88 100644
--- a/libparted/disk.c
+++ b/libparted/disk.c
@@ -1351,6 +1351,9 @@ ped_partition_is_active (const PedPartition* part)
  * refers to the partition that will be booted from on startup. On PC98
  * disk labels, the user can choose from any bootable partition on startup.
  *
+ * Flags can also be partition type specific. That is the case for read_only
+ * and no_auto.
+ *
  * \note It is an error to call this on an unavailable flag -- use
  * ped_partition_is_flag_available() to determine which flags are available
  * for a given disk label.
@@ -2411,6 +2414,10 @@ ped_partition_flag_get_name (PedPartitionFlag flag)
                 return N_("chromeos_kernel");
 	case PED_PARTITION_BLS_BOOT:
 		return N_("bls_boot");
+	case PED_PARTITION_READ_ONLY:
+		return N_("read_only");
+	case PED_PARTITION_NO_AUTO:
+		return N_("no_auto");
 
 	default:
 		ped_exception_throw (
diff --git a/libparted/labels/gpt.c b/libparted/labels/gpt.c
index 93f7add..9bde23a 100644
--- a/libparted/labels/gpt.c
+++ b/libparted/labels/gpt.c
@@ -190,16 +190,26 @@ struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t
   uint64_t RequiredToFunction:1;
   uint64_t NoBlockIOProtocol:1;
   uint64_t LegacyBIOSBootable:1;
-  uint64_t Reserved:45;
-  uint64_t GuidSpecific:16;
+  uint64_t Reserved1:45;
+  /* The meaning of the upper 16 bits depends on the partition type and thus
+     have only generic names. */
+  uint64_t GuidSpecific1:12;
+  uint64_t SBit13:1;
+  uint64_t GuidSpecific2:2;
+  uint64_t SBit16:1;
 #else
 #       warning "Using crippled partition entry type"
   uint32_t RequiredToFunction:1;
   uint32_t NoBlockIOProtocol:1;
   uint32_t LegacyBIOSBootable:1;
-  uint32_t Reserved:30;
-  uint32_t LOST:5;
-  uint32_t GuidSpecific:16;
+  uint32_t Reserved1:29;
+  uint32_t Reserved2:16;
+  /* The meaning of the upper 16 bits depends on the partition type and thus
+     have only generic names. */
+  uint64_t GuidSpecific1:12;
+  uint64_t SBit13:1;
+  uint64_t GuidSpecific2:2;
+  uint64_t SBit16:1;
 #endif
 };
 
@@ -313,6 +323,8 @@ typedef struct _GPTPartitionData
   int irst;
   int chromeos_kernel;
   int bls_boot;
+  int read_only;        /* only for swap */
+  int no_auto;          /* only for swap */
 } GPTPartitionData;
 
 static PedDiskType gpt_disk_type;
@@ -399,6 +411,20 @@ pth_get_raw (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
   return pth_raw;
 }
 
+
+/**
+ * Return whether the read_only and no_auto flags are supported depending
+ * on the partition.
+ */
+static int _GL_ATTRIBUTE_PURE
+supports_read_only_and_no_auto_flag (const GPTPartitionData *gpt_part_data)
+{
+  PED_ASSERT (gpt_part_data != NULL);
+
+  return gpt_part_data->swap == 1;
+}
+
+
 /**
  * swap_uuid_and_efi_guid() - converts between uuid formats
  * @uuid - uuid_t in either format (converts it to the other)
@@ -838,6 +864,8 @@ _parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
     = gpt_part_data->irst
     = gpt_part_data->chromeos_kernel
     = gpt_part_data->bls_boot
+    = gpt_part_data->read_only
+    = gpt_part_data->no_auto
     = gpt_part_data->bios_grub = gpt_part_data->atvrecv = 0;
 
   if (pte->Attributes.RequiredToFunction & 0x1)
@@ -874,6 +902,14 @@ _parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
   else if (!guid_cmp (gpt_part_data->type, PARTITION_BLS_BOOT_GUID))
     gpt_part_data->bls_boot = 1;
 
+  if (supports_read_only_and_no_auto_flag(gpt_part_data))
+  {
+    if (pte->Attributes.SBit13 & 0x1)
+      gpt_part_data->read_only = 1;
+    if (pte->Attributes.SBit16 & 0x1)
+      gpt_part_data->no_auto = 1;
+  }
+
   return part;
 }
 
@@ -1248,6 +1284,14 @@ _partition_generate_part_entry (PedPartition *part, GuidPartitionEntry_t *pte)
   if (gpt_part_data->legacy_boot)
     pte->Attributes.LegacyBIOSBootable = 1;
 
+  if (supports_read_only_and_no_auto_flag(gpt_part_data))
+  {
+    if (gpt_part_data->read_only)
+      pte->Attributes.SBit13 = 1;
+    if (gpt_part_data->no_auto)
+      pte->Attributes.SBit16 = 1;
+  }
+
   for (i = 0; i < 36; i++)
     pte->PartitionName[i] = gpt_part_data->name[i];
 }
@@ -1395,6 +1439,8 @@ gpt_partition_new (const PedDisk *disk,
   gpt_part_data->irst = 0;
   gpt_part_data->chromeos_kernel = 0;
   gpt_part_data->bls_boot = 0;
+  gpt_part_data->read_only = 0;
+  gpt_part_data->no_auto = 0;
   uuid_generate ((unsigned char *) &gpt_part_data->uuid);
   swap_uuid_and_efi_guid (&gpt_part_data->uuid);
   memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
@@ -1683,7 +1729,9 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
           = gpt_part_data->irst
           = gpt_part_data->chromeos_kernel
           = gpt_part_data->bls_boot
-          = gpt_part_data->atvrecv = 0;
+          = gpt_part_data->atvrecv
+	  = gpt_part_data->read_only
+	  = gpt_part_data->no_auto = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_BIOS_GRUB:
       gpt_part_data->bios_grub = state;
@@ -1700,7 +1748,9 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
           = gpt_part_data->irst
           = gpt_part_data->chromeos_kernel
           = gpt_part_data->bls_boot
-          = gpt_part_data->atvrecv = 0;
+          = gpt_part_data->atvrecv
+	  = gpt_part_data->read_only
+	  = gpt_part_data->no_auto = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_RAID:
       gpt_part_data->raid = state;
@@ -1717,7 +1767,9 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
           = gpt_part_data->irst
           = gpt_part_data->chromeos_kernel
           = gpt_part_data->bls_boot
-          = gpt_part_data->atvrecv = 0;
+          = gpt_part_data->atvrecv
+	  = gpt_part_data->read_only
+	  = gpt_part_data->no_auto = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_LVM:
       gpt_part_data->lvm = state;
@@ -1734,7 +1786,9 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
           = gpt_part_data->irst
           = gpt_part_data->chromeos_kernel
           = gpt_part_data->bls_boot
-          = gpt_part_data->atvrecv = 0;
+          = gpt_part_data->atvrecv
+	  = gpt_part_data->read_only
+	  = gpt_part_data->no_auto = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_SWAP:
       gpt_part_data->swap = state;
@@ -1752,6 +1806,9 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
           = gpt_part_data->chromeos_kernel
           = gpt_part_data->bls_boot
           = gpt_part_data->atvrecv = 0;
+      else
+	gpt_part_data->read_only
+	  = gpt_part_data->no_auto = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_HPSERVICE:
       gpt_part_data->hp_service = state;
@@ -1768,7 +1825,9 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
           = gpt_part_data->irst
           = gpt_part_data->chromeos_kernel
           = gpt_part_data->bls_boot
-          = gpt_part_data->atvrecv = 0;
+          = gpt_part_data->atvrecv
+	  = gpt_part_data->read_only
+	  = gpt_part_data->no_auto = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_MSFT_RESERVED:
       gpt_part_data->msftres = state;
@@ -1785,7 +1844,9 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
           = gpt_part_data->irst
           = gpt_part_data->chromeos_kernel
           = gpt_part_data->bls_boot
-          = gpt_part_data->atvrecv = 0;
+          = gpt_part_data->atvrecv
+	  = gpt_part_data->read_only
+	  = gpt_part_data->no_auto = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_MSFT_DATA:
       gpt_part_data->msftres = state;
@@ -1802,7 +1863,9 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
           = gpt_part_data->irst
           = gpt_part_data->chromeos_kernel
           = gpt_part_data->bls_boot
-          = gpt_part_data->atvrecv = 0;
+          = gpt_part_data->atvrecv
+	  = gpt_part_data->read_only
+	  = gpt_part_data->no_auto = 0;
         gpt_part_data->msftdata = 1;
       } else {
         gpt_part_data->msftdata = 0;
@@ -1822,7 +1885,9 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
           = gpt_part_data->prep
           = gpt_part_data->irst
           = gpt_part_data->chromeos_kernel
-          = gpt_part_data->atvrecv = 0;
+          = gpt_part_data->atvrecv
+	  = gpt_part_data->read_only
+	  = gpt_part_data->no_auto = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_APPLE_TV_RECOVERY:
       gpt_part_data->atvrecv = state;
@@ -1837,7 +1902,9 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
           = gpt_part_data->msftdata
           = gpt_part_data->prep
           = gpt_part_data->chromeos_kernel
-          = gpt_part_data->msftrecv = 0;
+          = gpt_part_data->msftrecv
+	  = gpt_part_data->read_only
+	  = gpt_part_data->no_auto = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_PREP:
       gpt_part_data->prep = state;
@@ -1853,7 +1920,9 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
           = gpt_part_data->atvrecv
           = gpt_part_data->chromeos_kernel
           = gpt_part_data->bls_boot
-          = gpt_part_data->msftrecv = 0;
+          = gpt_part_data->msftrecv
+	  = gpt_part_data->read_only
+	  = gpt_part_data->no_auto = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_IRST:
       gpt_part_data->irst = state;
@@ -1870,7 +1939,9 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
           = gpt_part_data->prep
           = gpt_part_data->chromeos_kernel
           = gpt_part_data->bls_boot
-          = gpt_part_data->atvrecv = 0;
+          = gpt_part_data->atvrecv
+	  = gpt_part_data->read_only
+	  = gpt_part_data->no_auto = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_CHROMEOS_KERNEL:
       gpt_part_data->chromeos_kernel = state;
@@ -1887,7 +1958,9 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
           = gpt_part_data->atvrecv
           = gpt_part_data->prep
           = gpt_part_data->irst
-          = gpt_part_data->bls_boot = 0;
+          = gpt_part_data->bls_boot
+	  = gpt_part_data->read_only
+	  = gpt_part_data->no_auto = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_BLS_BOOT:
       gpt_part_data->bls_boot = state;
@@ -1904,7 +1977,9 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
           = gpt_part_data->prep
           = gpt_part_data->irst
           = gpt_part_data->chromeos_kernel
-          = gpt_part_data->atvrecv = 0;
+          = gpt_part_data->atvrecv
+	  = gpt_part_data->read_only
+	  = gpt_part_data->no_auto = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_HIDDEN:
       gpt_part_data->hidden = state;
@@ -1912,6 +1987,16 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
     case PED_PARTITION_LEGACY_BOOT:
       gpt_part_data->legacy_boot = state;
       return 1;
+    case PED_PARTITION_READ_ONLY:
+      if (!supports_read_only_and_no_auto_flag(gpt_part_data))
+	return 0;
+      gpt_part_data->read_only = state;
+      return 1;
+    case PED_PARTITION_NO_AUTO:
+      if (!supports_read_only_and_no_auto_flag(gpt_part_data))
+	return 0;
+      gpt_part_data->no_auto = state;
+      return 1;
     case PED_PARTITION_ROOT:
     case PED_PARTITION_LBA:
     default:
@@ -1958,6 +2043,10 @@ gpt_partition_get_flag (const PedPartition *part, PedPartitionFlag flag)
       return gpt_part_data->irst;
     case PED_PARTITION_BLS_BOOT:
       return gpt_part_data->bls_boot;
+    case PED_PARTITION_READ_ONLY:
+      return gpt_part_data->read_only;
+    case PED_PARTITION_NO_AUTO:
+      return gpt_part_data->no_auto;
     case PED_PARTITION_SWAP:
 	return gpt_part_data->swap;
     case PED_PARTITION_CHROMEOS_KERNEL:
@@ -1970,10 +2059,15 @@ gpt_partition_get_flag (const PedPartition *part, PedPartitionFlag flag)
   return 0;
 }
 
-static int
+static int _GL_ATTRIBUTE_PURE
 gpt_partition_is_flag_available (const PedPartition *part,
                                  PedPartitionFlag flag)
 {
+  PED_ASSERT (part != NULL);
+  PED_ASSERT (part->disk_specific != NULL);
+
+  const GPTPartitionData *gpt_part_data = part->disk_specific;
+
   switch (flag)
     {
     case PED_PARTITION_RAID:
@@ -1994,6 +2088,9 @@ gpt_partition_is_flag_available (const PedPartition *part,
     case PED_PARTITION_CHROMEOS_KERNEL:
     case PED_PARTITION_BLS_BOOT:
       return 1;
+    case PED_PARTITION_READ_ONLY:
+    case PED_PARTITION_NO_AUTO:
+      return supports_read_only_and_no_auto_flag(gpt_part_data);
     case PED_PARTITION_ROOT:
     case PED_PARTITION_LBA:
     default:
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0d7c022..ce16448 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -58,6 +58,7 @@ TESTS = \
   t3200-type-change.sh \
   t3300-palo-prep.sh \
   t3310-flags.sh \
+  t3320-read_only-no_auto.sh \
   t3400-whole-disk-FAT-partition.sh \
   t4000-sun-raid-type.sh \
   t4001-sun-vtoc.sh \
diff --git a/tests/t3320-read_only-no_auto.sh b/tests/t3320-read_only-no_auto.sh
new file mode 100755
index 0000000..1e1a6e6
--- /dev/null
+++ b/tests/t3320-read_only-no_auto.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# Ensure that read_only and no_auto flags work properly.
+
+# Copyright (C) 2020 Free Software Foundation, Inc.
+
+# This program 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.
+
+# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/init.sh"; path_prepend_ ../parted
+ss=$sector_size_
+
+cat > exp <<EOF || framework_failure
+1:2048s:4095s:2048s:linux-swap(v1):test:swap, read_only;
+1:2048s:4095s:2048s:linux-swap(v1):test:swap, read_only, no_auto;
+1:2048s:4095s:2048s:linux-swap(v1):test:swap, no_auto;
+1:2048s:4095s:2048s:linux-swap(v1):test:swap;
+EOF
+
+dev=dev-file
+
+n_sectors=5000
+dd if=/dev/null of=$dev bs=$ss seek=$n_sectors || fail=1
+
+parted -m -s $dev mklabel gpt \
+  mkpart test linux-swap $((1*2048))s $((2*2048-1))s unit s \
+  set 1 swap on \
+  set 1 read_only on print \
+  set 1 no_auto on print \
+  set 1 read_only off print \
+  set 1 no_auto off print \
+    > out 2> err || fail=1
+
+grep -E '^1:2048s:4095s:2048s:linux-swap\(v1\):test:.*;$' out > k; mv k out
+
+compare exp out || fail=1
+
+Exit $fail
-- 
Arvin Schnell, <aschnell at suse.com>
Senior Software Engineer, Research & Development

SUSE Software Solutions Germany GmbH
Maxfeldstraße 5
90409 Nürnberg
Germany

(HRB 36809, AG Nürnberg)

Geschäftsführer: Felix Imendörffer



More information about the parted-devel mailing list