]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/gpt.c
tree-wide: Add more socket units (#37991)
[thirdparty/systemd.git] / src / shared / gpt.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
19ce38ce 2
69a283c5 3#include "alloc-util.h"
19ce38ce 4#include "gpt.h"
dd894023 5#include "string-table.h"
19ce38ce 6#include "string-util.h"
22a0a36e 7#include "utf8.h"
19ce38ce 8
d42e4fa2 9/* Gently push people towards defining GPT type UUIDs for all architectures we know */
92e72028
ZJS
10#if !defined(SD_GPT_ROOT_NATIVE) || \
11 !defined(SD_GPT_ROOT_NATIVE_VERITY) || \
12 !defined(SD_GPT_ROOT_NATIVE_VERITY_SIG) || \
13 !defined(SD_GPT_USR_NATIVE) || \
14 !defined(SD_GPT_USR_NATIVE_VERITY) || \
15 !defined(SD_GPT_USR_NATIVE_VERITY_SIG)
d42e4fa2
LP
16#pragma message "Please define GPT partition types for your architecture."
17#endif
18
dd894023
DDM
19bool partition_designator_is_versioned(PartitionDesignator d) {
20 /* Returns true for all designators where we want to support a concept of "versioning", i.e. which
21 * likely contain software binaries (or hashes thereof) that make sense to be versioned as a
22 * whole. We use this check to automatically pick the newest version of these partitions, by version
23 * comparing the partition labels. */
24
25 return IN_SET(d,
26 PARTITION_ROOT,
dd894023 27 PARTITION_USR,
dd894023 28 PARTITION_ROOT_VERITY,
dd894023 29 PARTITION_USR_VERITY,
dd894023 30 PARTITION_ROOT_VERITY_SIG,
22e932f4 31 PARTITION_USR_VERITY_SIG);
dd894023
DDM
32}
33
34PartitionDesignator partition_verity_of(PartitionDesignator p) {
35 switch (p) {
36
37 case PARTITION_ROOT:
38 return PARTITION_ROOT_VERITY;
39
dd894023
DDM
40 case PARTITION_USR:
41 return PARTITION_USR_VERITY;
42
dd894023
DDM
43 default:
44 return _PARTITION_DESIGNATOR_INVALID;
45 }
46}
47
48PartitionDesignator partition_verity_sig_of(PartitionDesignator p) {
49 switch (p) {
50
51 case PARTITION_ROOT:
52 return PARTITION_ROOT_VERITY_SIG;
53
dd894023
DDM
54 case PARTITION_USR:
55 return PARTITION_USR_VERITY_SIG;
56
dd894023
DDM
57 default:
58 return _PARTITION_DESIGNATOR_INVALID;
59 }
60}
61
86adf4a5
LP
62PartitionDesignator partition_verity_to_data(PartitionDesignator d) {
63 switch (d) {
64
65 case PARTITION_ROOT_VERITY:
66 return PARTITION_ROOT;
67
68 case PARTITION_USR_VERITY:
69 return PARTITION_USR;
70
71 default:
72 return _PARTITION_DESIGNATOR_INVALID;
73 }
74}
75
76PartitionDesignator partition_verity_sig_to_data(PartitionDesignator d) {
77 switch (d) {
78
79 case PARTITION_ROOT_VERITY_SIG:
80 return PARTITION_ROOT;
81
82 case PARTITION_USR_VERITY_SIG:
83 return PARTITION_USR;
84
85 default:
86 return _PARTITION_DESIGNATOR_INVALID;
87 }
88}
dd894023 89
3cde36ff 90static const char *const partition_designator_table[_PARTITION_DESIGNATOR_MAX] = {
dd894023 91 [PARTITION_ROOT] = "root",
dd894023 92 [PARTITION_USR] = "usr",
dd894023
DDM
93 [PARTITION_HOME] = "home",
94 [PARTITION_SRV] = "srv",
95 [PARTITION_ESP] = "esp",
96 [PARTITION_XBOOTLDR] = "xbootldr",
97 [PARTITION_SWAP] = "swap",
98 [PARTITION_ROOT_VERITY] = "root-verity",
dd894023 99 [PARTITION_USR_VERITY] = "usr-verity",
dd894023 100 [PARTITION_ROOT_VERITY_SIG] = "root-verity-sig",
dd894023 101 [PARTITION_USR_VERITY_SIG] = "usr-verity-sig",
dd894023
DDM
102 [PARTITION_TMP] = "tmp",
103 [PARTITION_VAR] = "var",
dd894023
DDM
104};
105
106DEFINE_STRING_TABLE_LOOKUP(partition_designator, PartitionDesignator);
107
3cde36ff 108static const char *const partition_mountpoint_table[_PARTITION_DESIGNATOR_MAX] = {
58b4ad76 109 [PARTITION_ROOT] = "/\0",
58b4ad76 110 [PARTITION_USR] = "/usr\0",
58b4ad76
DDM
111 [PARTITION_HOME] = "/home\0",
112 [PARTITION_SRV] = "/srv\0",
113 [PARTITION_ESP] = "/efi\0/boot\0",
114 [PARTITION_XBOOTLDR] = "/boot\0",
115 [PARTITION_TMP] = "/var/tmp\0",
116 [PARTITION_VAR] = "/var\0",
117};
118
0ecfcc97 119DEFINE_STRING_TABLE_LOOKUP_TO_STRING(partition_mountpoint, PartitionDesignator);
58b4ad76 120
a7f787d6 121#define _GPT_ARCH_SEXTET(arch, name) \
22e932f4
DDM
122 { SD_GPT_ROOT_##arch, "root-" name, ARCHITECTURE_##arch, .designator = PARTITION_ROOT }, \
123 { SD_GPT_ROOT_##arch##_VERITY, "root-" name "-verity", ARCHITECTURE_##arch, .designator = PARTITION_ROOT_VERITY }, \
124 { SD_GPT_ROOT_##arch##_VERITY_SIG, "root-" name "-verity-sig", ARCHITECTURE_##arch, .designator = PARTITION_ROOT_VERITY_SIG }, \
125 { SD_GPT_USR_##arch, "usr-" name, ARCHITECTURE_##arch, .designator = PARTITION_USR }, \
126 { SD_GPT_USR_##arch##_VERITY, "usr-" name "-verity", ARCHITECTURE_##arch, .designator = PARTITION_USR_VERITY }, \
127 { SD_GPT_USR_##arch##_VERITY_SIG, "usr-" name "-verity-sig", ARCHITECTURE_##arch, .designator = PARTITION_USR_VERITY_SIG }
a7f787d6 128
08a2bb7b
LB
129/* Two special cases: alias aarch64 to arm64, and amd64 to x86-64. The DSP mixes debianisms and CPUisms: for
130 * x86, it uses x86 and x86_64, but for aarch64 it uses arm64. This is confusing, and leads to issues for
131 * callers that have to know which -ism to use for which architecture. But we also don't really want to
132 * change the spec and add new partition labels, so add a user-friendly aliasing here, so that both are
133 * accepted but the end result on disk (ie: the partition label).
134 * So always list the canonical name FIRST, and then any aliases later, so that we can match on aliases,
135 * but always return the canonical name. And never return directly a match on the name, always re-resolve
136 * by UUID so that the canonical entry is always found. */
137
dc972b07 138const GptPartitionType gpt_partition_type_table[] = {
6b47cc98
ZJS
139 _GPT_ARCH_SEXTET(ALPHA, "alpha"),
140 _GPT_ARCH_SEXTET(ARC, "arc"),
a7f787d6 141 _GPT_ARCH_SEXTET(ARM, "arm"),
8340d500 142 _GPT_ARCH_SEXTET(ARM, "armv7l"), /* Alias: must be listed after arm */
16bcaebc 143 _GPT_ARCH_SEXTET(ARM64, "arm64"),
08a2bb7b 144 _GPT_ARCH_SEXTET(ARM64, "aarch64"), /* Alias: must be listed after arm64 */
a7f787d6 145 _GPT_ARCH_SEXTET(IA64, "ia64"),
0444a6e4 146 _GPT_ARCH_SEXTET(LOONGARCH64, "loongarch64"),
f0b151ce 147 _GPT_ARCH_SEXTET(LOONGARCH64, "loong64"), /* Alias: must be listed after loongarch64 */
7c6dd200
RH
148 _GPT_ARCH_SEXTET(MIPS, "mips"),
149 _GPT_ARCH_SEXTET(MIPS64, "mips64"),
6b47cc98 150 _GPT_ARCH_SEXTET(MIPS_LE, "mips-le"),
f0b151ce 151 _GPT_ARCH_SEXTET(MIPS_LE, "mipsel"), /* Alias: must be listed after mips-le */
6b47cc98 152 _GPT_ARCH_SEXTET(MIPS64_LE, "mips64-le"),
f0b151ce 153 _GPT_ARCH_SEXTET(MIPS64_LE, "mips64el"), /* Alias: must be listed after mips64-le */
5a9276f6 154 _GPT_ARCH_SEXTET(PARISC, "parisc"),
f0b151ce 155 _GPT_ARCH_SEXTET(PARISC, "hppa"), /* Alias: must be listed after parisc */
6b47cc98
ZJS
156 _GPT_ARCH_SEXTET(PPC, "ppc"),
157 _GPT_ARCH_SEXTET(PPC64, "ppc64"),
655eb073 158 _GPT_ARCH_SEXTET(PPC64_LE, "ppc64-le"),
8340d500 159 _GPT_ARCH_SEXTET(PPC64_LE, "ppc64le"), /* Alias: must be listed after ppc64-le */
f0b151ce 160 _GPT_ARCH_SEXTET(PPC64_LE, "ppc64el"), /* Alias: must be listed after ppc64-le */
a7f787d6
ZJS
161 _GPT_ARCH_SEXTET(RISCV32, "riscv32"),
162 _GPT_ARCH_SEXTET(RISCV64, "riscv64"),
6b47cc98
ZJS
163 _GPT_ARCH_SEXTET(S390, "s390"),
164 _GPT_ARCH_SEXTET(S390X, "s390x"),
165 _GPT_ARCH_SEXTET(TILEGX, "tilegx"),
a7f787d6 166 _GPT_ARCH_SEXTET(X86, "x86"),
f0b151ce
LB
167 _GPT_ARCH_SEXTET(X86, "i386"), /* Alias: must be listed after x86 */
168 _GPT_ARCH_SEXTET(X86, "i486"), /* Alias: must be listed after x86 */
169 _GPT_ARCH_SEXTET(X86, "i586"), /* Alias: must be listed after x86 */
170 _GPT_ARCH_SEXTET(X86, "i686"), /* Alias: must be listed after x86 */
a7f787d6 171 _GPT_ARCH_SEXTET(X86_64, "x86-64"),
8340d500 172 _GPT_ARCH_SEXTET(X86_64, "x86_64"), /* Alias: must be listed after x86-64 */
08a2bb7b 173 _GPT_ARCH_SEXTET(X86_64, "amd64"), /* Alias: must be listed after x86-64 */
92e72028 174#ifdef SD_GPT_ROOT_NATIVE
dd894023
DDM
175 { SD_GPT_ROOT_NATIVE, "root", native_architecture(), .designator = PARTITION_ROOT },
176 { SD_GPT_ROOT_NATIVE_VERITY, "root-verity", native_architecture(), .designator = PARTITION_ROOT_VERITY },
177 { SD_GPT_ROOT_NATIVE_VERITY_SIG, "root-verity-sig", native_architecture(), .designator = PARTITION_ROOT_VERITY_SIG },
178 { SD_GPT_USR_NATIVE, "usr", native_architecture(), .designator = PARTITION_USR },
179 { SD_GPT_USR_NATIVE_VERITY, "usr-verity", native_architecture(), .designator = PARTITION_USR_VERITY },
180 { SD_GPT_USR_NATIVE_VERITY_SIG, "usr-verity-sig", native_architecture(), .designator = PARTITION_USR_VERITY_SIG },
19ce38ce 181#endif
92e72028 182#ifdef SD_GPT_ROOT_SECONDARY
5249e953
DDM
183 { SD_GPT_ROOT_SECONDARY, "root-secondary", ARCHITECTURE_SECONDARY, .designator = PARTITION_ROOT },
184 { SD_GPT_ROOT_SECONDARY_VERITY, "root-secondary-verity", ARCHITECTURE_SECONDARY, .designator = PARTITION_ROOT_VERITY },
185 { SD_GPT_ROOT_SECONDARY_VERITY_SIG, "root-secondary-verity-sig", ARCHITECTURE_SECONDARY, .designator = PARTITION_ROOT_VERITY_SIG },
186 { SD_GPT_USR_SECONDARY, "usr-secondary", ARCHITECTURE_SECONDARY, .designator = PARTITION_USR },
187 { SD_GPT_USR_SECONDARY_VERITY, "usr-secondary-verity", ARCHITECTURE_SECONDARY, .designator = PARTITION_USR_VERITY },
188 { SD_GPT_USR_SECONDARY_VERITY_SIG, "usr-secondary-verity-sig", ARCHITECTURE_SECONDARY, .designator = PARTITION_USR_VERITY_SIG },
19ce38ce 189#endif
a7f787d6 190
dd894023
DDM
191 { SD_GPT_ESP, "esp", _ARCHITECTURE_INVALID, .designator = PARTITION_ESP },
192 { SD_GPT_XBOOTLDR, "xbootldr", _ARCHITECTURE_INVALID, .designator = PARTITION_XBOOTLDR },
193 { SD_GPT_SWAP, "swap", _ARCHITECTURE_INVALID, .designator = PARTITION_SWAP },
194 { SD_GPT_HOME, "home", _ARCHITECTURE_INVALID, .designator = PARTITION_HOME },
195 { SD_GPT_SRV, "srv", _ARCHITECTURE_INVALID, .designator = PARTITION_SRV },
196 { SD_GPT_VAR, "var", _ARCHITECTURE_INVALID, .designator = PARTITION_VAR },
197 { SD_GPT_TMP, "tmp", _ARCHITECTURE_INVALID, .designator = PARTITION_TMP },
df655bf3
DDM
198 { SD_GPT_USER_HOME, "user-home", _ARCHITECTURE_INVALID, .designator = _PARTITION_DESIGNATOR_INVALID },
199 { SD_GPT_LINUX_GENERIC, "linux-generic", _ARCHITECTURE_INVALID, .designator = _PARTITION_DESIGNATOR_INVALID },
dc972b07 200 {}
19ce38ce
ZJS
201};
202
cc97a3a5
LP
203static const GptPartitionType *gpt_partition_type_find_by_uuid(sd_id128_t id) {
204
716a413a
DDM
205 FOREACH_ARRAY(t, gpt_partition_type_table, ELEMENTSOF(gpt_partition_type_table) - 1)
206 if (sd_id128_equal(id, t->uuid))
207 return t;
19ce38ce
ZJS
208
209 return NULL;
210}
211
bfd5a068 212const char* gpt_partition_type_uuid_to_string(sd_id128_t id) {
cc97a3a5
LP
213 const GptPartitionType *pt;
214
215 pt = gpt_partition_type_find_by_uuid(id);
216 if (!pt)
217 return NULL;
218
219 return pt->name;
220}
221
bfd5a068 222const char* gpt_partition_type_uuid_to_string_harder(
19ce38ce 223 sd_id128_t id,
b7416360 224 char buffer[static SD_ID128_UUID_STRING_MAX]) {
19ce38ce
ZJS
225
226 const char *s;
227
228 assert(buffer);
229
230 s = gpt_partition_type_uuid_to_string(id);
231 if (s)
232 return s;
233
b7416360 234 return sd_id128_to_uuid_string(id, buffer);
19ce38ce
ZJS
235}
236
22e932f4 237int gpt_partition_type_from_string(const char *s, GptPartitionType *ret) {
08a2bb7b 238 sd_id128_t id = SD_ID128_NULL;
22e932f4
DDM
239 int r;
240
19ce38ce 241 assert(s);
19ce38ce 242
716a413a
DDM
243 FOREACH_ARRAY(t, gpt_partition_type_table, ELEMENTSOF(gpt_partition_type_table) - 1)
244 if (streq(s, t->name)) {
08a2bb7b
LB
245 /* Don't return immediately, instead re-resolve by UUID so that we can support
246 * aliases like aarch64 -> arm64 transparently. */
716a413a 247 id = t->uuid;
08a2bb7b 248 break;
19ce38ce
ZJS
249 }
250
08a2bb7b
LB
251 if (sd_id128_is_null(id)) {
252 r = sd_id128_from_string(s, &id);
253 if (r < 0)
254 return r;
255 }
22e932f4
DDM
256
257 if (ret)
258 *ret = gpt_partition_type_from_uuid(id);
259
260 return 0;
19ce38ce 261}
22a0a36e 262
7767b83f
DDM
263GptPartitionType gpt_partition_type_override_architecture(GptPartitionType type, Architecture arch) {
264 assert(arch >= 0);
265
266 FOREACH_ARRAY(t, gpt_partition_type_table, ELEMENTSOF(gpt_partition_type_table) - 1)
267 if (t->designator == type.designator && t->arch == arch)
268 return *t;
269
270 /* If we can't find an entry with the same designator and the requested architecture, just return the
271 * original partition type. */
272 return type;
273}
274
51d1c8f2 275Architecture gpt_partition_type_uuid_to_arch(sd_id128_t id) {
cc97a3a5
LP
276 const GptPartitionType *pt;
277
278 pt = gpt_partition_type_find_by_uuid(id);
279 if (!pt)
280 return _ARCHITECTURE_INVALID;
51d1c8f2 281
cc97a3a5 282 return pt->arch;
51d1c8f2
DDM
283}
284
22a0a36e
LP
285int gpt_partition_label_valid(const char *s) {
286 _cleanup_free_ char16_t *recoded = NULL;
287
ba091282 288 recoded = utf8_to_utf16(s, SIZE_MAX);
22a0a36e
LP
289 if (!recoded)
290 return -ENOMEM;
291
6001df65 292 return char16_strlen(recoded) <= GPT_LABEL_MAX;
22a0a36e 293}
e81acfd2 294
22e932f4 295GptPartitionType gpt_partition_type_from_uuid(sd_id128_t id) {
cc97a3a5
LP
296 const GptPartitionType *pt;
297
298 pt = gpt_partition_type_find_by_uuid(id);
299 if (pt)
300 return *pt;
6ddd80ae 301
dd894023
DDM
302 return (GptPartitionType) {
303 .uuid = id,
304 .arch = _ARCHITECTURE_INVALID,
305 .designator = _PARTITION_DESIGNATOR_INVALID,
306 };
6ddd80ae
DDM
307}
308
bfd5a068 309const char* gpt_partition_type_mountpoint_nulstr(GptPartitionType type) {
22e932f4 310 return partition_mountpoint_to_string(type.designator);
e81acfd2
LP
311}
312
22e932f4
DDM
313bool gpt_partition_type_knows_read_only(GptPartitionType type) {
314 return IN_SET(type.designator,
315 PARTITION_ROOT,
316 PARTITION_USR,
317 /* pretty much implied, but let's set the bit to make things really clear */
dd894023 318 PARTITION_ROOT_VERITY,
22e932f4
DDM
319 PARTITION_USR_VERITY,
320 PARTITION_HOME,
321 PARTITION_SRV,
322 PARTITION_VAR,
323 PARTITION_TMP,
324 PARTITION_XBOOTLDR);
e81acfd2
LP
325}
326
22e932f4
DDM
327bool gpt_partition_type_knows_growfs(GptPartitionType type) {
328 return IN_SET(type.designator,
329 PARTITION_ROOT,
dd894023 330 PARTITION_USR,
22e932f4
DDM
331 PARTITION_HOME,
332 PARTITION_SRV,
333 PARTITION_VAR,
334 PARTITION_TMP,
335 PARTITION_XBOOTLDR);
e81acfd2
LP
336}
337
22e932f4
DDM
338bool gpt_partition_type_knows_no_auto(GptPartitionType type) {
339 return IN_SET(type.designator,
340 PARTITION_ROOT,
341 PARTITION_ROOT_VERITY,
342 PARTITION_USR,
dd894023 343 PARTITION_USR_VERITY,
22e932f4
DDM
344 PARTITION_HOME,
345 PARTITION_SRV,
346 PARTITION_VAR,
347 PARTITION_TMP,
348 PARTITION_XBOOTLDR,
349 PARTITION_SWAP);
ff0771bf 350}
6b0651df 351
90a25577
DDM
352bool gpt_partition_type_has_filesystem(GptPartitionType type) {
353 return IN_SET(type.designator,
354 PARTITION_ROOT,
355 PARTITION_USR,
356 PARTITION_HOME,
357 PARTITION_SRV,
358 PARTITION_ESP,
359 PARTITION_XBOOTLDR,
360 PARTITION_TMP,
361 PARTITION_VAR);
362}
363
6b0651df
LP
364bool gpt_header_has_signature(const GptHeader *p) {
365 assert(p);
366
367 if (memcmp(p->signature, (const char[8]) { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' }, 8) != 0)
368 return false;
369
370 if (le32toh(p->revision) != UINT32_C(0x00010000)) /* the only known revision of the spec: 1.0 */
371 return false;
372
373 if (le32toh(p->header_size) < sizeof(GptHeader))
374 return false;
375
376 if (le32toh(p->header_size) > 4096) /* larger than a sector? something is off… */
377 return false;
378
379 if (le64toh(p->my_lba) != 1) /* this sector must claim to be at sector offset 1 */
380 return false;
381
382 return true;
383}