1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-22 17:35:35 +03:00

repart: Add --include/--exclude-partitions

Let's allow filtering the partitions to operate on by partition
type UUID. This is necessary when building bootable images with a
verity protected root/usr partition as we can only build the UKI
image when we have the verity roothash which means we cannot populate
the EFI partition yet when we run repart initially to determine the
verity roothash.
This commit is contained in:
Daan De Meyer 2022-10-14 12:06:55 +02:00
parent 00428745e3
commit 81d1098bc1
2 changed files with 123 additions and 0 deletions

View File

@ -363,6 +363,23 @@
if <option>--split</option> is enabled.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--include-partitions=</option><arg rep="repeat">PARTITION</arg></term>
<term><option>--exclude-partitions=</option><arg rep="repeat">PARTITION</arg></term>
<listitem><para>These options specify which partition types <command>systemd-repart</command> should
operate on. If <option>--include-partitions=</option> is used, all partitions that aren't specified
are excluded. If <option>--exclude-partitions=</option> is used, all partitions that are specified
are excluded. Both options take a comma separated list of GPT partition type UUIDs or identifiers
(see <varname>Type=</varname> in
<citerefentry><refentrytitle>repart.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>). 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 <command>systemd-repart</command> again without these options, the
missing partitions will be added as if they had not been excluded the first time
<command>systemd-repart</command> was executed.</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
<xi:include href="standard-options.xml" xpointer="no-pager" />

View File

@ -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;