]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/partition/repart.c
Merge pull request #28957 from yuwata/core-mount-set-dirty-on-umount
[thirdparty/systemd.git] / src / partition / repart.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
e594a3b1
LP
2
3#if HAVE_VALGRIND_MEMCHECK_H
4#include <valgrind/memcheck.h>
5#endif
6
7#include <fcntl.h>
8#include <getopt.h>
e594a3b1
LP
9#include <linux/fs.h>
10#include <linux/loop.h>
11#include <sys/file.h>
12#include <sys/ioctl.h>
13#include <sys/stat.h>
14
1a037ba2 15#include "sd-device.h"
e594a3b1
LP
16#include "sd-id128.h"
17
18#include "alloc-util.h"
19#include "blkid-util.h"
20#include "blockdev-util.h"
21#include "btrfs-util.h"
d6b4d1c7 22#include "build.h"
f461a28d 23#include "chase.h"
e594a3b1
LP
24#include "conf-files.h"
25#include "conf-parser.h"
28db6fbf 26#include "constants.h"
1e2f3230 27#include "cryptsetup-util.h"
ca822829 28#include "device-util.h"
7176f06c 29#include "devnum-util.h"
5c08da58 30#include "dirent-util.h"
e594a3b1
LP
31#include "efivars.h"
32#include "errno-util.h"
33#include "fd-util.h"
4dc07c3a 34#include "fdisk-util.h"
b9df3536 35#include "fileio.h"
e594a3b1
LP
36#include "format-table.h"
37#include "format-util.h"
38#include "fs-util.h"
d8e32c47 39#include "glyph-util.h"
e594a3b1 40#include "gpt.h"
889914ef 41#include "hexdecoct.h"
ade99252 42#include "hmac.h"
e594a3b1 43#include "id128-util.h"
baa6a42d 44#include "initrd-util.h"
b456191d 45#include "io-util.h"
a015fbe7 46#include "json.h"
e594a3b1 47#include "list.h"
53171c04 48#include "loop-util.h"
e594a3b1 49#include "main-func.h"
8a794850 50#include "mkdir.h"
53171c04 51#include "mkfs-util.h"
8a794850 52#include "mount-util.h"
5c08da58 53#include "mountpoint-util.h"
c0fad2d9 54#include "nulstr-util.h"
b456191d 55#include "openssl-util.h"
614b022c 56#include "parse-argument.h"
c3eaba2d 57#include "parse-helpers.h"
e594a3b1
LP
58#include "pretty-print.h"
59#include "proc-cmdline.h"
8a794850 60#include "process-util.h"
b9df3536 61#include "random-util.h"
170c9823 62#include "resize-fs.h"
95bfd3cd 63#include "rm-rf.h"
e594a3b1 64#include "sort-util.h"
e031166e 65#include "specifier.h"
e594a3b1 66#include "stdio-util.h"
889914ef 67#include "string-table.h"
e594a3b1
LP
68#include "string-util.h"
69#include "strv.h"
bf819d3a 70#include "sync-util.h"
e594a3b1 71#include "terminal-util.h"
e0e1f4f7
LP
72#include "tmpfile-util.h"
73#include "tpm2-pcr.h"
889914ef 74#include "tpm2-util.h"
8a794850 75#include "user-util.h"
e594a3b1
LP
76#include "utf8.h"
77
fb08381c 78/* If not configured otherwise use a minimal partition size of 10M */
b262cbe8 79#define DEFAULT_MIN_SIZE (10ULL*1024ULL*1024ULL)
fb08381c
LP
80
81/* Hard lower limit for new partition sizes */
b262cbe8 82#define HARD_MIN_SIZE 4096ULL
fb08381c 83
b456191d 84/* We know up front we're never going to put more than this in a verity sig partition. */
b262cbe8 85#define VERITY_SIG_SIZE (HARD_MIN_SIZE*4ULL)
b456191d 86
69e3234d 87/* libfdisk takes off slightly more than 1M of the disk size when creating a GPT disk label */
b262cbe8 88#define GPT_METADATA_SIZE (1044ULL*1024ULL)
170c9823
LP
89
90/* LUKS2 takes off 16M of the partition size with its metadata by default */
b262cbe8 91#define LUKS2_METADATA_SIZE (16ULL*1024ULL*1024ULL)
170c9823 92
48a09a8f
DDM
93/* To do LUKS2 offline encryption, we need to keep some extra free space at the end of the partition. */
94#define LUKS2_METADATA_KEEP_FREE (LUKS2_METADATA_SIZE*2ULL)
95
98e0456e
DDM
96/* LUKS2 volume key size. */
97#define VOLUME_KEY_SIZE (512ULL/8ULL)
98
93f125a6
DDM
99/* Use 4K as the default filesystem sector size because as long as the partitions are aligned to 4K, the
100 * filesystems will then also be compatible with sector sizes 512, 1024 and 2048. */
101#define DEFAULT_FILESYSTEM_SECTOR_SIZE 4096ULL
102
e57b7020
DDM
103#define APIVFS_TMP_DIRS_NULSTR "proc\0sys\0dev\0tmp\0run\0var/tmp\0"
104
e594a3b1
LP
105/* Note: When growing and placing new partitions we always align to 4K sector size. It's how newer hard disks
106 * are designed, and if everything is aligned to that performance is best. And for older hard disks with 512B
107 * sector size devices were generally assumed to have an even number of sectors, hence at the worst we'll
108 * waste 3K per partition, which is probably fine. */
109
110static enum {
111 EMPTY_REFUSE, /* refuse empty disks, never create a partition table */
112 EMPTY_ALLOW, /* allow empty disks, create partition table if necessary */
113 EMPTY_REQUIRE, /* require an empty disk, create a partition table */
114 EMPTY_FORCE, /* make disk empty, erase everything, create a partition table always */
a26f4a49 115 EMPTY_CREATE, /* create disk as loopback file, create a partition table always */
e594a3b1
LP
116} arg_empty = EMPTY_REFUSE;
117
53538e33 118typedef enum FilterPartitionType {
81d1098b
DDM
119 FILTER_PARTITIONS_NONE,
120 FILTER_PARTITIONS_EXCLUDE,
121 FILTER_PARTITIONS_INCLUDE,
122 _FILTER_PARTITIONS_MAX,
123 _FILTER_PARTITIONS_INVALID = -EINVAL,
124} FilterPartitionsType;
125
e594a3b1
LP
126static bool arg_dry_run = true;
127static const char *arg_node = NULL;
128static char *arg_root = NULL;
252d6267 129static char *arg_image = NULL;
224c853f 130static char **arg_definitions = NULL;
e594a3b1
LP
131static bool arg_discard = true;
132static bool arg_can_factory_reset = false;
133static int arg_factory_reset = -1;
134static sd_id128_t arg_seed = SD_ID128_NULL;
135static bool arg_randomize = false;
136static int arg_pretty = -1;
a26f4a49 137static uint64_t arg_size = UINT64_MAX;
170c9823 138static bool arg_size_auto = false;
6a01ea4a 139static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
896e678b
LP
140static PagerFlags arg_pager_flags = 0;
141static bool arg_legend = true;
b9df3536
LP
142static void *arg_key = NULL;
143static size_t arg_key_size = 0;
b456191d
DDM
144static EVP_PKEY *arg_private_key = NULL;
145static X509 *arg_certificate = NULL;
889914ef 146static char *arg_tpm2_device = NULL;
9e437994
DS
147static Tpm2PCRValue *arg_tpm2_hash_pcr_values = NULL;
148static size_t arg_tpm2_n_hash_pcr_values = 0;
149static bool arg_tpm2_hash_pcr_values_use_default = true;
02ef97cd 150static char *arg_tpm2_public_key = NULL;
9e437994
DS
151static uint32_t arg_tpm2_public_key_pcr_mask = 0;
152static bool arg_tpm2_public_key_pcr_mask_use_default = true;
4cee8333 153static bool arg_split = false;
9786dfe6 154static GptPartitionType *arg_filter_partitions = NULL;
d989dd76 155static size_t arg_n_filter_partitions = 0;
81d1098b 156static FilterPartitionsType arg_filter_partitions_type = FILTER_PARTITIONS_NONE;
9786dfe6 157static GptPartitionType *arg_defer_partitions = NULL;
8275334b 158static size_t arg_n_defer_partitions = 0;
e1878ef7 159static uint64_t arg_sector_size = 0;
84be0c71 160static ImagePolicy *arg_image_policy = NULL;
9786dfe6 161static Architecture arg_architecture = _ARCHITECTURE_INVALID;
fc10b158 162static int arg_offline = -1;
e1536d1f 163static char **arg_copy_from = NULL;
e594a3b1
LP
164
165STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
252d6267 166STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
224c853f 167STATIC_DESTRUCTOR_REGISTER(arg_definitions, strv_freep);
b9df3536 168STATIC_DESTRUCTOR_REGISTER(arg_key, erase_and_freep);
b456191d
DDM
169STATIC_DESTRUCTOR_REGISTER(arg_private_key, EVP_PKEY_freep);
170STATIC_DESTRUCTOR_REGISTER(arg_certificate, X509_freep);
889914ef 171STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
9e437994 172STATIC_DESTRUCTOR_REGISTER(arg_tpm2_hash_pcr_values, freep);
02ef97cd 173STATIC_DESTRUCTOR_REGISTER(arg_tpm2_public_key, freep);
81d1098b 174STATIC_DESTRUCTOR_REGISTER(arg_filter_partitions, freep);
84be0c71 175STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
e1536d1f 176STATIC_DESTRUCTOR_REGISTER(arg_copy_from, strv_freep);
e594a3b1 177
e594a3b1 178typedef struct FreeArea FreeArea;
e594a3b1 179
889914ef
LP
180typedef enum EncryptMode {
181 ENCRYPT_OFF,
182 ENCRYPT_KEY_FILE,
183 ENCRYPT_TPM2,
184 ENCRYPT_KEY_FILE_TPM2,
185 _ENCRYPT_MODE_MAX,
2d93c20e 186 _ENCRYPT_MODE_INVALID = -EINVAL,
889914ef
LP
187} EncryptMode;
188
b5b7879a
DDM
189typedef enum VerityMode {
190 VERITY_OFF,
191 VERITY_DATA,
192 VERITY_HASH,
b456191d 193 VERITY_SIG,
b5b7879a
DDM
194 _VERITY_MODE_MAX,
195 _VERITY_MODE_INVALID = -EINVAL,
196} VerityMode;
197
5c33b686
DDM
198typedef enum MinimizeMode {
199 MINIMIZE_OFF,
200 MINIMIZE_BEST,
201 MINIMIZE_GUESS,
202 _MINIMIZE_MODE_MAX,
203 _MINIMIZE_MODE_INVALID = -EINVAL,
204} MinimizeMode;
205
448cfb7f 206typedef struct Partition {
e594a3b1 207 char *definition_path;
39fc0174 208 char **drop_in_files;
e594a3b1 209
22e932f4 210 GptPartitionType type;
e594a3b1 211 sd_id128_t current_uuid, new_uuid;
11749b61 212 bool new_uuid_is_set;
e594a3b1 213 char *current_label, *new_label;
81e04781
VH
214 sd_id128_t fs_uuid, luks_uuid, verity_uuid;
215 uint8_t verity_salt[SHA256_DIGEST_SIZE];
e594a3b1
LP
216
217 bool dropped;
218 bool factory_reset;
219 int32_t priority;
220
221 uint32_t weight, padding_weight;
222
223 uint64_t current_size, new_size;
224 uint64_t size_min, size_max;
225
226 uint64_t current_padding, new_padding;
227 uint64_t padding_min, padding_max;
228
229 uint64_t partno;
230 uint64_t offset;
231
232 struct fdisk_partition *current_partition;
233 struct fdisk_partition *new_partition;
234 FreeArea *padding_area;
235 FreeArea *allocated_to_area;
236
757bc2e4 237 char *copy_blocks_path;
7d07030e 238 bool copy_blocks_path_is_our_file;
5c08da58 239 bool copy_blocks_auto;
585c5c75 240 const char *copy_blocks_root;
757bc2e4 241 int copy_blocks_fd;
1e46985a 242 uint64_t copy_blocks_offset;
757bc2e4
LP
243 uint64_t copy_blocks_size;
244
53171c04 245 char *format;
8a794850 246 char **copy_files;
600bf76c
DDM
247 char **exclude_files_source;
248 char **exclude_files_target;
d83d8048 249 char **make_directories;
440f805c 250 char **subvolumes;
889914ef 251 EncryptMode encrypt;
b5b7879a
DDM
252 VerityMode verity;
253 char *verity_match_key;
5c33b686 254 MinimizeMode minimize;
c380047b
MC
255 uint64_t verity_data_block_size;
256 uint64_t verity_hash_block_size;
53171c04 257
e73309c5 258 uint64_t gpt_flags;
ff0771bf 259 int no_auto;
e73309c5 260 int read_only;
1c41c1dc 261 int growfs;
e73309c5 262
b5b7879a
DDM
263 uint8_t *roothash;
264 size_t roothash_size;
265
4cee8333 266 char *split_name_format;
62108348 267 char *split_path;
4cee8333 268
448cfb7f 269 struct Partition *siblings[_VERITY_MODE_MAX];
b5b7879a 270
448cfb7f
DDM
271 LIST_FIELDS(struct Partition, partitions);
272} Partition;
e594a3b1
LP
273
274#define PARTITION_IS_FOREIGN(p) (!(p)->definition_path)
275#define PARTITION_EXISTS(p) (!!(p)->current_partition)
276
277struct FreeArea {
278 Partition *after;
279 uint64_t size;
280 uint64_t allocated;
281};
282
448cfb7f 283typedef struct Context {
e594a3b1
LP
284 LIST_HEAD(Partition, partitions);
285 size_t n_partitions;
286
287 FreeArea **free_areas;
319a4f4b 288 size_t n_free_areas;
e594a3b1
LP
289
290 uint64_t start, end, total;
291
292 struct fdisk_context *fdisk_context;
93f125a6 293 uint64_t sector_size, grain_size, fs_sector_size;
e594a3b1
LP
294
295 sd_id128_t seed;
cc751c75
DDM
296
297 char *node;
db1d4e6b 298 bool node_is_our_file;
cc751c75
DDM
299 int backing_fd;
300
301 bool from_scratch;
448cfb7f 302} Context;
e594a3b1 303
889914ef
LP
304static const char *encrypt_mode_table[_ENCRYPT_MODE_MAX] = {
305 [ENCRYPT_OFF] = "off",
306 [ENCRYPT_KEY_FILE] = "key-file",
307 [ENCRYPT_TPM2] = "tpm2",
308 [ENCRYPT_KEY_FILE_TPM2] = "key-file+tpm2",
309};
310
b5b7879a
DDM
311static const char *verity_mode_table[_VERITY_MODE_MAX] = {
312 [VERITY_OFF] = "off",
313 [VERITY_DATA] = "data",
314 [VERITY_HASH] = "hash",
b456191d 315 [VERITY_SIG] = "signature",
b5b7879a
DDM
316};
317
5c33b686
DDM
318static const char *minimize_mode_table[_MINIMIZE_MODE_MAX] = {
319 [MINIMIZE_OFF] = "off",
320 [MINIMIZE_BEST] = "best",
321 [MINIMIZE_GUESS] = "guess",
322};
323
2709d029 324DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(encrypt_mode, EncryptMode, ENCRYPT_KEY_FILE);
86bebe38 325DEFINE_PRIVATE_STRING_TABLE_LOOKUP(verity_mode, VerityMode);
5c33b686 326DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(minimize_mode, MinimizeMode, MINIMIZE_BEST);
889914ef 327
e594a3b1
LP
328static uint64_t round_down_size(uint64_t v, uint64_t p) {
329 return (v / p) * p;
330}
331
332static uint64_t round_up_size(uint64_t v, uint64_t p) {
333
334 v = DIV_ROUND_UP(v, p);
335
336 if (v > UINT64_MAX / p)
337 return UINT64_MAX; /* overflow */
338
339 return v * p;
340}
341
342static Partition *partition_new(void) {
343 Partition *p;
344
345 p = new(Partition, 1);
346 if (!p)
347 return NULL;
348
349 *p = (Partition) {
350 .weight = 1000,
351 .padding_weight = 0,
352 .current_size = UINT64_MAX,
353 .new_size = UINT64_MAX,
354 .size_min = UINT64_MAX,
355 .size_max = UINT64_MAX,
356 .current_padding = UINT64_MAX,
357 .new_padding = UINT64_MAX,
358 .padding_min = UINT64_MAX,
359 .padding_max = UINT64_MAX,
360 .partno = UINT64_MAX,
361 .offset = UINT64_MAX,
254d1313 362 .copy_blocks_fd = -EBADF,
1e46985a 363 .copy_blocks_offset = UINT64_MAX,
757bc2e4 364 .copy_blocks_size = UINT64_MAX,
ff0771bf 365 .no_auto = -1,
e73309c5 366 .read_only = -1,
1c41c1dc 367 .growfs = -1,
c380047b
MC
368 .verity_data_block_size = UINT64_MAX,
369 .verity_hash_block_size = UINT64_MAX,
e594a3b1
LP
370 };
371
372 return p;
373}
374
375static Partition* partition_free(Partition *p) {
376 if (!p)
377 return NULL;
378
379 free(p->current_label);
380 free(p->new_label);
381 free(p->definition_path);
39fc0174 382 strv_free(p->drop_in_files);
e594a3b1
LP
383
384 if (p->current_partition)
385 fdisk_unref_partition(p->current_partition);
386 if (p->new_partition)
387 fdisk_unref_partition(p->new_partition);
388
7d07030e
DDM
389 if (p->copy_blocks_path_is_our_file)
390 unlink_and_free(p->copy_blocks_path);
391 else
392 free(p->copy_blocks_path);
757bc2e4
LP
393 safe_close(p->copy_blocks_fd);
394
53171c04 395 free(p->format);
8a794850 396 strv_free(p->copy_files);
600bf76c
DDM
397 strv_free(p->exclude_files_source);
398 strv_free(p->exclude_files_target);
d83d8048 399 strv_free(p->make_directories);
440f805c 400 strv_free(p->subvolumes);
b5b7879a
DDM
401 free(p->verity_match_key);
402
403 free(p->roothash);
53171c04 404
4cee8333 405 free(p->split_name_format);
a2d7c42e 406 unlink_and_free(p->split_path);
4cee8333 407
e594a3b1
LP
408 return mfree(p);
409}
410
9ccceb9d
YW
411static void partition_foreignize(Partition *p) {
412 assert(p);
413 assert(PARTITION_EXISTS(p));
414
415 /* Reset several parameters set through definition file to make the partition foreign. */
416
9ccceb9d
YW
417 p->definition_path = mfree(p->definition_path);
418 p->drop_in_files = strv_free(p->drop_in_files);
419
420 p->copy_blocks_path = mfree(p->copy_blocks_path);
421 p->copy_blocks_fd = safe_close(p->copy_blocks_fd);
585c5c75 422 p->copy_blocks_root = NULL;
9ccceb9d
YW
423
424 p->format = mfree(p->format);
425 p->copy_files = strv_free(p->copy_files);
600bf76c
DDM
426 p->exclude_files_source = strv_free(p->exclude_files_source);
427 p->exclude_files_target = strv_free(p->exclude_files_target);
9ccceb9d 428 p->make_directories = strv_free(p->make_directories);
440f805c 429 p->subvolumes = strv_free(p->subvolumes);
9ccceb9d
YW
430 p->verity_match_key = mfree(p->verity_match_key);
431
9ccceb9d
YW
432 p->priority = 0;
433 p->weight = 1000;
434 p->padding_weight = 0;
435 p->size_min = UINT64_MAX;
436 p->size_max = UINT64_MAX;
437 p->padding_min = UINT64_MAX;
438 p->padding_max = UINT64_MAX;
439 p->no_auto = -1;
440 p->read_only = -1;
441 p->growfs = -1;
442 p->verity = VERITY_OFF;
443}
444
c74d50ff 445static bool partition_type_exclude(const GptPartitionType *type) {
81d1098b
DDM
446 if (arg_filter_partitions_type == FILTER_PARTITIONS_NONE)
447 return false;
448
d989dd76 449 for (size_t i = 0; i < arg_n_filter_partitions; i++)
c74d50ff 450 if (sd_id128_equal(type->uuid, arg_filter_partitions[i].uuid))
81d1098b
DDM
451 return arg_filter_partitions_type == FILTER_PARTITIONS_EXCLUDE;
452
453 return arg_filter_partitions_type == FILTER_PARTITIONS_INCLUDE;
454}
455
c74d50ff 456static bool partition_type_defer(const GptPartitionType *type) {
8275334b 457 for (size_t i = 0; i < arg_n_defer_partitions; i++)
c74d50ff 458 if (sd_id128_equal(type->uuid, arg_defer_partitions[i].uuid))
7d505753
DDM
459 return true;
460
461 return false;
462}
463
e594a3b1
LP
464static Partition* partition_unlink_and_free(Context *context, Partition *p) {
465 if (!p)
466 return NULL;
467
468 LIST_REMOVE(partitions, context->partitions, p);
469
470 assert(context->n_partitions > 0);
471 context->n_partitions--;
472
473 return partition_free(p);
474}
475
476DEFINE_TRIVIAL_CLEANUP_FUNC(Partition*, partition_free);
477
478static Context *context_new(sd_id128_t seed) {
479 Context *context;
480
481 context = new(Context, 1);
482 if (!context)
483 return NULL;
484
485 *context = (Context) {
486 .start = UINT64_MAX,
487 .end = UINT64_MAX,
488 .total = UINT64_MAX,
489 .seed = seed,
490 };
491
492 return context;
493}
494
495static void context_free_free_areas(Context *context) {
496 assert(context);
497
498 for (size_t i = 0; i < context->n_free_areas; i++)
499 free(context->free_areas[i]);
500
501 context->free_areas = mfree(context->free_areas);
502 context->n_free_areas = 0;
e594a3b1
LP
503}
504
505static Context *context_free(Context *context) {
506 if (!context)
507 return NULL;
508
509 while (context->partitions)
510 partition_unlink_and_free(context, context->partitions);
511 assert(context->n_partitions == 0);
512
513 context_free_free_areas(context);
514
515 if (context->fdisk_context)
516 fdisk_unref_context(context->fdisk_context);
517
cc751c75 518 safe_close(context->backing_fd);
db1d4e6b
DDM
519 if (context->node_is_our_file)
520 unlink_and_free(context->node);
521 else
522 free(context->node);
cc751c75 523
e594a3b1
LP
524 return mfree(context);
525}
526
527DEFINE_TRIVIAL_CLEANUP_FUNC(Context*, context_free);
528
529static int context_add_free_area(
530 Context *context,
531 uint64_t size,
532 Partition *after) {
533
534 FreeArea *a;
535
536 assert(context);
537 assert(!after || !after->padding_area);
538
319a4f4b 539 if (!GREEDY_REALLOC(context->free_areas, context->n_free_areas + 1))
e594a3b1
LP
540 return -ENOMEM;
541
542 a = new(FreeArea, 1);
543 if (!a)
544 return -ENOMEM;
545
546 *a = (FreeArea) {
547 .size = size,
548 .after = after,
549 };
550
551 context->free_areas[context->n_free_areas++] = a;
552
553 if (after)
554 after->padding_area = a;
555
556 return 0;
557}
558
9ccceb9d
YW
559static void partition_drop_or_foreignize(Partition *p) {
560 if (!p || p->dropped || PARTITION_IS_FOREIGN(p))
561 return;
562
563 if (PARTITION_EXISTS(p)) {
564 log_info("Can't grow existing partition %s of priority %" PRIi32 ", ignoring.",
565 strna(p->current_label ?: p->new_label), p->priority);
566
567 /* Handle the partition as foreign. Do not set dropped flag. */
568 partition_foreignize(p);
569 } else {
570 log_info("Can't fit partition %s of priority %" PRIi32 ", dropping.",
571 p->definition_path, p->priority);
572
573 p->dropped = true;
574 p->allocated_to_area = NULL;
575 }
576}
577
578static bool context_drop_or_foreignize_one_priority(Context *context) {
e594a3b1 579 int32_t priority = 0;
e594a3b1
LP
580
581 LIST_FOREACH(partitions, p, context->partitions) {
582 if (p->dropped)
583 continue;
e594a3b1 584
9ccceb9d 585 priority = MAX(priority, p->priority);
e594a3b1
LP
586 }
587
588 /* Refuse to drop partitions with 0 or negative priorities or partitions of priorities that have at
589 * least one existing priority */
9ccceb9d 590 if (priority <= 0)
e594a3b1
LP
591 return false;
592
593 LIST_FOREACH(partitions, p, context->partitions) {
594 if (p->priority < priority)
595 continue;
596
9ccceb9d 597 partition_drop_or_foreignize(p);
b5b7879a
DDM
598
599 /* We ensure that all verity sibling partitions have the same priority, so it's safe
600 * to drop all siblings here as well. */
601
9ccceb9d
YW
602 for (VerityMode mode = VERITY_OFF + 1; mode < _VERITY_MODE_MAX; mode++)
603 partition_drop_or_foreignize(p->siblings[mode]);
e594a3b1
LP
604 }
605
606 return true;
607}
608
a80701e6 609static uint64_t partition_min_size(const Context *context, const Partition *p) {
e594a3b1
LP
610 uint64_t sz;
611
994b3031
LP
612 assert(context);
613 assert(p);
614
e594a3b1
LP
615 /* Calculate the disk space we really need at minimum for this partition. If the partition already
616 * exists the current size is what we really need. If it doesn't exist yet refuse to allocate less
fb08381c
LP
617 * than 4K.
618 *
619 * DEFAULT_MIN_SIZE is the default SizeMin= we configure if nothing else is specified. */
e594a3b1
LP
620
621 if (PARTITION_IS_FOREIGN(p)) {
622 /* Don't allow changing size of partitions not managed by us */
623 assert(p->current_size != UINT64_MAX);
624 return p->current_size;
625 }
626
b456191d
DDM
627 if (p->verity == VERITY_SIG)
628 return VERITY_SIG_SIZE;
629
fb08381c 630 sz = p->current_size != UINT64_MAX ? p->current_size : HARD_MIN_SIZE;
757bc2e4 631
170c9823
LP
632 if (!PARTITION_EXISTS(p)) {
633 uint64_t d = 0;
634
889914ef 635 if (p->encrypt != ENCRYPT_OFF)
48a09a8f 636 d += round_up_size(LUKS2_METADATA_KEEP_FREE, context->grain_size);
170c9823
LP
637
638 if (p->copy_blocks_size != UINT64_MAX)
994b3031 639 d += round_up_size(p->copy_blocks_size, context->grain_size);
889914ef 640 else if (p->format || p->encrypt != ENCRYPT_OFF) {
170c9823
LP
641 uint64_t f;
642
643 /* If we shall synthesize a file system, take minimal fs size into account (assumed to be 4K if not known) */
994b3031
LP
644 f = p->format ? round_up_size(minimal_size_by_fs_name(p->format), context->grain_size) : UINT64_MAX;
645 d += f == UINT64_MAX ? context->grain_size : f;
170c9823
LP
646 }
647
648 if (d > sz)
649 sz = d;
650 }
757bc2e4 651
994b3031 652 return MAX(round_up_size(p->size_min != UINT64_MAX ? p->size_min : DEFAULT_MIN_SIZE, context->grain_size), sz);
e594a3b1
LP
653}
654
994b3031
LP
655static uint64_t partition_max_size(const Context *context, const Partition *p) {
656 uint64_t sm;
657
e594a3b1
LP
658 /* Calculate how large the partition may become at max. This is generally the configured maximum
659 * size, except when it already exists and is larger than that. In that case it's the existing size,
660 * since we never want to shrink partitions. */
661
994b3031
LP
662 assert(context);
663 assert(p);
664
e594a3b1
LP
665 if (PARTITION_IS_FOREIGN(p)) {
666 /* Don't allow changing size of partitions not managed by us */
667 assert(p->current_size != UINT64_MAX);
668 return p->current_size;
669 }
670
b456191d
DDM
671 if (p->verity == VERITY_SIG)
672 return VERITY_SIG_SIZE;
673
822d9b9a
YW
674 if (p->size_max == UINT64_MAX)
675 return UINT64_MAX;
676
994b3031
LP
677 sm = round_down_size(p->size_max, context->grain_size);
678
e594a3b1 679 if (p->current_size != UINT64_MAX)
b0fbf90b 680 sm = MAX(p->current_size, sm);
e594a3b1 681
b0fbf90b 682 return MAX(partition_min_size(context, p), sm);
e594a3b1
LP
683}
684
a801bb01
YW
685static uint64_t partition_min_padding(const Partition *p) {
686 assert(p);
687 return p->padding_min != UINT64_MAX ? p->padding_min : 0;
688}
689
690static uint64_t partition_max_padding(const Partition *p) {
691 assert(p);
692 return p->padding_max;
693}
694
994b3031 695static uint64_t partition_min_size_with_padding(Context *context, const Partition *p) {
e594a3b1
LP
696 uint64_t sz;
697
698 /* Calculate the disk space we need for this partition plus any free space coming after it. This
699 * takes user configured padding into account as well as any additional whitespace needed to align
700 * the next partition to 4K again. */
701
994b3031
LP
702 assert(context);
703 assert(p);
704
a801bb01 705 sz = partition_min_size(context, p) + partition_min_padding(p);
e594a3b1
LP
706
707 if (PARTITION_EXISTS(p)) {
708 /* If the partition wasn't aligned, add extra space so that any we might add will be aligned */
709 assert(p->offset != UINT64_MAX);
994b3031 710 return round_up_size(p->offset + sz, context->grain_size) - p->offset;
e594a3b1
LP
711 }
712
713 /* If this is a new partition we'll place it aligned, hence we just need to round up the required size here */
994b3031 714 return round_up_size(sz, context->grain_size);
e594a3b1
LP
715}
716
717static uint64_t free_area_available(const FreeArea *a) {
718 assert(a);
719
720 /* Determines how much of this free area is not allocated yet */
721
722 assert(a->size >= a->allocated);
723 return a->size - a->allocated;
724}
725
58b06ac1 726static uint64_t free_area_current_end(Context *context, const FreeArea *a) {
994b3031
LP
727 assert(context);
728 assert(a);
729
58b06ac1
YW
730 if (!a->after)
731 return free_area_available(a);
e594a3b1 732
58b06ac1
YW
733 assert(a->after->offset != UINT64_MAX);
734 assert(a->after->current_size != UINT64_MAX);
e594a3b1 735
58b06ac1
YW
736 /* Calculate where the free area ends, based on the offset of the partition preceding it. */
737 return round_up_size(a->after->offset + a->after->current_size, context->grain_size) + free_area_available(a);
738}
e594a3b1 739
58b06ac1
YW
740static uint64_t free_area_min_end(Context *context, const FreeArea *a) {
741 assert(context);
742 assert(a);
e594a3b1 743
58b06ac1
YW
744 if (!a->after)
745 return 0;
e594a3b1 746
58b06ac1
YW
747 assert(a->after->offset != UINT64_MAX);
748 assert(a->after->current_size != UINT64_MAX);
1052a114 749
58b06ac1
YW
750 /* Calculate where the partition would end when we give it as much as it needs. */
751 return round_up_size(a->after->offset + partition_min_size_with_padding(context, a->after), context->grain_size);
752}
753
754static uint64_t free_area_available_for_new_partitions(Context *context, const FreeArea *a) {
755 assert(context);
756 assert(a);
757
758 /* Similar to free_area_available(), but takes into account that the required size and padding of the
759 * preceding partition is honoured. */
e594a3b1 760
58b06ac1 761 return LESS_BY(free_area_current_end(context, a), free_area_min_end(context, a));
e594a3b1
LP
762}
763
994b3031
LP
764static int free_area_compare(FreeArea *const *a, FreeArea *const*b, Context *context) {
765 assert(context);
766
767 return CMP(free_area_available_for_new_partitions(context, *a),
768 free_area_available_for_new_partitions(context, *b));
e594a3b1
LP
769}
770
994b3031
LP
771static uint64_t charge_size(Context *context, uint64_t total, uint64_t amount) {
772 assert(context);
e594a3b1 773 /* Subtract the specified amount from total, rounding up to multiple of 4K if there's room */
184cf99a 774 assert(amount <= total);
994b3031 775 return LESS_BY(total, round_up_size(amount, context->grain_size));
e594a3b1
LP
776}
777
778static uint64_t charge_weight(uint64_t total, uint64_t amount) {
779 assert(amount <= total);
780 return total - amount;
781}
782
14a4c4ed 783static bool context_allocate_partitions(Context *context, uint64_t *ret_largest_free_area) {
e594a3b1
LP
784 assert(context);
785
f39cf264
YW
786 /* This may be called multiple times. Reset previous assignments. */
787 for (size_t i = 0; i < context->n_free_areas; i++)
788 context->free_areas[i]->allocated = 0;
789
14a4c4ed 790 /* Sort free areas by size, putting smallest first */
994b3031 791 typesafe_qsort_r(context->free_areas, context->n_free_areas, free_area_compare, context);
e594a3b1 792
14a4c4ed
LP
793 /* In any case return size of the largest free area (i.e. not the size of all free areas
794 * combined!) */
795 if (ret_largest_free_area)
796 *ret_largest_free_area =
797 context->n_free_areas == 0 ? 0 :
994b3031 798 free_area_available_for_new_partitions(context, context->free_areas[context->n_free_areas-1]);
14a4c4ed 799
cdbcc339
YW
800 /* Check that each existing partition can fit its area. */
801 for (size_t i = 0; i < context->n_free_areas; i++)
802 if (free_area_current_end(context, context->free_areas[i]) <
803 free_area_min_end(context, context->free_areas[i]))
804 return false;
805
14a4c4ed 806 /* A simple first-fit algorithm. We return true if we can fit the partitions in, otherwise false. */
e594a3b1
LP
807 LIST_FOREACH(partitions, p, context->partitions) {
808 bool fits = false;
809 uint64_t required;
810 FreeArea *a = NULL;
811
812 /* Skip partitions we already dropped or that already exist */
813 if (p->dropped || PARTITION_EXISTS(p))
814 continue;
815
e594a3b1 816 /* How much do we need to fit? */
994b3031
LP
817 required = partition_min_size_with_padding(context, p);
818 assert(required % context->grain_size == 0);
e594a3b1
LP
819
820 for (size_t i = 0; i < context->n_free_areas; i++) {
821 a = context->free_areas[i];
822
994b3031 823 if (free_area_available_for_new_partitions(context, a) >= required) {
e594a3b1
LP
824 fits = true;
825 break;
826 }
827 }
828
829 if (!fits)
830 return false; /* 😢 Oh no! We can't fit this partition into any free area! */
831
832 /* Assign the partition to this free area */
833 p->allocated_to_area = a;
834
835 /* Budget the minimal partition size */
836 a->allocated += required;
837 }
838
839 return true;
840}
841
842static int context_sum_weights(Context *context, FreeArea *a, uint64_t *ret) {
843 uint64_t weight_sum = 0;
e594a3b1
LP
844
845 assert(context);
846 assert(a);
847 assert(ret);
848
849 /* Determine the sum of the weights of all partitions placed in or before the specified free area */
850
851 LIST_FOREACH(partitions, p, context->partitions) {
852 if (p->padding_area != a && p->allocated_to_area != a)
853 continue;
854
855 if (p->weight > UINT64_MAX - weight_sum)
856 goto overflow_sum;
857 weight_sum += p->weight;
858
859 if (p->padding_weight > UINT64_MAX - weight_sum)
860 goto overflow_sum;
861 weight_sum += p->padding_weight;
862 }
863
864 *ret = weight_sum;
865 return 0;
866
867overflow_sum:
da890466 868 return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW), "Combined weight of partition exceeds unsigned 64-bit range, refusing.");
e594a3b1
LP
869}
870
0245e15a 871static uint64_t scale_by_weight(uint64_t value, uint64_t weight, uint64_t weight_sum) {
e594a3b1 872 assert(weight_sum >= weight);
e594a3b1 873
0245e15a
YW
874 for (;;) {
875 if (weight == 0)
876 return 0;
877 if (weight == weight_sum)
878 return value;
879 if (value <= UINT64_MAX / weight)
880 return value * weight / weight_sum;
881
882 /* Rescale weight and weight_sum to make not the calculation overflow. To satisfy the
883 * following conditions, 'weight_sum' is rounded up but 'weight' is rounded down:
884 * - the sum of scale_by_weight() for all weights must not be larger than the input value,
885 * - scale_by_weight() must not be larger than the ideal value (i.e. calculated with uint128_t). */
886 weight_sum = DIV_ROUND_UP(weight_sum, 2);
887 weight /= 2;
e594a3b1 888 }
e594a3b1
LP
889}
890
891typedef enum GrowPartitionPhase {
bf99aed6
YW
892 /* The zeroth phase: do not touch foreign partitions (i.e. those we don't manage). */
893 PHASE_FOREIGN,
894
e594a3b1
LP
895 /* The first phase: we charge partitions which need more (according to constraints) than their weight-based share. */
896 PHASE_OVERCHARGE,
897
898 /* The second phase: we charge partitions which need less (according to constraints) than their weight-based share. */
899 PHASE_UNDERCHARGE,
900
901 /* The third phase: we distribute what remains among the remaining partitions, according to the weights */
902 PHASE_DISTRIBUTE,
ae0613c6
LP
903
904 _GROW_PARTITION_PHASE_MAX,
e594a3b1
LP
905} GrowPartitionPhase;
906
0245e15a 907static bool context_grow_partitions_phase(
e594a3b1
LP
908 Context *context,
909 FreeArea *a,
910 GrowPartitionPhase phase,
911 uint64_t *span,
912 uint64_t *weight_sum) {
913
2a503ad2
YW
914 bool try_again = false;
915
e594a3b1
LP
916 assert(context);
917 assert(a);
0245e15a
YW
918 assert(span);
919 assert(weight_sum);
e594a3b1
LP
920
921 /* Now let's look at the intended weights and adjust them taking the minimum space assignments into
922 * account. i.e. if a partition has a small weight but a high minimum space value set it should not
923 * get any additional room from the left-overs. Similar, if two partitions have the same weight they
924 * should get the same space if possible, even if one has a smaller minimum size than the other. */
925 LIST_FOREACH(partitions, p, context->partitions) {
926
927 /* Look only at partitions associated with this free area, i.e. immediately
162392b7 928 * preceding it, or allocated into it */
e594a3b1
LP
929 if (p->allocated_to_area != a && p->padding_area != a)
930 continue;
931
932 if (p->new_size == UINT64_MAX) {
e594a3b1 933 uint64_t share, rsz, xsz;
2a503ad2 934 bool charge = false;
e594a3b1
LP
935
936 /* Calculate how much this space this partition needs if everyone would get
937 * the weight based share */
0245e15a 938 share = scale_by_weight(*span, p->weight, *weight_sum);
e594a3b1 939
994b3031
LP
940 rsz = partition_min_size(context, p);
941 xsz = partition_max_size(context, p);
e594a3b1 942
bf99aed6
YW
943 if (phase == PHASE_FOREIGN && PARTITION_IS_FOREIGN(p)) {
944 /* Never change of foreign partitions (i.e. those we don't manage) */
945
946 p->new_size = p->current_size;
947 charge = true;
948
949 } else if (phase == PHASE_OVERCHARGE && rsz > share) {
e594a3b1
LP
950 /* This partition needs more than its calculated share. Let's assign
951 * it that, and take this partition out of all calculations and start
952 * again. */
953
954 p->new_size = rsz;
955 charge = try_again = true;
956
822d9b9a 957 } else if (phase == PHASE_UNDERCHARGE && xsz < share) {
e594a3b1
LP
958 /* This partition accepts less than its calculated
959 * share. Let's assign it that, and take this partition out
960 * of all calculations and start again. */
961
962 p->new_size = xsz;
963 charge = try_again = true;
964
965 } else if (phase == PHASE_DISTRIBUTE) {
966 /* This partition can accept its calculated share. Let's
967 * assign it. There's no need to restart things here since
968 * assigning this shouldn't impact the shares of the other
969 * partitions. */
970
d7c46b5e
YW
971 assert(share >= rsz);
972 p->new_size = CLAMP(round_down_size(share, context->grain_size), rsz, xsz);
e594a3b1
LP
973 charge = true;
974 }
975
976 if (charge) {
994b3031 977 *span = charge_size(context, *span, p->new_size);
e594a3b1
LP
978 *weight_sum = charge_weight(*weight_sum, p->weight);
979 }
e594a3b1
LP
980 }
981
982 if (p->new_padding == UINT64_MAX) {
a801bb01 983 uint64_t share, rsz, xsz;
2a503ad2 984 bool charge = false;
e594a3b1 985
0245e15a 986 share = scale_by_weight(*span, p->padding_weight, *weight_sum);
e594a3b1 987
a801bb01
YW
988 rsz = partition_min_padding(p);
989 xsz = partition_max_padding(p);
990
991 if (phase == PHASE_OVERCHARGE && rsz > share) {
992 p->new_padding = rsz;
e594a3b1 993 charge = try_again = true;
a801bb01
YW
994 } else if (phase == PHASE_UNDERCHARGE && xsz < share) {
995 p->new_padding = xsz;
e594a3b1
LP
996 charge = try_again = true;
997 } else if (phase == PHASE_DISTRIBUTE) {
d7c46b5e
YW
998 assert(share >= rsz);
999 p->new_padding = CLAMP(round_down_size(share, context->grain_size), rsz, xsz);
e594a3b1
LP
1000 charge = true;
1001 }
1002
1003 if (charge) {
994b3031 1004 *span = charge_size(context, *span, p->new_padding);
e594a3b1
LP
1005 *weight_sum = charge_weight(*weight_sum, p->padding_weight);
1006 }
e594a3b1
LP
1007 }
1008 }
1009
2a503ad2 1010 return !try_again;
e594a3b1
LP
1011}
1012
19903a43
YW
1013static void context_grow_partition_one(Context *context, FreeArea *a, Partition *p, uint64_t *span) {
1014 uint64_t m;
1015
1016 assert(context);
1017 assert(a);
1018 assert(p);
1019 assert(span);
1020
1021 if (*span == 0)
1022 return;
1023
1024 if (p->allocated_to_area != a)
1025 return;
1026
1027 if (PARTITION_IS_FOREIGN(p))
1028 return;
1029
1030 assert(p->new_size != UINT64_MAX);
1031
1032 /* Calculate new size and align. */
1033 m = round_down_size(p->new_size + *span, context->grain_size);
1034 /* But ensure this doesn't shrink the size. */
1035 m = MAX(m, p->new_size);
1036 /* And ensure this doesn't exceed the maximum size. */
1037 m = MIN(m, partition_max_size(context, p));
1038
1039 assert(m >= p->new_size);
1040
1041 *span = charge_size(context, *span, m - p->new_size);
1042 p->new_size = m;
1043}
1044
e594a3b1
LP
1045static int context_grow_partitions_on_free_area(Context *context, FreeArea *a) {
1046 uint64_t weight_sum = 0, span;
1047 int r;
1048
1049 assert(context);
1050 assert(a);
1051
1052 r = context_sum_weights(context, a, &weight_sum);
1053 if (r < 0)
1054 return r;
1055
1056 /* Let's calculate the total area covered by this free area and the partition before it */
1057 span = a->size;
1058 if (a->after) {
1059 assert(a->after->offset != UINT64_MAX);
1060 assert(a->after->current_size != UINT64_MAX);
1061
994b3031 1062 span += round_up_size(a->after->offset + a->after->current_size, context->grain_size) - a->after->offset;
e594a3b1
LP
1063 }
1064
0245e15a
YW
1065 for (GrowPartitionPhase phase = 0; phase < _GROW_PARTITION_PHASE_MAX;)
1066 if (context_grow_partitions_phase(context, a, phase, &span, &weight_sum))
1067 phase++; /* go to the next phase */
e594a3b1 1068
162392b7 1069 /* We still have space left over? Donate to preceding partition if we have one */
19903a43
YW
1070 if (span > 0 && a->after)
1071 context_grow_partition_one(context, a, a->after, &span);
e594a3b1 1072
162392b7 1073 /* What? Even still some space left (maybe because there was no preceding partition, or it had a
e594a3b1 1074 * size limit), then let's donate it to whoever wants it. */
03677889 1075 if (span > 0)
e594a3b1 1076 LIST_FOREACH(partitions, p, context->partitions) {
19903a43 1077 context_grow_partition_one(context, a, p, &span);
e594a3b1
LP
1078 if (span == 0)
1079 break;
1080 }
e594a3b1 1081
162392b7 1082 /* Yuck, still no one? Then make it padding */
e594a3b1
LP
1083 if (span > 0 && a->after) {
1084 assert(a->after->new_padding != UINT64_MAX);
1085 a->after->new_padding += span;
1086 }
1087
1088 return 0;
1089}
1090
1091static int context_grow_partitions(Context *context) {
e594a3b1
LP
1092 int r;
1093
1094 assert(context);
1095
1096 for (size_t i = 0; i < context->n_free_areas; i++) {
1097 r = context_grow_partitions_on_free_area(context, context->free_areas[i]);
1098 if (r < 0)
1099 return r;
1100 }
1101
1102 /* All existing partitions that have no free space after them can't change size */
1103 LIST_FOREACH(partitions, p, context->partitions) {
1104 if (p->dropped)
1105 continue;
1106
1107 if (!PARTITION_EXISTS(p) || p->padding_area) {
1108 /* The algorithm above must have initialized this already */
1109 assert(p->new_size != UINT64_MAX);
1110 continue;
1111 }
1112
1113 assert(p->new_size == UINT64_MAX);
1114 p->new_size = p->current_size;
1115
1116 assert(p->new_padding == UINT64_MAX);
1117 p->new_padding = p->current_padding;
1118 }
1119
1120 return 0;
1121}
1122
00428745 1123static uint64_t find_first_unused_partno(Context *context) {
e594a3b1 1124 uint64_t partno = 0;
e594a3b1
LP
1125
1126 assert(context);
1127
5f59807d
DDM
1128 for (partno = 0;; partno++) {
1129 bool found = false;
1130 LIST_FOREACH(partitions, p, context->partitions)
1131 if (p->partno != UINT64_MAX && p->partno == partno)
1132 found = true;
1133 if (!found)
1134 break;
e594a3b1
LP
1135 }
1136
00428745
DDM
1137 return partno;
1138}
1139
1140static void context_place_partitions(Context *context) {
1141
1142 assert(context);
1143
e594a3b1
LP
1144 for (size_t i = 0; i < context->n_free_areas; i++) {
1145 FreeArea *a = context->free_areas[i];
2ea7eb00
FS
1146 _unused_ uint64_t left;
1147 uint64_t start;
e594a3b1
LP
1148
1149 if (a->after) {
1150 assert(a->after->offset != UINT64_MAX);
1151 assert(a->after->new_size != UINT64_MAX);
1152 assert(a->after->new_padding != UINT64_MAX);
1153
1154 start = a->after->offset + a->after->new_size + a->after->new_padding;
1155 } else
1156 start = context->start;
1157
994b3031 1158 start = round_up_size(start, context->grain_size);
e594a3b1
LP
1159 left = a->size;
1160
1161 LIST_FOREACH(partitions, p, context->partitions) {
1162 if (p->allocated_to_area != a)
1163 continue;
1164
1165 p->offset = start;
00428745 1166 p->partno = find_first_unused_partno(context);
e594a3b1
LP
1167
1168 assert(left >= p->new_size);
1169 start += p->new_size;
1170 left -= p->new_size;
1171
1172 assert(left >= p->new_padding);
1173 start += p->new_padding;
1174 left -= p->new_padding;
1175 }
1176 }
1177}
1178
e594a3b1
LP
1179static int config_parse_type(
1180 const char *unit,
1181 const char *filename,
1182 unsigned line,
1183 const char *section,
1184 unsigned section_line,
1185 const char *lvalue,
1186 int ltype,
1187 const char *rvalue,
1188 void *data,
1189 void *userdata) {
1190
22e932f4 1191 GptPartitionType *type = ASSERT_PTR(data);
e594a3b1
LP
1192 int r;
1193
1194 assert(rvalue);
e594a3b1 1195
22e932f4 1196 r = gpt_partition_type_from_string(rvalue, type);
e594a3b1
LP
1197 if (r < 0)
1198 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse partition type: %s", rvalue);
1199
9786dfe6
DDM
1200 if (arg_architecture >= 0)
1201 *type = gpt_partition_type_override_architecture(*type, arg_architecture);
1202
e594a3b1
LP
1203 return 0;
1204}
1205
1206static int config_parse_label(
1207 const char *unit,
1208 const char *filename,
1209 unsigned line,
1210 const char *section,
1211 unsigned section_line,
1212 const char *lvalue,
1213 int ltype,
1214 const char *rvalue,
1215 void *data,
1216 void *userdata) {
1217
e031166e 1218 _cleanup_free_ char *resolved = NULL;
99534007 1219 char **label = ASSERT_PTR(data);
e594a3b1
LP
1220 int r;
1221
1222 assert(rvalue);
e594a3b1 1223
be9ce018
LP
1224 /* Nota bene: the empty label is a totally valid one. Let's hence not follow our usual rule of
1225 * assigning the empty string to reset to default here, but really accept it as label to set. */
1226
de61a04b 1227 r = specifier_printf(rvalue, GPT_LABEL_MAX, system_and_tmp_specifier_table, arg_root, NULL, &resolved);
e031166e 1228 if (r < 0) {
e459258f 1229 log_syntax(unit, LOG_WARNING, filename, line, r,
e031166e
LP
1230 "Failed to expand specifiers in Label=, ignoring: %s", rvalue);
1231 return 0;
1232 }
1233
1234 if (!utf8_is_valid(resolved)) {
e594a3b1
LP
1235 log_syntax(unit, LOG_WARNING, filename, line, 0,
1236 "Partition label not valid UTF-8, ignoring: %s", rvalue);
1237 return 0;
1238 }
1239
22a0a36e
LP
1240 r = gpt_partition_label_valid(resolved);
1241 if (r < 0) {
1242 log_syntax(unit, LOG_WARNING, filename, line, r,
1243 "Failed to check if string is valid as GPT partition label, ignoring: \"%s\" (from \"%s\")",
1244 resolved, rvalue);
1245 return 0;
1246 }
1247 if (!r) {
e594a3b1 1248 log_syntax(unit, LOG_WARNING, filename, line, 0,
46072ae3
ZJS
1249 "Partition label too long for GPT table, ignoring: \"%s\" (from \"%s\")",
1250 resolved, rvalue);
e594a3b1
LP
1251 return 0;
1252 }
1253
e031166e 1254 free_and_replace(*label, resolved);
e594a3b1
LP
1255 return 0;
1256}
1257
1258static int config_parse_weight(
1259 const char *unit,
1260 const char *filename,
1261 unsigned line,
1262 const char *section,
1263 unsigned section_line,
1264 const char *lvalue,
1265 int ltype,
1266 const char *rvalue,
1267 void *data,
1268 void *userdata) {
1269
f126038f 1270 uint32_t *w = ASSERT_PTR(data), v;
e594a3b1
LP
1271 int r;
1272
1273 assert(rvalue);
e594a3b1
LP
1274
1275 r = safe_atou32(rvalue, &v);
1276 if (r < 0) {
1277 log_syntax(unit, LOG_WARNING, filename, line, r,
1278 "Failed to parse weight value, ignoring: %s", rvalue);
1279 return 0;
1280 }
1281
1282 if (v > 1000U*1000U) {
c8f3d767 1283 log_syntax(unit, LOG_WARNING, filename, line, 0,
e594a3b1
LP
1284 "Weight needs to be in range 0…10000000, ignoring: %" PRIu32, v);
1285 return 0;
1286 }
1287
f126038f 1288 *w = v;
e594a3b1
LP
1289 return 0;
1290}
1291
1292static int config_parse_size4096(
1293 const char *unit,
1294 const char *filename,
1295 unsigned line,
1296 const char *section,
1297 unsigned section_line,
1298 const char *lvalue,
1299 int ltype,
1300 const char *rvalue,
1301 void *data,
1302 void *userdata) {
1303
1304 uint64_t *sz = data, parsed;
1305 int r;
1306
1307 assert(rvalue);
1308 assert(data);
1309
1310 r = parse_size(rvalue, 1024, &parsed);
1311 if (r < 0)
c8f3d767 1312 return log_syntax(unit, LOG_ERR, filename, line, r,
e594a3b1
LP
1313 "Failed to parse size value: %s", rvalue);
1314
1315 if (ltype > 0)
1316 *sz = round_up_size(parsed, 4096);
1317 else if (ltype < 0)
1318 *sz = round_down_size(parsed, 4096);
1319 else
1320 *sz = parsed;
1321
1322 if (*sz != parsed)
e2341b6b
DT
1323 log_syntax(unit, LOG_NOTICE, filename, line, r, "Rounded %s= size %" PRIu64 " %s %" PRIu64 ", a multiple of 4096.",
1324 lvalue, parsed, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), *sz);
e594a3b1
LP
1325
1326 return 0;
1327}
1328
c380047b
MC
1329static int config_parse_block_size(
1330 const char *unit,
1331 const char *filename,
1332 unsigned line,
1333 const char *section,
1334 unsigned section_line,
1335 const char *lvalue,
1336 int ltype,
1337 const char *rvalue,
1338 void *data,
1339 void *userdata) {
1340
1341 uint64_t *blksz = ASSERT_PTR(data), parsed;
1342 int r;
1343
1344 assert(rvalue);
1345
1346 r = parse_size(rvalue, 1024, &parsed);
1347 if (r < 0)
1348 return log_syntax(unit, LOG_ERR, filename, line, r,
1349 "Failed to parse size value: %s", rvalue);
1350
1351 if (parsed < 512 || parsed > 4096)
1352 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
1353 "Value not between 512 and 4096: %s", rvalue);
1354
1355 if (!ISPOWEROF2(parsed))
1356 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
1357 "Value not a power of 2: %s", rvalue);
1358
1359 *blksz = parsed;
1360 return 0;
1361}
1362
53171c04
LP
1363static int config_parse_fstype(
1364 const char *unit,
1365 const char *filename,
1366 unsigned line,
1367 const char *section,
1368 unsigned section_line,
1369 const char *lvalue,
1370 int ltype,
1371 const char *rvalue,
1372 void *data,
1373 void *userdata) {
1374
99534007 1375 char **fstype = ASSERT_PTR(data);
53171c04
LP
1376
1377 assert(rvalue);
53171c04
LP
1378
1379 if (!filename_is_valid(rvalue))
1380 return log_syntax(unit, LOG_ERR, filename, line, 0,
1381 "File system type is not valid, refusing: %s", rvalue);
1382
1383 return free_and_strdup_warn(fstype, rvalue);
1384}
1385
8a794850
LP
1386static int config_parse_copy_files(
1387 const char *unit,
1388 const char *filename,
1389 unsigned line,
1390 const char *section,
1391 unsigned section_line,
1392 const char *lvalue,
1393 int ltype,
1394 const char *rvalue,
1395 void *data,
1396 void *userdata) {
1397
1398 _cleanup_free_ char *source = NULL, *buffer = NULL, *resolved_source = NULL, *resolved_target = NULL;
1399 const char *p = rvalue, *target;
de98e6a7 1400 char ***copy_files = ASSERT_PTR(data);
8a794850
LP
1401 int r;
1402
1403 assert(rvalue);
8a794850
LP
1404
1405 r = extract_first_word(&p, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_DONT_COALESCE_SEPARATORS);
1406 if (r < 0)
1407 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract source path: %s", rvalue);
1408 if (r == 0) {
1409 log_syntax(unit, LOG_WARNING, filename, line, 0, "No argument specified: %s", rvalue);
1410 return 0;
1411 }
1412
1413 r = extract_first_word(&p, &buffer, ":", EXTRACT_CUNESCAPE|EXTRACT_DONT_COALESCE_SEPARATORS);
1414 if (r < 0)
1415 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract target path: %s", rvalue);
1416 if (r == 0)
1417 target = source; /* No target, then it's the same as the source */
1418 else
1419 target = buffer;
1420
1421 if (!isempty(p))
1422 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "Too many arguments: %s", rvalue);
1423
de61a04b 1424 r = specifier_printf(source, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved_source);
8a794850
LP
1425 if (r < 0) {
1426 log_syntax(unit, LOG_WARNING, filename, line, r,
1427 "Failed to expand specifiers in CopyFiles= source, ignoring: %s", rvalue);
1428 return 0;
1429 }
1430
0ade2213
LP
1431 r = path_simplify_and_warn(resolved_source, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
1432 if (r < 0)
8a794850 1433 return 0;
8a794850 1434
de61a04b 1435 r = specifier_printf(target, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved_target);
8a794850
LP
1436 if (r < 0) {
1437 log_syntax(unit, LOG_WARNING, filename, line, r,
1438 "Failed to expand specifiers in CopyFiles= target, ignoring: %s", resolved_target);
1439 return 0;
1440 }
1441
0ade2213
LP
1442 r = path_simplify_and_warn(resolved_target, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
1443 if (r < 0)
8a794850 1444 return 0;
8a794850 1445
de98e6a7 1446 r = strv_consume_pair(copy_files, TAKE_PTR(resolved_source), TAKE_PTR(resolved_target));
8a794850
LP
1447 if (r < 0)
1448 return log_oom();
1449
1450 return 0;
1451}
1452
a9af8276
DDM
1453static int config_parse_exclude_files(
1454 const char *unit,
1455 const char *filename,
1456 unsigned line,
1457 const char *section,
1458 unsigned section_line,
1459 const char *lvalue,
1460 int ltype,
1461 const char *rvalue,
1462 void *data,
1463 void *userdata) {
1464 _cleanup_free_ char *resolved = NULL;
1465 char ***exclude_files = ASSERT_PTR(data);
1466 int r;
1467
1468 if (isempty(rvalue)) {
1469 *exclude_files = strv_free(*exclude_files);
1470 return 0;
1471 }
1472
1473 r = specifier_printf(rvalue, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved);
1474 if (r < 0) {
1475 log_syntax(unit, LOG_WARNING, filename, line, r,
1476 "Failed to expand specifiers in ExcludeFiles= path, ignoring: %s", rvalue);
1477 return 0;
1478 }
1479
d10eccbd 1480 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE|PATH_KEEP_TRAILING_SLASH, unit, filename, line, lvalue);
8a794850 1481 if (r < 0)
a9af8276
DDM
1482 return 0;
1483
1484 if (strv_consume(exclude_files, TAKE_PTR(resolved)) < 0)
8a794850
LP
1485 return log_oom();
1486
1487 return 0;
1488}
1489
5c08da58
LP
1490static int config_parse_copy_blocks(
1491 const char *unit,
1492 const char *filename,
1493 unsigned line,
1494 const char *section,
1495 unsigned section_line,
1496 const char *lvalue,
1497 int ltype,
1498 const char *rvalue,
1499 void *data,
1500 void *userdata) {
1501
1502 _cleanup_free_ char *d = NULL;
99534007 1503 Partition *partition = ASSERT_PTR(data);
5c08da58
LP
1504 int r;
1505
1506 assert(rvalue);
5c08da58
LP
1507
1508 if (isempty(rvalue)) {
1509 partition->copy_blocks_path = mfree(partition->copy_blocks_path);
1510 partition->copy_blocks_auto = false;
1511 return 0;
1512 }
1513
1514 if (streq(rvalue, "auto")) {
1515 partition->copy_blocks_path = mfree(partition->copy_blocks_path);
1516 partition->copy_blocks_auto = true;
585c5c75 1517 partition->copy_blocks_root = arg_root;
5c08da58
LP
1518 return 0;
1519 }
1520
de61a04b 1521 r = specifier_printf(rvalue, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &d);
5c08da58
LP
1522 if (r < 0) {
1523 log_syntax(unit, LOG_WARNING, filename, line, r,
1524 "Failed to expand specifiers in CopyBlocks= source path, ignoring: %s", rvalue);
1525 return 0;
1526 }
1527
1528 r = path_simplify_and_warn(d, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
1529 if (r < 0)
1530 return 0;
1531
1532 free_and_replace(partition->copy_blocks_path, d);
1533 partition->copy_blocks_auto = false;
585c5c75 1534 partition->copy_blocks_root = arg_root;
5c08da58
LP
1535 return 0;
1536}
1537
d83d8048
LP
1538static int config_parse_make_dirs(
1539 const char *unit,
1540 const char *filename,
1541 unsigned line,
1542 const char *section,
1543 unsigned section_line,
1544 const char *lvalue,
1545 int ltype,
1546 const char *rvalue,
1547 void *data,
1548 void *userdata) {
1549
440f805c 1550 char ***sv = ASSERT_PTR(data);
99534007 1551 const char *p = ASSERT_PTR(rvalue);
d83d8048
LP
1552 int r;
1553
d83d8048
LP
1554 for (;;) {
1555 _cleanup_free_ char *word = NULL, *d = NULL;
1556
1557 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
1558 if (r == -ENOMEM)
1559 return log_oom();
1560 if (r < 0) {
1561 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1562 return 0;
1563 }
1564 if (r == 0)
1565 return 0;
1566
de61a04b 1567 r = specifier_printf(word, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &d);
d83d8048
LP
1568 if (r < 0) {
1569 log_syntax(unit, LOG_WARNING, filename, line, r,
1570 "Failed to expand specifiers in MakeDirectories= parameter, ignoring: %s", word);
1571 continue;
1572 }
1573
1574 r = path_simplify_and_warn(d, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
1575 if (r < 0)
1576 continue;
1577
440f805c 1578 r = strv_consume(sv, TAKE_PTR(d));
d83d8048
LP
1579 if (r < 0)
1580 return log_oom();
1581 }
1582}
1583
889914ef
LP
1584static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_encrypt, encrypt_mode, EncryptMode, ENCRYPT_OFF, "Invalid encryption mode");
1585
e73309c5
LP
1586static int config_parse_gpt_flags(
1587 const char *unit,
1588 const char *filename,
1589 unsigned line,
1590 const char *section,
1591 unsigned section_line,
1592 const char *lvalue,
1593 int ltype,
1594 const char *rvalue,
1595 void *data,
1596 void *userdata) {
1597
99534007 1598 uint64_t *gpt_flags = ASSERT_PTR(data);
e73309c5
LP
1599 int r;
1600
1601 assert(rvalue);
e73309c5
LP
1602
1603 r = safe_atou64(rvalue, gpt_flags);
1604 if (r < 0) {
1605 log_syntax(unit, LOG_WARNING, filename, line, r,
1606 "Failed to parse Flags= value, ignoring: %s", rvalue);
1607 return 0;
1608 }
1609
1610 return 0;
1611}
1612
11749b61
DDM
1613static int config_parse_uuid(
1614 const char *unit,
1615 const char *filename,
1616 unsigned line,
1617 const char *section,
1618 unsigned section_line,
1619 const char *lvalue,
1620 int ltype,
1621 const char *rvalue,
1622 void *data,
1623 void *userdata) {
1624
1625 Partition *partition = ASSERT_PTR(data);
1626 int r;
1627
1628 if (isempty(rvalue)) {
1629 partition->new_uuid = SD_ID128_NULL;
1630 partition->new_uuid_is_set = false;
1631 return 0;
1632 }
1633
1634 if (streq(rvalue, "null")) {
1635 partition->new_uuid = SD_ID128_NULL;
1636 partition->new_uuid_is_set = true;
1637 return 0;
1638 }
1639
1640 r = sd_id128_from_string(rvalue, &partition->new_uuid);
1641 if (r < 0) {
da890466 1642 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse 128-bit ID/UUID, ignoring: %s", rvalue);
11749b61
DDM
1643 return 0;
1644 }
1645
1646 partition->new_uuid_is_set = true;
1647
1648 return 0;
1649}
1650
b5b7879a 1651static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_verity, verity_mode, VerityMode, VERITY_OFF, "Invalid verity mode");
5c33b686 1652static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_minimize, minimize_mode, MinimizeMode, MINIMIZE_OFF, "Invalid minimize mode");
b5b7879a 1653
39fc0174 1654static int partition_read_definition(Partition *p, const char *path, const char *const *conf_file_dirs) {
e594a3b1
LP
1655
1656 ConfigTableItem table[] = {
c380047b
MC
1657 { "Partition", "Type", config_parse_type, 0, &p->type },
1658 { "Partition", "Label", config_parse_label, 0, &p->new_label },
1659 { "Partition", "UUID", config_parse_uuid, 0, p },
1660 { "Partition", "Priority", config_parse_int32, 0, &p->priority },
1661 { "Partition", "Weight", config_parse_weight, 0, &p->weight },
1662 { "Partition", "PaddingWeight", config_parse_weight, 0, &p->padding_weight },
1663 { "Partition", "SizeMinBytes", config_parse_size4096, 1, &p->size_min },
1664 { "Partition", "SizeMaxBytes", config_parse_size4096, -1, &p->size_max },
1665 { "Partition", "PaddingMinBytes", config_parse_size4096, 1, &p->padding_min },
1666 { "Partition", "PaddingMaxBytes", config_parse_size4096, -1, &p->padding_max },
1667 { "Partition", "FactoryReset", config_parse_bool, 0, &p->factory_reset },
1668 { "Partition", "CopyBlocks", config_parse_copy_blocks, 0, p },
1669 { "Partition", "Format", config_parse_fstype, 0, &p->format },
1670 { "Partition", "CopyFiles", config_parse_copy_files, 0, &p->copy_files },
1671 { "Partition", "ExcludeFiles", config_parse_exclude_files, 0, &p->exclude_files_source },
1672 { "Partition", "ExcludeFilesTarget", config_parse_exclude_files, 0, &p->exclude_files_target },
1673 { "Partition", "MakeDirectories", config_parse_make_dirs, 0, &p->make_directories },
1674 { "Partition", "Encrypt", config_parse_encrypt, 0, &p->encrypt },
1675 { "Partition", "Verity", config_parse_verity, 0, &p->verity },
1676 { "Partition", "VerityMatchKey", config_parse_string, 0, &p->verity_match_key },
1677 { "Partition", "Flags", config_parse_gpt_flags, 0, &p->gpt_flags },
1678 { "Partition", "ReadOnly", config_parse_tristate, 0, &p->read_only },
1679 { "Partition", "NoAuto", config_parse_tristate, 0, &p->no_auto },
1680 { "Partition", "GrowFileSystem", config_parse_tristate, 0, &p->growfs },
1681 { "Partition", "SplitName", config_parse_string, 0, &p->split_name_format },
1682 { "Partition", "Minimize", config_parse_minimize, 0, &p->minimize },
1683 { "Partition", "Subvolumes", config_parse_make_dirs, 0, &p->subvolumes },
1684 { "Partition", "VerityDataBlockSizeBytes", config_parse_block_size, 0, &p->verity_data_block_size },
1685 { "Partition", "VerityHashBlockSizeBytes", config_parse_block_size, 0, &p->verity_hash_block_size },
e594a3b1
LP
1686 {}
1687 };
1688 int r;
39fc0174
RP
1689 _cleanup_free_ char *filename = NULL;
1690 const char* dropin_dirname;
e594a3b1 1691
39fc0174
RP
1692 r = path_extract_filename(path, &filename);
1693 if (r < 0)
bef69ae8 1694 return log_error_errno(r, "Failed to extract filename from path '%s': %m", path);
39fc0174
RP
1695
1696 dropin_dirname = strjoina(filename, ".d");
1697
1698 r = config_parse_many(
1699 STRV_MAKE_CONST(path),
1700 conf_file_dirs,
1701 dropin_dirname,
34f2fd50 1702 arg_definitions ? NULL : arg_root,
39fc0174
RP
1703 "Partition\0",
1704 config_item_table_lookup, table,
1705 CONFIG_PARSE_WARN,
1706 p,
1707 NULL,
1708 &p->drop_in_files);
e594a3b1
LP
1709 if (r < 0)
1710 return r;
1711
c74d50ff 1712 if (partition_type_exclude(&p->type))
7d505753
DDM
1713 return 0;
1714
e594a3b1
LP
1715 if (p->size_min != UINT64_MAX && p->size_max != UINT64_MAX && p->size_min > p->size_max)
1716 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1717 "SizeMinBytes= larger than SizeMaxBytes=, refusing.");
1718
1719 if (p->padding_min != UINT64_MAX && p->padding_max != UINT64_MAX && p->padding_min > p->padding_max)
1720 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1721 "PaddingMinBytes= larger than PaddingMaxBytes=, refusing.");
1722
22e932f4 1723 if (sd_id128_is_null(p->type.uuid))
e594a3b1
LP
1724 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1725 "Type= not defined, refusing.");
1726
86320e62
DDM
1727 if ((p->copy_blocks_path || p->copy_blocks_auto) &&
1728 (p->format || !strv_isempty(p->copy_files) || !strv_isempty(p->make_directories)))
1729 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1730 "Format=/CopyFiles=/MakeDirectories= and CopyBlocks= cannot be combined, refusing.");
1731
d83d8048 1732 if ((!strv_isempty(p->copy_files) || !strv_isempty(p->make_directories)) && streq_ptr(p->format, "swap"))
8a794850
LP
1733 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1734 "Format=swap and CopyFiles= cannot be combined, refusing.");
1735
973d6be4
DDM
1736 if (!p->format) {
1737 const char *format = NULL;
1738
1739 if (!strv_isempty(p->copy_files) || !strv_isempty(p->make_directories) || (p->encrypt != ENCRYPT_OFF && !(p->copy_blocks_path || p->copy_blocks_auto)))
1740 /* Pick "vfat" as file system for esp and xbootldr partitions, otherwise default to "ext4". */
1741 format = IN_SET(p->type.designator, PARTITION_ESP, PARTITION_XBOOTLDR) ? "vfat" : "ext4";
1742 else if (p->type.designator == PARTITION_SWAP)
1743 format = "swap";
1744
1745 if (format) {
1746 p->format = strdup(format);
1747 if (!p->format)
1748 return log_oom();
1749 }
8a794850
LP
1750 }
1751
5eef7047 1752 if (p->minimize != MINIMIZE_OFF && !p->format && p->verity != VERITY_HASH)
c4a87b76 1753 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
5eef7047 1754 "Minimize= can only be enabled if Format= or Verity=hash are set");
c4a87b76 1755
5eef7047 1756 if (p->minimize == MINIMIZE_BEST && (p->format && !fstype_is_ro(p->format)) && p->verity != VERITY_HASH)
5c33b686 1757 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
5eef7047 1758 "Minimize=best can only be used with read-only filesystems or Verity=hash");
5c33b686 1759
6d6cefad
DDM
1760 if ((!strv_isempty(p->copy_files) || !strv_isempty(p->make_directories)) && !mkfs_supports_root_option(p->format) && geteuid() != 0)
1761 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EPERM),
1762 "Need to be root to populate %s filesystems with CopyFiles=/MakeDirectories=",
1763 p->format);
1764
0eb23798
DDM
1765 if (p->format && fstype_is_ro(p->format) && strv_isempty(p->copy_files) && strv_isempty(p->make_directories))
1766 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1767 "Cannot format %s filesystem without source files, refusing", p->format);
1768
b5b7879a
DDM
1769 if (p->verity != VERITY_OFF || p->encrypt != ENCRYPT_OFF) {
1770 r = dlopen_cryptsetup();
1771 if (r < 0)
1772 return log_syntax(NULL, LOG_ERR, path, 1, r,
1773 "libcryptsetup not found, Verity=/Encrypt= are not supported: %m");
1774 }
1775
1776 if (p->verity != VERITY_OFF && !p->verity_match_key)
1777 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1778 "VerityMatchKey= must be set if Verity=%s", verity_mode_to_string(p->verity));
1779
1780 if (p->verity == VERITY_OFF && p->verity_match_key)
1781 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1782 "VerityMatchKey= can only be set if Verity= is not \"%s\"",
1783 verity_mode_to_string(p->verity));
1784
b456191d
DDM
1785 if (IN_SET(p->verity, VERITY_HASH, VERITY_SIG) &&
1786 (p->copy_files || p->copy_blocks_path || p->copy_blocks_auto || p->format || p->make_directories))
b5b7879a
DDM
1787 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1788 "CopyBlocks=/CopyFiles=/Format=/MakeDirectories= cannot be used with Verity=%s",
1789 verity_mode_to_string(p->verity));
1790
1791 if (p->verity != VERITY_OFF && p->encrypt != ENCRYPT_OFF)
1792 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1793 "Encrypting verity hash/data partitions is not supported");
1794
b456191d
DDM
1795 if (p->verity == VERITY_SIG && !arg_private_key)
1796 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1797 "Verity signature partition requested but no private key provided (--private-key=)");
1798
1799 if (p->verity == VERITY_SIG && !arg_certificate)
1800 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
ba4a5eff 1801 "Verity signature partition requested but no PEM certificate provided (--certificate=)");
b456191d
DDM
1802
1803 if (p->verity == VERITY_SIG && (p->size_min != UINT64_MAX || p->size_max != UINT64_MAX))
1804 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1805 "SizeMinBytes=/SizeMaxBytes= cannot be used with Verity=%s",
1806 verity_mode_to_string(p->verity));
1807
ffd9d75c 1808 if (!strv_isempty(p->subvolumes) && arg_offline > 0)
440f805c 1809 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EOPNOTSUPP),
ffd9d75c 1810 "Subvolumes= cannot be used with --offline=yes");
440f805c 1811
e73309c5 1812 /* Verity partitions are read only, let's imply the RO flag hence, unless explicitly configured otherwise. */
2208d492
DDM
1813 if ((IN_SET(p->type.designator,
1814 PARTITION_ROOT_VERITY,
ade85cd5 1815 PARTITION_USR_VERITY) || p->verity == VERITY_DATA) && p->read_only < 0)
e73309c5
LP
1816 p->read_only = true;
1817
1c41c1dc 1818 /* Default to "growfs" on, unless read-only */
22e932f4 1819 if (gpt_partition_type_knows_growfs(p->type) &&
1c41c1dc
LP
1820 p->read_only <= 0)
1821 p->growfs = true;
1822
4cee8333
DDM
1823 if (!p->split_name_format) {
1824 char *s = strdup("%t");
1825 if (!s)
1826 return log_oom();
1827
1828 p->split_name_format = s;
1829 } else if (streq(p->split_name_format, "-"))
1830 p->split_name_format = mfree(p->split_name_format);
1831
7d505753 1832 return 1;
e594a3b1
LP
1833}
1834
b5b7879a
DDM
1835static int find_verity_sibling(Context *context, Partition *p, VerityMode mode, Partition **ret) {
1836 Partition *s = NULL;
1837
1838 assert(p);
1839 assert(p->verity != VERITY_OFF);
1840 assert(p->verity_match_key);
1841 assert(mode != VERITY_OFF);
1842 assert(p->verity != mode);
1843 assert(ret);
1844
1845 /* Try to find the matching sibling partition of the given type for a verity partition. For a data
af3d3873
YW
1846 * partition, this is the corresponding hash partition with the same verity name (and vice versa for
1847 * the hash partition). */
b5b7879a
DDM
1848
1849 LIST_FOREACH(partitions, q, context->partitions) {
1850 if (p == q)
1851 continue;
1852
1853 if (q->verity != mode)
1854 continue;
1855
1856 assert(q->verity_match_key);
1857
1858 if (!streq(p->verity_match_key, q->verity_match_key))
1859 continue;
1860
1861 if (s)
1862 return -ENOTUNIQ;
1863
1864 s = q;
1865 }
1866
1867 if (!s)
1868 return -ENXIO;
1869
1870 *ret = s;
1871
1872 return 0;
1873}
1874
3cdcf4e2 1875static int context_open_and_lock_backing_fd(const char *node, int operation, int *backing_fd) {
1e46985a
DDM
1876 _cleanup_close_ int fd = -EBADF;
1877
1878 assert(node);
1879 assert(backing_fd);
1880
1881 if (*backing_fd >= 0)
1882 return 0;
1883
1884 fd = open(node, O_RDONLY|O_CLOEXEC);
1885 if (fd < 0)
1886 return log_error_errno(errno, "Failed to open device '%s': %m", node);
1887
1888 /* Tell udev not to interfere while we are processing the device */
3cdcf4e2 1889 if (flock(fd, operation) < 0)
1e46985a
DDM
1890 return log_error_errno(errno, "Failed to lock device '%s': %m", node);
1891
1892 log_debug("Device %s opened and locked.", node);
1893 *backing_fd = TAKE_FD(fd);
1894 return 1;
1895}
1896
1897static int determine_current_padding(
1898 struct fdisk_context *c,
1899 struct fdisk_table *t,
1900 struct fdisk_partition *p,
1901 uint64_t secsz,
1902 uint64_t grainsz,
1903 uint64_t *ret) {
1904
1905 size_t n_partitions;
1906 uint64_t offset, next = UINT64_MAX;
1907
1908 assert(c);
1909 assert(t);
1910 assert(p);
1911 assert(ret);
1912
1913 if (!fdisk_partition_has_end(p))
1914 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Partition has no end!");
1915
1916 offset = fdisk_partition_get_end(p);
1917 assert(offset < UINT64_MAX);
1918 offset++; /* The end is one sector before the next partition or padding. */
1919 assert(offset < UINT64_MAX / secsz);
1920 offset *= secsz;
1921
1922 n_partitions = fdisk_table_get_nents(t);
1923 for (size_t i = 0; i < n_partitions; i++) {
1924 struct fdisk_partition *q;
1925 uint64_t start;
1926
1927 q = fdisk_table_get_partition(t, i);
1928 if (!q)
1929 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read partition metadata: %m");
1930
1931 if (fdisk_partition_is_used(q) <= 0)
1932 continue;
1933
1934 if (!fdisk_partition_has_start(q))
1935 continue;
1936
1937 start = fdisk_partition_get_start(q);
1938 assert(start < UINT64_MAX / secsz);
1939 start *= secsz;
1940
1941 if (start >= offset && (next == UINT64_MAX || next > start))
1942 next = start;
1943 }
1944
1945 if (next == UINT64_MAX) {
1946 /* No later partition? In that case check the end of the usable area */
1947 next = fdisk_get_last_lba(c);
1948 assert(next < UINT64_MAX);
1949 next++; /* The last LBA is one sector before the end */
1950
1951 assert(next < UINT64_MAX / secsz);
1952 next *= secsz;
1953
1954 if (offset > next)
1955 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Partition end beyond disk end.");
1956 }
1957
1958 assert(next >= offset);
1959 offset = round_up_size(offset, grainsz);
1960 next = round_down_size(next, grainsz);
1961
1962 *ret = LESS_BY(next, offset); /* Saturated subtraction, rounding might have fucked things up */
1963 return 0;
1964}
1965
e1536d1f 1966static int context_copy_from_one(Context *context, const char *src) {
1e46985a
DDM
1967 _cleanup_close_ int fd = -EBADF;
1968 _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
1969 _cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL;
1970 Partition *last = NULL;
1971 unsigned long secsz, grainsz;
1972 size_t n_partitions;
1973 int r;
1974
e1536d1f 1975 assert(src);
1e46985a 1976
e1536d1f 1977 r = context_open_and_lock_backing_fd(src, LOCK_SH, &fd);
1e46985a
DDM
1978 if (r < 0)
1979 return r;
1980
1981 r = fd_verify_regular(fd);
1982 if (r < 0)
e1536d1f 1983 return log_error_errno(r, "%s is not a file: %m", src);
1e46985a 1984
fd9fe57a 1985 r = fdisk_new_context_at(fd, /* path = */ NULL, /* read_only = */ true, /* sector_size = */ UINT32_MAX, &c);
1e46985a
DDM
1986 if (r < 0)
1987 return log_error_errno(r, "Failed to create fdisk context: %m");
1988
1989 secsz = fdisk_get_sector_size(c);
1990 grainsz = fdisk_get_grain_size(c);
1991
1992 /* Insist on a power of two, and that it's a multiple of 512, i.e. the traditional sector size. */
1993 if (secsz < 512 || !ISPOWEROF2(secsz))
1994 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Sector size %lu is not a power of two larger than 512? Refusing.", secsz);
1995
1996 if (!fdisk_is_labeltype(c, FDISK_DISKLABEL_GPT))
e1536d1f 1997 return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON), "Cannot copy from disk %s with no GPT disk label.", src);
1e46985a
DDM
1998
1999 r = fdisk_get_partitions(c, &t);
2000 if (r < 0)
2001 return log_error_errno(r, "Failed to acquire partition table: %m");
2002
2003 n_partitions = fdisk_table_get_nents(t);
2004 for (size_t i = 0; i < n_partitions; i++) {
2005 _cleanup_(partition_freep) Partition *np = NULL;
2006 _cleanup_free_ char *label_copy = NULL;
2007 struct fdisk_partition *p;
2008 const char *label;
2009 uint64_t sz, start, padding;
2010 sd_id128_t ptid, id;
2011 GptPartitionType type;
2012
2013 p = fdisk_table_get_partition(t, i);
2014 if (!p)
2015 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read partition metadata: %m");
2016
2017 if (fdisk_partition_is_used(p) <= 0)
2018 continue;
2019
2020 if (fdisk_partition_has_start(p) <= 0 ||
2021 fdisk_partition_has_size(p) <= 0 ||
2022 fdisk_partition_has_partno(p) <= 0)
2023 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Found a partition without a position, size or number.");
2024
2025 r = fdisk_partition_get_type_as_id128(p, &ptid);
2026 if (r < 0)
2027 return log_error_errno(r, "Failed to query partition type UUID: %m");
2028
2029 type = gpt_partition_type_from_uuid(ptid);
2030
2031 r = fdisk_partition_get_uuid_as_id128(p, &id);
2032 if (r < 0)
2033 return log_error_errno(r, "Failed to query partition UUID: %m");
2034
2035 label = fdisk_partition_get_name(p);
2036 if (!isempty(label)) {
2037 label_copy = strdup(label);
2038 if (!label_copy)
2039 return log_oom();
2040 }
2041
2042 sz = fdisk_partition_get_size(p);
2043 assert(sz <= UINT64_MAX/secsz);
2044 sz *= secsz;
2045
2046 start = fdisk_partition_get_start(p);
2047 assert(start <= UINT64_MAX/secsz);
2048 start *= secsz;
2049
c74d50ff 2050 if (partition_type_exclude(&type))
1e46985a
DDM
2051 continue;
2052
2053 np = partition_new();
2054 if (!np)
2055 return log_oom();
2056
2057 np->type = type;
2058 np->new_uuid = id;
2059 np->new_uuid_is_set = true;
2060 np->size_min = np->size_max = sz;
2061 np->new_label = TAKE_PTR(label_copy);
2062
e1536d1f 2063 np->definition_path = strdup(src);
1e46985a
DDM
2064 if (!np->definition_path)
2065 return log_oom();
2066
2067 r = determine_current_padding(c, t, p, secsz, grainsz, &padding);
2068 if (r < 0)
2069 return r;
2070
2071 np->padding_min = np->padding_max = padding;
2072
e1536d1f 2073 np->copy_blocks_path = strdup(src);
1e46985a
DDM
2074 if (!np->copy_blocks_path)
2075 return log_oom();
2076
2077 np->copy_blocks_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
2078 if (np->copy_blocks_fd < 0)
e1536d1f 2079 return log_error_errno(r, "Failed to duplicate file descriptor of %s: %m", src);
1e46985a
DDM
2080
2081 np->copy_blocks_offset = start;
2082 np->copy_blocks_size = sz;
2083
2084 r = fdisk_partition_get_attrs_as_uint64(p, &np->gpt_flags);
2085 if (r < 0)
2086 return log_error_errno(r, "Failed to get partition flags: %m");
2087
2088 LIST_INSERT_AFTER(partitions, context->partitions, last, np);
2089 last = TAKE_PTR(np);
2090 context->n_partitions++;
2091 }
2092
2093 return 0;
2094}
2095
e1536d1f
DDM
2096static int context_copy_from(Context *context) {
2097 int r;
2098
2099 assert(context);
2100
2101 STRV_FOREACH(src, arg_copy_from) {
2102 r = context_copy_from_one(context, *src);
2103 if (r < 0)
2104 return r;
2105 }
2106
2107 return 0;
2108}
2109
4b047310 2110static int context_read_definitions(Context *context) {
e594a3b1 2111 _cleanup_strv_free_ char **files = NULL;
1e46985a 2112 Partition *last = LIST_FIND_TAIL(partitions, context->partitions);
39fc0174 2113 const char *const *dirs;
9b05a371 2114 int r;
e594a3b1
LP
2115
2116 assert(context);
2117
4b047310 2118 dirs = (const char* const*) (arg_definitions ?: CONF_PATHS_STRV("repart.d"));
39fc0174 2119
4b047310 2120 r = conf_files_list_strv(&files, ".conf", arg_definitions ? NULL : arg_root, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, dirs);
e594a3b1
LP
2121 if (r < 0)
2122 return log_error_errno(r, "Failed to enumerate *.conf files: %m");
2123
2124 STRV_FOREACH(f, files) {
2125 _cleanup_(partition_freep) Partition *p = NULL;
2126
2127 p = partition_new();
2128 if (!p)
2129 return log_oom();
2130
2131 p->definition_path = strdup(*f);
2132 if (!p->definition_path)
2133 return log_oom();
2134
39fc0174 2135 r = partition_read_definition(p, *f, dirs);
e594a3b1
LP
2136 if (r < 0)
2137 return r;
7d505753
DDM
2138 if (r == 0)
2139 continue;
e594a3b1
LP
2140
2141 LIST_INSERT_AFTER(partitions, context->partitions, last, p);
2142 last = TAKE_PTR(p);
2143 context->n_partitions++;
2144 }
2145
b5b7879a
DDM
2146 /* Check that each configured verity hash/data partition has a matching verity data/hash partition. */
2147
2148 LIST_FOREACH(partitions, p, context->partitions) {
2149 if (p->verity == VERITY_OFF)
2150 continue;
2151
2152 for (VerityMode mode = VERITY_OFF + 1; mode < _VERITY_MODE_MAX; mode++) {
b456191d 2153 Partition *q = NULL;
b5b7879a
DDM
2154
2155 if (p->verity == mode)
2156 continue;
2157
2158 if (p->siblings[mode])
2159 continue;
2160
2161 r = find_verity_sibling(context, p, mode, &q);
8e52ed02
DDM
2162 if (r == -ENXIO) {
2163 if (mode != VERITY_SIG)
2164 return log_syntax(NULL, LOG_ERR, p->definition_path, 1, SYNTHETIC_ERRNO(EINVAL),
2165 "Missing verity %s partition for verity %s partition with VerityMatchKey=%s",
2166 verity_mode_to_string(mode), verity_mode_to_string(p->verity), p->verity_match_key);
2167 } else if (r == -ENOTUNIQ)
b5b7879a
DDM
2168 return log_syntax(NULL, LOG_ERR, p->definition_path, 1, SYNTHETIC_ERRNO(EINVAL),
2169 "Multiple verity %s partitions found for verity %s partition with VerityMatchKey=%s",
2170 verity_mode_to_string(mode), verity_mode_to_string(p->verity), p->verity_match_key);
8e52ed02
DDM
2171 else if (r < 0)
2172 return log_syntax(NULL, LOG_ERR, p->definition_path, 1, r,
2173 "Failed to find verity %s partition for verity %s partition with VerityMatchKey=%s",
2174 verity_mode_to_string(mode), verity_mode_to_string(p->verity), p->verity_match_key);
b5b7879a 2175
b456191d
DDM
2176 if (q) {
2177 if (q->priority != p->priority)
2178 return log_syntax(NULL, LOG_ERR, p->definition_path, 1, SYNTHETIC_ERRNO(EINVAL),
2179 "Priority mismatch (%i != %i) for verity sibling partitions with VerityMatchKey=%s",
2180 p->priority, q->priority, p->verity_match_key);
b5b7879a 2181
b456191d
DDM
2182 p->siblings[mode] = q;
2183 }
b5b7879a
DDM
2184 }
2185 }
2186
5eef7047
DDM
2187 LIST_FOREACH(partitions, p, context->partitions) {
2188 Partition *dp;
2189
2190 if (p->verity != VERITY_HASH)
2191 continue;
2192
2193 if (p->minimize == MINIMIZE_OFF)
2194 continue;
2195
2196 assert_se(dp = p->siblings[VERITY_DATA]);
2197
2198 if (dp->minimize == MINIMIZE_OFF && !(p->copy_blocks_path || p->copy_blocks_auto))
2199 return log_syntax(NULL, LOG_ERR, p->definition_path, 1, SYNTHETIC_ERRNO(EINVAL),
2200 "Minimize= set for verity hash partition but data partition does "
2201 "not set CopyBlocks= or Minimize=");
2202
2203 }
2204
e594a3b1
LP
2205 return 0;
2206}
2207
e594a3b1
LP
2208static int fdisk_ask_cb(struct fdisk_context *c, struct fdisk_ask *ask, void *data) {
2209 _cleanup_free_ char *ids = NULL;
2210 int r;
2211
2212 if (fdisk_ask_get_type(ask) != FDISK_ASKTYPE_STRING)
2213 return -EINVAL;
2214
b7416360 2215 ids = new(char, SD_ID128_UUID_STRING_MAX);
e594a3b1
LP
2216 if (!ids)
2217 return -ENOMEM;
2218
b7416360 2219 r = fdisk_ask_string_set_result(ask, sd_id128_to_uuid_string(*(sd_id128_t*) data, ids));
e594a3b1
LP
2220 if (r < 0)
2221 return r;
2222
2223 TAKE_PTR(ids);
2224 return 0;
2225}
2226
2227static int fdisk_set_disklabel_id_by_uuid(struct fdisk_context *c, sd_id128_t id) {
2228 int r;
2229
2230 r = fdisk_set_ask(c, fdisk_ask_cb, &id);
2231 if (r < 0)
2232 return r;
2233
2234 r = fdisk_set_disklabel_id(c);
2235 if (r < 0)
2236 return r;
2237
2238 return fdisk_set_ask(c, NULL, NULL);
2239}
2240
53171c04 2241static int derive_uuid(sd_id128_t base, const char *token, sd_id128_t *ret) {
e594a3b1 2242 union {
ade99252 2243 uint8_t md[SHA256_DIGEST_SIZE];
e594a3b1
LP
2244 sd_id128_t id;
2245 } result;
2246
53171c04 2247 assert(token);
e594a3b1
LP
2248 assert(ret);
2249
53171c04
LP
2250 /* Derive a new UUID from the specified UUID in a stable and reasonably safe way. Specifically, we
2251 * calculate the HMAC-SHA256 of the specified token string, keyed by the supplied base (typically the
2252 * machine ID). We use the machine ID as key (and not as cleartext!) of the HMAC operation since it's
2253 * the machine ID we don't want to leak. */
e594a3b1 2254
ade99252 2255 hmac_sha256(base.bytes, sizeof(base.bytes), token, strlen(token), result.md);
e594a3b1
LP
2256
2257 /* Take the first half, mark it as v4 UUID */
2258 assert_cc(sizeof(result.md) == sizeof(result.id) * 2);
2259 *ret = id128_make_v4_uuid(result.id);
2260 return 0;
2261}
2262
81e04781
VH
2263static void derive_salt(sd_id128_t base, const char *token, uint8_t ret[static SHA256_DIGEST_SIZE]) {
2264 assert(token);
2265
2266 hmac_sha256(base.bytes, sizeof(base.bytes), token, strlen(token), ret);
2267}
2268
cc751c75 2269static int context_load_partition_table(Context *context) {
e594a3b1
LP
2270 _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
2271 _cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL;
2272 uint64_t left_boundary = UINT64_MAX, first_lba, last_lba, nsectors;
2273 _cleanup_free_ char *disk_uuid_string = NULL;
2274 bool from_scratch = false;
2275 sd_id128_t disk_uuid;
2276 size_t n_partitions;
994b3031 2277 unsigned long secsz;
93f125a6 2278 uint64_t grainsz, fs_secsz = DEFAULT_FILESYSTEM_SECTOR_SIZE;
e594a3b1
LP
2279 int r;
2280
2281 assert(context);
170c9823
LP
2282 assert(!context->fdisk_context);
2283 assert(!context->free_areas);
2284 assert(context->start == UINT64_MAX);
2285 assert(context->end == UINT64_MAX);
2286 assert(context->total == UINT64_MAX);
e594a3b1 2287
e1878ef7
DDM
2288 c = fdisk_new_context();
2289 if (!c)
2290 return log_oom();
2291
93f125a6 2292 if (arg_sector_size > 0) {
93f125a6 2293 fs_secsz = arg_sector_size;
5f13fb0a 2294 r = fdisk_save_user_sector_size(c, /* phy= */ 0, arg_sector_size);
93f125a6 2295 } else {
6c54e1d6 2296 uint32_t ssz;
93f125a6 2297 struct stat st;
6c54e1d6 2298
3cdcf4e2
DDM
2299 r = context_open_and_lock_backing_fd(context->node, arg_dry_run ? LOCK_SH : LOCK_EX,
2300 &context->backing_fd);
37734dc6
YW
2301 if (r < 0)
2302 return r;
6c54e1d6 2303
93f125a6
DDM
2304 if (fstat(context->backing_fd, &st) < 0)
2305 return log_error_errno(r, "Failed to stat %s: %m", context->node);
2306
6c54e1d6
LP
2307 /* Auto-detect sector size if not specified. */
2308 r = probe_sector_size_prefer_ioctl(context->backing_fd, &ssz);
e1878ef7 2309 if (r < 0)
6c54e1d6
LP
2310 return log_error_errno(r, "Failed to probe sector size of '%s': %m", context->node);
2311
93f125a6
DDM
2312 /* If we found the sector size and we're operating on a block device, use it as the file
2313 * system sector size as well, as we know its the sector size of the actual block device and
2314 * not just the offset at which we found the GPT header. */
2315 if (r > 0 && S_ISBLK(st.st_mode))
2316 fs_secsz = ssz;
2317
6c54e1d6 2318 r = fdisk_save_user_sector_size(c, /* phy= */ 0, ssz);
e1878ef7 2319 }
6c54e1d6
LP
2320 if (r < 0)
2321 return log_error_errno(r, "Failed to set sector size: %m");
e1878ef7 2322
a26f4a49
LP
2323 /* libfdisk doesn't have an API to operate on arbitrary fds, hence reopen the fd going via the
2324 * /proc/self/fd/ magic path if we have an existing fd. Open the original file otherwise. */
e1878ef7
DDM
2325 r = fdisk_assign_device(
2326 c,
2327 context->backing_fd >= 0 ? FORMAT_PROC_FD_PATH(context->backing_fd) : context->node,
2328 arg_dry_run);
170c9823
LP
2329 if (r == -EINVAL && arg_size_auto) {
2330 struct stat st;
2331
2332 /* libfdisk returns EINVAL if opening a file of size zero. Let's check for that, and accept
2333 * it if automatic sizing is requested. */
2334
cc751c75
DDM
2335 if (context->backing_fd < 0)
2336 r = stat(context->node, &st);
170c9823 2337 else
cc751c75 2338 r = fstat(context->backing_fd, &st);
170c9823 2339 if (r < 0)
cc751c75 2340 return log_error_errno(errno, "Failed to stat block device '%s': %m", context->node);
170c9823 2341
994b3031 2342 if (S_ISREG(st.st_mode) && st.st_size == 0) {
264668a8 2343 /* Use the fallback values if we have no better idea */
93f125a6
DDM
2344 context->sector_size = fdisk_get_sector_size(c);
2345 context->fs_sector_size = fs_secsz;
994b3031 2346 context->grain_size = 4096;
170c9823 2347 return /* from_scratch = */ true;
994b3031 2348 }
170c9823
LP
2349
2350 r = -EINVAL;
2351 }
e594a3b1 2352 if (r < 0)
cc751c75 2353 return log_error_errno(r, "Failed to open device '%s': %m", context->node);
a26f4a49 2354
cc751c75 2355 if (context->backing_fd < 0) {
a26f4a49 2356 /* If we have no fd referencing the device yet, make a copy of the fd now, so that we have one */
3cdcf4e2
DDM
2357 r = context_open_and_lock_backing_fd(FORMAT_PROC_FD_PATH(fdisk_get_devfd(c)),
2358 arg_dry_run ? LOCK_SH : LOCK_EX,
2359 &context->backing_fd);
37734dc6
YW
2360 if (r < 0)
2361 return r;
25baae50 2362 }
e594a3b1 2363
994b3031
LP
2364 /* The offsets/sizes libfdisk returns to us will be in multiple of the sector size of the
2365 * device. This is typically 512, and sometimes 4096. Let's query libfdisk once for it, and then use
2366 * it for all our needs. Note that the values we use ourselves always are in bytes though, thus mean
2367 * the same thing universally. Also note that regardless what kind of sector size is in use we'll
2368 * place partitions at multiples of 4K. */
2369 secsz = fdisk_get_sector_size(c);
2370
2371 /* Insist on a power of two, and that it's a multiple of 512, i.e. the traditional sector size. */
983ce0b5
LP
2372 if (secsz < 512 || !ISPOWEROF2(secsz))
2373 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Sector size %lu is not a power of two larger than 512? Refusing.", secsz);
994b3031
LP
2374
2375 /* Use at least 4K, and ensure it's a multiple of the sector size, regardless if that is smaller or
2376 * larger */
2377 grainsz = secsz < 4096 ? 4096 : secsz;
2378
2379 log_debug("Sector size of device is %lu bytes. Using grain size of %" PRIu64 ".", secsz, grainsz);
2380
e594a3b1
LP
2381 switch (arg_empty) {
2382
2383 case EMPTY_REFUSE:
2384 /* Refuse empty disks, insist on an existing GPT partition table */
2385 if (!fdisk_is_labeltype(c, FDISK_DISKLABEL_GPT))
cc751c75 2386 return log_notice_errno(SYNTHETIC_ERRNO(EHWPOISON), "Disk %s has no GPT disk label, not repartitioning.", context->node);
e594a3b1
LP
2387
2388 break;
2389
2390 case EMPTY_REQUIRE:
2391 /* Require an empty disk, refuse any existing partition table */
2392 r = fdisk_has_label(c);
2393 if (r < 0)
cc751c75 2394 return log_error_errno(r, "Failed to determine whether disk %s has a disk label: %m", context->node);
e594a3b1 2395 if (r > 0)
cc751c75 2396 return log_notice_errno(SYNTHETIC_ERRNO(EHWPOISON), "Disk %s already has a disk label, refusing.", context->node);
e594a3b1
LP
2397
2398 from_scratch = true;
2399 break;
2400
2401 case EMPTY_ALLOW:
2402 /* Allow both an empty disk and an existing partition table, but only GPT */
2403 r = fdisk_has_label(c);
2404 if (r < 0)
cc751c75 2405 return log_error_errno(r, "Failed to determine whether disk %s has a disk label: %m", context->node);
e594a3b1
LP
2406 if (r > 0) {
2407 if (!fdisk_is_labeltype(c, FDISK_DISKLABEL_GPT))
cc751c75 2408 return log_notice_errno(SYNTHETIC_ERRNO(EHWPOISON), "Disk %s has non-GPT disk label, not repartitioning.", context->node);
e594a3b1
LP
2409 } else
2410 from_scratch = true;
2411
2412 break;
2413
2414 case EMPTY_FORCE:
a26f4a49 2415 case EMPTY_CREATE:
e594a3b1
LP
2416 /* Always reinitiaize the disk, don't consider what there was on the disk before */
2417 from_scratch = true;
2418 break;
2419 }
2420
2421 if (from_scratch) {
e594a3b1
LP
2422 r = fdisk_create_disklabel(c, "gpt");
2423 if (r < 0)
2424 return log_error_errno(r, "Failed to create GPT disk label: %m");
2425
53171c04 2426 r = derive_uuid(context->seed, "disk-uuid", &disk_uuid);
e594a3b1
LP
2427 if (r < 0)
2428 return log_error_errno(r, "Failed to acquire disk GPT uuid: %m");
2429
2430 r = fdisk_set_disklabel_id_by_uuid(c, disk_uuid);
2431 if (r < 0)
2432 return log_error_errno(r, "Failed to set GPT disk label: %m");
2433
2434 goto add_initial_free_area;
2435 }
2436
2437 r = fdisk_get_disklabel_id(c, &disk_uuid_string);
2438 if (r < 0)
2439 return log_error_errno(r, "Failed to get current GPT disk label UUID: %m");
2440
aea3f594
ZJS
2441 r = id128_from_string_nonzero(disk_uuid_string, &disk_uuid);
2442 if (r == -ENXIO) {
53171c04 2443 r = derive_uuid(context->seed, "disk-uuid", &disk_uuid);
e594a3b1
LP
2444 if (r < 0)
2445 return log_error_errno(r, "Failed to acquire disk GPT uuid: %m");
2446
2447 r = fdisk_set_disklabel_id(c);
2448 if (r < 0)
2449 return log_error_errno(r, "Failed to set GPT disk label: %m");
aea3f594
ZJS
2450 } else if (r < 0)
2451 return log_error_errno(r, "Failed to parse current GPT disk label UUID: %m");
e594a3b1
LP
2452
2453 r = fdisk_get_partitions(c, &t);
2454 if (r < 0)
2455 return log_error_errno(r, "Failed to acquire partition table: %m");
2456
2457 n_partitions = fdisk_table_get_nents(t);
695cfd53 2458 for (size_t i = 0; i < n_partitions; i++) {
e594a3b1 2459 _cleanup_free_ char *label_copy = NULL;
03677889 2460 Partition *last = NULL;
e594a3b1 2461 struct fdisk_partition *p;
63b96eb9 2462 const char *label;
e594a3b1
LP
2463 uint64_t sz, start;
2464 bool found = false;
2465 sd_id128_t ptid, id;
2466 size_t partno;
2467
2468 p = fdisk_table_get_partition(t, i);
2469 if (!p)
2470 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read partition metadata: %m");
2471
2472 if (fdisk_partition_is_used(p) <= 0)
2473 continue;
2474
2475 if (fdisk_partition_has_start(p) <= 0 ||
2476 fdisk_partition_has_size(p) <= 0 ||
2477 fdisk_partition_has_partno(p) <= 0)
2478 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Found a partition without a position, size or number.");
2479
63b96eb9 2480 r = fdisk_partition_get_type_as_id128(p, &ptid);
e594a3b1 2481 if (r < 0)
63b96eb9 2482 return log_error_errno(r, "Failed to query partition type UUID: %m");
e594a3b1 2483
02e32aa6 2484 r = fdisk_partition_get_uuid_as_id128(p, &id);
e594a3b1 2485 if (r < 0)
02e32aa6 2486 return log_error_errno(r, "Failed to query partition UUID: %m");
e594a3b1
LP
2487
2488 label = fdisk_partition_get_name(p);
2489 if (!isempty(label)) {
2490 label_copy = strdup(label);
2491 if (!label_copy)
2492 return log_oom();
2493 }
2494
2495 sz = fdisk_partition_get_size(p);
ac33e147 2496 assert(sz <= UINT64_MAX/secsz);
994b3031 2497 sz *= secsz;
e594a3b1
LP
2498
2499 start = fdisk_partition_get_start(p);
ac33e147 2500 assert(start <= UINT64_MAX/secsz);
994b3031 2501 start *= secsz;
e594a3b1
LP
2502
2503 partno = fdisk_partition_get_partno(p);
2504
2505 if (left_boundary == UINT64_MAX || left_boundary > start)
2506 left_boundary = start;
2507
2508 /* Assign this existing partition to the first partition of the right type that doesn't have
2509 * an existing one assigned yet. */
2510 LIST_FOREACH(partitions, pp, context->partitions) {
2511 last = pp;
2512
22e932f4 2513 if (!sd_id128_equal(pp->type.uuid, ptid))
e594a3b1
LP
2514 continue;
2515
2516 if (!pp->current_partition) {
2517 pp->current_uuid = id;
2518 pp->current_size = sz;
2519 pp->offset = start;
2520 pp->partno = partno;
2521 pp->current_label = TAKE_PTR(label_copy);
2522
2523 pp->current_partition = p;
2524 fdisk_ref_partition(p);
2525
994b3031 2526 r = determine_current_padding(c, t, p, secsz, grainsz, &pp->current_padding);
e594a3b1
LP
2527 if (r < 0)
2528 return r;
2529
2530 if (pp->current_padding > 0) {
2531 r = context_add_free_area(context, pp->current_padding, pp);
2532 if (r < 0)
2533 return r;
2534 }
2535
2536 found = true;
2537 break;
2538 }
2539 }
2540
2541 /* If we have no matching definition, create a new one. */
2542 if (!found) {
2543 _cleanup_(partition_freep) Partition *np = NULL;
2544
2545 np = partition_new();
2546 if (!np)
2547 return log_oom();
2548
2549 np->current_uuid = id;
22e932f4 2550 np->type = gpt_partition_type_from_uuid(ptid);
e594a3b1
LP
2551 np->current_size = sz;
2552 np->offset = start;
2553 np->partno = partno;
2554 np->current_label = TAKE_PTR(label_copy);
2555
2556 np->current_partition = p;
2557 fdisk_ref_partition(p);
2558
994b3031 2559 r = determine_current_padding(c, t, p, secsz, grainsz, &np->current_padding);
e594a3b1
LP
2560 if (r < 0)
2561 return r;
2562
2563 if (np->current_padding > 0) {
2564 r = context_add_free_area(context, np->current_padding, np);
2565 if (r < 0)
2566 return r;
2567 }
2568
2569 LIST_INSERT_AFTER(partitions, context->partitions, last, TAKE_PTR(np));
2570 context->n_partitions++;
2571 }
2572 }
2573
2574add_initial_free_area:
2575 nsectors = fdisk_get_nsectors(c);
994b3031
LP
2576 assert(nsectors <= UINT64_MAX/secsz);
2577 nsectors *= secsz;
e594a3b1
LP
2578
2579 first_lba = fdisk_get_first_lba(c);
994b3031
LP
2580 assert(first_lba <= UINT64_MAX/secsz);
2581 first_lba *= secsz;
e594a3b1
LP
2582
2583 last_lba = fdisk_get_last_lba(c);
2584 assert(last_lba < UINT64_MAX);
2585 last_lba++;
994b3031
LP
2586 assert(last_lba <= UINT64_MAX/secsz);
2587 last_lba *= secsz;
e594a3b1
LP
2588
2589 assert(last_lba >= first_lba);
2590
2591 if (left_boundary == UINT64_MAX) {
2592 /* No partitions at all? Then the whole disk is up for grabs. */
2593
994b3031
LP
2594 first_lba = round_up_size(first_lba, grainsz);
2595 last_lba = round_down_size(last_lba, grainsz);
e594a3b1
LP
2596
2597 if (last_lba > first_lba) {
2598 r = context_add_free_area(context, last_lba - first_lba, NULL);
2599 if (r < 0)
2600 return r;
2601 }
2602 } else {
2603 /* Add space left of first partition */
2604 assert(left_boundary >= first_lba);
2605
994b3031
LP
2606 first_lba = round_up_size(first_lba, grainsz);
2607 left_boundary = round_down_size(left_boundary, grainsz);
2608 last_lba = round_down_size(last_lba, grainsz);
e594a3b1
LP
2609
2610 if (left_boundary > first_lba) {
2611 r = context_add_free_area(context, left_boundary - first_lba, NULL);
2612 if (r < 0)
2613 return r;
2614 }
2615 }
2616
2617 context->start = first_lba;
2618 context->end = last_lba;
2619 context->total = nsectors;
994b3031 2620 context->sector_size = secsz;
93f125a6 2621 context->fs_sector_size = fs_secsz;
994b3031 2622 context->grain_size = grainsz;
e594a3b1
LP
2623 context->fdisk_context = TAKE_PTR(c);
2624
2625 return from_scratch;
2626}
2627
2628static void context_unload_partition_table(Context *context) {
e594a3b1
LP
2629 assert(context);
2630
80a226b2 2631 LIST_FOREACH(partitions, p, context->partitions) {
e594a3b1
LP
2632
2633 /* Entirely remove partitions that have no configuration */
2634 if (PARTITION_IS_FOREIGN(p)) {
2635 partition_unlink_and_free(context, p);
2636 continue;
2637 }
2638
2639 /* Otherwise drop all data we read off the block device and everything we might have
2640 * calculated based on it */
2641
2642 p->dropped = false;
2643 p->current_size = UINT64_MAX;
2644 p->new_size = UINT64_MAX;
2645 p->current_padding = UINT64_MAX;
2646 p->new_padding = UINT64_MAX;
2647 p->partno = UINT64_MAX;
2648 p->offset = UINT64_MAX;
2649
2650 if (p->current_partition) {
2651 fdisk_unref_partition(p->current_partition);
2652 p->current_partition = NULL;
2653 }
2654
2655 if (p->new_partition) {
2656 fdisk_unref_partition(p->new_partition);
2657 p->new_partition = NULL;
2658 }
2659
2660 p->padding_area = NULL;
2661 p->allocated_to_area = NULL;
2662
15d43e30
LP
2663 p->current_uuid = SD_ID128_NULL;
2664 p->current_label = mfree(p->current_label);
e594a3b1
LP
2665 }
2666
2667 context->start = UINT64_MAX;
2668 context->end = UINT64_MAX;
2669 context->total = UINT64_MAX;
2670
2671 if (context->fdisk_context) {
2672 fdisk_unref_context(context->fdisk_context);
2673 context->fdisk_context = NULL;
2674 }
2675
2676 context_free_free_areas(context);
2677}
2678
2679static int format_size_change(uint64_t from, uint64_t to, char **ret) {
2b59bf51 2680 char *t;
e594a3b1
LP
2681
2682 if (from != UINT64_MAX) {
2683 if (from == to || to == UINT64_MAX)
2b59bf51 2684 t = strdup(FORMAT_BYTES(from));
e594a3b1 2685 else
fc03e80c 2686 t = strjoin(FORMAT_BYTES(from), " ", special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), " ", FORMAT_BYTES(to));
e594a3b1 2687 } else if (to != UINT64_MAX)
fc03e80c 2688 t = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), " ", FORMAT_BYTES(to));
e594a3b1
LP
2689 else {
2690 *ret = NULL;
2691 return 0;
2692 }
2693
2b59bf51 2694 if (!t)
e594a3b1
LP
2695 return log_oom();
2696
2b59bf51 2697 *ret = t;
e594a3b1
LP
2698 return 1;
2699}
2700
2701static const char *partition_label(const Partition *p) {
2702 assert(p);
2703
2704 if (p->new_label)
2705 return p->new_label;
2706
2707 if (p->current_label)
2708 return p->current_label;
2709
22e932f4 2710 return gpt_partition_type_uuid_to_string(p->type.uuid);
e594a3b1
LP
2711}
2712
cc751c75 2713static int context_dump_partitions(Context *context) {
e594a3b1
LP
2714 _cleanup_(table_unrefp) Table *t = NULL;
2715 uint64_t sum_padding = 0, sum_size = 0;
e594a3b1 2716 int r;
1ffa5cfb 2717 const size_t roothash_col = 14, dropin_files_col = 15, split_path_col = 16;
bf030f55 2718 bool has_roothash = false, has_dropin_files = false, has_split_path = false;
e594a3b1 2719
6a01ea4a 2720 if ((arg_json_format_flags & JSON_FORMAT_OFF) && context->n_partitions == 0) {
a015fbe7
TH
2721 log_info("Empty partition table.");
2722 return 0;
2723 }
2724
bf030f55
DDM
2725 t = table_new("type",
2726 "label",
2727 "uuid",
1ffa5cfb 2728 "partno",
bf030f55
DDM
2729 "file",
2730 "node",
2731 "offset",
2732 "old size",
2733 "raw size",
2734 "size",
2735 "old padding",
2736 "raw padding",
2737 "padding",
2738 "activity",
2739 "roothash",
2740 "drop-in files",
2741 "split path");
e594a3b1
LP
2742 if (!t)
2743 return log_oom();
2744
a015fbe7 2745 if (!DEBUG_LOGGING) {
6a01ea4a 2746 if (arg_json_format_flags & JSON_FORMAT_OFF)
a015fbe7 2747 (void) table_set_display(t, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4,
1ffa5cfb 2748 (size_t) 8, (size_t) 9, (size_t) 12, roothash_col, dropin_files_col,
bf030f55 2749 split_path_col);
a015fbe7
TH
2750 else
2751 (void) table_set_display(t, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4,
1ffa5cfb
DDM
2752 (size_t) 5, (size_t) 6, (size_t) 7, (size_t) 8, (size_t) 10,
2753 (size_t) 11, (size_t) 13, roothash_col, dropin_files_col,
bf030f55 2754 split_path_col);
a015fbe7 2755 }
e594a3b1 2756
e594a3b1 2757 (void) table_set_align_percent(t, table_get_cell(t, 0, 5), 100);
9c07c9ec
LP
2758 (void) table_set_align_percent(t, table_get_cell(t, 0, 6), 100);
2759 (void) table_set_align_percent(t, table_get_cell(t, 0, 7), 100);
2760 (void) table_set_align_percent(t, table_get_cell(t, 0, 8), 100);
2761 (void) table_set_align_percent(t, table_get_cell(t, 0, 9), 100);
2762 (void) table_set_align_percent(t, table_get_cell(t, 0, 10), 100);
2763 (void) table_set_align_percent(t, table_get_cell(t, 0, 11), 100);
e594a3b1
LP
2764
2765 LIST_FOREACH(partitions, p, context->partitions) {
b5b7879a 2766 _cleanup_free_ char *size_change = NULL, *padding_change = NULL, *partname = NULL, *rh = NULL;
b7416360 2767 char uuid_buffer[SD_ID128_UUID_STRING_MAX];
a015fbe7 2768 const char *label, *activity = NULL;
e594a3b1
LP
2769
2770 if (p->dropped)
2771 continue;
2772
a015fbe7
TH
2773 if (p->current_size == UINT64_MAX)
2774 activity = "create";
2775 else if (p->current_size != p->new_size)
2776 activity = "resize";
2777
e594a3b1 2778 label = partition_label(p);
cc751c75 2779 partname = p->partno != UINT64_MAX ? fdisk_partname(context->node, p->partno+1) : NULL;
e594a3b1
LP
2780
2781 r = format_size_change(p->current_size, p->new_size, &size_change);
2782 if (r < 0)
2783 return r;
2784
2785 r = format_size_change(p->current_padding, p->new_padding, &padding_change);
2786 if (r < 0)
2787 return r;
2788
2789 if (p->new_size != UINT64_MAX)
2790 sum_size += p->new_size;
2791 if (p->new_padding != UINT64_MAX)
2792 sum_padding += p->new_padding;
2793
2ecc7a5b
DDM
2794 if (p->verity != VERITY_OFF) {
2795 Partition *hp = p->verity == VERITY_HASH ? p : p->siblings[VERITY_HASH];
2796
2797 rh = hp->roothash ? hexmem(hp->roothash, hp->roothash_size) : strdup("TBD");
b5b7879a
DDM
2798 if (!rh)
2799 return log_oom();
2800 }
2801
e594a3b1
LP
2802 r = table_add_many(
2803 t,
22e932f4 2804 TABLE_STRING, gpt_partition_type_uuid_to_string_harder(p->type.uuid, uuid_buffer),
be9ce018 2805 TABLE_STRING, empty_to_null(label) ?: "-", TABLE_SET_COLOR, empty_to_null(label) ? NULL : ansi_grey(),
11749b61 2806 TABLE_UUID, p->new_uuid_is_set ? p->new_uuid : p->current_uuid,
1ffa5cfb 2807 TABLE_UINT64, p->partno,
d0242ac9 2808 TABLE_PATH_BASENAME, p->definition_path, TABLE_SET_COLOR, p->definition_path ? NULL : ansi_grey(),
a015fbe7 2809 TABLE_STRING, partname ?: "-", TABLE_SET_COLOR, partname ? NULL : ansi_highlight(),
e594a3b1 2810 TABLE_UINT64, p->offset,
a015fbe7 2811 TABLE_UINT64, p->current_size == UINT64_MAX ? 0 : p->current_size,
e594a3b1
LP
2812 TABLE_UINT64, p->new_size,
2813 TABLE_STRING, size_change, TABLE_SET_COLOR, !p->partitions_next && sum_size > 0 ? ansi_underline() : NULL,
a015fbe7 2814 TABLE_UINT64, p->current_padding == UINT64_MAX ? 0 : p->current_padding,
e594a3b1 2815 TABLE_UINT64, p->new_padding,
a015fbe7 2816 TABLE_STRING, padding_change, TABLE_SET_COLOR, !p->partitions_next && sum_padding > 0 ? ansi_underline() : NULL,
39fc0174 2817 TABLE_STRING, activity ?: "unchanged",
b5b7879a 2818 TABLE_STRING, rh,
bf030f55
DDM
2819 TABLE_STRV, p->drop_in_files,
2820 TABLE_STRING, empty_to_null(p->split_path) ?: "-");
e594a3b1 2821 if (r < 0)
f987a261 2822 return table_log_add_error(r);
39fc0174 2823
b5b7879a 2824 has_roothash = has_roothash || !isempty(rh);
3ab44dbd 2825 has_dropin_files = has_dropin_files || !strv_isempty(p->drop_in_files);
bf030f55 2826 has_split_path = has_split_path || !isempty(p->split_path);
e594a3b1
LP
2827 }
2828
6a01ea4a 2829 if ((arg_json_format_flags & JSON_FORMAT_OFF) && (sum_padding > 0 || sum_size > 0)) {
e594a3b1
LP
2830 const char *a, *b;
2831
2b59bf51
ZJS
2832 a = strjoina(special_glyph(SPECIAL_GLYPH_SIGMA), " = ", FORMAT_BYTES(sum_size));
2833 b = strjoina(special_glyph(SPECIAL_GLYPH_SIGMA), " = ", FORMAT_BYTES(sum_padding));
e594a3b1
LP
2834
2835 r = table_add_many(
2836 t,
2837 TABLE_EMPTY,
2838 TABLE_EMPTY,
2839 TABLE_EMPTY,
2840 TABLE_EMPTY,
2841 TABLE_EMPTY,
2842 TABLE_EMPTY,
2843 TABLE_EMPTY,
1ffa5cfb 2844 TABLE_EMPTY,
a015fbe7 2845 TABLE_EMPTY,
e594a3b1
LP
2846 TABLE_STRING, a,
2847 TABLE_EMPTY,
a015fbe7
TH
2848 TABLE_EMPTY,
2849 TABLE_STRING, b,
39fc0174 2850 TABLE_EMPTY,
b5b7879a 2851 TABLE_EMPTY,
bf030f55 2852 TABLE_EMPTY,
a015fbe7 2853 TABLE_EMPTY);
e594a3b1 2854 if (r < 0)
f987a261 2855 return table_log_add_error(r);
e594a3b1
LP
2856 }
2857
b5b7879a
DDM
2858 if (!has_roothash) {
2859 r = table_hide_column_from_display(t, roothash_col);
2860 if (r < 0)
2861 return log_error_errno(r, "Failed to set columns to display: %m");
2862 }
2863
3ab44dbd 2864 if (!has_dropin_files) {
39fc0174
RP
2865 r = table_hide_column_from_display(t, dropin_files_col);
2866 if (r < 0)
2867 return log_error_errno(r, "Failed to set columns to display: %m");
2868 }
2869
bf030f55
DDM
2870 if (!has_split_path) {
2871 r = table_hide_column_from_display(t, split_path_col);
2872 if (r < 0)
2873 return log_error_errno(r, "Failed to set columns to display: %m");
2874 }
2875
896e678b 2876 return table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend);
e594a3b1
LP
2877}
2878
2879static void context_bar_char_process_partition(
2880 Context *context,
2881 Partition *bar[],
2882 size_t n,
2883 Partition *p,
2884 size_t *ret_start) {
2885
2886 uint64_t from, to, total;
2887 size_t x, y;
2888
2889 assert(context);
2890 assert(bar);
2891 assert(n > 0);
2892 assert(p);
2893
2894 if (p->dropped)
2895 return;
2896
2897 assert(p->offset != UINT64_MAX);
2898 assert(p->new_size != UINT64_MAX);
2899
2900 from = p->offset;
2901 to = from + p->new_size;
2902
d8daed09
TY
2903 assert(context->total > 0);
2904 total = context->total;
e594a3b1 2905
d8daed09
TY
2906 assert(from <= total);
2907 x = from * n / total;
e594a3b1 2908
d8daed09
TY
2909 assert(to <= total);
2910 y = to * n / total;
e594a3b1
LP
2911
2912 assert(x <= y);
2913 assert(y <= n);
2914
2915 for (size_t i = x; i < y; i++)
2916 bar[i] = p;
2917
2918 *ret_start = x;
2919}
2920
2921static int partition_hint(const Partition *p, const char *node, char **ret) {
2922 _cleanup_free_ char *buf = NULL;
e594a3b1
LP
2923 const char *label;
2924 sd_id128_t id;
2925
2926 /* Tries really hard to find a suitable description for this partition */
2927
7b2ffb59
LP
2928 if (p->definition_path)
2929 return path_extract_filename(p->definition_path, ret);
e594a3b1
LP
2930
2931 label = partition_label(p);
2932 if (!isempty(label)) {
2933 buf = strdup(label);
2934 goto done;
2935 }
2936
2937 if (p->partno != UINT64_MAX) {
2938 buf = fdisk_partname(node, p->partno+1);
2939 goto done;
2940 }
2941
11749b61 2942 if (p->new_uuid_is_set)
e594a3b1
LP
2943 id = p->new_uuid;
2944 else if (!sd_id128_is_null(p->current_uuid))
2945 id = p->current_uuid;
2946 else
22e932f4 2947 id = p->type.uuid;
e594a3b1 2948
b7416360 2949 buf = strdup(SD_ID128_TO_UUID_STRING(id));
e594a3b1
LP
2950
2951done:
2952 if (!buf)
2953 return -ENOMEM;
2954
2955 *ret = TAKE_PTR(buf);
2956 return 0;
2957}
2958
cc751c75 2959static int context_dump_partition_bar(Context *context) {
e594a3b1
LP
2960 _cleanup_free_ Partition **bar = NULL;
2961 _cleanup_free_ size_t *start_array = NULL;
03677889 2962 Partition *last = NULL;
e594a3b1
LP
2963 bool z = false;
2964 size_t c, j = 0;
2965
f391597c 2966 assert_se((c = columns()) >= 2);
e594a3b1
LP
2967 c -= 2; /* We do not use the leftmost and rightmost character cell */
2968
2969 bar = new0(Partition*, c);
2970 if (!bar)
2971 return log_oom();
2972
2973 start_array = new(size_t, context->n_partitions);
2974 if (!start_array)
2975 return log_oom();
2976
2977 LIST_FOREACH(partitions, p, context->partitions)
2978 context_bar_char_process_partition(context, bar, c, p, start_array + j++);
2979
2980 putc(' ', stdout);
2981
2982 for (size_t i = 0; i < c; i++) {
2983 if (bar[i]) {
2984 if (last != bar[i])
2985 z = !z;
2986
2987 fputs(z ? ansi_green() : ansi_yellow(), stdout);
2988 fputs(special_glyph(SPECIAL_GLYPH_DARK_SHADE), stdout);
2989 } else {
2990 fputs(ansi_normal(), stdout);
2991 fputs(special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), stdout);
2992 }
2993
2994 last = bar[i];
2995 }
2996
2997 fputs(ansi_normal(), stdout);
2998 putc('\n', stdout);
2999
3000 for (size_t i = 0; i < context->n_partitions; i++) {
3001 _cleanup_free_ char **line = NULL;
3002
3003 line = new0(char*, c);
3004 if (!line)
3005 return log_oom();
3006
3007 j = 0;
3008 LIST_FOREACH(partitions, p, context->partitions) {
3009 _cleanup_free_ char *d = NULL;
3010 j++;
3011
3012 if (i < context->n_partitions - j) {
3013
3014 if (line[start_array[j-1]]) {
3015 const char *e;
3016
3017 /* Upgrade final corner to the right with a branch to the right */
3018 e = startswith(line[start_array[j-1]], special_glyph(SPECIAL_GLYPH_TREE_RIGHT));
3019 if (e) {
3020 d = strjoin(special_glyph(SPECIAL_GLYPH_TREE_BRANCH), e);
3021 if (!d)
3022 return log_oom();
3023 }
3024 }
3025
3026 if (!d) {
3027 d = strdup(special_glyph(SPECIAL_GLYPH_TREE_VERTICAL));
3028 if (!d)
3029 return log_oom();
3030 }
3031
3032 } else if (i == context->n_partitions - j) {
3033 _cleanup_free_ char *hint = NULL;
3034
cc751c75 3035 (void) partition_hint(p, context->node, &hint);
e594a3b1
LP
3036
3037 if (streq_ptr(line[start_array[j-1]], special_glyph(SPECIAL_GLYPH_TREE_VERTICAL)))
3038 d = strjoin(special_glyph(SPECIAL_GLYPH_TREE_BRANCH), " ", strna(hint));
3039 else
3040 d = strjoin(special_glyph(SPECIAL_GLYPH_TREE_RIGHT), " ", strna(hint));
3041
3042 if (!d)
3043 return log_oom();
3044 }
3045
3046 if (d)
3047 free_and_replace(line[start_array[j-1]], d);
3048 }
3049
3050 putc(' ', stdout);
3051
3052 j = 0;
3053 while (j < c) {
3054 if (line[j]) {
3055 fputs(line[j], stdout);
3056 j += utf8_console_width(line[j]);
3057 } else {
3058 putc(' ', stdout);
3059 j++;
3060 }
3061 }
3062
3063 putc('\n', stdout);
3064
3065 for (j = 0; j < c; j++)
3066 free(line[j]);
3067 }
3068
3069 return 0;
3070}
3071
b5b7879a
DDM
3072static bool context_has_roothash(Context *context) {
3073 LIST_FOREACH(partitions, p, context->partitions)
3074 if (p->roothash)
3075 return true;
3076
3077 return false;
3078}
3079
cc751c75 3080static int context_dump(Context *context, bool late) {
a26d463d
DDM
3081 int r;
3082
3083 assert(context);
a26d463d
DDM
3084
3085 if (arg_pretty == 0 && FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF))
3086 return 0;
3087
b5b7879a
DDM
3088 /* If we're outputting JSON, only dump after doing all operations so we can include the roothashes
3089 * in the output. */
3090 if (!late && !FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF))
3091 return 0;
3092
3093 /* If we're not outputting JSON, only dump again after doing all operations if there are any
3094 * roothashes that we need to communicate to the user. */
3095 if (late && FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF) && !context_has_roothash(context))
3096 return 0;
3097
cc751c75 3098 r = context_dump_partitions(context);
a26d463d
DDM
3099 if (r < 0)
3100 return r;
3101
b5b7879a
DDM
3102 /* Make sure we only write the partition bar once, even if we're writing the partition table twice to
3103 * communicate roothashes. */
3104 if (FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF) && !late) {
a26d463d
DDM
3105 putc('\n', stdout);
3106
cc751c75 3107 r = context_dump_partition_bar(context);
a26d463d
DDM
3108 if (r < 0)
3109 return r;
3110
3111 putc('\n', stdout);
3112 }
3113
3114 fflush(stdout);
3115
3116 return 0;
3117}
3118
3119
e594a3b1 3120static bool context_changed(const Context *context) {
03677889 3121 assert(context);
e594a3b1
LP
3122
3123 LIST_FOREACH(partitions, p, context->partitions) {
3124 if (p->dropped)
3125 continue;
3126
3127 if (p->allocated_to_area)
3128 return true;
3129
3130 if (p->new_size != p->current_size)
3131 return true;
3132 }
3133
3134 return false;
3135}
3136
81873a6b 3137static int context_wipe_range(Context *context, uint64_t offset, uint64_t size) {
e594a3b1
LP
3138 _cleanup_(blkid_free_probep) blkid_probe probe = NULL;
3139 int r;
3140
3141 assert(context);
81873a6b
LP
3142 assert(offset != UINT64_MAX);
3143 assert(size != UINT64_MAX);
e594a3b1
LP
3144
3145 probe = blkid_new_probe();
3146 if (!probe)
3147 return log_oom();
3148
e594a3b1 3149 errno = 0;
81873a6b 3150 r = blkid_probe_set_device(probe, fdisk_get_devfd(context->fdisk_context), offset, size);
e594a3b1 3151 if (r < 0)
81873a6b 3152 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to allocate device probe for wiping.");
e594a3b1
LP
3153
3154 errno = 0;
3155 if (blkid_probe_enable_superblocks(probe, true) < 0 ||
3156 blkid_probe_set_superblocks_flags(probe, BLKID_SUBLKS_MAGIC|BLKID_SUBLKS_BADCSUM) < 0 ||
3157 blkid_probe_enable_partitions(probe, true) < 0 ||
3158 blkid_probe_set_partitions_flags(probe, BLKID_PARTS_MAGIC) < 0)
81873a6b 3159 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to enable superblock and partition probing.");
e594a3b1
LP
3160
3161 for (;;) {
3162 errno = 0;
3163 r = blkid_do_probe(probe);
3164 if (r < 0)
3165 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe for file systems.");
3166 if (r > 0)
3167 break;
3168
3169 errno = 0;
3170 if (blkid_do_wipe(probe, false) < 0)
3171 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to wipe file system signature.");
3172 }
3173
e594a3b1
LP
3174 return 0;
3175}
3176
81873a6b
LP
3177static int context_wipe_partition(Context *context, Partition *p) {
3178 int r;
3179
3180 assert(context);
3181 assert(p);
3182 assert(!PARTITION_EXISTS(p)); /* Safety check: never wipe existing partitions */
3183
3184 assert(p->offset != UINT64_MAX);
3185 assert(p->new_size != UINT64_MAX);
3186
3187 r = context_wipe_range(context, p->offset, p->new_size);
3188 if (r < 0)
3189 return r;
3190
3191 log_info("Successfully wiped file system signatures from future partition %" PRIu64 ".", p->partno);
3192 return 0;
3193}
3194
3195static int context_discard_range(
3196 Context *context,
3197 uint64_t offset,
3198 uint64_t size) {
3199
e594a3b1
LP
3200 struct stat st;
3201 int fd;
3202
3203 assert(context);
3204 assert(offset != UINT64_MAX);
3205 assert(size != UINT64_MAX);
3206
3207 if (size <= 0)
3208 return 0;
3209
a26f4a49 3210 assert_se((fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
e594a3b1
LP
3211
3212 if (fstat(fd, &st) < 0)
3213 return -errno;
3214
3215 if (S_ISREG(st.st_mode)) {
3216 if (fallocate(fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, offset, size) < 0) {
3217 if (ERRNO_IS_NOT_SUPPORTED(errno))
3218 return -EOPNOTSUPP;
3219
3220 return -errno;
3221 }
3222
3223 return 1;
3224 }
3225
3226 if (S_ISBLK(st.st_mode)) {
3227 uint64_t range[2], end;
3228
994b3031 3229 range[0] = round_up_size(offset, context->sector_size);
e594a3b1 3230
55d38014
LP
3231 if (offset > UINT64_MAX - size)
3232 return -ERANGE;
3233
e594a3b1
LP
3234 end = offset + size;
3235 if (end <= range[0])
3236 return 0;
3237
994b3031 3238 range[1] = round_down_size(end - range[0], context->sector_size);
e594a3b1
LP
3239 if (range[1] <= 0)
3240 return 0;
3241
3242 if (ioctl(fd, BLKDISCARD, range) < 0) {
3243 if (ERRNO_IS_NOT_SUPPORTED(errno))
3244 return -EOPNOTSUPP;
3245
3246 return -errno;
3247 }
3248
3249 return 1;
3250 }
3251
3252 return -EOPNOTSUPP;
3253}
3254
3255static int context_discard_partition(Context *context, Partition *p) {
3256 int r;
3257
3258 assert(context);
3259 assert(p);
3260
3261 assert(p->offset != UINT64_MAX);
3262 assert(p->new_size != UINT64_MAX);
3263 assert(!PARTITION_EXISTS(p)); /* Safety check: never discard existing partitions */
3264
3265 if (!arg_discard)
3266 return 0;
3267
3268 r = context_discard_range(context, p->offset, p->new_size);
3269 if (r == -EOPNOTSUPP) {
5b5109e2 3270 log_info("Storage does not support discard, not discarding data in future partition %" PRIu64 ".", p->partno);
e594a3b1
LP
3271 return 0;
3272 }
22163eb5
LP
3273 if (r == -EBUSY) {
3274 /* Let's handle this gracefully: https://bugzilla.kernel.org/show_bug.cgi?id=211167 */
3275 log_info("Block device is busy, not discarding partition %" PRIu64 " because it probably is mounted.", p->partno);
3276 return 0;
3277 }
e594a3b1
LP
3278 if (r == 0) {
3279 log_info("Partition %" PRIu64 " too short for discard, skipping.", p->partno);
3280 return 0;
3281 }
3282 if (r < 0)
5b5109e2 3283 return log_error_errno(r, "Failed to discard data for future partition %" PRIu64 ".", p->partno);
e594a3b1 3284
5b5109e2 3285 log_info("Successfully discarded data from future partition %" PRIu64 ".", p->partno);
e594a3b1
LP
3286 return 1;
3287}
3288
3289static int context_discard_gap_after(Context *context, Partition *p) {
3290 uint64_t gap, next = UINT64_MAX;
e594a3b1
LP
3291 int r;
3292
3293 assert(context);
3294 assert(!p || (p->offset != UINT64_MAX && p->new_size != UINT64_MAX));
3295
5113436b
AF
3296 if (!arg_discard)
3297 return 0;
3298
e594a3b1
LP
3299 if (p)
3300 gap = p->offset + p->new_size;
3301 else
771805eb
SS
3302 /* The context start gets rounded up to grain_size, however
3303 * existing partitions may be before that so ensure the gap
3304 * starts at the first actually usable lba
3305 */
3306 gap = fdisk_get_first_lba(context->fdisk_context) * context->sector_size;
e594a3b1
LP
3307
3308 LIST_FOREACH(partitions, q, context->partitions) {
3309 if (q->dropped)
3310 continue;
3311
3312 assert(q->offset != UINT64_MAX);
3313 assert(q->new_size != UINT64_MAX);
3314
3315 if (q->offset < gap)
3316 continue;
3317
3318 if (next == UINT64_MAX || q->offset < next)
3319 next = q->offset;
3320 }
3321
3322 if (next == UINT64_MAX) {
771805eb 3323 next = (fdisk_get_last_lba(context->fdisk_context) + 1) * context->sector_size;
e594a3b1
LP
3324 if (gap > next)
3325 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Partition end beyond disk end.");
3326 }
3327
3328 assert(next >= gap);
3329 r = context_discard_range(context, gap, next - gap);
3330 if (r == -EOPNOTSUPP) {
3331 if (p)
5b5109e2 3332 log_info("Storage does not support discard, not discarding gap after partition %" PRIu64 ".", p->partno);
e594a3b1 3333 else
5b5109e2 3334 log_info("Storage does not support discard, not discarding gap at beginning of disk.");
e594a3b1
LP
3335 return 0;
3336 }
3337 if (r == 0) /* Too short */
3338 return 0;
3339 if (r < 0) {
3340 if (p)
3341 return log_error_errno(r, "Failed to discard gap after partition %" PRIu64 ".", p->partno);
3342 else
3343 return log_error_errno(r, "Failed to discard gap at beginning of disk.");
3344 }
3345
3346 if (p)
3347 log_info("Successfully discarded gap after partition %" PRIu64 ".", p->partno);
3348 else
3349 log_info("Successfully discarded gap at beginning of disk.");
3350
3351 return 0;
3352}
3353
cc751c75 3354static int context_wipe_and_discard(Context *context) {
e594a3b1
LP
3355 int r;
3356
3357 assert(context);
3358
3359 /* Wipe and discard the contents of all partitions we are about to create. We skip the discarding if
3360 * we were supposed to start from scratch anyway, as in that case we just discard the whole block
3361 * device in one go early on. */
3362
3363 LIST_FOREACH(partitions, p, context->partitions) {
3364
3365 if (!p->allocated_to_area)
3366 continue;
3367
c74d50ff 3368 if (partition_type_defer(&p->type))
81d1098b
DDM
3369 continue;
3370
e594a3b1
LP
3371 r = context_wipe_partition(context, p);
3372 if (r < 0)
3373 return r;
3374
cc751c75 3375 if (!context->from_scratch) {
f0cb1b95
LP
3376 r = context_discard_partition(context, p);
3377 if (r < 0)
3378 return r;
3379
e594a3b1
LP
3380 r = context_discard_gap_after(context, p);
3381 if (r < 0)
3382 return r;
3383 }
3384 }
3385
cc751c75 3386 if (!context->from_scratch) {
e594a3b1
LP
3387 r = context_discard_gap_after(context, NULL);
3388 if (r < 0)
3389 return r;
3390 }
3391
3392 return 0;
3393}
3394
a09ae915
DDM
3395typedef struct DecryptedPartitionTarget {
3396 int fd;
fd9b68d9 3397 char *dm_name;
a09ae915
DDM
3398 char *volume;
3399 struct crypt_device *device;
3400} DecryptedPartitionTarget;
3401
3402static DecryptedPartitionTarget* decrypted_partition_target_free(DecryptedPartitionTarget *t) {
465261bf 3403#if HAVE_LIBCRYPTSETUP
a09ae915
DDM
3404 int r;
3405
3406 if (!t)
3407 return NULL;
3408
a09ae915
DDM
3409 safe_close(t->fd);
3410
fd9b68d9
DDM
3411 /* udev or so might access out block device in the background while we are done. Let's hence
3412 * force detach the volume. We sync'ed before, hence this should be safe. */
3413 r = sym_crypt_deactivate_by_name(t->device, t->dm_name, CRYPT_DEACTIVATE_FORCE);
3414 if (r < 0)
3415 log_warning_errno(r, "Failed to deactivate LUKS device, ignoring: %m");
a09ae915
DDM
3416
3417 sym_crypt_free(t->device);
fd9b68d9 3418 free(t->dm_name);
a09ae915
DDM
3419 free(t->volume);
3420 free(t);
3421#endif
3422 return NULL;
3423}
3424
a64769d6
DDM
3425typedef struct {
3426 LoopDevice *loop;
3427 int fd;
3428 char *path;
3429 int whole_fd;
a09ae915 3430 DecryptedPartitionTarget *decrypted;
a64769d6
DDM
3431} PartitionTarget;
3432
3433static int partition_target_fd(PartitionTarget *t) {
3434 assert(t);
3435 assert(t->loop || t->fd >= 0 || t->whole_fd >= 0);
a09ae915
DDM
3436
3437 if (t->decrypted)
3438 return t->decrypted->fd;
3439
3440 if (t->loop)
3441 return t->loop->fd;
3442
3443 if (t->fd >= 0)
3444 return t->fd;
3445
3446 return t->whole_fd;
a64769d6
DDM
3447}
3448
3449static const char* partition_target_path(PartitionTarget *t) {
3450 assert(t);
3451 assert(t->loop || t->path);
a09ae915
DDM
3452
3453 if (t->decrypted)
3454 return t->decrypted->volume;
3455
3456 if (t->loop)
3457 return t->loop->node;
3458
3459 return t->path;
a64769d6
DDM
3460}
3461
3462static PartitionTarget *partition_target_free(PartitionTarget *t) {
3463 if (!t)
3464 return NULL;
3465
a09ae915 3466 decrypted_partition_target_free(t->decrypted);
a64769d6
DDM
3467 loop_device_unref(t->loop);
3468 safe_close(t->fd);
3469 unlink_and_free(t->path);
3470
3471 return mfree(t);
3472}
3473
3474DEFINE_TRIVIAL_CLEANUP_FUNC(PartitionTarget*, partition_target_free);
3475
d3201eb4
DDM
3476static int prepare_temporary_file(PartitionTarget *t, uint64_t size) {
3477 _cleanup_(unlink_and_freep) char *temp = NULL;
254d1313 3478 _cleanup_close_ int fd = -EBADF;
d3201eb4
DDM
3479 const char *vt;
3480 int r;
3481
3482 assert(t);
3483
3484 r = var_tmp_dir(&vt);
3485 if (r < 0)
3486 return log_error_errno(r, "Could not determine temporary directory: %m");
3487
3488 temp = path_join(vt, "repart-XXXXXX");
3489 if (!temp)
3490 return log_oom();
3491
3492 fd = mkostemp_safe(temp);
3493 if (fd < 0)
3494 return log_error_errno(fd, "Failed to create temporary file: %m");
3495
3496 if (ftruncate(fd, size) < 0)
3497 return log_error_errno(errno, "Failed to truncate temporary file to %s: %m",
3498 FORMAT_BYTES(size));
3499
3500 t->fd = TAKE_FD(fd);
3501 t->path = TAKE_PTR(temp);
3502
3503 return 0;
3504}
3505
a64769d6
DDM
3506static int partition_target_prepare(
3507 Context *context,
3508 Partition *p,
3509 uint64_t size,
3510 bool need_path,
3511 PartitionTarget **ret) {
3512
3513 _cleanup_(partition_target_freep) PartitionTarget *t = NULL;
d3201eb4
DDM
3514 _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
3515 int whole_fd, r;
a64769d6
DDM
3516
3517 assert(context);
3518 assert(p);
3519 assert(ret);
3520
3521 assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
3522
6b1ea55e 3523 t = new(PartitionTarget, 1);
a64769d6
DDM
3524 if (!t)
3525 return log_oom();
6b1ea55e 3526 *t = (PartitionTarget) {
254d1313
ZJS
3527 .fd = -EBADF,
3528 .whole_fd = -EBADF,
6b1ea55e 3529 };
a64769d6 3530
d3201eb4
DDM
3531 if (!need_path) {
3532 if (lseek(whole_fd, p->offset, SEEK_SET) == (off_t) -1)
3533 return log_error_errno(errno, "Failed to seek to partition offset: %m");
a64769d6 3534
d3201eb4
DDM
3535 t->whole_fd = whole_fd;
3536 *ret = TAKE_PTR(t);
3537 return 0;
3538 }
a64769d6 3539
d3201eb4
DDM
3540 /* Loopback block devices are not only useful to turn regular files into block devices, but
3541 * also to cut out sections of block devices into new block devices. */
a64769d6 3542
fc10b158 3543 if (arg_offline <= 0) {
66a8c74c 3544 r = loop_device_make(whole_fd, O_RDWR, p->offset, size, context->sector_size, 0, LOCK_EX, &d);
ffd9d75c 3545 if (r < 0 && (arg_offline == 0 || (r != -ENOENT && !ERRNO_IS_PRIVILEGE(r)) || !strv_isempty(p->subvolumes)))
fc10b158
DDM
3546 return log_error_errno(r, "Failed to make loopback device of future partition %" PRIu64 ": %m", p->partno);
3547 if (r >= 0) {
3548 t->loop = TAKE_PTR(d);
3549 *ret = TAKE_PTR(t);
3550 return 0;
3551 }
3552
3553 log_debug_errno(r, "No access to loop devices, falling back to a regular file");
d3201eb4 3554 }
a64769d6 3555
d3201eb4
DDM
3556 /* If we can't allocate a loop device, let's write to a regular file that we copy into the final
3557 * image so we can run in containers and without needing root privileges. On filesystems with
3558 * reflinking support, we can take advantage of this and just reflink the result into the image.
3559 */
a64769d6 3560
d3201eb4
DDM
3561 r = prepare_temporary_file(t, size);
3562 if (r < 0)
3563 return r;
a64769d6
DDM
3564
3565 *ret = TAKE_PTR(t);
3566
3567 return 0;
3568}
3569
3570static int partition_target_grow(PartitionTarget *t, uint64_t size) {
3571 int r;
3572
3573 assert(t);
a09ae915 3574 assert(!t->decrypted);
a64769d6
DDM
3575
3576 if (t->loop) {
3577 r = loop_device_refresh_size(t->loop, UINT64_MAX, size);
3578 if (r < 0)
3579 return log_error_errno(r, "Failed to refresh loopback device size: %m");
3580 } else if (t->fd >= 0) {
3581 if (ftruncate(t->fd, size) < 0)
3582 return log_error_errno(errno, "Failed to grow '%s' to %s by truncation: %m",
3583 t->path, FORMAT_BYTES(size));
3584 }
3585
3586 return 0;
3587}
3588
3589static int partition_target_sync(Context *context, Partition *p, PartitionTarget *t) {
3590 int whole_fd, r;
3591
3592 assert(context);
3593 assert(p);
3594 assert(t);
3595
3596 assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
3597
a09ae915
DDM
3598 if (t->decrypted && fsync(t->decrypted->fd) < 0)
3599 return log_error_errno(errno, "Failed to sync changes to '%s': %m", t->decrypted->volume);
3600
a64769d6
DDM
3601 if (t->loop) {
3602 r = loop_device_sync(t->loop);
3603 if (r < 0)
3604 return log_error_errno(r, "Failed to sync loopback device: %m");
3605 } else if (t->fd >= 0) {
e21be797
DDM
3606 struct stat st;
3607
a64769d6
DDM
3608 if (lseek(whole_fd, p->offset, SEEK_SET) == (off_t) -1)
3609 return log_error_errno(errno, "Failed to seek to partition offset: %m");
3610
6eccec00
DDM
3611 if (lseek(t->fd, 0, SEEK_SET) == (off_t) -1)
3612 return log_error_errno(errno, "Failed to seek to start of temporary file: %m");
3613
e21be797
DDM
3614 if (fstat(t->fd, &st) < 0)
3615 return log_error_errno(errno, "Failed to stat temporary file: %m");
3616
3617 if (st.st_size > (off_t) p->new_size)
3618 return log_error_errno(SYNTHETIC_ERRNO(ENOSPC),
3619 "Partition %" PRIu64 "'s contents (%s) don't fit in the partition (%s)",
3620 p->partno, FORMAT_BYTES(st.st_size), FORMAT_BYTES(p->new_size));
3621
a64769d6
DDM
3622 r = copy_bytes(t->fd, whole_fd, UINT64_MAX, COPY_REFLINK|COPY_HOLES|COPY_FSYNC);
3623 if (r < 0)
3624 return log_error_errno(r, "Failed to copy bytes to partition: %m");
3625 } else {
3626 if (fsync(t->whole_fd) < 0)
3627 return log_error_errno(errno, "Failed to sync changes: %m");
3628 }
3629
3630 return 0;
3631}
3632
a09ae915 3633static int partition_encrypt(Context *context, Partition *p, PartitionTarget *target, bool offline) {
48a09a8f 3634#if HAVE_LIBCRYPTSETUP && HAVE_CRYPT_SET_DATA_OFFSET && HAVE_CRYPT_REENCRYPT_INIT_BY_PASSPHRASE && HAVE_CRYPT_REENCRYPT
a09ae915 3635 const char *node = partition_target_path(target);
48a09a8f 3636 struct crypt_params_luks2 luks_params = {
922576e4 3637 .label = strempty(ASSERT_PTR(p)->new_label),
93f125a6 3638 .sector_size = ASSERT_PTR(context)->fs_sector_size,
a09ae915 3639 .data_device = offline ? node : NULL,
48a09a8f
DDM
3640 };
3641 struct crypt_params_reencrypt reencrypt_params = {
3642 .mode = CRYPT_REENCRYPT_ENCRYPT,
3643 .direction = CRYPT_REENCRYPT_BACKWARD,
3644 .resilience = "datashift",
3645 .data_shift = LUKS2_METADATA_SIZE / 512,
3646 .luks2 = &luks_params,
3647 .flags = CRYPT_REENCRYPT_INITIALIZE_ONLY|CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT,
3648 };
0d12936d 3649 _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
48a09a8f
DDM
3650 _cleanup_(erase_and_freep) char *base64_encoded = NULL;
3651 _cleanup_fclose_ FILE *h = NULL;
a09ae915 3652 _cleanup_free_ char *hp = NULL, *vol = NULL, *dm_name = NULL;
48a09a8f
DDM
3653 const char *passphrase = NULL;
3654 size_t passphrase_size = 0;
0b75744d 3655 const char *vt;
b9df3536
LP
3656 int r;
3657
994b3031 3658 assert(context);
b9df3536 3659 assert(p);
889914ef
LP
3660 assert(p->encrypt != ENCRYPT_OFF);
3661
0d12936d
LP
3662 r = dlopen_cryptsetup();
3663 if (r < 0)
3664 return log_error_errno(r, "libcryptsetup not found, cannot encrypt: %m");
3665
b9df3536
LP
3666 log_info("Encrypting future partition %" PRIu64 "...", p->partno);
3667
a09ae915
DDM
3668 if (offline) {
3669 r = var_tmp_dir(&vt);
3670 if (r < 0)
3671 return log_error_errno(r, "Failed to determine temporary files directory: %m");
0b75744d 3672
a09ae915
DDM
3673 r = fopen_temporary_child(vt, &h, &hp);
3674 if (r < 0)
3675 return log_error_errno(r, "Failed to create temporary LUKS header file: %m");
48a09a8f 3676
a09ae915
DDM
3677 /* Weird cryptsetup requirement which requires the header file to be the size of at least one
3678 * sector. */
93f125a6 3679 r = ftruncate(fileno(h), luks_params.sector_size);
a09ae915
DDM
3680 if (r < 0)
3681 return log_error_errno(r, "Failed to grow temporary LUKS header file: %m");
3682 } else {
3683 if (asprintf(&dm_name, "luks-repart-%08" PRIx64, random_u64()) < 0)
3684 return log_oom();
3685
3686 vol = path_join("/dev/mapper/", dm_name);
3687 if (!vol)
3688 return log_oom();
3689 }
48a09a8f 3690
a09ae915 3691 r = sym_crypt_init(&cd, offline ? hp : node);
48a09a8f
DDM
3692 if (r < 0)
3693 return log_error_errno(r, "Failed to allocate libcryptsetup context for %s: %m", hp);
b9df3536
LP
3694
3695 cryptsetup_enable_logging(cd);
3696
a09ae915
DDM
3697 if (offline) {
3698 /* Disable kernel keyring usage by libcryptsetup as a workaround for
3699 * https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests/273. This makes sure that we can
3700 * do offline encryption even when repart is running in a container. */
3701 r = sym_crypt_volume_key_keyring(cd, false);
3702 if (r < 0)
3703 return log_error_errno(r, "Failed to disable kernel keyring: %m");
48a09a8f 3704
a09ae915
DDM
3705 r = sym_crypt_metadata_locking(cd, false);
3706 if (r < 0)
3707 return log_error_errno(r, "Failed to disable metadata locking: %m");
48a09a8f 3708
a09ae915
DDM
3709 r = sym_crypt_set_data_offset(cd, LUKS2_METADATA_SIZE / 512);
3710 if (r < 0)
3711 return log_error_errno(r, "Failed to set data offset: %m");
3712 }
48a09a8f 3713
0d12936d 3714 r = sym_crypt_format(cd,
b9df3536
LP
3715 CRYPT_LUKS2,
3716 "aes",
3717 "xts-plain64",
15cad3a2 3718 SD_ID128_TO_UUID_STRING(p->luks_uuid),
98e0456e
DDM
3719 NULL,
3720 VOLUME_KEY_SIZE,
48a09a8f 3721 &luks_params);
b9df3536
LP
3722 if (r < 0)
3723 return log_error_errno(r, "Failed to LUKS2 format future partition: %m");
3724
889914ef
LP
3725 if (IN_SET(p->encrypt, ENCRYPT_KEY_FILE, ENCRYPT_KEY_FILE_TPM2)) {
3726 r = sym_crypt_keyslot_add_by_volume_key(
3727 cd,
3728 CRYPT_ANY_SLOT,
98e0456e
DDM
3729 NULL,
3730 VOLUME_KEY_SIZE,
889914ef
LP
3731 strempty(arg_key),
3732 arg_key_size);
3733 if (r < 0)
3734 return log_error_errno(r, "Failed to add LUKS2 key: %m");
48a09a8f
DDM
3735
3736 passphrase = strempty(arg_key);
3737 passphrase_size = arg_key_size;
889914ef
LP
3738 }
3739
3740 if (IN_SET(p->encrypt, ENCRYPT_TPM2, ENCRYPT_KEY_FILE_TPM2)) {
3741#if HAVE_TPM2
889914ef
LP
3742 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
3743 _cleanup_(erase_and_freep) void *secret = NULL;
02ef97cd 3744 _cleanup_free_ void *pubkey = NULL;
9e437994
DS
3745 _cleanup_free_ void *blob = NULL, *srk_buf = NULL;
3746 size_t secret_size, blob_size, pubkey_size = 0, srk_buf_size = 0;
5e476b85 3747 ssize_t base64_encoded_size;
889914ef
LP
3748 int keyslot;
3749
02ef97cd
LP
3750 if (arg_tpm2_public_key_pcr_mask != 0) {
3751 r = tpm2_load_pcr_public_key(arg_tpm2_public_key, &pubkey, &pubkey_size);
3752 if (r < 0) {
3753 if (arg_tpm2_public_key || r != -ENOENT)
3754 return log_error_errno(r, "Failed read TPM PCR public key: %m");
3755
3756 log_debug_errno(r, "Failed to read TPM2 PCR public key, proceeding without: %m");
3757 arg_tpm2_public_key_pcr_mask = 0;
3758 }
3759 }
3760
9e437994
DS
3761 _cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
3762 r = tpm2_context_new(arg_tpm2_device, &tpm2_context);
3763 if (r < 0)
3764 return r;
3765
3766 TPM2B_PUBLIC public;
3767 if (pubkey) {
3768 r = tpm2_tpm2b_public_from_pem(pubkey, pubkey_size, &public);
3769 if (r < 0)
3770 return log_error_errno(r, "Could not convert public key to TPM2B_PUBLIC: %m");
3771 }
3772
3773 r = tpm2_pcr_read_missing_values(tpm2_context, arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values);
3774 if (r < 0)
3775 return r;
3776
3777 uint16_t hash_pcr_bank = 0;
3778 uint32_t hash_pcr_mask = 0;
3779 if (arg_tpm2_n_hash_pcr_values > 0) {
3780 size_t hash_count;
3781 r = tpm2_pcr_values_hash_count(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, &hash_count);
3782 if (r < 0)
3783 return log_error_errno(r, "Could not get hash count: %m");
3784
3785 if (hash_count > 1)
3786 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Multiple PCR banks selected.");
3787
3788 hash_pcr_bank = arg_tpm2_hash_pcr_values[0].hash;
3789 r = tpm2_pcr_values_to_mask(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, hash_pcr_bank, &hash_pcr_mask);
3790 if (r < 0)
3791 return log_error_errno(r, "Could not get hash mask: %m");
3792 }
3793
3794 TPM2B_DIGEST policy = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE);
3795 r = tpm2_calculate_sealing_policy(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, &public, /* use_pin= */ false, &policy);
3796 if (r < 0)
3797 return r;
3798
3799 r = tpm2_seal(tpm2_context,
3800 &policy,
d9b5841d
LP
3801 /* pin= */ NULL,
3802 &secret, &secret_size,
3803 &blob, &blob_size,
9e437994
DS
3804 /* ret_primary_alg= */ NULL,
3805 &srk_buf, &srk_buf_size);
889914ef
LP
3806 if (r < 0)
3807 return log_error_errno(r, "Failed to seal to TPM2: %m");
3808
5e476b85
LP
3809 base64_encoded_size = base64mem(secret, secret_size, &base64_encoded);
3810 if (base64_encoded_size < 0)
3811 return log_error_errno(base64_encoded_size, "Failed to base64 encode secret key: %m");
889914ef
LP
3812
3813 r = cryptsetup_set_minimal_pbkdf(cd);
3814 if (r < 0)
3815 return log_error_errno(r, "Failed to set minimal PBKDF: %m");
3816
3817 keyslot = sym_crypt_keyslot_add_by_volume_key(
3818 cd,
3819 CRYPT_ANY_SLOT,
98e0456e
DDM
3820 NULL,
3821 VOLUME_KEY_SIZE,
889914ef 3822 base64_encoded,
5e476b85 3823 base64_encoded_size);
889914ef 3824 if (keyslot < 0)
48a09a8f 3825 return log_error_errno(keyslot, "Failed to add new TPM2 key: %m");
889914ef 3826
f0f4fcae
LP
3827 r = tpm2_make_luks2_json(
3828 keyslot,
9e437994
DS
3829 hash_pcr_mask,
3830 hash_pcr_bank,
02ef97cd
LP
3831 pubkey, pubkey_size,
3832 arg_tpm2_public_key_pcr_mask,
9e437994 3833 /* primary_alg= */ 0,
f0f4fcae 3834 blob, blob_size,
9e437994 3835 policy.buffer, policy.size,
aae6eb96 3836 NULL, 0, /* no salt because tpm2_seal has no pin */
acbb504e 3837 srk_buf, srk_buf_size,
f0f4fcae
LP
3838 0,
3839 &v);
889914ef
LP
3840 if (r < 0)
3841 return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");
3842
3843 r = cryptsetup_add_token_json(cd, v);
3844 if (r < 0)
3845 return log_error_errno(r, "Failed to add TPM2 JSON token to LUKS2 header: %m");
48a09a8f
DDM
3846
3847 passphrase = base64_encoded;
3848 passphrase_size = strlen(base64_encoded);
889914ef
LP
3849#else
3850 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
3851 "Support for TPM2 enrollment not enabled.");
3852#endif
3853 }
b9df3536 3854
a09ae915
DDM
3855 if (offline) {
3856 r = sym_crypt_reencrypt_init_by_passphrase(
3857 cd,
3858 NULL,
3859 passphrase,
3860 passphrase_size,
3861 CRYPT_ANY_SLOT,
3862 0,
3863 sym_crypt_get_cipher(cd),
3864 sym_crypt_get_cipher_mode(cd),
3865 &reencrypt_params);
3866 if (r < 0)
3867 return log_error_errno(r, "Failed to prepare for reencryption: %m");
b9df3536 3868
a09ae915
DDM
3869 /* crypt_reencrypt_init_by_passphrase() doesn't actually put the LUKS header at the front, we
3870 * have to do that ourselves. */
b9df3536 3871
a09ae915
DDM
3872 sym_crypt_free(cd);
3873 cd = NULL;
b9df3536 3874
a09ae915
DDM
3875 r = sym_crypt_init(&cd, node);
3876 if (r < 0)
3877 return log_error_errno(r, "Failed to allocate libcryptsetup context for %s: %m", node);
b9df3536 3878
a09ae915
DDM
3879 r = sym_crypt_header_restore(cd, CRYPT_LUKS2, hp);
3880 if (r < 0)
3881 return log_error_errno(r, "Failed to place new LUKS header at head of %s: %m", node);
b9df3536 3882
a09ae915 3883 reencrypt_params.flags &= ~CRYPT_REENCRYPT_INITIALIZE_ONLY;
b9df3536 3884
a09ae915
DDM
3885 r = sym_crypt_reencrypt_init_by_passphrase(
3886 cd,
3887 NULL,
3888 passphrase,
3889 passphrase_size,
3890 CRYPT_ANY_SLOT,
3891 0,
3892 NULL,
3893 NULL,
3894 &reencrypt_params);
3895 if (r < 0)
3896 return log_error_errno(r, "Failed to load reencryption context: %m");
b9df3536 3897
a09ae915
DDM
3898 r = sym_crypt_reencrypt(cd, NULL);
3899 if (r < 0)
3900 return log_error_errno(r, "Failed to encrypt %s: %m", node);
3901 } else {
3902 _cleanup_free_ DecryptedPartitionTarget *t = NULL;
3903 _cleanup_close_ int dev_fd = -1;
3904
3905 r = sym_crypt_activate_by_volume_key(
3906 cd,
3907 dm_name,
3908 NULL,
3909 VOLUME_KEY_SIZE,
3910 arg_discard ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0);
3911 if (r < 0)
3912 return log_error_errno(r, "Failed to activate LUKS superblock: %m");
3913
3914 dev_fd = open(vol, O_RDWR|O_CLOEXEC|O_NOCTTY);
3915 if (dev_fd < 0)
3916 return log_error_errno(errno, "Failed to open LUKS volume '%s': %m", vol);
3917
3918 if (flock(dev_fd, LOCK_EX) < 0)
3919 return log_error_errno(errno, "Failed to lock '%s': %m", vol);
3920
3921 t = new(DecryptedPartitionTarget, 1);
3922 if (!t)
3923 return log_oom();
3924
3925 *t = (DecryptedPartitionTarget) {
3926 .fd = TAKE_FD(dev_fd),
fd9b68d9 3927 .dm_name = TAKE_PTR(dm_name),
a09ae915
DDM
3928 .volume = TAKE_PTR(vol),
3929 .device = TAKE_PTR(cd),
3930 };
3931
3932 target->decrypted = TAKE_PTR(t);
3933 }
48a09a8f
DDM
3934
3935 log_info("Successfully encrypted future partition %" PRIu64 ".", p->partno);
b9df3536 3936
3dd8ae5c 3937 return 0;
48a09a8f
DDM
3938#else
3939 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
3940 "libcryptsetup is not supported or is missing required symbols, cannot encrypt: %m");
3dd8ae5c 3941#endif
b9df3536
LP
3942}
3943
2b392d86
DDM
3944static int partition_format_verity_hash(
3945 Context *context,
3946 Partition *p,
13bde177 3947 const char *node,
2b392d86
DDM
3948 const char *data_node) {
3949
3950#if HAVE_LIBCRYPTSETUP
3951 Partition *dp;
a64769d6 3952 _cleanup_(partition_target_freep) PartitionTarget *t = NULL;
2b392d86 3953 _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
cf18d96f 3954 _cleanup_free_ char *hint = NULL;
2b392d86
DDM
3955 _cleanup_free_ uint8_t *rh = NULL;
3956 size_t rhs;
a64769d6 3957 int r;
2b392d86
DDM
3958
3959 assert(context);
3960 assert(p);
deeae10e 3961 assert(p->verity == VERITY_HASH);
2b392d86
DDM
3962 assert(data_node);
3963
3964 if (p->dropped)
3965 return 0;
3966
3967 if (PARTITION_EXISTS(p)) /* Never format existing partitions */
3968 return 0;
3969
5eef7047
DDM
3970 /* Minimized partitions will use the copy blocks logic so let's make sure to skip those here. */
3971 if (p->copy_blocks_fd >= 0)
3972 return 0;
3973
2b392d86
DDM
3974 assert_se(dp = p->siblings[VERITY_DATA]);
3975 assert(!dp->dropped);
3976
cf18d96f
DDM
3977 (void) partition_hint(p, node, &hint);
3978
2b392d86
DDM
3979 r = dlopen_cryptsetup();
3980 if (r < 0)
3981 return log_error_errno(r, "libcryptsetup not found, cannot setup verity: %m");
3982
13bde177
DDM
3983 if (!node) {
3984 r = partition_target_prepare(context, p, p->new_size, /*need_path=*/ true, &t);
3985 if (r < 0)
3986 return r;
2b392d86 3987
13bde177
DDM
3988 node = partition_target_path(t);
3989 }
3990
c380047b
MC
3991 if (p->verity_data_block_size == UINT64_MAX)
3992 p->verity_data_block_size = context->fs_sector_size;
3993 if (p->verity_hash_block_size == UINT64_MAX)
3994 p->verity_hash_block_size = context->fs_sector_size;
3995
13bde177 3996 r = sym_crypt_init(&cd, node);
2b392d86 3997 if (r < 0)
cf18d96f 3998 return log_error_errno(r, "Failed to allocate libcryptsetup context for %s: %m", node);
2b392d86 3999
e21be797
DDM
4000 cryptsetup_enable_logging(cd);
4001
2b392d86 4002 r = sym_crypt_format(
81e04781 4003 cd, CRYPT_VERITY, NULL, NULL, SD_ID128_TO_UUID_STRING(p->verity_uuid), NULL, 0,
2b392d86
DDM
4004 &(struct crypt_params_verity){
4005 .data_device = data_node,
4006 .flags = CRYPT_VERITY_CREATE_HASH,
4007 .hash_name = "sha256",
4008 .hash_type = 1,
c380047b
MC
4009 .data_block_size = p->verity_data_block_size,
4010 .hash_block_size = p->verity_hash_block_size,
81e04781
VH
4011 .salt_size = sizeof(p->verity_salt),
4012 .salt = (const char*)p->verity_salt,
2b392d86 4013 });
e21be797
DDM
4014 if (r < 0) {
4015 /* libcryptsetup reports non-descriptive EIO errors for every I/O failure. Luckily, it
4016 * doesn't clobber errno so let's check for ENOSPC so we can report a better error if the
4017 * partition is too small. */
4018 if (r == -EIO && errno == ENOSPC)
4019 return log_error_errno(errno,
cf18d96f
DDM
4020 "Verity hash data does not fit in partition %s with size %s",
4021 strna(hint), FORMAT_BYTES(p->new_size));
e21be797 4022
cf18d96f 4023 return log_error_errno(r, "Failed to setup verity hash data of partition %s: %m", strna(hint));
e21be797 4024 }
2b392d86 4025
13bde177
DDM
4026 if (t) {
4027 r = partition_target_sync(context, p, t);
4028 if (r < 0)
4029 return r;
4030 }
a64769d6 4031
2b392d86
DDM
4032 r = sym_crypt_get_volume_key_size(cd);
4033 if (r < 0)
cf18d96f 4034 return log_error_errno(r, "Failed to determine verity root hash size of partition %s: %m", strna(hint));
2b392d86
DDM
4035 rhs = (size_t) r;
4036
4037 rh = malloc(rhs);
4038 if (!rh)
4039 return log_oom();
4040
4041 r = sym_crypt_volume_key_get(cd, CRYPT_ANY_SLOT, (char *) rh, &rhs, NULL, 0);
4042 if (r < 0)
cf18d96f 4043 return log_error_errno(r, "Failed to get verity root hash of partition %s: %m", strna(hint));
2b392d86
DDM
4044
4045 assert(rhs >= sizeof(sd_id128_t) * 2);
4046
4047 if (!dp->new_uuid_is_set) {
4048 memcpy_safe(dp->new_uuid.bytes, rh, sizeof(sd_id128_t));
4049 dp->new_uuid_is_set = true;
4050 }
4051
4052 if (!p->new_uuid_is_set) {
4053 memcpy_safe(p->new_uuid.bytes, rh + rhs - sizeof(sd_id128_t), sizeof(sd_id128_t));
4054 p->new_uuid_is_set = true;
4055 }
4056
4057 p->roothash = TAKE_PTR(rh);
4058 p->roothash_size = rhs;
4059
4060 return 0;
4061#else
4062 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "libcryptsetup is not supported, cannot setup verity hashes: %m");
4063#endif
4064}
4065
4ecd39c5
DDM
4066static int sign_verity_roothash(
4067 const uint8_t *roothash,
4068 size_t roothash_size,
4069 uint8_t **ret_signature,
4070 size_t *ret_signature_size) {
4071
4072#if HAVE_OPENSSL
4073 _cleanup_(BIO_freep) BIO *rb = NULL;
4074 _cleanup_(PKCS7_freep) PKCS7 *p7 = NULL;
4075 _cleanup_free_ char *hex = NULL;
4076 _cleanup_free_ uint8_t *sig = NULL;
4077 int sigsz;
4078
4079 assert(roothash);
4080 assert(roothash_size > 0);
4081 assert(ret_signature);
4082 assert(ret_signature_size);
4083
4084 hex = hexmem(roothash, roothash_size);
4085 if (!hex)
4086 return log_oom();
4087
4088 rb = BIO_new_mem_buf(hex, -1);
4089 if (!rb)
4090 return log_oom();
4091
4092 p7 = PKCS7_sign(arg_certificate, arg_private_key, NULL, rb, PKCS7_DETACHED|PKCS7_NOATTR|PKCS7_BINARY);
4093 if (!p7)
4094 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to calculate PKCS7 signature: %s",
4095 ERR_error_string(ERR_get_error(), NULL));
4096
4097 sigsz = i2d_PKCS7(p7, &sig);
4098 if (sigsz < 0)
4099 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to convert PKCS7 signature to DER: %s",
4100 ERR_error_string(ERR_get_error(), NULL));
4101
4102 *ret_signature = TAKE_PTR(sig);
4103 *ret_signature_size = sigsz;
4104
4105 return 0;
4106#else
4107 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "openssl is not supported, cannot setup verity signature: %m");
4108#endif
4109}
4110
4111static int partition_format_verity_sig(Context *context, Partition *p) {
4112 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
4113 _cleanup_free_ uint8_t *sig = NULL;
cf18d96f 4114 _cleanup_free_ char *text = NULL, *hint = NULL;
4ecd39c5
DDM
4115 Partition *hp;
4116 uint8_t fp[X509_FINGERPRINT_SIZE];
d28c6ce6 4117 size_t sigsz = 0; /* avoid false maybe-uninitialized warning */
4ecd39c5
DDM
4118 int whole_fd, r;
4119
4120 assert(p->verity == VERITY_SIG);
4121
4122 if (p->dropped)
4123 return 0;
4124
4125 if (PARTITION_EXISTS(p))
4126 return 0;
4127
cf18d96f
DDM
4128 (void) partition_hint(p, context->node, &hint);
4129
4ecd39c5
DDM
4130 assert_se(hp = p->siblings[VERITY_HASH]);
4131 assert(!hp->dropped);
4132
4133 assert(arg_certificate);
4134
4135 assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
4136
4137 r = sign_verity_roothash(hp->roothash, hp->roothash_size, &sig, &sigsz);
4138 if (r < 0)
4139 return r;
4140
4141 r = x509_fingerprint(arg_certificate, fp);
4142 if (r < 0)
4143 return log_error_errno(r, "Unable to calculate X509 certificate fingerprint: %m");
4144
4145 r = json_build(&v,
4146 JSON_BUILD_OBJECT(
4147 JSON_BUILD_PAIR("rootHash", JSON_BUILD_HEX(hp->roothash, hp->roothash_size)),
4148 JSON_BUILD_PAIR(
4149 "certificateFingerprint",
4150 JSON_BUILD_HEX(fp, sizeof(fp))
4151 ),
4152 JSON_BUILD_PAIR("signature", JSON_BUILD_BASE64(sig, sigsz))
4153 )
4154 );
4155 if (r < 0)
cf18d96f 4156 return log_error_errno(r, "Failed to build verity signature JSON object: %m");
4ecd39c5
DDM
4157
4158 r = json_variant_format(v, 0, &text);
4159 if (r < 0)
cf18d96f 4160 return log_error_errno(r, "Failed to format verity signature JSON object: %m");
4ecd39c5 4161
d28c6ce6 4162 r = strgrowpad0(&text, p->new_size);
4ecd39c5 4163 if (r < 0)
d28c6ce6 4164 return log_error_errno(r, "Failed to pad string to %s", FORMAT_BYTES(p->new_size));
4ecd39c5
DDM
4165
4166 if (lseek(whole_fd, p->offset, SEEK_SET) == (off_t) -1)
cf18d96f 4167 return log_error_errno(errno, "Failed to seek to partition %s offset: %m", strna(hint));
4ecd39c5 4168
d28c6ce6 4169 r = loop_write(whole_fd, text, p->new_size, /*do_poll=*/ false);
4ecd39c5 4170 if (r < 0)
cf18d96f 4171 return log_error_errno(r, "Failed to write verity signature to partition %s: %m", strna(hint));
4ecd39c5
DDM
4172
4173 if (fsync(whole_fd) < 0)
cf18d96f 4174 return log_error_errno(errno, "Failed to synchronize partition %s: %m", strna(hint));
4ecd39c5
DDM
4175
4176 return 0;
4177}
4178
757bc2e4 4179static int context_copy_blocks(Context *context) {
a64769d6 4180 int r;
757bc2e4
LP
4181
4182 assert(context);
4183
4184 /* Copy in file systems on the block level */
4185
4186 LIST_FOREACH(partitions, p, context->partitions) {
a64769d6 4187 _cleanup_(partition_target_freep) PartitionTarget *t = NULL;
757bc2e4
LP
4188
4189 if (p->copy_blocks_fd < 0)
4190 continue;
4191
4192 if (p->dropped)
4193 continue;
4194
4195 if (PARTITION_EXISTS(p)) /* Never copy over existing partitions */
4196 continue;
4197
c74d50ff 4198 if (partition_type_defer(&p->type))
81d1098b
DDM
4199 continue;
4200
757bc2e4
LP
4201 assert(p->new_size != UINT64_MAX);
4202 assert(p->copy_blocks_size != UINT64_MAX);
48a09a8f 4203 assert(p->new_size >= p->copy_blocks_size + (p->encrypt != ENCRYPT_OFF ? LUKS2_METADATA_KEEP_FREE : 0));
757bc2e4 4204
a64769d6
DDM
4205 r = partition_target_prepare(context, p, p->new_size,
4206 /*need_path=*/ p->encrypt != ENCRYPT_OFF || p->siblings[VERITY_HASH],
4207 &t);
4208 if (r < 0)
4209 return r;
757bc2e4 4210
a09ae915
DDM
4211 if (p->encrypt != ENCRYPT_OFF && t->loop) {
4212 r = partition_encrypt(context, p, t, /* offline = */ false);
4213 if (r < 0)
4214 return r;
4215 }
4216
2b59bf51
ZJS
4217 log_info("Copying in '%s' (%s) on block level into future partition %" PRIu64 ".",
4218 p->copy_blocks_path, FORMAT_BYTES(p->copy_blocks_size), p->partno);
757bc2e4 4219
1e46985a
DDM
4220 if (p->copy_blocks_offset != UINT64_MAX && lseek(p->copy_blocks_fd, p->copy_blocks_offset, SEEK_SET) < 0)
4221 return log_error_errno(errno, "Failed to seek to copy blocks offset in %s: %m", p->copy_blocks_path);
4222
a64769d6 4223 r = copy_bytes(p->copy_blocks_fd, partition_target_fd(t), p->copy_blocks_size, COPY_REFLINK);
757bc2e4
LP
4224 if (r < 0)
4225 return log_error_errno(r, "Failed to copy in data from '%s': %m", p->copy_blocks_path);
4226
a09ae915
DDM
4227 log_info("Copying in of '%s' on block level completed.", p->copy_blocks_path);
4228
4229 if (p->encrypt != ENCRYPT_OFF && !t->loop) {
4230 r = partition_encrypt(context, p, t, /* offline = */ true);
b9df3536
LP
4231 if (r < 0)
4232 return r;
b9df3536
LP
4233 }
4234
a64769d6
DDM
4235 r = partition_target_sync(context, p, t);
4236 if (r < 0)
4237 return r;
48a09a8f 4238
c74d50ff 4239 if (p->siblings[VERITY_HASH] && !partition_type_defer(&p->siblings[VERITY_HASH]->type)) {
a64769d6 4240 r = partition_format_verity_hash(context, p->siblings[VERITY_HASH],
13bde177 4241 /* node = */ NULL, partition_target_path(t));
2b392d86
DDM
4242 if (r < 0)
4243 return r;
4244 }
4ecd39c5 4245
c74d50ff 4246 if (p->siblings[VERITY_SIG] && !partition_type_defer(&p->siblings[VERITY_SIG]->type)) {
4ecd39c5
DDM
4247 r = partition_format_verity_sig(context, p->siblings[VERITY_SIG]);
4248 if (r < 0)
4249 return r;
4250 }
757bc2e4
LP
4251 }
4252
4253 return 0;
4254}
4255
e57b7020
DDM
4256static int add_exclude_path(const char *path, Hashmap **denylist, DenyType type) {
4257 _cleanup_free_ struct stat *st = NULL;
4258 int r;
4259
4260 assert(path);
4261 assert(denylist);
4262
4263 st = new(struct stat, 1);
4264 if (!st)
4265 return log_oom();
4266
4267 r = chase_and_stat(path, arg_root, CHASE_PREFIX_ROOT, NULL, st);
4268 if (r == -ENOENT)
4269 return 0;
4270 if (r < 0)
4271 return log_error_errno(r, "Failed to stat source file '%s/%s': %m", strempty(arg_root), path);
4272
4273 r = hashmap_ensure_put(denylist, &inode_hash_ops, st, INT_TO_PTR(type));
4274 if (r == -EEXIST)
4275 return 0;
4276 if (r < 0)
4277 return log_oom();
4278 if (r > 0)
4279 TAKE_PTR(st);
4280
4281 return 0;
4282}
4283
4284static int make_copy_files_denylist(
4285 Context *context,
4286 const Partition *p,
4287 const char *source,
4288 const char *target,
4289 Hashmap **ret) {
4290
4291 _cleanup_hashmap_free_ Hashmap *denylist = NULL;
4292 int r;
4293
4294 assert(context);
4295 assert(p);
4296 assert(source);
4297 assert(target);
4298 assert(ret);
4299
4300 /* Always exclude the top level APIVFS and temporary directories since the contents of these
4301 * directories are almost certainly not intended to end up in an image. */
4302
4303 NULSTR_FOREACH(s, APIVFS_TMP_DIRS_NULSTR) {
4304 r = add_exclude_path(s, &denylist, DENY_CONTENTS);
4305 if (r < 0)
4306 return r;
4307 }
4308
4309 /* Add the user configured excludes. */
4310
600bf76c 4311 STRV_FOREACH(e, p->exclude_files_source) {
e57b7020
DDM
4312 r = add_exclude_path(*e, &denylist, endswith(*e, "/") ? DENY_CONTENTS : DENY_INODE);
4313 if (r < 0)
4314 return r;
4315 }
4316
600bf76c
DDM
4317 STRV_FOREACH(e, p->exclude_files_target) {
4318 _cleanup_free_ char *path = NULL;
4319
4320 const char *s = path_startswith(*e, target);
4321 if (!s)
4322 continue;
4323
4324 path = path_join(source, s);
4325 if (!path)
4326 return log_oom();
4327
4328 r = add_exclude_path(path, &denylist, endswith(*e, "/") ? DENY_CONTENTS : DENY_INODE);
4329 if (r < 0)
4330 return r;
4331 }
4332
e57b7020
DDM
4333 /* If we're populating a root partition, we don't want any files to end up under the APIVFS mount
4334 * points. While we already exclude <source>/proc, users could still do something such as
4335 * "CopyFiles=/abc:/". Now, if /abc has a proc subdirectory with files in it, those will end up in
4336 * the top level proc directory in the root partition, which we want to avoid. To deal with these
4337 * cases, whenever we're populating a root partition and the target of CopyFiles= is the root
4338 * directory of the root partition, we exclude all directories under the source that are named after
4339 * APIVFS directories or named after mount points of other partitions that are also going to be part
4340 * of the image. */
4341
4342 if (p->type.designator == PARTITION_ROOT && empty_or_root(target)) {
4343 LIST_FOREACH(partitions, q, context->partitions) {
4344 if (q->type.designator == PARTITION_ROOT)
4345 continue;
4346
4347 const char *sources = gpt_partition_type_mountpoint_nulstr(q->type);
4348 if (!sources)
4349 continue;
4350
4351 NULSTR_FOREACH(s, sources) {
4352 _cleanup_free_ char *path = NULL;
4353
4354 /* Exclude only the children of partition mount points so that the nested
4355 * partition mount point itself still ends up in the upper partition. */
4356
4357 path = path_join(source, s);
4358 if (!path)
4359 return -ENOMEM;
4360
4361 r = add_exclude_path(path, &denylist, DENY_CONTENTS);
4362 if (r < 0)
4363 return r;
4364 }
4365 }
4366
4367 NULSTR_FOREACH(s, APIVFS_TMP_DIRS_NULSTR) {
4368 _cleanup_free_ char *path = NULL;
4369
4370 path = path_join(source, s);
4371 if (!path)
4372 return -ENOMEM;
4373
4374 r = add_exclude_path(path, &denylist, DENY_CONTENTS);
4375 if (r < 0)
4376 return r;
4377 }
4378 }
4379
4380 *ret = TAKE_PTR(denylist);
4381 return 0;
4382}
4383
440f805c
DDM
4384static int add_subvolume_path(const char *path, Set **subvolumes) {
4385 _cleanup_free_ struct stat *st = NULL;
4386 int r;
4387
4388 assert(path);
4389 assert(subvolumes);
4390
4391 st = new(struct stat, 1);
4392 if (!st)
4393 return log_oom();
4394
4395 r = chase_and_stat(path, arg_root, CHASE_PREFIX_ROOT, NULL, st);
4396 if (r == -ENOENT)
4397 return 0;
4398 if (r < 0)
4399 return log_error_errno(r, "Failed to stat source file '%s/%s': %m", strempty(arg_root), path);
4400
4401 r = set_ensure_put(subvolumes, &inode_hash_ops, st);
4402 if (r < 0)
4403 return log_oom();
4404 if (r > 0)
4405 TAKE_PTR(st);
4406
4407 return 0;
4408}
4409
4410static int make_subvolumes_set(
4411 Context *context,
4412 const Partition *p,
4413 const char *source,
4414 const char *target,
4415 Set **ret) {
4416 _cleanup_set_free_ Set *subvolumes = NULL;
4417 int r;
4418
4419 assert(context);
4420 assert(p);
4421 assert(target);
4422 assert(ret);
4423
4424 STRV_FOREACH(subvolume, p->subvolumes) {
4425 _cleanup_free_ char *path = NULL;
4426
4427 const char *s = path_startswith(*subvolume, target);
4428 if (!s)
4429 continue;
4430
4431 path = path_join(source, s);
4432 if (!path)
4433 return log_oom();
4434
4435 r = add_subvolume_path(path, &subvolumes);
4436 if (r < 0)
4437 return r;
4438 }
4439
4440 *ret = TAKE_PTR(subvolumes);
4441 return 0;
4442}
4443
e57b7020 4444static int do_copy_files(Context *context, Partition *p, const char *root) {
8a794850
LP
4445 int r;
4446
4447 assert(p);
92cd7e7c 4448 assert(root);
8a794850 4449
3e451460
DDM
4450 /* copy_tree_at() automatically copies the permissions of source directories to target directories if
4451 * it created them. However, the root directory is created by us, so we have to manually take care
4452 * that it is initialized. We use the first source directory targeting "/" as the metadata source for
4453 * the root directory. */
4454 STRV_FOREACH_PAIR(source, target, p->copy_files) {
4455 _cleanup_close_ int rfd = -EBADF, sfd = -EBADF;
4456
4457 if (!path_equal(*target, "/"))
4458 continue;
4459
4460 rfd = open(root, O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
4461 if (rfd < 0)
4462 return rfd;
4463
f461a28d 4464 sfd = chase_and_open(*source, arg_root, CHASE_PREFIX_ROOT, O_PATH|O_DIRECTORY|O_CLOEXEC|O_NOCTTY, NULL);
3e451460
DDM
4465 if (sfd < 0)
4466 return log_error_errno(sfd, "Failed to open source file '%s%s': %m", strempty(arg_root), *source);
4467
4468 (void) copy_xattr(sfd, NULL, rfd, NULL, COPY_ALL_XATTRS);
4469 (void) copy_access(sfd, rfd);
4470 (void) copy_times(sfd, rfd, 0);
4471
4472 break;
4473 }
4474
8a794850 4475 STRV_FOREACH_PAIR(source, target, p->copy_files) {
e57b7020 4476 _cleanup_hashmap_free_ Hashmap *denylist = NULL;
440f805c 4477 _cleanup_set_free_ Set *subvolumes_by_source_inode = NULL;
254d1313 4478 _cleanup_close_ int sfd = -EBADF, pfd = -EBADF, tfd = -EBADF;
8a794850 4479
e57b7020
DDM
4480 r = make_copy_files_denylist(context, p, *source, *target, &denylist);
4481 if (r < 0)
4482 return r;
4483
440f805c
DDM
4484 r = make_subvolumes_set(context, p, *source, *target, &subvolumes_by_source_inode);
4485 if (r < 0)
4486 return r;
4487
f461a28d 4488 sfd = chase_and_open(*source, arg_root, CHASE_PREFIX_ROOT, O_CLOEXEC|O_NOCTTY, NULL);
8a794850
LP
4489 if (sfd < 0)
4490 return log_error_errno(sfd, "Failed to open source file '%s%s': %m", strempty(arg_root), *source);
4491
4492 r = fd_verify_regular(sfd);
4493 if (r < 0) {
4494 if (r != -EISDIR)
4495 return log_error_errno(r, "Failed to check type of source file '%s': %m", *source);
4496
4497 /* We are looking at a directory */
f461a28d 4498 tfd = chase_and_open(*target, root, CHASE_PREFIX_ROOT, O_RDONLY|O_DIRECTORY|O_CLOEXEC, NULL);
8a794850 4499 if (tfd < 0) {
f21a3a82
LP
4500 _cleanup_free_ char *dn = NULL, *fn = NULL;
4501
8a794850
LP
4502 if (tfd != -ENOENT)
4503 return log_error_errno(tfd, "Failed to open target directory '%s': %m", *target);
4504
f21a3a82
LP
4505 r = path_extract_filename(*target, &fn);
4506 if (r < 0)
4507 return log_error_errno(r, "Failed to extract filename from '%s': %m", *target);
4508
4509 r = path_extract_directory(*target, &dn);
4510 if (r < 0)
4511 return log_error_errno(r, "Failed to extract directory from '%s': %m", *target);
4512
440f805c 4513 r = mkdir_p_root(root, dn, UID_INVALID, GID_INVALID, 0755, p->subvolumes);
8a794850
LP
4514 if (r < 0)
4515 return log_error_errno(r, "Failed to create parent directory '%s': %m", dn);
4516
f461a28d 4517 pfd = chase_and_open(dn, root, CHASE_PREFIX_ROOT, O_RDONLY|O_DIRECTORY|O_CLOEXEC, NULL);
8a794850
LP
4518 if (pfd < 0)
4519 return log_error_errno(pfd, "Failed to open parent directory of target: %m");
4520
652d9040
LP
4521 r = copy_tree_at(
4522 sfd, ".",
6020d00d 4523 pfd, fn,
ff1b55ff 4524 UID_INVALID, GID_INVALID,
ab645e0a 4525 COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_TRUNCATE,
440f805c 4526 denylist, subvolumes_by_source_inode);
8a794850 4527 } else
652d9040
LP
4528 r = copy_tree_at(
4529 sfd, ".",
4530 tfd, ".",
ff1b55ff 4531 UID_INVALID, GID_INVALID,
ab645e0a 4532 COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_TRUNCATE,
440f805c 4533 denylist, subvolumes_by_source_inode);
8a794850 4534 if (r < 0)
cf2ed23c
DDM
4535 return log_error_errno(r, "Failed to copy '%s%s' to '%s%s': %m",
4536 strempty(arg_root), *source, strempty(root), *target);
8a794850 4537 } else {
f21a3a82
LP
4538 _cleanup_free_ char *dn = NULL, *fn = NULL;
4539
8a794850
LP
4540 /* We are looking at a regular file */
4541
f21a3a82
LP
4542 r = path_extract_filename(*target, &fn);
4543 if (r == -EADDRNOTAVAIL || r == O_DIRECTORY)
4544 return log_error_errno(SYNTHETIC_ERRNO(EISDIR),
4545 "Target path '%s' refers to a directory, but source path '%s' refers to regular file, can't copy.", *target, *source);
4546 if (r < 0)
4547 return log_error_errno(r, "Failed to extract filename from '%s': %m", *target);
4548
4549 r = path_extract_directory(*target, &dn);
4550 if (r < 0)
4551 return log_error_errno(r, "Failed to extract directory from '%s': %m", *target);
4552
440f805c 4553 r = mkdir_p_root(root, dn, UID_INVALID, GID_INVALID, 0755, p->subvolumes);
8a794850
LP
4554 if (r < 0)
4555 return log_error_errno(r, "Failed to create parent directory: %m");
4556
f461a28d 4557 pfd = chase_and_open(dn, root, CHASE_PREFIX_ROOT, O_RDONLY|O_DIRECTORY|O_CLOEXEC, NULL);
8a794850 4558 if (pfd < 0)
a0ff9971 4559 return log_error_errno(pfd, "Failed to open parent directory of target: %m");
8a794850 4560
e2819067 4561 tfd = openat(pfd, fn, O_CREAT|O_EXCL|O_WRONLY|O_CLOEXEC, 0700);
8a794850
LP
4562 if (tfd < 0)
4563 return log_error_errno(errno, "Failed to create target file '%s': %m", *target);
4564
ab645e0a 4565 r = copy_bytes(sfd, tfd, UINT64_MAX, COPY_REFLINK|COPY_HOLES|COPY_SIGINT|COPY_TRUNCATE);
8a794850 4566 if (r < 0)
554a2b64 4567 return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target);
8a794850 4568
c17cfe6e 4569 (void) copy_xattr(sfd, NULL, tfd, NULL, COPY_ALL_XATTRS);
8a794850
LP
4570 (void) copy_access(sfd, tfd);
4571 (void) copy_times(sfd, tfd, 0);
4572 }
4573 }
4574
4575 return 0;
4576}
4577
49fb6e97 4578static int do_make_directories(Partition *p, const char *root) {
d83d8048
LP
4579 int r;
4580
4581 assert(p);
92cd7e7c 4582 assert(root);
d83d8048
LP
4583
4584 STRV_FOREACH(d, p->make_directories) {
440f805c 4585 r = mkdir_p_root(root, *d, UID_INVALID, GID_INVALID, 0755, p->subvolumes);
d83d8048
LP
4586 if (r < 0)
4587 return log_error_errno(r, "Failed to create directory '%s' in file system: %m", *d);
4588 }
4589
4590 return 0;
4591}
4592
d3201eb4
DDM
4593static bool partition_needs_populate(Partition *p) {
4594 assert(p);
4595 return !strv_isempty(p->copy_files) || !strv_isempty(p->make_directories);
4596}
4597
e57b7020 4598static int partition_populate_directory(Context *context, Partition *p, char **ret) {
95bfd3cd 4599 _cleanup_(rm_rf_physical_and_freep) char *root = NULL;
1eb86ddd 4600 const char *vt;
95bfd3cd
DDM
4601 int r;
4602
e59678b2 4603 assert(ret);
95bfd3cd 4604
b24bfd6e
DDM
4605 log_info("Populating %s filesystem.", p->format);
4606
1eb86ddd
DDM
4607 r = var_tmp_dir(&vt);
4608 if (r < 0)
4609 return log_error_errno(r, "Could not determine temporary directory: %m");
95bfd3cd 4610
1eb86ddd
DDM
4611 r = tempfn_random_child(vt, "repart", &root);
4612 if (r < 0)
4613 return log_error_errno(r, "Failed to generate temporary directory: %m");
4614
4615 r = mkdir(root, 0755);
4616 if (r < 0)
4617 return log_error_errno(errno, "Failed to create temporary directory: %m");
0b34f351 4618
e57b7020 4619 r = do_copy_files(context, p, root);
95bfd3cd
DDM
4620 if (r < 0)
4621 return r;
4622
49fb6e97 4623 r = do_make_directories(p, root);
95bfd3cd
DDM
4624 if (r < 0)
4625 return r;
4626
b24bfd6e
DDM
4627 log_info("Successfully populated %s filesystem.", p->format);
4628
e59678b2 4629 *ret = TAKE_PTR(root);
95bfd3cd
DDM
4630 return 0;
4631}
4632
e57b7020 4633static int partition_populate_filesystem(Context *context, Partition *p, const char *node) {
8a794850
LP
4634 int r;
4635
4636 assert(p);
4637 assert(node);
4638
b24bfd6e 4639 log_info("Populating %s filesystem.", p->format);
8a794850
LP
4640
4641 /* We copy in a child process, since we have to mount the fs for that, and we don't want that fs to
4642 * appear in the host namespace. Hence we fork a child that has its own file system namespace and
4643 * detached mount propagation. */
4644
4645 r = safe_fork("(sd-copy)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE, NULL);
4646 if (r < 0)
4647 return r;
4648 if (r == 0) {
4649 static const char fs[] = "/run/systemd/mount-root";
4650 /* This is a child process with its own mount namespace and propagation to host turned off */
4651
4652 r = mkdir_p(fs, 0700);
4653 if (r < 0) {
4654 log_error_errno(r, "Failed to create mount point: %m");
4655 _exit(EXIT_FAILURE);
4656 }
4657
511a8cfe 4658 if (mount_nofollow_verbose(LOG_ERR, node, fs, p->format, MS_NOATIME|MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL) < 0)
8a794850
LP
4659 _exit(EXIT_FAILURE);
4660
e57b7020 4661 if (do_copy_files(context, p, fs) < 0)
8a794850
LP
4662 _exit(EXIT_FAILURE);
4663
49fb6e97 4664 if (do_make_directories(p, fs) < 0)
d83d8048
LP
4665 _exit(EXIT_FAILURE);
4666
8a794850
LP
4667 r = syncfs_path(AT_FDCWD, fs);
4668 if (r < 0) {
4669 log_error_errno(r, "Failed to synchronize written files: %m");
4670 _exit(EXIT_FAILURE);
4671 }
4672
4673 _exit(EXIT_SUCCESS);
4674 }
4675
b24bfd6e 4676 log_info("Successfully populated %s filesystem.", p->format);
8a794850
LP
4677 return 0;
4678}
4679
53171c04 4680static int context_mkfs(Context *context) {
a64769d6 4681 int r;
53171c04
LP
4682
4683 assert(context);
4684
4685 /* Make a file system */
4686
4687 LIST_FOREACH(partitions, p, context->partitions) {
e59678b2 4688 _cleanup_(rm_rf_physical_and_freep) char *root = NULL;
a64769d6 4689 _cleanup_(partition_target_freep) PartitionTarget *t = NULL;
4b8ce14f 4690 _cleanup_strv_free_ char **extra_mkfs_options = NULL;
53171c04
LP
4691
4692 if (p->dropped)
4693 continue;
4694
4695 if (PARTITION_EXISTS(p)) /* Never format existing partitions */
4696 continue;
4697
4698 if (!p->format)
4699 continue;
4700
c4a87b76
DDM
4701 /* Minimized partitions will use the copy blocks logic so let's make sure to skip those here. */
4702 if (p->copy_blocks_fd >= 0)
4703 continue;
4704
c74d50ff 4705 if (partition_type_defer(&p->type))
81d1098b
DDM
4706 continue;
4707
53171c04
LP
4708 assert(p->offset != UINT64_MAX);
4709 assert(p->new_size != UINT64_MAX);
48a09a8f 4710 assert(p->new_size >= (p->encrypt != ENCRYPT_OFF ? LUKS2_METADATA_KEEP_FREE : 0));
53171c04 4711
a64769d6
DDM
4712 /* If we're doing encryption, we make sure we keep free space at the end which is required
4713 * for cryptsetup's offline encryption. */
4714 r = partition_target_prepare(context, p,
4715 p->new_size - (p->encrypt != ENCRYPT_OFF ? LUKS2_METADATA_KEEP_FREE : 0),
4716 /*need_path=*/ true,
4717 &t);
53171c04 4718 if (r < 0)
a64769d6 4719 return r;
53171c04 4720
a09ae915
DDM
4721 if (p->encrypt != ENCRYPT_OFF && t->loop) {
4722 r = partition_target_grow(t, p->new_size);
4723 if (r < 0)
4724 return r;
4725
4726 r = partition_encrypt(context, p, t, /* offline = */ false);
4727 if (r < 0)
4728 return log_error_errno(r, "Failed to encrypt device: %m");
4729 }
4730
53171c04
LP
4731 log_info("Formatting future partition %" PRIu64 ".", p->partno);
4732
d3201eb4
DDM
4733 /* If we're not writing to a loop device or if we're populating a read-only filesystem, we
4734 * have to populate using the filesystem's mkfs's --root (or equivalent) option. To do that,
4735 * we need to set up the final directory tree beforehand. */
4736
4737 if (partition_needs_populate(p) && (!t->loop || fstype_is_ro(p->format))) {
4738 if (!mkfs_supports_root_option(p->format))
4739 return log_error_errno(SYNTHETIC_ERRNO(ENODEV),
4740 "Loop device access is required to populate %s filesystems.",
4741 p->format);
95bfd3cd 4742
e57b7020 4743 r = partition_populate_directory(context, p, &root);
143c3c08
DDM
4744 if (r < 0)
4745 return r;
4746 }
95bfd3cd 4747
4b8ce14f
DDM
4748 r = mkfs_options_from_env("REPART", p->format, &extra_mkfs_options);
4749 if (r < 0)
4750 return log_error_errno(r,
4751 "Failed to determine mkfs command line options for '%s': %m",
4752 p->format);
4753
a64769d6 4754 r = make_filesystem(partition_target_path(t), p->format, strempty(p->new_label), root,
93f125a6
DDM
4755 p->fs_uuid, arg_discard, /* quiet = */ false,
4756 context->fs_sector_size, extra_mkfs_options);
48a09a8f 4757 if (r < 0)
53171c04
LP
4758 return r;
4759
4760 log_info("Successfully formatted future partition %" PRIu64 ".", p->partno);
4761
d3201eb4
DDM
4762 /* If we're writing to a loop device, we can now mount the empty filesystem and populate it. */
4763 if (partition_needs_populate(p) && !root) {
4764 assert(t->loop);
4765
a09ae915 4766 r = partition_populate_filesystem(context, p, partition_target_path(t));
48a09a8f 4767 if (r < 0)
143c3c08 4768 return r;
b9df3536
LP
4769 }
4770
a09ae915 4771 if (p->encrypt != ENCRYPT_OFF && !t->loop) {
a64769d6 4772 r = partition_target_grow(t, p->new_size);
b9df3536 4773 if (r < 0)
a64769d6 4774 return r;
b9df3536 4775
a09ae915 4776 r = partition_encrypt(context, p, t, /* offline = */ true);
48a09a8f
DDM
4777 if (r < 0)
4778 return log_error_errno(r, "Failed to encrypt device: %m");
b9df3536 4779 }
8a794850 4780
48a09a8f
DDM
4781 /* Note that we always sync explicitly here, since mkfs.fat doesn't do that on its own, and
4782 * if we don't sync before detaching a block device the in-flight sectors possibly won't hit
4783 * the disk. */
4784
a64769d6 4785 r = partition_target_sync(context, p, t);
53171c04 4786 if (r < 0)
a64769d6 4787 return r;
b5b7879a 4788
c74d50ff 4789 if (p->siblings[VERITY_HASH] && !partition_type_defer(&p->siblings[VERITY_HASH]->type)) {
a64769d6 4790 r = partition_format_verity_hash(context, p->siblings[VERITY_HASH],
13bde177 4791 /* node = */ NULL, partition_target_path(t));
2b392d86
DDM
4792 if (r < 0)
4793 return r;
b5b7879a 4794 }
4ecd39c5 4795
c74d50ff 4796 if (p->siblings[VERITY_SIG] && !partition_type_defer(&p->siblings[VERITY_SIG]->type)) {
4ecd39c5
DDM
4797 r = partition_format_verity_sig(context, p->siblings[VERITY_SIG]);
4798 if (r < 0)
4799 return r;
4800 }
b5b7879a
DDM
4801 }
4802
4803 return 0;
4804}
4805
b456191d
DDM
4806static int parse_x509_certificate(const char *certificate, size_t certificate_size, X509 **ret) {
4807#if HAVE_OPENSSL
4808 _cleanup_(X509_freep) X509 *cert = NULL;
4809 _cleanup_(BIO_freep) BIO *cb = NULL;
4810
4811 assert(certificate);
4812 assert(certificate_size > 0);
4813 assert(ret);
4814
4815 cb = BIO_new_mem_buf(certificate, certificate_size);
4816 if (!cb)
4817 return log_oom();
4818
4819 cert = PEM_read_bio_X509(cb, NULL, NULL, NULL);
4820 if (!cert)
4821 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse X.509 certificate: %s",
4822 ERR_error_string(ERR_get_error(), NULL));
4823
4824 if (ret)
4825 *ret = TAKE_PTR(cert);
4826
4827 return 0;
4828#else
4829 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "openssl is not supported, cannot parse X509 certificate.");
4830#endif
4831}
4832
4833static int parse_private_key(const char *key, size_t key_size, EVP_PKEY **ret) {
4834#if HAVE_OPENSSL
4835 _cleanup_(BIO_freep) BIO *kb = NULL;
4836 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pk = NULL;
4837
4838 assert(key);
4839 assert(key_size > 0);
4840 assert(ret);
4841
4842 kb = BIO_new_mem_buf(key, key_size);
4843 if (!kb)
4844 return log_oom();
4845
4846 pk = PEM_read_bio_PrivateKey(kb, NULL, NULL, NULL);
4847 if (!pk)
4848 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to parse PEM private key: %s",
4849 ERR_error_string(ERR_get_error(), NULL));
4850
4851 if (ret)
4852 *ret = TAKE_PTR(pk);
4853
4854 return 0;
4855#else
4856 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "openssl is not supported, cannot parse private key.");
4857#endif
4858}
4859
e594a3b1
LP
4860static int partition_acquire_uuid(Context *context, Partition *p, sd_id128_t *ret) {
4861 struct {
4862 sd_id128_t type_uuid;
4863 uint64_t counter;
695cfd53 4864 } _packed_ plaintext = {};
e594a3b1 4865 union {
ade99252 4866 uint8_t md[SHA256_DIGEST_SIZE];
e594a3b1
LP
4867 sd_id128_t id;
4868 } result;
4869
4870 uint64_t k = 0;
e594a3b1
LP
4871 int r;
4872
4873 assert(context);
4874 assert(p);
4875 assert(ret);
4876
4877 /* Calculate a good UUID for the indicated partition. We want a certain degree of reproducibility,
4878 * hence we won't generate the UUIDs randomly. Instead we use a cryptographic hash (precisely:
4879 * HMAC-SHA256) to derive them from a single seed. The seed is generally the machine ID of the
4880 * installation we are processing, but if random behaviour is desired can be random, too. We use the
4881 * seed value as key for the HMAC (since the machine ID is something we generally don't want to leak)
4882 * and the partition type as plaintext. The partition type is suffixed with a counter (only for the
4883 * second and later partition of the same type) if we have more than one partition of the same
4884 * time. Or in other words:
4885 *
4886 * With:
4887 * SEED := /etc/machine-id
4888 *
4889 * If first partition instance of type TYPE_UUID:
4890 * PARTITION_UUID := HMAC-SHA256(SEED, TYPE_UUID)
4891 *
4892 * For all later partition instances of type TYPE_UUID with INSTANCE being the LE64 encoded instance number:
4893 * PARTITION_UUID := HMAC-SHA256(SEED, TYPE_UUID || INSTANCE)
4894 */
4895
4896 LIST_FOREACH(partitions, q, context->partitions) {
4897 if (p == q)
4898 break;
4899
22e932f4 4900 if (!sd_id128_equal(p->type.uuid, q->type.uuid))
e594a3b1
LP
4901 continue;
4902
4903 k++;
4904 }
4905
22e932f4 4906 plaintext.type_uuid = p->type.uuid;
e594a3b1
LP
4907 plaintext.counter = htole64(k);
4908
ade99252
KK
4909 hmac_sha256(context->seed.bytes, sizeof(context->seed.bytes),
4910 &plaintext,
4911 k == 0 ? sizeof(sd_id128_t) : sizeof(plaintext),
4912 result.md);
e594a3b1
LP
4913
4914 /* Take the first half, mark it as v4 UUID */
4915 assert_cc(sizeof(result.md) == sizeof(result.id) * 2);
4916 result.id = id128_make_v4_uuid(result.id);
4917
4918 /* Ensure this partition UUID is actually unique, and there's no remaining partition from an earlier run? */
4919 LIST_FOREACH(partitions, q, context->partitions) {
4920 if (p == q)
4921 continue;
4922
580f48cc 4923 if (sd_id128_in_set(result.id, q->current_uuid, q->new_uuid)) {
da1af43d 4924 log_warning("Partition UUID calculated from seed for partition %" PRIu64 " already used, reverting to randomized UUID.", p->partno);
e594a3b1
LP
4925
4926 r = sd_id128_randomize(&result.id);
4927 if (r < 0)
4928 return log_error_errno(r, "Failed to generate randomized UUID: %m");
4929
4930 break;
4931 }
4932 }
4933
4934 *ret = result.id;
4935 return 0;
4936}
4937
4938static int partition_acquire_label(Context *context, Partition *p, char **ret) {
4939 _cleanup_free_ char *label = NULL;
4940 const char *prefix;
4941 unsigned k = 1;
4942
4943 assert(context);
4944 assert(p);
4945 assert(ret);
4946
22e932f4 4947 prefix = gpt_partition_type_uuid_to_string(p->type.uuid);
e594a3b1
LP
4948 if (!prefix)
4949 prefix = "linux";
4950
4951 for (;;) {
4952 const char *ll = label ?: prefix;
4953 bool retry = false;
e594a3b1
LP
4954
4955 LIST_FOREACH(partitions, q, context->partitions) {
4956 if (p == q)
4957 break;
4958
4959 if (streq_ptr(ll, q->current_label) ||
4960 streq_ptr(ll, q->new_label)) {
4961 retry = true;
4962 break;
4963 }
4964 }
4965
4966 if (!retry)
4967 break;
4968
4969 label = mfree(label);
e594a3b1
LP
4970 if (asprintf(&label, "%s-%u", prefix, ++k) < 0)
4971 return log_oom();
4972 }
4973
4974 if (!label) {
4975 label = strdup(prefix);
4976 if (!label)
4977 return log_oom();
4978 }
4979
4980 *ret = TAKE_PTR(label);
4981 return 0;
4982}
4983
4984static int context_acquire_partition_uuids_and_labels(Context *context) {
e594a3b1
LP
4985 int r;
4986
4987 assert(context);
4988
4989 LIST_FOREACH(partitions, p, context->partitions) {
15cad3a2
DDM
4990 sd_id128_t uuid;
4991
e594a3b1
LP
4992 /* Never touch foreign partitions */
4993 if (PARTITION_IS_FOREIGN(p)) {
4994 p->new_uuid = p->current_uuid;
4995
4996 if (p->current_label) {
78eee6ce
LP
4997 r = free_and_strdup_warn(&p->new_label, strempty(p->current_label));
4998 if (r < 0)
4999 return r;
e594a3b1
LP
5000 }
5001
5002 continue;
5003 }
5004
5005 if (!sd_id128_is_null(p->current_uuid))
15cad3a2
DDM
5006 p->new_uuid = uuid = p->current_uuid; /* Never change initialized UUIDs */
5007 else if (p->new_uuid_is_set)
5008 uuid = p->new_uuid;
5009 else {
12963533 5010 /* Not explicitly set by user! */
15cad3a2 5011 r = partition_acquire_uuid(context, p, &uuid);
e594a3b1
LP
5012 if (r < 0)
5013 return r;
11749b61 5014
15cad3a2
DDM
5015 /* The final verity hash/data UUIDs can only be determined after formatting the
5016 * verity hash partition. However, we still want to use the generated partition UUID
5017 * to derive other UUIDs to keep things unique and reproducible, so we always
5018 * generate a UUID if none is set, but we only use it as the actual partition UUID if
5019 * verity is not configured. */
5020 if (!IN_SET(p->verity, VERITY_DATA, VERITY_HASH)) {
5021 p->new_uuid = uuid;
5022 p->new_uuid_is_set = true;
5023 }
e594a3b1
LP
5024 }
5025
8bbbdfd7
DDM
5026 /* Calculate the UUID for the file system as HMAC-SHA256 of the string "file-system-uuid",
5027 * keyed off the partition UUID. */
15cad3a2 5028 r = derive_uuid(uuid, "file-system-uuid", &p->fs_uuid);
8bbbdfd7
DDM
5029 if (r < 0)
5030 return r;
5031
15cad3a2
DDM
5032 if (p->encrypt != ENCRYPT_OFF) {
5033 r = derive_uuid(uuid, "luks-uuid", &p->luks_uuid);
5034 if (r < 0)
5035 return r;
5036 }
5037
81e04781
VH
5038 /* Derive the verity salt and verity superblock UUID from the seed to keep them reproducible */
5039 if (p->verity == VERITY_HASH) {
5040 derive_salt(context->seed, "verity-salt", p->verity_salt);
5041
5042 r = derive_uuid(context->seed, "verity-uuid", &p->verity_uuid);
5043 if (r < 0)
5044 return log_error_errno(r, "Failed to acquire verity uuid: %m");
5045 }
5046
e594a3b1 5047 if (!isempty(p->current_label)) {
78eee6ce
LP
5048 /* never change initialized labels */
5049 r = free_and_strdup_warn(&p->new_label, p->current_label);
5050 if (r < 0)
5051 return r;
12963533
TH
5052 } else if (!p->new_label) {
5053 /* Not explicitly set by user! */
5054
e594a3b1
LP
5055 r = partition_acquire_label(context, p, &p->new_label);
5056 if (r < 0)
5057 return r;
5058 }
5059 }
5060
5061 return 0;
5062}
5063
e73309c5
LP
5064static int set_gpt_flags(struct fdisk_partition *q, uint64_t flags) {
5065 _cleanup_free_ char *a = NULL;
5066
5067 for (unsigned i = 0; i < sizeof(flags) * 8; i++) {
5068 uint64_t bit = UINT64_C(1) << i;
5069 char buf[DECIMAL_STR_MAX(unsigned)+1];
5070
5071 if (!FLAGS_SET(flags, bit))
5072 continue;
5073
5074 xsprintf(buf, "%u", i);
5075 if (!strextend_with_separator(&a, ",", buf))
5076 return -ENOMEM;
5077 }
5078
5079 return fdisk_partition_set_attrs(q, a);
5080}
5081
1c41c1dc
LP
5082static uint64_t partition_merge_flags(Partition *p) {
5083 uint64_t f;
5084
5085 assert(p);
5086
5087 f = p->gpt_flags;
5088
ff0771bf 5089 if (p->no_auto >= 0) {
22e932f4 5090 if (gpt_partition_type_knows_no_auto(p->type))
92e72028 5091 SET_FLAG(f, SD_GPT_FLAG_NO_AUTO, p->no_auto);
ff0771bf 5092 else {
b7416360 5093 char buffer[SD_ID128_UUID_STRING_MAX];
ff0771bf
LP
5094 log_warning("Configured NoAuto=%s for partition type '%s' that doesn't support it, ignoring.",
5095 yes_no(p->no_auto),
22e932f4 5096 gpt_partition_type_uuid_to_string_harder(p->type.uuid, buffer));
ff0771bf
LP
5097 }
5098 }
5099
1c41c1dc 5100 if (p->read_only >= 0) {
22e932f4 5101 if (gpt_partition_type_knows_read_only(p->type))
92e72028 5102 SET_FLAG(f, SD_GPT_FLAG_READ_ONLY, p->read_only);
1c41c1dc 5103 else {
b7416360 5104 char buffer[SD_ID128_UUID_STRING_MAX];
1c41c1dc
LP
5105 log_warning("Configured ReadOnly=%s for partition type '%s' that doesn't support it, ignoring.",
5106 yes_no(p->read_only),
22e932f4 5107 gpt_partition_type_uuid_to_string_harder(p->type.uuid, buffer));
1c41c1dc
LP
5108 }
5109 }
5110
5111 if (p->growfs >= 0) {
22e932f4 5112 if (gpt_partition_type_knows_growfs(p->type))
92e72028 5113 SET_FLAG(f, SD_GPT_FLAG_GROWFS, p->growfs);
1c41c1dc 5114 else {
b7416360 5115 char buffer[SD_ID128_UUID_STRING_MAX];
1c41c1dc
LP
5116 log_warning("Configured GrowFileSystem=%s for partition type '%s' that doesn't support it, ignoring.",
5117 yes_no(p->growfs),
22e932f4 5118 gpt_partition_type_uuid_to_string_harder(p->type.uuid, buffer));
1c41c1dc
LP
5119 }
5120 }
5121
5122 return f;
5123}
5124
f28d4f42 5125static int context_mangle_partitions(Context *context) {
f28d4f42 5126 int r;
e594a3b1
LP
5127
5128 assert(context);
5129
e594a3b1
LP
5130 LIST_FOREACH(partitions, p, context->partitions) {
5131 if (p->dropped)
5132 continue;
5133
c74d50ff 5134 if (partition_type_defer(&p->type))
81d1098b
DDM
5135 continue;
5136
e594a3b1
LP
5137 assert(p->new_size != UINT64_MAX);
5138 assert(p->offset != UINT64_MAX);
5139 assert(p->partno != UINT64_MAX);
5140
5141 if (PARTITION_EXISTS(p)) {
5142 bool changed = false;
5143
5144 assert(p->current_partition);
5145
5146 if (p->new_size != p->current_size) {
5147 assert(p->new_size >= p->current_size);
994b3031 5148 assert(p->new_size % context->sector_size == 0);
e594a3b1
LP
5149
5150 r = fdisk_partition_size_explicit(p->current_partition, true);
5151 if (r < 0)
5152 return log_error_errno(r, "Failed to enable explicit sizing: %m");
5153
994b3031 5154 r = fdisk_partition_set_size(p->current_partition, p->new_size / context->sector_size);
e594a3b1
LP
5155 if (r < 0)
5156 return log_error_errno(r, "Failed to grow partition: %m");
5157
5158 log_info("Growing existing partition %" PRIu64 ".", p->partno);
5159 changed = true;
5160 }
5161
5162 if (!sd_id128_equal(p->new_uuid, p->current_uuid)) {
b7416360 5163 r = fdisk_partition_set_uuid(p->current_partition, SD_ID128_TO_UUID_STRING(p->new_uuid));
e594a3b1
LP
5164 if (r < 0)
5165 return log_error_errno(r, "Failed to set partition UUID: %m");
5166
5167 log_info("Initializing UUID of existing partition %" PRIu64 ".", p->partno);
5168 changed = true;
5169 }
5170
5171 if (!streq_ptr(p->new_label, p->current_label)) {
be9ce018 5172 r = fdisk_partition_set_name(p->current_partition, strempty(p->new_label));
e594a3b1
LP
5173 if (r < 0)
5174 return log_error_errno(r, "Failed to set partition label: %m");
5175
5176 log_info("Setting partition label of existing partition %" PRIu64 ".", p->partno);
5177 changed = true;
5178 }
5179
5180 if (changed) {
5181 assert(!PARTITION_IS_FOREIGN(p)); /* never touch foreign partitions */
5182
5183 r = fdisk_set_partition(context->fdisk_context, p->partno, p->current_partition);
5184 if (r < 0)
5185 return log_error_errno(r, "Failed to update partition: %m");
5186 }
5187 } else {
5188 _cleanup_(fdisk_unref_partitionp) struct fdisk_partition *q = NULL;
5189 _cleanup_(fdisk_unref_parttypep) struct fdisk_parttype *t = NULL;
e594a3b1
LP
5190
5191 assert(!p->new_partition);
994b3031
LP
5192 assert(p->offset % context->sector_size == 0);
5193 assert(p->new_size % context->sector_size == 0);
be9ce018 5194 assert(p->new_label);
e594a3b1
LP
5195
5196 t = fdisk_new_parttype();
5197 if (!t)
5198 return log_oom();
5199
22e932f4 5200 r = fdisk_parttype_set_typestr(t, SD_ID128_TO_UUID_STRING(p->type.uuid));
e594a3b1
LP
5201 if (r < 0)
5202 return log_error_errno(r, "Failed to initialize partition type: %m");
5203
5204 q = fdisk_new_partition();
5205 if (!q)
5206 return log_oom();
5207
5208 r = fdisk_partition_set_type(q, t);
5209 if (r < 0)
5210 return log_error_errno(r, "Failed to set partition type: %m");
5211
5212 r = fdisk_partition_size_explicit(q, true);
5213 if (r < 0)
5214 return log_error_errno(r, "Failed to enable explicit sizing: %m");
5215
994b3031 5216 r = fdisk_partition_set_start(q, p->offset / context->sector_size);
e594a3b1
LP
5217 if (r < 0)
5218 return log_error_errno(r, "Failed to position partition: %m");
5219
994b3031 5220 r = fdisk_partition_set_size(q, p->new_size / context->sector_size);
e594a3b1
LP
5221 if (r < 0)
5222 return log_error_errno(r, "Failed to grow partition: %m");
5223
5224 r = fdisk_partition_set_partno(q, p->partno);
5225 if (r < 0)
5226 return log_error_errno(r, "Failed to set partition number: %m");
5227
b7416360 5228 r = fdisk_partition_set_uuid(q, SD_ID128_TO_UUID_STRING(p->new_uuid));
e594a3b1
LP
5229 if (r < 0)
5230 return log_error_errno(r, "Failed to set partition UUID: %m");
5231
be9ce018 5232 r = fdisk_partition_set_name(q, strempty(p->new_label));
e594a3b1
LP
5233 if (r < 0)
5234 return log_error_errno(r, "Failed to set partition label: %m");
5235
ff0771bf 5236 /* Merge the no auto + read only + growfs setting with the literal flags, and set them for the partition */
1c41c1dc 5237 r = set_gpt_flags(q, partition_merge_flags(p));
e73309c5
LP
5238 if (r < 0)
5239 return log_error_errno(r, "Failed to set GPT partition flags: %m");
5240
5b5109e2 5241 log_info("Adding new partition %" PRIu64 " to partition table.", p->partno);
e594a3b1
LP
5242
5243 r = fdisk_add_partition(context->fdisk_context, q, NULL);
5244 if (r < 0)
5245 return log_error_errno(r, "Failed to add partition: %m");
5246
5247 assert(!p->new_partition);
5248 p->new_partition = TAKE_PTR(q);
5249 }
5250 }
5251
f28d4f42
LP
5252 return 0;
5253}
5254
62108348 5255static int split_name_printf(Partition *p, char **ret) {
4cee8333
DDM
5256 assert(p);
5257
5258 const Specifier table[] = {
22e932f4
DDM
5259 { 't', specifier_string, GPT_PARTITION_TYPE_UUID_TO_STRING_HARDER(p->type.uuid) },
5260 { 'T', specifier_id128, &p->type.uuid },
4cee8333
DDM
5261 { 'U', specifier_id128, &p->new_uuid },
5262 { 'n', specifier_uint64, &p->partno },
5263
5264 COMMON_SYSTEM_SPECIFIERS,
5265 {}
5266 };
5267
62108348 5268 return specifier_printf(p->split_name_format, NAME_MAX, table, arg_root, p, ret);
4cee8333
DDM
5269}
5270
62108348
DDM
5271static int split_node(const char *node, char **ret_base, char **ret_ext) {
5272 _cleanup_free_ char *base = NULL, *ext = NULL;
5273 char *e;
5274 int r;
5275
5276 assert(node);
5277 assert(ret_base);
5278 assert(ret_ext);
5279
5280 r = path_extract_filename(node, &base);
5281 if (r == O_DIRECTORY || r == -EADDRNOTAVAIL)
5282 return log_error_errno(r, "Device node %s cannot be a directory", node);
5283 if (r < 0)
5284 return log_error_errno(r, "Failed to extract filename from %s: %m", node);
5285
5286 e = endswith(base, ".raw");
5287 if (e) {
5288 ext = strdup(e);
5289 if (!ext)
5290 return log_oom();
5291
5292 *e = 0;
5293 }
5294
5295 *ret_base = TAKE_PTR(base);
5296 *ret_ext = TAKE_PTR(ext);
5297
5298 return 0;
4cee8333
DDM
5299}
5300
5301static int split_name_resolve(Context *context) {
62108348 5302 _cleanup_free_ char *parent = NULL, *base = NULL, *ext = NULL;
4cee8333
DDM
5303 int r;
5304
62108348 5305 assert(context);
62108348 5306
cc751c75 5307 r = path_extract_directory(context->node, &parent);
62108348 5308 if (r < 0 && r != -EDESTADDRREQ)
cc751c75 5309 return log_error_errno(r, "Failed to extract directory from %s: %m", context->node);
62108348 5310
cc751c75 5311 r = split_node(context->node, &base, &ext);
62108348
DDM
5312 if (r < 0)
5313 return r;
5314
4cee8333 5315 LIST_FOREACH(partitions, p, context->partitions) {
62108348
DDM
5316 _cleanup_free_ char *resolved = NULL;
5317
4cee8333
DDM
5318 if (p->dropped)
5319 continue;
5320
5321 if (!p->split_name_format)
5322 continue;
5323
62108348 5324 r = split_name_printf(p, &resolved);
4cee8333
DDM
5325 if (r < 0)
5326 return log_error_errno(r, "Failed to resolve specifiers in %s: %m", p->split_name_format);
62108348
DDM
5327
5328 if (parent)
5329 p->split_path = strjoin(parent, "/", base, ".", resolved, ext);
5330 else
5331 p->split_path = strjoin(base, ".", resolved, ext);
5332 if (!p->split_path)
5333 return log_oom();
4cee8333
DDM
5334 }
5335
5336 LIST_FOREACH(partitions, p, context->partitions) {
62108348 5337 if (!p->split_path)
4cee8333
DDM
5338 continue;
5339
5340 LIST_FOREACH(partitions, q, context->partitions) {
5341 if (p == q)
5342 continue;
5343
62108348 5344 if (!q->split_path)
4cee8333
DDM
5345 continue;
5346
62108348 5347 if (!streq(p->split_path, q->split_path))
4cee8333
DDM
5348 continue;
5349
5350 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
5351 "%s and %s have the same resolved split name \"%s\", refusing",
62108348 5352 p->definition_path, q->definition_path, p->split_path);
4cee8333
DDM
5353 }
5354 }
5355
5356 return 0;
5357}
5358
4cee8333 5359static int context_split(Context *context) {
254d1313 5360 int fd = -EBADF, r;
4cee8333
DDM
5361
5362 if (!arg_split)
5363 return 0;
5364
5365 assert(context);
4cee8333
DDM
5366
5367 /* We can't do resolution earlier because the partition UUIDs for verity partitions are only filled
5368 * in after they've been generated. */
5369
5370 r = split_name_resolve(context);
5371 if (r < 0)
5372 return r;
5373
4cee8333 5374 LIST_FOREACH(partitions, p, context->partitions) {
254d1313 5375 _cleanup_close_ int fdt = -EBADF;
4cee8333
DDM
5376
5377 if (p->dropped)
5378 continue;
5379
62108348 5380 if (!p->split_path)
4cee8333
DDM
5381 continue;
5382
c74d50ff 5383 if (partition_type_defer(&p->type))
81d1098b
DDM
5384 continue;
5385
62108348 5386 fdt = open(p->split_path, O_WRONLY|O_NOCTTY|O_CLOEXEC|O_NOFOLLOW|O_CREAT|O_EXCL, 0666);
4cee8333 5387 if (fdt < 0)
62108348 5388 return log_error_errno(fdt, "Failed to open split partition file %s: %m", p->split_path);
4cee8333
DDM
5389
5390 if (fd < 0)
5391 assert_se((fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
5392
5393 if (lseek(fd, p->offset, SEEK_SET) < 0)
5394 return log_error_errno(errno, "Failed to seek to partition offset: %m");
5395
ab645e0a 5396 r = copy_bytes(fd, fdt, p->new_size, COPY_REFLINK|COPY_HOLES|COPY_TRUNCATE);
4cee8333 5397 if (r < 0)
62108348 5398 return log_error_errno(r, "Failed to copy to split partition %s: %m", p->split_path);
4cee8333
DDM
5399 }
5400
5401 return 0;
5402}
5403
cc751c75 5404static int context_write_partition_table(Context *context) {
f28d4f42
LP
5405 _cleanup_(fdisk_unref_tablep) struct fdisk_table *original_table = NULL;
5406 int capable, r;
5407
5408 assert(context);
5409
cc751c75 5410 if (!context->from_scratch && !context_changed(context)) {
f28d4f42
LP
5411 log_info("No changes.");
5412 return 0;
5413 }
5414
5415 if (arg_dry_run) {
5416 log_notice("Refusing to repartition, please re-run with --dry-run=no.");
5417 return 0;
5418 }
5419
5420 log_info("Applying changes.");
5421
cc751c75 5422 if (context->from_scratch) {
81873a6b
LP
5423 r = context_wipe_range(context, 0, context->total);
5424 if (r < 0)
5425 return r;
5426
5427 log_info("Wiped block device.");
5428
0dce448b
LB
5429 if (arg_discard) {
5430 r = context_discard_range(context, 0, context->total);
5431 if (r == -EOPNOTSUPP)
5432 log_info("Storage does not support discard, not discarding entire block device data.");
5433 else if (r < 0)
5434 return log_error_errno(r, "Failed to discard entire block device: %m");
5435 else if (r > 0)
5436 log_info("Discarded entire block device.");
5437 }
f28d4f42
LP
5438 }
5439
5440 r = fdisk_get_partitions(context->fdisk_context, &original_table);
5441 if (r < 0)
5442 return log_error_errno(r, "Failed to acquire partition table: %m");
5443
5444 /* Wipe fs signatures and discard sectors where the new partitions are going to be placed and in the
5445 * gaps between partitions, just to be sure. */
cc751c75 5446 r = context_wipe_and_discard(context);
f28d4f42
LP
5447 if (r < 0)
5448 return r;
5449
5450 r = context_copy_blocks(context);
5451 if (r < 0)
5452 return r;
5453
5454 r = context_mkfs(context);
5455 if (r < 0)
5456 return r;
5457
5458 r = context_mangle_partitions(context);
5459 if (r < 0)
5460 return r;
5461
e594a3b1
LP
5462 log_info("Writing new partition table.");
5463
5464 r = fdisk_write_disklabel(context->fdisk_context);
5465 if (r < 0)
5466 return log_error_errno(r, "Failed to write partition table: %m");
5467
911ba624 5468 capable = blockdev_partscan_enabled(fdisk_get_devfd(context->fdisk_context));
9a1deb85
LP
5469 if (capable == -ENOTBLK)
5470 log_debug("Not telling kernel to reread partition table, since we are not operating on a block device.");
5471 else if (capable < 0)
911ba624 5472 return log_error_errno(capable, "Failed to check if block device supports partition scanning: %m");
9a1deb85 5473 else if (capable > 0) {
e594a3b1
LP
5474 log_info("Telling kernel to reread partition table.");
5475
cc751c75 5476 if (context->from_scratch)
e594a3b1
LP
5477 r = fdisk_reread_partition_table(context->fdisk_context);
5478 else
5479 r = fdisk_reread_changes(context->fdisk_context, original_table);
5480 if (r < 0)
5481 return log_error_errno(r, "Failed to reread partition table: %m");
5482 } else
5483 log_notice("Not telling kernel to reread partition table, because selected image does not support kernel partition block devices.");
5484
5485 log_info("All done.");
5486
5487 return 0;
5488}
5489
5490static int context_read_seed(Context *context, const char *root) {
5491 int r;
5492
5493 assert(context);
5494
5495 if (!sd_id128_is_null(context->seed))
5496 return 0;
5497
5498 if (!arg_randomize) {
5ee37b70
YW
5499 r = id128_get_machine(root, &context->seed);
5500 if (r >= 0)
5501 return 0;
e594a3b1 5502
5ee37b70
YW
5503 if (!ERRNO_IS_MACHINE_ID_UNSET(r))
5504 return log_error_errno(r, "Failed to parse machine ID of image: %m");
74e795ee 5505
5ee37b70 5506 log_info("No machine ID set, using randomized partition UUIDs.");
e594a3b1
LP
5507 }
5508
5509 r = sd_id128_randomize(&context->seed);
5510 if (r < 0)
5511 return log_error_errno(r, "Failed to generate randomized seed: %m");
5512
5513 return 0;
5514}
5515
cc751c75 5516static int context_factory_reset(Context *context) {
e594a3b1
LP
5517 size_t n = 0;
5518 int r;
5519
5520 assert(context);
5521
5522 if (arg_factory_reset <= 0)
5523 return 0;
5524
cc751c75 5525 if (context->from_scratch) /* Nothing to reset if we start from scratch */
e594a3b1
LP
5526 return 0;
5527
5528 if (arg_dry_run) {
5529 log_notice("Refusing to factory reset, please re-run with --dry-run=no.");
5530 return 0;
5531 }
5532
5533 log_info("Applying factory reset.");
5534
5535 LIST_FOREACH(partitions, p, context->partitions) {
5536
5537 if (!p->factory_reset || !PARTITION_EXISTS(p))
5538 continue;
5539
5540 assert(p->partno != UINT64_MAX);
5541
5542 log_info("Removing partition %" PRIu64 " for factory reset.", p->partno);
5543
5544 r = fdisk_delete_partition(context->fdisk_context, p->partno);
5545 if (r < 0)
5546 return log_error_errno(r, "Failed to remove partition %" PRIu64 ": %m", p->partno);
5547
5548 n++;
5549 }
5550
5551 if (n == 0) {
5552 log_info("Factory reset requested, but no partitions to delete found.");
5553 return 0;
5554 }
5555
5556 r = fdisk_write_disklabel(context->fdisk_context);
5557 if (r < 0)
5558 return log_error_errno(r, "Failed to write disk label: %m");
5559
5560 log_info("Successfully deleted %zu partitions.", n);
5561 return 1;
5562}
5563
5564static int context_can_factory_reset(Context *context) {
e594a3b1
LP
5565 assert(context);
5566
5567 LIST_FOREACH(partitions, p, context->partitions)
5568 if (p->factory_reset && PARTITION_EXISTS(p))
5569 return true;
5570
5571 return false;
5572}
5573
5c08da58
LP
5574static int resolve_copy_blocks_auto_candidate(
5575 dev_t partition_devno,
22e932f4 5576 GptPartitionType partition_type,
5c08da58
LP
5577 dev_t restrict_devno,
5578 sd_id128_t *ret_uuid) {
5579
5580 _cleanup_(blkid_free_probep) blkid_probe b = NULL;
254d1313 5581 _cleanup_close_ int fd = -EBADF;
ca822829
YW
5582 _cleanup_free_ char *p = NULL;
5583 const char *pttype, *t;
5c08da58
LP
5584 sd_id128_t pt_parsed, u;
5585 blkid_partition pp;
5586 dev_t whole_devno;
5587 blkid_partlist pl;
5c08da58
LP
5588 int r;
5589
5590 /* Checks if the specified partition has the specified GPT type UUID, and is located on the specified
5591 * 'restrict_devno' device. The type check is particularly relevant if we have Verity volume which is
5592 * backed by two separate partitions: the data and the hash partitions, and we need to find the right
5593 * one of the two. */
5594
5595 r = block_get_whole_disk(partition_devno, &whole_devno);
5596 if (r < 0)
5597 return log_error_errno(
5598 r,
5599 "Unable to determine containing block device of partition %u:%u: %m",
5600 major(partition_devno), minor(partition_devno));
5601
5602 if (restrict_devno != (dev_t) -1 &&
5603 restrict_devno != whole_devno)
5604 return log_error_errno(
5605 SYNTHETIC_ERRNO(EPERM),
5606 "Partition %u:%u is located outside of block device %u:%u, refusing.",
5607 major(partition_devno), minor(partition_devno),
5608 major(restrict_devno), minor(restrict_devno));
5609
ca822829 5610 fd = r = device_open_from_devnum(S_IFBLK, whole_devno, O_RDONLY|O_CLOEXEC|O_NONBLOCK, &p);
5c08da58 5611 if (r < 0)
ca822829
YW
5612 return log_error_errno(r, "Failed to open block device " DEVNUM_FORMAT_STR ": %m",
5613 DEVNUM_FORMAT_VAL(whole_devno));
5c08da58
LP
5614
5615 b = blkid_new_probe();
5616 if (!b)
5617 return log_oom();
5618
5619 errno = 0;
5620 r = blkid_probe_set_device(b, fd, 0, 0);
5621 if (r != 0)
5622 return log_error_errno(errno_or_else(ENOMEM), "Failed to open block device '%s': %m", p);
5623
5624 (void) blkid_probe_enable_partitions(b, 1);
5625 (void) blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
5626
5627 errno = 0;
5628 r = blkid_do_safeprobe(b);
2e3944b8
LP
5629 if (r == _BLKID_SAFEPROBE_ERROR)
5630 return log_error_errno(errno_or_else(EIO), "Unable to probe for partition table of '%s': %m", p);
5631 if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND)) {
5c08da58
LP
5632 log_debug("Didn't find partition table on block device '%s'.", p);
5633 return false;
5634 }
2e3944b8
LP
5635
5636 assert(r == _BLKID_SAFEPROBE_FOUND);
5c08da58
LP
5637
5638 (void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
5639 if (!streq_ptr(pttype, "gpt")) {
5640 log_debug("Didn't find a GPT partition table on '%s'.", p);
5641 return false;
5642 }
5643
5644 errno = 0;
5645 pl = blkid_probe_get_partitions(b);
5646 if (!pl)
5647 return log_error_errno(errno_or_else(EIO), "Unable read partition table of '%s': %m", p);
5c08da58
LP
5648
5649 pp = blkid_partlist_devno_to_partition(pl, partition_devno);
5650 if (!pp) {
5651 log_debug("Partition %u:%u has no matching partition table entry on '%s'.",
5652 major(partition_devno), minor(partition_devno), p);
5653 return false;
5654 }
5655
5656 t = blkid_partition_get_type_string(pp);
5657 if (isempty(t)) {
5658 log_debug("Partition %u:%u has no type on '%s'.",
5659 major(partition_devno), minor(partition_devno), p);
5660 return false;
5661 }
5662
5663 r = sd_id128_from_string(t, &pt_parsed);
5664 if (r < 0) {
5665 log_debug_errno(r, "Failed to parse partition type \"%s\": %m", t);
5666 return false;
5667 }
5668
22e932f4 5669 if (!sd_id128_equal(pt_parsed, partition_type.uuid)) {
5c08da58
LP
5670 log_debug("Partition %u:%u has non-matching partition type " SD_ID128_FORMAT_STR " (needed: " SD_ID128_FORMAT_STR "), ignoring.",
5671 major(partition_devno), minor(partition_devno),
22e932f4 5672 SD_ID128_FORMAT_VAL(pt_parsed), SD_ID128_FORMAT_VAL(partition_type.uuid));
5c08da58
LP
5673 return false;
5674 }
5675
e3b9a5ff
LP
5676 r = blkid_partition_get_uuid_id128(pp, &u);
5677 if (r == -ENXIO) {
5678 log_debug_errno(r, "Partition " DEVNUM_FORMAT_STR " has no UUID.", DEVNUM_FORMAT_VAL(partition_devno));
5c08da58
LP
5679 return false;
5680 }
5c08da58 5681 if (r < 0) {
e3b9a5ff 5682 log_debug_errno(r, "Failed to read partition UUID of " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(partition_devno));
5c08da58
LP
5683 return false;
5684 }
5685
e3b9a5ff
LP
5686 log_debug("Automatically found partition " DEVNUM_FORMAT_STR " of right type " SD_ID128_FORMAT_STR ".",
5687 DEVNUM_FORMAT_VAL(partition_devno),
5c08da58
LP
5688 SD_ID128_FORMAT_VAL(pt_parsed));
5689
5690 if (ret_uuid)
5691 *ret_uuid = u;
5692
5693 return true;
5694}
5695
5696static int find_backing_devno(
5697 const char *path,
5698 const char *root,
5699 dev_t *ret) {
5700
5701 _cleanup_free_ char *resolved = NULL;
5702 int r;
5703
5704 assert(path);
5705
f461a28d 5706 r = chase(path, root, CHASE_PREFIX_ROOT, &resolved, NULL);
5c08da58
LP
5707 if (r < 0)
5708 return r;
5709
5710 r = path_is_mount_point(resolved, NULL, 0);
5711 if (r < 0)
5712 return r;
5713 if (r == 0) /* Not a mount point, then it's not a partition of its own, let's not automatically use it. */
5714 return -ENOENT;
5715
5716 r = get_block_device(resolved, ret);
5717 if (r < 0)
5718 return r;
5719 if (r == 0) /* Not backed by physical file system, we can't use this */
5720 return -ENOENT;
5721
5722 return 0;
5723}
5724
5725static int resolve_copy_blocks_auto(
22e932f4 5726 GptPartitionType type,
5c08da58
LP
5727 const char *root,
5728 dev_t restrict_devno,
1a037ba2 5729 dev_t *ret_devno,
5c08da58
LP
5730 sd_id128_t *ret_uuid) {
5731
5732 const char *try1 = NULL, *try2 = NULL;
5733 char p[SYS_BLOCK_PATH_MAX("/slaves")];
5d2a48da 5734 _cleanup_closedir_ DIR *d = NULL;
5c08da58
LP
5735 sd_id128_t found_uuid = SD_ID128_NULL;
5736 dev_t devno, found = 0;
5737 int r;
5738
86320e62
DDM
5739 /* Enforce some security restrictions: CopyBlocks=auto should not be an avenue to get outside of the
5740 * --root=/--image= confinement. Specifically, refuse CopyBlocks= in combination with --root= at all,
5741 * and restrict block device references in the --image= case to loopback block device we set up.
5742 *
5743 * restrict_devno contain the dev_t of the loop back device we operate on in case of --image=, and
5744 * thus declares which device (and its partition subdevices) we shall limit access to. If
5745 * restrict_devno is zero no device probing access shall be allowed at all (used for --root=) and if
5746 * it is (dev_t) -1 then free access shall be allowed (if neither switch is used). */
5747
5748 if (restrict_devno == 0)
5749 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
5750 "Automatic discovery of backing block devices not permitted in --root= mode, refusing.");
5751
5c08da58
LP
5752 /* Handles CopyBlocks=auto, and finds the right source partition to copy from. We look for matching
5753 * partitions in the host, using the appropriate directory as key and ensuring that the partition
5754 * type matches. */
5755
22e932f4 5756 if (type.designator == PARTITION_ROOT)
5c08da58 5757 try1 = "/";
22e932f4 5758 else if (type.designator == PARTITION_USR)
5c08da58 5759 try1 = "/usr/";
22e932f4 5760 else if (type.designator == PARTITION_ROOT_VERITY)
5c08da58 5761 try1 = "/";
22e932f4 5762 else if (type.designator == PARTITION_USR_VERITY)
5c08da58 5763 try1 = "/usr/";
22e932f4 5764 else if (type.designator == PARTITION_ESP) {
5c08da58
LP
5765 try1 = "/efi/";
5766 try2 = "/boot/";
22e932f4 5767 } else if (type.designator == PARTITION_XBOOTLDR)
5c08da58
LP
5768 try1 = "/boot/";
5769 else
5770 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
5771 "Partition type " SD_ID128_FORMAT_STR " not supported from automatic source block device discovery.",
22e932f4 5772 SD_ID128_FORMAT_VAL(type.uuid));
5c08da58
LP
5773
5774 r = find_backing_devno(try1, root, &devno);
5775 if (r == -ENOENT && try2)
5776 r = find_backing_devno(try2, root, &devno);
5777 if (r < 0)
5778 return log_error_errno(r, "Failed to resolve automatic CopyBlocks= path for partition type " SD_ID128_FORMAT_STR ", sorry: %m",
22e932f4 5779 SD_ID128_FORMAT_VAL(type.uuid));
5c08da58
LP
5780
5781 xsprintf_sys_block_path(p, "/slaves", devno);
5782 d = opendir(p);
5783 if (d) {
5784 struct dirent *de;
5785
5786 for (;;) {
5787 _cleanup_free_ char *q = NULL, *t = NULL;
5788 sd_id128_t u;
5789 dev_t sl;
5790
5791 errno = 0;
5792 de = readdir_no_dot(d);
5793 if (!de) {
5794 if (errno != 0)
5795 return log_error_errno(errno, "Failed to read directory '%s': %m", p);
5796
5797 break;
5798 }
5799
5800 if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
5801 continue;
5802
5803 q = path_join(p, de->d_name, "/dev");
5804 if (!q)
5805 return log_oom();
5806
5807 r = read_one_line_file(q, &t);
5808 if (r < 0)
5809 return log_error_errno(r, "Failed to read %s: %m", q);
5810
7176f06c 5811 r = parse_devnum(t, &sl);
5c08da58
LP
5812 if (r < 0) {
5813 log_debug_errno(r, "Failed to parse %s, ignoring: %m", q);
5814 continue;
5815 }
5816 if (major(sl) == 0) {
375ffdba 5817 log_debug("Device backing %s is special, ignoring.", q);
5c08da58
LP
5818 continue;
5819 }
5820
22e932f4 5821 r = resolve_copy_blocks_auto_candidate(sl, type, restrict_devno, &u);
5c08da58
LP
5822 if (r < 0)
5823 return r;
5824 if (r > 0) {
5825 /* We found a matching one! */
5826 if (found != 0)
5827 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
5828 "Multiple matching partitions found, refusing.");
5829
5830 found = sl;
5831 found_uuid = u;
5832 }
5833 }
5834 } else if (errno != ENOENT)
5835 return log_error_errno(errno, "Failed open %s: %m", p);
5836 else {
22e932f4 5837 r = resolve_copy_blocks_auto_candidate(devno, type, restrict_devno, &found_uuid);
5c08da58
LP
5838 if (r < 0)
5839 return r;
5840 if (r > 0)
5841 found = devno;
5842 }
5843
86320e62
DDM
5844 if (found == 0)
5845 return log_error_errno(SYNTHETIC_ERRNO(ENXIO),
5846 "Unable to automatically discover suitable partition to copy blocks from.");
5847
1a037ba2
YW
5848 if (ret_devno)
5849 *ret_devno = found;
5c08da58
LP
5850
5851 if (ret_uuid)
5852 *ret_uuid = found_uuid;
5853
86320e62 5854 return 0;
5c08da58
LP
5855}
5856
5857static int context_open_copy_block_paths(
5858 Context *context,
5c08da58
LP
5859 dev_t restrict_devno) {
5860
757bc2e4
LP
5861 int r;
5862
5863 assert(context);
5864
5865 LIST_FOREACH(partitions, p, context->partitions) {
254d1313 5866 _cleanup_close_ int source_fd = -EBADF;
5c08da58
LP
5867 _cleanup_free_ char *opened = NULL;
5868 sd_id128_t uuid = SD_ID128_NULL;
757bc2e4
LP
5869 uint64_t size;
5870 struct stat st;
5871
5eef7047
DDM
5872 if (p->copy_blocks_fd >= 0)
5873 continue;
5874
757bc2e4
LP
5875 assert(p->copy_blocks_size == UINT64_MAX);
5876
5877 if (PARTITION_EXISTS(p)) /* Never copy over partitions that already exist! */
5878 continue;
5879
5c08da58 5880 if (p->copy_blocks_path) {
757bc2e4 5881
f461a28d 5882 source_fd = chase_and_open(p->copy_blocks_path, p->copy_blocks_root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC|O_NONBLOCK, &opened);
5c08da58
LP
5883 if (source_fd < 0)
5884 return log_error_errno(source_fd, "Failed to open '%s': %m", p->copy_blocks_path);
757bc2e4 5885
5c08da58
LP
5886 if (fstat(source_fd, &st) < 0)
5887 return log_error_errno(errno, "Failed to stat block copy file '%s': %m", opened);
5888
5889 if (!S_ISREG(st.st_mode) && restrict_devno != (dev_t) -1)
5890 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
5891 "Copying from block device node is not permitted in --image=/--root= mode, refusing.");
5892
5893 } else if (p->copy_blocks_auto) {
03f5e501 5894 dev_t devno = 0; /* Fake initialization to appease gcc. */
5c08da58 5895
22e932f4 5896 r = resolve_copy_blocks_auto(p->type, p->copy_blocks_root, restrict_devno, &devno, &uuid);
5c08da58
LP
5897 if (r < 0)
5898 return r;
03f5e501 5899 assert(devno != 0);
5c08da58 5900
ca822829 5901 source_fd = r = device_open_from_devnum(S_IFBLK, devno, O_RDONLY|O_CLOEXEC|O_NONBLOCK, &opened);
1a037ba2 5902 if (r < 0)
ca822829
YW
5903 return log_error_errno(r, "Failed to open automatically determined source block copy device " DEVNUM_FORMAT_STR ": %m",
5904 DEVNUM_FORMAT_VAL(devno));
5c08da58
LP
5905
5906 if (fstat(source_fd, &st) < 0)
5907 return log_error_errno(errno, "Failed to stat block copy file '%s': %m", opened);
1a037ba2 5908 } else
5c08da58 5909 continue;
757bc2e4
LP
5910
5911 if (S_ISDIR(st.st_mode)) {
ca822829
YW
5912 _cleanup_free_ char *bdev = NULL;
5913 dev_t devt;
757bc2e4
LP
5914
5915 /* If the file is a directory, automatically find the backing block device */
5916
5917 if (major(st.st_dev) != 0)
ca822829 5918 devt = st.st_dev;
757bc2e4 5919 else {
757bc2e4 5920 /* Special support for btrfs */
757bc2e4 5921 r = btrfs_get_block_device_fd(source_fd, &devt);
67f0ac8c 5922 if (r == -EUCLEAN)
5c08da58 5923 return btrfs_log_dev_root(LOG_ERR, r, opened);
757bc2e4 5924 if (r < 0)
5c08da58 5925 return log_error_errno(r, "Unable to determine backing block device of '%s': %m", opened);
757bc2e4 5926 }
757bc2e4
LP
5927
5928 safe_close(source_fd);
5929
ca822829
YW
5930 source_fd = r = device_open_from_devnum(S_IFBLK, devt, O_RDONLY|O_CLOEXEC|O_NONBLOCK, &bdev);
5931 if (r < 0)
5932 return log_error_errno(r, "Failed to open block device backing '%s': %m", opened);
757bc2e4
LP
5933
5934 if (fstat(source_fd, &st) < 0)
5935 return log_error_errno(errno, "Failed to stat block device '%s': %m", bdev);
757bc2e4
LP
5936 }
5937
5938 if (S_ISREG(st.st_mode))
5939 size = st.st_size;
5940 else if (S_ISBLK(st.st_mode)) {
5941 if (ioctl(source_fd, BLKGETSIZE64, &size) != 0)
5942 return log_error_errno(errno, "Failed to determine size of block device to copy from: %m");
5943 } else
5c08da58 5944 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Specified path to copy blocks from '%s' is not a regular file, block device or directory, refusing: %m", opened);
757bc2e4
LP
5945
5946 if (size <= 0)
5c08da58 5947 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File to copy bytes from '%s' has zero size, refusing.", opened);
757bc2e4 5948 if (size % 512 != 0)
5c08da58 5949 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File to copy bytes from '%s' has size that is not multiple of 512, refusing.", opened);
757bc2e4
LP
5950
5951 p->copy_blocks_fd = TAKE_FD(source_fd);
5952 p->copy_blocks_size = size;
5c08da58
LP
5953
5954 free_and_replace(p->copy_blocks_path, opened);
5955
5956 /* When copying from an existing partition copy that partitions UUID if none is configured explicitly */
11749b61 5957 if (!p->new_uuid_is_set && !sd_id128_is_null(uuid)) {
5c08da58 5958 p->new_uuid = uuid;
11749b61
DDM
5959 p->new_uuid_is_set = true;
5960 }
757bc2e4
LP
5961 }
5962
5963 return 0;
5964}
5965
c4a87b76
DDM
5966static int fd_apparent_size(int fd, uint64_t *ret) {
5967 off_t initial = 0;
5968 uint64_t size = 0;
5969
5970 assert(fd >= 0);
5971 assert(ret);
5972
5973 initial = lseek(fd, 0, SEEK_CUR);
5974 if (initial < 0)
5975 return log_error_errno(errno, "Failed to get file offset: %m");
5976
5977 for (off_t off = 0;;) {
5978 off_t r;
5979
5980 r = lseek(fd, off, SEEK_DATA);
5981 if (r < 0 && errno == ENXIO)
5982 /* If errno == ENXIO, that means we've reached the final hole of the file and
5983 * that hole isn't followed by more data. */
5984 break;
5985 if (r < 0)
5986 return log_error_errno(errno, "Failed to seek data in file from offset %"PRIi64": %m", off);
5987
5988 off = r; /* Set the offset to the start of the data segment. */
5989
5990 /* After copying a potential hole, find the end of the data segment by looking for
5991 * the next hole. If we get ENXIO, we're at EOF. */
5992 r = lseek(fd, off, SEEK_HOLE);
5993 if (r < 0) {
5994 if (errno == ENXIO)
5995 break;
5996 return log_error_errno(errno, "Failed to seek hole in file from offset %"PRIi64": %m", off);
5997 }
5998
5999 size += r - off;
6000 off = r;
6001 }
6002
6003 if (lseek(fd, initial, SEEK_SET) < 0)
6004 return log_error_errno(errno, "Failed to reset file offset: %m");
6005
6006 *ret = size;
6007
6008 return 0;
6009}
6010
6011static int context_minimize(Context *context) {
c264ec5f 6012 const char *vt = NULL;
c4a87b76
DDM
6013 int r;
6014
6015 assert(context);
6016
c4a87b76 6017 LIST_FOREACH(partitions, p, context->partitions) {
e59678b2 6018 _cleanup_(rm_rf_physical_and_freep) char *root = NULL;
c4a87b76 6019 _cleanup_(unlink_and_freep) char *temp = NULL;
d3201eb4 6020 _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
4b8ce14f 6021 _cleanup_strv_free_ char **extra_mkfs_options = NULL;
254d1313 6022 _cleanup_close_ int fd = -EBADF;
b24bfd6e 6023 _cleanup_free_ char *hint = NULL;
c4a87b76 6024 sd_id128_t fs_uuid;
6ac299e3 6025 struct stat st;
c4a87b76
DDM
6026 uint64_t fsz;
6027
6028 if (p->dropped)
6029 continue;
6030
6031 if (PARTITION_EXISTS(p)) /* Never format existing partitions */
6032 continue;
6033
6034 if (!p->format)
6035 continue;
6036
dea0dc7b
DDM
6037 if (p->copy_blocks_fd >= 0)
6038 continue;
6039
5c33b686 6040 if (p->minimize == MINIMIZE_OFF)
c4a87b76
DDM
6041 continue;
6042
d3201eb4
DDM
6043 if (!partition_needs_populate(p))
6044 continue;
6045
c4a87b76
DDM
6046 assert(!p->copy_blocks_path);
6047
b24bfd6e
DDM
6048 (void) partition_hint(p, context->node, &hint);
6049
6050 log_info("Pre-populating %s filesystem of partition %s twice to calculate minimal partition size",
6051 p->format, strna(hint));
6052
c264ec5f
ZJS
6053 if (!vt) {
6054 r = var_tmp_dir(&vt);
6055 if (r < 0)
6056 return log_error_errno(r, "Could not determine temporary directory: %m");
6057 }
6058
c4a87b76
DDM
6059 r = tempfn_random_child(vt, "repart", &temp);
6060 if (r < 0)
6061 return log_error_errno(r, "Failed to generate temporary file path: %m");
6062
59e2be46
DDM
6063 if (fstype_is_ro(p->format))
6064 fs_uuid = p->fs_uuid;
6065 else {
c4a87b76
DDM
6066 fd = open(temp, O_CREAT|O_EXCL|O_CLOEXEC|O_RDWR|O_NOCTTY, 0600);
6067 if (fd < 0)
6068 return log_error_errno(errno, "Failed to open temporary file %s: %m", temp);
6069
6070 /* This may seem huge but it will be created sparse so it doesn't take up any space
d3201eb4 6071 * on disk until written to. */
c4a87b76
DDM
6072 if (ftruncate(fd, 1024ULL * 1024ULL * 1024ULL * 1024ULL) < 0)
6073 return log_error_errno(errno, "Failed to truncate temporary file to %s: %m",
6074 FORMAT_BYTES(1024ULL * 1024ULL * 1024ULL * 1024ULL));
6075
e30c6e91 6076 if (arg_offline <= 0) {
66a8c74c 6077 r = loop_device_make(fd, O_RDWR, 0, UINT64_MAX, context->sector_size, 0, LOCK_EX, &d);
ffd9d75c 6078 if (r < 0 && (arg_offline == 0 || (r != -ENOENT && !ERRNO_IS_PRIVILEGE(r)) || !strv_isempty(p->subvolumes)))
e30c6e91
DDM
6079 return log_error_errno(r, "Failed to make loopback device of %s: %m", temp);
6080 }
d3201eb4 6081
c4a87b76
DDM
6082 /* We're going to populate this filesystem twice so use a random UUID the first time
6083 * to avoid UUID conflicts. */
6084 r = sd_id128_randomize(&fs_uuid);
6085 if (r < 0)
6086 return r;
59e2be46
DDM
6087 }
6088
d3201eb4
DDM
6089 if (!d || fstype_is_ro(p->format)) {
6090 if (!mkfs_supports_root_option(p->format))
6091 return log_error_errno(SYNTHETIC_ERRNO(ENODEV),
6092 "Loop device access is required to populate %s filesystems",
6093 p->format);
6094
e57b7020 6095 r = partition_populate_directory(context, p, &root);
c4a87b76
DDM
6096 if (r < 0)
6097 return r;
c4a87b76
DDM
6098 }
6099
4b8ce14f
DDM
6100 r = mkfs_options_from_env("REPART", p->format, &extra_mkfs_options);
6101 if (r < 0)
6102 return log_error_errno(r,
6103 "Failed to determine mkfs command line options for '%s': %m",
6104 p->format);
6105
93f125a6
DDM
6106 r = make_filesystem(d ? d->node : temp,
6107 p->format,
6108 strempty(p->new_label),
6109 root,
6110 fs_uuid,
6111 arg_discard, /* quiet = */ false,
6112 context->fs_sector_size,
6113 extra_mkfs_options);
c4a87b76
DDM
6114 if (r < 0)
6115 return r;
6116
6117 /* Read-only filesystems are minimal from the first try because they create and size the
6118 * loopback file for us. */
6119 if (fstype_is_ro(p->format)) {
dea0dc7b 6120 assert(fd < 0);
2843df3e 6121
dea0dc7b
DDM
6122 fd = open(temp, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
6123 if (fd < 0)
6124 return log_error_errno(errno, "Failed to open temporary file %s: %m", temp);
6125
6126 if (fstat(fd, &st) < 0)
b24bfd6e
DDM
6127 return log_error_errno(errno, "Failed to stat temporary file: %m");
6128
6129 log_info("Minimal partition size of %s filesystem of partition %s is %s",
6130 p->format, strna(hint), FORMAT_BYTES(st.st_size));
6131
c4a87b76 6132 p->copy_blocks_path = TAKE_PTR(temp);
7d07030e 6133 p->copy_blocks_path_is_our_file = true;
2843df3e
DDM
6134 p->copy_blocks_fd = TAKE_FD(fd);
6135 p->copy_blocks_size = st.st_size;
c4a87b76
DDM
6136 continue;
6137 }
6138
d3201eb4
DDM
6139 if (!root) {
6140 assert(d);
6141
e57b7020 6142 r = partition_populate_filesystem(context, p, d->node);
59e2be46
DDM
6143 if (r < 0)
6144 return r;
6145 }
c4a87b76
DDM
6146
6147 /* Other filesystems need to be provided with a pre-sized loopback file and will adapt to
6148 * fully occupy it. Because we gave the filesystem a 1T sparse file, we need to shrink the
6149 * filesystem down to a reasonable size again to fit it in the disk image. While there are
6150 * some filesystems that support shrinking, it doesn't always work properly (e.g. shrinking
6151 * btrfs gives us a 2.0G filesystem regardless of what we put in it). Instead, let's populate
6152 * the filesystem again, but this time, instead of providing the filesystem with a 1T sparse
6153 * loopback file, let's size the loopback file based on the actual data used by the
6154 * filesystem in the sparse file after the first attempt. This should be a good guess of the
6155 * minimal amount of space needed in the filesystem to fit all the required data.
6156 */
6157 r = fd_apparent_size(fd, &fsz);
6158 if (r < 0)
6159 return r;
6160
6161 /* Massage the size a bit because just going by actual data used in the sparse file isn't
6162 * fool-proof. */
7bc6c028
DDM
6163 uint64_t heuristic = streq(p->format, "xfs") ? fsz : fsz / 2;
6164 fsz = round_up_size(fsz + heuristic, context->grain_size);
c4a87b76
DDM
6165 if (minimal_size_by_fs_name(p->format) != UINT64_MAX)
6166 fsz = MAX(minimal_size_by_fs_name(p->format), fsz);
6167
b24bfd6e
DDM
6168 log_info("Minimal partition size of %s filesystem of partition %s is %s",
6169 p->format, strna(hint), FORMAT_BYTES(fsz));
6170
d3201eb4
DDM
6171 d = loop_device_unref(d);
6172
c4a87b76
DDM
6173 /* Erase the previous filesystem first. */
6174 if (ftruncate(fd, 0))
6175 return log_error_errno(errno, "Failed to erase temporary file: %m");
6176
6177 if (ftruncate(fd, fsz))
6178 return log_error_errno(errno, "Failed to truncate temporary file to %s: %m", FORMAT_BYTES(fsz));
6179
e30c6e91 6180 if (arg_offline <= 0) {
66a8c74c 6181 r = loop_device_make(fd, O_RDWR, 0, UINT64_MAX, context->sector_size, 0, LOCK_EX, &d);
ffd9d75c 6182 if (r < 0 && (arg_offline == 0 || (r != -ENOENT && !ERRNO_IS_PRIVILEGE(r)) || !strv_isempty(p->subvolumes)))
e30c6e91
DDM
6183 return log_error_errno(r, "Failed to make loopback device of %s: %m", temp);
6184 }
d3201eb4 6185
93f125a6
DDM
6186 r = make_filesystem(d ? d->node : temp,
6187 p->format,
6188 strempty(p->new_label),
6189 root,
6190 p->fs_uuid,
6191 arg_discard,
6192 /* quiet = */ false,
6193 context->fs_sector_size,
6194 extra_mkfs_options);
c4a87b76
DDM
6195 if (r < 0)
6196 return r;
6197
d3201eb4
DDM
6198 if (!root) {
6199 assert(d);
6200
e57b7020 6201 r = partition_populate_filesystem(context, p, d->node);
59e2be46
DDM
6202 if (r < 0)
6203 return r;
6204 }
c4a87b76 6205
6ac299e3
DDM
6206 if (fstat(fd, &st) < 0)
6207 return log_error_errno(errno, "Failed to stat temporary file: %m");
dea0dc7b 6208
c4a87b76 6209 p->copy_blocks_path = TAKE_PTR(temp);
7d07030e 6210 p->copy_blocks_path_is_our_file = true;
2843df3e 6211 p->copy_blocks_fd = TAKE_FD(fd);
6ac299e3 6212 p->copy_blocks_size = st.st_size;
c4a87b76
DDM
6213 }
6214
5eef7047
DDM
6215 /* Now that we've done the data partitions, do the verity hash partitions. We do these in a separate
6216 * step because they might depend on data generated in the previous step. */
6217
6218 LIST_FOREACH(partitions, p, context->partitions) {
6219 _cleanup_(unlink_and_freep) char *temp = NULL;
6220 _cleanup_free_ char *hint = NULL;
2843df3e 6221 _cleanup_close_ int fd = -EBADF;
5eef7047
DDM
6222 struct stat st;
6223 Partition *dp;
6224
6225 if (p->dropped)
6226 continue;
6227
6228 if (PARTITION_EXISTS(p)) /* Never format existing partitions */
6229 continue;
6230
6231 if (p->minimize == MINIMIZE_OFF)
6232 continue;
6233
6234 if (p->verity != VERITY_HASH)
6235 continue;
6236
6237 assert_se(dp = p->siblings[VERITY_DATA]);
6238 assert(!dp->dropped);
6239 assert(dp->copy_blocks_path);
6240
6241 (void) partition_hint(p, context->node, &hint);
6242
6243 log_info("Pre-populating verity hash data of partition %s to calculate minimal partition size",
6244 strna(hint));
6245
c264ec5f
ZJS
6246 if (!vt) {
6247 r = var_tmp_dir(&vt);
6248 if (r < 0)
6249 return log_error_errno(r, "Could not determine temporary directory: %m");
6250 }
6251
5eef7047
DDM
6252 r = tempfn_random_child(vt, "repart", &temp);
6253 if (r < 0)
6254 return log_error_errno(r, "Failed to generate temporary file path: %m");
6255
6256 r = touch(temp);
6257 if (r < 0)
6258 return log_error_errno(r, "Failed to create temporary file: %m");
6259
6260 r = partition_format_verity_hash(context, p, temp, dp->copy_blocks_path);
6261 if (r < 0)
6262 return r;
6263
2843df3e
DDM
6264 fd = open(temp, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
6265 if (fd < 0)
6266 return log_error_errno(errno, "Failed to open temporary file %s: %m", temp);
6267
6268 if (fstat(fd, &st) < 0)
5eef7047
DDM
6269 return log_error_errno(r, "Failed to stat temporary file: %m");
6270
6271 log_info("Minimal partition size of verity hash partition %s is %s",
6272 strna(hint), FORMAT_BYTES(st.st_size));
6273
6274 p->copy_blocks_path = TAKE_PTR(temp);
6275 p->copy_blocks_path_is_our_file = true;
2843df3e
DDM
6276 p->copy_blocks_fd = TAKE_FD(fd);
6277 p->copy_blocks_size = st.st_size;
5eef7047
DDM
6278 }
6279
c4a87b76
DDM
6280 return 0;
6281}
6282
9786dfe6 6283static int parse_partition_types(const char *p, GptPartitionType **partitions, size_t *n_partitions) {
81d1098b
DDM
6284 int r;
6285
220780db
DDM
6286 assert(partitions);
6287 assert(n_partitions);
6288
81d1098b
DDM
6289 for (;;) {
6290 _cleanup_free_ char *name = NULL;
6291 GptPartitionType type;
6292
6293 r = extract_first_word(&p, &name, ",", EXTRACT_CUNESCAPE|EXTRACT_DONT_COALESCE_SEPARATORS);
6294 if (r == 0)
6295 break;
6296 if (r < 0)
766f52f2 6297 return log_error_errno(r, "Failed to extract partition type identifier or GUID: %s", p);
81d1098b
DDM
6298
6299 r = gpt_partition_type_from_string(name, &type);
6300 if (r < 0)
766f52f2 6301 return log_error_errno(r, "'%s' is not a valid partition type identifier or GUID", name);
81d1098b 6302
220780db 6303 if (!GREEDY_REALLOC(*partitions, *n_partitions + 1))
81d1098b
DDM
6304 return log_oom();
6305
9786dfe6 6306 (*partitions)[(*n_partitions)++] = type;
81d1098b
DDM
6307 }
6308
6309 return 0;
6310}
6311
e594a3b1
LP
6312static int help(void) {
6313 _cleanup_free_ char *link = NULL;
6314 int r;
6315
6dadf31d 6316 r = terminal_urlify_man("systemd-repart", "8", &link);
e594a3b1
LP
6317 if (r < 0)
6318 return log_oom();
6319
6320 printf("%s [OPTIONS...] [DEVICE]\n"
6321 "\n%sGrow and add partitions to partition table.%s\n\n"
6322 " -h --help Show this help\n"
6323 " --version Show package version\n"
896e678b
LP
6324 " --no-pager Do not pipe output into a pager\n"
6325 " --no-legend Do not show the headers and footers\n"
e594a3b1 6326 " --dry-run=BOOL Whether to run dry-run operation\n"
a26f4a49
LP
6327 " --empty=MODE One of refuse, allow, require, force, create; controls\n"
6328 " how to handle empty disks lacking partition tables\n"
e594a3b1 6329 " --discard=BOOL Whether to discard backing blocks for new partitions\n"
2d2d0a57 6330 " --pretty=BOOL Whether to show pretty summary before doing changes\n"
e594a3b1
LP
6331 " --factory-reset=BOOL Whether to remove data partitions before recreating\n"
6332 " them\n"
6333 " --can-factory-reset Test whether factory reset is defined\n"
6334 " --root=PATH Operate relative to root path\n"
252d6267 6335 " --image=PATH Operate relative to image file\n"
84be0c71
LP
6336 " --image-policy=POLICY\n"
6337 " Specify disk image dissection policy\n"
9d252fbb 6338 " --definitions=DIR Find partition definitions in specified directory\n"
b9df3536 6339 " --key-file=PATH Key to use when encrypting partitions\n"
b456191d
DDM
6340 " --private-key=PATH Private key to use when generating verity roothash\n"
6341 " signatures\n"
6342 " --certificate=PATH PEM certificate to use when generating verity\n"
6343 " roothash signatures\n"
889914ef 6344 " --tpm2-device=PATH Path to TPM2 device node to use\n"
a1788a69 6345 " --tpm2-pcrs=PCR1+PCR2+PCR3+…\n"
889914ef 6346 " TPM2 PCR indexes to use for TPM2 enrollment\n"
02ef97cd
LP
6347 " --tpm2-public-key=PATH\n"
6348 " Enroll signed TPM2 PCR policy against PEM public key\n"
6349 " --tpm2-public-key-pcrs=PCR1+PCR2+PCR3+…\n"
6350 " Enroll signed TPM2 PCR policy for specified TPM2 PCRs\n"
da890466 6351 " --seed=UUID 128-bit seed UUID to derive all UUIDs from\n"
a26f4a49 6352 " --size=BYTES Grow loopback file to specified size\n"
2d2d0a57 6353 " --json=pretty|short|off\n"
de8231b0 6354 " Generate JSON output\n"
4cee8333 6355 " --split=BOOL Whether to generate split artifacts\n"
81d1098b 6356 " --include-partitions=PARTITION1,PARTITION2,PARTITION3,…\n"
7d505753 6357 " Ignore partitions not of the specified types\n"
81d1098b 6358 " --exclude-partitions=PARTITION1,PARTITION2,PARTITION3,…\n"
7d505753 6359 " Ignore partitions of the specified types\n"
8275334b 6360 " --defer-partitions=PARTITION1,PARTITION2,PARTITION3,…\n"
7d505753
DDM
6361 " Take partitions of the specified types into account\n"
6362 " but don't populate them yet\n"
e1878ef7 6363 " --sector-size=SIZE Set the logical sector size for the image\n"
9786dfe6 6364 " --architecture=ARCH Set the generic architecture for the image\n"
fc10b158 6365 " --offline=BOOL Whether to build the image offline\n"
e1536d1f 6366 " --copy-from=IMAGE Copy partitions from the given image(s)\n"
bc556335
DDM
6367 "\nSee the %s for details.\n",
6368 program_invocation_short_name,
6369 ansi_highlight(),
6370 ansi_normal(),
6371 link);
e594a3b1
LP
6372
6373 return 0;
6374}
6375
6376static int parse_argv(int argc, char *argv[]) {
6377
6378 enum {
6379 ARG_VERSION = 0x100,
896e678b
LP
6380 ARG_NO_PAGER,
6381 ARG_NO_LEGEND,
e594a3b1
LP
6382 ARG_DRY_RUN,
6383 ARG_EMPTY,
6384 ARG_DISCARD,
6385 ARG_FACTORY_RESET,
6386 ARG_CAN_FACTORY_RESET,
6387 ARG_ROOT,
252d6267 6388 ARG_IMAGE,
06e78680 6389 ARG_IMAGE_POLICY,
e594a3b1
LP
6390 ARG_SEED,
6391 ARG_PRETTY,
6392 ARG_DEFINITIONS,
a26f4a49 6393 ARG_SIZE,
a015fbe7 6394 ARG_JSON,
b9df3536 6395 ARG_KEY_FILE,
b456191d
DDM
6396 ARG_PRIVATE_KEY,
6397 ARG_CERTIFICATE,
889914ef
LP
6398 ARG_TPM2_DEVICE,
6399 ARG_TPM2_PCRS,
02ef97cd
LP
6400 ARG_TPM2_PUBLIC_KEY,
6401 ARG_TPM2_PUBLIC_KEY_PCRS,
4cee8333 6402 ARG_SPLIT,
81d1098b
DDM
6403 ARG_INCLUDE_PARTITIONS,
6404 ARG_EXCLUDE_PARTITIONS,
8275334b 6405 ARG_DEFER_PARTITIONS,
e1878ef7 6406 ARG_SECTOR_SIZE,
84be0c71 6407 ARG_SKIP_PARTITIONS,
9786dfe6 6408 ARG_ARCHITECTURE,
fc10b158 6409 ARG_OFFLINE,
1e46985a 6410 ARG_COPY_FROM,
e594a3b1
LP
6411 };
6412
6413 static const struct option options[] = {
02ef97cd
LP
6414 { "help", no_argument, NULL, 'h' },
6415 { "version", no_argument, NULL, ARG_VERSION },
6416 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
6417 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
6418 { "dry-run", required_argument, NULL, ARG_DRY_RUN },
6419 { "empty", required_argument, NULL, ARG_EMPTY },
6420 { "discard", required_argument, NULL, ARG_DISCARD },
6421 { "factory-reset", required_argument, NULL, ARG_FACTORY_RESET },
6422 { "can-factory-reset", no_argument, NULL, ARG_CAN_FACTORY_RESET },
6423 { "root", required_argument, NULL, ARG_ROOT },
6424 { "image", required_argument, NULL, ARG_IMAGE },
06e78680 6425 { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY },
02ef97cd
LP
6426 { "seed", required_argument, NULL, ARG_SEED },
6427 { "pretty", required_argument, NULL, ARG_PRETTY },
6428 { "definitions", required_argument, NULL, ARG_DEFINITIONS },
6429 { "size", required_argument, NULL, ARG_SIZE },
6430 { "json", required_argument, NULL, ARG_JSON },
6431 { "key-file", required_argument, NULL, ARG_KEY_FILE },
b456191d
DDM
6432 { "private-key", required_argument, NULL, ARG_PRIVATE_KEY },
6433 { "certificate", required_argument, NULL, ARG_CERTIFICATE },
02ef97cd
LP
6434 { "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
6435 { "tpm2-pcrs", required_argument, NULL, ARG_TPM2_PCRS },
6436 { "tpm2-public-key", required_argument, NULL, ARG_TPM2_PUBLIC_KEY },
6437 { "tpm2-public-key-pcrs", required_argument, NULL, ARG_TPM2_PUBLIC_KEY_PCRS },
4cee8333 6438 { "split", required_argument, NULL, ARG_SPLIT },
81d1098b
DDM
6439 { "include-partitions", required_argument, NULL, ARG_INCLUDE_PARTITIONS },
6440 { "exclude-partitions", required_argument, NULL, ARG_EXCLUDE_PARTITIONS },
8275334b 6441 { "defer-partitions", required_argument, NULL, ARG_DEFER_PARTITIONS },
e1878ef7 6442 { "sector-size", required_argument, NULL, ARG_SECTOR_SIZE },
9786dfe6 6443 { "architecture", required_argument, NULL, ARG_ARCHITECTURE },
fc10b158 6444 { "offline", required_argument, NULL, ARG_OFFLINE },
1e46985a 6445 { "copy-from", required_argument, NULL, ARG_COPY_FROM },
e594a3b1
LP
6446 {}
6447 };
6448
a26f4a49 6449 int c, r, dry_run = -1;
e594a3b1
LP
6450
6451 assert(argc >= 0);
6452 assert(argv);
6453
6454 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
6455
6456 switch (c) {
6457
6458 case 'h':
6459 return help();
6460
6461 case ARG_VERSION:
6462 return version();
6463
896e678b
LP
6464 case ARG_NO_PAGER:
6465 arg_pager_flags |= PAGER_DISABLE;
6466 break;
6467
6468 case ARG_NO_LEGEND:
6469 arg_legend = false;
6470 break;
6471
e594a3b1 6472 case ARG_DRY_RUN:
599c7c54 6473 r = parse_boolean_argument("--dry-run=", optarg, &arg_dry_run);
e594a3b1 6474 if (r < 0)
599c7c54 6475 return r;
e594a3b1
LP
6476 break;
6477
6478 case ARG_EMPTY:
6479 if (isempty(optarg) || streq(optarg, "refuse"))
6480 arg_empty = EMPTY_REFUSE;
6481 else if (streq(optarg, "allow"))
6482 arg_empty = EMPTY_ALLOW;
6483 else if (streq(optarg, "require"))
6484 arg_empty = EMPTY_REQUIRE;
6485 else if (streq(optarg, "force"))
6486 arg_empty = EMPTY_FORCE;
a26f4a49
LP
6487 else if (streq(optarg, "create")) {
6488 arg_empty = EMPTY_CREATE;
6489
6490 if (dry_run < 0)
6491 dry_run = false; /* Imply --dry-run=no if we create the loopback file
6492 * anew. After all we cannot really break anyone's
6493 * partition tables that way. */
6494 } else
e594a3b1
LP
6495 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
6496 "Failed to parse --empty= parameter: %s", optarg);
6497 break;
6498
6499 case ARG_DISCARD:
599c7c54 6500 r = parse_boolean_argument("--discard=", optarg, &arg_discard);
e594a3b1 6501 if (r < 0)
599c7c54 6502 return r;
e594a3b1
LP
6503 break;
6504
6505 case ARG_FACTORY_RESET:
c3470872 6506 r = parse_boolean_argument("--factory-reset=", optarg, NULL);
e594a3b1 6507 if (r < 0)
c3470872 6508 return r;
e594a3b1
LP
6509 arg_factory_reset = r;
6510 break;
6511
6512 case ARG_CAN_FACTORY_RESET:
6513 arg_can_factory_reset = true;
6514 break;
6515
6516 case ARG_ROOT:
252d6267
LP
6517 r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_root);
6518 if (r < 0)
6519 return r;
6520 break;
6521
6522 case ARG_IMAGE:
6523 r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_image);
e594a3b1
LP
6524 if (r < 0)
6525 return r;
6526 break;
6527
06e78680
YW
6528 case ARG_IMAGE_POLICY:
6529 r = parse_image_policy_argument(optarg, &arg_image_policy);
6530 if (r < 0)
6531 return r;
6532 break;
6533
e594a3b1
LP
6534 case ARG_SEED:
6535 if (isempty(optarg)) {
6536 arg_seed = SD_ID128_NULL;
6537 arg_randomize = false;
6538 } else if (streq(optarg, "random"))
6539 arg_randomize = true;
6540 else {
6541 r = sd_id128_from_string(optarg, &arg_seed);
6542 if (r < 0)
6543 return log_error_errno(r, "Failed to parse seed: %s", optarg);
6544
6545 arg_randomize = false;
6546 }
6547
6548 break;
6549
6550 case ARG_PRETTY:
c3470872 6551 r = parse_boolean_argument("--pretty=", optarg, NULL);
e594a3b1 6552 if (r < 0)
c3470872 6553 return r;
e594a3b1
LP
6554 arg_pretty = r;
6555 break;
6556
224c853f
RP
6557 case ARG_DEFINITIONS: {
6558 _cleanup_free_ char *path = NULL;
6559 r = parse_path_argument(optarg, false, &path);
e594a3b1
LP
6560 if (r < 0)
6561 return r;
224c853f
RP
6562 if (strv_consume(&arg_definitions, TAKE_PTR(path)) < 0)
6563 return log_oom();
e594a3b1 6564 break;
224c853f 6565 }
e594a3b1 6566
a26f4a49
LP
6567 case ARG_SIZE: {
6568 uint64_t parsed, rounded;
6569
170c9823
LP
6570 if (streq(optarg, "auto")) {
6571 arg_size = UINT64_MAX;
6572 arg_size_auto = true;
6573 break;
6574 }
6575
a26f4a49
LP
6576 r = parse_size(optarg, 1024, &parsed);
6577 if (r < 0)
6578 return log_error_errno(r, "Failed to parse --size= parameter: %s", optarg);
6579
6580 rounded = round_up_size(parsed, 4096);
6581 if (rounded == 0)
6582 return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Specified image size too small, refusing.");
6583 if (rounded == UINT64_MAX)
6584 return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Specified image size too large, refusing.");
6585
6586 if (rounded != parsed)
e2341b6b
DT
6587 log_warning("Specified size is not a multiple of 4096, rounding up automatically. (%" PRIu64 " %s %" PRIu64 ")",
6588 parsed, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), rounded);
a26f4a49
LP
6589
6590 arg_size = rounded;
170c9823 6591 arg_size_auto = false;
a26f4a49
LP
6592 break;
6593 }
b9df3536 6594
a015fbe7 6595 case ARG_JSON:
b1e8f46c 6596 r = parse_json_argument(optarg, &arg_json_format_flags);
6a01ea4a
LP
6597 if (r <= 0)
6598 return r;
a015fbe7
TH
6599
6600 break;
6601
b9df3536
LP
6602 case ARG_KEY_FILE: {
6603 _cleanup_(erase_and_freep) char *k = NULL;
6604 size_t n = 0;
6605
8b3c3a49 6606 r = read_full_file_full(
986311c2 6607 AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
8b3c3a49
LP
6608 READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
6609 NULL,
6610 &k, &n);
b9df3536
LP
6611 if (r < 0)
6612 return log_error_errno(r, "Failed to read key file '%s': %m", optarg);
6613
6614 erase_and_free(arg_key);
6615 arg_key = TAKE_PTR(k);
6616 arg_key_size = n;
6617 break;
6618 }
a26f4a49 6619
b456191d
DDM
6620 case ARG_PRIVATE_KEY: {
6621 _cleanup_(erase_and_freep) char *k = NULL;
6622 size_t n = 0;
6623
6624 r = read_full_file_full(
6625 AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
6626 READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
6627 NULL,
6628 &k, &n);
6629 if (r < 0)
6630 return log_error_errno(r, "Failed to read key file '%s': %m", optarg);
6631
6632 EVP_PKEY_free(arg_private_key);
6633 arg_private_key = NULL;
6634 r = parse_private_key(k, n, &arg_private_key);
6635 if (r < 0)
6636 return r;
6637 break;
6638 }
6639
6640 case ARG_CERTIFICATE: {
6641 _cleanup_free_ char *cert = NULL;
6642 size_t n = 0;
6643
6644 r = read_full_file_full(
6645 AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
6646 READ_FULL_FILE_CONNECT_SOCKET,
6647 NULL,
6648 &cert, &n);
6649 if (r < 0)
6650 return log_error_errno(r, "Failed to read certificate file '%s': %m", optarg);
6651
6652 X509_free(arg_certificate);
6653 arg_certificate = NULL;
6654 r = parse_x509_certificate(cert, n, &arg_certificate);
6655 if (r < 0)
6656 return r;
6657 break;
6658 }
6659
889914ef
LP
6660 case ARG_TPM2_DEVICE: {
6661 _cleanup_free_ char *device = NULL;
6662
6663 if (streq(optarg, "list"))
6664 return tpm2_list_devices();
6665
6666 if (!streq(optarg, "auto")) {
6667 device = strdup(optarg);
6668 if (!device)
6669 return log_oom();
6670 }
6671
6672 free(arg_tpm2_device);
6673 arg_tpm2_device = TAKE_PTR(device);
6674 break;
6675 }
6676
222a951f 6677 case ARG_TPM2_PCRS:
9e437994
DS
6678 arg_tpm2_hash_pcr_values_use_default = false;
6679 r = tpm2_parse_pcr_argument_append(optarg, &arg_tpm2_hash_pcr_values, &arg_tpm2_n_hash_pcr_values);
889914ef
LP
6680 if (r < 0)
6681 return r;
6682
889914ef 6683 break;
889914ef 6684
02ef97cd
LP
6685 case ARG_TPM2_PUBLIC_KEY:
6686 r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_tpm2_public_key);
6687 if (r < 0)
6688 return r;
6689
6690 break;
6691
6692 case ARG_TPM2_PUBLIC_KEY_PCRS:
9e437994 6693 arg_tpm2_public_key_pcr_mask_use_default = false;
07c04061 6694 r = tpm2_parse_pcr_argument_to_mask(optarg, &arg_tpm2_public_key_pcr_mask);
02ef97cd
LP
6695 if (r < 0)
6696 return r;
6697
6698 break;
6699
4cee8333
DDM
6700 case ARG_SPLIT:
6701 r = parse_boolean_argument("--split=", optarg, NULL);
6702 if (r < 0)
6703 return r;
6704
6705 arg_split = r;
6706 break;
6707
81d1098b
DDM
6708 case ARG_INCLUDE_PARTITIONS:
6709 if (arg_filter_partitions_type == FILTER_PARTITIONS_EXCLUDE)
6710 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
6711 "Combination of --include-partitions= and --exclude-partitions= is invalid.");
6712
220780db 6713 r = parse_partition_types(optarg, &arg_filter_partitions, &arg_n_filter_partitions);
81d1098b
DDM
6714 if (r < 0)
6715 return r;
6716
6717 arg_filter_partitions_type = FILTER_PARTITIONS_INCLUDE;
6718
6719 break;
6720
6721 case ARG_EXCLUDE_PARTITIONS:
6722 if (arg_filter_partitions_type == FILTER_PARTITIONS_INCLUDE)
6723 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
6724 "Combination of --include-partitions= and --exclude-partitions= is invalid.");
6725
220780db 6726 r = parse_partition_types(optarg, &arg_filter_partitions, &arg_n_filter_partitions);
81d1098b
DDM
6727 if (r < 0)
6728 return r;
6729
6730 arg_filter_partitions_type = FILTER_PARTITIONS_EXCLUDE;
6731
6732 break;
6733
8275334b
DDM
6734 case ARG_DEFER_PARTITIONS:
6735 r = parse_partition_types(optarg, &arg_defer_partitions, &arg_n_defer_partitions);
7d505753
DDM
6736 if (r < 0)
6737 return r;
6738
6739 break;
6740
e1878ef7
DDM
6741 case ARG_SECTOR_SIZE:
6742 r = parse_sector_size(optarg, &arg_sector_size);
6743 if (r < 0)
6744 return r;
6745
6746 break;
6747
9786dfe6
DDM
6748 case ARG_ARCHITECTURE:
6749 r = architecture_from_string(optarg);
6750 if (r < 0)
6751 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid architecture '%s'", optarg);
6752
6753 arg_architecture = r;
6754 break;
6755
fc10b158
DDM
6756 case ARG_OFFLINE:
6757 if (streq(optarg, "auto"))
6758 arg_offline = -1;
6759 else {
6760 r = parse_boolean_argument("--offline=", optarg, NULL);
6761 if (r < 0)
6762 return r;
6763
6764 arg_offline = r;
6765 }
6766
6767 break;
6768
e1536d1f
DDM
6769 case ARG_COPY_FROM: {
6770 _cleanup_free_ char *p = NULL;
6771
6772 r = parse_path_argument(optarg, /* suppress_root= */ false, &p);
1e46985a
DDM
6773 if (r < 0)
6774 return r;
e1536d1f
DDM
6775
6776 if (strv_consume(&arg_copy_from, TAKE_PTR(p)) < 0)
6777 return log_oom();
6778
1e46985a 6779 break;
e1536d1f 6780 }
1e46985a 6781
e594a3b1
LP
6782 case '?':
6783 return -EINVAL;
6784
6785 default:
04499a70 6786 assert_not_reached();
e594a3b1
LP
6787 }
6788
6789 if (argc - optind > 1)
6790 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
6791 "Expected at most one argument, the path to the block device.");
6792
a26f4a49 6793 if (arg_factory_reset > 0 && IN_SET(arg_empty, EMPTY_FORCE, EMPTY_REQUIRE, EMPTY_CREATE))
e594a3b1 6794 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
a26f4a49 6795 "Combination of --factory-reset=yes and --empty=force/--empty=require/--empty=create is invalid.");
e594a3b1
LP
6796
6797 if (arg_can_factory_reset)
a26f4a49
LP
6798 arg_dry_run = true; /* When --can-factory-reset is specified we don't make changes, hence
6799 * non-dry-run mode makes no sense. Thus, imply dry run mode so that we
6800 * open things strictly read-only. */
6801 else if (dry_run >= 0)
6802 arg_dry_run = dry_run;
6803
170c9823 6804 if (arg_empty == EMPTY_CREATE && (arg_size == UINT64_MAX && !arg_size_auto))
a26f4a49
LP
6805 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
6806 "If --empty=create is specified, --size= must be specified, too.");
e594a3b1 6807
252d6267
LP
6808 if (arg_image && arg_root)
6809 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify either --root= or --image=, the combination of both is not supported.");
6810 else if (!arg_image && !arg_root && in_initrd()) {
8f47e32a
LP
6811
6812 /* By default operate on /sysusr/ or /sysroot/ when invoked in the initrd. We prefer the
6813 * former, if it is mounted, so that we have deterministic behaviour on systems where /usr/
6814 * is vendor-supplied but the root fs formatted on first boot. */
6815 r = path_is_mount_point("/sysusr/usr", NULL, 0);
6816 if (r <= 0) {
6817 if (r < 0 && r != -ENOENT)
6818 log_debug_errno(r, "Unable to determine whether /sysusr/usr is a mount point, assuming it is not: %m");
6819
6820 arg_root = strdup("/sysroot");
6821 } else
6822 arg_root = strdup("/sysusr");
252d6267
LP
6823 if (!arg_root)
6824 return log_oom();
6825 }
6826
e594a3b1 6827 arg_node = argc > optind ? argv[optind] : NULL;
a26f4a49 6828
252d6267 6829 if (IN_SET(arg_empty, EMPTY_FORCE, EMPTY_REQUIRE, EMPTY_CREATE) && !arg_node && !arg_image)
a26f4a49
LP
6830 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
6831 "A path to a device node or loopback file must be specified when --empty=force, --empty=require or --empty=create are used.");
6832
4cee8333
DDM
6833 if (arg_split && !arg_node)
6834 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
6835 "A path to a loopback file must be specified when --split is used.");
6836
9e437994 6837 if (arg_tpm2_public_key_pcr_mask_use_default && arg_tpm2_public_key)
2099cd62 6838 arg_tpm2_public_key_pcr_mask = INDEX_TO_MASK(uint32_t, TPM2_PCR_KERNEL_BOOT);
9e437994
DS
6839
6840 if (arg_tpm2_hash_pcr_values_use_default && !GREEDY_REALLOC_APPEND(
6841 arg_tpm2_hash_pcr_values,
6842 arg_tpm2_n_hash_pcr_values,
6843 &TPM2_PCR_VALUE_MAKE(TPM2_PCR_INDEX_DEFAULT, /* hash= */ 0, /* value= */ {}),
6844 1))
6845 return log_oom();
889914ef 6846
a26d463d
DDM
6847 if (arg_pretty < 0 && isatty(STDOUT_FILENO))
6848 arg_pretty = true;
6849
9786dfe6
DDM
6850 if (arg_architecture >= 0) {
6851 FOREACH_ARRAY(p, arg_filter_partitions, arg_n_filter_partitions)
6852 *p = gpt_partition_type_override_architecture(*p, arg_architecture);
6853
6854 FOREACH_ARRAY(p, arg_defer_partitions, arg_n_defer_partitions)
6855 *p = gpt_partition_type_override_architecture(*p, arg_architecture);
6856 }
6857
e594a3b1
LP
6858 return 1;
6859}
6860
6861static int parse_proc_cmdline_factory_reset(void) {
6862 bool b;
6863 int r;
6864
6865 if (arg_factory_reset >= 0) /* Never override what is specified on the process command line */
6866 return 0;
6867
6868 if (!in_initrd()) /* Never honour kernel command line factory reset request outside of the initrd */
6869 return 0;
6870
3787934b 6871 r = proc_cmdline_get_bool("systemd.factory_reset", /* flags = */ 0, &b);
e594a3b1
LP
6872 if (r < 0)
6873 return log_error_errno(r, "Failed to parse systemd.factory_reset kernel command line argument: %m");
6874 if (r > 0) {
6875 arg_factory_reset = b;
6876
6877 if (b)
6878 log_notice("Honouring factory reset requested via kernel command line.");
6879 }
6880
6881 return 0;
6882}
6883
6884static int parse_efi_variable_factory_reset(void) {
6885 _cleanup_free_ char *value = NULL;
6886 int r;
6887
6888 if (arg_factory_reset >= 0) /* Never override what is specified on the process command line */
6889 return 0;
6890
6891 if (!in_initrd()) /* Never honour EFI variable factory reset request outside of the initrd */
6892 return 0;
6893
e6f055cb 6894 r = efi_get_variable_string(EFI_SYSTEMD_VARIABLE(FactoryReset), &value);
6ce691c3
DL
6895 if (r < 0) {
6896 if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r))
6897 return 0;
e594a3b1 6898 return log_error_errno(r, "Failed to read EFI variable FactoryReset: %m");
6ce691c3 6899 }
e594a3b1
LP
6900
6901 r = parse_boolean(value);
6902 if (r < 0)
6903 return log_error_errno(r, "Failed to parse EFI variable FactoryReset: %m");
6904
6905 arg_factory_reset = r;
6906 if (r)
111a3aae 6907 log_notice("Factory reset requested via EFI variable FactoryReset.");
e594a3b1
LP
6908
6909 return 0;
6910}
6911
6912static int remove_efi_variable_factory_reset(void) {
6913 int r;
6914
e6f055cb 6915 r = efi_set_variable(EFI_SYSTEMD_VARIABLE(FactoryReset), NULL, 0);
6ce691c3
DL
6916 if (r < 0) {
6917 if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r))
6918 return 0;
e594a3b1 6919 return log_error_errno(r, "Failed to remove EFI variable FactoryReset: %m");
6ce691c3 6920 }
e594a3b1
LP
6921
6922 log_info("Successfully unset EFI variable FactoryReset.");
6923 return 0;
6924}
6925
252d6267
LP
6926static int acquire_root_devno(
6927 const char *p,
6928 const char *root,
6929 int mode,
6930 char **ret,
6931 int *ret_fd) {
6932
37734dc6 6933 _cleanup_free_ char *found_path = NULL, *node = NULL;
252d6267 6934 dev_t devno, fd_devno = MODE_INVALID;
254d1313 6935 _cleanup_close_ int fd = -EBADF;
e594a3b1 6936 struct stat st;
e594a3b1
LP
6937 int r;
6938
a26f4a49
LP
6939 assert(p);
6940 assert(ret);
6941 assert(ret_fd);
6942
f461a28d 6943 fd = chase_and_open(p, root, CHASE_PREFIX_ROOT, mode, &found_path);
e594a3b1 6944 if (fd < 0)
252d6267 6945 return fd;
e594a3b1
LP
6946
6947 if (fstat(fd, &st) < 0)
6948 return -errno;
6949
6950 if (S_ISREG(st.st_mode)) {
252d6267 6951 *ret = TAKE_PTR(found_path);
a26f4a49 6952 *ret_fd = TAKE_FD(fd);
e594a3b1
LP
6953 return 0;
6954 }
6955
252d6267
LP
6956 if (S_ISBLK(st.st_mode)) {
6957 /* Refuse referencing explicit block devices if a root dir is specified, after all we should
5c08da58 6958 * not be able to leave the image the root path constrains us to. */
252d6267
LP
6959 if (root)
6960 return -EPERM;
6961
a26f4a49 6962 fd_devno = devno = st.st_rdev;
252d6267 6963 } else if (S_ISDIR(st.st_mode)) {
e594a3b1
LP
6964
6965 devno = st.st_dev;
a26f4a49 6966 if (major(devno) == 0) {
e594a3b1
LP
6967 r = btrfs_get_block_device_fd(fd, &devno);
6968 if (r == -ENOTTY) /* not btrfs */
6969 return -ENODEV;
6970 if (r < 0)
6971 return r;
6972 }
e594a3b1
LP
6973 } else
6974 return -ENOTBLK;
6975
6976 /* From dm-crypt to backing partition */
6977 r = block_get_originating(devno, &devno);
8e5f3cec
LP
6978 if (r == -ENOENT)
6979 log_debug_errno(r, "Device '%s' has no dm-crypt/dm-verity device, no need to look for underlying block device.", p);
6980 else if (r < 0)
e594a3b1
LP
6981 log_debug_errno(r, "Failed to find underlying block device for '%s', ignoring: %m", p);
6982
6983 /* From partition to whole disk containing it */
6984 r = block_get_whole_disk(devno, &devno);
6985 if (r < 0)
162392b7 6986 log_debug_errno(r, "Failed to find whole disk block device for '%s', ignoring: %m", p);
e594a3b1 6987
37734dc6 6988 r = devname_from_devnum(S_IFBLK, devno, &node);
a26f4a49
LP
6989 if (r < 0)
6990 return log_debug_errno(r, "Failed to determine canonical path for '%s': %m", p);
6991
6bbae9f8 6992 /* Only if we still look at the same block device we can reuse the fd. Otherwise return an
a26f4a49 6993 * invalidated fd. */
37734dc6
YW
6994 if (fd_devno != MODE_INVALID && fd_devno == devno) {
6995 /* Tell udev not to interfere while we are processing the device */
6996 if (flock(fd, arg_dry_run ? LOCK_SH : LOCK_EX) < 0)
6997 return log_error_errno(errno, "Failed to lock device '%s': %m", node);
6998
6999 *ret_fd = TAKE_FD(fd);
7000 } else
7001 *ret_fd = -EBADF;
7002
7003 *ret = TAKE_PTR(node);
a26f4a49 7004 return 0;
e594a3b1
LP
7005}
7006
cc751c75 7007static int find_root(Context *context) {
54632d2e 7008 _cleanup_free_ char *device = NULL;
5980d463 7009 int r;
e594a3b1 7010
cc751c75 7011 assert(context);
a26f4a49 7012
e594a3b1 7013 if (arg_node) {
a26f4a49 7014 if (arg_empty == EMPTY_CREATE) {
254d1313 7015 _cleanup_close_ int fd = -EBADF;
a26f4a49
LP
7016 _cleanup_free_ char *s = NULL;
7017
7018 s = strdup(arg_node);
7019 if (!s)
7020 return log_oom();
7021
5332d7c6 7022 fd = open(arg_node, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOFOLLOW, 0666);
a26f4a49
LP
7023 if (fd < 0)
7024 return log_error_errno(errno, "Failed to create '%s': %m", arg_node);
7025
cc751c75 7026 context->node = TAKE_PTR(s);
db1d4e6b 7027 context->node_is_our_file = true;
cc751c75 7028 context->backing_fd = TAKE_FD(fd);
a26f4a49
LP
7029 return 0;
7030 }
7031
252d6267
LP
7032 /* Note that we don't specify a root argument here: if the user explicitly configured a node
7033 * we'll take it relative to the host, not the image */
cc751c75 7034 r = acquire_root_devno(arg_node, NULL, O_RDONLY|O_CLOEXEC, &context->node, &context->backing_fd);
67f0ac8c
LP
7035 if (r == -EUCLEAN)
7036 return btrfs_log_dev_root(LOG_ERR, r, arg_node);
e594a3b1 7037 if (r < 0)
aa2a74ad 7038 return log_error_errno(r, "Failed to open file or determine backing device of %s: %m", arg_node);
e594a3b1
LP
7039
7040 return 0;
7041 }
7042
a26f4a49
LP
7043 assert(IN_SET(arg_empty, EMPTY_REFUSE, EMPTY_ALLOW));
7044
54632d2e
KK
7045 /* If the root mount has been replaced by some form of volatile file system (overlayfs), the
7046 * original root block device node is symlinked in /run/systemd/volatile-root. Let's read that
7047 * here. */
7048 r = readlink_malloc("/run/systemd/volatile-root", &device);
7049 if (r == -ENOENT) { /* volatile-root not found */
7050 /* Let's search for the root device. We look for two cases here: first in /, and then in /usr. The
7051 * latter we check for cases where / is a tmpfs and only /usr is an actual persistent block device
7052 * (think: volatile setups) */
e594a3b1 7053
54632d2e 7054 FOREACH_STRING(p, "/", "/usr") {
e594a3b1 7055
cc751c75
DDM
7056 r = acquire_root_devno(p, arg_root, O_RDONLY|O_DIRECTORY|O_CLOEXEC, &context->node,
7057 &context->backing_fd);
54632d2e
KK
7058 if (r < 0) {
7059 if (r == -EUCLEAN)
7060 return btrfs_log_dev_root(LOG_ERR, r, p);
7061 if (r != -ENODEV)
7062 return log_error_errno(r, "Failed to determine backing device of %s: %m", p);
7063 } else
7064 return 0;
7065 }
7066 } else if (r < 0)
7067 return log_error_errno(r, "Failed to read symlink /run/systemd/volatile-root: %m");
7068 else {
cc751c75 7069 r = acquire_root_devno(device, NULL, O_RDONLY|O_CLOEXEC, &context->node, &context->backing_fd);
54632d2e
KK
7070 if (r == -EUCLEAN)
7071 return btrfs_log_dev_root(LOG_ERR, r, device);
7072 if (r < 0)
7073 return log_error_errno(r, "Failed to open file or determine backing device of %s: %m", device);
7074
7075 return 0;
e594a3b1
LP
7076 }
7077
7078 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "Failed to discover root block device.");
7079}
7080
81dde3d8 7081static int resize_pt(int fd, uint64_t sector_size) {
f9b3afae
LP
7082 _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
7083 int r;
7084
7085 /* After resizing the backing file we need to resize the partition table itself too, so that it takes
7086 * possession of the enlarged backing file. For this it suffices to open the device with libfdisk and
7087 * immediately write it again, with no changes. */
7088
fd9fe57a 7089 r = fdisk_new_context_at(fd, /* path= */ NULL, /* read_only= */ false, sector_size, &c);
f9b3afae 7090 if (r < 0)
ddb6eeaf 7091 return log_error_errno(r, "Failed to open device '%s': %m", FORMAT_PROC_FD_PATH(fd));
f9b3afae
LP
7092
7093 r = fdisk_has_label(c);
7094 if (r < 0)
ddb6eeaf 7095 return log_error_errno(r, "Failed to determine whether disk '%s' has a disk label: %m", FORMAT_PROC_FD_PATH(fd));
f9b3afae
LP
7096 if (r == 0) {
7097 log_debug("Not resizing partition table, as there currently is none.");
7098 return 0;
7099 }
7100
7101 r = fdisk_write_disklabel(c);
7102 if (r < 0)
7103 return log_error_errno(r, "Failed to write resized partition table: %m");
7104
7105 log_info("Resized partition table.");
7106 return 1;
7107}
7108
252d6267
LP
7109static int resize_backing_fd(
7110 const char *node, /* The primary way we access the disk image to operate on */
7111 int *fd, /* An O_RDONLY fd referring to that inode */
7112 const char *backing_file, /* If the above refers to a loopback device, the backing regular file for that, which we can grow */
81dde3d8
LP
7113 LoopDevice *loop_device,
7114 uint64_t sector_size) {
252d6267 7115
254d1313 7116 _cleanup_close_ int writable_fd = -EBADF;
252d6267 7117 uint64_t current_size;
a26f4a49
LP
7118 struct stat st;
7119 int r;
7120
7121 assert(node);
7122 assert(fd);
7123
7124 if (arg_size == UINT64_MAX) /* Nothing to do */
7125 return 0;
7126
7127 if (*fd < 0) {
7128 /* Open the file if we haven't opened it yet. Note that we open it read-only here, just to
7129 * keep a reference to the file we can pass around. */
7130 *fd = open(node, O_RDONLY|O_CLOEXEC);
7131 if (*fd < 0)
7132 return log_error_errno(errno, "Failed to open '%s' in order to adjust size: %m", node);
7133 }
7134
7135 if (fstat(*fd, &st) < 0)
7136 return log_error_errno(errno, "Failed to stat '%s': %m", node);
7137
252d6267
LP
7138 if (S_ISBLK(st.st_mode)) {
7139 if (!backing_file)
7140 return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Cannot resize block device '%s'.", node);
7141
7142 assert(loop_device);
a26f4a49 7143
252d6267
LP
7144 if (ioctl(*fd, BLKGETSIZE64, &current_size) < 0)
7145 return log_error_errno(errno, "Failed to determine size of block device %s: %m", node);
7146 } else {
7147 r = stat_verify_regular(&st);
7148 if (r < 0)
7149 return log_error_errno(r, "Specified path '%s' is not a regular file or loopback block device, cannot resize: %m", node);
7150
7151 assert(!backing_file);
7152 assert(!loop_device);
7153 current_size = st.st_size;
7154 }
7155
252d6267 7156 if (current_size >= arg_size) {
2b59bf51
ZJS
7157 log_info("File '%s' already is of requested size or larger, not growing. (%s >= %s)",
7158 node, FORMAT_BYTES(current_size), FORMAT_BYTES(arg_size));
a26f4a49
LP
7159 return 0;
7160 }
7161
252d6267
LP
7162 if (S_ISBLK(st.st_mode)) {
7163 assert(backing_file);
7164
7165 /* This is a loopback device. We can't really grow those directly, but we can grow the
7166 * backing file, hence let's do that. */
7167
7168 writable_fd = open(backing_file, O_WRONLY|O_CLOEXEC|O_NONBLOCK);
7169 if (writable_fd < 0)
7170 return log_error_errno(errno, "Failed to open backing file '%s': %m", backing_file);
7171
7172 if (fstat(writable_fd, &st) < 0)
7173 return log_error_errno(errno, "Failed to stat() backing file '%s': %m", backing_file);
7174
7175 r = stat_verify_regular(&st);
7176 if (r < 0)
7177 return log_error_errno(r, "Backing file '%s' of block device is not a regular file: %m", backing_file);
7178
7179 if ((uint64_t) st.st_size != current_size)
7180 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2b59bf51
ZJS
7181 "Size of backing file '%s' of loopback block device '%s' don't match, refusing.",
7182 node, backing_file);
252d6267
LP
7183 } else {
7184 assert(S_ISREG(st.st_mode));
7185 assert(!backing_file);
a26f4a49 7186
252d6267
LP
7187 /* The file descriptor is read-only. In order to grow the file we need to have a writable fd. We
7188 * reopen the file for that temporarily. We keep the writable fd only open for this operation though,
7189 * as fdisk can't accept it anyway. */
7190
7191 writable_fd = fd_reopen(*fd, O_WRONLY|O_CLOEXEC);
7192 if (writable_fd < 0)
7193 return log_error_errno(writable_fd, "Failed to reopen backing file '%s' writable: %m", node);
7194 }
a26f4a49
LP
7195
7196 if (!arg_discard) {
7197 if (fallocate(writable_fd, 0, 0, arg_size) < 0) {
7198 if (!ERRNO_IS_NOT_SUPPORTED(errno))
7199 return log_error_errno(errno, "Failed to grow '%s' from %s to %s by allocation: %m",
2b59bf51 7200 node, FORMAT_BYTES(current_size), FORMAT_BYTES(arg_size));
a26f4a49
LP
7201
7202 /* Fallback to truncation, if fallocate() is not supported. */
7203 log_debug("Backing file system does not support fallocate(), falling back to ftruncate().");
7204 } else {
252d6267 7205 if (current_size == 0) /* Likely regular file just created by us */
2b59bf51 7206 log_info("Allocated %s for '%s'.", FORMAT_BYTES(arg_size), node);
a26f4a49 7207 else
2b59bf51
ZJS
7208 log_info("File '%s' grown from %s to %s by allocation.",
7209 node, FORMAT_BYTES(current_size), FORMAT_BYTES(arg_size));
a26f4a49 7210
252d6267 7211 goto done;
a26f4a49
LP
7212 }
7213 }
7214
7215 if (ftruncate(writable_fd, arg_size) < 0)
7216 return log_error_errno(errno, "Failed to grow '%s' from %s to %s by truncation: %m",
2b59bf51 7217 node, FORMAT_BYTES(current_size), FORMAT_BYTES(arg_size));
a26f4a49 7218
252d6267 7219 if (current_size == 0) /* Likely regular file just created by us */
2b59bf51 7220 log_info("Sized '%s' to %s.", node, FORMAT_BYTES(arg_size));
252d6267 7221 else
2b59bf51
ZJS
7222 log_info("File '%s' grown from %s to %s by truncation.",
7223 node, FORMAT_BYTES(current_size), FORMAT_BYTES(arg_size));
252d6267
LP
7224
7225done:
81dde3d8 7226 r = resize_pt(writable_fd, sector_size);
f9b3afae
LP
7227 if (r < 0)
7228 return r;
7229
252d6267
LP
7230 if (loop_device) {
7231 r = loop_device_refresh_size(loop_device, UINT64_MAX, arg_size);
7232 if (r < 0)
7233 return log_error_errno(r, "Failed to update loop device size: %m");
7234 }
a26f4a49
LP
7235
7236 return 1;
7237}
7238
170c9823 7239static int determine_auto_size(Context *c) {
994b3031 7240 uint64_t sum;
170c9823 7241
ac33e147 7242 assert(c);
170c9823 7243
994b3031
LP
7244 sum = round_up_size(GPT_METADATA_SIZE, 4096);
7245
170c9823
LP
7246 LIST_FOREACH(partitions, p, c->partitions) {
7247 uint64_t m;
7248
7249 if (p->dropped)
7250 continue;
7251
994b3031 7252 m = partition_min_size_with_padding(c, p);
170c9823
LP
7253 if (m > UINT64_MAX - sum)
7254 return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW), "Image would grow too large, refusing.");
7255
7256 sum += m;
7257 }
7258
2b59bf51
ZJS
7259 if (c->total != UINT64_MAX)
7260 /* Image already allocated? Then show its size. */
7261 log_info("Automatically determined minimal disk image size as %s, current image size is %s.",
7262 FORMAT_BYTES(sum), FORMAT_BYTES(c->total));
7263 else
7264 /* If the image is being created right now, then it has no previous size, suppress any comment about it hence. */
7265 log_info("Automatically determined minimal disk image size as %s.",
7266 FORMAT_BYTES(sum));
170c9823
LP
7267
7268 arg_size = sum;
7269 return 0;
7270}
7271
e594a3b1 7272static int run(int argc, char *argv[]) {
252d6267 7273 _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
a4b3e942 7274 _cleanup_(umount_and_freep) char *mounted_dir = NULL;
e594a3b1 7275 _cleanup_(context_freep) Context* context = NULL;
cc751c75 7276 bool node_is_our_loop = false;
e594a3b1
LP
7277 int r;
7278
7279 log_show_color(true);
7280 log_parse_environment();
7281 log_open();
7282
e594a3b1
LP
7283 r = parse_argv(argc, argv);
7284 if (r <= 0)
7285 return r;
7286
7287 r = parse_proc_cmdline_factory_reset();
7288 if (r < 0)
7289 return r;
7290
7291 r = parse_efi_variable_factory_reset();
7292 if (r < 0)
7293 return r;
7294
30f19400
LP
7295#if HAVE_LIBCRYPTSETUP
7296 cryptsetup_enable_logging(NULL);
7297#endif
7298
252d6267
LP
7299 if (arg_image) {
7300 assert(!arg_root);
7301
7302 /* Mount this strictly read-only: we shall modify the partition table, not the file
7303 * systems */
7304 r = mount_image_privately_interactively(
7305 arg_image,
84be0c71 7306 arg_image_policy,
252d6267
LP
7307 DISSECT_IMAGE_MOUNT_READ_ONLY |
7308 (arg_node ? DISSECT_IMAGE_DEVICE_READ_ONLY : 0) | /* If a different node to make changes to is specified let's open the device in read-only mode) */
7309 DISSECT_IMAGE_GPT_ONLY |
7310 DISSECT_IMAGE_RELAX_VAR_CHECK |
7311 DISSECT_IMAGE_USR_NO_ROOT |
7312 DISSECT_IMAGE_REQUIRE_ROOT,
7313 &mounted_dir,
a133d2c3 7314 /* ret_dir_fd= */ NULL,
e330f97a 7315 &loop_device);
252d6267
LP
7316 if (r < 0)
7317 return r;
7318
7319 arg_root = strdup(mounted_dir);
7320 if (!arg_root)
7321 return log_oom();
7322
7323 if (!arg_node) {
7324 arg_node = strdup(loop_device->node);
7325 if (!arg_node)
7326 return log_oom();
7327
3d62af7d 7328 /* Remember that the device we are about to manipulate is actually the one we
252d6267
LP
7329 * allocated here, and thus to increase its backing file we know what to do */
7330 node_is_our_loop = true;
7331 }
7332 }
7333
e594a3b1
LP
7334 context = context_new(arg_seed);
7335 if (!context)
7336 return log_oom();
7337
1e46985a
DDM
7338 r = context_copy_from(context);
7339 if (r < 0)
7340 return r;
7341
224c853f
RP
7342 strv_uniq(arg_definitions);
7343
4b047310 7344 r = context_read_definitions(context);
e594a3b1
LP
7345 if (r < 0)
7346 return r;
7347
cc751c75 7348 r = find_root(context);
0ae5ffe0
YW
7349 if (r < 0)
7350 return r;
7351
a26f4a49 7352 if (arg_size != UINT64_MAX) {
252d6267 7353 r = resize_backing_fd(
cc751c75
DDM
7354 context->node,
7355 &context->backing_fd,
252d6267 7356 node_is_our_loop ? arg_image : NULL,
81dde3d8
LP
7357 node_is_our_loop ? loop_device : NULL,
7358 context->sector_size);
a26f4a49
LP
7359 if (r < 0)
7360 return r;
7361 }
7362
cc751c75 7363 r = context_load_partition_table(context);
e594a3b1
LP
7364 if (r == -EHWPOISON)
7365 return 77; /* Special return value which means "Not GPT, so not doing anything". This isn't
7366 * really an error when called at boot. */
7367 if (r < 0)
7368 return r;
cc751c75 7369 context->from_scratch = r > 0; /* Starting from scratch */
e594a3b1
LP
7370
7371 if (arg_can_factory_reset) {
7372 r = context_can_factory_reset(context);
7373 if (r < 0)
7374 return r;
7375 if (r == 0)
7376 return EXIT_FAILURE;
7377
7378 return 0;
7379 }
7380
cc751c75 7381 r = context_factory_reset(context);
e594a3b1
LP
7382 if (r < 0)
7383 return r;
7384 if (r > 0) {
7385 /* We actually did a factory reset! */
7386 r = remove_efi_variable_factory_reset();
7387 if (r < 0)
7388 return r;
7389
7390 /* Reload the reduced partition table */
7391 context_unload_partition_table(context);
cc751c75 7392 r = context_load_partition_table(context);
e594a3b1
LP
7393 if (r < 0)
7394 return r;
7395 }
7396
e594a3b1
LP
7397 r = context_read_seed(context, arg_root);
7398 if (r < 0)
7399 return r;
7400
8bbbdfd7
DDM
7401 /* Make sure each partition has a unique UUID and unique label */
7402 r = context_acquire_partition_uuids_and_labels(context);
7403 if (r < 0)
7404 return r;
7405
757bc2e4 7406 /* Open all files to copy blocks from now, since we want to take their size into consideration */
5c08da58
LP
7407 r = context_open_copy_block_paths(
7408 context,
7802194a 7409 loop_device ? loop_device->devno : /* if --image= is specified, only allow partitions on the loopback device */
5c08da58
LP
7410 arg_root && !arg_image ? 0 : /* if --root= is specified, don't accept any block device */
7411 (dev_t) -1); /* if neither is specified, make no restrictions */
757bc2e4
LP
7412 if (r < 0)
7413 return r;
7414
5eef7047
DDM
7415 r = context_minimize(context);
7416 if (r < 0)
7417 return r;
7418
170c9823
LP
7419 if (arg_size_auto) {
7420 r = determine_auto_size(context);
7421 if (r < 0)
7422 return r;
7423
7424 /* Flush out everything again, and let's grow the file first, then start fresh */
7425 context_unload_partition_table(context);
7426
ac33e147 7427 assert(arg_size != UINT64_MAX);
252d6267 7428 r = resize_backing_fd(
cc751c75
DDM
7429 context->node,
7430 &context->backing_fd,
252d6267 7431 node_is_our_loop ? arg_image : NULL,
81dde3d8
LP
7432 node_is_our_loop ? loop_device : NULL,
7433 context->sector_size);
170c9823
LP
7434 if (r < 0)
7435 return r;
7436
cc751c75 7437 r = context_load_partition_table(context);
170c9823
LP
7438 if (r < 0)
7439 return r;
7440 }
7441
e594a3b1
LP
7442 /* First try to fit new partitions in, dropping by priority until it fits */
7443 for (;;) {
14a4c4ed
LP
7444 uint64_t largest_free_area;
7445
7446 if (context_allocate_partitions(context, &largest_free_area))
e594a3b1
LP
7447 break; /* Success! */
7448
9ccceb9d 7449 if (!context_drop_or_foreignize_one_priority(context)) {
d17db7b2 7450 r = log_error_errno(SYNTHETIC_ERRNO(ENOSPC),
14a4c4ed 7451 "Can't fit requested partitions into available free space (%s), refusing.",
2b59bf51 7452 FORMAT_BYTES(largest_free_area));
d17db7b2
LP
7453 determine_auto_size(context);
7454 return r;
7455 }
e594a3b1
LP
7456 }
7457
7458 /* Now assign free space according to the weight logic */
7459 r = context_grow_partitions(context);
7460 if (r < 0)
7461 return r;
7462
0b7f574f 7463 /* Now calculate where each new partition gets placed */
e594a3b1
LP
7464 context_place_partitions(context);
7465
cc751c75 7466 (void) context_dump(context, /*late=*/ false);
a26d463d 7467
cc751c75 7468 r = context_write_partition_table(context);
e594a3b1
LP
7469 if (r < 0)
7470 return r;
7471
4cee8333
DDM
7472 r = context_split(context);
7473 if (r < 0)
7474 return r;
7475
cc751c75 7476 (void) context_dump(context, /*late=*/ true);
b5b7879a 7477
db1d4e6b
DDM
7478 context->node = mfree(context->node);
7479
a2d7c42e
DDM
7480 LIST_FOREACH(partitions, p, context->partitions)
7481 p->split_path = mfree(p->split_path);
b5b7879a 7482
e594a3b1
LP
7483 return 0;
7484}
7485
7486DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);