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