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