1#!/usr/bin/env python3 2# SPDX-License-Identifier: LGPL-2.1-or-later 3 4import re 5import sys 6import uuid 7 8HEADER = f'''\ 9| Name | Partition Type UUID | Allowed File Systems | Explanation | 10|------|---------------------|----------------------|-------------| 11''' 12 13ARCHITECTURES = { 14 'ALPHA': 'Alpha', 15 'ARC': 'ARC', 16 'ARM': '32-bit ARM', 17 'ARM64': '64-bit ARM/AArch64', 18 'IA64': 'Itanium/IA-64', 19 'LOONGARCH64': 'LoongArch 64-bit', 20 'MIPS_LE': '32-bit MIPS LittleEndian (mipsel)', 21 'MIPS64_LE': '64-bit MIPS LittleEndian (mips64el)', 22 'PPC': '32-bit PowerPC', 23 'PPC64': '64-bit PowerPC BigEndian', 24 'PPC64_LE': '64-bit PowerPC LittleEndian', 25 'RISCV32': 'RISC-V 32-bit', 26 'RISCV64': 'RISC-V 64-bit', 27 'S390': 's390', 28 'S390X': 's390x', 29 'TILEGX': 'TILE-Gx', 30 'X86': 'x86', 31 'X86_64': 'amd64/x86_64', 32} 33 34TYPES = { 35 'ROOT' : 'Root Partition', 36 'ROOT_VERITY' : 'Root Verity Partition', 37 'ROOT_VERITY_SIG' : 'Root Verity Signature Partition', 38 'USR' : '`/usr/` Partition', 39 'USR_VERITY' : '`/usr/` Verity Partition', 40 'USR_VERITY_SIG' : '`/usr/` Verity Signature Partition', 41 42 'ESP': 'EFI System Partition', 43 'SRV': 'Server Data Partition', 44 'VAR': 'Variable Data Partition', 45 'TMP': 'Temporary Data Partition', 46 'SWAP': 'Swap', 47 'HOME': 'Home Partition', 48 'USER_HOME': 'Per-user Home Partition', 49 'LINUX_GENERIC': 'Generic Linux Data Partition', 50 'XBOOTLDR': 'Extended Boot Loader Partition', 51} 52 53DESCRIPTIONS = { 54 'ROOT': ( 55 'Any native, optionally in LUKS', 56 'On systems with matching architecture, the first partition with this type UUID on the disk ' 57 'containing the active EFI ESP is automatically mounted to the root directory <tt>/</tt>. ' 58 'If the partition is encrypted with LUKS or has dm-verity integrity data (see below), the ' 59 'device mapper file will be named `/dev/mapper/root`.'), 60 'USR': ( 61 'Any native, optionally in LUKS', 62 'Similar semantics to root partition, but just the `/usr/` partition.'), 63 'ROOT_VERITY': ( 64 'A dm-verity superblock followed by hash data', 65 'Contains dm-verity integrity hash data for the matching root partition. If this feature is ' 66 'used the partition UUID of the root partition should be the first 128 bits of the root hash ' 67 'of the dm-verity hash data, and the partition UUID of this dm-verity partition should be the ' 68 'final 128 bits of it, so that the root partition and its Verity partition can be discovered ' 69 'easily, simply by specifying the root hash.'), 70 'USR_VERITY': ( 71 'A dm-verity superblock followed by hash data', 72 'Similar semantics to root Verity partition, but just for the `/usr/` partition.'), 73 'ROOT_VERITY_SIG': ( 74 'A serialized JSON object, see below', 75 'Contains a root hash and a PKCS#7 signature for it, permitting signed dm-verity GPT images.'), 76 'USR_VERITY_SIG': ( 77 'A serialized JSON object, see below', 78 'Similar semantics to root Verity signature partition, but just for the `/usr/` partition.'), 79 80 'ESP': ( 81 'VFAT', 82 'The ESP used for the current boot is automatically mounted to `/efi/` (or `/boot/` as ' 83 'fallback), unless a different partition is mounted there (possibly via `/etc/fstab`, or ' 84 'because the Extended Boot Loader Partition — see below — exists) or the directory is ' 85 'non-empty on the root disk. This partition type is defined by the ' 86 '[UEFI Specification](http://www.uefi.org/specifications).'), 87 'XBOOTLDR': ( 88 'Typically VFAT', 89 'The Extended Boot Loader Partition (XBOOTLDR) used for the current boot is automatically ' 90 'mounted to <tt>/boot/</tt>, unless a different partition is mounted there (possibly via ' 91 '<tt>/etc/fstab</tt>) or the directory is non-empty on the root disk. This partition type ' 92 'is defined by the [Boot Loader Specification](https://systemd.io/BOOT_LOADER_SPECIFICATION).'), 93 'SWAP': ( 94 'Swap, optionally in LUKS', 95 'All swap partitions on the disk containing the root partition are automatically enabled. ' 96 'If the partition is encrypted with LUKS, the device mapper file will be named ' 97 '`/dev/mapper/swap`. This partition type predates the Discoverable Partitions Specification.'), 98 'HOME': ( 99 'Any native, optionally in LUKS', 100 'The first partition with this type UUID on the disk containing the root partition is ' 101 'automatically mounted to `/home/`. If the partition is encrypted with LUKS, the device ' 102 'mapper file will be named `/dev/mapper/home`.'), 103 'SRV': ( 104 'Any native, optionally in LUKS', 105 'The first partition with this type UUID on the disk containing the root partition is ' 106 'automatically mounted to `/srv/`. If the partition is encrypted with LUKS, the device ' 107 'mapper file will be named `/dev/mapper/srv`.'), 108 'VAR': ( 109 'Any native, optionally in LUKS', 110 'The first partition with this type UUID on the disk containing the root partition is ' 111 'automatically mounted to `/var/` — under the condition that its partition UUID matches ' 112 'the first 128 bits of `HMAC-SHA256(machine-id, 0x4d21b016b53445c2a9fb5c16e091fd2d)` ' 113 '(i.e. the SHA256 HMAC hash of the binary type UUID keyed by the machine ID as read from ' 114 '[`/etc/machine-id`](https://www.freedesktop.org/software/systemd/man/machine-id.html). ' 115 'This special requirement is made because `/var/` (unlike the other partition types ' 116 'listed here) is inherently private to a specific installation and cannot possibly be ' 117 'shared between multiple OS installations on the same disk, and thus should be bound to ' 118 'a specific instance of the OS, identified by its machine ID. If the partition is ' 119 'encrypted with LUKS, the device mapper file will be named `/dev/mapper/var`.'), 120 'TMP': ( 121 'Any native, optionally in LUKS', 122 'The first partition with this type UUID on the disk containing the root partition is ' 123 'automatically mounted to `/var/tmp/`. If the partition is encrypted with LUKS, the ' 124 'device mapper file will be named `/dev/mapper/tmp`. Note that the intended mount point ' 125 'is indeed `/var/tmp/`, not `/tmp/`. The latter is typically maintained in memory via ' 126 '<tt>tmpfs</tt> and does not require a partition on disk. In some cases it might be ' 127 'desirable to make `/tmp/` persistent too, in which case it is recommended to make it ' 128 'a symlink or bind mount to `/var/tmp/`, thus not requiring its own partition type UUID.'), 129 'USER_HOME': ( 130 'Any native, optionally in LUKS', 131 'A home partition of a user, managed by ' 132 '[`systemd-homed`](https://www.freedesktop.org/software/systemd/man/systemd-homed.html).'), 133 'LINUX_GENERIC': ( 134 'Any native, optionally in LUKS', 135 'No automatic mounting takes place for other Linux data partitions. This partition type ' 136 'should be used for all partitions that carry Linux file systems. The installer needs ' 137 'to mount them explicitly via entries in <tt>/etc/fstab</tt>. Optionally, these ' 138 'partitions may be encrypted with LUKS. This partition type predates the Discoverable ' 139 'Partitions Specification.'), 140} 141 142def extract(file): 143 for line in file: 144 # print(line) 145 m = re.match(r'^#define\s+GPT_(.*SD_ID128_MAKE\(.*\))', line) 146 if not m: 147 continue 148 149 if m2 := re.match(r'^(ROOT|USR)_([A-Z0-9]+|X86_64|PPC64_LE|MIPS_LE|MIPS64_LE)(|_VERITY|_VERITY_SIG)\s+SD_ID128_MAKE\((.*)\)', m.group(1)): 150 type, arch, suffix, u = m2.groups() 151 u = uuid.UUID(u.replace(',', '')) 152 assert arch in ARCHITECTURES 153 type = f'{type}{suffix}' 154 assert type in TYPES 155 156 yield type, arch, u 157 158 elif m2 := re.match(r'(\w+)\s+SD_ID128_MAKE\((.*)\)', m.group(1)): 159 type, u = m2.groups() 160 u = uuid.UUID(u.replace(',', '')) 161 yield type, None, u 162 163 else: 164 raise Exception(f'Failed to match: {m.group(1)}') 165 166def generate(defines): 167 prevtype = None 168 169 print(HEADER, end='') 170 171 uuids = set() 172 173 for type, arch, uuid in defines: 174 tdesc = TYPES[type] 175 adesc = '' if arch is None else f' ({ARCHITECTURES[arch]})' 176 177 # Let's make sure that we didn't select&paste the same value twice 178 assert uuid not in uuids 179 uuids.add(uuid) 180 181 if type != prevtype: 182 prevtype = type 183 morea, moreb = DESCRIPTIONS[type] 184 else: 185 morea = moreb = 'ditto' 186 187 print(f'| _{tdesc}{adesc}_ | `{uuid}` | {morea} | {moreb} |') 188 189if __name__ == '__main__': 190 known = extract(sys.stdin) 191 generate(known) 192