From: Krzesimir Nowak Date: Wed, 28 Feb 2024 13:23:22 +0000 (+0100) Subject: sysext: Implement ephemeral import mode X-Git-Tag: v256-rc1~405^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3d6a34a591ca0415337a7728525459d4ed068f90;p=thirdparty%2Fsystemd.git sysext: Implement ephemeral import mode To enable it, use "ephemeral-import" either for mutable mode environment variable or for value of "--mutable=" flag. This is a combination of "ephemeral" and "import" modes. It results in a mutable hierarchy that includes contents of the mutable extension data, but the modifications are thrown away when the hierarchy is unmerged. --- diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index 51333dc6fde..57f06b26784 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -57,6 +57,7 @@ typedef enum MutableMode { MUTABLE_AUTO, MUTABLE_IMPORT, MUTABLE_EPHEMERAL, + MUTABLE_EPHEMERAL_IMPORT, _MUTABLE_MAX, _MUTABLE_INVALID = -EINVAL, } MutableMode; @@ -76,6 +77,8 @@ static MutableMode arg_mutable = MUTABLE_NO; /* Is set to IMAGE_CONFEXT when systemd is called with the confext functionality instead of the default */ static ImageClass arg_image_class = IMAGE_SYSEXT; +static const char *mutable_extensions_base_dir = "/var/lib/extensions.mutable"; + STATIC_DESTRUCTOR_REGISTER(arg_hierarchies, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); @@ -137,6 +140,9 @@ static int parse_mutable_mode(const char *p) { if (streq(p, "ephemeral")) return MUTABLE_EPHEMERAL; + if (streq(p, "ephemeral-import")) + return MUTABLE_EPHEMERAL_IMPORT; + r = parse_boolean(p); if (r < 0) return r; @@ -768,7 +774,7 @@ static int resolve_mutable_directory( char **ret_resolved_mutable_directory) { _cleanup_free_ char *path = NULL, *resolved_path = NULL, *dir_name = NULL; - const char *root = arg_root, *base = "/var/lib/extensions.mutable"; + const char *root = arg_root, *base = mutable_extensions_base_dir; int r; assert(hierarchy); @@ -780,7 +786,7 @@ static int resolve_mutable_directory( return 0; } - if (arg_mutable == MUTABLE_EPHEMERAL) { + if (IN_SET(arg_mutable, MUTABLE_EPHEMERAL, MUTABLE_EPHEMERAL_IMPORT)) { /* We create mutable directory inside the temporary tmpfs workspace, which is a fixed * location that ignores arg_root. */ root = NULL; @@ -795,7 +801,7 @@ static int resolve_mutable_directory( if (!path) return log_oom(); - if (IN_SET(arg_mutable, MUTABLE_YES, MUTABLE_EPHEMERAL)) { + if (IN_SET(arg_mutable, MUTABLE_YES, MUTABLE_EPHEMERAL, MUTABLE_EPHEMERAL_IMPORT)) { _cleanup_free_ char *path_in_root = NULL; path_in_root = path_join(root, path); @@ -848,6 +854,83 @@ static int overlayfs_paths_new(const char *hierarchy, const char *workspace_path return 0; } +static int resolved_paths_equal(const char *resolved_a, const char *resolved_b) { + /* Returns true if paths are of the same entry, false if not, <0 on error. */ + + if (path_equal(resolved_a, resolved_b)) + return 1; + + if (!resolved_a || !resolved_b) + return 0; + + return inode_same(resolved_a, resolved_b, 0); +} + +static int maybe_import_mutable_directory(OverlayFSPaths *op) { + int r; + + assert(op); + + /* If importing mutable layer and it actually exists and is not a hierarchy itself, add it just below + * the meta path */ + + if (arg_mutable != MUTABLE_IMPORT || !op->resolved_mutable_directory) + return 0; + + r = resolved_paths_equal(op->resolved_hierarchy, op->resolved_mutable_directory); + if (r < 0) + return log_error_errno(r, "Failed to check equality of hierarchy %s and its mutable directory %s: %m", op->resolved_hierarchy, op->resolved_mutable_directory); + if (r > 0) { + log_debug("Not importing mutable directory for hierarchy %s as a lower dir, because it points to the hierarchy itself", op->hierarchy); + return 0; + } + + r = strv_extend(&op->lower_dirs, op->resolved_mutable_directory); + if (r < 0) + return log_oom(); + + return 0; +} + +static int maybe_import_ignored_mutable_directory(OverlayFSPaths *op) { + _cleanup_free_ char *dir_name = NULL, *path = NULL, *resolved_path = NULL; + int r; + + assert(op); + + /* If importing the ignored mutable layer and it actually exists and is not a hierarchy itself, add + * it just below the meta path */ + if (arg_mutable != MUTABLE_EPHEMERAL_IMPORT) + return 0; + + dir_name = hierarchy_as_single_path_component(op->hierarchy); + if (!dir_name) + return log_oom(); + + path = path_join(mutable_extensions_base_dir, dir_name); + if (!path) + return log_oom(); + + r = chase(path, arg_root, CHASE_PREFIX_ROOT, &resolved_path, NULL); + if (r < 0 && r != -ENOENT) + return log_error_errno(r, "Failed to resolve mutable directory '%s': %m", path); + + r = resolved_paths_equal(op->resolved_hierarchy, resolved_path); + if (r < 0) + return log_error_errno(r, "Failed to check equality of hierarchy %s and its mutable directory %s: %m", op->resolved_hierarchy, op->resolved_mutable_directory); + + if (r > 0) { + log_debug("Not importing mutable directory for hierarchy %s as a lower dir, because it points to the hierarchy itself", op->hierarchy); + return 0; + } + + r = strv_consume(&op->lower_dirs, TAKE_PTR(resolved_path)); + if (r < 0) + return log_oom(); + + return 0; +} + static int determine_top_lower_dirs(OverlayFSPaths *op, const char *meta_path) { int r; @@ -859,12 +942,13 @@ static int determine_top_lower_dirs(OverlayFSPaths *op, const char *meta_path) { if (r < 0) return log_oom(); - /* If importing mutable layer and it actually exists, add it just below the meta path */ - if (arg_mutable == MUTABLE_IMPORT && op->resolved_mutable_directory) { - r = strv_extend(&op->lower_dirs, op->resolved_mutable_directory); - if (r < 0) - return r; - } + r = maybe_import_mutable_directory(op); + if (r < 0) + return r; + + r = maybe_import_ignored_mutable_directory(op); + if (r < 0) + return r; return 0; } @@ -928,7 +1012,12 @@ static int hierarchy_as_lower_dir(OverlayFSPaths *op) { } if (arg_mutable == MUTABLE_IMPORT) { - log_debug("Mutability for host hierarchy '%s' is disabled, so it will be a lowerdir", op->resolved_hierarchy); + log_debug("Mutability for host hierarchy '%s' is disabled, so host hierarchy will be a lowerdir", op->resolved_hierarchy); + return 0; + } + + if (arg_mutable == MUTABLE_EPHEMERAL_IMPORT) { + log_debug("Mutability for host hierarchy '%s' is ephemeral, so host hierarchy will be a lowerdir", op->resolved_hierarchy); return 0; } @@ -937,13 +1026,9 @@ static int hierarchy_as_lower_dir(OverlayFSPaths *op) { return 0; } - if (path_equal(op->resolved_hierarchy, op->resolved_mutable_directory)) { - log_debug("Host hierarchy '%s' will serve as upperdir.", op->resolved_hierarchy); - return 1; - } - r = inode_same(op->resolved_hierarchy, op->resolved_mutable_directory, 0); + r = resolved_paths_equal(op->resolved_hierarchy, op->resolved_mutable_directory); if (r < 0) - return log_error_errno(r, "Failed to check inode equality of hierarchy %s and its mutable directory %s: %m", op->resolved_hierarchy, op->resolved_mutable_directory); + return log_error_errno(r, "Failed to check equality of hierarchy %s and its mutable directory %s: %m", op->resolved_hierarchy, op->resolved_mutable_directory); if (r > 0) { log_debug("Host hierarchy '%s' will serve as upperdir.", op->resolved_hierarchy); return 1; @@ -963,7 +1048,7 @@ static int determine_bottom_lower_dirs(OverlayFSPaths *op) { if (!r) { r = strv_extend(&op->lower_dirs, op->resolved_hierarchy); if (r < 0) - return r; + return log_oom(); } return 0; @@ -1147,7 +1232,7 @@ static int write_work_dir_file(ImageClass image_class, const char *meta_path, co return 0; /* Do not store work dir path for ephemeral mode, it will be gone once this process is done. */ - if (arg_mutable == MUTABLE_EPHEMERAL) + if (IN_SET(arg_mutable, MUTABLE_EPHEMERAL, MUTABLE_EPHEMERAL_IMPORT)) return 0; work_dir_in_root = path_startswith(work_dir, empty_to_root(arg_root)); @@ -2038,7 +2123,7 @@ static int verb_help(int argc, char **argv, void *userdata) { " -h --help Show this help\n" " --version Show package version\n" "\n%3$sOptions:%4$s\n" - " --mutable=yes|no|auto|import|ephemeral\n" + " --mutable=yes|no|auto|import|ephemeral|ephemeral-import\n" " Specify a mutability mode of the merged hierarchy\n" " --no-pager Do not pipe output into a pager\n" " --no-legend Do not show the headers and footers\n"