]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
fdisk: add support for partition resizing
authorThomas Weißschuh <thomas@t-8ch.de>
Sun, 19 Nov 2023 16:20:55 +0000 (17:20 +0100)
committerThomas Weißschuh <thomas@t-8ch.de>
Fri, 8 Dec 2023 17:20:03 +0000 (18:20 +0100)
Fixes #2555
Signed-off-by: Thomas Weißschuh <thomas@t-8ch.de>
disk-utils/fdisk-menu.c
disk-utils/fdisk.c
disk-utils/fdisk.h
tests/expected/fdisk/resize [new file with mode: 0644]
tests/ts/fdisk/resize [new file with mode: 0755]

index 5cf00026ae377b5d8a2e0d6d16b9f2ea5073c09d..4c6a918934964a4910c9d22e80b9366fff6e3cd6 100644 (file)
@@ -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;
index 7c04cb5ff729e168f84f2e27fb4c3bdb2c9163de..c75a7a63c84bbeb71ab2c7c6e93147813d008086 100644 (file)
@@ -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 <size>{K,M,G,T,P} in bytes or <size>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;
index e7edc0651e708d0f8009567874a9e31816a79c0a..d4578e07249e6e8381beae14b9abc06a4fdc3d66 100644 (file)
@@ -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 (file)
index 0000000..32f9ce2
--- /dev/null
@@ -0,0 +1,75 @@
+Create initial partitions
+
+---layout----------
+Disk <removed>: 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 / <removed> bytes
+Disklabel type: gpt
+Disk identifier: <removed>
+
+Device             Start   End Sectors Size Type
+<removed>1  2048  4095    2048   1M Linux filesystem
+<removed>2  8192 10239    2048   1M Linux filesystem
+-------------------
+
+Grow first to max
+
+---layout----------
+Disk <removed>: 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 / <removed> bytes
+Disklabel type: gpt
+Disk identifier: <removed>
+
+Device             Start   End Sectors Size Type
+<removed>1  2048  8191    6144   3M Linux filesystem
+<removed>2  8192 10239    2048   1M Linux filesystem
+-------------------
+
+Grow second to max
+
+---layout----------
+Disk <removed>: 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 / <removed> bytes
+Disklabel type: gpt
+Disk identifier: <removed>
+
+Device             Start   End Sectors Size Type
+<removed>1  2048  8191    6144   3M Linux filesystem
+<removed>2  8192 20446   12255   6M Linux filesystem
+-------------------
+
+Resize first to 4096 bytes
+
+---layout----------
+Disk <removed>: 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 / <removed> bytes
+Disklabel type: gpt
+Disk identifier: <removed>
+
+Device             Start   End Sectors Size Type
+<removed>1  2048  2055       8   4K Linux filesystem
+<removed>2  8192 20446   12255   6M Linux filesystem
+-------------------
+
+Resize second to 8 sectors
+
+---layout----------
+Disk <removed>: 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 / <removed> bytes
+Disklabel type: gpt
+Disk identifier: <removed>
+
+Device             Start   End Sectors Size Type
+<removed>1  2048  2055       8   4K Linux filesystem
+<removed>2  8192  8199       8   4K Linux filesystem
+-------------------
+
diff --git a/tests/ts/fdisk/resize b/tests/ts/fdisk/resize
new file mode 100755 (executable)
index 0000000..9536cd7
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/bash
+#
+# This file is part of util-linux.
+#
+# Copyright (C) 2023 Thomas Weißschuh <thomas@t-8ch.de>
+#
+# 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