]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sysext: Add --mutable mode flag
authorKrzesimir Nowak <knowak@microsoft.com>
Thu, 15 Feb 2024 14:16:08 +0000 (15:16 +0100)
committerKrzesimir Nowak <knowak@microsoft.com>
Thu, 22 Feb 2024 18:06:22 +0000 (19:06 +0100)
The flag takes "auto" or "import" or a boolean value.

"auto" causes systemd-sysext to make a decision about mutability of the merged
hierarchy based on existence of the upper directory in
`/var/lib/extensions.mutable/${hierarchy}`.

"import" causes the existing upper dir to be actually used as another lower
dir, which results in read-only merged hierarchy.

True value makes systemd-sysext to create the upper dir if it's missing and to
make the merged hierarchy mutable.

False value makes systemd-sysext to ignore upper dir completely, and create a
read-only merged hierarchy.

The default is false value.

src/sysext/sysext.c

index e381b346b0d9e90e57d59c4288b8c7dc5a73ba4a..cb55d623226e4b9a1de44c13f0726ed112523c61 100644 (file)
 #include "varlink-io.systemd.sysext.h"
 #include "verbs.h"
 
+typedef enum MutableMode {
+        MUTABLE_YES,
+        MUTABLE_NO,
+        MUTABLE_AUTO,
+        MUTABLE_IMPORT,
+        _MUTABLE_MAX,
+        _MUTABLE_INVALID = -EINVAL,
+} MutableMode;
+
 static char **arg_hierarchies = NULL; /* "/usr" + "/opt" by default for sysext and /etc by default for confext */
 static char *arg_root = NULL;
 static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
@@ -61,6 +70,7 @@ static bool arg_no_reload = false;
 static int arg_noexec = -1;
 static ImagePolicy *arg_image_policy = NULL;
 static bool arg_varlink = false;
+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;
@@ -745,10 +755,28 @@ static int resolve_mutable_directory(const char *hierarchy, char **ret_resolved_
         assert(hierarchy);
         assert(ret_resolved_mutable_directory);
 
+        if (arg_mutable == MUTABLE_NO) {
+                log_debug("Mutability for hierarchy '%s' is disabled, not resolving mutable directory.", hierarchy);
+                *ret_resolved_mutable_directory = NULL;
+                return 0;
+        }
+
         path = determine_mutable_directory_path_for_hierarchy(hierarchy);
         if (!path)
                 return log_oom();
 
+        if (arg_mutable == MUTABLE_YES) {
+                _cleanup_free_ char *path_in_root = NULL;
+
+                path_in_root = path_join(arg_root, path);
+                if (!path_in_root)
+                        return log_oom();
+
+                r = mkdir_p(path_in_root, 0700);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to create a directory '%s': %m", path_in_root);
+        }
+
         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);
@@ -801,6 +829,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;
+        }
+
         return 0;
 }
 
@@ -862,6 +897,11 @@ static int hierarchy_as_lower_dir(OverlayFSPaths *op) {
                 return 1;
         }
 
+        if (arg_mutable == MUTABLE_IMPORT) {
+                log_debug("Mutability for host hierarchy '%s' is disabled, so it will be a lowerdir", op->resolved_hierarchy);
+                return 0;
+        }
+
         if (!op->resolved_mutable_directory) {
                 log_debug("No mutable directory found, so host hierarchy '%s' will be used as lowerdir", op->resolved_hierarchy);
                 return 0;
@@ -933,6 +973,11 @@ static int determine_upper_dir(OverlayFSPaths *op) {
         assert(op);
         assert(!op->upper_dir);
 
+        if (arg_mutable == MUTABLE_IMPORT) {
+                log_debug("Mutability is disabled, there will be no upperdir for host hierarchy '%s'", op->hierarchy);
+                return 0;
+        }
+
         if (!op->resolved_mutable_directory) {
                 log_debug("No mutable directory found for host hierarchy '%s', there will be no upperdir", op->hierarchy);
                 return 0;
@@ -963,6 +1008,9 @@ static int determine_work_dir(OverlayFSPaths *op) {
         if (!op->upper_dir)
                 return 0;
 
+        if (arg_mutable == MUTABLE_IMPORT)
+                return 0;
+
         r = work_dir_for_hierarchy(op->hierarchy, op->upper_dir, &work_dir);
         if (r < 0)
                 return r;
@@ -1981,6 +2029,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_IMAGE_POLICY,
                 ARG_NOEXEC,
                 ARG_NO_RELOAD,
+                ARG_MUTABLE,
         };
 
         static const struct option options[] = {
@@ -1994,6 +2043,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY },
                 { "noexec",       required_argument, NULL, ARG_NOEXEC       },
                 { "no-reload",    no_argument,       NULL, ARG_NO_RELOAD    },
+                { "mutable",      required_argument, NULL, ARG_MUTABLE      },
                 {}
         };
 
@@ -2057,6 +2107,19 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_no_reload = true;
                         break;
 
+                case ARG_MUTABLE:
+                        if (streq(optarg, "auto"))
+                                arg_mutable = MUTABLE_AUTO;
+                        else if (streq(optarg, "import"))
+                                arg_mutable = MUTABLE_IMPORT;
+                        else {
+                                r = parse_boolean(optarg);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to parse argument to --mutable=: %s", optarg);
+                                arg_mutable = r ? MUTABLE_YES : MUTABLE_NO;
+                        }
+                        break;
+
                 case '?':
                         return -EINVAL;