diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2020-08-03 10:04:36 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-03 10:04:36 +0200 |
commit | 7e6225721970a0bf9ae028c9a2fc84e9c0c591fb (patch) | |
tree | 33b336e15d72a8f8ab57984123b1266928900752 /src/core | |
parent | 09364a8043a2f9b698e49a172094d658ae289ac6 (diff) | |
parent | 18d73705874f9bf0643485714e9dc069a2e9b599 (diff) | |
download | systemd-7e6225721970a0bf9ae028c9a2fc84e9c0c591fb.tar.gz |
Merge pull request #16308 from bluca/root_image_options
service: add new RootImageOptions feature
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/dbus-execute.c | 88 | ||||
-rw-r--r-- | src/core/execute.c | 13 | ||||
-rw-r--r-- | src/core/execute.h | 1 | ||||
-rw-r--r-- | src/core/load-fragment-gperf.gperf.m4 | 1 | ||||
-rw-r--r-- | src/core/load-fragment.c | 91 | ||||
-rw-r--r-- | src/core/load-fragment.h | 1 | ||||
-rw-r--r-- | src/core/namespace.c | 2 | ||||
-rw-r--r-- | src/core/namespace.h | 1 |
8 files changed, 197 insertions, 1 deletions
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 50f7ada8ce..49729799ab 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -784,6 +784,37 @@ static int property_get_root_hash_sig( return sd_bus_message_append_array(reply, 'y', c->root_hash_sig, c->root_hash_sig_size); } +static int property_get_root_image_options( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + MountOptions *m; + int r; + + assert(bus); + assert(c); + assert(property); + assert(reply); + + r = sd_bus_message_open_container(reply, 'a', "(us)"); + if (r < 0) + return r; + + LIST_FOREACH(mount_options, m, c->root_image_options) { + r = sd_bus_message_append(reply, "(us)", m->partition_number, m->options); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST), @@ -826,6 +857,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RootImageOptions", "a(us)", property_get_root_image_options, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootHash", "ay", property_get_root_hash, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootHashPath", "s", NULL, offsetof(ExecContext, root_hash_path), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootHashSignature", "ay", property_get_root_hash_sig, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -1301,6 +1333,62 @@ int bus_exec_context_set_transient_property( if (streq(name, "RootImage")) return bus_set_transient_path(u, name, &c->root_image, message, flags, error); + if (streq(name, "RootImageOptions")) { + _cleanup_(mount_options_free_allp) MountOptions *options = NULL; + _cleanup_free_ char *format_str = NULL; + const char *mount_options; + unsigned partition_number; + + r = sd_bus_message_enter_container(message, 'a', "(us)"); + if (r < 0) + return r; + + while ((r = sd_bus_message_read(message, "(us)", &partition_number, &mount_options)) > 0) { + _cleanup_free_ char *previous = TAKE_PTR(format_str); + _cleanup_free_ MountOptions *o = NULL; + + if (chars_intersect(mount_options, WHITESPACE)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid mount options string, contains whitespace character(s): %s", mount_options); + + if (asprintf(&format_str, "%s%s%u:%s", strempty(previous), previous ? " " : "", partition_number, mount_options) < 0) + return -ENOMEM; + + o = new(MountOptions, 1); + if (!o) + return -ENOMEM; + *o = (MountOptions) { + .partition_number = partition_number, + .options = strdup(mount_options), + }; + if (!o->options) + return -ENOMEM; + LIST_APPEND(mount_options, options, TAKE_PTR(o)); + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (LIST_IS_EMPTY(options)) { + c->root_image_options = mount_options_free_all(c->root_image_options); + unit_write_settingf(u, flags, name, "%s=", name); + } else { + LIST_JOIN(mount_options, c->root_image_options, options); + unit_write_settingf( + u, flags|UNIT_ESCAPE_SPECIFIERS, name, + "%s=%s", + name, + format_str); + } + } + + return 1; + } + if (streq(name, "RootHash")) { const void *roothash_decoded; size_t roothash_decoded_size; diff --git a/src/core/execute.c b/src/core/execute.c index 2a4840a3a9..39ffcba580 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -2660,7 +2660,7 @@ static int apply_mount_namespace( if (context->mount_flags == MS_SHARED) log_unit_debug(u, "shared mount propagation hidden by other fs namespacing unit settings: ignoring"); - r = setup_namespace(root_dir, root_image, + r = setup_namespace(root_dir, root_image, context->root_image_options, &ns_info, context->read_write_paths, needs_sandboxing ? context->read_only_paths : NULL, needs_sandboxing ? context->inaccessible_paths : NULL, @@ -4207,6 +4207,7 @@ void exec_context_done(ExecContext *c) { c->working_directory = mfree(c->working_directory); c->root_directory = mfree(c->root_directory); c->root_image = mfree(c->root_image); + c->root_image_options = mount_options_free_all(c->root_image_options); c->root_hash = mfree(c->root_hash); c->root_hash_size = 0; c->root_hash_path = mfree(c->root_hash_path); @@ -4618,6 +4619,16 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { if (c->root_image) fprintf(f, "%sRootImage: %s\n", prefix, c->root_image); + if (c->root_image_options) { + MountOptions *o; + + fprintf(f, "%sRootImageOptions:", prefix); + LIST_FOREACH(mount_options, o, c->root_image_options) + if (!isempty(o->options)) + fprintf(f, " %u:%s", o->partition_number, o->options); + fprintf(f, "\n"); + } + if (c->root_hash) { _cleanup_free_ char *encoded = NULL; encoded = hexmem(c->root_hash, c->root_hash_size); diff --git a/src/core/execute.h b/src/core/execute.h index fc7bc5c24b..349f583c1a 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -158,6 +158,7 @@ struct ExecContext { char *working_directory, *root_directory, *root_image, *root_verity, *root_hash_path, *root_hash_sig_path; void *root_hash, *root_hash_sig; size_t root_hash_size, root_hash_sig_size; + LIST_HEAD(MountOptions, root_image_options); bool working_directory_missing_ok:1; bool working_directory_home:1; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 12ae78eb7d..a7c9bd9f71 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -23,6 +23,7 @@ m4_define(`EXEC_CONTEXT_CONFIG_ITEMS', `$1.WorkingDirectory, config_parse_working_directory, 0, offsetof($1, exec_context) $1.RootDirectory, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_directory) $1.RootImage, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_image) +$1.RootImageOptions, config_parse_root_image_options, 0, offsetof($1, exec_context) $1.RootHash, config_parse_exec_root_hash, 0, offsetof($1, exec_context) $1.RootHashSignature, config_parse_exec_root_hash_sig, 0, offsetof($1, exec_context) $1.RootVerity, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_verity) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 3036aa8ba4..2a2a5af58f 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1416,6 +1416,97 @@ int config_parse_exec_cpu_sched_prio(const char *unit, return 0; } +int config_parse_root_image_options( + 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) { + + _cleanup_(mount_options_free_allp) MountOptions *options = NULL; + ExecContext *c = data; + const Unit *u = userdata; + const char *p = rvalue; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + c->root_image_options = mount_options_free_all(c->root_image_options); + return 0; + } + + for (;;) { + _cleanup_free_ char *mount_options_resolved = NULL, *first = NULL, *tuple = NULL; + const char *mount_options = NULL, *second = NULL; + MountOptions *o = NULL; + unsigned int partition_number = 0; + + r = extract_first_word(&p, &tuple, WHITESPACE, EXTRACT_UNQUOTE); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue); + return 0; + } + + second = tuple; + r = extract_first_word(&second, &first, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS); + if (r == 0) + continue; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue); + continue; + } + + /* Format is either '0:foo' or 'foo' (0 is implied) */ + if (!isempty(second) && second[-1] == ':') { + mount_options = second; + r = safe_atou(first, &partition_number); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse partition number from \"%s\", ignoring: %m", first); + continue; + } + } else + mount_options = first; + + r = unit_full_printf(u, mount_options, &mount_options_resolved); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", mount_options); + continue; + } + + o = new(MountOptions, 1); + if (!o) + return log_oom(); + *o = (MountOptions) { + .partition_number = partition_number, + .options = TAKE_PTR(mount_options_resolved), + }; + LIST_APPEND(mount_options, options, o); + } + + /* empty spaces/separators only */ + if (LIST_IS_EMPTY(options)) + c->root_image_options = mount_options_free_all(c->root_image_options); + else + LIST_JOIN(mount_options, c->root_image_options, options); + + return 0; +} + int config_parse_exec_root_hash( const char *unit, const char *filename, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index ac3940a1b7..253de9467f 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -44,6 +44,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_policy); CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_prio); CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity); CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits); +CONFIG_PARSER_PROTOTYPE(config_parse_root_image_options); CONFIG_PARSER_PROTOTYPE(config_parse_exec_root_hash); CONFIG_PARSER_PROTOTYPE(config_parse_exec_root_hash_sig); CONFIG_PARSER_PROTOTYPE(config_parse_capability_set); diff --git a/src/core/namespace.c b/src/core/namespace.c index 36d5ff67ae..16d40fedc0 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -1257,6 +1257,7 @@ static bool home_read_only( int setup_namespace( const char* root_directory, const char* root_image, + const MountOptions *root_image_options, const NamespaceInfo *ns_info, char** read_write_paths, char** read_only_paths, @@ -1331,6 +1332,7 @@ int setup_namespace( root_hash ?: root_hash_decoded, root_hash_size, root_verity ?: verity_data, + root_image_options, dissect_image_flags, &dissected_image); if (r < 0) diff --git a/src/core/namespace.h b/src/core/namespace.h index b182223bd4..258bd7c131 100644 --- a/src/core/namespace.h +++ b/src/core/namespace.h @@ -75,6 +75,7 @@ struct TemporaryFileSystem { int setup_namespace( const char *root_directory, const char *root_image, + const MountOptions *root_image_options, const NamespaceInfo *ns_info, char **read_write_paths, char **read_only_paths, |