#!/bin/bash #Copyright 2002, William Stearns #Released under the GPL. Version=0.1 askYN () { TESTYN="" while [ "$TESTYN" != 'Y' ] && [ "$TESTYN" != 'N' ] ; do echo -n '?' >/dev/stderr read TESTYN || : case $TESTYN in T*|t*|Y*|y*) TESTYN='Y' ;; F*|f*|N*|n*) TESTYN='N' ;; esac done if [ "$TESTYN" = 'Y' ]; then return 0 #True else return 1 #False fi } #End of askYN usage () { echo "$0 Version $Version: Enlarges a filesystem that is stored in a file, as opposed" >>/dev/stderr echo 'to a partition.' >>/dev/stderr echo 'Usage:' >>/dev/stderr echo " $0 filesystemfile newsize" >>/dev/stderr echo 'Example:' >>/dev/stderr echo " $0 root_fs 750" >>/dev/stderr echo '' >>/dev/stderr echo 'The new size must be in megabytes and must be at least 2.' >>/dev/stderr exit 1 } fail () { echo "$* Exiting." >>/dev/stderr exit 1 } for OneUtil in awk cp dd e2fsck file ls mktemp resize2fs rm ; do type -path "$OneUtil" >/dev/null 2>/dev/null || fail Missing utility "$OneUtil" done #FIXME - check to see if file is in use before starting #FIXME - remind user to run cow first, if needed. #FIXME - check free space against size of root_fs + requested space FsFile="${1}" [ -n "$FsFile" ] || usage [ -f "$FsFile" ] || fail No file named \""$FsFile"\". NewMegs=${2} [ -n "$NewMegs" ] || usage case "$NewMegs" in # 2 10 100 1000 2000 2040 # 9 99 999 1999 2039 2047 [2-9]|[1-9][0-9]|[1-9][0-9][0-9]|1[0-9][0-9][0-9]|20[0-3][0-9]|204[0-7]) : ;; # 2048 2050 2100 3000 # 2049 2099 2999 9999 204[89]|20[5-9][0-9]|2[1-9][0-9][0-9]|[3-9][0-9][0-9][0-9]) #Bash ints overflow at 2047 * 1M. fail New sizes larger than 2047 are not supported at the moment. ;; *) fail The new size you specify must be a number of megabytes between 2 and 2047. ;; esac case `file "$FsFile"` in *:\ Linux\ rev\ 1.0\ ext2\ filesystem\ data|*:\ Linux\ rev\ 1.0\ ext3\ filesystem\ data) : ;; *:\ ASCII\ text,\ with\ no\ line\ terminators) fail Reiserfs not supported in this version. ;; *) fail Unrecognized filesystem type `file "$FsFile"` ;; esac TMPFILE=`mktemp "$FsFile.XXXXXX"` || fail Unable to create temporary file. CurFileSize=`ls -al "$FsFile" | awk '{print $5}'` NewFileSize=$[ $NewMegs * 1048576 ] echo Requested: $NewFileSize , Currently: $CurFileSize if [ $NewFileSize -eq $CurFileSize ]; then echo Requested size equals current size. cp -p --sparse=always $FsFile $TMPFILE resize2fs -p $TMPFILE || fail Resize2fs failed. elif [ $NewFileSize -lt $CurFileSize ]; then echo Requested size is less than current size. TMPFILE2=`mktemp "$FsFile.XXXXXX"` || fail Unable to create temporary file. cp -p --sparse=always $FsFile $TMPFILE2 resize2fs -p $TMPFILE2 $[ $NewMegs * 256 ] || fail Resize2fs failed. #FIXME - "perl -e open/truncate/close" if perl is available. cp -p --sparse=always <( dd bs=1048576 if=$TMPFILE2 count=$NewMegs ) $TMPFILE rm -f $TMPFILE2 elif [ $NewFileSize -gt $CurFileSize ]; then echo Requested size is larger than current size. #if new-cur > mem, the following dd fails with memory exhausted. # dd bs=$[ $NewFileSize - $CurFileSize ] count=1 if=/dev/zero #I've broken up the above dd if=/dev/zero into: #copy megabyte sized chunks of 0x0 bytes. #copy the remaining (<1M) bytes as a single block. cp -p --sparse=always <( \ dd bs=1048576 if=$FsFile ; \ if [ $[ $NewFileSize - $CurFileSize ] -ge 1048576 ]; then \ dd bs=1048576 count=$[ ( $NewFileSize - $CurFileSize ) / 1048576 ] if=/dev/zero ; \ fi ; \ if [ $[ $NewFileSize - $CurFileSize - ( ( ($NewFileSize - $CurFileSize) / 1048576 ) * 1048576 ) ] -gt 0 ]; then \ dd bs=$[ $NewFileSize - $CurFileSize - ( ( ($NewFileSize - $CurFileSize) / 1048576 ) * 1048576 ) ] count=1 if=/dev/zero ; \ fi \ ) $TMPFILE resize2fs -p $TMPFILE $[ $NewMegs * 256 ] || fail Resize2fs failed. fi [ $NewFileSize -eq `ls -al "$TMPFILE" | awk '{print $5}'` ] || fail $TMPFILE is not $NewFileSize bytes long. #Copy back if e2fsck says OK. if e2fsck -f $TMPFILE ; then echo Filesystem check of $TMPFILE passed. if echo -n "Would you like to replace the $FsFile" ; askYN ; then echo Resize OK, moving file back to $FsFile rm -f $FsFile cp -p --sparse=always $TMPFILE $FsFile rm -f $TMPFILE else echo Not replacing $FsFile. You may wish to delete $TMPFILE. fi else echo Filesystem check of $TMPFILE failed - not replacing $FsFile . if echo -n "Would you like to delete the $TMPFILE" ; askYN ; then rm -f $TMPFILE else echo Not removing $TMPFILE fi fi