diff --git a/man/systemd-repart.xml b/man/systemd-repart.xml
index 0c41ef38ab..2f20a6fe43 100644
--- a/man/systemd-repart.xml
+++ b/man/systemd-repart.xml
@@ -619,6 +619,30 @@
+
+
+
+ Takes one of no, auto or
+ replace. Controls how the generated
+ fstab5
+ file by will behave in case that there is a previously
+ existing file.
+
+ If no systemd-repart will complain and abort in
+ case that there is a file. This is the default behaviour. If replace
+ the file will be silently replaced with the new generated one.
+
+ If auto systemd-repart 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
+ # Start section ↓ of automatically generated fstab by systemd-repart and
+ # End section ↑ of automatically generated fstab by systemd-repart. The content
+ that is before and after those comments are considered user provided, and kept in the new file.
+
+
+
+
diff --git a/src/repart/repart.c b/src/repart/repart.c
index be4d66101a..c8cb286cb7 100644
--- a/src/repart/repart.c
+++ b/src/repart/repart.c
@@ -111,6 +111,9 @@
#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);