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