#!/bin/bash shopt -s extdebug bash-trace() { # shows function args when: shopt -s extdebug local -i argc_index=0 arg frame i start=${1:-1} max_indent=8 indent local source local extdebug=false if [[ $(shopt -p extdebug) == *-s* ]]; then extdebug=true fi for ((frame=0; frame < ${#FUNCNAME[@]}-1; frame++)); do argc=${BASH_ARGC[frame]} argc_index+=$argc ((frame < start)) && continue if (( ${#BASH_SOURCE[@]} > 1 )); then source="${BASH_SOURCE[frame+1]}:${BASH_LINENO[frame]}:" fi indent=$((frame-start+1)) indent=$((indent < max_indent ? indent : max_indent)) printf "%${indent}s↳%sin \`%s" '' "$source" "${FUNCNAME[frame]}" if $extdebug; then for ((i=argc_index-1; i >= argc_index-argc; i--)); do printf " %s" "${BASH_ARGV[i]}" done fi echo \' done } errcatch() { set -E; shopt -s extdebug _err-trap() { err=$? exec >&2 echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}:in \`$BASH_COMMAND' returned $err" bash-trace 2 echo "$0: exiting with code $err" exit $err } trap _err-trap ERR set -o pipefail } errcatch [[ $EUID == 0 ]] || sudo "$BASH_SOURCE" "$@" usage() { cat </dev/null; then echo "$0: error: install parted" exit 1 fi case $2 in swap|boot) : ;; *) echo "$0: error: bad 2nd arg"; usage 1 ;; esac #### end arg error checking #### boot=true [[ $2 == boot ]] || boot=false #size=${x#[+-]} op_size=$1 # operator plus size [[ $op_size != *g ]] || op_size=$(( ${op_size%g} / 1024 )) size=${op_size#[+-]} if [[ $op_size == +* ]]; then op_size_rev=-$size # rev = reverse grow=true else op_size_rev=+$size grow=false fi ##### end command line parsing ######## rootn=1 swapn=2 bootn=3 needs_reboot=false pmk() { part=$1 start_op=$2 end_op=$3 read start end < <(echo ${ptable[$part]}) p mkpart primary "$4" $((start $start_op)) $((end $end_op)) } swapoff -a while read devid dev; do if $dry_run; then e() { echo "+ $@"; } else e() { echo "+ $@"; "$@"; } fi ptable=() while IFS=: read id start end _; do [[ $id == [0-9] ]] || continue end=${end%MiB} start=${start%MiB} start=${start%.*} # small enough number that parted uses a decimal ptable[$id]="$start $end" done < <(parted -m /dev/$dev unit MiB print) parted /dev/$dev unit MiB print | tee /root/backup_partition p() { e parted -a optimal -s -- /dev/$dev unit MiB "$@"; } e systemctl stop systemd-cryptsetup@crypt_swap_$dev$swapn sleep 1 # These partition comments seems a little verbose now, but I bet they # will be helpfull if I read this in more than a week from now. # <> = deleted partition, () = partition p rm $swapn # ( root )< swap >( boot ) root_resize_cmd="e btrfs fi resize $devid:$op_size_rev /" if $grow; then $root_resize_cmd; fi # if $grow; then # < root >< swap >( boot ) # ( root ) >< swap >( boot ) # else # < root >< swap >( boot ) # ( root >< ) swap >( boot ) out=$(p rm $rootn 2>&1) echo "$out" pmk $rootn "" $op_size_rev if ! $grow; then if echo "$out" | \ grep "but we have been unable to inform the kernel" &>/dev/null; then e systemctl mask dev-mapper-crypt_swap_$dev$swapn.swap e systemctl mask systemd-cryptsetup@crypt_swap_$dev$swapn.service if ! $needs_reboot; then needs_reboot=true echo "$0: reboot and run /root/finish-resize to finish. The following commands are what will be executed:" rm -rf /root/finish-resize cat >/root/finish-resize <<'EOF' #!/bin/bash -x set -eE -o pipefail trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?"' ERR EOF chmod +x /root/finish-resize fi e() { echo "$@" | tee -a /root/finish-resize; } e systemctl unmask systemd-cryptsetup@crypt_swap_$dev$swapn.service e systemctl unmask dev-mapper-crypt_swap_$dev$swapn.swap # todo, disable swap for the next boot. currently have to wait # 1:30 for it to fail. fi $root_resize_cmd fi if $boot; then boot_devid=$(btrfs fi show /boot | \ sed -rn "s#^\s*devid\s+(\S+)\s.*$dev[0-9]#\1#p") if ! $grow; then # shrink boot, move it to a temp file e btrfs fi resize $boot_devid:$op_size /boot temp_boot=/root/temp_boot_dd e dd bs=1M if=/dev/$dev$bootn of=$temp_boot count=$size fi # if $grow; then # ( root ) >< swap >< boot > # ( root )( >< swap ) >< boot > # ( root )( >< swap )( >< boot ) # else # ( root >< ) swap >< boot > # ( root >< )( swap >< ) boot > # ( root >< )( swap >< )( boot ) e umount /boot p rm $bootn pmk $swapn $op_size_rev $op_size_rev "linux-swap" pmk $bootn $op_size_rev "" if $grow; then e dd bs=1M if=/dev/$dev$bootn of=/dev/$dev$bootn skip=$size e btrfs fi resize $boot_devid:$op_size /boot else e dd bs=1M if=$temp_boot of=/dev/$dev$bootn fi e mount /boot else # if $grow; then ( root )( >< swap )( boot ) # else ( root >< )( swap )( boot ) pmk $swapn $op_size_rev "" "linux-swap" fi done < <(btrfs fi show / | \ sed -nr 's#^\s*devid\s*(\S+)\s.*_([^_ ]+)[0-9]\s*$#\1 \2#p') if $boot; then e rm -rf $temp_boot e rm /root/finish-resize fi if $needs_reboot; then echo "$0: reminder, reboot then /root/finish-resize" fi #for dev in ${devs[@]}; do