1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "string-table.h"
5 #include "string-util.h"
8 /* Gently push people towards defining GPT type UUIDs for all architectures we know */
9 #if !defined(SD_GPT_ROOT_NATIVE) || \
10 !defined(SD_GPT_ROOT_NATIVE_VERITY) || \
11 !defined(SD_GPT_ROOT_NATIVE_VERITY_SIG) || \
12 !defined(SD_GPT_USR_NATIVE) || \
13 !defined(SD_GPT_USR_NATIVE_VERITY) || \
14 !defined(SD_GPT_USR_NATIVE_VERITY_SIG)
15 #pragma message "Please define GPT partition types for your architecture."
18 bool partition_designator_is_versioned(PartitionDesignator d
) {
19 /* Returns true for all designators where we want to support a concept of "versioning", i.e. which
20 * likely contain software binaries (or hashes thereof) that make sense to be versioned as a
21 * whole. We use this check to automatically pick the newest version of these partitions, by version
22 * comparing the partition labels. */
27 PARTITION_ROOT_VERITY
,
29 PARTITION_ROOT_VERITY_SIG
,
30 PARTITION_USR_VERITY_SIG
);
33 PartitionDesignator
partition_verity_of(PartitionDesignator p
) {
37 return PARTITION_ROOT_VERITY
;
40 return PARTITION_USR_VERITY
;
43 return _PARTITION_DESIGNATOR_INVALID
;
47 PartitionDesignator
partition_verity_sig_of(PartitionDesignator p
) {
51 return PARTITION_ROOT_VERITY_SIG
;
54 return PARTITION_USR_VERITY_SIG
;
57 return _PARTITION_DESIGNATOR_INVALID
;
61 PartitionDesignator
partition_verity_to_data(PartitionDesignator d
) {
64 case PARTITION_ROOT_VERITY
:
65 return PARTITION_ROOT
;
67 case PARTITION_USR_VERITY
:
71 return _PARTITION_DESIGNATOR_INVALID
;
75 PartitionDesignator
partition_verity_sig_to_data(PartitionDesignator d
) {
78 case PARTITION_ROOT_VERITY_SIG
:
79 return PARTITION_ROOT
;
81 case PARTITION_USR_VERITY_SIG
:
85 return _PARTITION_DESIGNATOR_INVALID
;
89 static const char *const partition_designator_table
[_PARTITION_DESIGNATOR_MAX
] = {
90 [PARTITION_ROOT
] = "root",
91 [PARTITION_USR
] = "usr",
92 [PARTITION_HOME
] = "home",
93 [PARTITION_SRV
] = "srv",
94 [PARTITION_ESP
] = "esp",
95 [PARTITION_XBOOTLDR
] = "xbootldr",
96 [PARTITION_SWAP
] = "swap",
97 [PARTITION_ROOT_VERITY
] = "root-verity",
98 [PARTITION_USR_VERITY
] = "usr-verity",
99 [PARTITION_ROOT_VERITY_SIG
] = "root-verity-sig",
100 [PARTITION_USR_VERITY_SIG
] = "usr-verity-sig",
101 [PARTITION_TMP
] = "tmp",
102 [PARTITION_VAR
] = "var",
105 DEFINE_STRING_TABLE_LOOKUP(partition_designator
, PartitionDesignator
);
107 static const char *const partition_mountpoint_table
[_PARTITION_DESIGNATOR_MAX
] = {
108 [PARTITION_ROOT
] = "/\0",
109 [PARTITION_USR
] = "/usr\0",
110 [PARTITION_HOME
] = "/home\0",
111 [PARTITION_SRV
] = "/srv\0",
112 [PARTITION_ESP
] = "/efi\0/boot\0",
113 [PARTITION_XBOOTLDR
] = "/boot\0",
114 [PARTITION_TMP
] = "/var/tmp\0",
115 [PARTITION_VAR
] = "/var\0",
118 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(partition_mountpoint
, PartitionDesignator
);
120 #define _GPT_ARCH_SEXTET(arch, name) \
121 { SD_GPT_ROOT_##arch, "root-" name, ARCHITECTURE_##arch, .designator = PARTITION_ROOT }, \
122 { SD_GPT_ROOT_##arch##_VERITY, "root-" name "-verity", ARCHITECTURE_##arch, .designator = PARTITION_ROOT_VERITY }, \
123 { SD_GPT_ROOT_##arch##_VERITY_SIG, "root-" name "-verity-sig", ARCHITECTURE_##arch, .designator = PARTITION_ROOT_VERITY_SIG }, \
124 { SD_GPT_USR_##arch, "usr-" name, ARCHITECTURE_##arch, .designator = PARTITION_USR }, \
125 { SD_GPT_USR_##arch##_VERITY, "usr-" name "-verity", ARCHITECTURE_##arch, .designator = PARTITION_USR_VERITY }, \
126 { SD_GPT_USR_##arch##_VERITY_SIG, "usr-" name "-verity-sig", ARCHITECTURE_##arch, .designator = PARTITION_USR_VERITY_SIG }
128 /* Two special cases: alias aarch64 to arm64, and amd64 to x86-64. The DSP mixes debianisms and CPUisms: for
129 * x86, it uses x86 and x86_64, but for aarch64 it uses arm64. This is confusing, and leads to issues for
130 * callers that have to know which -ism to use for which architecture. But we also don't really want to
131 * change the spec and add new partition labels, so add a user-friendly aliasing here, so that both are
132 * accepted but the end result on disk (ie: the partition label).
133 * So always list the canonical name FIRST, and then any aliases later, so that we can match on aliases,
134 * but always return the canonical name. And never return directly a match on the name, always re-resolve
135 * by UUID so that the canonical entry is always found. */
137 const GptPartitionType gpt_partition_type_table
[] = {
138 _GPT_ARCH_SEXTET(ALPHA
, "alpha"),
139 _GPT_ARCH_SEXTET(ARC
, "arc"),
140 _GPT_ARCH_SEXTET(ARM
, "arm"),
141 _GPT_ARCH_SEXTET(ARM
, "armv7l"), /* Alias: must be listed after arm */
142 _GPT_ARCH_SEXTET(ARM64
, "arm64"),
143 _GPT_ARCH_SEXTET(ARM64
, "aarch64"), /* Alias: must be listed after arm64 */
144 _GPT_ARCH_SEXTET(IA64
, "ia64"),
145 _GPT_ARCH_SEXTET(LOONGARCH64
, "loongarch64"),
146 _GPT_ARCH_SEXTET(MIPS
, "mips"),
147 _GPT_ARCH_SEXTET(MIPS64
, "mips64"),
148 _GPT_ARCH_SEXTET(MIPS_LE
, "mips-le"),
149 _GPT_ARCH_SEXTET(MIPS64_LE
, "mips64-le"),
150 _GPT_ARCH_SEXTET(PARISC
, "parisc"),
151 _GPT_ARCH_SEXTET(PPC
, "ppc"),
152 _GPT_ARCH_SEXTET(PPC64
, "ppc64"),
153 _GPT_ARCH_SEXTET(PPC64_LE
, "ppc64-le"),
154 _GPT_ARCH_SEXTET(PPC64_LE
, "ppc64le"), /* Alias: must be listed after ppc64-le */
155 _GPT_ARCH_SEXTET(RISCV32
, "riscv32"),
156 _GPT_ARCH_SEXTET(RISCV64
, "riscv64"),
157 _GPT_ARCH_SEXTET(S390
, "s390"),
158 _GPT_ARCH_SEXTET(S390X
, "s390x"),
159 _GPT_ARCH_SEXTET(TILEGX
, "tilegx"),
160 _GPT_ARCH_SEXTET(X86
, "x86"),
161 _GPT_ARCH_SEXTET(X86_64
, "x86-64"),
162 _GPT_ARCH_SEXTET(X86_64
, "x86_64"), /* Alias: must be listed after x86-64 */
163 _GPT_ARCH_SEXTET(X86_64
, "amd64"), /* Alias: must be listed after x86-64 */
164 #ifdef SD_GPT_ROOT_NATIVE
165 { SD_GPT_ROOT_NATIVE
, "root", native_architecture(), .designator
= PARTITION_ROOT
},
166 { SD_GPT_ROOT_NATIVE_VERITY
, "root-verity", native_architecture(), .designator
= PARTITION_ROOT_VERITY
},
167 { SD_GPT_ROOT_NATIVE_VERITY_SIG
, "root-verity-sig", native_architecture(), .designator
= PARTITION_ROOT_VERITY_SIG
},
168 { SD_GPT_USR_NATIVE
, "usr", native_architecture(), .designator
= PARTITION_USR
},
169 { SD_GPT_USR_NATIVE_VERITY
, "usr-verity", native_architecture(), .designator
= PARTITION_USR_VERITY
},
170 { SD_GPT_USR_NATIVE_VERITY_SIG
, "usr-verity-sig", native_architecture(), .designator
= PARTITION_USR_VERITY_SIG
},
172 #ifdef SD_GPT_ROOT_SECONDARY
173 { SD_GPT_ROOT_SECONDARY
, "root-secondary", ARCHITECTURE_SECONDARY
, .designator
= PARTITION_ROOT
},
174 { SD_GPT_ROOT_SECONDARY_VERITY
, "root-secondary-verity", ARCHITECTURE_SECONDARY
, .designator
= PARTITION_ROOT_VERITY
},
175 { SD_GPT_ROOT_SECONDARY_VERITY_SIG
, "root-secondary-verity-sig", ARCHITECTURE_SECONDARY
, .designator
= PARTITION_ROOT_VERITY_SIG
},
176 { SD_GPT_USR_SECONDARY
, "usr-secondary", ARCHITECTURE_SECONDARY
, .designator
= PARTITION_USR
},
177 { SD_GPT_USR_SECONDARY_VERITY
, "usr-secondary-verity", ARCHITECTURE_SECONDARY
, .designator
= PARTITION_USR_VERITY
},
178 { SD_GPT_USR_SECONDARY_VERITY_SIG
, "usr-secondary-verity-sig", ARCHITECTURE_SECONDARY
, .designator
= PARTITION_USR_VERITY_SIG
},
181 { SD_GPT_ESP
, "esp", _ARCHITECTURE_INVALID
, .designator
= PARTITION_ESP
},
182 { SD_GPT_XBOOTLDR
, "xbootldr", _ARCHITECTURE_INVALID
, .designator
= PARTITION_XBOOTLDR
},
183 { SD_GPT_SWAP
, "swap", _ARCHITECTURE_INVALID
, .designator
= PARTITION_SWAP
},
184 { SD_GPT_HOME
, "home", _ARCHITECTURE_INVALID
, .designator
= PARTITION_HOME
},
185 { SD_GPT_SRV
, "srv", _ARCHITECTURE_INVALID
, .designator
= PARTITION_SRV
},
186 { SD_GPT_VAR
, "var", _ARCHITECTURE_INVALID
, .designator
= PARTITION_VAR
},
187 { SD_GPT_TMP
, "tmp", _ARCHITECTURE_INVALID
, .designator
= PARTITION_TMP
},
188 { SD_GPT_USER_HOME
, "user-home", _ARCHITECTURE_INVALID
, .designator
= _PARTITION_DESIGNATOR_INVALID
},
189 { SD_GPT_LINUX_GENERIC
, "linux-generic", _ARCHITECTURE_INVALID
, .designator
= _PARTITION_DESIGNATOR_INVALID
},
193 static const GptPartitionType
*gpt_partition_type_find_by_uuid(sd_id128_t id
) {
195 FOREACH_ARRAY(t
, gpt_partition_type_table
, ELEMENTSOF(gpt_partition_type_table
) - 1)
196 if (sd_id128_equal(id
, t
->uuid
))
202 const char *gpt_partition_type_uuid_to_string(sd_id128_t id
) {
203 const GptPartitionType
*pt
;
205 pt
= gpt_partition_type_find_by_uuid(id
);
212 const char *gpt_partition_type_uuid_to_string_harder(
214 char buffer
[static SD_ID128_UUID_STRING_MAX
]) {
220 s
= gpt_partition_type_uuid_to_string(id
);
224 return sd_id128_to_uuid_string(id
, buffer
);
227 int gpt_partition_type_from_string(const char *s
, GptPartitionType
*ret
) {
228 sd_id128_t id
= SD_ID128_NULL
;
233 FOREACH_ARRAY(t
, gpt_partition_type_table
, ELEMENTSOF(gpt_partition_type_table
) - 1)
234 if (streq(s
, t
->name
)) {
235 /* Don't return immediately, instead re-resolve by UUID so that we can support
236 * aliases like aarch64 -> arm64 transparently. */
241 if (sd_id128_is_null(id
)) {
242 r
= sd_id128_from_string(s
, &id
);
248 *ret
= gpt_partition_type_from_uuid(id
);
253 GptPartitionType
gpt_partition_type_override_architecture(GptPartitionType type
, Architecture arch
) {
256 FOREACH_ARRAY(t
, gpt_partition_type_table
, ELEMENTSOF(gpt_partition_type_table
) - 1)
257 if (t
->designator
== type
.designator
&& t
->arch
== arch
)
260 /* If we can't find an entry with the same designator and the requested architecture, just return the
261 * original partition type. */
265 Architecture
gpt_partition_type_uuid_to_arch(sd_id128_t id
) {
266 const GptPartitionType
*pt
;
268 pt
= gpt_partition_type_find_by_uuid(id
);
270 return _ARCHITECTURE_INVALID
;
275 int gpt_partition_label_valid(const char *s
) {
276 _cleanup_free_ char16_t
*recoded
= NULL
;
278 recoded
= utf8_to_utf16(s
, SIZE_MAX
);
282 return char16_strlen(recoded
) <= GPT_LABEL_MAX
;
285 GptPartitionType
gpt_partition_type_from_uuid(sd_id128_t id
) {
286 const GptPartitionType
*pt
;
288 pt
= gpt_partition_type_find_by_uuid(id
);
292 return (GptPartitionType
) {
294 .arch
= _ARCHITECTURE_INVALID
,
295 .designator
= _PARTITION_DESIGNATOR_INVALID
,
299 const char *gpt_partition_type_mountpoint_nulstr(GptPartitionType type
) {
300 return partition_mountpoint_to_string(type
.designator
);
303 bool gpt_partition_type_knows_read_only(GptPartitionType type
) {
304 return IN_SET(type
.designator
,
307 /* pretty much implied, but let's set the bit to make things really clear */
308 PARTITION_ROOT_VERITY
,
309 PARTITION_USR_VERITY
,
317 bool gpt_partition_type_knows_growfs(GptPartitionType type
) {
318 return IN_SET(type
.designator
,
328 bool gpt_partition_type_knows_no_auto(GptPartitionType type
) {
329 return IN_SET(type
.designator
,
331 PARTITION_ROOT_VERITY
,
333 PARTITION_USR_VERITY
,
342 bool gpt_header_has_signature(const GptHeader
*p
) {
345 if (memcmp(p
->signature
, (const char[8]) { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' }, 8) != 0)
348 if (le32toh(p
->revision
) != UINT32_C(0x00010000)) /* the only known revision of the spec: 1.0 */
351 if (le32toh(p
->header_size
) < sizeof(GptHeader
))
354 if (le32toh(p
->header_size
) > 4096) /* larger than a sector? something is off… */
357 if (le64toh(p
->my_lba
) != 1) /* this sector must claim to be at sector offset 1 */