mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-10 01:17:44 +03:00
repart: add new ReadOnly= and Flags= settings for repart dropins
Let's make the GPT partition flags configurable when creating new partitions. This is primarily useful for the read-only flag (which we want to set for verity enabled partitions). This adds two settings for this: Flags= and ReadOnly=, which strictly speaking are redundant. The main reason to have both is that usually the ReadOnly= setting is the one wants to control, and it' more generic. Moreover we might later on introduce inherting of flags from CopyBlocks= partitions, where one might want to control most flags as is except for the RO flag and similar, hence let's keep them separate.
This commit is contained in:
parent
5c08da586f
commit
e73309c532
@ -565,6 +565,29 @@
|
||||
factory reset operation. This functionality is useful to implement schemes where images can be reset
|
||||
into their original state by removing partitions and creating them anew. Defaults to off.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Flags=</varname></term>
|
||||
|
||||
<listitem><para>Configures the 64bit GPT partition flags to set for the partition when creating
|
||||
it. This option has no effect if the partition already exists. If not specified the flags values is
|
||||
set to all zeroes, except if the partition type (as configured with <varname>Type=</varname> above)
|
||||
refers to a Verity partition, in wich case bit 60 is set (i.e. the read-only bit). This bit may also
|
||||
be configured separately via <varname>ReadOnly=</varname>, see below. Specify the flags value in
|
||||
hexadecimal (by prefixing it with <literal>0x</literal>), binary (prefix <literal>0b</literal>) or
|
||||
decimal (no prefix).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ReadOnly=</varname></term>
|
||||
|
||||
<listitem><para>Configures the Read-Only partition flags (bit 60) of the partition table entry. This
|
||||
option is a friendly way to set bit 60 of the partition flags value without setting any of the other
|
||||
bits, and may be set via <varname>Flags=</varname> too, see above.</para>
|
||||
|
||||
<para>If both <varname>Flags=</varname> and <varname>ReadOnly=</varname> are set the latter controls
|
||||
the value of the flag.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -168,6 +168,9 @@ struct Partition {
|
||||
char **make_directories;
|
||||
EncryptMode encrypt;
|
||||
|
||||
uint64_t gpt_flags;
|
||||
int read_only;
|
||||
|
||||
LIST_FIELDS(Partition, partitions);
|
||||
};
|
||||
|
||||
@ -239,6 +242,7 @@ static Partition *partition_new(void) {
|
||||
.offset = UINT64_MAX,
|
||||
.copy_blocks_fd = -1,
|
||||
.copy_blocks_size = UINT64_MAX,
|
||||
.read_only = -1,
|
||||
};
|
||||
|
||||
return p;
|
||||
@ -1263,6 +1267,34 @@ static int config_parse_make_dirs(
|
||||
|
||||
static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_encrypt, encrypt_mode, EncryptMode, ENCRYPT_OFF, "Invalid encryption mode");
|
||||
|
||||
static int config_parse_gpt_flags(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
uint64_t *gpt_flags = data;
|
||||
int r;
|
||||
|
||||
assert(rvalue);
|
||||
assert(gpt_flags);
|
||||
|
||||
r = safe_atou64(rvalue, gpt_flags);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to parse Flags= value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int partition_read_definition(Partition *p, const char *path) {
|
||||
|
||||
ConfigTableItem table[] = {
|
||||
@ -1282,6 +1314,8 @@ static int partition_read_definition(Partition *p, const char *path) {
|
||||
{ "Partition", "CopyFiles", config_parse_copy_files, 0, p },
|
||||
{ "Partition", "MakeDirectories", config_parse_make_dirs, 0, p },
|
||||
{ "Partition", "Encrypt", config_parse_encrypt, 0, &p->encrypt },
|
||||
{ "Partition", "Flags", config_parse_gpt_flags, 0, &p->gpt_flags },
|
||||
{ "Partition", "ReadOnly", config_parse_tristate, 0, &p->read_only },
|
||||
{}
|
||||
};
|
||||
int r;
|
||||
@ -1323,6 +1357,12 @@ static int partition_read_definition(Partition *p, const char *path) {
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
/* Verity partitions are read only, let's imply the RO flag hence, unless explicitly configured otherwise. */
|
||||
if ((gpt_partition_type_is_root_verity(p->type_uuid) ||
|
||||
gpt_partition_type_is_usr_verity(p->type_uuid)) &&
|
||||
p->read_only < 0)
|
||||
p->read_only = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3184,6 +3224,24 @@ static int context_acquire_partition_uuids_and_labels(Context *context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_gpt_flags(struct fdisk_partition *q, uint64_t flags) {
|
||||
_cleanup_free_ char *a = NULL;
|
||||
|
||||
for (unsigned i = 0; i < sizeof(flags) * 8; i++) {
|
||||
uint64_t bit = UINT64_C(1) << i;
|
||||
char buf[DECIMAL_STR_MAX(unsigned)+1];
|
||||
|
||||
if (!FLAGS_SET(flags, bit))
|
||||
continue;
|
||||
|
||||
xsprintf(buf, "%u", i);
|
||||
if (!strextend_with_separator(&a, ",", buf))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return fdisk_partition_set_attrs(q, a);
|
||||
}
|
||||
|
||||
static int context_mangle_partitions(Context *context) {
|
||||
Partition *p;
|
||||
int r;
|
||||
@ -3252,6 +3310,7 @@ static int context_mangle_partitions(Context *context) {
|
||||
_cleanup_(fdisk_unref_partitionp) struct fdisk_partition *q = NULL;
|
||||
_cleanup_(fdisk_unref_parttypep) struct fdisk_parttype *t = NULL;
|
||||
char ids[ID128_UUID_STRING_MAX];
|
||||
uint64_t f;
|
||||
|
||||
assert(!p->new_partition);
|
||||
assert(p->offset % 512 == 0);
|
||||
@ -3299,6 +3358,22 @@ static int context_mangle_partitions(Context *context) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set partition label: %m");
|
||||
|
||||
/* Merge the read only setting with the literal flags */
|
||||
f = p->gpt_flags;
|
||||
if (p->read_only >= 0) {
|
||||
if (gpt_partition_type_knows_read_only(p->type_uuid))
|
||||
SET_FLAG(f, GPT_FLAG_READ_ONLY, p->read_only);
|
||||
else {
|
||||
char buffer[ID128_UUID_STRING_MAX];
|
||||
log_warning("Configured ReadOnly=yes for partition type '%s' that doesn't support it, ignoring.",
|
||||
gpt_partition_type_uuid_to_string_harder(p->type_uuid, buffer));
|
||||
}
|
||||
}
|
||||
|
||||
r = set_gpt_flags(q, f);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set GPT partition flags: %m");
|
||||
|
||||
log_info("Adding new partition %" PRIu64 " to partition table.", p->partno);
|
||||
|
||||
r = fdisk_add_partition(context->fdisk_context, q, NULL);
|
||||
|
@ -146,3 +146,14 @@ bool gpt_partition_type_is_usr_verity(sd_id128_t id) {
|
||||
sd_id128_equal(id, GPT_USR_RISCV32_VERITY) ||
|
||||
sd_id128_equal(id, GPT_USR_RISCV64_VERITY);
|
||||
}
|
||||
|
||||
bool gpt_partition_type_knows_read_only(sd_id128_t id) {
|
||||
return gpt_partition_type_is_root(id) ||
|
||||
gpt_partition_type_is_usr(id) ||
|
||||
sd_id128_equal(id, GPT_HOME) ||
|
||||
sd_id128_equal(id, GPT_SRV) ||
|
||||
sd_id128_equal(id, GPT_VAR) ||
|
||||
sd_id128_equal(id, GPT_TMP) ||
|
||||
gpt_partition_type_is_root_verity(id) || /* pretty much implied, but let's set the bit to make things really clear */
|
||||
gpt_partition_type_is_usr_verity(id); /* ditto */
|
||||
}
|
||||
|
@ -133,3 +133,5 @@ bool gpt_partition_type_is_root(sd_id128_t id);
|
||||
bool gpt_partition_type_is_root_verity(sd_id128_t id);
|
||||
bool gpt_partition_type_is_usr(sd_id128_t id);
|
||||
bool gpt_partition_type_is_usr_verity(sd_id128_t id);
|
||||
|
||||
bool gpt_partition_type_knows_read_only(sd_id128_t id);
|
||||
|
Loading…
Reference in New Issue
Block a user