core: change mount options settings so that last defined wins

Currently mount options are handled in such a way that the first
definition for a given partition wins, and documented as such.
Change them so that they behave like other options, and the
last specified wins.
Applies to RootImageOptions=, MountImages= and ExtensionImages=.
Switch from a linked list to an array indexed by the partition
specifier to store them.
This commit is contained in:
Luca Boccassi
2026-01-06 17:59:10 +01:00
parent 9573ad4e76
commit 9de41f677c
14 changed files with 311 additions and 378 deletions
+91 -176
View File
@@ -1547,6 +1547,77 @@ static int exec_parameters_deserialize(ExecParameters *p, FILE *f, FDSet *fds) {
return 0;
}
static int serialize_mount_options(const MountOptions *mount_options, char **s) {
assert(s);
if (!mount_options)
return 0;
for (PartitionDesignator i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
_cleanup_free_ char *escaped = NULL;
if (isempty(mount_options->options[i]))
continue;
escaped = shell_escape(mount_options->options[i], ":");
if (!escaped)
return log_oom_debug();
if (!strextend(s,
" ",
partition_designator_to_string(i),
":",
escaped))
return log_oom_debug();
}
return 0;
}
static int deserialize_mount_options(const char *s, MountOptions **ret_mount_options) {
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
int r;
assert(ret_mount_options);
for (;;) {
_cleanup_free_ char *word = NULL, *mount_options = NULL, *partition = NULL;
PartitionDesignator partition_designator;
const char *p;
r = extract_first_word(&s, &word, NULL, 0);
if (r < 0)
return r;
if (r == 0)
break;
p = word;
r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
if (r < 0)
return r;
if (r == 0)
continue;
if (r != 2) {
log_warning("Failed to parse mount options entry '%s', ignoring.", word);
continue;
}
partition_designator = partition_designator_from_string(partition);
if (partition_designator < 0) {
log_warning_errno(partition_designator, "Unknown partition designator '%s' in exec-context-root-image-options= entry, ignoring.", partition);
continue;
}
r = mount_options_set_and_consume(&options, partition_designator, TAKE_PTR(mount_options));
if (r < 0)
return r;
}
*ret_mount_options = TAKE_PTR(options);
return 0;
}
static int exec_context_serialize(const ExecContext *c, FILE *f) {
int r;
@@ -1594,22 +1665,9 @@ static int exec_context_serialize(const ExecContext *c, FILE *f) {
if (c->root_image_options) {
_cleanup_free_ char *options = NULL;
LIST_FOREACH(mount_options, o, c->root_image_options) {
if (isempty(o->options))
continue;
_cleanup_free_ char *escaped = NULL;
escaped = shell_escape(o->options, ":");
if (!escaped)
return log_oom_debug();
if (!strextend(&options,
" ",
partition_designator_to_string(o->partition_designator),
":",
escaped))
return log_oom_debug();
}
r = serialize_mount_options(c->root_image_options, &options);
if (r < 0)
return r;
r = serialize_item(f, "exec-context-root-image-options", options);
if (r < 0)
@@ -2398,23 +2456,9 @@ static int exec_context_serialize(const ExecContext *c, FILE *f) {
if (!s)
return log_oom_debug();
LIST_FOREACH(mount_options, o, mount->mount_options) {
_cleanup_free_ char *escaped = NULL;
if (isempty(o->options))
continue;
escaped = shell_escape(o->options, ":");
if (!escaped)
return log_oom_debug();
if (!strextend(&s,
" ",
partition_designator_to_string(o->partition_designator),
":",
escaped))
return log_oom_debug();
}
r = serialize_mount_options(mount->mount_options, &s);
if (r < 0)
return r;
r = serialize_item(f, "exec-context-mount-image", s);
if (r < 0)
@@ -2433,23 +2477,9 @@ static int exec_context_serialize(const ExecContext *c, FILE *f) {
if (!s)
return log_oom_debug();
LIST_FOREACH(mount_options, o, mount->mount_options) {
_cleanup_free_ char *escaped = NULL;
if (isempty(o->options))
continue;
escaped = shell_escape(o->options, ":");
if (!escaped)
return log_oom_debug();
if (!strextend(&s,
" ",
partition_designator_to_string(o->partition_designator),
":",
escaped))
return log_oom_debug();
}
r = serialize_mount_options(mount->mount_options, &s);
if (r < 0)
return r;
r = serialize_item(f, "exec-context-extension-image", s);
if (r < 0)
@@ -2565,38 +2595,13 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) {
return k;
free_and_replace(c->root_image, p);
} else if ((val = startswith(l, "exec-context-root-image-options="))) {
for (;;) {
_cleanup_free_ char *word = NULL, *mount_options = NULL, *partition = NULL;
PartitionDesignator partition_designator;
MountOptions *o = NULL;
const char *p;
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
r = extract_first_word(&val, &word, NULL, 0);
if (r < 0)
return r;
if (r == 0)
break;
r = deserialize_mount_options(val, &options);
if (r < 0)
return r;
p = word;
r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
if (r < 0)
return r;
if (r == 0)
continue;
partition_designator = partition_designator_from_string(partition);
if (partition_designator < 0)
return -EINVAL;
o = new(MountOptions, 1);
if (!o)
return log_oom_debug();
*o = (MountOptions) {
.partition_designator = partition_designator,
.options = TAKE_PTR(mount_options),
};
LIST_APPEND(mount_options, c->root_image_options, o);
}
free_and_replace_full(c->root_image_options, options, mount_options_free_all);
} else if ((val = startswith(l, "exec-context-root-verity="))) {
r = free_and_strdup(&c->root_verity, val);
if (r < 0)
@@ -3538,54 +3543,9 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) {
if (isempty(destination))
continue;
for (;;) {
_cleanup_free_ char *tuple = NULL, *partition = NULL, *opts = NULL;
PartitionDesignator partition_designator;
MountOptions *o = NULL;
const char *p;
r = extract_first_word(&val, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
if (r < 0)
return r;
if (r == 0)
break;
p = tuple;
r = extract_many_words(&p,
":",
EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
&partition,
&opts);
if (r < 0)
return r;
if (r == 0)
continue;
if (r == 1) {
o = new(MountOptions, 1);
if (!o)
return log_oom_debug();
*o = (MountOptions) {
.partition_designator = PARTITION_ROOT,
.options = TAKE_PTR(partition),
};
LIST_APPEND(mount_options, options, o);
continue;
}
partition_designator = partition_designator_from_string(partition);
if (partition_designator < 0)
continue;
o = new(MountOptions, 1);
if (!o)
return log_oom_debug();
*o = (MountOptions) {
.partition_designator = partition_designator,
.options = TAKE_PTR(opts),
};
LIST_APPEND(mount_options, options, o);
}
r = deserialize_mount_options(val, &options);
if (r < 0)
return r;
r = mount_image_add(&c->mount_images, &c->n_mount_images,
&(MountImage) {
@@ -3618,54 +3578,9 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) {
s++;
}
for (;;) {
_cleanup_free_ char *tuple = NULL, *partition = NULL, *opts = NULL;
PartitionDesignator partition_designator;
MountOptions *o = NULL;
const char *p;
r = extract_first_word(&val, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
if (r < 0)
return r;
if (r == 0)
break;
p = tuple;
r = extract_many_words(&p,
":",
EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
&partition,
&opts);
if (r < 0)
return r;
if (r == 0)
continue;
if (r == 1) {
o = new(MountOptions, 1);
if (!o)
return log_oom_debug();
*o = (MountOptions) {
.partition_designator = PARTITION_ROOT,
.options = TAKE_PTR(partition),
};
LIST_APPEND(mount_options, options, o);
continue;
}
partition_designator = partition_designator_from_string(partition);
if (partition_designator < 0)
continue;
o = new(MountOptions, 1);
if (!o)
return log_oom_debug();
*o = (MountOptions) {
.partition_designator = partition_designator,
.options = TAKE_PTR(opts),
};
LIST_APPEND(mount_options, options, o);
}
r = deserialize_mount_options(val, &options);
if (r < 0)
return r;
r = mount_image_add(&c->extension_images, &c->n_extension_images,
&(MountImage) {