<varname>RootImage=</varname>. Optionally a partition name can be prefixed, followed by colon, in
case the image has multiple partitions, otherwise partition name <literal>root</literal> is implied.
Options for multiple partitions can be specified in a single line with space separators. Assigning an empty
- string removes previous assignments. Duplicated options are ignored. For a list of valid mount options, please
- refer to
+ string removes previous assignments. For a list of valid mount options, please refer to
<citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
</para>
return sd_bus_message_append_array(reply, 'y', c->root_hash_sig.iov_base, c->root_hash_sig.iov_len);
}
+static int bus_append_mount_options(
+ sd_bus_message *reply,
+ MountOptions *options) {
+
+ int r;
+
+ assert(reply);
+
+ r = sd_bus_message_open_container(reply, 'a', "(ss)");
+ if (r < 0)
+ return r;
+
+ if (options)
+ for (PartitionDesignator i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
+ if (isempty(options->options[i]))
+ continue;
+
+ r = sd_bus_message_append(reply, "(ss)",
+ partition_designator_to_string(i),
+ options->options[i]);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_bus_message_close_container(reply);
+}
+
static int property_get_root_image_options(
sd_bus *bus,
const char *path,
sd_bus_error *reterr_error) {
ExecContext *c = ASSERT_PTR(userdata);
- int r;
assert(bus);
assert(property);
assert(reply);
- r = sd_bus_message_open_container(reply, 'a', "(ss)");
- if (r < 0)
- return r;
-
- LIST_FOREACH(mount_options, m, c->root_image_options) {
- r = sd_bus_message_append(reply, "(ss)",
- partition_designator_to_string(m->partition_designator),
- m->options);
- if (r < 0)
- return r;
- }
-
- return sd_bus_message_close_container(reply);
+ return bus_append_mount_options(reply, c->root_image_options);
}
static int property_get_mount_images(
if (r < 0)
return r;
- r = sd_bus_message_open_container(reply, 'a', "(ss)");
- if (r < 0)
- return r;
-
- LIST_FOREACH(mount_options, m, i->mount_options) {
- r = sd_bus_message_append(reply, "(ss)",
- partition_designator_to_string(m->partition_designator),
- m->options);
- if (r < 0)
- return r;
- }
-
- r = sd_bus_message_close_container(reply);
+ r = bus_append_mount_options(reply, i->mount_options);
if (r < 0)
return r;
if (r < 0)
return r;
- r = sd_bus_message_open_container(reply, 'a', "(ss)");
- if (r < 0)
- return r;
-
- LIST_FOREACH(mount_options, m, i->mount_options) {
- r = sd_bus_message_append(reply, "(ss)",
- partition_designator_to_string(m->partition_designator),
- m->options);
- if (r < 0)
- return r;
- }
-
- r = sd_bus_message_close_container(reply);
+ r = bus_append_mount_options(reply, i->mount_options);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (options) {
- LIST_JOIN(mount_options, c->root_image_options, options);
+ if (!c->root_image_options)
+ c->root_image_options = TAKE_PTR(options);
+ else
+ for (PartitionDesignator j = 0; j < _PARTITION_DESIGNATOR_MAX; j++) {
+ if (isempty(options->options[j])) {
+ if (options->options[j]) /* Free current value if "" is passed */
+ c->root_image_options->options[j] = mfree(c->root_image_options->options[j]);
+ continue;
+ }
+ free_and_replace(c->root_image_options->options[j], options->options[j]);
+ }
unit_write_settingf(
u, flags|UNIT_ESCAPE_SPECIFIERS, name,
"%s=%s",
reterr_error);
}
-/* ret_format_str is an accumulator, so if it has any pre-existing content, new options will be appended to it */
+/* in_out_format_str is an accumulator, so if it has any pre-existing content it will be read, and new
+ * options will be appended to it */
int bus_read_mount_options(
sd_bus_message *message,
sd_bus_error *reterr_error,
MountOptions **ret_options,
- char **ret_format_str,
+ char **in_out_format_str,
const char *separator) {
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
while ((r = sd_bus_message_read(message, "(ss)", &partition, &mount_options)) > 0) {
_cleanup_free_ char *escaped = NULL;
- _cleanup_free_ MountOptions *o = NULL;
PartitionDesignator partition_designator;
if (chars_intersect(mount_options, WHITESPACE))
if (!escaped)
return -ENOMEM;
- if (!strextend_with_separator(&format_str, separator, partition, ":", escaped))
- return -ENOMEM;
+ if (!isempty(escaped)) {
+ if (!strextend_with_separator(&format_str, separator, partition, ":", escaped))
+ return -ENOMEM;
- o = new(MountOptions, 1);
- if (!o)
- return -ENOMEM;
- *o = (MountOptions) {
- .partition_designator = partition_designator,
- .options = strdup(mount_options),
- };
- if (!o->options)
- return -ENOMEM;
- LIST_APPEND(mount_options, options, TAKE_PTR(o));
+ if (!options) {
+ options = new0(MountOptions, 1);
+ if (!options)
+ return -ENOMEM;
+ }
+
+ r = free_and_strdup(&options->options[partition_designator], mount_options);
+ if (r < 0)
+ return r;
+ } else if (options)
+ options->options[partition_designator] = mfree(options->options[partition_designator]);
}
if (r < 0)
return r;
return r;
if (options) {
- if (ret_format_str) {
- char *final = strjoin(*ret_format_str, !isempty(*ret_format_str) ? separator : "", format_str);
- if (!final)
- return -ENOMEM;
- free_and_replace(*ret_format_str, final);
- }
- LIST_JOIN(mount_options, *ret_options, options);
+ if (in_out_format_str && !strextend_with_separator(in_out_format_str, separator, format_str))
+ return -ENOMEM;
+ *ret_options = TAKE_PTR(options);
}
return 0;
int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *reterr_error);
int bus_verify_bypass_dump_ratelimit_async(Manager *m, sd_bus_message *call, sd_bus_error *reterr_error);
-int bus_read_mount_options(sd_bus_message *message, sd_bus_error *reterr_error, MountOptions **ret_options, char **ret_format_str, const char *separator);
+int bus_read_mount_options(sd_bus_message *message, sd_bus_error *reterr_error, MountOptions **ret_options, char **in_out_format_str, const char *separator);
int bus_property_get_activation_details(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *reterr_error);
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;
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)
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)
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)
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;
-
- r = extract_first_word(&val, &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;
+ _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
- partition_designator = partition_designator_from_string(partition);
- if (partition_designator < 0)
- return -EINVAL;
+ r = deserialize_mount_options(val, &options);
+ if (r < 0)
+ return r;
- 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)
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) {
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) {
fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
if (c->root_image_options) {
- fprintf(f, "%sRootImageOptions:", prefix);
- LIST_FOREACH(mount_options, o, c->root_image_options)
- if (!isempty(o->options))
- fprintf(f, " %s:%s",
- partition_designator_to_string(o->partition_designator),
- o->options);
- fprintf(f, "\n");
+ _cleanup_free_ char *opts_str = NULL;
+
+ if (mount_options_to_string(c->root_image_options, &opts_str) >= 0 && !isempty(opts_str))
+ fprintf(f, "%sRootImageOptions: %s\n", prefix, opts_str);
}
if (iovec_is_set(&c->root_hash)) {
mount->ignore_enoent ? "-": "",
mount->source,
mount->destination);
- LIST_FOREACH(mount_options, o, mount->mount_options)
- fprintf(f, ":%s:%s",
- partition_designator_to_string(o->partition_designator),
- strempty(o->options));
+ if (mount->mount_options) {
+ _cleanup_free_ char *opts = NULL;
+
+ if (mount_options_to_string(mount->mount_options, &opts) >= 0 && !isempty(opts))
+ fprintf(f, " %s", opts);
+ }
fprintf(f, "\n");
}
fprintf(f, "%sExtensionImages: %s%s", prefix,
mount->ignore_enoent ? "-": "",
mount->source);
- LIST_FOREACH(mount_options, o, mount->mount_options)
- fprintf(f, ":%s:%s",
- partition_designator_to_string(o->partition_designator),
- strempty(o->options));
+ if (mount->mount_options) {
+ _cleanup_free_ char *opts = NULL;
+
+ if (mount_options_to_string(mount->mount_options, &opts) >= 0 && !isempty(opts))
+ fprintf(f, " %s", opts);
+ }
fprintf(f, "\n");
}
struct rlimit *rlimit[_RLIMIT_MAX];
char *working_directory, *root_directory, *root_image, *root_verity, *root_hash_path, *root_hash_sig_path;
struct iovec root_hash, root_hash_sig;
- LIST_HEAD(MountOptions, root_image_options);
+ MountOptions *root_image_options;
bool root_ephemeral;
bool working_directory_missing_ok:1;
bool working_directory_home:1;
}
STRV_FOREACH_PAIR(first, second, l) {
- MountOptions *o = NULL;
_cleanup_free_ char *mount_options_resolved = NULL;
const char *mount_options = NULL, *partition = "root";
PartitionDesignator partition_designator;
continue;
}
- o = new(MountOptions, 1);
- if (!o)
- return log_oom();
- *o = (MountOptions) {
- .partition_designator = partition_designator,
- .options = TAKE_PTR(mount_options_resolved),
- };
- LIST_APPEND(mount_options, options, TAKE_PTR(o));
+ r = mount_options_set_and_consume(&options, partition_designator, TAKE_PTR(mount_options_resolved));
+ if (r < 0)
+ return r;
}
- if (options)
- LIST_JOIN(mount_options, c->root_image_options, options);
- else
- /* empty spaces/separators only */
- c->root_image_options = mount_options_free_all(c->root_image_options);
-
- return 0;
+ return free_and_replace_full(c->root_image_options, options, mount_options_free_all);
}
int config_parse_exec_root_hash(
for (;;) {
_cleanup_free_ char *partition = NULL, *mount_options = NULL, *mount_options_resolved = NULL;
- MountOptions *o = NULL;
PartitionDesignator partition_designator;
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
continue;
}
- o = new(MountOptions, 1);
- if (!o)
- return log_oom();
- *o = (MountOptions) {
- .partition_designator = PARTITION_ROOT,
- .options = TAKE_PTR(mount_options_resolved),
- };
- LIST_APPEND(mount_options, options, o);
+ r = mount_options_set_and_consume(&options, PARTITION_ROOT, TAKE_PTR(mount_options_resolved));
+ if (r < 0)
+ return r;
break;
}
continue;
}
- o = new(MountOptions, 1);
- if (!o)
- return log_oom();
- *o = (MountOptions) {
- .partition_designator = partition_designator,
- .options = TAKE_PTR(mount_options_resolved),
- };
- LIST_APPEND(mount_options, options, o);
+ r = mount_options_set_and_consume(&options, partition_designator, TAKE_PTR(mount_options_resolved));
+ if (r < 0)
+ return r;
}
r = mount_image_add(&c->mount_images, &c->n_mount_images,
for (;;) {
_cleanup_free_ char *partition = NULL, *mount_options = NULL, *mount_options_resolved = NULL;
- MountOptions *o = NULL;
PartitionDesignator partition_designator;
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
continue;
}
- o = new(MountOptions, 1);
- if (!o)
- return log_oom();
- *o = (MountOptions) {
- .partition_designator = PARTITION_ROOT,
- .options = TAKE_PTR(mount_options_resolved),
- };
- LIST_APPEND(mount_options, options, o);
+ if (!options) {
+ options = new0(MountOptions, 1);
+ if (!options)
+ return log_oom();
+ }
+ free_and_replace(options->options[PARTITION_ROOT], mount_options_resolved);
break;
}
continue;
}
- o = new(MountOptions, 1);
- if (!o)
- return log_oom();
- *o = (MountOptions) {
- .partition_designator = partition_designator,
- .options = TAKE_PTR(mount_options_resolved),
- };
- LIST_APPEND(mount_options, options, o);
+ if (!options) {
+ options = new0(MountOptions, 1);
+ if (!options)
+ return log_oom();
+ }
+ free_and_replace(options->options[partition_designator], mount_options_resolved);
}
r = mount_image_add(&c->extension_images, &c->n_extension_images,
#include "glyph-util.h"
#include "iovec-util.h"
#include "label-util.h"
-#include "list.h"
#include "lock-util.h"
#include "log.h"
#include "loop-util.h"
char *options_malloc;
unsigned long flags; /* Mount flags used by EMPTY_DIR and TMPFS. Do not include MS_RDONLY here, but please use read_only. */
unsigned n_followed;
- LIST_HEAD(MountOptions, image_options_const);
+ MountOptions *image_options_const;
char **overlay_layers;
VeritySettings verity;
ImageClass filter_class; /* Used for live updates to skip inapplicable images */
int mount_image_add(MountImage **m, size_t *n, const MountImage *item) {
_cleanup_free_ char *s = NULL, *d = NULL;
- _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
+ _cleanup_(mount_options_free_allp) MountOptions *o = NULL;
+ int r;
assert(m);
assert(n);
return -ENOMEM;
}
- LIST_FOREACH(mount_options, i, item->mount_options) {
- _cleanup_(mount_options_free_allp) MountOptions *o = NULL;
-
- o = new(MountOptions, 1);
- if (!o)
- return -ENOMEM;
-
- *o = (MountOptions) {
- .partition_designator = i->partition_designator,
- .options = strdup(i->options),
- };
- if (!o->options)
- return -ENOMEM;
-
- LIST_APPEND(mount_options, options, TAKE_PTR(o));
+ if (item->mount_options) {
+ r = mount_options_dup(item->mount_options, &o);
+ if (r < 0)
+ return r;
}
if (!GREEDY_REALLOC(*m, *n + 1))
(*m)[(*n)++] = (MountImage) {
.source = TAKE_PTR(s),
.destination = TAKE_PTR(d),
- .mount_options = TAKE_PTR(options),
+ .mount_options = TAKE_PTR(o),
.ignore_enoent = item->ignore_enoent,
.type = item->type,
};
***/
#include "core-forward.h"
-#include "list.h"
#include "runtime-scope.h"
typedef enum ProtectHome {
typedef struct MountImage {
char *source;
char *destination; /* Unused if MountImageType == MOUNT_IMAGE_EXTENSION */
- LIST_HEAD(MountOptions, mount_options);
+ MountOptions *mount_options;
bool ignore_enoent;
MountImageType type;
} MountImage;
SD_JSON_BUILD_PAIR_BOOLEAN("missingOK", c->working_directory_missing_ok));
}
-static int root_image_options_build_json(sd_json_variant **ret, const char *name, void *userdata) {
- _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
- MountOptions *root_image_options = userdata;
+static int json_append_mount_options(sd_json_variant **v, MountOptions *options) {
int r;
- assert(ret);
- assert(name);
+ assert(v);
+
+ if (!options)
+ return 0;
+
+ for (PartitionDesignator j = 0; j < _PARTITION_DESIGNATOR_MAX; j++) {
+ if (!options->options[j])
+ continue;
- LIST_FOREACH(mount_options, m, root_image_options) {
r = sd_json_variant_append_arraybo(
- &v,
- SD_JSON_BUILD_PAIR_STRING("partitionDesignator", partition_designator_to_string(m->partition_designator)),
- SD_JSON_BUILD_PAIR_STRING("options", m->options));
+ v,
+ SD_JSON_BUILD_PAIR_STRING("partitionDesignator", partition_designator_to_string(j)),
+ SD_JSON_BUILD_PAIR_STRING("options", options->options[j]));
if (r < 0)
return r;
}
- *ret = TAKE_PTR(v);
return 0;
}
+static int root_image_options_build_json(sd_json_variant **ret, const char *name, void *userdata) {
+ MountOptions *root_image_options = userdata;
+
+ assert(ret);
+ assert(name);
+
+ if (!root_image_options) {
+ *ret = NULL;
+ return 0;
+ }
+
+ return json_append_mount_options(ret, root_image_options);
+}
+
static int image_policy_build_json(sd_json_variant **ret, const char *name, void *userdata) {
_cleanup_free_ char *s = NULL;
ImagePolicy *policy = userdata;
FOREACH_ARRAY(i, c->mount_images, c->n_mount_images) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *mo = NULL;
- LIST_FOREACH(mount_options, m, i->mount_options) {
- r = sd_json_variant_append_arraybo(
- &mo,
- SD_JSON_BUILD_PAIR_STRING("partitionDesignator", partition_designator_to_string(m->partition_designator)),
- SD_JSON_BUILD_PAIR_STRING("options", m->options));
- if (r < 0)
- return r;
- }
+ r = json_append_mount_options(&mo, i->mount_options);
+ if (r < 0)
+ return r;
r = sd_json_variant_append_arraybo(
&v,
FOREACH_ARRAY(i, c->extension_images, c->n_extension_images) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *mo = NULL;
- LIST_FOREACH(mount_options, m, i->mount_options) {
- r = sd_json_variant_append_arraybo(
- &mo,
- SD_JSON_BUILD_PAIR_STRING("partitionDesignator", partition_designator_to_string(m->partition_designator)),
- SD_JSON_BUILD_PAIR_STRING("options", m->options));
- if (r < 0)
- return r;
- }
+ r = json_append_mount_options(&mo, i->mount_options);
+ if (r < 0)
+ return r;
r = sd_json_variant_append_arraybo(
&v,
return k >= 0 && image->partitions[k].found;
}
+int mount_options_set_and_consume(MountOptions **options, PartitionDesignator d, char *s) {
+ assert(options);
+ assert(d >= 0);
+
+ if (!*options) {
+ *options = new0(MountOptions, 1);
+ if (!*options) {
+ free(s);
+ return log_oom();
+ }
+ }
+
+ free_and_replace((*options)->options[d], s);
+
+ return 0;
+}
+
+int mount_options_dup(const MountOptions *source, MountOptions **ret) {
+ _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
+
+ assert(source);
+ assert(ret);
+
+ options = new0(MountOptions, 1);
+ if (!options)
+ return log_oom();
+
+ for (PartitionDesignator d = 0; d < _PARTITION_DESIGNATOR_MAX; d++)
+ if (source->options[d]) {
+ options->options[d] = strdup(source->options[d]);
+ if (!options->options[d])
+ return log_oom_debug();
+ }
+
+ *ret = TAKE_PTR(options);
+ return 0;
+}
+
+int mount_options_to_string(const MountOptions *mount_options, char **ret) {
+ _cleanup_free_ char *s = NULL;
+
+ assert(mount_options);
+ assert(ret);
+
+ for (PartitionDesignator i = 0; i < _PARTITION_DESIGNATOR_MAX; i++)
+ if (!isempty(mount_options->options[i]))
+ if (!strextend_with_separator(&s, ":", "%s:%s",
+ partition_designator_to_string(i),
+ mount_options->options[i]))
+ return log_oom_debug();
+
+ *ret = TAKE_PTR(s);
+
+ return 0;
+}
+
MountOptions* mount_options_free_all(MountOptions *options) {
- MountOptions *m;
+ if (!options)
+ return NULL;
- while ((m = LIST_POP(mount_options, options))) {
- free(m->options);
- free(m);
- }
+ free_many_charp(options->options, _PARTITION_DESIGNATOR_MAX);
- return NULL;
+ return mfree(options);
}
const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator) {
- LIST_FOREACH(mount_options, m, options)
- if (designator == m->partition_designator && !isempty(m->options))
- return m->options;
+ assert(designator >= 0 && designator < _PARTITION_DESIGNATOR_MAX);
- return NULL;
+ if (!options)
+ return NULL;
+
+ return options->options[designator];
}
int mount_image_privately_interactively(
return false;
return string_contains_word(mount_options_from_designator(options, PARTITION_ROOT), ",", "x-systemd.relax-extension-release-check") ||
- string_contains_word(mount_options_from_designator(options, PARTITION_USR), ",", "x-systemd.relax-extension-release-check") ||
- string_contains_word(options->options, ",", "x-systemd.relax-extension-release-check");
+ string_contains_word(mount_options_from_designator(options, PARTITION_USR), ",", "x-systemd.relax-extension-release-check");
}
int verity_dissect_and_mount(
#include "architecture.h"
#include "gpt.h"
#include "iovec-util.h"
-#include "list.h"
#include "shared-forward.h"
typedef struct DecryptedImage DecryptedImage;
} DissectedImage;
typedef struct MountOptions {
- PartitionDesignator partition_designator;
- char *options;
- LIST_FIELDS(MountOptions, mount_options);
+ char *options[_PARTITION_DESIGNATOR_MAX];
} MountOptions;
typedef struct VeritySettings {
MountOptions* mount_options_free_all(MountOptions *options);
DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all);
const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator);
+int mount_options_set_and_consume(MountOptions **options, PartitionDesignator d, char *s);
+int mount_options_dup(const MountOptions *source, MountOptions **ret);
+int mount_options_to_string(const MountOptions *mount_options, char **ret);
int probe_filesystem_full(int fd, const char *path, uint64_t offset, uint64_t size, bool restrict_fstypes, char **ret_fstype);
static inline int probe_filesystem(const char *path, char **ret_fstype) {
cat /usr/lib/os-release | grep -F "MARKER=1" >/dev/null
systemd-run -P \
-p RootImage="$MINIMAL_IMAGE.raw" \
- -p RootImageOptions="root:nosuid,dev home:ro,dev ro,noatime" \
+ -p RootImageOptions="root:noatime,dev home:ro,dev ro,nosuid" \
mount | grep -F "squashfs" | grep -F "nosuid" >/dev/null
systemd-run -P \
-p RootImage="$MINIMAL_IMAGE.gpt" \
- -p RootImageOptions="root:ro,noatime root:ro,dev" \
+ -p RootImageOptions="root:ro,dev root:ro,noatime" \
mount | grep -F "squashfs" | grep -F "noatime" >/dev/null
mkdir -p "$IMAGE_DIR/result"
BindPaths=$IMAGE_DIR/result:/run/result
TemporaryFileSystem=/run
RootImage=$MINIMAL_IMAGE.raw
-RootImageOptions=root:ro,noatime home:ro,dev relatime,dev
-RootImageOptions=nosuid,dev
+RootImageOptions=root:relatime,dev home:ro,dev nosuid,dev
+RootImageOptions=ro,noatime
EOF
systemctl start testservice-50a.service
grep -F "squashfs" "$IMAGE_DIR/result/a" | grep -F "noatime" >/dev/null
BindPaths=$IMAGE_DIR/result:/run/result
TemporaryFileSystem=/run
RootImage=$MINIMAL_IMAGE.gpt
-RootImageOptions=root:ro,noatime,nosuid home:ro,dev nosuid,dev
-RootImageOptions=home:ro,dev nosuid,dev,%%foo
+RootImageOptions=nosuid,dev home:ro,dev nosuid,dev
+RootImageOptions=home:ro,dev,%%foo root:ro,noatime,nosuid
# this is the default, but let's specify once to test the parser
MountAPIVFS=yes
EOF
# Check that specifier escape is applied %%foo → %foo
busctl get-property org.freedesktop.systemd1 \
/org/freedesktop/systemd1/unit/testservice_2d50b_2eservice \
- org.freedesktop.systemd1.Service RootImageOptions | grep -F "nosuid,dev,%foo"
+ org.freedesktop.systemd1.Service RootImageOptions | grep -F "ro,dev,%foo"
# Now do some checks with MountImages, both by itself, with options and in combination with RootImage, and as single FS or GPT image
systemd-run -P \