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