| /* 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); |
| } |