1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-27 01:55:22 +03:00
systemd/tools/list-discoverable-partitions.py
Alyssa Ross f000edf9ea docs: fix descriptions in discoverable partitions
00db9a114e ("docs: generate table from header using a script") got the
descriptions for the partition types mixed up.  After that change, the
spec claimed, for example, that the /usr partition should contain
"dm-verity integrity hash data for the matching root partition", and
that the /usr verity partition should be of type "Any native, optionally
in LUKS".  This made the spec an extremely confusing read before I
figured out what must have happened!

I've gone through the table as it existed prior to 00db9a114e, and moved
the descriptions around in the script that generates the table until
they matched up with what they used to be.  Then I regenerated the
table from the fixed script.
2021-11-27 13:46:35 +00:00

192 lines
8.9 KiB
Python

#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-2.1-or-later
import re
import sys
import uuid
HEADER = f'''\
| Partition Type UUID | Name | Allowed File Systems | Explanation |
|---------------------|------|----------------------|-------------|
'''
ARCHITECTURES = {
'ALPHA': 'Alpha',
'ARC': 'ARC',
'ARM': '32-bit ARM',
'ARM64': '64-bit ARM/AArch64',
'IA64': 'Itanium/IA-64',
'LOONGARCH64': 'LoongArch 64-bit',
'MIPS_LE': '32-bit MIPS LittleEndian (mipsel)',
'MIPS64_LE': '64-bit MIPS LittleEndian (mips64el)',
'PPC': '32-bit PowerPC',
'PPC64': '64-bit PowerPC BigEndian',
'PPC64_LE': '64-bit PowerPC LittleEndian',
'RISCV32': 'RISC-V 32-bit',
'RISCV64': 'RISC-V 64-bit',
'S390': 's390',
'S390X': 's390x',
'TILEGX': 'TILE-Gx',
'X86': 'x86',
'X86_64': 'amd64/x86_64',
}
TYPES = {
'ROOT' : 'Root Partition',
'ROOT_VERITY' : 'Root Verity Partition',
'ROOT_VERITY_SIG' : 'Root Verity Signature Partition',
'USR' : '`/usr/` Partition',
'USR_VERITY' : '`/usr/` Verity Partition',
'USR_VERITY_SIG' : '`/usr/` Verity Signature Partition',
'ESP': 'EFI System Partition',
'SRV': 'Server Data Partition',
'VAR': 'Variable Data Partition',
'TMP': 'Temporary Data Partition',
'SWAP': 'Swap',
'HOME': 'Home Partition',
'USER_HOME': 'Per-user Home Partition',
'LINUX_GENERIC': 'Generic Linux Data Partition',
'XBOOTLDR': 'Extended Boot Loader Partition',
}
DESCRIPTIONS = {
'ROOT': (
'Any native, optionally in LUKS',
'On systems with matching architecture, the first partition with this type UUID on the disk '
'containing the active EFI ESP is automatically mounted to the root directory <tt>/</tt>. '
'If the partition is encrypted with LUKS or has dm-verity integrity data (see below), the '
'device mapper file will be named `/dev/mapper/root`.'),
'USR': (
'Any native, optionally in LUKS',
'Similar semantics to root partition, but just the `/usr/` partition.'),
'ROOT_VERITY': (
'A dm-verity superblock followed by hash data',
'Contains dm-verity integrity hash data for the matching root partition. If this feature is '
'used the partition UUID of the root partition should be the first 128 bits of the root hash '
'of the dm-verity hash data, and the partition UUID of this dm-verity partition should be the '
'final 128 bits of it, so that the root partition and its Verity partition can be discovered '
'easily, simply by specifying the root hash.'),
'USR_VERITY': (
'A dm-verity superblock followed by hash data',
'Similar semantics to root Verity partition, but just for the `/usr/` partition.'),
'ROOT_VERITY_SIG': (
'A serialized JSON object, see below',
'Contains a root hash and a PKCS#7 signature for it, permitting signed dm-verity GPT images.'),
'USR_VERITY_SIG': (
'A serialized JSON object, see below',
'Similar semantics to root Verity signature partition, but just for the `/usr/` partition.'),
'ESP': (
'VFAT',
'The ESP used for the current boot is automatically mounted to `/efi/` (or `/boot/` as '
'fallback), unless a different partition is mounted there (possibly via `/etc/fstab`, or '
'because the Extended Boot Loader Partition — see below — exists) or the directory is '
'non-empty on the root disk. This partition type is defined by the '
'[UEFI Specification](http://www.uefi.org/specifications).'),
'XBOOTLDR': (
'Typically VFAT',
'The Extended Boot Loader Partition (XBOOTLDR) used for the current boot is automatically '
'mounted to <tt>/boot/</tt>, unless a different partition is mounted there (possibly via '
'<tt>/etc/fstab</tt>) or the directory is non-empty on the root disk. This partition type '
'is defined by the [Boot Loader Specification](https://systemd.io/BOOT_LOADER_SPECIFICATION).'),
'SWAP': (
'Swap, optionally in LUKS',
'All swap partitions on the disk containing the root partition are automatically enabled. '
'If the partition is encrypted with LUKS, the device mapper file will be named '
'`/dev/mapper/swap`. This partition type predates the Discoverable Partitions Specification.'),
'HOME': (
'Any native, optionally in LUKS',
'The first partition with this type UUID on the disk containing the root partition is '
'automatically mounted to `/home/`. If the partition is encrypted with LUKS, the device '
'mapper file will be named `/dev/mapper/home`.'),
'SRV': (
'Any native, optionally in LUKS',
'The first partition with this type UUID on the disk containing the root partition is '
'automatically mounted to `/srv/`. If the partition is encrypted with LUKS, the device '
'mapper file will be named `/dev/mapper/srv`.'),
'VAR': (
'Any native, optionally in LUKS',
'The first partition with this type UUID on the disk containing the root partition is '
'automatically mounted to `/var/` — under the condition that its partition UUID matches '
'the first 128 bits of `HMAC-SHA256(machine-id, 0x4d21b016b53445c2a9fb5c16e091fd2d)` '
'(i.e. the SHA256 HMAC hash of the binary type UUID keyed by the machine ID as read from '
'[`/etc/machine-id`](https://www.freedesktop.org/software/systemd/man/machine-id.html). '
'This special requirement is made because `/var/` (unlike the other partition types '
'listed here) is inherently private to a specific installation and cannot possibly be '
'shared between multiple OS installations on the same disk, and thus should be bound to '
'a specific instance of the OS, identified by its machine ID. If the partition is '
'encrypted with LUKS, the device mapper file will be named `/dev/mapper/var`.'),
'TMP': (
'Any native, optionally in LUKS',
'The first partition with this type UUID on the disk containing the root partition is '
'automatically mounted to `/var/tmp/`. If the partition is encrypted with LUKS, the '
'device mapper file will be named `/dev/mapper/tmp`. Note that the intended mount point '
'is indeed `/var/tmp/`, not `/tmp/`. The latter is typically maintained in memory via '
'<tt>tmpfs</tt> and does not require a partition on disk. In some cases it might be '
'desirable to make `/tmp/` persistent too, in which case it is recommended to make it '
'a symlink or bind mount to `/var/tmp/`, thus not requiring its own partition type UUID.'),
'USER_HOME': (
'Any native, optionally in LUKS',
'A home partition of a user, managed by '
'[`systemd-homed`](https://www.freedesktop.org/software/systemd/man/systemd-homed.html).'),
'LINUX_GENERIC': (
'Any native, optionally in LUKS',
'No automatic mounting takes place for other Linux data partitions. This partition type '
'should be used for all partitions that carry Linux file systems. The installer needs '
'to mount them explicitly via entries in <tt>/etc/fstab</tt>. Optionally, these '
'partitions may be encrypted with LUKS. This partition type predates the Discoverable '
'Partitions Specification.'),
}
def extract(file):
for line in file:
# print(line)
m = re.match(r'^#define\s+GPT_(.*SD_ID128_MAKE.*)', line)
if not m:
continue
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)):
type, arch, suffix, u = m2.groups()
u = uuid.UUID(u.replace(',', ''))
assert arch in ARCHITECTURES
type = f'{type}{suffix}'
assert type in TYPES
yield type, arch, u
elif m2 := re.match(r'(\w+)\s+SD_ID128_MAKE\((.*)\)', m.group(1)):
type, u = m2.groups()
u = uuid.UUID(u.replace(',', ''))
yield type, None, u
else:
raise Exception(f'Failed to match: {m.group(1)}')
def generate(defines):
prevtype = None
print(HEADER, end='')
uuids = set()
for type, arch, uuid in defines:
tdesc = TYPES[type]
adesc = '' if arch is None else f' ({ARCHITECTURES[arch]})'
# Let's make sure that we didn't select&paste the same value twice
assert uuid not in uuids
uuids.add(uuid)
if type != prevtype:
prevtype = type
morea, moreb = DESCRIPTIONS[type]
else:
morea = moreb = 'ditto'
print(f'| _{tdesc}{adesc}_ | `{uuid}` | {morea} | {moreb} |')
if __name__ == '__main__':
known = extract(sys.stdin)
generate(known)