]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
repart: add knobs for automatically deferring all partitions marked as empty or for...
authorLennart Poettering <lennart@poettering.net>
Tue, 16 Sep 2025 11:26:42 +0000 (13:26 +0200)
committerLennart Poettering <lennart@poettering.net>
Sat, 1 Nov 2025 21:01:35 +0000 (22:01 +0100)
man/systemd-repart.xml
src/repart/repart.c
src/shared/varlink-io.systemd.Repart.c

index 41e386212ce462e41ee6d9da953c8a81c063eff5..a38f5186693b4bc653cadf41ef8c0f4711915bca 100644 (file)
         <xi:include href="version-info.xml" xpointer="v253"/></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--defer-partitions-empty=yes</option></term>
+
+        <listitem><para>This is very similar to <option>--defer-partitions=</option> but automatically
+        selects all partitions for deferral that have <option>Format=empty</option> set. It may be used in
+        conjunction with <option>--defer-partitions=</option> or
+        <option>--defer-partitions-factory-reset=yes</option>, in which case all matching partitions are
+        deferred.</para>
+
+        <xi:include href="version-info.xml" xpointer="v259"/></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--defer-partitions-factory-reset=yes</option></term>
+
+        <listitem><para>This is very similar to <option>--defer-partitions=</option> but automatically
+        selects all partitions for deferral that have <option>FactoryReset=yes</option> set. It may be used
+        in conjunction with <option>--defer-partitions=</option> or
+        <option>--defer-partitions-empty=yes</option>, in which case all matching partitions are
+        deferred.</para>
+
+        <xi:include href="version-info.xml" xpointer="v259"/></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--sector-size=<replaceable>BYTES</replaceable></option></term>
 
index d8a602d6fa8d0549be73190b792fcfb7f8732cf2..2d6d74072519942db4ade635f66bcb2232c3d9e0 100644 (file)
@@ -196,6 +196,8 @@ static size_t arg_n_filter_partitions = 0;
 static FilterPartitionsType arg_filter_partitions_type = FILTER_PARTITIONS_NONE;
 static GptPartitionType *arg_defer_partitions = NULL;
 static size_t arg_n_defer_partitions = 0;
+static bool arg_defer_partitions_empty = false;
+static bool arg_defer_partitions_factory_reset = false;
 static uint64_t arg_sector_size = 0;
 static ImagePolicy *arg_image_policy = NULL;
 static Architecture arg_architecture = _ARCHITECTURE_INVALID;
@@ -522,6 +524,9 @@ struct Context {
         X509 *certificate;
         EVP_PKEY *private_key;
 
+        bool defer_partitions_empty;
+        bool defer_partitions_factory_reset;
+
         sd_varlink *link; /* If 'more' is used on the Varlink call, we'll send progress info over this link */
 };
 
@@ -4641,6 +4646,22 @@ static int context_discard_gap_after(Context *context, Partition *p) {
         return 0;
 }
 
