From: Zbigniew JÄ™drzejewski-Szmek Date: Thu, 16 Jul 2026 16:11:31 +0000 (+0200) Subject: sysinstall: don't ask whether to erase a disk that contains no partitions X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=9d8f8d55ed15ec13601cfbb455d61dd4b344df5b;p=thirdparty%2Fsystemd.git sysinstall: don't ask whether to erase a disk that contains no partitions When the target disk carried no partitions, the installer still asked: Please type 'keep' to install the OS in addition to what the disk already contains, or 'erase' to erase all data on the disk: The question is meaningless in that case: there's nothing on the disk worth preserving, and both answers lead to the same result. Modify fsystemd-repart to report in the dry-run reply of io.systemd.Repart.Run() the number of partitions currently on the disk. The field is only included if the existing partition table was actually read, i.e. in the 'refuse' and 'allow' empty modes, and omitted otherwise. Make systemd-sysinstall skip the erase question if the reply positively indicates that there are no partitions, proceeding as if 'keep' was selected. --- diff --git a/src/repart/repart.c b/src/repart/repart.c index 7a6c542c692..31277c82082 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -11608,10 +11608,21 @@ static int vl_method_run( if (r < 0) return r; + bool count_partitions = IN_SET(context->empty, EMPTY_REFUSE, EMPTY_ALLOW); + uint64_t n_partitions = 0; + + if (count_partitions) + LIST_FOREACH(partitions, pp, context->partitions) + n_partitions += PARTITION_EXISTS(pp); + + /* In 'force' and 'require' modes the existing partition table is not read, hence we don't + * know how many partitions the disk contains, and say nothing about it. */ return sd_varlink_replybo( link, SD_JSON_BUILD_PAIR_UNSIGNED("minimalSizeBytes", minimal_size), - SD_JSON_BUILD_PAIR_UNSIGNED("currentSizeBytes", context->total)); + SD_JSON_BUILD_PAIR_UNSIGNED("currentSizeBytes", context->total), + SD_JSON_BUILD_PAIR_CONDITION(count_partitions, + "partitionCount", SD_JSON_BUILD_UNSIGNED(n_partitions))); } r = context_write_partition_table(context); diff --git a/src/shared/varlink-io.systemd.Repart.c b/src/shared/varlink-io.systemd.Repart.c index 968d643f017..33b16525ae2 100644 --- a/src/shared/varlink-io.systemd.Repart.c +++ b/src/shared/varlink-io.systemd.Repart.c @@ -59,6 +59,8 @@ static SD_VARLINK_DEFINE_METHOD_FULL( 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."), SD_VARLINK_DEFINE_OUTPUT(currentSizeBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE), + SD_VARLINK_FIELD_COMMENT("Returns the number of partitions currently on the selected block device. Omitted if not determined by the workflow, e.g. if the existing partition table was not read because empty mode 'force' or 'require' was selected."), + SD_VARLINK_DEFINE_OUTPUT(partitionCount, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("If used with the 'more' flag, a phase identifier is sent in progress updates."), SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(phase, ProgressPhase, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("If used with the 'more' flag, an object identifier string is sent in progress updates."), diff --git a/src/sysinstall/sysinstall.c b/src/sysinstall/sysinstall.c index 7a531edfcc3..b3b730b914a 100644 --- a/src/sysinstall/sysinstall.c +++ b/src/sysinstall/sysinstall.c @@ -689,11 +689,12 @@ static int sysinstall_context_invoke_repart_run(SysInstallContext *context) { return result.ret; } -static int read_space_metrics( +static int read_repart_metrics( sd_json_variant *v, uint64_t *min_size, uint64_t *current_size, - uint64_t *need_free) { + uint64_t *need_free, + uint64_t *n_partitions) { int r; @@ -701,16 +702,19 @@ static int read_space_metrics( uint64_t min_size; uint64_t current_size; uint64_t need_free; + uint64_t n_partitions; } p = { .min_size = UINT64_MAX, .current_size = UINT64_MAX, .need_free = UINT64_MAX, + .n_partitions = UINT64_MAX, }; static const sd_json_dispatch_field dispatch_table[] = { { "minimalSizeBytes", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, voffsetof(p, min_size), 0 }, { "currentSizeBytes", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, voffsetof(p, current_size), 0 }, { "needFreeBytes", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, voffsetof(p, need_free), 0 }, + { "partitionCount", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, voffsetof(p, n_partitions), 0 }, {} }; @@ -724,6 +728,8 @@ static int read_space_metrics( *current_size = p.current_size; if (need_free) *need_free = p.need_free; + if (n_partitions) + *n_partitions = p.n_partitions; return 0; } @@ -736,7 +742,8 @@ static int invoke_repart( char **definitions, uint64_t *min_size, /* initialized both on success and error */ uint64_t *current_size, /* ditto */ - uint64_t *need_free) { /* ditto */ + uint64_t *need_free, /* ditto */ + uint64_t *n_partitions) { /* ditto; UINT64_MAX if not determined */ int r; @@ -747,7 +754,7 @@ static int invoke_repart( r = connect_to_repart(link); if (r < 0) { - read_space_metrics(/* v= */ NULL, min_size, current_size, need_free); + read_repart_metrics(/* v= */ NULL, min_size, current_size, need_free, n_partitions); return r; } @@ -772,19 +779,19 @@ static int invoke_repart( SD_JSON_BUILD_PAIR_BOOLEAN("deferPartitionsEmpty", true), SD_JSON_BUILD_PAIR_BOOLEAN("deferPartitionsFactoryReset", true)); if (r < 0) { - read_space_metrics(/* v= */ NULL, min_size, current_size, need_free); + read_repart_metrics(/* v= */ NULL, min_size, current_size, need_free, n_partitions); return log_error_errno(r, "Failed to issue io.systemd.Repart.Run() varlink call: %m"); } if (error_id) { if (streq(error_id, "io.systemd.Repart.InsufficientFreeSpace")) { - (void) read_space_metrics(reply, min_size, current_size, need_free); + (void) read_repart_metrics(reply, min_size, current_size, need_free, n_partitions); return log_full_errno( dry_run ? LOG_DEBUG : LOG_ERR, SYNTHETIC_ERRNO(ENOSPC), "Not enough free space on disk, cannot install."); } if (streq(error_id, "io.systemd.Repart.DiskTooSmall")) { - (void) read_space_metrics(reply, min_size, current_size, need_free); + (void) read_repart_metrics(reply, min_size, current_size, need_free, n_partitions); return log_full_errno( dry_run ? LOG_DEBUG : LOG_ERR, SYNTHETIC_ERRNO(E2BIG), @@ -792,7 +799,7 @@ static int invoke_repart( } /* For all other errors reset the metrics */ - read_space_metrics(/* v= */ NULL, min_size, current_size, need_free); + read_repart_metrics(/* v= */ NULL, min_size, current_size, need_free, n_partitions); if (streq(error_id, "io.systemd.Repart.ConflictingDiskLabelPresent")) return log_full_errno( @@ -807,7 +814,7 @@ static int invoke_repart( return log_error_errno(r, "Failed to issue io.systemd.Repart.Run() varlink call: %s", error_id); } - (void) read_space_metrics(reply, min_size, current_size, need_free); + (void) read_repart_metrics(reply, min_size, current_size, need_free, n_partitions); return 0; } @@ -923,7 +930,8 @@ static int validate_run(sd_varlink **repart_link, const char *node) { /* First loop: either with explicitly configured --erase= value, or false. A second loop only if not configured explicitly. */ bool try_erase = arg_erase > 0, conflicting_disk_label = false; for (;;) { - uint64_t min_size = UINT64_MAX, current_size = UINT64_MAX, need_free = UINT64_MAX; + uint64_t min_size = UINT64_MAX, current_size = UINT64_MAX, need_free = UINT64_MAX, + n_partitions = UINT64_MAX; r = invoke_repart( repart_link, node, @@ -932,7 +940,8 @@ static int validate_run(sd_varlink **repart_link, const char *node) { arg_definitions, &min_size, ¤t_size, - &need_free); + &need_free, + &n_partitions); if (r == -ENOSPC) { /* The disk is large enough, but there's not enough unallocated space. Hence proceed, but require erasing */ if (try_erase || arg_erase >= 0) @@ -970,9 +979,16 @@ static int validate_run(sd_varlink **repart_link, const char *node) { log_warning("A conflicting disk label has been found, and must be erased for installation."); if (arg_erase < 0) { - r = prompt_erase(/* can_add= */ !try_erase, &arg_erase); - if (r < 0) - return r; + if (n_partitions == 0) { + /* If the disk contains no partitions there's nothing worth preserving on + * it, hence don't bother asking whether to erase it. */ + log_info("The selected disk contains no partitions, proceeding."); + arg_erase = false; + } else { + r = prompt_erase(/* can_add= */ !try_erase, &arg_erase); + if (r < 0) + return r; + } } return 0; @@ -1754,7 +1770,8 @@ static int fetch_candidate_devices_reply( context->definitions, &min_size, ¤t_size, - &need_free); + &need_free, + /* n_partitions= */ NULL); DeviceFit fit; if (r < 0) { @@ -2132,7 +2149,8 @@ static int run(int argc, char *argv[]) { arg_definitions, &min_size, /* current_size= */ NULL, - /* need_free= */ NULL); + /* need_free= */ NULL, + /* n_partitions= */ NULL); if (r < 0) return r;