diff --git a/man/systemd-repart.xml b/man/systemd-repart.xml
index 3585cbf1076..6559fceedb4 100644
--- a/man/systemd-repart.xml
+++ b/man/systemd-repart.xml
@@ -363,6 +363,23 @@
if is enabled.
+
+ PARTITION
+ PARTITION
+
+ These options specify which partition types systemd-repart should
+ operate on. If is used, all partitions that aren't specified
+ are excluded. If is used, all partitions that are specified
+ are excluded. Both options take a comma separated list of GPT partition type UUIDs or identifiers
+ (see Type= in
+ repart.d5). All
+ partitions that are excluded using these options are still taken into account when calculating the
+ sizes and offsets of other partitions, but aren't actually written to the disk image. The net effect
+ of this option is that if you run systemd-repart again without these options, the
+ missing partitions will be added as if they had not been excluded the first time
+ systemd-repart was executed.
+
+
diff --git a/src/partition/repart.c b/src/partition/repart.c
index c2051de6596..f4c37087662 100644
--- a/src/partition/repart.c
+++ b/src/partition/repart.c
@@ -103,6 +103,14 @@ static enum {
EMPTY_CREATE, /* create disk as loopback file, create a partition table always */
} arg_empty = EMPTY_REFUSE;
+typedef enum {
+ FILTER_PARTITIONS_NONE,
+ FILTER_PARTITIONS_EXCLUDE,
+ FILTER_PARTITIONS_INCLUDE,
+ _FILTER_PARTITIONS_MAX,
+ _FILTER_PARTITIONS_INVALID = -EINVAL,
+} FilterPartitionsType;
+
static bool arg_dry_run = true;
static const char *arg_node = NULL;
static char *arg_root = NULL;
@@ -128,6 +136,9 @@ static uint32_t arg_tpm2_pcr_mask = UINT32_MAX;
static char *arg_tpm2_public_key = NULL;
static uint32_t arg_tpm2_public_key_pcr_mask = UINT32_MAX;
static bool arg_split = false;
+static sd_id128_t *arg_filter_partitions = NULL;
+static size_t arg_filter_partitions_size = 0;
+static FilterPartitionsType arg_filter_partitions_type = FILTER_PARTITIONS_NONE;
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
@@ -137,6 +148,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_private_key, EVP_PKEY_freep);
STATIC_DESTRUCTOR_REGISTER(arg_certificate, X509_freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_public_key, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_filter_partitions, freep);
typedef struct Partition Partition;
typedef struct FreeArea FreeArea;
@@ -372,6 +384,19 @@ static void partition_foreignize(Partition *p) {
p->verity = VERITY_OFF;
}
+static bool partition_skip(const Partition *p) {
+ assert(p);
+
+ if (arg_filter_partitions_type == FILTER_PARTITIONS_NONE)
+ return false;
+
+ for (size_t i = 0; i < arg_filter_partitions_size; i++)
+ if (sd_id128_equal(p->type.uuid, arg_filter_partitions[i]))
+ return arg_filter_partitions_type == FILTER_PARTITIONS_EXCLUDE;
+
+ return arg_filter_partitions_type == FILTER_PARTITIONS_INCLUDE;
+}
+
static Partition* partition_unlink_and_free(Context *context, Partition *p) {
if (!p)
return NULL;
@@ -2930,6 +2955,9 @@ static int context_wipe_and_discard(Context *context, bool from_scratch) {
if (!p->allocated_to_area)
continue;
+ if (partition_skip(p))
+ continue;
+
r = context_wipe_partition(context, p);
if (r < 0)
return r;
@@ -3187,6 +3215,9 @@ static int context_copy_blocks(Context *context) {
if (PARTITION_EXISTS(p)) /* Never copy over existing partitions */
continue;
+ if (partition_skip(p))
+ continue;
+
assert(p->new_size != UINT64_MAX);
assert(p->copy_blocks_size != UINT64_MAX);
assert(p->new_size >= p->copy_blocks_size);
@@ -3537,6 +3568,9 @@ static int context_mkfs(Context *context) {
if (p->copy_blocks_fd >= 0)
continue;
+ if (partition_skip(p))
+ continue;
+
assert(p->offset != UINT64_MAX);
assert(p->new_size != UINT64_MAX);
@@ -3708,6 +3742,9 @@ static int context_verity_hash(Context *context) {
if (p->verity != VERITY_HASH)
continue;
+ if (partition_skip(p))
+ continue;
+
assert_se(dp = p->siblings[VERITY_DATA]);
assert(!dp->dropped);
@@ -3870,6 +3907,9 @@ static int context_verity_sig(Context *context) {
if (p->verity != VERITY_SIG)
continue;
+ if (partition_skip(p))
+ continue;
+
assert_se(hp = p->siblings[VERITY_HASH]);
assert(!hp->dropped);
@@ -4171,6 +4211,9 @@ static int context_mangle_partitions(Context *context) {
if (p->dropped)
continue;
+ if (partition_skip(p))
+ continue;
+
assert(p->new_size != UINT64_MAX);
assert(p->offset != UINT64_MAX);
assert(p->partno != UINT64_MAX);
@@ -4411,6 +4454,9 @@ static int context_split(Context *context) {
if (!p->split_name_resolved)
continue;
+ if (partition_skip(p))
+ continue;
+
fname = strjoin(base, ".", p->split_name_resolved, ext);
if (!fname)
return log_oom();
@@ -5180,6 +5226,32 @@ static int context_minimize(Context *context) {
return 0;
}
+static int parse_filter_partitions(const char *p) {
+ int r;
+
+ for (;;) {
+ _cleanup_free_ char *name = NULL;
+ GptPartitionType type;
+
+ r = extract_first_word(&p, &name, ",", EXTRACT_CUNESCAPE|EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r == 0)
+ break;
+ if (r < 0)
+ return log_error_errno(r, "Failed to extract partition designator: %s", optarg);
+
+ r = gpt_partition_type_from_string(name, &type);
+ if (r < 0)
+ return log_error_errno(r, "'%s' is not a valid partition designator", name);
+
+ if (!GREEDY_REALLOC(arg_filter_partitions, arg_filter_partitions_size + 1))
+ return log_oom();
+
+ arg_filter_partitions[arg_filter_partitions_size++] = type.uuid;
+ }
+
+ return 0;
+}
+
static int help(void) {
_cleanup_free_ char *link = NULL;
int r;
@@ -5222,6 +5294,10 @@ static int help(void) {
" --json=pretty|short|off\n"
" Generate JSON output\n"
" --split=BOOL Whether to generate split artifacts\n"
+ " --include-partitions=PARTITION1,PARTITION2,PARTITION3,…\n"
+ " Only operate on partitions of the specified types\n"
+ " --exclude-partitions=PARTITION1,PARTITION2,PARTITION3,…\n"
+ " Don't operate on partitions of the specified types\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
@@ -5257,6 +5333,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_TPM2_PUBLIC_KEY,
ARG_TPM2_PUBLIC_KEY_PCRS,
ARG_SPLIT,
+ ARG_INCLUDE_PARTITIONS,
+ ARG_EXCLUDE_PARTITIONS,
};
static const struct option options[] = {
@@ -5284,6 +5362,8 @@ static int parse_argv(int argc, char *argv[]) {
{ "tpm2-public-key", required_argument, NULL, ARG_TPM2_PUBLIC_KEY },
{ "tpm2-public-key-pcrs", required_argument, NULL, ARG_TPM2_PUBLIC_KEY_PCRS },
{ "split", required_argument, NULL, ARG_SPLIT },
+ { "include-partitions", required_argument, NULL, ARG_INCLUDE_PARTITIONS },
+ { "exclude-partitions", required_argument, NULL, ARG_EXCLUDE_PARTITIONS },
{}
};
@@ -5538,6 +5618,32 @@ static int parse_argv(int argc, char *argv[]) {
arg_split = r;
break;
+ case ARG_INCLUDE_PARTITIONS:
+ if (arg_filter_partitions_type == FILTER_PARTITIONS_EXCLUDE)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Combination of --include-partitions= and --exclude-partitions= is invalid.");
+
+ r = parse_filter_partitions(optarg);
+ if (r < 0)
+ return r;
+
+ arg_filter_partitions_type = FILTER_PARTITIONS_INCLUDE;
+
+ break;
+
+ case ARG_EXCLUDE_PARTITIONS:
+ if (arg_filter_partitions_type == FILTER_PARTITIONS_INCLUDE)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Combination of --include-partitions= and --exclude-partitions= is invalid.");
+
+ r = parse_filter_partitions(optarg);
+ if (r < 0)
+ return r;
+
+ arg_filter_partitions_type = FILTER_PARTITIONS_EXCLUDE;
+
+ break;
+
case '?':
return -EINVAL;