diff --git a/man/systemd-repart.xml b/man/systemd-repart.xml
index 346cc88441..7ebac168b4 100644
--- a/man/systemd-repart.xml
+++ b/man/systemd-repart.xml
@@ -444,12 +444,13 @@
IMAGE
Instructs systemd-repart to synthesize partition definitions from
- the partition table in the given image. The generated definitions will copy the partitions into the
- destination partition table. The copied partitions will have the same size, metadata and contents but
- might have a different partition number and might be located at a different offset in the destination
- partition table. These definitions can be combined with partition definitions read from regular
- partition definition files. The synthesized definitions take precedence over the definitions read
- from partition definition files.
+ the partition table in the given image. This option can be specified multiple times to synthesize
+ definitions from each of the given images. The generated definitions will copy the partitions into
+ the destination partition table. The copied partitions will have the same size, metadata and contents
+ but might have a different partition number and might be located at a different offset in the
+ destination partition table. These definitions can be combined with partition definitions read from
+ regular partition definition files. The synthesized definitions take precedence over the definitions
+ read from partition definition files.
diff --git a/src/partition/repart.c b/src/partition/repart.c
index 033f441af3..88669db586 100644
--- a/src/partition/repart.c
+++ b/src/partition/repart.c
@@ -156,7 +156,7 @@ static uint64_t arg_sector_size = 0;
static ImagePolicy *arg_image_policy = NULL;
static Architecture arg_architecture = _ARCHITECTURE_INVALID;
static int arg_offline = -1;
-static char *arg_copy_from = NULL;
+static char **arg_copy_from = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
@@ -169,7 +169,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_tpm2_hash_pcr_values, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_public_key, freep);
STATIC_DESTRUCTOR_REGISTER(arg_filter_partitions, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
-STATIC_DESTRUCTOR_REGISTER(arg_copy_from, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_copy_from, strv_freep);
typedef struct FreeArea FreeArea;
@@ -1814,7 +1814,7 @@ static int find_verity_sibling(Context *context, Partition *p, VerityMode mode,
return 0;
}
-static int context_open_and_lock_backing_fd(const char *node, int *backing_fd) {
+static int context_open_and_lock_backing_fd(const char *node, int operation, int *backing_fd) {
_cleanup_close_ int fd = -EBADF;
assert(node);
@@ -1828,7 +1828,7 @@ static int context_open_and_lock_backing_fd(const char *node, int *backing_fd) {
return log_error_errno(errno, "Failed to open device '%s': %m", node);
/* Tell udev not to interfere while we are processing the device */
- if (flock(fd, arg_dry_run ? LOCK_SH : LOCK_EX) < 0)
+ if (flock(fd, operation) < 0)
return log_error_errno(errno, "Failed to lock device '%s': %m", node);
log_debug("Device %s opened and locked.", node);
@@ -1905,7 +1905,7 @@ static int determine_current_padding(
return 0;
}
-static int context_copy_from(Context *context) {
+static int context_copy_from_one(Context *context, const char *src) {
_cleanup_close_ int fd = -EBADF;
_cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
_cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL;
@@ -1914,16 +1914,15 @@ static int context_copy_from(Context *context) {
size_t n_partitions;
int r;
- if (!arg_copy_from)
- return 0;
+ assert(src);
- r = context_open_and_lock_backing_fd(arg_copy_from, &fd);
+ r = context_open_and_lock_backing_fd(src, LOCK_SH, &fd);
if (r < 0)
return r;
r = fd_verify_regular(fd);
if (r < 0)
- return log_error_errno(r, "%s is not a file: %m", arg_copy_from);
+ return log_error_errno(r, "%s is not a file: %m", src);
r = fdisk_new_context_fd(fd, /* read_only = */ true, /* sector_size = */ UINT32_MAX, &c);
if (r < 0)
@@ -1937,7 +1936,7 @@ static int context_copy_from(Context *context) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Sector size %lu is not a power of two larger than 512? Refusing.", secsz);
if (!fdisk_is_labeltype(c, FDISK_DISKLABEL_GPT))
- return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON), "Cannot copy from disk %s with no GPT disk label.", arg_copy_from);
+ return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON), "Cannot copy from disk %s with no GPT disk label.", src);
r = fdisk_get_partitions(c, &t);
if (r < 0)
@@ -2003,7 +2002,7 @@ static int context_copy_from(Context *context) {
np->size_min = np->size_max = sz;
np->new_label = TAKE_PTR(label_copy);
- np->definition_path = strdup(arg_copy_from);
+ np->definition_path = strdup(src);
if (!np->definition_path)
return log_oom();
@@ -2013,13 +2012,13 @@ static int context_copy_from(Context *context) {
np->padding_min = np->padding_max = padding;
- np->copy_blocks_path = strdup(arg_copy_from);
+ np->copy_blocks_path = strdup(src);
if (!np->copy_blocks_path)
return log_oom();
np->copy_blocks_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (np->copy_blocks_fd < 0)
- return log_error_errno(r, "Failed to duplicate file descriptor of %s: %m", arg_copy_from);
+ return log_error_errno(r, "Failed to duplicate file descriptor of %s: %m", src);
np->copy_blocks_offset = start;
np->copy_blocks_size = sz;
@@ -2036,6 +2035,20 @@ static int context_copy_from(Context *context) {
return 0;
}
+static int context_copy_from(Context *context) {
+ int r;
+
+ assert(context);
+
+ STRV_FOREACH(src, arg_copy_from) {
+ r = context_copy_from_one(context, *src);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
static int context_read_definitions(Context *context) {
_cleanup_strv_free_ char **files = NULL;
Partition *last = LIST_FIND_TAIL(partitions, context->partitions);
@@ -2223,7 +2236,8 @@ static int context_load_partition_table(Context *context) {
else {
uint32_t ssz;
- r = context_open_and_lock_backing_fd(context->node, &context->backing_fd);
+ r = context_open_and_lock_backing_fd(context->node, arg_dry_run ? LOCK_SH : LOCK_EX,
+ &context->backing_fd);
if (r < 0)
return r;
@@ -2270,7 +2284,9 @@ static int context_load_partition_table(Context *context) {
if (context->backing_fd < 0) {
/* If we have no fd referencing the device yet, make a copy of the fd now, so that we have one */
- r = context_open_and_lock_backing_fd(FORMAT_PROC_FD_PATH(fdisk_get_devfd(c)), &context->backing_fd);
+ r = context_open_and_lock_backing_fd(FORMAT_PROC_FD_PATH(fdisk_get_devfd(c)),
+ arg_dry_run ? LOCK_SH : LOCK_EX,
+ &context->backing_fd);
if (r < 0)
return r;
}
@@ -6192,7 +6208,7 @@ static int help(void) {
" --sector-size=SIZE Set the logical sector size for the image\n"
" --architecture=ARCH Set the generic architecture for the image\n"
" --offline=BOOL Whether to build the image offline\n"
- " --copy-from=IMAGE Copy partitions from the given image\n"
+ " --copy-from=IMAGE Copy partitions from the given image(s)\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
@@ -6595,11 +6611,18 @@ static int parse_argv(int argc, char *argv[]) {
break;
- case ARG_COPY_FROM:
- r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_copy_from);
+ case ARG_COPY_FROM: {
+ _cleanup_free_ char *p = NULL;
+
+ r = parse_path_argument(optarg, /* suppress_root= */ false, &p);
if (r < 0)
return r;
+
+ if (strv_consume(&arg_copy_from, TAKE_PTR(p)) < 0)
+ return log_oom();
+
break;
+ }
case '?':
return -EINVAL;
diff --git a/test/units/testsuite-58.sh b/test/units/testsuite-58.sh
index 118d797f2b..249c1b04bb 100755
--- a/test/units/testsuite-58.sh
+++ b/test/units/testsuite-58.sh
@@ -160,12 +160,24 @@ last-lba: 2097118
$imgs/zzz1 : start= 2048, size= 1775576, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=4980595D-D74A-483A-AA9E-9903879A0EE5, name=\"home-first\", attrs=\"GUID:59\"
$imgs/zzz2 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=78C92DB8-3D2B-4823-B0DC-792B78F66F1E, name=\"swap\""
+ systemd-repart --offline="$OFFLINE" \
+ --definitions="$defs" \
+ --empty=create \
+ --size=50M \
+ --seed="$seed" \
+ --include-partitions=root,home \
+ "$imgs/qqq"
+
+ sfdisk -d "$imgs/qqq" | grep -v -e 'sector-size' -e '^$'
+
systemd-repart --offline="$OFFLINE" \
--empty=create \
--size=1G \
--dry-run=no \
--seed="$seed" \
- --copy-from="$imgs/zzz" \
+ --definitions "" \
+ --copy-from="$imgs/qqq" \
+ --copy-from="$imgs/qqq" \
"$imgs/copy"
output=$(sfdisk -d "$imgs/copy" | grep -v -e 'sector-size' -e '^$')
@@ -176,10 +188,14 @@ device: $imgs/copy
unit: sectors
first-lba: 2048
last-lba: 2097118
-$imgs/copy1 : start= 2048, size= 1775576, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=4980595D-D74A-483A-AA9E-9903879A0EE5, name=\"home-first\", attrs=\"GUID:59\"
-$imgs/copy2 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=78C92DB8-3D2B-4823-B0DC-792B78F66F1E, name=\"swap\""
+$imgs/copy1 : start= 2048, size= 33432, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=4980595D-D74A-483A-AA9E-9903879A0EE5, name=\"home-first\", attrs=\"GUID:59\"
+$imgs/copy2 : start= 35480, size= 33440, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=60F33797-1D71-4DCB-AA6F-20564F036CD0, name=\"root-x86-64\", attrs=\"GUID:59\"
+$imgs/copy3 : start= 68920, size= 33440, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=73A4CCD2-EAF5-44DA-A366-F99188210FDC, name=\"root-x86-64-2\", attrs=\"GUID:59\"
+$imgs/copy4 : start= 102360, size= 33432, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=4980595D-D74A-483A-AA9E-9903879A0EE5, name=\"home-first\", attrs=\"GUID:59\"
+$imgs/copy5 : start= 135792, size= 33440, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=60F33797-1D71-4DCB-AA6F-20564F036CD0, name=\"root-x86-64\", attrs=\"GUID:59\"
+$imgs/copy6 : start= 169232, size= 33440, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=73A4CCD2-EAF5-44DA-A366-F99188210FDC, name=\"root-x86-64-2\", attrs=\"GUID:59\""
- rm "$imgs/copy" # Save disk space
+ rm "$imgs/qqq" "$imgs/copy" # Save disk space
systemd-repart --offline="$OFFLINE" \
--definitions="$defs" \