2010-05-14 15:33:20 +04:00
#!/bin/bash
2007-12-17 15:31:50 +03:00
#
2017-06-29 14:15:47 +03:00
# Copyright (C) 2007-2017 Red Hat, Inc. All rights reserved.
2007-12-17 15:31:50 +03:00
#
# This file is part of LVM2.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
2016-01-21 13:49:46 +03:00
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2007-12-17 15:31:50 +03:00
#
2008-01-08 19:45:43 +03:00
# Author: Zdenek Kabelac <zkabelac at redhat.com>
2007-12-17 15:31:50 +03:00
#
# Script for resizing devices (usable for LVM resize)
#
# Needed utilities:
2017-10-06 17:28:35 +03:00
# mount, umount, grep, readlink, blockdev, blkid, fsck, xfs_check, cryptsetup
2007-12-17 15:31:50 +03:00
#
2009-02-04 15:47:05 +03:00
# ext2/ext3/ext4: resize2fs, tune2fs
2007-12-17 15:31:50 +03:00
# reiserfs: resize_reiserfs, reiserfstune
# xfs: xfs_growfs, xfs_info
#
2010-11-01 17:08:51 +03:00
# Return values:
# 0 success
# 1 error
# 2 break detected
# 3 unsupported online filesystem check for given mounted fs
2007-12-17 15:31:50 +03:00
TOOL = fsadm
2011-09-19 17:51:09 +04:00
_SAVEPATH = $PATH
2017-06-29 14:15:47 +03:00
PATH = " /sbin:/usr/sbin:/bin:/usr/sbin: $PATH "
2007-12-17 15:31:50 +03:00
# utilities
TUNE_EXT = tune2fs
RESIZE_EXT = resize2fs
TUNE_REISER = reiserfstune
RESIZE_REISER = resize_reiserfs
TUNE_XFS = xfs_info
RESIZE_XFS = xfs_growfs
MOUNT = mount
UMOUNT = umount
MKDIR = mkdir
2008-01-08 19:45:43 +03:00
RMDIR = rmdir
BLOCKDEV = blockdev
BLKID = blkid
2010-11-11 15:17:15 +03:00
DATE = date
2007-12-17 15:31:50 +03:00
GREP = grep
READLINK = readlink
2008-04-29 19:25:28 +04:00
READLINK_E = "-e"
2007-12-17 15:31:50 +03:00
FSCK = fsck
XFS_CHECK = xfs_check
2014-01-20 14:57:39 +04:00
# XFS_REPAIR -n is used when XFS_CHECK is not found
XFS_REPAIR = xfs_repair
2017-10-06 17:28:35 +03:00
CRYPTSETUP = cryptsetup
2007-12-17 15:31:50 +03:00
2009-06-09 19:31:36 +04:00
# user may override lvm location by setting LVM_BINARY
2010-10-08 18:49:25 +04:00
LVM = ${ LVM_BINARY :- lvm }
2008-02-06 15:45:32 +03:00
2010-10-08 17:49:20 +04:00
YES = ${ _FSADM_YES }
2007-12-17 15:31:50 +03:00
DRY = 0
2008-02-06 15:45:32 +03:00
VERB =
2007-12-17 15:31:50 +03:00
FORCE =
2012-03-16 16:53:05 +04:00
EXTOFF = ${ _FSADM_EXTOFF :- 0 }
2008-02-06 15:45:32 +03:00
DO_LVRESIZE = 0
2007-12-17 15:31:50 +03:00
FSTYPE = unknown
VOLUME = unknown
TEMPDIR = " ${ TMPDIR :- /tmp } / ${ TOOL } _ ${ RANDOM } $$ /m "
2011-09-19 23:36:52 +04:00
DM_DEV_DIR = " ${ DM_DEV_DIR :- /dev } "
2007-12-17 15:31:50 +03:00
BLOCKSIZE =
BLOCKCOUNT =
MOUNTPOINT =
MOUNTED =
REMOUNT =
2017-05-10 16:32:48 +03:00
PROCDIR = "/proc"
PROCMOUNTS = " $PROCDIR /mounts "
PROCSELFMOUNTINFO = " $PROCDIR /self/mountinfo "
2011-09-19 23:36:52 +04:00
NULL = " $DM_DEV_DIR /null "
2007-12-17 15:31:50 +03:00
IFS_OLD = $IFS
2009-06-09 19:31:36 +04:00
# without bash $'\n'
NL = '
'
2007-12-17 15:31:50 +03:00
tool_usage( ) {
2007-12-17 17:47:22 +03:00
echo " ${ TOOL } : Utility to resize or check the filesystem on a device "
echo
2015-10-05 13:28:00 +03:00
echo " ${ TOOL } [options] check <device> "
2007-12-17 17:47:22 +03:00
echo " - Check the filesystem on device using fsck"
echo
2015-10-05 13:28:00 +03:00
echo " ${ TOOL } [options] resize <device> [<new_size>[BKMGTPE]] "
2007-12-17 17:47:22 +03:00
echo " - Change the size of the filesystem on device to new_size"
echo
echo " Options:"
echo " -h | --help Show this help message"
echo " -v | --verbose Be verbose"
2009-02-04 15:47:05 +03:00
echo " -e | --ext-offline unmount filesystem before ext2/ext3/ext4 resize"
2007-12-17 17:47:22 +03:00
echo " -f | --force Bypass sanity checks"
echo " -n | --dry-run Print commands without running them"
2008-02-06 15:45:32 +03:00
echo " -l | --lvresize Resize given device (if it is LVM device)"
2017-10-06 17:28:35 +03:00
echo " -c | --cryptresize Resize given crypt device"
2007-12-17 17:47:22 +03:00
echo " -y | --yes Answer \"yes\" at any prompts"
echo
echo " new_size - Absolute number of filesystem blocks to be in the filesystem,"
echo " or an absolute size using a suffix (in powers of 1024)."
echo " If new_size is not supplied, the whole device is used."
2007-12-17 15:31:50 +03:00
exit
}
verbose( ) {
2017-06-28 17:13:29 +03:00
test -z " $VERB " || echo " $TOOL : " " $@ "
2007-12-17 15:31:50 +03:00
}
2017-05-10 16:32:48 +03:00
# Support multi-line error messages
2007-12-17 15:31:50 +03:00
error( ) {
2017-05-10 16:32:48 +03:00
for i in " $@ " ; do
echo " $TOOL : $i " >& 2
done
2007-12-17 15:31:50 +03:00
cleanup 1
}
dry( ) {
2008-01-08 19:45:43 +03:00
if [ " $DRY " -ne 0 ] ; then
2017-06-29 17:01:42 +03:00
verbose "Dry execution" " $@ "
2008-01-08 19:45:43 +03:00
return 0
fi
2017-06-29 17:01:42 +03:00
verbose "Executing" " $@ "
2012-03-16 16:53:05 +04:00
" $@ "
2007-12-17 15:31:50 +03:00
}
cleanup( ) {
trap '' 2
# reset MOUNTPOINT - avoid recursion
test " $MOUNTPOINT " = " $TEMPDIR " && MOUNTPOINT = "" temp_umount
if [ -n " $REMOUNT " ] ; then
verbose "Remounting unmounted filesystem back"
2011-09-19 17:47:37 +04:00
dry " $MOUNT " " $VOLUME " " $MOUNTED "
2007-12-17 15:31:50 +03:00
fi
IFS = $IFS_OLD
trap 2
2008-02-06 15:45:32 +03:00
2010-11-01 17:08:51 +03:00
test " $1 " -eq 2 && verbose "Break detected"
2010-10-08 17:47:10 +04:00
if [ " $DO_LVRESIZE " -eq 2 ] ; then
# start LVRESIZE with the filesystem modification flag
# and allow recursive call of fsadm
2010-10-08 17:49:20 +04:00
_FSADM_YES = $YES
2012-03-16 16:53:05 +04:00
_FSADM_EXTOFF = $EXTOFF
export _FSADM_YES _FSADM_EXTOFF
2010-10-08 17:47:10 +04:00
unset FSADM_RUNNING
2011-09-19 17:51:09 +04:00
test -n " $LVM_BINARY " && PATH = $_SAVEPATH
2017-10-06 17:28:35 +03:00
dry exec " $LVM " lvresize $VERB $FORCE -r -L" ${ NEWSIZE_ORIG } b " " $VOLUME_ORIG "
2010-10-08 17:47:10 +04:00
fi
2011-09-19 17:51:09 +04:00
2010-10-08 16:35:56 +04:00
# error exit status for break
2017-06-29 14:15:47 +03:00
exit " ${ 1 :- 1 } "
2007-12-17 15:31:50 +03:00
}
2008-01-08 19:45:43 +03:00
# convert parameter from Exa/Peta/Tera/Giga/Mega/Kilo/Bytes and blocks
# (2^(60/50/40/30/20/10/0))
2007-12-17 15:31:50 +03:00
decode_size( ) {
case " $1 " in
2008-01-08 19:45:43 +03:00
*[ eE] ) NEWSIZE = $(( ${ 1 %[eE] } * 1152921504606846976 )) ; ;
*[ pP] ) NEWSIZE = $(( ${ 1 %[pP] } * 1125899906842624 )) ; ;
2007-12-17 15:31:50 +03:00
*[ tT] ) NEWSIZE = $(( ${ 1 %[tT] } * 1099511627776 )) ; ;
*[ gG] ) NEWSIZE = $(( ${ 1 %[gG] } * 1073741824 )) ; ;
*[ mM] ) NEWSIZE = $(( ${ 1 %[mM] } * 1048576 )) ; ;
*[ kK] ) NEWSIZE = $(( ${ 1 %[kK] } * 1024 )) ; ;
*[ bB] ) NEWSIZE = ${ 1 %[bB] } ; ;
*) NEWSIZE = $(( $1 * $2 )) ; ;
esac
#NEWBLOCKCOUNT=$(round_block_size $NEWSIZE $2)
2017-06-29 14:15:47 +03:00
NEWBLOCKCOUNT = $(( NEWSIZE / $2 ))
2008-02-06 15:45:32 +03:00
2017-06-29 14:15:47 +03:00
if [ " $DO_LVRESIZE " -eq 1 ] ; then
2008-02-06 15:45:32 +03:00
# start lvresize, but first cleanup mounted dirs
DO_LVRESIZE = 2
cleanup 0
fi
2007-12-17 15:31:50 +03:00
}
2017-05-10 16:32:48 +03:00
decode_major_minor( ) {
# 0x00000fff00 mask MAJOR
# 0xfffff000ff mask MINOR
#MINOR=$(( $1 / 1048576 ))
#MAJOR=$(( ($1 - ${MINOR} * 1048576) / 256 ))
#MINOR=$(( $1 - ${MINOR} * 1048576 - ${MAJOR} * 256 + ${MINOR} * 256))
echo " $(( ( $1 >> 8 ) & 4095 )) : $(( ( ( $1 >> 12 ) & 268435200 ) | ( $1 & 255 ) )) "
}
2007-12-17 15:31:50 +03:00
# detect filesystem on the given device
# dereference device name if it is symbolic link
detect_fs( ) {
2017-10-06 17:28:35 +03:00
test -n " $VOLUME_ORIG " || VOLUME_ORIG = $1
2011-09-19 23:36:52 +04:00
VOLUME = ${ 1 /# " ${ DM_DEV_DIR } / " / }
2017-05-09 21:52:15 +03:00
VOLUME = $( " $READLINK " $READLINK_E " $DM_DEV_DIR / $VOLUME " )
test -n " $VOLUME " || error " Cannot get readlink \" $1 \". "
2010-10-08 18:55:19 +04:00
RVOLUME = $VOLUME
case " $RVOLUME " in
2017-05-10 16:13:35 +03:00
# hardcoded /dev since udev does not create these entries elsewhere
2010-10-08 18:55:19 +04:00
/dev/dm-[ 0-9] *)
2017-06-28 17:07:33 +03:00
read -r <" /sys/block/ ${ RVOLUME #/dev/ } /dm/name " SYSVOLUME 2>& 1 && VOLUME = " $DM_DEV_DIR /mapper/ $SYSVOLUME "
read -r <" /sys/block/ ${ RVOLUME #/dev/ } /dev " MAJORMINOR 2>& 1 || error " Cannot get major:minor for \" $VOLUME \". "
2017-05-10 16:23:54 +03:00
MAJOR = ${ MAJORMINOR %% : * }
MINOR = ${ MAJORMINOR ##* : }
2010-10-08 18:55:19 +04:00
; ;
2016-03-18 17:55:36 +03:00
*)
2017-06-29 14:15:47 +03:00
STAT = $( stat --format "MAJOR=\$((0x%t)) MINOR=\$((0x%T))" " $RVOLUME " )
2017-05-09 21:52:15 +03:00
test -n " $STAT " || error " Cannot get major:minor for \" $VOLUME \". "
2017-05-10 16:13:35 +03:00
eval " $STAT "
MAJORMINOR = " ${ MAJOR } : ${ MINOR } "
2016-03-18 17:55:36 +03:00
; ;
2010-10-08 18:55:19 +04:00
esac
2011-09-19 23:36:52 +04:00
# use null device as cache file to be sure about the result
2009-02-06 17:28:06 +03:00
# not using option '-o value' to be compatible with older version of blkid
2017-05-09 21:52:15 +03:00
FSTYPE = $( " $BLKID " -c " $NULL " -s TYPE " $VOLUME " )
test -n " $FSTYPE " || error " Cannot get FSTYPE of \" $VOLUME \". "
2009-02-06 17:28:06 +03:00
FSTYPE = ${ FSTYPE ##*TYPE= \" } # cut quotation marks
FSTYPE = ${ FSTYPE %% \" * }
2017-05-10 16:13:35 +03:00
verbose " \" $FSTYPE \" filesystem found on \" $VOLUME \". "
2007-12-17 15:31:50 +03:00
}
2017-05-10 16:32:48 +03:00
# Check that passed mounted MAJOR:MINOR is not matching $MAJOR:MINOR of resized $VOLUME
validate_mounted_major_minor( ) {
test " $1 " = " $MAJORMINOR " || {
2017-06-28 17:02:13 +03:00
local REFNAME
local CURNAME
REFNAME = $( dmsetup info -c -j " ${ 1 %% : * } " -m " ${ 1 ##* : } " -o name --noheadings 2>/dev/null)
CURNAME = $( dmsetup info -c -j " $MAJOR " -m " $MINOR " -o name --noheadings 2>/dev/null)
2017-05-10 16:32:48 +03:00
error " Cannot ${ CHECK +CHECK } ${ RESIZE +RESIZE } device \" $VOLUME \" without umounting filesystem $MOUNTED first. " \
" Mounted filesystem is using device $CURNAME , but referenced device is $REFNAME . " \
"Filesystem utilities currently do not support renamed devices."
}
}
# ATM fsresize & fsck tools are not able to work properly
# when mounted device has changed its name.
# So whenever such device no longer exists with original name
# abort further command processing
check_valid_mounted_device( ) {
local MOUNTEDMAJORMINOR
2017-06-28 17:02:13 +03:00
local VOL
local CURNAME
2017-05-10 16:32:48 +03:00
local SUGGEST = " Possibly device \" $1 \" has been renamed to \" $CURNAME \"? "
2017-06-28 17:02:13 +03:00
VOL = $( " $READLINK " $READLINK_E " $1 " )
CURNAME = $( dmsetup info -c -j " $MAJOR " -m " $MINOR " -o name --noheadings)
2017-05-10 16:32:48 +03:00
# more confused, device is not DM....
test -n " $CURNAME " || SUGGEST = "Mounted volume is not a device mapper device???"
test -n " $VOL " ||
error " Cannot access device \" $1 \" referenced by mounted filesystem \" $MOUNTED \". " \
" $SUGGEST " \
"Filesystem utilities currently do not support renamed devices."
case " $VOL " in
# hardcoded /dev since udev does not create these entries elsewhere
/dev/dm-[ 0-9] *)
2017-06-28 17:07:33 +03:00
read -r <" /sys/block/ ${ VOL #/dev/ } /dev " MOUNTEDMAJORMINOR 2>& 1 || error " Cannot get major:minor for \" $VOLUME \". "
2017-05-10 16:32:48 +03:00
; ;
*)
STAT = $( stat --format "MOUNTEDMAJORMINOR=\$((0x%t)):\$((0x%T))" " $VOL " )
test -n " $STAT " || error " Cannot get major:minor for \" $VOLUME \". "
eval " $STAT "
; ;
esac
validate_mounted_major_minor " $MOUNTEDMAJORMINOR "
}
2017-05-10 16:13:35 +03:00
detect_mounted_with_proc_self_mountinfo( ) {
2017-05-10 16:32:48 +03:00
# Check self mountinfo
# grab major:minor mounted_device mount_point
MOUNTED = $( " $GREP " " ^[0-9]* [0-9]* $MAJORMINOR " " $PROCSELFMOUNTINFO " 2>/dev/null | head -1)
# If device is opened and not yet found as self mounted
# check all other mountinfos (since it can be mounted in cgroups)
# Use 'find' to not fail on to long list of args with too many pids
# only 1st. line is needed
test -z " $MOUNTED " &&
2017-06-29 14:15:47 +03:00
test " $( dmsetup info -c --noheading -o open -j " $MAJOR " -m " $MINOR " ) " -gt 0 &&
2017-05-10 16:32:48 +03:00
MOUNTED = $( find " $PROCDIR " -maxdepth 2 -name mountinfo -print0 | xargs -0 " $GREP " " ^[0-9]* [0-9]* $MAJORMINOR " 2>/dev/null | head -1 2>/dev/null)
2016-03-18 15:42:06 +03:00
2017-05-10 16:32:48 +03:00
# TODO: for performance compare with sed and stop with 1st. match:
# sed -n "/$MAJORMINOR/ {;p;q;}"
# extract 2nd field after ' - ' separator as mouted device
2017-06-29 14:15:47 +03:00
MOUNTDEV = $( echo " ${ MOUNTED ##* - } " | cut -d ' ' -f 2)
MOUNTDEV = $( echo -n -e " $MOUNTDEV " )
2017-05-10 16:32:48 +03:00
# extract 5th field as mount point
2016-03-18 15:42:06 +03:00
# echo -e translates \040 to spaces
2017-06-29 14:15:47 +03:00
MOUNTED = $( echo " $MOUNTED " | cut -d ' ' -f 5)
MOUNTED = $( echo -n -e " $MOUNTED " )
2016-03-18 15:42:06 +03:00
2017-05-10 16:32:48 +03:00
test -n " $MOUNTED " || return 1 # Not seen mounted anywhere
check_valid_mounted_device " $MOUNTDEV "
2016-03-18 15:42:06 +03:00
}
2010-10-08 18:55:19 +04:00
2017-05-10 16:32:48 +03:00
# With older systems without /proc/*/mountinfo we may need to check
# every mount point as cannot easily depend on the name of mounted
# device (which could have been renamed).
# We need to visit every mount point and check it's major minor
2017-05-10 16:13:35 +03:00
detect_mounted_with_proc_mounts( ) {
2012-03-16 16:53:05 +04:00
MOUNTED = $( " $GREP " " ^ $VOLUME [ \t] " " $PROCMOUNTS " )
2010-10-08 18:55:19 +04:00
# for empty string try again with real volume name
2012-03-16 16:53:05 +04:00
test -z " $MOUNTED " && MOUNTED = $( " $GREP " " ^ $RVOLUME [ \t] " " $PROCMOUNTS " )
2010-10-08 18:55:19 +04:00
2017-06-29 14:15:47 +03:00
MOUNTDEV = $( echo -n -e " ${ MOUNTED %% * } " )
2010-10-08 18:55:19 +04:00
# cut device name prefix and trim everything past mountpoint
# echo translates \040 to spaces
MOUNTED = ${ MOUNTED #* }
2017-06-29 14:15:47 +03:00
MOUNTED = $( echo -n -e " ${ MOUNTED %% * } " )
2010-11-10 19:14:02 +03:00
# for systems with different device names - check also mount output
if test -z " $MOUNTED " ; then
2017-05-10 16:32:48 +03:00
# will not work with spaces in paths
2013-01-22 14:25:02 +04:00
MOUNTED = $( LC_ALL = C " $MOUNT " | " $GREP " " ^ $VOLUME [ \t] " )
test -z " $MOUNTED " && MOUNTED = $( LC_ALL = C " $MOUNT " | " $GREP " " ^ $RVOLUME [ \t] " )
2017-05-10 16:32:48 +03:00
MOUNTDEV = ${ MOUNTED %% on * }
2010-11-10 19:14:02 +03:00
MOUNTED = ${ MOUNTED ##* on }
MOUNTED = ${ MOUNTED % type * } # allow type in the mount name
fi
2017-05-10 16:32:48 +03:00
if test -n " $MOUNTED " ; then
check_valid_mounted_device " $MOUNTDEV "
return 0 # mounted
fi
# If still nothing found and volume is in use
# check every known mount point against MAJOR:MINOR
2017-06-29 14:15:47 +03:00
if test " $( dmsetup info -c --noheading -o open -j " $MAJOR " -m " $MINOR " ) " -gt 0 ; then
2017-05-10 16:32:48 +03:00
while IFS = $'\n' read -r i ; do
2017-06-29 14:15:47 +03:00
MOUNTDEV = $( echo -n -e " ${ i %% * } " )
2017-05-10 16:32:48 +03:00
MOUNTED = ${ i #* }
2017-06-29 14:15:47 +03:00
MOUNTED = $( echo -n -e " ${ MOUNTED %% * } " )
STAT = $( stat --format "%d" " $MOUNTED " )
validate_mounted_major_minor " $( decode_major_minor " $STAT " ) "
2017-05-10 16:32:48 +03:00
done < " $PROCMOUNTS "
fi
return 1 # nothing is mounted
2007-12-17 15:31:50 +03:00
}
2016-03-18 15:42:06 +03:00
# check if the given device is already mounted and where
# FIXME: resolve swap usage and device stacking
2017-05-10 16:13:35 +03:00
detect_mounted( ) {
2016-03-18 15:42:06 +03:00
if test -e " $PROCSELFMOUNTINFO " ; then
detect_mounted_with_proc_self_mountinfo
elif test -e " $PROCMOUNTS " ; then
detect_mounted_with_proc_mounts
else
2017-05-10 16:13:35 +03:00
error " Cannot detect mounted device \" $VOLUME \". "
2016-03-18 15:42:06 +03:00
fi
}
2007-12-17 15:31:50 +03:00
# get the full size of device in bytes
detect_device_size( ) {
2008-04-29 19:25:28 +04:00
# check if blockdev supports getsize64
2017-10-05 11:16:20 +03:00
" $BLOCKDEV " --help 2>& 1 | " $GREP " getsize64 >" $NULL "
2009-02-24 18:48:00 +03:00
if test $? -eq 0; then
2017-05-09 21:52:15 +03:00
DEVSIZE = $( " $BLOCKDEV " --getsize64 " $VOLUME " )
test -n " $DEVSIZE " || error " Cannot read size of device \" $VOLUME \". "
2008-04-29 19:25:28 +04:00
else
2017-05-09 21:52:15 +03:00
DEVSIZE = $( " $BLOCKDEV " --getsize " $VOLUME " )
test -n " $DEVSIZE " || error " Cannot read size of device \" $VOLUME \". "
SSSIZE = $( " $BLOCKDEV " --getss " $VOLUME " )
test -n " $SSSIZE " || error " Cannot read sector size of device \" $VOLUME \". "
2017-06-29 14:15:47 +03:00
DEVSIZE = $(( " $DEVSIZE " * " $SSSIZE " ))
2008-04-29 19:25:28 +04:00
fi
2007-12-17 15:31:50 +03:00
}
# round up $1 / $2
# could be needed to gaurantee 'at least given size'
# but it makes many troubles
round_up_block_size( ) {
echo $(( ( $1 + $2 - 1 ) / $2 ))
}
temp_mount( ) {
2017-05-10 16:13:35 +03:00
dry " $MKDIR " -p -m 0000 " $TEMPDIR " || error " Failed to create $TEMPDIR . "
dry " $MOUNT " " $VOLUME " " $TEMPDIR " || error " Failed to mount $TEMPDIR . "
2007-12-17 15:31:50 +03:00
}
temp_umount( ) {
2017-05-10 16:13:35 +03:00
dry " $UMOUNT " " $TEMPDIR " || error " Failed to umount \" $TEMPDIR \". "
dry " $RMDIR " " ${ TEMPDIR } " || error " Failed to remove \" $TEMPDIR \", "
dry " $RMDIR " " ${ TEMPDIR %%m } " || error " Failed to remove \" ${ TEMPDIR %%m } \". "
2007-12-17 15:31:50 +03:00
}
yes_no( ) {
2017-06-29 17:01:42 +03:00
echo -n " $@ " "? [Y|n] "
2009-02-24 18:48:00 +03:00
2007-12-17 15:31:50 +03:00
if [ -n " $YES " ] ; then
2009-02-24 18:48:00 +03:00
echo y ; return 0
2007-12-17 15:31:50 +03:00
fi
2009-02-24 18:48:00 +03:00
while read -r -s -n 1 ANS ; do
case " $ANS " in
2017-05-23 14:58:12 +03:00
"y" | "Y" ) echo y ; return 0 ; ;
2017-06-19 13:37:40 +03:00
"n" | "N" ) break ; ;
2017-05-23 14:58:12 +03:00
"" ) if [ -t 1 ] ; then
echo y ; return 0
fi ; ;
2009-02-24 18:48:00 +03:00
esac
done
2017-05-23 14:58:12 +03:00
echo n
return 1
2007-12-17 15:31:50 +03:00
}
try_umount( ) {
2011-09-19 17:47:37 +04:00
yes_no " Do you want to unmount \" $MOUNTED \" " && dry " $UMOUNT " " $MOUNTED " && return 0
2017-05-10 16:13:35 +03:00
error " Cannot proceed with mounted filesystem \" $MOUNTED \". "
2007-12-17 15:31:50 +03:00
}
validate_parsing( ) {
2017-06-28 17:13:29 +03:00
if test -z " $BLOCKSIZE " || test -z " $BLOCKCOUNT " ; then
error " Cannot parse $1 output. "
fi
2007-12-17 15:31:50 +03:00
}
####################################
2009-02-04 15:47:05 +03:00
# Resize ext2/ext3/ext4 filesystem
2007-12-17 15:31:50 +03:00
# - unmounted or mounted for upsize
# - unmounted for downsize
####################################
resize_ext( ) {
2017-05-22 15:39:10 +03:00
local IS_MOUNTED = 0
detect_mounted && IS_MOUNTED = 1
2007-12-17 15:31:50 +03:00
verbose " Parsing $TUNE_EXT -l \" $VOLUME \" "
2013-01-22 14:25:02 +04:00
for i in $( LC_ALL = C " $TUNE_EXT " -l " $VOLUME " ) ; do
2007-12-17 15:31:50 +03:00
case " $i " in
"Block size" *) BLOCKSIZE = ${ i ##* } ; ;
"Block count" *) BLOCKCOUNT = ${ i ##* } ; ;
esac
done
2011-09-19 17:47:37 +04:00
validate_parsing " $TUNE_EXT "
2017-06-29 14:15:47 +03:00
decode_size " $1 " " $BLOCKSIZE "
2007-12-17 15:31:50 +03:00
FSFORCE = $FORCE
2017-06-28 17:13:29 +03:00
if test " $NEWBLOCKCOUNT " -lt " $BLOCKCOUNT " || test " $EXTOFF " -eq 1 ; then
2017-06-29 14:15:47 +03:00
test " $IS_MOUNTED " -eq 1 && verbose " $RESIZE_EXT needs unmounted filesystem " && try_umount
2007-12-17 15:31:50 +03:00
REMOUNT = $MOUNTED
2010-11-10 19:14:02 +03:00
if test -n " $MOUNTED " ; then
# Forced fsck -f for umounted extX filesystem.
case " $- " in
2011-09-19 17:47:37 +04:00
*i*) dry " $FSCK " $YES -f " $VOLUME " ; ;
*) dry " $FSCK " -f -p " $VOLUME " ; ;
2010-11-10 19:14:02 +03:00
esac
fi
2007-12-17 15:31:50 +03:00
fi
2009-02-24 18:48:00 +03:00
verbose " Resizing filesystem on device \" $VOLUME \" to $NEWSIZE bytes ( $BLOCKCOUNT -> $NEWBLOCKCOUNT blocks of $BLOCKSIZE bytes) "
2017-06-29 14:15:47 +03:00
dry " $RESIZE_EXT " $FSFORCE " $VOLUME " " $NEWBLOCKCOUNT "
2007-12-17 15:31:50 +03:00
}
#############################
# Resize reiserfs filesystem
# - unmounted for upsize
# - unmounted for downsize
#############################
resize_reiser( ) {
2009-02-24 18:48:00 +03:00
detect_mounted && verbose "ReiserFS resizes only unmounted filesystem" && try_umount
REMOUNT = $MOUNTED
2007-12-17 15:31:50 +03:00
verbose " Parsing $TUNE_REISER \" $VOLUME \" "
2013-01-22 14:25:02 +04:00
for i in $( LC_ALL = C " $TUNE_REISER " " $VOLUME " ) ; do
2007-12-17 15:31:50 +03:00
case " $i " in
"Blocksize" *) BLOCKSIZE = ${ i ##* : } ; ;
"Count of blocks" *) BLOCKCOUNT = ${ i ##* : } ; ;
esac
done
2011-09-19 17:47:37 +04:00
validate_parsing " $TUNE_REISER "
2017-06-29 14:15:47 +03:00
decode_size " $1 " " $BLOCKSIZE "
2007-12-17 15:31:50 +03:00
verbose " Resizing \" $VOLUME \" $BLOCKCOUNT -> $NEWBLOCKCOUNT blocks ( $NEWSIZE bytes, bs: $NEWBLOCKCOUNT ) "
if [ -n " $YES " ] ; then
2017-06-29 14:15:47 +03:00
echo y | dry " $RESIZE_REISER " -s " $NEWSIZE " " $VOLUME "
2007-12-17 15:31:50 +03:00
else
2017-06-29 14:15:47 +03:00
dry " $RESIZE_REISER " -s " $NEWSIZE " " $VOLUME "
2007-12-17 15:31:50 +03:00
fi
}
########################
# Resize XFS filesystem
# - mounted for upsize
2010-10-08 15:18:29 +04:00
# - cannot downsize
2007-12-17 15:31:50 +03:00
########################
resize_xfs( ) {
detect_mounted
MOUNTPOINT = $MOUNTED
if [ -z " $MOUNTED " ] ; then
MOUNTPOINT = $TEMPDIR
2017-05-10 16:13:35 +03:00
temp_mount || error "Cannot mount Xfs filesystem."
2007-12-17 15:31:50 +03:00
fi
verbose " Parsing $TUNE_XFS \" $MOUNTPOINT \" "
2013-01-22 14:25:02 +04:00
for i in $( LC_ALL = C " $TUNE_XFS " " $MOUNTPOINT " ) ; do
2007-12-17 15:31:50 +03:00
case " $i " in
"data" *) BLOCKSIZE = ${ i ##*bsize= } ; BLOCKCOUNT = ${ i ##*blocks= } ; ;
esac
done
BLOCKSIZE = ${ BLOCKSIZE %%[^0-9]* }
BLOCKCOUNT = ${ BLOCKCOUNT %%[^0-9]* }
2011-09-19 17:47:37 +04:00
validate_parsing " $TUNE_XFS "
2017-06-29 14:15:47 +03:00
decode_size " $1 " " $BLOCKSIZE "
if [ " $NEWBLOCKCOUNT " -gt " $BLOCKCOUNT " ] ; then
2007-12-17 15:31:50 +03:00
verbose " Resizing Xfs mounted on \" $MOUNTPOINT \" to fill device \" $VOLUME \" "
2017-06-29 14:15:47 +03:00
dry " $RESIZE_XFS " " $MOUNTPOINT "
elif [ " $NEWBLOCKCOUNT " -eq " $BLOCKCOUNT " ] ; then
2007-12-17 15:31:50 +03:00
verbose "Xfs filesystem already has the right size"
else
2017-05-10 16:13:35 +03:00
error "Xfs filesystem shrinking is unsupported."
2007-12-17 15:31:50 +03:00
fi
}
2017-10-06 17:28:35 +03:00
# Find active LUKS device on original volume
# 1) look for LUKS device with well-known UUID format (CRYPT-LUKS[12]-<uuid>-<dmname>)
# 2) the dm-crypt device has to be on top of original device (dont't support detached LUKS headers)
detect_luks_device( ) {
2017-10-23 19:11:32 +03:00
local _LUKS_VERSION
local _LUKS_UUID
2017-10-06 17:28:35 +03:00
CRYPT_NAME = ""
CRYPT_DATA_OFFSET = ""
2017-11-05 20:22:02 +03:00
_LUKS_VERSION = $( " $CRYPTSETUP " luksDump " $VOLUME " 2> /dev/null | " $GREP " "Version:" )
2017-10-06 17:28:35 +03:00
2017-10-11 12:17:36 +03:00
if [ -z " $_LUKS_VERSION " ] ; then
2017-10-06 17:28:35 +03:00
verbose " Failed to parse LUKS version on volume \" $VOLUME \" "
return
fi
_LUKS_VERSION = ${ _LUKS_VERSION //[Version : [ : space : ]]/ }
2017-11-05 20:22:02 +03:00
_LUKS_UUID = $( " $CRYPTSETUP " luksDump " $VOLUME " 2> /dev/null | " $GREP " "UUID:" )
2017-10-06 17:28:35 +03:00
2017-10-11 12:17:36 +03:00
if [ -z " $_LUKS_UUID " ] ; then
2017-10-06 17:28:35 +03:00
verbose " Failed to parse LUKS UUID on volume \" $VOLUME \" "
return
fi
2017-10-10 16:21:28 +03:00
_LUKS_UUID = " CRYPT-LUKS $_LUKS_VERSION - ${ _LUKS_UUID //[UID : [ : space : ]-]/ } - "
2017-10-06 17:28:35 +03:00
2017-10-10 16:21:28 +03:00
CRYPT_NAME = $( dmsetup info -c --noheadings -S " UUID=~^ $_LUKS_UUID &&segments=1&&devnos_used=' $MAJOR : $MINOR ' " -o name)
2017-11-05 20:22:02 +03:00
test -z " $CRYPT_NAME " || CRYPT_DATA_OFFSET = $( dmsetup table " $CRYPT_NAME " | cut -d ' ' -f 8)
2017-10-11 12:17:36 +03:00
# LUKS device must be active and mapped over volume where detected
2017-11-05 20:22:02 +03:00
if [ -z " $CRYPT_NAME " ] || [ -z " $CRYPT_DATA_OFFSET " ] ; then
2017-10-11 12:17:36 +03:00
error " Can not find active LUKS device. Unlock \" $VOLUME \" volume first. "
fi
2017-10-06 17:28:35 +03:00
}
######################################
# Resize active LUKS device
# - LUKS must be active for fs resize
######################################
resize_luks( ) {
2017-10-23 19:11:32 +03:00
local L_NEWSIZE
local L_NEWBLOCKCOUNT
local NAME
2017-10-06 17:28:35 +03:00
local SHRINK = 0
detect_luks_device
NAME = $CRYPT_NAME
verbose " Found active LUKS device \" $NAME \" for volume \" $VOLUME \" "
decode_size " $1 " 512
if [ $(( NEWSIZE % 512 )) -gt 0 ] ; then
error "New size is not sector alligned"
fi
2017-10-23 16:31:44 +03:00
if [ $(( NEWBLOCKCOUNT - CRYPT_DATA_OFFSET)) -lt 1 ] ; then
error " New size is smaller than minimum ( $(( ( CRYPT_DATA_OFFSET + 1 ) * 512 )) bytes) for LUKS device $VOLUME "
fi
2017-10-23 19:11:32 +03:00
L_NEWBLOCKCOUNT = $(( NEWBLOCKCOUNT - CRYPT_DATA_OFFSET))
L_NEWSIZE = $(( L_NEWBLOCKCOUNT * 512 ))
2017-10-06 17:28:35 +03:00
2017-10-10 18:43:45 +03:00
VOLUME = " $DM_DEV_DIR /mapper/ $NAME "
2017-10-06 17:28:35 +03:00
detect_device_size
2017-10-23 19:11:32 +03:00
test " $DEVSIZE " -le " $L_NEWSIZE " || SHRINK = 1
2017-10-06 17:28:35 +03:00
if [ $SHRINK -eq 1 ] ; then
# shrink fs on LUKS device first
2017-10-23 19:11:32 +03:00
resize " $DM_DEV_DIR /mapper/ $NAME " " $L_NEWSIZE " b
2017-10-06 17:28:35 +03:00
fi
# resize LUKS device
2017-11-05 20:22:02 +03:00
dry " $CRYPTSETUP " resize " $NAME " --size $L_NEWBLOCKCOUNT || error "Failed to resize active LUKS device"
2017-10-06 17:28:35 +03:00
if [ $SHRINK -eq 0 ] ; then
# grow fs on top of LUKS device
2017-10-23 19:11:32 +03:00
resize " $DM_DEV_DIR /mapper/ $NAME " " $L_NEWSIZE " b
2017-10-06 17:28:35 +03:00
fi
}
2017-10-24 12:53:22 +03:00
detect_crypt_device( ) {
local CRYPT_TYPE
local L_NEWSIZE
local TMP
2017-10-06 17:28:35 +03:00
2017-11-05 20:22:02 +03:00
which " $CRYPTSETUP " > /dev/null 2>& 1 || error " $CRYPTSETUP utility required to resize crypt device "
2017-10-06 17:28:35 +03:00
2017-11-05 20:22:02 +03:00
CRYPT_TYPE = $( " $CRYPTSETUP " status " $1 " 2> /dev/null | " $GREP " "type:" )
2017-10-06 17:28:35 +03:00
test -n " $CRYPT_TYPE " || error " $CRYPTSETUP failed to detect device type on $1 . "
CRYPT_TYPE = ${ CRYPT_TYPE ##*[[ : space : ]] }
2017-10-24 12:53:22 +03:00
case " $CRYPT_TYPE " in
LUKS[ 12] | PLAIN)
verbose " \" $1 \" crypt device is type $CRYPT_TYPE "
; ;
*)
error " Unsupported crypt type \" $CRYPT_TYPE \" "
esac
2017-10-06 17:28:35 +03:00
2017-10-24 12:53:22 +03:00
TMP = $NEWSIZE
2017-10-06 17:28:35 +03:00
decode_size " $2 " 512
2017-10-24 12:53:22 +03:00
L_NEWSIZE = $NEWSIZE
NEWSIZE = $TMP
2017-10-06 17:28:35 +03:00
2017-10-24 12:53:22 +03:00
if [ $(( L_NEWSIZE % 512 )) -ne 0 ] ; then
error "New size is not sector alligned"
2017-10-06 17:28:35 +03:00
fi
2017-10-24 12:53:22 +03:00
CRYPT_RESIZE_BLOCKS = $NEWBLOCKCOUNT
2017-10-06 17:28:35 +03:00
2017-10-24 12:53:22 +03:00
if [ " $DEVSIZE " -ge " $L_NEWSIZE " ] ; then
CRYPT_SHRINK = 1
else
CRYPT_GROW = 1
2017-10-06 17:28:35 +03:00
fi
2017-10-24 12:53:22 +03:00
}
2017-10-06 17:28:35 +03:00
2017-10-24 12:53:22 +03:00
#################################
# Resize active crypt device
# (on direct user request only)
#################################
resize_crypt( ) {
2017-11-05 20:22:02 +03:00
dry " $CRYPTSETUP " resize " $1 " --size $CRYPT_RESIZE_BLOCKS || error " $CRYPTSETUP failed to resize device $1 "
2017-10-06 17:28:35 +03:00
}
2007-12-17 15:31:50 +03:00
####################
# Resize filesystem
####################
resize( ) {
2008-02-06 15:45:32 +03:00
NEWSIZE = $2
2007-12-17 15:31:50 +03:00
detect_fs " $1 "
detect_device_size
2009-02-24 18:48:00 +03:00
verbose " Device \" $VOLUME \" size is $DEVSIZE bytes "
2007-12-17 15:31:50 +03:00
# if the size parameter is missing use device size
2008-02-06 15:45:32 +03:00
#if [ -n "$NEWSIZE" -a $NEWSIZE <
2008-01-08 19:45:43 +03:00
test -z " $NEWSIZE " && NEWSIZE = ${ DEVSIZE } b
2017-10-06 17:28:35 +03:00
test -n " $NEWSIZE_ORIG " || NEWSIZE_ORIG = $NEWSIZE
2009-06-09 19:31:36 +04:00
IFS = $NL
2017-10-24 12:53:22 +03:00
test -z " $DO_CRYPTRESIZE " || detect_crypt_device " $VOLUME_ORIG " " $NEWSIZE_ORIG "
test -z " $CRYPT_GROW " || resize_crypt " $VOLUME_ORIG "
2007-12-17 15:31:50 +03:00
case " $FSTYPE " in
2009-02-04 15:47:05 +03:00
"ext3" | "ext2" | "ext4" ) resize_ext $NEWSIZE ; ;
2007-12-17 15:31:50 +03:00
"reiserfs" ) resize_reiser $NEWSIZE ; ;
"xfs" ) resize_xfs $NEWSIZE ; ;
2017-10-06 17:28:35 +03:00
"crypto_LUKS" )
2017-11-05 20:22:02 +03:00
which " $CRYPTSETUP " > /dev/null 2>& 1 || error " $CRYPTSETUP utility required to resize LUKS volume "
2017-10-06 17:28:35 +03:00
resize_luks $NEWSIZE ; ;
2017-05-10 16:13:35 +03:00
*) error " Filesystem \" $FSTYPE \" on device \" $VOLUME \" is not supported by this tool. " ; ;
esac || error " Resize $FSTYPE failed. "
2017-10-24 12:53:22 +03:00
test -z " $CRYPT_SHRINK " || resize_crypt " $VOLUME_ORIG "
2007-12-17 15:31:50 +03:00
}
2010-11-10 19:14:02 +03:00
####################################
# Calclulate diff between two dates
2013-01-22 14:25:02 +04:00
# LC_ALL=C input is expected the
2010-11-10 19:14:02 +03:00
# only one supported
####################################
diff_dates( ) {
2011-09-19 23:36:52 +04:00
echo $(( $( " $DATE " -u -d" $1 " +%s 2>" $NULL " ) - $( " $DATE " -u -d" $2 " +%s 2>" $NULL " ) ))
2010-11-10 19:14:02 +03:00
}
2017-10-11 12:17:36 +03:00
check_luks( ) {
detect_luks_device
check " $DM_DEV_DIR /mapper/ $CRYPT_NAME "
}
2007-12-17 15:31:50 +03:00
###################
# Check filesystem
###################
check( ) {
detect_fs " $1 "
2010-11-01 17:08:51 +03:00
if detect_mounted ; then
verbose " Skipping filesystem check for device \" $VOLUME \" as the filesystem is mounted on $MOUNTED " ;
cleanup 3
fi
2010-11-10 19:14:02 +03:00
case " $FSTYPE " in
"ext2" | "ext3" | "ext4" )
IFS_CHECK = $IFS
IFS = $NL
2013-01-22 14:25:02 +04:00
for i in $( LC_ALL = C " $TUNE_EXT " -l " $VOLUME " ) ; do
2010-11-10 19:14:02 +03:00
case " $i " in
"Last mount" *) LASTMOUNT = ${ i ##* : } ; ;
"Last checked" *) LASTCHECKED = ${ i ##* : } ; ;
esac
done
case " $LASTMOUNT " in
*"n/a" ) ; ; # nothing to do - system was not mounted yet
*)
2017-06-29 14:15:47 +03:00
LASTDIFF = $( diff_dates " $LASTMOUNT " " $LASTCHECKED " )
2010-11-10 19:14:02 +03:00
if test " $LASTDIFF " -gt 0 ; then
verbose "Filesystem has not been checked after the last mount, using fsck -f"
FORCE = "-f"
fi
; ;
esac
IFS = $IFS_CHECK
esac
2007-12-17 15:31:50 +03:00
case " $FSTYPE " in
2014-01-20 14:57:39 +04:00
"xfs" ) if which " $XFS_CHECK " >" $NULL " 2>& 1 ; then
dry " $XFS_CHECK " " $VOLUME "
else
# Replacement for outdated xfs_check
# FIXME: for small devices we need to force_geometry,
# since we run in '-n' mode, it shouldn't be problem.
# Think about better way....
dry " $XFS_REPAIR " -n -o force_geometry " $VOLUME "
fi ; ;
2017-10-11 11:20:38 +03:00
"ext2" | "ext3" | "ext4" | "reiserfs" )
# check if executed from interactive shell environment
2010-10-08 19:02:05 +04:00
case " $- " in
2011-09-19 17:47:37 +04:00
*i*) dry " $FSCK " $YES $FORCE " $VOLUME " ; ;
*) dry " $FSCK " $FORCE -p " $VOLUME " ; ;
2017-10-11 11:20:38 +03:00
esac ; ;
2017-10-11 12:17:36 +03:00
"crypto_LUKS" )
2017-11-05 20:22:02 +03:00
which " $CRYPTSETUP " > /dev/null 2>& 1 || error " $CRYPTSETUP utility required. "
2017-10-11 12:17:36 +03:00
check_luks ; ;
2017-10-11 11:20:38 +03:00
*)
error " Filesystem \" $FSTYPE \" on device \" $VOLUME \" is not supported by this tool. " ; ;
2007-12-17 15:31:50 +03:00
esac
}
#############################
# start point of this script
# - parsing parameters
#############################
2010-11-01 17:08:51 +03:00
trap "cleanup 2" 2
2008-01-08 19:45:43 +03:00
2008-02-06 15:45:32 +03:00
# test if we are not invoked recursively
test -n " $FSADM_RUNNING " && exit 0
2008-01-08 19:45:43 +03:00
# test some prerequisities
2014-06-30 22:03:05 +04:00
for i in " $TUNE_EXT " " $RESIZE_EXT " " $TUNE_REISER " " $RESIZE_REISER " \
" $TUNE_XFS " " $RESIZE_XFS " " $MOUNT " " $UMOUNT " " $MKDIR " \
" $RMDIR " " $BLOCKDEV " " $BLKID " " $GREP " " $READLINK " \
" $DATE " " $FSCK " " $XFS_CHECK " " $XFS_REPAIR " " $LVM " ; do
test -n " $i " || error "Required command definitions in the script are missing!"
done
2008-04-29 19:25:28 +04:00
2017-05-10 16:13:35 +03:00
" $LVM " version >" $NULL " 2>& 1 || error " Could not run lvm binary \" $LVM \". "
2017-06-29 17:04:19 +03:00
" $READLINK " -e / >" $NULL " 2>& 1 || READLINK_E = "-f"
2008-01-08 19:45:43 +03:00
TEST64BIT = $(( 1000 * 1000000000000 ))
2017-05-10 16:13:35 +03:00
test " $TEST64BIT " -eq 1000000000000000 || error "Shell does not handle 64bit arithmetic."
2017-06-29 17:04:19 +03:00
echo Y | " $GREP " Y >" $NULL " || error "Grep does not work properly."
2017-06-29 14:15:47 +03:00
test " $( " $DATE " -u -d"Jan 01 00:00:01 1970" +%s) " -eq 1 || error "Date translation does not work."
2008-01-08 19:45:43 +03:00
2009-02-24 18:48:00 +03:00
if [ " $# " -eq 0 ] ; then
2007-12-17 15:31:50 +03:00
tool_usage
fi
2009-02-24 18:48:00 +03:00
while [ " $# " -ne 0 ]
2007-12-17 15:31:50 +03:00
do
2009-02-24 18:48:00 +03:00
case " $1 " in
"" ) ; ;
"-h" | "--help" ) tool_usage ; ;
"-v" | "--verbose" ) VERB = "-v" ; ;
"-n" | "--dry-run" ) DRY = 1 ; ;
"-f" | "--force" ) FORCE = "-f" ; ;
"-e" | "--ext-offline" ) EXTOFF = 1 ; ;
"-y" | "--yes" ) YES = "-y" ; ;
"-l" | "--lvresize" ) DO_LVRESIZE = 1 ; ;
2017-10-06 17:28:35 +03:00
"-c" | "--cryptresize" ) DO_CRYPTRESIZE = 1 ; ;
2017-07-04 12:55:17 +03:00
"check" ) CHECK = $2 ; shift ; ;
"resize" ) RESIZE = $2 ; NEWSIZE = $3 ; shift 2 ; ;
2009-02-24 18:48:00 +03:00
*) error " Wrong argument \" $1 \". (see: $TOOL --help) "
2007-12-17 15:31:50 +03:00
esac
shift
done
2017-07-04 12:55:17 +03:00
test " $YES " = "-y" || YES = ""
2012-03-16 16:53:05 +04:00
test " $EXTOFF " -eq 1 || EXTOFF = 0
2007-12-17 15:31:50 +03:00
if [ -n " $CHECK " ] ; then
check " $CHECK "
elif [ -n " $RESIZE " ] ; then
2008-02-06 15:45:32 +03:00
export FSADM_RUNNING = "fsadm"
2007-12-17 15:31:50 +03:00
resize " $RESIZE " " $NEWSIZE "
2017-10-06 17:28:35 +03:00
cleanup 0
2007-12-17 15:31:50 +03:00
else
error " Missing command. (see: $TOOL --help) "
fi