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