1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-06 00:58:29 +03:00

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.
This commit is contained in:
Krzesimir Nowak 2024-02-28 14:23:22 +01:00
parent 153e7f7b24
commit 3d6a34a591

View File

@ -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"