3 [[ $EUID == 0 ]] ||
exec sudo
"$BASH_SOURCE" "$@"
5 x
="$(readlink -f "$BASH_SOURCE")"; source "${x%/*}/bash-trace"
9 Usage: ${0##*/} [OPTIONS] -- +/-SIZE[g] swap|boot
11 Assuming Ian Kelling's partition scheme and we are currently into one of
12 it's encrypted oses (we it's btrfs filesystem to be mounted), resize
13 swap or boot, expanding or shrinking the root fs and partition to
14 compensate. If it changes the partition tables incorrectly, the
15 originals are stored in /root/backup_partition_table_<device_names>.
17 TODO: only tested on stretch. deactivation of swap on reboot
18 probably needs to be fixed on other oses. Even on stretch,
19 we get 1.5 minutes of waiting for the crypt_dev and normal
22 Warning!!! Backup your data. This script could have bugs in it.
24 -n Dry run. Note, this likely won't be the exact commands,
25 for example, if you are running outside a vm, there will
26 probably be a reboot required in the middle so the kernel
27 can know about partition changes.
28 -r Reboot right away if it's needed.
29 -f Force running on a distro that has not been tested.
30 -h|--help Print help and exit.
32 SIZE is MiB, or if g is specified, GiB.
34 If using multiple devices, SIZE is applied to each device, so total change is
37 Note: Uses GNU getopt options parsing style
46 temp
=$
(getopt
-l help rnfh
"$@") || usage
1
50 -r) reboot_now
=true
; shift ;;
51 -n) dry_run
=true
; shift ;;
52 -f) force
=true
; shift ;;
55 *) echo "$0: Internal error!" ; exit 1 ;;
59 #### begin arg error checking ####
61 if [[ $# != 2 ]]; then
62 echo "$0: error: expected 2 arguments"
66 if [[ $1 != [+-][0-9]* ]]; then
67 echo "$0: error: bad 1st arg: $1"
71 if ! which parted
&>/dev
/null
; then
72 echo "$0: error: install parted"
76 case $2 in swap|boot
) : ;; *) echo "$0: error: bad 2nd arg"; usage
1 ;; esac
78 if ! $force && ! grep -q 'VERSION=.*stretch' /etc
/os-release
; then
79 echo "$0: error: This distro is untested. Only tested version atm is Stretch."
83 #### end arg error checking ####
87 [[ $2 == boot
]] || boot
=false
89 op_size
=$1 # operator plus size
90 if [[ $op_size == *g
]]; then
94 size
=$
(( $size * 1024 ))
100 if [[ $op_size == +* ]]; then
101 op_size_rev
=-$size # rev = reverse
108 ##### end command line parsing ########
114 reboot_script_initialized
=false
116 pmk
() { # partition make
122 # This fails outside a vm, but actually succeeds. also prints this
124 # Error: Partition(s) 2 on /dev/sda have been written, but
125 # we have been unable to inform the kernel of the change, probably
126 # because it/they are in use. As a result, the old partition(s)
127 # will remain in use. You should reboot now before making further
130 if ! p mkpart primary
"$fs_type" \
131 $
((${ptable[start$part]} $start_op)) $
((${ptable[end$part]} $end_op)); then
132 echo "$0: warning: ignoring failure return of mkpart"
140 e
() { echo "+ $@"; "$@"; }
147 while read devid dev
; do
150 # older oses, it points to /dev/dm-x
151 dev
=$
(dmsetup info
$dev |
sed -rn 's/^\s*Name:\s*(\S*)/\1/p')
154 dev
=${dev#/dev/mapper/}
157 echo "$0: error: could not find devicemapper root dev,
158 make sure you are running from a encrypted root this script is resizing"
162 if [[ $dev != crypt_dev_
*-part$rootn ]]; then
163 echo "$0: error: unexpected root device name,
164 make sure you are running from a encrypted root this script is resizing"
167 dev
=${dev#crypt_dev_}
168 dev
=${dev%-part$rootn}
169 devpath
=/dev
/disk
/by-id
/$dev
173 while IFS
=: read id start end psize _
; do
174 [[ $id == [0-9] ]] ||
continue
175 ptable
[start
$id]=start
=${start%%[^0-9]*}
176 ptable
[end
$id]=${end%%[^0-9]*}
177 ptable
[size
$id]=${psize%%[^0-9]*}
178 done < <(parted
-m $devpath unit MiB print
)
179 parted
$devpath unit MiB print |
tee /root
/backup_partition_table_
$dev
180 p
() { e parted
-a optimal
-s -- $devpath unit MiB
"$@"; }
181 unit
=systemd-cryptsetup@crypt_dev_
$dev-part$swapn
182 # note systemctl show can test if a unit exists.
183 if ! e systemctl stop
$unit; then
186 # there is a bug in jessie. this and the .swap unit are
187 # generated from /etc/fstab, and it escapes - to x2d, then doesn't escape it
188 # when looking for the file to use as swap. so, no swap is working on jessie
190 sleep 1 # dunno if this is needed,
191 # but systemd likes to do these kind of things in the background.
193 # These partition comments seems a little verbose now, but I bet they
194 # will be helpfull if I read this in more than a week from now.
195 # <> = deleted partition, () = partition
196 p
rm $swapn # ( root )< swap >( boot )
198 root_resize_cmd
="e btrfs fi resize $devid:${op_size_rev}M /"
199 if $grow; then $root_resize_cmd; fi
201 # < root >< swap >( boot )
202 # ( root ) >< swap >( boot )
204 # < root >< swap >( boot )
205 # ( root >< ) swap >( boot )
207 out
=$
(p
rm $rootn 2>&1)
210 pmk
$rootn "" $op_size_rev
213 grep "but we have been unable to inform the kernel" &>/dev
/null
; then
216 if $needs_reboot; then
217 # note: even if these units don't exist, this will succeed.
218 e systemctl mask dev-mapper-crypt_swap_
$dev$swapn.swap
219 e systemctl mask systemd-cryptsetup@crypt_swap_
$dev$swapn.service
220 e
() { echo "$@" >> /root
/finish-resize
; }
221 if ! $reboot_script_initialized; then
222 reboot_script_initialized
=true
223 rm -rf /root
/finish-resize
224 cat >/root
/finish-resize
<<'EOF'
227 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
229 chmod +x
/root
/finish-resize
232 e systemctl unmask systemd-cryptsetup@crypt_swap_
$dev$swapn.service
233 e systemctl unmask dev-mapper-crypt_swap_
$dev$swapn.swap
239 # non by-id path, to match what btrfs fi show will tell us
240 boot_dev_path
=$
(readlink
-f $devpath-part$bootn)
241 boot_devid
=$
(btrfs
fi show
/boot | \
242 sed -rn "s#^\s*devid\s+(\S+)\s.*$boot_dev_path#\1#p")
245 # shrink boot, move it to a temp file
246 e btrfs
fi resize
$boot_devid:${op_size}M
/boot
248 temp_boot
=/root
/temp_boot_
$dev
249 e
dd bs
=1M
if=$boot_dev_path of
=$temp_boot \
250 count
=$
((${ptable[size$bootn]} $op_size))
255 # ( root ) >< swap >< boot >
256 # ( root )( >< swap ) >< boot >
257 # ( root )( >< swap )( >< boot )
259 # ( root >< ) swap >< boot >
260 # ( root >< )( swap >< ) boot >
261 # ( root >< )( swap >< )( boot )
263 pmk
$swapn $op_size_rev $op_size_rev "linux-swap"
264 pmk
$bootn $op_size_rev ""
267 e
dd bs
=1M
if=$boot_dev_path of
=$boot_dev_path skip
=$size
269 e btrfs
fi resize
$boot_devid:${op_size}M
/boot
271 e
dd bs
=1M
if=$temp_boot of
=$boot_dev_path
275 # if $grow; then ( root )( >< swap )( boot )
276 # else ( root >< )( swap )( boot )
277 pmk
$swapn $op_size_rev "" "linux-swap"
278 e systemctl start systemd-cryptsetup@crypt_swap_
$dev$swapn
280 done < <(btrfs
fi show
/ |
sed -nr 's#^\s*devid\s*(\S+).* path (.*)$#\1 \2#p')
284 e
rm -rf "/root/temp_boot_*"
285 e
rm -f /root
/finish-resize
288 if $needs_reboot; then
289 echo "$0: Reboot, run /root/finish-resize. It's contents:"
290 cat /root
/finish-resize
292 echo "$0: rebooting now"