]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
repart: add --append-fstab parameter 37238/head
authorAlberto Planas <aplanas@suse.com>
Thu, 24 Apr 2025 13:02:27 +0000 (15:02 +0200)
committerAlberto Planas <aplanas@suse.com>
Tue, 20 May 2025 08:32:14 +0000 (10:32 +0200)
If --generate-fstab=PATH is used, there is the possibility that the
fstab file already exists, making systemd-repart fail.

This commit will add a new --append-fstab= parameter, that will read
the file and merge it with the new generated content.  Using the
comments, the command can separate the automatic-generated section from
the user-provided section, allowing for the next append the replacement
only of the automatic-generated section, keeping the user one.

Signed-off-by: Alberto Planas <aplanas@suse.com>
man/systemd-repart.xml
src/repart/repart.c

index 0c41ef38ab093e0e7d1c397f0a6112a44fc85906..2f20a6fe43a59c119d5da1fadcac0d605d566731 100644 (file)
         <xi:include href="version-info.xml" xpointer="v255"/></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--append-fstab=</option></term>
+
+        <listitem><para>Takes one of <literal>no</literal>, <literal>auto</literal> or
+        <literal>replace</literal>. Controls how the generated
+        <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+        file by <option>--generate-fstab=</option> will behave in case that there is a previously
+        existing file.</para>
+
+        <para>If <literal>no</literal> <command>systemd-repart</command> will complain and abort in
+        case that there is a file. This is the default behaviour. If <literal>replace</literal>
+        the file will be silently replaced with the new generated one.</para>
+
+        <para>If <literal>auto</literal> <command>systemd-repart</command> will search in the pre-existing file
+        the section that belong to the automatically generated content and will replace it with the newer
+        generated content, and keep the user provided section if there is one. The generated section is
+        identified looking for the automatic content surrounded by
+        <literal># Start section ↓ of automatically generated fstab by systemd-repart</literal> and
+        <literal># End section ↑ of automatically generated fstab by systemd-repart</literal>. The content
+        that is before and after those comments are considered user provided, and kept in the new file.</para>
+
+        <xi:include href="version-info.xml" xpointer="v258"/></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--generate-fstab=<replaceable>PATH</replaceable></option></term>
 
index be4d66101acf6bcd4044518b2be6363836cd7d2c..c8cb286cb7a2f9ff6a583741f143448318afb39c 100644 (file)
 
 #define APIVFS_TMP_DIRS_NULSTR "proc\0sys\0dev\0tmp\0run\0var/tmp\0"
 
