]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/partition/repart.c
string-table: add private version of lookup macro with boolean fallback
[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>
9#include <libfdisk.h>
10#include <linux/fs.h>
11#include <linux/loop.h>
12#include <sys/file.h>
13#include <sys/ioctl.h>
14#include <sys/stat.h>
15
16#include <openssl/hmac.h>
17#include <openssl/sha.h>
18
19#include "sd-id128.h"
20
21#include "alloc-util.h"
22#include "blkid-util.h"
23#include "blockdev-util.h"
24#include "btrfs-util.h"
25#include "conf-files.h"
26#include "conf-parser.h"
1e2f3230 27#include "cryptsetup-util.h"
e594a3b1
LP
28#include "def.h"
29#include "efivars.h"
30#include "errno-util.h"
31#include "fd-util.h"
b9df3536 32#include "fileio.h"
e594a3b1
LP
33#include "format-table.h"
34#include "format-util.h"
35#include "fs-util.h"
36#include "gpt.h"
37#include "id128-util.h"
a015fbe7 38#include "json.h"
e594a3b1
LP
39#include "list.h"
40#include "locale-util.h"
53171c04 41#include "loop-util.h"
e594a3b1 42#include "main-func.h"
8a794850 43#include "mkdir.h"
53171c04 44#include "mkfs-util.h"
8a794850 45#include "mount-util.h"
e594a3b1
LP
46#include "parse-util.h"
47#include "path-util.h"
48#include "pretty-print.h"
49#include "proc-cmdline.h"
8a794850 50#include "process-util.h"
b9df3536 51#include "random-util.h"
170c9823 52#include "resize-fs.h"
e594a3b1 53#include "sort-util.h"
e031166e 54#include "specifier.h"
e594a3b1
LP
55#include "stat-util.h"
56#include "stdio-util.h"
57#include "string-util.h"
58#include "strv.h"
59#include "terminal-util.h"
8a794850 60#include "user-util.h"
e594a3b1
LP
61#include "utf8.h"
62
fb08381c
LP
63/* If not configured otherwise use a minimal partition size of 10M */
64#define DEFAULT_MIN_SIZE (10*1024*1024)
65
66/* Hard lower limit for new partition sizes */
67#define HARD_MIN_SIZE 4096
68
69e3234d 69/* libfdisk takes off slightly more than 1M of the disk size when creating a GPT disk label */
170c9823
LP
70#define GPT_METADATA_SIZE (1044*1024)
71
72/* LUKS2 takes off 16M of the partition size with its metadata by default */
73#define LUKS2_METADATA_SIZE (16*1024*1024)
74
3dd8ae5c 75#if !HAVE_LIBCRYPTSETUP
76struct crypt_device;
77static inline void sym_crypt_free(struct crypt_device* cd) {}
78static inline void sym_crypt_freep(struct crypt_device** cd) {}
79#endif
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;
97static char *arg_definitions = NULL;
98static bool arg_discard = true;
99static bool arg_can_factory_reset = false;
100static int arg_factory_reset = -1;
101static sd_id128_t arg_seed = SD_ID128_NULL;
102static bool arg_randomize = false;
103static int arg_pretty = -1;
a26f4a49 104static uint64_t arg_size = UINT64_MAX;
170c9823 105static bool arg_size_auto = false;
a015fbe7
TH
106static bool arg_json = false;
107static JsonFormatFlags arg_json_format_flags = 0;
b9df3536
LP
108static void *arg_key = NULL;
109static size_t arg_key_size = 0;
e594a3b1
LP
110
111STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
112STATIC_DESTRUCTOR_REGISTER(arg_definitions, freep);
b9df3536 113STATIC_DESTRUCTOR_REGISTER(arg_key, erase_and_freep);
e594a3b1
LP
114
115typedef struct Partition Partition;
116typedef struct FreeArea FreeArea;
117typedef struct Context Context;
118
119struct Partition {
120 char *definition_path;
121
122 sd_id128_t type_uuid;
123 sd_id128_t current_uuid, new_uuid;
124 char *current_label, *new_label;
125
126 bool dropped;
127 bool factory_reset;
128 int32_t priority;
129
130 uint32_t weight, padding_weight;
131
132 uint64_t current_size, new_size;
133 uint64_t size_min, size_max;
134
135 uint64_t current_padding, new_padding;
136 uint64_t padding_min, padding_max;
137
138 uint64_t partno;
139 uint64_t offset;
140
141 struct fdisk_partition *current_partition;
142 struct fdisk_partition *new_partition;
143 FreeArea *padding_area;
144 FreeArea *allocated_to_area;
145
757bc2e4
LP
146 char *copy_blocks_path;
147 int copy_blocks_fd;
148 uint64_t copy_blocks_size;
149
53171c04 150 char *format;
8a794850 151 char **copy_files;
b9df3536 152 bool encrypt;
53171c04 153
e594a3b1
LP
154 LIST_FIELDS(Partition, partitions);
155};
156
157#define PARTITION_IS_FOREIGN(p) (!(p)->definition_path)
158#define PARTITION_EXISTS(p) (!!(p)->current_partition)
159
160struct FreeArea {
161 Partition *after;
162 uint64_t size;
163 uint64_t allocated;
164};
165
166struct Context {
167 LIST_HEAD(Partition, partitions);
168 size_t n_partitions;
169
170 FreeArea **free_areas;
171 size_t n_free_areas, n_allocated_free_areas;
172
173 uint64_t start, end, total;
174
175 struct fdisk_context *fdisk_context;
176
177 sd_id128_t seed;
178};
179
180static uint64_t round_down_size(uint64_t v, uint64_t p) {
181 return (v / p) * p;
182}
183
184static uint64_t round_up_size(uint64_t v, uint64_t p) {
185
186 v = DIV_ROUND_UP(v, p);
187
188 if (v > UINT64_MAX / p)
189 return UINT64_MAX; /* overflow */
190
191 return v * p;
192}
193
194static Partition *partition_new(void) {
195 Partition *p;
196
197 p = new(Partition, 1);
198 if (!p)
199 return NULL;
200
201 *p = (Partition) {
202 .weight = 1000,
203 .padding_weight = 0,
204 .current_size = UINT64_MAX,
205 .new_size = UINT64_MAX,
206 .size_min = UINT64_MAX,
207 .size_max = UINT64_MAX,
208 .current_padding = UINT64_MAX,
209 .new_padding = UINT64_MAX,
210 .padding_min = UINT64_MAX,
211 .padding_max = UINT64_MAX,
212 .partno = UINT64_MAX,
213 .offset = UINT64_MAX,
757bc2e4
LP
214 .copy_blocks_fd = -1,
215 .copy_blocks_size = UINT64_MAX,
e594a3b1
LP
216 };
217
218 return p;
219}
220
221static Partition* partition_free(Partition *p) {
222 if (!p)
223 return NULL;
224
225 free(p->current_label);
226 free(p->new_label);
227 free(p->definition_path);
228
229 if (p->current_partition)
230 fdisk_unref_partition(p->current_partition);
231 if (p->new_partition)
232 fdisk_unref_partition(p->new_partition);
233
757bc2e4
LP
234 free(p->copy_blocks_path);
235 safe_close(p->copy_blocks_fd);
236
53171c04 237 free(p->format);
8a794850 238 strv_free(p->copy_files);
53171c04 239
e594a3b1
LP
240 return mfree(p);
241}
242
243static Partition* partition_unlink_and_free(Context *context, Partition *p) {
244 if (!p)
245 return NULL;
246
247 LIST_REMOVE(partitions, context->partitions, p);
248
249 assert(context->n_partitions > 0);
250 context->n_partitions--;
251
252 return partition_free(p);
253}
254
255DEFINE_TRIVIAL_CLEANUP_FUNC(Partition*, partition_free);
256
257static Context *context_new(sd_id128_t seed) {
258 Context *context;
259
260 context = new(Context, 1);
261 if (!context)
262 return NULL;
263
264 *context = (Context) {
265 .start = UINT64_MAX,
266 .end = UINT64_MAX,
267 .total = UINT64_MAX,
268 .seed = seed,
269 };
270
271 return context;
272}
273
274static void context_free_free_areas(Context *context) {
275 assert(context);
276
277 for (size_t i = 0; i < context->n_free_areas; i++)
278 free(context->free_areas[i]);
279
280 context->free_areas = mfree(context->free_areas);
281 context->n_free_areas = 0;
282 context->n_allocated_free_areas = 0;
283}
284
285static Context *context_free(Context *context) {
286 if (!context)
287 return NULL;
288
289 while (context->partitions)
290 partition_unlink_and_free(context, context->partitions);
291 assert(context->n_partitions == 0);
292
293 context_free_free_areas(context);
294
295 if (context->fdisk_context)
296 fdisk_unref_context(context->fdisk_context);
297
298 return mfree(context);
299}
300
301DEFINE_TRIVIAL_CLEANUP_FUNC(Context*, context_free);
302
303static int context_add_free_area(
304 Context *context,
305 uint64_t size,
306 Partition *after) {
307
308 FreeArea *a;
309
310 assert(context);
311 assert(!after || !after->padding_area);
312
313 if (!GREEDY_REALLOC(context->free_areas, context->n_allocated_free_areas, context->n_free_areas + 1))
314 return -ENOMEM;
315
316 a = new(FreeArea, 1);
317 if (!a)
318 return -ENOMEM;
319
320 *a = (FreeArea) {
321 .size = size,
322 .after = after,
323 };
324
325 context->free_areas[context->n_free_areas++] = a;
326
327 if (after)
328 after->padding_area = a;
329
330 return 0;
331}
332
333static bool context_drop_one_priority(Context *context) {
334 int32_t priority = 0;
335 Partition *p;
336 bool exists = false;
337
338 LIST_FOREACH(partitions, p, context->partitions) {
339 if (p->dropped)
340 continue;
341 if (p->priority < priority)
342 continue;
343 if (p->priority == priority) {
344 exists = exists || PARTITION_EXISTS(p);
345 continue;
346 }
347
348 priority = p->priority;
349 exists = PARTITION_EXISTS(p);
350 }
351
352 /* Refuse to drop partitions with 0 or negative priorities or partitions of priorities that have at
353 * least one existing priority */
354 if (priority <= 0 || exists)
355 return false;
356
357 LIST_FOREACH(partitions, p, context->partitions) {
358 if (p->priority < priority)
359 continue;
360
361 if (p->dropped)
362 continue;
363
364 p->dropped = true;
365 log_info("Can't fit partition %s of priority %" PRIi32 ", dropping.", p->definition_path, p->priority);
366 }
367
368 return true;
369}
370
371static uint64_t partition_min_size(const Partition *p) {
372 uint64_t sz;
373
374 /* Calculate the disk space we really need at minimum for this partition. If the partition already
375 * exists the current size is what we really need. If it doesn't exist yet refuse to allocate less
fb08381c
LP
376 * than 4K.
377 *
378 * DEFAULT_MIN_SIZE is the default SizeMin= we configure if nothing else is specified. */
e594a3b1
LP
379
380 if (PARTITION_IS_FOREIGN(p)) {
381 /* Don't allow changing size of partitions not managed by us */
382 assert(p->current_size != UINT64_MAX);
383 return p->current_size;
384 }
385
fb08381c 386 sz = p->current_size != UINT64_MAX ? p->current_size : HARD_MIN_SIZE;
757bc2e4 387
170c9823
LP
388 if (!PARTITION_EXISTS(p)) {
389 uint64_t d = 0;
390
391 if (p->encrypt)
392 d += round_up_size(LUKS2_METADATA_SIZE, 4096);
393
394 if (p->copy_blocks_size != UINT64_MAX)
395 d += round_up_size(p->copy_blocks_size, 4096);
396 else if (p->format || p->encrypt) {
397 uint64_t f;
398
399 /* If we shall synthesize a file system, take minimal fs size into account (assumed to be 4K if not known) */
400 f = p->format ? minimal_size_by_fs_name(p->format) : UINT64_MAX;
401 d += f == UINT64_MAX ? 4096 : f;
402 }
403
404 if (d > sz)
405 sz = d;
406 }
757bc2e4
LP
407
408 return MAX(p->size_min != UINT64_MAX ? p->size_min : DEFAULT_MIN_SIZE, sz);
e594a3b1
LP
409}
410
411static uint64_t partition_max_size(const Partition *p) {
412 /* Calculate how large the partition may become at max. This is generally the configured maximum
413 * size, except when it already exists and is larger than that. In that case it's the existing size,
414 * since we never want to shrink partitions. */
415
416 if (PARTITION_IS_FOREIGN(p)) {
417 /* Don't allow changing size of partitions not managed by us */
418 assert(p->current_size != UINT64_MAX);
419 return p->current_size;
420 }
421
422 if (p->current_size != UINT64_MAX)
423 return MAX(p->current_size, p->size_max);
424
425 return p->size_max;
426}
427
428static uint64_t partition_min_size_with_padding(const Partition *p) {
429 uint64_t sz;
430
431 /* Calculate the disk space we need for this partition plus any free space coming after it. This
432 * takes user configured padding into account as well as any additional whitespace needed to align
433 * the next partition to 4K again. */
434
435 sz = partition_min_size(p);
436
437 if (p->padding_min != UINT64_MAX)
438 sz += p->padding_min;
439
440 if (PARTITION_EXISTS(p)) {
441 /* If the partition wasn't aligned, add extra space so that any we might add will be aligned */
442 assert(p->offset != UINT64_MAX);
443 return round_up_size(p->offset + sz, 4096) - p->offset;
444 }
445
446 /* If this is a new partition we'll place it aligned, hence we just need to round up the required size here */
447 return round_up_size(sz, 4096);
448}
449
450static uint64_t free_area_available(const FreeArea *a) {
451 assert(a);
452
453 /* Determines how much of this free area is not allocated yet */
454
455 assert(a->size >= a->allocated);
456 return a->size - a->allocated;
457}
458
459static uint64_t free_area_available_for_new_partitions(const FreeArea *a) {
460 uint64_t avail;
461
462 /* Similar to free_area_available(), but takes into account that the required size and padding of the
162392b7 463 * preceding partition is honoured. */
e594a3b1
LP
464
465 avail = free_area_available(a);
466 if (a->after) {
467 uint64_t need, space;
468
469 need = partition_min_size_with_padding(a->after);
470
471 assert(a->after->offset != UINT64_MAX);
472 assert(a->after->current_size != UINT64_MAX);
473
474 space = round_up_size(a->after->offset + a->after->current_size, 4096) - a->after->offset + avail;
475 if (need >= space)
476 return 0;
477
478 return space - need;
479 }
480
481 return avail;
482}
483
484static int free_area_compare(FreeArea *const *a, FreeArea *const*b) {
485 return CMP(free_area_available_for_new_partitions(*a),
486 free_area_available_for_new_partitions(*b));
487}
488
489static uint64_t charge_size(uint64_t total, uint64_t amount) {
490 uint64_t rounded;
491
492 assert(amount <= total);
493
494 /* Subtract the specified amount from total, rounding up to multiple of 4K if there's room */
495 rounded = round_up_size(amount, 4096);
496 if (rounded >= total)
497 return 0;
498
499 return total - rounded;
500}
501
502static uint64_t charge_weight(uint64_t total, uint64_t amount) {
503 assert(amount <= total);
504 return total - amount;
505}
506
507static bool context_allocate_partitions(Context *context) {
508 Partition *p;
509
510 assert(context);
511
512 /* A simple first-fit algorithm, assuming the array of free areas is sorted by size in decreasing
513 * order. */
514
515 LIST_FOREACH(partitions, p, context->partitions) {
516 bool fits = false;
517 uint64_t required;
518 FreeArea *a = NULL;
519
520 /* Skip partitions we already dropped or that already exist */
521 if (p->dropped || PARTITION_EXISTS(p))
522 continue;
523
524 /* Sort by size */
525 typesafe_qsort(context->free_areas, context->n_free_areas, free_area_compare);
526
527 /* How much do we need to fit? */
528 required = partition_min_size_with_padding(p);
529 assert(required % 4096 == 0);
530
531 for (size_t i = 0; i < context->n_free_areas; i++) {
532 a = context->free_areas[i];
533
534 if (free_area_available_for_new_partitions(a) >= required) {
535 fits = true;
536 break;
537 }
538 }
539
540 if (!fits)
541 return false; /* 😢 Oh no! We can't fit this partition into any free area! */
542
543 /* Assign the partition to this free area */
544 p->allocated_to_area = a;
545
546 /* Budget the minimal partition size */
547 a->allocated += required;
548 }
549
550 return true;
551}
552
553static int context_sum_weights(Context *context, FreeArea *a, uint64_t *ret) {
554 uint64_t weight_sum = 0;
555 Partition *p;
556
557 assert(context);
558 assert(a);
559 assert(ret);
560
561 /* Determine the sum of the weights of all partitions placed in or before the specified free area */
562
563 LIST_FOREACH(partitions, p, context->partitions) {
564 if (p->padding_area != a && p->allocated_to_area != a)
565 continue;
566
567 if (p->weight > UINT64_MAX - weight_sum)
568 goto overflow_sum;
569 weight_sum += p->weight;
570
571 if (p->padding_weight > UINT64_MAX - weight_sum)
572 goto overflow_sum;
573 weight_sum += p->padding_weight;
574 }
575
576 *ret = weight_sum;
577 return 0;
578
579overflow_sum:
580 return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW), "Combined weight of partition exceeds unsigned 64bit range, refusing.");
581}
582
583static int scale_by_weight(uint64_t value, uint64_t weight, uint64_t weight_sum, uint64_t *ret) {
584 assert(weight_sum >= weight);
585 assert(ret);
586
587 if (weight == 0) {
588 *ret = 0;
589 return 0;
590 }
591
592 if (value > UINT64_MAX / weight)
593 return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW), "Scaling by weight of partition exceeds unsigned 64bit range, refusing.");
594
595 *ret = value * weight / weight_sum;
596 return 0;
597}
598
599typedef enum GrowPartitionPhase {
600 /* The first phase: we charge partitions which need more (according to constraints) than their weight-based share. */
601 PHASE_OVERCHARGE,
602
603 /* The second phase: we charge partitions which need less (according to constraints) than their weight-based share. */
604 PHASE_UNDERCHARGE,
605
606 /* The third phase: we distribute what remains among the remaining partitions, according to the weights */
607 PHASE_DISTRIBUTE,
608} GrowPartitionPhase;
609
610static int context_grow_partitions_phase(
611 Context *context,
612 FreeArea *a,
613 GrowPartitionPhase phase,
614 uint64_t *span,
615 uint64_t *weight_sum) {
616
617 Partition *p;
618 int r;
619
620 assert(context);
621 assert(a);
622
623 /* Now let's look at the intended weights and adjust them taking the minimum space assignments into
624 * account. i.e. if a partition has a small weight but a high minimum space value set it should not
625 * get any additional room from the left-overs. Similar, if two partitions have the same weight they
626 * should get the same space if possible, even if one has a smaller minimum size than the other. */
627 LIST_FOREACH(partitions, p, context->partitions) {
628
629 /* Look only at partitions associated with this free area, i.e. immediately
162392b7 630 * preceding it, or allocated into it */
e594a3b1
LP
631 if (p->allocated_to_area != a && p->padding_area != a)
632 continue;
633
634 if (p->new_size == UINT64_MAX) {
635 bool charge = false, try_again = false;
636 uint64_t share, rsz, xsz;
637
638 /* Calculate how much this space this partition needs if everyone would get
639 * the weight based share */
640 r = scale_by_weight(*span, p->weight, *weight_sum, &share);
641 if (r < 0)
642 return r;
643
644 rsz = partition_min_size(p);
645 xsz = partition_max_size(p);
646
647 if (phase == PHASE_OVERCHARGE && rsz > share) {
648 /* This partition needs more than its calculated share. Let's assign
649 * it that, and take this partition out of all calculations and start
650 * again. */
651
652 p->new_size = rsz;
653 charge = try_again = true;
654
655 } else if (phase == PHASE_UNDERCHARGE && xsz != UINT64_MAX && xsz < share) {
656 /* This partition accepts less than its calculated
657 * share. Let's assign it that, and take this partition out
658 * of all calculations and start again. */
659
660 p->new_size = xsz;
661 charge = try_again = true;
662
663 } else if (phase == PHASE_DISTRIBUTE) {
664 /* This partition can accept its calculated share. Let's
665 * assign it. There's no need to restart things here since
666 * assigning this shouldn't impact the shares of the other
667 * partitions. */
668
669 if (PARTITION_IS_FOREIGN(p))
670 /* Never change of foreign partitions (i.e. those we don't manage) */
671 p->new_size = p->current_size;
672 else
673 p->new_size = MAX(round_down_size(share, 4096), rsz);
674
675 charge = true;
676 }
677
678 if (charge) {
679 *span = charge_size(*span, p->new_size);
680 *weight_sum = charge_weight(*weight_sum, p->weight);
681 }
682
683 if (try_again)
684 return 0; /* try again */
685 }
686
687 if (p->new_padding == UINT64_MAX) {
688 bool charge = false, try_again = false;
689 uint64_t share;
690
691 r = scale_by_weight(*span, p->padding_weight, *weight_sum, &share);
692 if (r < 0)
693 return r;
694
695 if (phase == PHASE_OVERCHARGE && p->padding_min != UINT64_MAX && p->padding_min > share) {
696 p->new_padding = p->padding_min;
697 charge = try_again = true;
698 } else if (phase == PHASE_UNDERCHARGE && p->padding_max != UINT64_MAX && p->padding_max < share) {
699 p->new_padding = p->padding_max;
700 charge = try_again = true;
701 } else if (phase == PHASE_DISTRIBUTE) {
702
703 p->new_padding = round_down_size(share, 4096);
704 if (p->padding_min != UINT64_MAX && p->new_padding < p->padding_min)
705 p->new_padding = p->padding_min;
706
707 charge = true;
708 }
709
710 if (charge) {
711 *span = charge_size(*span, p->new_padding);
712 *weight_sum = charge_weight(*weight_sum, p->padding_weight);
713 }
714
715 if (try_again)
716 return 0; /* try again */
717 }
718 }
719
720 return 1; /* done */
721}
722
723static int context_grow_partitions_on_free_area(Context *context, FreeArea *a) {
724 uint64_t weight_sum = 0, span;
725 int r;
726
727 assert(context);
728 assert(a);
729
730 r = context_sum_weights(context, a, &weight_sum);
731 if (r < 0)
732 return r;
733
734 /* Let's calculate the total area covered by this free area and the partition before it */
735 span = a->size;
736 if (a->after) {
737 assert(a->after->offset != UINT64_MAX);
738 assert(a->after->current_size != UINT64_MAX);
739
740 span += round_up_size(a->after->offset + a->after->current_size, 4096) - a->after->offset;
741 }
742
743 GrowPartitionPhase phase = PHASE_OVERCHARGE;
744 for (;;) {
745 r = context_grow_partitions_phase(context, a, phase, &span, &weight_sum);
746 if (r < 0)
747 return r;
748 if (r == 0) /* not done yet, re-run this phase */
749 continue;
750
751 if (phase == PHASE_OVERCHARGE)
752 phase = PHASE_UNDERCHARGE;
753 else if (phase == PHASE_UNDERCHARGE)
754 phase = PHASE_DISTRIBUTE;
755 else if (phase == PHASE_DISTRIBUTE)
756 break;
757 }
758
162392b7 759 /* We still have space left over? Donate to preceding partition if we have one */
e594a3b1
LP
760 if (span > 0 && a->after && !PARTITION_IS_FOREIGN(a->after)) {
761 uint64_t m, xsz;
762
763 assert(a->after->new_size != UINT64_MAX);
764 m = a->after->new_size + span;
765
766 xsz = partition_max_size(a->after);
767 if (xsz != UINT64_MAX && m > xsz)
768 m = xsz;
769
770 span = charge_size(span, m - a->after->new_size);
771 a->after->new_size = m;
772 }
773
162392b7 774 /* What? Even still some space left (maybe because there was no preceding partition, or it had a
e594a3b1
LP
775 * size limit), then let's donate it to whoever wants it. */
776 if (span > 0) {
777 Partition *p;
778
779 LIST_FOREACH(partitions, p, context->partitions) {
780 uint64_t m, xsz;
781
782 if (p->allocated_to_area != a)
783 continue;
784
785 if (PARTITION_IS_FOREIGN(p))
786 continue;
787
788 assert(p->new_size != UINT64_MAX);
789 m = p->new_size + span;
790
db144226 791 xsz = partition_max_size(p);
e594a3b1
LP
792 if (xsz != UINT64_MAX && m > xsz)
793 m = xsz;
794
795 span = charge_size(span, m - p->new_size);
796 p->new_size = m;
797
798 if (span == 0)
799 break;
800 }
801 }
802
162392b7 803 /* Yuck, still no one? Then make it padding */
e594a3b1
LP
804 if (span > 0 && a->after) {
805 assert(a->after->new_padding != UINT64_MAX);
806 a->after->new_padding += span;
807 }
808
809 return 0;
810}
811
812static int context_grow_partitions(Context *context) {
813 Partition *p;
814 int r;
815
816 assert(context);
817
818 for (size_t i = 0; i < context->n_free_areas; i++) {
819 r = context_grow_partitions_on_free_area(context, context->free_areas[i]);
820 if (r < 0)
821 return r;
822 }
823
824 /* All existing partitions that have no free space after them can't change size */
825 LIST_FOREACH(partitions, p, context->partitions) {
826 if (p->dropped)
827 continue;
828
829 if (!PARTITION_EXISTS(p) || p->padding_area) {
830 /* The algorithm above must have initialized this already */
831 assert(p->new_size != UINT64_MAX);
832 continue;
833 }
834
835 assert(p->new_size == UINT64_MAX);
836 p->new_size = p->current_size;
837
838 assert(p->new_padding == UINT64_MAX);
839 p->new_padding = p->current_padding;
840 }
841
842 return 0;
843}
844
845static void context_place_partitions(Context *context) {
846 uint64_t partno = 0;
847 Partition *p;
848
849 assert(context);
850
851 /* Determine next partition number to assign */
852 LIST_FOREACH(partitions, p, context->partitions) {
853 if (!PARTITION_EXISTS(p))
854 continue;
855
856 assert(p->partno != UINT64_MAX);
857 if (p->partno >= partno)
858 partno = p->partno + 1;
859 }
860
861 for (size_t i = 0; i < context->n_free_areas; i++) {
862 FreeArea *a = context->free_areas[i];
863 uint64_t start, left;
864
865 if (a->after) {
866 assert(a->after->offset != UINT64_MAX);
867 assert(a->after->new_size != UINT64_MAX);
868 assert(a->after->new_padding != UINT64_MAX);
869
870 start = a->after->offset + a->after->new_size + a->after->new_padding;
871 } else
872 start = context->start;
873
874 start = round_up_size(start, 4096);
875 left = a->size;
876
877 LIST_FOREACH(partitions, p, context->partitions) {
878 if (p->allocated_to_area != a)
879 continue;
880
881 p->offset = start;
882 p->partno = partno++;
883
884 assert(left >= p->new_size);
885 start += p->new_size;
886 left -= p->new_size;
887
888 assert(left >= p->new_padding);
889 start += p->new_padding;
890 left -= p->new_padding;
891 }
892 }
893}
894
e594a3b1
LP
895static int config_parse_type(
896 const char *unit,
897 const char *filename,
898 unsigned line,
899 const char *section,
900 unsigned section_line,
901 const char *lvalue,
902 int ltype,
903 const char *rvalue,
904 void *data,
905 void *userdata) {
906
907 sd_id128_t *type_uuid = data;
908 int r;
909
910 assert(rvalue);
911 assert(type_uuid);
912
913 r = gpt_partition_type_uuid_from_string(rvalue, type_uuid);
914 if (r < 0)
915 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse partition type: %s", rvalue);
916
917 return 0;
918}
919
8a794850 920static const Specifier specifier_table[] = {
2824aa07 921 COMMON_SYSTEM_SPECIFIERS,
8a794850
LP
922 {}
923};
924
e594a3b1
LP
925static int config_parse_label(
926 const char *unit,
927 const char *filename,
928 unsigned line,
929 const char *section,
930 unsigned section_line,
931 const char *lvalue,
932 int ltype,
933 const char *rvalue,
934 void *data,
935 void *userdata) {
936
937 _cleanup_free_ char16_t *recoded = NULL;
e031166e 938 _cleanup_free_ char *resolved = NULL;
e594a3b1
LP
939 char **label = data;
940 int r;
941
942 assert(rvalue);
943 assert(label);
944
e031166e
LP
945 r = specifier_printf(rvalue, specifier_table, NULL, &resolved);
946 if (r < 0) {
e459258f 947 log_syntax(unit, LOG_WARNING, filename, line, r,
e031166e
LP
948 "Failed to expand specifiers in Label=, ignoring: %s", rvalue);
949 return 0;
950 }
951
952 if (!utf8_is_valid(resolved)) {
e594a3b1
LP
953 log_syntax(unit, LOG_WARNING, filename, line, 0,
954 "Partition label not valid UTF-8, ignoring: %s", rvalue);
955 return 0;
956 }
957
e031166e 958 recoded = utf8_to_utf16(resolved, strlen(resolved));
e594a3b1
LP
959 if (!recoded)
960 return log_oom();
961
962 if (char16_strlen(recoded) > 36) {
963 log_syntax(unit, LOG_WARNING, filename, line, 0,
46072ae3
ZJS
964 "Partition label too long for GPT table, ignoring: \"%s\" (from \"%s\")",
965 resolved, rvalue);
e594a3b1
LP
966 return 0;
967 }
968
e031166e 969 free_and_replace(*label, resolved);
e594a3b1
LP
970 return 0;
971}
972
973static int config_parse_weight(
974 const char *unit,
975 const char *filename,
976 unsigned line,
977 const char *section,
978 unsigned section_line,
979 const char *lvalue,
980 int ltype,
981 const char *rvalue,
982 void *data,
983 void *userdata) {
984
985 uint32_t *priority = data, v;
986 int r;
987
988 assert(rvalue);
989 assert(priority);
990
991 r = safe_atou32(rvalue, &v);
992 if (r < 0) {
993 log_syntax(unit, LOG_WARNING, filename, line, r,
994 "Failed to parse weight value, ignoring: %s", rvalue);
995 return 0;
996 }
997
998 if (v > 1000U*1000U) {
c8f3d767 999 log_syntax(unit, LOG_WARNING, filename, line, 0,
e594a3b1
LP
1000 "Weight needs to be in range 0…10000000, ignoring: %" PRIu32, v);
1001 return 0;
1002 }
1003
1004 *priority = v;
1005 return 0;
1006}
1007
1008static int config_parse_size4096(
1009 const char *unit,
1010 const char *filename,
1011 unsigned line,
1012 const char *section,
1013 unsigned section_line,
1014 const char *lvalue,
1015 int ltype,
1016 const char *rvalue,
1017 void *data,
1018 void *userdata) {
1019
1020 uint64_t *sz = data, parsed;
1021 int r;
1022
1023 assert(rvalue);
1024 assert(data);
1025
1026 r = parse_size(rvalue, 1024, &parsed);
1027 if (r < 0)
c8f3d767 1028 return log_syntax(unit, LOG_ERR, filename, line, r,
e594a3b1
LP
1029 "Failed to parse size value: %s", rvalue);
1030
1031 if (ltype > 0)
1032 *sz = round_up_size(parsed, 4096);
1033 else if (ltype < 0)
1034 *sz = round_down_size(parsed, 4096);
1035 else
1036 *sz = parsed;
1037
1038 if (*sz != parsed)
1039 log_syntax(unit, LOG_NOTICE, filename, line, r, "Rounded %s= size %" PRIu64 " → %" PRIu64 ", a multiple of 4096.", lvalue, parsed, *sz);
1040
1041 return 0;
1042}
1043
53171c04
LP
1044static int config_parse_fstype(
1045 const char *unit,
1046 const char *filename,
1047 unsigned line,
1048 const char *section,
1049 unsigned section_line,
1050 const char *lvalue,
1051 int ltype,
1052 const char *rvalue,
1053 void *data,
1054 void *userdata) {
1055
1056 char **fstype = data;
1057
1058 assert(rvalue);
1059 assert(data);
1060
1061 if (!filename_is_valid(rvalue))
1062 return log_syntax(unit, LOG_ERR, filename, line, 0,
1063 "File system type is not valid, refusing: %s", rvalue);
1064
1065 return free_and_strdup_warn(fstype, rvalue);
1066}
1067
8a794850
LP
1068static int config_parse_copy_files(
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 _cleanup_free_ char *source = NULL, *buffer = NULL, *resolved_source = NULL, *resolved_target = NULL;
1081 const char *p = rvalue, *target;
1082 Partition *partition = data;
1083 int r;
1084
1085 assert(rvalue);
1086 assert(partition);
1087
1088 r = extract_first_word(&p, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_DONT_COALESCE_SEPARATORS);
1089 if (r < 0)
1090 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract source path: %s", rvalue);
1091 if (r == 0) {
1092 log_syntax(unit, LOG_WARNING, filename, line, 0, "No argument specified: %s", rvalue);
1093 return 0;
1094 }
1095
1096 r = extract_first_word(&p, &buffer, ":", EXTRACT_CUNESCAPE|EXTRACT_DONT_COALESCE_SEPARATORS);
1097 if (r < 0)
1098 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract target path: %s", rvalue);
1099 if (r == 0)
1100 target = source; /* No target, then it's the same as the source */
1101 else
1102 target = buffer;
1103
1104 if (!isempty(p))
1105 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "Too many arguments: %s", rvalue);
1106
1107 r = specifier_printf(source, specifier_table, NULL, &resolved_source);
1108 if (r < 0) {
1109 log_syntax(unit, LOG_WARNING, filename, line, r,
1110 "Failed to expand specifiers in CopyFiles= source, ignoring: %s", rvalue);
1111 return 0;
1112 }
1113
1114 if (!path_is_absolute(resolved_source) || !path_is_normalized(resolved_source)) {
1115 log_syntax(unit, LOG_WARNING, filename, line, 0,
1116 "Invalid path name in CopyFiles= source, ignoring: %s", resolved_source);
1117 return 0;
1118 }
1119
1120 r = specifier_printf(target, specifier_table, NULL, &resolved_target);
1121 if (r < 0) {
1122 log_syntax(unit, LOG_WARNING, filename, line, r,
1123 "Failed to expand specifiers in CopyFiles= target, ignoring: %s", resolved_target);
1124 return 0;
1125 }
1126
1127 if (!path_is_absolute(resolved_target) || !path_is_normalized(resolved_target)) {
1128 log_syntax(unit, LOG_WARNING, filename, line, 0,
1129 "Invalid path name in CopyFiles= source, ignoring: %s", resolved_target);
1130 return 0;
1131 }
1132
1133 r = strv_consume_pair(&partition->copy_files, TAKE_PTR(resolved_source), TAKE_PTR(resolved_target));
1134 if (r < 0)
1135 return log_oom();
1136
1137 return 0;
1138}
1139
e594a3b1
LP
1140static int partition_read_definition(Partition *p, const char *path) {
1141
1142 ConfigTableItem table[] = {
8a794850
LP
1143 { "Partition", "Type", config_parse_type, 0, &p->type_uuid },
1144 { "Partition", "Label", config_parse_label, 0, &p->new_label },
1145 { "Partition", "UUID", config_parse_id128, 0, &p->new_uuid },
1146 { "Partition", "Priority", config_parse_int32, 0, &p->priority },
1147 { "Partition", "Weight", config_parse_weight, 0, &p->weight },
1148 { "Partition", "PaddingWeight", config_parse_weight, 0, &p->padding_weight },
1149 { "Partition", "SizeMinBytes", config_parse_size4096, 1, &p->size_min },
1150 { "Partition", "SizeMaxBytes", config_parse_size4096, -1, &p->size_max },
1151 { "Partition", "PaddingMinBytes", config_parse_size4096, 1, &p->padding_min },
1152 { "Partition", "PaddingMaxBytes", config_parse_size4096, -1, &p->padding_max },
1153 { "Partition", "FactoryReset", config_parse_bool, 0, &p->factory_reset },
1154 { "Partition", "CopyBlocks", config_parse_path, 0, &p->copy_blocks_path },
1155 { "Partition", "Format", config_parse_fstype, 0, &p->format },
1156 { "Partition", "CopyFiles", config_parse_copy_files, 0, p },
b9df3536 1157 { "Partition", "Encrypt", config_parse_bool, 0, &p->encrypt },
e594a3b1
LP
1158 {}
1159 };
1160 int r;
1161
4f9ff96a
LP
1162 r = config_parse(NULL, path, NULL,
1163 "Partition\0",
1164 config_item_table_lookup, table,
1165 CONFIG_PARSE_WARN,
1166 p,
1167 NULL);
e594a3b1
LP
1168 if (r < 0)
1169 return r;
1170
1171 if (p->size_min != UINT64_MAX && p->size_max != UINT64_MAX && p->size_min > p->size_max)
1172 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1173 "SizeMinBytes= larger than SizeMaxBytes=, refusing.");
1174
1175 if (p->padding_min != UINT64_MAX && p->padding_max != UINT64_MAX && p->padding_min > p->padding_max)
1176 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1177 "PaddingMinBytes= larger than PaddingMaxBytes=, refusing.");
1178
1179 if (sd_id128_is_null(p->type_uuid))
1180 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1181 "Type= not defined, refusing.");
1182
8a794850 1183 if (p->copy_blocks_path && (p->format || !strv_isempty(p->copy_files)))
53171c04
LP
1184 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1185 "Format= and CopyBlocks= cannot be combined, refusing.");
1186
8a794850
LP
1187 if (!strv_isempty(p->copy_files) && streq_ptr(p->format, "swap"))
1188 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
1189 "Format=swap and CopyFiles= cannot be combined, refusing.");
1190
b9df3536
LP
1191 if (!p->format && (!strv_isempty(p->copy_files) || (p->encrypt && !p->copy_blocks_path))) {
1192 /* Pick "ext4" as file system if we are configured to copy files or encrypt the device */
8a794850
LP
1193 p->format = strdup("ext4");
1194 if (!p->format)
1195 return log_oom();
1196 }
1197
e594a3b1
LP
1198 return 0;
1199}
1200
1201static int context_read_definitions(
1202 Context *context,
1203 const char *directory,
1204 const char *root) {
1205
1206 _cleanup_strv_free_ char **files = NULL;
1207 Partition *last = NULL;
1208 char **f;
1209 int r;
1210
1211 assert(context);
1212
1213 if (directory)
1214 r = conf_files_list_strv(&files, ".conf", NULL, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, (const char**) STRV_MAKE(directory));
1215 else
1216 r = conf_files_list_strv(&files, ".conf", root, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, (const char**) CONF_PATHS_STRV("repart.d"));
1217 if (r < 0)
1218 return log_error_errno(r, "Failed to enumerate *.conf files: %m");
1219
1220 STRV_FOREACH(f, files) {
1221 _cleanup_(partition_freep) Partition *p = NULL;
1222
1223 p = partition_new();
1224 if (!p)
1225 return log_oom();
1226
1227 p->definition_path = strdup(*f);
1228 if (!p->definition_path)
1229 return log_oom();
1230
1231 r = partition_read_definition(p, *f);
1232 if (r < 0)
1233 return r;
1234
1235 LIST_INSERT_AFTER(partitions, context->partitions, last, p);
1236 last = TAKE_PTR(p);
1237 context->n_partitions++;
1238 }
1239
1240 return 0;
1241}
1242
1243DEFINE_TRIVIAL_CLEANUP_FUNC(struct fdisk_context*, fdisk_unref_context);
1244DEFINE_TRIVIAL_CLEANUP_FUNC(struct fdisk_partition*, fdisk_unref_partition);
1245DEFINE_TRIVIAL_CLEANUP_FUNC(struct fdisk_parttype*, fdisk_unref_parttype);
1246DEFINE_TRIVIAL_CLEANUP_FUNC(struct fdisk_table*, fdisk_unref_table);
1247
1248static int determine_current_padding(
1249 struct fdisk_context *c,
1250 struct fdisk_table *t,
1251 struct fdisk_partition *p,
1252 uint64_t *ret) {
1253
1254 size_t n_partitions;
1255 uint64_t offset, next = UINT64_MAX;
1256
1257 assert(c);
1258 assert(t);
1259 assert(p);
1260
1261 if (!fdisk_partition_has_end(p))
1262 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Partition has no end!");
1263
1264 offset = fdisk_partition_get_end(p);
1265 assert(offset < UINT64_MAX / 512);
1266 offset *= 512;
1267
1268 n_partitions = fdisk_table_get_nents(t);
1269 for (size_t i = 0; i < n_partitions; i++) {
1270 struct fdisk_partition *q;
1271 uint64_t start;
1272
1273 q = fdisk_table_get_partition(t, i);
1274 if (!q)
1275 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read partition metadata: %m");
1276
1277 if (fdisk_partition_is_used(q) <= 0)
1278 continue;
1279
1280 if (!fdisk_partition_has_start(q))
1281 continue;
1282
1283 start = fdisk_partition_get_start(q);
1284 assert(start < UINT64_MAX / 512);
1285 start *= 512;
1286
1287 if (start >= offset && (next == UINT64_MAX || next > start))
1288 next = start;
1289 }
1290
1291 if (next == UINT64_MAX) {
1292 /* No later partition? In that case check the end of the usable area */
1293 next = fdisk_get_last_lba(c);
1294 assert(next < UINT64_MAX);
1295 next++; /* The last LBA is one sector before the end */
1296
1297 assert(next < UINT64_MAX / 512);
1298 next *= 512;
1299
1300 if (offset > next)
1301 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Partition end beyond disk end.");
1302 }
1303
1304 assert(next >= offset);
1305 offset = round_up_size(offset, 4096);
1306 next = round_down_size(next, 4096);
1307
1308 if (next >= offset) /* Check again, rounding might have fucked things up */
1309 *ret = next - offset;
1310 else
1311 *ret = 0;
1312
1313 return 0;
1314}
1315
1316static int fdisk_ask_cb(struct fdisk_context *c, struct fdisk_ask *ask, void *data) {
1317 _cleanup_free_ char *ids = NULL;
1318 int r;
1319
1320 if (fdisk_ask_get_type(ask) != FDISK_ASKTYPE_STRING)
1321 return -EINVAL;
1322
1323 ids = new(char, ID128_UUID_STRING_MAX);
1324 if (!ids)
1325 return -ENOMEM;
1326
1327 r = fdisk_ask_string_set_result(ask, id128_to_uuid_string(*(sd_id128_t*) data, ids));
1328 if (r < 0)
1329 return r;
1330
1331 TAKE_PTR(ids);
1332 return 0;
1333}
1334
1335static int fdisk_set_disklabel_id_by_uuid(struct fdisk_context *c, sd_id128_t id) {
1336 int r;
1337
1338 r = fdisk_set_ask(c, fdisk_ask_cb, &id);
1339 if (r < 0)
1340 return r;
1341
1342 r = fdisk_set_disklabel_id(c);
1343 if (r < 0)
1344 return r;
1345
1346 return fdisk_set_ask(c, NULL, NULL);
1347}
1348
53171c04 1349static int derive_uuid(sd_id128_t base, const char *token, sd_id128_t *ret) {
e594a3b1
LP
1350 union {
1351 unsigned char md[SHA256_DIGEST_LENGTH];
1352 sd_id128_t id;
1353 } result;
1354
53171c04 1355 assert(token);
e594a3b1
LP
1356 assert(ret);
1357
53171c04
LP
1358 /* Derive a new UUID from the specified UUID in a stable and reasonably safe way. Specifically, we
1359 * calculate the HMAC-SHA256 of the specified token string, keyed by the supplied base (typically the
1360 * machine ID). We use the machine ID as key (and not as cleartext!) of the HMAC operation since it's
1361 * the machine ID we don't want to leak. */
e594a3b1
LP
1362
1363 if (!HMAC(EVP_sha256(),
53171c04
LP
1364 &base, sizeof(base),
1365 (const unsigned char*) token, strlen(token),
e594a3b1
LP
1366 result.md, NULL))
1367 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "HMAC-SHA256 calculation failed.");
1368
1369 /* Take the first half, mark it as v4 UUID */
1370 assert_cc(sizeof(result.md) == sizeof(result.id) * 2);
1371 *ret = id128_make_v4_uuid(result.id);
1372 return 0;
1373}
1374
a26f4a49
LP
1375static int context_load_partition_table(
1376 Context *context,
1377 const char *node,
1378 int *backing_fd) {
1379
e594a3b1
LP
1380 _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
1381 _cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL;
1382 uint64_t left_boundary = UINT64_MAX, first_lba, last_lba, nsectors;
1383 _cleanup_free_ char *disk_uuid_string = NULL;
1384 bool from_scratch = false;
1385 sd_id128_t disk_uuid;
1386 size_t n_partitions;
1387 int r;
1388
1389 assert(context);
1390 assert(node);
a26f4a49 1391 assert(backing_fd);
170c9823
LP
1392 assert(!context->fdisk_context);
1393 assert(!context->free_areas);
1394 assert(context->start == UINT64_MAX);
1395 assert(context->end == UINT64_MAX);
1396 assert(context->total == UINT64_MAX);
e594a3b1
LP
1397
1398 c = fdisk_new_context();
1399 if (!c)
1400 return log_oom();
1401
a26f4a49
LP
1402 /* libfdisk doesn't have an API to operate on arbitrary fds, hence reopen the fd going via the
1403 * /proc/self/fd/ magic path if we have an existing fd. Open the original file otherwise. */
1404 if (*backing_fd < 0)
1405 r = fdisk_assign_device(c, node, arg_dry_run);
1406 else {
1407 char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
1408 xsprintf(procfs_path, "/proc/self/fd/%i", *backing_fd);
1409
1410 r = fdisk_assign_device(c, procfs_path, arg_dry_run);
1411 }
170c9823
LP
1412 if (r == -EINVAL && arg_size_auto) {
1413 struct stat st;
1414
1415 /* libfdisk returns EINVAL if opening a file of size zero. Let's check for that, and accept
1416 * it if automatic sizing is requested. */
1417
1418 if (*backing_fd < 0)
1419 r = stat(node, &st);
1420 else
1421 r = fstat(*backing_fd, &st);
1422 if (r < 0)
1423 return log_error_errno(errno, "Failed to stat block device '%s': %m", node);
1424
1425 if (S_ISREG(st.st_mode) && st.st_size == 0)
1426 return /* from_scratch = */ true;
1427
1428 r = -EINVAL;
1429 }
e594a3b1 1430 if (r < 0)
a26f4a49
LP
1431 return log_error_errno(r, "Failed to open device '%s': %m", node);
1432
1433 if (*backing_fd < 0) {
1434 /* If we have no fd referencing the device yet, make a copy of the fd now, so that we have one */
1435 *backing_fd = fcntl(fdisk_get_devfd(c), F_DUPFD_CLOEXEC, 3);
1436 if (*backing_fd < 0)
1437 return log_error_errno(errno, "Failed to duplicate fdisk fd: %m");
1438 }
e594a3b1
LP
1439
1440 /* Tell udev not to interfere while we are processing the device */
1441 if (flock(fdisk_get_devfd(c), arg_dry_run ? LOCK_SH : LOCK_EX) < 0)
1442 return log_error_errno(errno, "Failed to lock block device: %m");
1443
1444 switch (arg_empty) {
1445
1446 case EMPTY_REFUSE:
1447 /* Refuse empty disks, insist on an existing GPT partition table */
1448 if (!fdisk_is_labeltype(c, FDISK_DISKLABEL_GPT))
1449 return log_notice_errno(SYNTHETIC_ERRNO(EHWPOISON), "Disk %s has no GPT disk label, not repartitioning.", node);
1450
1451 break;
1452
1453 case EMPTY_REQUIRE:
1454 /* Require an empty disk, refuse any existing partition table */
1455 r = fdisk_has_label(c);
1456 if (r < 0)
1457 return log_error_errno(r, "Failed to determine whether disk %s has a disk label: %m", node);
1458 if (r > 0)
1459 return log_notice_errno(SYNTHETIC_ERRNO(EHWPOISON), "Disk %s already has a disk label, refusing.", node);
1460
1461 from_scratch = true;
1462 break;
1463
1464 case EMPTY_ALLOW:
1465 /* Allow both an empty disk and an existing partition table, but only GPT */
1466 r = fdisk_has_label(c);
1467 if (r < 0)
1468 return log_error_errno(r, "Failed to determine whether disk %s has a disk label: %m", node);
1469 if (r > 0) {
1470 if (!fdisk_is_labeltype(c, FDISK_DISKLABEL_GPT))
1471 return log_notice_errno(SYNTHETIC_ERRNO(EHWPOISON), "Disk %s has non-GPT disk label, not repartitioning.", node);
1472 } else
1473 from_scratch = true;
1474
1475 break;
1476
1477 case EMPTY_FORCE:
a26f4a49 1478 case EMPTY_CREATE:
e594a3b1
LP
1479 /* Always reinitiaize the disk, don't consider what there was on the disk before */
1480 from_scratch = true;
1481 break;
1482 }
1483
1484 if (from_scratch) {
e594a3b1
LP
1485 r = fdisk_create_disklabel(c, "gpt");
1486 if (r < 0)
1487 return log_error_errno(r, "Failed to create GPT disk label: %m");
1488
53171c04 1489 r = derive_uuid(context->seed, "disk-uuid", &disk_uuid);
e594a3b1
LP
1490 if (r < 0)
1491 return log_error_errno(r, "Failed to acquire disk GPT uuid: %m");
1492
1493 r = fdisk_set_disklabel_id_by_uuid(c, disk_uuid);
1494 if (r < 0)
1495 return log_error_errno(r, "Failed to set GPT disk label: %m");
1496
1497 goto add_initial_free_area;
1498 }
1499
1500 r = fdisk_get_disklabel_id(c, &disk_uuid_string);
1501 if (r < 0)
1502 return log_error_errno(r, "Failed to get current GPT disk label UUID: %m");
1503
1504 r = sd_id128_from_string(disk_uuid_string, &disk_uuid);
1505 if (r < 0)
1506 return log_error_errno(r, "Failed to parse current GPT disk label UUID: %m");
1507
1508 if (sd_id128_is_null(disk_uuid)) {
53171c04 1509 r = derive_uuid(context->seed, "disk-uuid", &disk_uuid);
e594a3b1
LP
1510 if (r < 0)
1511 return log_error_errno(r, "Failed to acquire disk GPT uuid: %m");
1512
1513 r = fdisk_set_disklabel_id(c);
1514 if (r < 0)
1515 return log_error_errno(r, "Failed to set GPT disk label: %m");
1516 }
1517
1518 r = fdisk_get_partitions(c, &t);
1519 if (r < 0)
1520 return log_error_errno(r, "Failed to acquire partition table: %m");
1521
1522 n_partitions = fdisk_table_get_nents(t);
1523 for (size_t i = 0; i < n_partitions; i++) {
1524 _cleanup_free_ char *label_copy = NULL;
1525 Partition *pp, *last = NULL;
1526 struct fdisk_partition *p;
1527 struct fdisk_parttype *pt;
1528 const char *pts, *ids, *label;
1529 uint64_t sz, start;
1530 bool found = false;
1531 sd_id128_t ptid, id;
1532 size_t partno;
1533
1534 p = fdisk_table_get_partition(t, i);
1535 if (!p)
1536 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read partition metadata: %m");
1537
1538 if (fdisk_partition_is_used(p) <= 0)
1539 continue;
1540
1541 if (fdisk_partition_has_start(p) <= 0 ||
1542 fdisk_partition_has_size(p) <= 0 ||
1543 fdisk_partition_has_partno(p) <= 0)
1544 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Found a partition without a position, size or number.");
1545
1546 pt = fdisk_partition_get_type(p);
1547 if (!pt)
1548 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to acquire type of partition: %m");
1549
1550 pts = fdisk_parttype_get_string(pt);
1551 if (!pts)
1552 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to acquire type of partition as string: %m");
1553
1554 r = sd_id128_from_string(pts, &ptid);
1555 if (r < 0)
1556 return log_error_errno(r, "Failed to parse partition type UUID %s: %m", pts);
1557
1558 ids = fdisk_partition_get_uuid(p);
1559 if (!ids)
1560 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Found a partition without a UUID.");
1561
1562 r = sd_id128_from_string(ids, &id);
1563 if (r < 0)
1564 return log_error_errno(r, "Failed to parse partition UUID %s: %m", ids);
1565
1566 label = fdisk_partition_get_name(p);
1567 if (!isempty(label)) {
1568 label_copy = strdup(label);
1569 if (!label_copy)
1570 return log_oom();
1571 }
1572
1573 sz = fdisk_partition_get_size(p);
1574 assert_se(sz <= UINT64_MAX/512);
1575 sz *= 512;
1576
1577 start = fdisk_partition_get_start(p);
1578 assert_se(start <= UINT64_MAX/512);
1579 start *= 512;
1580
1581 partno = fdisk_partition_get_partno(p);
1582
1583 if (left_boundary == UINT64_MAX || left_boundary > start)
1584 left_boundary = start;
1585
1586 /* Assign this existing partition to the first partition of the right type that doesn't have
1587 * an existing one assigned yet. */
1588 LIST_FOREACH(partitions, pp, context->partitions) {
1589 last = pp;
1590
1591 if (!sd_id128_equal(pp->type_uuid, ptid))
1592 continue;
1593
1594 if (!pp->current_partition) {
1595 pp->current_uuid = id;
1596 pp->current_size = sz;
1597 pp->offset = start;
1598 pp->partno = partno;
1599 pp->current_label = TAKE_PTR(label_copy);
1600
1601 pp->current_partition = p;
1602 fdisk_ref_partition(p);
1603
1604 r = determine_current_padding(c, t, p, &pp->current_padding);
1605 if (r < 0)
1606 return r;
1607
1608 if (pp->current_padding > 0) {
1609 r = context_add_free_area(context, pp->current_padding, pp);
1610 if (r < 0)
1611 return r;
1612 }
1613
1614 found = true;
1615 break;
1616 }
1617 }
1618
1619 /* If we have no matching definition, create a new one. */
1620 if (!found) {
1621 _cleanup_(partition_freep) Partition *np = NULL;
1622
1623 np = partition_new();
1624 if (!np)
1625 return log_oom();
1626
1627 np->current_uuid = id;
1628 np->type_uuid = ptid;
1629 np->current_size = sz;
1630 np->offset = start;
1631 np->partno = partno;
1632 np->current_label = TAKE_PTR(label_copy);
1633
1634 np->current_partition = p;
1635 fdisk_ref_partition(p);
1636
1637 r = determine_current_padding(c, t, p, &np->current_padding);
1638 if (r < 0)
1639 return r;
1640
1641 if (np->current_padding > 0) {
1642 r = context_add_free_area(context, np->current_padding, np);
1643 if (r < 0)
1644 return r;
1645 }
1646
1647 LIST_INSERT_AFTER(partitions, context->partitions, last, TAKE_PTR(np));
1648 context->n_partitions++;
1649 }
1650 }
1651
1652add_initial_free_area:
1653 nsectors = fdisk_get_nsectors(c);
1654 assert(nsectors <= UINT64_MAX/512);
1655 nsectors *= 512;
1656
1657 first_lba = fdisk_get_first_lba(c);
1658 assert(first_lba <= UINT64_MAX/512);
1659 first_lba *= 512;
1660
1661 last_lba = fdisk_get_last_lba(c);
1662 assert(last_lba < UINT64_MAX);
1663 last_lba++;
1664 assert(last_lba <= UINT64_MAX/512);
1665 last_lba *= 512;
1666
1667 assert(last_lba >= first_lba);
1668
1669 if (left_boundary == UINT64_MAX) {
1670 /* No partitions at all? Then the whole disk is up for grabs. */
1671
1672 first_lba = round_up_size(first_lba, 4096);
1673 last_lba = round_down_size(last_lba, 4096);
1674
1675 if (last_lba > first_lba) {
1676 r = context_add_free_area(context, last_lba - first_lba, NULL);
1677 if (r < 0)
1678 return r;
1679 }
1680 } else {
1681 /* Add space left of first partition */
1682 assert(left_boundary >= first_lba);
1683
1684 first_lba = round_up_size(first_lba, 4096);
1685 left_boundary = round_down_size(left_boundary, 4096);
1686 last_lba = round_down_size(last_lba, 4096);
1687
1688 if (left_boundary > first_lba) {
1689 r = context_add_free_area(context, left_boundary - first_lba, NULL);
1690 if (r < 0)
1691 return r;
1692 }
1693 }
1694
1695 context->start = first_lba;
1696 context->end = last_lba;
1697 context->total = nsectors;
1698 context->fdisk_context = TAKE_PTR(c);
1699
1700 return from_scratch;
1701}
1702
1703static void context_unload_partition_table(Context *context) {
1704 Partition *p, *next;
1705
1706 assert(context);
1707
1708 LIST_FOREACH_SAFE(partitions, p, next, context->partitions) {
1709
1710 /* Entirely remove partitions that have no configuration */
1711 if (PARTITION_IS_FOREIGN(p)) {
1712 partition_unlink_and_free(context, p);
1713 continue;
1714 }
1715
1716 /* Otherwise drop all data we read off the block device and everything we might have
1717 * calculated based on it */
1718
1719 p->dropped = false;
1720 p->current_size = UINT64_MAX;
1721 p->new_size = UINT64_MAX;
1722 p->current_padding = UINT64_MAX;
1723 p->new_padding = UINT64_MAX;
1724 p->partno = UINT64_MAX;
1725 p->offset = UINT64_MAX;
1726
1727 if (p->current_partition) {
1728 fdisk_unref_partition(p->current_partition);
1729 p->current_partition = NULL;
1730 }
1731
1732 if (p->new_partition) {
1733 fdisk_unref_partition(p->new_partition);
1734 p->new_partition = NULL;
1735 }
1736
1737 p->padding_area = NULL;
1738 p->allocated_to_area = NULL;
1739
15d43e30
LP
1740 p->current_uuid = SD_ID128_NULL;
1741 p->current_label = mfree(p->current_label);
e594a3b1
LP
1742 }
1743
1744 context->start = UINT64_MAX;
1745 context->end = UINT64_MAX;
1746 context->total = UINT64_MAX;
1747
1748 if (context->fdisk_context) {
1749 fdisk_unref_context(context->fdisk_context);
1750 context->fdisk_context = NULL;
1751 }
1752
1753 context_free_free_areas(context);
1754}
1755
1756static int format_size_change(uint64_t from, uint64_t to, char **ret) {
1757 char format_buffer1[FORMAT_BYTES_MAX], format_buffer2[FORMAT_BYTES_MAX], *buf;
1758
1759 if (from != UINT64_MAX)
1760 format_bytes(format_buffer1, sizeof(format_buffer1), from);
1761 if (to != UINT64_MAX)
1762 format_bytes(format_buffer2, sizeof(format_buffer2), to);
1763
1764 if (from != UINT64_MAX) {
1765 if (from == to || to == UINT64_MAX)
1766 buf = strdup(format_buffer1);
1767 else
1768 buf = strjoin(format_buffer1, " ", special_glyph(SPECIAL_GLYPH_ARROW), " ", format_buffer2);
1769 } else if (to != UINT64_MAX)
1770 buf = strjoin(special_glyph(SPECIAL_GLYPH_ARROW), " ", format_buffer2);
1771 else {
1772 *ret = NULL;
1773 return 0;
1774 }
1775
1776 if (!buf)
1777 return log_oom();
1778
1779 *ret = TAKE_PTR(buf);
1780 return 1;
1781}
1782
1783static const char *partition_label(const Partition *p) {
1784 assert(p);
1785
1786 if (p->new_label)
1787 return p->new_label;
1788
1789 if (p->current_label)
1790 return p->current_label;
1791
1792 return gpt_partition_type_uuid_to_string(p->type_uuid);
1793}
1794
1795static int context_dump_partitions(Context *context, const char *node) {
1796 _cleanup_(table_unrefp) Table *t = NULL;
1797 uint64_t sum_padding = 0, sum_size = 0;
1798 Partition *p;
1799 int r;
1800
a015fbe7
TH
1801 if (!arg_json && context->n_partitions == 0) {
1802 log_info("Empty partition table.");
1803 return 0;
1804 }
1805
1806 t = table_new("type", "label", "uuid", "file", "node", "offset", "old size", "raw size", "size", "old padding", "raw padding", "padding", "activity");
e594a3b1
LP
1807 if (!t)
1808 return log_oom();
1809
a015fbe7
TH
1810 if (!DEBUG_LOGGING) {
1811 if (arg_json)
1812 (void) table_set_display(t, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4,
1813 (size_t) 5, (size_t) 6, (size_t) 7, (size_t) 9, (size_t) 10, (size_t) 12, (size_t) -1);
1814 else
1815 (void) table_set_display(t, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4,
1816 (size_t) 8, (size_t) 11, (size_t) -1);
1817 }
e594a3b1
LP
1818
1819 (void) table_set_align_percent(t, table_get_cell(t, 0, 4), 100);
1820 (void) table_set_align_percent(t, table_get_cell(t, 0, 5), 100);
1821
1822 LIST_FOREACH(partitions, p, context->partitions) {
1823 _cleanup_free_ char *size_change = NULL, *padding_change = NULL, *partname = NULL;
1824 char uuid_buffer[ID128_UUID_STRING_MAX];
a015fbe7 1825 const char *label, *activity = NULL;
e594a3b1
LP
1826
1827 if (p->dropped)
1828 continue;
1829
a015fbe7
TH
1830 if (p->current_size == UINT64_MAX)
1831 activity = "create";
1832 else if (p->current_size != p->new_size)
1833 activity = "resize";
1834
e594a3b1
LP
1835 label = partition_label(p);
1836 partname = p->partno != UINT64_MAX ? fdisk_partname(node, p->partno+1) : NULL;
1837
1838 r = format_size_change(p->current_size, p->new_size, &size_change);
1839 if (r < 0)
1840 return r;
1841
1842 r = format_size_change(p->current_padding, p->new_padding, &padding_change);
1843 if (r < 0)
1844 return r;
1845
1846 if (p->new_size != UINT64_MAX)
1847 sum_size += p->new_size;
1848 if (p->new_padding != UINT64_MAX)
1849 sum_padding += p->new_padding;
1850
1851 r = table_add_many(
1852 t,
1853 TABLE_STRING, gpt_partition_type_uuid_to_string_harder(p->type_uuid, uuid_buffer),
1854 TABLE_STRING, label ?: "-", TABLE_SET_COLOR, label ? NULL : ansi_grey(),
1855 TABLE_UUID, sd_id128_is_null(p->new_uuid) ? p->current_uuid : p->new_uuid,
1856 TABLE_STRING, p->definition_path ? basename(p->definition_path) : "-", TABLE_SET_COLOR, p->definition_path ? NULL : ansi_grey(),
a015fbe7 1857 TABLE_STRING, partname ?: "-", TABLE_SET_COLOR, partname ? NULL : ansi_highlight(),
e594a3b1 1858 TABLE_UINT64, p->offset,
a015fbe7 1859 TABLE_UINT64, p->current_size == UINT64_MAX ? 0 : p->current_size,
e594a3b1
LP
1860 TABLE_UINT64, p->new_size,
1861 TABLE_STRING, size_change, TABLE_SET_COLOR, !p->partitions_next && sum_size > 0 ? ansi_underline() : NULL,
a015fbe7 1862 TABLE_UINT64, p->current_padding == UINT64_MAX ? 0 : p->current_padding,
e594a3b1 1863 TABLE_UINT64, p->new_padding,
a015fbe7
TH
1864 TABLE_STRING, padding_change, TABLE_SET_COLOR, !p->partitions_next && sum_padding > 0 ? ansi_underline() : NULL,
1865 TABLE_STRING, activity ?: "unknown");
e594a3b1 1866 if (r < 0)
f987a261 1867 return table_log_add_error(r);
e594a3b1
LP
1868 }
1869
a015fbe7 1870 if (!arg_json && (sum_padding > 0 || sum_size > 0)) {
e594a3b1
LP
1871 char s[FORMAT_BYTES_MAX];
1872 const char *a, *b;
1873
1874 a = strjoina(special_glyph(SPECIAL_GLYPH_SIGMA), " = ", format_bytes(s, sizeof(s), sum_size));
1875 b = strjoina(special_glyph(SPECIAL_GLYPH_SIGMA), " = ", format_bytes(s, sizeof(s), sum_padding));
1876
1877 r = table_add_many(
1878 t,
1879 TABLE_EMPTY,
1880 TABLE_EMPTY,
1881 TABLE_EMPTY,
1882 TABLE_EMPTY,
1883 TABLE_EMPTY,
1884 TABLE_EMPTY,
1885 TABLE_EMPTY,
a015fbe7 1886 TABLE_EMPTY,
e594a3b1
LP
1887 TABLE_STRING, a,
1888 TABLE_EMPTY,
a015fbe7
TH
1889 TABLE_EMPTY,
1890 TABLE_STRING, b,
1891 TABLE_EMPTY);
e594a3b1 1892 if (r < 0)
f987a261 1893 return table_log_add_error(r);
e594a3b1
LP
1894 }
1895
a015fbe7
TH
1896 if (arg_json)
1897 r = table_print_json(t, stdout, arg_json_format_flags);
1898 else
1899 r = table_print(t, stdout);
e594a3b1
LP
1900 if (r < 0)
1901 return log_error_errno(r, "Failed to dump table: %m");
1902
1903 return 0;
1904}
1905
1906static void context_bar_char_process_partition(
1907 Context *context,
1908 Partition *bar[],
1909 size_t n,
1910 Partition *p,
1911 size_t *ret_start) {
1912
1913 uint64_t from, to, total;
1914 size_t x, y;
1915
1916 assert(context);
1917 assert(bar);
1918 assert(n > 0);
1919 assert(p);
1920
1921 if (p->dropped)
1922 return;
1923
1924 assert(p->offset != UINT64_MAX);
1925 assert(p->new_size != UINT64_MAX);
1926
1927 from = p->offset;
1928 to = from + p->new_size;
1929
1930 assert(context->end >= context->start);
1931 total = context->end - context->start;
1932
1933 assert(from >= context->start);
1934 assert(from <= context->end);
1935 x = (from - context->start) * n / total;
1936
1937 assert(to >= context->start);
1938 assert(to <= context->end);
1939 y = (to - context->start) * n / total;
1940
1941 assert(x <= y);
1942 assert(y <= n);
1943
1944 for (size_t i = x; i < y; i++)
1945 bar[i] = p;
1946
1947 *ret_start = x;
1948}
1949
1950static int partition_hint(const Partition *p, const char *node, char **ret) {
1951 _cleanup_free_ char *buf = NULL;
1952 char ids[ID128_UUID_STRING_MAX];
1953 const char *label;
1954 sd_id128_t id;
1955
1956 /* Tries really hard to find a suitable description for this partition */
1957
1958 if (p->definition_path) {
1959 buf = strdup(basename(p->definition_path));
1960 goto done;
1961 }
1962
1963 label = partition_label(p);
1964 if (!isempty(label)) {
1965 buf = strdup(label);
1966 goto done;
1967 }
1968
1969 if (p->partno != UINT64_MAX) {
1970 buf = fdisk_partname(node, p->partno+1);
1971 goto done;
1972 }
1973
1974 if (!sd_id128_is_null(p->new_uuid))
1975 id = p->new_uuid;
1976 else if (!sd_id128_is_null(p->current_uuid))
1977 id = p->current_uuid;
1978 else
1979 id = p->type_uuid;
1980
1981 buf = strdup(id128_to_uuid_string(id, ids));
1982
1983done:
1984 if (!buf)
1985 return -ENOMEM;
1986
1987 *ret = TAKE_PTR(buf);
1988 return 0;
1989}
1990
1991static int context_dump_partition_bar(Context *context, const char *node) {
1992 _cleanup_free_ Partition **bar = NULL;
1993 _cleanup_free_ size_t *start_array = NULL;
1994 Partition *p, *last = NULL;
1995 bool z = false;
1996 size_t c, j = 0;
1997
f391597c 1998 assert_se((c = columns()) >= 2);
e594a3b1
LP
1999 c -= 2; /* We do not use the leftmost and rightmost character cell */
2000
2001 bar = new0(Partition*, c);
2002 if (!bar)
2003 return log_oom();
2004
2005 start_array = new(size_t, context->n_partitions);
2006 if (!start_array)
2007 return log_oom();
2008
2009 LIST_FOREACH(partitions, p, context->partitions)
2010 context_bar_char_process_partition(context, bar, c, p, start_array + j++);
2011
2012 putc(' ', stdout);
2013
2014 for (size_t i = 0; i < c; i++) {
2015 if (bar[i]) {
2016 if (last != bar[i])
2017 z = !z;
2018
2019 fputs(z ? ansi_green() : ansi_yellow(), stdout);
2020 fputs(special_glyph(SPECIAL_GLYPH_DARK_SHADE), stdout);
2021 } else {
2022 fputs(ansi_normal(), stdout);
2023 fputs(special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), stdout);
2024 }
2025
2026 last = bar[i];
2027 }
2028
2029 fputs(ansi_normal(), stdout);
2030 putc('\n', stdout);
2031
2032 for (size_t i = 0; i < context->n_partitions; i++) {
2033 _cleanup_free_ char **line = NULL;
2034
2035 line = new0(char*, c);
2036 if (!line)
2037 return log_oom();
2038
2039 j = 0;
2040 LIST_FOREACH(partitions, p, context->partitions) {
2041 _cleanup_free_ char *d = NULL;
2042 j++;
2043
2044 if (i < context->n_partitions - j) {
2045
2046 if (line[start_array[j-1]]) {
2047 const char *e;
2048
2049 /* Upgrade final corner to the right with a branch to the right */
2050 e = startswith(line[start_array[j-1]], special_glyph(SPECIAL_GLYPH_TREE_RIGHT));
2051 if (e) {
2052 d = strjoin(special_glyph(SPECIAL_GLYPH_TREE_BRANCH), e);
2053 if (!d)
2054 return log_oom();
2055 }
2056 }
2057
2058 if (!d) {
2059 d = strdup(special_glyph(SPECIAL_GLYPH_TREE_VERTICAL));
2060 if (!d)
2061 return log_oom();
2062 }
2063
2064 } else if (i == context->n_partitions - j) {
2065 _cleanup_free_ char *hint = NULL;
2066
2067 (void) partition_hint(p, node, &hint);
2068
2069 if (streq_ptr(line[start_array[j-1]], special_glyph(SPECIAL_GLYPH_TREE_VERTICAL)))
2070 d = strjoin(special_glyph(SPECIAL_GLYPH_TREE_BRANCH), " ", strna(hint));
2071 else
2072 d = strjoin(special_glyph(SPECIAL_GLYPH_TREE_RIGHT), " ", strna(hint));
2073
2074 if (!d)
2075 return log_oom();
2076 }
2077
2078 if (d)
2079 free_and_replace(line[start_array[j-1]], d);
2080 }
2081
2082 putc(' ', stdout);
2083
2084 j = 0;
2085 while (j < c) {
2086 if (line[j]) {
2087 fputs(line[j], stdout);
2088 j += utf8_console_width(line[j]);
2089 } else {
2090 putc(' ', stdout);
2091 j++;
2092 }
2093 }
2094
2095 putc('\n', stdout);
2096
2097 for (j = 0; j < c; j++)
2098 free(line[j]);
2099 }
2100
2101 return 0;
2102}
2103
2104static bool context_changed(const Context *context) {
2105 Partition *p;
2106
2107 LIST_FOREACH(partitions, p, context->partitions) {
2108 if (p->dropped)
2109 continue;
2110
2111 if (p->allocated_to_area)
2112 return true;
2113
2114 if (p->new_size != p->current_size)
2115 return true;
2116 }
2117
2118 return false;
2119}
2120
81873a6b 2121static int context_wipe_range(Context *context, uint64_t offset, uint64_t size) {
e594a3b1
LP
2122 _cleanup_(blkid_free_probep) blkid_probe probe = NULL;
2123 int r;
2124
2125 assert(context);
81873a6b
LP
2126 assert(offset != UINT64_MAX);
2127 assert(size != UINT64_MAX);
e594a3b1
LP
2128
2129 probe = blkid_new_probe();
2130 if (!probe)
2131 return log_oom();
2132
e594a3b1 2133 errno = 0;
81873a6b 2134 r = blkid_probe_set_device(probe, fdisk_get_devfd(context->fdisk_context), offset, size);
e594a3b1 2135 if (r < 0)
81873a6b 2136 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to allocate device probe for wiping.");
e594a3b1
LP
2137
2138 errno = 0;
2139 if (blkid_probe_enable_superblocks(probe, true) < 0 ||
2140 blkid_probe_set_superblocks_flags(probe, BLKID_SUBLKS_MAGIC|BLKID_SUBLKS_BADCSUM) < 0 ||
2141 blkid_probe_enable_partitions(probe, true) < 0 ||
2142 blkid_probe_set_partitions_flags(probe, BLKID_PARTS_MAGIC) < 0)
81873a6b 2143 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to enable superblock and partition probing.");
e594a3b1
LP
2144
2145 for (;;) {
2146 errno = 0;
2147 r = blkid_do_probe(probe);
2148 if (r < 0)
2149 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe for file systems.");
2150 if (r > 0)
2151 break;
2152
2153 errno = 0;
2154 if (blkid_do_wipe(probe, false) < 0)
2155 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to wipe file system signature.");
2156 }
2157
e594a3b1
LP
2158 return 0;
2159}
2160
81873a6b
LP
2161static int context_wipe_partition(Context *context, Partition *p) {
2162 int r;
2163
2164 assert(context);
2165 assert(p);
2166 assert(!PARTITION_EXISTS(p)); /* Safety check: never wipe existing partitions */
2167
2168 assert(p->offset != UINT64_MAX);
2169 assert(p->new_size != UINT64_MAX);
2170
2171 r = context_wipe_range(context, p->offset, p->new_size);
2172 if (r < 0)
2173 return r;
2174
2175 log_info("Successfully wiped file system signatures from future partition %" PRIu64 ".", p->partno);
2176 return 0;
2177}
2178
2179static int context_discard_range(
2180 Context *context,
2181 uint64_t offset,
2182 uint64_t size) {
2183
e594a3b1
LP
2184 struct stat st;
2185 int fd;
2186
2187 assert(context);
2188 assert(offset != UINT64_MAX);
2189 assert(size != UINT64_MAX);
2190
2191 if (size <= 0)
2192 return 0;
2193
a26f4a49 2194 assert_se((fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
e594a3b1
LP
2195
2196 if (fstat(fd, &st) < 0)
2197 return -errno;
2198
2199 if (S_ISREG(st.st_mode)) {
2200 if (fallocate(fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, offset, size) < 0) {
2201 if (ERRNO_IS_NOT_SUPPORTED(errno))
2202 return -EOPNOTSUPP;
2203
2204 return -errno;
2205 }
2206
2207 return 1;
2208 }
2209
2210 if (S_ISBLK(st.st_mode)) {
2211 uint64_t range[2], end;
2212
2213 range[0] = round_up_size(offset, 512);
2214
2215 end = offset + size;
2216 if (end <= range[0])
2217 return 0;
2218
2219 range[1] = round_down_size(end - range[0], 512);
2220 if (range[1] <= 0)
2221 return 0;
2222
2223 if (ioctl(fd, BLKDISCARD, range) < 0) {
2224 if (ERRNO_IS_NOT_SUPPORTED(errno))
2225 return -EOPNOTSUPP;
2226
2227 return -errno;
2228 }
2229
2230 return 1;
2231 }
2232
2233 return -EOPNOTSUPP;
2234}
2235
2236static int context_discard_partition(Context *context, Partition *p) {
2237 int r;
2238
2239 assert(context);
2240 assert(p);
2241
2242 assert(p->offset != UINT64_MAX);
2243 assert(p->new_size != UINT64_MAX);
2244 assert(!PARTITION_EXISTS(p)); /* Safety check: never discard existing partitions */
2245
2246 if (!arg_discard)
2247 return 0;
2248
2249 r = context_discard_range(context, p->offset, p->new_size);
2250 if (r == -EOPNOTSUPP) {
5b5109e2 2251 log_info("Storage does not support discard, not discarding data in future partition %" PRIu64 ".", p->partno);
e594a3b1
LP
2252 return 0;
2253 }
2254 if (r == 0) {
2255 log_info("Partition %" PRIu64 " too short for discard, skipping.", p->partno);
2256 return 0;
2257 }
2258 if (r < 0)
5b5109e2 2259 return log_error_errno(r, "Failed to discard data for future partition %" PRIu64 ".", p->partno);
e594a3b1 2260
5b5109e2 2261 log_info("Successfully discarded data from future partition %" PRIu64 ".", p->partno);
e594a3b1
LP
2262 return 1;
2263}
2264
2265static int context_discard_gap_after(Context *context, Partition *p) {
2266 uint64_t gap, next = UINT64_MAX;
2267 Partition *q;
2268 int r;
2269
2270 assert(context);
2271 assert(!p || (p->offset != UINT64_MAX && p->new_size != UINT64_MAX));
2272
2273 if (p)
2274 gap = p->offset + p->new_size;
2275 else
2276 gap = context->start;
2277
2278 LIST_FOREACH(partitions, q, context->partitions) {
2279 if (q->dropped)
2280 continue;
2281
2282 assert(q->offset != UINT64_MAX);
2283 assert(q->new_size != UINT64_MAX);
2284
2285 if (q->offset < gap)
2286 continue;
2287
2288 if (next == UINT64_MAX || q->offset < next)
2289 next = q->offset;
2290 }
2291
2292 if (next == UINT64_MAX) {
2293 next = context->end;
2294 if (gap > next)
2295 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Partition end beyond disk end.");
2296 }
2297
2298 assert(next >= gap);
2299 r = context_discard_range(context, gap, next - gap);
2300 if (r == -EOPNOTSUPP) {
2301 if (p)
5b5109e2 2302 log_info("Storage does not support discard, not discarding gap after partition %" PRIu64 ".", p->partno);
e594a3b1 2303 else
5b5109e2 2304 log_info("Storage does not support discard, not discarding gap at beginning of disk.");
e594a3b1
LP
2305 return 0;
2306 }
2307 if (r == 0) /* Too short */
2308 return 0;
2309 if (r < 0) {
2310 if (p)
2311 return log_error_errno(r, "Failed to discard gap after partition %" PRIu64 ".", p->partno);
2312 else
2313 return log_error_errno(r, "Failed to discard gap at beginning of disk.");
2314 }
2315
2316 if (p)
2317 log_info("Successfully discarded gap after partition %" PRIu64 ".", p->partno);
2318 else
2319 log_info("Successfully discarded gap at beginning of disk.");
2320
2321 return 0;
2322}
2323
2324static int context_wipe_and_discard(Context *context, bool from_scratch) {
2325 Partition *p;
2326 int r;
2327
2328 assert(context);
2329
2330 /* Wipe and discard the contents of all partitions we are about to create. We skip the discarding if
2331 * we were supposed to start from scratch anyway, as in that case we just discard the whole block
2332 * device in one go early on. */
2333
2334 LIST_FOREACH(partitions, p, context->partitions) {
2335
2336 if (!p->allocated_to_area)
2337 continue;
2338
e594a3b1
LP
2339 r = context_wipe_partition(context, p);
2340 if (r < 0)
2341 return r;
2342
2343 if (!from_scratch) {
f0cb1b95
LP
2344 r = context_discard_partition(context, p);
2345 if (r < 0)
2346 return r;
2347
e594a3b1
LP
2348 r = context_discard_gap_after(context, p);
2349 if (r < 0)
2350 return r;
2351 }
2352 }
2353
2354 if (!from_scratch) {
2355 r = context_discard_gap_after(context, NULL);
2356 if (r < 0)
2357 return r;
2358 }
2359
2360 return 0;
2361}
2362
b9df3536
LP
2363static int partition_encrypt(
2364 Partition *p,
2365 const char *node,
2366 struct crypt_device **ret_cd,
2367 char **ret_volume,
2368 int *ret_fd) {
3dd8ae5c 2369#if HAVE_LIBCRYPTSETUP
0d12936d 2370 _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
b9df3536
LP
2371 _cleanup_(erase_and_freep) void *volume_key = NULL;
2372 _cleanup_free_ char *dm_name = NULL, *vol = NULL;
2373 char suuid[ID128_UUID_STRING_MAX];
2374 size_t volume_key_size = 256 / 8;
2375 sd_id128_t uuid;
2376 int r;
2377
2378 assert(p);
2379 assert(p->encrypt);
2380
0d12936d
LP
2381 r = dlopen_cryptsetup();
2382 if (r < 0)
2383 return log_error_errno(r, "libcryptsetup not found, cannot encrypt: %m");
2384
b9df3536
LP
2385 if (asprintf(&dm_name, "luks-repart-%08" PRIx64, random_u64()) < 0)
2386 return log_oom();
2387
2388 if (ret_volume) {
2389 vol = path_join("/dev/mapper/", dm_name);
2390 if (!vol)
2391 return log_oom();
2392 }
2393
2394 r = derive_uuid(p->new_uuid, "luks-uuid", &uuid);
2395 if (r < 0)
2396 return r;
2397
2398 log_info("Encrypting future partition %" PRIu64 "...", p->partno);
2399
2400 volume_key = malloc(volume_key_size);
2401 if (!volume_key)
2402 return log_oom();
2403
2404 r = genuine_random_bytes(volume_key, volume_key_size, RANDOM_BLOCK);
2405 if (r < 0)
2406 return log_error_errno(r, "Failed to generate volume key: %m");
2407
0d12936d 2408 r = sym_crypt_init(&cd, node);
b9df3536
LP
2409 if (r < 0)
2410 return log_error_errno(r, "Failed to allocate libcryptsetup context: %m");
2411
2412 cryptsetup_enable_logging(cd);
2413
0d12936d 2414 r = sym_crypt_format(cd,
b9df3536
LP
2415 CRYPT_LUKS2,
2416 "aes",
2417 "xts-plain64",
2418 id128_to_uuid_string(uuid, suuid),
2419 volume_key,
2420 volume_key_size,
2421 &(struct crypt_params_luks2) {
2422 .label = p->new_label,
2423 .sector_size = 512U,
2424 });
2425 if (r < 0)
2426 return log_error_errno(r, "Failed to LUKS2 format future partition: %m");
2427
0d12936d 2428 r = sym_crypt_keyslot_add_by_volume_key(
b9df3536
LP
2429 cd,
2430 CRYPT_ANY_SLOT,
2431 volume_key,
2432 volume_key_size,
2433 strempty(arg_key),
2434 arg_key_size);
2435 if (r < 0)
2436 return log_error_errno(r, "Failed to add LUKS2 key: %m");
2437
0d12936d 2438 r = sym_crypt_activate_by_volume_key(
b9df3536
LP
2439 cd,
2440 dm_name,
2441 volume_key,
2442 volume_key_size,
2443 arg_discard ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0);
2444 if (r < 0)
2445 return log_error_errno(r, "Failed to activate LUKS superblock: %m");
2446
2447 log_info("Successfully encrypted future partition %" PRIu64 ".", p->partno);
2448
2449 if (ret_fd) {
2450 _cleanup_close_ int dev_fd = -1;
2451
2452 dev_fd = open(vol, O_RDWR|O_CLOEXEC|O_NOCTTY);
2453 if (dev_fd < 0)
2454 return log_error_errno(errno, "Failed to open LUKS volume '%s': %m", vol);
2455
2456 *ret_fd = TAKE_FD(dev_fd);
2457 }
2458
2459 if (ret_cd)
2460 *ret_cd = TAKE_PTR(cd);
2461 if (ret_volume)
2462 *ret_volume = TAKE_PTR(vol);
2463
2464 return 0;
3dd8ae5c 2465#else
2466 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "libcryptsetup is not supported, cannot encrypt: %m");
2467#endif
b9df3536
LP
2468}
2469
2470static int deactivate_luks(struct crypt_device *cd, const char *node) {
3dd8ae5c 2471#if HAVE_LIBCRYPTSETUP
b9df3536
LP
2472 int r;
2473
2474 if (!cd)
2475 return 0;
2476
2477 assert(node);
2478
2479 /* udev or so might access out block device in the background while we are done. Let's hence force
2480 * detach the volume. We sync'ed before, hence this should be safe. */
2481
0d12936d 2482 r = sym_crypt_deactivate_by_name(cd, basename(node), CRYPT_DEACTIVATE_FORCE);
b9df3536
LP
2483 if (r < 0)
2484 return log_error_errno(r, "Failed to deactivate LUKS device: %m");
2485
2486 return 1;
3dd8ae5c 2487#else
2488 return 0;
2489#endif
b9df3536
LP
2490}
2491
757bc2e4
LP
2492static int context_copy_blocks(Context *context) {
2493 Partition *p;
b9df3536 2494 int whole_fd = -1, r;
757bc2e4
LP
2495
2496 assert(context);
2497
2498 /* Copy in file systems on the block level */
2499
2500 LIST_FOREACH(partitions, p, context->partitions) {
0d12936d 2501 _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
b9df3536
LP
2502 _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
2503 _cleanup_free_ char *encrypted = NULL;
2504 _cleanup_close_ int encrypted_dev_fd = -1;
757bc2e4 2505 char buf[FORMAT_BYTES_MAX];
b9df3536 2506 int target_fd;
757bc2e4
LP
2507
2508 if (p->copy_blocks_fd < 0)
2509 continue;
2510
2511 if (p->dropped)
2512 continue;
2513
2514 if (PARTITION_EXISTS(p)) /* Never copy over existing partitions */
2515 continue;
2516
2517 assert(p->new_size != UINT64_MAX);
2518 assert(p->copy_blocks_size != UINT64_MAX);
2519 assert(p->new_size >= p->copy_blocks_size);
2520
b9df3536
LP
2521 if (whole_fd < 0)
2522 assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
2523
2524 if (p->encrypt) {
2525 r = loop_device_make(whole_fd, O_RDWR, p->offset, p->new_size, 0, &d);
2526 if (r < 0)
2527 return log_error_errno(r, "Failed to make loopback device of future partition %" PRIu64 ": %m", p->partno);
2528
2529 r = loop_device_flock(d, LOCK_EX);
2530 if (r < 0)
2531 return log_error_errno(r, "Failed to lock loopback device: %m");
2532
2533 r = partition_encrypt(p, d->node, &cd, &encrypted, &encrypted_dev_fd);
2534 if (r < 0)
2535 return log_error_errno(r, "Failed to encrypt device: %m");
757bc2e4 2536
b9df3536
LP
2537 if (flock(encrypted_dev_fd, LOCK_EX) < 0)
2538 return log_error_errno(errno, "Failed to lock LUKS device: %m");
2539
2540 target_fd = encrypted_dev_fd;
2541 } else {
2542 if (lseek(whole_fd, p->offset, SEEK_SET) == (off_t) -1)
2543 return log_error_errno(errno, "Failed to seek to partition offset: %m");
2544
2545 target_fd = whole_fd;
2546 }
757bc2e4 2547
5b5109e2 2548 log_info("Copying in '%s' (%s) on block level into future partition %" PRIu64 ".", p->copy_blocks_path, format_bytes(buf, sizeof(buf), p->copy_blocks_size), p->partno);
757bc2e4 2549
b9df3536 2550 r = copy_bytes_full(p->copy_blocks_fd, target_fd, p->copy_blocks_size, 0, NULL, NULL, NULL, NULL);
757bc2e4
LP
2551 if (r < 0)
2552 return log_error_errno(r, "Failed to copy in data from '%s': %m", p->copy_blocks_path);
2553
b9df3536
LP
2554 if (fsync(target_fd) < 0)
2555 return log_error_errno(r, "Failed to synchronize copied data blocks: %m");
2556
2557 if (p->encrypt) {
2558 encrypted_dev_fd = safe_close(encrypted_dev_fd);
2559
2560 r = deactivate_luks(cd, encrypted);
2561 if (r < 0)
2562 return r;
2563
0d12936d 2564 sym_crypt_free(cd);
b9df3536
LP
2565 cd = NULL;
2566
2567 r = loop_device_sync(d);
2568 if (r < 0)
2569 return log_error_errno(r, "Failed to sync loopback device: %m");
2570 }
2571
757bc2e4
LP
2572 log_info("Copying in of '%s' on block level completed.", p->copy_blocks_path);
2573 }
2574
2575 return 0;
2576}
2577
8a794850
LP
2578static int do_copy_files(Partition *p, const char *fs) {
2579 char **source, **target;
2580 int r;
2581
2582 assert(p);
2583 assert(fs);
2584
2585 STRV_FOREACH_PAIR(source, target, p->copy_files) {
2586 _cleanup_close_ int sfd = -1, pfd = -1, tfd = -1;
2587 _cleanup_free_ char *dn = NULL;
2588
2589 dn = dirname_malloc(*target);
2590 if (!dn)
2591 return log_oom();
2592
2593 sfd = chase_symlinks_and_open(*source, arg_root, CHASE_PREFIX_ROOT|CHASE_WARN, O_CLOEXEC|O_NOCTTY, NULL);
2594 if (sfd < 0)
2595 return log_error_errno(sfd, "Failed to open source file '%s%s': %m", strempty(arg_root), *source);
2596
2597 r = fd_verify_regular(sfd);
2598 if (r < 0) {
2599 if (r != -EISDIR)
2600 return log_error_errno(r, "Failed to check type of source file '%s': %m", *source);
2601
2602 /* We are looking at a directory */
2603 tfd = chase_symlinks_and_open(*target, fs, CHASE_PREFIX_ROOT|CHASE_WARN, O_RDONLY|O_DIRECTORY|O_CLOEXEC, NULL);
2604 if (tfd < 0) {
2605 if (tfd != -ENOENT)
2606 return log_error_errno(tfd, "Failed to open target directory '%s': %m", *target);
2607
2608 r = mkdir_p_root(fs, dn, UID_INVALID, GID_INVALID, 0755);
2609 if (r < 0)
2610 return log_error_errno(r, "Failed to create parent directory '%s': %m", dn);
2611
2612 pfd = chase_symlinks_and_open(dn, fs, CHASE_PREFIX_ROOT|CHASE_WARN, O_RDONLY|O_DIRECTORY|O_CLOEXEC, NULL);
2613 if (pfd < 0)
2614 return log_error_errno(pfd, "Failed to open parent directory of target: %m");
2615
652d9040
LP
2616 r = copy_tree_at(
2617 sfd, ".",
2618 pfd, basename(*target),
2619 UID_INVALID, GID_INVALID,
2620 COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS);
8a794850 2621 } else
652d9040
LP
2622 r = copy_tree_at(
2623 sfd, ".",
2624 tfd, ".",
2625 UID_INVALID, GID_INVALID,
2626 COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS);
8a794850
LP
2627 if (r < 0)
2628 return log_error_errno(r, "Failed to copy %s%s to %s: %m", strempty(arg_root), *source, *target);
2629 } else {
2630 /* We are looking at a regular file */
2631
2632 r = mkdir_p_root(fs, dn, UID_INVALID, GID_INVALID, 0755);
2633 if (r < 0)
2634 return log_error_errno(r, "Failed to create parent directory: %m");
2635
2636 pfd = chase_symlinks_and_open(dn, fs, CHASE_PREFIX_ROOT|CHASE_WARN, O_RDONLY|O_DIRECTORY|O_CLOEXEC, NULL);
2637 if (pfd < 0)
2638 return log_error_errno(tfd, "Failed to open parent directory of target: %m");
2639
2640 tfd = openat(pfd, basename(*target), O_CREAT|O_EXCL|O_WRONLY|O_CLOEXEC, 0700);
2641 if (tfd < 0)
2642 return log_error_errno(errno, "Failed to create target file '%s': %m", *target);
2643
2644 r = copy_bytes(sfd, tfd, UINT64_MAX, COPY_REFLINK|COPY_SIGINT);
2645 if (r < 0)
2646 return log_error_errno(r, "Failed to copy '%s%s' to '%s': %m", strempty(arg_root), *source, *target);
2647
2648 (void) copy_xattr(sfd, tfd);
2649 (void) copy_access(sfd, tfd);
2650 (void) copy_times(sfd, tfd, 0);
2651 }
2652 }
2653
2654 return 0;
2655}
2656
2657static int partition_copy_files(Partition *p, const char *node) {
2658 int r;
2659
2660 assert(p);
2661 assert(node);
2662
2663 if (strv_isempty(p->copy_files))
2664 return 0;
2665
2666 log_info("Populating partition %" PRIu64 " with files.", p->partno);
2667
2668 /* We copy in a child process, since we have to mount the fs for that, and we don't want that fs to
2669 * appear in the host namespace. Hence we fork a child that has its own file system namespace and
2670 * detached mount propagation. */
2671
2672 r = safe_fork("(sd-copy)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE, NULL);
2673 if (r < 0)
2674 return r;
2675 if (r == 0) {
2676 static const char fs[] = "/run/systemd/mount-root";
2677 /* This is a child process with its own mount namespace and propagation to host turned off */
2678
2679 r = mkdir_p(fs, 0700);
2680 if (r < 0) {
2681 log_error_errno(r, "Failed to create mount point: %m");
2682 _exit(EXIT_FAILURE);
2683 }
2684
511a8cfe 2685 if (mount_nofollow_verbose(LOG_ERR, node, fs, p->format, MS_NOATIME|MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL) < 0)
8a794850
LP
2686 _exit(EXIT_FAILURE);
2687
2688 if (do_copy_files(p, fs) < 0)
2689 _exit(EXIT_FAILURE);
2690
2691 r = syncfs_path(AT_FDCWD, fs);
2692 if (r < 0) {
2693 log_error_errno(r, "Failed to synchronize written files: %m");
2694 _exit(EXIT_FAILURE);
2695 }
2696
2697 _exit(EXIT_SUCCESS);
2698 }
2699
2700 log_info("Successfully populated partition %" PRIu64 " with files.", p->partno);
2701 return 0;
2702}
2703
53171c04
LP
2704static int context_mkfs(Context *context) {
2705 Partition *p;
2706 int fd = -1, r;
2707
2708 assert(context);
2709
2710 /* Make a file system */
2711
2712 LIST_FOREACH(partitions, p, context->partitions) {
0d12936d 2713 _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
53171c04 2714 _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
b9df3536
LP
2715 _cleanup_free_ char *encrypted = NULL;
2716 _cleanup_close_ int encrypted_dev_fd = -1;
2717 const char *fsdev;
53171c04
LP
2718 sd_id128_t fs_uuid;
2719
2720 if (p->dropped)
2721 continue;
2722
2723 if (PARTITION_EXISTS(p)) /* Never format existing partitions */
2724 continue;
2725
2726 if (!p->format)
2727 continue;
2728
2729 assert(p->offset != UINT64_MAX);
2730 assert(p->new_size != UINT64_MAX);
2731
2732 if (fd < 0)
2733 assert_se((fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
2734
2735 /* Loopback block devices are not only useful to turn regular files into block devices, but
2736 * also to cut out sections of block devices into new block devices. */
2737
2738 r = loop_device_make(fd, O_RDWR, p->offset, p->new_size, 0, &d);
2739 if (r < 0)
5b5109e2 2740 return log_error_errno(r, "Failed to make loopback device of future partition %" PRIu64 ": %m", p->partno);
53171c04
LP
2741
2742 r = loop_device_flock(d, LOCK_EX);
2743 if (r < 0)
2744 return log_error_errno(r, "Failed to lock loopback device: %m");
2745
b9df3536
LP
2746 if (p->encrypt) {
2747 r = partition_encrypt(p, d->node, &cd, &encrypted, &encrypted_dev_fd);
2748 if (r < 0)
2749 return log_error_errno(r, "Failed to encrypt device: %m");
2750
2751 if (flock(encrypted_dev_fd, LOCK_EX) < 0)
2752 return log_error_errno(errno, "Failed to lock LUKS device: %m");
2753
2754 fsdev = encrypted;
2755 } else
2756 fsdev = d->node;
2757
53171c04
LP
2758 log_info("Formatting future partition %" PRIu64 ".", p->partno);
2759
2760 /* Calculate the UUID for the file system as HMAC-SHA256 of the string "file-system-uuid",
2761 * keyed off the partition UUID. */
2762 r = derive_uuid(p->new_uuid, "file-system-uuid", &fs_uuid);
2763 if (r < 0)
2764 return r;
2765
b9df3536
LP
2766 r = make_filesystem(fsdev, p->format, p->new_label, fs_uuid, arg_discard);
2767 if (r < 0) {
2768 encrypted_dev_fd = safe_close(encrypted_dev_fd);
2769 (void) deactivate_luks(cd, encrypted);
53171c04 2770 return r;
b9df3536 2771 }
53171c04
LP
2772
2773 log_info("Successfully formatted future partition %" PRIu64 ".", p->partno);
2774
b9df3536
LP
2775 /* The file system is now created, no need to delay udev further */
2776 if (p->encrypt)
2777 if (flock(encrypted_dev_fd, LOCK_UN) < 0)
2778 return log_error_errno(errno, "Failed to unlock LUKS device: %m");
2779
2780 r = partition_copy_files(p, fsdev);
2781 if (r < 0) {
2782 encrypted_dev_fd = safe_close(encrypted_dev_fd);
2783 (void) deactivate_luks(cd, encrypted);
8a794850 2784 return r;
b9df3536
LP
2785 }
2786
2787 /* Note that we always sync explicitly here, since mkfs.fat doesn't do that on its own, and
2788 * if we don't sync before detaching a block device the in-flight sectors possibly won't hit
2789 * the disk. */
2790
2791 if (p->encrypt) {
2792 if (fsync(encrypted_dev_fd) < 0)
2793 return log_error_errno(r, "Failed to synchronize LUKS volume: %m");
2794 encrypted_dev_fd = safe_close(encrypted_dev_fd);
2795
2796 r = deactivate_luks(cd, encrypted);
2797 if (r < 0)
2798 return r;
2799
0d12936d 2800 sym_crypt_free(cd);
b9df3536
LP
2801 cd = NULL;
2802 }
8a794850 2803
53171c04
LP
2804 r = loop_device_sync(d);
2805 if (r < 0)
2806 return log_error_errno(r, "Failed to sync loopback device: %m");
2807 }
2808
2809 return 0;
2810}
2811
e594a3b1
LP
2812static int partition_acquire_uuid(Context *context, Partition *p, sd_id128_t *ret) {
2813 struct {
2814 sd_id128_t type_uuid;
2815 uint64_t counter;
2816 } _packed_ plaintext = {};
2817 union {
2818 unsigned char md[SHA256_DIGEST_LENGTH];
2819 sd_id128_t id;
2820 } result;
2821
2822 uint64_t k = 0;
2823 Partition *q;
2824 int r;
2825
2826 assert(context);
2827 assert(p);
2828 assert(ret);
2829
2830 /* Calculate a good UUID for the indicated partition. We want a certain degree of reproducibility,
2831 * hence we won't generate the UUIDs randomly. Instead we use a cryptographic hash (precisely:
2832 * HMAC-SHA256) to derive them from a single seed. The seed is generally the machine ID of the
2833 * installation we are processing, but if random behaviour is desired can be random, too. We use the
2834 * seed value as key for the HMAC (since the machine ID is something we generally don't want to leak)
2835 * and the partition type as plaintext. The partition type is suffixed with a counter (only for the
2836 * second and later partition of the same type) if we have more than one partition of the same
2837 * time. Or in other words:
2838 *
2839 * With:
2840 * SEED := /etc/machine-id
2841 *
2842 * If first partition instance of type TYPE_UUID:
2843 * PARTITION_UUID := HMAC-SHA256(SEED, TYPE_UUID)
2844 *
2845 * For all later partition instances of type TYPE_UUID with INSTANCE being the LE64 encoded instance number:
2846 * PARTITION_UUID := HMAC-SHA256(SEED, TYPE_UUID || INSTANCE)
2847 */
2848
2849 LIST_FOREACH(partitions, q, context->partitions) {
2850 if (p == q)
2851 break;
2852
2853 if (!sd_id128_equal(p->type_uuid, q->type_uuid))
2854 continue;
2855
2856 k++;
2857 }
2858
2859 plaintext.type_uuid = p->type_uuid;
2860 plaintext.counter = htole64(k);
2861
2862 if (!HMAC(EVP_sha256(),
2863 &context->seed, sizeof(context->seed),
2864 (const unsigned char*) &plaintext, k == 0 ? sizeof(sd_id128_t) : sizeof(plaintext),
2865 result.md, NULL))
2866 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "SHA256 calculation failed.");
2867
2868 /* Take the first half, mark it as v4 UUID */
2869 assert_cc(sizeof(result.md) == sizeof(result.id) * 2);
2870 result.id = id128_make_v4_uuid(result.id);
2871
2872 /* Ensure this partition UUID is actually unique, and there's no remaining partition from an earlier run? */
2873 LIST_FOREACH(partitions, q, context->partitions) {
2874 if (p == q)
2875 continue;
2876
2877 if (sd_id128_equal(q->current_uuid, result.id) ||
2878 sd_id128_equal(q->new_uuid, result.id)) {
2879 log_warning("Partition UUID calculated from seed for partition %" PRIu64 " exists already, reverting to randomized UUID.", p->partno);
2880
2881 r = sd_id128_randomize(&result.id);
2882 if (r < 0)
2883 return log_error_errno(r, "Failed to generate randomized UUID: %m");
2884
2885 break;
2886 }
2887 }
2888
2889 *ret = result.id;
2890 return 0;
2891}
2892
2893static int partition_acquire_label(Context *context, Partition *p, char **ret) {
2894 _cleanup_free_ char *label = NULL;
2895 const char *prefix;
2896 unsigned k = 1;
2897
2898 assert(context);
2899 assert(p);
2900 assert(ret);
2901
2902 prefix = gpt_partition_type_uuid_to_string(p->type_uuid);
2903 if (!prefix)
2904 prefix = "linux";
2905
2906 for (;;) {
2907 const char *ll = label ?: prefix;
2908 bool retry = false;
2909 Partition *q;
2910
2911 LIST_FOREACH(partitions, q, context->partitions) {
2912 if (p == q)
2913 break;
2914
2915 if (streq_ptr(ll, q->current_label) ||
2916 streq_ptr(ll, q->new_label)) {
2917 retry = true;
2918 break;
2919 }
2920 }
2921
2922 if (!retry)
2923 break;
2924
2925 label = mfree(label);
2926
2927
2928 if (asprintf(&label, "%s-%u", prefix, ++k) < 0)
2929 return log_oom();
2930 }
2931
2932 if (!label) {
2933 label = strdup(prefix);
2934 if (!label)
2935 return log_oom();
2936 }
2937
2938 *ret = TAKE_PTR(label);
2939 return 0;
2940}
2941
2942static int context_acquire_partition_uuids_and_labels(Context *context) {
2943 Partition *p;
2944 int r;
2945
2946 assert(context);
2947
2948 LIST_FOREACH(partitions, p, context->partitions) {
e594a3b1
LP
2949 /* Never touch foreign partitions */
2950 if (PARTITION_IS_FOREIGN(p)) {
2951 p->new_uuid = p->current_uuid;
2952
2953 if (p->current_label) {
12963533 2954 free(p->new_label);
e594a3b1
LP
2955 p->new_label = strdup(p->current_label);
2956 if (!p->new_label)
2957 return log_oom();
2958 }
2959
2960 continue;
2961 }
2962
2963 if (!sd_id128_is_null(p->current_uuid))
2964 p->new_uuid = p->current_uuid; /* Never change initialized UUIDs */
12963533
TH
2965 else if (sd_id128_is_null(p->new_uuid)) {
2966 /* Not explicitly set by user! */
e594a3b1
LP
2967 r = partition_acquire_uuid(context, p, &p->new_uuid);
2968 if (r < 0)
2969 return r;
2970 }
2971
2972 if (!isempty(p->current_label)) {
12963533 2973 free(p->new_label);
e594a3b1
LP
2974 p->new_label = strdup(p->current_label); /* never change initialized labels */
2975 if (!p->new_label)
2976 return log_oom();
12963533
TH
2977 } else if (!p->new_label) {
2978 /* Not explicitly set by user! */
2979
e594a3b1
LP
2980 r = partition_acquire_label(context, p, &p->new_label);
2981 if (r < 0)
2982 return r;
2983 }
2984 }
2985
2986 return 0;
2987}
2988
f28d4f42 2989static int context_mangle_partitions(Context *context) {
e594a3b1 2990 Partition *p;
f28d4f42 2991 int r;
e594a3b1
LP
2992
2993 assert(context);
2994
e594a3b1
LP
2995 LIST_FOREACH(partitions, p, context->partitions) {
2996 if (p->dropped)
2997 continue;
2998
2999 assert(p->new_size != UINT64_MAX);
3000 assert(p->offset != UINT64_MAX);
3001 assert(p->partno != UINT64_MAX);
3002
3003 if (PARTITION_EXISTS(p)) {
3004 bool changed = false;
3005
3006 assert(p->current_partition);
3007
3008 if (p->new_size != p->current_size) {
3009 assert(p->new_size >= p->current_size);
3010 assert(p->new_size % 512 == 0);
3011
3012 r = fdisk_partition_size_explicit(p->current_partition, true);
3013 if (r < 0)
3014 return log_error_errno(r, "Failed to enable explicit sizing: %m");
3015
3016 r = fdisk_partition_set_size(p->current_partition, p->new_size / 512);
3017 if (r < 0)
3018 return log_error_errno(r, "Failed to grow partition: %m");
3019
3020 log_info("Growing existing partition %" PRIu64 ".", p->partno);
3021 changed = true;
3022 }
3023
3024 if (!sd_id128_equal(p->new_uuid, p->current_uuid)) {
3025 char buf[ID128_UUID_STRING_MAX];
3026
3027 assert(!sd_id128_is_null(p->new_uuid));
3028
3029 r = fdisk_partition_set_uuid(p->current_partition, id128_to_uuid_string(p->new_uuid, buf));
3030 if (r < 0)
3031 return log_error_errno(r, "Failed to set partition UUID: %m");
3032
3033 log_info("Initializing UUID of existing partition %" PRIu64 ".", p->partno);
3034 changed = true;
3035 }
3036
3037 if (!streq_ptr(p->new_label, p->current_label)) {
3038 assert(!isempty(p->new_label));
3039
3040 r = fdisk_partition_set_name(p->current_partition, p->new_label);
3041 if (r < 0)
3042 return log_error_errno(r, "Failed to set partition label: %m");
3043
3044 log_info("Setting partition label of existing partition %" PRIu64 ".", p->partno);
3045 changed = true;
3046 }
3047
3048 if (changed) {
3049 assert(!PARTITION_IS_FOREIGN(p)); /* never touch foreign partitions */
3050
3051 r = fdisk_set_partition(context->fdisk_context, p->partno, p->current_partition);
3052 if (r < 0)
3053 return log_error_errno(r, "Failed to update partition: %m");
3054 }
3055 } else {
3056 _cleanup_(fdisk_unref_partitionp) struct fdisk_partition *q = NULL;
3057 _cleanup_(fdisk_unref_parttypep) struct fdisk_parttype *t = NULL;
3058 char ids[ID128_UUID_STRING_MAX];
3059
3060 assert(!p->new_partition);
3061 assert(p->offset % 512 == 0);
3062 assert(p->new_size % 512 == 0);
3063 assert(!sd_id128_is_null(p->new_uuid));
3064 assert(!isempty(p->new_label));
3065
3066 t = fdisk_new_parttype();
3067 if (!t)
3068 return log_oom();
3069
3070 r = fdisk_parttype_set_typestr(t, id128_to_uuid_string(p->type_uuid, ids));
3071 if (r < 0)
3072 return log_error_errno(r, "Failed to initialize partition type: %m");
3073
3074 q = fdisk_new_partition();
3075 if (!q)
3076 return log_oom();
3077
3078 r = fdisk_partition_set_type(q, t);
3079 if (r < 0)
3080 return log_error_errno(r, "Failed to set partition type: %m");
3081
3082 r = fdisk_partition_size_explicit(q, true);
3083 if (r < 0)
3084 return log_error_errno(r, "Failed to enable explicit sizing: %m");
3085
3086 r = fdisk_partition_set_start(q, p->offset / 512);
3087 if (r < 0)
3088 return log_error_errno(r, "Failed to position partition: %m");
3089
3090 r = fdisk_partition_set_size(q, p->new_size / 512);
3091 if (r < 0)
3092 return log_error_errno(r, "Failed to grow partition: %m");
3093
3094 r = fdisk_partition_set_partno(q, p->partno);
3095 if (r < 0)
3096 return log_error_errno(r, "Failed to set partition number: %m");
3097
3098 r = fdisk_partition_set_uuid(q, id128_to_uuid_string(p->new_uuid, ids));
3099 if (r < 0)
3100 return log_error_errno(r, "Failed to set partition UUID: %m");
3101
3102 r = fdisk_partition_set_name(q, p->new_label);
3103 if (r < 0)
3104 return log_error_errno(r, "Failed to set partition label: %m");
3105
5b5109e2 3106 log_info("Adding new partition %" PRIu64 " to partition table.", p->partno);
e594a3b1
LP
3107
3108 r = fdisk_add_partition(context->fdisk_context, q, NULL);
3109 if (r < 0)
3110 return log_error_errno(r, "Failed to add partition: %m");
3111
3112 assert(!p->new_partition);
3113 p->new_partition = TAKE_PTR(q);
3114 }
3115 }
3116
f28d4f42
LP
3117 return 0;
3118}
3119
3120static int context_write_partition_table(
3121 Context *context,
3122 const char *node,
3123 bool from_scratch) {
3124
3125 _cleanup_(fdisk_unref_tablep) struct fdisk_table *original_table = NULL;
3126 int capable, r;
3127
3128 assert(context);
3129
3130 if (arg_pretty > 0 ||
3131 (arg_pretty < 0 && isatty(STDOUT_FILENO) > 0) ||
3132 arg_json) {
3133
3134 (void) context_dump_partitions(context, node);
3135
3136 putc('\n', stdout);
3137
3138 if (!arg_json)
3139 (void) context_dump_partition_bar(context, node);
3140 putc('\n', stdout);
3141 fflush(stdout);
3142 }
3143
3144 if (!from_scratch && !context_changed(context)) {
3145 log_info("No changes.");
3146 return 0;
3147 }
3148
3149 if (arg_dry_run) {
3150 log_notice("Refusing to repartition, please re-run with --dry-run=no.");
3151 return 0;
3152 }
3153
3154 log_info("Applying changes.");
3155
3156 if (from_scratch) {
81873a6b
LP
3157 r = context_wipe_range(context, 0, context->total);
3158 if (r < 0)
3159 return r;
3160
3161 log_info("Wiped block device.");
3162
f28d4f42
LP
3163 r = context_discard_range(context, 0, context->total);
3164 if (r == -EOPNOTSUPP)
5b5109e2 3165 log_info("Storage does not support discard, not discarding entire block device data.");
f28d4f42
LP
3166 else if (r < 0)
3167 return log_error_errno(r, "Failed to discard entire block device: %m");
3168 else if (r > 0)
3169 log_info("Discarded entire block device.");
3170 }
3171
3172 r = fdisk_get_partitions(context->fdisk_context, &original_table);
3173 if (r < 0)
3174 return log_error_errno(r, "Failed to acquire partition table: %m");
3175
3176 /* Wipe fs signatures and discard sectors where the new partitions are going to be placed and in the
3177 * gaps between partitions, just to be sure. */
3178 r = context_wipe_and_discard(context, from_scratch);
3179 if (r < 0)
3180 return r;
3181
3182 r = context_copy_blocks(context);
3183 if (r < 0)
3184 return r;
3185
3186 r = context_mkfs(context);
3187 if (r < 0)
3188 return r;
3189
3190 r = context_mangle_partitions(context);
3191 if (r < 0)
3192 return r;
3193
e594a3b1
LP
3194 log_info("Writing new partition table.");
3195
3196 r = fdisk_write_disklabel(context->fdisk_context);
3197 if (r < 0)
3198 return log_error_errno(r, "Failed to write partition table: %m");
3199
911ba624 3200 capable = blockdev_partscan_enabled(fdisk_get_devfd(context->fdisk_context));
9a1deb85
LP
3201 if (capable == -ENOTBLK)
3202 log_debug("Not telling kernel to reread partition table, since we are not operating on a block device.");
3203 else if (capable < 0)
911ba624 3204 return log_error_errno(capable, "Failed to check if block device supports partition scanning: %m");
9a1deb85 3205 else if (capable > 0) {
e594a3b1
LP
3206 log_info("Telling kernel to reread partition table.");
3207
3208 if (from_scratch)
3209 r = fdisk_reread_partition_table(context->fdisk_context);
3210 else
3211 r = fdisk_reread_changes(context->fdisk_context, original_table);
3212 if (r < 0)
3213 return log_error_errno(r, "Failed to reread partition table: %m");
3214 } else
3215 log_notice("Not telling kernel to reread partition table, because selected image does not support kernel partition block devices.");
3216
3217 log_info("All done.");
3218
3219 return 0;
3220}
3221
3222static int context_read_seed(Context *context, const char *root) {
3223 int r;
3224
3225 assert(context);
3226
3227 if (!sd_id128_is_null(context->seed))
3228 return 0;
3229
3230 if (!arg_randomize) {
3231 _cleanup_close_ int fd = -1;
3232
3233 fd = chase_symlinks_and_open("/etc/machine-id", root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC, NULL);
3234 if (fd == -ENOENT)
3235 log_info("No machine ID set, using randomized partition UUIDs.");
3236 else if (fd < 0)
3237 return log_error_errno(fd, "Failed to determine machine ID of image: %m");
3238 else {
448b782c 3239 r = id128_read_fd(fd, ID128_PLAIN_OR_UNINIT, &context->seed);
e594a3b1
LP
3240 if (r == -ENOMEDIUM)
3241 log_info("No machine ID set, using randomized partition UUIDs.");
3242 else if (r < 0)
3243 return log_error_errno(r, "Failed to parse machine ID of image: %m");
3244
3245 return 0;
3246 }
3247 }
3248
3249 r = sd_id128_randomize(&context->seed);
3250 if (r < 0)
3251 return log_error_errno(r, "Failed to generate randomized seed: %m");
3252
3253 return 0;
3254}
3255
3256static int context_factory_reset(Context *context, bool from_scratch) {
3257 Partition *p;
3258 size_t n = 0;
3259 int r;
3260
3261 assert(context);
3262
3263 if (arg_factory_reset <= 0)
3264 return 0;
3265
3266 if (from_scratch) /* Nothing to reset if we start from scratch */
3267 return 0;
3268
3269 if (arg_dry_run) {
3270 log_notice("Refusing to factory reset, please re-run with --dry-run=no.");
3271 return 0;
3272 }
3273
3274 log_info("Applying factory reset.");
3275
3276 LIST_FOREACH(partitions, p, context->partitions) {
3277
3278 if (!p->factory_reset || !PARTITION_EXISTS(p))
3279 continue;
3280
3281 assert(p->partno != UINT64_MAX);
3282
3283 log_info("Removing partition %" PRIu64 " for factory reset.", p->partno);
3284
3285 r = fdisk_delete_partition(context->fdisk_context, p->partno);
3286 if (r < 0)
3287 return log_error_errno(r, "Failed to remove partition %" PRIu64 ": %m", p->partno);
3288
3289 n++;
3290 }
3291
3292 if (n == 0) {
3293 log_info("Factory reset requested, but no partitions to delete found.");
3294 return 0;
3295 }
3296
3297 r = fdisk_write_disklabel(context->fdisk_context);
3298 if (r < 0)
3299 return log_error_errno(r, "Failed to write disk label: %m");
3300
3301 log_info("Successfully deleted %zu partitions.", n);
3302 return 1;
3303}
3304
3305static int context_can_factory_reset(Context *context) {
3306 Partition *p;
3307
3308 assert(context);
3309
3310 LIST_FOREACH(partitions, p, context->partitions)
3311 if (p->factory_reset && PARTITION_EXISTS(p))
3312 return true;
3313
3314 return false;
3315}
3316
757bc2e4
LP
3317static int context_open_copy_block_paths(Context *context) {
3318 Partition *p;
3319 int r;
3320
3321 assert(context);
3322
3323 LIST_FOREACH(partitions, p, context->partitions) {
3324 _cleanup_close_ int source_fd = -1;
3325 uint64_t size;
3326 struct stat st;
3327
3328 assert(p->copy_blocks_fd < 0);
3329 assert(p->copy_blocks_size == UINT64_MAX);
3330
3331 if (PARTITION_EXISTS(p)) /* Never copy over partitions that already exist! */
3332 continue;
3333
3334 if (!p->copy_blocks_path)
3335 continue;
3336
3337 source_fd = open(p->copy_blocks_path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
3338 if (source_fd < 0)
3339 return log_error_errno(errno, "Failed to open block copy file '%s': %m", p->copy_blocks_path);
3340
3341 if (fstat(source_fd, &st) < 0)
3342 return log_error_errno(errno, "Failed to stat block copy file '%s': %m", p->copy_blocks_path);
3343
3344 if (S_ISDIR(st.st_mode)) {
3345 _cleanup_free_ char *bdev = NULL;
3346
3347 /* If the file is a directory, automatically find the backing block device */
3348
3349 if (major(st.st_dev) != 0)
3350 r = device_path_make_major_minor(S_IFBLK, st.st_dev, &bdev);
3351 else {
3352 dev_t devt;
3353
3354 /* Special support for btrfs */
3355
3356 r = btrfs_get_block_device_fd(source_fd, &devt);
67f0ac8c
LP
3357 if (r == -EUCLEAN)
3358 return btrfs_log_dev_root(LOG_ERR, r, p->copy_blocks_path);
757bc2e4
LP
3359 if (r < 0)
3360 return log_error_errno(r, "Unable to determine backing block device of '%s': %m", p->copy_blocks_path);
3361
3362 r = device_path_make_major_minor(S_IFBLK, devt, &bdev);
3363 }
3364 if (r < 0)
3365 return log_error_errno(r, "Failed to determine block device path for block device backing '%s': %m", p->copy_blocks_path);
3366
3367 safe_close(source_fd);
3368
3369 source_fd = open(bdev, O_RDONLY|O_CLOEXEC|O_NOCTTY);
3370 if (source_fd < 0)
3371 return log_error_errno(errno, "Failed to open block device '%s': %m", bdev);
3372
3373 if (fstat(source_fd, &st) < 0)
3374 return log_error_errno(errno, "Failed to stat block device '%s': %m", bdev);
3375
3376 if (!S_ISBLK(st.st_mode))
3377 return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Block device '%s' is not actually a block device, refusing.", bdev);
3378 }
3379
3380 if (S_ISREG(st.st_mode))
3381 size = st.st_size;
3382 else if (S_ISBLK(st.st_mode)) {
3383 if (ioctl(source_fd, BLKGETSIZE64, &size) != 0)
3384 return log_error_errno(errno, "Failed to determine size of block device to copy from: %m");
3385 } else
3386 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", p->copy_blocks_path);
3387
3388 if (size <= 0)
3389 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File to copy bytes from '%s' has zero size, refusing.", p->copy_blocks_path);
3390 if (size % 512 != 0)
3391 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File to copy bytes from '%s' has size that is not multiple of 512, refusing.", p->copy_blocks_path);
3392
3393 p->copy_blocks_fd = TAKE_FD(source_fd);
3394 p->copy_blocks_size = size;
3395 }
3396
3397 return 0;
3398}
3399
e594a3b1
LP
3400static int help(void) {
3401 _cleanup_free_ char *link = NULL;
3402 int r;
3403
3404 r = terminal_urlify_man("systemd-repart", "1", &link);
3405 if (r < 0)
3406 return log_oom();
3407
3408 printf("%s [OPTIONS...] [DEVICE]\n"
3409 "\n%sGrow and add partitions to partition table.%s\n\n"
3410 " -h --help Show this help\n"
3411 " --version Show package version\n"
3412 " --dry-run=BOOL Whether to run dry-run operation\n"
a26f4a49
LP
3413 " --empty=MODE One of refuse, allow, require, force, create; controls\n"
3414 " how to handle empty disks lacking partition tables\n"
e594a3b1 3415 " --discard=BOOL Whether to discard backing blocks for new partitions\n"
2d2d0a57 3416 " --pretty=BOOL Whether to show pretty summary before doing changes\n"
e594a3b1
LP
3417 " --factory-reset=BOOL Whether to remove data partitions before recreating\n"
3418 " them\n"
3419 " --can-factory-reset Test whether factory reset is defined\n"
3420 " --root=PATH Operate relative to root path\n"
3421 " --definitions=DIR Find partitions in specified directory\n"
b9df3536 3422 " --key-file=PATH Key to use when encrypting partitions\n"
e594a3b1 3423 " --seed=UUID 128bit seed UUID to derive all UUIDs from\n"
a26f4a49 3424 " --size=BYTES Grow loopback file to specified size\n"
2d2d0a57 3425 " --json=pretty|short|off\n"
de8231b0 3426 " Generate JSON output\n"
e594a3b1
LP
3427 "\nSee the %s for details.\n"
3428 , program_invocation_short_name
3429 , ansi_highlight(), ansi_normal()
3430 , link
3431 );
3432
3433 return 0;
3434}
3435
3436static int parse_argv(int argc, char *argv[]) {
3437
3438 enum {
3439 ARG_VERSION = 0x100,
3440 ARG_DRY_RUN,
3441 ARG_EMPTY,
3442 ARG_DISCARD,
3443 ARG_FACTORY_RESET,
3444 ARG_CAN_FACTORY_RESET,
3445 ARG_ROOT,
3446 ARG_SEED,
3447 ARG_PRETTY,
3448 ARG_DEFINITIONS,
a26f4a49 3449 ARG_SIZE,
a015fbe7 3450 ARG_JSON,
b9df3536 3451 ARG_KEY_FILE,
e594a3b1
LP
3452 };
3453
3454 static const struct option options[] = {
3455 { "help", no_argument, NULL, 'h' },
3456 { "version", no_argument, NULL, ARG_VERSION },
3457 { "dry-run", required_argument, NULL, ARG_DRY_RUN },
3458 { "empty", required_argument, NULL, ARG_EMPTY },
3459 { "discard", required_argument, NULL, ARG_DISCARD },
3460 { "factory-reset", required_argument, NULL, ARG_FACTORY_RESET },
3461 { "can-factory-reset", no_argument, NULL, ARG_CAN_FACTORY_RESET },
3462 { "root", required_argument, NULL, ARG_ROOT },
3463 { "seed", required_argument, NULL, ARG_SEED },
3464 { "pretty", required_argument, NULL, ARG_PRETTY },
3465 { "definitions", required_argument, NULL, ARG_DEFINITIONS },
a26f4a49 3466 { "size", required_argument, NULL, ARG_SIZE },
a015fbe7 3467 { "json", required_argument, NULL, ARG_JSON },
b9df3536 3468 { "key-file", required_argument, NULL, ARG_KEY_FILE },
e594a3b1
LP
3469 {}
3470 };
3471
a26f4a49 3472 int c, r, dry_run = -1;
e594a3b1
LP
3473
3474 assert(argc >= 0);
3475 assert(argv);
3476
3477 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
3478
3479 switch (c) {
3480
3481 case 'h':
3482 return help();
3483
3484 case ARG_VERSION:
3485 return version();
3486
3487 case ARG_DRY_RUN:
3488 r = parse_boolean(optarg);
3489 if (r < 0)
3490 return log_error_errno(r, "Failed to parse --dry-run= parameter: %s", optarg);
3491
a26f4a49 3492 dry_run = r;
e594a3b1
LP
3493 break;
3494
3495 case ARG_EMPTY:
3496 if (isempty(optarg) || streq(optarg, "refuse"))
3497 arg_empty = EMPTY_REFUSE;
3498 else if (streq(optarg, "allow"))
3499 arg_empty = EMPTY_ALLOW;
3500 else if (streq(optarg, "require"))
3501 arg_empty = EMPTY_REQUIRE;
3502 else if (streq(optarg, "force"))
3503 arg_empty = EMPTY_FORCE;
a26f4a49
LP
3504 else if (streq(optarg, "create")) {
3505 arg_empty = EMPTY_CREATE;
3506
3507 if (dry_run < 0)
3508 dry_run = false; /* Imply --dry-run=no if we create the loopback file
3509 * anew. After all we cannot really break anyone's
3510 * partition tables that way. */
3511 } else
e594a3b1
LP
3512 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3513 "Failed to parse --empty= parameter: %s", optarg);
3514 break;
3515
3516 case ARG_DISCARD:
3517 r = parse_boolean(optarg);
3518 if (r < 0)
3519 return log_error_errno(r, "Failed to parse --discard= parameter: %s", optarg);
3520
3521 arg_discard = r;
3522 break;
3523
3524 case ARG_FACTORY_RESET:
3525 r = parse_boolean(optarg);
3526 if (r < 0)
3527 return log_error_errno(r, "Failed to parse --factory-reset= parameter: %s", optarg);
3528
3529 arg_factory_reset = r;
3530 break;
3531
3532 case ARG_CAN_FACTORY_RESET:
3533 arg_can_factory_reset = true;
3534 break;
3535
3536 case ARG_ROOT:
3537 r = parse_path_argument_and_warn(optarg, false, &arg_root);
3538 if (r < 0)
3539 return r;
3540 break;
3541
3542 case ARG_SEED:
3543 if (isempty(optarg)) {
3544 arg_seed = SD_ID128_NULL;
3545 arg_randomize = false;
3546 } else if (streq(optarg, "random"))
3547 arg_randomize = true;
3548 else {
3549 r = sd_id128_from_string(optarg, &arg_seed);
3550 if (r < 0)
3551 return log_error_errno(r, "Failed to parse seed: %s", optarg);
3552
3553 arg_randomize = false;
3554 }
3555
3556 break;
3557
3558 case ARG_PRETTY:
3559 r = parse_boolean(optarg);
3560 if (r < 0)
3561 return log_error_errno(r, "Failed to parse --pretty= parameter: %s", optarg);
3562
3563 arg_pretty = r;
3564 break;
3565
3566 case ARG_DEFINITIONS:
3567 r = parse_path_argument_and_warn(optarg, false, &arg_definitions);
3568 if (r < 0)
3569 return r;
3570 break;
3571
a26f4a49
LP
3572 case ARG_SIZE: {
3573 uint64_t parsed, rounded;
3574
170c9823
LP
3575 if (streq(optarg, "auto")) {
3576 arg_size = UINT64_MAX;
3577 arg_size_auto = true;
3578 break;
3579 }
3580
a26f4a49
LP
3581 r = parse_size(optarg, 1024, &parsed);
3582 if (r < 0)
3583 return log_error_errno(r, "Failed to parse --size= parameter: %s", optarg);
3584
3585 rounded = round_up_size(parsed, 4096);
3586 if (rounded == 0)
3587 return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Specified image size too small, refusing.");
3588 if (rounded == UINT64_MAX)
3589 return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Specified image size too large, refusing.");
3590
3591 if (rounded != parsed)
3592 log_warning("Specified size is not a multiple of 4096, rounding up automatically. (%" PRIu64 " → %" PRIu64 ")",
3593 parsed, rounded);
3594
3595 arg_size = rounded;
170c9823 3596 arg_size_auto = false;
a26f4a49
LP
3597 break;
3598 }
b9df3536 3599
a015fbe7
TH
3600 case ARG_JSON:
3601 if (streq(optarg, "pretty")) {
3602 arg_json = true;
3603 arg_json_format_flags = JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR_AUTO;
3604 } else if (streq(optarg, "short")) {
3605 arg_json = true;
3606 arg_json_format_flags = JSON_FORMAT_NEWLINE;
3607 } else if (streq(optarg, "off")) {
3608 arg_json = false;
3609 arg_json_format_flags = 0;
3610 } else if (streq(optarg, "help")) {
3611 puts("pretty\n"
3612 "short\n"
3613 "off");
3614 return 0;
3615 } else
3616 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown argument to --json=: %s", optarg);
3617
3618 break;
3619
b9df3536
LP
3620 case ARG_KEY_FILE: {
3621 _cleanup_(erase_and_freep) char *k = NULL;
3622 size_t n = 0;
3623
8b3c3a49 3624 r = read_full_file_full(
986311c2 3625 AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
8b3c3a49
LP
3626 READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
3627 NULL,
3628 &k, &n);
b9df3536
LP
3629 if (r < 0)
3630 return log_error_errno(r, "Failed to read key file '%s': %m", optarg);
3631
3632 erase_and_free(arg_key);
3633 arg_key = TAKE_PTR(k);
3634 arg_key_size = n;
3635 break;
3636 }
a26f4a49 3637
e594a3b1
LP
3638 case '?':
3639 return -EINVAL;
3640
3641 default:
3642 assert_not_reached("Unhandled option");
3643 }
3644
3645 if (argc - optind > 1)
3646 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3647 "Expected at most one argument, the path to the block device.");
3648
a26f4a49 3649 if (arg_factory_reset > 0 && IN_SET(arg_empty, EMPTY_FORCE, EMPTY_REQUIRE, EMPTY_CREATE))
e594a3b1 3650 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
a26f4a49 3651 "Combination of --factory-reset=yes and --empty=force/--empty=require/--empty=create is invalid.");
e594a3b1
LP
3652
3653 if (arg_can_factory_reset)
a26f4a49
LP
3654 arg_dry_run = true; /* When --can-factory-reset is specified we don't make changes, hence
3655 * non-dry-run mode makes no sense. Thus, imply dry run mode so that we
3656 * open things strictly read-only. */
3657 else if (dry_run >= 0)
3658 arg_dry_run = dry_run;
3659
170c9823 3660 if (arg_empty == EMPTY_CREATE && (arg_size == UINT64_MAX && !arg_size_auto))
a26f4a49
LP
3661 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3662 "If --empty=create is specified, --size= must be specified, too.");
e594a3b1
LP
3663
3664 arg_node = argc > optind ? argv[optind] : NULL;
a26f4a49
LP
3665
3666 if (IN_SET(arg_empty, EMPTY_FORCE, EMPTY_REQUIRE, EMPTY_CREATE) && !arg_node)
3667 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3668 "A path to a device node or loopback file must be specified when --empty=force, --empty=require or --empty=create are used.");
3669
e594a3b1
LP
3670 return 1;
3671}
3672
3673static int parse_proc_cmdline_factory_reset(void) {
3674 bool b;
3675 int r;
3676
3677 if (arg_factory_reset >= 0) /* Never override what is specified on the process command line */
3678 return 0;
3679
3680 if (!in_initrd()) /* Never honour kernel command line factory reset request outside of the initrd */
3681 return 0;
3682
3683 r = proc_cmdline_get_bool("systemd.factory_reset", &b);
3684 if (r < 0)
3685 return log_error_errno(r, "Failed to parse systemd.factory_reset kernel command line argument: %m");
3686 if (r > 0) {
3687 arg_factory_reset = b;
3688
3689 if (b)
3690 log_notice("Honouring factory reset requested via kernel command line.");
3691 }
3692
3693 return 0;
3694}
3695
3696static int parse_efi_variable_factory_reset(void) {
3697 _cleanup_free_ char *value = NULL;
3698 int r;
3699
3700 if (arg_factory_reset >= 0) /* Never override what is specified on the process command line */
3701 return 0;
3702
3703 if (!in_initrd()) /* Never honour EFI variable factory reset request outside of the initrd */
3704 return 0;
3705
3706 r = efi_get_variable_string(EFI_VENDOR_SYSTEMD, "FactoryReset", &value);
3707 if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r))
3708 return 0;
3709 if (r < 0)
3710 return log_error_errno(r, "Failed to read EFI variable FactoryReset: %m");
3711
3712 r = parse_boolean(value);
3713 if (r < 0)
3714 return log_error_errno(r, "Failed to parse EFI variable FactoryReset: %m");
3715
3716 arg_factory_reset = r;
3717 if (r)
3718 log_notice("Honouring factory reset requested via EFI variable FactoryReset: %m");
3719
3720 return 0;
3721}
3722
3723static int remove_efi_variable_factory_reset(void) {
3724 int r;
3725
3726 r = efi_set_variable(EFI_VENDOR_SYSTEMD, "FactoryReset", NULL, 0);
3727 if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r))
3728 return 0;
3729 if (r < 0)
3730 return log_error_errno(r, "Failed to remove EFI variable FactoryReset: %m");
3731
3732 log_info("Successfully unset EFI variable FactoryReset.");
3733 return 0;
3734}
3735
a26f4a49 3736static int acquire_root_devno(const char *p, int mode, char **ret, int *ret_fd) {
e594a3b1
LP
3737 _cleanup_close_ int fd = -1;
3738 struct stat st;
a26f4a49 3739 dev_t devno, fd_devno = (mode_t) -1;
e594a3b1
LP
3740 int r;
3741
a26f4a49
LP
3742 assert(p);
3743 assert(ret);
3744 assert(ret_fd);
3745
e594a3b1
LP
3746 fd = open(p, mode);
3747 if (fd < 0)
3748 return -errno;
3749
3750 if (fstat(fd, &st) < 0)
3751 return -errno;
3752
3753 if (S_ISREG(st.st_mode)) {
3754 char *s;
3755
3756 s = strdup(p);
3757 if (!s)
3758 return log_oom();
3759
3760 *ret = s;
a26f4a49
LP
3761 *ret_fd = TAKE_FD(fd);
3762
e594a3b1
LP
3763 return 0;
3764 }
3765
3766 if (S_ISBLK(st.st_mode))
a26f4a49 3767 fd_devno = devno = st.st_rdev;
e594a3b1
LP
3768 else if (S_ISDIR(st.st_mode)) {
3769
3770 devno = st.st_dev;
a26f4a49 3771 if (major(devno) == 0) {
e594a3b1
LP
3772 r = btrfs_get_block_device_fd(fd, &devno);
3773 if (r == -ENOTTY) /* not btrfs */
3774 return -ENODEV;
3775 if (r < 0)
3776 return r;
3777 }
e594a3b1
LP
3778 } else
3779 return -ENOTBLK;
3780
3781 /* From dm-crypt to backing partition */
3782 r = block_get_originating(devno, &devno);
3783 if (r < 0)
3784 log_debug_errno(r, "Failed to find underlying block device for '%s', ignoring: %m", p);
3785
3786 /* From partition to whole disk containing it */
3787 r = block_get_whole_disk(devno, &devno);
3788 if (r < 0)
162392b7 3789 log_debug_errno(r, "Failed to find whole disk block device for '%s', ignoring: %m", p);
e594a3b1 3790
a26f4a49
LP
3791 r = device_path_make_canonical(S_IFBLK, devno, ret);
3792 if (r < 0)
3793 return log_debug_errno(r, "Failed to determine canonical path for '%s': %m", p);
3794
3795 /* Only if we still lock at the same block device we can reuse the fd. Otherwise return an
3796 * invalidated fd. */
3797 *ret_fd = fd_devno != (mode_t) -1 && fd_devno == devno ? TAKE_FD(fd) : -1;
3798 return 0;
e594a3b1
LP
3799}
3800
a26f4a49 3801static int find_root(char **ret, int *ret_fd) {
e594a3b1
LP
3802 const char *t;
3803 int r;
3804
a26f4a49
LP
3805 assert(ret);
3806 assert(ret_fd);
3807
e594a3b1 3808 if (arg_node) {
a26f4a49
LP
3809 if (arg_empty == EMPTY_CREATE) {
3810 _cleanup_close_ int fd = -1;
3811 _cleanup_free_ char *s = NULL;
3812
3813 s = strdup(arg_node);
3814 if (!s)
3815 return log_oom();
3816
5332d7c6 3817 fd = open(arg_node, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOFOLLOW, 0666);
a26f4a49
LP
3818 if (fd < 0)
3819 return log_error_errno(errno, "Failed to create '%s': %m", arg_node);
3820
3821 *ret = TAKE_PTR(s);
3822 *ret_fd = TAKE_FD(fd);
3823 return 0;
3824 }
3825
3826 r = acquire_root_devno(arg_node, O_RDONLY|O_CLOEXEC, ret, ret_fd);
67f0ac8c
LP
3827 if (r == -EUCLEAN)
3828 return btrfs_log_dev_root(LOG_ERR, r, arg_node);
e594a3b1 3829 if (r < 0)
aa2a74ad 3830 return log_error_errno(r, "Failed to open file or determine backing device of %s: %m", arg_node);
e594a3b1
LP
3831
3832 return 0;
3833 }
3834
a26f4a49
LP
3835 assert(IN_SET(arg_empty, EMPTY_REFUSE, EMPTY_ALLOW));
3836
e594a3b1
LP
3837 /* Let's search for the root device. We look for two cases here: first in /, and then in /usr. The
3838 * latter we check for cases where / is a tmpfs and only /usr is an actual persistent block device
3839 * (think: volatile setups) */
3840
3841 FOREACH_STRING(t, "/", "/usr") {
3842 _cleanup_free_ char *j = NULL;
3843 const char *p;
3844
3845 if (in_initrd()) {
3846 j = path_join("/sysroot", t);
3847 if (!j)
3848 return log_oom();
3849
3850 p = j;
3851 } else
3852 p = t;
3853
a26f4a49 3854 r = acquire_root_devno(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC, ret, ret_fd);
e594a3b1 3855 if (r < 0) {
67f0ac8c
LP
3856 if (r == -EUCLEAN)
3857 return btrfs_log_dev_root(LOG_ERR, r, p);
e594a3b1
LP
3858 if (r != -ENODEV)
3859 return log_error_errno(r, "Failed to determine backing device of %s: %m", p);
3860 } else
3861 return 0;
3862 }
3863
3864 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "Failed to discover root block device.");
3865}
3866
a26f4a49
LP
3867static int resize_backing_fd(const char *node, int *fd) {
3868 char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
3869 _cleanup_close_ int writable_fd = -1;
3870 struct stat st;
3871 int r;
3872
3873 assert(node);
3874 assert(fd);
3875
3876 if (arg_size == UINT64_MAX) /* Nothing to do */
3877 return 0;
3878
3879 if (*fd < 0) {
3880 /* Open the file if we haven't opened it yet. Note that we open it read-only here, just to
3881 * keep a reference to the file we can pass around. */
3882 *fd = open(node, O_RDONLY|O_CLOEXEC);
3883 if (*fd < 0)
3884 return log_error_errno(errno, "Failed to open '%s' in order to adjust size: %m", node);
3885 }
3886
3887 if (fstat(*fd, &st) < 0)
3888 return log_error_errno(errno, "Failed to stat '%s': %m", node);
3889
3890 r = stat_verify_regular(&st);
3891 if (r < 0)
3892 return log_error_errno(r, "Specified path '%s' is not a regular file, cannot resize: %m", node);
3893
3894 assert_se(format_bytes(buf1, sizeof(buf1), st.st_size));
3895 assert_se(format_bytes(buf2, sizeof(buf2), arg_size));
3896
3897 if ((uint64_t) st.st_size >= arg_size) {
3898 log_info("File '%s' already is of requested size or larger, not growing. (%s >= %s)", node, buf1, buf2);
3899 return 0;
3900 }
3901
3902 /* The file descriptor is read-only. In order to grow the file we need to have a writable fd. We
3903 * reopen the file for that temporarily. We keep the writable fd only open for this operation though,
3904 * as fdisk can't accept it anyway. */
3905
3906 writable_fd = fd_reopen(*fd, O_WRONLY|O_CLOEXEC);
3907 if (writable_fd < 0)
3908 return log_error_errno(writable_fd, "Failed to reopen backing file '%s' writable: %m", node);
3909
3910 if (!arg_discard) {
3911 if (fallocate(writable_fd, 0, 0, arg_size) < 0) {
3912 if (!ERRNO_IS_NOT_SUPPORTED(errno))
3913 return log_error_errno(errno, "Failed to grow '%s' from %s to %s by allocation: %m",
3914 node, buf1, buf2);
3915
3916 /* Fallback to truncation, if fallocate() is not supported. */
3917 log_debug("Backing file system does not support fallocate(), falling back to ftruncate().");
3918 } else {
3919 if (st.st_size == 0) /* Likely regular file just created by us */
3920 log_info("Allocated %s for '%s'.", buf2, node);
3921 else
3922 log_info("File '%s' grown from %s to %s by allocation.", node, buf1, buf2);
3923
3924 return 1;
3925 }
3926 }
3927
3928 if (ftruncate(writable_fd, arg_size) < 0)
3929 return log_error_errno(errno, "Failed to grow '%s' from %s to %s by truncation: %m",
3930 node, buf1, buf2);
3931
3932 if (st.st_size == 0) /* Likely regular file just created by us */
3933 log_info("Sized '%s' to %s.", node, buf2);
3934 else
3935 log_info("File '%s' grown from %s to %s by truncation.", node, buf1, buf2);
3936
3937 return 1;
3938}
3939
170c9823
LP
3940static int determine_auto_size(Context *c) {
3941 uint64_t sum = round_up_size(GPT_METADATA_SIZE, 4096);
3942 char buf[FORMAT_BYTES_MAX];
3943 Partition *p;
3944
3945 assert_se(c);
3946 assert_se(arg_size == UINT64_MAX);
3947 assert_se(arg_size_auto);
3948
3949 LIST_FOREACH(partitions, p, c->partitions) {
3950 uint64_t m;
3951
3952 if (p->dropped)
3953 continue;
3954
3955 m = partition_min_size_with_padding(p);
3956 if (m > UINT64_MAX - sum)
3957 return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW), "Image would grow too large, refusing.");
3958
3959 sum += m;
3960 }
3961
3962 assert_se(format_bytes(buf, sizeof(buf), sum));
3963 log_info("Automatically determined minimal disk image size as %s.", buf);
3964
3965 arg_size = sum;
3966 return 0;
3967}
3968
e594a3b1
LP
3969static int run(int argc, char *argv[]) {
3970 _cleanup_(context_freep) Context* context = NULL;
3971 _cleanup_free_ char *node = NULL;
a26f4a49 3972 _cleanup_close_ int backing_fd = -1;
e594a3b1
LP
3973 bool from_scratch;
3974 int r;
3975
3976 log_show_color(true);
3977 log_parse_environment();
3978 log_open();
3979
3980 if (in_initrd()) {
3981 /* Default to operation on /sysroot when invoked in the initrd! */
3982 arg_root = strdup("/sysroot");
3983 if (!arg_root)
3984 return log_oom();
3985 }
3986
3987 r = parse_argv(argc, argv);
3988 if (r <= 0)
3989 return r;
3990
3991 r = parse_proc_cmdline_factory_reset();
3992 if (r < 0)
3993 return r;
3994
3995 r = parse_efi_variable_factory_reset();
3996 if (r < 0)
3997 return r;
3998
e594a3b1
LP
3999 context = context_new(arg_seed);
4000 if (!context)
4001 return log_oom();
4002
4003 r = context_read_definitions(context, arg_definitions, arg_root);
4004 if (r < 0)
4005 return r;
4006
a26f4a49 4007 if (context->n_partitions <= 0 && arg_empty == EMPTY_REFUSE) {
e2d65cd2 4008 log_info("Didn't find any partition definition files, nothing to do.");
0ae5ffe0 4009 return 0;
e2d65cd2 4010 }
0ae5ffe0 4011
a26f4a49 4012 r = find_root(&node, &backing_fd);
0ae5ffe0
YW
4013 if (r < 0)
4014 return r;
4015
a26f4a49
LP
4016 if (arg_size != UINT64_MAX) {
4017 r = resize_backing_fd(node, &backing_fd);
4018 if (r < 0)
4019 return r;
4020 }
4021
4022 r = context_load_partition_table(context, node, &backing_fd);
e594a3b1
LP
4023 if (r == -EHWPOISON)
4024 return 77; /* Special return value which means "Not GPT, so not doing anything". This isn't
4025 * really an error when called at boot. */
4026 if (r < 0)
4027 return r;
4028 from_scratch = r > 0; /* Starting from scratch */
4029
4030 if (arg_can_factory_reset) {
4031 r = context_can_factory_reset(context);
4032 if (r < 0)
4033 return r;
4034 if (r == 0)
4035 return EXIT_FAILURE;
4036
4037 return 0;
4038 }
4039
4040 r = context_factory_reset(context, from_scratch);
4041 if (r < 0)
4042 return r;
4043 if (r > 0) {
4044 /* We actually did a factory reset! */
4045 r = remove_efi_variable_factory_reset();
4046 if (r < 0)
4047 return r;
4048
4049 /* Reload the reduced partition table */
4050 context_unload_partition_table(context);
a26f4a49 4051 r = context_load_partition_table(context, node, &backing_fd);
e594a3b1
LP
4052 if (r < 0)
4053 return r;
4054 }
4055
4056#if 0
4057 (void) context_dump_partitions(context, node);
4058 putchar('\n');
4059#endif
4060
4061 r = context_read_seed(context, arg_root);
4062 if (r < 0)
4063 return r;
4064
757bc2e4
LP
4065 /* Open all files to copy blocks from now, since we want to take their size into consideration */
4066 r = context_open_copy_block_paths(context);
4067 if (r < 0)
4068 return r;
4069
170c9823
LP
4070 if (arg_size_auto) {
4071 r = determine_auto_size(context);
4072 if (r < 0)
4073 return r;
4074
4075 /* Flush out everything again, and let's grow the file first, then start fresh */
4076 context_unload_partition_table(context);
4077
4078 assert_se(arg_size != UINT64_MAX);
4079 r = resize_backing_fd(node, &backing_fd);
4080 if (r < 0)
4081 return r;
4082
4083 r = context_load_partition_table(context, node, &backing_fd);
4084 if (r < 0)
4085 return r;
4086 }
4087
e594a3b1
LP
4088 /* First try to fit new partitions in, dropping by priority until it fits */
4089 for (;;) {
4090 if (context_allocate_partitions(context))
4091 break; /* Success! */
4092
4093 if (!context_drop_one_priority(context))
4094 return log_error_errno(SYNTHETIC_ERRNO(ENOSPC),
4095 "Can't fit requested partitions into free space, refusing.");
4096 }
4097
4098 /* Now assign free space according to the weight logic */
4099 r = context_grow_partitions(context);
4100 if (r < 0)
4101 return r;
4102
4103 /* Now calculate where each partition gets placed */
4104 context_place_partitions(context);
4105
4106 /* Make sure each partition has a unique UUID and unique label */
4107 r = context_acquire_partition_uuids_and_labels(context);
4108 if (r < 0)
4109 return r;
4110
4111 r = context_write_partition_table(context, node, from_scratch);
4112 if (r < 0)
4113 return r;
4114
4115 return 0;
4116}
4117
4118DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);