+static bool partition_defer(Context *c, const Partition *p) {
+        assert(c);
+        assert(p);
+
+        if (partition_type_defer(&p->type))
+                return true;
+
+        if (c->defer_partitions_empty && streq_ptr(p->new_label, "_empty"))
+                return true;
+
+        if (c->defer_partitions_factory_reset && p->factory_reset)
+                return true;
+
+        return false;
+}
+
 static int context_wipe_and_discard(Context *context) {
         int r;
 
@@ -4658,7 +4679,7 @@ static int context_wipe_and_discard(Context *context) {
                 if (!p->allocated_to_area)
                         continue;
 
-                if (partition_type_defer(&p->type))
+                if (partition_defer(context, p))
                         continue;
 
                 (void) context_notify(context, PROGRESS_WIPING_PARTITION, p->definition_path, UINT_MAX);
@@ -5691,7 +5712,7 @@ static int context_copy_blocks(Context *context) {
                 if (PARTITION_EXISTS(p)) /* Never copy over existing partitions */
                         continue;
 
-                if (partition_type_defer(&p->type))
+                if (partition_defer(context, p))
                         continue;
 
                 /* For offline signing case */
@@ -5762,14 +5783,14 @@ static int context_copy_blocks(Context *context) {
                         log_info("Block level copying and synchronization of partition %" PRIu64 " complete in %s.",
                                  p->partno, FORMAT_TIMESPAN(time_spent, 0));
 
-                if (p->siblings[VERITY_HASH] && !partition_type_defer(&p->siblings[VERITY_HASH]->type)) {
+                if (p->siblings[VERITY_HASH] && !partition_defer(context, p->siblings[VERITY_HASH])) {
                         r = partition_format_verity_hash(context, p->siblings[VERITY_HASH],
                                                          /* node = */ NULL, partition_target_path(t));
                         if (r < 0)
                                 return r;
                 }
 
-                if (p->siblings[VERITY_SIG] && !partition_type_defer(&p->siblings[VERITY_SIG]->type)) {
+                if (p->siblings[VERITY_SIG] && !partition_defer(context, p->siblings[VERITY_SIG])) {
                         r = partition_format_verity_sig(context, p->siblings[VERITY_SIG]);
                         if (r < 0)
                                 return r;
@@ -6666,7 +6687,7 @@ static int context_mkfs(Context *context) {
                 if (!p->format)
                         continue;
 
-                if (partition_type_defer(&p->type))
+                if (partition_defer(context, p))
                         continue;
 
                 /* For offline signing case */
@@ -6777,14 +6798,14 @@ static int context_mkfs(Context *context) {
                 if (r < 0)
                         return r;
 
-                if (p->siblings[VERITY_HASH] && !partition_type_defer(&p->siblings[VERITY_HASH]->type)) {
+                if (p->siblings[VERITY_HASH] && !partition_defer(context, p->siblings[VERITY_HASH])) {
                         r = partition_format_verity_hash(context, p->siblings[VERITY_HASH],
                                                          /* node = */ NULL, partition_target_path(t));
                         if (r < 0)
                                 return r;
                 }
 
-                if (p->siblings[VERITY_SIG] && !partition_type_defer(&p->siblings[VERITY_SIG]->type)) {
+                if (p->siblings[VERITY_SIG] && !partition_defer(context, p->siblings[VERITY_SIG])) {
                         r = partition_format_verity_sig(context, p->siblings[VERITY_SIG]);
                         if (r < 0)
                                 return r;
@@ -7065,7 +7086,7 @@ static int context_mangle_partitions(Context *context) {
                 if (p->dropped)
                         continue;
 
-                if (partition_type_defer(&p->type))
+                if (partition_defer(context, p))
                         continue;
 
                 (void) context_notify(context, PROGRESS_ADJUSTING_PARTITION, p->definition_path, UINT_MAX);
@@ -7317,7 +7338,7 @@ static int context_split(Context *context) {
                 if (!p->split_path)
                         continue;
 
-                if (partition_type_defer(&p->type))
+                if (partition_defer(context, p))
                         continue;
 
                 if (fd < 0) {
@@ -8838,6 +8859,10 @@ static int help(void) {
                "     --defer-partitions=PARTITION1,PARTITION2,PARTITION3,…\n"
                "                          Take partitions of the specified types into account\n"
                "                          but don't populate them yet\n"
+               "     --defer-partitions-empty=yes\n"
+               "                          Defer all partitions marked for formatting as empty\n"
+               "     --defer-partitions-factory-reset=yes\n"
+               "                          Defer all partitions marked for factory reset\n"
                "\n%3$sCopying:%4$s\n"
                "  -s --copy-source=PATH   Specify the primary source tree to copy files from\n"
                "     --copy-from=IMAGE    Copy partitions from the given image(s)\n"
@@ -8903,6 +8928,8 @@ static int parse_argv(
                 ARG_INCLUDE_PARTITIONS,
                 ARG_EXCLUDE_PARTITIONS,
                 ARG_DEFER_PARTITIONS,
+                ARG_DEFER_PARTITIONS_EMPTY,
+                ARG_DEFER_PARTITIONS_FACTORY_RESET,
                 ARG_SECTOR_SIZE,
                 ARG_SKIP_PARTITIONS,
                 ARG_ARCHITECTURE,
@@ -8917,50 +8944,52 @@ static int parse_argv(
         };
 
         static const struct option options[] = {
-                { "help",                 no_argument,       NULL, 'h'                      },
-                { "version",              no_argument,       NULL, ARG_VERSION              },
-                { "no-pager",             no_argument,       NULL, ARG_NO_PAGER             },
-                { "no-legend",            no_argument,       NULL, ARG_NO_LEGEND            },
-                { "dry-run",              required_argument, NULL, ARG_DRY_RUN              },
-                { "empty",                required_argument, NULL, ARG_EMPTY                },
-                { "discard",              required_argument, NULL, ARG_DISCARD              },
-                { "factory-reset",        required_argument, NULL, ARG_FACTORY_RESET        },
-                { "can-factory-reset",    no_argument,       NULL, ARG_CAN_FACTORY_RESET    },
-                { "root",                 required_argument, NULL, ARG_ROOT                 },
-                { "image",                required_argument, NULL, ARG_IMAGE                },
-                { "image-policy",         required_argument, NULL, ARG_IMAGE_POLICY         },
-                { "seed",                 required_argument, NULL, ARG_SEED                 },
-                { "pretty",               required_argument, NULL, ARG_PRETTY               },
-                { "definitions",          required_argument, NULL, ARG_DEFINITIONS          },
-                { "size",                 required_argument, NULL, ARG_SIZE                 },
-                { "json",                 required_argument, NULL, ARG_JSON                 },
-                { "key-file",             required_argument, NULL, ARG_KEY_FILE             },
-                { "private-key",          required_argument, NULL, ARG_PRIVATE_KEY          },
-                { "private-key-source",   required_argument, NULL, ARG_PRIVATE_KEY_SOURCE   },
-                { "certificate",          required_argument, NULL, ARG_CERTIFICATE          },
-                { "certificate-source",   required_argument, NULL, ARG_CERTIFICATE_SOURCE   },
-                { "tpm2-device",          required_argument, NULL, ARG_TPM2_DEVICE          },
-                { "tpm2-device-key",      required_argument, NULL, ARG_TPM2_DEVICE_KEY      },
-                { "tpm2-seal-key-handle", required_argument, NULL, ARG_TPM2_SEAL_KEY_HANDLE },
-                { "tpm2-pcrs",            required_argument, NULL, ARG_TPM2_PCRS            },
-                { "tpm2-public-key",      required_argument, NULL, ARG_TPM2_PUBLIC_KEY      },
-                { "tpm2-public-key-pcrs", required_argument, NULL, ARG_TPM2_PUBLIC_KEY_PCRS },
-                { "tpm2-pcrlock",         required_argument, NULL, ARG_TPM2_PCRLOCK         },
-                { "split",                required_argument, NULL, ARG_SPLIT                },
-                { "include-partitions",   required_argument, NULL, ARG_INCLUDE_PARTITIONS   },
-                { "exclude-partitions",   required_argument, NULL, ARG_EXCLUDE_PARTITIONS   },
-                { "defer-partitions",     required_argument, NULL, ARG_DEFER_PARTITIONS     },
-                { "sector-size",          required_argument, NULL, ARG_SECTOR_SIZE          },
-                { "architecture",         required_argument, NULL, ARG_ARCHITECTURE         },
-                { "offline",              required_argument, NULL, ARG_OFFLINE              },
-                { "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         },
-                { "join-signature",       required_argument, NULL, ARG_JOIN_SIGNATURE       },
+                { "help",                           no_argument,       NULL, 'h'                                },
+                { "version",                        no_argument,       NULL, ARG_VERSION                        },
+                { "no-pager",                       no_argument,       NULL, ARG_NO_PAGER                       },
+                { "no-legend",                      no_argument,       NULL, ARG_NO_LEGEND                      },
+                { "dry-run",                        required_argument, NULL, ARG_DRY_RUN                        },
+                { "empty",                          required_argument, NULL, ARG_EMPTY                          },
+                { "discard",                        required_argument, NULL, ARG_DISCARD                        },
+                { "factory-reset",                  required_argument, NULL, ARG_FACTORY_RESET                  },
+                { "can-factory-reset",              no_argument,       NULL, ARG_CAN_FACTORY_RESET              },
+                { "root",                           required_argument, NULL, ARG_ROOT                           },
+                { "image",                          required_argument, NULL, ARG_IMAGE                          },
+                { "image-policy",                   required_argument, NULL, ARG_IMAGE_POLICY                   },
+                { "seed",                           required_argument, NULL, ARG_SEED                           },
+                { "pretty",                         required_argument, NULL, ARG_PRETTY                         },
+                { "definitions",                    required_argument, NULL, ARG_DEFINITIONS                    },
+                { "size",                           required_argument, NULL, ARG_SIZE                           },
+                { "json",                           required_argument, NULL, ARG_JSON                           },
+                { "key-file",                       required_argument, NULL, ARG_KEY_FILE                       },
+                { "private-key",                    required_argument, NULL, ARG_PRIVATE_KEY                    },
+                { "private-key-source",             required_argument, NULL, ARG_PRIVATE_KEY_SOURCE             },
+                { "certificate",                    required_argument, NULL, ARG_CERTIFICATE                    },
+                { "certificate-source",             required_argument, NULL, ARG_CERTIFICATE_SOURCE             },
+                { "tpm2-device",                    required_argument, NULL, ARG_TPM2_DEVICE                    },
+                { "tpm2-device-key",                required_argument, NULL, ARG_TPM2_DEVICE_KEY                },
+                { "tpm2-seal-key-handle",           required_argument, NULL, ARG_TPM2_SEAL_KEY_HANDLE           },
+                { "tpm2-pcrs",                      required_argument, NULL, ARG_TPM2_PCRS                      },
+                { "tpm2-public-key",                required_argument, NULL, ARG_TPM2_PUBLIC_KEY                },
+                { "tpm2-public-key-pcrs",           required_argument, NULL, ARG_TPM2_PUBLIC_KEY_PCRS           },
+                { "tpm2-pcrlock",                   required_argument, NULL, ARG_TPM2_PCRLOCK                   },
+                { "split",                          required_argument, NULL, ARG_SPLIT                          },
+                { "include-partitions",             required_argument, NULL, ARG_INCLUDE_PARTITIONS             },
+                { "exclude-partitions",             required_argument, NULL, ARG_EXCLUDE_PARTITIONS             },
+                { "defer-partitions",               required_argument, NULL, ARG_DEFER_PARTITIONS               },
+                { "defer-partitions-empty",         required_argument, NULL, ARG_DEFER_PARTITIONS_EMPTY         },
+                { "defer-partitions-factory-reset", required_argument, NULL, ARG_DEFER_PARTITIONS_FACTORY_RESET },
+                { "sector-size",                    required_argument, NULL, ARG_SECTOR_SIZE                    },
+                { "architecture",                   required_argument, NULL, ARG_ARCHITECTURE                   },
+                { "offline",                        required_argument, NULL, ARG_OFFLINE                        },
+                { "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                   },
+                { "join-signature",                 required_argument, NULL, ARG_JOIN_SIGNATURE                 },
                 {}
         };
 
@@ -9258,6 +9287,20 @@ static int parse_argv(
 
                         break;
 
+                case ARG_DEFER_PARTITIONS_EMPTY:
+                        r = parse_boolean_argument("--defer-partitions-empty=", optarg, &arg_defer_partitions_empty);
+                        if (r < 0)
+                                return r;
+
+                        break;
+
+                case ARG_DEFER_PARTITIONS_FACTORY_RESET:
+                        r = parse_boolean_argument("--defer-partitions-factory-reset=", optarg, &arg_defer_partitions_factory_reset);
+                        if (r < 0)
+                                return r;
+
+                        break;
+
                 case ARG_SECTOR_SIZE:
                         r = parse_sector_size(optarg, &arg_sector_size);
                         if (r < 0)
@@ -10124,6 +10167,8 @@ typedef struct RunParameters {
         bool dry_run;
         sd_id128_t seed;
         char **definitions;
+        bool defer_partitions_empty;
+        bool defer_partitions_factory_reset;
 } RunParameters;
 
 static void run_parameters_done(RunParameters *p) {
@@ -10140,11 +10185,13 @@ static int vl_method_run(
                 void *userdata) {
 
         static const sd_json_dispatch_field dispatch_table[] = {
-                { "node",        SD_JSON_VARIANT_STRING,  sd_json_dispatch_string,  offsetof(RunParameters, node),        SD_JSON_NULLABLE                 },
-                { "empty",       SD_JSON_VARIANT_STRING,  json_dispatch_empty_mode, offsetof(RunParameters, empty),       SD_JSON_MANDATORY                },
-                { "seed",        SD_JSON_VARIANT_STRING,  sd_json_dispatch_id128,   offsetof(RunParameters, seed),        SD_JSON_NULLABLE                 },
-                { "dryRun",      SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(RunParameters, dry_run),     SD_JSON_MANDATORY                },
-                { "definitions", SD_JSON_VARIANT_ARRAY,   json_dispatch_strv_path,  offsetof(RunParameters, definitions), SD_JSON_MANDATORY|SD_JSON_STRICT },
+                { "node",                        SD_JSON_VARIANT_STRING,  sd_json_dispatch_string,  offsetof(RunParameters, node),                           SD_JSON_NULLABLE                 },
+                { "empty",                       SD_JSON_VARIANT_STRING,  json_dispatch_empty_mode, offsetof(RunParameters, empty),                          SD_JSON_MANDATORY                },
+                { "seed",                        SD_JSON_VARIANT_STRING,  sd_json_dispatch_id128,   offsetof(RunParameters, seed),                           SD_JSON_NULLABLE                 },
+                { "dryRun",                      SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(RunParameters, dry_run),                        SD_JSON_MANDATORY                },
+                { "definitions",                 SD_JSON_VARIANT_ARRAY,   json_dispatch_strv_path,  offsetof(RunParameters, definitions),                    SD_JSON_MANDATORY|SD_JSON_STRICT },
+                { "deferPartitionsEmpty",        SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(RunParameters, defer_partitions_empty),         SD_JSON_NULLABLE                 },
+                { "deferPartitionsFactoryReset", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(RunParameters, defer_partitions_factory_reset), SD_JSON_NULLABLE                 },
                 {}
         };
 
@@ -10175,6 +10222,9 @@ static int vl_method_run(
         if (!context)
                 return log_oom();
 
+        context->defer_partitions_empty = p.defer_partitions_empty;
+        context->defer_partitions_factory_reset = p.defer_partitions_factory_reset;
+
         if (FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
                 context->link = sd_varlink_ref(link);
 
@@ -10393,6 +10443,9 @@ static int run(int argc, char *argv[]) {
         TAKE_PTR(certificate);
         TAKE_PTR(private_key);
 
+        context->defer_partitions_empty = arg_defer_partitions_empty;
+        context->defer_partitions_factory_reset = arg_defer_partitions_factory_reset;
+
         r = context_read_seed(context, arg_root);
         if (r < 0)
                 return r;
index ce46eb0b1f2ec30f0dfb843de3750a62104ef927..c47dbe9cfcaaaa11ed357cb3a1f18a4b2edbb5c9 100644 (file)
@@ -44,6 +44,10 @@ static SD_VARLINK_DEFINE_METHOD_FULL(
                 SD_VARLINK_DEFINE_INPUT(seed, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
                 SD_VARLINK_FIELD_COMMENT("Path to directory containing definition files."),
                 SD_VARLINK_DEFINE_INPUT(definitions, SD_VARLINK_STRING, SD_VARLINK_ARRAY),
+                SD_VARLINK_FIELD_COMMENT("If true, automatically defer creation of all partitions whose label is \"empty\"."),
+                SD_VARLINK_DEFINE_INPUT(deferPartitionsEmpty, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("If true, automatically defer creation of all partitions which are marked for factory reset."),
+                SD_VARLINK_DEFINE_INPUT(deferPartitionsFactoryReset, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
                 SD_VARLINK_FIELD_COMMENT("In dry-run mode returns the minimal disk size required."),
                 SD_VARLINK_DEFINE_OUTPUT(minimalSizeBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
                 SD_VARLINK_FIELD_COMMENT("In dry-run mode returns the size of the selected block device."),