+#define AUTOMATIC_FSTAB_HEADER_START "# Start section ↓ of automatically generated fstab by systemd-repart"
+#define AUTOMATIC_FSTAB_HEADER_END   "# End section ↑ of automatically generated fstab by systemd-repart"
+
 /* Note: When growing and placing new partitions we always align to 4K sector size. It's how newer hard disks
  * are designed, and if everything is aligned to that performance is best. And for older hard disks with 512B
  * sector size devices were generally assumed to have an even number of sectors, hence at the worst we'll
@@ -135,6 +138,14 @@ typedef enum FilterPartitionType {
         _FILTER_PARTITIONS_INVALID = -EINVAL,
 } FilterPartitionsType;
 
+typedef enum AppendMode {
+        APPEND_NO,
+        APPEND_AUTO,
+        APPEND_REPLACE,
+        _APPEND_MODE_MAX,
+        _APPEND_MODE_INVALID = -EINVAL,
+} AppendMode;
+
 static EmptyMode arg_empty = EMPTY_UNSET;
 static bool arg_dry_run = true;
 static char *arg_node = NULL;
@@ -181,6 +192,7 @@ static int arg_offline = -1;
 static char **arg_copy_from = NULL;
 static char *arg_copy_source = NULL;
 static char *arg_make_ddi = NULL;
+static AppendMode arg_append_fstab = APPEND_NO;
 static char *arg_generate_fstab = NULL;
 static char *arg_generate_crypttab = NULL;
 static Set *arg_verity_settings = NULL;
@@ -455,6 +467,12 @@ static const char *empty_mode_table[_EMPTY_MODE_MAX] = {
         [EMPTY_CREATE]  = "create",
 };
 
+static const char *append_mode_table[_APPEND_MODE_MAX] = {
+        [APPEND_NO]      = "no",
+        [APPEND_AUTO]    = "auto",
+        [APPEND_REPLACE] = "replace",
+};
+
 static const char *encrypt_mode_table[_ENCRYPT_MODE_MAX] = {
         [ENCRYPT_OFF] = "off",
         [ENCRYPT_KEY_FILE] = "key-file",
@@ -476,6 +494,7 @@ static const char *minimize_mode_table[_MINIMIZE_MODE_MAX] = {
 };
 
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(empty_mode, EmptyMode);
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP(append_mode, AppendMode);
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(encrypt_mode, EncryptMode, ENCRYPT_KEY_FILE);
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(verity_mode, VerityMode);
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(minimize_mode, MinimizeMode, MINIMIZE_BEST);
@@ -7495,7 +7514,7 @@ static bool need_fstab(const Context *context) {
 static int context_fstab(Context *context) {
         _cleanup_(unlink_and_freep) char *t = NULL;
         _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char *path = NULL;
+        _cleanup_free_ char *path = NULL, *c = NULL;
         int r;
 
         assert(context);
@@ -7517,7 +7536,7 @@ static int context_fstab(Context *context) {
         if (r < 0)
                 return log_error_errno(r, "Failed to open temporary file for %s: %m", path);
 
-        fprintf(f, "# Automatically generated by systemd-repart\n\n");
+        fputs(AUTOMATIC_FSTAB_HEADER_START "\n", f);
 
         LIST_FOREACH(partitions, p, context->partitions) {
                 _cleanup_free_ char *what = NULL, *options = NULL;
@@ -7552,7 +7571,38 @@ static int context_fstab(Context *context) {
                 }
         }
 
-        r = flink_tmpfile(f, t, path, 0);
+        fputs(AUTOMATIC_FSTAB_HEADER_END "\n", f);
+
+        switch (arg_append_fstab) {
+        case APPEND_AUTO: {
+                r = read_full_file(path, &c, NULL);
+                if (r < 0) {
+                        if (r == -ENOENT) {
+                                log_debug("File fstab not found in %s", path);
+                                break;
+                        }
+                        return log_error_errno(r, "Failed to open %s: %m", path);
+                }
+
+                const char *acs, *ace;
+                acs = find_line(c, AUTOMATIC_FSTAB_HEADER_START);
+                if (acs) {
+                        fwrite(c, 1, acs - c, f);
+                        ace = find_line_after(acs, AUTOMATIC_FSTAB_HEADER_END);
+                        if (ace)
+                                fputs(ace, f);
+                } else
+                        fputs(c, f);
+                break;
+        }
+        case APPEND_NO:
+        case APPEND_REPLACE:
+                break;
+        default:
+                assert_not_reached();
+        }
+
+        r = flink_tmpfile(f, t, path, IN_SET(arg_append_fstab, APPEND_AUTO, APPEND_REPLACE) ? LINK_TMPFILE_REPLACE : 0);
         if (r < 0)
                 return log_error_errno(r, "Failed to link temporary file to %s: %m", path);
 
@@ -8174,6 +8224,8 @@ static int help(void) {
                "  -C --make-ddi=confext   Make a configuration extension DDI\n"
                "  -P --make-ddi=portable  Make a portable service DDI\n"
                "\n%3$sAuxiliary Resource Generation:%4$s\n"
+               "     --append-fstab=MODE  One of no, auto, replace; controls how to join the\n"
+               "                          content of a pre-existing fstab with the generated one\n"
                "     --generate-fstab=PATH\n"
                "                          Write fstab configuration to the given path\n"
                "     --generate-crypttab=PATH\n"
@@ -8229,6 +8281,7 @@ static int parse_argv(int argc, char *argv[], X509 **ret_certificate, EVP_PKEY *
                 ARG_OFFLINE,
                 ARG_COPY_FROM,
                 ARG_MAKE_DDI,
+                ARG_APPEND_FSTAB,
                 ARG_GENERATE_FSTAB,
                 ARG_GENERATE_CRYPTTAB,
                 ARG_LIST_DEVICES,
@@ -8275,6 +8328,7 @@ static int parse_argv(int argc, char *argv[], X509 **ret_certificate, EVP_PKEY *
                 { "copy-from",            required_argument, NULL, ARG_COPY_FROM            },
                 { "copy-source",          required_argument, NULL, 's'                      },
                 { "make-ddi",             required_argument, NULL, ARG_MAKE_DDI             },
+                { "append-fstab",         required_argument, NULL, ARG_APPEND_FSTAB         },
                 { "generate-fstab",       required_argument, NULL, ARG_GENERATE_FSTAB       },
                 { "generate-crypttab",    required_argument, NULL, ARG_GENERATE_CRYPTTAB    },
                 { "list-devices",         no_argument,       NULL, ARG_LIST_DEVICES         },
@@ -8658,6 +8712,17 @@ static int parse_argv(int argc, char *argv[], X509 **ret_certificate, EVP_PKEY *
                                 return r;
                         break;
 
+                case ARG_APPEND_FSTAB:
+                        if (isempty(optarg)) {
+                                arg_append_fstab = APPEND_AUTO;
+                                break;
+                        }
+
+                        arg_append_fstab = append_mode_from_string(optarg);
+                        if (arg_append_fstab < 0)
+                                return log_error_errno(arg_append_fstab, "Failed to parse --append-fstab= parameter: %s", optarg);
+                        break;
+
                 case ARG_GENERATE_FSTAB:
                         r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_generate_fstab);
                         if (r < 0)
@@ -8850,6 +8915,9 @@ static int parse_argv(int argc, char *argv[], X509 **ret_certificate, EVP_PKEY *
                         return log_error_errno(r, "Failed to load private key from %s: %m", arg_private_key);
         }
 
+        if (arg_append_fstab && !arg_generate_fstab)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No --generate-fstab= specified for --append-fstab=%s.", append_mode_to_string(arg_append_fstab));
+
         *ret_certificate = TAKE_PTR(certificate);
         *ret_private_key = TAKE_PTR(private_key);
         *ret_ui = TAKE_PTR(ui);