blob: 3e1a385124dd5de1796bd533e23e187cd79bc738 [file] [log] [blame]
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "gpt.h"
#include "string-table.h"
#include "string-util.h"
#include "utf8.h"
/* Gently push people towards defining GPT type UUIDs for all architectures we know */
#if !defined(SD_GPT_ROOT_NATIVE) || \
!defined(SD_GPT_ROOT_NATIVE_VERITY) || \
!defined(SD_GPT_ROOT_NATIVE_VERITY_SIG) || \
!defined(SD_GPT_USR_NATIVE) || \
!defined(SD_GPT_USR_NATIVE_VERITY) || \
!defined(SD_GPT_USR_NATIVE_VERITY_SIG)
#pragma message "Please define GPT partition types for your architecture."
#endif
bool partition_designator_is_versioned(PartitionDesignator d) {
/* Returns true for all designators where we want to support a concept of "versioning", i.e. which
* likely contain software binaries (or hashes thereof) that make sense to be versioned as a
* whole. We use this check to automatically pick the newest version of these partitions, by version
* comparing the partition labels. */
return IN_SET(d,
PARTITION_ROOT,
PARTITION_USR,
PARTITION_ROOT_VERITY,
PARTITION_USR_VERITY,
PARTITION_ROOT_VERITY_SIG,
PARTITION_USR_VERITY_SIG);
}
PartitionDesignator partition_verity_of(PartitionDesignator p) {
switch (p) {
case PARTITION_ROOT:
return PARTITION_ROOT_VERITY;
case PARTITION_USR:
return PARTITION_USR_VERITY;
default:
return _PARTITION_DESIGNATOR_INVALID;
}
}
PartitionDesignator partition_verity_sig_of(PartitionDesignator p) {
switch (p) {
case PARTITION_ROOT:
return PARTITION_ROOT_VERITY_SIG;
case PARTITION_USR:
return PARTITION_USR_VERITY_SIG;
default:
return _PARTITION_DESIGNATOR_INVALID;
}
}
PartitionDesignator partition_verity_to_data(PartitionDesignator d) {
switch (d) {
case PARTITION_ROOT_VERITY:
return PARTITION_ROOT;
case PARTITION_USR_VERITY:
return PARTITION_USR;
default:
return _PARTITION_DESIGNATOR_INVALID;
}
}
PartitionDesignator partition_verity_sig_to_data(PartitionDesignator d) {
switch (d) {
case PARTITION_ROOT_VERITY_SIG:
return PARTITION_ROOT;
case PARTITION_USR_VERITY_SIG:
return PARTITION_USR;
default:
return _PARTITION_DESIGNATOR_INVALID;
}
}
static const char *const partition_designator_table[_PARTITION_DESIGNATOR_MAX] = {
[PARTITION_ROOT] = "root",
[PARTITION_USR] = "usr",
[PARTITION_HOME] = "home",
[PARTITION_SRV] = "srv",
[PARTITION_ESP] = "esp",
[PARTITION_XBOOTLDR] = "xbootldr",
[PARTITION_SWAP] = "swap",
[PARTITION_ROOT_VERITY] = "root-verity",
[PARTITION_USR_VERITY] = "usr-verity",
[PARTITION_ROOT_VERITY_SIG] = "root-verity-sig",
[PARTITION_USR_VERITY_SIG] = "usr-verity-sig",
[PARTITION_TMP] = "tmp",
[PARTITION_VAR] = "var",
};
DEFINE_STRING_TABLE_LOOKUP(partition_designator, PartitionDesignator);
static const char *const partition_mountpoint_table[_PARTITION_DESIGNATOR_MAX] = {
[PARTITION_ROOT] = "/\0",
[PARTITION_USR] = "/usr\0",
[PARTITION_HOME] = "/home\0",
[PARTITION_SRV] = "/srv\0",
[PARTITION_ESP] = "/efi\0/boot\0",
[PARTITION_XBOOTLDR] = "/boot\0",
[PARTITION_TMP] = "/var/tmp\0",
[PARTITION_VAR] = "/var\0",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(partition_mountpoint, PartitionDesignator);
#define _GPT_ARCH_SEXTET(arch, name) \
{ SD_GPT_ROOT_##arch, "root-" name, ARCHITECTURE_##arch, .designator = PARTITION_ROOT }, \
{ SD_GPT_ROOT_##arch##_VERITY, "root-" name "-verity", ARCHITECTURE_##arch, .designator = PARTITION_ROOT_VERITY }, \
{ SD_GPT_ROOT_##arch##_VERITY_SIG, "root-" name "-verity-sig", ARCHITECTURE_##arch, .designator = PARTITION_ROOT_VERITY_SIG }, \
{ SD_GPT_USR_##arch, "usr-" name, ARCHITECTURE_##arch, .designator = PARTITION_USR }, \
{ SD_GPT_USR_##arch##_VERITY, "usr-" name "-verity", ARCHITECTURE_##arch, .designator = PARTITION_USR_VERITY }, \
{ SD_GPT_USR_##arch##_VERITY_SIG, "usr-" name "-verity-sig", ARCHITECTURE_##arch, .designator = PARTITION_USR_VERITY_SIG }
const GptPartitionType gpt_partition_type_table[] = {
_GPT_ARCH_SEXTET(ALPHA, "alpha"),
_GPT_ARCH_SEXTET(ARC, "arc"),
_GPT_ARCH_SEXTET(ARM, "arm"),
_GPT_ARCH_SEXTET(ARM64, "arm64"),
_GPT_ARCH_SEXTET(IA64, "ia64"),
_GPT_ARCH_SEXTET(LOONGARCH64, "loongarch64"),
_GPT_ARCH_SEXTET(MIPS_LE, "mips-le"),
_GPT_ARCH_SEXTET(MIPS64_LE, "mips64-le"),
_GPT_ARCH_SEXTET(PARISC, "parisc"),
_GPT_ARCH_SEXTET(PPC, "ppc"),
_GPT_ARCH_SEXTET(PPC64, "ppc64"),
_GPT_ARCH_SEXTET(PPC64_LE, "ppc64-le"),
_GPT_ARCH_SEXTET(RISCV32, "riscv32"),
_GPT_ARCH_SEXTET(RISCV64, "riscv64"),
_GPT_ARCH_SEXTET(S390, "s390"),
_GPT_ARCH_SEXTET(S390X, "s390x"),
_GPT_ARCH_SEXTET(TILEGX, "tilegx"),
_GPT_ARCH_SEXTET(X86, "x86"),
_GPT_ARCH_SEXTET(X86_64, "x86-64"),
#ifdef SD_GPT_ROOT_NATIVE
{ SD_GPT_ROOT_NATIVE, "root", native_architecture(), .designator = PARTITION_ROOT },
{ SD_GPT_ROOT_NATIVE_VERITY, "root-verity", native_architecture(), .designator = PARTITION_ROOT_VERITY },
{ SD_GPT_ROOT_NATIVE_VERITY_SIG, "root-verity-sig", native_architecture(), .designator = PARTITION_ROOT_VERITY_SIG },
{ SD_GPT_USR_NATIVE, "usr", native_architecture(), .designator = PARTITION_USR },
{ SD_GPT_USR_NATIVE_VERITY, "usr-verity", native_architecture(), .designator = PARTITION_USR_VERITY },
{ SD_GPT_USR_NATIVE_VERITY_SIG, "usr-verity-sig", native_architecture(), .designator = PARTITION_USR_VERITY_SIG },
#endif
#ifdef SD_GPT_ROOT_SECONDARY
{ SD_GPT_ROOT_NATIVE, "root-secondary", native_architecture(), .designator = PARTITION_ROOT },
{ SD_GPT_ROOT_NATIVE_VERITY, "root-secondary-verity", native_architecture(), .designator = PARTITION_ROOT_VERITY },
{ SD_GPT_ROOT_NATIVE_VERITY_SIG, "root-secondary-verity-sig", native_architecture(), .designator = PARTITION_ROOT_VERITY_SIG },
{ SD_GPT_USR_NATIVE, "usr-secondary", native_architecture(), .designator = PARTITION_USR },
{ SD_GPT_USR_NATIVE_VERITY, "usr-secondary-verity", native_architecture(), .designator = PARTITION_USR_VERITY },
{ SD_GPT_USR_NATIVE_VERITY_SIG, "usr-secondary-verity-sig", native_architecture(), .designator = PARTITION_USR_VERITY_SIG },
#endif
{ SD_GPT_ESP, "esp", _ARCHITECTURE_INVALID, .designator = PARTITION_ESP },
{ SD_GPT_XBOOTLDR, "xbootldr", _ARCHITECTURE_INVALID, .designator = PARTITION_XBOOTLDR },
{ SD_GPT_SWAP, "swap", _ARCHITECTURE_INVALID, .designator = PARTITION_SWAP },
{ SD_GPT_HOME, "home", _ARCHITECTURE_INVALID, .designator = PARTITION_HOME },
{ SD_GPT_SRV, "srv", _ARCHITECTURE_INVALID, .designator = PARTITION_SRV },
{ SD_GPT_VAR, "var", _ARCHITECTURE_INVALID, .designator = PARTITION_VAR },
{ SD_GPT_TMP, "tmp", _ARCHITECTURE_INVALID, .designator = PARTITION_TMP },
{ SD_GPT_USER_HOME, "user-home", _ARCHITECTURE_INVALID, .designator = _PARTITION_DESIGNATOR_INVALID },
{ SD_GPT_LINUX_GENERIC, "linux-generic", _ARCHITECTURE_INVALID, .designator = _PARTITION_DESIGNATOR_INVALID },
{}
};
static const GptPartitionType *gpt_partition_type_find_by_uuid(sd_id128_t id) {
for (size_t i = 0; i < ELEMENTSOF(gpt_partition_type_table) - 1; i++)
if (sd_id128_equal(id, gpt_partition_type_table[i].uuid))
return gpt_partition_type_table + i;
return NULL;
}
const char *gpt_partition_type_uuid_to_string(sd_id128_t id) {
const GptPartitionType *pt;
pt = gpt_partition_type_find_by_uuid(id);
if (!pt)
return NULL;
return pt->name;
}
const char *gpt_partition_type_uuid_to_string_harder(
sd_id128_t id,
char buffer[static SD_ID128_UUID_STRING_MAX]) {
const char *s;
assert(buffer);
s = gpt_partition_type_uuid_to_string(id);
if (s)
return s;
return sd_id128_to_uuid_string(id, buffer);
}
int gpt_partition_type_from_string(const char *s, GptPartitionType *ret) {
sd_id128_t id;
int r;
assert(s);
for (size_t i = 0; i < ELEMENTSOF(gpt_partition_type_table) - 1; i++)
if (streq(s, gpt_partition_type_table[i].name)) {
if (ret)
*ret = gpt_partition_type_table[i];
return 0;
}
r = sd_id128_from_string(s, &id);
if (r < 0)
return r;
if (ret)
*ret = gpt_partition_type_from_uuid(id);
return 0;
}
Architecture gpt_partition_type_uuid_to_arch(sd_id128_t id) {
const GptPartitionType *pt;
pt = gpt_partition_type_find_by_uuid(id);
if (!pt)
return _ARCHITECTURE_INVALID;
return pt->arch;
}
int gpt_partition_label_valid(const char *s) {
_cleanup_free_ char16_t *recoded = NULL;
recoded = utf8_to_utf16(s, strlen(s));
if (!recoded)
return -ENOMEM;
return char16_strlen(recoded) <= GPT_LABEL_MAX;
}
GptPartitionType gpt_partition_type_from_uuid(sd_id128_t id) {
const GptPartitionType *pt;
pt = gpt_partition_type_find_by_uuid(id);
if (pt)
return *pt;
return (GptPartitionType) {
.uuid = id,
.arch = _ARCHITECTURE_INVALID,
.designator = _PARTITION_DESIGNATOR_INVALID,
};
}
const char *gpt_partition_type_mountpoint_nulstr(GptPartitionType type) {
return partition_mountpoint_to_string(type.designator);
}
bool gpt_partition_type_knows_read_only(GptPartitionType type) {
return IN_SET(type.designator,
PARTITION_ROOT,
PARTITION_USR,
/* pretty much implied, but let's set the bit to make things really clear */
PARTITION_ROOT_VERITY,
PARTITION_USR_VERITY,
PARTITION_HOME,
PARTITION_SRV,
PARTITION_VAR,
PARTITION_TMP,
PARTITION_XBOOTLDR);
}
bool gpt_partition_type_knows_growfs(GptPartitionType type) {
return IN_SET(type.designator,
PARTITION_ROOT,
PARTITION_USR,
PARTITION_HOME,
PARTITION_SRV,
PARTITION_VAR,
PARTITION_TMP,
PARTITION_XBOOTLDR);
}
bool gpt_partition_type_knows_no_auto(GptPartitionType type) {
return IN_SET(type.designator,
PARTITION_ROOT,
PARTITION_ROOT_VERITY,
PARTITION_USR,
PARTITION_USR_VERITY,
PARTITION_HOME,
PARTITION_SRV,
PARTITION_VAR,
PARTITION_TMP,
PARTITION_XBOOTLDR,
PARTITION_SWAP);
}