]> sourceware.org Git - lvm2.git/blame - scripts/fsadm.sh
metadata: use lv_hash in segment-specific metadata parsing
[lvm2.git] / scripts / fsadm.sh
CommitLineData
75153387 1#!/bin/bash
f29e7ac5 2#
51a53271 3# Copyright (C) 2007-2020 Red Hat, Inc. All rights reserved.
f29e7ac5
AK
4#
5# This file is part of LVM2.
6#
7# This copyrighted material is made available to anyone wishing to use,
8# modify, copy, or redistribute it subject to the terms and conditions
9# of the GNU General Public License v.2.
10#
11# You should have received a copy of the GNU General Public License
12# along with this program; if not, write to the Free Software Foundation,
fcbef05a 13# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
f29e7ac5 14#
50c41b09 15# Author: Zdenek Kabelac <zkabelac at redhat.com>
f29e7ac5
AK
16#
17# Script for resizing devices (usable for LVM resize)
18#
19# Needed utilities:
30293baa 20# mount, umount, grep, readlink, blockdev, blkid, fsck, xfs_check, cryptsetup
f29e7ac5 21#
cd96532e 22# ext2/ext3/ext4: resize2fs, tune2fs
f29e7ac5
AK
23# reiserfs: resize_reiserfs, reiserfstune
24# xfs: xfs_growfs, xfs_info
25#
4886fa21
ZK
26# Return values:
27# 0 success
28# 1 error
29# 2 break detected
30# 3 unsupported online filesystem check for given mounted fs
f29e7ac5 31
8c2779ba
ZK
32set -euE -o pipefail
33
e5e957e3 34TOOL="fsadm"
f29e7ac5 35
53c09bce 36_SAVEPATH=$PATH
b68235c5 37PATH="/sbin:/usr/sbin:/bin:/usr/sbin:$PATH"
f29e7ac5
AK
38
39# utilities
e5e957e3
ZK
40TUNE_EXT="tune2fs"
41RESIZE_EXT="resize2fs"
42TUNE_REISER="reiserfstune"
43RESIZE_REISER="resize_reiserfs"
44TUNE_XFS="xfs_info"
45RESIZE_XFS="xfs_growfs"
46
47MOUNT="mount"
48UMOUNT="umount"
49MKDIR="mkdir"
50RMDIR="rmdir"
51BLOCKDEV="blockdev"
52BLKID="blkid"
53DATE="date"
54GREP="grep"
55READLINK="readlink"
9ad2ba2a 56READLINK_E="-e"
e5e957e3
ZK
57FSCK="fsck"
58XFS_CHECK="xfs_check"
59336a2a 59# XFS_REPAIR -n is used when XFS_CHECK is not found
e5e957e3
ZK
60XFS_REPAIR="xfs_repair"
61CRYPTSETUP="cryptsetup"
f29e7ac5 62
33048414 63# user may override lvm location by setting LVM_BINARY
0d9ed7ad 64LVM=${LVM_BINARY:-lvm}
17dd04ca 65
8c2779ba 66YES="${_FSADM_YES-}"
f29e7ac5 67DRY=0
17dd04ca 68VERB=
f29e7ac5 69FORCE=
a9382908 70EXTOFF=${_FSADM_EXTOFF:-0}
17dd04ca 71DO_LVRESIZE=0
e5e957e3
ZK
72FSTYPE="unknown"
73VOLUME="unknown"
f29e7ac5 74TEMPDIR="${TMPDIR:-/tmp}/${TOOL}_${RANDOM}$$/m"
8f8c5580 75DM_DEV_DIR="${DM_DEV_DIR:-/dev}"
f29e7ac5
AK
76BLOCKSIZE=
77BLOCKCOUNT=
78MOUNTPOINT=
79MOUNTED=
80REMOUNT=
9e04e048
ZK
81PROCDIR="/proc"
82PROCMOUNTS="$PROCDIR/mounts"
83PROCSELFMOUNTINFO="$PROCDIR/self/mountinfo"
8f8c5580 84NULL="$DM_DEV_DIR/null"
f29e7ac5
AK
85
86IFS_OLD=$IFS
33048414
ZK
87# without bash $'\n'
88NL='
89'
f29e7ac5
AK
90
91tool_usage() {
d7b5bfc2
AK
92 echo "${TOOL}: Utility to resize or check the filesystem on a device"
93 echo
4b1cadbd 94 echo " ${TOOL} [options] check <device>"
d7b5bfc2
AK
95 echo " - Check the filesystem on device using fsck"
96 echo
4b1cadbd 97 echo " ${TOOL} [options] resize <device> [<new_size>[BKMGTPE]]"
d7b5bfc2
AK
98 echo " - Change the size of the filesystem on device to new_size"
99 echo
100 echo " Options:"
101 echo " -h | --help Show this help message"
102 echo " -v | --verbose Be verbose"
cd96532e 103 echo " -e | --ext-offline unmount filesystem before ext2/ext3/ext4 resize"
d7b5bfc2
AK
104 echo " -f | --force Bypass sanity checks"
105 echo " -n | --dry-run Print commands without running them"
17dd04ca 106 echo " -l | --lvresize Resize given device (if it is LVM device)"
30293baa 107 echo " -c | --cryptresize Resize given crypt device"
d7b5bfc2
AK
108 echo " -y | --yes Answer \"yes\" at any prompts"
109 echo
110 echo " new_size - Absolute number of filesystem blocks to be in the filesystem,"
111 echo " or an absolute size using a suffix (in powers of 1024)."
112 echo " If new_size is not supplied, the whole device is used."
113
f29e7ac5
AK
114 exit
115}
116
117verbose() {
95ca7cfd 118 test -z "$VERB" || echo "$TOOL:" "$@"
f29e7ac5
AK
119}
120
9e04e048 121# Support multi-line error messages
f29e7ac5 122error() {
9e04e048
ZK
123 for i in "$@" ; do
124 echo "$TOOL: $i" >&2
125 done
f29e7ac5
AK
126 cleanup 1
127}
128
129dry() {
50c41b09 130 if [ "$DRY" -ne 0 ]; then
afded3e5 131 verbose "Dry execution" "$@"
50c41b09
ZK
132 return 0
133 fi
afded3e5 134 verbose "Executing" "$@"
51a53271
ZK
135 $@
136}
137
39b7d1ba 138# Accept as success also return code 1 with fsck
51a53271
ZK
139accept_0_1() {
140 $@
141 local ret="$?"
142 test "$ret" -eq 1 || return "$ret"
143 # Filesystem was corrected
f29e7ac5
AK
144}
145
146cleanup() {
147 trap '' 2
148 # reset MOUNTPOINT - avoid recursion
149 test "$MOUNTPOINT" = "$TEMPDIR" && MOUNTPOINT="" temp_umount
150 if [ -n "$REMOUNT" ]; then
151 verbose "Remounting unmounted filesystem back"
d2010960 152 dry "$MOUNT" "$VOLUME" "$MOUNTED"
f29e7ac5
AK
153 fi
154 IFS=$IFS_OLD
155 trap 2
17dd04ca 156
4886fa21
ZK
157 test "$1" -eq 2 && verbose "Break detected"
158
fd867543
ZK
159 if [ "$DO_LVRESIZE" -eq 2 ]; then
160 # start LVRESIZE with the filesystem modification flag
161 # and allow recursive call of fsadm
685940c0 162 _FSADM_YES=$YES
a9382908
ZK
163 _FSADM_EXTOFF=$EXTOFF
164 export _FSADM_YES _FSADM_EXTOFF
fd867543 165 unset FSADM_RUNNING
646e3280 166 test -n "${LVM_BINARY-}" && PATH=$_SAVEPATH
264827cb 167 dry exec "$LVM" lvresize $VERB $FORCE $YES --fs resize_fsadm -L"${NEWSIZE_ORIG}b" "$VOLUME_ORIG"
fd867543 168 fi
53c09bce 169
829fe014 170 # error exit status for break
b68235c5 171 exit "${1:-1}"
f29e7ac5
AK
172}
173
50c41b09
ZK
174# convert parameter from Exa/Peta/Tera/Giga/Mega/Kilo/Bytes and blocks
175# (2^(60/50/40/30/20/10/0))
f29e7ac5
AK
176decode_size() {
177 case "$1" in
50c41b09
ZK
178 *[eE]) NEWSIZE=$(( ${1%[eE]} * 1152921504606846976 )) ;;
179 *[pP]) NEWSIZE=$(( ${1%[pP]} * 1125899906842624 )) ;;
f29e7ac5
AK
180 *[tT]) NEWSIZE=$(( ${1%[tT]} * 1099511627776 )) ;;
181 *[gG]) NEWSIZE=$(( ${1%[gG]} * 1073741824 )) ;;
182 *[mM]) NEWSIZE=$(( ${1%[mM]} * 1048576 )) ;;
183 *[kK]) NEWSIZE=$(( ${1%[kK]} * 1024 )) ;;
184 *[bB]) NEWSIZE=${1%[bB]} ;;
185 *) NEWSIZE=$(( $1 * $2 )) ;;
186 esac
187 #NEWBLOCKCOUNT=$(round_block_size $NEWSIZE $2)
b68235c5 188 NEWBLOCKCOUNT=$(( NEWSIZE / $2 ))
17dd04ca 189
b68235c5 190 if [ "$DO_LVRESIZE" -eq 1 ]; then
17dd04ca
ZK
191 # start lvresize, but first cleanup mounted dirs
192 DO_LVRESIZE=2
193 cleanup 0
194 fi
f29e7ac5
AK
195}
196
9e04e048
ZK
197decode_major_minor() {
198 # 0x00000fff00 mask MAJOR
199 # 0xfffff000ff mask MINOR
200
201 #MINOR=$(( $1 / 1048576 ))
202 #MAJOR=$(( ($1 - ${MINOR} * 1048576) / 256 ))
203 #MINOR=$(( $1 - ${MINOR} * 1048576 - ${MAJOR} * 256 + ${MINOR} * 256))
204
205 echo "$(( ( $1 >> 8 ) & 4095 )):$(( ( ( $1 >> 12 ) & 268435200 ) | ( $1 & 255 ) ))"
206}
207
f29e7ac5
AK
208# detect filesystem on the given device
209# dereference device name if it is symbolic link
210detect_fs() {
8c2779ba 211 test -n "${VOLUME_ORIG-}" || VOLUME_ORIG=$1
8f8c5580 212 VOLUME=${1/#"${DM_DEV_DIR}/"/}
1107d483
ZK
213 VOLUME=$("$READLINK" $READLINK_E "$DM_DEV_DIR/$VOLUME")
214 test -n "$VOLUME" || error "Cannot get readlink \"$1\"."
55b94bf3
ZK
215 RVOLUME=$VOLUME
216 case "$RVOLUME" in
8ea33b63 217 # hardcoded /dev since udev does not create these entries elsewhere
55b94bf3 218 /dev/dm-[0-9]*)
c6a5964c
ZK
219 read -r <"/sys/block/${RVOLUME#/dev/}/dm/name" SYSVOLUME 2>&1 && VOLUME="$DM_DEV_DIR/mapper/$SYSVOLUME"
220 read -r <"/sys/block/${RVOLUME#/dev/}/dev" MAJORMINOR 2>&1 || error "Cannot get major:minor for \"$VOLUME\"."
a1a9ae0a
ZK
221 MAJOR=${MAJORMINOR%%:*}
222 MINOR=${MAJORMINOR##*:}
55b94bf3 223 ;;
6c10d1f3 224 *)
b68235c5 225 STAT=$(stat --format "MAJOR=\$((0x%t)) MINOR=\$((0x%T))" "$RVOLUME")
1107d483 226 test -n "$STAT" || error "Cannot get major:minor for \"$VOLUME\"."
8ea33b63
ZK
227 eval "$STAT"
228 MAJORMINOR="${MAJOR}:${MINOR}"
6c10d1f3 229 ;;
55b94bf3 230 esac
8f8c5580 231 # use null device as cache file to be sure about the result
284f4496 232 # not using option '-o value' to be compatible with older version of blkid
28865f97 233 FSTYPE=$("$BLKID" -c "$NULL" -s TYPE "$VOLUME" || true)
1107d483 234 test -n "$FSTYPE" || error "Cannot get FSTYPE of \"$VOLUME\"."
284f4496
ZK
235 FSTYPE=${FSTYPE##*TYPE=\"} # cut quotation marks
236 FSTYPE=${FSTYPE%%\"*}
8ea33b63 237 verbose "\"$FSTYPE\" filesystem found on \"$VOLUME\"."
f29e7ac5
AK
238}
239
9e04e048
ZK
240
241# Check that passed mounted MAJOR:MINOR is not matching $MAJOR:MINOR of resized $VOLUME
242validate_mounted_major_minor() {
243 test "$1" = "$MAJORMINOR" || {
05a6d434
ZK
244 local REFNAME
245 local CURNAME
73ef86ae
ZK
246 REFNAME=$(dmsetup info -c -j "${1%%:*}" -m "${1##*:}" -o name --noheadings 2>"$NULL")
247 CURNAME=$(dmsetup info -c -j "$MAJOR" -m "$MINOR" -o name --noheadings 2>"$NULL")
9e04e048
ZK
248 error "Cannot ${CHECK+CHECK}${RESIZE+RESIZE} device \"$VOLUME\" without umounting filesystem $MOUNTED first." \
249 "Mounted filesystem is using device $CURNAME, but referenced device is $REFNAME." \
250 "Filesystem utilities currently do not support renamed devices."
251 }
252}
253
254# ATM fsresize & fsck tools are not able to work properly
255# when mounted device has changed its name.
256# So whenever such device no longer exists with original name
257# abort further command processing
258check_valid_mounted_device() {
259 local MOUNTEDMAJORMINOR
05a6d434
ZK
260 local VOL
261 local CURNAME
9e04e048 262
05a6d434
ZK
263 VOL=$("$READLINK" $READLINK_E "$1")
264 CURNAME=$(dmsetup info -c -j "$MAJOR" -m "$MINOR" -o name --noheadings)
9e04e048 265 # more confused, device is not DM....
8c2779ba 266 local SUGGEST="Possibly device \"$1\" has been renamed to \"$CURNAME\"?"
9e04e048
ZK
267 test -n "$CURNAME" || SUGGEST="Mounted volume is not a device mapper device???"
268
269 test -n "$VOL" ||
270 error "Cannot access device \"$1\" referenced by mounted filesystem \"$MOUNTED\"." \
271 "$SUGGEST" \
272 "Filesystem utilities currently do not support renamed devices."
273
274 case "$VOL" in
8c2779ba 275 # hardcoded /dev since kernel does not create these entries elsewhere
9e04e048 276 /dev/dm-[0-9]*)
c6a5964c 277 read -r <"/sys/block/${VOL#/dev/}/dev" MOUNTEDMAJORMINOR 2>&1 || error "Cannot get major:minor for \"$VOLUME\"."
9e04e048
ZK
278 ;;
279 *)
280 STAT=$(stat --format "MOUNTEDMAJORMINOR=\$((0x%t)):\$((0x%T))" "$VOL")
281 test -n "$STAT" || error "Cannot get major:minor for \"$VOLUME\"."
282 eval "$STAT"
283 ;;
284 esac
285
286 validate_mounted_major_minor "$MOUNTEDMAJORMINOR"
287}
288
8ea33b63 289detect_mounted_with_proc_self_mountinfo() {
9e04e048
ZK
290 # Check self mountinfo
291 # grab major:minor mounted_device mount_point
73ef86ae 292 MOUNTED=$("$GREP" "^[0-9]* [0-9]* $MAJORMINOR " "$PROCSELFMOUNTINFO" 2>"$NULL" | head -1)
9e04e048
ZK
293
294 # If device is opened and not yet found as self mounted
295 # check all other mountinfos (since it can be mounted in cgroups)
296 # Use 'find' to not fail on to long list of args with too many pids
297 # only 1st. line is needed
298 test -z "$MOUNTED" &&
b68235c5 299 test "$(dmsetup info -c --noheading -o open -j "$MAJOR" -m "$MINOR")" -gt 0 &&
73ef86ae 300 MOUNTED=$(find "$PROCDIR" -maxdepth 2 -name mountinfo -print0 | xargs -0 "$GREP" "^[0-9]* [0-9]* $MAJORMINOR " 2>"$NULL" | head -1 2>"$NULL")
2879eff8 301
9e04e048
ZK
302 # TODO: for performance compare with sed and stop with 1st. match:
303 # sed -n "/$MAJORMINOR/ {;p;q;}"
304
305 # extract 2nd field after ' - ' separator as mouted device
b68235c5
ZK
306 MOUNTDEV=$(echo "${MOUNTED##* - }" | cut -d ' ' -f 2)
307 MOUNTDEV=$(echo -n -e "$MOUNTDEV")
9e04e048
ZK
308
309 # extract 5th field as mount point
2879eff8 310 # echo -e translates \040 to spaces
b68235c5
ZK
311 MOUNTED=$(echo "$MOUNTED" | cut -d ' ' -f 5)
312 MOUNTED=$(echo -n -e "$MOUNTED")
2879eff8 313
9e04e048
ZK
314 test -n "$MOUNTED" || return 1 # Not seen mounted anywhere
315
316 check_valid_mounted_device "$MOUNTDEV"
2879eff8 317}
55b94bf3 318
9e04e048
ZK
319# With older systems without /proc/*/mountinfo we may need to check
320# every mount point as cannot easily depend on the name of mounted
321# device (which could have been renamed).
322# We need to visit every mount point and check it's major minor
8ea33b63 323detect_mounted_with_proc_mounts() {
e5e957e3 324 MOUNTED=$("$GREP" "^${VOLUME}[ \\t]" "$PROCMOUNTS")
55b94bf3
ZK
325
326 # for empty string try again with real volume name
e5e957e3 327 test -z "$MOUNTED" && MOUNTED=$("$GREP" "^${RVOLUME}[ \\t]" "$PROCMOUNTS")
55b94bf3 328
b68235c5 329 MOUNTDEV=$(echo -n -e "${MOUNTED%% *}")
55b94bf3
ZK
330 # cut device name prefix and trim everything past mountpoint
331 # echo translates \040 to spaces
332 MOUNTED=${MOUNTED#* }
b68235c5 333 MOUNTED=$(echo -n -e "${MOUNTED%% *}")
a9d6333b
ZK
334
335 # for systems with different device names - check also mount output
336 if test -z "$MOUNTED" ; then
9e04e048 337 # will not work with spaces in paths
e5e957e3
ZK
338 MOUNTED=$(LC_ALL=C "$MOUNT" | "$GREP" "^${VOLUME}[ \\t]")
339 test -z "$MOUNTED" && MOUNTED=$(LC_ALL=C "$MOUNT" | "$GREP" "^${RVOLUME}[ \\t]")
9e04e048 340 MOUNTDEV=${MOUNTED%% on *}
a9d6333b
ZK
341 MOUNTED=${MOUNTED##* on }
342 MOUNTED=${MOUNTED% type *} # allow type in the mount name
343 fi
344
9e04e048
ZK
345 if test -n "$MOUNTED" ; then
346 check_valid_mounted_device "$MOUNTDEV"
347 return 0 # mounted
348 fi
349
350 # If still nothing found and volume is in use
351 # check every known mount point against MAJOR:MINOR
b68235c5 352 if test "$(dmsetup info -c --noheading -o open -j "$MAJOR" -m "$MINOR")" -gt 0 ; then
9e04e048 353 while IFS=$'\n' read -r i ; do
b68235c5 354 MOUNTDEV=$(echo -n -e "${i%% *}")
9e04e048 355 MOUNTED=${i#* }
b68235c5
ZK
356 MOUNTED=$(echo -n -e "${MOUNTED%% *}")
357 STAT=$(stat --format "%d" "$MOUNTED")
358 validate_mounted_major_minor "$(decode_major_minor "$STAT")"
9e04e048
ZK
359 done < "$PROCMOUNTS"
360 fi
361
362 return 1 # nothing is mounted
f29e7ac5
AK
363}
364
2879eff8
PR
365# check if the given device is already mounted and where
366# FIXME: resolve swap usage and device stacking
8ea33b63 367detect_mounted() {
2879eff8
PR
368 if test -e "$PROCSELFMOUNTINFO"; then
369 detect_mounted_with_proc_self_mountinfo
370 elif test -e "$PROCMOUNTS"; then
371 detect_mounted_with_proc_mounts
372 else
8ea33b63 373 error "Cannot detect mounted device \"$VOLUME\"."
2879eff8
PR
374 fi
375}
376
f29e7ac5
AK
377# get the full size of device in bytes
378detect_device_size() {
9ad2ba2a 379 # check if blockdev supports getsize64
b0333841 380 DEVSIZE=$("$BLOCKDEV" --getsize64 "$VOLUME" 2>"$NULL" || true)
63c58d2a 381 if test -z "$DEVSIZE" ; then
b0333841 382 DEVSIZE=$("$BLOCKDEV" --getsize "$VOLUME" || true)
1107d483 383 test -n "$DEVSIZE" || error "Cannot read size of device \"$VOLUME\"."
b0333841 384 SSSIZE=$("$BLOCKDEV" --getss "$VOLUME" || true)
1107d483 385 test -n "$SSSIZE" || error "Cannot read sector size of device \"$VOLUME\"."
f6780523 386 DEVSIZE=$(( DEVSIZE * SSSIZE ))
9ad2ba2a 387 fi
f29e7ac5
AK
388}
389
390# round up $1 / $2
39b7d1ba 391# could be needed to guarantee 'at least given size'
f29e7ac5
AK
392# but it makes many troubles
393round_up_block_size() {
394 echo $(( ($1 + $2 - 1) / $2 ))
395}
396
397temp_mount() {
8ea33b63
ZK
398 dry "$MKDIR" -p -m 0000 "$TEMPDIR" || error "Failed to create $TEMPDIR."
399 dry "$MOUNT" "$VOLUME" "$TEMPDIR" || error "Failed to mount $TEMPDIR."
f29e7ac5
AK
400}
401
402temp_umount() {
8ea33b63
ZK
403 dry "$UMOUNT" "$TEMPDIR" || error "Failed to umount \"$TEMPDIR\"."
404 dry "$RMDIR" "${TEMPDIR}" || error "Failed to remove \"$TEMPDIR\","
405 dry "$RMDIR" "${TEMPDIR%%m}" || error "Failed to remove \"${TEMPDIR%%m}\"."
f29e7ac5
AK
406}
407
408yes_no() {
afded3e5 409 echo -n "$@" "? [Y|n] "
c8669f6b 410
f29e7ac5 411 if [ -n "$YES" ]; then
c8669f6b 412 echo y ; return 0
f29e7ac5 413 fi
c8669f6b
ZK
414
415 while read -r -s -n 1 ANS ; do
416 case "$ANS" in
1fe4f80e 417 "y" | "Y" ) echo y ; return 0 ;;
1c212b8a 418 "n" | "N") break ;;
1fe4f80e
ZK
419 "" ) if [ -t 1 ] ; then
420 echo y ; return 0
421 fi ;;
c8669f6b
ZK
422 esac
423 done
1fe4f80e
ZK
424
425 echo n
426 return 1
f29e7ac5
AK
427}
428
429try_umount() {
d2010960 430 yes_no "Do you want to unmount \"$MOUNTED\"" && dry "$UMOUNT" "$MOUNTED" && return 0
8ea33b63 431 error "Cannot proceed with mounted filesystem \"$MOUNTED\"."
f29e7ac5
AK
432}
433
434validate_parsing() {
95ca7cfd
ZK
435 if test -z "$BLOCKSIZE" || test -z "$BLOCKCOUNT" ; then
436 error "Cannot parse $1 output."
437 fi
f29e7ac5
AK
438}
439####################################
cd96532e 440# Resize ext2/ext3/ext4 filesystem
f29e7ac5
AK
441# - unmounted or mounted for upsize
442# - unmounted for downsize
443####################################
444resize_ext() {
2b7ac2bf
ZK
445 local IS_MOUNTED=0
446 detect_mounted && IS_MOUNTED=1
447
f29e7ac5 448 verbose "Parsing $TUNE_EXT -l \"$VOLUME\""
8bcc1da2 449 for i in $(LC_ALL=C "$TUNE_EXT" -l "$VOLUME"); do
f29e7ac5
AK
450 case "$i" in
451 "Block size"*) BLOCKSIZE=${i##* } ;;
452 "Block count"*) BLOCKCOUNT=${i##* } ;;
453 esac
454 done
d2010960 455 validate_parsing "$TUNE_EXT"
b68235c5 456 decode_size "$1" "$BLOCKSIZE"
f29e7ac5
AK
457 FSFORCE=$FORCE
458
95ca7cfd 459 if test "$NEWBLOCKCOUNT" -lt "$BLOCKCOUNT" || test "$EXTOFF" -eq 1 ; then
b68235c5 460 test "$IS_MOUNTED" -eq 1 && verbose "$RESIZE_EXT needs unmounted filesystem" && try_umount
f29e7ac5 461 REMOUNT=$MOUNTED
a9d6333b
ZK
462 if test -n "$MOUNTED" ; then
463 # Forced fsck -f for umounted extX filesystem.
464 case "$-" in
51a53271
ZK
465 *i*) FLAG=$YES ;;
466 *) FLAG="-p" ;;
a9d6333b 467 esac
51a53271 468 accept_0_1 dry "$FSCK" -f $FLAG "$VOLUME" || error "Failed to fsck $VOLUME"
a9d6333b 469 fi
f29e7ac5
AK
470 fi
471
c8669f6b 472 verbose "Resizing filesystem on device \"$VOLUME\" to $NEWSIZE bytes ($BLOCKCOUNT -> $NEWBLOCKCOUNT blocks of $BLOCKSIZE bytes)"
b68235c5 473 dry "$RESIZE_EXT" $FSFORCE "$VOLUME" "$NEWBLOCKCOUNT"
f29e7ac5
AK
474}
475
476#############################
477# Resize reiserfs filesystem
478# - unmounted for upsize
479# - unmounted for downsize
480#############################
481resize_reiser() {
c8669f6b
ZK
482 detect_mounted && verbose "ReiserFS resizes only unmounted filesystem" && try_umount
483 REMOUNT=$MOUNTED
f29e7ac5 484 verbose "Parsing $TUNE_REISER \"$VOLUME\""
8bcc1da2 485 for i in $(LC_ALL=C "$TUNE_REISER" "$VOLUME"); do
f29e7ac5
AK
486 case "$i" in
487 "Blocksize"*) BLOCKSIZE=${i##*: } ;;
488 "Count of blocks"*) BLOCKCOUNT=${i##*: } ;;
489 esac
490 done
d2010960 491 validate_parsing "$TUNE_REISER"
b68235c5 492 decode_size "$1" "$BLOCKSIZE"
f29e7ac5
AK
493 verbose "Resizing \"$VOLUME\" $BLOCKCOUNT -> $NEWBLOCKCOUNT blocks ($NEWSIZE bytes, bs: $NEWBLOCKCOUNT)"
494 if [ -n "$YES" ]; then
b68235c5 495 echo y | dry "$RESIZE_REISER" -s "$NEWSIZE" "$VOLUME"
f29e7ac5 496 else
b68235c5 497 dry "$RESIZE_REISER" -s "$NEWSIZE" "$VOLUME"
f29e7ac5
AK
498 fi
499}
500
501########################
502# Resize XFS filesystem
503# - mounted for upsize
3a6e5f36 504# - cannot downsize
f29e7ac5
AK
505########################
506resize_xfs() {
507 detect_mounted
508 MOUNTPOINT=$MOUNTED
509 if [ -z "$MOUNTED" ]; then
510 MOUNTPOINT=$TEMPDIR
8ea33b63 511 temp_mount || error "Cannot mount Xfs filesystem."
f29e7ac5
AK
512 fi
513 verbose "Parsing $TUNE_XFS \"$MOUNTPOINT\""
8bcc1da2 514 for i in $(LC_ALL=C "$TUNE_XFS" "$MOUNTPOINT"); do
f29e7ac5
AK
515 case "$i" in
516 "data"*) BLOCKSIZE=${i##*bsize=} ; BLOCKCOUNT=${i##*blocks=} ;;
517 esac
518 done
519 BLOCKSIZE=${BLOCKSIZE%%[^0-9]*}
520 BLOCKCOUNT=${BLOCKCOUNT%%[^0-9]*}
d2010960 521 validate_parsing "$TUNE_XFS"
b68235c5
ZK
522 decode_size "$1" "$BLOCKSIZE"
523 if [ "$NEWBLOCKCOUNT" -gt "$BLOCKCOUNT" ]; then
f29e7ac5 524 verbose "Resizing Xfs mounted on \"$MOUNTPOINT\" to fill device \"$VOLUME\""
b68235c5
ZK
525 dry "$RESIZE_XFS" "$MOUNTPOINT"
526 elif [ "$NEWBLOCKCOUNT" -eq "$BLOCKCOUNT" ]; then
f29e7ac5
AK
527 verbose "Xfs filesystem already has the right size"
528 else
8ea33b63 529 error "Xfs filesystem shrinking is unsupported."
f29e7ac5
AK
530 fi
531}
532
30293baa
OK
533# Find active LUKS device on original volume
534# 1) look for LUKS device with well-known UUID format (CRYPT-LUKS[12]-<uuid>-<dmname>)
39b7d1ba 535# 2) the dm-crypt device has to be on top of original device (don't support detached LUKS headers)
30293baa 536detect_luks_device() {
9916d8fa
OK
537 local _LUKS_VERSION
538 local _LUKS_UUID
30293baa
OK
539
540 CRYPT_NAME=""
541 CRYPT_DATA_OFFSET=""
542
73ef86ae 543 _LUKS_VERSION=$("$CRYPTSETUP" luksDump "$VOLUME" 2>"$NULL" | "$GREP" "Version:")
30293baa 544
f5beb585 545 if [ -z "$_LUKS_VERSION" ]; then
30293baa
OK
546 verbose "Failed to parse LUKS version on volume \"$VOLUME\""
547 return
548 fi
549
550 _LUKS_VERSION=${_LUKS_VERSION//[Version:[:space:]]/}
551
73ef86ae 552 _LUKS_UUID=$("$CRYPTSETUP" luksDump "$VOLUME" 2>"$NULL" | "$GREP" "UUID:")
30293baa 553
f5beb585 554 if [ -z "$_LUKS_UUID" ]; then
30293baa
OK
555 verbose "Failed to parse LUKS UUID on volume \"$VOLUME\""
556 return
557 fi
558
59145715 559 _LUKS_UUID="CRYPT-LUKS$_LUKS_VERSION-${_LUKS_UUID//[UID:[:space:]-]/}-"
30293baa 560
59145715 561 CRYPT_NAME=$(dmsetup info -c --noheadings -S "UUID=~^$_LUKS_UUID&&segments=1&&devnos_used='$MAJOR:$MINOR'" -o name)
d45a9c0f 562 test -z "$CRYPT_NAME" || CRYPT_DATA_OFFSET=$(dmsetup table "$CRYPT_NAME" | cut -d ' ' -f 8)
f5beb585
OK
563
564 # LUKS device must be active and mapped over volume where detected
d45a9c0f 565 if [ -z "$CRYPT_NAME" ] || [ -z "$CRYPT_DATA_OFFSET" ]; then
f5beb585
OK
566 error "Can not find active LUKS device. Unlock \"$VOLUME\" volume first."
567 fi
30293baa
OK
568}
569
570######################################
571# Resize active LUKS device
572# - LUKS must be active for fs resize
573######################################
574resize_luks() {
9916d8fa
OK
575 local L_NEWSIZE
576 local L_NEWBLOCKCOUNT
577 local NAME
30293baa
OK
578 local SHRINK=0
579
580 detect_luks_device
581
30293baa
OK
582 NAME=$CRYPT_NAME
583
584 verbose "Found active LUKS device \"$NAME\" for volume \"$VOLUME\""
585
586 decode_size "$1" 512
587
588 if [ $((NEWSIZE % 512)) -gt 0 ]; then
7da47cea 589 error "New size is not sector aligned."
30293baa
OK
590 fi
591
6df79175
OK
592 if [ $((NEWBLOCKCOUNT - CRYPT_DATA_OFFSET)) -lt 1 ]; then
593 error "New size is smaller than minimum ($(((CRYPT_DATA_OFFSET + 1) * 512)) bytes) for LUKS device $VOLUME"
594 fi
595
9916d8fa
OK
596 L_NEWBLOCKCOUNT=$((NEWBLOCKCOUNT - CRYPT_DATA_OFFSET))
597 L_NEWSIZE=$(( L_NEWBLOCKCOUNT * 512))
30293baa 598
74fd0dd6 599 VOLUME="$DM_DEV_DIR/mapper/$NAME"
30293baa
OK
600 detect_device_size
601
9916d8fa 602 test "$DEVSIZE" -le "$L_NEWSIZE" || SHRINK=1
30293baa
OK
603
604 if [ $SHRINK -eq 1 ]; then
605 # shrink fs on LUKS device first
9916d8fa 606 resize "$DM_DEV_DIR/mapper/$NAME" "$L_NEWSIZE"b
30293baa
OK
607 fi
608
609 # resize LUKS device
d45a9c0f 610 dry "$CRYPTSETUP" resize "$NAME" --size $L_NEWBLOCKCOUNT || error "Failed to resize active LUKS device"
30293baa
OK
611
612 if [ $SHRINK -eq 0 ]; then
613 # grow fs on top of LUKS device
9916d8fa 614 resize "$DM_DEV_DIR/mapper/$NAME" "$L_NEWSIZE"b
30293baa
OK
615 fi
616}
617
dcc8f90c
OK
618detect_crypt_device() {
619 local CRYPT_TYPE
620 local L_NEWSIZE
621 local TMP
30293baa 622
73ef86ae 623 which "$CRYPTSETUP" >"$NULL" 2>&1 || error "$CRYPTSETUP utility required to resize crypt device"
30293baa 624
73ef86ae 625 CRYPT_TYPE=$("$CRYPTSETUP" status "$1" 2>"$NULL" | "$GREP" "type:")
30293baa
OK
626
627 test -n "$CRYPT_TYPE" || error "$CRYPTSETUP failed to detect device type on $1."
628
629 CRYPT_TYPE=${CRYPT_TYPE##*[[:space:]]}
630
dcc8f90c
OK
631 case "$CRYPT_TYPE" in
632 LUKS[12]|PLAIN)
633 verbose "\"$1\" crypt device is type $CRYPT_TYPE"
634 ;;
635 *)
636 error "Unsupported crypt type \"$CRYPT_TYPE\""
637 esac
30293baa 638
dcc8f90c 639 TMP=$NEWSIZE
30293baa 640 decode_size "$2" 512
dcc8f90c
OK
641 L_NEWSIZE=$NEWSIZE
642 NEWSIZE=$TMP
30293baa 643
dcc8f90c 644 if [ $((L_NEWSIZE % 512)) -ne 0 ]; then
7da47cea 645 error "New size is not sector aligned."
30293baa
OK
646 fi
647
dcc8f90c 648 CRYPT_RESIZE_BLOCKS=$NEWBLOCKCOUNT
30293baa 649
dcc8f90c
OK
650 if [ "$DEVSIZE" -ge "$L_NEWSIZE" ]; then
651 CRYPT_SHRINK=1
652 else
653 CRYPT_GROW=1
30293baa 654 fi
dcc8f90c 655}
30293baa 656
dcc8f90c
OK
657#################################
658# Resize active crypt device
659# (on direct user request only)
660#################################
661resize_crypt() {
d45a9c0f 662 dry "$CRYPTSETUP" resize "$1" --size $CRYPT_RESIZE_BLOCKS || error "$CRYPTSETUP failed to resize device $1"
30293baa
OK
663}
664
f29e7ac5
AK
665####################
666# Resize filesystem
667####################
668resize() {
17dd04ca 669 NEWSIZE=$2
f29e7ac5
AK
670 detect_fs "$1"
671 detect_device_size
c8669f6b 672 verbose "Device \"$VOLUME\" size is $DEVSIZE bytes"
f29e7ac5 673 # if the size parameter is missing use device size
17dd04ca 674 #if [ -n "$NEWSIZE" -a $NEWSIZE <
50c41b09 675 test -z "$NEWSIZE" && NEWSIZE=${DEVSIZE}b
8c2779ba 676 NEWSIZE_ORIG=${NEWSIZE_ORIG:-$NEWSIZE}
33048414 677 IFS=$NL
8c2779ba
ZK
678 test -z "${DO_CRYPTRESIZE-}" || detect_crypt_device "$VOLUME_ORIG" "$NEWSIZE_ORIG"
679 test -z "${CRYPT_GROW-}" || resize_crypt "$VOLUME_ORIG"
680
f29e7ac5 681 case "$FSTYPE" in
8c2779ba
ZK
682 ext[234]) CMD=resize_ext ;;
683 "reiserfs") CMD=resize_reiser ;;
684 "xfs") CMD=resize_xfs ;;
30293baa 685 "crypto_LUKS")
73ef86ae 686 which "$CRYPTSETUP" >"$NULL" 2>&1 || error "$CRYPTSETUP utility required to resize LUKS volume"
8c2779ba 687 CMD=resize_luks ;;
8ea33b63 688 *) error "Filesystem \"$FSTYPE\" on device \"$VOLUME\" is not supported by this tool." ;;
8c2779ba
ZK
689 esac
690
691 $CMD $NEWSIZE || error "$FSTYPE resize failed."
692 test -z "${CRYPT_SHRINK-}" || resize_crypt "$VOLUME_ORIG"
f29e7ac5
AK
693}
694
a9d6333b 695####################################
39b7d1ba 696# Calculate diff between two dates
8bcc1da2 697# LC_ALL=C input is expected the
a9d6333b
ZK
698# only one supported
699####################################
700diff_dates() {
8f8c5580 701 echo $(( $("$DATE" -u -d"$1" +%s 2>"$NULL") - $("$DATE" -u -d"$2" +%s 2>"$NULL") ))
a9d6333b
ZK
702}
703
f5beb585
OK
704check_luks() {
705 detect_luks_device
706
707 check "$DM_DEV_DIR/mapper/$CRYPT_NAME"
708}
709
f29e7ac5
AK
710###################
711# Check filesystem
712###################
713check() {
714 detect_fs "$1"
4886fa21
ZK
715 if detect_mounted ; then
716 verbose "Skipping filesystem check for device \"$VOLUME\" as the filesystem is mounted on $MOUNTED";
717 cleanup 3
718 fi
a9d6333b
ZK
719
720 case "$FSTYPE" in
8c2779ba 721 ext[234])
a9d6333b
ZK
722 IFS_CHECK=$IFS
723 IFS=$NL
8bcc1da2 724 for i in $(LC_ALL=C "$TUNE_EXT" -l "$VOLUME"); do
a9d6333b
ZK
725 case "$i" in
726 "Last mount"*) LASTMOUNT=${i##*: } ;;
727 "Last checked"*) LASTCHECKED=${i##*: } ;;
728 esac
729 done
730 case "$LASTMOUNT" in
731 *"n/a") ;; # nothing to do - system was not mounted yet
732 *)
b68235c5 733 LASTDIFF=$(diff_dates "$LASTMOUNT" "$LASTCHECKED")
a9d6333b
ZK
734 if test "$LASTDIFF" -gt 0 ; then
735 verbose "Filesystem has not been checked after the last mount, using fsck -f"
736 FORCE="-f"
737 fi
738 ;;
739 esac
740 IFS=$IFS_CHECK
741 esac
742
f29e7ac5 743 case "$FSTYPE" in
59336a2a 744 "xfs") if which "$XFS_CHECK" >"$NULL" 2>&1 ; then
8c2779ba 745 dry "$XFS_CHECK" "$VOLUME" || error "Xfs check failed."
59336a2a
ZK
746 else
747 # Replacement for outdated xfs_check
748 # FIXME: for small devices we need to force_geometry,
749 # since we run in '-n' mode, it shouldn't be problem.
750 # Think about better way....
8c2779ba 751 dry "$XFS_REPAIR" -n -o force_geometry "$VOLUME" || error "Xfs repair failed."
59336a2a 752 fi ;;
8c2779ba 753 ext[234]|"reiserfs")
c795a3b3 754 # check if executed from interactive shell environment
bd79af9f 755 case "$-" in
51a53271
ZK
756 *i*) FLAG=$YES ;;
757 *) FLAG="-p" ;;
758 esac
759 accept_0_1 dry "$FSCK" $FORCE $FLAG "$VOLUME" || error "Fsck $FSTYPE failed."
760 ;;
f5beb585 761 "crypto_LUKS")
73ef86ae 762 which "$CRYPTSETUP" >"$NULL" 2>&1 || error "$CRYPTSETUP utility required."
8c2779ba
ZK
763 check_luks || error "Crypto luks check failed."
764 ;;
c795a3b3
OK
765 *)
766 error "Filesystem \"$FSTYPE\" on device \"$VOLUME\" is not supported by this tool." ;;
f29e7ac5
AK
767 esac
768}
769
770#############################
771# start point of this script
772# - parsing parameters
773#############################
4886fa21 774trap "cleanup 2" 2
50c41b09 775
17dd04ca 776# test if we are not invoked recursively
8c2779ba 777test -n "${FSADM_RUNNING-}" && exit 0
17dd04ca 778
39b7d1ba 779# test some prerequisites
6f6900d4
ZK
780for i in "$TUNE_EXT" "$RESIZE_EXT" "$TUNE_REISER" "$RESIZE_REISER" \
781 "$TUNE_XFS" "$RESIZE_XFS" "$MOUNT" "$UMOUNT" "$MKDIR" \
782 "$RMDIR" "$BLOCKDEV" "$BLKID" "$GREP" "$READLINK" \
783 "$DATE" "$FSCK" "$XFS_CHECK" "$XFS_REPAIR" "$LVM" ; do
784 test -n "$i" || error "Required command definitions in the script are missing!"
785done
9ad2ba2a 786
8ea33b63 787"$LVM" version >"$NULL" 2>&1 || error "Could not run lvm binary \"$LVM\"."
439aaca3 788"$READLINK" -e / >"$NULL" 2>&1 || READLINK_E="-f"
50c41b09 789TEST64BIT=$(( 1000 * 1000000000000 ))
8ea33b63 790test "$TEST64BIT" -eq 1000000000000000 || error "Shell does not handle 64bit arithmetic."
439aaca3 791echo Y | "$GREP" Y >"$NULL" || error "Grep does not work properly."
b68235c5 792test "$("$DATE" -u -d"Jan 01 00:00:01 1970" +%s)" -eq 1 || error "Date translation does not work."
50c41b09
ZK
793
794
c8669f6b 795if [ "$#" -eq 0 ] ; then
f29e7ac5
AK
796 tool_usage
797fi
798
8c2779ba
ZK
799CHECK=""
800RESIZE=""
47608ff4 801NEWSIZE=""
8c2779ba 802
c8669f6b 803while [ "$#" -ne 0 ]
f29e7ac5 804do
c8669f6b
ZK
805 case "$1" in
806 "") ;;
807 "-h"|"--help") tool_usage ;;
808 "-v"|"--verbose") VERB="-v" ;;
809 "-n"|"--dry-run") DRY=1 ;;
810 "-f"|"--force") FORCE="-f" ;;
811 "-e"|"--ext-offline") EXTOFF=1 ;;
812 "-y"|"--yes") YES="-y" ;;
813 "-l"|"--lvresize") DO_LVRESIZE=1 ;;
30293baa 814 "-c"|"--cryptresize") DO_CRYPTRESIZE=1 ;;
47608ff4
ZK
815 "check") test -z "${2-}" && error "Missing <device>. (see: $TOOL --help)"
816 CHECK=$2 ; shift ;;
817 "resize") test -z "${2-}" && error "Missing <device>. (see: $TOOL --help)"
818 RESIZE=$2 ; shift
819 if test -n "${2-}" ; then NEWSIZE="${2-}" ; shift ; fi ;;
c8669f6b 820 *) error "Wrong argument \"$1\". (see: $TOOL --help)"
f29e7ac5
AK
821 esac
822 shift
823done
824
73bbd552 825test "$YES" = "-y" || YES=""
a9382908
ZK
826test "$EXTOFF" -eq 1 || EXTOFF=0
827
f29e7ac5
AK
828if [ -n "$CHECK" ]; then
829 check "$CHECK"
830elif [ -n "$RESIZE" ]; then
17dd04ca 831 export FSADM_RUNNING="fsadm"
f29e7ac5 832 resize "$RESIZE" "$NEWSIZE"
30293baa 833 cleanup 0
f29e7ac5
AK
834else
835 error "Missing command. (see: $TOOL --help)"
836fi
This page took 0.289803 seconds and 6 git commands to generate.