diff options
Diffstat (limited to 'draft/other-tools/clonezilla/ocs-expand-gpt-pt')
-rwxr-xr-x | draft/other-tools/clonezilla/ocs-expand-gpt-pt | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/draft/other-tools/clonezilla/ocs-expand-gpt-pt b/draft/other-tools/clonezilla/ocs-expand-gpt-pt new file mode 100755 index 0000000..191bc06 --- /dev/null +++ b/draft/other-tools/clonezilla/ocs-expand-gpt-pt @@ -0,0 +1,386 @@ +#!/bin/bash +# Author: Steven Shiau <steven _at_ nchc org tw> +# License: GPL +# A script to expand the GPT partition table by disk size ratio. +# ///NOTE/// This program only works for GPT partition table, not for MBR. + +# Load DRBL setting and functions +DRBL_SCRIPT_PATH="${DRBL_SCRIPT_PATH:-/usr/share/drbl}" + +. $DRBL_SCRIPT_PATH/sbin/drbl-conf-functions +. /etc/drbl/drbl-ocs.conf +. $DRBL_SCRIPT_PATH/sbin/ocs-functions + +# Settings +# Flag to check target disk size before creating partition table +chk_tgt_disk_size_bf_mk_pt="yes" + +# +cmd_name="$(basename $0)" +# +USAGE() { + echo "$cmd_name: To create a proportional MBR partition table (not GPT) in a disk based on a existing partition table (sfdisk format)" + echo "Usage:" + echo " $cmd_name [OPTION] PARTITION_TABLE_FILE TARGET_DEVICE" + echo + echo "OPTION:" + echo " -b, --batch Run $cmd_name in batch mode, i.e. without any prompt or wait to press enter. VERY DANGEROUS!" + echo "$cmd_name will honor experimental variable EXTRA_SFDISK_OPT and use it as the option for sfdisk." + echo " -icds, --ignore-chk-dsk-size-pt Skip checking destination disk size before creating the partition table on it. By default it will be checked and if the size is smaller than the source disk, quit." + echo "Example:" + echo " To create a proportional partition table on disk /dev/sda based on /home/partimag/IMAGE/sda-pt.sf, use:" + echo "$cmd_name /home/partimag/IMAGE/sda-pt.sf /dev/sda" +} + +# Parse command-line options +while [ $# -gt 0 ]; do + case "$1" in + -b|--batch) + batch_mode="yes" + shift;; + -icds|--ignore-chk-dsk-size-pt) + chk_tgt_disk_size_bf_mk_pt="no" + shift;; + -*) echo "${0}: ${1}: invalid option" >&2 + USAGE >& 2 + exit 2 ;; + *) break ;; + esac +done + +# Original sfdisk format file +orig_sf=$1 # orig_sf is like: /home/partimag/IMAGE/sda-pt.sf +target_disk=$2 # target_disk is like: /dev/sda + +# +ask_and_load_lang_set $specified_lang + +# +if [ -z "$orig_sf" ]; then + [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE + echo "No source partition table file was assigned!" + [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL + USAGE + echo "$msg_program_stop!" + exit 1 +fi +if [ ! -f "$orig_sf" ]; then + [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE + echo "Source partition table file \"$orig_sf\" was _NOT_ found" + [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL + echo "$msg_program_stop!" + exit 1 +fi + +if [ -z "$target_disk" ]; then + [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE + echo "No target disk was assigned!" + [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL + echo "$msg_program_stop!" + USAGE + exit 1 +fi + +# +if [ "$batch_mode" != "yes" ]; then + [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING + echo "This program will create a partition table in $target_disk" + echo "ALL THE DATA IN THE TARGET DEVICE WILL BE ERASED!!!" + [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL + echo -n "$msg_are_u_sure_u_want_to_continue ? (y/N) " + read continue_confirm_ans + case "$continue_confirm_ans" in + y|Y|[yY][eE][sS]) + echo "$msg_ok_let_do_it!" + ;; + *) + echo "$msg_program_stop!" + exit 1 + esac +fi + +# Check if GPT disk, if yes, exit +if `is_mbr_partitition_table_disk $target_disk`; then + [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE + echo "Disk $target_disk is MBR format. This program only works for GPT format." + [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL + echo "$msg_program_stop!" + exit 1 +fi + +# Check if the format of sfdisk is created by sfdisk >= 2.26 +if [ -z "$(LC_ALL=C grep -E "^label: gpt" $orig_sf)" ]; then + [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE + echo "Partition table file \"$orig_sf\" does not contain GPT info." + echo "Make sure it's GPT format and outputted by sfdisk >= 2.26." + [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL + echo "$msg_program_stop!" + exit 1 +fi + +# No size info in sda-pt.sf, we have to use sda-pt.parted. +orig_parted_tab="${orig_sf/.sf/.parted}" +orig_parted_dir="$(dirname $orig_sf)" +if [ ! -e "$orig_parted_tab" ]; then + [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE + echo "$orig_parted_tab was not found! It is required so that we know the original disk size! Maybe your Clonezilla image is too old ? You can try to create such an file in your source machine by: \"parted -s /dev/$SOURCE_DEV unit s print > $orig_parted_tab\" (Replace $SOURCE_DEV with your device name)" + [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL + echo "$msg_program_stop!" + exit 1 +fi + +# parted output format example: +# Disk /dev/sda: 16777215s +# Sector size (logical/physical): 512B/512B +# Partition Table: msdos +# +# Number Start End Size Type File system Flags +# 1 63s 586844s 586782s primary boot +# 2 586845s 978074s 391230s primary +# 3 978075s 1955204s 977130s primary +# 4 1955205s 16776584s 14821380s extended +# 5 1955268s 2151764s 196497s logical +# 6 2151828s 2542994s 391167s logical +# 7 2543058s 16776584s 14233527s logical + +ori_disk_size="$(LC_ALL=C grep -E "^Disk /dev" $orig_parted_tab | awk -F":" '{print $2}' | sed -e "s/s$//g")" +# If nothing in target disk, parted will show like this: +# sudo parted -s /dev/sda unit s print +# Error: Unable to open /dev/sda - unrecognised disk label. + +if ! LC_ALL=C parted -s $target_disk unit s print &>/dev/null; then + # Try to create a partition table so that we can read the size via parted -s $dev unit s print + echo "No initial GPT table on disk $target_disk. Create one now by:" | tee --append $OCS_LOGFILE + echo "parted -s $target_disk mklabel gpt" | tee --append $OCS_LOGFILE + LC_ALL=C parted -s $target_disk mklabel gpt | tee --append $OCS_LOGFILE +fi +tgt_disk_size="$(LC_ALL=C parted -s $target_disk unit s print | grep -E "^Disk /dev" | awk -F":" '{print $2}' | sed -e "s/s$//g")" + +# +ratio=$(echo "scale=10; $tgt_disk_size / $ori_disk_size" | bc -l) || exit 1 +echo "The ratio for target disk size to original disk size is $ratio." +if [ "$chk_tgt_disk_size_bf_mk_pt" = "yes" ]; then + if [ "$(LC_ALL=C echo "$ratio < 1" | bc -l)" = "1" ]; then + [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE + echo "The target disk (size=$tgt_disk_size sectors) is smaller than the source disk (size=$ori_disk_size sectors)!" + echo "Clonezilla won't be able to restore a partition image to smaller partition!" + [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL + echo "Program terminated!" + exit 1 + fi +fi + +new_sf="$(mktemp /tmp/new_sf.XXXXXX)" || exit 1 +new_sf_tmp="$(mktemp /tmp/new_sf_tmp.XXXXXX)" || exit 1 +# Increase. Example for sfdisk format: +# ===================================== +# label: gpt +# label-id: ADC40CC4-77D7-4858-8F0E-8BC2447052AE +# device: /dev/sda +# unit: sectors +# first-lba: 34 +# last-lba: 125829086 +# +# /dev/sda1 : start= 2048, size= 409600, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=E8D785ED-A65F-4EA1-ADF0-CC61E75677EB +# /dev/sda2 : start= 411648, size= 1024000, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=AB72A495-4141-4500-AE48-B7AC492160B4 +# /dev/sda3 : start= 1435648, size= 40505344, type=E6D6D379-F507-44C2-A23C-238F2A3DF928, uuid=C7A87C41-72FD-41DB-9B10-DF3568A4089D +# ===================================== +# label: gpt +# label-id: D4165706-2FAD-491E-82CA-7866982D196B +# device: /dev/sda +# unit: sectors +# first-lba: 34 +# last-lba: 125829086 +# +# /dev/sda1 : start= 2048, size= 614400, type=DE94BBA4-06D1-4D40-A16A-BFD50179D6AC, uuid=0802BFF4-2549-4CD4-A1CA-93D54AEE26F0, name="Basic data partition", attrs="RequiredPartiton GUID:63" +# /dev/sda2 : start= 616448, size= 202752, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=C9C164D5-5E0F-476D-B2EA-A4D818A266CF, name="EFI system partition", attrs="GUID:63" +# /dev/sda3 : start= 819200, size= 262144, type=E3C9E316-0B5C-4DB8-817D-F92DF00215AE, uuid=15D5A869-5C6E-4F2C-B234-7D6B91B58555, name="Microsoft reserved partition", attrs="GUID:63" +# /dev/sda4 : start= 1081344, size= 124745728, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=E53DEA7E-2639-4AE9-9DFD-DDD2406C3EC0, name="Basic data partition" +# ===================================== + +# We only need those required info +grep -E "^/dev" $orig_sf > $new_sf_tmp +# start=291579750 or size=291563622 is not a good format for us to parse, we need a space between "=" and "number" +# i.e. +# No good: +# /dev/sda1 : start= 63, size=291563622, Id= 7, bootable +# /dev/sda2 : start=291579750, size= 20980890, Id= 7 +# /dev/sda3 : start= 0, size= 0, Id= 0 +# /dev/sda4 : start= 0, size= 0, Id= 0 +# +# Good: +# /dev/sda1 : start= 63, size= 291563622, Id= 7, bootable +# /dev/sda2 : start= 291579750, size= 20980890, Id= 7 +# /dev/sda3 : start= 0, size= 0, Id= 0 +# /dev/sda4 : start= 0, size= 0, Id= 0 + +# //NOTE// For partitions number >=10, it looks like: +# label: gpt +# label-id: 56C0DC13-942C-493F-B141-F9903658453B +# device: /dev/sda +# unit: sectors +# first-lba: 34 +# last-lba: 125829086 +# +# /dev/sda1 : start= 2048, size= 2097152, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=4F5FF221-D350-4CE7-BADA-20022DA453CC, name="Linux filesystem" +# /dev/sda2 : start= 2099200, size= 2097152, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=975A9722-E2ED-46CC-B0E1-995095A6BB66, name="Linux filesystem" +# /dev/sda3 : start= 4196352, size= 2097152, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=A27C9E16-70B1-48D0-9A3F-915AFBA8FCC7, name="Linux filesystem" +# /dev/sda4 : start= 6293504, size= 2097152, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=3E134963-5B14-49C1-9F83-9BAF9C5F61C9, name="Linux filesystem" +# /dev/sda5 : start= 8390656, size= 2097152, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=FB1FB744-E6DC-48FA-9891-256AD0F3CF7C, name="Linux filesystem" +# /dev/sda6 : start= 10487808, size= 2097152, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=BB764A64-35BF-4415-A8D6-84642339FB3F, name="Linux filesystem" +# /dev/sda7 : start= 12584960, size= 2097152, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=B0D77252-85AB-4AFB-8866-38C21605DB7B, name="Linux filesystem" +# /dev/sda8 : start= 14682112, size= 2097152, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=79E8897A-B821-4C5D-A481-5F8628C57D2E, name="Linux filesystem" +# /dev/sda9 : start= 16779264, size= 2097152, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=2CA8A44E-9A2B-475A-BFC8-1E6295847F6A, name="Linux filesystem" +# /dev/sda10 : start= 18876416, size= 2097152, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=B454EC36-562F-4844-B8D9-28C5C1C111C9, name="Linux filesystem" +# /dev/sda11 : start= 20973568, size= 104855519, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=FA55D210-62EE-4948-A853-FDD4360CDCB5, name="Linux filesystem" + +# Therefore we force to put a space no matter there is already space or not +perl -pi -e "s/start=/start= /g" $new_sf_tmp +perl -pi -e "s/size=/size= /g" $new_sf_tmp +# Remove ":" in the temp file, since it's only for parsing, won't be used for sfdisk /dev/... < $new_sf_tmp ... +perl -pi -e "s/://g" $new_sf_tmp + +# Get the line number of "last-lba:" +header_line="$(LC_ALL=C grep -E -n "^last-lba:" $orig_sf | awk -F":" '{print $1}')" +if [ -z "$header_line" ]; then + [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE + echo "Failed to find the line \"last-lba:\" in $orig_sf!" + [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL + echo "$msg_program_stop!" + exit 1 +fi +# We do not output the line "last-lba:" in the generated line. Otherwise we have to calculate the last-lba number. +LC_ALL=C head -n "$((header_line -1))" $orig_sf > $new_sf +echo "" >> $new_sf +start_no_keep="" +size_no_keep="" +append_to_next="0" +# Initial gap for the 1st partition. After this, it should be 0. +logical_part_gap="2" +while read dev start start_no size size_no type uuid name attrs; do + pt_no="$(LC_ALL=C get_part_number $dev | sed -r -e "s|^[^[:digit:]]*||g")" + if `is_partition $dev` ; then + [ -z "$start_no_keep" ] && start_no_keep=${start_no/,/} # The 1st one + [ -z "$size_no_keep" ] && size_no_keep=0 + if [ "${size_no/,/}" -eq 0 ]; then + start_no=0 + size_no=0 + else + # If we found the partition is EFI System partition, keep the size. + # EFI System partition: C12A7328-F81F-11D2-BA4B-00A0C93EC93B, + # Ref: https://en.wikipedia.org/wiki/GUID_Partition_Table + expand="true" + if [ -n "$(echo $type | grep -iE "type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B")" ]; then + expand="false" + [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING + echo "\"EFI System partition\" found. Not to expand this partition." + [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL + fi + # If we found the partition is MS Windows "system reserved partition", keep the size. + # Microsoft Reserved Partition (MSR): E3C9E316-0B5C-4DB8-817D-F92DF00215AE + # Ref: https://en.wikipedia.org/wiki/GUID_Partition_Table + if [ -n "$(echo $type | grep -iE "type=E3C9E316-0B5C-4DB8-817D-F92DF00215AE")" ]; then + expand="false" + [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING + echo "\"Microsoft Reserved Partition (MSR)\" found. Not to expand this partition." + [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL + fi + # If we found the partition is MS Windows "system reserved partition", keep the size. + # Windows Recovery Environment DE94BBA4-06D1-4D40-A16A-BFD50179D6AC + # Ref: https://en.wikipedia.org/wiki/GUID_Partition_Table + if [ -n "$(echo $type | grep -iE "type=DE94BBA4-06D1-4D40-A16A-BFD50179D6AC")" ]; then + expand="false" + [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING + echo "\"Windows Recovery Environment\" found. Not to expand this partition." + [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL + fi + # For newer Clonezilla (>=2.4.36-1drbl), a tag file (sda1.info) might exist + if [ -e "$orig_parted_dir/$(to_filename ${dev}).info" ]; then + . $orig_parted_dir/$(to_filename ${dev}).info + if [ "$PARTITION_TYPE" = "Win_boot_reserved" ]; then + expand="false" + fi + fi + # For Linux Swap partition + if [ -n "$(echo $type | grep -iE "type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F")" ]; then + [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING + echo "Linux swap partition \"$type\" found. Not to expand this partition." + [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL + expand="false" + fi + + if [ "$expand" = "true" ]; then + start_no="$(LC_ALL=C printf "%.0f" "$(echo "($start_no_keep + $size_no_keep)" | bc -l)")" + size_no="$(LC_ALL=C printf "%.0f" "$(echo "${size_no/,/}*$ratio + $append_to_next" | bc -l)")" + # Reset the space append_to_next. + append_to_next="0" + else + start_no="$(LC_ALL=C printf "%.0f" "$(echo "($start_no_keep + $size_no_keep)" | bc -l)")" + size_no="${size_no/,/}" + # Since we do not expand this "system reserved partition" or "swap partition", + # we append the space to the next partition. + # It's possible that there are more than one partition which will be + # kept as original size, e.g. + # Number Start End Size File system Name Flags + # 1 1049kB 106MB 105MB EFI system partition boot, esp + # 2 106MB 240MB 134MB Microsoft reserved partition msftres + # 3 240MB 128GB 128GB Basic data partition msftdata + # In the above, partition 1 and 2 will not be expanded. Therefore we + # might need to add the previous $append_to_next + append_to_next="$(LC_ALL=C printf "%.0f" "$(echo "$append_to_next + ${size_no}*$ratio - ${size_no}" | bc -l)")" + fi + fi + if [ "$size_no" -lt 0 ]; then + # append_to_next might be nagtive when "-icds" is enabled and ration is < 1, therefore + # we have to check the size_no. + [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE + echo "The calculated size of $dev is < 0!" + echo "Unable to create a smaller partitions layout." + [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL + echo "$msg_program_stop!" + exit 1 + fi + echo $dev : $start $start_no, $size $size_no, $type $uuid $name $attrs >> $new_sf + [ "$start_no" -ne 0 ] && start_no_keep="${start_no/,/}" + [ "$size_no" -ne 0 ] && size_no_keep="${size_no/,/}" + fi +done < $new_sf_tmp + +echo "The partition table to write in $target_disk:" +echo "*****************************************" +cat $new_sf +echo "*****************************************" + +# EXTRA_SFDISK_OPT is environment variable +# If not --force, we force to append it since by default if sfdisk find some CHS it does not like, it won't do it without --force +if [ -z "$(echo $EXTRA_SFDISK_OPT | grep -Ew -- "--force")" ]; then + EXTRA_SFDISK_OPT="$EXTRA_SFDISK_OPT --force" +fi +echo "Running: sfdisk $EXTRA_SFDISK_OPT $target_disk < $new_sf" +LC_ALL=C sfdisk $EXTRA_SFDISK_OPT $target_disk < $new_sf +echo "Partition table was created by: sfdisk $EXTRA_SFDISK_OPT $target_disk < $new_sf" + +# Use parted to fill the last partitition to the end of disk because +# there might be some resudial in the calculation. +# Thanks to Conan for this suggestion. +# Ref: https://sourceforge.net/p/clonezilla/discussion/ +# Clonezilla_live/thread/c5e92d87/?limit=25#080c +if [ -n "$(LC_ALL=C parted -h | grep -w resizepart)" ]; then + # Find the last partition number. + # Firstly we get the line number for "Number Start End Size + # File system Name Flags" + line_after="$(LC_ALL=C parted -s $target_disk print | \ + grep -n -Ew "^Number[[:space:]]+Start[[:space:]]+End.*" | \ + awk -F":" '{print $1}')" + line_after="$((line_after +1))" + last_part_no="$(LC_ALL=C parted -s $target_disk print | \ + tail -n +${line_after} | awk -F" " '{print $1}' | sort -V | tail -n 1)" + if [ -n "$last_part_no" ]; then + echo "Trying to extend the last partition to the end of disk by:" + echo "parted -s $target_disk resizepart $last_part_no 100%" + LC_ALL=C parted -s $target_disk resizepart $last_part_no 100% + fi +fi + +[ -e "$new_sf" ] && rm -f $new_sf +[ -e "$new_sf_tmp" ] && rm -f $new_sf_tmp |