From: Thomas Weißschuh Date: Sun, 19 Nov 2023 16:20:55 +0000 (+0100) Subject: fdisk: add support for partition resizing X-Git-Tag: v2.40-rc1~117 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d45820df1058027fd986db250681de25b8ce92a2;p=thirdparty%2Futil-linux.git fdisk: add support for partition resizing Fixes #2555 Signed-off-by: Thomas Weißschuh --- diff --git a/disk-utils/fdisk-menu.c b/disk-utils/fdisk-menu.c index 5cf00026ae..4c6a918934 100644 --- a/disk-utils/fdisk-menu.c +++ b/disk-utils/fdisk-menu.c @@ -111,6 +111,7 @@ static const struct menu menu_generic = { MENU_ENT ('t', N_("change a partition type")), MENU_BENT_E('v', N_("verify the partition table"), FDISK_DISKLABEL_BSD), MENU_ENT ('i', N_("print information about a partition")), + MENU_ENT ('e', N_("resize a partition")), MENU_XENT('d', N_("print the raw data of the first sector from the device")), MENU_XENT('D', N_("print the raw data of the disklabel from the device")), @@ -686,6 +687,9 @@ static int generic_menu_cb(struct fdisk_context **cxt0, rc = ask_for_wipe(cxt, partno); break; } + case 'e': + resize_partition(cxt); + break; case 't': change_partition_type(cxt); break; diff --git a/disk-utils/fdisk.c b/disk-utils/fdisk.c index 7c04cb5ff7..c75a7a63c8 100644 --- a/disk-utils/fdisk.c +++ b/disk-utils/fdisk.c @@ -636,6 +636,101 @@ void toggle_dos_compatibility_flag(struct fdisk_context *cxt) fdisk_reset_alignment(cxt); /* reset the current label */ } +static int strtosize_sectors(const char *str, unsigned long sector_size, + uintmax_t *res) +{ + size_t len = strlen(str); + int insec = 0; + int rc; + + if (!len) + return 0; + + if (str[len - 1] == 'S' || str[len - 1] == 's') { + insec = 1; + str = strndup(str, len - 1); /* strip trailing 's' */ + if (!str) + return -errno; + } + + rc = strtosize(str, res); + if (rc) + return rc; + + if (insec) { + *res *= sector_size; + free((void *)str); + } + + return 0; +} + +void resize_partition(struct fdisk_context *cxt) +{ + struct fdisk_partition *pa = NULL, *npa = NULL, *next = NULL; + char *query = NULL, *response = NULL, *default_size; + struct fdisk_table *tb = NULL; + uint64_t max_size, size, secs; + size_t i; + int rc; + + assert(cxt); + + rc = fdisk_ask_partnum(cxt, &i, FALSE); + if (rc) + goto err; + + rc = fdisk_partition_get_max_size(cxt, i, &max_size); + if (rc) + goto err; + + max_size *= fdisk_get_sector_size(cxt); + + default_size = size_to_human_string(0, max_size); + xasprintf(&query, _("New {K,M,G,T,P} in bytes or S in sectors (default %s)"), + default_size); + free(default_size); + + rc = fdisk_ask_string(cxt, query, &response); + if (rc) + goto err; + + size = max_size; + rc = strtosize_sectors(response, fdisk_get_sector_size(cxt), &size); + if (rc || size > max_size) { + fdisk_warnx(cxt, _("Invalid size")); + goto err; + } + + npa = fdisk_new_partition(); + if (!npa) + goto err; + + secs = size / fdisk_get_sector_size(cxt); + fdisk_partition_size_explicit(npa, 1); + fdisk_partition_set_size(npa, secs); + + rc = fdisk_set_partition(cxt, i, npa); + if (rc) + goto err; + + fdisk_info(cxt, _("Partition %zu has been resized."), i + 1); + +out: + free(query); + free(response); + fdisk_unref_partition(next); + fdisk_unref_partition(pa); + fdisk_unref_partition(npa); + fdisk_unref_table(tb); + return; + +err: + fdisk_warnx(cxt, _("Could not resize partition %zu: %s"), + i + 1, strerror(-rc)); + goto out; +} + void change_partition_type(struct fdisk_context *cxt) { size_t i; diff --git a/disk-utils/fdisk.h b/disk-utils/fdisk.h index e7edc0651e..d4578e0724 100644 --- a/disk-utils/fdisk.h +++ b/disk-utils/fdisk.h @@ -63,4 +63,6 @@ extern void toggle_dos_compatibility_flag(struct fdisk_context *cxt); extern void follow_wipe_mode(struct fdisk_context *cxt); +extern void resize_partition(struct fdisk_context *cxt); + #endif /* UTIL_LINUX_FDISK_H */ diff --git a/tests/expected/fdisk/resize b/tests/expected/fdisk/resize new file mode 100644 index 0000000000..32f9ce2786 --- /dev/null +++ b/tests/expected/fdisk/resize @@ -0,0 +1,75 @@ +Create initial partitions + +---layout---------- +Disk : 10 MiB, 10485760 bytes, 20480 sectors +Units: sectors of 1 * 512 = 512 bytes +Sector size (logical/physical): 512 bytes / 512 bytes +I/O size (minimum/optimal): 512 bytes / bytes +Disklabel type: gpt +Disk identifier: + +Device Start End Sectors Size Type +1 2048 4095 2048 1M Linux filesystem +2 8192 10239 2048 1M Linux filesystem +------------------- + +Grow first to max + +---layout---------- +Disk : 10 MiB, 10485760 bytes, 20480 sectors +Units: sectors of 1 * 512 = 512 bytes +Sector size (logical/physical): 512 bytes / 512 bytes +I/O size (minimum/optimal): 512 bytes / bytes +Disklabel type: gpt +Disk identifier: + +Device Start End Sectors Size Type +1 2048 8191 6144 3M Linux filesystem +2 8192 10239 2048 1M Linux filesystem +------------------- + +Grow second to max + +---layout---------- +Disk : 10 MiB, 10485760 bytes, 20480 sectors +Units: sectors of 1 * 512 = 512 bytes +Sector size (logical/physical): 512 bytes / 512 bytes +I/O size (minimum/optimal): 512 bytes / bytes +Disklabel type: gpt +Disk identifier: + +Device Start End Sectors Size Type +1 2048 8191 6144 3M Linux filesystem +2 8192 20446 12255 6M Linux filesystem +------------------- + +Resize first to 4096 bytes + +---layout---------- +Disk : 10 MiB, 10485760 bytes, 20480 sectors +Units: sectors of 1 * 512 = 512 bytes +Sector size (logical/physical): 512 bytes / 512 bytes +I/O size (minimum/optimal): 512 bytes / bytes +Disklabel type: gpt +Disk identifier: + +Device Start End Sectors Size Type +1 2048 2055 8 4K Linux filesystem +2 8192 20446 12255 6M Linux filesystem +------------------- + +Resize second to 8 sectors + +---layout---------- +Disk : 10 MiB, 10485760 bytes, 20480 sectors +Units: sectors of 1 * 512 = 512 bytes +Sector size (logical/physical): 512 bytes / 512 bytes +I/O size (minimum/optimal): 512 bytes / bytes +Disklabel type: gpt +Disk identifier: + +Device Start End Sectors Size Type +1 2048 2055 8 4K Linux filesystem +2 8192 8199 8 4K Linux filesystem +------------------- + diff --git a/tests/ts/fdisk/resize b/tests/ts/fdisk/resize new file mode 100755 index 0000000000..9536cd7e51 --- /dev/null +++ b/tests/ts/fdisk/resize @@ -0,0 +1,66 @@ +#!/bin/bash +# +# This file is part of util-linux. +# +# Copyright (C) 2023 Thomas Weißschuh +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# + +TS_TOPDIR="${0%/*}/../.." +TS_DESC="resize" + +. "$TS_TOPDIR"/functions.sh +ts_init "$*" + +ts_check_test_command "$TS_CMD_FDISK" + +TEST_IMAGE_NAME=$(ts_image_init 10) + +function print_layout { + echo -ne "\n---layout----------\n" >> "$TS_OUTPUT" + "$TS_CMD_FDISK" -l "${TEST_IMAGE_NAME}" >> "$TS_OUTPUT" 2>> "$TS_ERRLOG" + echo -ne "-------------------\n\n" >> "$TS_OUTPUT" + + ts_fdisk_clean "${TEST_IMAGE_NAME}" +} + +function test_fdisk() { + "$TS_CMD_FDISK" --noauto-pt "${TEST_IMAGE_NAME}" &> /dev/null +} + +ts_log "Create initial partitions" +echo -e "g\nn\n\n\n+1M\nn\n\n8192\n+1M\nw\n" | test_fdisk + +print_layout + +ts_log "Grow first to max" +echo -e "e\n1\n\nw\n" | test_fdisk + +print_layout + +ts_log "Grow second to max" +echo -e "e\n2\n\nw\n" | test_fdisk + +print_layout + +ts_log "Resize first to 4096 bytes" +echo -e "e\n1\n4K\nw\n" | test_fdisk + +print_layout + +ts_log "Resize second to 8 sectors" +echo -e "e\n2\n8S\nw\n" | test_fdisk + +print_layout + +ts_finalize